Initial version of libomxil-vc4 for RPI3 83/161583/2 submit/tizen_4.0/20171213.043831
authorSejun Park <sejun79.park@samsung.com>
Fri, 24 Nov 2017 08:12:58 +0000 (17:12 +0900)
committerHackseung Lee <lhs@dignsys.com>
Thu, 7 Dec 2017 02:33:45 +0000 (11:33 +0900)
  build: changed build specs.

  Changed packaging names as below:
      libomxil-vc4-0.0.1-0.1.armv7l.rpm
  libomxil-vc4-debuginfo-0.0.1-0.1.armv7l.rpm
  libomxil-vc4-debugsource-0.0.1-0.1.armv7l.rpm
  libomxil-vc4-devel-0.0.1-0.1.armv7l.rpm
  libomxil-vc4-utils-0.0.1-0.1.armv7l.rpm
  libomxil-vc4-utils-debuginfo-0.0.1-0.1.armv7l.rpm

Change-Id: I53d1515c6af3ba427740fc57479608c4e5abd98e
Signed-off-by: Hackseung Lee <lhs@dignsys.com>
817 files changed:
.gitignore [new file with mode: 0755]
CMakeLists.txt [new file with mode: 0755]
COPYING [new file with mode: 0755]
LICENCE [new file with mode: 0755]
README.md [new file with mode: 0755]
buildme [new file with mode: 0755]
containers/CMakeLists.txt [new file with mode: 0755]
containers/asf/CMakeLists.txt [new file with mode: 0755]
containers/asf/asf_reader.c [new file with mode: 0755]
containers/asf/asf_writer.c [new file with mode: 0755]
containers/avi/CMakeLists.txt [new file with mode: 0755]
containers/avi/avi_reader.c [new file with mode: 0755]
containers/avi/avi_writer.c [new file with mode: 0755]
containers/binary/CMakeLists.txt [new file with mode: 0755]
containers/binary/binary_reader.c [new file with mode: 0755]
containers/binary/binary_writer.c [new file with mode: 0755]
containers/containers.h [new file with mode: 0755]
containers/containers_codecs.h [new file with mode: 0755]
containers/containers_types.h [new file with mode: 0755]
containers/core/containers.c [new file with mode: 0755]
containers/core/containers_bits.c [new file with mode: 0755]
containers/core/containers_bits.h [new file with mode: 0755]
containers/core/containers_bytestream.h [new file with mode: 0755]
containers/core/containers_codecs.c [new file with mode: 0755]
containers/core/containers_common.h [new file with mode: 0755]
containers/core/containers_filters.c [new file with mode: 0755]
containers/core/containers_filters.h [new file with mode: 0755]
containers/core/containers_index.c [new file with mode: 0755]
containers/core/containers_index.h [new file with mode: 0755]
containers/core/containers_io.c [new file with mode: 0755]
containers/core/containers_io.h [new file with mode: 0755]
containers/core/containers_io_helpers.c [new file with mode: 0755]
containers/core/containers_io_helpers.h [new file with mode: 0755]
containers/core/containers_list.c [new file with mode: 0755]
containers/core/containers_list.h [new file with mode: 0755]
containers/core/containers_loader.c [new file with mode: 0755]
containers/core/containers_loader.h [new file with mode: 0755]
containers/core/containers_logging.c [new file with mode: 0755]
containers/core/containers_logging.h [new file with mode: 0755]
containers/core/containers_private.h [new file with mode: 0755]
containers/core/containers_time.h [new file with mode: 0755]
containers/core/containers_uri.c [new file with mode: 0755]
containers/core/containers_uri.h [new file with mode: 0755]
containers/core/containers_utils.c [new file with mode: 0755]
containers/core/containers_utils.h [new file with mode: 0755]
containers/core/containers_waveformat.h [new file with mode: 0755]
containers/core/containers_writer_utils.c [new file with mode: 0755]
containers/core/containers_writer_utils.h [new file with mode: 0755]
containers/core/packetizers.c [new file with mode: 0755]
containers/core/packetizers_private.h [new file with mode: 0755]
containers/dummy/CMakeLists.txt [new file with mode: 0755]
containers/dummy/dummy_writer.c [new file with mode: 0755]
containers/flash/CMakeLists.txt [new file with mode: 0755]
containers/flash/flv_reader.c [new file with mode: 0755]
containers/h264/avc1_packetizer.c [new file with mode: 0755]
containers/io/io_file.c [new file with mode: 0755]
containers/io/io_http.c [new file with mode: 0755]
containers/io/io_net.c [new file with mode: 0755]
containers/io/io_null.c [new file with mode: 0755]
containers/io/io_pktfile.c [new file with mode: 0755]
containers/metadata/id3/CMakeLists.txt [new file with mode: 0755]
containers/metadata/id3/id3_metadata_reader.c [new file with mode: 0755]
containers/metadata/id3/id3_metadata_strings.h [new file with mode: 0755]
containers/mkv/CMakeLists.txt [new file with mode: 0755]
containers/mkv/matroska_reader.c [new file with mode: 0755]
containers/mp4/CMakeLists.txt [new file with mode: 0755]
containers/mp4/mp4_common.h [new file with mode: 0755]
containers/mp4/mp4_reader.c [new file with mode: 0755]
containers/mp4/mp4_writer.c [new file with mode: 0755]
containers/mpeg/CMakeLists.txt [new file with mode: 0755]
containers/mpeg/ps_reader.c [new file with mode: 0755]
containers/mpga/CMakeLists.txt [new file with mode: 0755]
containers/mpga/mpga_common.h [new file with mode: 0755]
containers/mpga/mpga_packetizer.c [new file with mode: 0755]
containers/mpga/mpga_reader.c [new file with mode: 0755]
containers/mpgv/mpgv_packetizer.c [new file with mode: 0755]
containers/net/net_sockets.h [new file with mode: 0755]
containers/net/net_sockets_bsd.c [new file with mode: 0755]
containers/net/net_sockets_bsd.h [new file with mode: 0755]
containers/net/net_sockets_common.c [new file with mode: 0755]
containers/net/net_sockets_null.c [new file with mode: 0755]
containers/net/net_sockets_priv.h [new file with mode: 0755]
containers/net/net_sockets_win32.c [new file with mode: 0755]
containers/net/net_sockets_win32.h [new file with mode: 0755]
containers/packetizers.h [new file with mode: 0755]
containers/pcm/pcm_packetizer.c [new file with mode: 0755]
containers/qsynth/CMakeLists.txt [new file with mode: 0755]
containers/qsynth/qsynth_reader.c [new file with mode: 0755]
containers/raw/CMakeLists.txt [new file with mode: 0755]
containers/raw/raw_video_common.h [new file with mode: 0755]
containers/raw/raw_video_reader.c [new file with mode: 0755]
containers/raw/raw_video_writer.c [new file with mode: 0755]
containers/rcv/CMakeLists.txt [new file with mode: 0755]
containers/rcv/rcv_reader.c [new file with mode: 0755]
containers/rtp/CMakeLists.txt [new file with mode: 0755]
containers/rtp/rtp_base64.c [new file with mode: 0755]
containers/rtp/rtp_base64.h [new file with mode: 0755]
containers/rtp/rtp_h264.c [new file with mode: 0755]
containers/rtp/rtp_h264.h [new file with mode: 0755]
containers/rtp/rtp_mpeg4.c [new file with mode: 0755]
containers/rtp/rtp_mpeg4.h [new file with mode: 0755]
containers/rtp/rtp_priv.h [new file with mode: 0755]
containers/rtp/rtp_reader.c [new file with mode: 0755]
containers/rtsp/CMakeLists.txt [new file with mode: 0755]
containers/rtsp/rtsp_reader.c [new file with mode: 0755]
containers/rv9/CMakeLists.txt [new file with mode: 0755]
containers/rv9/rv9_reader.c [new file with mode: 0755]
containers/simple/CMakeLists.txt [new file with mode: 0755]
containers/simple/simple_common.h [new file with mode: 0755]
containers/simple/simple_reader.c [new file with mode: 0755]
containers/simple/simple_writer.c [new file with mode: 0755]
containers/test/CMakeLists.txt [new file with mode: 0755]
containers/test/autotest.cpp [new file with mode: 0755]
containers/test/check_frame_int.c [new file with mode: 0755]
containers/test/crc_32.c [new file with mode: 0755]
containers/test/datagram_receiver.c [new file with mode: 0755]
containers/test/datagram_sender.c [new file with mode: 0755]
containers/test/dump_pktfile.c [new file with mode: 0755]
containers/test/nb_io.h [new file with mode: 0755]
containers/test/nb_io_unix.c [new file with mode: 0755]
containers/test/nb_io_win32.c [new file with mode: 0755]
containers/test/rtp_decoder.c [new file with mode: 0755]
containers/test/stream_client.c [new file with mode: 0755]
containers/test/stream_server.c [new file with mode: 0755]
containers/test/test.c [new file with mode: 0755]
containers/test/test_bits.c [new file with mode: 0755]
containers/test/test_uri.c [new file with mode: 0755]
containers/test/uri_pipe.c [new file with mode: 0755]
containers/wav/CMakeLists.txt [new file with mode: 0755]
containers/wav/wav_reader.c [new file with mode: 0755]
helpers/dtoverlay/CMakeLists.txt [new file with mode: 0755]
helpers/dtoverlay/dtoverlay.c [new file with mode: 0755]
helpers/dtoverlay/dtoverlay.h [new file with mode: 0755]
helpers/v3d/v3d_common.h [new file with mode: 0755]
helpers/v3d/v3d_ver.h [new file with mode: 0755]
helpers/vc_image/metadata_fourcc.h [new file with mode: 0755]
helpers/vc_image/vc_image.h [new file with mode: 0755]
helpers/vc_image/vc_image_helper.h [new file with mode: 0755]
helpers/vc_image/vc_image_metadata.h [new file with mode: 0755]
host_applications/android/apps/vidtex/CMakeLists.txt [new file with mode: 0755]
host_applications/android/apps/vidtex/applog.h [new file with mode: 0755]
host_applications/android/apps/vidtex/launcher.h [new file with mode: 0755]
host_applications/android/apps/vidtex/launcher_rpi.c [new file with mode: 0755]
host_applications/android/apps/vidtex/launcher_rpi.h [new file with mode: 0755]
host_applications/android/apps/vidtex/main.cpp [new file with mode: 0755]
host_applications/android/apps/vidtex/svp.c [new file with mode: 0755]
host_applications/android/apps/vidtex/svp.h [new file with mode: 0755]
host_applications/android/apps/vidtex/vidtex.c [new file with mode: 0755]
host_applications/android/apps/vidtex/vidtex.h [new file with mode: 0755]
host_applications/framework/common/host_ilcore.h [new file with mode: 0755]
host_applications/framework/common/ilcore.c [new file with mode: 0755]
host_applications/linux/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/apps/dtmerge/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/apps/dtmerge/dtmerge.c [new file with mode: 0755]
host_applications/linux/apps/dtoverlay/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/apps/dtoverlay/dtoverlay-post [new file with mode: 0755]
host_applications/linux/apps/dtoverlay/dtoverlay-pre [new file with mode: 0755]
host_applications/linux/apps/dtoverlay/dtoverlay_main.c [new file with mode: 0755]
host_applications/linux/apps/dtoverlay/utils.c [new file with mode: 0755]
host_applications/linux/apps/dtoverlay/utils.h [new file with mode: 0755]
host_applications/linux/apps/gencmd/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/apps/gencmd/gencmd.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/apps/hello_pi/Makefile.include [new file with mode: 0755]
host_applications/linux/apps/hello_pi/README [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_audio/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_audio/Makefile [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_audio/audio.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_audio/audioplay.h [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_audio/sinewave.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_dispmanx/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_dispmanx/Makefile [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_dispmanx/dispmanx.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_encode/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_encode/Makefile [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_encode/encode.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/gpu_fft.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/gpu_fft.h [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/gpu_fft.txt [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/gpu_fft_base.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/gpu_fft_shaders.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/gpu_fft_trans.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/gpu_fft_trans.h [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/gpu_fft_twiddles.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/hello_fft.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/hello_fft_2d.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/hello_fft_2d_bitmap.h [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/hex/shader_1024k.hex [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/hex/shader_128k.hex [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/hex/shader_16k.hex [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/hex/shader_1k.hex [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/hex/shader_2048k.hex [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/hex/shader_256.hex [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/hex/shader_256k.hex [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/hex/shader_2k.hex [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/hex/shader_32k.hex [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/hex/shader_4096k.hex [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/hex/shader_4k.hex [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/hex/shader_512.hex [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/hex/shader_512k.hex [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/hex/shader_64k.hex [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/hex/shader_8k.hex [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/hex/shader_trans.hex [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/mailbox.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/mailbox.h [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/makefile [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft.qinc [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_1024k.qasm [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_128k.qasm [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_16k.qasm [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_1k.qasm [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_2048k.qasm [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_2048k.qinc [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_256.qasm [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_256k.qasm [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_2k.qasm [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_32k.qasm [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_4096k.qasm [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_4k.qasm [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_512.qasm [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_512k.qasm [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_64k.qasm [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_8k.qasm [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_ex.qinc [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_trans.qasm [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_font/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_font/Makefile [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_font/Vera.ttf [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_font/main.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_jpeg/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_jpeg/Makefile [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_jpeg/jpeg.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_jpeg/jpeg.h [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_mmal_encode/Makefile [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_mmal_encode/mmal_encode.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_teapot/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_teapot/Makefile [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_teapot/README.md [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_teapot/cube_texture_and_coords.h [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_teapot/models.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_teapot/models.h [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_teapot/teapot.obj.dat [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_teapot/triangle.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_teapot/triangle.h [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_teapot/video.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_tiger/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_tiger/Makefile [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_tiger/license.txt [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_tiger/main.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_tiger/readme.txt [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_tiger/tiger.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_tiger/tiger.h [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_triangle/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_triangle/Makefile [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_triangle/cube_texture_and_coords.h [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_triangle/triangle.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_triangle2/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_triangle2/Makefile [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_triangle2/triangle2.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_video/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_video/Makefile [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_video/README [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_video/omx_comp_debug_levels.h [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_video/queue.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_video/queue.h [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_video/tags [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_video/tsemaphore.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_video/tsemaphore.h [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_video/user_debug_levels.h [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_video/video.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_video/video.h [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_videocube/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_videocube/Makefile [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_videocube/README.md [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_videocube/cube_texture_and_coords.h [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_videocube/triangle.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_videocube/triangle.h [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_videocube/video.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_world/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_world/Makefile [new file with mode: 0755]
host_applications/linux/apps/hello_pi/hello_world/world.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/libs/ilclient/Makefile [new file with mode: 0755]
host_applications/linux/apps/hello_pi/libs/ilclient/ilclient.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/libs/ilclient/ilclient.h [new file with mode: 0755]
host_applications/linux/apps/hello_pi/libs/ilclient/ilcore.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/libs/vgfont/Makefile [new file with mode: 0755]
host_applications/linux/apps/hello_pi/libs/vgfont/font.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/libs/vgfont/graphics.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/libs/vgfont/graphics_x_private.h [new file with mode: 0755]
host_applications/linux/apps/hello_pi/libs/vgfont/vgfont.h [new file with mode: 0755]
host_applications/linux/apps/hello_pi/libs/vgfont/vgft.c [new file with mode: 0755]
host_applications/linux/apps/hello_pi/libs/vgfont/vgft.h [new file with mode: 0755]
host_applications/linux/apps/hello_pi/rebuild.sh [new file with mode: 0755]
host_applications/linux/apps/raspicam/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/apps/raspicam/Doxyfile [new file with mode: 0755]
host_applications/linux/apps/raspicam/Makefile [new file with mode: 0755]
host_applications/linux/apps/raspicam/README.md [new file with mode: 0755]
host_applications/linux/apps/raspicam/RaspiCLI.c [new file with mode: 0755]
host_applications/linux/apps/raspicam/RaspiCLI.h [new file with mode: 0755]
host_applications/linux/apps/raspicam/RaspiCamControl.c [new file with mode: 0755]
host_applications/linux/apps/raspicam/RaspiCamControl.h [new file with mode: 0755]
host_applications/linux/apps/raspicam/RaspiPreview.c [new file with mode: 0755]
host_applications/linux/apps/raspicam/RaspiPreview.h [new file with mode: 0755]
host_applications/linux/apps/raspicam/RaspiStill.c [new file with mode: 0755]
host_applications/linux/apps/raspicam/RaspiStillYUV.c [new file with mode: 0755]
host_applications/linux/apps/raspicam/RaspiTex.c [new file with mode: 0755]
host_applications/linux/apps/raspicam/RaspiTex.h [new file with mode: 0755]
host_applications/linux/apps/raspicam/RaspiTexUtil.c [new file with mode: 0755]
host_applications/linux/apps/raspicam/RaspiTexUtil.h [new file with mode: 0755]
host_applications/linux/apps/raspicam/RaspiVid.c [new file with mode: 0755]
host_applications/linux/apps/raspicam/RaspiVidYUV.c [new file with mode: 0755]
host_applications/linux/apps/raspicam/gl_scenes/cube_texture_and_coords.h [new file with mode: 0755]
host_applications/linux/apps/raspicam/gl_scenes/mirror.c [new file with mode: 0755]
host_applications/linux/apps/raspicam/gl_scenes/mirror.h [new file with mode: 0755]
host_applications/linux/apps/raspicam/gl_scenes/models.c [new file with mode: 0755]
host_applications/linux/apps/raspicam/gl_scenes/models.h [new file with mode: 0755]
host_applications/linux/apps/raspicam/gl_scenes/sobel.c [new file with mode: 0755]
host_applications/linux/apps/raspicam/gl_scenes/sobel.h [new file with mode: 0755]
host_applications/linux/apps/raspicam/gl_scenes/square.c [new file with mode: 0755]
host_applications/linux/apps/raspicam/gl_scenes/square.h [new file with mode: 0755]
host_applications/linux/apps/raspicam/gl_scenes/teapot.c [new file with mode: 0755]
host_applications/linux/apps/raspicam/gl_scenes/teapot.h [new file with mode: 0755]
host_applications/linux/apps/raspicam/gl_scenes/vcsm_square.c [new file with mode: 0755]
host_applications/linux/apps/raspicam/gl_scenes/vcsm_square.h [new file with mode: 0755]
host_applications/linux/apps/raspicam/gl_scenes/yuv.c [new file with mode: 0755]
host_applications/linux/apps/raspicam/gl_scenes/yuv.h [new file with mode: 0755]
host_applications/linux/apps/raspicam/imv_examples/README.md [new file with mode: 0755]
host_applications/linux/apps/raspicam/imv_examples/imv2pgm.c [new file with mode: 0755]
host_applications/linux/apps/raspicam/imv_examples/imv2txt.c [new file with mode: 0755]
host_applications/linux/apps/raspicam/imv_examples/plot.par [new file with mode: 0755]
host_applications/linux/apps/raspicam/tga.c [new file with mode: 0755]
host_applications/linux/apps/raspicam/tga.h [new file with mode: 0755]
host_applications/linux/apps/smem/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/apps/smem/smem.c [new file with mode: 0755]
host_applications/linux/apps/tvservice/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/apps/tvservice/tvservice.c [new file with mode: 0755]
host_applications/linux/apps/vcmailbox/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/apps/vcmailbox/vcmailbox.c [new file with mode: 0755]
host_applications/linux/kernel_headers/vmcs_sm_ioctl.h [new file with mode: 0755]
host_applications/linux/libs/bcm_host/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/libs/bcm_host/bcm_host.c [new file with mode: 0755]
host_applications/linux/libs/bcm_host/include/bcm_host.h [new file with mode: 0755]
host_applications/linux/libs/debug_sym/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/libs/debug_sym/debug_sym.c [new file with mode: 0755]
host_applications/linux/libs/debug_sym/debug_sym.h [new file with mode: 0755]
host_applications/linux/libs/sm/CMakeLists.txt [new file with mode: 0755]
host_applications/linux/libs/sm/user-vcsm.c [new file with mode: 0755]
host_applications/linux/libs/sm/user-vcsm.h [new file with mode: 0755]
host_applications/vmcs/test_apps/mmalcam/mmalcam.c [new file with mode: 0755]
host_applications/vmcs/test_apps/mmalcam/mmalcam.h [new file with mode: 0755]
host_applications/vmcs/test_apps/mmalcam/viewfinder.c [new file with mode: 0755]
host_applications/vmcs/test_apps/mmalplay/mmalplay.c [new file with mode: 0755]
host_applications/vmcs/test_apps/mmalplay/mmalplay.h [new file with mode: 0755]
host_applications/vmcs/test_apps/mmalplay/playback.c [new file with mode: 0755]
host_applications/vmcs/vmcs_config.h.in [new file with mode: 0755]
host_support/include/vc_debug_sym.h [new file with mode: 0755]
host_support/include/vc_mem.h [new file with mode: 0755]
interface/khronos/CMakeLists.txt [new file with mode: 0755]
interface/khronos/common/abstract/khrn_client_platform_filler_abstract.h [new file with mode: 0755]
interface/khronos/common/direct/khrn_client_platform_filler_direct.h [new file with mode: 0755]
interface/khronos/common/khrn_client.c [new file with mode: 0755]
interface/khronos/common/khrn_client.h [new file with mode: 0755]
interface/khronos/common/khrn_client_cache.c [new file with mode: 0755]
interface/khronos/common/khrn_client_cache.h [new file with mode: 0755]
interface/khronos/common/khrn_client_check_types.h [new file with mode: 0755]
interface/khronos/common/khrn_client_cr.c [new file with mode: 0755]
interface/khronos/common/khrn_client_global_image_map.c [new file with mode: 0755]
interface/khronos/common/khrn_client_global_image_map.h [new file with mode: 0755]
interface/khronos/common/khrn_client_mangle.h [new file with mode: 0755]
interface/khronos/common/khrn_client_platform.h [new file with mode: 0755]
interface/khronos/common/khrn_client_pointermap.c [new file with mode: 0755]
interface/khronos/common/khrn_client_pointermap.h [new file with mode: 0755]
interface/khronos/common/khrn_client_rpc.h [new file with mode: 0755]
interface/khronos/common/khrn_client_unmangle.h [new file with mode: 0755]
interface/khronos/common/khrn_client_vector.c [new file with mode: 0755]
interface/khronos/common/khrn_client_vector.h [new file with mode: 0755]
interface/khronos/common/khrn_int_color.h [new file with mode: 0755]
interface/khronos/common/khrn_int_common.h [new file with mode: 0755]
interface/khronos/common/khrn_int_generic_map.c [new file with mode: 0755]
interface/khronos/common/khrn_int_generic_map.h [new file with mode: 0755]
interface/khronos/common/khrn_int_hash.c [new file with mode: 0755]
interface/khronos/common/khrn_int_hash.h [new file with mode: 0755]
interface/khronos/common/khrn_int_hash_asm.s [new file with mode: 0755]
interface/khronos/common/khrn_int_ids.h [new file with mode: 0755]
interface/khronos/common/khrn_int_image.c [new file with mode: 0755]
interface/khronos/common/khrn_int_image.h [new file with mode: 0755]
interface/khronos/common/khrn_int_math.h [new file with mode: 0755]
interface/khronos/common/khrn_int_misc_impl.h [new file with mode: 0755]
interface/khronos/common/khrn_int_util.c [new file with mode: 0755]
interface/khronos/common/khrn_int_util.h [new file with mode: 0755]
interface/khronos/common/khrn_int_util_cr.h [new file with mode: 0755]
interface/khronos/common/khrn_options.c [new file with mode: 0755]
interface/khronos/common/khrn_options.h [new file with mode: 0755]
interface/khronos/common/linux/khrn_client_platform_linux.c [new file with mode: 0755]
interface/khronos/common/linux/khrn_client_rpc_linux.c [new file with mode: 0755]
interface/khronos/common/openwfc/khrn_client_platform_openwfc.c [new file with mode: 0755]
interface/khronos/common/vcos/khrn_client_platform_filler_vcos.h [new file with mode: 0755]
interface/khronos/common/vcos_vchiq/khrn_client_platform_filler_vcos_vchiq.h [new file with mode: 0755]
interface/khronos/egl/egl_client.c [new file with mode: 0755]
interface/khronos/egl/egl_client_config.c [new file with mode: 0755]
interface/khronos/egl/egl_client_config.h [new file with mode: 0755]
interface/khronos/egl/egl_client_config_cr.c [new file with mode: 0755]
interface/khronos/egl/egl_client_context.c [new file with mode: 0755]
interface/khronos/egl/egl_client_context.h [new file with mode: 0755]
interface/khronos/egl/egl_client_cr.c [new file with mode: 0755]
interface/khronos/egl/egl_client_get_proc.c [new file with mode: 0755]
interface/khronos/egl/egl_client_surface.c [new file with mode: 0755]
interface/khronos/egl/egl_client_surface.h [new file with mode: 0755]
interface/khronos/egl/egl_int.h [new file with mode: 0755]
interface/khronos/egl/egl_int_config.h [new file with mode: 0755]
interface/khronos/egl/egl_int_impl.h [new file with mode: 0755]
interface/khronos/ext/egl_brcm_driver_monitor_client.c [new file with mode: 0755]
interface/khronos/ext/egl_brcm_driver_monitor_client.h [new file with mode: 0755]
interface/khronos/ext/egl_brcm_flush_client.c [new file with mode: 0755]
interface/khronos/ext/egl_brcm_global_image_client.c [new file with mode: 0755]
interface/khronos/ext/egl_brcm_perf_monitor_client.c [new file with mode: 0755]
interface/khronos/ext/egl_brcm_perf_monitor_client.h [new file with mode: 0755]
interface/khronos/ext/egl_khr_image_client.c [new file with mode: 0755]
interface/khronos/ext/egl_khr_lock_surface_client.c [new file with mode: 0755]
interface/khronos/ext/egl_khr_sync_client.c [new file with mode: 0755]
interface/khronos/ext/egl_khr_sync_client.h [new file with mode: 0755]
interface/khronos/ext/egl_openmaxil_client.c [new file with mode: 0755]
interface/khronos/ext/egl_openmaxil_client.h [new file with mode: 0755]
interface/khronos/ext/ext_gl_debug_marker.c [new file with mode: 0755]
interface/khronos/ext/gl_oes_draw_texture_client.c [new file with mode: 0755]
interface/khronos/ext/gl_oes_egl_image_client.c [new file with mode: 0755]
interface/khronos/ext/gl_oes_framebuffer_object.c [new file with mode: 0755]
interface/khronos/ext/gl_oes_map_buffer.c [new file with mode: 0755]
interface/khronos/ext/gl_oes_matrix_palette_client.c [new file with mode: 0755]
interface/khronos/ext/gl_oes_query_matrix_client.c [new file with mode: 0755]
interface/khronos/glxx/gl11_int_config.h [new file with mode: 0755]
interface/khronos/glxx/gl11_int_impl.h [new file with mode: 0755]
interface/khronos/glxx/gl20_int_impl.h [new file with mode: 0755]
interface/khronos/glxx/glxx_client.c [new file with mode: 0755]
interface/khronos/glxx/glxx_client.h [new file with mode: 0755]
interface/khronos/glxx/glxx_int_attrib.h [new file with mode: 0755]
interface/khronos/glxx/glxx_int_config.h [new file with mode: 0755]
interface/khronos/glxx/glxx_int_impl.h [new file with mode: 0755]
interface/khronos/include/EGL/egl.h [new file with mode: 0755]
interface/khronos/include/EGL/eglext.h [new file with mode: 0755]
interface/khronos/include/EGL/eglext_android.h [new file with mode: 0755]
interface/khronos/include/EGL/eglext_brcm.h [new file with mode: 0755]
interface/khronos/include/EGL/eglext_nvidia.h [new file with mode: 0755]
interface/khronos/include/EGL/eglplatform.h [new file with mode: 0755]
interface/khronos/include/GLES/gl.h [new file with mode: 0755]
interface/khronos/include/GLES/glext.h [new file with mode: 0755]
interface/khronos/include/GLES/glplatform.h [new file with mode: 0755]
interface/khronos/include/GLES2/gl2.h [new file with mode: 0755]
interface/khronos/include/GLES2/gl2ext.h [new file with mode: 0755]
interface/khronos/include/GLES2/gl2platform.h [new file with mode: 0755]
interface/khronos/include/KHR/khrplatform.h [new file with mode: 0755]
interface/khronos/include/VG/openvg.h [new file with mode: 0755]
interface/khronos/include/VG/vgext.h [new file with mode: 0755]
interface/khronos/include/VG/vgplatform.h [new file with mode: 0755]
interface/khronos/include/VG/vgu.h [new file with mode: 0755]
interface/khronos/include/WF/wfc.h [new file with mode: 0755]
interface/khronos/include/WF/wfcplatform.h [new file with mode: 0755]
interface/khronos/vg/vg_client.c [new file with mode: 0755]
interface/khronos/vg/vg_client.h [new file with mode: 0755]
interface/khronos/vg/vg_int.h [new file with mode: 0755]
interface/khronos/vg/vg_int_config.h [new file with mode: 0755]
interface/khronos/vg/vg_int_impl.h [new file with mode: 0755]
interface/khronos/vg/vg_int_mat3x3.c [new file with mode: 0755]
interface/khronos/vg/vg_int_mat3x3.h [new file with mode: 0755]
interface/khronos/vg/vg_int_util.h [new file with mode: 0755]
interface/khronos/wf/wfc_client.c [new file with mode: 0755]
interface/khronos/wf/wfc_client_ipc.c [new file with mode: 0755]
interface/khronos/wf/wfc_client_ipc.h [new file with mode: 0755]
interface/khronos/wf/wfc_client_server_api.c [new file with mode: 0755]
interface/khronos/wf/wfc_client_stream.c [new file with mode: 0755]
interface/khronos/wf/wfc_client_stream.h [new file with mode: 0755]
interface/khronos/wf/wfc_int.h [new file with mode: 0755]
interface/khronos/wf/wfc_ipc.h [new file with mode: 0755]
interface/khronos/wf/wfc_server_api.h [new file with mode: 0755]
interface/mmal/CMakeLists.txt [new file with mode: 0755]
interface/mmal/client/CMakeLists.txt [new file with mode: 0755]
interface/mmal/client/brcmjpeg/CMakeLists.txt [new file with mode: 0755]
interface/mmal/client/brcmjpeg/brcmjpeg.c [new file with mode: 0755]
interface/mmal/client/brcmjpeg/brcmjpeg.h [new file with mode: 0755]
interface/mmal/client/brcmjpeg/brcmjpeg_test.c [new file with mode: 0755]
interface/mmal/components/CMakeLists.txt [new file with mode: 0755]
interface/mmal/components/aaf_audio_render.cpp [new file with mode: 0755]
interface/mmal/components/aggregator.c [new file with mode: 0755]
interface/mmal/components/android_media_codec.cpp [new file with mode: 0755]
interface/mmal/components/artificial_camera.c [new file with mode: 0755]
interface/mmal/components/avcodec_audio_decoder.c [new file with mode: 0755]
interface/mmal/components/avcodec_video_decoder.c [new file with mode: 0755]
interface/mmal/components/clock.c [new file with mode: 0755]
interface/mmal/components/container_reader.c [new file with mode: 0755]
interface/mmal/components/copy.c [new file with mode: 0755]
interface/mmal/components/null_sink.c [new file with mode: 0755]
interface/mmal/components/passthrough.c [new file with mode: 0755]
interface/mmal/components/scheduler.c [new file with mode: 0755]
interface/mmal/components/sdl_audio_render.c [new file with mode: 0755]
interface/mmal/components/sdl_video_render.c [new file with mode: 0755]
interface/mmal/components/spdif.c [new file with mode: 0755]
interface/mmal/components/splitter.c [new file with mode: 0755]
interface/mmal/core/CMakeLists.txt [new file with mode: 0755]
interface/mmal/core/mmal_buffer.c [new file with mode: 0755]
interface/mmal/core/mmal_buffer_private.h [new file with mode: 0755]
interface/mmal/core/mmal_clock.c [new file with mode: 0755]
interface/mmal/core/mmal_clock_private.h [new file with mode: 0755]
interface/mmal/core/mmal_component.c [new file with mode: 0755]
interface/mmal/core/mmal_component_private.h [new file with mode: 0755]
interface/mmal/core/mmal_core_private.h [new file with mode: 0755]
interface/mmal/core/mmal_events.c [new file with mode: 0755]
interface/mmal/core/mmal_events_private.h [new file with mode: 0755]
interface/mmal/core/mmal_format.c [new file with mode: 0755]
interface/mmal/core/mmal_logging.c [new file with mode: 0755]
interface/mmal/core/mmal_pool.c [new file with mode: 0755]
interface/mmal/core/mmal_port.c [new file with mode: 0755]
interface/mmal/core/mmal_port_clock.c [new file with mode: 0755]
interface/mmal/core/mmal_port_private.h [new file with mode: 0755]
interface/mmal/core/mmal_queue.c [new file with mode: 0755]
interface/mmal/mmal.h [new file with mode: 0755]
interface/mmal/mmal_buffer.h [new file with mode: 0755]
interface/mmal/mmal_clock.h [new file with mode: 0755]
interface/mmal/mmal_common.h [new file with mode: 0755]
interface/mmal/mmal_component.h [new file with mode: 0755]
interface/mmal/mmal_encodings.h [new file with mode: 0755]
interface/mmal/mmal_events.h [new file with mode: 0755]
interface/mmal/mmal_format.h [new file with mode: 0755]
interface/mmal/mmal_logging.h [new file with mode: 0755]
interface/mmal/mmal_metadata.h [new file with mode: 0755]
interface/mmal/mmal_parameters.h [new file with mode: 0755]
interface/mmal/mmal_parameters_audio.h [new file with mode: 0755]
interface/mmal/mmal_parameters_camera.h [new file with mode: 0755]
interface/mmal/mmal_parameters_clock.h [new file with mode: 0755]
interface/mmal/mmal_parameters_common.h [new file with mode: 0755]
interface/mmal/mmal_parameters_video.h [new file with mode: 0755]
interface/mmal/mmal_pool.h [new file with mode: 0755]
interface/mmal/mmal_port.h [new file with mode: 0755]
interface/mmal/mmal_queue.h [new file with mode: 0755]
interface/mmal/mmal_types.h [new file with mode: 0755]
interface/mmal/openmaxil/CMakeLists.txt [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx.h [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx_buffer.c [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx_buffer.h [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx_commands.c [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx_commands.h [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx_core.c [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx_logging.c [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx_logging.h [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx_marks.c [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx_marks.h [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx_parameters.c [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx_parameters.h [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx_registry.c [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx_registry.h [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx_roles.c [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx_roles.h [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx_util_params.c [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx_util_params.h [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx_util_params_audio.c [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx_util_params_camera.c [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx_util_params_common.h [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx_util_params_misc.c [new file with mode: 0755]
interface/mmal/openmaxil/mmalomx_util_params_video.c [new file with mode: 0755]
interface/mmal/test/CMakeLists.txt [new file with mode: 0755]
interface/mmal/test/examples/example_basic_1.c [new file with mode: 0755]
interface/mmal/test/examples/example_basic_2.c [new file with mode: 0755]
interface/mmal/test/examples/example_connections.c [new file with mode: 0755]
interface/mmal/test/examples/example_graph.c [new file with mode: 0755]
interface/mmal/util/CMakeLists.txt [new file with mode: 0755]
interface/mmal/util/mmal_component_wrapper.c [new file with mode: 0755]
interface/mmal/util/mmal_component_wrapper.h [new file with mode: 0755]
interface/mmal/util/mmal_connection.c [new file with mode: 0755]
interface/mmal/util/mmal_connection.h [new file with mode: 0755]
interface/mmal/util/mmal_default_components.h [new file with mode: 0755]
interface/mmal/util/mmal_graph.c [new file with mode: 0755]
interface/mmal/util/mmal_graph.h [new file with mode: 0755]
interface/mmal/util/mmal_il.c [new file with mode: 0755]
interface/mmal/util/mmal_il.h [new file with mode: 0755]
interface/mmal/util/mmal_list.c [new file with mode: 0755]
interface/mmal/util/mmal_list.h [new file with mode: 0755]
interface/mmal/util/mmal_param_convert.c [new file with mode: 0755]
interface/mmal/util/mmal_param_convert.h [new file with mode: 0755]
interface/mmal/util/mmal_util.c [new file with mode: 0755]
interface/mmal/util/mmal_util.h [new file with mode: 0755]
interface/mmal/util/mmal_util_params.c [new file with mode: 0755]
interface/mmal/util/mmal_util_params.h [new file with mode: 0755]
interface/mmal/util/mmal_util_rational.c [new file with mode: 0755]
interface/mmal/util/mmal_util_rational.h [new file with mode: 0755]
interface/mmal/vc/CMakeLists.txt [new file with mode: 0755]
interface/mmal/vc/mmal_vc_api.c [new file with mode: 0755]
interface/mmal/vc/mmal_vc_api.h [new file with mode: 0755]
interface/mmal/vc/mmal_vc_api_drm.c [new file with mode: 0755]
interface/mmal/vc/mmal_vc_api_drm.h [new file with mode: 0755]
interface/mmal/vc/mmal_vc_client.c [new file with mode: 0755]
interface/mmal/vc/mmal_vc_client_priv.h [new file with mode: 0755]
interface/mmal/vc/mmal_vc_dbglog.h [new file with mode: 0755]
interface/mmal/vc/mmal_vc_diag.c [new file with mode: 0755]
interface/mmal/vc/mmal_vc_msgnames.c [new file with mode: 0755]
interface/mmal/vc/mmal_vc_msgnames.h [new file with mode: 0755]
interface/mmal/vc/mmal_vc_msgs.h [new file with mode: 0755]
interface/mmal/vc/mmal_vc_opaque_alloc.c [new file with mode: 0755]
interface/mmal/vc/mmal_vc_opaque_alloc.h [new file with mode: 0755]
interface/mmal/vc/mmal_vc_shm.c [new file with mode: 0755]
interface/mmal/vc/mmal_vc_shm.h [new file with mode: 0755]
interface/peer/vc_vchi_dispmanx_common.h [new file with mode: 0755]
interface/vchi/common/endian.h [new file with mode: 0755]
interface/vchi/connections/connection.h [new file with mode: 0755]
interface/vchi/message_drivers/message.h [new file with mode: 0755]
interface/vchi/vchi.h [new file with mode: 0755]
interface/vchi/vchi_cfg.h [new file with mode: 0755]
interface/vchi/vchi_cfg_internal.h [new file with mode: 0755]
interface/vchi/vchi_common.h [new file with mode: 0755]
interface/vchi/vchi_mh.h [new file with mode: 0755]
interface/vchiq_arm/CMakeLists.txt [new file with mode: 0755]
interface/vchiq_arm/vchiq.h [new file with mode: 0755]
interface/vchiq_arm/vchiq_cfg.h [new file with mode: 0755]
interface/vchiq_arm/vchiq_if.h [new file with mode: 0755]
interface/vchiq_arm/vchiq_ioctl.h [new file with mode: 0755]
interface/vchiq_arm/vchiq_lib.c [new file with mode: 0755]
interface/vchiq_arm/vchiq_test.c [new file with mode: 0755]
interface/vchiq_arm/vchiq_test.h [new file with mode: 0755]
interface/vchiq_arm/vchiq_test_if.h [new file with mode: 0755]
interface/vchiq_arm/vchiq_util.c [new file with mode: 0755]
interface/vchiq_arm/vchiq_util.h [new file with mode: 0755]
interface/vcos/CMakeLists.txt [new file with mode: 0755]
interface/vcos/generic/CMakeLists.txt [new file with mode: 0755]
interface/vcos/generic/vcos_abort.c [new file with mode: 0755]
interface/vcos/generic/vcos_cmd.c [new file with mode: 0755]
interface/vcos/generic/vcos_common.h [new file with mode: 0755]
interface/vcos/generic/vcos_deprecated.h [new file with mode: 0755]
interface/vcos/generic/vcos_generic_blockpool.c [new file with mode: 0755]
interface/vcos/generic/vcos_generic_blockpool.h [new file with mode: 0755]
interface/vcos/generic/vcos_generic_event_flags.c [new file with mode: 0755]
interface/vcos/generic/vcos_generic_event_flags.h [new file with mode: 0755]
interface/vcos/generic/vcos_generic_named_sem.c [new file with mode: 0755]
interface/vcos/generic/vcos_generic_named_sem.h [new file with mode: 0755]
interface/vcos/generic/vcos_generic_quickslow_mutex.h [new file with mode: 0755]
interface/vcos/generic/vcos_generic_reentrant_mtx.c [new file with mode: 0755]
interface/vcos/generic/vcos_generic_reentrant_mtx.h [new file with mode: 0755]
interface/vcos/generic/vcos_generic_safe_string.c [new file with mode: 0755]
interface/vcos/generic/vcos_generic_tls.h [new file with mode: 0755]
interface/vcos/generic/vcos_init.c [new file with mode: 0755]
interface/vcos/generic/vcos_joinable_thread_from_plain.h [new file with mode: 0755]
interface/vcos/generic/vcos_latch_from_sem.h [new file with mode: 0755]
interface/vcos/generic/vcos_logcat.c [new file with mode: 0755]
interface/vcos/generic/vcos_mem_from_malloc.c [new file with mode: 0755]
interface/vcos/generic/vcos_mem_from_malloc.h [new file with mode: 0755]
interface/vcos/generic/vcos_msgqueue.c [new file with mode: 0755]
interface/vcos/generic/vcos_mutexes_are_reentrant.h [new file with mode: 0755]
interface/vcos/generic/vcos_thread_reaper.h [new file with mode: 0755]
interface/vcos/glibc/vcos_backtrace.c [new file with mode: 0755]
interface/vcos/pthreads/CMakeLists.txt [new file with mode: 0755]
interface/vcos/pthreads/vcos_dlfcn.c [new file with mode: 0755]
interface/vcos/pthreads/vcos_futex_mutex.h [new file with mode: 0755]
interface/vcos/pthreads/vcos_platform.h [new file with mode: 0755]
interface/vcos/pthreads/vcos_platform_types.h [new file with mode: 0755]
interface/vcos/pthreads/vcos_pthreads.c [new file with mode: 0755]
interface/vcos/user_nodefs.h [new file with mode: 0755]
interface/vcos/vcos.h [new file with mode: 0755]
interface/vcos/vcos_assert.h [new file with mode: 0755]
interface/vcos/vcos_atomic_flags.h [new file with mode: 0755]
interface/vcos/vcos_attr.h [new file with mode: 0755]
interface/vcos/vcos_blockpool.h [new file with mode: 0755]
interface/vcos/vcos_build_info.h [new file with mode: 0755]
interface/vcos/vcos_cfg.h [new file with mode: 0755]
interface/vcos/vcos_cmd.h [new file with mode: 0755]
interface/vcos/vcos_ctype.h [new file with mode: 0755]
interface/vcos/vcos_dlfcn.h [new file with mode: 0755]
interface/vcos/vcos_event.h [new file with mode: 0755]
interface/vcos/vcos_event_flags.h [new file with mode: 0755]
interface/vcos/vcos_init.h [new file with mode: 0755]
interface/vcos/vcos_inttypes.h [new file with mode: 0755]
interface/vcos/vcos_isr.h [new file with mode: 0755]
interface/vcos/vcos_legacy_isr.h [new file with mode: 0755]
interface/vcos/vcos_logging.h [new file with mode: 0755]
interface/vcos/vcos_logging_control.h [new file with mode: 0755]
interface/vcos/vcos_lowlevel_thread.h [new file with mode: 0755]
interface/vcos/vcos_mem.h [new file with mode: 0755]
interface/vcos/vcos_mempool.h [new file with mode: 0755]
interface/vcos/vcos_msgqueue.h [new file with mode: 0755]
interface/vcos/vcos_mutex.h [new file with mode: 0755]
interface/vcos/vcos_named_semaphore.h [new file with mode: 0755]
interface/vcos/vcos_once.h [new file with mode: 0755]
interface/vcos/vcos_queue.h [new file with mode: 0755]
interface/vcos/vcos_quickslow_mutex.h [new file with mode: 0755]
interface/vcos/vcos_reentrant_mutex.h [new file with mode: 0755]
interface/vcos/vcos_semaphore.h [new file with mode: 0755]
interface/vcos/vcos_stdbool.h [new file with mode: 0755]
interface/vcos/vcos_stdint.h [new file with mode: 0755]
interface/vcos/vcos_string.h [new file with mode: 0755]
interface/vcos/vcos_thread.h [new file with mode: 0755]
interface/vcos/vcos_thread_attr.h [new file with mode: 0755]
interface/vcos/vcos_timer.h [new file with mode: 0755]
interface/vcos/vcos_tls.h [new file with mode: 0755]
interface/vcos/vcos_types.h [new file with mode: 0755]
interface/vctypes/vc_display_types.h [new file with mode: 0755]
interface/vctypes/vc_image_structs.h [new file with mode: 0755]
interface/vctypes/vc_image_types.h [new file with mode: 0755]
interface/vmcs_host/CMakeLists.txt [new file with mode: 0755]
interface/vmcs_host/khronos/IL/OMX_Audio.h [new file with mode: 0755]
interface/vmcs_host/khronos/IL/OMX_Broadcom.h [new file with mode: 0755]
interface/vmcs_host/khronos/IL/OMX_Component.h [new file with mode: 0755]
interface/vmcs_host/khronos/IL/OMX_Core.h [new file with mode: 0755]
interface/vmcs_host/khronos/IL/OMX_ILCS.h [new file with mode: 0755]
interface/vmcs_host/khronos/IL/OMX_IVCommon.h [new file with mode: 0755]
interface/vmcs_host/khronos/IL/OMX_Image.h [new file with mode: 0755]
interface/vmcs_host/khronos/IL/OMX_Index.h [new file with mode: 0755]
interface/vmcs_host/khronos/IL/OMX_Other.h [new file with mode: 0755]
interface/vmcs_host/khronos/IL/OMX_Types.h [new file with mode: 0755]
interface/vmcs_host/khronos/IL/OMX_Video.h [new file with mode: 0755]
interface/vmcs_host/linux/vcfiled/CMakeLists.txt [new file with mode: 0755]
interface/vmcs_host/linux/vcfiled/etc/init.d/vcfiled [new file with mode: 0755]
interface/vmcs_host/linux/vcfiled/vcfiled.c [new file with mode: 0755]
interface/vmcs_host/linux/vcfiled/vcfiled_check.c [new file with mode: 0755]
interface/vmcs_host/linux/vcfiled/vcfiled_check.h [new file with mode: 0755]
interface/vmcs_host/linux/vcfiled/vcfiled_lock_test.c [new file with mode: 0755]
interface/vmcs_host/linux/vcfilesys.c [new file with mode: 0755]
interface/vmcs_host/linux/vchost_config.h [new file with mode: 0755]
interface/vmcs_host/linux/vcmisc.c [new file with mode: 0755]
interface/vmcs_host/vc_cec.h [new file with mode: 0755]
interface/vmcs_host/vc_cecservice.h [new file with mode: 0755]
interface/vmcs_host/vc_cecservice_defs.h [new file with mode: 0755]
interface/vmcs_host/vc_cma.h [new file with mode: 0755]
interface/vmcs_host/vc_dispmanx.h [new file with mode: 0755]
interface/vmcs_host/vc_dispmanx_types.h [new file with mode: 0755]
interface/vmcs_host/vc_dispservice_defs.h [new file with mode: 0755]
interface/vmcs_host/vc_dispservice_x_defs.h [new file with mode: 0755]
interface/vmcs_host/vc_fileservice_defs.h [new file with mode: 0755]
interface/vmcs_host/vc_gencmd_defs.h [new file with mode: 0755]
interface/vmcs_host/vc_hdmi.h [new file with mode: 0755]
interface/vmcs_host/vc_hdmi_property.h [new file with mode: 0755]
interface/vmcs_host/vc_ilcs_defs.h [new file with mode: 0755]
interface/vmcs_host/vc_imageconv_defs.h [new file with mode: 0755]
interface/vmcs_host/vc_sdtv.h [new file with mode: 0755]
interface/vmcs_host/vc_service_common.c [new file with mode: 0755]
interface/vmcs_host/vc_service_common.h [new file with mode: 0755]
interface/vmcs_host/vc_tvservice.h [new file with mode: 0755]
interface/vmcs_host/vc_tvservice_defs.h [new file with mode: 0755]
interface/vmcs_host/vc_vchi_audioserv_defs.h [new file with mode: 0755]
interface/vmcs_host/vc_vchi_bufman.h [new file with mode: 0755]
interface/vmcs_host/vc_vchi_bufman_defs.h [new file with mode: 0755]
interface/vmcs_host/vc_vchi_cecservice.c [new file with mode: 0755]
interface/vmcs_host/vc_vchi_dispmanx.c [new file with mode: 0755]
interface/vmcs_host/vc_vchi_dispmanx.h [new file with mode: 0755]
interface/vmcs_host/vc_vchi_fileservice_defs.h [new file with mode: 0755]
interface/vmcs_host/vc_vchi_filesys.c [new file with mode: 0755]
interface/vmcs_host/vc_vchi_filesys.h [new file with mode: 0755]
interface/vmcs_host/vc_vchi_gencmd.c [new file with mode: 0755]
interface/vmcs_host/vc_vchi_gencmd.h [new file with mode: 0755]
interface/vmcs_host/vc_vchi_gpuserv.c [new file with mode: 0755]
interface/vmcs_host/vc_vchi_gpuserv.h [new file with mode: 0755]
interface/vmcs_host/vc_vchi_tvservice.c [new file with mode: 0755]
interface/vmcs_host/vcfilesys.h [new file with mode: 0755]
interface/vmcs_host/vcfilesys_defs.h [new file with mode: 0755]
interface/vmcs_host/vcgencmd.h [new file with mode: 0755]
interface/vmcs_host/vchost.h [new file with mode: 0755]
interface/vmcs_host/vchost_platform_config.h [new file with mode: 0755]
interface/vmcs_host/vcilcs.c [new file with mode: 0755]
interface/vmcs_host/vcilcs.h [new file with mode: 0755]
interface/vmcs_host/vcilcs_common.c [new file with mode: 0755]
interface/vmcs_host/vcilcs_common.h [new file with mode: 0755]
interface/vmcs_host/vcilcs_in.c [new file with mode: 0755]
interface/vmcs_host/vcilcs_out.c [new file with mode: 0755]
makefiles/cmake/arm-linux.cmake [new file with mode: 0755]
makefiles/cmake/cmake_config.h.in [new file with mode: 0755]
makefiles/cmake/global_settings.cmake [new file with mode: 0755]
makefiles/cmake/srcs/test-mtrace.c [new file with mode: 0755]
makefiles/cmake/toolchains/arm-linux-gnueabihf.cmake [new file with mode: 0755]
makefiles/cmake/toolchains/bcm2708-glibc-linux.cmake [new file with mode: 0755]
makefiles/cmake/vmcs.cmake [new file with mode: 0755]
middleware/dlloader/dlfcn.h [new file with mode: 0755]
middleware/imageconv/imageconv.h [new file with mode: 0755]
middleware/khronos/common/2708/khrn_interlock_filler_4.h [new file with mode: 0755]
middleware/khronos/common/2708/khrn_prod_4.h [new file with mode: 0755]
middleware/khronos/common/khrn_hw.h [new file with mode: 0755]
middleware/khronos/common/khrn_image.h [new file with mode: 0755]
middleware/khronos/common/khrn_interlock.h [new file with mode: 0755]
middleware/khronos/common/khrn_map.h [new file with mode: 0755]
middleware/khronos/common/khrn_mem.h [new file with mode: 0755]
middleware/khronos/common/khrn_misc.h [new file with mode: 0755]
middleware/khronos/common/khrn_pid_map.h [new file with mode: 0755]
middleware/khronos/common/khrn_pid_map_value.h [new file with mode: 0755]
middleware/khronos/common/khrn_server_pointermap.h [new file with mode: 0755]
middleware/khronos/dispatch/khrn_dispatch.h [new file with mode: 0755]
middleware/khronos/egl/egl_disp.h [new file with mode: 0755]
middleware/khronos/egl/egl_server.h [new file with mode: 0755]
middleware/khronos/ext/egl_khr_image.h [new file with mode: 0755]
middleware/khronos/vg/2708/vg_config_filler_4.h [new file with mode: 0755]
middleware/khronos/vg/vg_image.h [new file with mode: 0755]
middleware/khronos/wf/wfc_server_stream.h [new file with mode: 0755]
middleware/openmaxil/CMakeLists.txt [new file with mode: 0755]
opensrc/helpers/libfdt/CMakeLists.txt [new file with mode: 0755]
opensrc/helpers/libfdt/fdt.c [new file with mode: 0755]
opensrc/helpers/libfdt/fdt.h [new file with mode: 0755]
opensrc/helpers/libfdt/fdt_empty_tree.c [new file with mode: 0755]
opensrc/helpers/libfdt/fdt_ro.c [new file with mode: 0755]
opensrc/helpers/libfdt/fdt_rw.c [new file with mode: 0755]
opensrc/helpers/libfdt/fdt_strerror.c [new file with mode: 0755]
opensrc/helpers/libfdt/fdt_sw.c [new file with mode: 0755]
opensrc/helpers/libfdt/fdt_wip.c [new file with mode: 0755]
opensrc/helpers/libfdt/libfdt.h [new file with mode: 0755]
opensrc/helpers/libfdt/libfdt_env.h [new file with mode: 0755]
opensrc/helpers/libfdt/libfdt_internal.h [new file with mode: 0755]
packaging/libomxil-vc4.manifest [new file with mode: 0755]
packaging/libomxil-vc4.spec [new file with mode: 0755]
pkgconfig/bcm_host.pc.in [new file with mode: 0755]
pkgconfig/brcmegl.pc.in [new file with mode: 0755]
pkgconfig/brcmglesv2.pc.in [new file with mode: 0755]
pkgconfig/brcmvg.pc.in [new file with mode: 0755]
pkgconfig/egl.pc.in [new file with mode: 0755]
pkgconfig/glesv2.pc.in [new file with mode: 0755]
pkgconfig/mmal.pc.in [new file with mode: 0755]
pkgconfig/vcsm.pc.in [new file with mode: 0755]
pkgconfig/vg.pc.in [new file with mode: 0755]
vcfw/drivers/driver.h [new file with mode: 0755]
vcfw/logging/logging.h [new file with mode: 0755]
vcfw/rtos/common/rtos_common_mem.h [new file with mode: 0755]
vcfw/rtos/rtos.h [new file with mode: 0755]
vcfw/vclib/vclib.h [new file with mode: 0755]
vcinclude/common.h [new file with mode: 0755]
vcinclude/vc_image_types.h [new file with mode: 0755]
vcinclude/vcore.h [new file with mode: 0755]

diff --git a/.gitignore b/.gitignore
new file mode 100755 (executable)
index 0000000..63570f1
--- /dev/null
@@ -0,0 +1,32 @@
+# Build directory
+build/
+
+# Compiled Object files
+*.slo
+*.lo
+*.o
+
+# Compiled Dynamic libraries
+*.so
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+
+*.raw
+*.rgb
+*.bgr
+*.h264
+*.264
+*.yuyv
+*.uyvy
+*.yvyu
+*.vyuy
+*.i420
+*.yuv
+*.jpg
+*.avi
+*.pts
+*.ppm
+*.mkv
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..cfc8ae5
--- /dev/null
@@ -0,0 +1,132 @@
+cmake_minimum_required(VERSION 2.8)
+
+project(vmcs_host_apps)
+
+SET(PROJECT_VER_MAJOR 1)
+SET(PROJECT_VER_MINOR 0)
+SET(PROJECT_VER_PATCH 0)
+SET(PROJECT_VER "${PROJECT_VER_MAJOR}.${PROJECT_VER_MINOR}.${PROJECT_VER_PATCH}")
+SET(PROJECT_APIVER "${PROJECT_VER}")
+
+if(ARM64)
+   set(BUILD_MMAL FALSE)
+   set(BUILD_MMAL_APPS FALSE)
+else()
+   set(BUILD_MMAL TRUE)
+   set(BUILD_MMAL_APPS TRUE)
+endif()
+set(vmcs_root ${PROJECT_SOURCE_DIR})
+get_filename_component(VIDEOCORE_ROOT . ABSOLUTE)
+
+set(VCOS_PTHREADS_BUILD_SHARED TRUE)
+
+include(makefiles/cmake/global_settings.cmake)
+include(makefiles/cmake/arm-linux.cmake)
+include(makefiles/cmake/vmcs.cmake)
+
+enable_language(ASM)
+
+# Global include paths
+include_directories(host_applications/framework)
+include_directories(${PROJECT_SOURCE_DIR})
+include_directories(interface/vcos/pthreads)
+include_directories(interface/vmcs_host/linux)
+include_directories(interface/vmcs_host)
+include_directories(interface/vmcs_host/khronos)
+include_directories(interface/khronos/include)
+include_directories(${PROJECT_BINARY_DIR})
+include_directories(interface/vchiq_arm)
+#include_directories(tools/inet_transport)
+include_directories(host_support/include)
+
+# Global compiler flags
+if(CMAKE_COMPILER_IS_GNUCC)
+   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-multichar -Wall -Wno-unused-but-set-variable -fPIC")
+endif()
+
+add_definitions(-D_REENTRANT)
+add_definitions(-DUSE_VCHIQ_ARM -DVCHI_BULK_ALIGN=1 -DVCHI_BULK_GRANULARITY=1)
+add_definitions(-DOMX_SKIP64BIT)
+add_definitions(-DEGL_SERVER_DISPMANX)
+add_definitions(-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64)
+add_definitions(-D_GNU_SOURCE)
+
+# do we actually need this?
+add_definitions(-D__VIDEOCORE4__)
+add_definitions(-DTV_SUPPORTED_MODE_NO_DEPRECATED)
+
+# add_definitions(-DKHRONOS_CLIENT_LOGGING)
+
+# Check for OpenWF-C value set via command line
+if(KHRONOS_EGL_PLATFORM MATCHES "openwfc")
+   add_definitions(-DKHRONOS_EGL_PLATFORM_OPENWFC)
+endif()
+
+# List of subsidiary CMakeLists
+add_subdirectory(interface/vcos)
+add_subdirectory(interface/vmcs_host)
+add_subdirectory(interface/vchiq_arm)
+if(NOT ARM64)
+   add_subdirectory(interface/khronos)
+endif()
+
+#add_subdirectory(opensrc/tools/lua)
+if(BUILD_MMAL)
+   include_directories(interface/mmal)
+   add_subdirectory(interface/mmal)
+   add_subdirectory(containers)
+endif()
+
+# VidTex supports Android and Linux
+if(BUILD_MMAL_APPS)
+add_subdirectory(host_applications/android/apps/vidtex)
+endif(BUILD_MMAL_APPS)
+
+if(NOT ARM64)
+   add_subdirectory(middleware/openmaxil)
+endif()
+
+# 3d demo code
+#if(NOT ANDROID)
+#   add_subdirectory(thirdparty/applications/demos)
+#   add_subdirectory(opensrc/applications/demos)
+#endif()
+
+#if(ENABLE_3D_TESTS)
+#   add_subdirectory(thirdparty/applications/test)
+#endif()
+
+# FIXME: we should use a pre-packaged version of freetype
+# rather than the one included in the repo.
+#add_subdirectory(opensrc/helpers/freetype)
+#add_subdirectory(${PROJECT_SOURCE_DIR}/opensrc/helpers/fonts/ttf-bitstream-vera)
+
+# VMCS Host Applications
+#add_subdirectory(host_applications/framework)
+
+# add_subdirectory(interface/vchiq/test/win32)
+
+# Apps and libraries supporting Camera Tuning Tool
+#add_subdirectory(tools/inet_transport/linux)
+#add_subdirectory(host_support/vcstandalone)
+
+# add linux apps
+add_subdirectory(host_applications/linux)
+add_subdirectory(opensrc/helpers/libfdt)
+add_subdirectory(helpers/dtoverlay)
+
+set(vmcs_host_apps_VERSION_MAJOR 1)
+set(vmcs_host_apps_VERSION_MINOR 0)
+
+include_directories("${PROJECT_BINARY_DIR}")
+include(FindPkgConfig QUIET)
+if(PKG_CONFIG_FOUND)
+       # Produce a pkg-config file
+       foreach(PCFILE bcm_host.pc egl.pc glesv2.pc vg.pc brcmegl.pc brcmglesv2.pc  brcmvg.pc vcsm.pc mmal.pc )
+               configure_file("pkgconfig/${PCFILE}.in" "${PCFILE}" @ONLY)
+               install(FILES       "${CMAKE_CURRENT_BINARY_DIR}/${PCFILE}"
+                       DESTINATION "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig")
+       endforeach()
+endif()
+# Remove cache entry, if one added by command line
+unset(KHRONOS_EGL_PLATFORM CACHE)
diff --git a/COPYING b/COPYING
new file mode 100755 (executable)
index 0000000..a60e55d
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,21 @@
+Copyright (C) 2017 Samsung Electronics co., Ltd. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sub license, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
+IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR
+ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/LICENCE b/LICENCE
new file mode 100755 (executable)
index 0000000..dea4c26
--- /dev/null
+++ b/LICENCE
@@ -0,0 +1,26 @@
+Copyright (c) 2012, Broadcom Europe Ltd
+Copyright (c) 2015, Raspberry Pi (Trading) Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/README.md b/README.md
new file mode 100755 (executable)
index 0000000..358d2b4
--- /dev/null
+++ b/README.md
@@ -0,0 +1,6 @@
+This repository contains the source code for the ARM side libraries used on Raspberry Pi.
+These typically are installed in /opt/vc/lib and includes source for the ARM side code to interface to:
+EGL, mmal, GLESv2, vcos, openmaxil, vchiq_arm, bcm_host, WFC, OpenVG.
+
+Use buildme to build. It requires cmake to be installed and an arm cross compiler. It is set up to use this one:
+https://github.com/raspberrypi/tools/tree/master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian
diff --git a/buildme b/buildme
new file mode 100755 (executable)
index 0000000..b8fd440
--- /dev/null
+++ b/buildme
@@ -0,0 +1,44 @@
+#!/bin/bash
+BUILDTYPE=Release
+
+if [ "$1" = "--debug" ]; then
+       BUILDTYPE=Debug
+       shift
+fi
+
+BUILDSUBDIR=`echo $BUILDTYPE | tr '[A-Z]' '[a-z]'`;
+
+if [ "armv6l" = `arch` ] || [ "armv7l" = `arch` ]; then
+       # Native compile on the Raspberry Pi
+       mkdir -p build/raspberry/$BUILDSUBDIR
+       pushd build/raspberry/$BUILDSUBDIR
+       cmake -DCMAKE_BUILD_TYPE=$BUILDTYPE ../../..
+       if [ "armv6l" = `arch` ]; then
+               make
+       else
+               make -j4
+       fi
+       if [ "$1" != "" ]; then
+               sudo make install DESTDIR=$1
+       else
+               sudo make install
+       fi
+elif [ "$1" = "--native" ]; then
+       # Build natively on the host
+       mkdir -p build/native/$BUILDSUBDIR
+       pushd build/native/$BUILDSUBDIR
+       cmake -DCMAKE_BUILD_TYPE=$BUILDTYPE ../../..
+       shift
+       make -j `nproc` $*
+else
+       # Cross compile on a more capable machine
+       mkdir -p build/arm-linux/$BUILDSUBDIR
+       pushd build/arm-linux/$BUILDSUBDIR
+       cmake -DCMAKE_TOOLCHAIN_FILE=../../../makefiles/cmake/toolchains/arm-linux-gnueabihf.cmake -DCMAKE_BUILD_TYPE=$BUILDTYPE ../../..
+       make -j `nproc`
+
+       if [ "$1" != "" ]; then
+               sudo make install DESTDIR=$1
+       fi
+fi
+popd
diff --git a/containers/CMakeLists.txt b/containers/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..5570038
--- /dev/null
@@ -0,0 +1,124 @@
+SET( SOURCE_DIR . )
+
+# We support building both static and shared libraries
+if (NOT DEFINED LIBRARY_TYPE)
+set(LIBRARY_TYPE SHARED)
+endif (NOT DEFINED LIBRARY_TYPE)
+
+# Make sure the compiler can find the necessary include files
+include_directories (${SOURCE_DIR}/.. ${SOURCE_DIR}/../interface/vcos)
+
+# Needed for the container loader
+add_definitions(-DDL_PATH_PREFIX="${VMCS_PLUGIN_DIR}/")
+
+SET( GCC_COMPILER_FLAGS -Wall -g -O2 -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wcast-qual -Wwrite-strings -Wundef )
+SET( GCC_COMPILER_FLAGS ${GCC_COMPILER_FLAGS} -Wextra )#-Wno-missing-field-initializers )
+SET( GCC_COMPILER_FLAGS ${GCC_COMPILER_FLAGS} -std=c99 -D_POSIX_C_SOURCE=200112L )
+SET( GCC_COMPILER_FLAGS ${GCC_COMPILER_FLAGS} -Wno-missing-field-initializers )
+SET( GCC_COMPILER_FLAGS ${GCC_COMPILER_FLAGS} -Wno-unused-value )
+
+add_definitions( ${GCC_COMPILER_FLAGS} )
+
+# Containers core library
+set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers.c)
+set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_io.c)
+set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_io_helpers.c)
+set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_codecs.c)
+set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_utils.c)
+set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_writer_utils.c)
+set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_loader.c)
+set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_filters.c)
+set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_logging.c)
+set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_uri.c)
+set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_bits.c)
+set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_list.c)
+set(core_SRCS ${core_SRCS} ${SOURCE_DIR}/core/containers_index.c)
+
+# Containers io library
+set(io_SRCS ${io_SRCS} ${SOURCE_DIR}/io/io_file.c)
+set(io_SRCS ${io_SRCS} ${SOURCE_DIR}/io/io_null.c)
+set(io_SRCS ${io_SRCS} ${SOURCE_DIR}/io/io_net.c)
+set(io_SRCS ${io_SRCS} ${SOURCE_DIR}/io/io_pktfile.c)
+set(io_SRCS ${io_SRCS} ${SOURCE_DIR}/io/io_http.c)
+add_definitions( -DENABLE_CONTAINER_IO_HTTP )
+
+# Containers net library
+if (DEFINED MSVC)
+set(net_SRCS ${net_SRCS} ${SOURCE_DIR}/net/net_sockets_common.c)
+set(net_SRCS ${net_SRCS} ${SOURCE_DIR}/net/net_sockets_win32.c)
+elseif (DEFINED LINUX OR DEFINED UNIX)
+set(net_SRCS ${net_SRCS} ${SOURCE_DIR}/net/net_sockets_common.c)
+set(net_SRCS ${net_SRCS} ${SOURCE_DIR}/net/net_sockets_bsd.c)
+else (DEFINED MSVC)
+set(net_SRCS ${net_SRCS} ${SOURCE_DIR}/net/net_sockets_null.c)
+endif (DEFINED MSVC)
+set(extra_net_SRCS net_sockets_win32.c net_sockets_win32.h net_sockets_null.c)
+add_custom_target(containers_net_extra ALL
+    COMMAND touch ${extra_net_SRCS}
+    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/containers/net)
+
+# Packetizers library
+set(packetizers_SRCS ${packetizers_SRCS} ${SOURCE_DIR}/core/packetizers.c)
+set(packetizers_SRCS ${packetizers_SRCS} ${SOURCE_DIR}/mpga/mpga_packetizer.c)
+set(packetizers_SRCS ${packetizers_SRCS} ${SOURCE_DIR}/mpgv/mpgv_packetizer.c)
+set(packetizers_SRCS ${packetizers_SRCS} ${SOURCE_DIR}/pcm/pcm_packetizer.c)
+set(packetizers_SRCS ${packetizers_SRCS} ${SOURCE_DIR}/h264/avc1_packetizer.c)
+
+add_library(containers ${LIBRARY_TYPE} ${core_SRCS} ${io_SRCS} ${net_SRCS} ${packetizers_SRCS})
+target_link_libraries(containers vcos)
+install(TARGETS containers DESTINATION lib)
+
+set(container_readers)
+set(container_writers)
+
+# Container modules
+add_subdirectory(mp4)
+set(container_readers ${container_readers} reader_mp4)
+set(container_writers ${container_writers} writer_mp4)
+add_subdirectory(mpeg)
+set(container_readers ${container_readers} reader_ps)
+add_subdirectory(mpga)
+set(container_readers ${container_readers} reader_mpga)
+add_subdirectory(binary)
+set(container_readers ${container_readers} reader_binary)
+set(container_writers ${container_writers} writer_binary)
+add_subdirectory(mkv)
+set(container_readers ${container_readers} reader_mkv)
+add_subdirectory(wav)
+set(container_readers ${container_readers} reader_wav)
+add_subdirectory(asf)
+set(container_readers ${container_readers} reader_asf)
+set(container_writers ${container_writers} writer_asf)
+add_subdirectory(flash)
+set(container_readers ${container_readers} reader_flv)
+add_subdirectory(avi)
+set(container_readers ${container_readers} reader_avi)
+set(container_writers ${container_writers} writer_avi)
+add_subdirectory(rtp)
+set(container_readers ${container_readers} reader_rtp)
+add_subdirectory(rtsp)
+set(container_readers ${container_readers} reader_rtsp)
+add_subdirectory(rcv)
+set(container_readers ${container_readers} reader_rcv)
+add_subdirectory(rv9)
+set(container_readers ${container_readers} reader_rv9)
+add_subdirectory(qsynth)
+set(container_readers ${container_readers} reader_qsynth)
+add_subdirectory(simple)
+set(container_readers ${container_readers} reader_simple)
+set(container_writers ${container_writers} writer_simple)
+add_subdirectory(raw)
+set(container_readers ${container_readers} reader_raw_video)
+set(container_writers ${container_writers} writer_raw_video)
+add_subdirectory(dummy)
+set(container_writers ${container_writers} writer_dummy)
+
+add_subdirectory(metadata/id3)
+set(container_readers ${container_readers} reader_metadata_id3)
+
+if (${LIBRARY_TYPE} STREQUAL STATIC)
+target_link_libraries(containers ${container_readers} ${container_writers})
+endif (${LIBRARY_TYPE} STREQUAL STATIC)
+
+# Test apps
+add_subdirectory(test)
diff --git a/containers/asf/CMakeLists.txt b/containers/asf/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..2cd7ac2
--- /dev/null
@@ -0,0 +1,19 @@
+# Container module needs to go in as a plugins so different prefix
+# and install path
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+
+# Make sure the compiler can find the necessary include files
+include_directories (../..)
+
+add_library(reader_asf ${LIBRARY_TYPE} asf_reader.c)
+
+target_link_libraries(reader_asf containers)
+
+install(TARGETS reader_asf DESTINATION ${VMCS_PLUGIN_DIR})
+
+add_library(writer_asf ${LIBRARY_TYPE} asf_writer.c)
+
+target_link_libraries(writer_asf containers)
+
+install(TARGETS writer_asf DESTINATION ${VMCS_PLUGIN_DIR})
+
diff --git a/containers/asf/asf_reader.c b/containers/asf/asf_reader.c
new file mode 100755 (executable)
index 0000000..c36ed5e
--- /dev/null
@@ -0,0 +1,2247 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <string.h>
+
+/* prevent double-defines when it is defined on the command line - as in the test app */
+#ifndef ENABLE_CONTAINERS_LOG_FORMAT
+//#define ENABLE_CONTAINERS_LOG_FORMAT
+#endif
+#ifndef ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
+//#define ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
+#endif
+
+#define CONTAINER_HELPER_LOG_INDENT(a) (a)->priv->module->object_level
+
+/* For the sanity of the Visual Studio debugger make local names for structures */
+#define  VC_CONTAINER_TRACK_MODULE_T ASF_VC_CONTAINER_TRACK_MODULE_T
+#define  VC_CONTAINER_MODULE_T ASF_VC_CONTAINER_MODULE_T
+#define  VC_CONTAINER_T ASF_VC_CONTAINER_T
+
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_logging.h"
+
+/******************************************************************************
+Defines.
+******************************************************************************/
+#define ASF_TRACKS_MAX 2
+#define ASF_EXTRADATA_MAX 256
+
+#define ASF_MAX_OBJECT_LEVEL 4
+#define ASF_MAX_CONSECUTIVE_UNKNOWN_OBJECTS 5
+#define ASF_MAX_OBJECT_SIZE  (1<<29) /* Does not apply to the data object */
+#define ASF_OBJECT_HEADER_SIZE (16+8)
+#define ASF_UNKNOWN_PTS ((uint32_t)(-1))
+#define ASF_MAX_CONSECUTIVE_CORRUPTED_PACKETS 100
+#define ASF_MAX_SEARCH_PACKETS 1000
+
+#define ASF_SKIP_GUID(ctx, size, n) (size -= 16, SKIP_GUID(ctx,n))
+#define ASF_SKIP_U8(ctx, size, n)   (size -= 1, SKIP_U8(ctx,n))
+#define ASF_SKIP_U16(ctx, size, n)  (size -= 2, SKIP_U16(ctx,n))
+#define ASF_SKIP_U24(ctx, size, n)  (size -= 3, SKIP_U24(ctx,n))
+#define ASF_SKIP_U32(ctx, size, n)  (size -= 4, SKIP_U32(ctx,n))
+#define ASF_SKIP_U64(ctx, size, n)  (size -= 8, SKIP_U64(ctx,n))
+#define ASF_READ_GUID(ctx, size, buffer, n) (size -= 16, READ_GUID(ctx,(uint8_t *)buffer,n))
+#define ASF_READ_U8(ctx, size, n)   (size -= 1, READ_U8(ctx,n))
+#define ASF_READ_U16(ctx, size, n)  (size -= 2, READ_U16(ctx,n))
+#define ASF_READ_U24(ctx, size, n)  (size -= 3, READ_U24(ctx,n))
+#define ASF_READ_U32(ctx, size, n)  (size -= 4, READ_U32(ctx,n))
+#define ASF_READ_U64(ctx, size, n)  (size -= 8, READ_U64(ctx,n))
+#define ASF_READ_STRING(ctx, size, buffer, to_read, n) (size -= to_read, READ_STRING_UTF16(ctx,buffer,to_read,n))
+#define ASF_SKIP_STRING(ctx, size, to_read, n) (size -= to_read, SKIP_STRING_UTF16(ctx,to_read,n))
+#define ASF_READ_BYTES(ctx, size, buffer, to_read) (size -= to_read, READ_BYTES(ctx,buffer,to_read))
+#define ASF_SKIP_BYTES(ctx, size, to_read) (size -= to_read, SKIP_BYTES(ctx,to_read))
+
+/* Read variable length field from p_context. */
+#define READ_VLC(p_context, length, value_if_missing, txt) \
+   (length) == 1 ? READ_U8(p_context, txt) : \
+   (length) == 2 ? READ_U16(p_context, txt) : \
+   (length) == 3 ? READ_U32(p_context, txt) : value_if_missing
+
+#define CHECK_POINT(p_context, amount_to_read) do { \
+   if(amount_to_read < 0) return VC_CONTAINER_ERROR_CORRUPTED; \
+   if(STREAM_STATUS(p_context)) return STREAM_STATUS(p_context); } while(0)
+
+/******************************************************************************
+Type definitions.
+******************************************************************************/
+
+/** Context for our reader
+  */
+typedef struct
+{
+   uint64_t start;            /* The byte offset start of the current packet in the file */
+   uint32_t size;
+   uint32_t padding_size;
+   uint64_t send_time;        /* read in mS, stored in uS */
+   bool     eos;
+   bool     corrupted;
+   uint16_t bad_packets;
+
+   /* All the different Length Types for the VLC codes */
+   unsigned int replicated_data_lt;
+   unsigned int offset_into_media_object_lt;
+   unsigned int media_object_number_lt;
+   unsigned int payload_lt;
+
+   unsigned int multiple_payloads;
+   unsigned int compressed_payloads;
+
+   uint8_t num_payloads;
+   uint8_t current_payload;
+   uint32_t current_offset;            /* The offset in the current packet for the next byte to be read */
+
+   /* Info already read */
+   uint32_t stream_num;                /* Stream number and key-frame flag */
+   uint32_t media_object_num;
+   uint32_t media_object_off;
+   uint32_t payload_size;
+   uint32_t subpayload_size;
+
+   /* Info read from the replicated data */
+   uint32_t media_object_size;
+   uint64_t media_object_pts;         /**< Presentation timestamp in microseconds */
+   uint64_t media_object_pts_delta;   /**< Presentation timestamp delta in microseconds */
+
+} ASF_PACKET_STATE;
+
+typedef struct VC_CONTAINER_TRACK_MODULE_T
+{
+   /* The ID of the stream (the index in the containing array need not be the ID) */
+   unsigned int stream_id;
+   bool b_valid;
+
+   uint8_t extradata[ASF_EXTRADATA_MAX];
+
+   ASF_PACKET_STATE *p_packet_state;
+   ASF_PACKET_STATE local_packet_state;
+
+   /* Simple index structure. Corresponds to the simple index in 6.1 of the spec
+    * This index has locations in packets, not in bytes, and relies on the
+    * file having fixed-length packets - as is required */
+   struct
+   {
+      uint64_t offset;        /**< Offset to the start of the simple index data */
+      uint32_t num_entries;
+      int64_t  time_interval; /* in uS */
+      bool     incomplete;    /* The index does not go to the end of the file */
+   } simple_index;
+
+} VC_CONTAINER_TRACK_MODULE_T;
+
+typedef struct VC_CONTAINER_MODULE_T
+{
+   int object_level;
+
+   uint32_t packet_size;   /**< Size of a data packet */
+   uint64_t packets_num;   /**< Number of packets contained in the data object */
+
+   bool broadcast;         /**< Specifies if we are dealing with a broadcast stream */
+   int64_t duration;       /**< Duration of the stream in microseconds */
+   int64_t preroll;        /**< Duration of the preroll in microseconds. */
+                           /* This is the PTS of the first packet; all are offset by this amount. */
+   uint64_t  time_offset;  /**< Offset added to timestamps in microseconds */
+
+   uint64_t data_offset;   /**< Offset to the start of the data packets */
+   int64_t data_size;      /**< Size of the data contained in the data object */
+
+   /* The track objects. There's a count of these in VC_CONTAINER_T::tracks_num */
+   VC_CONTAINER_TRACK_T *tracks[ASF_TRACKS_MAX];
+
+   /* Translation table from stream_number to index in the tracks array */
+   unsigned char stream_number_to_index[128];
+
+   /* Data for a top-level index structure as defined in 6.2 of the spec */
+   struct
+   {
+      uint64_t entry_time_interval;                /* The time interval between specifiers, scaled to uS */
+      uint32_t specifiers_count;                   /* The number of specifiers in the file, 0 if no index */
+      uint64_t active_specifiers[ASF_TRACKS_MAX];  /* the specifier in use for each track,
+                                                    * or >=specifiers_count if none */
+      uint64_t specifiers_offset;                  /* The file address of the first specifier. */
+      uint32_t block_count;                        /* The number of index blocks */
+      uint64_t blocks_offset;                      /* The file address of the first block */
+   } top_level_index;
+
+   /* A pointer to the track (in the tracks array) which is to be used with a simple index.
+    * null if there is no such track */
+   ASF_VC_CONTAINER_TRACK_MODULE_T *simple_index_track;
+
+   /* Shared packet state. This is used when the tracks are in sync,
+      and for the track at the earliest position in the file when they are not in sync */
+   ASF_PACKET_STATE packet_state;
+
+} VC_CONTAINER_MODULE_T;
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+VC_CONTAINER_STATUS_T asf_reader_open( VC_CONTAINER_T * );
+
+/******************************************************************************
+Prototypes for local functions
+******************************************************************************/
+static VC_CONTAINER_STATUS_T asf_read_object( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T asf_read_object_header( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T asf_read_object_header_ext( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T asf_read_object_file_properties( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T asf_read_object_stream_properties( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T asf_read_object_ext_stream_properties( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T asf_read_object_simple_index( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T asf_read_object_index( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T asf_read_object_index_parameters( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T asf_read_object_data( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T asf_read_object_codec_list( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T asf_read_object_content_description( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T asf_read_object_stream_bitrate_props( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T asf_read_object_content_encryption( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T asf_read_object_ext_content_encryption( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T asf_read_object_adv_content_encryption( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T asf_skip_unprocessed_object( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T seek_to_positions(VC_CONTAINER_T *p_ctx,
+   uint64_t track_positions[ASF_TRACKS_MAX], int64_t *p_time,
+   VC_CONTAINER_SEEK_FLAGS_T flags, unsigned int start_track,
+   bool seek_on_start_track);
+
+/******************************************************************************
+GUID list for the different ASF objects
+******************************************************************************/
+static const GUID_T asf_guid_header = {0x75B22630, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
+static const GUID_T asf_guid_file_props = {0x8CABDCA1, 0xA947, 0x11CF, {0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
+static const GUID_T asf_guid_stream_props = {0xB7DC0791, 0xA9B7, 0x11CF, {0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
+static const GUID_T asf_guid_ext_stream_props = {0x14E6A5CB, 0xC672, 0x4332, {0x83, 0x99, 0xA9, 0x69, 0x52, 0x06, 0x5B, 0x5A}};
+static const GUID_T asf_guid_data = {0x75B22636, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
+static const GUID_T asf_guid_simple_index = {0x33000890, 0xE5B1, 0x11CF, {0x89, 0xF4, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB}};
+static const GUID_T asf_guid_index = {0xD6E229D3, 0x35DA, 0x11D1, {0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE}};
+static const GUID_T asf_guid_index_parameters = {0xD6E229DF, 0x35DA, 0x11D1, {0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE}};
+static const GUID_T asf_guid_header_ext = {0x5FBF03B5, 0xA92E, 0x11CF, {0x8E, 0xE3, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
+static const GUID_T asf_guid_codec_list = {0x86D15240, 0x311D, 0x11D0, {0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6}};
+static const GUID_T asf_guid_content_description = {0x75B22633, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
+static const GUID_T asf_guid_ext_content_description = {0xD2D0A440, 0xE307, 0x11D2, {0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5E, 0xA8, 0x50}};
+static const GUID_T asf_guid_stream_bitrate_props = {0x7BF875CE, 0x468D, 0x11D1, {0x8D, 0x82, 0x00, 0x60, 0x97, 0xC9, 0xA2, 0xB2}};
+static const GUID_T asf_guid_language_list = {0x7C4346A9, 0xEFE0, 0x4BFC, {0xB2, 0x29, 0x39, 0x3E, 0xDE, 0x41, 0x5C, 0x85}};
+static const GUID_T asf_guid_metadata = {0xC5F8CBEA, 0x5BAF, 0x4877, {0x84, 0x67, 0xAA, 0x8C, 0x44, 0xFA, 0x4C, 0xCA}};
+static const GUID_T asf_guid_padding = {0x1806D474, 0xCADF, 0x4509, {0xA4, 0xBA, 0x9A, 0xAB, 0xCB, 0x96, 0xAA, 0xE8}};
+static const GUID_T asf_guid_content_encryption = {0x2211B3FB, 0xBD23, 0x11D2, {0xB4, 0xB7, 0x00, 0xA0, 0xC9, 0x55, 0xFC, 0x6E}};
+static const GUID_T asf_guid_ext_content_encryption = {0x298AE614, 0x2622, 0x4C17, {0xB9, 0x35, 0xDA, 0xE0, 0x7E, 0xE9, 0x28, 0x9C}};
+static const GUID_T asf_guid_adv_content_encryption = {0x43058533, 0x6981, 0x49E6, {0x9B, 0x74, 0xAD, 0x12, 0xCB, 0x86, 0xD5, 0x8C}};
+static const GUID_T asf_guid_compatibility = {0x26F18B5D, 0x4584, 0x47EC, {0x9F, 0x5F, 0x0E, 0x65, 0x1F, 0x04, 0x52, 0xC9}};
+static const GUID_T asf_guid_script_command = {0x1EFB1A30, 0x0B62, 0x11D0, {0xA3, 0x9B, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6}};
+static const GUID_T asf_guid_mutual_exclusion = {0xD6E229DC, 0x35DA, 0x11D1, {0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE}};
+
+static const GUID_T asf_guid_stream_type_video = {0xBC19EFC0, 0x5B4D, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}};
+static const GUID_T asf_guid_stream_type_audio = {0xF8699E40, 0x5B4D, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}};
+
+/******************************************************************************
+List of GUIDs and their associated processing functions
+******************************************************************************/
+static struct {
+  const GUID_T *guid;
+  const char *psz_name;
+  VC_CONTAINER_STATUS_T (*pf_func)( VC_CONTAINER_T *, int64_t );
+
+} asf_object_list[] =
+{
+   {&asf_guid_header, "header", asf_read_object_header},
+   {&asf_guid_file_props, "file properties", asf_read_object_file_properties},
+   {&asf_guid_stream_props, "stream properties", asf_read_object_stream_properties},
+   {&asf_guid_ext_stream_props, "extended stream properties", asf_read_object_ext_stream_properties},
+   {&asf_guid_data, "data", asf_read_object_data},
+   {&asf_guid_simple_index, "simple index", asf_read_object_simple_index},
+   {&asf_guid_index, "index", asf_read_object_index},
+   {&asf_guid_index_parameters, "index parameters", asf_read_object_index_parameters},
+   {&asf_guid_header_ext, "header extension", asf_read_object_header_ext},
+   {&asf_guid_codec_list, "codec list", asf_read_object_codec_list},
+   {&asf_guid_content_description, "content description", asf_read_object_content_description},
+   {&asf_guid_ext_content_description, "extended content description", asf_skip_unprocessed_object},
+   {&asf_guid_stream_bitrate_props, "stream bitrate properties", asf_read_object_stream_bitrate_props},
+   {&asf_guid_language_list, "language list", asf_skip_unprocessed_object},
+   {&asf_guid_metadata, "metadata", asf_skip_unprocessed_object},
+   {&asf_guid_padding, "padding", asf_skip_unprocessed_object},
+   {&asf_guid_compatibility, "compatibility", asf_skip_unprocessed_object},
+   {&asf_guid_script_command, "script command", asf_skip_unprocessed_object},
+   {&asf_guid_mutual_exclusion, "mutual exclusion", asf_skip_unprocessed_object},
+   {&asf_guid_content_encryption, "content encryption", &asf_read_object_content_encryption},
+   {&asf_guid_ext_content_encryption, "extended content encryption", &asf_read_object_ext_content_encryption},
+   {&asf_guid_adv_content_encryption, "advanced content encryption", &asf_read_object_adv_content_encryption},
+   {0, "unknown", asf_skip_unprocessed_object}
+};
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+
+/** Find the track associated with an ASF stream id */
+static VC_CONTAINER_TRACK_T *asf_reader_find_track( VC_CONTAINER_T *p_ctx, unsigned int stream_id,
+   bool b_create)
+{
+   VC_CONTAINER_TRACK_T *p_track = 0;
+   VC_CONTAINER_MODULE_T * module = p_ctx->priv->module;
+   unsigned int i;
+
+   /* discard the key-frame flag */
+   stream_id &= 0x7f;
+
+   /* look to see if we have already allocated the stream */
+   i = module->stream_number_to_index[stream_id];
+
+   if(i < p_ctx->tracks_num) /* We found it */
+      p_track = p_ctx->tracks[i];
+
+   if(!p_track && b_create && p_ctx->tracks_num < ASF_TRACKS_MAX)
+   {
+      /* Allocate and initialise a new track */
+      p_ctx->tracks[p_ctx->tracks_num] = p_track =
+         vc_container_allocate_track(p_ctx, sizeof(*p_ctx->tracks[0]->priv->module));
+      if(p_track)
+      {
+         /* store the stream ID */
+         p_track->priv->module->stream_id = stream_id;
+
+         /* Store the translation table value */
+         module->stream_number_to_index[stream_id] = p_ctx->tracks_num;
+
+         /* count the track */
+         p_ctx->tracks_num++;
+      }
+   }
+
+   if(!p_track && b_create)
+      LOG_DEBUG(p_ctx, "could not create track for stream id: %i", stream_id);
+
+   return p_track;
+}
+
+/** Base function used to read an ASF object from the ASF header.
+ * This will read the object header do lots of sanity checking and pass on the rest
+ * of the reading to the object specific reading function */
+static VC_CONTAINER_STATUS_T asf_read_object( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   int64_t object_size, offset = STREAM_POSITION(p_ctx);
+   unsigned int i, unknown_objects = 0, is_data_object;
+   GUID_T guid;
+
+   /* Sanity check the size of the data */
+   if(size && size < ASF_OBJECT_HEADER_SIZE)
+   {
+      LOG_DEBUG(p_ctx, "invalid object header (too small)");
+      return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+
+   if(READ_GUID(p_ctx, &guid, "Object ID") != sizeof(guid))
+      return STREAM_STATUS(p_ctx);
+
+   /* Find out which GUID we are dealing with */
+   for( i = 0; asf_object_list[i].guid; i++ )
+   {
+      if(guid.word0 != asf_object_list[i].guid->word0) continue;
+      if(!memcmp(&guid, asf_object_list[i].guid, sizeof(guid))) break;
+   }
+
+   LOG_FORMAT(p_ctx, "Object Name: %s", asf_object_list[i].psz_name);
+
+   /* Bail out if we find too many consecutive unknown objects */
+   if(!asf_object_list[i].guid) unknown_objects++;
+   else unknown_objects = 0;
+   if(unknown_objects >= ASF_MAX_CONSECUTIVE_UNKNOWN_OBJECTS)
+   {
+      LOG_DEBUG(p_ctx, "too many unknown objects");
+      return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+
+   is_data_object = asf_object_list[i].pf_func == asf_read_object_data;
+
+   object_size = READ_U64(p_ctx, "Object Size");
+
+   /* Sanity check the object size */
+   if(object_size < 0 /* Shouldn't ever get that big */ ||
+      /* Minimum size check (data object can have a size == 0) */
+      (object_size < ASF_OBJECT_HEADER_SIZE && !(is_data_object && !object_size)) ||
+      /* Only the data object can really be massive */
+      (!is_data_object && object_size > ASF_MAX_OBJECT_SIZE))
+   {
+      LOG_DEBUG(p_ctx, "object %s has an invalid size (%"PRIi64")",
+                asf_object_list[i].psz_name, object_size);
+      return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+   if(size && object_size > size)
+   {
+      LOG_DEBUG(p_ctx, "object %s is bigger than it should (%"PRIi64" > %"PRIi64")",
+                asf_object_list[i].psz_name, object_size, size);
+      return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+   size = object_size;
+
+   if(module->object_level >= 2 * ASF_MAX_OBJECT_LEVEL)
+   {
+      LOG_DEBUG(p_ctx, "object %s is too deep. skipping", asf_object_list[i].psz_name);
+      status = asf_skip_unprocessed_object(p_ctx, size - ASF_OBJECT_HEADER_SIZE);
+      /* Just bail out, hoping we have enough data */
+   }
+   else
+   {
+      module->object_level++;
+
+      /* Call the object specific parsing function */
+      status = asf_object_list[i].pf_func(p_ctx, size - ASF_OBJECT_HEADER_SIZE);
+
+      module->object_level--;
+
+      if(status != VC_CONTAINER_SUCCESS)
+         LOG_DEBUG(p_ctx, "object %s appears to be corrupted (%i)", asf_object_list[i].psz_name, status);
+   }
+
+   /* The stream position should be exactly at the end of the object */
+   {
+      int64_t bytes_processed = STREAM_POSITION(p_ctx) - offset;
+
+      /* fail with overruns */
+      if (bytes_processed > size)
+      {
+         /* Things have gone really bad here and we ended up reading past the end of the
+          * object. We could maybe try to be clever and recover by seeking back to the end
+          * of the object. However if we get there, the file is clearly corrupted so there's
+          * no guarantee it would work anyway. */
+         LOG_DEBUG(p_ctx, "%"PRIi64" bytes overrun past the end of object %s",
+                   bytes_processed-size, asf_object_list[i].psz_name);
+         return VC_CONTAINER_ERROR_CORRUPTED;
+      }
+
+      /* Handle underruns  by throwing away the data (this should never happen, but we don't really care if it does) */
+      if (bytes_processed < size)
+      {
+         size -= bytes_processed;
+         LOG_DEBUG(p_ctx, "%"PRIi64" bytes left unread in object %s", size, asf_object_list[i].psz_name);
+
+         if(size < ASF_MAX_OBJECT_SIZE)
+            SKIP_BYTES(p_ctx, size);                     /* read a small amount */
+         else
+            SEEK(p_ctx, STREAM_POSITION(p_ctx) + size);  /* seek a large distance */
+      }
+   }
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/** Reads an ASF header object */
+static VC_CONTAINER_STATUS_T asf_read_object_header( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   int64_t offset = STREAM_POSITION(p_ctx);
+
+   /* Sanity check the size of the data */
+   if((size -= 6) < 0) return VC_CONTAINER_ERROR_CORRUPTED;
+
+   SKIP_U32(p_ctx, "Number of Header Objects"); /* FIXME: could use that */
+   SKIP_U8(p_ctx, "Reserved1");
+   SKIP_U8(p_ctx, "Reserved2");
+
+   /* Read contained objects */
+   module->object_level++;
+   while(status == VC_CONTAINER_SUCCESS && size >= ASF_OBJECT_HEADER_SIZE)
+   {
+      offset = STREAM_POSITION(p_ctx);
+      status = asf_read_object(p_ctx, size);
+      size -= (STREAM_POSITION(p_ctx) - offset);
+   }
+   module->object_level--;
+
+   return status;
+}
+
+/** Reads an ASF extended header object */
+static VC_CONTAINER_STATUS_T asf_read_object_header_ext( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   int64_t data_size, offset;
+
+   ASF_SKIP_GUID(p_ctx, size, "Reserved Field 1");
+   ASF_SKIP_U16(p_ctx, size, "Reserved Field 2");
+   data_size = ASF_READ_U32(p_ctx, size, "Header Extension Data Size");
+
+   if(data_size != size)
+      LOG_DEBUG(p_ctx, "invalid header extension data size (%"PRIi64",%"PRIi64")", data_size, size);
+
+   CHECK_POINT(p_ctx, size);
+
+   /* Read contained objects */
+   module->object_level++;
+   while(status == VC_CONTAINER_SUCCESS && size >= ASF_OBJECT_HEADER_SIZE)
+   {
+      offset = STREAM_POSITION(p_ctx);
+      status = asf_read_object(p_ctx, size);
+      size -= (STREAM_POSITION(p_ctx) - offset);
+   }
+   module->object_level--;
+
+   return status;
+}
+
+/** Reads an ASF file properties object */
+static VC_CONTAINER_STATUS_T asf_read_object_file_properties( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   uint32_t max_packet_size;
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+
+   ASF_SKIP_GUID(p_ctx, size, "File ID");
+   ASF_SKIP_U64(p_ctx, size, "File Size");
+   ASF_SKIP_U64(p_ctx, size, "Creation Date");
+   ASF_SKIP_U64(p_ctx, size, "Data Packets Count");
+   module->duration = ASF_READ_U64(p_ctx, size, "Play Duration") / UINT64_C(10);  /* read in 100nS units, stored in uS */
+   ASF_SKIP_U64(p_ctx, size, "Send Duration");
+   module->preroll = ASF_READ_U64(p_ctx, size, "Preroll") * UINT64_C(1000);      /* read in mS, storedin uS */
+   module->broadcast = ASF_READ_U32(p_ctx, size, "Flags") & 0x1;
+   module->packet_size = ASF_READ_U32(p_ctx, size, "Minimum Data Packet Size");
+   max_packet_size = ASF_READ_U32(p_ctx, size, "Maximum Data Packet Size");
+   ASF_SKIP_U32(p_ctx, size, "Maximum Bitrate");
+
+   if(module->preroll < module->duration) module->duration -= module->preroll;
+   else module->duration = 0;
+
+   /* Sanity check the packet size */
+   if(!module->packet_size)
+   {
+      LOG_DEBUG(p_ctx, "packet size cannot be 0");
+      return VC_CONTAINER_ERROR_FORMAT_FEATURE_NOT_SUPPORTED;
+   }
+
+   if(max_packet_size != module->packet_size)
+   {
+      LOG_DEBUG(p_ctx, "asf stream not supported (min packet size: %i != max packet size: %i)",
+                module->packet_size, max_packet_size);
+      return VC_CONTAINER_ERROR_FORMAT_FEATURE_NOT_SUPPORTED;
+   }
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/** Reads the bitmapinfoheader structure contained in a stream properties object */
+static VC_CONTAINER_STATUS_T asf_read_bitmapinfoheader( VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_TRACK_T *p_track, int64_t size )
+{
+   uint32_t bmih_size, formatdata_size;
+   uint32_t fourcc;
+
+   /* Sanity check the size of the data */
+   if(size < 40 + 11) return VC_CONTAINER_ERROR_CORRUPTED;
+
+   /* Read the preamble to the BITMAPINFOHEADER */
+   ASF_SKIP_U32(p_ctx, size, "Encoded Image Width");
+   ASF_SKIP_U32(p_ctx, size, "Encoded Image Height");
+   ASF_SKIP_U8(p_ctx, size, "Reserved Flags");
+   formatdata_size = ASF_READ_U16(p_ctx, size, "Format Data Size");
+
+   /* Sanity check the size of the data */
+   if(formatdata_size < 40 || size < formatdata_size) return VC_CONTAINER_ERROR_CORRUPTED;
+   bmih_size = ASF_READ_U32(p_ctx, size, "Format Data Size");
+   if(bmih_size < 40 || bmih_size > formatdata_size) return VC_CONTAINER_ERROR_CORRUPTED;
+
+   /* Read BITMAPINFOHEADER structure */
+   p_track->format->type->video.width = ASF_READ_U32(p_ctx, size, "Image Width");
+   p_track->format->type->video.height = ASF_READ_U32(p_ctx, size, "Image Height"); /* Signed */
+   ASF_SKIP_U16(p_ctx, size, "Reserved");
+   ASF_SKIP_U16(p_ctx, size, "Bits Per Pixel Count");
+   ASF_READ_BYTES(p_ctx, size, (char *)&fourcc, 4); /* Compression ID */
+   LOG_FORMAT(p_ctx, "Compression ID: %4.4s", (char *)&fourcc);
+   p_track->format->codec = vfw_fourcc_to_codec(fourcc);
+   if(p_track->format->codec == VC_CONTAINER_CODEC_UNKNOWN)
+      p_track->format->codec = fourcc;
+   ASF_SKIP_U32(p_ctx, size, "Image Size");
+   ASF_SKIP_U32(p_ctx, size, "Horizontal Pixels Per Meter");
+   ASF_SKIP_U32(p_ctx, size, "Vertical Pixels Per Meter");
+   ASF_SKIP_U32(p_ctx, size, "Colors Used Count");
+   ASF_SKIP_U32(p_ctx, size, "Important Colors Count");
+
+   if(!(bmih_size -= 40))return VC_CONTAINER_SUCCESS;
+
+   if(bmih_size > ASF_EXTRADATA_MAX)
+   {
+      LOG_DEBUG(p_ctx, "extradata truncated");
+      bmih_size = ASF_EXTRADATA_MAX;
+   }
+   p_track->format->extradata = p_track->priv->module->extradata;
+   p_track->format->extradata_size = ASF_READ_BYTES(p_ctx, size, p_track->format->extradata, bmih_size);
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/** Reads the waveformatex structure contained in a stream properties object */
+static VC_CONTAINER_STATUS_T asf_read_waveformatex( VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_TRACK_T *p_track, int64_t size)
+{
+   uint16_t extradata_size;
+
+   /* Read WAVEFORMATEX structure */
+   p_track->format->codec = waveformat_to_codec(ASF_READ_U16(p_ctx, size, "Codec ID"));
+   p_track->format->type->audio.channels = ASF_READ_U16(p_ctx, size, "Number of Channels");
+   p_track->format->type->audio.sample_rate = ASF_READ_U32(p_ctx, size, "Samples per Second");
+   p_track->format->bitrate = ASF_READ_U32(p_ctx, size, "Average Number of Bytes Per Second") * 8;
+   p_track->format->type->audio.block_align = ASF_READ_U16(p_ctx, size, "Block Alignment");
+   p_track->format->type->audio.bits_per_sample = ASF_READ_U16(p_ctx, size, "Bits Per Sample");
+   extradata_size = ASF_READ_U16(p_ctx, size, "Codec Specific Data Size");
+
+   CHECK_POINT(p_ctx, size);
+
+   if(!extradata_size) return VC_CONTAINER_SUCCESS;
+
+   /* Sanity check the size of the data */
+   if(extradata_size > size) return VC_CONTAINER_ERROR_CORRUPTED;
+
+   if(extradata_size > ASF_EXTRADATA_MAX)
+   {
+      LOG_DEBUG(p_ctx, "extradata truncated");
+      extradata_size = ASF_EXTRADATA_MAX;
+   }
+   p_track->format->extradata = p_track->priv->module->extradata;
+   p_track->format->extradata_size = ASF_READ_BYTES(p_ctx, size, p_track->format->extradata, extradata_size);
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/** Reads an ASF stream properties object */
+static VC_CONTAINER_STATUS_T asf_read_object_stream_properties( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *p_track;
+   unsigned int ts_length, flags;
+   VC_CONTAINER_ES_TYPE_T type = VC_CONTAINER_ES_TYPE_UNKNOWN;
+   GUID_T stream_type;
+   int64_t offset;
+
+   ASF_READ_GUID(p_ctx, size, &stream_type, "Stream Type");
+   ASF_SKIP_GUID(p_ctx, size, "Error Correction Type");
+
+   /* The time_offset field is in 100nS units. Scale back to uS */
+   module->time_offset = ASF_READ_U64(p_ctx, size, "Time Offset") / UINT64_C(10);
+   ts_length = ASF_READ_U32(p_ctx, size, "Type-Specific Data Length");
+   ASF_SKIP_U32(p_ctx, size, "Error Correction Data Length");
+   flags = ASF_READ_U16(p_ctx, size, "Flags");
+   ASF_SKIP_U32(p_ctx, size, "Reserved");
+
+   CHECK_POINT(p_ctx, size);
+
+   /* Zero is not a valid stream id */
+   if(!(flags & 0x7F)) goto skip;
+
+   if(!memcmp(&stream_type, &asf_guid_stream_type_video, sizeof(GUID_T)))
+      type = VC_CONTAINER_ES_TYPE_VIDEO;
+   else if(!memcmp(&stream_type, &asf_guid_stream_type_audio, sizeof(GUID_T)))
+      type = VC_CONTAINER_ES_TYPE_AUDIO;
+
+   /* Check we know what to do with this track */
+   if(type == VC_CONTAINER_ES_TYPE_UNKNOWN) goto skip;
+
+   /* Sanity check sizes */
+   if(ts_length > size) return VC_CONTAINER_ERROR_CORRUPTED;
+
+   p_track = asf_reader_find_track( p_ctx, flags, true);
+   if(!p_track) return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+
+   p_track->format->es_type = type;
+
+   offset = STREAM_POSITION(p_ctx);
+   if(type == VC_CONTAINER_ES_TYPE_AUDIO)
+      status = asf_read_waveformatex(p_ctx, p_track, (int64_t)ts_length);
+   else if(type == VC_CONTAINER_ES_TYPE_VIDEO)
+      status = asf_read_bitmapinfoheader(p_ctx, p_track, (int64_t)ts_length);
+   size -= STREAM_POSITION(p_ctx) - offset;
+
+   if(status) return status;
+
+   p_track->priv->module->b_valid = true;
+   p_track->is_enabled = true;
+   p_track->format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
+
+   /* Codec specific work-arounds */
+   switch(p_track->format->codec)
+   {
+   case VC_CONTAINER_CODEC_MPGA:
+      /* Can't guarantee that the data is framed */
+      p_track->format->flags &= ~VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
+      break;
+   default: break;
+   }
+
+ skip:
+   if(size) SKIP_BYTES(p_ctx, size);
+   return STREAM_STATUS(p_ctx);
+}
+
+/** Reads an ASF extended stream properties object */
+static VC_CONTAINER_STATUS_T asf_read_object_ext_stream_properties( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_TRACK_T *p_track;
+   unsigned int i, name_count, pes_count, length, stream_id;
+
+   ASF_SKIP_U64(p_ctx, size, "Start Time");
+   ASF_SKIP_U64(p_ctx, size, "End Time");
+   ASF_SKIP_U32(p_ctx, size, "Data Bitrate");
+   ASF_SKIP_U32(p_ctx, size, "Buffer Size");
+   ASF_SKIP_U32(p_ctx, size, "Initial Buffer Fullness");
+   ASF_SKIP_U32(p_ctx, size, "Alternate Data Bitrate");
+   ASF_SKIP_U32(p_ctx, size, "Alternate Buffer Size");
+   ASF_SKIP_U32(p_ctx, size, "Alternate Initial Buffer Fullness");
+   ASF_SKIP_U32(p_ctx, size, "Maximum Object Size");
+   ASF_SKIP_U32(p_ctx, size, "Flags");
+   stream_id = ASF_READ_U16(p_ctx, size, "Stream Number");
+   ASF_SKIP_U16(p_ctx, size, "Stream Language ID Index");
+   ASF_SKIP_U64(p_ctx, size, "Average Time Per Frame");
+   name_count = ASF_READ_U16(p_ctx, size, "Stream Name Count");
+   pes_count = ASF_READ_U16(p_ctx, size, "Payload Extension System Count");
+
+   CHECK_POINT(p_ctx, size);
+
+   p_track = asf_reader_find_track( p_ctx, stream_id, true);
+   if(!p_track) return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+
+   /* Stream Names */
+   for(i = 0; i < name_count; i++)
+   {
+      if(size < 4) return VC_CONTAINER_ERROR_CORRUPTED;
+      ASF_SKIP_U16(p_ctx, size, "Language ID Index");
+      length = ASF_READ_U16(p_ctx, size, "Stream Name Length");
+      if(size < length) return VC_CONTAINER_ERROR_CORRUPTED;
+      ASF_SKIP_BYTES(p_ctx, size, length); /* Stream Name */
+   }
+
+   CHECK_POINT(p_ctx, size);
+
+   /* Payload Extension Systems */
+   for(i = 0; i < pes_count; i++)
+   {
+      if(size < 22) return VC_CONTAINER_ERROR_CORRUPTED;
+      ASF_SKIP_GUID(p_ctx, size, "Extension System ID");
+      ASF_SKIP_U16(p_ctx, size, "Extension Data Size");
+      length = ASF_READ_U32(p_ctx, size, "Extension System Info Length");
+      if(size < length) return VC_CONTAINER_ERROR_CORRUPTED;
+      ASF_SKIP_BYTES(p_ctx, size, length); /* Extension System Info */
+   }
+
+   CHECK_POINT(p_ctx, size);
+
+   /* Optional Stream Properties Object */
+   if(size >= ASF_OBJECT_HEADER_SIZE)
+      status = asf_read_object(p_ctx, size);
+
+   return status;
+}
+
+/** Reads an ASF simple index object */
+static VC_CONTAINER_STATUS_T asf_read_object_simple_index( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = 0;
+   uint64_t time_interval, index_duration;
+   uint32_t count;
+   unsigned int i;
+
+   ASF_SKIP_GUID(p_ctx, size, "File ID");
+
+   /* time in 100nS units, converted to uS */
+   time_interval = ASF_READ_U64(p_ctx, size, "Index Entry Time Interval") / UINT64_C(10);
+   ASF_SKIP_U32(p_ctx, size, "Maximum Packet Count");
+   count = ASF_READ_U32(p_ctx, size, "Index Entries Count");
+
+   CHECK_POINT(p_ctx, size);
+
+   if(count > size / 6)
+   {
+      LOG_DEBUG(p_ctx, "invalid number of entries in the index (%i, %"PRIi64")", count, size / 6);
+      count = (uint32_t)(size / 6);
+   }
+
+   /* Find the track corresponding to this index */
+   for(i = 0; i < p_ctx->tracks_num; i++)
+   {
+      if(p_ctx->tracks[i]->format->es_type != VC_CONTAINER_ES_TYPE_VIDEO) continue;
+      if(p_ctx->tracks[i]->priv->module->simple_index.offset) continue;
+      break;
+   }
+
+   /* Skip the index if we can't find the associated track */
+   if(i == p_ctx->tracks_num || !count || !time_interval) return VC_CONTAINER_SUCCESS;
+   track_module = p_ctx->tracks[i]->priv->module;
+
+   track_module->simple_index.offset = STREAM_POSITION(p_ctx);
+   track_module->simple_index.time_interval = time_interval;
+   track_module->simple_index.num_entries = count;
+
+   /* Check that the index covers the whole duration of the stream */
+   index_duration = (count * time_interval);
+   if(module->preroll + module->time_offset < index_duration)
+      index_duration -= module->preroll + module->time_offset;
+   else
+      index_duration = 0;
+
+   if((uint64_t)module->duration > index_duration + time_interval)
+   {
+      track_module->simple_index.incomplete = true;
+   }
+
+   LOG_DEBUG(p_ctx, "index covers %fS on %fS",
+      (float)index_duration / 1E6, (float)module->duration / 1E6);
+
+#if defined(ENABLE_CONTAINERS_LOG_FORMAT) && defined(ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE)
+   for(i = 0; i < count; i++)
+   {
+      LOG_FORMAT(p_ctx, "Entry: %u", i);
+      ASF_SKIP_U32(p_ctx, size, "Packet Number");
+      ASF_SKIP_U16(p_ctx, size, "Packet Count");
+      if(STREAM_STATUS(p_ctx) != VC_CONTAINER_SUCCESS) break;
+   }
+   size = i * 6;
+#else
+   size = CACHE_BYTES(p_ctx, count * 6);
+#endif
+
+   /* Check that the index is complete */
+   if(size / 6 != count )
+   {
+      LOG_DEBUG(p_ctx, "index is incomplete (%i entries on %i)", (int)size / 6, count);
+      track_module->simple_index.num_entries = (uint32_t)(size / 6);
+      track_module->simple_index.incomplete = true;
+   }
+
+   /* If we haven't had an index before, or this track is enabled, we'll store this one.
+    * (Usually there will only be one video track, and it will be enabled, so both tests
+    * will pass. This check is an attempt to handle content not structured as it should be) */
+   if ((!module->simple_index_track) || (p_ctx->tracks[i]->is_enabled))
+   {
+      /* Save the track so we don't have to look for it in when seeking */
+      module->simple_index_track = track_module;
+   }
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/** Reads an ASF index object */
+static VC_CONTAINER_STATUS_T asf_read_object_index( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   uint32_t i, specifiers_count, blocks_count;
+   uint32_t best_specifier_type[ASF_TRACKS_MAX] = {0};
+
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+
+   /* Read the time interval and scale to microseconds */
+   module->top_level_index.entry_time_interval
+      = (uint64_t)ASF_READ_U32(p_ctx, size, "Index Entry Time Interval") * INT64_C(1000);
+
+   module->top_level_index.specifiers_count
+      = specifiers_count
+      = (uint32_t)ASF_READ_U16(p_ctx, size, "Index Specifiers Count");
+
+   module->top_level_index.block_count
+      = blocks_count
+      = ASF_READ_U32(p_ctx, size, "Index Blocks Count");
+
+   CHECK_POINT(p_ctx, size);
+
+   /* Index specifiers. Search for the one we like best */
+   if(size < specifiers_count * 4) return VC_CONTAINER_ERROR_CORRUPTED;
+   for(i = 0; i < specifiers_count; i++)
+   {
+      uint32_t stream_id = (uint32_t)ASF_READ_U16(p_ctx, size, "Stream Number");
+      uint32_t index_type = (uint32_t)ASF_READ_U16(p_ctx, size, "Index Type");
+
+      /* Find the track index for this stream */
+      unsigned track = module->stream_number_to_index[stream_id];
+
+      if ((track < ASF_TRACKS_MAX) &&
+         (index_type > best_specifier_type[track]))
+      {
+         /* We like this better than any we have seen before. Note - if we don't like any
+          * the file must be subtly corrupt - best we say nothing, and attempt a seek with
+          * the data for the first specifier, it will be better than nothing. At worst it
+          * will play until a seek is attempted */
+         module->top_level_index.active_specifiers[track] = i;
+         best_specifier_type[track] = index_type;
+      }
+   }
+
+   for (i = 0; i < p_ctx->tracks_num; i++)
+   {
+      LOG_DEBUG(p_ctx, "indexing track %"PRIu32" with specifier %"PRIu32,
+         i, module->top_level_index.active_specifiers[i]);
+   }
+
+   CHECK_POINT(p_ctx, size);
+
+   /* The blocks start here */
+   module->top_level_index.blocks_offset = STREAM_POSITION(p_ctx);
+
+   /* Index blocks */
+#if !(defined(ENABLE_CONTAINERS_LOG_FORMAT) && defined(ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE))
+   blocks_count = 0; /* Don't log the index. Note we'll get a warning on unprocessed data */
+#endif
+   /* coverity[dead_error_condition] Code needs to stay there for debugging purposes */
+   for(i = 0; i < blocks_count; i++)
+   {
+      uint32_t j, k, count = ASF_READ_U32(p_ctx, size, "Index Entry Count");
+
+      for(j = 0; j < specifiers_count; j++)
+      {
+         ASF_SKIP_U64(p_ctx, size, "Block Positions");
+      }
+      for(j = 0; j < count; j++)
+      {
+         for(k = 0; k < specifiers_count; k++)
+         {
+            ASF_SKIP_U32(p_ctx, size, "Offsets");
+         }
+      }
+   }
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/** Reads an ASF index parameters object */
+static VC_CONTAINER_STATUS_T asf_read_object_index_parameters( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+#ifdef ENABLE_CONTAINERS_LOG_FORMAT
+   /* This is added for debugging only. The spec (section 4.9) states that this is also enclosed in
+    * the index object (see above) and that they are identical. I think they aren't always... */
+   uint32_t i, specifiers_count;
+
+   /* Read the time interval in milliseconds */
+   ASF_SKIP_U32(p_ctx, size, "Index Entry Time Interval");
+
+   specifiers_count = (uint32_t)ASF_READ_U16(p_ctx, size, "Index Specifiers Count");
+
+   CHECK_POINT(p_ctx, size);
+
+   /* Index specifiers. Search for the one we like best */
+   if(size < specifiers_count * 4) return VC_CONTAINER_ERROR_CORRUPTED;
+   for(i = 0; i < specifiers_count; i++)
+   {
+      ASF_SKIP_U16(p_ctx, size, "Stream Number");
+      ASF_SKIP_U16(p_ctx, size, "Index Type");
+   }
+#endif
+   CHECK_POINT(p_ctx, size);
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/** Reads an ASF codec list object */
+static VC_CONTAINER_STATUS_T asf_read_object_codec_list( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   uint32_t i, count, length;
+
+   ASF_SKIP_GUID(p_ctx, size, "Reserved");
+   count = ASF_READ_U32(p_ctx, size, "Codec Entries Count");
+
+   CHECK_POINT(p_ctx, size);
+
+   /* Codec entries */
+   for(i = 0; i < count; i++)
+   {
+      ASF_SKIP_U16(p_ctx, size, "Type");
+      length = ASF_READ_U16(p_ctx, size, "Codec Name Length");
+      if(size < length) return VC_CONTAINER_ERROR_CORRUPTED;
+      ASF_SKIP_STRING(p_ctx, size, length * 2, "Codec Name");
+      length = ASF_READ_U16(p_ctx, size, "Codec Description Length");
+      if(size < length) return VC_CONTAINER_ERROR_CORRUPTED;
+      ASF_SKIP_STRING(p_ctx, size, length * 2, "Codec Description");
+      length = ASF_READ_U16(p_ctx, size, "Codec Information Length");
+      if(size < length) return VC_CONTAINER_ERROR_CORRUPTED;
+      ASF_SKIP_BYTES(p_ctx, size, length);
+
+      CHECK_POINT(p_ctx, size);
+   }
+
+   return status;
+}
+
+/** Reads an ASF content description object */
+static VC_CONTAINER_STATUS_T asf_read_object_content_description( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   uint16_t t_length, a_length, c_length, d_length, r_length;
+
+   t_length = ASF_READ_U16(p_ctx, size, "Title Length");
+   a_length = ASF_READ_U16(p_ctx, size, "Author Length");
+   c_length = ASF_READ_U16(p_ctx, size, "Copyright Length");
+   d_length = ASF_READ_U16(p_ctx, size, "Description Length");
+   r_length = ASF_READ_U16(p_ctx, size, "Rating Length");
+
+   CHECK_POINT(p_ctx, size);
+
+   if(size < t_length) return VC_CONTAINER_ERROR_CORRUPTED;
+   ASF_SKIP_STRING(p_ctx, size, t_length, "Title");
+   if(size < a_length) return VC_CONTAINER_ERROR_CORRUPTED;
+   ASF_SKIP_STRING(p_ctx, size, a_length, "Author");
+   if(size < c_length) return VC_CONTAINER_ERROR_CORRUPTED;
+   ASF_SKIP_STRING(p_ctx, size, c_length, "Copyright");
+   if(size < d_length) return VC_CONTAINER_ERROR_CORRUPTED;
+   ASF_SKIP_STRING(p_ctx, size, d_length, "Description");
+   if(size < r_length) return VC_CONTAINER_ERROR_CORRUPTED;
+   ASF_SKIP_STRING(p_ctx, size, r_length, "Rating");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/** Reads an ASF stream bitrate properties object */
+static VC_CONTAINER_STATUS_T asf_read_object_stream_bitrate_props( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   uint16_t i, count;
+
+   count = ASF_READ_U16(p_ctx, size, "Bitrate Records Count");
+
+   /* Bitrate records */
+   if(size < count * 6) return VC_CONTAINER_ERROR_CORRUPTED;
+   for(i = 0; i < count; i++)
+   {
+      ASF_SKIP_U16(p_ctx, size, "Flags");
+      ASF_SKIP_U32(p_ctx, size, "Average Bitrate");
+   }
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/** Reads an ASF content encryption object */
+static VC_CONTAINER_STATUS_T asf_read_object_content_encryption( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   uint32_t length;
+
+   length = ASF_READ_U32(p_ctx, size, "Secret Data Length");
+   ASF_SKIP_BYTES(p_ctx, size, length);
+
+   length = ASF_READ_U32(p_ctx, size, "Protection Type Length");
+   ASF_SKIP_BYTES(p_ctx, size, length);
+
+   length = ASF_READ_U32(p_ctx, size, "Key ID Length");
+   ASF_SKIP_BYTES(p_ctx, size, length);
+
+   length = ASF_READ_U32(p_ctx, size, "License URL Length");
+   ASF_SKIP_BYTES(p_ctx, size, length); /* null-terminated ASCII string */
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/** Reads an ASF extended content encryption object */
+static VC_CONTAINER_STATUS_T asf_read_object_ext_content_encryption( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   uint32_t length;
+
+   length = ASF_READ_U32(p_ctx, size, "Data Size");
+   ASF_SKIP_BYTES(p_ctx, size, length);
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/** Reads an ASF advanced content encryption object */
+static VC_CONTAINER_STATUS_T asf_read_object_adv_content_encryption( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   uint32_t i, count;
+
+   count = ASF_READ_U16(p_ctx, size, "Content Encryption Records Count");
+
+   for(i = 0; i < count; i++)
+   {
+      uint32_t j, rec_count, data_size, length;
+
+      ASF_SKIP_GUID(p_ctx, size, "System ID");
+      ASF_SKIP_U32(p_ctx, size, "System Version");
+      rec_count = ASF_READ_U16(p_ctx, size, "Encrypted Object Record Count");
+
+      CHECK_POINT(p_ctx, size);
+
+      for(j = 0; j < rec_count; j++)
+      {
+         ASF_SKIP_U16(p_ctx, size, "Encrypted Object ID Type");
+         length = ASF_READ_U16(p_ctx, size, "Encrypted Object ID Length");
+         if(length > size) return VC_CONTAINER_ERROR_CORRUPTED;
+         ASF_SKIP_BYTES(p_ctx, size, length);
+         CHECK_POINT(p_ctx, size);
+      }
+
+      data_size = ASF_READ_U32(p_ctx, size, "Data Size");
+      if(data_size > size) return VC_CONTAINER_ERROR_CORRUPTED;
+      ASF_SKIP_BYTES(p_ctx, size, data_size);
+      CHECK_POINT(p_ctx, size);
+   }
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/** Skips over an object that is if a type we don't handle, or is nested too deep */
+static VC_CONTAINER_STATUS_T asf_skip_unprocessed_object( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   LOG_DEBUG(p_ctx, "%"PRIi64" bytes ignored in unhandled object", size);
+
+   if(size < ASF_MAX_OBJECT_SIZE)
+      SKIP_BYTES(p_ctx, size);                     /* read a small amount */
+   else
+      SEEK(p_ctx, STREAM_POSITION(p_ctx) + size);  /* seek a large distance */
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T asf_find_packet_header( VC_CONTAINER_T *p_ctx,
+   ASF_PACKET_STATE *p_state )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   unsigned int search_size = 64*1024; /* should be max packet size according to spec */
+#ifdef ENABLE_CONTAINER_LOG_DEBUG
+   uint64_t offset = STREAM_POSITION(p_ctx);
+#endif
+   uint8_t h[3];
+   VC_CONTAINER_PARAM_UNUSED(p_state);
+
+   /* Limit the search up to what should theoretically be the packet boundary */
+   if(module->packet_size)
+      search_size = module->packet_size -
+         (STREAM_POSITION(p_ctx) - module->data_offset) % module->packet_size;
+
+   for(; search_size > sizeof(h); search_size--)
+   {
+      if(PEEK_BYTES(p_ctx, h, sizeof(h)) != sizeof(h))
+         return STREAM_STATUS(p_ctx);
+
+      if(!h[0] && !h[1] && h[2] == 0x82)
+      {
+         search_size = 2;
+         break; /* Got it */
+      }
+
+      SKIP_BYTES(p_ctx, 1);
+   }
+
+   /* If we failed, we just skip to the theoretical packet boundary */
+   SKIP_BYTES(p_ctx, search_size);
+
+   LOG_DEBUG(p_ctx, "found potential sync, discarded %"PRIu64" bytes)",
+             STREAM_POSITION(p_ctx) - offset);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T asf_read_packet_header( VC_CONTAINER_T *p_ctx,
+   ASF_PACKET_STATE *p_state, uint64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   uint64_t offset = STREAM_POSITION(p_ctx);
+   uint8_t flags, property_flags, length;
+   VC_CONTAINER_PARAM_UNUSED(size);
+
+   p_state->start = offset;
+
+   LOG_FORMAT(p_ctx, "Packet Offset: %"PRIu64, offset);
+
+   if ((module->data_size > 0) && (offset >= (module->data_size + module->data_offset)))
+   {
+      return VC_CONTAINER_ERROR_EOS;
+   }
+
+   /* Find out whether we are dealing with error correction data or payload parsing info */
+   if( PEEK_U8(p_ctx) >> 7 )
+   {
+      /* We have error correction data */
+      flags = READ_U8(p_ctx, "Error Correction Flags");
+      length = flags & 0xF;
+      SKIP_BYTES(p_ctx, length); /* Error correction data */
+   }
+
+   /* Payload parsing information */
+   flags = READ_U8(p_ctx, "Length Type Flags");
+   p_state->multiple_payloads = flags & 1;
+   property_flags = READ_U8(p_ctx, "Property Flags");
+   p_state->replicated_data_lt = (property_flags >> 0) & 0x3;
+   p_state->offset_into_media_object_lt = (property_flags >> 2) & 0x3;
+   p_state->media_object_number_lt = (property_flags >> 4) & 0x3;
+
+   /* Sanity check stream number length type */
+   if(((property_flags >> 6) & 0x3) != 1)
+      goto error;
+
+   /* If there's no packet size field we default to the size in the file header. */
+   p_state->size = READ_VLC(p_ctx, (flags >> 5) & 0x3 /* Packet length type */,
+                             module->packet_size, "Packet Length");
+
+   READ_VLC(p_ctx, (flags>>1)&0x3 /* Sequence type */, 0, "Sequence");
+   p_state->padding_size = READ_VLC(p_ctx, (flags>>3)&0x3 /* Padding length type */, 0, "Padding Length");
+   p_state->send_time = READ_U32(p_ctx, "Send Time") * UINT64_C(1000); /* Read in millisecond units, stored in uS */
+   SKIP_U16(p_ctx, "Duration"); /* in milliseconds */
+
+   p_state->num_payloads = 1;
+   p_state->current_payload = 0;
+   if(p_state->multiple_payloads)
+   {
+      LOG_FORMAT(p_ctx, "Multiple Payloads");
+      flags = READ_U8(p_ctx, "Payload Flags");
+      p_state->num_payloads = flags & 0x3F;
+      LOG_FORMAT(p_ctx, "Number of Payloads: %i", p_state->num_payloads);
+      p_state->payload_lt = (flags >> 6) & 3;
+
+      /* Sanity check */
+      if(!p_state->num_payloads) goto error;
+   }
+
+   /* Update the current offset in the packet. */
+   p_state->current_offset = STREAM_POSITION(p_ctx) - offset;
+
+   /* Sanity check offset */
+   if(p_state->current_offset > p_state->size) goto error;
+
+   /* Sanity check padding size */
+   if(p_state->padding_size + p_state->current_offset > p_state->size) goto error;
+
+   /* Sanity check packet size */
+   if(!module->broadcast &&
+      (p_state->size != module->packet_size)) goto error;
+
+   return STREAM_STATUS(p_ctx);
+
+ error:
+   LOG_FORMAT(p_ctx, "Invalid payload parsing information (offset %"PRIu64")", STREAM_POSITION(p_ctx));
+   return STREAM_STATUS(p_ctx) == VC_CONTAINER_SUCCESS ?
+      VC_CONTAINER_ERROR_CORRUPTED : STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T asf_read_payload_header( VC_CONTAINER_T *p_ctx,
+   ASF_PACKET_STATE *p_state /* uint64_t size */ )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   uint32_t rep_data_length;
+
+   if(p_state->current_payload >= p_state->num_payloads)
+      return VC_CONTAINER_ERROR_CORRUPTED;
+
+   p_state->stream_num = READ_U8(p_ctx, "Stream Number");
+   if(!(p_state->stream_num & 0x7F)) return VC_CONTAINER_ERROR_CORRUPTED;
+
+   p_state->media_object_num = READ_VLC(p_ctx, p_state->media_object_number_lt, 0, "Media Object Number");
+
+   /* For a compressed packet this field is a timestamp, and is moved to p_state->media_object_pts later */
+   p_state->media_object_off = READ_VLC(p_ctx, p_state->offset_into_media_object_lt, 0, "Offset Into Media Object");
+   rep_data_length = READ_VLC(p_ctx, p_state->replicated_data_lt, 0, "Replicated Data Length");
+
+   /* Sanity check the replicated data length */
+   if(rep_data_length && rep_data_length != 1 &&
+      (rep_data_length < 8 ||
+       STREAM_POSITION(p_ctx) - p_state->start + p_state->padding_size + rep_data_length > p_state->size))
+   {
+      LOG_FORMAT(p_ctx, "invalid replicated data length");
+      return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+
+   /* Read what we need from the replicated data */
+   if(rep_data_length > 1)
+   {
+      p_state->media_object_size = READ_U32(p_ctx, "Media Object Size");
+      p_state->media_object_pts = READ_U32(p_ctx, "Presentation Time") * UINT64_C(1000);
+      p_state->compressed_payloads = 0;
+      SKIP_BYTES(p_ctx, rep_data_length - 8); /* Rest of replicated data */
+   }
+   else if(rep_data_length == 1)
+   {
+      LOG_FORMAT(p_ctx, "Compressed Payload Data");
+      p_state->media_object_pts_delta = READ_U8(p_ctx, "Presentation Time Delta") * UINT64_C(1000);
+      p_state->compressed_payloads = 1;
+
+      /* Move the pts from media_object_off where it was read, and adjust it */
+      p_state->media_object_off *= UINT64_C(1000);
+      p_state->media_object_pts = p_state->media_object_off - p_state->media_object_pts_delta;
+      p_state->media_object_off = 0;
+      p_state->media_object_size = 0;
+   }
+   else
+   {
+      p_state->media_object_size = 0;
+      p_state->media_object_pts = p_state->send_time;
+      p_state->compressed_payloads = 0;
+   }
+
+   if(p_state->media_object_pts > module->preroll + module->time_offset)
+      p_state->media_object_pts -= (module->preroll + module->time_offset);
+   else p_state->media_object_pts = 0;
+
+   p_state->payload_size = p_state->size - p_state->padding_size - (STREAM_POSITION(p_ctx) - p_state->start);
+   if(p_state->multiple_payloads)
+   {
+      p_state->payload_size = READ_VLC(p_ctx, p_state->payload_lt, 0, "Payload Length");
+      if(!p_state->payload_size) return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+   else
+      LOG_FORMAT(p_ctx, "Payload Length: %i", p_state->payload_size);
+
+   if(p_state->payload_size >= p_state->size) return VC_CONTAINER_ERROR_CORRUPTED;
+
+   p_state->subpayload_size = p_state->payload_size;
+
+   /* Update current_offset to reflect the variable number of bytes we just read */
+   p_state->current_offset = STREAM_POSITION(p_ctx) - p_state->start;
+
+   /* Sanity check offset */
+   if(p_state->current_offset > p_state->size) return VC_CONTAINER_ERROR_CORRUPTED;
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T asf_read_object_data( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   unsigned int i;
+   VC_CONTAINER_PARAM_UNUSED(size);
+
+   SKIP_GUID(p_ctx, "File ID");
+   SKIP_U64(p_ctx, "Total Data Packets");
+   SKIP_U16(p_ctx, "Reserved");
+   module->data_offset = STREAM_POSITION(p_ctx);
+
+   /* Initialise state for all tracks */
+   module->packet_state.start = module->data_offset;
+   for(i = 0; i < p_ctx->tracks_num; i++)
+   {
+      VC_CONTAINER_TRACK_T *p_track = p_ctx->tracks[i];
+      p_track->priv->module->p_packet_state = &module->packet_state;
+   }
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+/* Read the next sub-payload or next payload */
+static VC_CONTAINER_STATUS_T asf_read_next_payload_header( VC_CONTAINER_T *p_ctx,
+   ASF_PACKET_STATE *p_state, uint32_t *pi_track, uint32_t *pi_length)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status;
+
+   if(p_state->subpayload_size)
+   {
+      /* We still haven't read the current subpayload, return the info we already have */
+      goto end;
+   }
+
+   /* Check if we're done reading a packet */
+   if(p_state->current_payload >= p_state->num_payloads)
+   {
+      /* Skip the padding at the end */
+      if(p_state->size)
+      {
+         int32_t pad_length = p_state->size - (STREAM_POSITION(p_ctx) - p_state->start);
+         if(pad_length < 0) return VC_CONTAINER_ERROR_CORRUPTED;
+         SKIP_BYTES(p_ctx, pad_length); /* Padding */
+      }
+
+      /* Read the header for the next packet */
+      module->object_level = 0; /* For debugging */
+      status = asf_read_packet_header( p_ctx, p_state, (uint64_t)0/*size???*/ );
+      module->object_level = 1; /* For debugging */
+      if(status != VC_CONTAINER_SUCCESS) return status;
+   }
+
+   /* Check if we're done reading a payload */
+   if(!p_state->payload_size)
+   {
+      /* Read the payload header */
+      status = asf_read_payload_header( p_ctx, p_state );
+      if(status != VC_CONTAINER_SUCCESS) return status;
+   }
+
+   /* For compressed payloads, payload_size != subpayload_size */
+   if(p_state->compressed_payloads && p_state->payload_size)
+   {
+      p_state->payload_size--;
+      p_state->subpayload_size = READ_U8(p_ctx, "Sub-Payload Data Length");
+      if(p_state->subpayload_size > p_state->payload_size)
+      {
+         /* TODO: do something ? */
+         LOG_DEBUG(p_ctx, "subpayload is too big");
+         p_state->subpayload_size = p_state->payload_size;
+      }
+      p_state->media_object_off = 0;
+      p_state->media_object_size = p_state->subpayload_size;
+      p_state->media_object_pts += p_state->media_object_pts_delta;
+   }
+
+ end:
+   /* We've read the payload header, return the requested info */
+   if(pi_track) *pi_track = module->stream_number_to_index[p_state->stream_num & 0x7F];
+   if(pi_length) *pi_length = p_state->subpayload_size;
+
+   p_state->current_offset = STREAM_POSITION(p_ctx) - p_state->start;
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+/* read the next payload (not sub-payload) */
+static VC_CONTAINER_STATUS_T asf_read_next_payload( VC_CONTAINER_T *p_ctx,
+   ASF_PACKET_STATE *p_state, uint8_t *p_data, uint32_t *pi_size )
+{
+   uint32_t subpayload_size = p_state->subpayload_size;
+
+   if(p_data && *pi_size < subpayload_size) subpayload_size = *pi_size;
+
+   if(!p_state->subpayload_size)
+      return VC_CONTAINER_SUCCESS;
+
+   p_state->payload_size -= subpayload_size;
+   if(!p_state->payload_size) p_state->current_payload++;
+   p_state->subpayload_size -= subpayload_size;
+   p_state->media_object_off += subpayload_size;
+
+   if(p_data) *pi_size = READ_BYTES(p_ctx, p_data, subpayload_size);
+   else *pi_size = SKIP_BYTES(p_ctx, subpayload_size);
+
+   p_state->current_offset += subpayload_size;
+
+   if(*pi_size!= subpayload_size)
+      return STREAM_STATUS(p_ctx);
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/******************************************************************************
+Functions exported as part of the Container Module API
+ *****************************************************************************/
+/*****************************************************************************/
+/** Read data from the ASF file
+
+@param   p_ctx    Context for the file being read from
+
+@param   p_packet Packet information. Includes data buffer and stream ID as aprropriate.
+
+@param   flags    Flags controlling the read.
+                  May request reading only, skipping a packet or force access to a set track.
+
+******************************************************************************/
+static VC_CONTAINER_STATUS_T asf_reader_read( VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_PACKET_T *p_packet, uint32_t flags )
+{
+   VC_CONTAINER_MODULE_T *global_module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   ASF_PACKET_STATE *p_state;
+   uint32_t buffer_size = 0, track, data_size;
+   uint64_t state_pos;
+
+   LOG_DEBUG(p_ctx, "asf_reader_read track %"PRIu32" flags %u", p_packet->track, flags);
+
+   /* If a specific track has been selected, we need to use the track packet state */
+   if(flags & VC_CONTAINER_READ_FLAG_FORCE_TRACK)
+   {
+      vc_container_assert(p_packet->track < p_ctx->tracks_num);
+      /* The state to use is the one referred to by the track we selected */
+      p_state = p_ctx->tracks[p_packet->track]->priv->module->p_packet_state;
+   }
+   else
+   {
+      /* No specific track was selected. Read the next data from the global position. */
+       p_state = &global_module->packet_state;
+   }
+
+   /* Stop if the stream can't be read */
+   if(p_state->eos) return VC_CONTAINER_ERROR_EOS;
+   if(p_state->corrupted) return VC_CONTAINER_ERROR_CORRUPTED;
+
+   /* If we aren't in the right position in the file go there now. */
+   state_pos = p_state->start + p_state->current_offset;
+   if ((uint64_t)STREAM_POSITION(p_ctx) != state_pos)
+   {
+      LOG_DEBUG(p_ctx, "seeking from %"PRIu64" to %"PRIu64, STREAM_POSITION(p_ctx), state_pos);
+      SEEK(p_ctx, state_pos);
+   }
+
+   /* Look at the next payload header */
+   status = asf_read_next_payload_header( p_ctx, p_state, &track, &data_size );
+   if((status == VC_CONTAINER_ERROR_CORRUPTED)
+      && (p_state->bad_packets < ASF_MAX_CONSECUTIVE_CORRUPTED_PACKETS))
+   {
+      /* If the current packet is corrupted we will try to search for the next packet */
+      uint32_t corrupted = p_state->bad_packets;
+      LOG_DEBUG(p_ctx, "packet offset %"PRIi64" is corrupted", p_state->start);
+      memset(p_state, 0, sizeof(*p_state));
+      p_state->bad_packets = corrupted + 1;
+
+      /* TODO: flag discontinuity */
+
+      if(asf_find_packet_header(p_ctx, p_state) == VC_CONTAINER_SUCCESS)
+      {
+         p_state->start = STREAM_POSITION(p_ctx);
+         return VC_CONTAINER_ERROR_CONTINUE;
+      }
+   }
+   if(status == VC_CONTAINER_ERROR_EOS) p_state->eos = true;
+   if(status == VC_CONTAINER_ERROR_CORRUPTED) p_state->corrupted = true;
+   if(status != VC_CONTAINER_SUCCESS)
+   {
+      return status;
+   }
+
+   p_state->bad_packets = 0;
+
+   /* bad track number or track is disabled */
+   if(track >= p_ctx->tracks_num || !p_ctx->tracks[track]->is_enabled)
+   {
+      LOG_DEBUG(p_ctx, "skipping packet because track %u is invalid or disabled", track);
+
+      /* Skip payload by reading with a null buffer */
+      status = asf_read_next_payload(p_ctx, p_state, 0, &data_size );
+      if(status != VC_CONTAINER_SUCCESS) return status;
+      return VC_CONTAINER_ERROR_CONTINUE;
+   }
+
+   track_module = p_ctx->tracks[track]->priv->module;
+
+   /* If we are reading from the global state, and the track we found is not on the global state,
+    * either skip the data or reconnect it to the global state */
+   if ((p_state == &global_module->packet_state) &&
+      (track_module->p_packet_state != &global_module->packet_state))
+   {
+      uint64_t track_pos =
+         track_module->p_packet_state->start
+         + track_module->p_packet_state->current_offset;
+
+      /* Check if the end of the current packet is beyond the track's position */
+      if (track_pos > state_pos + track_module->p_packet_state->size)
+      {
+         LOG_DEBUG(p_ctx, "skipping packet from track %u as it has already been read", track);
+         status = asf_read_next_payload(p_ctx, p_state, 0, &data_size);
+
+         if(status != VC_CONTAINER_SUCCESS) return status;
+         return VC_CONTAINER_ERROR_CONTINUE;
+      }
+      else
+      {
+         LOG_DEBUG(p_ctx, "switching track index %u location %"PRIu64" back to global state", track, track_pos);
+         track_module->p_packet_state = &global_module->packet_state;
+
+         /* Update the global state to the precise position */
+         global_module->packet_state = track_module->local_packet_state;
+         return VC_CONTAINER_ERROR_CONTINUE;
+      }
+   }
+
+   /* If we are forcing, and the data is from a different track, skip it.
+    * We may need to move the track we want onto a local state. */
+   if ((flags & VC_CONTAINER_READ_FLAG_FORCE_TRACK)
+      && (track != p_packet->track))
+   {
+      track_module = p_ctx->tracks[p_packet->track]->priv->module;
+
+      /* If the track we found is on the same state as the track we want they must both be on the global state */
+      if (p_ctx->tracks[track]->priv->module->p_packet_state == p_state)
+      {
+         LOG_DEBUG(p_ctx, "switching track index %u location %"PRIu64" away from global state", p_packet->track, state_pos);
+
+         /* Change the track we want onto a local state */
+         track_module->p_packet_state = &track_module->local_packet_state;
+
+         /* Copy the global state into the local state for the track we are forcing */
+         track_module->local_packet_state = global_module->packet_state;
+      }
+
+      LOG_DEBUG(p_ctx, "skipping packet from track %u while forcing %u", track, p_packet->track);
+      status = asf_read_next_payload(p_ctx, track_module->p_packet_state, 0, &data_size );
+      return VC_CONTAINER_ERROR_CONTINUE;
+   }
+
+   /* If we arrive here either the data is from the track we are forcing, or we are not forcing
+    * and we haven't already read the data while forcing that track */
+
+   /* If skip, and no info required, skip over it and return now. */
+   if((flags & VC_CONTAINER_READ_FLAG_SKIP) && !(flags & VC_CONTAINER_READ_FLAG_INFO))
+      return asf_read_next_payload(p_ctx, p_state, 0, &data_size );
+
+   /* Fill-in the packet information */
+   if(p_state->media_object_pts == ASF_UNKNOWN_PTS || p_state->media_object_off)
+      p_packet->dts = p_packet->pts = VC_CONTAINER_TIME_UNKNOWN;
+   else
+      p_packet->dts = p_packet->pts = p_state->media_object_pts;
+
+   p_packet->flags = 0;
+
+   if(p_state->stream_num >> 7) p_packet->flags |= VC_CONTAINER_PACKET_FLAG_KEYFRAME;
+
+   if(!p_state->media_object_off) p_packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
+
+   if(p_state->media_object_size &&
+         p_state->media_object_off + data_size >= p_state->media_object_size)
+      p_packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
+
+   if(!p_state->media_object_size)
+      p_packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
+
+   p_packet->track = track;
+
+   p_packet->frame_size = p_state->media_object_size;
+
+   p_packet->size = data_size;
+
+   /* If the skip flag is set (Info must have been too) skip the data and return */
+   if(flags & VC_CONTAINER_READ_FLAG_SKIP)
+   {
+      /* Skip payload by reading with a null buffer */
+      return asf_read_next_payload(p_ctx, p_state, 0, &data_size );
+   }
+   else if(flags & VC_CONTAINER_READ_FLAG_INFO)
+   {
+      return VC_CONTAINER_SUCCESS;
+   }
+
+   /* Read the payload data */
+   buffer_size = p_packet->buffer_size;
+   status = asf_read_next_payload(p_ctx, p_state, p_packet->data, &buffer_size );
+   if(status != VC_CONTAINER_SUCCESS)
+   {
+      /* FIXME */
+      return status;
+   }
+
+   p_packet->size = buffer_size;
+   if(buffer_size != data_size)
+      p_packet->flags &= ~VC_CONTAINER_PACKET_FLAG_FRAME_END;
+   LOG_DEBUG(p_ctx, "asf_reader_read exit %u PTS %"PRIi64" track %"PRIu32, status, p_packet->pts, track);
+
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T asf_reader_index_find_time( VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_TRACK_MODULE_T* track_module, int64_t time, uint32_t *packet_num, bool forward )
+{
+   VC_CONTAINER_STATUS_T status;
+   uint32_t entry, previous_packet_num;
+   bool eos = false;
+
+   /* Default to beginning of file in case of error */
+   *packet_num = 0;
+
+   /* Special case - time zero is beginning of file */
+   if(time == 0) {return VC_CONTAINER_SUCCESS;}
+
+   /* Sanity checking */
+   if(!track_module->simple_index.num_entries) return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+   if(!track_module->simple_index.time_interval) return VC_CONTAINER_ERROR_CORRUPTED;
+
+   entry = time / track_module->simple_index.time_interval;
+   LOG_DEBUG(p_ctx, "entry: %i, offset: %"PRIi64", interv: %"PRIi64, entry,
+             track_module->simple_index.offset, track_module->simple_index.time_interval);
+   if(entry >= track_module->simple_index.num_entries)
+   {
+      entry = track_module->simple_index.num_entries - 1;
+      eos = true;
+   }
+
+   /* Fetch the entry from the index */
+   status = SEEK(p_ctx, track_module->simple_index.offset + 6 * entry);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+   *packet_num = READ_U32(p_ctx, "Packet Number");
+   if(STREAM_STATUS(p_ctx) != VC_CONTAINER_SUCCESS) return STREAM_STATUS(p_ctx);
+
+   /* When asking for the following keyframe we need to find the next entry with a greater
+    * packet number */
+   previous_packet_num = *packet_num;
+   while(!eos && forward && previous_packet_num == *packet_num)
+   {
+      if(++entry == track_module->simple_index.num_entries) {eos = true; break;}
+      status = SEEK(p_ctx, track_module->simple_index.offset + 6 * entry);
+      if(status != VC_CONTAINER_SUCCESS) break;
+      *packet_num = READ_U32(p_ctx, "Packet Number");
+      if(STREAM_STATUS(p_ctx) != VC_CONTAINER_SUCCESS) break;
+   }
+
+   if(eos && track_module->simple_index.incomplete) return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
+   else if(eos) return VC_CONTAINER_ERROR_EOS;
+   else return STREAM_STATUS(p_ctx);
+}
+
+#if 0
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T asf_reader_index_find_packet( VC_CONTAINER_T *p_ctx,
+   unsigned int track, uint32_t *packet_num, bool forward )
+{
+   VC_CONTAINER_STATUS_T status;
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = 0;
+   uint32_t i, prev_packet_num = 0, next_packet_num;
+   bool eos = false;
+
+   /* Sanity checking */
+   if(track >= p_ctx->tracks_num) return VC_CONTAINER_ERROR_FAILED;
+   track_module = p_ctx->tracks[track]->priv->module;
+   if(!track_module->num_index_entries) return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+   if(!track_module->index_time_interval) return VC_CONTAINER_ERROR_CORRUPTED;
+
+   status = SEEK(p_ctx, track_module->index_offset);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   /* Loop through all the entries in the index */
+   for(i = 0; i < track_module->num_index_entries; i++)
+   {
+      next_packet_num = READ_U32(p_ctx, "Packet Number");
+      SKIP_U16(p_ctx, "Packet Count");
+      if(next_packet_num > *packet_num) break;
+      if(STREAM_STATUS(p_ctx) != VC_CONTAINER_SUCCESS) break;
+      prev_packet_num = next_packet_num;
+   }
+   if(i == track_module->num_index_entries ) eos = true;
+
+   if(STREAM_STATUS(p_ctx) == VC_CONTAINER_SUCCESS && !eos)
+   {
+      if(forward) *packet_num = next_packet_num;
+      else *packet_num = prev_packet_num;
+   }
+
+   if(eos && track_module->index_incomplete) return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
+   else if(eos) return VC_CONTAINER_ERROR_EOS;
+   else return STREAM_STATUS(p_ctx);
+}
+#endif
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T asf_reader_find_next_frame( VC_CONTAINER_T *p_ctx,
+   unsigned int track, ASF_PACKET_STATE *p_state, bool keyframe, bool timeout )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   uint32_t data_track, data_size;
+   unsigned int packets = 0;
+
+   if(p_ctx->tracks[track]->format->es_type != VC_CONTAINER_ES_TYPE_VIDEO)
+      keyframe = false;
+
+   /* We still need to go to the right payload */
+   while(status == VC_CONTAINER_SUCCESS &&
+         (!timeout || packets++ < ASF_MAX_SEARCH_PACKETS))
+   {
+      status = asf_read_next_payload_header( p_ctx, p_state, &data_track, &data_size );
+      if(status != VC_CONTAINER_SUCCESS) break;
+
+      if(data_track == track && ((p_state->stream_num >> 7) || !keyframe) &&
+         !p_state->media_object_off) break;
+
+      /* Skip payload */
+      status = asf_read_next_payload(p_ctx, p_state, 0, &data_size );
+   }
+
+   return status;
+}
+
+/*****************************************************************************/
+/* Helper for asf_reader_seek - seek when there is a top-level index (spec section 6.2) */
+static VC_CONTAINER_STATUS_T seek_by_top_level_index(
+   VC_CONTAINER_T *p_ctx,
+   int64_t *p_time,
+   VC_CONTAINER_SEEK_MODE_T mode,
+   VC_CONTAINER_SEEK_FLAGS_T flags)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   unsigned index;
+   uint64_t time = 0;
+   uint64_t block_address = module->top_level_index.blocks_offset;
+   uint64_t track_positions[ASF_TRACKS_MAX];
+
+   VC_CONTAINER_PARAM_UNUSED(mode);
+   LOG_DEBUG(p_ctx, "seek_by_top_level_index");
+
+   for (index = 0; index < ASF_TRACKS_MAX; ++index)
+   {
+      /* Set all to a stupid value */
+      track_positions[index] = UINT64_MAX;
+   }
+
+   /* Loop through the index blocks to find the one(s) that deal with the time(s) in question.
+      * Note that most ASF files only have one index block. */
+   for (index = 0; index < module->top_level_index.block_count; ++index)
+   {
+      uint64_t block_duration, block_position;
+      uint32_t index_entry_count, stream;
+      LOG_DEBUG(p_ctx, "looking for index blocks at offset %"PRIu64, block_address);
+      status = SEEK(p_ctx, block_address);
+      if(status != VC_CONTAINER_SUCCESS) return status;
+
+      /* Read the number of entries for this index block. */
+      index_entry_count = READ_U32(p_ctx, "Index Entry Count");
+
+      /* Turn into a duration */
+      block_duration = (uint64_t)index_entry_count * module->top_level_index.entry_time_interval;
+
+      /* Go through each stream */
+      for (stream = 0; stream < p_ctx->tracks_num; ++stream)
+      {
+         /* Work out the track's target time */
+         uint64_t track_time = *p_time + module->preroll + module->time_offset;
+
+         /* Have we the correct index block for the seek time? */
+         if ((time <= track_time) && (track_time < time + block_duration))
+         {
+            /* We have the correct index block for the seek time. Work out where in it. */
+            uint32_t block_index = (track_time - time) / module->top_level_index.entry_time_interval;
+            uint64_t active_specifier = module->top_level_index.active_specifiers[stream];
+            uint64_t new_position;
+
+            /* Read the Block Positions value for the correct specifier */
+            status = SEEK(p_ctx,
+               block_address + INT64_C(4)
+               + active_specifier * INT64_C(8));
+            if (status != VC_CONTAINER_SUCCESS)
+            {
+               return status;
+            }
+            block_position = READ_U32(p_ctx, "Block Position");
+
+            /* Read the target address for the stream */
+            status = SEEK(p_ctx, block_address + 4                                        /* skip index entry count */
+               + (UINT64_C(8) * module->top_level_index.specifiers_count)                 /* block positions */
+               + (UINT64_C(4) * module->top_level_index.specifiers_count * block_index)   /* prior index entries */
+               + (UINT64_C(4) * active_specifier));                                       /* correct specifier */
+            LOG_DEBUG(p_ctx, "reading at %"PRIu64, STREAM_POSITION(p_ctx));
+
+            new_position = module->data_offset + block_position + (uint64_t)READ_U32(p_ctx, "Offset");
+            LOG_DEBUG(p_ctx, "actual address for stream %"PRIu32" = %"PRIu64, stream, new_position);
+            track_positions[stream] = new_position;
+         }
+      }
+
+      /* Work out where the next block is */
+      block_address += (UINT64_C(8) * module->top_level_index.specifiers_count)
+            +  (UINT64_C(4) * module->top_level_index.specifiers_count * index_entry_count);
+   }
+
+   return seek_to_positions(p_ctx, track_positions, p_time, flags, 0, 0);
+}
+
+/* Helper for asf_reader_seek -
+ * Given a set of positions seek the tracks. The status is the result of physically seeking each one.
+ * It is expected that the positions will be before *p_time; if the flags require it search
+ * for the next keyframe that is at or above *p_time. */
+static VC_CONTAINER_STATUS_T seek_to_positions(VC_CONTAINER_T *p_ctx, uint64_t track_positions[ASF_TRACKS_MAX],
+   int64_t *p_time, VC_CONTAINER_SEEK_FLAGS_T flags,
+   unsigned int start_track, bool seek_on_start_track)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   uint64_t global_position = UINT64_MAX;
+   unsigned int lowest_track, index, tracks;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+
+   int64_t track_best_pts[ASF_TRACKS_MAX];
+
+   if (*p_time == 0)
+   {
+      // Special case: Time 0 means beginning of file. Don't search for the matching packet(s).
+      memset(&module->packet_state, 0, sizeof(module->packet_state));
+      module->packet_state.start = track_positions[0];
+      status = SEEK(p_ctx, module->packet_state.start);
+
+      // Set each track to using the global state
+      for(index = 0; index < p_ctx->tracks_num; index++)
+      {
+         p_ctx->tracks[index]->priv->module->p_packet_state = &module->packet_state;
+      }
+
+      return status;
+   }
+
+   for(tracks = 0, index = start_track; tracks < p_ctx->tracks_num;
+       tracks++, index = (index+1) % p_ctx->tracks_num)
+   {
+      uint32_t data_size;
+
+      /* Use an on-stack packet state. We can't use the global state, as we must leave it at
+       * the lowest position. We can't use any track's private state, as we will move it past
+       * the desired location. */
+      ASF_PACKET_STATE private_state;
+      memset(&private_state, 0, sizeof(private_state));
+
+      track_best_pts[index] = INT64_MAX;
+
+      status = SEEK(p_ctx, track_positions[index]);
+
+      /* loop until we find the packet we're looking for.
+       * stop when we've seen a big enough PTS, and are on a key frame */
+      while(status == VC_CONTAINER_SUCCESS)
+      {
+         /* Get the next key-frame */
+         status = asf_reader_find_next_frame(p_ctx, index, &private_state, true, true);
+         if(status == VC_CONTAINER_SUCCESS)
+         {
+            /* Get the PTS, if any */
+            int64_t pts = (int64_t)private_state.media_object_pts;
+
+            if(pts != ASF_UNKNOWN_PTS)
+            {
+               if ((track_best_pts[index] == INT64_MAX)        /* we don't have a time yet */
+                  || (pts <= *p_time)                          /* it's before our target */
+                  || (flags & VC_CONTAINER_SEEK_FLAG_FORWARD)) /* we want after target */
+               {
+                  /* Store this time. It's the best yet. */
+                  track_best_pts[index] = pts;
+
+                  /* Update the desired position */
+                  track_positions[index] = private_state.start + private_state.current_offset;
+
+                  /* Copy the local state into this track's private state */
+                  p_ctx->tracks[index]->priv->module->local_packet_state = private_state;
+
+                  LOG_DEBUG(p_ctx, "seek forward track %u to pts %"PRIu64,
+                     index, track_best_pts[index]);
+               }
+
+               /* If we've got to our target time we can stop. */
+               if (pts >= *p_time)
+               {
+                  /* Then stop. */
+                  break;
+               }
+            }
+
+            status = asf_read_next_payload(p_ctx, &private_state, 0, &data_size );
+         }
+      }
+
+      /* If we are seeking using a specific track, usually this is the video track
+       * and we want all the other tracks to start at the same time or later */
+      if (seek_on_start_track && start_track == index)
+      {
+         flags |= VC_CONTAINER_SEEK_FLAG_FORWARD;
+         *p_time = track_best_pts[index];
+      }
+
+      {
+         ASF_PACKET_STATE *p_state = &p_ctx->tracks[index]->priv->module->local_packet_state;
+
+         LOG_DEBUG(p_ctx, "seek track %u to pts %"PRIu64" (key:%i,moo:%i)",
+            index, track_best_pts[index], p_state->stream_num >> 7, p_state->media_object_off);
+      }
+   }
+
+   /* Find the smallest track address in track_positions. This will be the global position */
+   /* Also the lowest PTS in track_best_pts, this will be the new global PTS */
+   for (index = 0, lowest_track = 0; index < p_ctx->tracks_num; ++index)
+   {
+      /* If it is smaller, remember it */
+      if (track_positions[index] < global_position)
+      {
+         global_position = track_positions[index];
+         lowest_track = index;
+      }
+
+      /* Put the lowest PTS into entry 0 of the array */
+      if ((track_best_pts[index] != INT64_MAX) && (track_best_pts[index] < track_best_pts[0]))
+      {
+         track_best_pts[0] = track_best_pts[index];
+      }
+   }
+
+   /* Update the caller with the lowest real PTS, if any. (we may have already done this above) */
+   if (track_best_pts[0] != INT64_MAX)
+   {
+      *p_time = track_best_pts[0];
+   }
+   else
+   {
+      LOG_DEBUG(p_ctx, "no PTS suitable to update the caller");
+   }
+
+   /* As we did an extra read on the index track past the desired location seek back to it */
+   status = SEEK(p_ctx, global_position);
+
+   /* Copy the packet state for the stream with the lowest address into the global state */
+   module->packet_state = p_ctx->tracks[lowest_track]->priv->module->local_packet_state;
+
+   for(index = 0; index < p_ctx->tracks_num; index++)
+   {
+      VC_CONTAINER_TRACK_MODULE_T* track_mod = p_ctx->tracks[index]->priv->module;
+
+      /* If the track position is the global position, or it is invalid, use the global state */
+      if ((track_positions[index] <= global_position) || (track_positions[index] == UINT64_MAX))
+      {
+         track_mod->p_packet_state = &module->packet_state;
+      }
+      else
+      {
+         /* Track is not at the global position. Use the local state. */
+         LOG_DEBUG(p_ctx, "track %u local position %"PRIu64, index, track_positions[index]);
+         track_mod->p_packet_state = &track_mod->local_packet_state;
+      }
+   }
+
+   return status;
+}
+
+/*****************************************************************************/
+/* Seek to a location in the file, using whatever indices are available
+ * If flags bit VC_CONTAINER_SEEK_FLAG_FORWARD is set the position is guaranteed to
+ * be a keyframe at or after the requested location. Conversely if it is not set
+ * the position is guaranteed to be at or before the request. */
+static VC_CONTAINER_STATUS_T asf_reader_seek( VC_CONTAINER_T *p_ctx, int64_t *p_time,
+   VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_EOS;      /* initialised to known fail state */
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   unsigned int stream;
+
+   VC_CONTAINER_PARAM_UNUSED(mode);
+
+   LOG_DEBUG(p_ctx, "asf_reader_seek");
+
+   /* Prefer the top-level index to the simple index - it has byte offsets not packet offsets,
+   * and is likely to have separate tables for every track */
+   if (module->top_level_index.block_count)
+   {
+      status = seek_by_top_level_index(p_ctx, p_time, mode, flags);
+   }
+   else
+   {
+      uint64_t track_positions[ASF_TRACKS_MAX];
+      int seek_track = -1;
+      uint32_t packet_num;
+      uint64_t new_position;
+
+      if (*p_time == 0)
+      {
+         // Special optimisation - for time zero just go to the beginning.
+         packet_num = 0;
+      }
+      /* If there is a simple index use the packet number from it */
+      else if (module->simple_index_track)
+      {
+         /* Correct time desired */
+         uint64_t track_time = *p_time + module->preroll + module->time_offset;
+
+         LOG_DEBUG(p_ctx, "using simple index");
+
+         /* Search the index for the correct packet */
+         status = asf_reader_index_find_time(p_ctx, module->simple_index_track, track_time,
+            &packet_num, flags & VC_CONTAINER_SEEK_FLAG_FORWARD);
+      }
+      else
+      {
+         /* No index at all. Use arithmetic to guess the packet number. */
+         LOG_DEBUG(p_ctx, "index not usable %u", (unsigned)status);
+
+         if (module->packets_num == 0)
+         {
+            /* This is a broadcast stream, and we can't do the arithmetic.
+            * Set it to a value that will guarantee a seek fail. */
+            LOG_DEBUG(p_ctx, "no packets in file");
+            packet_num = UINT32_MAX;
+         }
+         else
+         {
+            packet_num = *p_time * module->packets_num / module->duration;
+         }
+      }
+
+      /* calculate the byte address of the packet, relative to the start of data */
+      new_position = (uint64_t)packet_num * (uint64_t)module->packet_size;
+
+      LOG_DEBUG(p_ctx, "packet number %"PRIu32" approx byte offset %"PRIu64 , packet_num, new_position + module->data_offset);
+      if (new_position > (uint64_t)module->data_size)
+      {
+         new_position = module->data_size;
+         LOG_DEBUG(p_ctx, "arithmetic error, seeking to end of file %" PRIu64 , new_position + module->data_offset);
+      }
+
+      new_position += module->data_offset;
+
+      for(stream = 0; stream < p_ctx->tracks_num; stream++)
+      {
+         /* Use the 1st enabled video track as the seek stream */
+         if(p_ctx->tracks[stream]->format->es_type ==
+               VC_CONTAINER_ES_TYPE_VIDEO &&
+            p_ctx->tracks[stream]->is_enabled && seek_track < 0)
+            seek_track = stream;
+
+         track_positions[stream] = new_position;
+      }     /* repeat for all tracks */
+
+      /* Work out if we actually got anywhere. If so, save the positions for the subsequent reads */
+      status = seek_to_positions(p_ctx, track_positions, p_time, flags,
+         seek_track < 0 ? 0 : seek_track, seek_track >= 0);
+   }
+
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T asf_reader_close( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   unsigned int i;
+
+/* FIXME: metadata is currently shared across all readers so freeing
+          it is left to the common layer but this isn't necessarily
+          the best solution.
+   for(i = 0; i <p_ctx->meta_num; i++)
+      free(p_ctx->meta[i]);
+   if(p_ctx->meta_num) free(p_ctx->meta);
+   p_ctx->meta_num = 0;
+*/
+   for(i = 0; i < p_ctx->tracks_num; i++)
+      vc_container_free_track(p_ctx, p_ctx->tracks[i]);
+   p_ctx->tracks_num = 0;
+   free(module);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T asf_reader_open( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = 0;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   unsigned int i;
+   GUID_T guid;
+
+   /* Check for an ASF top-level header object */
+   if(PEEK_BYTES(p_ctx, (uint8_t *)&guid, sizeof(guid)) < sizeof(guid) ||
+      memcmp(&guid, &asf_guid_header, sizeof(guid)))
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   /*
+    *  We are dealing with an ASF file
+    */
+
+   /* Allocate our context */
+   module = malloc(sizeof(*module));
+   if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(module, 0, sizeof(*module));
+
+   /* Set the translation table to all error values */
+   memset(&module->stream_number_to_index, 0xff, sizeof(module->stream_number_to_index));
+   p_ctx->priv->module = module;
+   p_ctx->tracks = module->tracks;
+
+   /* Read the top level header object */
+   status = asf_read_object(p_ctx, INT64_C(0));
+   if(status != VC_CONTAINER_SUCCESS)
+      goto error;
+
+   /* Bail out if we didn't find a track */
+   if(!p_ctx->tracks_num) {status = VC_CONTAINER_ERROR_NO_TRACK_AVAILABLE; goto error;}
+
+   /*
+    *  The top level data object must come next
+    */
+   if(READ_GUID(p_ctx, &guid, "Object ID") != sizeof(guid) ||
+      memcmp(&guid, &asf_guid_data, sizeof(guid)))
+      goto error;
+
+   LOG_FORMAT(p_ctx, "Object Name: data");
+   module->data_size = READ_U64(p_ctx, "Object Size");
+
+   /* If the data size was supplied remove the size of the common object header and the local header for this object */
+   if(module->data_size) module->data_size -= ASF_OBJECT_HEADER_SIZE + 16 + 8 + 2;
+
+   /* Sanity check the data object size */
+   if(module->data_size < 0)
+      goto error;
+
+   module->object_level++;
+   SKIP_GUID(p_ctx, "File ID");
+   module->packets_num = READ_U64(p_ctx, "Total Data Packets");
+   if(module->broadcast) module->packets_num = 0;
+   SKIP_U16(p_ctx, "Reserved");
+
+   if (module->packet_size)
+   {
+      LOG_DEBUG(p_ctx, "object size %"PRIu64" means %f packets",
+         module->data_size, (float)(module->data_size) / (float)(module->packet_size));
+   }
+
+   module->data_offset = STREAM_POSITION(p_ctx);
+   LOG_DEBUG(p_ctx, "expect end of data at address %"PRIu64, module->data_size + module->data_offset);
+
+   module->object_level--;
+
+   /*
+    *  We now have all the information we really need to start playing the stream
+    */
+
+   /* Initialise state for all tracks */
+   module->packet_state.start = module->data_offset;
+   for(i = 0; i < p_ctx->tracks_num; i++)
+   {
+      VC_CONTAINER_TRACK_T *p_track = p_ctx->tracks[i];
+      p_track->priv->module->p_packet_state = &module->packet_state;
+   }
+
+   p_ctx->priv->pf_close = asf_reader_close;
+   p_ctx->priv->pf_read = asf_reader_read;
+   p_ctx->priv->pf_seek = asf_reader_seek;
+
+   if(STREAM_SEEKABLE(p_ctx))
+   {
+      p_ctx->capabilities |= VC_CONTAINER_CAPS_CAN_SEEK;
+      p_ctx->capabilities |= VC_CONTAINER_CAPS_FORCE_TRACK;
+   }
+
+   p_ctx->duration = module->duration;
+
+   /* Check if we're done */
+   if(!module->data_size || !STREAM_SEEKABLE(p_ctx))
+      return VC_CONTAINER_SUCCESS;
+
+   /* If the stream is seekable and not a broadcast stream, we want to use any index there
+    * might be at the end of the stream */
+
+   /* Seek back to the end of the data object */
+   if( SEEK(p_ctx, module->data_offset + module->data_size) == VC_CONTAINER_SUCCESS)
+   {
+      /* This will catch the simple index object if it is there */
+      do {
+         status = asf_read_object(p_ctx, INT64_C(0));
+      } while(status == VC_CONTAINER_SUCCESS);
+   }
+
+   for(i = 0; i < p_ctx->tracks_num; i++)
+   {
+      if(p_ctx->tracks[i]->priv->module->simple_index.offset)
+         LOG_DEBUG(p_ctx, "track %i has an index", i);
+   }
+
+   /* Seek back to the start of the data */
+   return SEEK(p_ctx, module->data_offset);
+
+ error:
+   if(status == VC_CONTAINER_SUCCESS) status = VC_CONTAINER_ERROR_FORMAT_INVALID;
+   LOG_DEBUG(p_ctx, "asf: error opening stream (%i)", status);
+   if(module) asf_reader_close(p_ctx);
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+ ********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak reader_open asf_reader_open
+#endif
diff --git a/containers/asf/asf_writer.c b/containers/asf/asf_writer.c
new file mode 100755 (executable)
index 0000000..60da7ce
--- /dev/null
@@ -0,0 +1,577 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <string.h>
+
+//#define ENABLE_CONTAINERS_LOG_FORMAT
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_writer_utils.h"
+#include "containers/core/containers_logging.h"
+#undef CONTAINER_HELPER_LOG_INDENT
+#define CONTAINER_HELPER_LOG_INDENT(a) (a)->priv->module->object_level
+
+VC_CONTAINER_STATUS_T asf_writer_open( VC_CONTAINER_T *p_ctx );
+
+/******************************************************************************
+Defines.
+******************************************************************************/
+#define ASF_TRACKS_MAX 16
+#define ASF_OBJECT_HEADER_SIZE (16+8)
+
+/******************************************************************************
+Type definitions.
+******************************************************************************/
+typedef enum {
+   ASF_OBJECT_TYPE_UNKNOWN = 0,
+   ASF_OBJECT_TYPE_HEADER,
+   ASF_OBJECT_TYPE_FILE_PROPS,
+   ASF_OBJECT_TYPE_STREAM_PROPS,
+   ASF_OBJECT_TYPE_EXT_STREAM_PROPS,
+   ASF_OBJECT_TYPE_DATA,
+   ASF_OBJECT_TYPE_SIMPLE_INDEX,
+   ASF_OBJECT_TYPE_INDEX,
+   ASF_OBJECT_TYPE_HEADER_EXT,
+   ASF_OBJECT_TYPE_HEADER_EXT_INTERNAL,
+   ASF_OBJECT_TYPE_CODEC_LIST,
+   ASF_OBJECT_TYPE_CONTENT_DESCRIPTION,
+   ASF_OBJECT_TYPE_EXT_CONTENT_DESCRIPTION,
+   ASF_OBJECT_TYPE_STREAM_BITRATE_PROPS,
+   ASF_OBJECT_TYPE_LANGUAGE_LIST,
+   ASF_OBJECT_TYPE_METADATA,
+   ASF_OBJECT_TYPE_PADDING,
+} ASF_OBJECT_TYPE_T;
+
+typedef struct VC_CONTAINER_TRACK_MODULE_T
+{
+   unsigned int stream_id;
+   uint64_t time_offset;
+   bool b_valid;
+
+   uint64_t index_offset;
+   uint32_t num_index_entries;
+   int64_t  index_time_interval;
+} VC_CONTAINER_TRACK_MODULE_T;
+
+typedef struct VC_CONTAINER_MODULE_T
+{
+   int object_level;
+   uint32_t packet_size;
+
+   VC_CONTAINER_TRACK_T *tracks[ASF_TRACKS_MAX];
+
+   VC_CONTAINER_WRITER_EXTRAIO_T null;
+   bool b_header_done;
+
+   unsigned int current_track;
+
+} VC_CONTAINER_MODULE_T;
+
+/******************************************************************************
+Static functions within this file.
+******************************************************************************/
+static VC_CONTAINER_STATUS_T asf_write_object( VC_CONTAINER_T *p_ctx, ASF_OBJECT_TYPE_T object_type );
+static VC_CONTAINER_STATUS_T asf_write_object_header( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T asf_write_object_header_ext( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T asf_write_object_header_ext_internal( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T asf_write_object_file_properties( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T asf_write_object_stream_properties( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T asf_write_object_ext_stream_properties( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T asf_write_object_simple_index( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T asf_write_object_index( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T asf_write_object_data( VC_CONTAINER_T *p_ctx );
+#if 0
+static VC_CONTAINER_STATUS_T asf_write_object_codec_list( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T asf_write_object_content_description( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T asf_write_object_stream_bitrate_props( VC_CONTAINER_T *p_ctx );
+#endif
+
+static const GUID_T asf_guid_header = {0x75B22630, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
+static const GUID_T asf_guid_file_props = {0x8CABDCA1, 0xA947, 0x11CF, {0x8E, 0xE4, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
+static const GUID_T asf_guid_stream_props = {0xB7DC0791, 0xA9B7, 0x11CF, {0x8E, 0xE6, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
+static const GUID_T asf_guid_ext_stream_props = {0x14E6A5CB, 0xC672, 0x4332, {0x83, 0x99, 0xA9, 0x69, 0x52, 0x06, 0x5B, 0x5A}};
+static const GUID_T asf_guid_data = {0x75B22636, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
+static const GUID_T asf_guid_simple_index = {0x33000890, 0xE5B1, 0x11CF, {0x89, 0xF4, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xCB}};
+static const GUID_T asf_guid_index = {0xD6E229D3, 0x35DA, 0x11D1, {0x90, 0x34, 0x00, 0xA0, 0xC9, 0x03, 0x49, 0xBE}};
+static const GUID_T asf_guid_header_ext = {0x5FBF03B5, 0xA92E, 0x11CF, {0x8E, 0xE3, 0x00, 0xC0, 0x0C, 0x20, 0x53, 0x65}};
+static const GUID_T asf_guid_codec_list = {0x86D15240, 0x311D, 0x11D0, {0xA3, 0xA4, 0x00, 0xA0, 0xC9, 0x03, 0x48, 0xF6}};
+static const GUID_T asf_guid_content_description = {0x75B22633, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
+static const GUID_T asf_guid_ext_content_description = {0xD2D0A440, 0xE307, 0x11D2, {0x97, 0xF0, 0x00, 0xA0, 0xC9, 0x5E, 0xA8, 0x50}};
+static const GUID_T asf_guid_stream_bitrate_props = {0x7BF875CE, 0x468D, 0x11D1, {0x8D, 0x82, 0x00, 0x60, 0x97, 0xC9, 0xA2, 0xB2}};
+static const GUID_T asf_guid_language_list = {0x7C4346A9, 0xEFE0, 0x4BFC, {0xB2, 0x29, 0x39, 0x3E, 0xDE, 0x41, 0x5C, 0x85}};
+static const GUID_T asf_guid_metadata = {0xC5F8CBEA, 0x5BAF, 0x4877, {0x84, 0x67, 0xAA, 0x8C, 0x44, 0xFA, 0x4C, 0xCA}};
+static const GUID_T asf_guid_padding = {0x1806D474, 0xCADF, 0x4509, {0xA4, 0xBA, 0x9A, 0xAB, 0xCB, 0x96, 0xAA, 0xE8}};
+
+static const GUID_T asf_guid_stream_type_video = {0xBC19EFC0, 0x5B4D, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}};
+static const GUID_T asf_guid_stream_type_audio = {0xF8699E40, 0x5B4D, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}};
+static const GUID_T asf_guid_error_correction = {0x20FB5700, 0x5B55, 0x11CF, {0xA8, 0xFD, 0x00, 0x80, 0x5F, 0x5C, 0x44, 0x2B}};
+
+static struct {
+  const ASF_OBJECT_TYPE_T type;
+  const GUID_T *guid;
+  const char *psz_name;
+  VC_CONTAINER_STATUS_T (*pf_func)( VC_CONTAINER_T * );
+
+} asf_object_list[] =
+{
+   {ASF_OBJECT_TYPE_HEADER, &asf_guid_header, "header", asf_write_object_header},
+   {ASF_OBJECT_TYPE_FILE_PROPS, &asf_guid_file_props, "file properties", asf_write_object_file_properties},
+   {ASF_OBJECT_TYPE_STREAM_PROPS, &asf_guid_stream_props, "stream properties", asf_write_object_stream_properties},
+   {ASF_OBJECT_TYPE_EXT_STREAM_PROPS, &asf_guid_ext_stream_props, "extended stream properties", asf_write_object_ext_stream_properties},
+   {ASF_OBJECT_TYPE_DATA, &asf_guid_data, "data", asf_write_object_data},
+   {ASF_OBJECT_TYPE_SIMPLE_INDEX, &asf_guid_simple_index, "simple index", asf_write_object_simple_index},
+   {ASF_OBJECT_TYPE_INDEX, &asf_guid_index, "index", asf_write_object_index},
+   {ASF_OBJECT_TYPE_HEADER_EXT, &asf_guid_header_ext, "header extension", asf_write_object_header_ext},
+   {ASF_OBJECT_TYPE_HEADER_EXT_INTERNAL, &asf_guid_header_ext, "header extension", asf_write_object_header_ext_internal},
+#if 0
+   {ASF_OBJECT_TYPE_CODEC_LIST, &asf_guid_codec_list, "codec list", asf_write_object_codec_list},
+   {ASF_OBJECT_TYPE_CONTENT_DESCRIPTION, &asf_guid_content_description, "content description", asf_write_object_content_description},
+   {ASF_OBJECT_TYPE_EXT_CONTENT_DESCRIPTION, &asf_guid_ext_content_description, "extended content description", 0},
+   {ASF_OBJECT_TYPE_STREAM_BITRATE_PROPS, &asf_guid_stream_bitrate_props, "stream bitrate properties", asf_write_object_stream_bitrate_props},
+#endif
+   {ASF_OBJECT_TYPE_UNKNOWN, 0, "unknown", 0}
+};
+
+static GUID_T guid_null;
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T asf_write_object( VC_CONTAINER_T *p_ctx, ASF_OBJECT_TYPE_T type )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   int64_t object_size = 0;
+   unsigned int i;
+
+   /* Find out which object we want to write */
+   for( i = 0; asf_object_list[i].type && asf_object_list[i].type != type; i++ );
+
+   /* Check we found the requested type */
+   if(!asf_object_list[i].type)
+   {
+      vc_container_assert(0);
+      return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+
+   /* We need to find out the size of the object we're going to write.
+    * Because we want to be streamable, we can't just come back later to update the size field.
+    * The easiest way to find out the size of the data we're going to write is to write a dummy
+    * version of it and get the size from that. It is a bit wasteful but is so much easier and
+    * shouldn't really impact performance as there's no actual i/o involved. */
+   if(!vc_container_writer_extraio_enable(p_ctx, &module->null))
+   {
+      asf_object_list[i].pf_func(p_ctx);
+      object_size = STREAM_POSITION(p_ctx);
+   }
+   vc_container_writer_extraio_disable(p_ctx, &module->null);
+
+   /* Special case for header extension internal function */
+   if(type == ASF_OBJECT_TYPE_HEADER_EXT_INTERNAL)
+   {
+      WRITE_U32(p_ctx, object_size, "Header Extension Data Size");
+      /* Call the object specific writing function */
+      status  = asf_object_list[i].pf_func(p_ctx);
+      return status;
+   }
+
+   /* Write the object header */
+
+   if(WRITE_GUID(p_ctx, asf_object_list[i].guid, "Object ID") != sizeof(GUID_T))
+      return VC_CONTAINER_ERROR_EOS;
+
+   LOG_FORMAT(p_ctx, "Object Name: %s", asf_object_list[i].psz_name);
+
+   WRITE_U64(p_ctx, object_size + ASF_OBJECT_HEADER_SIZE, "Object Size");
+
+   module->object_level++;
+
+   /* Call the object specific writing function */
+   status  = asf_object_list[i].pf_func(p_ctx);
+
+   module->object_level--;
+
+   if(status != VC_CONTAINER_SUCCESS)
+      LOG_DEBUG(p_ctx, "object %s appears to be corrupted", asf_object_list[i].psz_name);
+
+   return status;
+}
+
+static VC_CONTAINER_STATUS_T asf_write_object_header( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+
+   WRITE_U32(p_ctx, 0, "Number of Header Objects"); /* FIXME: could use that */
+   WRITE_U8(p_ctx, 0, "Reserved1");
+   WRITE_U8(p_ctx, 0, "Reserved2");
+
+   status = asf_write_object(p_ctx, ASF_OBJECT_TYPE_FILE_PROPS);
+   status = asf_write_object(p_ctx, ASF_OBJECT_TYPE_HEADER_EXT);
+
+   for(module->current_track = 0; module->current_track < p_ctx->tracks_num;
+       module->current_track++)
+   {
+      status = asf_write_object(p_ctx, ASF_OBJECT_TYPE_STREAM_PROPS);
+   }
+
+   /* Codec List */
+   /* Content Description */
+   /* Stream Bitrate Properties */
+
+   return status;
+}
+
+static VC_CONTAINER_STATUS_T asf_write_object_header_ext( VC_CONTAINER_T *p_ctx )
+{
+   WRITE_GUID(p_ctx, &guid_null, "Reserved Field 1");
+   WRITE_U16(p_ctx, 0, "Reserved Field 2");
+
+   return asf_write_object(p_ctx, ASF_OBJECT_TYPE_HEADER_EXT_INTERNAL);
+}
+
+static VC_CONTAINER_STATUS_T asf_write_object_header_ext_internal( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+
+   for(module->current_track = 0; module->current_track < p_ctx->tracks_num;
+       module->current_track++)
+   {
+      status = asf_write_object(p_ctx, ASF_OBJECT_TYPE_EXT_STREAM_PROPS);
+   }
+
+   return status;
+}
+
+static VC_CONTAINER_STATUS_T asf_write_object_file_properties( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+
+   WRITE_GUID(p_ctx, &guid_null, "File ID");
+   WRITE_U64(p_ctx, 0, "File Size");
+   WRITE_U64(p_ctx, 0, "Creation Date");
+   WRITE_U64(p_ctx, 0, "Data Packets Count");
+   WRITE_U64(p_ctx, 0, "Play Duration");
+   WRITE_U64(p_ctx, 0, "Send Duration");
+   WRITE_U64(p_ctx, 0, "Preroll");
+   WRITE_U32(p_ctx, 0, "Flags");
+   WRITE_U32(p_ctx, module->packet_size, "Minimum Data Packet Size");
+   WRITE_U32(p_ctx, module->packet_size, "Maximum Data Packet Size");
+   WRITE_U32(p_ctx, 0, "Maximum Bitrate");
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+static VC_CONTAINER_STATUS_T asf_write_bitmapinfoheader( VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_TRACK_T *p_track )
+{
+   uint32_t fourcc;
+
+   /* Write the preamble to the BITMAPINFOHEADER */
+   WRITE_U32(p_ctx, p_track->format->type->video.width, "Encoded Image Width");
+   WRITE_U32(p_ctx, p_track->format->type->video.height, "Encoded Image Height");
+   WRITE_U8(p_ctx, 0, "Reserved Flags");
+   WRITE_U16(p_ctx, 40 + p_track->format->extradata_size, "Format Data Size");
+
+   /* Write BITMAPINFOHEADER structure */
+   WRITE_U32(p_ctx, 40 + p_track->format->extradata_size, "Format Data Size");
+   WRITE_U32(p_ctx, p_track->format->type->video.width, "Image Width");
+   WRITE_U32(p_ctx, p_track->format->type->video.height, "Image Height");
+   WRITE_U16(p_ctx, 0, "Reserved");
+   WRITE_U16(p_ctx, 0, "Bits Per Pixel Count");
+   fourcc = codec_to_fourcc(p_track->format->codec);
+   WRITE_BYTES(p_ctx, (char *)&fourcc, 4); /* Compression ID */
+   LOG_FORMAT(p_ctx, "Compression ID: %4.4s", (char *)&fourcc);
+   WRITE_U32(p_ctx, 0, "Image Size");
+   WRITE_U32(p_ctx, 0, "Horizontal Pixels Per Meter");
+   WRITE_U32(p_ctx, 0, "Vertical Pixels Per Meter");
+   WRITE_U32(p_ctx, 0, "Colors Used Count");
+   WRITE_U32(p_ctx, 0, "Important Colors Count");
+
+   WRITE_BYTES(p_ctx, p_track->format->extradata, p_track->format->extradata_size);
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+static VC_CONTAINER_STATUS_T asf_write_waveformatex( VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_TRACK_T *p_track)
+{
+   /* Write WAVEFORMATEX structure */
+   WRITE_U16(p_ctx, codec_to_waveformat(p_track->format->codec), "Codec ID");
+   WRITE_U16(p_ctx, p_track->format->type->audio.channels, "Number of Channels");
+   WRITE_U32(p_ctx, p_track->format->type->audio.sample_rate, "Samples per Second");
+   WRITE_U32(p_ctx, p_track->format->bitrate, "Average Number of Bytes Per Second");
+   WRITE_U16(p_ctx, p_track->format->type->audio.block_align, "Block Alignment");
+   WRITE_U16(p_ctx, p_track->format->type->audio.bits_per_sample, "Bits Per Sample");
+   WRITE_U16(p_ctx, p_track->format->extradata_size, "Codec Specific Data Size");
+   WRITE_BYTES(p_ctx, p_track->format->extradata, p_track->format->extradata_size);
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+static VC_CONTAINER_STATUS_T asf_write_object_stream_properties( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   unsigned int track = module->current_track, ts_size = 0;
+   const GUID_T *p_guid = &guid_null;
+
+   if(p_ctx->tracks[track]->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO)
+   {
+      p_guid = &asf_guid_stream_type_video;
+      ts_size = 11 + 40 + p_ctx->tracks[track]->format->extradata_size;
+   }
+   else if(p_ctx->tracks[track]->format->es_type == VC_CONTAINER_ES_TYPE_AUDIO)
+   {
+      p_guid = &asf_guid_stream_type_audio;
+      ts_size = 18 + p_ctx->tracks[track]->format->extradata_size;
+   }
+
+   WRITE_GUID(p_ctx, p_guid, "Stream Type");
+   WRITE_GUID(p_ctx, &asf_guid_error_correction, "Error Correction Type");
+   WRITE_U64(p_ctx, 0, "Time Offset");
+   WRITE_U32(p_ctx, ts_size, "Type-Specific Data Length");
+   WRITE_U32(p_ctx, 0, "Error Correction Data Length");
+   WRITE_U16(p_ctx, track + 1, "Flags");
+   WRITE_U32(p_ctx, 0, "Reserved");
+
+   /* Type-Specific Data */
+   if(ts_size)
+   {
+      if(p_ctx->tracks[track]->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO)
+         status = asf_write_bitmapinfoheader( p_ctx, p_ctx->tracks[track]);
+      else if(p_ctx->tracks[track]->format->es_type == VC_CONTAINER_ES_TYPE_AUDIO)
+         status = asf_write_waveformatex( p_ctx, p_ctx->tracks[track]);
+   }
+
+   /* Error Correction Data */
+
+   return status;
+}
+
+static VC_CONTAINER_STATUS_T asf_write_object_ext_stream_properties( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+
+   WRITE_U64(p_ctx, 0, "Start Time");
+   WRITE_U64(p_ctx, 0, "End Time");
+   WRITE_U32(p_ctx, 0, "Data Bitrate");
+   WRITE_U32(p_ctx, 0, "Buffer Size");
+   WRITE_U32(p_ctx, 0, "Initial Buffer Fullness");
+   WRITE_U32(p_ctx, 0, "Alternate Data Bitrate");
+   WRITE_U32(p_ctx, 0, "Alternate Buffer Size");
+   WRITE_U32(p_ctx, 0, "Alternate Initial Buffer Fullness");
+   WRITE_U32(p_ctx, 0, "Maximum Object Size");
+   WRITE_U32(p_ctx, 0, "Flags");
+   WRITE_U16(p_ctx, module->current_track + 1, "Stream Number");
+   WRITE_U16(p_ctx, 0, "Stream Language ID Index");
+   WRITE_U64(p_ctx, 0, "Average Time Per Frame");
+   WRITE_U16(p_ctx, 0, "Stream Name Count");
+   WRITE_U16(p_ctx, 0, "Payload Extension System Count");
+   /* Stream Names */
+   /* Payload Extension Systems */
+   /* Stream Properties Object */
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+static VC_CONTAINER_STATUS_T asf_write_object_index( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+   return VC_CONTAINER_SUCCESS;
+}
+
+static VC_CONTAINER_STATUS_T asf_write_object_simple_index( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+   return VC_CONTAINER_SUCCESS;
+}
+
+static VC_CONTAINER_STATUS_T asf_write_object_data( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T asf_write_header( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_STATUS_T status;
+
+   /* TODO Sanity check the tracks */
+
+   status = asf_write_object(p_ctx, ASF_OBJECT_TYPE_HEADER);
+   status = asf_write_object(p_ctx, ASF_OBJECT_TYPE_DATA);
+
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T asf_writer_write( VC_CONTAINER_T *p_ctx,
+                                               VC_CONTAINER_PACKET_T *p_packet )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_PARAM_UNUSED(p_packet);
+
+   if(!module->b_header_done)
+   {
+      module->b_header_done = true;
+      status = asf_write_header(p_ctx);
+   }
+
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T asf_writer_close( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+
+   for(; p_ctx->tracks_num > 0; p_ctx->tracks_num--)
+      vc_container_free_track(p_ctx, p_ctx->tracks[p_ctx->tracks_num-1]);
+
+   vc_container_writer_extraio_delete(p_ctx, &module->null);
+   free(module);
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T asf_writer_add_track( VC_CONTAINER_T *p_ctx, VC_CONTAINER_ES_FORMAT_T *format )
+{
+   VC_CONTAINER_STATUS_T status;
+   VC_CONTAINER_TRACK_T *track;
+
+   /* TODO check we support this format */
+
+   if(!(format->flags & VC_CONTAINER_ES_FORMAT_FLAG_FRAMED))
+      return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+   
+   /* Allocate and initialise track data */
+   if(p_ctx->tracks_num >= ASF_TRACKS_MAX) return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+   p_ctx->tracks[p_ctx->tracks_num] = track =
+      vc_container_allocate_track(p_ctx, sizeof(*p_ctx->tracks[0]->priv->module));
+   if(!track) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+
+   if(format->extradata_size)
+   {
+      status = vc_container_track_allocate_extradata( p_ctx, track, format->extradata_size );
+      if(status) goto error;
+   }
+
+   vc_container_format_copy(track->format, format, format->extradata_size);
+   p_ctx->tracks_num++;
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+   vc_container_free_track(p_ctx, track);
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T asf_writer_control( VC_CONTAINER_T *p_ctx, VC_CONTAINER_CONTROL_T operation, va_list args )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status;
+
+   switch(operation)
+   {
+   case VC_CONTAINER_CONTROL_TRACK_ADD:
+      {
+         VC_CONTAINER_ES_FORMAT_T *p_format =
+            (VC_CONTAINER_ES_FORMAT_T *)va_arg( args, VC_CONTAINER_ES_FORMAT_T * );
+         return asf_writer_add_track(p_ctx, p_format);
+      }
+
+   case VC_CONTAINER_CONTROL_TRACK_ADD_DONE:
+      if(!module->b_header_done)
+      {
+         status = asf_write_header(p_ctx);
+         if(status != VC_CONTAINER_SUCCESS) return status;
+         module->b_header_done = true;
+      }
+      return VC_CONTAINER_SUCCESS;
+
+   default: return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+   }
+}
+
+/******************************************************************************
+Global function definitions.
+******************************************************************************/
+
+VC_CONTAINER_STATUS_T asf_writer_open( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   const char *extension = vc_uri_path_extension(p_ctx->priv->uri);
+   VC_CONTAINER_MODULE_T *module = 0;
+   unsigned int i;
+
+   /* Check if the user has specified a container */
+   vc_uri_find_query(p_ctx->priv->uri, 0, "container", &extension);
+
+   /* Check we're the right writer for this */
+   if(!extension)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   if(strcasecmp(extension, "asf") && strcasecmp(extension, "wmv") &&
+      strcasecmp(extension, "wma"))
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   /* Allocate our context */
+   module = malloc(sizeof(*module));
+   if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(module, 0, sizeof(*module));
+   p_ctx->priv->module = module;
+   p_ctx->tracks = module->tracks;
+
+   /* Create a null i/o writer to help us out in writing our data */
+   status = vc_container_writer_extraio_create_null(p_ctx, &module->null);
+   if(status != VC_CONTAINER_SUCCESS) goto error;
+
+   /* We'll only write the header once we've got all our tracks */
+
+   p_ctx->priv->pf_close = asf_writer_close;
+   p_ctx->priv->pf_write = asf_writer_write;
+   p_ctx->priv->pf_control = asf_writer_control;
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+   LOG_DEBUG(p_ctx, "asf: error opening stream");
+   for(i = 0; i < ASF_TRACKS_MAX && p_ctx->tracks && p_ctx->tracks[i]; i++)
+      vc_container_free_track(p_ctx, p_ctx->tracks[i]);
+   free(module);
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+ ********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak writer_open asf_writer_open
+#endif
diff --git a/containers/avi/CMakeLists.txt b/containers/avi/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..f8589c1
--- /dev/null
@@ -0,0 +1,19 @@
+# Container module needs to go in as a plugins so different prefix
+# and install path
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+
+# Make sure the compiler can find the necessary include files
+include_directories (../..)
+
+add_library(reader_avi ${LIBRARY_TYPE} avi_reader.c)
+
+target_link_libraries(reader_avi containers)
+
+install(TARGETS reader_avi DESTINATION ${VMCS_PLUGIN_DIR})
+
+add_library(writer_avi ${LIBRARY_TYPE} avi_writer.c)
+
+target_link_libraries(writer_avi containers)
+
+install(TARGETS writer_avi DESTINATION ${VMCS_PLUGIN_DIR})
+
diff --git a/containers/avi/avi_reader.c b/containers/avi/avi_reader.c
new file mode 100755 (executable)
index 0000000..4c4c3f4
--- /dev/null
@@ -0,0 +1,1521 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <string.h>
+
+#define CONTAINER_IS_LITTLE_ENDIAN
+//#define ENABLE_CONTAINERS_LOG_FORMAT
+//#define ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
+#define CONTAINER_HELPER_LOG_INDENT(a) 0
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_logging.h"
+#include "containers/core/containers_waveformat.h"
+
+/******************************************************************************
+Defines.
+******************************************************************************/
+#define AVISF_DISABLED        0x00000001 /*< If set stream should not be enabled by default. */
+#define AVIF_MUSTUSEINDEX     0x00000020
+#define AVIF_TRUSTCKTYPE      0x00000800 /*< (OpenDML) keyframe information reliable. */
+
+#define AVIIF_LIST            0x00000001
+#define AVIIF_KEYFRAME        0x00000010
+#define AVIIF_NOTIME          0x00000100
+
+#define AVI_INDEX_OF_INDEXES  0x00
+#define AVI_INDEX_OF_CHUNKS   0x01
+#define AVI_INDEX_2FIELD      0x01
+#define AVI_INDEX_DELTAFRAME  0x80000000
+#define AVI_TRACKS_MAX 16 /*< We won't try to handle streams with more tracks than this */
+
+#define AVI_TWOCC(a,b) ((a) | (b << 8))
+
+#define AVI_SYNC_CHUNK(ctx)                               \
+      while(STREAM_POSITION(ctx) & 1)                     \
+      {                                                   \
+         if (SKIP_BYTES(ctx, 1) != 1) break;              \
+      }
+
+#define AVI_SKIP_CHUNK(ctx, size)                         \
+   do {                                                   \
+      SKIP_BYTES(ctx, size);                              \
+      AVI_SYNC_CHUNK(ctx);                                \
+   } while(0)
+      
+/******************************************************************************
+Type definitions
+******************************************************************************/
+typedef struct AVI_TRACK_STREAM_STATE_T
+{
+   unsigned current_track_num;     /**< Number of track currently being read */
+   int64_t data_offset;            /**< Offset within the stream to find the track data */
+   uint32_t chunk_size;            /**< Size of the current chunk being read */
+   uint32_t chunk_data_left;       /**< Data left from the current chunk being read */
+
+   unsigned extra_chunk_track_num; /**< Temporary storage for in-band data e.g. 'dd'
+                                        chunks */
+   uint32_t extra_chunk_data[4];
+   uint32_t extra_chunk_data_offs;
+   uint32_t extra_chunk_data_len;
+} AVI_TRACK_STREAM_STATE_T;
+
+typedef struct AVI_TRACK_CHUNK_STATE_T
+{
+   uint64_t index;
+   uint64_t offs;        /**< offset into bytestream consisting of all chunks for this track  */
+   int64_t  time_pos;    /**< pts of chunk (if known) */
+   uint32_t flags;       /**< flags associated with chunk */
+   AVI_TRACK_STREAM_STATE_T local_state;
+   AVI_TRACK_STREAM_STATE_T *state;
+} AVI_TRACK_CHUNK_STATE_T;
+
+typedef struct VC_CONTAINER_TRACK_MODULE_T
+{
+   int64_t  time_start;    /**< i.e. 'dwStart' in 'strh' (converted to microseconds) */
+   int64_t  duration;      /**< i.e. 'dwLength' in 'strh' (converted to microseconds) */
+   uint32_t time_num;      /**< i.e. 'dwScale' in 'strh' */
+   uint32_t time_den;      /**< i.e. 'dwRate' in 'strh', time_num / time_den = 
+                                samples (or frames) / second for audio (or video) */
+   uint32_t sample_size;   /**< i.e. 'dwSampleSize' in 'strh' */
+
+   uint64_t index_offset;  /**< Offset to the start of an OpenDML index i.e. 'indx' 
+                                (if available) */
+   uint32_t index_size;    /**< Size of the OpenDML index chunk */
+   AVI_TRACK_CHUNK_STATE_T chunk;
+} VC_CONTAINER_TRACK_MODULE_T;
+
+typedef struct VC_CONTAINER_MODULE_T
+{ 
+   VC_CONTAINER_TRACK_T *tracks[AVI_TRACKS_MAX];
+   uint64_t data_offset;           /**< Offset to the start of data packets i.e. 
+                                        the data in the 'movi' list */
+   uint64_t data_size;             /**< Size of the chunk containing data packets */
+   uint64_t index_offset;          /**< Offset to the start of index data e.g. 
+                                        the data in a 'idx1' list */
+   uint32_t index_size;            /**< Size of the chunk containing index data */
+   AVI_TRACK_STREAM_STATE_T state;
+} VC_CONTAINER_MODULE_T;
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+VC_CONTAINER_STATUS_T avi_reader_open( VC_CONTAINER_T * );
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+
+static VC_CONTAINER_STATUS_T avi_find_chunk(VC_CONTAINER_T *p_ctx, VC_CONTAINER_FOURCC_T id, uint32_t *size)
+{
+   VC_CONTAINER_STATUS_T status;
+   VC_CONTAINER_FOURCC_T chunk_id;
+   uint32_t chunk_size;
+
+   do {
+      chunk_id = READ_FOURCC(p_ctx, "Chunk ID");
+      chunk_size = READ_U32(p_ctx, "Chunk size");
+      if((status = STREAM_STATUS(p_ctx)) != VC_CONTAINER_SUCCESS) return status;
+
+      if(chunk_id == id) 
+      {
+         *size = chunk_size;
+         return VC_CONTAINER_SUCCESS;
+      }
+      /* Not interested in this chunk, skip it. */
+      AVI_SKIP_CHUNK(p_ctx, chunk_size);
+   } while((status = STREAM_STATUS(p_ctx)) == VC_CONTAINER_SUCCESS);
+
+   return status; /* chunk not found */
+}
+
+static VC_CONTAINER_STATUS_T avi_find_list(VC_CONTAINER_T *p_ctx, VC_CONTAINER_FOURCC_T fourcc, uint32_t *size)
+{
+   VC_CONTAINER_STATUS_T status;
+   VC_CONTAINER_FOURCC_T chunk_id;
+   uint32_t chunk_size;
+   uint32_t peek_buf[1];
+   
+   do {
+      chunk_id = READ_FOURCC(p_ctx, "Chunk ID");
+      chunk_size = READ_U32(p_ctx, "Chunk size");
+      if((status = STREAM_STATUS(p_ctx)) != VC_CONTAINER_SUCCESS) return status;
+
+      if(chunk_id == VC_FOURCC('L','I','S','T')) 
+      {
+         if (PEEK_BYTES(p_ctx, (uint8_t*)peek_buf, 4) != 4)
+            return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+         if (peek_buf[0] == fourcc)
+         {
+            *size = chunk_size;
+            return VC_CONTAINER_SUCCESS;
+         }
+      }
+      /* Not interested in this chunk, skip it. */
+      AVI_SKIP_CHUNK(p_ctx, chunk_size);
+   } while((status = STREAM_STATUS(p_ctx)) == VC_CONTAINER_SUCCESS);
+
+   return status; /* list not found */
+}
+
+static int64_t avi_stream_ticks_to_us(VC_CONTAINER_TRACK_MODULE_T *track_module, uint64_t ticks)
+{
+   int64_t time;
+   vc_container_assert(track_module->time_den != 0);
+   time = INT64_C(1000000) * track_module->time_num * ticks / track_module->time_den;
+   return time;
+}
+
+static int64_t avi_calculate_chunk_time(VC_CONTAINER_TRACK_MODULE_T *track_module)
+{
+   if (track_module->sample_size == 0)
+      return track_module->time_start + avi_stream_ticks_to_us(track_module, track_module->chunk.index);
+   else
+      return track_module->time_start + avi_stream_ticks_to_us(track_module, 
+         ((track_module->chunk.offs + (track_module->sample_size >> 1)) / track_module->sample_size));
+}
+
+static VC_CONTAINER_STATUS_T avi_read_stream_header_list(VC_CONTAINER_T *p_ctx, VC_CONTAINER_TRACK_T *track,
+                                                         VC_CONTAINER_TRACK_MODULE_T *track_module)
+{
+   VC_CONTAINER_STATUS_T status;
+   int64_t list_offset;
+   uint32_t list_size, chunk_id, chunk_size;
+
+   int stream_header_chunk_read = 0, stream_format_chunk_read = 0;
+   
+   /* Look for a 'strl' LIST (sub)chunk */   
+   status = avi_find_list(p_ctx, VC_FOURCC('s','t','r','l'), &chunk_size);
+   if (status != VC_CONTAINER_SUCCESS)
+   {
+      LOG_DEBUG(p_ctx, "'strl' LIST not found for stream");
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+
+   list_offset = STREAM_POSITION(p_ctx);
+   list_size = chunk_size;
+   SKIP_FOURCC(p_ctx, "strl");
+
+   while((status = STREAM_STATUS(p_ctx)) == VC_CONTAINER_SUCCESS && STREAM_POSITION(p_ctx) < list_offset + list_size)
+   {
+      int64_t offset = STREAM_POSITION(p_ctx);
+      chunk_id = READ_FOURCC(p_ctx, "Chunk ID");
+      chunk_size = READ_U32(p_ctx, "Chunk size");
+      LOG_FORMAT(p_ctx, "chunk %4.4s, offset: %"PRIi64", size: %i", (char *)&chunk_id, offset, chunk_size);
+
+      if((status = STREAM_STATUS(p_ctx)) != VC_CONTAINER_SUCCESS) return status;
+
+      if(chunk_id == VC_FOURCC('s','t','r','h'))
+      {
+         VC_CONTAINER_FOURCC_T fourcc_type, fourcc_handler;
+         uint32_t flags, scale, rate, div, start, length, sample_size;
+         
+         /* We won't accept more than one 'strh' per stream */
+         if (stream_header_chunk_read)
+         {
+            LOG_DEBUG(p_ctx, "rejecting invalid 'strl', found more than one 'strh'");
+            return VC_CONTAINER_ERROR_FORMAT_INVALID;
+         }
+         
+         fourcc_type = READ_FOURCC(p_ctx, "fccType");
+         fourcc_handler = READ_FOURCC(p_ctx, "fccHandler");
+         flags = READ_U32(p_ctx, "dwFlags");
+         SKIP_U16(p_ctx, "wPriority");
+         SKIP_U16(p_ctx, "wLanguage");
+         SKIP_U32(p_ctx, "dwInitialFrames");
+         scale = READ_U32(p_ctx, "dwScale");
+         rate = READ_U32(p_ctx, "dwRate");
+         start = READ_U32(p_ctx, "dwStart");
+         length = READ_U32(p_ctx, "dwLength");
+         SKIP_U32(p_ctx, "dwSuggestedBufferSize");
+         SKIP_U32(p_ctx, "dwQuality");
+         sample_size = READ_U32(p_ctx, "dwSampleSize");
+         SKIP_U16(p_ctx, "rcFrame.left");
+         SKIP_U16(p_ctx, "rcFrame.top");
+         SKIP_U16(p_ctx, "rcFrame.right");
+         SKIP_U16(p_ctx, "rcFrame.bottom");
+
+         /* In AVI, sec/frame = scale/rate and frames/sec = rate/scale */
+         if (rate == 0)
+         {
+            LOG_DEBUG(p_ctx, "invalid dwRate: 0, using 1 as a guess");
+            LOG_DEBUG(p_ctx, "timestamps will almost certainly be wrong");
+            rate = 1;
+         }
+
+         div = vc_container_maths_gcd((int64_t)scale, (int64_t)rate);
+         scale = scale / div; 
+         rate = rate / div;
+
+         track->format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
+         if(fourcc_type == VC_FOURCC('v','i','d','s'))
+         {
+            track->format->es_type = VC_CONTAINER_ES_TYPE_VIDEO;
+            track->format->type->video.frame_rate_num = rate;
+            track->format->type->video.frame_rate_den = scale;
+            
+            if (sample_size != 0)
+            {
+               LOG_DEBUG(p_ctx, "ignoring dwSampleSize (%d) for video stream", sample_size);
+               sample_size = 0;
+            }
+         }
+         else if(fourcc_type == VC_FOURCC('a','u','d','s'))
+         {
+            track->format->es_type = VC_CONTAINER_ES_TYPE_AUDIO;
+            /* VBR audio is going to be non-framed */
+            track->format->flags &= ~VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
+         }
+         else if(fourcc_type == VC_FOURCC('t','x','t','s'))
+            track->format->es_type = VC_CONTAINER_ES_TYPE_SUBPICTURE;
+   
+         /* Don't overwrite any existing value (i.e. in the unlikely case where we 
+            see 'strf' before 'strh') */
+         if(!track->format->codec) track->format->codec = vfw_fourcc_to_codec(fourcc_handler);
+   
+         /* FIXME: enable this once read_media does the right thing */
+         if (!(flags & AVISF_DISABLED) || 1)
+            track->is_enabled = 1;
+            
+         track_module->time_num = scale;
+         track_module->time_den = rate;
+         track_module->time_start = avi_stream_ticks_to_us(track_module, (uint64_t)start);
+         track_module->duration = avi_stream_ticks_to_us(track_module, (uint64_t)length);
+         track_module->sample_size = sample_size;
+         
+         p_ctx->duration = MAX(p_ctx->duration, track_module->duration);
+         
+         stream_header_chunk_read = 1;
+      }
+      else if(chunk_id == VC_FOURCC('s','t','r','f')) 
+      {
+         uint8_t *buffer;
+         unsigned extra_offset = 0, extra_size = 0;
+
+         /* We won't accept more than one 'strf' per stream */
+         if (stream_format_chunk_read) 
+         {
+            LOG_DEBUG(p_ctx, "rejecting invalid 'strl', found more than one 'strf'");
+            return VC_CONTAINER_ERROR_FORMAT_INVALID;
+         }
+
+         /* Use the extradata buffer for reading in the entire 'strf' (should not be a large chunk) */
+         if ((status = vc_container_track_allocate_extradata(p_ctx, track, chunk_size)) != VC_CONTAINER_SUCCESS)
+         {
+            LOG_DEBUG(p_ctx, "failed to allocate memory for 'strf' (%d bytes)", chunk_size);
+            return status;
+         }
+         
+         buffer = track->priv->extradata;
+         if(READ_BYTES(p_ctx, buffer, chunk_size) != chunk_size) 
+            return VC_CONTAINER_ERROR_FORMAT_INVALID;
+         AVI_SYNC_CHUNK(p_ctx);
+         
+         if(track->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO)
+         {
+            status = vc_container_bitmapinfoheader_to_es_format(buffer, chunk_size, &extra_offset, &extra_size, track->format);
+         }
+         else if(track->format->es_type == VC_CONTAINER_ES_TYPE_AUDIO)
+         {
+            status = vc_container_waveformatex_to_es_format(buffer, chunk_size, &extra_offset, &extra_size, track->format);
+            if (track_module->sample_size != 0 && track_module->sample_size != track->format->type->audio.block_align)
+            {
+               LOG_DEBUG(p_ctx, "invalid dwSampleSize (%d), should match nBlockAlign (%d) for audio streams.", 
+                  track_module->sample_size, track->format->type->audio.block_align);
+   
+               /* Note that if nBlockAlign really is 0, strf is seriously broken... */
+               if (track->format->type->audio.block_align != 0)
+                  track_module->sample_size = track->format->type->audio.block_align;
+            }
+            else
+            {
+               /* Flawed muxers might only set nBlockAlign (i.e. not set dwSampleSize correctly). */
+               if (track->format->type->audio.block_align == 1) 
+                  track_module->sample_size = 1;
+            }
+         }
+
+         if (status != VC_CONTAINER_SUCCESS) return status;
+   
+         if (extra_size)
+         {
+            track->format->extradata = buffer + extra_offset;
+            track->format->extradata_size = extra_size;
+         }
+
+         /* Codec specific fix-up */
+         if (track->format->codec == VC_CONTAINER_CODEC_MP4A &&
+             track->format->extradata_size)
+         {
+            /* This is going to be raw AAC so it will be framed */
+            track_module->sample_size = 0;
+            track->format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
+         }
+
+         /* WMA specific fix-up */
+         if ((track->format->codec == VC_CONTAINER_CODEC_WMA1 ||
+              track->format->codec == VC_CONTAINER_CODEC_WMA2 ||
+              track->format->codec == VC_CONTAINER_CODEC_WMAP ||
+              track->format->codec == VC_CONTAINER_CODEC_WMAL ||
+              track->format->codec == VC_CONTAINER_CODEC_WMAV) &&
+              track->format->extradata_size)
+         {
+            track_module->sample_size = 0;
+            track->format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
+         }
+
+         stream_format_chunk_read = 1;
+      }
+      else if(chunk_id == VC_FOURCC('s','t','r','d'))
+      {
+         /* The data in a 'strd' chunk is either codec configuration data or DRM information, 
+            we can safely assume it might be either as long as we don't overwrite any config 
+            data read previously from a 'strf' chunk */
+         if ((status = vc_container_track_allocate_drmdata(p_ctx, track, chunk_size)) != VC_CONTAINER_SUCCESS)
+         {
+            LOG_DEBUG(p_ctx, "failed to allocate memory for 'strd' (%d bytes)", chunk_size);
+            return status;
+         }
+                 
+         if(READ_BYTES(p_ctx, track->priv->drmdata, chunk_size) != chunk_size) 
+            return VC_CONTAINER_ERROR_FORMAT_INVALID;
+         AVI_SYNC_CHUNK(p_ctx);
+         
+         if (!track->format->extradata)
+         {
+            if (vc_container_track_allocate_extradata(p_ctx, track, chunk_size) == VC_CONTAINER_SUCCESS)
+            {
+               memcpy(track->format->extradata, track->priv->drmdata, chunk_size);
+               
+               track->format->extradata = track->priv->extradata;
+               track->format->extradata_size = chunk_size;
+            }
+            else
+            {
+               LOG_DEBUG(p_ctx, "failed to allocate memory for 'strd' (%d bytes)", chunk_size);
+               LOG_DEBUG(p_ctx, "no codec configuration data set");
+            }
+         }
+      }
+      else if(chunk_id == VC_FOURCC('i','n','d','x'))
+      {
+         track_module->index_offset = STREAM_POSITION(p_ctx);
+         track_module->index_size = chunk_size;
+      }
+      else
+      {
+         /* Not interested in this chunk, skip it. */
+      }
+
+      /* Skip any left-over data */
+      AVI_SKIP_CHUNK(p_ctx, offset + chunk_size + 8 - STREAM_POSITION(p_ctx) );
+   }
+
+   if (!stream_header_chunk_read || !stream_format_chunk_read)
+   {
+      LOG_DEBUG(p_ctx, "invalid 'strl', 'strh' and 'strf' are both required");
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+
+   return status;
+}
+
+static VC_CONTAINER_STATUS_T avi_find_next_data_chunk(VC_CONTAINER_T *p_ctx, uint32_t *id, uint32_t *size)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_FOURCC_T chunk_id;
+   uint32_t chunk_size = 0;
+   uint32_t peek_buf[1];
+
+   do
+   {
+      chunk_id = READ_FOURCC(p_ctx, "Chunk ID");
+      chunk_size = READ_U32(p_ctx, "Chunk size");
+      if((status = STREAM_STATUS(p_ctx)) != VC_CONTAINER_SUCCESS)
+         break;
+
+      /* Check if this is a 'rec ' or a 'movi' LIST instead of a plain data chunk */
+      if(chunk_id == VC_FOURCC('L','I','S','T')) 
+      {
+         if (PEEK_BYTES(p_ctx, (uint8_t*)peek_buf, 4) != 4)
+            return VC_CONTAINER_ERROR_EOS;
+         if (peek_buf[0] == VC_FOURCC('r','e','c',' '))
+            SKIP_FOURCC(p_ctx, "rec ");
+         else if (peek_buf[0] == VC_FOURCC('m','o','v','i'))
+            SKIP_FOURCC(p_ctx, "movi");
+         else
+            AVI_SKIP_CHUNK(p_ctx, chunk_size); /* Not interested in this LIST chunk, skip it. */
+         continue;
+      }
+
+      /* Check if this is a 'AVIX' RIFF header instead of a data chunk */
+      if(chunk_id == VC_FOURCC('R','I','F','F'))
+      {
+         if (PEEK_BYTES(p_ctx, (uint8_t*)peek_buf, 4) != 4)
+            return VC_CONTAINER_ERROR_EOS;
+         if (peek_buf[0] == VC_FOURCC('A','V','I','X'))
+            SKIP_FOURCC(p_ctx, "AVIX");
+         else
+            AVI_SKIP_CHUNK(p_ctx, chunk_size); /* Not interested in this RIFF header, skip it. */
+         continue;
+      }
+
+      /* We treat only db/dc/dd or wb chunks as data */
+      if((uint32_t)chunk_id >> 16 == AVI_TWOCC('d','c') ||
+         (uint32_t)chunk_id >> 16 == AVI_TWOCC('d','b') ||
+         (uint32_t)chunk_id >> 16 == AVI_TWOCC('d','d') ||
+         (uint32_t)chunk_id >> 16 == AVI_TWOCC('w','b'))
+      {
+         *id = chunk_id;
+         *size = chunk_size;
+         break;
+      }
+
+      /* Need to exit if a zero sized chunk encountered so we don't loop forever. */
+      if(chunk_size == 0 && chunk_id == 0) return VC_CONTAINER_ERROR_EOS;
+
+      /* Not interested in this chunk, skip it */
+      AVI_SKIP_CHUNK(p_ctx, chunk_size);
+   } while ((status = STREAM_STATUS(p_ctx)) == VC_CONTAINER_SUCCESS);
+
+   return status;
+}
+
+static void avi_track_from_chunk_id(VC_CONTAINER_FOURCC_T chunk_id, uint16_t *data_type, uint16_t *track_num)
+{
+   *track_num = (((uint8_t*)&chunk_id)[0] - 48) * 10 + ((uint8_t*)&chunk_id)[1] - 48;
+   *data_type = (uint32_t)chunk_id >> 16;
+}
+
+static VC_CONTAINER_STATUS_T avi_check_track(VC_CONTAINER_T *p_ctx, uint16_t data_type, uint16_t track_num)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   
+   if (track_num < p_ctx->tracks_num)
+   {
+      if (data_type == AVI_TWOCC('w','b') && p_ctx->tracks[track_num]->format->es_type != VC_CONTAINER_ES_TYPE_AUDIO)
+      {
+         LOG_DEBUG(p_ctx, "suspicious track type ('wb'), track %d is not an audio track", track_num);
+         status = VC_CONTAINER_ERROR_FAILED;
+      }
+      if (data_type == AVI_TWOCC('d','b') && p_ctx->tracks[track_num]->format->es_type != VC_CONTAINER_ES_TYPE_VIDEO)
+      {
+         LOG_DEBUG(p_ctx, "suspicious track type ('db'), track %d is not a video track", track_num);
+         status = VC_CONTAINER_ERROR_FAILED;
+      }
+      if (data_type == AVI_TWOCC('d','c') && p_ctx->tracks[track_num]->format->es_type != VC_CONTAINER_ES_TYPE_VIDEO)
+      {
+         LOG_DEBUG(p_ctx, "suspicious track type ('dc'), track %d is not a video track", track_num);
+         status = VC_CONTAINER_ERROR_FAILED;
+      }
+      if (data_type == AVI_TWOCC('d','d') && p_ctx->tracks[track_num]->format->es_type != VC_CONTAINER_ES_TYPE_VIDEO)
+      {
+         LOG_DEBUG(p_ctx, "suspicious track type ('dd'), track %d is not a video track", track_num);
+         status = VC_CONTAINER_ERROR_FAILED;
+      }
+   }
+   else
+   {
+      LOG_DEBUG(p_ctx, "invalid track number %d (no more than %d tracks expected)", 
+         track_num, p_ctx->tracks_num);
+      status = VC_CONTAINER_ERROR_FAILED;        
+   }
+      
+   return status;
+}
+
+static int avi_compare_seek_time(int64_t chunk_time, int64_t seek_time, 
+   int chunk_is_keyframe, VC_CONTAINER_SEEK_FLAGS_T seek_flags)
+{
+   if (chunk_time == seek_time && chunk_is_keyframe && !(seek_flags & VC_CONTAINER_SEEK_FLAG_FORWARD))
+      return 0;
+   
+   if (chunk_time > seek_time && chunk_is_keyframe && (seek_flags & VC_CONTAINER_SEEK_FLAG_FORWARD))
+      return 0;
+
+   if (chunk_time > seek_time && !(seek_flags & VC_CONTAINER_SEEK_FLAG_FORWARD))
+      return 1; /* Chunk time is past seek time, caller should use the previous keyframe */
+      
+   return -1;
+}
+
+static VC_CONTAINER_STATUS_T avi_scan_legacy_index_chunk(VC_CONTAINER_T *p_ctx, int seek_track_num,
+   int64_t *time, VC_CONTAINER_SEEK_FLAGS_T flags, uint64_t *pos)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status;
+   VC_CONTAINER_TRACK_MODULE_T *track_module;
+   AVI_TRACK_CHUNK_STATE_T selected_chunk;
+   int64_t base_offset = module->data_offset;
+   int64_t selected_chunk_offset = base_offset + 4;
+   int32_t extra_offset = 0;
+   int first_chunk_offset = 1;
+   uint64_t position;
+
+   SEEK(p_ctx, module->index_offset);
+   memset(&selected_chunk, 0, sizeof(selected_chunk));
+
+   while((status = STREAM_STATUS(p_ctx)) == VC_CONTAINER_SUCCESS &&
+         (uint64_t)STREAM_POSITION(p_ctx) < module->index_offset + module->index_size)
+   {
+      VC_CONTAINER_FOURCC_T chunk_id;
+      uint16_t data_type, track_num;
+      uint32_t chunk_flags, offset, size;
+
+      chunk_id     = READ_FOURCC(p_ctx, "Chunk ID");
+      chunk_flags  = READ_U32(p_ctx, "dwFlags");
+      offset       = READ_U32(p_ctx, "dwOffset");
+      size         = READ_U32(p_ctx, "dwSize");
+
+      if((status = STREAM_STATUS(p_ctx)) != VC_CONTAINER_SUCCESS) break;
+   
+      /* Although it's rare, the offsets might be given from the start of the file 
+      instead of the data chunk, we have to handle both cases. */
+      if (first_chunk_offset)
+      {
+         if (offset > module->data_offset) base_offset = INT64_C(0);
+         selected_chunk_offset = base_offset + 4;
+         first_chunk_offset = 0;
+      }
+   
+      avi_track_from_chunk_id(chunk_id, &data_type, &track_num);
+      LOG_DEBUG(p_ctx, "reading track %"PRIu16, track_num);
+      
+      if (avi_check_track(p_ctx, data_type, track_num) != VC_CONTAINER_SUCCESS)
+      {
+         LOG_DEBUG(p_ctx, "skipping index entry for track %d/%d", track_num, p_ctx->tracks_num);
+         continue;
+      }
+
+      track_module = p_ctx->tracks[track_num]->priv->module;
+
+      if (data_type == AVI_TWOCC('d','d'))
+      {
+         if (track_num == seek_track_num)
+            track_module->chunk.flags |= VC_CONTAINER_PACKET_FLAG_ENCRYPTED;
+         extra_offset = -(size + 8);
+      }
+
+      /* If this entry does not affect timing, skip it */
+      if ((chunk_flags & (AVIIF_LIST | AVIIF_NOTIME)) || data_type == AVI_TWOCC('d','d'))
+         continue;
+   
+      position = base_offset + offset + extra_offset;
+      extra_offset = INT64_C(0);
+
+      /* Check validity of position */
+      if (position <= module->data_offset /* || (*pos > module->data_offset + module->data_size*/)
+          return VC_CONTAINER_ERROR_FORMAT_INVALID;
+     
+      if (track_num == seek_track_num)
+      {
+         bool is_keyframe = true;
+         int res;
+
+         if (p_ctx->tracks[track_num]->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO)
+            is_keyframe = chunk_flags & AVIIF_KEYFRAME;
+
+         if (is_keyframe)
+            track_module->chunk.flags |= VC_CONTAINER_PACKET_FLAG_KEYFRAME;
+         else
+            track_module->chunk.flags &= ~(VC_CONTAINER_PACKET_FLAG_KEYFRAME);
+
+         res = avi_compare_seek_time(track_module->chunk.time_pos, *time, is_keyframe, flags);
+         if (res > 0)
+            break; /* We've found the keyframe we wanted */
+
+         if (is_keyframe)
+         {
+            selected_chunk_offset = position;
+            selected_chunk = track_module->chunk;
+         }
+
+         if (res == 0)
+            break; /* We've found the keyframe we wanted */
+
+         track_module->chunk.index++;
+         track_module->chunk.offs += size;
+         track_module->chunk.time_pos = avi_calculate_chunk_time(track_module);
+
+         LOG_DEBUG(p_ctx, "index %"PRIu64", offs %"PRIu64", time %"PRIi64"us", track_module->chunk.index,
+                   track_module->chunk.offs, track_module->chunk.time_pos);
+      }
+   }
+
+   if (status == VC_CONTAINER_SUCCESS ||
+       /* When seeking backwards, always return the last good position */
+       !(flags & VC_CONTAINER_SEEK_FLAG_FORWARD))
+   {
+      *pos = selected_chunk_offset;
+      track_module = p_ctx->tracks[seek_track_num]->priv->module;
+      track_module->chunk.index = selected_chunk.index;
+      track_module->chunk.offs = selected_chunk.offs;
+      track_module->chunk.flags = selected_chunk.flags;
+      track_module->chunk.time_pos = selected_chunk.time_pos;
+      *time = track_module->chunk.time_pos;
+      return VC_CONTAINER_SUCCESS;
+   }
+
+   return VC_CONTAINER_ERROR_NOT_FOUND;
+}
+
+static VC_CONTAINER_STATUS_T avi_scan_standard_index_chunk(VC_CONTAINER_T *p_ctx, uint64_t index_offset, 
+   unsigned seek_track_num, int64_t *time, VC_CONTAINER_SEEK_FLAGS_T flags, uint64_t *pos) 
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_NOT_FOUND;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = NULL;
+   VC_CONTAINER_FOURCC_T chunk_id; 
+   uint32_t chunk_size;
+   uint16_t data_type, track_num;
+   uint8_t index_type, index_sub_type;
+   uint32_t entry, entry_count = 0;
+   uint16_t entry_size;
+   uint64_t base_offset = UINT64_C(0);
+   uint64_t position = UINT64_C(0);
+   uint64_t prev_keyframe_offs = INT64_C(0);
+   AVI_TRACK_CHUNK_STATE_T prev_keyframe_chunk = { 0 };
+
+   SEEK(p_ctx, index_offset);
+
+   chunk_id = READ_FOURCC(p_ctx, "Chunk ID");
+   chunk_size = READ_U32(p_ctx, "Chunk Size");
+
+   entry_size = READ_U16(p_ctx, "wLongsPerEntry");
+   index_sub_type = READ_U8(p_ctx, "bIndexSubType");
+   index_type = READ_U8(p_ctx, "bIndexType");
+   entry_count = READ_U32(p_ctx, "nEntriesInUse");
+   chunk_id = READ_FOURCC(p_ctx, "dwChunkId");
+   base_offset = READ_U64(p_ctx, "qwBaseOffset");
+   SKIP_U32(p_ctx, "dwReserved");
+
+   if ((status = STREAM_STATUS(p_ctx)) != VC_CONTAINER_SUCCESS)
+      return status;
+
+   avi_track_from_chunk_id(chunk_id, &data_type, &track_num);   
+   status = avi_check_track(p_ctx, data_type, track_num);
+   if (status || chunk_size < 24 || track_num != seek_track_num)
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+
+   if (entry_size != 2 || index_sub_type != 0 || index_type != AVI_INDEX_OF_CHUNKS)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   entry_count = MIN(entry_count, (chunk_size - 24) / (entry_size * 4));
+
+   track_module = p_ctx->tracks[seek_track_num]->priv->module;
+
+   for (entry = 0; entry < entry_count; ++entry)
+   {
+      uint32_t chunk_offset;
+      int key_frame = 0;
+      
+      chunk_offset = READ_U32(p_ctx, "dwOffset");
+      chunk_size = READ_U32(p_ctx, "dwSize");
+      
+      if ((status = STREAM_STATUS(p_ctx)) != VC_CONTAINER_SUCCESS)
+         break;
+
+      status = VC_CONTAINER_ERROR_NOT_FOUND;
+
+      if (!(chunk_size & AVI_INDEX_DELTAFRAME)) 
+         key_frame = 1;
+      chunk_size &= ~AVI_INDEX_DELTAFRAME;
+
+      position = base_offset + chunk_offset - 8;
+
+      if (key_frame)
+         track_module->chunk.flags = VC_CONTAINER_PACKET_FLAG_KEYFRAME;
+      else
+         track_module->chunk.flags = 0;
+
+      if (time != NULL)
+      {
+         int res;
+         status = VC_CONTAINER_ERROR_NOT_FOUND;
+         res = avi_compare_seek_time(track_module->chunk.time_pos, *time, key_frame, flags);
+
+         if (res == 0)
+         {
+            *pos = position;
+            *time = track_module->chunk.time_pos;
+            status = VC_CONTAINER_SUCCESS;
+            break;
+         }
+         else if (res > 0)
+         {
+            if (prev_keyframe_offs)
+            {
+               *pos = prev_keyframe_offs;
+               track_module->chunk = prev_keyframe_chunk;
+               *time = track_module->chunk.time_pos;
+               status = VC_CONTAINER_SUCCESS;
+            }
+            break;
+         }
+           
+         if (key_frame)
+         {
+            prev_keyframe_offs = position;
+            prev_keyframe_chunk = track_module->chunk;
+         }
+      }
+      else
+      {
+         /* Not seeking to a time position, but scanning
+            track chunk state up to a certain file position 
+            instead */
+         if (position >= *pos)
+         {
+            status = VC_CONTAINER_SUCCESS;
+            break;
+         }
+      }
+
+      track_module->chunk.index++;
+      track_module->chunk.offs += chunk_size;
+      track_module->chunk.time_pos = avi_calculate_chunk_time(track_module);
+   }
+
+   return status;
+}
+
+static VC_CONTAINER_STATUS_T avi_scan_super_index_chunk(VC_CONTAINER_T *p_ctx, unsigned index_track_num, 
+   int64_t *time, VC_CONTAINER_SEEK_FLAGS_T flags, uint64_t *pos)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_NOT_FOUND;
+   VC_CONTAINER_FOURCC_T chunk_id;
+   uint64_t index_offset;
+   uint32_t index_size;
+   uint16_t data_type, track_num;
+   uint32_t entry, entry_count;
+   uint16_t entry_size; 
+   uint8_t index_sub_type, index_type;
+   
+   index_offset = p_ctx->tracks[index_track_num]->priv->module->index_offset;
+   index_size = p_ctx->tracks[index_track_num]->priv->module->index_size;
+   
+   SEEK(p_ctx, index_offset);
+   
+   entry_size = READ_U16(p_ctx, "wLongsPerEntry");
+   index_sub_type = READ_U8(p_ctx, "bIndexSubType");
+   index_type = READ_U8(p_ctx, "bIndexType");
+   entry_count = READ_U32(p_ctx, "nEntriesInUse");
+   chunk_id = READ_FOURCC(p_ctx, "dwChunkId");
+   SKIP_U32(p_ctx, "dwReserved0");
+   SKIP_U32(p_ctx, "dwReserved1");
+   SKIP_U32(p_ctx, "dwReserved2");
+
+   if ((status = STREAM_STATUS(p_ctx)) != VC_CONTAINER_SUCCESS)
+      return status;
+      
+   if (index_type == AVI_INDEX_OF_INDEXES)
+   {
+      avi_track_from_chunk_id(chunk_id, &data_type, &track_num);
+      status = avi_check_track(p_ctx, data_type, track_num);
+      if (status || index_size < 24 || track_num != index_track_num) return VC_CONTAINER_ERROR_FORMAT_INVALID;
+      
+      /* FIXME: We should probably support AVI_INDEX_2FIELD as well */
+      if (entry_size != 4 || index_sub_type != 0)
+         return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   
+      entry_count = MIN(entry_count, (index_size - 24) / entry_size);
+
+      for (entry = 0; entry < entry_count; ++entry)
+      {
+         uint64_t entry_offset, standard_index_offset;
+         standard_index_offset = READ_U64(p_ctx, "qwOffset");
+         SKIP_U32(p_ctx, "dwSize");
+         SKIP_U32(p_ctx, "dwDuration");
+         
+         if ((status = STREAM_STATUS(p_ctx)) != VC_CONTAINER_SUCCESS) 
+            break;            
+
+         if (standard_index_offset == UINT64_C(0))
+         {
+            status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; /* Not plausible */
+            break;
+         }
+
+         entry_offset = STREAM_POSITION(p_ctx);
+         status = avi_scan_standard_index_chunk(p_ctx, standard_index_offset, index_track_num, time, flags, pos);
+         if (status != VC_CONTAINER_ERROR_NOT_FOUND) break;
+         SEEK(p_ctx, entry_offset); /* Move to next entry ('ix' chunk); */
+      }
+   }
+   else if (index_type == AVI_INDEX_OF_CHUNKS)
+   {
+      /* It seems we are dealing with a standard index instead... */
+      status = avi_scan_standard_index_chunk(p_ctx, index_offset, index_track_num, time, flags, pos);
+   }
+   else
+   {
+      status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   }
+   
+   return status;
+}
+
+static VC_CONTAINER_STATUS_T avi_read_dd_chunk( VC_CONTAINER_T *p_ctx,
+   AVI_TRACK_STREAM_STATE_T *p_state, uint16_t data_type, uint32_t chunk_size,
+   uint16_t track_num )
+{
+   if (data_type == AVI_TWOCC('d','d'))
+   {
+      if (p_state->extra_chunk_data_len ||
+          chunk_size > sizeof(p_state->extra_chunk_data))
+      {
+         LOG_DEBUG(p_ctx, "cannot handle multiple consecutive 'dd' chunks");
+         return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+      }
+      if(READ_BYTES(p_ctx, p_state->extra_chunk_data, chunk_size) != chunk_size)
+         return VC_CONTAINER_ERROR_FORMAT_INVALID;
+
+      AVI_SYNC_CHUNK(p_ctx);
+      p_state->extra_chunk_track_num = track_num;
+      p_state->extra_chunk_data_len = chunk_size;
+      p_state->extra_chunk_data_offs = 0;
+
+      return VC_CONTAINER_ERROR_CONTINUE;
+   }
+   else if (p_state->extra_chunk_data_len &&
+      p_state->extra_chunk_track_num != track_num)
+   {
+      LOG_DEBUG(p_ctx, "dropping data from '%02ddd' chunk, not for this track (%d)",
+         p_state->extra_chunk_track_num, track_num);
+      p_state->extra_chunk_data_len = 0;
+   }
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************
+Functions exported as part of the Container Module API
+ *****************************************************************************/
+
+static VC_CONTAINER_STATUS_T avi_reader_read( VC_CONTAINER_T *p_ctx,
+                                              VC_CONTAINER_PACKET_T *p_packet, uint32_t flags )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = NULL;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   AVI_TRACK_STREAM_STATE_T *p_state = &module->state;
+
+   if (flags & VC_CONTAINER_READ_FLAG_FORCE_TRACK)
+   {
+      p_state = p_ctx->tracks[p_packet->track]->priv->module->chunk.state;
+   }
+
+   LOG_DEBUG(p_ctx, "seeking to %"PRIi64, p_state->data_offset);
+   SEEK(p_ctx, p_state->data_offset);
+
+   if (p_state->chunk_data_left == 0)
+   {
+      VC_CONTAINER_FOURCC_T chunk_id;
+      uint32_t chunk_size;
+      uint16_t data_type, track_num;
+      
+      if ((status = avi_find_next_data_chunk(p_ctx, &chunk_id, &chunk_size)) != VC_CONTAINER_SUCCESS)
+      {
+         LOG_DEBUG(p_ctx, "unable to find the next data chunk %d", status);
+         p_state->data_offset = STREAM_POSITION(p_ctx);
+         return status;
+      }
+
+      avi_track_from_chunk_id(chunk_id, &data_type, &track_num);
+
+      if (avi_check_track(p_ctx, data_type, track_num) != VC_CONTAINER_SUCCESS)
+      {
+         AVI_SKIP_CHUNK(p_ctx, chunk_size);
+         LOG_DEBUG(p_ctx, "skipping data for track %d/%d", track_num, p_ctx->tracks_num);
+
+         p_state->data_offset = STREAM_POSITION(p_ctx);
+         return VC_CONTAINER_ERROR_CONTINUE;
+      }
+
+      /* If we are reading from the global state (i.e. normal read or forced
+         read from the track on the global state), and the track we found is
+         not on the global state, connect the two */
+      if (p_state == &module->state &&
+         p_ctx->tracks[track_num]->priv->module->chunk.state != &module->state)
+      {
+         int64_t next_chunk;
+
+         /* The track's offset is past the current position, skip it as we are
+            not interested in track data from before the track's offset. If we
+            were to read it we would return the same data multiple times. */
+         next_chunk = (STREAM_POSITION(p_ctx) + chunk_size + 1) & ~1;
+         if (p_ctx->tracks[track_num]->priv->module->chunk.state->data_offset > next_chunk)
+         {
+            AVI_SKIP_CHUNK(p_ctx, chunk_size);
+            LOG_DEBUG(p_ctx, "skipping track %d/%d as we have already read it", track_num, p_ctx->tracks_num);
+            p_state->data_offset = STREAM_POSITION(p_ctx);
+            return VC_CONTAINER_ERROR_CONTINUE;
+         }
+
+         /* The track state must be pointing to the current chunk. We need to
+            reconnect the track to the global state. */
+         LOG_DEBUG(p_ctx, "reconnect track %u to the global state", track_num);
+
+         p_ctx->tracks[track_num]->priv->module->chunk.state = &module->state;
+
+         module->state = p_ctx->tracks[track_num]->priv->module->chunk.local_state;
+
+         vc_container_assert(chunk_size >= p_state->chunk_data_left);
+         vc_container_assert(!p_state->chunk_data_left ||
+            ((p_state->data_offset + p_state->chunk_data_left + 1) & ~1) == next_chunk);
+         vc_container_assert(p_state->current_track_num == track_num);
+
+         return VC_CONTAINER_ERROR_CONTINUE;
+      }
+
+      /* If we are not forcing, or if we are and found the track we are
+         interested in, check for dd data and set the track module for the later code */
+      if (!(flags & VC_CONTAINER_READ_FLAG_FORCE_TRACK) ||
+          (track_num == p_packet->track))
+      {
+         if ((status = avi_read_dd_chunk(p_ctx, p_state, data_type, chunk_size, track_num)) != VC_CONTAINER_SUCCESS)
+         {
+            p_state->data_offset = STREAM_POSITION(p_ctx);
+            return status;
+         }
+      }
+
+      p_state->chunk_size = p_state->chunk_data_left = chunk_size;
+      p_state->current_track_num = track_num;
+   }
+
+   /* If there is data from another track skip past it */
+   if (flags & VC_CONTAINER_READ_FLAG_FORCE_TRACK &&
+       p_state->current_track_num != p_packet->track)
+   {
+      p_state->data_offset = STREAM_POSITION(p_ctx);
+
+      AVI_SKIP_CHUNK(p_ctx, p_state->chunk_data_left);
+      LOG_DEBUG(p_ctx, "skipping track %d/%d as we are ignoring it",
+         p_state->current_track_num, p_ctx->tracks_num);
+
+      track_module = p_ctx->tracks[p_packet->track]->priv->module;
+
+      /* Handle disconnection from global state */
+      if (p_state == &module->state &&
+         p_ctx->tracks[p_state->current_track_num]->priv->module->chunk.state == &module->state)
+      {
+         /* Make a copy of the global state */
+         LOG_DEBUG(p_ctx, "using local state on track %d", p_packet->track);
+         track_module->chunk.local_state = module->state;
+         track_module->chunk.state = &track_module->chunk.local_state;
+      }
+
+      track_module->chunk.state->data_offset = STREAM_POSITION(p_ctx);
+      track_module->chunk.state->chunk_data_left = 0;
+
+      return VC_CONTAINER_ERROR_CONTINUE;
+   }
+
+   track_module = p_ctx->tracks[p_state->current_track_num]->priv->module;
+
+   if (flags & VC_CONTAINER_READ_FLAG_FORCE_TRACK)
+   {
+      vc_container_assert(p_state->current_track_num == p_packet->track);
+   }
+
+   LOG_DEBUG(p_ctx, "reading track %u chunk at time %"PRIi64"us, offset %"PRIu64,
+             p_state->current_track_num, track_module->chunk.time_pos,
+             track_module->chunk.offs);
+   if (p_state->extra_chunk_data_len)
+      track_module->chunk.flags |= VC_CONTAINER_PACKET_FLAG_ENCRYPTED;
+   else
+      track_module->chunk.flags &= ~VC_CONTAINER_PACKET_FLAG_ENCRYPTED;
+
+   if (p_packet)
+   {
+      p_packet->track = p_state->current_track_num;
+      p_packet->size = p_state->chunk_data_left +
+                       p_state->extra_chunk_data_len;
+      p_packet->flags = track_module->chunk.flags;
+
+      if (p_state->chunk_data_left == p_state->chunk_size)
+      {
+         p_packet->pts = track_module->chunk.time_pos;
+         if (track_module->sample_size == 0)
+            p_packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME;
+      }
+      else
+      {
+         p_packet->pts = VC_CONTAINER_TIME_UNKNOWN;
+         if (track_module->sample_size == 0)
+            p_packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
+      }
+    
+      p_packet->dts = VC_CONTAINER_TIME_UNKNOWN;
+   }
+
+   if (flags & VC_CONTAINER_READ_FLAG_SKIP)
+   {
+      SKIP_BYTES(p_ctx, p_state->chunk_data_left);
+      AVI_SYNC_CHUNK(p_ctx);
+      p_state->chunk_data_left = 0;
+      p_state->extra_chunk_data_len = 0;
+   }
+
+   if (flags & VC_CONTAINER_READ_FLAG_INFO)
+   {
+      p_state->data_offset = STREAM_POSITION(p_ctx);
+
+      LOG_DEBUG(p_ctx, "data position %"PRIi64, p_state->data_offset);
+
+      return VC_CONTAINER_SUCCESS;
+   }
+   
+   if (p_packet)
+   {
+      uint8_t *data = p_packet->data;
+      uint32_t buffer_size = p_packet->buffer_size;
+      uint32_t size = 0;
+      uint32_t len;     
+      
+      /* See if we need to insert extra data */
+      if (p_state->extra_chunk_data_len)
+      {
+         len = MIN(buffer_size, p_state->extra_chunk_data_len);
+         memcpy(data, p_state->extra_chunk_data + p_state->extra_chunk_data_offs, len);
+         data += len;
+         buffer_size -= len;
+         size = len;
+         p_state->extra_chunk_data_len -= len;
+         p_state->extra_chunk_data_offs += len;
+      }
+
+      /* Now try to read data into buffer */
+      len = MIN(buffer_size, p_state->chunk_data_left);
+      READ_BYTES(p_ctx, data, len);
+      size += len;
+      p_state->chunk_data_left -= len;
+      p_packet->size = size;
+
+      if (p_state->chunk_data_left)
+         p_packet->flags &= ~VC_CONTAINER_PACKET_FLAG_FRAME_END;
+   }
+
+   if (p_state->chunk_data_left == 0)
+   {
+      AVI_SYNC_CHUNK(p_ctx);
+      track_module->chunk.index++;
+      track_module->chunk.offs += p_state->chunk_size;
+      track_module->chunk.flags = 0;
+      track_module->chunk.time_pos = avi_calculate_chunk_time(track_module);
+   }
+
+   /* Update the track's position */
+   p_state->data_offset = STREAM_POSITION(p_ctx);
+
+   LOG_DEBUG(p_ctx, "data position %"PRIi64, p_state->data_offset);
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avi_reader_seek( VC_CONTAINER_T *p_ctx, int64_t *p_offset,
+   VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status;
+   uint64_t position, pos;
+   AVI_TRACK_CHUNK_STATE_T chunk_state[AVI_TRACKS_MAX];
+   AVI_TRACK_STREAM_STATE_T global_state;
+   unsigned seek_track_num, i;
+
+   if (mode != VC_CONTAINER_SEEK_MODE_TIME || !STREAM_SEEKABLE(p_ctx))
+      return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+
+   LOG_DEBUG(p_ctx, "AVI seeking to %"PRIi64"us", *p_offset);
+
+   /* Save current position and chunk state so we can restore it if we 
+      hit an error whilst scanning index data */
+   position = STREAM_POSITION(p_ctx);
+   for(i = 0; i < p_ctx->tracks_num; i++)
+     chunk_state[i] = p_ctx->tracks[i]->priv->module->chunk;
+   global_state = p_ctx->priv->module->state;
+
+   /* Clear track state affected by a seek operation of any kind */
+   for(i = 0; i < p_ctx->tracks_num; i++)
+   {
+      p_ctx->tracks[i]->priv->module->chunk.index = INT64_C(0);
+      p_ctx->tracks[i]->priv->module->chunk.offs = INT64_C(0);
+      p_ctx->tracks[i]->priv->module->chunk.flags = 0;
+      p_ctx->tracks[i]->priv->module->chunk.time_pos = p_ctx->tracks[i]->priv->module->time_start;
+      p_ctx->tracks[i]->priv->module->chunk.state = &p_ctx->tracks[i]->priv->module->chunk.local_state;
+      p_ctx->tracks[i]->priv->module->chunk.local_state.chunk_data_left = UINT64_C(0);
+      p_ctx->tracks[i]->priv->module->chunk.local_state.chunk_size = UINT64_C(0);
+      p_ctx->tracks[i]->priv->module->chunk.local_state.extra_chunk_data_len = 0;
+      p_ctx->tracks[i]->priv->module->chunk.local_state.data_offset = module->data_offset + 4;
+   }
+
+   /* Clear the global state */
+   p_ctx->priv->module->state.chunk_data_left = UINT64_C(0);
+   p_ctx->priv->module->state.chunk_size = UINT64_C(0);
+   p_ctx->priv->module->state.extra_chunk_data_len = 0;
+   p_ctx->priv->module->state.data_offset = module->data_offset + 4;
+
+   /* Choose track to use for seeking, favor video tracks and tracks
+      that are enabled */
+   for(i = 0; i < p_ctx->tracks_num; i++)
+      if(p_ctx->tracks[i]->is_enabled &&
+         p_ctx->tracks[i]->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO) break;
+   if(i == p_ctx->tracks_num)
+      for(i = 0; i < p_ctx->tracks_num; i++)
+         if(p_ctx->tracks[i]->is_enabled) break;
+   if(i == p_ctx->tracks_num) i = 0;
+
+   LOG_DEBUG(p_ctx, "seek on track %d/%d", i, p_ctx->tracks_num);
+   seek_track_num = i;
+
+   if (p_ctx->tracks[seek_track_num]->priv->module->index_offset)
+   {
+      LOG_DEBUG(p_ctx, "seeking using the super index");
+      status = avi_scan_super_index_chunk(p_ctx, seek_track_num, p_offset, flags, &pos);
+      if (status != VC_CONTAINER_SUCCESS) goto error;
+
+      /* As AVI chunks don't convey timestamp information, we need to scan all tracks
+         to the seek file position */
+      for(i = 0; i < p_ctx->tracks_num; i++)
+      {
+         if (p_ctx->tracks[i]->priv->module->index_offset && i != seek_track_num)
+         {
+            uint64_t track_pos;
+            int64_t track_time = *p_offset;
+
+            status = avi_scan_super_index_chunk(p_ctx, i, &track_time, flags, &track_pos);
+            if (status != VC_CONTAINER_SUCCESS) goto error;
+            p_ctx->tracks[i]->priv->module->chunk.local_state.data_offset = track_pos;
+         }
+      }
+   }
+   else
+   {
+      LOG_DEBUG(p_ctx, "seeking using the legacy index");
+
+      /* The legacy index comes after data so it might not have been available at the
+         time the container was opened; if this is the case, see if we can find an index
+         now, if we can't, then there's no way we can proceed with the seek. */
+      if(!module->index_offset)
+      {
+         uint32_t chunk_size;
+
+         LOG_DEBUG(p_ctx, "no index offset, searching for one");
+
+         /* Locate data chunk and skip it */
+         SEEK(p_ctx, module->data_offset);
+         AVI_SKIP_CHUNK(p_ctx, module->data_size);
+         /* Now search for the index */
+         status = avi_find_chunk(p_ctx, VC_FOURCC('i','d','x','1'), &chunk_size);
+         if (status == VC_CONTAINER_SUCCESS)
+         {
+            /* Store offset to index data */
+            module->index_offset = STREAM_POSITION(p_ctx);
+            module->index_size = chunk_size;
+            p_ctx->capabilities |= VC_CONTAINER_CAPS_HAS_INDEX;
+            p_ctx->capabilities |= VC_CONTAINER_CAPS_DATA_HAS_KEYFRAME_FLAG;
+         }
+      }
+      /* Check again, we may or may not have an index */
+      if (!module->index_offset)
+      {
+         /* If there is no index and we are seeking to 0 we can assume the
+            correct location is the start of the data. Otherwise we are unable
+            to seek to a specified non-zero location without an index */
+         if (*p_offset != INT64_C(0))
+         {
+            LOG_DEBUG(p_ctx, "failed to find the legacy index, unable to seek");
+            status = VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+            goto error;
+         }
+         pos = module->data_offset;
+      }
+      else
+      {
+         LOG_DEBUG(p_ctx, "scanning the legacy index chunk");
+         status = avi_scan_legacy_index_chunk(p_ctx, seek_track_num, p_offset, flags, &pos);
+         if (status != VC_CONTAINER_SUCCESS) goto error;
+
+         for (i = 0; i < p_ctx->tracks_num; i++)
+         {
+            if (i != seek_track_num)
+            {
+               uint64_t track_pos = pos;
+               int64_t track_time = *p_offset;
+
+               status = avi_scan_legacy_index_chunk(p_ctx, i, &track_time, flags, &track_pos);
+               if (status != VC_CONTAINER_SUCCESS) goto error;
+               p_ctx->tracks[i]->priv->module->chunk.local_state.data_offset = track_pos;
+               p_ctx->tracks[i]->priv->module->chunk.local_state.current_track_num = i;
+            }
+         }
+      }
+   }
+
+   position = pos;
+
+   /* Set the seek track's data offset */
+   p_ctx->tracks[seek_track_num]->priv->module->chunk.local_state.data_offset = position;
+   p_ctx->tracks[seek_track_num]->priv->module->chunk.local_state.current_track_num = seek_track_num;
+
+   /* Connect the earlier track(s) to the global state. Needs 2 passes */
+   module->state.data_offset = INT64_MAX;
+   for(i = 0; i < p_ctx->tracks_num; i++)
+   {
+      if(p_ctx->tracks[i]->priv->module->chunk.local_state.data_offset <
+         module->state.data_offset)
+         module->state = p_ctx->tracks[i]->priv->module->chunk.local_state;
+   }
+   for(i = 0; i < p_ctx->tracks_num; i++)
+   {
+      if(p_ctx->tracks[i]->priv->module->chunk.local_state.data_offset ==
+         module->state.data_offset)
+         p_ctx->tracks[i]->priv->module->chunk.state = &module->state;
+   }
+
+   LOG_DEBUG(p_ctx, "seek to %"PRIi64", position %"PRIu64, *p_offset, pos);
+
+   return SEEK(p_ctx, position);
+
+error:
+   p_ctx->priv->module->state = global_state;
+   for(i = 0; i < p_ctx->tracks_num; i++)
+     p_ctx->tracks[i]->priv->module->chunk = chunk_state[i];
+   SEEK(p_ctx, position);
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avi_reader_close( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;   
+   unsigned int i;
+
+   for(i = 0; i < p_ctx->tracks_num; i++)
+      vc_container_free_track(p_ctx, p_ctx->tracks[i]);
+   p_ctx->tracks = NULL;
+   p_ctx->tracks_num = 0;
+   free(module);
+   p_ctx->priv->module = 0;  
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T avi_reader_open( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = 0;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_INVALID;
+   uint32_t chunk_size;
+   uint32_t peek_buf[3];
+   unsigned int i;
+   uint32_t flags, num_streams;
+   int64_t offset;
+
+   /* Check the RIFF chunk descriptor */
+   if (PEEK_BYTES(p_ctx, (uint8_t*)peek_buf, 12) != 12)
+     return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   if( peek_buf[0] != VC_FOURCC('R','I','F','F') )
+     return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   if( peek_buf[2] != VC_FOURCC('A','V','I',' ') )
+     return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   /*
+    *  We now know we are dealing with an AVI file
+    */
+   SKIP_FOURCC(p_ctx, "RIFF ID");
+   SKIP_U32(p_ctx, "fileSize");
+   SKIP_FOURCC(p_ctx, "fileType");
+
+   /* Look for the 'hdrl' LIST (sub)chunk */   
+   status = avi_find_list(p_ctx, VC_FOURCC('h','d','r','l'), &chunk_size);
+   if (status != VC_CONTAINER_SUCCESS)
+   {
+      LOG_DEBUG(p_ctx, "'hdrl' LIST not found");
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+
+   SKIP_FOURCC(p_ctx, "hdrl");
+
+   /* Now look for the 'avih' sub-chunk */
+   status = avi_find_chunk(p_ctx, VC_FOURCC('a','v','i','h'), &chunk_size);
+   if (status != VC_CONTAINER_SUCCESS)
+   {
+      LOG_DEBUG(p_ctx, "'avih' not found");
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+
+   /* Parse the 'avih' sub-chunk */
+   SKIP_U32(p_ctx, "dwMicroSecPerFrame");
+   SKIP_U32(p_ctx, "dwMaxBytesPerSec");
+   SKIP_U32(p_ctx, "dwPaddingGranularity");
+   flags = READ_U32(p_ctx, "dwFlags");
+   SKIP_U32(p_ctx, "dwTotalFrames");
+   SKIP_U32(p_ctx, "dwInitialFrames");
+   num_streams = READ_U32(p_ctx, "dwStreams");
+   SKIP_U32(p_ctx, "dwSuggestedBufferSize");
+   SKIP_U32(p_ctx, "dwWidth");
+   SKIP_U32(p_ctx, "dwHeight");
+   SKIP_U32(p_ctx, "dwReserved0");
+   SKIP_U32(p_ctx, "dwReserved1");
+   SKIP_U32(p_ctx, "dwReserved2");
+   SKIP_U32(p_ctx, "dwReserved3");
+
+   if((status = STREAM_STATUS(p_ctx)) != VC_CONTAINER_SUCCESS)
+      goto error;
+
+   /* Allocate our context and tracks */
+   if ((module = malloc(sizeof(*module))) == NULL)
+      return VC_CONTAINER_ERROR_OUT_OF_MEMORY; 
+   memset(module, 0, sizeof(*module));
+   p_ctx->priv->module = module;
+   p_ctx->tracks = module->tracks;
+
+   if (num_streams > AVI_TRACKS_MAX)
+   {
+      LOG_DEBUG(p_ctx, "cannot handle %u tracks, restricted to %d", num_streams, AVI_TRACKS_MAX);
+      num_streams = AVI_TRACKS_MAX; 
+   }
+
+   for (p_ctx->tracks_num = 0; p_ctx->tracks_num != num_streams; p_ctx->tracks_num++)
+   {
+      p_ctx->tracks[p_ctx->tracks_num] = vc_container_allocate_track(p_ctx, sizeof(*p_ctx->tracks[0]->priv->module));
+      if(!p_ctx->tracks[p_ctx->tracks_num]) break;
+   }
+   if(p_ctx->tracks_num != num_streams)
+   { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+
+   /* Try to read stream header list chunks ('strl') */
+   for (i = 0; i != num_streams; ++i)
+   {
+      status = avi_read_stream_header_list(p_ctx, p_ctx->tracks[i], p_ctx->tracks[i]->priv->module);
+      if(status != VC_CONTAINER_SUCCESS) goto error;
+   }
+
+   /* Look for the 'movi' LIST (sub)chunk */
+   status = avi_find_list(p_ctx, VC_FOURCC('m','o','v','i'), &chunk_size);
+   if (status != VC_CONTAINER_SUCCESS)
+   {
+      LOG_DEBUG(p_ctx, "'movi' LIST not found");
+      status = VC_CONTAINER_ERROR_FORMAT_INVALID;
+      goto error;
+   }
+         
+   /* Store offset to the start and size of data (the 'movi' LIST) */
+   module->data_offset = STREAM_POSITION(p_ctx);
+   module->data_size = chunk_size;
+
+   p_ctx->priv->pf_close = avi_reader_close;
+   p_ctx->priv->pf_read = avi_reader_read;
+   p_ctx->priv->pf_seek = avi_reader_seek;
+
+   if (flags & AVIF_MUSTUSEINDEX)
+   {
+      LOG_DEBUG(p_ctx, "AVIF_MUSTUSEINDEX not supported, playback might not work properly");
+   }
+
+   /* If the stream is seekable, see if we can find an index (for at 
+      least one of the tracks); even if we cannot find an index now, 
+      one might become available later (e.g. when the stream grows
+      run-time), in that case we might want to report that we can seek 
+      and re-search for the index again if or when we're requested to 
+      seek. */
+   if(STREAM_SEEKABLE(p_ctx))
+   {
+      p_ctx->capabilities |= VC_CONTAINER_CAPS_CAN_SEEK;
+      p_ctx->capabilities |= VC_CONTAINER_CAPS_FORCE_TRACK;
+
+      for(i = 0; i < p_ctx->tracks_num; i++)
+         if(p_ctx->tracks[i]->priv->module->index_offset) break;
+
+      if (i < p_ctx->tracks_num)
+      {
+         p_ctx->capabilities |= VC_CONTAINER_CAPS_HAS_INDEX;
+         if (flags & AVIF_TRUSTCKTYPE)
+            p_ctx->capabilities |= VC_CONTAINER_CAPS_DATA_HAS_KEYFRAME_FLAG;
+      }
+      else
+      {
+         /* Skip data first */
+         AVI_SKIP_CHUNK(p_ctx, module->data_size);
+         /* Now search for the index */
+         status = avi_find_chunk(p_ctx, VC_FOURCC('i','d','x','1'), &chunk_size);
+         if (status == VC_CONTAINER_SUCCESS)
+         {
+            LOG_DEBUG(p_ctx, "'idx1' found");
+            /* Store offset to index data */
+            module->index_offset = STREAM_POSITION(p_ctx);
+            module->index_size = chunk_size;
+            p_ctx->capabilities |= VC_CONTAINER_CAPS_HAS_INDEX;
+            p_ctx->capabilities |= VC_CONTAINER_CAPS_DATA_HAS_KEYFRAME_FLAG;
+         }
+   
+         /* Seek back to the start of the data */
+         SEEK(p_ctx, module->data_offset);
+      }
+   }
+
+   SKIP_FOURCC(p_ctx, "movi");
+
+   for (i = 0; i != num_streams; i++)
+   {
+      p_ctx->tracks[i]->priv->module->chunk.state = &p_ctx->priv->module->state;
+   }
+   p_ctx->priv->module->state.data_offset = STREAM_POSITION(p_ctx);
+
+   /* Update the tracks to set their data offsets. This help with bad
+      interleaving, for example when there is all the video tracks followed
+      by all the audio tracks. It means we don't have to read through the
+      tracks we are not interested in when forcing a read from a given track,
+      as could be the case in the above example. If this fails we will fall
+      back to skipping track data. */
+   offset = INT64_C(0);
+   avi_reader_seek(p_ctx, &offset, VC_CONTAINER_SEEK_MODE_TIME, VC_CONTAINER_SEEK_FLAG_PRECISE);
+
+   if((status = STREAM_STATUS(p_ctx)) != VC_CONTAINER_SUCCESS) goto error;
+   return VC_CONTAINER_SUCCESS;
+
+error:
+   LOG_DEBUG(p_ctx, "error opening stream (%i)", status);
+   for(i = 0; i < p_ctx->tracks_num; i++)
+      vc_container_free_track(p_ctx, p_ctx->tracks[i]);
+   p_ctx->tracks = NULL;
+   p_ctx->tracks_num = 0;
+   if (module) free(module);
+   p_ctx->priv->module = NULL;
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+ ********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak reader_open avi_reader_open
+#endif
diff --git a/containers/avi/avi_writer.c b/containers/avi/avi_writer.c
new file mode 100755 (executable)
index 0000000..589ee13
--- /dev/null
@@ -0,0 +1,1171 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define CONTAINER_IS_LITTLE_ENDIAN
+//#define ENABLE_CONTAINERS_LOG_FORMAT
+//#define ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
+#define CONTAINER_HELPER_LOG_INDENT(a) 0
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_writer_utils.h"
+#include "containers/core/containers_logging.h"
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+VC_CONTAINER_STATUS_T avi_writer_open( VC_CONTAINER_T *p_ctx );
+
+/******************************************************************************
+Defines.
+******************************************************************************/
+#define AVISF_DISABLED        0x00000001 /*< If set stream should not be enabled by default. */
+#define AVIF_HASINDEX         0x00000010 
+#define AVIF_TRUSTCKTYPE      0x00000800
+#define AVIIF_KEYFRAME        0x00000010
+
+#define AVI_INDEX_OF_INDEXES  0x00
+#define AVI_INDEX_OF_CHUNKS   0x01
+#define AVI_INDEX_DELTAFRAME  0x80000000
+
+#define AVI_INDEX_ENTRY_SIZE        16
+#define AVI_SUPER_INDEX_ENTRY_SIZE  16
+#define AVI_STD_INDEX_ENTRY_SIZE     8
+#define AVI_FRAME_BUFFER_SIZE       100000
+
+#define AVI_TRACKS_MAX 3
+
+#define AVI_AUDIO_CHUNK_SIZE_LIMIT 16384 /*< Watermark limit for data chunks when 'dwSampleSize'
+                                             is non-zero */
+
+#define AVI_END_CHUNK(ctx)                                            \
+   do {                                                               \
+      if(STREAM_POSITION(ctx) & 1) WRITE_U8(ctx, 0, "AVI_END_CHUNK"); \
+   } while(0)
+
+#define AVI_PACKET_KEYFRAME (VC_CONTAINER_PACKET_FLAG_KEYFRAME | VC_CONTAINER_PACKET_FLAG_FRAME_END)
+#define AVI_PACKET_IS_KEYFRAME(flags) (((flags) & AVI_PACKET_KEYFRAME) == AVI_PACKET_KEYFRAME)
+
+/******************************************************************************
+Type definitions.
+******************************************************************************/
+typedef struct VC_CONTAINER_TRACK_MODULE_T
+{
+   uint32_t chunk_index;      /**< index of current chunk */
+   uint32_t chunk_offs;       /**< current offset into bytestream consisting of all 
+                                   chunks for this track  */
+   uint32_t sample_size;      /**< i.e. 'dwSampleSize' in 'strh' */
+   uint32_t max_chunk_size;   /**< largest chunk written so far */
+   uint64_t index_offset;     /**< Offset to the start of an OpenDML index for this track 
+                                   i.e. 'indx' */
+   uint32_t index_size;       /**< Size of the OpenDML index for this track i.e. 'indx' */
+} VC_CONTAINER_TRACK_MODULE_T;
+
+typedef struct VC_CONTAINER_MODULE_T
+{
+   VC_CONTAINER_TRACK_T *tracks[AVI_TRACKS_MAX];
+   VC_CONTAINER_WRITER_EXTRAIO_T null_io; /**< Null I/O for calculating chunk sizes, etc. */
+   VC_CONTAINER_WRITER_EXTRAIO_T temp_io; /**< I/O for temporary storage of index data */
+   int headers_written;
+
+   uint32_t header_list_offset;           /**< Offset to the header list chunk ('hdrl') */
+   uint32_t header_list_size;             /**< Size of the header list chunk ('hdrl') */
+   uint32_t data_offset;                  /**< Offset to the start of data packets i.e. 
+                                               the data in the AVI RIFF 'movi' list */
+   uint64_t data_size;                    /**< Size of the chunk containing data packets */
+   uint32_t index_offset;                 /**< Offset to the start of index data e.g. 
+                                               the data in an 'idx1' list */                                          
+   unsigned current_track_num;            /**< Number of track currently being written */
+   uint32_t chunk_size;                   /**< Final size of the current chunk being written (if known) */
+   uint32_t chunk_data_written;           /**< Data written to the current chunk so far */
+   uint8_t *avi_frame_buffer;             /**< For accumulating whole frames when seeking isn't available. */
+   VC_CONTAINER_PACKET_T frame_packet;    /**< Packet header for whole frame. */
+
+   VC_CONTAINER_STATUS_T index_status;
+} VC_CONTAINER_MODULE_T;
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+static void avi_chunk_id_from_track_num( VC_CONTAINER_T *p_ctx, 
+   VC_CONTAINER_FOURCC_T *p_chunk_id, unsigned int track_num )
+{
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[track_num];
+   VC_CONTAINER_FOURCC_T chunk_id = 0;
+   char track_num_buf[3];
+
+   if(track->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO)
+      chunk_id = VC_FOURCC('0','0','d','c');
+   else if(track->format->es_type == VC_CONTAINER_ES_TYPE_AUDIO)
+      chunk_id = VC_FOURCC('0','0','w','b');
+   else
+   {
+      /* Note that avi_writer_add_track should ensure this 
+         can't happen */
+      *p_chunk_id  = VC_FOURCC('J','U','N','K'); return;
+   }
+
+   snprintf(track_num_buf, sizeof(track_num_buf), "%02d", track_num);
+   memcpy(&chunk_id, track_num_buf, 2);
+
+   *p_chunk_id = chunk_id;
+}
+
+/*****************************************************************************/
+static void avi_index_chunk_id_from_track_num(VC_CONTAINER_FOURCC_T *p_chunk_id, 
+   unsigned int track_num )
+{
+   VC_CONTAINER_FOURCC_T chunk_id = 0;
+   char track_num_buf[3];
+
+   chunk_id = VC_FOURCC('i','x','0','0');
+
+   snprintf(track_num_buf, sizeof(track_num_buf), "%02d", track_num);
+   memcpy(((uint8_t*)&chunk_id) + 2, track_num_buf, 2);
+
+   *p_chunk_id = chunk_id;
+}
+
+/*****************************************************************************/
+static uint32_t avi_num_chunks( VC_CONTAINER_T *p_ctx )
+{
+   unsigned int i;
+   uint32_t num_chunks = 0;
+   for (i = 0; i < p_ctx->tracks_num; i++)
+      num_chunks += p_ctx->tracks[i]->priv->module->chunk_index;
+
+   return num_chunks;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avi_finish_data_chunk( VC_CONTAINER_T *p_ctx, uint32_t chunk_size )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   if (chunk_size)
+   {
+      /* Rewrite the chunk size, this won't be efficient if it happens often */
+      if (STREAM_SEEKABLE(p_ctx))
+      {
+         SEEK(p_ctx, STREAM_POSITION(p_ctx) - chunk_size - 4);
+         WRITE_U32(p_ctx, chunk_size, "Chunk Size");
+         SKIP_BYTES(p_ctx, chunk_size);
+      }
+      else
+      {
+         LOG_DEBUG(p_ctx, "warning, can't rewrite chunk size, data will be malformed");
+         status = VC_CONTAINER_ERROR_FAILED;
+      }
+   }
+      
+   AVI_END_CHUNK(p_ctx);
+
+   if (status != VC_CONTAINER_SUCCESS) status = STREAM_STATUS(p_ctx);
+
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avi_write_index_entry( VC_CONTAINER_T *p_ctx, uint8_t track_num, 
+   uint32_t chunk_size, int keyframe )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   uint32_t deltaframe = keyframe ? 0 : AVI_INDEX_DELTAFRAME;
+
+   vc_container_io_write_uint8(module->temp_io.io, track_num);
+   vc_container_io_write_be_uint32(module->temp_io.io, chunk_size | deltaframe);
+
+   if (module->temp_io.io->status != VC_CONTAINER_SUCCESS)
+   {
+      module->index_status = module->temp_io.io->status;
+      LOG_DEBUG(p_ctx, "warning, couldn't store index data, index data will be incorrect");
+   }
+
+   return module->temp_io.io->status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avi_read_index_entry( VC_CONTAINER_T *p_ctx,
+   unsigned int *p_track_num, uint32_t *p_chunk_size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   uint32_t chunk_size;
+   uint8_t track_num;
+   
+   track_num = vc_container_io_read_uint8(module->temp_io.io);
+   chunk_size = vc_container_io_read_be_uint32(module->temp_io.io);
+
+   /* This shouldn't really happen if the temporary I/O is reliable */
+   if (track_num >= p_ctx->tracks_num) return VC_CONTAINER_ERROR_FAILED;
+      
+   *p_track_num = track_num;
+   *p_chunk_size = chunk_size;
+
+   return module->temp_io.io->status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avi_write_stream_format_chunk(VC_CONTAINER_T *p_ctx, 
+   VC_CONTAINER_TRACK_T *track, uint32_t chunk_size)
+{
+   VC_CONTAINER_STATUS_T status;
+   
+   WRITE_FOURCC(p_ctx, VC_FOURCC('s','t','r','f'), "Chunk ID");
+   WRITE_U32(p_ctx, chunk_size, "Chunk Size");
+  
+   if ((status = STREAM_STATUS(p_ctx)) != VC_CONTAINER_SUCCESS) return status;
+  
+   if(track->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO)
+      status = vc_container_write_bitmapinfoheader(p_ctx, track->format);
+   else if(track->format->es_type == VC_CONTAINER_ES_TYPE_AUDIO)
+      status = vc_container_write_waveformatex(p_ctx, track->format);
+
+   if (status != VC_CONTAINER_SUCCESS) return status;
+
+   AVI_END_CHUNK(p_ctx);
+   
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avi_write_stream_header_chunk(VC_CONTAINER_T *p_ctx, 
+   VC_CONTAINER_TRACK_T *track)
+{
+   VC_CONTAINER_FOURCC_T fourcc_type = 0, fourcc_handler = 0;
+   uint32_t flags, scale = 0, rate = 0, div, start = 0, sample_size = 0;
+   uint16_t left = 0, right = 0, top = 0, bottom = 0;
+   uint32_t max_chunk_size, length = 0;
+   
+   WRITE_FOURCC(p_ctx, VC_FOURCC('s','t','r','h'), "Chunk ID");
+   WRITE_U32(p_ctx, 56, "Chunk Size");
+
+   if (!track->is_enabled)
+      flags = 0; /* AVISF_DISABLED; FIXME: write_media should set this correctly! */
+   else
+      flags = 0;
+
+   if (track->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO)
+   {
+      fourcc_type = VC_FOURCC('v','i','d','s');
+      sample_size = 0;
+      scale = track->format->type->video.frame_rate_den;
+      rate = track->format->type->video.frame_rate_num;
+      if (rate == 0 || scale == 0)
+      {
+         LOG_DEBUG(p_ctx, "invalid video framerate (%d/%d)", rate, scale);
+         LOG_DEBUG(p_ctx, "using 30/1 (playback timing will almost certainly be incorrect)");
+         scale = 1; rate = 30;
+      }
+
+      top = track->format->type->video.y_offset;
+      left = track->format->type->video.x_offset;
+      bottom = track->format->type->video.y_offset + track->format->type->video.visible_height;
+      right = track->format->type->video.x_offset + track->format->type->video.visible_width;
+   }
+   else if (track->format->es_type == VC_CONTAINER_ES_TYPE_AUDIO)
+   {
+      fourcc_type = VC_FOURCC('a','u','d','s');
+      sample_size = track->format->type->audio.block_align;
+      scale = 1;
+
+      if (track->format->type->audio.block_align) 
+         rate = (track->format->bitrate / track->format->type->audio.block_align) >> 3;
+
+      if (rate == 0)
+      {
+         rate = track->format->type->audio.sample_rate ? track->format->type->audio.sample_rate : 32000;
+         LOG_DEBUG(p_ctx, "invalid audio rate, using %d (playback timing will almost certainly be incorrect)", 
+                   rate);
+      }
+   }
+   else
+   {
+      /* avi_writer_add_track should ensure this can't happen */
+      vc_container_assert(0);
+   }
+   
+   fourcc_handler = codec_to_vfw_fourcc(track->format->codec);
+
+   div = vc_container_maths_gcd((int64_t)scale, (int64_t)rate);
+   scale /= div;
+   rate /= div;
+
+   length = sample_size ? track->priv->module->chunk_offs : track->priv->module->chunk_index;
+   max_chunk_size = track->priv->module->max_chunk_size;
+   track->priv->module->sample_size = sample_size;
+
+   WRITE_FOURCC(p_ctx, fourcc_type, "fccType");
+   WRITE_FOURCC(p_ctx, fourcc_handler, "fccHandler");
+   WRITE_U32(p_ctx, flags, "dwFlags");
+   WRITE_U16(p_ctx, 0, "wPriority");
+   WRITE_U16(p_ctx, 0, "wLanguage");
+   WRITE_U32(p_ctx, 0, "dwInitialFrames");
+   WRITE_U32(p_ctx, scale, "dwScale");
+   WRITE_U32(p_ctx, rate, "dwRate");
+   WRITE_U32(p_ctx, start, "dwStart");
+   WRITE_U32(p_ctx, length, "dwLength");
+   WRITE_U32(p_ctx, max_chunk_size, "dwSuggestedBufferSize");
+   WRITE_U32(p_ctx, 0, "dwQuality");
+   WRITE_U32(p_ctx, sample_size, "dwSampleSize");
+   WRITE_U16(p_ctx, left, "rcFrame.left");
+   WRITE_U16(p_ctx, top, "rcFrame.top");
+   WRITE_U16(p_ctx, right, "rcFrame.right");
+   WRITE_U16(p_ctx, bottom, "rcFrame.bottom");
+   
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avi_write_super_index_chunk(VC_CONTAINER_T *p_ctx, unsigned int index_track_num,
+   uint32_t index_size)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[index_track_num]->priv->module;
+   VC_CONTAINER_FOURCC_T chunk_id; 
+   uint32_t num_indices = 1; /* FIXME: support for multiple RIFF chunks (AVIX) */
+   unsigned int i;
+
+   if(module->null_io.refcount)
+   {
+      /* Assume that we're not actually writing the data, just want know the index chunk size */
+      WRITE_BYTES(p_ctx, NULL, 8 + 24 + num_indices * (int64_t)AVI_SUPER_INDEX_ENTRY_SIZE);
+      return STREAM_STATUS(p_ctx);
+   }
+  
+   if (track_module->index_offset)
+      WRITE_FOURCC(p_ctx, VC_FOURCC('i','n','d','x'), "Chunk ID");
+   else
+      WRITE_FOURCC(p_ctx, VC_FOURCC('J','U','N','K'), "Chunk ID");
+      
+   WRITE_U32(p_ctx, index_size, "Chunk Size");
+   
+   avi_chunk_id_from_track_num(p_ctx, &chunk_id, index_track_num);   
+   WRITE_U16(p_ctx, 4, "wLongsPerEntry");
+   WRITE_U8(p_ctx, 0, "bIndexSubType");
+   WRITE_U8(p_ctx, AVI_INDEX_OF_INDEXES, "bIndexType");
+   WRITE_U32(p_ctx, num_indices, "nEntriesInUse");
+   WRITE_FOURCC(p_ctx, chunk_id, "dwChunkId");
+   WRITE_U32(p_ctx, 0, "dwReserved0");
+   WRITE_U32(p_ctx, 0, "dwReserved1");
+   WRITE_U32(p_ctx, 0, "dwReserved2");
+   
+   for (i = 0; i < num_indices; ++i)
+   {  
+      uint64_t index_offset = track_module->index_offset;
+      uint32_t chunk_size = track_module->index_size;  
+      uint32_t length = track_module->sample_size ? 
+         track_module->chunk_offs : track_module->chunk_index;
+      WRITE_U64(p_ctx, index_offset, "qwOffset");
+      WRITE_U32(p_ctx, chunk_size, "dwSize");
+      WRITE_U32(p_ctx, length, "dwDuration");
+   }
+
+   AVI_END_CHUNK(p_ctx);
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avi_write_stream_header_list(VC_CONTAINER_T *p_ctx, 
+   unsigned int track_num, uint32_t list_size)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[track_num];
+   VC_CONTAINER_STATUS_T status;
+   uint32_t chunk_size = 0;
+
+   WRITE_FOURCC(p_ctx, VC_FOURCC('L','I','S','T'), "Chunk ID");
+   WRITE_U32(p_ctx, list_size, "LIST Size");
+   WRITE_FOURCC(p_ctx, VC_FOURCC('s','t','r','l'), "Chunk ID");
+
+   if ((status = STREAM_STATUS(p_ctx)) != VC_CONTAINER_SUCCESS) return status;
+
+   /* Write the stream header chunk ('strh') */
+   status = avi_write_stream_header_chunk(p_ctx, track);
+   if (status != VC_CONTAINER_SUCCESS) return status;
+
+   /* Write the stream format chunk ('strf') */
+   if(!vc_container_writer_extraio_enable(p_ctx, &module->null_io))
+   {
+      status = avi_write_stream_format_chunk(p_ctx, track, 0);
+      chunk_size = STREAM_POSITION(p_ctx) - 8;
+   }
+   vc_container_writer_extraio_disable(p_ctx, &module->null_io);
+      
+   status = avi_write_stream_format_chunk(p_ctx, track, chunk_size);
+   if (status != VC_CONTAINER_SUCCESS) return status;
+
+   /* If the track has DRM data, write it into the 'strd' chunk (we don't write
+      write codec configuration data into 'strd') */
+   if (track->priv->drmdata && track->priv->drmdata_size)
+   {
+      WRITE_FOURCC(p_ctx, VC_FOURCC('s','t','r','d'), "Chunk ID");
+      WRITE_U32(p_ctx, track->priv->drmdata_size, "Chunk Size");
+      WRITE_BYTES(p_ctx, track->priv->drmdata, track->priv->drmdata_size);
+      AVI_END_CHUNK(p_ctx);
+      if ((status = STREAM_STATUS(p_ctx)) != VC_CONTAINER_SUCCESS) return status;
+   }
+
+   /* Write the super index chunk ('indx') */
+   if(!vc_container_writer_extraio_enable(p_ctx, &module->null_io))
+   {
+      status = avi_write_super_index_chunk(p_ctx, track_num, 0);
+      chunk_size = STREAM_POSITION(p_ctx) - 8;
+   }
+   vc_container_writer_extraio_disable(p_ctx, &module->null_io);
+      
+   status = avi_write_super_index_chunk(p_ctx, track_num, chunk_size);
+   if (status != VC_CONTAINER_SUCCESS) return status;
+      
+   AVI_END_CHUNK(p_ctx);
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avi_write_avi_header_chunk(VC_CONTAINER_T *p_ctx)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   uint32_t bitrate = 0, width = 0, height = 0, frame_interval = 0;
+   uint32_t flags, num_chunks = 0, max_video_chunk_size = 0;
+   uint32_t num_streams = p_ctx->tracks_num;
+   unsigned int i;
+
+   for (i = 0; i < p_ctx->tracks_num; i++)
+   {
+      VC_CONTAINER_TRACK_T *track = p_ctx->tracks[i];
+      VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[i]->priv->module;
+      if (track->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO)
+      {
+         width = track->format->type->video.width;
+         height = track->format->type->video.height;
+         if (track->format->type->video.frame_rate_num)
+            frame_interval = track->format->type->video.frame_rate_den * UINT64_C(1000000) / 
+                              track->format->type->video.frame_rate_num;
+         num_chunks = track_module->chunk_index;
+         max_video_chunk_size = track_module->max_chunk_size;
+         break;
+      }
+   }
+
+   flags = (module->index_offset && module->index_status == VC_CONTAINER_SUCCESS) ? 
+      (AVIF_HASINDEX | AVIF_TRUSTCKTYPE) : 0;
+
+   WRITE_FOURCC(p_ctx, VC_FOURCC('a','v','i','h'), "Chunk ID");
+   WRITE_U32(p_ctx, 56, "Chunk Size");
+   WRITE_U32(p_ctx, frame_interval, "dwMicroSecPerFrame");
+   WRITE_U32(p_ctx, bitrate >> 3, "dwMaxBytesPerSec");
+   WRITE_U32(p_ctx, 0, "dwPaddingGranularity");
+   WRITE_U32(p_ctx, flags, "dwFlags");
+   WRITE_U32(p_ctx, num_chunks, "dwTotalFrames");
+   WRITE_U32(p_ctx, 0, "dwInitialFrames");
+   WRITE_U32(p_ctx, num_streams, "dwStreams");
+   WRITE_U32(p_ctx, max_video_chunk_size, "dwSuggestedBufferSize");
+   WRITE_U32(p_ctx, width, "dwWidth");
+   WRITE_U32(p_ctx, height, "dwHeight");
+   WRITE_U32(p_ctx, 0, "dwReserved0");
+   WRITE_U32(p_ctx, 0, "dwReserved1");
+   WRITE_U32(p_ctx, 0, "dwReserved2");
+   WRITE_U32(p_ctx, 0, "dwReserved3");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avi_write_header_list( VC_CONTAINER_T *p_ctx, uint32_t header_list_size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status;
+   unsigned int i;
+   
+   WRITE_FOURCC(p_ctx, VC_FOURCC('L','I','S','T'), "Chunk ID");
+   WRITE_U32(p_ctx, header_list_size, "LIST Size");
+   WRITE_FOURCC(p_ctx, VC_FOURCC('h','d','r','l'), "Chunk ID");
+   if ((status = STREAM_STATUS(p_ctx)) != VC_CONTAINER_SUCCESS) return status;
+
+   /* Write the main AVI header chunk ('avih') */
+   if ((status = avi_write_avi_header_chunk(p_ctx)) != VC_CONTAINER_SUCCESS)
+      return status;
+
+   for (i = 0; i < p_ctx->tracks_num; i++)
+   {
+      uint32_t list_size = 0;
+      
+      /* Write a stream header list chunk ('strl') */
+      if(!vc_container_writer_extraio_enable(p_ctx, &module->null_io))
+      {
+         status = avi_write_stream_header_list(p_ctx, i, 0);
+         if (status != VC_CONTAINER_SUCCESS) return status;
+         list_size = STREAM_POSITION(p_ctx) - 8;
+      }
+      vc_container_writer_extraio_disable(p_ctx, &module->null_io);
+   
+      status = avi_write_stream_header_list(p_ctx, i, list_size);
+      if (status != VC_CONTAINER_SUCCESS) return status;
+   }
+
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avi_write_headers( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status;
+   uint32_t header_list_offset, header_list_size = 0;
+
+   /* Write the header list chunk ('hdrl') */
+   if(!vc_container_writer_extraio_enable(p_ctx, &module->null_io))
+   {
+      status = avi_write_header_list(p_ctx, 0);
+      if (status != VC_CONTAINER_SUCCESS) return status;
+      header_list_size = STREAM_POSITION(p_ctx) - 8;
+   }
+   vc_container_writer_extraio_disable(p_ctx, &module->null_io);
+
+   header_list_offset = STREAM_POSITION(p_ctx);
+   status = avi_write_header_list(p_ctx, header_list_size);
+   if (status == VC_CONTAINER_SUCCESS && !module->header_list_offset)
+   {
+      module->header_list_offset = header_list_offset;
+      module->header_list_size = header_list_size;
+   }
+   
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avi_write_legacy_index_chunk( VC_CONTAINER_T *p_ctx, uint32_t index_size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status;
+   uint32_t chunk_offset = 4;
+   unsigned int track_num;
+
+   vc_container_assert(8 + avi_num_chunks(p_ctx) * INT64_C(16) <= (int64_t)ULONG_MAX);
+
+   if(module->null_io.refcount)
+   {
+      /* Assume that we're not actually writing the data, 
+         just want know the index size */
+      WRITE_BYTES(p_ctx, NULL, 8 + avi_num_chunks(p_ctx) * (int64_t)AVI_INDEX_ENTRY_SIZE);
+      return STREAM_STATUS(p_ctx);
+   }
+      
+   module->index_offset = STREAM_POSITION(p_ctx);
+  
+   WRITE_FOURCC(p_ctx, VC_FOURCC('i','d','x','1'), "Chunk ID");
+   WRITE_U32(p_ctx, index_size, "Chunk Size");
+
+   /* Scan through all written entries, convert to appropriate index format */
+   vc_container_io_seek(module->temp_io.io, INT64_C(0));
+   
+   while((status = STREAM_STATUS(p_ctx)) == VC_CONTAINER_SUCCESS)
+   {      
+      VC_CONTAINER_FOURCC_T chunk_id;
+      uint32_t chunk_size, flags;
+      
+      status = avi_read_index_entry(p_ctx, &track_num, &chunk_size);
+      if (status != VC_CONTAINER_SUCCESS) break;
+
+      avi_chunk_id_from_track_num(p_ctx, &chunk_id, track_num);
+      flags = (chunk_size & AVI_INDEX_DELTAFRAME) ? 0 : AVIIF_KEYFRAME;
+      chunk_size &= ~AVI_INDEX_DELTAFRAME;
+   
+      WRITE_FOURCC(p_ctx, chunk_id, "Chunk ID");
+      WRITE_U32(p_ctx, flags, "dwFlags");
+      WRITE_U32(p_ctx, chunk_offset, "dwOffset");
+      WRITE_U32(p_ctx, chunk_size, "dwSize");
+      
+      chunk_offset += ((chunk_size + 1) & ~1) + 8;
+   }
+   
+   AVI_END_CHUNK(p_ctx);
+
+   /* Note that currently, we might write a partial index but still set AVIF_HASINDEX */
+   /* if ( STREAM_STATUS(p_ctx) != VC_CONTAINER_SUCCESS ) module->index_offset = 0 */
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avi_write_standard_index_chunk( VC_CONTAINER_T *p_ctx, unsigned int index_track_num, 
+   uint32_t index_size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[index_track_num]->priv->module;
+   VC_CONTAINER_STATUS_T status;
+   VC_CONTAINER_FOURCC_T chunk_id; 
+   int64_t base_offset = module->data_offset + 12;
+   uint32_t num_chunks = track_module->chunk_index;
+   uint32_t chunk_offset = 4;
+
+   vc_container_assert(32 + num_chunks * (int64_t)AVI_STD_INDEX_ENTRY_SIZE <= (int64_t)ULONG_MAX);
+
+   if(module->null_io.refcount)
+   {
+      /* Assume that we're not actually writing the data, just want know the index chunk size */
+      WRITE_BYTES(p_ctx, NULL, 8 + 24 + num_chunks * INT64_C(8));
+      return STREAM_STATUS(p_ctx);
+   }
+
+   track_module->index_offset = STREAM_POSITION(p_ctx);
+   track_module->index_size = index_size ? (index_size - 8) : 0;
+
+   avi_index_chunk_id_from_track_num(&chunk_id, index_track_num);
+   WRITE_FOURCC(p_ctx, chunk_id, "Chunk ID");
+   WRITE_U32(p_ctx, index_size, "Chunk Size");
+
+   avi_chunk_id_from_track_num(p_ctx, &chunk_id, index_track_num);
+   WRITE_U16(p_ctx, 2, "wLongsPerEntry");
+   WRITE_U8(p_ctx, 0, "bIndexSubType");
+   WRITE_U8(p_ctx, AVI_INDEX_OF_CHUNKS, "bIndexType");
+   WRITE_U32(p_ctx, num_chunks, "nEntriesInUse");
+   WRITE_FOURCC(p_ctx, chunk_id, "dwChunkId");
+   WRITE_U64(p_ctx, base_offset, "qwBaseOffset");
+   WRITE_U32(p_ctx, 0, "dwReserved");
+
+   /* Scan through all written entries, convert to appropriate index format */
+   vc_container_io_seek(module->temp_io.io, INT64_C(0));
+   
+   while(STREAM_STATUS(p_ctx) == VC_CONTAINER_SUCCESS)
+   {      
+      uint32_t chunk_size;
+      unsigned int track_num;
+      
+      status = avi_read_index_entry(p_ctx, &track_num, &chunk_size);
+      if (status != VC_CONTAINER_SUCCESS) break;
+         
+      if(track_num != index_track_num) continue;
+   
+      WRITE_U32(p_ctx, chunk_offset, "dwOffset");
+      WRITE_U32(p_ctx, chunk_size, "dwSize");
+
+      chunk_offset += ((chunk_size + 1) & ~(1 | AVI_INDEX_DELTAFRAME)) + 12;
+   }
+   
+   AVI_END_CHUNK(p_ctx);
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avi_write_legacy_index_data( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;   
+   uint32_t chunk_size = 0;
+
+   /* Write the legacy index chunk ('idx1') */
+   if(!vc_container_writer_extraio_enable(p_ctx, &module->null_io))
+   {
+      status = avi_write_legacy_index_chunk(p_ctx, 0);
+      if (status != VC_CONTAINER_SUCCESS) return status;
+      chunk_size = STREAM_POSITION(p_ctx) - 8;
+   }
+   vc_container_writer_extraio_disable(p_ctx, &module->null_io);
+
+   status = avi_write_legacy_index_chunk(p_ctx, chunk_size);  
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avi_write_standard_index_data( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   uint32_t chunk_size = 0;
+   unsigned int i;
+
+   /* Write the standard index chunks ('ix00') */
+   for (i = 0; i < p_ctx->tracks_num; i++)
+   {
+      if(!vc_container_writer_extraio_enable(p_ctx, &module->null_io))
+      {
+         status = avi_write_standard_index_chunk(p_ctx, i, 0);
+         if (status != VC_CONTAINER_SUCCESS) return status;
+         chunk_size = STREAM_POSITION(p_ctx) - 8;
+      }
+      vc_container_writer_extraio_disable(p_ctx, &module->null_io);
+   
+      status = avi_write_standard_index_chunk(p_ctx, i, chunk_size);
+      if (status != VC_CONTAINER_SUCCESS) return status;
+   }
+   
+   return status;
+}
+
+/*****************************************************************************/
+static int64_t avi_calculate_file_size( VC_CONTAINER_T *p_ctx, 
+   VC_CONTAINER_PACKET_T *p_packet )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   int64_t filesize = 0;
+   int refcount;
+
+   /* Start from current file position */
+   filesize = STREAM_POSITION(p_ctx);
+
+   refcount = vc_container_writer_extraio_enable(p_ctx, &module->null_io);
+   vc_container_assert(refcount == 0); /* Although perfectly harmless, we should 
+                                          not be called with the null i/o enabled. */
+   VC_CONTAINER_PARAM_UNUSED(refcount);
+
+   do {
+      /* If we know what the final size of the chunk is going to be,
+         we can use that here to avoid writing a partial final packet */
+      WRITE_BYTES(p_ctx, NULL, p_packet->frame_size ? p_packet->frame_size : p_packet->size);
+      AVI_END_CHUNK(p_ctx);
+      
+      /* Index entries for the chunk */
+      WRITE_BYTES(p_ctx, NULL, AVI_INDEX_ENTRY_SIZE + AVI_STD_INDEX_ENTRY_SIZE);
+      
+      /* Current standard index data */
+      if (avi_write_standard_index_data(p_ctx) != VC_CONTAINER_SUCCESS) break;
+      
+      /* Current legacy index data */
+      status = avi_write_legacy_index_data(p_ctx);
+      if (status != VC_CONTAINER_SUCCESS) break;
+   } while(0);
+   
+   filesize += STREAM_POSITION(p_ctx);
+
+   vc_container_writer_extraio_disable(p_ctx, &module->null_io);
+
+   return filesize;
+}
+
+/*****************************************************************************
+Functions exported as part of the Container Module API
+ *****************************************************************************/
+static VC_CONTAINER_STATUS_T avi_writer_write( VC_CONTAINER_T *p_ctx,
+                                               VC_CONTAINER_PACKET_T *p_packet )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_TRACK_T *track = NULL;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = NULL;
+
+   /* Check we have written headers before any data */
+   if(!module->headers_written)
+   {
+      if ((status = avi_write_headers(p_ctx)) != VC_CONTAINER_SUCCESS) return status;
+      module->headers_written = 1;
+   }
+
+   /* Check that we have started the 'movi' list */
+   if (!module->data_offset)
+   {
+      module->data_offset = STREAM_POSITION(p_ctx);
+      vc_container_assert(module->data_offset != INT64_C(0));
+
+      WRITE_FOURCC(p_ctx, VC_FOURCC('L','I','S','T'), "Chunk ID");
+      WRITE_U32(p_ctx, 0, "LIST Size");
+      WRITE_FOURCC(p_ctx, VC_FOURCC('m','o','v','i'), "Chunk ID");
+      if ((status = STREAM_STATUS(p_ctx)) != VC_CONTAINER_SUCCESS) return status;
+   }
+
+   /* If the container is passing in a frame from a new track but we 
+      arent't finished with a chunk from another track we need to finish 
+      that chunk first */
+   if (module->chunk_data_written && p_packet->track != module->current_track_num)
+   {
+      track_module = p_ctx->tracks[module->current_track_num]->priv->module;
+      status = avi_finish_data_chunk(p_ctx, module->chunk_data_written);
+      avi_write_index_entry(p_ctx, module->current_track_num, module->chunk_data_written, 0);
+      track_module->chunk_index++;
+      track_module->chunk_offs += module->chunk_data_written;
+      track_module->max_chunk_size = MAX(track_module->max_chunk_size, module->chunk_data_written);
+      module->chunk_data_written = 0;
+      if (status != VC_CONTAINER_SUCCESS) return status;
+   }
+
+   /* Check we are not about to go over the limit of total number of chunks */
+   if (avi_num_chunks(p_ctx) == (uint32_t)ULONG_MAX) return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+
+    if(STREAM_SEEKABLE(p_ctx))
+    {
+       /* Check we are not about to go over the maximum file size */
+       if (avi_calculate_file_size(p_ctx, p_packet) >= (int64_t)ULONG_MAX) return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+    }
+
+   /* FIXME: are we expected to handle this case or should it be picked up by the above layer? */
+   vc_container_assert(!(module->chunk_data_written && (p_packet->flags & VC_CONTAINER_PACKET_FLAG_FRAME_START)));
+   
+   track = p_ctx->tracks[p_packet->track];
+   track_module = p_ctx->tracks[p_packet->track]->priv->module;
+   module->current_track_num = p_packet->track;
+
+   if (module->chunk_data_written == 0)
+   {
+      /* This is the first fragment of the chunk */
+      VC_CONTAINER_FOURCC_T chunk_id;
+      uint32_t chunk_size;
+
+      avi_chunk_id_from_track_num(p_ctx, &chunk_id, p_packet->track);
+
+      if (p_packet->frame_size)
+      {
+         /* We know what the final size of the chunk is going to be */
+         chunk_size = module->chunk_size = p_packet->frame_size;
+      }
+      else
+      {
+         chunk_size = p_packet->size;
+         module->chunk_size = 0;
+      }
+
+      WRITE_FOURCC(p_ctx, chunk_id, "Chunk ID");
+      if(STREAM_SEEKABLE(p_ctx) || p_packet->flags & VC_CONTAINER_PACKET_FLAG_FRAME_END)
+      {
+         /* If the output stream can seek we can fix up the frame size later, and if the
+          * packet holds the whole frame we won't need to, so write data straight out. */
+         WRITE_U32(p_ctx, chunk_size, "Chunk Size");
+         WRITE_BYTES(p_ctx, p_packet->data, p_packet->size);
+      }
+      else
+      {
+         vc_container_assert(module->avi_frame_buffer);
+         if(p_packet->size > AVI_FRAME_BUFFER_SIZE)
+            return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+         module->frame_packet = *p_packet;
+         module->frame_packet.data = module->avi_frame_buffer;
+         memcpy(module->frame_packet.data, 
+                  p_packet->data, module->frame_packet.size);
+      }
+      
+      module->chunk_data_written = p_packet->size;
+   }
+   else
+   {
+      if(module->frame_packet.size > 0 && module->avi_frame_buffer)
+      {
+         if(module->frame_packet.size > 0)
+         {
+            if(module->frame_packet.size + p_packet->size > AVI_FRAME_BUFFER_SIZE)
+               return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+            memcpy(module->frame_packet.data + module->frame_packet.size, 
+                     p_packet->data, p_packet->size);
+            module->frame_packet.size += p_packet->size;
+         }
+      }
+      else
+      {
+         WRITE_BYTES(p_ctx, p_packet->data, p_packet->size);
+      }
+      module->chunk_data_written += p_packet->size;
+   }
+
+   if ((status = STREAM_STATUS(p_ctx)) != VC_CONTAINER_SUCCESS) 
+      return status;
+
+   if ((p_packet->flags & VC_CONTAINER_PACKET_FLAG_FRAME_END) ||
+       (track->format->es_type == VC_CONTAINER_ES_TYPE_AUDIO && 
+        track->format->type->audio.block_align &&
+        module->chunk_data_written > AVI_AUDIO_CHUNK_SIZE_LIMIT))
+   {
+      if(module->frame_packet.size > 0)
+      {
+         WRITE_U32(p_ctx, module->frame_packet.size, "Chunk Size");
+         WRITE_BYTES(p_ctx, module->frame_packet.data, module->frame_packet.size);
+         p_packet->size = module->frame_packet.size;
+         module->frame_packet.size = 0;
+      }
+      
+      if (!module->chunk_size && module->chunk_data_written > p_packet->size)
+      {
+         /* The chunk size needs to be rewritten */
+         status = avi_finish_data_chunk(p_ctx, module->chunk_data_written);
+      }
+      else
+      {
+         status = avi_finish_data_chunk(p_ctx, 0);
+      }
+
+      if(!STREAM_SEEKABLE(p_ctx))
+      {
+         /* If we are streaming then flush to avoid delaying data transport. */
+         vc_container_control(p_ctx, VC_CONTAINER_CONTROL_IO_FLUSH);
+      }
+
+      if(STREAM_SEEKABLE(p_ctx))
+      {
+          /* Keep track of data written so we can check we don't exceed file size and also for doing
+           * index fix-ups, but only do this if we are writing to a seekable IO. */
+          avi_write_index_entry(p_ctx, p_packet->track, module->chunk_data_written, AVI_PACKET_IS_KEYFRAME(p_packet->flags));
+      }
+      track_module->chunk_index++;
+      track_module->chunk_offs += module->chunk_data_written;
+      track_module->max_chunk_size = MAX(track_module->max_chunk_size, module->chunk_data_written);
+      module->chunk_data_written = 0;
+
+      if (status != VC_CONTAINER_SUCCESS) return status;
+   }
+
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avi_writer_close( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   unsigned int i;
+
+   /* If we arent't finished with a chunk we need to finish it first */
+   if (module->chunk_data_written)
+   {
+      VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[module->current_track_num]->priv->module;
+      status = avi_finish_data_chunk(p_ctx, module->chunk_data_written);
+      if (status != VC_CONTAINER_SUCCESS)
+      {       
+         LOG_DEBUG(p_ctx, "warning, writing failed, last chunk truncated");
+      }      
+      avi_write_index_entry(p_ctx, module->current_track_num, module->chunk_data_written, 0);
+      track_module->chunk_index++;
+      track_module->chunk_offs += module->chunk_data_written;
+      track_module->max_chunk_size = MAX(track_module->max_chunk_size, module->chunk_data_written);
+      module->chunk_data_written = 0;
+   }
+
+   if(STREAM_SEEKABLE(p_ctx))
+   {
+      uint32_t filesize;
+
+      /* Write standard index data before finalising the size of the 'movi' list */
+      status = avi_write_standard_index_data(p_ctx);
+      if (status != VC_CONTAINER_SUCCESS)
+      {
+         module->index_status = status;
+         LOG_DEBUG(p_ctx, "warning, writing standard index data failed, file will be malformed");
+      }
+
+      /* FIXME: support for multiple RIFF chunks (AVIX) */
+      module->data_size = STREAM_POSITION(p_ctx) - module->data_offset - 8;
+
+      /* Now write the legacy index */
+      status = avi_write_legacy_index_data(p_ctx);
+      if (status != VC_CONTAINER_SUCCESS)
+      {
+         module->index_status = status;
+         LOG_DEBUG(p_ctx, "warning, writing legacy index data failed, file will be malformed");
+      }
+
+      /* If we can, do the necessary fixups for values not know at the
+       time of writing chunk headers */
+
+      /* Rewrite the AVI RIFF chunk size */
+      filesize = (uint32_t)STREAM_POSITION(p_ctx);
+      SEEK(p_ctx, 4);
+      WRITE_U32(p_ctx, filesize, "fileSize");
+      if(STREAM_STATUS(p_ctx) != VC_CONTAINER_SUCCESS)
+      {
+         LOG_DEBUG(p_ctx, "warning, rewriting 'fileSize' failed, file will be malformed");
+      }   
+
+      /* Rewrite the header list chunk ('hdrl') */
+      SEEK(p_ctx, module->header_list_offset);
+      status = avi_write_header_list(p_ctx, module->header_list_size);
+      if (status != VC_CONTAINER_SUCCESS)
+      {
+         LOG_DEBUG(p_ctx, "warning, rewriting 'hdrl' failed, file will be malformed");
+      }
+
+      /* Rewrite the AVI RIFF 'movi' list size */
+      SEEK(p_ctx, module->data_offset + 4);
+      WRITE_U32(p_ctx, module->data_size, "Chunk Size");
+      if(STREAM_STATUS(p_ctx) != VC_CONTAINER_SUCCESS)
+      {
+         LOG_DEBUG(p_ctx, "warning, rewriting 'movi' list size failed, file will be malformed");
+      }
+   }
+
+   vc_container_writer_extraio_delete(p_ctx, &module->null_io);
+   if(module->temp_io.io) vc_container_writer_extraio_delete(p_ctx, &module->temp_io);
+
+   for(i = 0; i < p_ctx->tracks_num; i++)
+      vc_container_free_track(p_ctx, p_ctx->tracks[i]);
+   p_ctx->tracks_num = 0;
+   p_ctx->tracks = NULL;
+
+   if(module->avi_frame_buffer) free(module->avi_frame_buffer);
+   free(module);
+
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avi_writer_add_track( VC_CONTAINER_T *p_ctx, VC_CONTAINER_ES_FORMAT_T *format )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_TRACK_T *track = NULL;
+
+   if (module->headers_written) return VC_CONTAINER_ERROR_FAILED;
+
+   /* FIXME: should we check the format in more detail? */
+   if((format->es_type != VC_CONTAINER_ES_TYPE_VIDEO && format->es_type != VC_CONTAINER_ES_TYPE_AUDIO) ||
+      format->codec == VC_CONTAINER_CODEC_UNKNOWN)
+      return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+
+   if(!(format->flags & VC_CONTAINER_ES_FORMAT_FLAG_FRAMED))
+      return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+
+   /* Allocate new track */
+   if(p_ctx->tracks_num >= AVI_TRACKS_MAX) return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+   p_ctx->tracks[p_ctx->tracks_num] = track =
+      vc_container_allocate_track(p_ctx, sizeof(*p_ctx->tracks[0]->priv->module));
+   if(!track) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+
+   if(format->extradata_size)
+   {
+      status = vc_container_track_allocate_extradata( p_ctx, track, format->extradata_size );
+      if(status) goto error;
+   }
+
+   status = vc_container_format_copy(track->format, format, format->extradata_size);
+   if(status) goto error;
+
+   p_ctx->tracks_num++;
+   return VC_CONTAINER_SUCCESS;
+
+error:
+   vc_container_free_track(p_ctx, track);
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avi_writer_control( VC_CONTAINER_T *p_ctx, VC_CONTAINER_CONTROL_T operation, va_list args )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status;
+   
+   switch(operation)
+   {
+      case VC_CONTAINER_CONTROL_TRACK_ADD:
+      {
+         VC_CONTAINER_ES_FORMAT_T *format =
+            (VC_CONTAINER_ES_FORMAT_T *)va_arg( args, VC_CONTAINER_ES_FORMAT_T * );
+         return avi_writer_add_track(p_ctx, format);
+      }
+      case VC_CONTAINER_CONTROL_TRACK_ADD_DONE:
+      {
+         if(!module->headers_written)
+         {
+            if ((status = avi_write_headers(p_ctx)) != VC_CONTAINER_SUCCESS) return status;
+            module->headers_written = 1;
+            return VC_CONTAINER_SUCCESS;
+         }
+         else
+            return VC_CONTAINER_ERROR_FAILED;
+      }
+      default: return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+   }
+}
+
+/******************************************************************************
+Global function definitions.
+******************************************************************************/
+VC_CONTAINER_STATUS_T avi_writer_open( VC_CONTAINER_T *p_ctx )
+{
+   const char *extension = vc_uri_path_extension(p_ctx->priv->uri);
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_MODULE_T *module = 0;
+
+   /* Check if the user has specified a container */
+   vc_uri_find_query(p_ctx->priv->uri, 0, "container", &extension);
+
+   /* Check we're the right writer for this */
+   if(!extension)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   if(strcasecmp(extension, "avi") && strcasecmp(extension, "divx"))
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   /* Allocate our context */
+   module = malloc(sizeof(*module));
+   if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(module, 0, sizeof(*module));
+   p_ctx->priv->module = module;
+
+   /* Create a null i/o writer to help us out in writing our data */
+   status = vc_container_writer_extraio_create_null(p_ctx, &module->null_io);
+   if(status != VC_CONTAINER_SUCCESS) goto error;
+
+   if(STREAM_SEEKABLE(p_ctx))
+   {
+       /* Create a temporary i/o writer for storage of index data while we are writing */
+       status = vc_container_writer_extraio_create_temp(p_ctx, &module->temp_io);
+       if(status != VC_CONTAINER_SUCCESS) goto error;
+   }
+   else
+   {
+      module->avi_frame_buffer = malloc(AVI_FRAME_BUFFER_SIZE);
+      if(!module->avi_frame_buffer)
+         { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   }
+   module->frame_packet.size = 0;
+
+   p_ctx->tracks = module->tracks;
+
+   /* Write the RIFF chunk descriptor */
+   WRITE_FOURCC(p_ctx, VC_FOURCC('R','I','F','F'), "RIFF ID");
+   WRITE_U32(p_ctx, 0, "fileSize");
+   WRITE_FOURCC(p_ctx, VC_FOURCC('A','V','I',' '), "fileType");
+   
+   if((status = STREAM_STATUS(p_ctx)) != VC_CONTAINER_SUCCESS) goto error;
+
+   p_ctx->priv->pf_close = avi_writer_close;
+   p_ctx->priv->pf_write = avi_writer_write;
+   p_ctx->priv->pf_control = avi_writer_control;
+
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+   LOG_DEBUG(p_ctx, "error opening stream");
+   p_ctx->tracks_num = 0;
+   p_ctx->tracks = NULL;
+   if(module)
+   {
+      if(module->avi_frame_buffer) free(module->avi_frame_buffer);
+      free(module);
+   }
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+ ********************************************************************************/
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak writer_open avi_writer_open
+#endif
diff --git a/containers/binary/CMakeLists.txt b/containers/binary/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..c159b40
--- /dev/null
@@ -0,0 +1,19 @@
+# Container module needs to go in as a plugins so different prefix
+# and install path
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+
+# Make sure the compiler can find the necessary include files
+include_directories (../..)
+
+add_library(reader_binary ${LIBRARY_TYPE} binary_reader.c)
+
+target_link_libraries(reader_binary containers)
+
+install(TARGETS reader_binary DESTINATION ${VMCS_PLUGIN_DIR})
+
+add_library(writer_binary ${LIBRARY_TYPE} binary_writer.c)
+
+target_link_libraries(writer_binary containers)
+
+install(TARGETS writer_binary DESTINATION ${VMCS_PLUGIN_DIR})
+
diff --git a/containers/binary/binary_reader.c b/containers/binary/binary_reader.c
new file mode 100755 (executable)
index 0000000..0bcf389
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <string.h>
+
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_logging.h"
+
+/******************************************************************************
+Defines.
+******************************************************************************/
+#define DEFAULT_BLOCK_SIZE (1024*16)
+/* Work-around for JPEG because our decoder expects that much at the start */
+#define DEFAULT_JPEG_BLOCK_SIZE (1024*80)
+
+/******************************************************************************
+Type definitions
+******************************************************************************/
+typedef struct VC_CONTAINER_MODULE_T
+{
+   VC_CONTAINER_TRACK_T *track;
+   unsigned int default_block_size;
+   unsigned int block_size;
+   bool init;
+
+   VC_CONTAINER_STATUS_T status;
+
+} VC_CONTAINER_MODULE_T;
+
+static struct
+{
+   const char *ext;
+   VC_CONTAINER_ES_TYPE_T type;
+   VC_CONTAINER_FOURCC_T codec;
+
+} extension_to_format_table[] =
+{
+   /* Audio */
+   {"mp3",     VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_MPGA},
+   {"aac",     VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_MP4A},
+   {"adts",    VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_MP4A},
+   {"ac3",     VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_AC3},
+   {"ec3",     VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_EAC3},
+   {"amr",     VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_AMRNB},
+   {"awb",     VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_AMRWB},
+   {"evrc",    VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_EVRC},
+   {"dts",     VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_DTS},
+
+   /* Video */
+   {"m1v",     VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_MP1V},
+   {"m2v",     VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_MP2V},
+   {"m4v",     VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_MP4V},
+   {"mp4v",    VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_MP4V},
+   {"h263",    VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_H263},
+   {"263",     VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_H263},
+   {"h264",    VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_H264},
+   {"264",     VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_H264},
+   {"mvc",     VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_MVC},
+   {"vc1l",    VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_WVC1},
+
+   /* Image */ 
+   {"gif",     VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_GIF},
+   {"jpg",     VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_JPEG},
+   {"jpeg",    VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_JPEG},
+   {"png",     VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_PNG},
+   {"ppm",     VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_PPM},
+   {"tga",     VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_TGA},
+   {"bmp",     VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_BMP},
+
+   {"bin",     0, 0},
+   {0, 0, 0}
+};
+
+static struct
+{
+   const char *ext;
+   VC_CONTAINER_ES_TYPE_T type;
+   VC_CONTAINER_FOURCC_T codec;
+
+} bin_extension_to_format_table[] =
+{
+   {"m4v.bin", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_MP4V},
+   {"263.bin", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_H263},
+   {"264.bin", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_H264},
+   {0, 0, 0}
+};
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+VC_CONTAINER_STATUS_T binary_reader_open( VC_CONTAINER_T * );
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+
+/*****************************************************************************
+Functions exported as part of the Container Module API
+ *****************************************************************************/
+static VC_CONTAINER_STATUS_T binary_reader_read( VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_PACKET_T *packet, uint32_t flags )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   unsigned int size;
+
+   if(module->status != VC_CONTAINER_SUCCESS)
+      return module->status;
+
+   if(!module->block_size)
+   {
+      module->block_size = module->default_block_size;
+      module->init = 0;
+   }
+
+   packet->size = module->block_size;
+   packet->dts = packet->pts = VC_CONTAINER_TIME_UNKNOWN;
+   if(module->init) packet->dts = packet->pts = 0;
+   packet->track = 0;
+   packet->flags = 0;
+
+   if(flags & VC_CONTAINER_READ_FLAG_SKIP)
+   {
+      size = SKIP_BYTES(p_ctx, module->block_size);
+      module->block_size -= size;
+      module->status = STREAM_STATUS(p_ctx);
+      return module->status;
+   }
+
+   if(flags & VC_CONTAINER_READ_FLAG_INFO)
+      return VC_CONTAINER_SUCCESS;
+
+   size = MIN(module->block_size, packet->buffer_size);
+   size = READ_BYTES(p_ctx, packet->data, size);
+   module->block_size -= size;
+   packet->size = size;
+
+   module->status = size ? VC_CONTAINER_SUCCESS : STREAM_STATUS(p_ctx);
+   return module->status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T binary_reader_seek( VC_CONTAINER_T *p_ctx, int64_t *offset,
+   VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_PARAM_UNUSED(module);
+   VC_CONTAINER_PARAM_UNUSED(offset);
+   VC_CONTAINER_PARAM_UNUSED(mode);
+   VC_CONTAINER_PARAM_UNUSED(flags);
+   return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T binary_reader_close( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   for(; p_ctx->tracks_num > 0; p_ctx->tracks_num--)
+      vc_container_free_track(p_ctx, p_ctx->tracks[p_ctx->tracks_num-1]);
+   free(module);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T binary_reader_open( VC_CONTAINER_T *p_ctx )
+{
+   const char *extension = vc_uri_path_extension(p_ctx->priv->uri);
+   VC_CONTAINER_MODULE_T *module = 0;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_INVALID;
+   VC_CONTAINER_ES_TYPE_T es_type = 0;
+   VC_CONTAINER_FOURCC_T codec = 0;
+   unsigned int i;
+
+   /* Check if the user has specified a container */
+   vc_uri_find_query(p_ctx->priv->uri, 0, "container", &extension);
+
+   /* Check if the extension is supported */
+   if(!extension || !vc_uri_path(p_ctx->priv->uri))
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   for(i = 0; extension_to_format_table[i].ext; i++)
+   {
+      if(strcasecmp(extension, extension_to_format_table[i].ext))
+         continue;
+
+      es_type = extension_to_format_table[i].type;
+      codec = extension_to_format_table[i].codec;
+      break;
+   }
+   if(!extension_to_format_table[i].ext) return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   /* If this a .bin file we look in our bin list */
+   for(i = 0; !codec && bin_extension_to_format_table[i].ext; i++)
+   {
+      if(!strstr(vc_uri_path(p_ctx->priv->uri), bin_extension_to_format_table[i].ext) &&
+         !strstr(extension, bin_extension_to_format_table[i].ext))
+         continue;
+
+      es_type = bin_extension_to_format_table[i].type;
+      codec = bin_extension_to_format_table[i].codec;
+      break;
+   }
+   if(!codec) return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   /* Allocate our context */
+   module = malloc(sizeof(*module));
+   if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(module, 0, sizeof(*module));
+   p_ctx->priv->module = module;
+   p_ctx->tracks_num = 1;
+   p_ctx->tracks = &module->track;
+   p_ctx->tracks[0] = vc_container_allocate_track(p_ctx, 0);
+   if(!p_ctx->tracks[0]) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+   p_ctx->tracks[0]->format->es_type = es_type;
+   p_ctx->tracks[0]->format->codec = codec;
+   p_ctx->tracks[0]->is_enabled = true;
+   module->default_block_size = DEFAULT_BLOCK_SIZE;
+   if(codec == VC_CONTAINER_CODEC_JPEG)
+      module->default_block_size = DEFAULT_JPEG_BLOCK_SIZE;
+   module->block_size = module->default_block_size;
+   module->init = 1;
+
+   /*
+    *  We now have all the information we really need to start playing the stream
+    */
+
+   p_ctx->priv->pf_close = binary_reader_close;
+   p_ctx->priv->pf_read = binary_reader_read;
+   p_ctx->priv->pf_seek = binary_reader_seek;
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+   LOG_DEBUG(p_ctx, "binary: error opening stream (%i)", status);
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+ ********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak reader_open binary_reader_open
+#endif
diff --git a/containers/binary/binary_writer.c b/containers/binary/binary_writer.c
new file mode 100755 (executable)
index 0000000..b4580ea
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <string.h>
+
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_logging.h"
+
+/******************************************************************************
+Supported extensions
+******************************************************************************/
+static const char *extensions[] =
+{ "mp3", "aac", "adts", "ac3", "ec3", "amr", "awb", "evrc", "dts",
+  "m1v", "m2v", "mp4v", "h263", "263", "h264", "264", "mvc",
+  "bin", 0
+};
+
+/******************************************************************************
+Type definitions
+******************************************************************************/
+typedef struct VC_CONTAINER_MODULE_T
+{
+   VC_CONTAINER_TRACK_T *track;
+
+} VC_CONTAINER_MODULE_T;
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+VC_CONTAINER_STATUS_T binary_writer_open( VC_CONTAINER_T * );
+
+/*****************************************************************************
+Functions exported as part of the Container Module API
+ *****************************************************************************/
+static VC_CONTAINER_STATUS_T binary_writer_close( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   for(; p_ctx->tracks_num > 0; p_ctx->tracks_num--)
+      vc_container_free_track(p_ctx, p_ctx->tracks[p_ctx->tracks_num-1]);
+   free(module);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T binary_writer_write( VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_PACKET_T *packet )
+{
+   WRITE_BYTES(p_ctx, packet->data, packet->size);
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T binary_writer_control( VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_CONTROL_T operation, va_list args )
+{
+   VC_CONTAINER_ES_FORMAT_T *format;
+   VC_CONTAINER_TRACK_T *track;
+   VC_CONTAINER_STATUS_T status;
+
+   switch(operation)
+   {
+   case VC_CONTAINER_CONTROL_TRACK_ADD:
+      format = (VC_CONTAINER_ES_FORMAT_T *)va_arg( args, VC_CONTAINER_ES_FORMAT_T * );
+
+      /* Allocate and initialise track data */
+      if(p_ctx->tracks_num >= 1) return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+      p_ctx->tracks[p_ctx->tracks_num] = track = vc_container_allocate_track(p_ctx, 0);
+      if(!track) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+
+      if(format->extradata_size)
+      {
+         status = vc_container_track_allocate_extradata( p_ctx, track, format->extradata_size );
+         if(status != VC_CONTAINER_SUCCESS)
+         {
+            vc_container_free_track(p_ctx, track);
+            return status;
+         }
+         WRITE_BYTES(p_ctx, format->extradata, format->extradata_size);
+      }
+
+      vc_container_format_copy(track->format, format, format->extradata_size);
+      p_ctx->tracks_num++;
+      return VC_CONTAINER_SUCCESS;
+
+   case VC_CONTAINER_CONTROL_TRACK_ADD_DONE:
+      return VC_CONTAINER_SUCCESS;
+
+   default: return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+   }
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T binary_writer_open( VC_CONTAINER_T *p_ctx )
+{
+   const char *extension = vc_uri_path_extension(p_ctx->priv->uri);
+   VC_CONTAINER_MODULE_T *module = 0;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_INVALID;
+   unsigned int i;
+
+   /* Check if the user has specified a container */
+   vc_uri_find_query(p_ctx->priv->uri, 0, "container", &extension);
+
+   /* Check we're the right writer for this */
+   if(!extension)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   for(i = 0; extensions[i]; i++)
+      if(!strcasecmp(extension, extensions[i])) break;
+   if(!extensions[i])
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   /* Allocate our context */
+   module = malloc(sizeof(*module));
+   if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(module, 0, sizeof(*module));
+   p_ctx->priv->module = module;
+   p_ctx->tracks = &module->track;
+
+   p_ctx->priv->pf_close = binary_writer_close;
+   p_ctx->priv->pf_write = binary_writer_write;
+   p_ctx->priv->pf_control = binary_writer_control;
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+   LOG_DEBUG(p_ctx, "binary: error opening stream (%i)", status);
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+ ********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak writer_open binary_writer_open
+#endif
diff --git a/containers/containers.h b/containers/containers.h
new file mode 100755 (executable)
index 0000000..4b090c9
--- /dev/null
@@ -0,0 +1,746 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef VC_CONTAINERS_H
+#define VC_CONTAINERS_H
+
+/** \file containers.h
+ * Public API for container readers and writers
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "containers/containers_types.h"
+
+/** \defgroup VcContainerApi Container API
+ *  API for container readers and writers */
+/* @{ */
+
+/** Status codes returned by the container API */
+typedef enum
+{
+   VC_CONTAINER_SUCCESS = 0,                        /**< No error */
+   VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED,         /**< Format of container is not supported */
+   VC_CONTAINER_ERROR_FORMAT_FEATURE_NOT_SUPPORTED, /**< Format of container uses unsupported features */
+   VC_CONTAINER_ERROR_FORMAT_INVALID,               /**< Format of container is invalid */
+   VC_CONTAINER_ERROR_CORRUPTED,                    /**< Container is corrupted */
+   VC_CONTAINER_ERROR_URI_NOT_FOUND,                /**< URI could not be found */
+   VC_CONTAINER_ERROR_URI_OPEN_FAILED,              /**< URI could not be opened */
+   VC_CONTAINER_ERROR_OUT_OF_MEMORY,                /**< Out of memory */
+   VC_CONTAINER_ERROR_OUT_OF_SPACE,                 /**< Out of disk space (used when writing) */
+   VC_CONTAINER_ERROR_OUT_OF_RESOURCES,             /**< Out of resources (other than memory) */
+   VC_CONTAINER_ERROR_EOS,                          /**< End of stream reached */
+   VC_CONTAINER_ERROR_LIMIT_REACHED,                /**< User defined limit reached (used when writing) */
+   VC_CONTAINER_ERROR_BUFFER_TOO_SMALL,             /**< Given buffer is too small for data to be copied */
+   VC_CONTAINER_ERROR_INCOMPLETE_DATA,              /**< Requested data is incomplete */
+   VC_CONTAINER_ERROR_NO_TRACK_AVAILABLE,           /**< Container doesn't have any track */
+   VC_CONTAINER_ERROR_TRACK_FORMAT_NOT_SUPPORTED,   /**< Format of the track is not supported */
+   VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION,        /**< The requested operation is not supported */
+   VC_CONTAINER_ERROR_INVALID_ARGUMENT,             /**< The argument provided is invalid */
+   VC_CONTAINER_ERROR_CONTINUE,                     /**< The requested operation was interrupted and needs to be tried again */
+   VC_CONTAINER_ERROR_ABORTED,                      /**< The requested operation was aborted */
+   VC_CONTAINER_ERROR_NOT_FOUND,                    /**< The requested data was not found */
+   VC_CONTAINER_ERROR_DRM_NOT_AUTHORIZED,           /**< The DRM was not authorized */
+   VC_CONTAINER_ERROR_DRM_EXPIRED,                  /**< The DRM has expired */
+   VC_CONTAINER_ERROR_DRM_FAILED,                   /**< Generic DRM error */
+   VC_CONTAINER_ERROR_FAILED,                       /**< Generic error */
+   VC_CONTAINER_ERROR_NOT_READY                     /**< The container was not yet able to carry out the operation. */
+} VC_CONTAINER_STATUS_T;
+
+/** Four Character Code type used to identify codecs, etc. */
+typedef uint32_t VC_CONTAINER_FOURCC_T;
+
+/** Type definition for language codes.
+ * Language are defined as ISO639 Alpha-3 codes (http://en.wikipedia.org/wiki/List_of_ISO_639-2_codes) */
+typedef uint8_t VC_CONTAINER_LANGUAGE_T[3];
+
+/** Enumeration of the character encodings supported. */
+typedef enum {
+   VC_CONTAINER_CHAR_ENCODING_UNKNOWN = 0, /**< Encoding is unknown */
+   VC_CONTAINER_CHAR_ENCODING_UTF8         /**< UTF8 encoding */
+} VC_CONTAINER_CHAR_ENCODING_T;
+
+/** \name Container Capabilities
+ * The following flags are exported by containers to describe their capabilities */
+/* @{ */
+/** Type definition for container capabilities */
+typedef uint32_t VC_CONTAINER_CAPABILITIES_T;
+/** The container can seek */
+#define VC_CONTAINER_CAPS_CAN_SEEK               0x1
+/** Seeking is fast. The absence of this flag can be used as a hint to avoid seeking as much as possible */
+#define VC_CONTAINER_CAPS_SEEK_IS_FAST           0x2
+/** The container controls the pace at which it is reading the data */
+#define VC_CONTAINER_CAPS_CAN_CONTROL_PACE       0x4
+/** The container provides an index. This basically means that seeking will be precise and fast */
+#define VC_CONTAINER_CAPS_HAS_INDEX              0x8
+/** The container provides keyframe information */
+#define VC_CONTAINER_CAPS_DATA_HAS_KEYFRAME_FLAG 0x10
+/** The container supports adding tracks after TRACK_ADD_DONE control message has been sent */
+#define VC_CONTAINER_CAPS_DYNAMIC_TRACK_ADD      0x20
+/** The container supports forcing reading of a given track */
+#define VC_CONTAINER_CAPS_FORCE_TRACK            0x40
+/* @} */
+
+/** \defgroup VcContainerMetadata Container Metadata
+ * Container metadata contains descriptive information which is associated with the multimedia data */
+/* @{ */
+
+/** Enumeration of the different metadata keys available. */
+typedef enum {
+   /* Metadata of global scope */
+   VC_CONTAINER_METADATA_KEY_TITLE       = VC_FOURCC('t','i','t','l'),
+   VC_CONTAINER_METADATA_KEY_ARTIST      = VC_FOURCC('a','r','t','i'),
+   VC_CONTAINER_METADATA_KEY_ALBUM       = VC_FOURCC('a','l','b','m'),
+   VC_CONTAINER_METADATA_KEY_DESCRIPTION = VC_FOURCC('d','e','s','c'),
+   VC_CONTAINER_METADATA_KEY_YEAR        = VC_FOURCC('y','e','a','r'),
+   VC_CONTAINER_METADATA_KEY_GENRE       = VC_FOURCC('g','e','n','r'),
+   VC_CONTAINER_METADATA_KEY_TRACK       = VC_FOURCC('t','r','a','k'),
+   VC_CONTAINER_METADATA_KEY_LYRICS      = VC_FOURCC('l','y','r','x'),
+
+   VC_CONTAINER_METADATA_KEY_UNKNOWN     = 0
+
+} VC_CONTAINER_METADATA_KEY_T;
+
+/** Definition of the metadata type.
+ * This type is used to store one element of metadata */
+typedef struct VC_CONTAINER_METADATA_T
+{
+   /** Identifier for the type of metadata the value refers to.
+    * Using an enum for the id will mean that a list of possible values will have to be
+    * defined and maintained. This might limit extensibility and customisation.\n
+    * Maybe it would be better to use a FOURCC or even a string here. */
+   VC_CONTAINER_METADATA_KEY_T key;
+
+   VC_CONTAINER_LANGUAGE_T language; /**< Language code for the metadata */
+   VC_CONTAINER_CHAR_ENCODING_T encoding; /**< Encoding of the metadata */
+
+   /** Metadata value. This value is defined as null-terminated UTF-8 string.\n
+    * Do we want to support other types than strings (e.g. integer) ?\n
+    * We need an encoding conversion library! */
+   char *value;
+
+   /** Size of the memory area reserved for metadata value (including any 
+    * terminating characters). */
+   unsigned int size;
+} VC_CONTAINER_METADATA_T;
+/* @} */
+
+/** \defgroup VcContainerESFormat Container Elementary Stream Format
+ * This describes the format of an elementary stream associated with a track */
+/* @{ */
+
+/** Enumeration of the different types of elementary streams.
+ * This divides elementary streams into 4 big categories. */
+typedef enum
+{
+   VC_CONTAINER_ES_TYPE_UNKNOWN,     /**< Unknown elementary stream type */
+   VC_CONTAINER_ES_TYPE_AUDIO,       /**< Audio elementary stream */
+   VC_CONTAINER_ES_TYPE_VIDEO,       /**< Video elementary stream */
+   VC_CONTAINER_ES_TYPE_SUBPICTURE   /**< Sub-picture elementary stream (e.g. subtitles, overlays) */
+
+} VC_CONTAINER_ES_TYPE_T;
+
+/** Definition of a video format.
+ * This describes the properties specific to a video stream */
+typedef struct VC_CONTAINER_VIDEO_FORMAT_T
+{
+   uint32_t width;           /**< Width of the frame */
+   uint32_t height;          /**< Height of the frame */
+   uint32_t visible_width;   /**< Width of the visible area of the frame */
+   uint32_t visible_height;  /**< Height of the visible area of the frame */
+   uint32_t x_offset;        /**< Offset to the start of the visible width */
+   uint32_t y_offset;        /**< Offset to the start of the visible height */
+   uint32_t frame_rate_num;  /**< Frame rate numerator */
+   uint32_t frame_rate_den;  /**< Frame rate denominator */
+   uint32_t par_num;         /**< Pixel aspect ratio numerator */
+   uint32_t par_den;         /**< Pixel aspect ratio denominator */
+} VC_CONTAINER_VIDEO_FORMAT_T;
+
+/** Enumeration for the different channel locations */
+typedef enum
+{
+   VC_CONTAINER_AUDIO_CHANNEL_LEFT = 0,            /**< Left channel */
+   VC_CONTAINER_AUDIO_CHANNEL_RIGHT,               /**< Right channel */
+   VC_CONTAINER_AUDIO_CHANNEL_CENTER,              /**< Center channel */
+   VC_CONTAINER_AUDIO_CHANNEL_LOW_FREQUENCY,       /**< Low frequency channel */
+   VC_CONTAINER_AUDIO_CHANNEL_BACK_LEFT,           /**< Back left channel */
+   VC_CONTAINER_AUDIO_CHANNEL_BACK_RIGHT,          /**< Back right channel */
+   VC_CONTAINER_AUDIO_CHANNEL_BACK_CENTER,         /**< Back center channel */
+   VC_CONTAINER_AUDIO_CHANNEL_SIDE_LEFT,           /**< Side left channel */
+   VC_CONTAINER_AUDIO_CHANNEL_SIDE_RIGHT,          /**< Side right channel */
+
+   VC_CONTAINER_AUDIO_CHANNELS_MAX = 32            /**< Maximum number of channels supported */
+
+} VC_CONTAINER_AUDIO_CHANNEL_T;
+
+/** \name Audio format flags
+ * \anchor audioformatflags
+ * The following flags describe properties of an audio stream */
+/* @{ */
+#define VC_CONTAINER_AUDIO_FORMAT_FLAG_CHANNEL_MAPPING 0x1 /**< Channel mapping available */
+/* @} */
+
+/** Definition of an audio format.
+ * This describes the properties specific to an audio stream */
+typedef struct VC_CONTAINER_AUDIO_FORMAT_T
+{
+   uint32_t channels;           /**< Number of audio channels */
+   uint32_t sample_rate;        /**< Sample rate */
+
+   uint32_t bits_per_sample;    /**< Bits per sample */
+   uint32_t block_align;        /**< Size of a block of data */
+
+   uint32_t flags;              /**< Flags describing the audio format.
+                                 * See \ref audioformatflags "Audio format flags". */
+
+   /** Mapping of the channels in order of appearance */
+   VC_CONTAINER_AUDIO_CHANNEL_T channel_mapping[VC_CONTAINER_AUDIO_CHANNELS_MAX];
+
+   uint16_t gap_delay;   /**< Delay introduced by the encoder. Used for gapless playback */
+   uint16_t gap_padding; /**< Padding introduced by the encoder. Used for gapless playback */
+
+   /** Replay gain information. First element is the track information and the second
+    * is the album information. */
+   struct {
+      float peak; /**< Peak value (full range is 1.0) */
+      float gain; /**< Gain value in dB */
+   } replay_gain[2];
+
+} VC_CONTAINER_AUDIO_FORMAT_T;
+
+/** Definition of a subpicture format.
+ * This describes the properties specific to a subpicture stream */
+typedef struct VC_CONTAINER_SUBPICTURE_FORMAT_T
+{
+   VC_CONTAINER_CHAR_ENCODING_T encoding; /**< Encoding for text based subpicture formats */
+   uint32_t x_offset;        /**< Width offset to the start of the subpicture */
+   uint32_t y_offset;        /**< Height offset to the start of the subpicture */
+} VC_CONTAINER_SUBPICTURE_FORMAT_T;
+
+/** \name Elementary stream format flags
+ * \anchor esformatflags
+ * The following flags describe properties of an elementary stream */
+/* @{ */
+#define VC_CONTAINER_ES_FORMAT_FLAG_FRAMED 0x1 /**< Elementary stream is framed */
+/* @} */
+
+/** Definition of the type specific format.
+ * This describes the type specific information of the elementary stream. */
+typedef union
+{
+   VC_CONTAINER_AUDIO_FORMAT_T      audio;      /**< Audio specific information */
+   VC_CONTAINER_VIDEO_FORMAT_T      video;      /**< Video specific information */
+   VC_CONTAINER_SUBPICTURE_FORMAT_T subpicture; /**< Subpicture specific information */
+} VC_CONTAINER_ES_SPECIFIC_FORMAT_T;
+
+/** Definition of an elementary stream format */
+typedef struct VC_CONTAINER_ES_FORMAT_T
+{
+   VC_CONTAINER_ES_TYPE_T es_type;    /**< Type of the elementary stream */
+   VC_CONTAINER_FOURCC_T  codec;      /**< Coding of the elementary stream */
+   VC_CONTAINER_FOURCC_T  codec_variant;  /**< If set, indicates a variant of the coding */
+
+   VC_CONTAINER_ES_SPECIFIC_FORMAT_T *type; /**< Type specific information for the elementary stream */
+
+   uint32_t bitrate;         /**< Bitrate */
+
+   VC_CONTAINER_LANGUAGE_T language; /**< Language code for the elementary stream */
+   uint32_t group_id;                /**< ID of the group this elementary stream belongs to */
+
+   uint32_t flags;         /**< Flags describing the properties of an elementary stream.
+                            * See \ref esformatflags "Elementary stream format flags". */
+
+   unsigned int extradata_size; /**< Size of the codec specific data */
+   uint8_t *extradata;     /**< Codec specific data */
+
+} VC_CONTAINER_ES_FORMAT_T;
+/* @} */
+
+/** \defgroup VcContainerPacket Container Packet
+ * A container packet is the unit of data that is being read from or written to a container */
+/* @{ */
+
+/** Structure describing a data packet */
+typedef struct VC_CONTAINER_PACKET_T
+{
+   struct VC_CONTAINER_PACKET_T *next; /**< Used to build lists of packets */
+   uint8_t *data;              /**< Pointer to the buffer containing the actual data for the packet */
+   unsigned int buffer_size;   /**< Size of the p_data buffer. This is used to indicate how much data can be read in p_data */
+   unsigned int size;          /**< Size of the data contained in p_data */
+   unsigned int frame_size;    /**< If set, indicates the size of the frame this packet belongs to */
+   int64_t pts;                /**< Presentation Timestamp of the packet */
+   int64_t dts;                /**< Decoding Timestamp of the packet */
+   uint64_t num;               /**< Number of this packet */
+   uint32_t track;             /**< Track associated with this packet */
+   uint32_t flags;             /**< Flags associated with this packet */
+
+   void *user_data;            /**< Field reserved for use by the client */
+   void *framework_data;       /**< Field reserved for use by the framework */
+
+} VC_CONTAINER_PACKET_T;
+
+/** \name Container Packet Flags
+ * The following flags describe properties of the data packet */
+/* @{ */
+#define VC_CONTAINER_PACKET_FLAG_KEYFRAME       0x01   /**< Packet is a keyframe */
+#define VC_CONTAINER_PACKET_FLAG_FRAME_START    0x02   /**< Packet starts a frame */
+#define VC_CONTAINER_PACKET_FLAG_FRAME_END      0x04   /**< Packet ends a frame */
+#define VC_CONTAINER_PACKET_FLAG_FRAME          0x06   /**< Packet contains only complete frames */
+#define VC_CONTAINER_PACKET_FLAG_DISCONTINUITY  0x08   /**< Packet comes after a discontinuity in the stream. Decoders might have to be flushed */
+#define VC_CONTAINER_PACKET_FLAG_ENCRYPTED      0x10   /**< Packet contains DRM encrypted data */
+#define VC_CONTAINER_PACKET_FLAG_CONFIG         0x20   /**< Packet contains stream specific config data */
+/* @} */
+
+/** \name Special Unknown Time Value
+ * This is the special value used to signal that a timestamp is not known */
+/* @{ */
+#define VC_CONTAINER_TIME_UNKNOWN (INT64_C(1)<<63)     /**< Special value for signalling that time is not known */
+/* @} */
+
+/* @} */
+
+/** \name Track flags
+ * \anchor trackflags
+ * The following flags describe properties of a track */
+/* @{ */
+#define VC_CONTAINER_TRACK_FLAG_CHANGED 0x1 /**< Track definition has changed */
+/* @} */
+
+/** Definition of the track type */
+typedef struct VC_CONTAINER_TRACK_T
+{
+   struct VC_CONTAINER_TRACK_PRIVATE_T *priv; /**< Private member used by the implementation */
+   uint32_t is_enabled;               /**< Flag to specify if the track is enabled */
+   uint32_t flags;                    /**< Flags describing the properties of a track.
+                                       * See \ref trackflags "Track flags". */
+
+   VC_CONTAINER_ES_FORMAT_T *format;  /**< Format of the elementary stream contained in the track */
+
+   unsigned int meta_num;             /**< Number of metadata elements associated with the track */
+   VC_CONTAINER_METADATA_T **meta;    /**< Array of metadata elements associated with the track */
+
+} VC_CONTAINER_TRACK_T;
+
+/** Definition of the DRM type */
+typedef struct VC_CONTAINER_DRM_T
+{
+   VC_CONTAINER_FOURCC_T format;    /**< Four character code describing the format of the DRM in use */
+   unsigned int views_max;          /**< Maximum number of views allowed */
+   unsigned int views_current;      /**< Current number of views */
+
+} VC_CONTAINER_DRM_T;
+
+/** Type definition for the progress reporting function. This function will be called regularly
+ * by the container during a call which blocks for too long and will report the progress of the
+ * operation as an estimated total length in microseconds and a percentage done.
+ * Returning anything else than VC_CONTAINER_SUCCESS in this function will abort the current
+ * operation. */
+typedef VC_CONTAINER_STATUS_T (*VC_CONTAINER_PROGRESS_REPORT_FUNC_T)(void *userdata,
+   int64_t length, unsigned int percentage_done);
+
+/** \name Container Events
+ * The following flags are exported by containers to notify the application of events */
+/* @{ */
+/** Type definition for container events */
+typedef uint32_t VC_CONTAINER_EVENTS_T;
+#define VC_CONTAINER_EVENT_TRACKS_CHANGE   1    /**< Track information has changed */
+#define VC_CONTAINER_EVENT_METADATA_CHANGE 2    /**< Metadata has changed */
+/* @} */
+
+/** Definition of the container context */
+typedef struct VC_CONTAINER_T
+{
+   struct VC_CONTAINER_PRIVATE_T *priv; /**< Private member used by the implementation */
+
+   VC_CONTAINER_EVENTS_T events; /**< Events generated by the container */
+   VC_CONTAINER_CAPABILITIES_T capabilities; /**< Capabilities exported by the container */
+
+   VC_CONTAINER_PROGRESS_REPORT_FUNC_T pf_progress; /**< Progress report function pointer */
+   void *progress_userdata;                          /**< Progress report user data */
+
+   int64_t duration;                  /**< Duration of the media in microseconds */
+   int64_t position;                  /**< Current time position into the media */
+   int64_t size;                      /**< Size of the media in bytes */
+
+   unsigned int tracks_num;           /**< Number of tracks available */
+   /** Pointer to an array of pointers to track elements.
+    * The reasoning for using a pointer to pointers here is to allow us to extend
+    * VC_CONTAINER_TRACK_T without losing binary backward compatibility. */
+   VC_CONTAINER_TRACK_T **tracks;
+
+   unsigned int meta_num;             /**< Number of metadata elements associated with the container */
+   VC_CONTAINER_METADATA_T **meta;    /**< Array of metadata elements associated with the container */
+
+   VC_CONTAINER_DRM_T *drm;           /**< Description used for DRM protected content */
+
+} VC_CONTAINER_T;
+
+/** Forward declaration of a container input / output context.
+ * This structure defines the context for a container io instance */
+typedef struct VC_CONTAINER_IO_T VC_CONTAINER_IO_T;
+
+/** Opens the media container pointed to by the URI for reading.
+ * This will create an an instance of a container reader and its associated context.
+ * The context returned will also be filled with the information retrieved from the media.
+ *
+ * If the media isn't accessible or recognized, this will return a null pointer as well as
+ * an error code indicating why this failed.
+ *
+ * \param  psz_uri      Unified Resource Identifier pointing to the media container
+ * \param  status       Returns the status of the operation
+ * \param  pf_progress  User provided function pointer to a progress report function. Can be set to
+ *                      null if no progress report is wanted. This function will be used during
+ *                      the whole lifetime of the instance (i.e. it will be used during
+ *                      open / seek / close)
+ * \param  progress_userdata User provided pointer that will be passed during the progress report
+ *                      function call.
+ * \return              A pointer to the context of the new instance of the
+ *                      container reader. Returns NULL on failure.
+ */
+VC_CONTAINER_T *vc_container_open_reader( const char *psz_uri, VC_CONTAINER_STATUS_T *status,
+   VC_CONTAINER_PROGRESS_REPORT_FUNC_T pf_progress, void *progress_userdata);
+
+/** Opens for reading the media container pointed to by the container i/o.
+ * This will create an an instance of a container reader and its associated context.
+ * The context returned will also be filled with the information retrieved from the media.
+ *
+ * If the media isn't accessible or recognized, this will return a null pointer as well as
+ * an error code indicating why this failed.
+ *
+ * \param  p_io         Instance of the container i/o to use
+ * \param  psz_uri      Unified Resource Identifier pointing to the media container (optional)
+ * \param  status       Returns the status of the operation
+ * \param  pf_progress  User provided function pointer to a progress report function. Can be set to
+ *                      null if no progress report is wanted. This function will be used during
+ *                      the whole lifetime of the instance (i.e. it will be used during
+ *                      open / seek / close)
+ * \param  progress_userdata User provided pointer that will be passed during the progress report
+ *                      function call.
+ * \return              A pointer to the context of the new instance of the
+ *                      container reader. Returns NULL on failure.
+ */
+VC_CONTAINER_T *vc_container_open_reader_with_io( VC_CONTAINER_IO_T *p_io,
+   const char *psz_uri, VC_CONTAINER_STATUS_T *status,
+   VC_CONTAINER_PROGRESS_REPORT_FUNC_T pf_progress, void *progress_userdata);
+
+/** Opens the media container pointed to by the URI for writing.
+ * This will create an an instance of a container writer and its associated context.
+ * The context returned will be initialised to sensible values.
+ *
+ * The application will need to add all the media tracks using \ref vc_container_control before
+ * it starts writing data using \ref vc_container_write.
+ *
+ * If the media isn't accessible or recognized, this will return a null pointer as well as
+ * an error code indicating why this failed.
+ *
+ * \param  psz_uri      Unified Resource Identifier pointing to the media container
+ * \param  status       Returns the status of the operation
+ * \param  pf_progress User provided function pointer to a progess report function. Can be set to
+ *                      null if no progress report is wanted.
+ * \param  progress_userdata User provided pointer that will be passed during the progress report
+ *                      function call.
+ * \return              A pointer to the context of the new instance of the
+ *                      container writer. Returns NULL on failure.
+ */
+VC_CONTAINER_T *vc_container_open_writer( const char *psz_uri, VC_CONTAINER_STATUS_T *status,
+   VC_CONTAINER_PROGRESS_REPORT_FUNC_T pf_progress, void *progress_userdata);
+
+/** Closes an instance of a container reader / writer.
+ * This will free all the resources associated with the context.
+ *
+ * \param  context   Pointer to the context of the instance to close
+ * \return           the status of the operation
+ */
+VC_CONTAINER_STATUS_T vc_container_close( VC_CONTAINER_T *context );
+
+/** \name Container read flags
+ * The following flags can be passed during a read call */
+/* @{ */
+/** Type definition for the read flags */
+typedef uint32_t VC_CONTAINER_READ_FLAGS_T;
+/** Ask the container to only return information on the next packet without reading it */
+#define VC_CONTAINER_READ_FLAG_INFO   1
+/** Ask the container to skip the next packet */
+#define VC_CONTAINER_READ_FLAG_SKIP   2
+/** Force the container to read data from the specified track */
+#define VC_CONTAINER_READ_FLAG_FORCE_TRACK 4
+/* @} */
+
+/** Reads a data packet from a container reader.
+ * By default, the reader will read whatever packet comes next in the container and update the
+ * given \ref VC_CONTAINER_PACKET_T structure with this packet's information.
+ * This behaviour can be changed using the \ref VC_CONTAINER_READ_FLAGS_T.\n
+ * \ref VC_CONTAINER_READ_FLAG_INFO will instruct the reader to only return information on the
+ * following packet but not its actual data. The data can be retreived later by issuing another
+ * read request.\n
+ * \ref VC_CONTAINER_READ_FLAG_FORCE_TRACK will force the reader to read the next packet for the
+ * selected track (as present in the \ref VC_CONTAINER_PACKET_T structure) instead of defaulting
+ * to reading the packet which comes next in the container.\n
+ * \ref VC_CONTAINER_READ_FLAG_SKIP will instruct the reader to skip the next packet. In this case
+ * it isn't necessary for the caller to pass a pointer to a \ref VC_CONTAINER_PACKET_T structure
+ * unless the \ref VC_CONTAINER_READ_FLAG_INFO is also given.\n
+ * A combination of all these flags can be used.
+ *
+ * \param  context   Pointer to the context of the reader to use
+ * \param  packet    Pointer to the VC_CONTAINER_PACKET_T structure describing the data packet
+ *                   This needs to be partially filled before the call (buffer, buffer_size)
+ * \param  flags     Flags controlling the read operation
+ * \return           the status of the operation
+ */
+VC_CONTAINER_STATUS_T vc_container_read( VC_CONTAINER_T *context,
+   VC_CONTAINER_PACKET_T *packet, VC_CONTAINER_READ_FLAGS_T flags );
+
+/** Writes a data packet to a container writer.
+ *
+ * \param  context   Pointer to the context of the writer to use
+ * \param  packet    Pointer to the VC_CONTAINER_PACKET_T structure describing the data packet
+ * \return           the status of the operation
+ */
+VC_CONTAINER_STATUS_T vc_container_write( VC_CONTAINER_T *context,
+   VC_CONTAINER_PACKET_T *packet );
+
+/** Definition of the different seek modes */
+typedef enum
+{
+   /** The offset provided for seeking is an absolute time offset in microseconds */
+   VC_CONTAINER_SEEK_MODE_TIME = 0,
+   /** The offset provided for seeking is a percentage (Q32 ?) */
+   VC_CONTAINER_SEEK_MODE_PERCENT
+
+} VC_CONTAINER_SEEK_MODE_T;
+
+/** \name Container Seek Flags
+ * The following flags control seek operations */
+/* @{ */
+/** Type definition for the seek flags */
+typedef uint32_t VC_CONTAINER_SEEK_FLAGS_T;
+/** Choose precise seeking even if slower */
+#define VC_CONTAINER_SEEK_FLAG_PRECISE     0x1
+/** By default a seek will always seek to the keyframe which comes just before the requested
+ * position. This flag allows the caller to force the container to seek to the keyframe which
+ * comes just after the requested position. */
+#define VC_CONTAINER_SEEK_FLAG_FORWARD     0x2
+/* @} */
+
+/** Seek into a container reader.
+ *
+ * \param  context   Pointer to the context of the reader to use
+ * \param  offset    Offset to seek to. Used as an input as well as output value.
+ * \param  mode      Seeking mode requested.
+ * \param  flags     Flags affecting the seeking operation.
+ * \return           the status of the operation
+ */
+VC_CONTAINER_STATUS_T vc_container_seek( VC_CONTAINER_T *context, int64_t *offset,
+      VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags);
+
+/** Performance statistics.
+ */
+/** The maximum number of bins a statistics value is held in */
+#define VC_CONTAINER_STATS_BINS 10
+
+/** This type is used to represent multiple values of a statistic.
+ */
+typedef struct VC_CONTAINER_STATS_T
+{
+   /** The number of places to right shift count before using.  Resulting values
+    * of zero are rounded to 1. */
+   uint32_t shift;
+
+   /** We store VC_CONTAINER_STATS_BINS+1 records, in sorted order of numpc.
+    * At least one will be invalid and all zero.  We combine adjacent records
+    * as necessary. */
+   struct {
+      /** Sum of count.  For single value statistics this is the freqency, for paired statistics
+       * this is the number of bytes written. */
+      uint32_t count;
+      /** Number of count. For single value statistics this is the total value, for paired statistics
+       * this is the total length of time.  */
+      uint32_t num;
+      /** Number>>shift per count.  Stored to save recalculation. */
+      uint32_t numpc;
+   } record[VC_CONTAINER_STATS_BINS+1];
+} VC_CONTAINER_STATS_T;
+
+/** This type represents the statistics saved by the io layer. */
+typedef struct VC_CONTAINER_WRITE_STATS_T
+{
+   /** This logs the number of bytes written in count, and the microseconds taken to write
+    * in num. */
+   VC_CONTAINER_STATS_T write;
+   /** This logs the length of time the write function has to wait for the asynchronous task. */
+   VC_CONTAINER_STATS_T wait;
+   /** This logs the length of time that we wait for a flush command to complete. */
+   VC_CONTAINER_STATS_T flush;
+} VC_CONTAINER_WRITE_STATS_T;
+   
+
+/** Control operations which can be done on containers. */
+typedef enum
+{
+   /** Adds a new track to the list of tracks. This should be used by writers to create
+    * their list of tracks.\n
+    * Arguments:\n
+    *   arg1= VC_CONTAINER_ES_FORMAT_T *: format of the track to add\n
+    *   return=  VC_CONTAINER_ERROR_TRACK_FORMAT_NOT_SUPPORTED if the format is not supported */
+   VC_CONTAINER_CONTROL_TRACK_ADD = 0,
+
+   /** Specifies that we're done adding new tracks. This is optional but can be used by writers
+    * to trigger the writing of the container header early. If this isn't used, the header will be
+    * written when the first data packet is received.\n
+    * No arguments.\n
+    *   return=  VC_CONTAINER_ERROR_TRACK_FORMAT_NOT_SUPPORTED if the format is not supported */
+   VC_CONTAINER_CONTROL_TRACK_ADD_DONE,
+
+   /** Change the format of a track in the list of tracks. This should be used by writers to modify
+    * the format of a track at run-time.\n
+    * Arguments:\n
+    *   arg1= unsigned int: index of track to change\n
+    *   arg2= VC_CONTAINER_ES_FORMAT_T *: format of the track to add\n
+    *   return=  VC_CONTAINER_ERROR_TRACK_FORMAT_NOT_SUPPORTED if the format is not supported */
+   VC_CONTAINER_CONTROL_TRACK_CHANGE,
+
+   /** Deletes a track from the list of tracks. This should be used by writers to delete tracks
+    * during run-time. Note that vc_container_close will automatically delete all track so it
+    * isn't necessary to call this before closing a writer.\n
+    * Arguments:\n
+    *   arg1= index of the track to delete  */
+   VC_CONTAINER_CONTROL_TRACK_DEL,
+
+   /** Activate the playback of DRM protected content.\n
+    * No arguments.\n
+    *   return=  one of the VC_CONTAINER_ERROR_DRM error codes if content can't be played */
+   VC_CONTAINER_CONTROL_DRM_PLAY,
+
+   /** TBD */
+   VC_CONTAINER_CONTROL_METADATA_ADD,
+   /** TBD */
+   VC_CONTAINER_CONTROL_METADATA_CHANGE,
+   /** TBD */
+   VC_CONTAINER_CONTROL_METADATA_DEL,
+
+   /** TBD */
+   VC_CONTAINER_CONTROL_CHAPTER_ADD,
+   /** TBD */
+   VC_CONTAINER_CONTROL_CHAPTER_DEL,
+
+   /** Set a maximum size for files generated by writers.\n
+    * Arguments:\n
+    *   arg1= uint64_t: maximum size */
+   VC_CONTAINER_CONTROL_SET_MAXIMUM_SIZE,
+
+   /** Enables/disabled performance statistic gathering.\n
+    * Arguments:\n
+    *   arg1= bool: enable or disable */
+   VC_CONTAINER_CONTROL_SET_IO_PERF_STATS,
+
+   /** Collects performance statistics.\n
+    * Arguments:\n
+    *   arg1= VC_CONTAINER_WRITE_STATS_T *: */
+   VC_CONTAINER_CONTROL_GET_IO_PERF_STATS,
+
+   /** HACK.\n
+    * Arguments:\n
+    *   arg1= void (*)(void *): callback function
+    *   arg1= void *: opaque pointer to pass during the callback */
+   VC_CONTAINER_CONTROL_SET_IO_BUFFER_FULL_CALLBACK,
+
+   /** Set the I/O read buffer size to be used.\n
+    * Arguments:\n
+    *   arg1= uint32_t: New buffer size in bytes*/
+   VC_CONTAINER_CONTROL_IO_SET_READ_BUFFER_SIZE,
+
+   /** Set the timeout on I/O read operations, if applicable.\n
+    * Arguments:\n
+    *   arg1= uint32_t: New timeout in milliseconds, or VC_CONTAINER_READ_TIMEOUT_BLOCK */
+   VC_CONTAINER_CONTROL_IO_SET_READ_TIMEOUT_MS,
+
+   /** Set the timestamp base.\n
+    * The timestamp passed equates to time zero for the stream.\n
+    * Arguments:\n
+    *   arg1= uint32_t: Timestamp base in stream clock units. */
+   VC_CONTAINER_CONTROL_SET_TIMESTAMP_BASE,
+
+   /** Set the next expected sequence number for the stream.\n
+    * Arguments:\n
+    *   arg1= uint32_t: Next expected sequence number. */
+   VC_CONTAINER_CONTROL_SET_NEXT_SEQUENCE_NUMBER,
+
+   /** Set the source ID for the container.\n
+    * Arguments:\n
+    *   arg1= uint32_t: Source identifier. */
+   VC_CONTAINER_CONTROL_SET_SOURCE_ID,
+
+   /** Arguments:\n
+    *   arg1= void *: metadata buffer
+    *   arg2= unsigned long: length of metadata in bytes */ 
+   VC_CONTAINER_CONTROL_GET_DRM_METADATA,
+
+   /** Arguments:\n
+    *   arg1= unsigned long: track number
+    *   arg2= VC_CONTAINER_FOURCC_T : drm type
+    *   arg3= void *: encryption configuration parameters.
+    *   arg4= unsigned long: configuration data length */
+   VC_CONTAINER_CONTROL_ENCRYPT_TRACK,
+
+   /** Causes the io to be flushed.\n
+    * Arguments: none */
+   VC_CONTAINER_CONTROL_IO_FLUSH,
+
+   /** Request the container reader to packetize data for the specified track.
+    * Arguments:\n
+    *   arg1= unsigned long: track number
+    *   arg2= VC_CONTAINER_FOURCC_T: codec variant to output */
+   VC_CONTAINER_CONTROL_TRACK_PACKETIZE,
+
+   /** Private user extensions must be above this number */
+   VC_CONTAINER_CONTROL_USER_EXTENSIONS = 0x1000
+
+} VC_CONTAINER_CONTROL_T;
+
+/** Used with the VC_CONTAINER_CONTROL_IO_SET_READ_TIMEOUT_MS control to indicate the read shall
+ * block until either data is available, or an error occurs.
+ */
+#define VC_CONTAINER_READ_TIMEOUT_BLOCK   (uint32_t)(-1)
+
+/** Extensible control function for container readers and writers.
+ * This function takes a variable number of arguments which will depend on the specific operation.
+ *
+ * \param  context   Pointer to the VC_CONTAINER_T context to use
+ * \param  operation The requested operation
+ * \return           the status of the operation. Can be \ref VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION
+ *                   if the operation is not supported or implemented by the container.
+ */
+VC_CONTAINER_STATUS_T vc_container_control( VC_CONTAINER_T *context, VC_CONTAINER_CONTROL_T operation, ... );
+
+/* @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* VC_CONTAINERS_H */
diff --git a/containers/containers_codecs.h b/containers/containers_codecs.h
new file mode 100755 (executable)
index 0000000..3a6bc4b
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef VC_CONTAINERS_CODECS_H
+#define VC_CONTAINERS_CODECS_H
+
+/** \file containers_codecs.h
+ * Codec helpers
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "containers/containers_types.h"
+
+/* Video */
+#define VC_CONTAINER_CODEC_MP1V        VC_FOURCC('m','p','1','v')
+#define VC_CONTAINER_CODEC_MP2V        VC_FOURCC('m','p','2','v')
+#define VC_CONTAINER_CODEC_MP4V        VC_FOURCC('m','p','4','v')
+#define VC_CONTAINER_CODEC_DIV3        VC_FOURCC('d','i','v','3')
+#define VC_CONTAINER_CODEC_DIV4        VC_FOURCC('d','i','v','4')
+#define VC_CONTAINER_CODEC_H263        VC_FOURCC('h','2','6','3')
+#define VC_CONTAINER_CODEC_H264        VC_FOURCC('h','2','6','4')
+#define VC_CONTAINER_CODEC_MVC         VC_FOURCC('m','v','c',' ')
+#define VC_CONTAINER_CODEC_WMV1        VC_FOURCC('w','m','v','1')
+#define VC_CONTAINER_CODEC_WMV2        VC_FOURCC('w','m','v','2')
+#define VC_CONTAINER_CODEC_WMV3        VC_FOURCC('w','m','v','3')
+#define VC_CONTAINER_CODEC_WVC1        VC_FOURCC('w','v','c','1')
+#define VC_CONTAINER_CODEC_WMVA        VC_FOURCC('w','m','v','a')
+#define VC_CONTAINER_CODEC_MJPEG       VC_FOURCC('m','j','p','g')
+#define VC_CONTAINER_CODEC_MJPEGA      VC_FOURCC('m','j','p','a')
+#define VC_CONTAINER_CODEC_MJPEGB      VC_FOURCC('m','j','p','b')
+#define VC_CONTAINER_CODEC_THEORA      VC_FOURCC('t','h','e','o')
+#define VC_CONTAINER_CODEC_VP3         VC_FOURCC('v','p','3',' ')
+#define VC_CONTAINER_CODEC_VP6         VC_FOURCC('v','p','6',' ')
+#define VC_CONTAINER_CODEC_VP7         VC_FOURCC('v','p','7',' ')
+#define VC_CONTAINER_CODEC_VP8         VC_FOURCC('v','p','8',' ')
+#define VC_CONTAINER_CODEC_RV10        VC_FOURCC('r','v','1','0')
+#define VC_CONTAINER_CODEC_RV20        VC_FOURCC('r','v','2','0')
+#define VC_CONTAINER_CODEC_RV30        VC_FOURCC('r','v','3','0')
+#define VC_CONTAINER_CODEC_RV40        VC_FOURCC('r','v','4','0')
+#define VC_CONTAINER_CODEC_AVS         VC_FOURCC('a','v','s',' ')
+#define VC_CONTAINER_CODEC_SPARK       VC_FOURCC('s','p','r','k')
+#define VC_CONTAINER_CODEC_DIRAC       VC_FOURCC('d','r','a','c')
+
+#define VC_CONTAINER_CODEC_YUV         VC_FOURCC('y','u','v',' ')
+#define VC_CONTAINER_CODEC_I420        VC_FOURCC('I','4','2','0')
+#define VC_CONTAINER_CODEC_YV12        VC_FOURCC('Y','V','1','2')
+#define VC_CONTAINER_CODEC_I422        VC_FOURCC('I','4','2','2')
+#define VC_CONTAINER_CODEC_YUYV        VC_FOURCC('Y','U','Y','V')
+#define VC_CONTAINER_CODEC_YVYU        VC_FOURCC('Y','V','Y','U')
+#define VC_CONTAINER_CODEC_UYVY        VC_FOURCC('U','Y','V','Y')
+#define VC_CONTAINER_CODEC_VYUY        VC_FOURCC('V','Y','U','Y')
+#define VC_CONTAINER_CODEC_NV12        VC_FOURCC('N','V','1','2')
+#define VC_CONTAINER_CODEC_NV21        VC_FOURCC('N','V','2','1')
+#define VC_CONTAINER_CODEC_ARGB        VC_FOURCC('A','R','G','B')
+#define VC_CONTAINER_CODEC_RGBA        VC_FOURCC('R','G','B','A')
+#define VC_CONTAINER_CODEC_ABGR        VC_FOURCC('A','B','G','R')
+#define VC_CONTAINER_CODEC_BGRA        VC_FOURCC('B','G','R','A')
+#define VC_CONTAINER_CODEC_RGB16       VC_FOURCC('R','G','B','2')
+#define VC_CONTAINER_CODEC_RGB24       VC_FOURCC('R','G','B','3')
+#define VC_CONTAINER_CODEC_RGB32       VC_FOURCC('R','G','B','4')
+#define VC_CONTAINER_CODEC_BGR16       VC_FOURCC('B','G','R','2')
+#define VC_CONTAINER_CODEC_BGR24       VC_FOURCC('B','G','R','3')
+#define VC_CONTAINER_CODEC_BGR32       VC_FOURCC('B','G','R','4')
+#define VC_CONTAINER_CODEC_YUVUV128    VC_FOURCC('S','A','N','D')
+
+#define VC_CONTAINER_CODEC_JPEG        VC_FOURCC('j','p','e','g')
+#define VC_CONTAINER_CODEC_PNG         VC_FOURCC('p','n','g',' ')
+#define VC_CONTAINER_CODEC_GIF         VC_FOURCC('g','i','f',' ')
+#define VC_CONTAINER_CODEC_PPM         VC_FOURCC('p','p','m',' ')
+#define VC_CONTAINER_CODEC_TGA         VC_FOURCC('t','g','a',' ')
+#define VC_CONTAINER_CODEC_BMP         VC_FOURCC('b','m','p',' ')
+
+/* Audio */
+#define VC_CONTAINER_CODEC_PCM_UNSIGNED_BE  VC_FOURCC('P','C','M','U')
+#define VC_CONTAINER_CODEC_PCM_UNSIGNED_LE  VC_FOURCC('p','c','m','u')
+#define VC_CONTAINER_CODEC_PCM_SIGNED_BE    VC_FOURCC('P','C','M','S')
+#define VC_CONTAINER_CODEC_PCM_SIGNED_LE    VC_FOURCC('p','c','m','s')
+#define VC_CONTAINER_CODEC_PCM_FLOAT_BE     VC_FOURCC('P','C','M','F')
+#define VC_CONTAINER_CODEC_PCM_FLOAT_LE     VC_FOURCC('p','c','m','f')
+/* Defines for native endianness */
+#ifdef VC_CONTAINER_IS_BIG_ENDIAN
+#define VC_CONTAINER_CODEC_PCM_UNSIGNED     VC_CONTAINER_CODEC_PCM_UNSIGNED_BE
+#define VC_CONTAINER_CODEC_PCM_SIGNED       VC_CONTAINER_CODEC_PCM_SIGNED_BE
+#define VC_CONTAINER_CODEC_PCM_FLOAT        VC_CONTAINER_CODEC_PCM_FLOAT_BE
+#else
+#define VC_CONTAINER_CODEC_PCM_UNSIGNED     VC_CONTAINER_CODEC_PCM_UNSIGNED_LE
+#define VC_CONTAINER_CODEC_PCM_SIGNED       VC_CONTAINER_CODEC_PCM_SIGNED_LE
+#define VC_CONTAINER_CODEC_PCM_FLOAT        VC_CONTAINER_CODEC_PCM_FLOAT_LE
+#endif
+
+#define VC_CONTAINER_CODEC_MPGA        VC_FOURCC('m','p','g','a')
+#define VC_CONTAINER_CODEC_MP4A        VC_FOURCC('m','p','4','a')
+#define VC_CONTAINER_CODEC_ALAW        VC_FOURCC('a','l','a','w')
+#define VC_CONTAINER_CODEC_MULAW       VC_FOURCC('u','l','a','w')
+#define VC_CONTAINER_CODEC_ADPCM_MS    VC_FOURCC('m','s',0x0,0x2)
+#define VC_CONTAINER_CODEC_ADPCM_IMA_MS VC_FOURCC('m','s',0x0,0x1)
+#define VC_CONTAINER_CODEC_ADPCM_SWF   VC_FOURCC('a','s','w','f')
+#define VC_CONTAINER_CODEC_WMA1        VC_FOURCC('w','m','a','1')
+#define VC_CONTAINER_CODEC_WMA2        VC_FOURCC('w','m','a','2')
+#define VC_CONTAINER_CODEC_WMAP        VC_FOURCC('w','m','a','p')
+#define VC_CONTAINER_CODEC_WMAL        VC_FOURCC('w','m','a','l')
+#define VC_CONTAINER_CODEC_WMAV        VC_FOURCC('w','m','a','v')
+#define VC_CONTAINER_CODEC_AMRNB       VC_FOURCC('a','m','r','n')
+#define VC_CONTAINER_CODEC_AMRWB       VC_FOURCC('a','m','r','w')
+#define VC_CONTAINER_CODEC_AMRWBP      VC_FOURCC('a','m','r','p')
+#define VC_CONTAINER_CODEC_AC3         VC_FOURCC('a','c','3',' ')
+#define VC_CONTAINER_CODEC_EAC3        VC_FOURCC('e','a','c','3')
+#define VC_CONTAINER_CODEC_DTS         VC_FOURCC('d','t','s',' ')
+#define VC_CONTAINER_CODEC_MLP         VC_FOURCC('m','l','p',' ')
+#define VC_CONTAINER_CODEC_FLAC        VC_FOURCC('f','l','a','c')
+#define VC_CONTAINER_CODEC_VORBIS      VC_FOURCC('v','o','r','b')
+#define VC_CONTAINER_CODEC_SPEEX       VC_FOURCC('s','p','x',' ')
+#define VC_CONTAINER_CODEC_ATRAC3      VC_FOURCC('a','t','r','3')
+#define VC_CONTAINER_CODEC_ATRACX      VC_FOURCC('a','t','r','x')
+#define VC_CONTAINER_CODEC_ATRACL      VC_FOURCC('a','t','r','l')
+#define VC_CONTAINER_CODEC_MIDI        VC_FOURCC('m','i','d','i')
+#define VC_CONTAINER_CODEC_EVRC        VC_FOURCC('e','v','r','c')
+#define VC_CONTAINER_CODEC_NELLYMOSER  VC_FOURCC('n','e','l','y')
+#define VC_CONTAINER_CODEC_QCELP       VC_FOURCC('q','c','e','l')
+
+/* Text */
+#define VC_CONTAINER_CODEC_TEXT        VC_FOURCC('t','e','x','t')
+#define VC_CONTAINER_CODEC_SSA         VC_FOURCC('s','s','a',' ')
+#define VC_CONTAINER_CODEC_USF         VC_FOURCC('u','s','f',' ')
+#define VC_CONTAINER_CODEC_VOBSUB      VC_FOURCC('v','s','u','b')
+
+#define VC_CONTAINER_CODEC_UNKNOWN     VC_FOURCC('u','n','k','n')
+
+/* Codec variants */
+
+/** ISO 14496-10 Annex B byte stream format */
+#define VC_CONTAINER_VARIANT_H264_DEFAULT    0
+/** ISO 14496-15 AVC format (used in mp4/mkv and other containers) */
+#define VC_CONTAINER_VARIANT_H264_AVC1       VC_FOURCC('a','v','c','C')
+/** Implicitly delineated NAL units without emulation prevention */
+#define VC_CONTAINER_VARIANT_H264_RAW        VC_FOURCC('r','a','w',' ')
+
+/** MPEG 1/2 Audio - Layer unknown */
+#define VC_CONTAINER_VARIANT_MPGA_DEFAULT    0
+/** MPEG 1/2 Audio - Layer 1 */
+#define VC_CONTAINER_VARIANT_MPGA_L1         VC_FOURCC('l','1',' ',' ')
+/** MPEG 1/2 Audio - Layer 2 */
+#define VC_CONTAINER_VARIANT_MPGA_L2         VC_FOURCC('l','2',' ',' ')
+/** MPEG 1/2 Audio - Layer 3 */
+#define VC_CONTAINER_VARIANT_MPGA_L3         VC_FOURCC('l','3',' ',' ')
+
+/** Converts a WaveFormat ID into a VC_CONTAINER_FOURCC_T.
+ *
+ * \param  waveformat_id WaveFormat ID to convert
+ * \return a valid VC_CONTAINER_FOURCC_T or VC_CONTAINER_CODEC_UNKNOWN if no mapping was found.
+ */
+VC_CONTAINER_FOURCC_T waveformat_to_codec(uint16_t waveformat_id);
+
+/** Converts a VC_CONTAINER_FOURCC_T into a WaveFormat ID.
+ *
+ * \param  codec VC_CONTAINER_FOURCC_T to convert
+ * \return a valid WaveFormat ID of 0 if no mapping was found.
+ */
+uint16_t codec_to_waveformat(VC_CONTAINER_FOURCC_T codec);
+
+/** Tries to convert a generic fourcc into a VC_CONTAINER_FOURCC_T.
+ *
+ * \param  fourcc fourcc to convert
+ * \return a valid VC_CONTAINER_FOURCC_T or VC_CONTAINER_CODEC_UNKNOWN if no mapping was found.
+ */
+VC_CONTAINER_FOURCC_T fourcc_to_codec(uint32_t fourcc);
+
+uint32_t codec_to_fourcc(VC_CONTAINER_FOURCC_T codec);
+
+/** Tries to convert VideoForWindows fourcc into a VC_CONTAINER_FOURCC_T.
+ *
+ * \param  fourcc vfw fourcc to convert
+ * \return a valid VC_CONTAINER_FOURCC_T or VC_CONTAINER_CODEC_UNKNOWN if no mapping was found.
+ */
+VC_CONTAINER_FOURCC_T vfw_fourcc_to_codec(uint32_t fourcc);
+
+/** Tries to convert a VC_CONTAINER_FOURCC_T into a VideoForWindows fourcc.
+ *
+ * \param  codec VC_CONTAINER_FOURCC_T to convert
+ * \return a valid vfw fourcc or 0 if no mapping was found.
+ */
+uint32_t codec_to_vfw_fourcc(VC_CONTAINER_FOURCC_T codec);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* VC_CONTAINERS_CODECS_H */
diff --git a/containers/containers_types.h b/containers/containers_types.h
new file mode 100755 (executable)
index 0000000..4cf6666
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef VC_CONTAINERS_TYPES_H
+#define VC_CONTAINERS_TYPES_H
+
+/** \file containers_types.h
+ * Definition of types used by the containers API
+ */
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <stddef.h>
+
+#if defined( __STDC__ ) && defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+#include <stdint.h>
+#include <inttypes.h>
+
+#elif defined( __GNUC__ )
+#include <stdint.h>
+#include <inttypes.h>
+
+#elif defined(_MSC_VER)
+#include <stdint.h>
+#if (_MSC_VER < 1700)
+typedef          __int8    int8_t;
+typedef unsigned __int8    uint8_t;
+typedef          __int16   int16_t;
+typedef unsigned __int16   uint16_t;
+typedef          __int32   int32_t;
+typedef unsigned __int32   uint32_t;
+typedef          __int64   int64_t;
+typedef unsigned __int64   uint64_t;
+#endif
+#define PRIu16 "u"
+#define PRIu32 "u"
+#define PRId64 "I64d"
+#define PRIi64 "I64i"
+#define PRIo64 "I64o"
+#define PRIu64 "I64u"
+#define PRIx64 "I64x"
+
+#else
+typedef signed   char      int8_t;
+typedef unsigned char      uint8_t;
+typedef signed   short     int16_t;
+typedef unsigned short     uint16_t;
+typedef signed   long      int32_t;
+typedef unsigned long      uint32_t;
+typedef signed   long long int64_t;
+typedef unsigned long long uint64_t;
+#endif
+
+/* C99 64bits integers */
+#ifndef INT64_C
+# define INT64_C(value) value##LL
+# define UINT64_C(value) value##ULL
+#endif
+
+/* C99 boolean */
+#ifndef __cplusplus
+#ifndef bool
+# define bool int
+#endif
+#ifndef true
+# define true 1
+#endif
+#ifndef false
+# define false 0
+#endif
+#endif /* __cplusplus */
+
+/* FIXME: should be different for big endian */
+#define VC_FOURCC(a,b,c,d) ((a) | (b << 8) | (c << 16) | (d << 24))
+
+#endif /* VC_CONTAINERS_TYPES_H */
diff --git a/containers/core/containers.c b/containers/core/containers.c
new file mode 100755 (executable)
index 0000000..3693e35
--- /dev/null
@@ -0,0 +1,637 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io.h"
+#include "containers/core/containers_filters.h"
+#include "containers/core/containers_loader.h"
+#include "containers/core/containers_logging.h"
+#include "containers/core/containers_utils.h"
+
+#define WRITER_SPACE_SAFETY_MARGIN (10*1024)
+#define PACKETIZER_BUFFER_SIZE (32*1024)
+
+/*****************************************************************************/
+VC_CONTAINER_T *vc_container_open_reader_with_io( struct VC_CONTAINER_IO_T *io,
+   const char *uri, VC_CONTAINER_STATUS_T *p_status,
+   VC_CONTAINER_PROGRESS_REPORT_FUNC_T pfn_progress, void *progress_userdata)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_T *p_ctx = 0;
+   const char *extension;
+
+   VC_CONTAINER_PARAM_UNUSED(pfn_progress);
+   VC_CONTAINER_PARAM_UNUSED(progress_userdata);
+   VC_CONTAINER_PARAM_UNUSED(uri);
+
+   /* Sanity check the i/o */
+   if (!io || !io->pf_read || !io->pf_seek)
+   {
+      LOG_ERROR(0, "invalid i/o instance: %p", io);
+      status = VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+      goto error;
+   }
+
+   /* Allocate our context before trying out the different readers / writers */
+   p_ctx = malloc( sizeof(*p_ctx) + sizeof(*p_ctx->priv) + sizeof(*p_ctx->drm));
+   if(!p_ctx) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(p_ctx, 0, sizeof(*p_ctx) + sizeof(*p_ctx->priv) + sizeof(*p_ctx->drm));
+   p_ctx->priv = (VC_CONTAINER_PRIVATE_T *)(p_ctx + 1);
+   p_ctx->priv->verbosity = vc_container_log_get_default_verbosity();
+   p_ctx->drm = (VC_CONTAINER_DRM_T *)(p_ctx->priv + 1);
+   p_ctx->size = io->size;
+   p_ctx->priv->io = io;
+   p_ctx->priv->uri = io->uri_parts;
+
+   /* If the uri has an extension, use it as a hint when loading the container */
+   extension = vc_uri_path_extension(p_ctx->priv->uri);
+   /* If the user has specified a container, then use that instead */
+   vc_uri_find_query(p_ctx->priv->uri, 0, "container", &extension);
+
+   status = vc_container_load_reader(p_ctx, extension);
+   if (status != VC_CONTAINER_SUCCESS)
+      goto error;
+
+   p_ctx->priv->drm_filter = vc_container_filter_open(VC_FOURCC('d','r','m',' '), 
+      VC_FOURCC('u','n','k','n'), p_ctx, &status); 
+   if (status != VC_CONTAINER_SUCCESS)
+   {
+      /* Some other problem occurred aside from the filter not being appropriate or
+         the stream not needing it. */
+      if (status != VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED) goto error;
+
+      /* Report no DRM and continue as normal */
+      p_ctx->drm = NULL;
+      status = VC_CONTAINER_SUCCESS;
+   }
+
+end:
+   if(p_status) *p_status = status;
+   return p_ctx;
+
+error:
+   if (p_ctx)
+   {
+      p_ctx->priv->io = NULL; /* The i/o doesn't belong to us */
+      vc_container_close(p_ctx);
+      p_ctx = NULL;
+   }
+   goto end;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_T *vc_container_open_reader( const char *uri, VC_CONTAINER_STATUS_T *p_status,
+   VC_CONTAINER_PROGRESS_REPORT_FUNC_T pfn_progress, void *progress_userdata)
+{
+   VC_CONTAINER_IO_T *io;
+   VC_CONTAINER_T *ctx;
+
+   /* Start by opening the URI */
+   io = vc_container_io_open( uri, VC_CONTAINER_IO_MODE_READ, p_status );
+   if (!io)
+      return 0;
+
+   ctx = vc_container_open_reader_with_io( io, uri, p_status, pfn_progress, progress_userdata);
+   if (!ctx)
+      vc_container_io_close(io);
+   return ctx;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_T *vc_container_open_writer( const char *uri, VC_CONTAINER_STATUS_T *p_status,
+   VC_CONTAINER_PROGRESS_REPORT_FUNC_T pfn_progress, void *progress_userdata)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_T *p_ctx = 0;
+   VC_CONTAINER_IO_T *io;
+   const char *extension;
+   VC_CONTAINER_PARAM_UNUSED(pfn_progress);
+   VC_CONTAINER_PARAM_UNUSED(progress_userdata);
+
+   /* Start by opening the URI */
+   io = vc_container_io_open( uri, VC_CONTAINER_IO_MODE_WRITE, &status );
+   if(!io) goto error;
+
+   /* Make sure we have enough space available to start writing */
+   if(io->max_size && io->max_size < WRITER_SPACE_SAFETY_MARGIN)
+   {
+      LOG_DEBUG(p_ctx, "not enough space available to open a writer");
+      status = VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+      goto error;
+   }
+
+   /* Allocate our context before trying out the different readers / writers */
+   p_ctx = malloc( sizeof(*p_ctx) + sizeof(*p_ctx->priv));
+   if(!p_ctx) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(p_ctx, 0, sizeof(*p_ctx) + sizeof(*p_ctx->priv));
+   p_ctx->priv = (VC_CONTAINER_PRIVATE_T *)(p_ctx + 1);
+   p_ctx->priv->verbosity = vc_container_log_get_default_verbosity();
+   p_ctx->priv->io = io;
+   p_ctx->priv->uri = io->uri_parts;
+   io = NULL; /* io now owned by the context */
+
+   /* If the uri has an extension, use it as a hint when loading the container */
+   extension = vc_uri_path_extension(p_ctx->priv->uri);
+   /* If the user has specified a container, then use that instead */
+   vc_uri_find_query(p_ctx->priv->uri, 0, "container", &extension);
+
+   status = vc_container_load_writer(p_ctx, extension);
+   if(status != VC_CONTAINER_SUCCESS) goto error;
+
+ end:
+   if(p_status) *p_status = status;
+   return p_ctx;
+
+error:
+   if(io) vc_container_io_close(io);
+   if (p_ctx) vc_container_close(p_ctx);
+   p_ctx = NULL;
+   goto end;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_close( VC_CONTAINER_T *p_ctx )
+{
+   unsigned int i;
+
+   if(!p_ctx)
+      return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+
+   for(i = 0; i < p_ctx->tracks_num; i++)
+      if(p_ctx->tracks[i]->priv->packetizer)
+         vc_packetizer_close(p_ctx->tracks[i]->priv->packetizer);
+   if(p_ctx->priv->packetizer_buffer) free(p_ctx->priv->packetizer_buffer);
+   if(p_ctx->priv->drm_filter) vc_container_filter_close(p_ctx->priv->drm_filter);
+   if(p_ctx->priv->pf_close) p_ctx->priv->pf_close(p_ctx);
+   if(p_ctx->priv->io) vc_container_io_close(p_ctx->priv->io);
+   if(p_ctx->priv->module_handle) vc_container_unload(p_ctx);
+   for(i = 0; i < p_ctx->meta_num; i++) free(p_ctx->meta[i]);
+   if(p_ctx->meta_num) free(p_ctx->meta);
+   p_ctx->meta_num = 0;
+   free(p_ctx);
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T container_read_packet( VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_PACKET_T *p_packet, uint32_t flags )
+{
+   VC_CONTAINER_STATUS_T status;
+
+   while(1)
+   {
+      status = p_ctx->priv->pf_read(p_ctx, p_packet, flags);
+      if(status == VC_CONTAINER_ERROR_CONTINUE)
+         continue;
+
+      if(!p_packet || (flags & VC_CONTAINER_READ_FLAG_SKIP))
+         return status; /* We've just been requested to skip the data */
+
+      if(status != VC_CONTAINER_SUCCESS)
+         return status;
+
+      /* Skip data from out of bounds tracks, disabled tracks or packets that are encrypted
+         and cannot be decrypted */
+      if(p_packet->track >= p_ctx->tracks_num ||
+         !p_ctx->tracks[p_packet->track]->is_enabled ||
+         ((p_packet->flags & VC_CONTAINER_PACKET_FLAG_ENCRYPTED) && !p_ctx->priv->drm_filter))
+      {
+         if(flags & VC_CONTAINER_READ_FLAG_INFO)
+            status = p_ctx->priv->pf_read(p_ctx, p_packet, VC_CONTAINER_READ_FLAG_SKIP);
+         if(status == VC_CONTAINER_SUCCESS || status == VC_CONTAINER_ERROR_CONTINUE)
+            continue;
+      }
+      if(status != VC_CONTAINER_SUCCESS)
+         return status;
+
+      if(p_ctx->priv->drm_filter)
+         status = vc_container_filter_process(p_ctx->priv->drm_filter, p_packet);
+
+      break;
+   }
+   return status;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_read( VC_CONTAINER_T *p_ctx, VC_CONTAINER_PACKET_T *p_packet, uint32_t flags )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_CONTINUE;
+   VC_PACKETIZER_FLAGS_T packetizer_flags = 0;
+   VC_PACKETIZER_T *packetizer;
+   uint32_t force = flags & VC_CONTAINER_READ_FLAG_FORCE_TRACK;
+   unsigned int i;
+
+   if(!p_packet && !(flags & VC_CONTAINER_READ_FLAG_SKIP))
+      return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+   if(!p_packet && (flags & VC_CONTAINER_READ_FLAG_INFO))
+      return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+   if(p_packet && !p_packet->data && !(flags & (VC_CONTAINER_READ_FLAG_INFO | VC_CONTAINER_READ_FLAG_SKIP)))
+      return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+   if((flags & VC_CONTAINER_READ_FLAG_FORCE_TRACK) &&
+      (!p_packet || p_packet->track >= p_ctx->tracks_num || !p_ctx->tracks[p_packet->track]->is_enabled))
+      return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+
+   /* Always having a packet structure to work with simplifies things */
+   if(!p_packet)
+      p_packet = &p_ctx->priv->packetizer_packet;
+
+   /* Simple/Fast case first */
+   if(!p_ctx->priv->packetizing)
+   {
+      status = container_read_packet( p_ctx, p_packet, flags );
+      goto end;
+   }
+
+   if(flags & VC_CONTAINER_READ_FLAG_INFO)
+      packetizer_flags |= VC_PACKETIZER_FLAG_INFO;
+   if(flags & VC_CONTAINER_READ_FLAG_SKIP)
+      packetizer_flags |= VC_PACKETIZER_FLAG_SKIP;
+
+   /* Loop through all the packetized tracks first to see if we've got any
+    * data to consume there */
+   for(i = 0; i < p_ctx->tracks_num; i++)
+   {
+      VC_PACKETIZER_T *packetizer = p_ctx->tracks[i]->priv->packetizer;
+      if(!p_ctx->tracks[i]->is_enabled || !packetizer ||
+         (force && i != p_packet->track))
+         continue;
+
+      status = vc_packetizer_read(packetizer, p_packet, packetizer_flags);
+      p_packet->track = i;
+      if(status == VC_CONTAINER_SUCCESS)
+         break;
+   }
+   if(i < p_ctx->tracks_num) /* We've got some data */
+      goto end;
+
+   /* Let's go and read some data from the actual container */
+   while(1)
+   {
+      VC_CONTAINER_PACKET_T *tmp = &p_ctx->priv->packetizer_packet;
+      tmp->track = p_packet->track;
+
+      /* Let's check what the container has to offer */
+      status = container_read_packet( p_ctx, tmp, force|VC_PACKETIZER_FLAG_INFO );
+      if(status != VC_CONTAINER_SUCCESS)
+         return status;
+
+      if(!p_ctx->tracks[tmp->track]->priv->packetizer)
+      {
+         status = container_read_packet( p_ctx, p_packet, flags );
+         break;
+      }
+
+      /* Feed data from the container onto the packetizer */
+      packetizer = p_ctx->tracks[tmp->track]->priv->packetizer;
+
+      tmp->data = p_ctx->priv->packetizer_buffer;
+      tmp->buffer_size = PACKETIZER_BUFFER_SIZE;
+      tmp->size = 0;
+      status = container_read_packet( p_ctx, tmp, force );
+      if(status != VC_CONTAINER_SUCCESS)
+         return status;
+
+      p_packet->track = tmp->track;
+      vc_packetizer_push(packetizer, tmp);
+      vc_packetizer_pop(packetizer, &tmp, VC_PACKETIZER_FLAG_FORCE_RELEASE_INPUT);
+
+      status = vc_packetizer_read(packetizer, p_packet, packetizer_flags);
+      if(status == VC_CONTAINER_SUCCESS)
+         break;
+   }
+
+ end:
+   if(status != VC_CONTAINER_SUCCESS)
+      return status;
+
+   if(p_packet && p_packet->dts > p_ctx->position)
+      p_ctx->position = p_packet->dts;
+   if(p_packet && p_packet->pts > p_ctx->position)
+      p_ctx->position = p_packet->pts;
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_write( VC_CONTAINER_T *p_ctx, VC_CONTAINER_PACKET_T *p_packet )
+{
+   VC_CONTAINER_STATUS_T status;
+   void * p_metadata_buffer = NULL;
+   uint32_t metadata_length = 0;
+
+   /* TODO: check other similar argument errors and non-stateless errors */
+   if (!p_packet || !p_packet->data || p_packet->track >= p_ctx->tracks_num) 
+      return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+
+   /* Check for a previous error */
+   if(p_ctx->priv->status != VC_CONTAINER_SUCCESS && p_ctx->priv->status != VC_CONTAINER_ERROR_NOT_READY)
+      return p_ctx->priv->status;
+
+   /* Check we have enough space to write the data */
+   if(p_ctx->priv->max_size &&
+      p_ctx->size + p_packet->size + WRITER_SPACE_SAFETY_MARGIN > p_ctx->priv->max_size)
+   {status = VC_CONTAINER_ERROR_LIMIT_REACHED; goto end;}
+   if(p_ctx->priv->io->max_size &&
+      p_ctx->size + p_packet->size + WRITER_SPACE_SAFETY_MARGIN +
+         (p_ctx->priv->tmp_io ? p_ctx->priv->tmp_io->offset : 0) > p_ctx->priv->io->max_size)
+   {status = VC_CONTAINER_ERROR_OUT_OF_SPACE; goto end;}
+
+   /* If a filter is created, then send the packet to the filter for encryption. */
+   if(p_ctx->priv->drm_filter)
+   {
+      status = vc_container_filter_process(p_ctx->priv->drm_filter, p_packet);
+
+      if(status == VC_CONTAINER_SUCCESS)
+      {
+         /* Get the encryption metadata and send it to the output first. */
+         if(vc_container_control(p_ctx, VC_CONTAINER_CONTROL_GET_DRM_METADATA, 
+             &p_metadata_buffer, &metadata_length) == VC_CONTAINER_SUCCESS && metadata_length > 0)
+         {
+            /* Make a packet up with the metadata in the payload and write it. */
+            VC_CONTAINER_PACKET_T metadata_packet;
+            metadata_packet.data = p_metadata_buffer;
+            metadata_packet.buffer_size = metadata_length; 
+            metadata_packet.size = metadata_length; 
+            metadata_packet.frame_size = p_packet->frame_size + metadata_length;                 
+            metadata_packet.pts = p_packet->pts;
+            metadata_packet.dts = p_packet->dts;
+            metadata_packet.num = p_packet->num;   
+            metadata_packet.track = p_packet->track;
+            /* As this packet is written first, we must transfer any frame start 
+               flag from the following packet. Also, this packet can never have the end flag set. */
+            metadata_packet.flags = p_packet->flags & ~VC_CONTAINER_PACKET_FLAG_FRAME_END;
+
+            p_packet->pts = p_packet->dts = VC_CONTAINER_TIME_UNKNOWN;
+            p_packet->flags &= ~VC_CONTAINER_PACKET_FLAG_FRAME_START;
+            if(p_ctx->priv->pf_write(p_ctx, &metadata_packet) != VC_CONTAINER_SUCCESS) goto end;
+         }
+      }
+      else if (status != VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION)
+      {
+         /* Encryption was appropriate but a problem has occurred. Skip the write of data
+            to the io and return the status to the caller. */
+         goto end;
+      }
+   }
+     
+   status = p_ctx->priv->pf_write(p_ctx, p_packet);
+
+ end:
+   p_ctx->priv->status = status;
+   return status;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_seek( VC_CONTAINER_T *p_ctx, int64_t *p_offset,
+   VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags)
+{
+   VC_CONTAINER_STATUS_T status;
+   int64_t offset = *p_offset;
+   unsigned int i;
+
+   /* Reset all packetizers */
+   for(i = 0; i < p_ctx->tracks_num; i++)
+      if(p_ctx->tracks[i]->priv->packetizer)
+         vc_packetizer_reset(p_ctx->tracks[i]->priv->packetizer);
+
+   status = p_ctx->priv->pf_seek(p_ctx, p_offset, mode, flags);
+
+   /* */
+   if(status == VC_CONTAINER_SUCCESS && (flags & VC_CONTAINER_SEEK_FLAG_FORWARD) &&
+      *p_offset < offset)
+   {
+      LOG_DEBUG(p_ctx, "container didn't seek forward as requested (%"PRIi64"/%"PRIi64")",
+                *p_offset, offset);
+      for(i = 1; i <= 5 && *p_offset < offset; i++)
+      {
+         *p_offset = offset + i * i * 100000;
+         status = p_ctx->priv->pf_seek(p_ctx, p_offset, mode, flags);
+         if(status != VC_CONTAINER_SUCCESS) break;
+      }
+   }
+
+   return status;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_control( VC_CONTAINER_T *p_ctx, VC_CONTAINER_CONTROL_T operation, ... )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+   va_list args;
+
+   va_start( args, operation );
+
+   if(operation == VC_CONTAINER_CONTROL_ENCRYPT_TRACK)
+   {
+      VC_CONTAINER_FOURCC_T type = va_arg(args, VC_CONTAINER_FOURCC_T);
+
+      uint32_t track_num = va_arg(args, uint32_t);
+      void *p_drm_data = va_arg(args, void *);
+      int drm_data_size = va_arg(args, uint32_t);
+
+      if(!p_ctx->priv->drm_filter && track_num < p_ctx->tracks_num)
+      {
+         VC_CONTAINER_TRACK_T * p_track = p_ctx->tracks[track_num];
+
+         if ((status = vc_container_track_allocate_drmdata(p_ctx, p_track, drm_data_size)) != VC_CONTAINER_SUCCESS)
+         {
+            LOG_DEBUG(p_ctx, "failed to allocate memory for 'drm data' (%d bytes)", drm_data_size);
+            goto end;
+         }
+         memcpy(p_track->priv->drmdata, p_drm_data, drm_data_size);
+
+         /* Track encryption enabled and no filter - create one now. */
+         p_ctx->priv->drm_filter = vc_container_filter_open(VC_FOURCC('d','r','m',' '), type, p_ctx, &status);  
+         if(status != VC_CONTAINER_SUCCESS)
+            goto end;
+     
+         status = vc_container_filter_control(p_ctx->priv->drm_filter, operation, track_num);
+      }
+   }
+   else if(operation == VC_CONTAINER_CONTROL_GET_DRM_METADATA)
+   {
+      void *p_drm_data = va_arg(args, void *);
+      int *drm_data_size = va_arg(args, int *);
+      status = vc_container_filter_control(p_ctx->priv->drm_filter, operation, p_drm_data, drm_data_size);      
+   }
+
+   if(status == VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION && p_ctx->priv->pf_control)
+      status = p_ctx->priv->pf_control(p_ctx, operation, args);
+
+   /* If the request has already been handled then we're done */
+   if(status != VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION)
+      goto end;
+
+   switch(operation)
+   {
+   case VC_CONTAINER_CONTROL_DRM_PLAY:
+      if (p_ctx->priv->drm_filter)
+         status = vc_container_filter_control(p_ctx->priv->drm_filter, operation, args);
+      break;
+
+   case VC_CONTAINER_CONTROL_SET_MAXIMUM_SIZE:
+      p_ctx->priv->max_size = (uint64_t)va_arg( args, uint64_t );
+      if(p_ctx->priv->io->max_size &&
+         p_ctx->priv->max_size > p_ctx->priv->io->max_size)
+         p_ctx->priv->max_size = p_ctx->priv->io->max_size;
+      status = VC_CONTAINER_SUCCESS;
+      break;
+
+   case VC_CONTAINER_CONTROL_TRACK_PACKETIZE:
+      {
+         unsigned int track_num = va_arg(args, unsigned int);
+         VC_CONTAINER_FOURCC_T fourcc = va_arg(args, VC_CONTAINER_FOURCC_T);
+         VC_CONTAINER_TRACK_T *p_track;
+
+         if(track_num >= p_ctx->tracks_num)
+         {
+            status = VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+            break;
+         }
+         if(p_ctx->tracks[track_num]->priv->packetizer)
+         {
+            status = VC_CONTAINER_SUCCESS;
+            break;
+         }
+
+         p_track = p_ctx->tracks[track_num];
+         p_track->priv->packetizer = vc_packetizer_open( p_track->format, fourcc, &status );
+         if(!p_track->priv->packetizer)
+            break;
+
+         if(!p_ctx->priv->packetizer_buffer)
+         {
+            p_ctx->priv->packetizer_buffer = malloc(PACKETIZER_BUFFER_SIZE);
+            if(!p_ctx->priv->packetizer_buffer)
+            {
+               status = VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+               vc_packetizer_close(p_track->priv->packetizer);
+               p_track->priv->packetizer = NULL;
+               break;
+            }
+         }
+
+         vc_container_format_copy(p_track->format, p_track->priv->packetizer->out,
+            p_track->format->extradata_size);
+         p_track->format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
+         p_ctx->priv->packetizing = true;
+      }
+      break;
+
+   default: break;
+   }
+
+   if (status == VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION)
+      status = vc_container_io_control_list(p_ctx->priv->io, operation, args);
+
+ end:
+   va_end( args );
+   return status;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_TRACK_T *vc_container_allocate_track( VC_CONTAINER_T *context, unsigned int extra_size )
+{
+   VC_CONTAINER_TRACK_T *p_ctx;
+   unsigned int size;
+   VC_CONTAINER_PARAM_UNUSED(context);
+
+   size = sizeof(*p_ctx) + sizeof(*p_ctx->priv) + sizeof(*p_ctx->format) +
+      sizeof(*p_ctx->format->type) + extra_size;
+
+   p_ctx = malloc(size);
+   if(!p_ctx) return 0;
+
+   memset(p_ctx, 0, size);
+   p_ctx->priv = (VC_CONTAINER_TRACK_PRIVATE_T *)(p_ctx + 1);
+   p_ctx->format = (VC_CONTAINER_ES_FORMAT_T *)(p_ctx->priv + 1);
+   p_ctx->format->type = (void *)(p_ctx->format + 1);
+   p_ctx->priv->module = (struct VC_CONTAINER_TRACK_MODULE_T *)(p_ctx->format->type + 1);
+   return p_ctx;
+}
+
+/*****************************************************************************/
+void vc_container_free_track( VC_CONTAINER_T *context, VC_CONTAINER_TRACK_T *p_track )
+{
+   VC_CONTAINER_PARAM_UNUSED(context);
+   if(p_track)
+   {
+      if(p_track->priv->extradata) free(p_track->priv->extradata);
+      if(p_track->priv->drmdata) free(p_track->priv->drmdata);
+      free(p_track);
+   }
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_track_allocate_extradata( VC_CONTAINER_T *context,
+   VC_CONTAINER_TRACK_T *p_track, unsigned int extra_size )
+{
+   VC_CONTAINER_PARAM_UNUSED(context);
+
+   /* Sanity check the size of the extra data */
+   if(extra_size > 100*1024) return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+
+   /* Check if we need to allocate a buffer */
+   if(extra_size > p_track->priv->extradata_size)
+   {
+      p_track->priv->extradata_size = 0;
+      if(p_track->priv->extradata) free(p_track->priv->extradata);
+      p_track->priv->extradata = malloc(extra_size);
+      p_track->format->extradata = p_track->priv->extradata;
+      if(!p_track->priv->extradata) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+      p_track->priv->extradata_size = extra_size;
+   }
+   p_track->format->extradata = p_track->priv->extradata;
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_track_allocate_drmdata( VC_CONTAINER_T *context,
+   VC_CONTAINER_TRACK_T *p_track, unsigned int size )
+{
+   VC_CONTAINER_PARAM_UNUSED(context);
+
+   /* Sanity check the size of the drm data */
+   if(size > 200*1024) return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+
+   /* Check if we need to allocate a buffer */
+   if(size > p_track->priv->drmdata_size)
+   {
+      p_track->priv->drmdata_size = 0;
+      if(p_track->priv->drmdata) free(p_track->priv->drmdata);
+      p_track->priv->drmdata = malloc(size);
+      if(!p_track->priv->drmdata) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+      p_track->priv->drmdata_size = size;
+   }
+
+   return VC_CONTAINER_SUCCESS;
+}
diff --git a/containers/core/containers_bits.c b/containers/core/containers_bits.c
new file mode 100755 (executable)
index 0000000..30f8650
--- /dev/null
@@ -0,0 +1,490 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "containers/core/containers_bits.h"
+#include "containers/core/containers_common.h"
+
+#ifdef    ENABLE_CONTAINERS_LOG_FORMAT
+#include "containers/core/containers_logging.h"
+#endif
+
+/******************************************************************************
+Defines and constants.
+******************************************************************************/
+
+#ifdef    ENABLE_CONTAINERS_LOG_FORMAT
+/** String used for indentation. If more spaces are needed, just add them. */
+#define INDENT_SPACES_STRING  ">                         "
+#define INDENT_SPACES_LENGTH  (sizeof(INDENT_SPACES_STRING) - 1)
+#endif /* ENABLE_CONTAINERS_LOG_FORMAT */
+
+/******************************************************************************
+Type definitions
+******************************************************************************/
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+
+#ifdef    ENABLE_CONTAINERS_LOG_FORMAT
+
+/**************************************************************************//**
+ * Returns a string that indicates whether the bit stream is valid or not.
+ *
+ * \pre bit_stream is not NULL.
+ *
+ * \param bit_stream The bit stream object.
+ * \return  A string indicating the validity of the stream.
+ */
+static const char * vc_container_bits_valid_str( VC_CONTAINER_BITS_T *bit_stream )
+{
+   return vc_container_bits_valid(bit_stream) ? "" : " - stream invalid";
+}
+
+/**************************************************************************//**
+ * Returns a string of spaces the length of which is determined by the
+ * parameter.
+ * The length is limited to a certain size, above which a greater than symbol
+ * prefixes the maximum number of spaces.
+ *
+ * \param length  The required length of the string.
+ * \return  A string indicating the validity of the stream.
+ */
+static const char * vc_container_bits_indent_str(uint32_t length)
+{
+   uint32_t str_length = length;
+
+   if (str_length > INDENT_SPACES_LENGTH)
+      str_length = INDENT_SPACES_LENGTH;
+
+   return INDENT_SPACES_STRING + (INDENT_SPACES_LENGTH - str_length);
+}
+
+#endif /* ENABLE_CONTAINERS_LOG_FORMAT */
+
+/**************************************************************************//**
+ * Returns the number of consecutive zero bits in the stream.
+ * the zero bits are terminated either by a one bit, or the end of the stream.
+ * In the former case, the zero bits and the terminating one bit are removed
+ * from the stream.
+ * In the latter case, the stream becomes invalid. The stream also becomes
+ * invalid if there are not as many bits after the one bit as zero bits before
+ * it.
+ * If the stream is already or becomes invalid, zero is returned.
+ *
+ * \pre bit_stream is not NULL.
+ *
+ * \param bit_stream The bit stream object.
+ * \return  The number of consecutive zero bits, or zero if the stream is
+ *          invalid.
+ */
+static uint32_t vc_container_bits_get_leading_zero_bits( VC_CONTAINER_BITS_T *bit_stream )
+{
+   uint32_t leading_zero_bits;
+   uint32_t bits_left = vc_container_bits_available(bit_stream);
+   uint32_t bits;
+   uint8_t mask, current_byte;
+
+   if (!bits_left)
+      return vc_container_bits_invalidate(bit_stream);
+
+   /* Cache 'bits' field to avoid repeated pointer access */
+   bits = bit_stream->bits;
+   if (bits)
+   {
+      current_byte = *bit_stream->buffer;
+      mask = 1 << (bits - 1);
+   } else {
+      /* Initialize variables to placate the compiler */
+      current_byte = 0;
+      mask = 0;
+   }
+
+   /* Scan for the first one bit, counting the number of zeroes. This gives the
+    * number of further bits after the one that are part of the value. See
+    * section 9.1 of ITU-T REC H.264 201003 for more details. */
+
+   for (leading_zero_bits = 0; leading_zero_bits < bits_left; leading_zero_bits++)
+   {
+      if (!bits)
+      {
+         if (!bit_stream->bytes)
+            return vc_container_bits_invalidate(bit_stream);
+         bit_stream->bytes--;
+         current_byte = *(++bit_stream->buffer);
+         bits = 8;
+         mask = 0x80;
+      }
+
+      bits--;
+      bits_left--;
+      if (current_byte & mask)
+         break;      /* Found the marker bit */
+
+      mask >>= 1;
+   }
+
+   /* Check enough bits are left in the stream for the value. */
+   if (leading_zero_bits > bits_left)
+      return vc_container_bits_invalidate(bit_stream);
+
+   /* Return cached value of bits to the stream */
+   bit_stream->bits = bits;
+   
+   return leading_zero_bits;
+}
+
+/*****************************************************************************
+Functions exported as part of the bit stream API
+ *****************************************************************************/
+
+/*****************************************************************************/
+void vc_container_bits_init(VC_CONTAINER_BITS_T *bit_stream,
+      const uint8_t *buffer,
+      uint32_t available)
+{
+   vc_container_assert(buffer && (buffer != (const uint8_t *)1));
+
+   /* Start with buffer pointing at the previous byte with no bits available
+    * to make the mathematics easier */
+   bit_stream->buffer = buffer - 1;
+   bit_stream->bytes = available;
+   bit_stream->bits = 0;
+}
+
+/*****************************************************************************/
+uint32_t vc_container_bits_invalidate( VC_CONTAINER_BITS_T *bit_stream )
+{
+   bit_stream->buffer = NULL;
+   return 0;
+}
+
+/*****************************************************************************/
+bool vc_container_bits_valid(VC_CONTAINER_BITS_T *bit_stream)
+{
+   return (bit_stream->buffer != NULL);
+}
+
+/*****************************************************************************/
+void vc_container_bits_reset(VC_CONTAINER_BITS_T *bit_stream)
+{
+   bit_stream->bytes = 0;
+   bit_stream->bits = 0;
+}
+
+/*****************************************************************************/
+const uint8_t *vc_container_bits_current_pointer(const VC_CONTAINER_BITS_T *bit_stream)
+{
+   const uint8_t *buffer = bit_stream->buffer;
+
+   /* Only valid on byte boundaries, where buffer pointer has not been moved yet */
+   vc_container_assert(!bit_stream->bits);
+
+   return buffer ? (buffer + 1) : NULL;
+}
+
+/*****************************************************************************/
+void vc_container_bits_copy_stream(VC_CONTAINER_BITS_T *dst,
+      const VC_CONTAINER_BITS_T *src)
+{
+   memcpy(dst, src, sizeof(VC_CONTAINER_BITS_T));
+}
+
+/*****************************************************************************/
+uint32_t vc_container_bits_available(const VC_CONTAINER_BITS_T *bit_stream)
+{
+   if (!bit_stream->buffer)
+      return 0;
+   return (bit_stream->bytes << 3) + bit_stream->bits;
+}
+
+/*****************************************************************************/
+uint32_t vc_container_bits_bytes_available(const VC_CONTAINER_BITS_T *bit_stream)
+{
+   if (!bit_stream->buffer)
+      return 0;
+
+   vc_container_assert(!bit_stream->bits);
+
+   return vc_container_bits_available(bit_stream) >> 3;
+}
+
+/*****************************************************************************/
+void vc_container_bits_skip(VC_CONTAINER_BITS_T *bit_stream,
+      uint32_t bits_to_skip)
+{
+   uint32_t have_bits;
+   uint32_t new_bytes;
+
+   have_bits = vc_container_bits_available(bit_stream);
+   if (have_bits < bits_to_skip)
+   {
+      vc_container_bits_invalidate(bit_stream);
+      return;
+   }
+
+   have_bits -= bits_to_skip;
+   new_bytes = have_bits >> 3;
+   bit_stream->bits = have_bits & 7;
+   bit_stream->buffer += (bit_stream->bytes - new_bytes);
+   bit_stream->bytes = new_bytes;
+}
+
+/*****************************************************************************/
+void vc_container_bits_skip_bytes(VC_CONTAINER_BITS_T *bit_stream,
+      uint32_t bytes_to_skip)
+{
+   /* Only valid on byte boundaries */
+   vc_container_assert(!bit_stream->bits);
+
+   vc_container_bits_skip(bit_stream, bytes_to_skip << 3);
+}
+
+/*****************************************************************************/
+void vc_container_bits_reduce_bytes(VC_CONTAINER_BITS_T *bit_stream,
+      uint32_t bytes_to_reduce)
+{
+   if (bit_stream->bytes >= bytes_to_reduce)
+      bit_stream->bytes -= bytes_to_reduce;
+   else
+      vc_container_bits_invalidate(bit_stream);
+}
+
+/*****************************************************************************/
+void vc_container_bits_copy_bytes(VC_CONTAINER_BITS_T *bit_stream,
+      uint32_t bytes_to_copy,
+      uint8_t *dst)
+{
+   vc_container_assert(!bit_stream->bits);
+
+   if (bit_stream->bytes < bytes_to_copy)
+   {
+      /* Not enough data */
+      vc_container_bits_invalidate(bit_stream);
+      return;
+   }
+
+   /* When the number of bits is zero, the next byte to take is at buffer + 1 */
+   memcpy(dst, bit_stream->buffer + 1, bytes_to_copy);
+   bit_stream->buffer += bytes_to_copy;
+   bit_stream->bytes -= bytes_to_copy;
+}
+
+/*****************************************************************************/
+uint32_t vc_container_bits_read_u32(VC_CONTAINER_BITS_T *bit_stream,
+      uint32_t value_bits)
+{
+   uint32_t value = 0;
+   uint32_t needed = value_bits;
+   uint32_t bits;
+
+   vc_container_assert(value_bits <= 32);
+
+   if (needed > vc_container_bits_available(bit_stream))
+      return vc_container_bits_invalidate(bit_stream);
+
+   bits = bit_stream->bits;
+   while (needed)
+   {
+      uint32_t take;
+
+      if (!bits)
+      {
+         bit_stream->bytes--;
+         bit_stream->buffer++;
+         bits = 8;
+      }
+
+      take = bits;
+      if (needed < take) take = needed;
+
+      bits -= take;
+      needed -= take;
+
+      value <<= take;
+      if (take == 8)
+         value |= *bit_stream->buffer;  /* optimize whole byte case */
+      else
+         value |= (*bit_stream->buffer >> bits) & ((1 << take) - 1);
+   }
+
+   bit_stream->bits = bits;
+   return value;
+}
+
+/*****************************************************************************/
+void vc_container_bits_skip_exp_golomb(VC_CONTAINER_BITS_T *bit_stream)
+{
+   vc_container_bits_skip(bit_stream, vc_container_bits_get_leading_zero_bits(bit_stream));
+}
+
+/*****************************************************************************/
+uint32_t vc_container_bits_read_u32_exp_golomb(VC_CONTAINER_BITS_T *bit_stream)
+{
+   uint32_t leading_zero_bits;
+   uint32_t codeNum;
+
+   leading_zero_bits = vc_container_bits_get_leading_zero_bits(bit_stream);
+
+   /* Anything bigger than 32 bits is definitely overflow */
+   if (leading_zero_bits > 32)
+      return vc_container_bits_invalidate(bit_stream);
+
+   codeNum = vc_container_bits_read_u32(bit_stream, leading_zero_bits);
+
+   if (leading_zero_bits == 32)
+   {
+      /* If codeNum is non-zero, it would need 33 bits, so is also overflow */
+      if (codeNum)
+         return vc_container_bits_invalidate(bit_stream);
+
+      return 0xFFFFFFFF;
+   }
+
+   return codeNum + (1 << leading_zero_bits) - 1;
+}
+
+/*****************************************************************************/
+int32_t vc_container_bits_read_s32_exp_golomb(VC_CONTAINER_BITS_T *bit_stream)
+{
+   uint32_t uval;
+
+   uval = vc_container_bits_read_u32_exp_golomb(bit_stream);
+
+   /* The signed Exp-Golomb code 0xFFFFFFFF cannot be represented as a signed 32-bit
+    * integer, because it should be one larger than the largest positive value. */
+   if (uval == 0xFFFFFFFF)
+      return vc_container_bits_invalidate(bit_stream);
+
+   /* Definition of conversion is
+    *    s = ((-1)^(u + 1)) * Ceil(u / 2)
+    * where '^' is power, but this should be equivalent */
+   return ((int32_t)((uval & 1) << 1) - 1) * (int32_t)((uval >> 1) + (uval & 1));
+}
+
+#ifdef    ENABLE_CONTAINERS_LOG_FORMAT
+
+/*****************************************************************************/
+void vc_container_bits_log(VC_CONTAINER_T *p_ctx,
+      uint32_t indent,
+      const char *txt,
+      VC_CONTAINER_BITS_T *bit_stream,
+      VC_CONTAINER_BITS_LOG_OP_T op,
+      uint32_t length)
+{
+   const char *valid_str = vc_container_bits_valid_str(bit_stream);
+   const char *indent_str = vc_container_bits_indent_str(indent);
+
+   switch (op)
+   {
+   case VC_CONTAINER_BITS_LOG_SKIP:
+      vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: %u bits skipped%s", indent_str, txt, length, valid_str);
+      break;
+   case VC_CONTAINER_BITS_LOG_SKIP_BYTES:
+      vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: %u bytes skipped%s", indent_str, txt, length, valid_str);
+      break;
+   case VC_CONTAINER_BITS_LOG_COPY_BYTES:
+      vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: %u bytes copied%s", indent_str, txt, length, valid_str);
+      break;
+   case VC_CONTAINER_BITS_LOG_REDUCE_BYTES:
+      vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: %u bytes reduced%s", indent_str, txt, length, valid_str);
+      break;
+   case VC_CONTAINER_BITS_LOG_EG_SKIP:
+      vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: Exp-Golomb value skipped%s", indent_str, txt, valid_str);
+      break;
+   default:
+      /* Unexpected operation. Check bit stream logging macros */
+      vc_container_assert(0);
+   }
+}
+
+/*****************************************************************************/
+uint32_t vc_container_bits_log_u32(VC_CONTAINER_T *p_ctx,
+      uint32_t indent,
+      const char *txt,
+      VC_CONTAINER_BITS_T *bit_stream,
+      VC_CONTAINER_BITS_LOG_OP_T op,
+      uint32_t length,
+      uint32_t value)
+{
+   const char *valid_str = vc_container_bits_valid_str(bit_stream);
+   const char *indent_str = vc_container_bits_indent_str(indent);
+
+   switch (op)
+   {
+   case VC_CONTAINER_BITS_LOG_U8:
+      vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: 0x%02x (%u) in %u bits%s", indent_str, txt, value, value, length, valid_str);
+      break;
+   case VC_CONTAINER_BITS_LOG_U16:
+      vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: 0x%04x (%u) in %u bits%s", indent_str, txt, value, value, length, valid_str);
+      break;
+   case VC_CONTAINER_BITS_LOG_U32:
+      vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: 0x%08x (%u) in %u bits%s", indent_str, txt, value, value, length, valid_str);
+      break;
+   case VC_CONTAINER_BITS_LOG_EG_U32:
+      vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: 0x%08x (%u) unsigned Exp-Golomb%s", indent_str, txt, value, value, valid_str);
+      break;
+   default:
+      /* Unexpected operation. Check bit stream logging macros */
+      vc_container_assert(0);
+   }
+
+   return value;
+}
+
+/*****************************************************************************/
+int32_t vc_container_bits_log_s32(VC_CONTAINER_T *p_ctx,
+      uint32_t indent,
+      const char *txt,
+      VC_CONTAINER_BITS_T *bit_stream,
+      VC_CONTAINER_BITS_LOG_OP_T op,
+      uint32_t length,
+      int32_t value)
+{
+   const char *valid_str = vc_container_bits_valid_str(bit_stream);
+   const char *indent_str = vc_container_bits_indent_str(indent);
+
+   VC_CONTAINER_PARAM_UNUSED(length);
+
+   switch (op)
+   {
+   case VC_CONTAINER_BITS_LOG_EG_S32:
+      vc_container_log(p_ctx, VC_CONTAINER_LOG_FORMAT, "%s%s: 0x%08x (%d) signed Exp-Golomb%s", indent_str, txt, value, value, valid_str);
+      break;
+   default:
+      /* Unexpected operation. Check bit stream logging macros */
+      vc_container_assert(0);
+   }
+
+   return value;
+}
+
+#endif /* ENABLE_CONTAINERS_LOG_FORMAT */
diff --git a/containers/core/containers_bits.h b/containers/core/containers_bits.h
new file mode 100755 (executable)
index 0000000..10f1cd1
--- /dev/null
@@ -0,0 +1,344 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VC_CONTAINERS_BITS_H
+#define VC_CONTAINERS_BITS_H
+
+#include "containers/containers.h"
+
+/** Bit stream structure
+ * Value are read from the buffer, taking bits from MSB to LSB in sequential
+ * bytes until the number of bit and the number of bytes runs out. */
+typedef struct vc_container_bits_tag
+{
+   const uint8_t *buffer;  /**< Buffer from which to take bits */
+   uint32_t bytes;         /**< Number of bytes available from buffer */
+   uint32_t bits;          /**< Number of bits available at current pointer */
+} VC_CONTAINER_BITS_T;
+
+/** Initialise a bit stream object.
+ *
+ * \pre  bit_stream is not NULL.
+ *
+ * \param bit_stream The bit stream object to initialise.
+ * \param buffer     Pointer to the start of the byte buffer.
+ * \param available  Number of bytes in the bit stream.
+ */
+void vc_container_bits_init(VC_CONTAINER_BITS_T *bit_stream, const uint8_t *buffer, uint32_t available);
+
+/** Invalidates the bit stream.
+ * Also returns zero, because it allows callers that need to invalidate and
+ * immediately return zero to do so in a single statement.
+ *
+ * \pre bit_stream is not NULL.
+ *
+ * \param bit_stream The bit stream object.
+ * \return  Zero, always.
+ */
+uint32_t vc_container_bits_invalidate( VC_CONTAINER_BITS_T *bit_stream );
+
+/** Returns true if the bit stream is currently valid.
+ * The stream becomes invalid when a read or skip operation goe beyond the end
+ * of the stream.
+ *
+ * \pre  bit_stream is not NULL.
+ *
+ * \param bit_stream The bit stream object.
+ * \return  True if the stream is valid, false if it is invalid.
+ */
+bool vc_container_bits_valid(VC_CONTAINER_BITS_T *bit_stream);
+
+/** Reset a valid bit stream object to appear empty.
+ * Once a stream has become invalid, reset has no effect.
+ *
+ * \pre  bit_stream is not NULL.
+ *
+ * \param bit_stream The bit stream object.
+ */
+void vc_container_bits_reset(VC_CONTAINER_BITS_T *bit_stream);
+
+/** Return the current byte pointer for the bit stream.
+ *
+ * \pre  bit_stream is not NULL.
+ * \pre  The stream is on a byte boundary.
+ *
+ * \param bit_stream The bit stream object.
+ * \return  The current byte pointer, or NULL if the stream is invalid.
+ */
+const uint8_t *vc_container_bits_current_pointer(const VC_CONTAINER_BITS_T *bit_stream);
+
+/** Copy one bit stream to another.
+ * If the source stream is invalid, the destination one will become so as well.
+ *
+ * \pre  Neither bit stream is NULL.
+ *
+ * \param dst  The destination bit stream object.
+ * \param src  The source bit stream object.
+ */
+void vc_container_bits_copy_stream(VC_CONTAINER_BITS_T *dst, const VC_CONTAINER_BITS_T *src);
+
+/** Return the number of bits left to take from the stream.
+ * If the stream is invalid, zero is returned.
+ *
+ * \pre  bit_stream is not NULL.
+ *
+ * \param bit_stream The bit stream object.
+ * \return  The number of bits left to take.
+ */
+uint32_t vc_container_bits_available(const VC_CONTAINER_BITS_T *bit_stream);
+
+/** Return the number of bytes left to take from the stream.
+ * If the stream is invalid, zero is returned.
+ *
+ * \pre  bit_stream is not NULL.
+ *
+ * \param bit_stream The bit stream object.
+ * \return  The number of bytes left to take.
+ */
+uint32_t vc_container_bits_bytes_available(const VC_CONTAINER_BITS_T *bit_stream);
+
+/** Skip past a number of bits in the stream.
+ * If bits_to_skip is greater than the number of bits available in the stream,
+ * the stream becomes invalid.
+ * If the stream is already invalid, this has no effect.
+ *
+ * \pre  bit_stream is not NULL.
+ *
+ * \param bit_stream    The bit stream object.
+ * \param bits_to_skip  The number of bits to skip.
+ */
+void vc_container_bits_skip(VC_CONTAINER_BITS_T *bit_stream, uint32_t bits_to_skip);
+
+/** Skip past a number of bytes in the stream.
+ * If bytes_to_skip is greater than the number of bytes available in the stream,
+ * the stream becomes invalid.
+ * If the stream is already invalid, this has no effect.
+ *
+ * \pre  bit_stream is not NULL.
+ * \pre  The stream is on a byte boundary.
+ *
+ * \param bit_stream    The bit stream object.
+ * \param bytes_to_skip The number of bytes to skip.
+ */
+void vc_container_bits_skip_bytes(VC_CONTAINER_BITS_T *bit_stream, uint32_t bytes_to_skip);
+
+/** Reduce the length of the bit stream by a number of bytes.
+ * This reduces the number of bits/bytes available without changing the current
+ * position in the stream. If bytes_to_reduce is greater than the number of
+ * bytes available in the stream, the stream becomes invalid.
+ * If the stream is already invalid, this has no effect.
+ *
+ * \pre  bit_stream is not NULL.
+ *
+ * \param bit_stream       The bit stream object.
+ * \param bytes_to_reduce  The number of bytes by which to reduce the stream.
+ */
+void vc_container_bits_reduce_bytes(VC_CONTAINER_BITS_T *bit_stream, uint32_t bytes_to_reduce);
+
+/** Copies a number of bytes from the stream to a byte buffer.
+ * If the stream is or becomes invalid, no data is copied.
+ *
+ * \pre  bit_stream is not NULL.
+ * \pre  The stream is on a byte boundary.
+ *
+ * \param bit_stream    The bit stream object.
+ * \param bytes_to_copy The number of bytes to copy.
+ * \param dst           The byte buffer destination.
+ */
+void vc_container_bits_copy_bytes(VC_CONTAINER_BITS_T *bit_stream, uint32_t bytes_to_copy, uint8_t *dst);
+
+/** Returns the next value_bits from the stream. The last bit will be the least
+ * significant bit in the returned value.
+ * If value_bits is greater than the number of bits available in the stream,
+ * the stream becomes invalid.
+ * If the stream is invalid, or becomes invalid while reading the value, zero
+ * is returned.
+ *
+ * \pre  bit_stream is not NULL.
+ * \pre  value_bits is not larger than 32.
+ *
+ * \param bit_stream The bit stream object.
+ * \param value_bits The number of bits to retrieve.
+ * \return  The value read from the stream, or zero if the stream is invalid.
+ */
+uint32_t vc_container_bits_read_u32(VC_CONTAINER_BITS_T *bit_stream, uint32_t value_bits);
+
+/** Skips the next Exp-Golomb value in the stream.
+ * See section 9.1 of ITU-T REC H.264 201003 for details.
+ * If there are not enough bits in the stream to complete an Exp-Golomb value,
+ * the stream becomes invalid.
+ * If the stream is already invalid, this has no effect.
+ *
+ * \pre  bit_stream is not NULL.
+ *
+ * \param bit_stream The bit stream object.
+ */
+void vc_container_bits_skip_exp_golomb(VC_CONTAINER_BITS_T *bit_stream);
+
+/** Returns the next unsigned Exp-Golomb value from the stream.
+ * See section 9.1 of ITU-T REC H.264 201003 for details.
+ * If there are not enough bits in the stream to complete an Exp-Golomb value,
+ * the stream becomes invalid.
+ * If the next unsigned Exp-Golomb value in the stream is larger than 32 bits,
+ * or the stream is or becomes invalid, zero is returned.
+ *
+ * \pre  bit_stream is not NULL.
+ *
+ * \param bit_stream The bit stream object.
+ * \return  The next unsigned value from the stream, or zero on error.
+ */
+uint32_t vc_container_bits_read_u32_exp_golomb(VC_CONTAINER_BITS_T *bit_stream);
+
+/** Returns the next signed Exp-Golomb value from the stream.
+ * See section 9.1.1 of ITU-T REC H.264 201003 for details.
+ * If there are not enough bits in the stream to complete an Exp-Golomb value,
+ * the stream becomes invalid.
+ * If the next signed Exp-Golomb value in the stream is larger than 32 bits,
+ * or the stream is or becomes invalid, zero is returned.
+ *
+ * \pre  bit_stream is not NULL.
+ *
+ * \param bit_stream The bit stream object.
+ * \return  The next signed value from the stream, or zero on error.
+ */
+int32_t vc_container_bits_read_s32_exp_golomb(VC_CONTAINER_BITS_T *bit_stream);
+
+/******************************************************************************
+ * Macros reduce function name length and enable logging of some operations   *
+ ******************************************************************************/
+#define BITS_INIT(ctx, bits, buffer, available) (VC_CONTAINER_PARAM_UNUSED(ctx), vc_container_bits_init(bits, buffer, available))
+#define BITS_INVALIDATE(ctx, bits)              (VC_CONTAINER_PARAM_UNUSED(ctx), vc_container_bits_invalidate(bits))
+#define BITS_VALID(ctx, bits)                   (VC_CONTAINER_PARAM_UNUSED(ctx), vc_container_bits_valid(bits))
+#define BITS_RESET(ctx, bits)                   (VC_CONTAINER_PARAM_UNUSED(ctx), vc_container_bits_reset(bits))
+#define BITS_AVAILABLE(ctx, bits)               (VC_CONTAINER_PARAM_UNUSED(ctx), vc_container_bits_available(bits))
+#define BITS_BYTES_AVAILABLE(ctx, bits)         (VC_CONTAINER_PARAM_UNUSED(ctx), vc_container_bits_bytes_available(bits))
+#define BITS_CURRENT_POINTER(ctx, bits)         (VC_CONTAINER_PARAM_UNUSED(ctx), vc_container_bits_current_pointer(bits))
+#define BITS_COPY_STREAM(ctx, dst, src)         (VC_CONTAINER_PARAM_UNUSED(ctx), vc_container_bits_copy_stream(dst, src))
+
+#ifdef    ENABLE_CONTAINERS_LOG_FORMAT
+
+typedef enum {
+   VC_CONTAINER_BITS_LOG_SKIP,
+   VC_CONTAINER_BITS_LOG_SKIP_BYTES,
+   VC_CONTAINER_BITS_LOG_U8,
+   VC_CONTAINER_BITS_LOG_U16,
+   VC_CONTAINER_BITS_LOG_U32,
+   VC_CONTAINER_BITS_LOG_COPY_BYTES,
+   VC_CONTAINER_BITS_LOG_REDUCE_BYTES,
+   VC_CONTAINER_BITS_LOG_EG_SKIP,
+   VC_CONTAINER_BITS_LOG_EG_U32,
+   VC_CONTAINER_BITS_LOG_EG_S32,
+} VC_CONTAINER_BITS_LOG_OP_T;
+
+/** Logs an operation with void return.
+ *
+ * \pre  None of p_ctx, txt or bit_stream are NULL.
+ *
+ * \param p_ctx      Container context.
+ * \param indent     Indent level.
+ * \param txt        Description of what is being read.
+ * \param bit_stream The bit stream object.
+ * \param op         The operation just performed.
+ * \param length     The length of the operation.
+ */
+void vc_container_bits_log(VC_CONTAINER_T *p_ctx, uint32_t indent, const char *txt, VC_CONTAINER_BITS_T *bit_stream, VC_CONTAINER_BITS_LOG_OP_T op, uint32_t length);
+
+/** Logs an operation with unsigned 32-bit integer return.
+ *
+ * \pre  None of p_ctx, txt or bit_stream are NULL.
+ *
+ * \param p_ctx      Container context.
+ * \param indent     Indent level.
+ * \param txt        Description of what is being read.
+ * \param bit_stream The bit stream object.
+ * \param op         The operation just performed.
+ * \param length     The length of the operation.
+ * \param value      The value returned by the operation.
+ * \return  The unsigned 32-bit integer value passed in.
+ */
+uint32_t vc_container_bits_log_u32(VC_CONTAINER_T *p_ctx, uint32_t indent, const char *txt, VC_CONTAINER_BITS_T *bit_stream, VC_CONTAINER_BITS_LOG_OP_T op, uint32_t length, uint32_t value);
+
+/** Logs an operation with signed 32-bit integer return.
+ *
+ * \pre  None of p_ctx, txt or bit_stream are NULL.
+ *
+ * \param p_ctx      Container context.
+ * \param indent     Indent level.
+ * \param txt        Description of what is being read.
+ * \param bit_stream The bit stream object.
+ * \param op         The operation just performed.
+ * \param length     The length of the operation.
+ * \param value      The value returned by the operation.
+ * \return  The signed 32-bit integer value passed in.
+ */
+int32_t vc_container_bits_log_s32(VC_CONTAINER_T *p_ctx, uint32_t indent, const char *txt, VC_CONTAINER_BITS_T *bit_stream, VC_CONTAINER_BITS_LOG_OP_T op, uint32_t length, int32_t value);
+
+#ifndef BITS_LOG_INDENT
+# ifndef CONTAINER_HELPER_LOG_INDENT
+#  define BITS_LOG_INDENT(ctx) 0
+# else
+#  define BITS_LOG_INDENT(ctx) ((ctx)->priv->io->module ? CONTAINER_HELPER_LOG_INDENT(a) : 0)
+# endif
+#endif
+
+#define BITS_SKIP(ctx, bits, length, txt)             (vc_container_bits_skip(bits, length), vc_container_bits_log(ctx, BITS_LOG_INDENT(ctx), txt, bits, VC_CONTAINER_BITS_LOG_SKIP, length))
+#define BITS_SKIP_BYTES(ctx, bits, length, txt)       (vc_container_bits_skip_bytes(bits, length), vc_container_bits_log(ctx, BITS_LOG_INDENT(ctx), txt, bits, VC_CONTAINER_BITS_LOG_SKIP_BYTES, length))
+
+#define BITS_READ_U8(ctx, bits, length, txt)          (uint8_t)vc_container_bits_log_u32(ctx, BITS_LOG_INDENT(ctx), txt, bits, VC_CONTAINER_BITS_LOG_U8, length, vc_container_bits_read_u32(bits, length))
+#define BITS_READ_U16(ctx, bits, length, txt)         (uint16_t)vc_container_bits_log_u32(ctx, BITS_LOG_INDENT(ctx), txt, bits, VC_CONTAINER_BITS_LOG_U16, length, vc_container_bits_read_u32(bits, length))
+#define BITS_READ_U32(ctx, bits, length, txt)         vc_container_bits_log_u32(ctx, BITS_LOG_INDENT(ctx), txt, bits, VC_CONTAINER_BITS_LOG_U32, length, vc_container_bits_read_u32(bits, length))
+
+#define BITS_COPY_BYTES(ctx, bits, length, dst, txt)  (vc_container_bits_copy_bytes(bits, length, dst), vc_container_bits_log(ctx, BITS_LOG_INDENT(ctx), txt, bits, VC_CONTAINER_BITS_LOG_COPY_BYTES, length))
+
+#define BITS_REDUCE_BYTES(ctx, bits, length, txt)     (vc_container_bits_reduce_bytes(bits, length), vc_container_bits_log(ctx, BITS_LOG_INDENT(ctx), txt, bits, VC_CONTAINER_BITS_LOG_REDUCE_BYTES, length))
+
+#define BITS_SKIP_EXP(ctx, bits, txt)                 (vc_container_bits_skip_exp_golomb(bits), vc_container_bits_log(ctx, BITS_LOG_INDENT(ctx), txt, bits, VC_CONTAINER_BITS_LOG_EG_SKIP, 0))
+
+#define BITS_READ_S32_EXP(ctx, bits, txt)             vc_container_bits_log_s32(ctx, BITS_LOG_INDENT(ctx), txt, bits, VC_CONTAINER_BITS_LOG_EG_S32, 0, vc_container_bits_read_s32_exp_golomb(bits))
+#define BITS_READ_U32_EXP(ctx, bits, txt)             vc_container_bits_log_u32(ctx, BITS_LOG_INDENT(ctx), txt, bits, VC_CONTAINER_BITS_LOG_EG_U32, 0, vc_container_bits_read_u32_exp_golomb(bits))
+
+#else  /* ENABLE_CONTAINERS_LOG_FORMAT */
+
+#define BITS_SKIP(ctx, bits, length, txt)             (VC_CONTAINER_PARAM_UNUSED(ctx), VC_CONTAINER_PARAM_UNUSED(txt), vc_container_bits_skip(bits, length))
+#define BITS_SKIP_BYTES(ctx, bits, length, txt)       (VC_CONTAINER_PARAM_UNUSED(ctx), VC_CONTAINER_PARAM_UNUSED(txt), vc_container_bits_skip_bytes(bits, length))
+
+#define BITS_READ_U8(ctx, bits, length, txt)          (uint8_t)(VC_CONTAINER_PARAM_UNUSED(ctx), VC_CONTAINER_PARAM_UNUSED(txt), vc_container_bits_read_u32(bits, length))
+#define BITS_READ_U16(ctx, bits, length, txt)         (uint16_t)(VC_CONTAINER_PARAM_UNUSED(ctx), VC_CONTAINER_PARAM_UNUSED(txt), vc_container_bits_read_u32(bits, length))
+#define BITS_READ_U32(ctx, bits, length, txt)         (VC_CONTAINER_PARAM_UNUSED(ctx), VC_CONTAINER_PARAM_UNUSED(txt), vc_container_bits_read_u32(bits, length))
+
+#define BITS_COPY_BYTES(ctx, bits, length, dst, txt)  (VC_CONTAINER_PARAM_UNUSED(ctx), VC_CONTAINER_PARAM_UNUSED(txt), vc_container_bits_copy_bytes(bits, length, dst))
+
+#define BITS_REDUCE_BYTES(ctx, bits, length, txt)     (VC_CONTAINER_PARAM_UNUSED(ctx), VC_CONTAINER_PARAM_UNUSED(txt), vc_container_bits_reduce_bytes(bits, length))
+
+#define BITS_SKIP_EXP(ctx, bits, txt)                 (VC_CONTAINER_PARAM_UNUSED(ctx), VC_CONTAINER_PARAM_UNUSED(txt), vc_container_bits_skip_exp_golomb(bits))
+
+#define BITS_READ_S32_EXP(ctx, bits, txt)             (VC_CONTAINER_PARAM_UNUSED(ctx), VC_CONTAINER_PARAM_UNUSED(txt), vc_container_bits_read_s32_exp_golomb(bits))
+#define BITS_READ_U32_EXP(ctx, bits, txt)             (VC_CONTAINER_PARAM_UNUSED(ctx), VC_CONTAINER_PARAM_UNUSED(txt), vc_container_bits_read_u32_exp_golomb(bits))
+
+#endif /* ENABLE_CONTAINERS_LOG_FORMAT */
+
+#endif /* VC_CONTAINERS_BITS_H */
diff --git a/containers/core/containers_bytestream.h b/containers/core/containers_bytestream.h
new file mode 100755 (executable)
index 0000000..95b3a61
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef VC_CONTAINERS_BYTESTREAM_H
+#define VC_CONTAINERS_BYTESTREAM_H
+
+/** \file
+ * Utility functions to provide a byte stream out of a list of container packets
+ */
+
+typedef struct VC_CONTAINER_BYTESTREAM_T
+{
+   VC_CONTAINER_PACKET_T *first;  /**< first packet in the chain */
+   VC_CONTAINER_PACKET_T **last;  /**< last packet in the chain */
+
+   VC_CONTAINER_PACKET_T *current;  /**< packet containing the current read pointer */
+   size_t current_offset; /**< position of current packet (in bytes) */
+   size_t offset; /**< position within the current packet */
+
+   size_t bytes; /**< Number of bytes available in the bytestream */
+
+} VC_CONTAINER_BYTESTREAM_T;
+
+/*****************************************************************************/
+STATIC_INLINE void bytestream_init( VC_CONTAINER_BYTESTREAM_T *stream )
+{
+   stream->first = stream->current = NULL;
+   stream->last = &stream->first;
+   stream->offset = stream->current_offset = stream->bytes = 0;
+}
+
+STATIC_INLINE void bytestream_push( VC_CONTAINER_BYTESTREAM_T *stream,
+                                    VC_CONTAINER_PACKET_T *packet )
+{
+   *stream->last = packet;
+   stream->last = &packet->next;
+   packet->next = NULL;
+   if( !stream->current ) stream->current = packet;
+   stream->bytes += packet->size;
+}
+
+STATIC_INLINE VC_CONTAINER_PACKET_T *bytestream_pop( VC_CONTAINER_BYTESTREAM_T *stream )
+{
+   VC_CONTAINER_PACKET_T *packet = stream->first;
+
+   if( stream->current == packet )
+      return NULL;
+   vc_container_assert(packet);
+
+   stream->bytes -= packet->size;
+   stream->current_offset -= packet->size;
+   stream->first = packet->next;
+   if( !stream->first )
+      stream->last = &stream->first;
+   return packet;
+}
+
+STATIC_INLINE VC_CONTAINER_PACKET_T *bytestream_get_packet( VC_CONTAINER_BYTESTREAM_T *stream, size_t *offset )
+{
+   VC_CONTAINER_PACKET_T *packet = stream->current;
+   size_t off = stream->offset;
+
+   while(packet && packet->size == off)
+   {
+      packet = packet->next;
+      off = 0;
+   }
+
+   if (offset)
+      *offset = off;
+
+   return packet;
+}
+
+STATIC_INLINE bool bytestream_skip_packet( VC_CONTAINER_BYTESTREAM_T *stream )
+{
+   VC_CONTAINER_PACKET_T *packet = stream->current;
+
+   if( packet )
+   {
+      stream->current = packet->next;
+      stream->current_offset += (packet->size - stream->offset);
+      stream->offset = 0;
+   }
+
+   return !!packet;
+}
+
+STATIC_INLINE void bytestream_get_timestamps( VC_CONTAINER_BYTESTREAM_T *stream, int64_t *pts, int64_t *dts, bool b_same )
+{
+   VC_CONTAINER_PACKET_T *packet = bytestream_get_packet( stream, 0 );
+
+   if(packet)
+   {
+      if(b_same && packet->pts == VC_CONTAINER_TIME_UNKNOWN) packet->pts = packet->dts;
+      if(pts) *pts = packet->pts;
+      if(dts) *dts = packet->dts;
+
+      packet->pts = packet->dts = VC_CONTAINER_TIME_UNKNOWN;
+      return;
+   }
+
+   if(pts) *pts = VC_CONTAINER_TIME_UNKNOWN;
+   if(dts) *dts = VC_CONTAINER_TIME_UNKNOWN;
+}
+
+STATIC_INLINE void bytestream_get_timestamps_and_offset( VC_CONTAINER_BYTESTREAM_T *stream,
+   int64_t *pts, int64_t *dts, size_t *offset, bool b_same )
+{
+   VC_CONTAINER_PACKET_T *packet = bytestream_get_packet( stream, offset );
+
+   if(packet)
+   {
+      if(b_same && packet->pts == VC_CONTAINER_TIME_UNKNOWN) packet->pts = packet->dts;
+      if(pts) *pts = packet->pts;
+      if(dts) *dts = packet->dts;
+
+      packet->pts = packet->dts = VC_CONTAINER_TIME_UNKNOWN;
+      return;
+   }
+
+   if(pts) *pts = VC_CONTAINER_TIME_UNKNOWN;
+   if(dts) *dts = VC_CONTAINER_TIME_UNKNOWN;
+}
+
+STATIC_INLINE size_t bytestream_size( VC_CONTAINER_BYTESTREAM_T *stream )
+{
+   return stream->bytes - stream->current_offset - stream->offset;
+}
+
+STATIC_INLINE VC_CONTAINER_STATUS_T bytestream_skip( VC_CONTAINER_BYTESTREAM_T *stream, size_t size )
+{
+   VC_CONTAINER_PACKET_T *packet;
+   size_t offset, bytes = 0, skip;
+
+   if( !size )
+      return VC_CONTAINER_SUCCESS; /* Nothing to do */
+   if( stream->bytes - stream->current_offset - stream->offset < size )
+      return VC_CONTAINER_ERROR_EOS; /* Not enough data */
+
+   for( packet = stream->current, offset = stream->offset; ;
+        packet = packet->next, offset = 0 )
+   {
+      if( packet->size - offset >= size)
+         break;
+
+      skip = packet->size - offset;
+      bytes += skip;
+      size -= skip;
+   }
+
+   stream->current = packet;
+   stream->current_offset += stream->offset - offset + bytes;
+   stream->offset = offset + size;
+   return VC_CONTAINER_SUCCESS;
+}
+
+STATIC_INLINE VC_CONTAINER_STATUS_T bytestream_get( VC_CONTAINER_BYTESTREAM_T *stream, uint8_t *data, size_t size )
+{
+   VC_CONTAINER_PACKET_T *packet;
+   size_t offset, bytes = 0, copy;
+
+   if( !size )
+      return VC_CONTAINER_SUCCESS; /* Nothing to do */
+   if( stream->bytes - stream->current_offset - stream->offset < size )
+      return VC_CONTAINER_ERROR_EOS; /* Not enough data */
+
+   for( packet = stream->current, offset = stream->offset; ;
+        packet = packet->next, offset = 0 )
+   {
+      if( packet->size - offset >= size)
+         break;
+
+      copy = packet->size - offset;
+      memcpy( data, packet->data + offset, copy );
+      bytes += copy;
+      data += copy;
+      size -= copy;
+   }
+
+   memcpy( data, packet->data + offset, size );
+   stream->current = packet;
+   stream->current_offset += stream->offset - offset + bytes;
+   stream->offset = offset + size;
+   return VC_CONTAINER_SUCCESS;
+}
+
+STATIC_INLINE VC_CONTAINER_STATUS_T bytestream_peek( VC_CONTAINER_BYTESTREAM_T *stream, uint8_t *data, size_t size )
+{
+   VC_CONTAINER_PACKET_T *packet;
+   size_t offset, copy;
+
+   if( !size )
+      return VC_CONTAINER_SUCCESS; /* Nothing to do */
+   if( stream->bytes - stream->current_offset - stream->offset < size )
+      return VC_CONTAINER_ERROR_EOS; /* Not enough data */
+
+   for( packet = stream->current, offset = stream->offset; ;
+        packet = packet->next, offset = 0 )
+   {
+      if( packet->size - offset >= size)
+         break;
+
+      copy = packet->size - offset;
+      memcpy( data, packet->data + offset, copy );
+      data += copy;
+      size -= copy;
+   }
+
+   memcpy( data, packet->data + offset, size );
+   return VC_CONTAINER_SUCCESS;
+}
+
+STATIC_INLINE VC_CONTAINER_STATUS_T bytestream_peek_at( VC_CONTAINER_BYTESTREAM_T *stream,
+   size_t peek_offset, uint8_t *data, size_t size )
+{
+   VC_CONTAINER_PACKET_T *packet;
+   size_t copy;
+
+   if( !size )
+      return VC_CONTAINER_SUCCESS; /* Nothing to do */
+   if( stream->bytes - stream->current_offset - stream->offset < peek_offset + size )
+      return VC_CONTAINER_ERROR_EOS; /* Not enough data */
+
+   peek_offset += stream->offset;
+
+   /* Find the right place */
+   for( packet = stream->current; ; packet = packet->next )
+   {
+      if( packet->size > peek_offset )
+         break;
+
+      peek_offset -= packet->size;
+   }
+
+   /* Copy the data */
+   for( ; ; packet = packet->next, peek_offset = 0 )
+   {
+      if( packet->size - peek_offset >= size)
+         break;
+
+      copy = packet->size - peek_offset;
+      memcpy( data, packet->data + peek_offset, copy );
+      data += copy;
+      size -= copy;
+   }
+
+   memcpy( data, packet->data + peek_offset, size );
+   return VC_CONTAINER_SUCCESS;
+}
+
+STATIC_INLINE VC_CONTAINER_STATUS_T bytestream_skip_byte( VC_CONTAINER_BYTESTREAM_T *stream )
+{
+   VC_CONTAINER_PACKET_T *packet = stream->current;
+
+   if( !packet )
+      return VC_CONTAINER_ERROR_EOS;
+
+   /* Fast path first */
+   if( packet->size - stream->offset )
+   {
+      stream->offset++;
+      return VC_CONTAINER_SUCCESS;
+   }
+
+   return bytestream_skip( stream, 1 );
+}
+
+STATIC_INLINE VC_CONTAINER_STATUS_T packet_peek_byte( VC_CONTAINER_BYTESTREAM_T *stream,
+                                                      uint8_t *data )
+{
+   VC_CONTAINER_PACKET_T *packet = stream->current;
+
+   if( !packet )
+      return VC_CONTAINER_ERROR_EOS;
+
+   /* Fast path first */
+   if( packet->size - stream->offset )
+   {
+      *data = packet->data[stream->offset];
+      return VC_CONTAINER_SUCCESS;
+   }
+
+   return bytestream_peek( stream, data, 1 );
+}
+
+STATIC_INLINE VC_CONTAINER_STATUS_T packet_get_byte( VC_CONTAINER_BYTESTREAM_T *stream,
+                                                     uint8_t *data )
+{
+   VC_CONTAINER_PACKET_T *packet = stream->current;
+
+   if( !packet )
+      return VC_CONTAINER_ERROR_EOS;
+
+   /* Fast path first */
+   if( packet->size - stream->offset )
+   {
+      *data = packet->data[stream->offset];
+      stream->offset++;
+      return VC_CONTAINER_SUCCESS;
+   }
+
+   return bytestream_get( stream, data, 1 );
+}
+
+STATIC_INLINE VC_CONTAINER_STATUS_T bytestream_find_startcode( VC_CONTAINER_BYTESTREAM_T *stream,
+   size_t *search_offset, const uint8_t *startcode, unsigned int length )
+{
+   VC_CONTAINER_PACKET_T *packet, *backup_packet = NULL;
+   size_t position, start_offset = position = *search_offset;
+   size_t offset, backup_offset = 0;
+   unsigned int match = 0;
+
+   if( stream->bytes - stream->current_offset - stream->offset < start_offset + length )
+      return VC_CONTAINER_ERROR_EOS; /* Not enough data */
+
+   /* Find the right place */
+   for( packet = stream->current, offset = stream->offset;
+        packet != NULL; packet = packet->next, offset = 0 )
+   {
+      if( packet->size - offset > start_offset)
+         break;
+
+      start_offset -= (packet->size - offset);
+   }
+
+   /* Start the search for the start code.
+    * To make things simple we try to find a match one byte at a time. */
+   for( offset += start_offset;
+        packet != NULL; packet = packet->next, offset = 0 )
+   {
+      for( ; offset < packet->size; offset++ )
+      {
+         if( packet->data[offset] != startcode[match] )
+         {
+            if ( match ) /* False positive */
+            {
+               packet = backup_packet;
+               offset = backup_offset;
+               match = 0;
+            }
+            position++;
+            continue;
+         }
+
+         /* We've got a match */
+         if( !match++ )
+         {
+            backup_packet = packet;
+            backup_offset = offset;
+         }
+
+         if( match == length )
+         {
+            /* We have the full start code it */
+            *search_offset = position;
+            return VC_CONTAINER_SUCCESS;
+         }
+      }
+   }
+
+   *search_offset = position;
+   return VC_CONTAINER_ERROR_EOS; /* No luck in finding the start code */
+}
+
+#endif /* VC_CONTAINERS_BYTESTREAM_H */
diff --git a/containers/core/containers_codecs.c b/containers/core/containers_codecs.c
new file mode 100755 (executable)
index 0000000..16e1593
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "containers/containers.h"
+#include "containers/containers_codecs.h"
+#include "containers/core/containers_utils.h"
+
+/*****************************************************************************/
+static struct {
+   VC_CONTAINER_FOURCC_T codec;
+   uint16_t id;
+} codec_to_wf_table[] =
+{
+   {VC_CONTAINER_CODEC_PCM_SIGNED_LE, WAVE_FORMAT_PCM},
+   {VC_CONTAINER_CODEC_ALAW, WAVE_FORMAT_ALAW},
+   {VC_CONTAINER_CODEC_MULAW, WAVE_FORMAT_MULAW},
+   {VC_CONTAINER_CODEC_ADPCM_MS, WAVE_FORMAT_ADPCM},
+   {VC_CONTAINER_CODEC_MPGA, WAVE_FORMAT_MPEG},
+   {VC_CONTAINER_CODEC_MPGA, WAVE_FORMAT_MPEGLAYER3},
+   {VC_CONTAINER_CODEC_WMA1, WAVE_FORMAT_WMAUDIO1},
+   {VC_CONTAINER_CODEC_WMA2, WAVE_FORMAT_WMAUDIO2},
+   {VC_CONTAINER_CODEC_WMAP, WAVE_FORMAT_WMAUDIOPRO},
+   {VC_CONTAINER_CODEC_WMAL, WAVE_FORMAT_WMAUDIO_LOSSLESS},
+   {VC_CONTAINER_CODEC_WMAV, WAVE_FORMAT_WMAUDIO_VOICE},
+   {VC_CONTAINER_CODEC_AC3,  WAVE_FORMAT_DVM},
+   {VC_CONTAINER_CODEC_AC3,  WAVE_FORMAT_DOLBY_AC3_SPDIF}, /**< AC-3 padded for S/PDIF */
+   {VC_CONTAINER_CODEC_AC3,  WAVE_FORMAT_RAW_SPORT},       /**< AC-3 padded for S/PDIF */
+   {VC_CONTAINER_CODEC_AC3,  WAVE_FORMAT_ESST_AC3},        /**< AC-3 padded for S/PDIF */
+   {VC_CONTAINER_CODEC_EAC3, WAVE_FORMAT_DVM},
+   {VC_CONTAINER_CODEC_DTS, WAVE_FORMAT_DTS},
+#if 0
+   {CODEC_G726, WAVE_FORMAT_G726_ADPCM},
+   {CODEC_G726, WAVE_FORMAT_DF_G726},
+   {CODEC_G726, WAVE_FORMAT_G726ADPCM},
+   {CODEC_G726, WAVE_FORMAT_PANASONIC_G726},
+#endif
+   {VC_CONTAINER_CODEC_MP4A, WAVE_FORMAT_AAC},
+   {VC_CONTAINER_CODEC_MP4A, WAVE_FORMAT_MP4A},
+   {VC_CONTAINER_CODEC_ATRAC3, WAVE_FORMAT_SONY_SCX},
+   {VC_CONTAINER_CODEC_UNKNOWN, WAVE_FORMAT_UNKNOWN}
+};
+
+VC_CONTAINER_FOURCC_T waveformat_to_codec(uint16_t waveformat_id)
+{
+   unsigned int i;
+   for(i = 0; codec_to_wf_table[i].codec != VC_CONTAINER_CODEC_UNKNOWN; i++)
+      if(codec_to_wf_table[i].id == waveformat_id) break;
+   return codec_to_wf_table[i].codec;
+}
+
+uint16_t codec_to_waveformat(VC_CONTAINER_FOURCC_T codec)
+{
+   unsigned int i;
+   for(i = 0; codec_to_wf_table[i].codec != VC_CONTAINER_CODEC_UNKNOWN; i++)
+      if(codec_to_wf_table[i].codec == codec) break;
+   return codec_to_wf_table[i].id;
+}
+
+static struct {
+   VC_CONTAINER_FOURCC_T codec;
+   uint32_t fourcc;
+} codec_to_vfw_table[] =
+{
+#if defined(ENABLE_CONTAINERS_STANDALONE) || !defined(NDEBUG)
+   /* We are legally required to not play DivX in RELEASE mode. See Jira SW-3138 */
+   {VC_CONTAINER_CODEC_DIV3,             VC_FOURCC('D','I','V','3')},
+   {VC_CONTAINER_CODEC_DIV3,             VC_FOURCC('d','i','v','3')},
+   {VC_CONTAINER_CODEC_DIV4,             VC_FOURCC('D','I','V','4')},
+   {VC_CONTAINER_CODEC_DIV4,             VC_FOURCC('d','i','v','4')},
+   {VC_CONTAINER_CODEC_MP4V,             VC_FOURCC('D','X','5','0')},
+   {VC_CONTAINER_CODEC_MP4V,             VC_FOURCC('D','I','V','X')},
+   {VC_CONTAINER_CODEC_MP4V,             VC_FOURCC('d','i','v','x')},
+#endif /* ENABLE_CONTAINERS_STANDALONE || !NDEBUG */
+   {VC_CONTAINER_CODEC_MP4V,             VC_FOURCC('M','P','4','V')},
+   {VC_CONTAINER_CODEC_MP4V,             VC_FOURCC('m','p','4','v')},
+   {VC_CONTAINER_CODEC_MP4V,             VC_FOURCC('M','P','4','S')},
+   {VC_CONTAINER_CODEC_MP4V,             VC_FOURCC('m','p','4','s')},
+   {VC_CONTAINER_CODEC_MP4V,             VC_FOURCC('M','4','S','2')},
+   {VC_CONTAINER_CODEC_MP4V,             VC_FOURCC('m','4','s','2')},
+   {VC_CONTAINER_CODEC_MP4V,             VC_FOURCC('F','M','P','4')},
+   {VC_CONTAINER_CODEC_MP4V,             VC_FOURCC('X','V','I','D')},
+   {VC_CONTAINER_CODEC_MP4V,             VC_FOURCC('x','v','i','d')},
+   {VC_CONTAINER_CODEC_DIV3,             VC_FOURCC('M','P','4','3')},
+   {VC_CONTAINER_CODEC_DIV3,             VC_FOURCC('m','p','4','3')},
+   {VC_CONTAINER_CODEC_MP1V,             VC_FOURCC('m','p','g','1')},
+   {VC_CONTAINER_CODEC_MP1V,             VC_FOURCC('M','P','G','1')},
+   {VC_CONTAINER_CODEC_MP2V,             VC_FOURCC('m','p','g','2')},
+   {VC_CONTAINER_CODEC_MP2V,             VC_FOURCC('M','P','G','2')},
+   {VC_CONTAINER_CODEC_MJPEG,            VC_FOURCC('M','J','P','G')},
+   {VC_CONTAINER_CODEC_MJPEG,            VC_FOURCC('m','j','p','g')},
+   {VC_CONTAINER_CODEC_WMV1,             VC_FOURCC('W','M','V','1')},
+   {VC_CONTAINER_CODEC_WMV1,             VC_FOURCC('w','m','v','1')},
+   {VC_CONTAINER_CODEC_WMV2,             VC_FOURCC('W','M','V','2')},
+   {VC_CONTAINER_CODEC_WMV2,             VC_FOURCC('w','m','v','2')},
+   {VC_CONTAINER_CODEC_WMV3,             VC_FOURCC('W','M','V','3')},
+   {VC_CONTAINER_CODEC_WMV3,             VC_FOURCC('w','m','v','3')},
+   {VC_CONTAINER_CODEC_WVC1,             VC_FOURCC('W','V','C','1')},
+   {VC_CONTAINER_CODEC_WVC1,             VC_FOURCC('w','v','c','1')},
+   {VC_CONTAINER_CODEC_WMVA,             VC_FOURCC('w','m','v','a')},
+   {VC_CONTAINER_CODEC_WMVA,             VC_FOURCC('W','M','V','A')},
+   {VC_CONTAINER_CODEC_VP6,              VC_FOURCC('V','P','6','F')},
+   {VC_CONTAINER_CODEC_VP6,              VC_FOURCC('v','p','6','f')},
+   {VC_CONTAINER_CODEC_VP7,              VC_FOURCC('V','P','7','0')},
+   {VC_CONTAINER_CODEC_VP7,              VC_FOURCC('v','p','7','0')},
+   {VC_CONTAINER_CODEC_H263,             VC_FOURCC('H','2','6','3')},
+   {VC_CONTAINER_CODEC_H263,             VC_FOURCC('h','2','6','3')},
+   {VC_CONTAINER_CODEC_H264,             VC_FOURCC('H','2','6','4')},
+   {VC_CONTAINER_CODEC_H264,             VC_FOURCC('h','2','6','4')},
+   {VC_CONTAINER_CODEC_H264,             VC_FOURCC('A','V','C','1')},
+   {VC_CONTAINER_CODEC_H264,             VC_FOURCC('a','v','c','1')},
+   {VC_CONTAINER_CODEC_SPARK,            VC_FOURCC('F','L','V','1')},
+   {VC_CONTAINER_CODEC_SPARK,            VC_FOURCC('f','l','v','1')},
+   {VC_CONTAINER_CODEC_UNKNOWN, 0}
+};
+
+VC_CONTAINER_FOURCC_T vfw_fourcc_to_codec(uint32_t fourcc)
+{
+   unsigned int i;
+   for(i = 0; codec_to_vfw_table[i].codec != VC_CONTAINER_CODEC_UNKNOWN; i++)
+      if(codec_to_vfw_table[i].fourcc == fourcc) break;
+
+   if(codec_to_vfw_table[i].codec == VC_CONTAINER_CODEC_UNKNOWN)
+      return fourcc;
+
+   return codec_to_vfw_table[i].codec;
+}
+
+uint32_t codec_to_vfw_fourcc(VC_CONTAINER_FOURCC_T codec)
+{
+   unsigned int i;
+   for(i = 0; codec_to_vfw_table[i].codec != VC_CONTAINER_CODEC_UNKNOWN; i++)
+      if(codec_to_vfw_table[i].codec == codec) break;
+
+   return codec_to_vfw_table[i].fourcc;
+}
+
+static struct {
+   VC_CONTAINER_FOURCC_T codec;
+   uint32_t fourcc;
+} codec_to_fourcc_table[] =
+{
+   {VC_CONTAINER_CODEC_MP4V,             VC_FOURCC('M','P','4','S')},
+   {VC_CONTAINER_CODEC_MP4V,             VC_FOURCC('M','4','S','2')},
+   {VC_CONTAINER_CODEC_MP4V,             VC_FOURCC('m','p','4','s')},
+   {VC_CONTAINER_CODEC_MP4V,             VC_FOURCC('m','4','s','2')},
+   {VC_CONTAINER_CODEC_MP4V,             VC_FOURCC('M','P','4','V')},
+   {VC_CONTAINER_CODEC_MP4V,             VC_FOURCC('m','p','4','v')},
+   {VC_CONTAINER_CODEC_MP4V,             VC_FOURCC('F','M','P','4')},
+   {VC_CONTAINER_CODEC_DIV3,             VC_FOURCC('M','P','4','3')},
+   {VC_CONTAINER_CODEC_DIV3,             VC_FOURCC('m','p','4','3')},
+   {VC_CONTAINER_CODEC_WMV1,             VC_FOURCC('W','M','V','1')},
+   {VC_CONTAINER_CODEC_WMV1,             VC_FOURCC('w','m','v','1')},
+   {VC_CONTAINER_CODEC_WMV2,             VC_FOURCC('W','M','V','2')},
+   {VC_CONTAINER_CODEC_WMV2,             VC_FOURCC('w','m','v','2')},
+   {VC_CONTAINER_CODEC_WMV3,             VC_FOURCC('W','M','V','3')},
+   {VC_CONTAINER_CODEC_WMV3,             VC_FOURCC('w','m','v','3')},
+   {VC_CONTAINER_CODEC_MP1V,             VC_FOURCC('m','p','g','1')},
+   {VC_CONTAINER_CODEC_MP1V,             VC_FOURCC('M','P','G','1')},
+   {VC_CONTAINER_CODEC_MP2V,             VC_FOURCC('m','p','g','2')},
+   {VC_CONTAINER_CODEC_MP2V,             VC_FOURCC('M','P','G','2')},
+   {VC_CONTAINER_CODEC_MJPEG,            VC_FOURCC('M','J','P','G')},
+   {VC_CONTAINER_CODEC_MJPEG,            VC_FOURCC('m','j','p','g')},
+   {VC_CONTAINER_CODEC_UNKNOWN, 0}
+};
+
+VC_CONTAINER_FOURCC_T fourcc_to_codec(uint32_t fourcc)
+{
+   unsigned int i;
+   for(i = 0; codec_to_fourcc_table[i].codec != VC_CONTAINER_CODEC_UNKNOWN; i++)
+      if(codec_to_fourcc_table[i].fourcc == fourcc) break;
+
+   return codec_to_fourcc_table[i].codec;
+}
+
+uint32_t codec_to_fourcc(VC_CONTAINER_FOURCC_T codec)
+{
+   unsigned int i;
+   for(i = 0; codec_to_fourcc_table[i].codec != VC_CONTAINER_CODEC_UNKNOWN; i++)
+      if(codec_to_fourcc_table[i].codec == codec) break;
+
+   return codec_to_fourcc_table[i].fourcc;
+}
diff --git a/containers/core/containers_common.h b/containers/core/containers_common.h
new file mode 100755 (executable)
index 0000000..eb18671
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef VC_CONTAINERS_COMMON_H
+#define VC_CONTAINERS_COMMON_H
+
+/** \file containers_common.h
+ * Common definitions for containers infrastructure
+ */
+
+#ifndef ENABLE_CONTAINERS_STANDALONE
+# include "vcos.h"
+# define vc_container_assert(a) vcos_assert(a)
+#else
+# include "assert.h"
+# define vc_container_assert(a) assert(a)
+#endif /* ENABLE_CONTAINERS_STANDALONE */
+
+#ifndef countof
+# define countof(a) (sizeof(a) / sizeof(a[0]))
+#endif
+
+#ifndef MIN
+# define MIN(a, b) ((a) < (b) ? (a) : (b))
+#endif
+#ifndef MAX
+# define MAX(a, b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifdef _MSC_VER
+# define strcasecmp stricmp
+# define strncasecmp strnicmp
+#endif
+
+#define STATIC_INLINE static __inline
+#define VC_CONTAINER_PARAM_UNUSED(a) (void)(a)
+
+#if defined(__HIGHC__) && !defined(strcasecmp)
+# define strcasecmp(a,b) _stricmp(a,b)
+#endif
+
+#if defined(__GNUC__) && (__GNUC__ > 2)
+# define VC_CONTAINER_CONSTRUCTOR(func) void __attribute__((constructor,used)) func(void)
+# define VC_CONTAINER_DESTRUCTOR(func) void __attribute__((destructor,used)) func(void)
+#else
+# define VC_CONTAINER_CONSTRUCTOR(func) void func(void)
+# define VC_CONTAINER_DESTRUCTOR(func) void func(void)
+#endif
+
+#endif /* VC_CONTAINERS_COMMON_H */
diff --git a/containers/core/containers_filters.c b/containers/core/containers_filters.c
new file mode 100755 (executable)
index 0000000..a5bc0b7
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "containers/containers.h"
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_filters.h"
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE)
+   #include "vcos_dlfcn.h"
+   #define DL_SUFFIX VCOS_SO_EXT
+   #ifndef DL_PATH_PREFIX
+      #define DL_PATH_PREFIX ""
+   #endif   
+#endif
+
+typedef struct VC_CONTAINER_FILTER_PRIVATE_T
+{
+   /** Pointer to the container filter code and symbols */
+   void *handle;   
+} VC_CONTAINER_FILTER_PRIVATE_T;
+
+typedef VC_CONTAINER_STATUS_T (*VC_CONTAINER_FILTER_OPEN_FUNC_T)(VC_CONTAINER_FILTER_T*, VC_CONTAINER_FOURCC_T);
+
+static VC_CONTAINER_FILTER_OPEN_FUNC_T load_library(void **handle, VC_CONTAINER_FOURCC_T filter, const char *name);
+static void unload_library(void *handle);
+
+static struct {
+   VC_CONTAINER_FOURCC_T filter;
+   const char *name;
+} filter_to_name_table[] =
+{
+   {VC_FOURCC('d','r','m',' '), "divx"},
+   {VC_FOURCC('d','r','m',' '), "hdcp2"},
+   {0, NULL}
+};
+
+static VC_CONTAINER_STATUS_T vc_container_filter_load(VC_CONTAINER_FILTER_T *p_ctx, 
+                                                      VC_CONTAINER_FOURCC_T filter,
+                                                      VC_CONTAINER_FOURCC_T type)
+{
+   void *handle = NULL;
+   VC_CONTAINER_FILTER_OPEN_FUNC_T func;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   unsigned int i;
+   
+   for(i = 0; filter_to_name_table[i].filter; ++i) 
+   {
+      if (filter_to_name_table[i].filter == filter)
+      {
+         if ((func = load_library(&handle, filter, filter_to_name_table[i].name)) != NULL)
+         {
+            status = (*func)(p_ctx, type);
+            if(status == VC_CONTAINER_SUCCESS) break;
+            unload_library(handle);
+            if (status != VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED) break;
+         }
+      }
+   }
+    
+   p_ctx->priv->handle = handle;
+   return status;
+}
+
+static void vc_container_filter_unload(VC_CONTAINER_FILTER_T *p_ctx)
+{
+   unload_library(p_ctx->priv->handle);
+   p_ctx->priv->handle = NULL;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_FILTER_T *vc_container_filter_open(VC_CONTAINER_FOURCC_T filter, 
+                                                VC_CONTAINER_FOURCC_T type,
+                                                VC_CONTAINER_T *p_container, 
+   VC_CONTAINER_STATUS_T *p_status )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_NOT_FOUND;
+   VC_CONTAINER_FILTER_T *p_ctx = 0;
+   VC_CONTAINER_FILTER_PRIVATE_T *priv = 0;
+
+   /* Allocate our context before trying out the different filter modules */
+   p_ctx = malloc(sizeof(*p_ctx) + sizeof(*priv));
+   if(!p_ctx) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(p_ctx, 0, sizeof(*p_ctx) + sizeof(*priv));
+   p_ctx->priv = priv = (VC_CONTAINER_FILTER_PRIVATE_T *)&p_ctx[1];
+   p_ctx->container = p_container;
+   
+   status = vc_container_filter_load(p_ctx, filter, type);
+   if(status != VC_CONTAINER_SUCCESS) goto error;
+   
+ end:
+   if(p_status) *p_status = status;
+   return p_ctx;
+
+ error:
+   if(p_ctx) free(p_ctx);
+   p_ctx = 0;
+   goto end;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_filter_close( VC_CONTAINER_FILTER_T *p_ctx )
+{
+   if (p_ctx)
+   {
+      if(p_ctx->pf_close) p_ctx->pf_close(p_ctx);
+      if(p_ctx->priv && p_ctx->priv->handle) vc_container_filter_unload(p_ctx);
+      free(p_ctx);
+   }
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_filter_process( VC_CONTAINER_FILTER_T *p_ctx, VC_CONTAINER_PACKET_T *p_packet )
+{
+   VC_CONTAINER_STATUS_T status;
+   status = p_ctx->pf_process(p_ctx, p_packet);
+   return status;
+}
+
+VC_CONTAINER_STATUS_T vc_container_filter_control(VC_CONTAINER_FILTER_T *p_ctx, VC_CONTAINER_CONTROL_T operation, ... )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+   va_list args;
+
+   va_start( args, operation );
+   if(p_ctx->pf_control)
+      status = p_ctx->pf_control(p_ctx, operation, args);
+   va_end( args );
+
+   return status;
+}
+
+static VC_CONTAINER_FILTER_OPEN_FUNC_T load_library(void **handle, VC_CONTAINER_FOURCC_T filter, const char *name)
+{  
+   VC_CONTAINER_FILTER_OPEN_FUNC_T func = NULL;
+#ifdef ENABLE_CONTAINERS_STANDALONE
+   VC_CONTAINER_PARAM_UNUSED(handle);
+   VC_CONTAINER_PARAM_UNUSED(filter);
+   VC_CONTAINER_PARAM_UNUSED(name);
+#else
+   char *dl_name, *entrypt_name;
+   const char *entrypt_name_short = "filter_open";
+   char filter_[6], *ptr;
+   void *dl_handle;
+   int dl_name_len;
+   int entrypt_name_len;
+
+   snprintf(filter_, sizeof(filter_), "%4.4s", (const char*)&filter);
+   ptr = strchr(filter_, '\0');
+   while (ptr > filter_ && isspace(*--ptr)) *ptr = '\0';
+   strncat(filter_, "_", 1);    
+
+   dl_name_len = strlen(DL_PATH_PREFIX) + strlen(filter_) + strlen(name) + strlen(DL_SUFFIX) + 1;
+   dl_name = malloc(dl_name_len);
+   if (!dl_name) return NULL;
+
+   entrypt_name_len = strlen(name) + 1 + strlen(filter_) + strlen(entrypt_name_short) + 1;
+   entrypt_name = malloc(entrypt_name_len);
+   if (!entrypt_name)
+   {
+      free(dl_name);
+      return NULL;
+   }
+
+   snprintf(dl_name, dl_name_len, "%s%s%s%s", DL_PATH_PREFIX, filter_, name, DL_SUFFIX);
+   snprintf(entrypt_name, entrypt_name_len, "%s_%s%s", name, filter_, entrypt_name_short);
+
+   if ((dl_handle = vcos_dlopen(dl_name, VCOS_DL_NOW)) != NULL)
+   {
+      /* Try generic entrypoint name before the mangled, full name */
+      func = (VC_CONTAINER_FILTER_OPEN_FUNC_T)vcos_dlsym(dl_handle, entrypt_name_short);
+      if (!func) func = (VC_CONTAINER_FILTER_OPEN_FUNC_T)vcos_dlsym(dl_handle, entrypt_name);
+      /* Only return handle if symbol found */
+      if (func)
+         *handle = dl_handle;
+      else
+         vcos_dlclose(dl_handle);      
+   }
+
+   free(dl_name);
+   free(entrypt_name);
+#endif
+   return func;
+}
+      
+static void unload_library(void *handle)
+{
+#ifdef ENABLE_CONTAINERS_STANDALONE
+   VC_CONTAINER_PARAM_UNUSED(handle);
+#else
+   vcos_dlclose(handle);
+#endif
+}
diff --git a/containers/core/containers_filters.h b/containers/core/containers_filters.h
new file mode 100755 (executable)
index 0000000..9026274
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef VC_CONTAINERS_FILTERS_H
+#define VC_CONTAINERS_FILTERS_H
+
+/** \file containers_filters.h
+ * Interface definition for the filter abstraction used by the container
+ * common layer */
+#include <stdarg.h>
+
+#include "containers/containers.h"
+
+/** \defgroup VcContainerFilterApi Container Filter API */
+/* @{ */
+
+/** Container Filter Context.
+ * This structure defines the context for a container filter instance */
+typedef struct VC_CONTAINER_FILTER_T
+{   
+   /** Pointer to container instance */
+   struct VC_CONTAINER_T *container;
+   /** Pointer to information private to the container filter instance */
+   struct VC_CONTAINER_FILTER_PRIVATE_T *priv;
+   /** Pointer to information private to the container filter module */
+   struct VC_CONTAINER_FILTER_MODULE_T *module;
+
+   /** \note the following list of function pointers should not be used directly.
+    * They defines the interface for implementing container filter modules and are 
+    * filled in by the container filter modules themselves. */
+
+   /** \private
+    * Function pointer to close and free all resources allocated by a
+    * container filter module */
+   VC_CONTAINER_STATUS_T (*pf_close)(struct VC_CONTAINER_FILTER_T *filter);
+
+   /** \private
+    * Function pointer to filter a data packet using a container filter module */
+   VC_CONTAINER_STATUS_T (*pf_process)(struct VC_CONTAINER_FILTER_T *filter, VC_CONTAINER_PACKET_T *p_packet);
+
+   /** \private
+    * Function pointer to control container filter module */
+   VC_CONTAINER_STATUS_T (*pf_control)( struct VC_CONTAINER_FILTER_T *filter, VC_CONTAINER_CONTROL_T operation, va_list args );
+
+} VC_CONTAINER_FILTER_T;
+
+/** Opens a container filter using a four character code describing the filter.
+ * This will create an instance of the container filter.
+ *
+ * \param  filter       Four Character Code describing the filter
+ * \param  type         Four Character Code describing the subtype - indicated whether filter is encrypt or decrypt
+ * \param  container    Pointer to the container instance
+ * \param  status       Returns the status of the operation
+ * \return              If successful, this returns a pointer to the new instance
+ *                      of the container filter. Returns NULL on failure.
+ */
+VC_CONTAINER_FILTER_T *vc_container_filter_open(VC_CONTAINER_FOURCC_T filter,
+                                                VC_CONTAINER_FOURCC_T type, 
+                                                VC_CONTAINER_T *container,
+                                                VC_CONTAINER_STATUS_T *status );
+
+/** Closes an instance of a container filter.
+ * \param  context      Pointer to the VC_CONTAINER_FILTER_T context of the instance to close
+ * \return              VC_CONTAINER_SUCCESS on success.
+ */
+VC_CONTAINER_STATUS_T vc_container_filter_close( VC_CONTAINER_FILTER_T *context );
+
+/** Filter a data packet using a container filter module.
+ * \param  context      Pointer to the VC_CONTAINER_FILTER_T instance to use
+ * \param  packet       Pointer to the VC_CONTAINER_PACKET_T structure to process
+ * \return              the status of the operation
+ */
+VC_CONTAINER_STATUS_T vc_container_filter_process(VC_CONTAINER_FILTER_T *context, VC_CONTAINER_PACKET_T *p_packet);
+/** Extensible control function for container filter modules.
+* This function takes a variable number of arguments which will depend on the specific operation.
+*
+* \param  context      Pointer to the VC_CONTAINER_FILTER_T instance to use
+* \param  operation    The requested operation
+* \param  args         Arguments for the operation
+* \return              the status of the operation
+*/ 
+VC_CONTAINER_STATUS_T vc_container_filter_control(VC_CONTAINER_FILTER_T *context, VC_CONTAINER_CONTROL_T operation, ... );
+
+/* @} */
+
+#endif /* VC_CONTAINERS_FILTERS_H */
diff --git a/containers/core/containers_index.c b/containers/core/containers_index.c
new file mode 100755 (executable)
index 0000000..7edebfa
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "containers/containers.h"
+#include "containers/core/containers_index.h"
+
+typedef struct {
+   int64_t file_offset;
+   int64_t time;
+} VC_CONTAINER_INDEX_POS_T;
+
+struct  VC_CONTAINER_INDEX_T {
+   int len;                           // log2 of length of entry array
+   int next;                          // next array entry to write into
+   int gap;                           // log2 of the passes through entry array to build the full list
+   int mgap;                          // len-gap, stored for convenience
+   int count;                         // number of calls to index_add since last entry added
+   int max_count;                     // log2 of the number of calls to discard between each entry added
+   int64_t max_time;                  // time of the latest entry
+   VC_CONTAINER_INDEX_POS_T entry[0]; // array of position/time pairs   
+};
+
+// We have a fixed length list, and when it is full we want to discard half the entries.
+// This is done without coping data by mapping the entry number to the index to the array,
+// in the following way:
+// Length is a power of two, so the entry number is a fixed constant bit width.  The highest gap
+// bits are used as a direct offset into the array (o), the lowest mgap bits are right shifted by
+// gap to increment this (S).  Each time we double the number of passes through the actual array.
+// So if len=3, we start off with mgap=3, gap=0, we have a single pass with the trivial mapping:
+// |S|S|S|  [0 1 2 3 4 5 6 7]
+// when this is full we change to mgap=2, gap=1, so we iterate this way:
+// |o|S|S|  [0 2 4 6] [1 3 5 7]
+// when this is full we change to mgap=1, gap=2
+// |o|o|S|  [0 4] [1 5] [2 6] [3 7]  
+// when this is full we change to this, which is equivalent to where we started
+// |o|o|o|  [0] [1] [2] [3] [4] [5] [6] [7]
+
+#define ENTRY(x, i) ((x)->gap == 0 ? (i) : ((i)>>(x)->mgap) + (((i) & ((1<<(x)->mgap)-1)) << (x)->gap))
+
+VC_CONTAINER_STATUS_T vc_container_index_create( VC_CONTAINER_INDEX_T **index, int length )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+   VC_CONTAINER_INDEX_T *id = NULL;
+   int len = 0;
+
+   if(length < 16) length = 16;
+   if(length > 4096) length = 4096;
+   while((length >>= 1) != 0)
+      len++;
+
+   id = malloc(sizeof(VC_CONTAINER_INDEX_T) + (sizeof(VC_CONTAINER_INDEX_POS_T)<<len));
+   if(id == NULL) { goto error; }
+   
+   memset(id, 0, sizeof(VC_CONTAINER_INDEX_T));
+
+   id->len = id->mgap = len;
+
+   *index = id;
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+   return status;
+}
+
+VC_CONTAINER_STATUS_T vc_container_index_free( VC_CONTAINER_INDEX_T *index )
+{
+   if(index == NULL)
+      return VC_CONTAINER_ERROR_FAILED;
+
+   free(index);
+   return VC_CONTAINER_SUCCESS;
+}
+
+VC_CONTAINER_STATUS_T vc_container_index_add( VC_CONTAINER_INDEX_T *index, int64_t time, int64_t file_offset )
+{
+   if(index == NULL)
+      return VC_CONTAINER_ERROR_FAILED;
+
+   // reject entries if they are in part of the time covered
+   if(index->next != 0 && time <= index->max_time)
+      return VC_CONTAINER_SUCCESS;
+
+   index->count++;
+   if(index->count == (1<<index->max_count))
+   {
+      int entry;
+      if(index->next == (1<<index->len))
+      {
+         // New entry doesn't fit, we discard every other index record
+         // by changing how we map index positions to array entry indexes.
+         index->next >>= 1;
+         index->gap++;
+         index->mgap--;
+         index->max_count++;
+
+         if(index->gap == index->len)
+         {
+            index->gap = 0;
+            index->mgap = index->len;
+         }
+      }
+
+      entry = ENTRY(index, index->next);
+
+      index->entry[entry].file_offset = file_offset;
+      index->entry[entry].time = time;
+      index->count = 0;
+      index->next++;
+      index->max_time = time;
+   }
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+VC_CONTAINER_STATUS_T vc_container_index_get( VC_CONTAINER_INDEX_T *index, int later, int64_t *time, int64_t *file_offset, int *past )
+{
+   int guess, start, end, entry;
+
+   if(index == NULL || index->next == 0)
+      return VC_CONTAINER_ERROR_FAILED;
+
+   guess = start = 0;
+   end = index->next-1;
+
+   *past = *time > index->max_time;
+
+   while(end-start > 1)
+   {
+      int64_t gtime;
+      guess = (start+end)>>1;
+      gtime = index->entry[ENTRY(index, guess)].time;
+
+      if(*time < gtime)
+         end = guess;
+      else if(*time > gtime)
+         start = guess;
+      else
+         break;
+   }
+
+   if (*time != index->entry[ENTRY(index, guess)].time)
+   {
+      if(later)
+      {
+         if(*time <= index->entry[ENTRY(index, start)].time)
+            guess = start;
+         else
+            guess = end;
+      }
+      else
+      {
+         if(*time >= index->entry[ENTRY(index, end)].time)
+            guess = end;
+         else
+            guess = start;
+      }
+   }
+
+   entry = ENTRY(index, guess);
+   *time = index->entry[entry].time;
+   *file_offset = index->entry[entry].file_offset;
+
+   return VC_CONTAINER_SUCCESS;
+}
+
diff --git a/containers/core/containers_index.h b/containers/core/containers_index.h
new file mode 100755 (executable)
index 0000000..f0c49c3
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef VC_CONTAINERS_INDEX_H
+#define VC_CONTAINERS_INDEX_H
+
+/** \file containers_index.h
+ * Definition of index utilitie for containers.  Creates and maintains an
+ * index of file offsets and times, and is able to suggest a file position
+ * to seek to achieve a given time target.  Useful for container formats
+ * that don't include an index.
+ */
+
+#include "containers/containers.h" 
+
+struct VC_CONTAINER_INDEX_T;
+typedef struct VC_CONTAINER_INDEX_T VC_CONTAINER_INDEX_T;
+
+/**
+ * Creates an index with a suggested number of entries.
+ * @param  index   Pointer to created index will be filled here on success.
+ * @param  length  Suggested length of index.
+ * @return         Status code
+ */
+VC_CONTAINER_STATUS_T vc_container_index_create( VC_CONTAINER_INDEX_T **index, int length );
+
+
+/**
+ * Frees an index.
+ * @param index  Pointer to valid index.
+ * @return       Status code.
+ */
+VC_CONTAINER_STATUS_T vc_container_index_free( VC_CONTAINER_INDEX_T *index );
+
+
+/**
+ * Adds an entry to the index.  If the index is full then some stored records will be
+ * discarded.
+ * @param index        Pointer to a valid index.
+ * @param time         Timestamp of new index entry.
+ * @param file_offset  File offset for new index entry.
+ * @return             Status code
+ */
+VC_CONTAINER_STATUS_T vc_container_index_add( VC_CONTAINER_INDEX_T *index, int64_t time, int64_t file_offset );
+
+
+/**
+ * Retrieves the best entry for the supplied time offset.
+ * @param index        Pointer to valid index.
+ * @param later        If true, the selected entry is the earliest retained entry with a greater or equal timestamp. 
+ *                     If false, the selected entry is the latest retained entry with an earlier or equal timestamp.
+ * @param time         The requested time.  On success, this is filled in with the time of the selected entry.
+ * @param file_offset  On success, this is filled in with the file offset of the selected entry.
+ * @param past         Set if the requested time is after the last entry in the index.
+ * @return             Status code.
+ */
+VC_CONTAINER_STATUS_T vc_container_index_get( VC_CONTAINER_INDEX_T *index, int later, int64_t *time, int64_t *file_offset, int *past );
+
+#endif /* VC_CONTAINERS_WRITER_UTILS_H */
diff --git a/containers/core/containers_io.c b/containers/core/containers_io.c
new file mode 100755 (executable)
index 0000000..907a2a0
--- /dev/null
@@ -0,0 +1,1088 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "containers/containers.h"
+#include "containers/core/containers_io.h"
+#include "containers/core/containers_common.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_uri.h"
+
+#define MAX_NUM_CACHED_AREAS 16
+#define MAX_NUM_MEMORY_AREAS 4
+#define NUM_TMP_MEMORY_AREAS 2
+#define MEM_CACHE_READ_MAX_SIZE (32*1024) /* Needs to be a power of 2 */
+#define MEM_CACHE_WRITE_MAX_SIZE (128*1024) /* Needs to be a power of 2 */
+#define MEM_CACHE_TMP_MAX_SIZE (32*1024) /* Needs to be a power of 2 */
+#define MEM_CACHE_ALIGNMENT (1*1024) /* Needs to be a power of 2 */
+#define MEM_CACHE_AREA_READ_MAX_SIZE (4*1024*1024) /* Needs to be a power of 2 */
+
+typedef struct VC_CONTAINER_IO_PRIVATE_CACHE_T
+{
+   int64_t start; /**< Offset to the start of the cached area in the stream */
+   int64_t end;    /**< Offset to the end of the cached area in the stream */
+
+   int64_t offset; /**< Offset of the currently cached data in the stream */
+   size_t size;    /**< Size of the cached area */
+   bool dirty;     /**< Whether the cache is dirty and needs to be written back */
+
+   size_t position; /**< Current position in the cache */
+
+   uint8_t *buffer;          /**< Pointer to the start of the valid cache area */
+   uint8_t *buffer_end;      /**< Pointer to the end of the cache */
+
+   unsigned int mem_max_size; /**< Maximum size of the memory cache */
+   unsigned int mem_size; /**< Size of the memory cache */
+   uint8_t *mem;          /**< Pointer to the memory cache */
+
+   VC_CONTAINER_IO_T *io;
+
+} VC_CONTAINER_IO_PRIVATE_CACHE_T;
+
+typedef struct VC_CONTAINER_IO_PRIVATE_T
+{
+   VC_CONTAINER_IO_PRIVATE_CACHE_T *cache; /**< Current cache */
+
+   unsigned int caches_num;
+   VC_CONTAINER_IO_PRIVATE_CACHE_T caches;
+
+   unsigned int cached_areas_num;
+   VC_CONTAINER_IO_PRIVATE_CACHE_T cached_areas[MAX_NUM_CACHED_AREAS];
+
+   int64_t actual_offset;
+
+   struct VC_CONTAINER_IO_ASYNC_T *async_io;
+
+} VC_CONTAINER_IO_PRIVATE_T;
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_io_file_open( VC_CONTAINER_IO_T *p_ctx, const char *uri,
+                                                 VC_CONTAINER_IO_MODE_T mode );
+VC_CONTAINER_STATUS_T vc_container_io_null_open( VC_CONTAINER_IO_T *p_ctx, const char *uri,
+                                                 VC_CONTAINER_IO_MODE_T mode );
+VC_CONTAINER_STATUS_T vc_container_io_net_open( VC_CONTAINER_IO_T *p_ctx, const char *uri,
+                                                 VC_CONTAINER_IO_MODE_T mode );
+VC_CONTAINER_STATUS_T vc_container_io_pktfile_open( VC_CONTAINER_IO_T *p_ctx, const char *uri,
+                                                 VC_CONTAINER_IO_MODE_T mode );
+VC_CONTAINER_STATUS_T vc_container_io_http_open( VC_CONTAINER_IO_T *p_ctx, const char *uri,
+                                                 VC_CONTAINER_IO_MODE_T mode );
+static VC_CONTAINER_STATUS_T io_seek_not_seekable(VC_CONTAINER_IO_T *p_ctx, int64_t offset);
+
+static size_t vc_container_io_cache_read( VC_CONTAINER_IO_T *p_ctx,
+   VC_CONTAINER_IO_PRIVATE_CACHE_T *cache, uint8_t *data, size_t size );
+static int32_t vc_container_io_cache_write( VC_CONTAINER_IO_T *p_ctx,
+   VC_CONTAINER_IO_PRIVATE_CACHE_T *cache, const uint8_t *data, size_t size );
+static VC_CONTAINER_STATUS_T vc_container_io_cache_seek( VC_CONTAINER_IO_T *p_ctx,
+   VC_CONTAINER_IO_PRIVATE_CACHE_T *cache, int64_t offset );
+static size_t vc_container_io_cache_refill( VC_CONTAINER_IO_T *p_ctx,
+   VC_CONTAINER_IO_PRIVATE_CACHE_T *cache );
+static size_t vc_container_io_cache_flush( VC_CONTAINER_IO_T *p_ctx,
+   VC_CONTAINER_IO_PRIVATE_CACHE_T *cache, int complete );
+
+static struct VC_CONTAINER_IO_ASYNC_T *async_io_start( VC_CONTAINER_IO_T *io, int num_areas, VC_CONTAINER_STATUS_T * );
+static VC_CONTAINER_STATUS_T async_io_stop( struct VC_CONTAINER_IO_ASYNC_T *ctx );
+static int async_io_write( struct VC_CONTAINER_IO_ASYNC_T *ctx, VC_CONTAINER_IO_PRIVATE_CACHE_T *cache );
+static VC_CONTAINER_STATUS_T async_io_wait_complete( struct VC_CONTAINER_IO_ASYNC_T *ctx,
+                                                     VC_CONTAINER_IO_PRIVATE_CACHE_T *cache, int complete  );
+static void async_io_stats_initialise( struct VC_CONTAINER_IO_ASYNC_T *ctx, int enable );
+static void async_io_stats_get( struct VC_CONTAINER_IO_ASYNC_T *ctx, VC_CONTAINER_WRITE_STATS_T *stats );
+
+/*****************************************************************************/
+static VC_CONTAINER_IO_T *vc_container_io_open_core( const char *uri, VC_CONTAINER_IO_MODE_T mode,
+                                                     VC_CONTAINER_IO_CAPABILITIES_T capabilities,
+                                                     bool b_open, VC_CONTAINER_STATUS_T *p_status )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_IO_T *p_ctx = 0;
+   VC_CONTAINER_IO_PRIVATE_T *private = 0;
+   unsigned int uri_length, caches = 0, cache_max_size, num_areas = MAX_NUM_MEMORY_AREAS;
+
+   /* XXX */
+   uri_length = strlen(uri) + 1;
+
+   /* Allocate our context before trying out the different io modules */
+   p_ctx = malloc( sizeof(*p_ctx) + sizeof(*private) + uri_length);
+   if(!p_ctx) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(p_ctx, 0, sizeof(*p_ctx) + sizeof(*private) + uri_length );
+   p_ctx->priv = private = (VC_CONTAINER_IO_PRIVATE_T *)&p_ctx[1];
+   p_ctx->uri = (char *)&private[1];
+   memcpy((char *)p_ctx->uri, uri, uri_length);
+   p_ctx->uri_parts = vc_uri_create();
+   if(!p_ctx->uri_parts) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   vc_uri_parse(p_ctx->uri_parts, uri);
+
+   if (b_open)
+   {
+      /* Open the actual i/o module */
+      status = vc_container_io_null_open(p_ctx, uri, mode);
+      if(status) status = vc_container_io_net_open(p_ctx, uri, mode);
+      if(status) status = vc_container_io_pktfile_open(p_ctx, uri, mode);
+#ifdef ENABLE_CONTAINER_IO_HTTP
+      if(status) status = vc_container_io_http_open(p_ctx, uri, mode);
+#endif
+      if(status) status = vc_container_io_file_open(p_ctx, uri, mode);
+      if(status != VC_CONTAINER_SUCCESS) goto error;
+
+      if(!p_ctx->pf_seek || (p_ctx->capabilities & VC_CONTAINER_IO_CAPS_CANT_SEEK))
+      {
+         p_ctx->capabilities |= VC_CONTAINER_IO_CAPS_CANT_SEEK;
+         p_ctx->pf_seek = io_seek_not_seekable;
+      }
+   }
+   else
+   {
+      /* We're only creating an empty container i/o */
+      p_ctx->capabilities = capabilities;
+   }
+
+   if(p_ctx->capabilities & VC_CONTAINER_IO_CAPS_NO_CACHING)
+      caches = 1;
+
+   if(mode == VC_CONTAINER_IO_MODE_WRITE) cache_max_size = MEM_CACHE_WRITE_MAX_SIZE;
+   else cache_max_size = MEM_CACHE_READ_MAX_SIZE;
+
+   if(mode == VC_CONTAINER_IO_MODE_WRITE &&
+      vc_uri_path_extension(p_ctx->uri_parts) &&
+      !strcasecmp(vc_uri_path_extension(p_ctx->uri_parts), "tmp"))
+   {
+      caches = 1;
+      cache_max_size = MEM_CACHE_TMP_MAX_SIZE;
+      num_areas = NUM_TMP_MEMORY_AREAS;
+   }
+
+   /* Check if the I/O needs caching */
+   if(caches)
+   {
+      VC_CONTAINER_IO_PRIVATE_CACHE_T *cache = &p_ctx->priv->caches;
+      cache->mem_max_size = cache_max_size;
+      cache->mem_size = cache->mem_max_size;
+      cache->io = p_ctx;
+      cache->mem = malloc(p_ctx->priv->caches.mem_size);
+      if(cache->mem)
+      {      
+         cache->buffer = cache->mem;
+         cache->buffer_end = cache->mem + cache->mem_size;
+         p_ctx->priv->caches_num = 1;
+      }
+   }
+
+   if(p_ctx->priv->caches_num)
+      p_ctx->priv->cache = &p_ctx->priv->caches;
+
+
+   /* Try to start an asynchronous io if we're in write mode and we've got at least 2 cache memory areas */
+   if(mode == VC_CONTAINER_IO_MODE_WRITE && p_ctx->priv->cache && num_areas >= 2)
+      p_ctx->priv->async_io = async_io_start( p_ctx, num_areas, 0 );
+
+ end:
+   if(p_status) *p_status = status;
+   return p_ctx;
+
+ error:
+   if(p_ctx) vc_uri_release(p_ctx->uri_parts);
+   if(p_ctx) free(p_ctx);
+   p_ctx = 0;
+   goto end;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_IO_T *vc_container_io_open( const char *uri, VC_CONTAINER_IO_MODE_T mode,
+                                         VC_CONTAINER_STATUS_T *p_status )
+{
+   return vc_container_io_open_core( uri, mode, 0, true, p_status );
+}
+
+/*****************************************************************************/
+VC_CONTAINER_IO_T *vc_container_io_create( const char *uri, VC_CONTAINER_IO_MODE_T mode,
+                                           VC_CONTAINER_IO_CAPABILITIES_T capabilities,
+                                           VC_CONTAINER_STATUS_T *p_status )
+{
+   return vc_container_io_open_core( uri, mode, capabilities, false, p_status );
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_io_close( VC_CONTAINER_IO_T *p_ctx )
+{
+   unsigned int i;
+
+   if(p_ctx)
+   {
+      if(p_ctx->priv)
+      {
+         if(p_ctx->priv->caches_num)
+         {
+            if(p_ctx->priv->caches.dirty)
+               vc_container_io_cache_flush( p_ctx, &p_ctx->priv->caches, 1 );
+         }
+         
+         if(p_ctx->priv->async_io)
+            async_io_stop( p_ctx->priv->async_io );
+         else if(p_ctx->priv->caches_num)
+            free(p_ctx->priv->caches.mem);
+
+         for(i = 0; i < p_ctx->priv->cached_areas_num; i++)
+            free(p_ctx->priv->cached_areas[i].mem);
+         
+         if(p_ctx->pf_close)
+            p_ctx->pf_close(p_ctx);
+      }
+      vc_uri_release(p_ctx->uri_parts);
+      free(p_ctx);
+   }
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+size_t vc_container_io_peek(VC_CONTAINER_IO_T *p_ctx, void *buffer, size_t size)
+{
+   size_t ret;
+
+   if(p_ctx->priv->cache)
+   {
+      /* FIXME: do something a bit more clever than this */
+      int64_t offset = p_ctx->offset;
+      ret = vc_container_io_read(p_ctx, buffer, size);
+      vc_container_io_seek(p_ctx, offset);
+      return ret;
+   }
+
+   if (p_ctx->capabilities & VC_CONTAINER_IO_CAPS_CANT_SEEK)
+      return 0;
+
+   ret = p_ctx->pf_read(p_ctx, buffer, size);
+   p_ctx->pf_seek(p_ctx, p_ctx->offset);
+   return ret;
+}
+
+/*****************************************************************************/
+size_t vc_container_io_read(VC_CONTAINER_IO_T *p_ctx, void *buffer, size_t size)
+{
+   size_t ret;
+
+   if(p_ctx->priv->cache)
+      ret = vc_container_io_cache_read( p_ctx, p_ctx->priv->cache, (uint8_t*)buffer, size );
+   else
+   {
+      ret = p_ctx->pf_read(p_ctx, buffer, size);
+      p_ctx->priv->actual_offset += ret;
+   }
+
+   p_ctx->offset += ret;
+   return ret;
+}
+
+/*****************************************************************************/
+size_t vc_container_io_write(VC_CONTAINER_IO_T *p_ctx, const void *buffer, size_t size)
+{
+   int32_t ret;
+
+   if(p_ctx->priv->cache)
+      ret = vc_container_io_cache_write( p_ctx, p_ctx->priv->cache, (const uint8_t*)buffer, size );
+   else
+   {
+      ret = p_ctx->pf_write(p_ctx, buffer, size);
+      p_ctx->priv->actual_offset += ret;
+   }
+
+   p_ctx->offset += ret;
+   return ret < 0 ? 0 : ret;
+}
+
+/*****************************************************************************/
+size_t vc_container_io_skip(VC_CONTAINER_IO_T *p_ctx, size_t size)
+{
+   if(!size) return 0;
+
+   if(size < 8)
+   {
+      uint8_t value[8];
+      return vc_container_io_read(p_ctx, value, size);
+   }
+
+   if(p_ctx->priv->cache)
+   {
+      if(vc_container_io_cache_seek(p_ctx, p_ctx->priv->cache, p_ctx->offset + size)) return 0;
+      p_ctx->offset += size;
+      return size;
+   }
+
+   if(vc_container_io_seek(p_ctx, p_ctx->offset + size)) return 0;
+   return size;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_io_seek(VC_CONTAINER_IO_T *p_ctx, int64_t offset)
+{
+   VC_CONTAINER_STATUS_T status;
+   unsigned int i;
+
+   /* Check if the requested position is in one of the cached areas */
+   for(i = 0; i < p_ctx->priv->cached_areas_num; i++)
+   {
+      VC_CONTAINER_IO_PRIVATE_CACHE_T *cache = &p_ctx->priv->cached_areas[i];
+      if(offset >= cache->start && offset < cache->end)
+      {
+         p_ctx->priv->cache = cache;
+         break;
+      }
+   }
+   if(i == p_ctx->priv->cached_areas_num)
+      p_ctx->priv->cache = p_ctx->priv->caches_num ? &p_ctx->priv->caches : 0;
+
+   if(p_ctx->priv->cache)
+   {
+      status = vc_container_io_cache_seek( p_ctx, p_ctx->priv->cache, offset );
+      if(status == VC_CONTAINER_SUCCESS) p_ctx->offset = offset;
+      return status;
+   }
+
+   if(p_ctx->status == VC_CONTAINER_SUCCESS &&
+      offset == p_ctx->offset) return VC_CONTAINER_SUCCESS;
+
+   status = p_ctx->pf_seek(p_ctx, offset);
+   if(status == VC_CONTAINER_SUCCESS) p_ctx->offset = offset;
+   p_ctx->priv->actual_offset = p_ctx->offset;
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T io_seek_not_seekable(VC_CONTAINER_IO_T *p_ctx, int64_t offset)
+{
+   VC_CONTAINER_IO_PRIVATE_T *private = p_ctx->priv;
+
+   vc_container_assert(offset >= private->actual_offset);
+   if(offset == private->actual_offset)  return VC_CONTAINER_SUCCESS;
+
+   if(offset < private->actual_offset)
+   {
+      p_ctx->status = VC_CONTAINER_ERROR_EOS;
+      return p_ctx->status;
+   }
+
+   offset -= private->actual_offset;
+   while(offset && !p_ctx->status)
+   {
+      uint8_t value[64];
+      unsigned int ret, size = MIN(offset, 64);
+      ret = p_ctx->pf_read(p_ctx, value, size);
+      if(ret != size) p_ctx->status = VC_CONTAINER_ERROR_EOS;
+      offset -= ret;
+   }
+   return p_ctx->status;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_io_control_list(VC_CONTAINER_IO_T *context, VC_CONTAINER_CONTROL_T operation, va_list args)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+
+   if (context->pf_control)
+      status = context->pf_control(context, operation, args);
+
+   /* Option to add generic I/O control here */
+
+   if(operation == VC_CONTAINER_CONTROL_IO_FLUSH && context->priv->cache)
+   {
+      status = VC_CONTAINER_SUCCESS;
+      (void)vc_container_io_cache_flush( context, context->priv->cache, 1 );
+   }
+
+   if(operation == VC_CONTAINER_CONTROL_SET_IO_PERF_STATS && context->priv->async_io)
+   {
+      status = VC_CONTAINER_SUCCESS;
+      async_io_stats_initialise(context->priv->async_io, va_arg(args, int));
+   }
+
+   if(operation == VC_CONTAINER_CONTROL_GET_IO_PERF_STATS && context->priv->async_io)
+   {
+      status = VC_CONTAINER_SUCCESS;
+      async_io_stats_get(context->priv->async_io, va_arg(args, VC_CONTAINER_WRITE_STATS_T *));
+   }
+
+   return status;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_io_control(VC_CONTAINER_IO_T *context, VC_CONTAINER_CONTROL_T operation, ...)
+{
+   VC_CONTAINER_STATUS_T result;
+   va_list args;
+
+   va_start(args, operation);
+   result = vc_container_io_control_list(context, operation, args);
+   va_end(args);
+
+   return result;
+}
+
+/*****************************************************************************/
+size_t vc_container_io_cache(VC_CONTAINER_IO_T *p_ctx, size_t size)
+{
+   VC_CONTAINER_IO_PRIVATE_T *private = p_ctx->priv;
+   VC_CONTAINER_IO_PRIVATE_CACHE_T *cache, *main_cache;
+   VC_CONTAINER_STATUS_T status;
+
+   /* Sanity checking */
+   if(private->cached_areas_num >= MAX_NUM_CACHED_AREAS) return 0;
+
+   cache = &private->cached_areas[private->cached_areas_num];
+   cache->start = p_ctx->offset;
+   cache->end = cache->start + size;
+   cache->offset = p_ctx->offset;
+   cache->position = 0;
+   cache->size = 0;
+   cache->io = p_ctx;
+
+   /* Set the size of the cache area depending on the capabilities of the i/o */
+   if(p_ctx->capabilities & VC_CONTAINER_IO_CAPS_CANT_SEEK)
+      cache->mem_max_size = MEM_CACHE_AREA_READ_MAX_SIZE;
+   else if((p_ctx->capabilities & VC_CONTAINER_IO_CAPS_SEEK_SLOW) &&
+           size <= MEM_CACHE_AREA_READ_MAX_SIZE)
+      cache->mem_max_size = MEM_CACHE_AREA_READ_MAX_SIZE;
+   else
+      cache->mem_max_size = MEM_CACHE_READ_MAX_SIZE;
+
+   cache->mem_size = size;
+   if(cache->mem_size > cache->mem_max_size) cache->mem_size = cache->mem_max_size;
+   cache->mem = malloc(cache->mem_size);
+
+   cache->buffer = cache->mem;
+   cache->buffer_end = cache->mem + cache->mem_size;
+
+   if(!cache->mem) return 0;
+   private->cached_areas_num++;
+
+   /* Copy any data we've got in the current cache into the new cache */
+   main_cache = p_ctx->priv->cache;
+   if(main_cache && main_cache->position < main_cache->size)
+   {
+      cache->size = main_cache->size - main_cache->position;
+      if(cache->size > cache->mem_size) cache->size = cache->mem_size;
+      memcpy(cache->buffer, main_cache->buffer + main_cache->position, cache->size);
+      main_cache->position += cache->size;
+   }
+
+   /* Read the rest of the cache directly from the stream */
+   if(cache->mem_size > cache->size)
+   {
+      size_t ret = cache->io->pf_read(cache->io, cache->buffer + cache->size,
+                                      cache->mem_size - cache->size);
+      cache->size += ret;
+      cache->io->priv->actual_offset = cache->offset + cache->size;
+   }
+
+   status = vc_container_io_seek(p_ctx, cache->end);
+   if(status != VC_CONTAINER_SUCCESS)
+      return 0;
+
+   if(p_ctx->capabilities & VC_CONTAINER_IO_CAPS_CANT_SEEK)
+      return cache->size;
+   else
+      return size;
+}
+
+/*****************************************************************************/
+static size_t vc_container_io_cache_refill( VC_CONTAINER_IO_T *p_ctx,
+   VC_CONTAINER_IO_PRIVATE_CACHE_T *cache )
+{
+   size_t ret = vc_container_io_cache_flush( p_ctx, cache, 1 );
+
+   if(ret) return 0; /* TODO what should we do there ? */
+
+   if(p_ctx->priv->actual_offset != cache->offset)
+   {
+      if(cache->io->pf_seek(cache->io, cache->offset) != VC_CONTAINER_SUCCESS)
+         return 0;
+   }
+
+   ret = cache->io->pf_read(cache->io, cache->buffer, cache->buffer_end - cache->buffer);
+   cache->size = ret;
+   cache->position = 0;
+   cache->io->priv->actual_offset = cache->offset + ret;
+   return ret;
+}
+
+/*****************************************************************************/
+static size_t vc_container_io_cache_refill_bypass( VC_CONTAINER_IO_T *p_ctx,
+   VC_CONTAINER_IO_PRIVATE_CACHE_T *cache, uint8_t *buffer, size_t size )
+{
+   size_t ret = vc_container_io_cache_flush( p_ctx, cache, 1 );
+
+   if(ret) return 0; /* TODO what should we do there ? */
+
+   if(p_ctx->priv->actual_offset != cache->offset)
+   {
+      if(cache->io->pf_seek(cache->io, cache->offset) != VC_CONTAINER_SUCCESS)
+         return 0;
+   }
+
+   ret = cache->io->pf_read(cache->io, buffer, size);
+   cache->size = cache->position = 0;
+   cache->offset += ret;
+   cache->io->priv->actual_offset = cache->offset;
+   return ret;
+}
+
+/*****************************************************************************/
+static size_t vc_container_io_cache_read( VC_CONTAINER_IO_T *p_ctx,
+   VC_CONTAINER_IO_PRIVATE_CACHE_T *cache, uint8_t *data, size_t size )
+{
+   size_t read = 0, bytes, ret;
+
+   while(size)
+   {
+      bytes = cache->size - cache->position; /* Bytes left in cache */
+
+#if 1 // FIXME Only if stream is seekable
+      /* Try to read directly from the stream if the cache just gets in the way */
+      if(!bytes && size > cache->mem_size)
+      {
+         bytes = cache->mem_size;
+         ret = vc_container_io_cache_refill_bypass( p_ctx, cache, data + read, bytes);
+         read += ret;
+
+         if(ret != bytes) /* We didn't read as many bytes as we had hoped */
+            goto end;
+
+         size -= bytes;
+         continue;
+      }
+#endif
+
+      /* Refill the cache if it is empty */
+      if(!bytes) bytes = vc_container_io_cache_refill( p_ctx, cache );
+      if(!bytes) goto end;
+
+      /* We do have some data in the cache so override the status */
+      p_ctx->status = VC_CONTAINER_SUCCESS;
+
+      /* Read data directly from the cache */
+      if(bytes > size) bytes = size;
+      memcpy(data + read, cache->buffer + cache->position, bytes);
+      cache->position += bytes;
+      read += bytes;
+      size -= bytes;
+   }
+
+ end:
+   vc_container_assert(cache->offset + cache->position == p_ctx->offset + read);
+   return read;
+}
+
+/*****************************************************************************/
+static int32_t vc_container_io_cache_write( VC_CONTAINER_IO_T *p_ctx,
+   VC_CONTAINER_IO_PRIVATE_CACHE_T *cache, const uint8_t *data, size_t size )
+{
+   int32_t written = 0;
+   size_t bytes, ret;
+
+   /* If we do not have a write cache then we need to flush it */
+   if(cache->size && !cache->dirty)
+   {
+      ret = vc_container_io_cache_flush( p_ctx, cache, 1 );
+      if(ret) return -(int32_t)ret;
+   }
+
+   while(size)
+   {
+      bytes = (cache->buffer_end - cache->buffer) - cache->position; /* Space left in cache */
+
+      /* Flush the cache if it is full */
+      if(!bytes)
+      {
+         /* Cache full, flush it */
+         ret = vc_container_io_cache_flush( p_ctx, cache, 0 );
+         if(ret)
+         {
+            written -= ret;
+            return written;
+         }
+         continue;
+      }
+
+      if(bytes > size) bytes = size;
+
+      if(!p_ctx->priv->async_io && bytes == cache->mem_size)
+      {
+         /* Write directly from the buffer */
+         ret = cache->io->pf_write(cache->io, data + written, bytes);
+         cache->offset += ret;
+         cache->io->priv->actual_offset += ret;
+      }
+      else
+      {
+         /* Write in the cache */
+         memcpy(cache->buffer + cache->position, data + written, bytes);
+         cache->position += bytes;
+         cache->dirty = 1;
+         ret = bytes;
+      }
+
+      written += ret;
+      if(ret != bytes) goto end;
+
+      size -= bytes;
+   }
+
+ end:
+   vc_container_assert(cache->offset + (int64_t)cache->position == p_ctx->offset + written);
+   if(cache->position > cache->size) cache->size = cache->position;
+   return written;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T vc_container_io_cache_seek(VC_CONTAINER_IO_T *p_ctx,
+   VC_CONTAINER_IO_PRIVATE_CACHE_T *cache, int64_t offset)
+{
+   VC_CONTAINER_STATUS_T status;
+   size_t shift, ret;
+
+   /* Check if the seek position is within our cache */
+   if(offset >= cache->offset && offset < cache->offset + (int64_t)cache->size)
+   {
+      cache->position = offset - cache->offset;
+      return VC_CONTAINER_SUCCESS;
+   }
+
+   shift = cache->buffer - cache->mem;
+   if(!cache->dirty && shift && cache->size &&
+      offset >= cache->offset - (int64_t)shift && offset < cache->offset)
+   {
+      /* We need to refill the partial bit of the cache that we didn't take care of last time */
+      status = cache->io->pf_seek(cache->io, cache->offset - shift);
+      if(status != VC_CONTAINER_SUCCESS) return status;
+      cache->offset -= shift;
+      cache->buffer -= shift;
+
+      ret = cache->io->pf_read(cache->io, cache->buffer, shift);
+      vc_container_assert(ret == shift); /* FIXME: ret must = shift */
+      cache->size += shift;
+      cache->position = offset - cache->offset;
+      cache->io->priv->actual_offset = cache->offset + ret;
+      return VC_CONTAINER_SUCCESS;
+   }
+
+   if(cache->dirty) vc_container_io_cache_flush( p_ctx, cache, 1 );
+   // FIXME: what if all the data couldn't be flushed ?
+
+   if(p_ctx->priv->async_io) async_io_wait_complete( p_ctx->priv->async_io, cache, 1 );
+
+   status = cache->io->pf_seek(cache->io, offset);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   vc_container_io_cache_flush( p_ctx, cache, 1 );
+
+   cache->offset = offset;
+   cache->io->priv->actual_offset = offset;
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static size_t vc_container_io_cache_flush( VC_CONTAINER_IO_T *p_ctx,
+   VC_CONTAINER_IO_PRIVATE_CACHE_T *cache, int complete )
+{
+   size_t ret = 0, shift;
+
+   if(cache->position > cache->size) cache->size = cache->position;
+
+   if(cache->dirty && cache->size)
+   {
+      if(p_ctx->priv->actual_offset != cache->offset)
+      {
+         if(p_ctx->priv->async_io) async_io_wait_complete( p_ctx->priv->async_io, cache, complete );
+
+         if(cache->io->pf_seek(cache->io, cache->offset) != VC_CONTAINER_SUCCESS)
+            return 0;
+      }
+
+      if(p_ctx->priv->async_io)
+      {
+         ret = async_io_write( p_ctx->priv->async_io, cache );
+         if(async_io_wait_complete( p_ctx->priv->async_io, cache, complete ) != VC_CONTAINER_SUCCESS)
+            ret = 0;
+      }
+      else
+         ret = cache->io->pf_write(cache->io, cache->buffer, cache->size);
+
+      cache->io->priv->actual_offset = cache->offset + ret;
+      ret = cache->position - ret;
+   }
+   cache->dirty = 0;
+
+   cache->offset += cache->size;
+   if(cache->mem_size == cache->mem_max_size)
+   {
+      shift = cache->offset &(MEM_CACHE_ALIGNMENT-1);
+      cache->buffer = cache->mem + shift;
+   }
+
+   cache->position = cache->size = 0;
+   return ret;
+}
+
+/*****************************************************************************
+ * Asynchronous I/O.
+ * This is here to keep the I/O as busy as possible by allowing the writer
+ * to continue its work while the I/O is taking place in the background.
+ *****************************************************************************/
+
+#ifdef ENABLE_CONTAINERS_ASYNC_IO
+#include "vcos.h"
+
+#define NUMPC(c,n,s) ((c) < (1<<(s)) ? (n) : ((n) / (c >> (s))))
+
+static void stats_initialise(VC_CONTAINER_STATS_T *st, uint32_t shift)
+{
+   memset(st, 0, sizeof(VC_CONTAINER_STATS_T));
+   st->shift = shift;
+}
+
+static void stats_add_value(VC_CONTAINER_STATS_T *st, uint32_t count, uint32_t num)
+{
+   uint32_t numpc;
+   int i, j;
+
+   if(count == 0) 
+      return;
+
+   numpc = NUMPC(count, num, st->shift);
+   // insert in the right place
+   i=0;
+   while(i < VC_CONTAINER_STATS_BINS && st->record[i].count != 0 && st->record[i].numpc > numpc)
+      i++;
+
+   if(st->record[i].count != 0 && st->record[i].numpc == numpc)
+   {
+      // equal numpc, can merge now
+      st->record[i].count += count;
+      st->record[i].num += num;
+   }
+   else
+   {
+      // shift higher records up
+      for(j=VC_CONTAINER_STATS_BINS; j>i; j--)
+         st->record[j] = st->record[j-1];
+
+      // write record in
+      st->record[i].count = count;
+      st->record[i].num = num;
+      st->record[i].numpc = numpc;
+
+      // if full, join the two closest records
+      if(st->record[VC_CONTAINER_STATS_BINS].count)
+      {
+         uint32_t min_diff = 0;
+         j = -1;
+
+         // find closest, based on difference between numpc
+         for(i=0; i<VC_CONTAINER_STATS_BINS; i++)
+         {
+            uint32_t diff = st->record[i].numpc - st->record[i+1].numpc;
+            if(j == -1 || diff < min_diff)
+            {
+               j = i;
+               min_diff = diff;
+            }
+         }
+
+         // merge these records
+         st->record[j].count += st->record[j+1].count;
+         st->record[j].num += st->record[j+1].num;
+         st->record[j].numpc = NUMPC(st->record[j].count, st->record[j].num, st->shift);
+
+         // shift down higher records
+         while(++j < VC_CONTAINER_STATS_BINS)
+            st->record[j] = st->record[j+1];
+
+         // zero the free top record
+         st->record[VC_CONTAINER_STATS_BINS].count = 0;
+         st->record[VC_CONTAINER_STATS_BINS].num = 0;
+         st->record[VC_CONTAINER_STATS_BINS].numpc = 0;
+      }
+   }
+}
+
+typedef struct VC_CONTAINER_IO_ASYNC_T
+{
+   VC_CONTAINER_IO_T *io;
+   VCOS_THREAD_T thread;
+   VCOS_SEMAPHORE_T spare_sema;
+   VCOS_SEMAPHORE_T queue_sema;
+   VCOS_EVENT_T wake_event;
+   int quit;
+
+   unsigned int num_area;
+   uint8_t *mem[MAX_NUM_MEMORY_AREAS];    /**< Base address of memory areas */
+   uint8_t *buffer[MAX_NUM_MEMORY_AREAS]; /**< When queued for writing, pointer to start of valid cache area */
+   size_t size[MAX_NUM_MEMORY_AREAS];     /**< When queued for writing, size of valid area to write */
+   unsigned int cur_area;
+
+   unsigned char stack[3000];
+   int error;
+
+   int stats_enable;
+   VC_CONTAINER_WRITE_STATS_T stats;
+
+} VC_CONTAINER_IO_ASYNC_T;
+
+/*****************************************************************************/
+static void async_io_stats_initialise( struct VC_CONTAINER_IO_ASYNC_T *ctx, int enable )
+{
+   ctx->stats_enable = enable;
+   stats_initialise(&ctx->stats.write, 8);
+   stats_initialise(&ctx->stats.wait, 0);
+   stats_initialise(&ctx->stats.flush, 0);
+}
+
+static void async_io_stats_get( struct VC_CONTAINER_IO_ASYNC_T *ctx, VC_CONTAINER_WRITE_STATS_T *stats )
+{
+   *stats = ctx->stats;
+}
+
+static void *async_io_thread(VOID *argv)
+{
+   VC_CONTAINER_IO_ASYNC_T *ctx = argv;
+   unsigned int write_area = 0;
+
+   while (1)
+   {
+      unsigned long time = 0;
+
+      vcos_event_wait(&ctx->wake_event);
+      if(ctx->quit) break;
+
+      while(vcos_semaphore_trywait(&ctx->queue_sema) == VCOS_SUCCESS)
+      {
+         uint8_t *buffer = ctx->buffer[write_area];
+         size_t size = ctx->size[write_area];
+
+         if(ctx->stats_enable)
+            time = vcos_getmicrosecs();
+
+         if(ctx->io->pf_write(ctx->io, buffer, size) != size)
+            ctx->error = 1;
+
+         if(ctx->stats_enable)
+            stats_add_value(&ctx->stats.write, size, vcos_getmicrosecs() - time);
+
+         /* Signal that the write is done */
+         vcos_semaphore_post(&ctx->spare_sema);
+
+         if(++write_area == ctx->num_area)
+            write_area = 0;
+      }
+   }
+
+   return NULL;
+}
+
+static int async_io_write( VC_CONTAINER_IO_ASYNC_T *ctx, VC_CONTAINER_IO_PRIVATE_CACHE_T *cache )
+{
+   unsigned long time = 0;
+   unsigned int offset;
+
+   if(ctx->stats_enable)
+      time = vcos_getmicrosecs();
+
+   /* post the current area */
+   ctx->buffer[ctx->cur_area] = cache->buffer;
+   ctx->size[ctx->cur_area] = cache->size;
+   vcos_semaphore_post(&ctx->queue_sema);
+   vcos_event_signal(&ctx->wake_event);
+
+   /* now we need to grab another area */
+   vcos_semaphore_wait(&ctx->spare_sema);
+   if(++ctx->cur_area == ctx->num_area)
+      ctx->cur_area = 0;
+
+   if(ctx->stats_enable)
+      stats_add_value(&ctx->stats.wait, 1, vcos_getmicrosecs() - time);
+
+   /* alter cache mem to point to the new cur_area */
+   offset = cache->buffer - cache->mem;
+   cache->mem = ctx->mem[ctx->cur_area];
+   cache->buffer = cache->mem + offset;
+   cache->buffer_end = cache->mem + cache->mem_size;
+
+   return ctx->error ? 0 : cache->size;
+}
+
+static VC_CONTAINER_STATUS_T async_io_wait_complete( struct VC_CONTAINER_IO_ASYNC_T *ctx,
+                                                     VC_CONTAINER_IO_PRIVATE_CACHE_T *cache, int complete )
+{
+   unsigned int time = 0;
+
+   if(ctx->stats_enable)
+      time = vcos_getmicrosecs();
+
+   if(complete)
+   {
+      int num;
+      /* Need to make sure that all memory areas have been written out, so should have num-1 spare */
+      for(num=0; num<ctx->num_area-1; num++)
+         vcos_semaphore_wait(&ctx->spare_sema);
+
+      for(num=0; num<ctx->num_area-1; num++)
+         vcos_semaphore_post(&ctx->spare_sema);
+   }
+   else
+   {
+      /* Need to make sure we can acquire one memory area */
+      vcos_semaphore_wait(&ctx->spare_sema);
+      vcos_semaphore_post(&ctx->spare_sema);
+   }
+   
+   if(ctx->stats_enable)
+      stats_add_value(&ctx->stats.flush, 1, vcos_getmicrosecs() - time);
+
+   return ctx->error ? VC_CONTAINER_ERROR_FAILED : VC_CONTAINER_SUCCESS;
+}
+
+static VC_CONTAINER_IO_ASYNC_T *async_io_start( VC_CONTAINER_IO_T *io, int num_areas, VC_CONTAINER_STATUS_T *status )
+{
+   VC_CONTAINER_IO_ASYNC_T *ctx = 0;
+   VCOS_UNSIGNED pri = 0;
+
+   /* Allocate our context  */
+   ctx = malloc(sizeof(*ctx));
+   if(!ctx) goto error_spare_sema;
+   memset(ctx, 0, sizeof(*ctx));
+   ctx->io = io;
+
+   ctx->mem[0] = io->priv->cache->mem;
+
+   for(ctx->num_area = 1; ctx->num_area < num_areas; ctx->num_area++)
+   {
+      ctx->mem[ctx->num_area] = malloc(io->priv->cache->mem_size);
+      if(!ctx->mem[ctx->num_area])
+         break;
+   }
+
+   if(ctx->num_area == 1) // no real benefit in asynchronous writes
+      goto error_spare_sema;
+
+   async_io_stats_initialise(ctx, 0);
+
+   if(vcos_semaphore_create(&ctx->spare_sema, "async_spare_sem", ctx->num_area-1) != VCOS_SUCCESS)
+      goto error_spare_sema;
+
+   if(vcos_semaphore_create(&ctx->queue_sema, "async_queue_sem", 0) != VCOS_SUCCESS)
+      goto error_queue_sema;
+
+   if (vcos_event_create(&ctx->wake_event, "async_wake_event") != VCOS_SUCCESS)
+      goto error_event;
+
+   // run this thread at a slightly higher priority than the calling thread - that means that
+   // we prefer to write to the SD card rather than filling the memory buffer.
+   pri = vcos_thread_get_priority(vcos_thread_current());
+   if(vcos_thread_create_classic(&ctx->thread, "async_io", async_io_thread, ctx,
+         ctx->stack, sizeof(ctx->stack), pri-1, 10, VCOS_START) != VCOS_SUCCESS)
+      goto error_thread;
+
+   if(status) *status = VC_CONTAINER_SUCCESS;
+   return ctx;
+
+ error_thread:
+   vcos_event_delete(&ctx->wake_event);
+ error_event:
+   vcos_semaphore_delete(&ctx->queue_sema);
+ error_queue_sema:
+   vcos_semaphore_delete(&ctx->spare_sema);
+ error_spare_sema:
+   if(ctx) free(ctx);
+   if(status) *status = VC_CONTAINER_ERROR_FAILED;
+   return 0;
+}
+
+static VC_CONTAINER_STATUS_T async_io_stop( VC_CONTAINER_IO_ASYNC_T *ctx )
+{
+   /* Block if a write operation is already in progress */
+   //vcos_semaphore_wait(&ctx->sema);
+   // XXX block until all done
+
+   ctx->quit = 1;
+   vcos_event_signal(&ctx->wake_event);
+   vcos_thread_join(&ctx->thread,NULL);
+   vcos_event_delete(&ctx->wake_event);
+   vcos_semaphore_delete(&ctx->queue_sema);
+   vcos_semaphore_delete(&ctx->spare_sema);
+
+   while(ctx->num_area > 0)
+      free(ctx->mem[--ctx->num_area]);
+
+   free(ctx);
+   return VC_CONTAINER_SUCCESS;
+}
+#else
+
+static struct VC_CONTAINER_IO_ASYNC_T *async_io_start( VC_CONTAINER_IO_T *io, int num_areas, VC_CONTAINER_STATUS_T *status )
+{
+   VC_CONTAINER_PARAM_UNUSED(io);
+   VC_CONTAINER_PARAM_UNUSED(num_areas);
+   if(status) *status = VC_CONTAINER_ERROR_FAILED;
+   return 0;
+}
+
+static int async_io_write( struct VC_CONTAINER_IO_ASYNC_T *ctx, VC_CONTAINER_IO_PRIVATE_CACHE_T *cache )
+{
+   VC_CONTAINER_PARAM_UNUSED(ctx);
+   VC_CONTAINER_PARAM_UNUSED(cache);
+   return 0;
+}
+
+static VC_CONTAINER_STATUS_T async_io_wait_complete( struct VC_CONTAINER_IO_ASYNC_T *ctx,
+                                                     VC_CONTAINER_IO_PRIVATE_CACHE_T *cache, int complete )
+{
+   VC_CONTAINER_PARAM_UNUSED(ctx);
+   VC_CONTAINER_PARAM_UNUSED(cache);
+   VC_CONTAINER_PARAM_UNUSED(complete);
+   return 0;
+}
+
+static VC_CONTAINER_STATUS_T async_io_stop( struct VC_CONTAINER_IO_ASYNC_T *ctx )
+{
+   VC_CONTAINER_PARAM_UNUSED(ctx);
+   return VC_CONTAINER_SUCCESS;
+}
+
+static void async_io_stats_initialise( struct VC_CONTAINER_IO_ASYNC_T *ctx, int enable )
+{
+   VC_CONTAINER_PARAM_UNUSED(ctx);
+   VC_CONTAINER_PARAM_UNUSED(enable);
+}
+
+static void async_io_stats_get( struct VC_CONTAINER_IO_ASYNC_T *ctx, VC_CONTAINER_WRITE_STATS_T *stats )
+{
+   VC_CONTAINER_PARAM_UNUSED(ctx);
+   VC_CONTAINER_PARAM_UNUSED(stats);
+}
+
+
+#endif
diff --git a/containers/core/containers_io.h b/containers/core/containers_io.h
new file mode 100755 (executable)
index 0000000..8cd4407
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef VC_CONTAINERS_IO_H
+#define VC_CONTAINERS_IO_H
+
+/** \file containers_io.h
+ * Interface definition for the input / output abstraction layer used by container
+ * readers and writers */
+#include "containers/containers.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup VcContainerIoApi Container I/O API */
+/* @{ */
+
+/** Container io opening mode.
+ * This is used to specify whether a reader or writer is requested.
+ */
+typedef enum {
+   VC_CONTAINER_IO_MODE_READ = 0,  /**< Container io opened in reading mode */
+   VC_CONTAINER_IO_MODE_WRITE = 1  /**< Container io opened in writing mode */
+} VC_CONTAINER_IO_MODE_T;
+
+/** \name Container I/O Capabilities
+ * The following flags are exported by container i/o modules to describe their capabilities */
+/* @{ */
+/** Type definition for container I/O capabilities */
+typedef uint32_t VC_CONTAINER_IO_CAPABILITIES_T;
+/** Seeking is not supported */
+#define VC_CONTAINER_IO_CAPS_CANT_SEEK    0x1
+/** Seeking is slow and should be avoided */
+#define VC_CONTAINER_IO_CAPS_SEEK_SLOW    0x2
+/** The I/O doesn't provide any caching of the data */
+#define VC_CONTAINER_IO_CAPS_NO_CACHING   0x4
+/* @} */
+
+/** Container Input / Output Context.
+ * This structure defines the context for a container io instance */
+struct VC_CONTAINER_IO_T
+{
+   /** Pointer to information private to the container io instance */
+   struct VC_CONTAINER_IO_PRIVATE_T *priv;
+
+   /** Pointer to information private to the container io module */
+   struct VC_CONTAINER_IO_MODULE_T *module;
+
+   /** Uniform Resource Identifier for the stream to open.
+    * This is a string encoded in UTF-8 which follows the syntax defined in
+    * RFC2396 (http://tools.ietf.org/html/rfc2396). */
+   char *uri;
+
+   /** Pre-parsed URI */
+   struct VC_URI_PARTS_T *uri_parts;
+
+   /** Current offset into the i/o stream */
+   int64_t offset;
+
+   /** Current size of the i/o stream (0 if unknown). This size might grow during the
+    * lifetime of the i/o instance (for instance when doing progressive download). */
+   int64_t size;
+
+   /** Capabilities of the i/o stream */
+   VC_CONTAINER_IO_CAPABILITIES_T capabilities;
+
+   /** Status of the i/o stream */
+   VC_CONTAINER_STATUS_T status;
+
+   /** Maximum size allowed for this i/o stream (0 if unknown). This is used during writing
+    * to limit the size of the stream to below this value. */
+   int64_t max_size;
+
+   /** \note the following list of function pointers should not be used directly.
+    * They defines the interface for implementing container io modules and are filled in
+    * by the container modules themselves. */
+
+   /** \private
+    * Function pointer to close and free all resources allocated by a
+    * container io module */
+   VC_CONTAINER_STATUS_T (*pf_close)(struct VC_CONTAINER_IO_T *io);
+
+   /** \private
+    * Function pointer to read or skip data from container io module */
+   size_t (*pf_read)(struct VC_CONTAINER_IO_T *io, void *buffer, size_t size);
+
+   /** \private
+    * Function pointer to write data to a container io module */
+   size_t (*pf_write)(struct VC_CONTAINER_IO_T *io, const void *buffer, size_t size);
+
+   /** \private
+    * Function pointer to seek into a container io module */
+   VC_CONTAINER_STATUS_T (*pf_seek)(struct VC_CONTAINER_IO_T *io, int64_t offset);
+
+   /** \private
+    * Function pointer to perform a control operation on a container io module */
+   VC_CONTAINER_STATUS_T (*pf_control)(struct VC_CONTAINER_IO_T *io, 
+                                       VC_CONTAINER_CONTROL_T operation, va_list args);
+
+};
+
+/** Opens an i/o stream pointed to by a URI.
+ * This will create an instance of the container i/o module.
+ *
+ * \param  uri         Uniform Resource Identifier pointing to the multimedia container
+ * \param  mode        Mode in which the i/o stream will be opened
+ * \param  status      Returns the status of the operation
+ * \return             If successful, this returns a pointer to the new instance
+ *                     of the i/o module. Returns NULL on failure.
+ */
+VC_CONTAINER_IO_T *vc_container_io_open( const char *uri, VC_CONTAINER_IO_MODE_T mode,
+                                         VC_CONTAINER_STATUS_T *status );
+
+/** Creates an empty i/o stream. The i/o function pointers will have to be set
+ * by the caller before the i/o gets used.
+ * This will create an instance of the container i/o module.
+ *
+ * \param  uri         Uniform Resource Identifier pointing to the multimedia container
+ * \param  mode        Mode in which the i/o stream will be opened
+ * \param  capabilities Flags indicating the capabilities of the i/o
+ * \param  status      Returns the status of the operation
+ * \return             If successful, this returns a pointer to the new instance
+ *                     of the i/o module. Returns NULL on failure.
+ */
+VC_CONTAINER_IO_T *vc_container_io_create( const char *uri, VC_CONTAINER_IO_MODE_T mode,
+                                           VC_CONTAINER_IO_CAPABILITIES_T capabilities,
+                                           VC_CONTAINER_STATUS_T *p_status );
+
+/** Closes an instance of a container i/o module.
+ * \param  context     Pointer to the VC_CONTAINER_IO_T context of the instance to close
+ * \return             VC_CONTAINER_SUCCESS on success.
+ */
+VC_CONTAINER_STATUS_T vc_container_io_close( VC_CONTAINER_IO_T *context );
+
+/** Read data from an i/o stream without advancing the read position within the stream.
+ * \param  context     Pointer to the VC_CONTAINER_IO_T instance to use
+ * \param  buffer      Pointer to the buffer where the data will be read
+ * \param  size        Number of bytes to read
+ * \return             The size of the data actually read.
+ */
+size_t vc_container_io_peek(VC_CONTAINER_IO_T *context, void *buffer, size_t size);
+
+/** Read data from an i/o stream.
+ * \param  context     Pointer to the VC_CONTAINER_IO_T instance to use
+ * \param  buffer      Pointer to the buffer where the data will be read
+ * \param  size        Number of bytes to read
+ * \return             The size of the data actually read.
+ */
+size_t vc_container_io_read(VC_CONTAINER_IO_T *context, void *buffer, size_t size);
+
+/** Skip data in an i/o stream without reading it.
+ * \param  context     Pointer to the VC_CONTAINER_IO_T instance to use
+ * \param  size        Number of bytes to skip
+ * \return             The size of the data actually skipped.
+ */
+size_t vc_container_io_skip(VC_CONTAINER_IO_T *context, size_t size);
+
+/** Write data to an i/o stream.
+ * \param  context     Pointer to the VC_CONTAINER_IO_T instance to use
+ * \param  buffer      Pointer to the buffer containing the data to write
+ * \param  size        Number of bytes to write
+ * \return             The size of the data actually written.
+ */
+size_t vc_container_io_write(VC_CONTAINER_IO_T *context, const void *buffer, size_t size);
+
+/** Seek into an i/o stream.
+ * \param  context     Pointer to the VC_CONTAINER_IO_T instance to use
+ * \param  offset      Absolute file offset to seek to
+ * \return             Status of the operation
+ */
+VC_CONTAINER_STATUS_T vc_container_io_seek(VC_CONTAINER_IO_T *context, int64_t offset);
+
+/** Perform control operation on an i/o stream (va_list).
+ * \param  context     Pointer to the VC_CONTAINER_IO_T instance to use
+ * \param  operation   Control operation to be performed
+ * \param  args        Additional arguments for the operation
+ * \return             Status of the operation
+ */
+VC_CONTAINER_STATUS_T vc_container_io_control_list(VC_CONTAINER_IO_T *context, 
+                                                   VC_CONTAINER_CONTROL_T operation, va_list args);
+
+/** Perform control operation on an i/o stream (varargs).
+ * \param  context     Pointer to the VC_CONTAINER_IO_T instance to use
+ * \param  operation   Control operation to be performed
+ * \param  ...         Additional arguments for the operation
+ * \return             Status of the operation
+ */
+VC_CONTAINER_STATUS_T vc_container_io_control(VC_CONTAINER_IO_T *context, 
+                                                VC_CONTAINER_CONTROL_T operation, ...);
+
+/** Cache the pointed region of the i/o stream (from current position).
+ * This will allow future seeking into the specified region even on non-seekable streams.
+ * \param  context     Pointer to the VC_CONTAINER_IO_T instance to use
+ * \param  size        Size of the region to cache
+ * \return             Status of the operation
+ */
+size_t vc_container_io_cache(VC_CONTAINER_IO_T *context, size_t size);
+
+/* @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* VC_CONTAINERS_HELPERS_H */
diff --git a/containers/core/containers_io_helpers.c b/containers/core/containers_io_helpers.c
new file mode 100755 (executable)
index 0000000..88e08cc
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_logging.h"
+
+void vc_container_helper_format_debug(VC_CONTAINER_T *ctx, int indent, const char *format, ...)
+{
+   char debug_string[512];
+   va_list args;
+   int result;
+
+   if(indent >= (int)sizeof(debug_string)) return;
+   memset(debug_string, ' ', indent);
+
+   va_start( args, format );
+   result = vsnprintf(debug_string + indent, sizeof(debug_string) - indent, format, args);
+   va_end( args );
+
+   if(result <= 0) return;
+
+   vc_container_log(ctx, VC_CONTAINER_LOG_FORMAT, debug_string);
+   fflush(0);
+}
+
+uint64_t vc_container_helper_int_debug(VC_CONTAINER_T *ctx, int type, uint64_t value, const char *name, int indent)
+{
+   VC_CONTAINER_PARAM_UNUSED(ctx);
+
+   if(type == LOG_FORMAT_TYPE_HEX)
+      vc_container_helper_format_debug(ctx, indent, "%s: 0x%"PRIx64, name, value);
+   else
+      vc_container_helper_format_debug(ctx, indent, "%s: %"PRIi64, name, value);
+   return value;
+}
+
+uint64_t vc_container_helper_read_debug(VC_CONTAINER_T *ctx, int type, int size,
+   const char *name, uint8_t *buffer, int indent, int b_skip)
+{
+   int64_t offset = STREAM_POSITION(ctx);
+   uint64_t value = 0;
+   GUID_T guid;
+
+   if(type == LOG_FORMAT_TYPE_STRING ||
+      type == LOG_FORMAT_TYPE_STRING_UTF16_LE ||
+      type == LOG_FORMAT_TYPE_STRING_UTF16_BE)
+   {
+      uint8_t stringbuf[256];
+      char utf8buf[256];
+      int stringsize = sizeof(stringbuf) - 2;
+
+      if(!buffer)
+      {
+         buffer = stringbuf;
+         if(size < stringsize) stringsize = size;
+      }
+      else stringsize = size;
+
+      value = vc_container_io_read(ctx->priv->io, buffer, stringsize);
+
+      if(!utf8_from_charset(type == LOG_FORMAT_TYPE_STRING ? "UTF8" : "UTF16-LE",
+            utf8buf, sizeof(utf8buf), buffer, stringsize))
+         vc_container_helper_format_debug(ctx, indent, "%s: \"%s\"", name, utf8buf);
+      else
+         vc_container_helper_format_debug(ctx, indent, "%s: (could not read)", name);
+
+      if(size - stringsize)
+         value += vc_container_io_skip(ctx->priv->io, size - stringsize);
+      return value;
+   }
+
+   if(type == LOG_FORMAT_TYPE_UINT_LE)
+   {
+      switch(size)
+      {
+      case 1: value = vc_container_io_read_uint8(ctx->priv->io);  break;
+      case 2: value = vc_container_io_read_le_uint16(ctx->priv->io); break;
+      case 3: value = vc_container_io_read_le_uint24(ctx->priv->io); break;
+      case 4: value = vc_container_io_read_le_uint32(ctx->priv->io); break;
+      case 5: value = vc_container_io_read_le_uint40(ctx->priv->io); break;
+      case 6: value = vc_container_io_read_le_uint48(ctx->priv->io); break;
+      case 7: value = vc_container_io_read_le_uint56(ctx->priv->io); break;
+      case 8: value = vc_container_io_read_le_uint64(ctx->priv->io); break;
+      }
+   }
+   else if(type == LOG_FORMAT_TYPE_UINT_BE)
+   {
+      switch(size)
+      {
+      case 1: value = vc_container_io_read_uint8(ctx->priv->io);  break;
+      case 2: value = vc_container_io_read_be_uint16(ctx->priv->io); break;
+      case 3: value = vc_container_io_read_be_uint24(ctx->priv->io); break;
+      case 4: value = vc_container_io_read_be_uint32(ctx->priv->io); break;
+      case 5: value = vc_container_io_read_be_uint40(ctx->priv->io); break;
+      case 6: value = vc_container_io_read_be_uint48(ctx->priv->io); break;
+      case 7: value = vc_container_io_read_be_uint56(ctx->priv->io); break;
+      case 8: value = vc_container_io_read_be_uint64(ctx->priv->io); break;
+      }
+   }
+   else if(type == LOG_FORMAT_TYPE_FOURCC)
+   {
+      value = vc_container_io_read_fourcc(ctx->priv->io);
+   }
+   else if(type == LOG_FORMAT_TYPE_GUID)
+   {
+      value = vc_container_io_read(ctx->priv->io, &guid, 16);
+   }
+   else
+   {
+      vc_container_assert(0);
+      return 0;
+   }
+
+   if(type == LOG_FORMAT_TYPE_GUID)
+   {
+      if(value == 16)
+      {
+      vc_container_helper_format_debug(ctx, indent, "%s: 0x%x-0x%x-0x%x-0x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
+            name, guid.word0, guid.short0, guid.short1,
+            guid.bytes[0], guid.bytes[1], guid.bytes[2], guid.bytes[3],
+            guid.bytes[4], guid.bytes[5], guid.bytes[6], guid.bytes[7]);
+      if(buffer) memcpy(buffer, &guid, sizeof(guid));
+      }
+   }
+   else if(type == LOG_FORMAT_TYPE_FOURCC)
+   {
+      uint32_t val = value;
+      vc_container_helper_format_debug(ctx, indent, "%s: %4.4s", name, (char *)&val);
+   }
+   else
+   {
+      vc_container_helper_format_debug(ctx, indent, "%s: %"PRIi64, name, value);
+   }
+
+   if(b_skip) value = (STREAM_POSITION(ctx) - offset) != size;
+   return value;
+}
+
+VC_CONTAINER_STATUS_T vc_container_helper_write_debug(VC_CONTAINER_T *ctx, int type, int size,
+   const char *name, uint64_t value, const uint8_t *buffer, int indent, int silent)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+
+   if(type == LOG_FORMAT_TYPE_STRING)
+   {
+      value = vc_container_io_write(ctx->priv->io, buffer, size);
+      if(!silent)
+         vc_container_helper_format_debug(ctx, indent, "%s: \"%ls\"", name, buffer);
+      return value == (uint64_t)size ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FAILED;
+   }
+
+   if(type == LOG_FORMAT_TYPE_UINT_LE)
+   {
+      switch(size)
+      {
+      case 1: status = vc_container_io_write_uint8(ctx->priv->io, (uint8_t)value);  break;
+      case 2: status = vc_container_io_write_le_uint16(ctx->priv->io, (uint16_t)value); break;
+      case 3: status = vc_container_io_write_le_uint24(ctx->priv->io, (uint32_t)value); break;
+      case 4: status = vc_container_io_write_le_uint32(ctx->priv->io, (uint32_t)value); break;
+      case 8: status = vc_container_io_write_le_uint64(ctx->priv->io, value); break;
+      }
+   }
+   else if(type == LOG_FORMAT_TYPE_UINT_BE)
+   {
+      switch(size)
+      {
+      case 1: status = vc_container_io_write_uint8(ctx->priv->io, (uint8_t)value);  break;
+      case 2: status = vc_container_io_write_be_uint16(ctx->priv->io, (uint16_t)value); break;
+      case 3: status = vc_container_io_write_be_uint24(ctx->priv->io, (uint32_t)value); break;
+      case 4: status = vc_container_io_write_be_uint32(ctx->priv->io, (uint32_t)value); break;
+      case 8: status = vc_container_io_write_be_uint64(ctx->priv->io, value); break;
+      }
+   }
+   else if(type == LOG_FORMAT_TYPE_FOURCC)
+   {
+      status = vc_container_io_write_fourcc(ctx->priv->io, (uint32_t)value);
+   }  
+   else if(type == LOG_FORMAT_TYPE_GUID)
+   {
+      value = vc_container_io_write(ctx->priv->io, buffer, 16);
+   }
+   else
+   {
+      vc_container_assert(0);
+      return 0;
+   }
+
+   if(status)
+   {
+      vc_container_helper_format_debug(ctx, indent, "write failed for %s", name);
+      return status;
+   }
+
+   if(!silent)
+   {
+      if (type == LOG_FORMAT_TYPE_FOURCC)
+      {
+         vc_container_helper_format_debug(ctx, indent, "%s: %4.4s", name, (char *)&value);
+      }
+      else if(type == LOG_FORMAT_TYPE_GUID)
+      {
+         GUID_T guid;
+         memcpy(&guid, buffer, sizeof(guid));
+         vc_container_helper_format_debug(ctx, indent, "%s: 0x%x-0x%x-0x%x-0x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
+               name, guid.word0, guid.short0, guid.short1,
+               guid.bytes[0], guid.bytes[1], guid.bytes[2], guid.bytes[3],
+               guid.bytes[4], guid.bytes[5], guid.bytes[6], guid.bytes[7]);
+      }
+      else
+      {
+         vc_container_helper_format_debug(ctx, indent, "%s: %"PRIi64, name, value);
+      }
+   }
+
+   return status;
+}
diff --git a/containers/core/containers_io_helpers.h b/containers/core/containers_io_helpers.h
new file mode 100755 (executable)
index 0000000..1f9b460
--- /dev/null
@@ -0,0 +1,716 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef VC_CONTAINERS_IO_HELPERS_H
+#define VC_CONTAINERS_IO_HELPERS_H
+
+/** \file containers_io_helpers.h
+ * Helper functions and macros which provide functionality which is often used by containers
+ */
+
+#include "containers/core/containers_io.h"
+#include "containers/core/containers_utils.h"
+
+/*****************************************************************************
+ * Helper inline functions to read integers from an i/o stream
+ *****************************************************************************/
+
+/** Reads an unsigned 8 bits integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint8_t vc_container_io_read_uint8(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value;
+   size_t ret = vc_container_io_read(io, &value, 1);
+   return ret == 1 ? value : 0;
+}
+
+/** Reads a FOURCC from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The FOURCC to read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE VC_CONTAINER_FOURCC_T vc_container_io_read_fourcc(VC_CONTAINER_IO_T *io)
+{
+   VC_CONTAINER_FOURCC_T value;
+   size_t ret = vc_container_io_read(io, (int8_t *)&value, 4);
+   return ret == 4 ? value : 0;
+}
+
+/** Reads an unsigned 16 bits big endian integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint16_t vc_container_io_read_be_uint16(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value[2];
+   size_t ret = vc_container_io_read(io, value, 2);
+   return ret == 2 ? (value[0] << 8) | value[1] : 0;
+}
+
+/** Reads an unsigned 24 bits big endian integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint32_t vc_container_io_read_be_uint24(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value[3];
+   size_t ret = vc_container_io_read(io, value, 3);
+   return ret == 3 ? (value[0] << 16) | (value[1] << 8) | value[2] : 0;
+}
+
+/** Reads an unsigned 32 bits big endian integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint32_t vc_container_io_read_be_uint32(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value[4];
+   size_t ret = vc_container_io_read(io, value, 4);
+   return ret == 4 ? (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | value[3] : 0;
+}
+
+/** Reads an unsigned 40 bits big endian integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint64_t vc_container_io_read_be_uint40(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value[5];
+   uint32_t value1, value2;
+   size_t ret = vc_container_io_read(io, value, 5);
+
+   value1 = (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | value[3];
+   value2 = value[4];
+
+   return ret == 5 ? (((uint64_t)value1) << 8)|value2 : 0;
+}
+
+/** Reads an unsigned 48 bits big endian integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint64_t vc_container_io_read_be_uint48(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value[6];
+   uint32_t value1, value2;
+   size_t ret = vc_container_io_read(io, value, 6);
+
+   value1 = (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | value[3];
+   value2 = (value[4] << 8) | value[5];
+
+   return ret == 6 ? (((uint64_t)value1) << 16)|value2 : 0;
+}
+
+/** Reads an unsigned 56 bits big endian integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint64_t vc_container_io_read_be_uint56(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value[7];
+   uint32_t value1, value2;
+   size_t ret = vc_container_io_read(io, value, 7);
+
+   value1 = (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | value[3];
+   value2 = (value[4] << 16) | (value[5] << 8) | value[6];
+
+   return ret == 7 ? (((uint64_t)value1) << 24)|value2 : 0;
+}
+
+/** Reads an unsigned 64 bits big endian integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint64_t vc_container_io_read_be_uint64(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value[8];
+   uint32_t value1, value2;
+   size_t ret = vc_container_io_read(io, value, 8);
+
+   value1 = (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | value[3];
+   value2 = (value[4] << 24) | (value[5] << 16) | (value[6] << 8) | value[7];
+
+   return ret == 8 ? (((uint64_t)value1) << 32)|value2 : 0;
+}
+
+/** Reads an unsigned 16 bits little endian integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint16_t vc_container_io_read_le_uint16(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value[2];
+   size_t ret = vc_container_io_read(io, value, 2);
+   return ret == 2 ? (value[1] << 8) | value[0] : 0;
+}
+
+/** Reads an unsigned 24 bits little endian integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint32_t vc_container_io_read_le_uint24(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value[3];
+   size_t ret = vc_container_io_read(io, value, 3);
+   return ret == 3 ? (value[2] << 16) | (value[1] << 8) | value[0] : 0;
+}
+
+/** Reads an unsigned 32 bits little endian integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint32_t vc_container_io_read_le_uint32(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value[4];
+   size_t ret = vc_container_io_read(io, value, 4);
+   return ret == 4 ? (value[3] << 24) | (value[2] << 16) | (value[1] << 8) | value[0] : 0;
+}
+
+/** Reads an unsigned 40 bits little endian integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint64_t vc_container_io_read_le_uint40(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value[5];
+   uint32_t value1, value2;
+   size_t ret = vc_container_io_read(io, value, 5);
+
+   value1 = (value[3] << 24) | (value[2] << 16) | (value[1] << 8) | value[0];
+   value2 = value[4];
+
+   return ret == 5 ? (((uint64_t)value2) << 32)|value1 : 0;
+}
+
+/** Reads an unsigned 48 bits little endian integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint64_t vc_container_io_read_le_uint48(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value[6];
+   uint32_t value1, value2;
+   size_t ret = vc_container_io_read(io, value, 6);
+
+   value1 = (value[3] << 24) | (value[2] << 16) | (value[1] << 8) | value[0];
+   value2 = (value[5] << 8) | value[4];
+
+   return ret == 6 ? (((uint64_t)value2) << 32)|value1 : 0;
+}
+
+/** Reads an unsigned 56 bits little endian integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint64_t vc_container_io_read_le_uint56(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value[7];
+   uint32_t value1, value2;
+   size_t ret = vc_container_io_read(io, value, 7);
+
+   value1 = (value[3] << 24) | (value[2] << 16) | (value[1] << 8) | value[0];
+   value2 = (value[6] << 16) | (value[5] << 8) | value[4];
+
+   return ret == 7 ? (((uint64_t)value2) << 32)|value1 : 0;
+}
+
+/** Reads an unsigned 64 bits little endian integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint64_t vc_container_io_read_le_uint64(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value[8];
+   uint32_t value1, value2;
+   size_t ret = vc_container_io_read(io, value, 8);
+
+   value1 = (value[3] << 24) | (value[2] << 16) | (value[1] << 8) | value[0];
+   value2 = (value[7] << 24) | (value[6] << 16) | (value[5] << 8) | value[4];
+
+   return ret == 8 ? (((uint64_t)value2) << 32)|value1 : 0;
+}
+
+/*****************************************************************************
+ * Helper inline functions to peek integers from an i/o stream
+ *****************************************************************************/
+
+/** Peeks an unsigned 8 bits integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint8_t vc_container_io_peek_uint8(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value;
+   size_t ret = vc_container_io_peek(io, &value, 1);
+   return ret == 1 ? value : 0;
+}
+
+/** Peeks an unsigned 16 bits big endian integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint16_t vc_container_io_peek_be_uint16(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value[2];
+   size_t ret = vc_container_io_peek(io, value, 2);
+   return ret == 2 ? (value[0] << 8) | value[1] : 0;
+}
+
+/** Peeks an unsigned 24 bits big endian integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint32_t vc_container_io_peek_be_uint24(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value[3];
+   size_t ret = vc_container_io_peek(io, value, 3);
+   return ret == 3 ? (value[0] << 16) | (value[1] << 8) | value[2] : 0;
+}
+
+/** Peeks an unsigned 32 bits big endian integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint32_t vc_container_io_peek_be_uint32(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value[4];
+   size_t ret = vc_container_io_peek(io, value, 4);
+   return ret == 4 ? (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | value[3] : 0;
+}
+
+/** Peeks an unsigned 64 bits big endian integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint64_t vc_container_io_peek_be_uint64(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value[8];
+   uint32_t value1, value2;
+   size_t ret = vc_container_io_peek(io, value, 8);
+
+   value1 = (value[0] << 24) | (value[1] << 16) | (value[2] << 8) | value[3];
+   value2 = (value[4] << 24) | (value[5] << 16) | (value[6] << 8) | value[7];
+
+   return ret == 8 ? (((uint64_t)value1) << 32)|value2 : 0;
+}
+
+/** Peeks an unsigned 16 bits little endian integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint16_t vc_container_io_peek_le_uint16(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value[2];
+   size_t ret = vc_container_io_peek(io, value, 2);
+   return ret == 2 ? (value[1] << 8) | value[0] : 0;
+}
+
+/** Peeks an unsigned 24 bits little endian integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint32_t vc_container_io_peek_le_uint24(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value[3];
+   size_t ret = vc_container_io_peek(io, value, 3);
+   return ret == 3 ? (value[2] << 16) | (value[1] << 8) | value[0] : 0;
+}
+
+/** Peeks an unsigned 32 bits little endian integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint32_t vc_container_io_peek_le_uint32(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value[4];
+   size_t ret = vc_container_io_peek(io, value, 4);
+   return ret == 4 ? (value[3] << 24) | (value[2] << 16) | (value[1] << 8) | value[0] : 0;
+}
+
+/** Peeks an unsigned 64 bits little endian integer from an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \return             The integer read. In case of failure during the read,
+ *                     this will return a value of 0.
+ */
+STATIC_INLINE uint64_t vc_container_io_peek_le_uint64(VC_CONTAINER_IO_T *io)
+{
+   uint8_t value[8];
+   uint32_t value1, value2;
+   size_t ret = vc_container_io_peek(io, value, 8);
+
+   value1 = (value[3] << 24) | (value[2] << 16) | (value[1] << 8) | value[0];
+   value2 = (value[7] << 24) | (value[6] << 16) | (value[5] << 8) | value[4];
+
+   return ret == 8 ? (((uint64_t)value2) << 32)|value1 : 0;
+}
+
+/*****************************************************************************
+ * Helper inline functions to write integers to an i/o stream
+ *****************************************************************************/
+
+/** Writes an unsigned 8 bits integer to an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \param  value       The integer to write.
+ * \return             The status of the operation.
+ */
+STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_io_write_uint8(VC_CONTAINER_IO_T *io, uint8_t value)
+{
+   size_t ret = vc_container_io_write(io, &value, 1);
+   return ret == 1 ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FAILED;
+}
+
+/** Writes a FOURCC to an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \param  value       The FOURCC to write.
+ * \return             The status of the operation.
+ */
+STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_io_write_fourcc(VC_CONTAINER_IO_T *io, VC_CONTAINER_FOURCC_T value)
+{
+   size_t ret = vc_container_io_write(io, (uint8_t *)&value, 4);
+   return ret == 4 ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FAILED;
+}
+
+/** Writes an unsigned 16 bits big endian integer to an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \param  value       The integer to write.
+ * \return             The status of the operation.
+ */
+STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_io_write_be_uint16(VC_CONTAINER_IO_T *io, uint16_t value)
+{
+   uint8_t bytes[2] = {(uint8_t)(value >> 8), (uint8_t)value};
+   size_t ret = vc_container_io_write(io, bytes, 2);
+   return ret == 2 ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FAILED;
+}
+
+/** Writes an unsigned 24 bits big endian integer to an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \param  value       The integer to write.
+ * \return             The status of the operation.
+ */
+STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_io_write_be_uint24(VC_CONTAINER_IO_T *io, uint32_t value)
+{
+   uint8_t bytes[3] = {(uint8_t)(value >> 16), (uint8_t)(value >> 8), (uint8_t)value};
+   size_t ret = vc_container_io_write(io, bytes, 3);
+   return ret == 3 ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FAILED;
+}
+
+/** Writes an unsigned 32 bits big endian integer to an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \param  value       The integer to write.
+ * \return             The status of the operation.
+ */
+STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_io_write_be_uint32(VC_CONTAINER_IO_T *io, uint32_t value)
+{
+   uint8_t bytes[4] = {value >> 24, value >> 16, value >> 8, value};
+   size_t ret = vc_container_io_write(io, bytes, 4);
+   return ret == 4 ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FAILED;
+}
+
+/** Writes an unsigned 64 bits big endian integer to an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \param  value       The integer to write.
+ * \return             The status of the operation.
+ */
+STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_io_write_be_uint64(VC_CONTAINER_IO_T *io, uint64_t value)
+{
+   uint8_t bytes[8] =
+   {
+      (uint8_t)(value >> 56),
+      (uint8_t)(value >> 48),
+      (uint8_t)(value >> 40),
+      (uint8_t)(value >> 32),
+      (uint8_t)(value >> 24),
+      (uint8_t)(value >> 16),
+      (uint8_t)(value >> 8),
+      (uint8_t) value
+   };
+   size_t ret = vc_container_io_write(io, bytes, 8);
+   return ret == 8 ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FAILED;
+}
+
+/** Writes an unsigned 16 bits little endian integer to an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \param  value       The integer to write.
+ * \return             The status of the operation.
+ */
+STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_io_write_le_uint16(VC_CONTAINER_IO_T *io, uint16_t value)
+{
+   uint8_t bytes[2] = {(uint8_t)value, (uint8_t)(value >> 8)};
+   size_t ret = vc_container_io_write(io, bytes, 2);
+   return ret == 2 ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FAILED;
+}
+
+/** Writes an unsigned 24 bits little endian integer to an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \param  value       The integer to write.
+ * \return             The status of the operation.
+ */
+STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_io_write_le_uint24(VC_CONTAINER_IO_T *io, uint32_t value)
+{
+   uint8_t bytes[3] = {value, value >> 8, value >> 16};
+   size_t ret = vc_container_io_write(io, bytes, 3);
+   return ret == 3 ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FAILED;
+}
+
+/** Writes an unsigned 32 bits little endian integer to an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \param  value       The integer to write.
+ * \return             The status of the operation.
+ */
+STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_io_write_le_uint32(VC_CONTAINER_IO_T *io, uint32_t value)
+{
+   uint8_t bytes[4] = {value, value >> 8, value >> 16, value >> 24};
+   size_t ret = vc_container_io_write(io, bytes, 4);
+   return ret == 4 ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FAILED;
+}
+
+/** Writes an unsigned 64 bits little endian integer to an i/o stream.
+ * \param  io          Pointer to the VC_CONTAINER_IO_T instance to use
+ * \param  value       The integer to write.
+ * \return             The status of the operation.
+ */
+STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_io_write_le_uint64(VC_CONTAINER_IO_T *io, uint64_t value)
+{
+   uint8_t bytes[8] =
+   {
+      (uint8_t) value,
+      (uint8_t)(value >> 8),
+      (uint8_t)(value >> 16),
+      (uint8_t)(value >> 24),
+      (uint8_t)(value >> 32),
+      (uint8_t)(value >> 40),
+      (uint8_t)(value >> 48),
+      (uint8_t)(value >> 56)
+   };
+   size_t ret = vc_container_io_write(io, bytes, 8);
+   return ret == 8 ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FAILED;
+}
+
+/*****************************************************************************
+ * Helper macros for accessing the i/o stream. These will also call the right
+ * functions depending on the endianness defined.
+ *****************************************************************************/
+
+/** Macro which returns the current position within the stream */
+#define STREAM_POSITION(ctx) (ctx)->priv->io->offset
+/** Macro which returns true if the end of stream has been reached */
+#define STREAM_EOS(ctx) ((ctx)->priv->io->status == VC_CONTAINER_ERROR_EOS)
+/** Macro which returns the status of the stream */
+#define STREAM_STATUS(ctx) (ctx)->priv->io->status
+/** Macro which returns true if an error other than end of stream has occurred */
+#define STREAM_ERROR(ctx) ((ctx)->priv->io->status && (ctx)->priv->io->status != VC_CONTAINER_ERROR_EOS)
+/** Macro which returns true if we can seek into the stream */
+#define STREAM_SEEKABLE(ctx) (!((ctx)->priv->io->capabilities & VC_CONTAINER_IO_CAPS_CANT_SEEK))
+
+#define PEEK_BYTES(ctx, buffer, size) vc_container_io_peek((ctx)->priv->io, buffer, (size_t)(size))
+#define READ_BYTES(ctx, buffer, size) vc_container_io_read((ctx)->priv->io, buffer, (size_t)(size))
+#define SKIP_BYTES(ctx, size) vc_container_io_skip((ctx)->priv->io, (size_t)(size))
+#define SEEK(ctx, off) vc_container_io_seek((ctx)->priv->io, (int64_t)(off))
+#define CACHE_BYTES(ctx, size) vc_container_io_cache((ctx)->priv->io, (size_t)(size))
+
+#define _SKIP_GUID(ctx) vc_container_io_skip((ctx)->priv->io, 16)
+#define _SKIP_U8(ctx)  (vc_container_io_skip((ctx)->priv->io, 1) != 1)
+#define _SKIP_U16(ctx) (vc_container_io_skip((ctx)->priv->io, 2) != 2)
+#define _SKIP_U24(ctx) (vc_container_io_skip((ctx)->priv->io, 3) != 3)
+#define _SKIP_U32(ctx) (vc_container_io_skip((ctx)->priv->io, 4) != 4)
+#define _SKIP_U64(ctx) (vc_container_io_skip((ctx)->priv->io, 8) != 8)
+#define _SKIP_FOURCC(ctx) (vc_container_io_skip((ctx)->priv->io, 4) != 4)
+
+#define _READ_GUID(ctx, buffer) vc_container_io_read((ctx)->priv->io, buffer, 16)
+#define _READ_U8(ctx)  vc_container_io_read_uint8((ctx)->priv->io)
+#define _READ_FOURCC(ctx) vc_container_io_read_fourcc((ctx)->priv->io)
+#define PEEK_GUID(ctx, buffer) vc_container_io_peek((ctx)->priv->io, buffer, 16)
+#define PEEK_U8(ctx)  vc_container_io_peek_uint8((ctx)->priv->io)
+#ifdef CONTAINER_IS_BIG_ENDIAN
+# define _READ_U16(ctx) vc_container_io_read_be_uint16((ctx)->priv->io)
+# define _READ_U24(ctx) vc_container_io_read_be_uint24((ctx)->priv->io)
+# define _READ_U32(ctx) vc_container_io_read_be_uint32((ctx)->priv->io)
+# define _READ_U40(ctx) vc_container_io_read_be_uint40((ctx)->priv->io)
+# define _READ_U48(ctx) vc_container_io_read_be_uint48((ctx)->priv->io)
+# define _READ_U56(ctx) vc_container_io_read_be_uint56((ctx)->priv->io)
+# define _READ_U64(ctx) vc_container_io_read_be_uint64((ctx)->priv->io)
+# define PEEK_U16(ctx) vc_container_io_peek_be_uint16((ctx)->priv->io)
+# define PEEK_U24(ctx) vc_container_io_peek_be_uint24((ctx)->priv->io)
+# define PEEK_U32(ctx) vc_container_io_peek_be_uint32((ctx)->priv->io)
+# define PEEK_U64(ctx) vc_container_io_peek_be_uint64((ctx)->priv->io)
+#else
+# define _READ_U16(ctx) vc_container_io_read_le_uint16((ctx)->priv->io)
+# define _READ_U24(ctx) vc_container_io_read_le_uint24((ctx)->priv->io)
+# define _READ_U32(ctx) vc_container_io_read_le_uint32((ctx)->priv->io)
+# define _READ_U40(ctx) vc_container_io_read_le_uint40((ctx)->priv->io)
+# define _READ_U48(ctx) vc_container_io_read_le_uint48((ctx)->priv->io)
+# define _READ_U56(ctx) vc_container_io_read_le_uint56((ctx)->priv->io)
+# define _READ_U64(ctx) vc_container_io_read_le_uint64((ctx)->priv->io)
+# define PEEK_U16(ctx) vc_container_io_peek_le_uint16((ctx)->priv->io)
+# define PEEK_U24(ctx) vc_container_io_peek_le_uint24((ctx)->priv->io)
+# define PEEK_U32(ctx) vc_container_io_peek_le_uint32((ctx)->priv->io)
+# define PEEK_U64(ctx) vc_container_io_peek_le_uint64((ctx)->priv->io)
+#endif
+
+#define WRITE_BYTES(ctx, buffer, size) vc_container_io_write((ctx)->priv->io, buffer, (size_t)(size))
+#define _WRITE_GUID(ctx, buffer) vc_container_io_write((ctx)->priv->io, buffer, 16)
+#define _WRITE_U8(ctx, v)  vc_container_io_write_uint8((ctx)->priv->io, v)
+#define _WRITE_FOURCC(ctx, v) vc_container_io_write_fourcc((ctx)->priv->io, v)
+#ifdef CONTAINER_IS_BIG_ENDIAN
+# define _WRITE_U16(ctx, v) vc_container_io_write_be_uint16((ctx)->priv->io, v)
+# define _WRITE_U24(ctx, v) vc_container_io_write_be_uint24((ctx)->priv->io, v)
+# define _WRITE_U32(ctx, v) vc_container_io_write_be_uint32((ctx)->priv->io, v)
+# define _WRITE_U64(ctx, v) vc_container_io_write_be_uint64((ctx)->priv->io, v)
+#else
+# define _WRITE_U16(ctx, v) vc_container_io_write_le_uint16((ctx)->priv->io, v)
+# define _WRITE_U24(ctx, v) vc_container_io_write_le_uint24((ctx)->priv->io, v)
+# define _WRITE_U32(ctx, v) vc_container_io_write_le_uint32((ctx)->priv->io, v)
+# define _WRITE_U64(ctx, v) vc_container_io_write_le_uint64((ctx)->priv->io, v)
+#endif
+
+#ifndef CONTAINER_HELPER_LOG_INDENT
+# define CONTAINER_HELPER_LOG_INDENT(a) 0
+#endif
+
+#ifdef CONTAINER_IS_BIG_ENDIAN
+# define LOG_FORMAT_TYPE_UINT LOG_FORMAT_TYPE_UINT_BE
+# define LOG_FORMAT_TYPE_STRING_UTF16 LOG_FORMAT_TYPE_STRING_UTF16_BE
+#else
+# define LOG_FORMAT_TYPE_UINT LOG_FORMAT_TYPE_UINT_LE
+# define LOG_FORMAT_TYPE_STRING_UTF16 LOG_FORMAT_TYPE_STRING_UTF16_LE
+#endif
+
+#ifndef ENABLE_CONTAINERS_LOG_FORMAT
+#define SKIP_GUID(ctx,n) _SKIP_GUID(ctx)
+#define SKIP_U8(ctx,n)  _SKIP_U8(ctx)
+#define SKIP_U16(ctx,n) _SKIP_U16(ctx)
+#define SKIP_U24(ctx,n) _SKIP_U24(ctx)
+#define SKIP_U32(ctx,n) _SKIP_U32(ctx)
+#define SKIP_U64(ctx,n) _SKIP_U64(ctx)
+#define SKIP_FOURCC(ctx,n) _SKIP_FOURCC(ctx)
+#define READ_GUID(ctx,buffer,n) _READ_GUID(ctx,(uint8_t *)buffer)
+#define READ_U8(ctx,n)  _READ_U8(ctx)
+#define READ_U16(ctx,n) _READ_U16(ctx)
+#define READ_U24(ctx,n) _READ_U24(ctx)
+#define READ_U32(ctx,n) _READ_U32(ctx)
+#define READ_U40(ctx,n) _READ_U40(ctx)
+#define READ_U48(ctx,n) _READ_U48(ctx)
+#define READ_U56(ctx,n) _READ_U56(ctx)
+#define READ_U64(ctx,n) _READ_U64(ctx)
+#define READ_FOURCC(ctx,n) _READ_FOURCC(ctx)
+#define READ_STRING(ctx,buffer,sz,n) READ_BYTES(ctx,buffer,sz)
+#define READ_STRING_UTF16(ctx,buffer,sz,n) READ_BYTES(ctx,buffer,sz)
+#define SKIP_STRING(ctx,sz,n) SKIP_BYTES(ctx,sz)
+#define SKIP_STRING_UTF16(ctx,sz,n) SKIP_BYTES(ctx,sz)
+#else
+#define SKIP_GUID(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_GUID, 16, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 1)
+#define SKIP_U8(ctx,n)  vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 1, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 1)
+#define SKIP_U16(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 2, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 1)
+#define SKIP_U24(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 3, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 1)
+#define SKIP_U32(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 4, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 1)
+#define SKIP_U64(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 8, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 1)
+#define SKIP_FOURCC(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_FOURCC, 4, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 1)
+#define READ_GUID(ctx,buffer,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_GUID, 16, n, (uint8_t *)buffer, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
+#define READ_U8(ctx,n)  (uint8_t)vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 1, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
+#define READ_U16(ctx,n) (uint16_t)vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 2, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
+#define READ_U24(ctx,n) (uint32_t)vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 3, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
+#define READ_U32(ctx,n) (uint32_t)vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 4, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
+#define READ_U40(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 5, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
+#define READ_U48(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 6, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
+#define READ_U56(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 7, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
+#define READ_U64(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_UINT, 8, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
+#define READ_FOURCC(ctx,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_FOURCC, 4, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
+#define READ_STRING_UTF16(ctx,buffer,sz,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_STRING_UTF16, sz, n, (uint8_t *)buffer, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
+#define READ_STRING(ctx,buffer,sz,n) vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_STRING, sz, n, (uint8_t *)buffer, CONTAINER_HELPER_LOG_INDENT(ctx), 0)
+#define SKIP_STRING_UTF16(ctx,sz,n)  vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_STRING_UTF16, sz, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 1)
+#define SKIP_STRING(ctx,sz,n)  vc_container_helper_read_debug(ctx, LOG_FORMAT_TYPE_STRING, sz, n, 0, CONTAINER_HELPER_LOG_INDENT(ctx), 1)
+#endif
+
+#ifndef ENABLE_CONTAINERS_LOG_FORMAT
+#define WRITE_GUID(ctx,buffer,n) _WRITE_GUID(ctx,(const uint8_t *)buffer)
+#define WRITE_U8(ctx,v,n) _WRITE_U8(ctx,(uint8_t)(v))
+#define WRITE_FOURCC(ctx,v,n) _WRITE_FOURCC(ctx,(uint32_t)(v))
+#define WRITE_U16(ctx,v,n) _WRITE_U16(ctx,(uint16_t)(v))
+#define WRITE_U24(ctx,v,n) _WRITE_U24(ctx,(uint32_t)(v))
+#define WRITE_U32(ctx,v,n) _WRITE_U32(ctx,(uint32_t)(v))
+#define WRITE_U64(ctx,v,n) _WRITE_U64(ctx,(uint64_t)(v))
+#define WRITE_STRING(ctx,buffer,size,n) WRITE_BYTES(ctx, buffer, size)
+#else
+#define WRITE_GUID(ctx,buffer,n) (vc_container_helper_write_debug(ctx, LOG_FORMAT_TYPE_GUID, 16, n, UINT64_C(0), (const uint8_t *)buffer, CONTAINER_HELPER_LOG_INDENT(ctx), !(ctx)->priv->io->module) ? 0 : 16)
+#define WRITE_U8(ctx,v,n)  vc_container_helper_write_debug(ctx, LOG_FORMAT_TYPE_UINT, 1, n, (uint64_t)(v), 0, CONTAINER_HELPER_LOG_INDENT(ctx), !(ctx)->priv->io->module)
+#define WRITE_FOURCC(ctx,v,n) vc_container_helper_write_debug(ctx, LOG_FORMAT_TYPE_FOURCC, 4, n, (uint64_t)(v), 0, CONTAINER_HELPER_LOG_INDENT(ctx), !(ctx)->priv->io->module)
+#define WRITE_U16(ctx,v,n) (uint16_t)vc_container_helper_write_debug(ctx, LOG_FORMAT_TYPE_UINT, 2, n, (uint64_t)(v), 0, CONTAINER_HELPER_LOG_INDENT(ctx), !(ctx)->priv->io->module)
+#define WRITE_U24(ctx,v,n) vc_container_helper_write_debug(ctx, LOG_FORMAT_TYPE_UINT, 3, n, (uint64_t)(v), 0, CONTAINER_HELPER_LOG_INDENT(ctx), !(ctx)->priv->io->module)
+#define WRITE_U32(ctx,v,n) vc_container_helper_write_debug(ctx, LOG_FORMAT_TYPE_UINT, 4, n, (uint64_t)(v), 0, CONTAINER_HELPER_LOG_INDENT(ctx), !(ctx)->priv->io->module)
+#define WRITE_U64(ctx,v,n) vc_container_helper_write_debug(ctx, LOG_FORMAT_TYPE_UINT, 8, n, (uint64_t)(v), 0, CONTAINER_HELPER_LOG_INDENT(ctx), !(ctx)->priv->io->module)
+#define WRITE_STRING(ctx,buffer,size,n) (vc_container_helper_write_debug(ctx, LOG_FORMAT_TYPE_STRING, size, n, UINT64_C(0), (const uint8_t *)buffer, CONTAINER_HELPER_LOG_INDENT(ctx), !(ctx)->priv->io->module) ? 0 : size)
+#endif
+
+#ifdef ENABLE_CONTAINERS_LOG_FORMAT
+#define LOG_FORMAT(ctx, ...) do { if((ctx)->priv->io->module) vc_container_helper_format_debug(ctx, CONTAINER_HELPER_LOG_INDENT(ctx), __VA_ARGS__); } while(0)
+#else
+#define LOG_FORMAT(ctx, ...) do {} while (0)
+#endif
+
+#define LOG_FORMAT_TYPE_UINT_LE  0
+#define LOG_FORMAT_TYPE_UINT_BE  1
+#define LOG_FORMAT_TYPE_STRING   2
+#define LOG_FORMAT_TYPE_STRING_UTF16_LE 3
+#define LOG_FORMAT_TYPE_STRING_UTF16_BE 4
+#define LOG_FORMAT_TYPE_FOURCC   5
+#define LOG_FORMAT_TYPE_GUID     6
+#define LOG_FORMAT_TYPE_HEX  0x100
+
+uint64_t vc_container_helper_int_debug(VC_CONTAINER_T *ctx, int type, uint64_t value, const char *name, int indent);
+uint64_t vc_container_helper_read_debug(VC_CONTAINER_T *ctx, int type, int size, const char *name,
+   uint8_t *buffer, int indent, int b_skip);
+VC_CONTAINER_STATUS_T vc_container_helper_write_debug(VC_CONTAINER_T *ctx, int type, int size, const char *name,
+   uint64_t value, const uint8_t *buffer, int indent, int silent);
+void vc_container_helper_format_debug(VC_CONTAINER_T *ctx, int indent, const char *format, ...);
+
+#endif /* VC_CONTAINERS_IO_HELPERS_H */
+/* End of file */
+/*-----------------------------------------------------------------------------*/
diff --git a/containers/core/containers_list.c b/containers/core/containers_list.c
new file mode 100755 (executable)
index 0000000..333f052
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "containers/core/containers_common.h"
+#include "containers/core/containers_list.h"
+
+/******************************************************************************
+Defines and constants.
+******************************************************************************/
+
+/******************************************************************************
+Type definitions
+******************************************************************************/
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+
+/** Find an entry in the list, or the insertion point.
+ * Uses binary sub-division to find the search item. If index is not NULL, the
+ * index of the matching entry, or the point at which to insert if not found, is
+ * written to that address.
+ *
+ * \param list The list to be searched.
+ * \param entry The entry for which to search.
+ * \param index Set to index of match, or insertion point if not found. May be NULL.
+ * \return True if a match was found, false if not. */
+static bool vc_containers_list_find_index(const VC_CONTAINERS_LIST_T *list,
+      const void *entry,
+      uint32_t *index)
+{
+   const char *entries = (const char *)list->entries;
+   size_t entry_size = list->entry_size;
+   VC_CONTAINERS_LIST_COMPARATOR_T comparator = list->comparator;
+   uint32_t start = 0, end = list->size;
+   uint32_t mid = end >> 1;
+   bool match = false;
+
+   while (mid < end)
+   {
+      int comparison = comparator(entry, entries + mid * entry_size);
+
+      if (comparison < 0)
+         end = mid;
+      else if (comparison > 0)
+         start = mid + 1;
+      else {
+         match = true;
+         break;
+      }
+
+      mid = (start + end) >> 1;
+   }
+
+   if (index) *index = mid;
+   return match;
+}
+
+/******************************************************************************
+Functions exported as part of the API
+******************************************************************************/
+
+/*****************************************************************************/
+VC_CONTAINERS_LIST_T *vc_containers_list_create(uint32_t capacity,
+      size_t entry_size,
+      VC_CONTAINERS_LIST_COMPARATOR_T comparator)
+{
+   VC_CONTAINERS_LIST_T *list;
+
+   list = (VC_CONTAINERS_LIST_T *)malloc(sizeof(VC_CONTAINERS_LIST_T));
+   if (!list)
+      return NULL;
+
+   /* Ensure non-zero capacity, as that signifies a read-only list */
+   if (!capacity) capacity = 1;
+
+   list->entries = malloc(capacity * entry_size);
+   if (!list->entries)
+   {
+      free(list);
+      return NULL;
+   }
+
+   list->size = 0;
+   list->capacity = capacity;
+   list->entry_size = entry_size;
+   list->comparator = comparator;
+
+   return list;
+}
+
+/*****************************************************************************/
+void vc_containers_list_destroy(VC_CONTAINERS_LIST_T *list)
+{
+   /* Avoid trying to destroy read-only lists */
+   if (list && list->capacity)
+   {
+      if (list->entries)
+         free(list->entries);
+      free(list);
+   }
+}
+
+/*****************************************************************************/
+void vc_containers_list_reset(VC_CONTAINERS_LIST_T *list)
+{
+   /* Avoid trying to reset read-only lists */
+   if (list && list->capacity)
+      list->size = 0;
+}
+
+/*****************************************************************************/
+bool vc_containers_list_insert(VC_CONTAINERS_LIST_T *list,
+      void *new_entry,
+      bool allow_duplicates)
+{
+   uint32_t insert_idx;
+   char *insert_ptr;
+   size_t entry_size;
+   bool match;
+
+   if (!list || !list->capacity) return false;
+
+   entry_size = list->entry_size;
+   match = vc_containers_list_find_index(list, new_entry, &insert_idx);
+   insert_ptr = (char *)list->entries + entry_size * insert_idx;
+
+   if (!match || allow_duplicates)
+   {
+      /* Ensure there is space for the new entry */
+      if (list->size == list->capacity)
+      {
+         void *new_entries = realloc(list->entries, (list->size + 1) * entry_size);
+
+         if (!new_entries)
+            return false;
+         list->entries = new_entries;
+         list->capacity++;
+      }
+
+      /* Move up anything above the insertion point */
+      if (insert_idx < list->size)
+         memmove(insert_ptr + entry_size, insert_ptr, (list->size - insert_idx) * entry_size);
+
+      list->size++;
+   }
+
+   /* Copy in the new entry (overwriting the old one if necessary) */
+   memcpy(insert_ptr, new_entry, list->entry_size);
+
+   return true;
+}
+
+/*****************************************************************************/
+bool vc_containers_list_find_entry(const VC_CONTAINERS_LIST_T *list,
+      void *entry)
+{
+   uint32_t index;
+   size_t entry_size;
+
+   if (!vc_containers_list_find_index(list, entry, &index))
+      return false;
+
+   entry_size = list->entry_size;
+   memcpy(entry, (const char *)list->entries + entry_size * index, entry_size);
+
+   return true;
+}
+
+/*****************************************************************************/
+void vc_containers_list_validate(const VC_CONTAINERS_LIST_T *list)
+{
+   uint32_t ii, entry_size;
+   const uint8_t *entry_ptr;
+
+   vc_container_assert(list);
+   vc_container_assert(!list->capacity || list->size <= list->capacity);
+   vc_container_assert(list->entry_size);
+   vc_container_assert(list->comparator);
+   vc_container_assert(list->entries);
+
+   /* Check all entries are in sorted order */
+   entry_ptr = (const uint8_t *)list->entries;
+   entry_size = list->entry_size;
+   for (ii = 1; ii < list->size; ii++)
+   {
+      vc_container_assert(list->comparator(entry_ptr, entry_ptr + entry_size) <= 0);
+      entry_ptr += entry_size;
+   }
+}
diff --git a/containers/core/containers_list.h b/containers/core/containers_list.h
new file mode 100755 (executable)
index 0000000..5b08997
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _VC_CONTAINERS_LIST_H_
+#define _VC_CONTAINERS_LIST_H_
+
+#include "containers/containers.h"
+
+/** List entry comparison prototype.
+ * Returns zero if items at a and b match, positive if a is "bigger" than b and
+ * negative if a is "smaller" than b. */
+typedef int (*VC_CONTAINERS_LIST_COMPARATOR_T)(const void *a, const void *b);
+
+/** Sorted list type.
+ * Storage type providing efficient insertion and search via binary sub-division. */
+typedef struct vc_containers_list_tag
+{
+   uint32_t size;                               /**< Number of defined entries in list */
+   uint32_t capacity;                           /**< Capacity of list, in entries, or zero for read-only */
+   size_t entry_size;                           /**< Size of one entry, in bytes */
+   VC_CONTAINERS_LIST_COMPARATOR_T comparator;  /**< Entry comparison function */
+   void *entries;                               /**< Pointer to array of entries */
+} VC_CONTAINERS_LIST_T;
+
+/** Macro to generate a static, read-only list from an array and comparator */
+#define VC_CONTAINERS_STATIC_LIST(L, A, C)  static VC_CONTAINERS_LIST_T L = { countof(A), 0, sizeof(*(A)), (VC_CONTAINERS_LIST_COMPARATOR_T)(C), A }
+
+
+/** Create an empty list.
+ * The list is created based on the details provided, minimum capacity one entry.
+ *
+ * \param The initial capacity in entries.
+ * \param entry_size The size of each entry, in bytes.
+ * \param comparator A function for comparing two entries.
+ * \return The new list or NULL. */
+VC_CONTAINERS_LIST_T *vc_containers_list_create(uint32_t capacity, size_t entry_size, VC_CONTAINERS_LIST_COMPARATOR_T comparator);
+
+/** Destroy a list.
+ * Has no effect on a static list.
+ *
+ * \param list The list to be destroyed. */
+void vc_containers_list_destroy(VC_CONTAINERS_LIST_T *list);
+
+/** Reset a list to be empty.
+ * Has no effect on a static list.
+ *
+ * \param list The list to be reset. */
+void vc_containers_list_reset(VC_CONTAINERS_LIST_T *list);
+
+/** Insert an entry into the list.
+ *
+ * \param list The list.
+ * \param new_entry The new entry to be inserted.
+ * \param allow_duplicates Determines whether to insert or overwrite if there
+ *    is an existing matching entry.
+ * \return True if the entry has successfully been inserted, false if the list
+ *    needed to be enlarged and the memory allocation failed. */
+bool vc_containers_list_insert(VC_CONTAINERS_LIST_T *list, void *new_entry, bool allow_duplicates);
+
+/** Find an entry in the list and fill in the result.
+ * Searches for an entry in the list using the comparator and if found
+ * overwrites the one passed in with the one found.
+ *
+ * \param list The list to search.
+ * \param entry An entry with enough defined to find it in the list, filled in
+ *    with the rest if found.
+ * \return True if found, false if not. */
+bool vc_containers_list_find_entry(const VC_CONTAINERS_LIST_T *list, void *entry);
+
+/** Validates a list pointer.
+ * Fields and contents of a list are checked and asserted to be correct. With a
+ * large list this may be slow, so it is recommended only to call this in debug
+ * builds.
+ *
+ * \param list The list to be validated. */
+void vc_containers_list_validate(const VC_CONTAINERS_LIST_T *list);
+
+#endif /* _VC_CONTAINERS_LIST_H_ */
diff --git a/containers/core/containers_loader.c b/containers/core/containers_loader.c
new file mode 100755 (executable)
index 0000000..b597301
--- /dev/null
@@ -0,0 +1,436 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_loader.h"
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE)
+   #include "vcos_dlfcn.h"
+   #define DL_SUFFIX VCOS_SO_EXT
+   #ifndef DL_PATH_PREFIX
+      #define DL_PATH_PREFIX ""
+   #endif
+#endif
+
+/******************************************************************************
+Type definitions.
+******************************************************************************/
+
+typedef VC_CONTAINER_STATUS_T (*VC_CONTAINER_READER_OPEN_FUNC_T)(VC_CONTAINER_T *);
+typedef VC_CONTAINER_STATUS_T (*VC_CONTAINER_WRITER_OPEN_FUNC_T)(VC_CONTAINER_T *);
+
+/******************************************************************************
+Prototypes for local functions
+******************************************************************************/
+
+static void reset_context(VC_CONTAINER_T *p_ctx);
+static VC_CONTAINER_READER_OPEN_FUNC_T load_library(void **handle, const char *name, const char *ext, int read);
+static void unload_library(void *handle);
+static VC_CONTAINER_READER_OPEN_FUNC_T load_reader(void **handle, const char *name);
+static VC_CONTAINER_READER_OPEN_FUNC_T load_writer(void **handle, const char *name);
+static VC_CONTAINER_READER_OPEN_FUNC_T load_metadata_reader(void **handle, const char *name);
+static const char* container_for_fileext(const char *fileext);
+
+/********************************************************************************
+ List of supported containers
+ ********************************************************************************/
+
+static const char *readers[] =
+{"mp4", "asf", "avi", "mkv", "wav", "flv", "simple", "rawvideo", "mpga", "ps", "rtp", "rtsp", "rcv", "rv9", "qsynth", "binary", 0};
+static const char *writers[] =
+{"mp4", "asf", "avi", "binary", "simple", "rawvideo", 0};
+static const char *metadata_readers[] =
+{"id3", 0};
+
+#if defined(ENABLE_CONTAINERS_STANDALONE)
+VC_CONTAINER_STATUS_T asf_reader_open( VC_CONTAINER_T * );
+VC_CONTAINER_STATUS_T avi_reader_open( VC_CONTAINER_T * );
+VC_CONTAINER_STATUS_T avi_writer_open( VC_CONTAINER_T * );
+VC_CONTAINER_STATUS_T mp4_reader_open( VC_CONTAINER_T * );
+VC_CONTAINER_STATUS_T mp4_writer_open( VC_CONTAINER_T * );
+VC_CONTAINER_STATUS_T mpga_reader_open( VC_CONTAINER_T * );
+VC_CONTAINER_STATUS_T mkv_reader_open( VC_CONTAINER_T * );
+VC_CONTAINER_STATUS_T wav_reader_open( VC_CONTAINER_T * );
+VC_CONTAINER_STATUS_T flv_reader_open( VC_CONTAINER_T * );
+VC_CONTAINER_STATUS_T ps_reader_open( VC_CONTAINER_T * );
+VC_CONTAINER_STATUS_T rtp_reader_open( VC_CONTAINER_T * );
+VC_CONTAINER_STATUS_T rtsp_reader_open( VC_CONTAINER_T * );
+VC_CONTAINER_STATUS_T binary_reader_open( VC_CONTAINER_T * );
+VC_CONTAINER_STATUS_T binary_writer_open( VC_CONTAINER_T * );
+VC_CONTAINER_STATUS_T rcv_reader_open( VC_CONTAINER_T * );
+VC_CONTAINER_STATUS_T rv9_reader_open( VC_CONTAINER_T * );
+VC_CONTAINER_STATUS_T qsynth_reader_open( VC_CONTAINER_T * );
+VC_CONTAINER_STATUS_T simple_reader_open( VC_CONTAINER_T * );
+VC_CONTAINER_STATUS_T simple_writer_open( VC_CONTAINER_T * );
+VC_CONTAINER_STATUS_T rawvideo_reader_open( VC_CONTAINER_T * );
+VC_CONTAINER_STATUS_T rawvideo_writer_open( VC_CONTAINER_T * );
+
+VC_CONTAINER_STATUS_T id3_metadata_reader_open( VC_CONTAINER_T * );
+
+static struct
+{
+   const char *name;
+   VC_CONTAINER_READER_OPEN_FUNC_T func;
+} reader_entry_points[] =
+{
+   {"asf", &asf_reader_open},
+   {"avi", &avi_reader_open},
+   {"mpga", &mpga_reader_open},
+   {"mkv", &mkv_reader_open},
+   {"wav", &wav_reader_open},
+   {"mp4",  &mp4_reader_open},
+   {"flv",  &flv_reader_open},
+   {"ps",  &ps_reader_open},
+   {"binary",  &binary_reader_open},
+   {"rtp",  &rtp_reader_open},
+   {"rtsp", &rtsp_reader_open},
+   {"rcv", &rcv_reader_open},
+   {"rv9", &rv9_reader_open},
+   {"qsynth", &qsynth_reader_open},
+   {"simple", &simple_reader_open},
+   {"rawvideo", &rawvideo_reader_open},
+   {0, 0}
+};
+
+static struct
+{
+   const char *name;
+   VC_CONTAINER_READER_OPEN_FUNC_T func;
+} metadata_reader_entry_points[] =
+{
+   {"id3", &id3_metadata_reader_open},
+   {0, 0}
+};
+
+static struct
+{
+   const char *name;
+   VC_CONTAINER_WRITER_OPEN_FUNC_T func;
+} writer_entry_points[] =
+{
+   {"avi", &avi_writer_open},
+   {"mp4", &mp4_writer_open},
+   {"binary", &binary_writer_open},
+   {"simple", &simple_writer_open},
+   {"rawvideo", &rawvideo_writer_open},
+   {0, 0}
+};
+#endif /* defined(ENABLE_CONTAINERS_STANDALONE) */
+
+/** Table describing the mapping between file extensions and container name.
+    This is only used as optimisation to decide which container to try first.
+    Entries where the file extension and container have the same name can be omitted. */
+static const struct {
+   const char *extension;
+   const char *container;
+} extension_container_mapping[] =
+{
+   { "wma",  "asf" },
+   { "wmv",  "asf" },
+   { "mov",  "mp4" },
+   { "3gp",  "mp4" },
+   { "mp2",  "mpga" },
+   { "mp3",  "mpga" },
+   { "webm", "mkv" },
+   { "mid",  "qsynth" },
+   { "mld",  "qsynth" },
+   { "mmf",  "qsynth" },
+   { 0, 0 }
+};
+
+/********************************************************************************
+ Public functions
+ ********************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_load_reader(VC_CONTAINER_T *p_ctx, const char *fileext)
+{
+   const char *name;
+   void *handle = NULL;
+   VC_CONTAINER_READER_OPEN_FUNC_T func;
+   VC_CONTAINER_STATUS_T status;
+   unsigned int i;
+   int64_t offset;
+   
+   vc_container_assert(p_ctx && !p_ctx->priv->module_handle);
+
+   /* FIXME: the missing part here is code that reads a configuration or
+      searches the filesystem for container libraries. Instead, we currently
+      rely on static arrays i.e. 'readers', 'writers', etc. */
+
+   /* Before trying proper container readers, iterate through metadata 
+      readers to parse tags concatenated to start/end of stream */
+   for(i = 0; metadata_readers[i]; i++)
+   {
+      if ((func = load_metadata_reader(&handle, metadata_readers[i])) != NULL)
+      {
+         status = (*func)(p_ctx);
+         if(!status && p_ctx->priv->pf_close) p_ctx->priv->pf_close(p_ctx);
+         reset_context(p_ctx);
+         unload_library(handle);
+         if(status == VC_CONTAINER_SUCCESS) break;
+         if (status != VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED) goto error;
+      }
+   }
+
+   /* Store the current position, in case any containers don't leave the stream
+      at the start, and the IO layer can cope with the seek */
+   offset = p_ctx->priv->io->offset;
+
+   /* Now move to containers, try to find a readers using the file extension to name 
+      mapping first */
+   if (fileext && (name = container_for_fileext(fileext)) != NULL && (func = load_reader(&handle, name)) != NULL)
+   {
+      status = (*func)(p_ctx);
+      if(status == VC_CONTAINER_SUCCESS) goto success;
+      unload_library(handle);
+      if (status != VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED) goto error;
+   }
+
+   /* If there was no suitable mapping, iterate through all readers. */
+   for(i = 0; readers[i]; i++)
+   {
+      if ((func = load_reader(&handle, readers[i])) != NULL)
+      {
+         if(vc_container_io_seek(p_ctx->priv->io, offset) != VC_CONTAINER_SUCCESS)
+         {
+            unload_library(handle);
+            goto error;
+         }
+
+         status = (*func)(p_ctx);
+         if(status == VC_CONTAINER_SUCCESS) goto success;
+         reset_context(p_ctx);
+         unload_library(handle);
+         if (status != VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED) goto error;
+      }
+   }
+
+ error:
+   return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+ success:
+   p_ctx->priv->module_handle = handle;
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_load_writer(VC_CONTAINER_T *p_ctx, const char *fileext)
+{
+   const char *name;
+   void *handle = NULL;
+   VC_CONTAINER_WRITER_OPEN_FUNC_T func;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FAILED;
+   unsigned int i;
+   
+   vc_container_assert(p_ctx && !p_ctx->priv->module_handle);
+     
+   /* Do we have a container mapping for this file extension? */
+   if ((name = container_for_fileext(fileext)) != NULL && (func = load_writer(&handle, name)) != NULL)
+   {
+      status = (*func)(p_ctx);
+      if(status == VC_CONTAINER_SUCCESS) goto success;
+      unload_library(handle);
+      if (status != VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED) goto error;
+   }
+
+   /* If there was no suitable mapping, iterate through all writers. */
+   for(i = 0; writers[i]; i++)
+   {
+      if ((func = load_writer(&handle, writers[i])) != NULL)
+      {
+         status = (*func)(p_ctx);
+         if(status == VC_CONTAINER_SUCCESS) goto success;
+         unload_library(handle);
+         if (status != VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED) goto error;
+      }
+   }
+
+ error:
+   return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+ success:
+   p_ctx->priv->module_handle = handle;
+   return status;
+}
+
+/*****************************************************************************/
+void vc_container_unload(VC_CONTAINER_T *p_ctx)
+{
+   if (p_ctx->priv->module_handle)
+   {
+      unload_library(p_ctx->priv->module_handle);
+      p_ctx->priv->module_handle = NULL;
+   }
+}
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+static void reset_context(VC_CONTAINER_T *p_ctx)
+{
+   vc_container_assert(p_ctx);
+   
+   p_ctx->capabilities = 0;
+   p_ctx->tracks = NULL;
+   p_ctx->tracks_num = 0;
+   p_ctx->drm = NULL;
+   p_ctx->priv->module = NULL;
+   p_ctx->priv->pf_close = NULL;
+   p_ctx->priv->pf_read = NULL;
+   p_ctx->priv->pf_write = NULL;
+   p_ctx->priv->pf_seek = NULL;
+   p_ctx->priv->pf_control = NULL;
+   p_ctx->priv->tmp_io = NULL;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_READER_OPEN_FUNC_T load_reader(void **handle, const char *name)
+{
+   return load_library(handle, name, NULL, 1);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_READER_OPEN_FUNC_T load_writer(void **handle, const char *name)
+{
+   return load_library(handle, name, NULL, 0);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_READER_OPEN_FUNC_T load_metadata_reader(void **handle, const char *name)
+{
+   #define DL_PREFIX_METADATA "metadata_"
+   return load_library(handle, name, DL_PREFIX_METADATA, 1);
+}
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE)
+
+/*****************************************************************************/
+static VC_CONTAINER_READER_OPEN_FUNC_T load_library(void **handle, const char *name, const char *ext, int read)
+{
+   #define DL_PREFIX_RD "reader_"
+   #define DL_PREFIX_WR "writer_"
+   const char *entrypt_read = {"reader_open"};
+   const char *entrypt_write = {"writer_open"};
+   char *dl_name, *entrypt_name;
+   void *dl_handle;
+   VC_CONTAINER_READER_OPEN_FUNC_T func = NULL;
+   unsigned dl_size, ep_size, name_len = strlen(name) + (ext ? strlen(ext) : 0);
+   
+   vc_container_assert(read == 0 || read == 1);
+   
+   dl_size = strlen(DL_PATH_PREFIX) + MAX(strlen(DL_PREFIX_RD), strlen(DL_PREFIX_WR)) + name_len + strlen(DL_SUFFIX) + 1;
+   if ((dl_name = malloc(dl_size)) == NULL)
+      return NULL;
+
+   ep_size = name_len + 1 + MAX(strlen(entrypt_read), strlen(entrypt_write)) + 1;
+   if ((entrypt_name = malloc(ep_size)) == NULL)
+   {
+      free(dl_name);
+      return NULL;
+   }
+
+   snprintf(dl_name, dl_size, "%s%s%s%s%s", DL_PATH_PREFIX, read ? DL_PREFIX_RD : DL_PREFIX_WR, ext ? ext : "", name, DL_SUFFIX);
+   snprintf(entrypt_name, ep_size, "%s_%s%s", name, ext ? ext : "", read ? entrypt_read : entrypt_write);
+      
+   if ( (dl_handle = vcos_dlopen(dl_name, VCOS_DL_NOW)) != NULL )
+   {
+      /* Try generic entrypoint name before the mangled, full name */
+      func = (VC_CONTAINER_READER_OPEN_FUNC_T)vcos_dlsym(dl_handle, read ? entrypt_read : entrypt_write);
+#if !defined(__VIDEOCORE__) /* The following would be pointless on MW/VideoCore */
+      if (!func) func = (VC_CONTAINER_READER_OPEN_FUNC_T)vcos_dlsym(dl_handle, entrypt_name);
+#endif
+      /* Only return handle if symbol found */
+      if (func)
+         *handle = dl_handle;
+      else
+         vcos_dlclose(dl_handle);
+   }
+  
+   free(entrypt_name);
+   free(dl_name);  
+   return func;
+}
+
+/*****************************************************************************/
+static void unload_library(void *handle)
+{
+   vcos_dlclose(handle);
+}
+
+#else /* !defined(ENABLE_CONTAINERS_STANDALONE) */
+
+/*****************************************************************************/
+static VC_CONTAINER_READER_OPEN_FUNC_T load_library(void **handle, const char *name, const char *ext, int read)
+{
+   int i;
+   VC_CONTAINER_PARAM_UNUSED(handle);
+   VC_CONTAINER_PARAM_UNUSED(ext);
+
+   if (read)
+   {
+      for (i = 0; reader_entry_points[i].name; i++)
+         if (!strcasecmp(reader_entry_points[i].name, name))
+            return reader_entry_points[i].func;
+      
+      for (i = 0; metadata_reader_entry_points[i].name; i++)
+         if (!strcasecmp(metadata_reader_entry_points[i].name, name))
+            return metadata_reader_entry_points[i].func;
+   }
+   else
+   {
+      for (i = 0; writer_entry_points[i].name; i++)
+         if (!strcasecmp(writer_entry_points[i].name, name))
+            return writer_entry_points[i].func;
+   }
+
+   return NULL;
+}
+
+/*****************************************************************************/
+static void unload_library(void *handle)
+{
+   (void)handle;
+}
+
+#endif /* !defined(ENABLE_CONTAINERS_STANDALONE) */
+
+/*****************************************************************************/
+static const char* container_for_fileext(const char *fileext)
+{
+   int i;
+
+   for( i = 0; fileext && extension_container_mapping[i].extension; i++ )
+   {
+      if (!strcasecmp( fileext, extension_container_mapping[i].extension ))
+         return extension_container_mapping[i].container;
+   }
+
+   return fileext;
+}
diff --git a/containers/core/containers_loader.h b/containers/core/containers_loader.h
new file mode 100755 (executable)
index 0000000..946eaf6
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VC_CONTAINERS_LOADER_H
+#define VC_CONTAINERS_LOADER_H
+
+/** Find and attempt to load & open reader, 'fileext' is a hint that can be used 
+    to speed up loading. */
+VC_CONTAINER_STATUS_T vc_container_load_reader(VC_CONTAINER_T *p_ctx, const char *fileext);
+
+/** Find and attempt to load & open writer, 'fileext' is a hint used to help in 
+    selecting the appropriate container format. */
+VC_CONTAINER_STATUS_T vc_container_load_writer(VC_CONTAINER_T *p_ctx, const char *fileext);
+
+void vc_container_unload(VC_CONTAINER_T *p_ctx);
+
+#endif /* VC_CONTAINERS_LOADER_H */
diff --git a/containers/core/containers_logging.c b/containers/core/containers_logging.c
new file mode 100755 (executable)
index 0000000..5a739a3
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include "containers/containers.h"
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_logging.h"
+
+#ifndef ENABLE_CONTAINERS_STANDALONE
+# include "vcos.h"
+#endif
+
+#ifdef __ANDROID__
+#define LOG_TAG "ContainersCore"
+#include <cutils/log.h>
+#endif
+
+/* Default verbosity that will be inherited by containers */
+static uint32_t default_verbosity_mask = VC_CONTAINER_LOG_ALL;
+
+/* By default log everything that's not associated with a container context */
+static uint32_t verbosity_mask = VC_CONTAINER_LOG_ALL;
+
+void vc_container_log_set_default_verbosity(uint32_t mask)
+{
+   default_verbosity_mask = mask;
+}
+
+uint32_t vc_container_log_get_default_verbosity(void)
+{
+   return default_verbosity_mask;
+}
+
+void vc_container_log_set_verbosity(VC_CONTAINER_T *ctx, uint32_t mask)
+{
+   if(!ctx) verbosity_mask = mask;
+   else ctx->priv->verbosity = mask;
+}
+
+void vc_container_log(VC_CONTAINER_T *ctx, VC_CONTAINER_LOG_TYPE_T type, const char *format, ...)
+{
+   uint32_t verbosity = ctx ? ctx->priv->verbosity : verbosity_mask;
+   va_list args;
+
+   // Optimise out the call to vc_container_log_vargs etc. when it won't do anything.
+   if(!(type & verbosity)) return;
+
+   va_start( args, format );
+   vc_container_log_vargs(ctx, type, format, args);
+   va_end( args );
+}
+
+void vc_container_log_vargs(VC_CONTAINER_T *ctx, VC_CONTAINER_LOG_TYPE_T type, const char *format, va_list args)
+{
+   uint32_t verbosity = ctx ? ctx->priv->verbosity : verbosity_mask;
+
+   // If the verbosity is such that the type doesn't need logging quit now.
+   if(!(type & verbosity)) return;
+
+#ifdef __ANDROID__
+   {
+      // Default to Android's "verbose" level (doesn't usually come out)
+      android_LogPriority logLevel = ANDROID_LOG_VERBOSE;
+
+      // Where type suggest a higher level is required update logLevel.
+      // (Usually type contains only 1 bit as set by the LOG_DEBUG, LOG_ERROR or LOG_INFO macros)
+      if (type & VC_CONTAINER_LOG_ERROR)
+         logLevel = ANDROID_LOG_ERROR;
+      else if (type & VC_CONTAINER_LOG_INFO)
+         logLevel = ANDROID_LOG_INFO;
+      else if (type & VC_CONTAINER_LOG_DEBUG)
+         logLevel = ANDROID_LOG_DEBUG;
+
+      // Actually put the message out.
+      LOG_PRI_VA(logLevel, LOG_TAG, format, args);
+   }
+#else
+#ifndef ENABLE_CONTAINERS_STANDALONE
+   vcos_vlog(format, args);
+#else
+   vprintf(format, args); printf("\n");
+   fflush(0);
+#endif
+#endif
+}
diff --git a/containers/core/containers_logging.h b/containers/core/containers_logging.h
new file mode 100755 (executable)
index 0000000..a7c2bd9
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef VC_CONTAINERS_LOGGING_H
+#define VC_CONTAINERS_LOGGING_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file containers_logging.h
+ * Logging API used by container readers and writers
+ */
+
+typedef enum {
+   VC_CONTAINER_LOG_ERROR  = 0x01,
+   VC_CONTAINER_LOG_INFO   = 0x02,
+   VC_CONTAINER_LOG_DEBUG  = 0x04,
+   VC_CONTAINER_LOG_FORMAT = 0x08,
+   VC_CONTAINER_LOG_ALL = 0xFF
+} VC_CONTAINER_LOG_TYPE_T;
+
+void vc_container_log(VC_CONTAINER_T *ctx, VC_CONTAINER_LOG_TYPE_T type, const char *format, ...);
+void vc_container_log_vargs(VC_CONTAINER_T *ctx, VC_CONTAINER_LOG_TYPE_T type, const char *format, va_list args);
+void vc_container_log_set_verbosity(VC_CONTAINER_T *ctx, uint32_t mask);
+void vc_container_log_set_default_verbosity(uint32_t mask);
+uint32_t vc_container_log_get_default_verbosity(void);
+
+#define ENABLE_CONTAINER_LOG_ERROR
+#define ENABLE_CONTAINER_LOG_INFO
+
+#ifdef ENABLE_CONTAINER_LOG_DEBUG
+# define LOG_DEBUG(ctx, ...) vc_container_log(ctx, VC_CONTAINER_LOG_DEBUG, __VA_ARGS__)
+#else
+# define LOG_DEBUG(ctx, ...) VC_CONTAINER_PARAM_UNUSED(ctx)
+#endif
+
+#ifdef ENABLE_CONTAINER_LOG_ERROR
+# define LOG_ERROR(ctx, ...) vc_container_log(ctx, VC_CONTAINER_LOG_ERROR, __VA_ARGS__)
+#else
+# define LOG_ERROR(ctx, ...) VC_CONTAINER_PARAM_UNUSED(ctx)
+#endif
+
+#ifdef ENABLE_CONTAINER_LOG_INFO
+# define LOG_INFO(ctx, ...) vc_container_log(ctx, VC_CONTAINER_LOG_INFO, __VA_ARGS__)
+#else
+# define LOG_INFO(ctx, ...) VC_CONTAINER_PARAM_UNUSED(ctx)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* VC_CONTAINERS_LOGGING_H */
diff --git a/containers/core/containers_private.h b/containers/core/containers_private.h
new file mode 100755 (executable)
index 0000000..8c379c6
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef VC_CONTAINERS_PRIVATE_H
+#define VC_CONTAINERS_PRIVATE_H
+
+/** \file containers_private.h
+ * Private interface for container readers and writers
+ */
+
+#include <stdarg.h>
+#include "containers/containers.h"
+#include "containers/core/containers_common.h"
+#include "containers/core/containers_io.h"
+#include "containers/core/containers_filters.h"
+#include "containers/packetizers.h"
+#include "containers/core/containers_uri.h"
+
+#define URI_MAX_LEN 256
+
+/** \defgroup VcContainerModuleApi Container Module API
+ * Private interface for modules implementing container readers and writers */
+/* @{ */
+
+/** Track context private to the container reader / writer instance. This private context is used to
+ * store data which shouldn't be exported by the public API. */
+typedef struct VC_CONTAINER_TRACK_PRIVATE_T
+{
+   /** Pointer to the private data of the container module in use */
+   struct VC_CONTAINER_TRACK_MODULE_T *module;
+
+   /** Pointer to the allocated buffer for the track extradata */
+   uint8_t *extradata;
+   /** Size of the allocated buffer for the track extradata */
+   uint32_t extradata_size;
+
+   /** Pointer to the allocated buffer for the track DRM data*/
+   uint8_t *drmdata;
+   /** Size of the allocated buffer for the track DRM data */
+   uint32_t drmdata_size;
+
+   /** Packetizer used by this track */
+   VC_PACKETIZER_T *packetizer;
+
+} VC_CONTAINER_TRACK_PRIVATE_T;
+
+/** Context private to the container reader / writer instance. This private context is used to
+ * store data which shouldn't be exported by the public API. */
+typedef struct VC_CONTAINER_PRIVATE_T
+{
+   /** Pointer to the container i/o instance used to read / write to the container */
+   struct VC_CONTAINER_IO_T *io;
+   /** Pointer to the private data of the container module in use */
+   struct VC_CONTAINER_MODULE_T *module;
+
+   /** Reads a data packet from a container reader.
+    * By default, the reader will read whatever packet comes next in the container and update the
+    * given \ref VC_CONTAINER_PACKET_T structure with this packet's information.
+    * This behaviour can be changed using the \ref VC_CONTAINER_READ_FLAGS_T.\n
+    * \ref VC_CONTAINER_READ_FLAG_INFO will instruct the reader to only return information on the
+    * following packet but not its actual data. The data can be retreived later by issuing another
+    * read request.
+    * \ref VC_CONTAINER_READ_FLAG_FORCE_TRACK will force the reader to read the next packet for the
+    * selected track (as present in the \ref VC_CONTAINER_PACKET_T structure) instead of defaulting
+    * to reading the packet which comes next in the container.
+    * \ref VC_CONTAINER_READ_FLAG_SKIP will instruct the reader to skip the next packet. In this case
+    * it isn't necessary for the caller to pass a pointer to a \ref VC_CONTAINER_PACKET_T structure
+    * unless the \ref VC_CONTAINER_READ_FLAG_INFO is also given.
+    * A combination of all these flags can be used.
+    *
+    * \param  context   Pointer to the context of the reader to use
+    * \param  packet    Pointer to the VC_CONTAINER_PACKET_T structure describing the data packet
+    *                   This needs to be partially filled before the call (buffer, buffer_size)
+    * \param  flags     Flags controlling the read operation
+    * \return           the status of the operation
+    */
+   VC_CONTAINER_STATUS_T (*pf_read)( VC_CONTAINER_T *context,
+      VC_CONTAINER_PACKET_T *packet, VC_CONTAINER_READ_FLAGS_T flags );
+
+   /** Writes a data packet to a container writer.
+    *
+    * \param  context   Pointer to the context of the writer to use
+    * \param  packet    Pointer to the VC_CONTAINER_PACKET_T structure describing the data packet
+    * \return           the status of the operation
+    */
+   VC_CONTAINER_STATUS_T (*pf_write)( struct VC_CONTAINER_T *context,
+      VC_CONTAINER_PACKET_T *packet );
+
+   /** Seek into a container reader.
+    *
+    * \param  context   Pointer to the context of the reader to use
+    * \param  offset    Offset to seek to. Used as an input as well as output value.
+    * \param  mode      Seeking mode requested.
+    * \param  flags     Flags affecting the seeking operation.
+    * \return           the status of the operation
+    */
+   VC_CONTAINER_STATUS_T (*pf_seek)( VC_CONTAINER_T *context, int64_t *offset,
+         VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags);
+
+   /** Extensible control function for container readers and writers.
+    * This function takes a variable number of arguments which will depend on the specific operation.
+    *
+    * \param  context   Pointer to the VC_CONTAINER_T context to use
+    * \param  operation The requested operation
+    * \return           the status of the operation
+    */
+   VC_CONTAINER_STATUS_T (*pf_control)( VC_CONTAINER_T *context, VC_CONTAINER_CONTROL_T operation, va_list args );
+
+   /** Closes a container reader / writer module.
+    *
+    * \param  context   Pointer to the context of the instance to close
+    * \return           the status of the operation
+    */
+   VC_CONTAINER_STATUS_T (*pf_close)( struct VC_CONTAINER_T *context );
+
+   /** Pointer to container filter instance used for DRM */
+   struct VC_CONTAINER_FILTER_T *drm_filter;
+
+   /** Pointer to the container module code and symbols*/
+   void *module_handle;
+
+   /** Maximum size of a stream that is being written.
+    * This is set by the client using the control mechanism */
+   int64_t max_size;
+
+   /** Pointer to the temp i/o instance used to write temporary data */
+   struct VC_CONTAINER_IO_T *tmp_io;
+
+   /** Current status of the container (only used for writers to prevent trying to write
+    * more data if one of the writes failed) */
+   VC_CONTAINER_STATUS_T status;
+
+   /** Logging verbosity */
+   uint32_t verbosity;
+
+   /** Uniform Resource Identifier */
+   struct VC_URI_PARTS_T *uri;
+
+   /** Flag specifying whether one of the tracks is being packetized */
+   bool packetizing;
+
+   /** Temporary packet structure used to feed data to the packetizer */
+   VC_CONTAINER_PACKET_T packetizer_packet;
+
+   /** Temporary buffer used by the packetizer */
+   uint8_t *packetizer_buffer;
+
+} VC_CONTAINER_PRIVATE_T;
+
+/* Internal functions */
+VC_CONTAINER_TRACK_T *vc_container_allocate_track( VC_CONTAINER_T *context, unsigned int extra_size );
+void vc_container_free_track( VC_CONTAINER_T *context, VC_CONTAINER_TRACK_T *track );
+VC_CONTAINER_STATUS_T vc_container_track_allocate_extradata( VC_CONTAINER_T *context,
+   VC_CONTAINER_TRACK_T *p_track, unsigned int extra_size );
+VC_CONTAINER_STATUS_T vc_container_track_allocate_drmdata( VC_CONTAINER_T *context,
+   VC_CONTAINER_TRACK_T *p_track, unsigned int size );
+   
+/* @} */
+
+#endif /* VC_CONTAINERS_PRIVATE_H */
diff --git a/containers/core/containers_time.h b/containers/core/containers_time.h
new file mode 100755 (executable)
index 0000000..e625c34
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef VC_CONTAINERS_TIME_H
+#define VC_CONTAINERS_TIME_H
+
+/** \file
+ * Utility functions to help with timestamping of elementary stream frames
+ */
+
+typedef struct VC_CONTAINER_TIME_T
+{
+   uint32_t samplerate_num;
+   uint32_t samplerate_den;
+   uint32_t time_base;
+
+   uint32_t remainder;
+
+   int64_t time;
+
+} VC_CONTAINER_TIME_T;
+
+/*****************************************************************************/
+STATIC_INLINE void vc_container_time_init( VC_CONTAINER_TIME_T *time, uint32_t time_base )
+{
+   time->samplerate_num = 0;
+   time->samplerate_den = 0;
+   time->remainder = 0;
+   time->time_base = time_base;
+   time->time = VC_CONTAINER_TIME_UNKNOWN;
+}
+
+/*****************************************************************************/
+STATIC_INLINE int64_t vc_container_time_get( VC_CONTAINER_TIME_T *time )
+{
+   if (time->time == VC_CONTAINER_TIME_UNKNOWN || !time->samplerate_num || !time->samplerate_den)
+      return VC_CONTAINER_TIME_UNKNOWN;
+   return time->time + time->remainder * (int64_t)time->time_base * time->samplerate_den / time->samplerate_num;
+}
+
+/*****************************************************************************/
+STATIC_INLINE void vc_container_time_set_samplerate( VC_CONTAINER_TIME_T *time, uint32_t samplerate_num, uint32_t samplerate_den )
+{
+   if(time->samplerate_num == samplerate_num &&
+      time->samplerate_den == samplerate_den)
+      return;
+
+   /* We're changing samplerate, we need to reset our remainder */
+   if(time->remainder)
+      time->time = vc_container_time_get( time );
+   time->remainder = 0;
+   time->samplerate_num = samplerate_num;
+   time->samplerate_den = samplerate_den;
+}
+
+/*****************************************************************************/
+STATIC_INLINE void vc_container_time_set( VC_CONTAINER_TIME_T *time, int64_t new_time )
+{
+   if (new_time == VC_CONTAINER_TIME_UNKNOWN)
+      return;
+   time->remainder = 0;
+   time->time = new_time;
+}
+
+/*****************************************************************************/
+STATIC_INLINE int64_t vc_container_time_add( VC_CONTAINER_TIME_T *time, uint32_t samples )
+{
+   uint32_t increment;
+
+   if (time->time == VC_CONTAINER_TIME_UNKNOWN || !time->samplerate_num || !time->samplerate_den)
+      return VC_CONTAINER_TIME_UNKNOWN;
+
+   samples += time->remainder;
+   increment = samples * time->samplerate_den / time->samplerate_num;
+   time->time += increment * time->time_base;
+   time->remainder = samples - increment * time->samplerate_num / time->samplerate_den;
+   return vc_container_time_get(time);
+}
+
+#endif /* VC_CONTAINERS_TIME_H */
diff --git a/containers/core/containers_uri.c b/containers/core/containers_uri.c
new file mode 100755 (executable)
index 0000000..b0d3c59
--- /dev/null
@@ -0,0 +1,1120 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "containers/core/containers_uri.h"
+
+/*****************************************************************************/
+/* Internal types and definitions                                            */
+/*****************************************************************************/
+
+typedef struct VC_URI_QUERY_T
+{
+   char *name;
+   char *value;
+} VC_URI_QUERY_T;
+
+struct VC_URI_PARTS_T
+{
+   char *scheme;     /**< Unescaped scheme */
+   char *userinfo;   /**< Unescaped userinfo */
+   char *host;       /**< Unescaped host name/IP address */
+   char *port;       /**< Unescaped port */
+   char *path;       /**< Unescaped path */
+   char *path_extension; /**< Unescaped path extension */
+   char *fragment;   /**< Unescaped fragment */
+   VC_URI_QUERY_T *queries;   /**< Array of queries */
+   uint32_t num_queries;      /**< Number of queries in array */
+};
+
+typedef const uint32_t *RESERVED_CHARS_TABLE_T;
+
+/** Reserved character table for scheme component
+ * Controls, space, !"#$%&'()*,/:;<=>?@[\]^`{|} and 0x7F and above reserved. */
+static uint32_t scheme_reserved_chars[8] = {
+   0xFFFFFFFF, 0xFC0097FF, 0x78000001, 0xB8000001, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
+};
+
+/** Reserved character table for userinfo component
+ * Controls, space, "#%/<>?@[\]^`{|} and 0x7F and above reserved. */
+static uint32_t userinfo_reserved_chars[8] = {
+   0xFFFFFFFF, 0xD000802D, 0x78000001, 0xB8000001, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
+};
+
+/** Reserved character table for host component
+ * Controls, space, "#%/<>?@\^`{|} and 0x7F and above reserved. */
+static uint32_t host_reserved_chars[8] = {
+   0xFFFFFFFF, 0xD000802D, 0x50000001, 0xB8000001, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
+};
+
+/** Reserved character table for port component
+ * Controls, space, !"#$%&'()*+,/:;<=>?@[\]^`{|} and 0x7F and above reserved. */
+static uint32_t port_reserved_chars[8] = {
+   0xFFFFFFFF, 0xFC009FFF, 0x78000001, 0xB8000001, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
+};
+
+/** Reserved character table for path component
+ * Controls, space, "#%<>?[\]^`{|} and 0x7F and above reserved. */
+static uint32_t path_reserved_chars[8] = {
+   0xFFFFFFFF, 0xD000002D, 0x78000000, 0xB8000001, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
+};
+
+/** Reserved character table for query component
+ * Controls, space, "#%<>[\]^`{|} and 0x7F and above reserved. */
+static uint32_t query_reserved_chars[8] = {
+   0xFFFFFFFF, 0x5000002D, 0x78000000, 0xB8000001, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
+};
+
+/** Reserved character table for fragment component
+ * Controls, space, "#%<>[\]^`{|} and 0x7F and above reserved. */
+static uint32_t fragment_reserved_chars[8] = {
+   0xFFFFFFFF, 0x5000002D, 0x78000000, 0xB8000001, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF
+};
+
+#define URI_RESERVED(C, TABLE) (!!((TABLE)[(unsigned char)(C) >> 5] & (1 << ((C) & 0x1F))))
+
+#define SCHEME_DELIMITERS     ":/?#"
+#define NETWORK_DELIMITERS    "@/?#"
+#define HOST_PORT_DELIMITERS  "/?#"
+#define PATH_DELIMITERS       "?#"
+#define QUERY_DELIMITERS      "#"
+
+/*****************************************************************************/
+/* Internal functions                                                        */
+/*****************************************************************************/
+
+static char to_hex(int v)
+{
+   if (v > 9)
+      return 'A' + v - 10;
+   return '0' + v;
+}
+
+/*****************************************************************************/
+static uint32_t from_hex(const char *str, uint32_t str_len)
+{
+   uint32_t val = 0;
+
+   while (str_len--)
+   {
+      char c = *str++;
+      if (c >= '0' && c <= '9')
+         c -= '0';
+      else if (c >= 'A' && c <= 'F')
+         c -= 'A' - 10;
+      else if (c >= 'a' && c <= 'f')
+         c -= 'a' - 10;
+      else
+         c = 0;   /* Illegal character (not hex) */
+      val = (val << 4) + c;
+   }
+
+   return val;
+}
+
+/*****************************************************************************/
+static uint32_t escaped_length( const char *str, RESERVED_CHARS_TABLE_T reserved )
+{
+   uint32_t ii;
+   uint32_t esclen = 0;
+   char c;
+
+   for (ii = strlen(str); ii > 0; ii--)
+   {
+      c = *str++;
+      if (URI_RESERVED(c, reserved))
+      {
+         /* Reserved character needs escaping as %xx */
+         esclen += 3;
+      } else {
+         esclen++;
+      }
+   }
+
+   return esclen;
+}
+
+/*****************************************************************************/
+static uint32_t escape_string( const char *str, char *escaped,
+      RESERVED_CHARS_TABLE_T reserved )
+{
+   uint32_t ii;
+   uint32_t esclen = 0;
+
+   if (!str)
+      return 0;
+
+   for (ii = strlen(str); ii > 0; ii--)
+   {
+      char c = *str++;
+
+      if (URI_RESERVED(c, reserved))
+      {
+         escaped[esclen++] = '%';
+         escaped[esclen++] = to_hex((c >> 4) & 0xF);
+         escaped[esclen++] = to_hex(c & 0xF);
+      } else {
+         escaped[esclen++] = c;
+      }
+   }
+
+   return esclen;
+}
+
+/*****************************************************************************/
+static uint32_t unescaped_length( const char *str, uint32_t str_len )
+{
+   uint32_t ii;
+   uint32_t unesclen = 0;
+
+   for (ii = 0; ii < str_len; ii++)
+   {
+      if (*str++ == '%' && (ii + 2) < str_len)
+      {
+         str += 2;  /* Should be two hex values next */
+         ii += 2;
+      }
+      unesclen++;
+   }
+
+   return unesclen;
+}
+
+/*****************************************************************************/
+static void unescape_string( const char *str, uint32_t str_len, char *unescaped )
+{
+   uint32_t ii;
+
+   for (ii = 0; ii < str_len; ii++)
+   {
+      char c = *str++;
+
+      if (c == '%' && (ii + 2) < str_len )
+      {
+         c = (char)(from_hex(str, 2) & 0xFF);
+         str += 2;
+         ii += 2;
+      }
+      *unescaped++ = c;
+   }
+
+   *unescaped = '\0';
+}
+
+/*****************************************************************************/
+static char *create_unescaped_string( const char *escstr, uint32_t esclen )
+{
+   char *unescstr;
+
+   unescstr = (char *)malloc(unescaped_length(escstr, esclen) + 1);  /* Allow for NUL */
+   if (unescstr)
+      unescape_string(escstr, esclen, unescstr);
+
+   return unescstr;
+}
+
+/*****************************************************************************/
+static bool duplicate_string( const char *src, char **p_dst )
+{
+   if (*p_dst)
+      free(*p_dst);
+
+   if (src)
+   {
+      size_t str_size = strlen(src) + 1;
+
+      *p_dst = (char *)malloc(str_size);
+      if (!*p_dst)
+         return false;
+
+      memcpy(*p_dst, src, str_size);
+   } else
+      *p_dst = NULL;
+
+   return true;
+}
+
+/*****************************************************************************/
+static void release_string( char **str )
+{
+   if (*str)
+   {
+      free(*str);
+      *str = NULL;
+   }
+}
+
+/*****************************************************************************/
+static void to_lower_string( char *str )
+{
+   char c;
+
+   while ((c = *str) != '\0')
+   {
+      if (c >= 'A' && c <= 'Z')
+         *str = c - 'A' + 'a';
+      str++;
+   }
+}
+
+/*****************************************************************************/
+static const char *vc_uri_find_delimiter(const char *str, const char *delimiters)
+{
+   const char *ptr = str;
+   char c;
+
+   while ((c = *ptr) != 0)
+   {
+      if (strchr(delimiters, c) != 0)
+         break;
+      ptr++;
+   }
+
+   return ptr;
+}
+
+/*****************************************************************************/
+static void vc_uri_set_path_extension(VC_URI_PARTS_T *p_uri)
+{
+   char *end;
+
+   if (!p_uri)
+      return;
+
+   p_uri->path_extension = NULL;
+
+   if (!p_uri->path)
+      return;
+
+   /* Look for the magic dot */
+   for (end = p_uri->path + strlen(p_uri->path); *end != '.'; end--)
+      if (end == p_uri->path || *end == '/' || *end == '\\')
+         return;
+
+   p_uri->path_extension = end + 1;
+}
+
+/*****************************************************************************/
+static bool parse_authority( VC_URI_PARTS_T *p_uri, const char *str,
+      uint32_t str_len, const char *userinfo_end )
+{
+   const char *marker = userinfo_end;
+   const char *str_end = str + str_len;
+   char c;
+
+   if (marker)
+   {
+      p_uri->userinfo = create_unescaped_string(str, marker - str);
+      if (!p_uri->userinfo)
+         return false;
+      str = marker + 1; /* Past '@' character */
+   }
+
+   if (*str == '[')     /* IPvFuture / IPv6 address */
+   {
+      /* Find end of address marker */
+      for (marker = str; marker < str_end; marker++)
+      {
+         c = *marker;
+         if (c == ']')
+            break;
+      }
+
+      if (marker < str_end)
+         marker++;   /* Found marker, move to next character */
+   } else {
+      /* Find port value marker*/
+      for (marker = str; marker < str_end; marker++)
+      {
+         c = *marker;
+         if (c == ':')
+            break;
+      }
+   }
+
+   /* Always store the host, even if empty, to trigger the "://" form of URI */
+   p_uri->host = create_unescaped_string(str, marker - str);
+   if (!p_uri->host)
+      return false;
+   to_lower_string(p_uri->host);    /* Host names are case-insensitive */
+
+   if (*marker == ':')
+   {
+      str = marker + 1;
+      p_uri->port = create_unescaped_string(str, str_end - str);
+      if (!p_uri->port)
+         return false;
+   }
+
+   return true;
+}
+
+/*****************************************************************************/
+static bool store_query( VC_URI_PARTS_T *p_uri, const char *name_start,
+      const char *equals_ptr, const char *query_end)
+{
+   uint32_t name_len, value_len;
+
+   if (equals_ptr)
+   {
+      name_len = equals_ptr - name_start;
+      value_len = query_end - equals_ptr - 1;   /* Don't include '=' itself */
+   } else {
+      name_len = query_end - name_start;
+      value_len = 0;
+   }
+
+   /* Only store something if there is a name */
+   if (name_len)
+   {
+      char *name, *value = NULL;
+      VC_URI_QUERY_T *p_query;
+
+      if (equals_ptr)
+      {
+         value = create_unescaped_string(equals_ptr + 1, value_len);
+         if (!value)
+            return false;
+         equals_ptr = query_end;
+      }
+
+      name = create_unescaped_string(name_start, name_len);
+      if (!name)
+      {
+         if (value)
+            free(value);
+         return false;
+      }
+
+      /* Store query data in URI structure */
+      p_query = &p_uri->queries[ p_uri->num_queries++ ];
+      p_query->name = name;
+      p_query->value = value;
+   }
+
+   return true;
+}
+
+/*****************************************************************************/
+static bool parse_query( VC_URI_PARTS_T *p_uri, const char *str, uint32_t str_len )
+{
+   uint32_t ii;
+   uint32_t query_count;
+   VC_URI_QUERY_T *queries;
+   const char *name_start = str;
+   const char *equals_ptr = NULL;
+   char c;
+
+   if (!str_len)
+      return true;
+
+   /* Scan for the number of query items, so array can be allocated the right size */
+   query_count = 1;  /* At least */
+   for (ii = 0; ii < str_len; ii++)
+   {
+      c = str[ii];
+
+      if (c == '&' || c ==';')
+         query_count++;
+   }
+
+   queries = (VC_URI_QUERY_T *)malloc(query_count * sizeof(VC_URI_QUERY_T));
+   if (!queries)
+      return false;
+
+   p_uri->queries = queries;
+
+   /* Go back and parse the string for each query item and store in array */
+   for (ii = 0; ii < str_len; ii++)
+   {
+      c = *str;
+
+      /* Take first '=' as break between name and value */
+      if (c == '=' && !equals_ptr)
+         equals_ptr = str;
+      
+      /* If at the end of the name or name/value pair */
+      if (c == '&' || c ==';')
+      {
+         if (!store_query(p_uri, name_start, equals_ptr, str))
+            return false;
+
+         equals_ptr = NULL;
+         name_start = str + 1;
+      }
+
+      str++;
+   }
+
+   return store_query(p_uri, name_start, equals_ptr, str);
+}
+
+/*****************************************************************************/
+static uint32_t calculate_uri_length(const VC_URI_PARTS_T *p_uri)
+{
+   uint32_t length = 0;
+   uint32_t count;
+
+   /* With no scheme, assume this is a plain path (without escaping) */
+   if (!p_uri->scheme)
+      return p_uri->path ? strlen(p_uri->path) : 0;
+
+   length += escaped_length(p_uri->scheme, scheme_reserved_chars);
+   length++; /* for the colon */
+
+   if (p_uri->host)
+   {
+      length += escaped_length(p_uri->host, host_reserved_chars) + 2;  /* for the double slash */
+      if (p_uri->userinfo)
+         length += escaped_length(p_uri->userinfo, userinfo_reserved_chars) + 1; /* for the '@' */
+      if (p_uri->port)
+         length += escaped_length(p_uri->port, port_reserved_chars) + 1;     /* for the ':' */
+   }
+
+   if (p_uri->path)
+      length += escaped_length(p_uri->path, path_reserved_chars);
+
+   count = p_uri->num_queries;
+   if (count)
+   {
+      VC_URI_QUERY_T * queries = p_uri->queries;
+
+      while (count--)
+      {
+         /* The name is preceded by either the '?' or the '&' */
+         length += escaped_length(queries->name, query_reserved_chars) + 1;
+
+         /* The value is optional, but if present will require an '=' */
+         if (queries->value)
+            length += escaped_length(queries->value, query_reserved_chars) + 1;
+         queries++;
+      }
+   }
+
+   if (p_uri->fragment)
+      length += escaped_length(p_uri->fragment, fragment_reserved_chars) + 1; /* for the '#' */
+
+   return length;
+}
+
+/*****************************************************************************/
+static void build_uri(const VC_URI_PARTS_T *p_uri, char *buffer, size_t buffer_size)
+{
+   uint32_t count;
+
+   /* With no scheme, assume this is a plain path (without escaping) */
+   if (!p_uri->scheme)
+   {
+      if (p_uri->path)
+         strncpy(buffer, p_uri->path, buffer_size);
+      else
+         buffer[0] = '\0';
+      return;
+   }
+
+   buffer += escape_string(p_uri->scheme, buffer, scheme_reserved_chars);
+   *buffer++ = ':';
+
+   if (p_uri->host)
+   {
+      *buffer++ = '/';
+      *buffer++ = '/';
+      if (p_uri->userinfo)
+      {
+         buffer += escape_string(p_uri->userinfo, buffer, userinfo_reserved_chars);
+         *buffer++ = '@';
+      }
+      buffer += escape_string(p_uri->host, buffer, host_reserved_chars);
+      if (p_uri->port)
+      {
+         *buffer++ = ':';
+         buffer += escape_string(p_uri->port, buffer, port_reserved_chars);
+      }
+   }
+
+   if (p_uri->path)
+      buffer += escape_string(p_uri->path, buffer, path_reserved_chars);
+
+   count = p_uri->num_queries;
+   if (count)
+   {
+      VC_URI_QUERY_T * queries = p_uri->queries;
+
+      *buffer++ = '?';
+      while (count--)
+      {
+         buffer += escape_string(queries->name, buffer, query_reserved_chars);
+
+         if (queries->value)
+         {
+            *buffer++ = '=';
+            buffer += escape_string(queries->value, buffer, query_reserved_chars);
+         }
+
+         /* Add separator if there is another item to add */
+         if (count)
+            *buffer++ = '&';
+
+         queries++;
+      }
+   }
+
+   if (p_uri->fragment)
+   {
+      *buffer++ = '#';
+      buffer += escape_string(p_uri->fragment, buffer, fragment_reserved_chars);
+   }
+
+   *buffer = '\0';
+}
+
+/*****************************************************************************/
+static bool vc_uri_copy_base_path( const VC_URI_PARTS_T *base_uri,
+      VC_URI_PARTS_T *relative_uri )
+{
+   const char *base_path = vc_uri_path(base_uri);
+
+   /* No path set (or empty), copy from base */
+   if (!vc_uri_set_path(relative_uri, base_path))
+      return false;
+
+   /* If relative path has no queries, copy base queries across */
+   if (!vc_uri_num_queries(relative_uri))
+   {
+      uint32_t base_queries = vc_uri_num_queries(base_uri);
+      const char *name, *value;
+      uint32_t ii;
+
+      for (ii = 0; ii < base_queries; ii++)
+      {
+         vc_uri_query(base_uri, ii, &name, &value);
+         if (!vc_uri_add_query(relative_uri, name, value))
+            return false;
+      }
+   }
+
+   return true;
+}
+
+/*****************************************************************************/
+static void vc_uri_remove_single_dot_segments( char *path_str )
+{
+   char *slash = path_str - 1;
+
+   while (slash++)
+   {
+      if (*slash == '.')
+      {
+         switch (slash[1])
+         {
+         case '/':   /* Single dot segment, remove it */
+            memmove(slash, slash + 2, strlen(slash + 2) + 1);
+            break;
+         case '\0':  /* Trailing single dot, remove it */
+            *slash = '\0';
+            break;
+         default:    /* Something else (e.g. ".." or ".foo") */
+            ;  /* Do nothing */
+         }
+      }
+      slash = strchr(slash, '/');
+   }
+}
+
+/*****************************************************************************/
+static void vc_uri_remove_double_dot_segments( char *path_str )
+{
+   char *previous_segment = path_str;
+   char *slash;
+
+   if (previous_segment[0] == '/')
+      previous_segment++;
+
+   /* Remove strings of the form "<segment>/../" (or "<segment>/.." at the end of the path)
+    * as long as <segment> is not itself ".." */
+   slash = strchr(previous_segment, '/');
+   while (slash)
+   {
+      if (previous_segment[0] != '.' || previous_segment[1] != '.' || previous_segment[2] != '/')
+      {
+         if (slash[1] == '.' && slash[2] == '.')
+         {
+            bool previous_segment_removed = true;
+
+            switch (slash[3])
+            {
+            case '/':   /* "/../" inside path, snip it and last segment out */
+               memmove(previous_segment, slash + 4, strlen(slash + 4) + 1);
+               break;
+            case '\0':  /* Trailing "/.." on path, just terminate path at last segment */
+               *previous_segment = '\0';
+               break;
+            default:    /* Not a simple ".." segment, so skip over it */
+               previous_segment_removed = false;
+            }
+
+            if (previous_segment_removed)
+            {
+               /* The segment just removed was the first one in the path (optionally
+                * prefixed by a slash), so no more can be removed: stop. */
+               if (previous_segment < path_str + 2)
+                  break;
+
+               /* Move back to slash before previous segment, or the start of the path */
+               slash = previous_segment - 1;
+               while (--slash >= path_str && *slash != '/')
+                  ; /* Everything done in the while */
+            }
+         }
+      }
+      previous_segment = slash + 1;
+      slash = strchr(previous_segment, '/');
+   }
+}
+
+/*****************************************************************************/
+/* API functions                                                             */
+/*****************************************************************************/
+
+VC_URI_PARTS_T *vc_uri_create( void )
+{
+   VC_URI_PARTS_T *p_uri;
+
+   p_uri = (VC_URI_PARTS_T *)malloc(sizeof(VC_URI_PARTS_T));
+   if (p_uri)
+   {
+      memset(p_uri, 0, sizeof(VC_URI_PARTS_T));
+   }
+
+   return p_uri;
+}
+
+/*****************************************************************************/
+void vc_uri_clear( VC_URI_PARTS_T *p_uri )
+{
+   if (!p_uri)
+      return;
+
+   release_string(&p_uri->scheme);
+   release_string(&p_uri->userinfo);
+   release_string(&p_uri->host);
+   release_string(&p_uri->port);
+   release_string(&p_uri->path);
+   release_string(&p_uri->fragment);
+
+   if (p_uri->queries)
+   {
+      VC_URI_QUERY_T *queries = p_uri->queries;
+      uint32_t count = p_uri->num_queries;
+
+      while (count--)
+      {
+         release_string(&queries[count].name);
+         release_string(&queries[count].value);
+      }
+
+      free(queries);
+      p_uri->queries = NULL;
+      p_uri->num_queries = 0;
+   }
+}
+
+/*****************************************************************************/
+void vc_uri_release( VC_URI_PARTS_T *p_uri )
+{
+   if (!p_uri)
+      return;
+
+   vc_uri_clear(p_uri);
+
+   free(p_uri);
+}
+
+/*****************************************************************************/
+bool vc_uri_parse( VC_URI_PARTS_T *p_uri, const char *uri )
+{
+   const char *marker;
+   uint32_t len;
+
+   if (!p_uri || !uri)
+      return false;
+
+   vc_uri_clear(p_uri);
+
+   /* URI = scheme ":" hier_part [ "?" query ] [ "#" fragment ] */
+
+   /* Find end of scheme, or another separator */
+   marker = vc_uri_find_delimiter(uri, SCHEME_DELIMITERS);
+
+   if (*marker == ':')
+   {
+      len = (marker - uri);
+      if (isalpha((int)*uri) && len == 1 && marker[1] == '\\')
+      {
+         /* Looks like a bare, absolute DOS/Windows filename with a drive letter */
+         /* coverity[double_free] Pointer freed and set to NULL */
+         bool ret = duplicate_string(uri, &p_uri->path);
+         vc_uri_set_path_extension(p_uri);
+         return ret;
+      }
+
+      p_uri->scheme = create_unescaped_string(uri, len);
+      if (!p_uri->scheme)
+         goto error;
+
+      to_lower_string(p_uri->scheme);  /* Schemes should be handled case-insensitively */
+      uri = marker + 1;
+   }
+
+   if (uri[0] == '/' && uri[1] == '/') /* hier-part includes authority */
+   {
+      const char *userinfo_end = NULL;
+
+      /* authority = [ userinfo "@" ] host [ ":" port ] */
+      uri += 2;
+
+      marker = vc_uri_find_delimiter(uri, NETWORK_DELIMITERS);
+      if (*marker == '@')
+      {
+         userinfo_end = marker;
+         marker = vc_uri_find_delimiter(marker + 1, HOST_PORT_DELIMITERS);
+      }
+
+      if (!parse_authority(p_uri, uri, marker - uri, userinfo_end))
+         goto error;
+      uri = marker;
+   }
+
+   /* path */
+   marker = vc_uri_find_delimiter(uri, PATH_DELIMITERS);
+   len = marker - uri;
+   if (len)
+   {
+      p_uri->path = create_unescaped_string(uri, len);
+      vc_uri_set_path_extension(p_uri);
+      if (!p_uri->path)
+         goto error;
+   }
+
+   /* query */
+   if (*marker == '?')
+   {
+      uri = marker + 1;
+      marker = vc_uri_find_delimiter(uri, QUERY_DELIMITERS);
+      if (!parse_query(p_uri, uri, marker - uri))
+         goto error;
+   }
+
+   /* fragment */
+   if (*marker == '#')
+   {
+      uri = marker + 1;
+      p_uri->fragment = create_unescaped_string(uri, strlen(uri));
+      if (!p_uri->fragment)
+         goto error;
+   }
+
+   return true;
+
+error:
+   vc_uri_clear(p_uri);
+   return false;
+}
+
+/*****************************************************************************/
+uint32_t vc_uri_build( const VC_URI_PARTS_T *p_uri, char *buffer, size_t buffer_size )
+{
+   uint32_t required_length;
+
+   if (!p_uri)
+      return 0;
+
+   required_length = calculate_uri_length(p_uri);
+   if (buffer && required_length < buffer_size)  /* Allow for NUL */
+      build_uri(p_uri, buffer, buffer_size);
+
+   return required_length;
+}
+
+/*****************************************************************************/
+const char *vc_uri_scheme( const VC_URI_PARTS_T *p_uri )
+{
+   return p_uri ? p_uri->scheme : NULL;
+}
+
+/*****************************************************************************/
+const char *vc_uri_userinfo( const VC_URI_PARTS_T *p_uri )
+{
+   return p_uri ? p_uri->userinfo : NULL;
+}
+
+/*****************************************************************************/
+const char *vc_uri_host( const VC_URI_PARTS_T *p_uri )
+{
+   return p_uri ? p_uri->host : NULL;
+}
+
+/*****************************************************************************/
+const char *vc_uri_port( const VC_URI_PARTS_T *p_uri )
+{
+   return p_uri ? p_uri->port : NULL;
+}
+
+/*****************************************************************************/
+const char *vc_uri_path( const VC_URI_PARTS_T *p_uri )
+{
+   return p_uri ? p_uri->path : NULL;
+}
+
+/*****************************************************************************/
+const char *vc_uri_path_extension( const VC_URI_PARTS_T *p_uri )
+{
+   return p_uri ? p_uri->path_extension : NULL;
+}
+
+/*****************************************************************************/
+const char *vc_uri_fragment( const VC_URI_PARTS_T *p_uri )
+{
+   return p_uri ? p_uri->fragment : NULL;
+}
+
+/*****************************************************************************/
+uint32_t vc_uri_num_queries( const VC_URI_PARTS_T *p_uri )
+{
+   return p_uri ? p_uri->num_queries : 0;
+}
+
+/*****************************************************************************/
+void vc_uri_query( const VC_URI_PARTS_T *p_uri, uint32_t index, const char **p_name, const char **p_value )
+{
+   const char *name = NULL;
+   const char *value = NULL;
+
+   if (p_uri)
+   {
+      if (index < p_uri->num_queries)
+      {
+         name = p_uri->queries[index].name;
+         value = p_uri->queries[index].value;
+      }
+   }
+
+   if (p_name)
+      *p_name = name;
+   if (p_value)
+      *p_value = value;
+}
+
+/*****************************************************************************/
+bool vc_uri_find_query( VC_URI_PARTS_T *p_uri, uint32_t *p_index, const char *name, const char **p_value )
+{
+   unsigned int i = p_index ? *p_index : 0;
+
+   if (!p_uri)
+      return false;
+
+   for (; name && i < p_uri->num_queries; i++)
+   {
+      if (!strcmp(name, p_uri->queries[i].name))
+      {
+         if (p_value)
+            *p_value = p_uri->queries[i].value;
+         if (p_index)
+            *p_index = i;
+         return true;
+      }
+   }
+
+   return false;
+}
+
+/*****************************************************************************/
+bool vc_uri_set_scheme( VC_URI_PARTS_T *p_uri, const char *scheme )
+{
+   return p_uri ? duplicate_string(scheme, &p_uri->scheme) : false;
+}
+
+/*****************************************************************************/
+bool vc_uri_set_userinfo( VC_URI_PARTS_T *p_uri, const char *userinfo )
+{
+   return p_uri ? duplicate_string(userinfo, &p_uri->userinfo) : false;
+}
+
+/*****************************************************************************/
+bool vc_uri_set_host( VC_URI_PARTS_T *p_uri, const char *host )
+{
+   return p_uri ? duplicate_string(host, &p_uri->host) : false;
+}
+
+/*****************************************************************************/
+bool vc_uri_set_port( VC_URI_PARTS_T *p_uri, const char *port )
+{
+   return p_uri ? duplicate_string(port, &p_uri->port) : false;
+}
+
+/*****************************************************************************/
+bool vc_uri_set_path( VC_URI_PARTS_T *p_uri, const char *path )
+{
+   bool ret = p_uri ? duplicate_string(path, &p_uri->path) : false;
+   vc_uri_set_path_extension(p_uri);
+   return ret;
+}
+
+/*****************************************************************************/
+bool vc_uri_set_fragment( VC_URI_PARTS_T *p_uri, const char *fragment )
+{
+   return p_uri ? duplicate_string(fragment, &p_uri->fragment) : false;
+}
+
+/*****************************************************************************/
+bool vc_uri_add_query( VC_URI_PARTS_T *p_uri, const char *name, const char *value )
+{
+   VC_URI_QUERY_T *queries;
+   uint32_t count;
+
+   if (!p_uri || !name)
+      return false;
+
+   count = p_uri->num_queries;
+   if (p_uri->queries)
+      queries = (VC_URI_QUERY_T *)realloc(p_uri->queries, (count + 1) * sizeof(VC_URI_QUERY_T));
+   else
+      queries = (VC_URI_QUERY_T *)malloc(sizeof(VC_URI_QUERY_T));
+
+   if (!queries)
+      return false;
+
+   /* Always store the pointer, in case it has changed, and even if we fail to copy name/value */
+   p_uri->queries = queries;
+   queries[count].name = NULL;
+   queries[count].value = NULL;
+
+   if (duplicate_string(name, &queries[count].name))
+   {
+      if (duplicate_string(value, &queries[count].value))
+      {
+         /* Successful exit path */
+         p_uri->num_queries++;
+         return true;
+      }
+
+      release_string(&queries[count].name);
+   }
+
+   return false;
+}
+
+/*****************************************************************************/
+bool vc_uri_merge( const VC_URI_PARTS_T *base_uri, VC_URI_PARTS_T *relative_uri )
+{
+   bool success = true;
+   const char *relative_path;
+
+   /* If scheme is already set, the URI is already absolute */
+   if (relative_uri->scheme)
+      return true;
+
+   /* Otherwise, copy the base scheme */
+   if (!duplicate_string(base_uri->scheme, &relative_uri->scheme))
+      return false;
+
+   /* If any of the network info is set, use the rest of the relative URI as-is */
+   if (relative_uri->host || relative_uri->port || relative_uri->userinfo)
+      return true;
+
+   /* Otherwise, copy the base network info */
+   if (!duplicate_string(base_uri->host, &relative_uri->host) ||
+         !duplicate_string(base_uri->port, &relative_uri->port) ||
+         !duplicate_string(base_uri->userinfo, &relative_uri->userinfo))
+      return false;
+
+   relative_path = relative_uri->path;
+
+   if (!relative_path || !*relative_path)
+   {
+      /* No relative path (could be queries and/or fragment), so take base path */
+      success = vc_uri_copy_base_path(base_uri, relative_uri);
+   }
+   else if (*relative_path != '/')
+   {
+      const char *base_path = base_uri->path;
+      char *merged_path;
+      char *slash;
+      size_t len;
+
+      /* Path is relative, merge in with base path */
+      if (!base_path || !*base_path)
+      {
+         if (relative_uri->host || relative_uri->port || relative_uri->userinfo)
+            base_path = "/";  /* Need a separator to split network info from path */
+         else
+            base_path = "";
+      }
+
+      len = strlen(base_path) + strlen(relative_path) + 1;
+
+      /* Allocate space for largest possible combined path */
+      merged_path = (char *)malloc(len);
+      if (!merged_path)
+         return false;
+
+      strncpy(merged_path, base_path, len);
+
+      slash = strrchr(merged_path, '/');  /* Note: reverse search */
+      if (*relative_path == ';')
+      {
+         char *semi;
+
+         /* Relative path is just parameters, so remove any base parameters in final segment */
+         if (!slash)
+            slash = merged_path;
+         semi = strchr(slash, ';');
+         if (semi)
+            semi[0] = '\0';
+      } else {
+         /* Remove final segment */
+         if (slash)
+            slash[1] = '\0';
+         else
+            merged_path[0] = '\0';
+      }
+      strncat(merged_path, relative_path, len - strlen(merged_path) - 1);
+
+      vc_uri_remove_single_dot_segments(merged_path);
+      vc_uri_remove_double_dot_segments(merged_path);
+
+      success = duplicate_string(merged_path, &relative_uri->path);
+
+      free(merged_path);
+   }
+   /* Otherwise path is absolute, which can be left as-is */
+
+   return success;
+}
diff --git a/containers/core/containers_uri.h b/containers/core/containers_uri.h
new file mode 100755 (executable)
index 0000000..77a06e7
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VC_CONTAINERS_URI_H
+#define VC_CONTAINERS_URI_H
+
+/** \file containers_uri.h
+ * API for parsing and building URI strings as described in RFC3986.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "containers/containers.h"
+
+typedef struct VC_URI_PARTS_T VC_URI_PARTS_T;
+
+/** Create an empty URI structure.
+ *
+ * \return The new URI structure. */
+VC_URI_PARTS_T *vc_uri_create( void );
+
+/** Destroy a URI structure.
+ *
+ * \param p_uri Pointer to a URI parts structure. */
+void vc_uri_release( VC_URI_PARTS_T *p_uri );
+
+/** Clear a URI structure.
+ * Any URI component strings held are released, but the structure itself is not.
+ *
+ * \param p_uri Pointer to a URI parts structure. */
+void vc_uri_clear( VC_URI_PARTS_T *p_uri );
+
+/** Parses and unescapes a URI into the component parts.
+ *
+ * \param p_uri Pointer to a URI parts structure.
+ * \param uri Pointer to a URI string to be parsed.
+ * \return True if successful, false if not. */
+bool vc_uri_parse( VC_URI_PARTS_T *p_uri, const char *uri );
+
+/** Builds the URI component parts into a URI string.
+ * If buffer is NULL, or buffer_size is too small, nothing is written to the 
+ * buffer but the required string length is still returned. buffer_size must be
+ * at least one more than the value returned.
+ *
+ * \param p_uri Pointer to a URI parts structure.
+ * \param buffer Pointer to where the URI string is to be built, or NULL.
+ * \param buffer_size Number of bytes available in the buffer.
+ * \return The length of the URI string. */
+uint32_t vc_uri_build( const VC_URI_PARTS_T *p_uri, char *buffer, size_t buffer_size );
+
+/** Retrieves the scheme of the URI.
+ * The string is valid until either the scheme is changed or the URI is released.
+ *
+ * \param p_uri The parsed URI.
+ * \return Pointer to the scheme string. */
+const char *vc_uri_scheme( const VC_URI_PARTS_T *p_uri );
+
+/** Retrieves the userinfo of the URI.
+ * The string is valid until either the userinfo is changed or the URI is released.
+ *
+ * \param p_uri The parsed URI.
+ * \return Pointer to the userinfo string. */
+const char *vc_uri_userinfo( const VC_URI_PARTS_T *p_uri );
+
+/** Retrieves the host of the URI.
+ * The string is valid until either the host is changed or the URI is released.
+ *
+ * \param p_uri The parsed URI.
+ * \return Pointer to the host string. */
+const char *vc_uri_host( const VC_URI_PARTS_T *p_uri );
+
+/** Retrieves the port of the URI.
+ * The string is valid until either the port is changed or the URI is released.
+ *
+ * \param p_uri The parsed URI.
+ * \return Pointer to the port string. */
+const char *vc_uri_port( const VC_URI_PARTS_T *p_uri );
+
+/** Retrieves the path of the URI.
+ * The string is valid until either the path is changed or the URI is released.
+ *
+ * \param p_uri The parsed URI.
+ * \return Pointer to the path string. */
+const char *vc_uri_path( const VC_URI_PARTS_T *p_uri );
+
+/** Retrieves the extension part of the path of the URI.
+ * The string is valid until either the path is changed or the URI is released.
+ *
+ * \param p_uri The parsed URI.
+ * \return Pointer to the extension string. */
+const char *vc_uri_path_extension( const VC_URI_PARTS_T *p_uri );
+
+/** Retrieves the fragment of the URI.
+ * The string is valid until either the fragment is changed or the URI is released.
+ *
+ * \param p_uri The parsed URI.
+ * \return Pointer to the fragment string. */
+const char *vc_uri_fragment( const VC_URI_PARTS_T *p_uri );
+
+/** Returns the number of query name/value pairs stored.
+ *
+ * \param p_uri The parsed URI.
+ * \return Number of queries stored. */
+uint32_t vc_uri_num_queries( const VC_URI_PARTS_T *p_uri );
+
+/** Retrieves a given query's name and value
+ * If either p_name or p_value are NULL, that part of the query is not returned,
+ * otherwise it is set to the address of the string (which may itself be NULL).
+ *
+ * \param p_uri The parsed URI.
+ * \param index Selects the query to get.
+ * \param p_name Address of a string pointer to receive query name, or NULL.
+ * \param p_value Address of a string pointer to receive query value, or NULL. */
+void vc_uri_query( const VC_URI_PARTS_T *p_uri, uint32_t index, const char **p_name, const char **p_value );
+
+/** Finds a specific query in the array.
+ * If p_index is NULL, then it is assumed the search should start at index 0,
+ * otherwise the search will start at the specified index and the index will
+ * be updated on return to point to the query which has been found.
+ * If p_value is NULL, that part of the query is not returned,
+ * otherwise it is set to the address of the value string (which may itself be NULL).
+ *
+ * \param p_uri Pointer to a URI parts structure.
+ * \param p_index Index from which to start the search. May be NULL.
+ * \param name Unescaped query name.
+ * \param value Unescaped query value. May be NULL.
+ * \return True if successful, false if not. */
+bool vc_uri_find_query( VC_URI_PARTS_T *p_uri, uint32_t *p_index, const char *name, const char **p_value );
+
+/** Sets the scheme of the URI.
+ * The string will be copied and stored in the URI, releasing and replacing
+ * any existing string. If NULL is passed, any existing string shall simply be
+ * released.
+ *
+ * \param p_uri The parsed URI.
+ * \param scheme Pointer to the new scheme string, or NULL.
+ * \return True if successful, false on memory allocation failure. */
+bool vc_uri_set_scheme( VC_URI_PARTS_T *p_uri, const char *scheme );
+
+/** Sets the userinfo of the URI.
+ * The string will be copied and stored in the URI, releasing and replacing
+ * any existing string. If NULL is passed, any existing string shall simply be
+ * released.
+ *
+ * \param p_uri The parsed URI.
+ * \param userinfo Pointer to the new userinfo string, or NULL.
+ * \return True if successful, false on memory allocation failure. */
+bool vc_uri_set_userinfo( VC_URI_PARTS_T *p_uri, const char *userinfo );
+
+/** Sets the host of the URI.
+ * The string will be copied and stored in the URI, releasing and replacing
+ * any existing string. If NULL is passed, any existing string shall simply be
+ * released.
+ *
+ * \param p_uri The parsed URI.
+ * \param host Pointer to the new host string, or NULL.
+ * \return True if successful, false on memory allocation failure. */
+bool vc_uri_set_host( VC_URI_PARTS_T *p_uri, const char *host );
+
+/** Sets the port of the URI.
+ * The string will be copied and stored in the URI, releasing and replacing
+ * any existing string. If NULL is passed, any existing string shall simply be
+ * released.
+ *
+ * \param p_uri The parsed URI.
+ * \param port Pointer to the new port string, or NULL.
+ * \return True if successful, false on memory allocation failure. */
+bool vc_uri_set_port( VC_URI_PARTS_T *p_uri, const char *port );
+
+/** Sets the path of the URI.
+ * The string will be copied and stored in the URI, releasing and replacing
+ * any existing string. If NULL is passed, any existing string shall simply be
+ * released.
+ *
+ * \param p_uri The parsed URI.
+ * \param path Pointer to the new path string, or NULL.
+ * \return True if successful, false on memory allocation failure. */
+bool vc_uri_set_path( VC_URI_PARTS_T *p_uri, const char *path );
+
+/** Sets the fragment of the URI.
+ * The string will be copied and stored in the URI, releasing and replacing
+ * any existing string. If NULL is passed, any existing string shall simply be
+ * released.
+ *
+ * \param p_uri The parsed URI.
+ * \param fragment Pointer to the new fragment string, or NULL.
+ * \return True if successful, false on memory allocation failure. */
+bool vc_uri_set_fragment( VC_URI_PARTS_T *p_uri, const char *fragment );
+
+/** Adds an query to the array.
+ * Note that the queries pointer may change after this function is called.
+ * May fail due to memory allocation failure or invalid parameters.
+ *
+ * \param p_uri Pointer to a URI parts structure.
+ * \param name Unescaped query name.
+ * \param value Unescaped query value. May be NULL.
+ * \return True if successful, false if not. */
+bool vc_uri_add_query( VC_URI_PARTS_T *p_uri, const char *name, const char *value );
+
+/** Merge a base URI and a relative URI.
+ * In general, where the relative URI does not have a given element, the
+ * corresponding element from the base URI is used. See RFC1808.
+ * The combined URI is left in relative_uri. If the function is unsuccessful,
+ * the relative_uri may have been partially modified.
+ *
+ * \param base_uri Pointer to the base URI parts structure.
+ * \param relative_uri Pointer to the relative URI parts structure.
+ * \return True if successful, false if not. */
+bool vc_uri_merge( const VC_URI_PARTS_T *base_uri, VC_URI_PARTS_T *relative_uri );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* VC_CONTAINERS_URI_H */
diff --git a/containers/core/containers_utils.c b/containers/core/containers_utils.c
new file mode 100755 (executable)
index 0000000..477093f
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "containers/containers.h"
+#include "containers/core/containers_common.h"
+#include "containers/core/containers_utils.h"
+
+/******************************************************************************
+Defines.
+******************************************************************************/
+#define BITMAPINFOHEADER_SIZE_MAX 40
+#define MAX_EXTENSION_SIZE 4
+
+#define VC_CONTAINER_ES_FORMAT_MAGIC ((uint32_t)VC_FOURCC('m','a','g','f'))
+#define EXTRADATA_SIZE_DEFAULT 32
+#define EXTRADATA_SIZE_MAX (10*1024)
+
+/*****************************************************************************/
+typedef struct VC_CONTAINER_ES_FORMAT_PRIVATE_T
+{
+   VC_CONTAINER_ES_FORMAT_T format;
+   VC_CONTAINER_ES_SPECIFIC_FORMAT_T type;
+
+   uint32_t magic;
+
+   unsigned int extradata_size;
+   uint8_t *extradata;
+
+   uint8_t buffer[EXTRADATA_SIZE_DEFAULT];
+
+} VC_CONTAINER_ES_FORMAT_PRIVATE_T;
+
+/*****************************************************************************/
+VC_CONTAINER_ES_FORMAT_T *vc_container_format_create(unsigned int extradata_size)
+{
+   VC_CONTAINER_ES_FORMAT_PRIVATE_T *private;
+   VC_CONTAINER_STATUS_T status;
+
+   private = malloc(sizeof(*private));
+   if(!private) return 0;
+   memset(private, 0, sizeof(*private));
+
+   private->magic = VC_CONTAINER_ES_FORMAT_MAGIC;
+   private->format.type = (void *)&private->type;
+   private->extradata_size = EXTRADATA_SIZE_DEFAULT;
+
+   status = vc_container_format_extradata_alloc(&private->format, extradata_size);
+   if(status != VC_CONTAINER_SUCCESS)
+   {
+      free(private);
+      return NULL;
+   }
+
+   return &private->format;
+}
+
+/*****************************************************************************/
+void vc_container_format_delete(VC_CONTAINER_ES_FORMAT_T *format)
+{
+   VC_CONTAINER_ES_FORMAT_PRIVATE_T *private = (VC_CONTAINER_ES_FORMAT_PRIVATE_T *)format;
+   vc_container_assert(private->magic == VC_CONTAINER_ES_FORMAT_MAGIC);
+   if(private->extradata) free(private->extradata);
+   free(private);
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_format_extradata_alloc(
+   VC_CONTAINER_ES_FORMAT_T *format, unsigned int size)
+{
+   VC_CONTAINER_ES_FORMAT_PRIVATE_T *private = (VC_CONTAINER_ES_FORMAT_PRIVATE_T *)format;
+   vc_container_assert(private->magic == VC_CONTAINER_ES_FORMAT_MAGIC);
+
+   /* Sanity check the size requested */
+   if(size > EXTRADATA_SIZE_MAX)
+      return VC_CONTAINER_ERROR_CORRUPTED;
+
+   /* Allocate memory if needed */
+   if(private->extradata_size < size)
+   {
+      if(private->extradata) free(private->extradata);
+      private->extradata = malloc(size);
+      if(!private->extradata)
+         return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+      private->extradata_size = size;
+   }
+
+   /* Set the fields in the actual format structure */
+   if(private->extradata) private->format.extradata = private->extradata;
+   else private->format.extradata = private->buffer;
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_format_copy( VC_CONTAINER_ES_FORMAT_T *p_out,
+                                                VC_CONTAINER_ES_FORMAT_T *p_in,
+                                                unsigned int extra_buffer_size)
+{
+   void *type = p_out->type;
+   uint8_t *extradata = p_out->extradata;
+
+   /* Check we have a sufficient buffer to copy the extra data */
+   if(p_in->extradata_size > extra_buffer_size ||
+      (p_in->extradata_size && !p_out->extradata))
+      return VC_CONTAINER_ERROR_BUFFER_TOO_SMALL;
+
+   *p_out->type = *p_in->type;
+   *p_out = *p_in;
+   p_out->type = type;
+   p_out->extradata = extradata;
+   if(p_in->extradata_size)
+      memcpy(p_out->extradata, p_in->extradata, p_in->extradata_size);
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+int utf8_from_charset(const char *charset, char *out, unsigned int out_size,
+                      const void *in, unsigned int in_size)
+{
+   unsigned int i;
+   const uint16_t *in16 = (const uint16_t *)in;
+   const uint8_t *in8 = (const uint8_t *)in;
+
+   if(out_size < 1) return 1;
+   if(!strcmp(charset, "UTF16-LE")) goto utf16le;
+   if(!strcmp(charset, "UTF8")) goto utf8;
+   else return 1;
+
+ utf16le:
+   for(i = 0; i < in_size / 2 && in16[i] && i < out_size - 1; i++)
+   {
+      out[i] = in16[i];
+   }
+   out[i] = 0;
+   return 0;
+
+ utf8:
+   for(i = 0; i < in_size && in8[i] && i < out_size - 1; i++)
+   {
+      out[i] = in8[i];
+   }
+   out[i] = 0;
+   return 0;
+}
+
+/*****************************************************************************/
+unsigned int vc_container_es_format_to_waveformatex(VC_CONTAINER_ES_FORMAT_T *format,
+                                                    uint8_t *buffer, unsigned int buffer_size)
+{
+   uint16_t waveformat = codec_to_waveformat(format->codec);
+
+   if(format->es_type != VC_CONTAINER_ES_TYPE_AUDIO ||
+      waveformat == WAVE_FORMAT_UNKNOWN) return 0;
+
+   if(!buffer) return format->extradata_size + 18;
+
+   if(buffer_size < format->extradata_size + 18) return 0;
+
+   /* Build a waveformatex header */
+   buffer[0] = waveformat;
+   buffer[1] = waveformat >> 8;
+   buffer[2] = format->type->audio.channels;
+   buffer[3] = 0;
+   buffer[4] = (format->type->audio.sample_rate >> 0) & 0xFF;
+   buffer[5] = (format->type->audio.sample_rate >> 8) & 0xFF;
+   buffer[6] = (format->type->audio.sample_rate >> 16) & 0xFF;
+   buffer[7] = (format->type->audio.sample_rate >> 24) & 0xFF;
+   buffer[8] = (format->bitrate >> 3) & 0xFF;
+   buffer[9] = (format->bitrate >> 11) & 0xFF;
+   buffer[10] = (format->bitrate >> 19) & 0xFF;
+   buffer[11] = (format->bitrate >> 27) & 0xFF;
+   buffer[12] = (format->type->audio.block_align >> 0) & 0xFF;
+   buffer[13] = (format->type->audio.block_align >> 8) & 0xFF;
+   buffer[14] = (format->type->audio.bits_per_sample >> 0) & 0xFF;
+   buffer[15] = (format->type->audio.bits_per_sample >> 8) & 0xFF;
+   buffer[16] = (format->extradata_size >> 0) & 0xFF;
+   buffer[17] = (format->extradata_size >> 8) & 0xFF;
+   memcpy(buffer+18, format->extradata, format->extradata_size);
+   return format->extradata_size + 18;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_waveformatex_to_es_format(uint8_t *p,
+   unsigned int buffer_size, unsigned int *extra_offset, unsigned int *extra_size,
+   VC_CONTAINER_ES_FORMAT_T *format)
+{
+   VC_CONTAINER_FOURCC_T fourcc;
+   uint32_t waveformat_id;
+
+   if(!p || buffer_size < 16) return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+   waveformat_id = (p[1] << 8) | p[0];
+   fourcc = waveformat_to_codec(waveformat_id);
+
+   /* Read the waveformatex header */
+   if(extra_offset) *extra_offset = 16;
+   if(extra_size) *extra_size = 0;
+   format->type->audio.channels = p[2];
+   format->type->audio.sample_rate = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
+   format->bitrate = ((p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8]) * 8;
+   format->type->audio.block_align = (p[13] << 8) | p[12];
+   format->type->audio.bits_per_sample = (p[15] << 8) | p[14];
+
+   if(waveformat_id == WAVE_FORMAT_PCM && format->type->audio.bits_per_sample == 8)
+      fourcc = VC_CONTAINER_CODEC_PCM_UNSIGNED_LE;
+
+   if(buffer_size >= 18)
+   {
+      if(extra_size)
+      {
+         *extra_size = (p[17] << 8) | p[16];
+         if(*extra_size + 18 > buffer_size) *extra_size = buffer_size - 18;
+      }
+      if(extra_offset) *extra_offset = 18;
+   }
+
+   /* Skip the MPEGLAYER3WAVEFORMAT structure */
+   if(waveformat_id == WAVE_FORMAT_MPEGLAYER3 && extra_size)
+   {
+      if(extra_offset) *extra_offset += *extra_size;
+      *extra_size = 0;
+   }
+
+   format->es_type = VC_CONTAINER_ES_TYPE_AUDIO;
+   format->codec = fourcc;
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+unsigned int vc_container_es_format_to_bitmapinfoheader(VC_CONTAINER_ES_FORMAT_T *format,
+                                                        uint8_t *buffer, unsigned int buffer_size)
+{
+   uint32_t fourcc = codec_to_vfw_fourcc(format->codec);
+   uint32_t size = BITMAPINFOHEADER_SIZE_MAX + format->extradata_size;
+
+   if(format->es_type != VC_CONTAINER_ES_TYPE_VIDEO ||
+      fourcc == VC_CONTAINER_CODEC_UNKNOWN) return 0;
+
+   if(!buffer) return size;
+   if(buffer_size < size) return 0;
+
+   /* Build a bitmapinfoheader header */
+   memset(buffer, 0, BITMAPINFOHEADER_SIZE_MAX);
+   buffer[0] = (size >> 0) & 0xFF;
+   buffer[1] = (size >> 8) & 0xFF;
+   buffer[2] = (size >> 16) & 0xFF;
+   buffer[3] = (size >> 24) & 0xFF;
+   buffer[4] = (format->type->video.width >> 0) & 0xFF;
+   buffer[5] = (format->type->video.width >> 8) & 0xFF;
+   buffer[6] = (format->type->video.width >> 16) & 0xFF;
+   buffer[7] = (format->type->video.width >> 24) & 0xFF;
+   buffer[8] = (format->type->video.height >> 0) & 0xFF;
+   buffer[9] = (format->type->video.height >> 8) & 0xFF;
+   buffer[10] = (format->type->video.height >> 16) & 0xFF;
+   buffer[11] = (format->type->video.height >> 24) & 0xFF;
+   memcpy(buffer + 16, &fourcc, 4);
+   memcpy(buffer + BITMAPINFOHEADER_SIZE_MAX, format->extradata, format->extradata_size);
+   return size;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_bitmapinfoheader_to_es_format(uint8_t *p,
+   unsigned int buffer_size, unsigned int *extra_offset, unsigned int *extra_size, 
+   VC_CONTAINER_ES_FORMAT_T *format)
+{
+   VC_CONTAINER_FOURCC_T fourcc;
+   
+   if(!p || buffer_size < BITMAPINFOHEADER_SIZE_MAX) return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+   /* size = (p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]; */
+   format->type->video.width = (p[7] << 24) | (p[6] << 16) | (p[5] << 8) | p[4];
+   format->type->video.height = (p[11] << 24) | (p[10] << 16) | (p[9] << 8) | p[8];
+   memcpy(&fourcc, p + 16, 4);
+  
+   format->es_type = VC_CONTAINER_ES_TYPE_VIDEO;
+   format->codec = vfw_fourcc_to_codec(fourcc);
+   
+   /* If no mapping is found from vfw, try a more generic one */
+   if (format->codec == fourcc && (fourcc = fourcc_to_codec(fourcc)) != VC_CONTAINER_CODEC_UNKNOWN)
+      format->codec = fourcc;
+
+   if(extra_offset) *extra_offset = BITMAPINFOHEADER_SIZE_MAX;
+   if(extra_size) 
+   {
+      if (buffer_size > BITMAPINFOHEADER_SIZE_MAX)
+         *extra_size = buffer_size - BITMAPINFOHEADER_SIZE_MAX;
+      else
+         *extra_size = 0;
+   }
+
+   return VC_CONTAINER_SUCCESS;   
+}
+
+/*****************************************************************************/
+static struct {
+   VC_CONTAINER_METADATA_KEY_T key;
+   const char *name;
+} meta_key_conv[] =
+{  {VC_CONTAINER_METADATA_KEY_TITLE, "title"},
+   {VC_CONTAINER_METADATA_KEY_ARTIST, "artist"},
+   {VC_CONTAINER_METADATA_KEY_ALBUM, "album"},
+   {VC_CONTAINER_METADATA_KEY_DESCRIPTION, "description"},
+   {VC_CONTAINER_METADATA_KEY_YEAR, "year"},
+   {VC_CONTAINER_METADATA_KEY_GENRE, "genre"},
+   {VC_CONTAINER_METADATA_KEY_TRACK, "track"},
+   {VC_CONTAINER_METADATA_KEY_LYRICS, "lyrics"},
+   {VC_CONTAINER_METADATA_KEY_UNKNOWN, 0} };
+
+/*****************************************************************************/
+const char *vc_container_metadata_id_to_string(VC_CONTAINER_METADATA_KEY_T key)
+{
+   int i;
+   for(i = 0; meta_key_conv[i].key != VC_CONTAINER_METADATA_KEY_UNKNOWN; i++ )
+      if(meta_key_conv[i].key == key) break;
+   return meta_key_conv[i].name;
+}
+
+/*****************************************************************************/
+int64_t vc_container_maths_gcd(int64_t a, int64_t b)
+{
+   while(b != 0)
+   {
+      int64_t t = b;
+      b = a % b;
+      a = t;
+   }
+   return a;
+}
+
+/*****************************************************************************/
+void vc_container_maths_rational_simplify(uint32_t *num, uint32_t *den)
+{
+   int64_t div = vc_container_maths_gcd((int64_t)*num, (int64_t)*den);
+   if(div)
+   {
+      *num /= div;
+      *den /= div;
+   }
+}
diff --git a/containers/core/containers_utils.h b/containers/core/containers_utils.h
new file mode 100755 (executable)
index 0000000..22349ef
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef VC_CONTAINERS_UTILS_H
+#define VC_CONTAINERS_UTILS_H
+
+#include "containers/containers.h"
+#include "containers/containers_codecs.h"
+#include "containers/core/containers_waveformat.h"
+
+/*****************************************************************************
+ * Type definitions
+ *****************************************************************************/
+
+/** Definition of the Global Unique Identifier type as used by some containers */
+typedef struct GUID_T
+{
+   uint32_t word0;
+   uint16_t short0;
+   uint16_t short1;
+   uint8_t bytes[8];
+
+} GUID_T;
+
+VC_CONTAINER_ES_FORMAT_T *vc_container_format_create(unsigned int extradata_size);
+void vc_container_format_delete(VC_CONTAINER_ES_FORMAT_T *);
+VC_CONTAINER_STATUS_T vc_container_format_extradata_alloc(
+   VC_CONTAINER_ES_FORMAT_T *format, unsigned int size);
+VC_CONTAINER_STATUS_T vc_container_format_copy( VC_CONTAINER_ES_FORMAT_T *p_out,
+                                                VC_CONTAINER_ES_FORMAT_T *p_in,
+                                                unsigned int extra_buffer_size );
+int utf8_from_charset(const char *charset, char *out, unsigned int out_size,
+                      const void *in, unsigned int in_size);
+const char *vc_container_metadata_id_to_string(VC_CONTAINER_METADATA_KEY_T key);
+
+unsigned int vc_container_es_format_to_waveformatex(VC_CONTAINER_ES_FORMAT_T *format,
+                                                    uint8_t *buffer, unsigned int buffer_size);
+unsigned int vc_container_es_format_to_bitmapinfoheader(VC_CONTAINER_ES_FORMAT_T *format,
+                                                        uint8_t *buffer, unsigned int buffer_size);
+VC_CONTAINER_STATUS_T vc_container_waveformatex_to_es_format(uint8_t *p,
+   unsigned int buffer_size, unsigned int *extra_offset, unsigned int *extra_size,
+   VC_CONTAINER_ES_FORMAT_T *format);
+VC_CONTAINER_STATUS_T vc_container_bitmapinfoheader_to_es_format(uint8_t *p,
+   unsigned int buffer_size, unsigned int *extra_offset, unsigned int *extra_size, 
+   VC_CONTAINER_ES_FORMAT_T *format);
+
+/** Find the greatest common denominator of 2 numbers.
+ *
+ * @param a first number
+ * @param b second number
+ *
+ * @return greatest common denominator of a and b
+ */
+int64_t vc_container_maths_gcd(int64_t a, int64_t b);
+
+/** Reduce a rational number to it's simplest form.
+ *
+ * @param num Pointer to the numerator of the rational number to simplify
+ * @param den Pointer to the denominator of the rational number to simplify
+ */
+void vc_container_maths_rational_simplify(uint32_t *num, uint32_t *den);
+
+#endif /* VC_CONTAINERS_UTILS_H */
diff --git a/containers/core/containers_waveformat.h b/containers/core/containers_waveformat.h
new file mode 100755 (executable)
index 0000000..ade6b9e
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef VC_CONTAINERS_WAVEFORMAT_H
+#define VC_CONTAINERS_WAVEFORMAT_H
+
+/* WAVE form wFormatTag IDs */
+#define  WAVE_FORMAT_UNKNOWN                    0x0000 /* Microsoft Corporation */
+#define  WAVE_FORMAT_ADPCM                      0x0002 /* Microsoft Corporation */
+#define  WAVE_FORMAT_IEEE_FLOAT                 0x0003 /* Microsoft Corporation */
+#define  WAVE_FORMAT_VSELP                      0x0004 /* Compaq Computer Corp. */
+#define  WAVE_FORMAT_IBM_CVSD                   0x0005 /* IBM Corporation */
+#define  WAVE_FORMAT_ALAW                       0x0006 /* Microsoft Corporation */
+#define  WAVE_FORMAT_MULAW                      0x0007 /* Microsoft Corporation */
+#define  WAVE_FORMAT_DTS                        0x0008 /* Microsoft Corporation */
+#define  WAVE_FORMAT_DRM                        0x0009 /* Microsoft Corporation */
+#define  WAVE_FORMAT_WMAUDIO_VOICE              0x000A /* Microsoft Corporation */
+#define  WAVE_FORMAT_OKI_ADPCM                  0x0010 /* OKI */
+#define  WAVE_FORMAT_DVI_ADPCM                  0x0011 /* Intel Corporation */
+#define  WAVE_FORMAT_IMA_ADPCM                  (WAVE_FORMAT_DVI_ADPCM) /* Intel Corporation */
+#define  WAVE_FORMAT_MEDIASPACE_ADPCM           0x0012 /* Videologic */
+#define  WAVE_FORMAT_SIERRA_ADPCM               0x0013 /* Sierra Semiconductor Corp */
+#define  WAVE_FORMAT_G723_ADPCM                 0x0014 /* Antex Electronics Corporation */
+#define  WAVE_FORMAT_DIGISTD                    0x0015 /* DSP Solutions, Inc. */
+#define  WAVE_FORMAT_DIGIFIX                    0x0016 /* DSP Solutions, Inc. */
+#define  WAVE_FORMAT_DIALOGIC_OKI_ADPCM         0x0017 /* Dialogic Corporation */
+#define  WAVE_FORMAT_MEDIAVISION_ADPCM          0x0018 /* Media Vision, Inc. */
+#define  WAVE_FORMAT_CU_CODEC                   0x0019 /* Hewlett-Packard Company */
+#define  WAVE_FORMAT_YAMAHA_ADPCM               0x0020 /* Yamaha Corporation of America */
+#define  WAVE_FORMAT_SONARC                     0x0021 /* Speech Compression */
+#define  WAVE_FORMAT_DSPGROUP_TRUESPEECH        0x0022 /* DSP Group, Inc */
+#define  WAVE_FORMAT_ECHOSC1                    0x0023 /* Echo Speech Corporation */
+#define  WAVE_FORMAT_AUDIOFILE_AF36             0x0024 /* Virtual Music, Inc. */
+#define  WAVE_FORMAT_APTX                       0x0025 /* Audio Processing Technology */
+#define  WAVE_FORMAT_AUDIOFILE_AF10             0x0026 /* Virtual Music, Inc. */
+#define  WAVE_FORMAT_PROSODY_1612               0x0027 /* Aculab plc */
+#define  WAVE_FORMAT_LRC                        0x0028 /* Merging Technologies S.A. */
+#define  WAVE_FORMAT_DOLBY_AC2                  0x0030 /* Dolby Laboratories */
+#define  WAVE_FORMAT_GSM610                     0x0031 /* Microsoft Corporation */
+#define  WAVE_FORMAT_MSNAUDIO                   0x0032 /* Microsoft Corporation */
+#define  WAVE_FORMAT_ANTEX_ADPCME               0x0033 /* Antex Electronics Corporation */
+#define  WAVE_FORMAT_CONTROL_RES_VQLPC          0x0034 /* Control Resources Limited */
+#define  WAVE_FORMAT_DIGIREAL                   0x0035 /* DSP Solutions, Inc. */
+#define  WAVE_FORMAT_DIGIADPCM                  0x0036 /* DSP Solutions, Inc. */
+#define  WAVE_FORMAT_CONTROL_RES_CR10           0x0037 /* Control Resources Limited */
+#define  WAVE_FORMAT_NMS_VBXADPCM               0x0038 /* Natural MicroSystems */
+#define  WAVE_FORMAT_CS_IMAADPCM                0x0039 /* Crystal Semiconductor IMA ADPCM */
+#define  WAVE_FORMAT_ECHOSC3                    0x003A /* Echo Speech Corporation */
+#define  WAVE_FORMAT_ROCKWELL_ADPCM             0x003B /* Rockwell International */
+#define  WAVE_FORMAT_ROCKWELL_DIGITALK          0x003C /* Rockwell International */
+#define  WAVE_FORMAT_XEBEC                      0x003D /* Xebec Multimedia Solutions Limited */
+#define  WAVE_FORMAT_G721_ADPCM                 0x0040 /* Antex Electronics Corporation */
+#define  WAVE_FORMAT_G728_CELP                  0x0041 /* Antex Electronics Corporation */
+#define  WAVE_FORMAT_MSG723                     0x0042 /* Microsoft Corporation */
+#define  WAVE_FORMAT_PANASONIC_G726             0x0045 /* Not official Panasonic G.726 codec */
+#define  WAVE_FORMAT_MPEG                       0x0050 /* Microsoft Corporation */
+#define  WAVE_FORMAT_RT24                       0x0052 /* InSoft, Inc. */
+#define  WAVE_FORMAT_PAC                        0x0053 /* InSoft, Inc. */
+#define  WAVE_FORMAT_MPEGLAYER3                 0x0055 /* ISO/MPEG Layer3 Format Tag */
+#define  WAVE_FORMAT_LUCENT_G723                0x0059 /* Lucent Technologies */
+#define  WAVE_FORMAT_CIRRUS                     0x0060 /* Cirrus Logic */
+#define  WAVE_FORMAT_ESPCM                      0x0061 /* ESS Technology */
+#define  WAVE_FORMAT_VOXWARE                    0x0062 /* Voxware Inc */
+#define  WAVE_FORMAT_CANOPUS_ATRAC              0x0063 /* Canopus, co., Ltd. */
+#define  WAVE_FORMAT_G726_ADPCM                 0x0064 /* APICOM */
+#define  WAVE_FORMAT_G722_ADPCM                 0x0065 /* APICOM */
+#define  WAVE_FORMAT_DSAT_DISPLAY               0x0067 /* Microsoft Corporation */
+#define  WAVE_FORMAT_VOXWARE_BYTE_ALIGNED       0x0069 /* Voxware Inc */
+#define  WAVE_FORMAT_VOXWARE_AC8                0x0070 /* Voxware Inc */
+#define  WAVE_FORMAT_VOXWARE_AC10               0x0071 /* Voxware Inc */
+#define  WAVE_FORMAT_VOXWARE_AC16               0x0072 /* Voxware Inc */
+#define  WAVE_FORMAT_VOXWARE_AC20               0x0073 /* Voxware Inc */
+#define  WAVE_FORMAT_VOXWARE_RT24               0x0074 /* Voxware Inc */
+#define  WAVE_FORMAT_VOXWARE_RT29               0x0075 /* Voxware Inc */
+#define  WAVE_FORMAT_VOXWARE_RT29HW             0x0076 /* Voxware Inc */
+#define  WAVE_FORMAT_VOXWARE_VR12               0x0077 /* Voxware Inc */
+#define  WAVE_FORMAT_VOXWARE_VR18               0x0078 /* Voxware Inc */
+#define  WAVE_FORMAT_VOXWARE_TQ40               0x0079 /* Voxware Inc */
+#define  WAVE_FORMAT_SOFTSOUND                  0x0080 /* Softsound, Ltd. */
+#define  WAVE_FORMAT_VOXWARE_TQ60               0x0081 /* Voxware Inc */
+#define  WAVE_FORMAT_MSRT24                     0x0082 /* Microsoft Corporation */
+#define  WAVE_FORMAT_G729A                      0x0083 /* AT&T Labs, Inc. */
+#define  WAVE_FORMAT_MVI_MVI2                   0x0084 /* Motion Pixels */
+#define  WAVE_FORMAT_DF_G726                    0x0085 /* DataFusion Systems (Pty) (Ltd) */
+#define  WAVE_FORMAT_DF_GSM610                  0x0086 /* DataFusion Systems (Pty) (Ltd) */
+#define  WAVE_FORMAT_ISIAUDIO                   0x0088 /* Iterated Systems, Inc. */
+#define  WAVE_FORMAT_ONLIVE                     0x0089 /* OnLive! Technologies, Inc. */
+#define  WAVE_FORMAT_SBC24                      0x0091 /* Siemens Business Communications Sys */
+#define  WAVE_FORMAT_DOLBY_AC3_SPDIF            0x0092 /* Sonic Foundry */
+#define  WAVE_FORMAT_MEDIASONIC_G723            0x0093 /* MediaSonic */
+#define  WAVE_FORMAT_PROSODY_8KBPS              0x0094 /* Aculab plc */
+#define  WAVE_FORMAT_ZYXEL_ADPCM                0x0097 /* ZyXEL Communications, Inc. */
+#define  WAVE_FORMAT_PHILIPS_LPCBB              0x0098 /* Philips Speech Processing */
+#define  WAVE_FORMAT_PACKED                     0x0099 /* Studer Professional Audio AG */
+#define  WAVE_FORMAT_MALDEN_PHONYTALK           0x00A0 /* Malden Electronics Ltd. */
+#define  WAVE_FORMAT_MP4A                       0x00FF /* AAC */
+#define  WAVE_FORMAT_RHETOREX_ADPCM             0x0100 /* Rhetorex Inc. */
+#define  WAVE_FORMAT_IRAT                       0x0101 /* BeCubed Software Inc. */
+#define  WAVE_FORMAT_VIVO_G723                  0x0111 /* Vivo Software */
+#define  WAVE_FORMAT_VIVO_SIREN                 0x0112 /* Vivo Software */
+#define  WAVE_FORMAT_DIGITAL_G723               0x0123 /* Digital Equipment Corporation */
+#define  WAVE_FORMAT_SANYO_LD_ADPCM             0x0125 /* Sanyo Electric Co., Ltd. */
+#define  WAVE_FORMAT_SIPROLAB_ACEPLNET          0x0130 /* Sipro Lab Telecom Inc. */
+#define  WAVE_FORMAT_SIPROLAB_ACELP4800         0x0131 /* Sipro Lab Telecom Inc. */
+#define  WAVE_FORMAT_SIPROLAB_ACELP8V3          0x0132 /* Sipro Lab Telecom Inc. */
+#define  WAVE_FORMAT_SIPROLAB_G729              0x0133 /* Sipro Lab Telecom Inc. */
+#define  WAVE_FORMAT_SIPROLAB_G729A             0x0134 /* Sipro Lab Telecom Inc. */
+#define  WAVE_FORMAT_SIPROLAB_KELVIN            0x0135 /* Sipro Lab Telecom Inc. */
+#define  WAVE_FORMAT_G726ADPCM                  0x0140 /* Dictaphone Corporation */
+#define  WAVE_FORMAT_QUALCOMM_PUREVOICE         0x0150 /* Qualcomm, Inc. */
+#define  WAVE_FORMAT_QUALCOMM_HALFRATE          0x0151 /* Qualcomm, Inc. */
+#define  WAVE_FORMAT_TUBGSM                     0x0155 /* Ring Zero Systems, Inc. */
+#define  WAVE_FORMAT_WMAUDIO1                   0x0160 /* Microsoft Corporation */
+#define  WAVE_FORMAT_WMAUDIO2                   0x0161 /* Microsoft Corporation */
+#define  WAVE_FORMAT_WMAUDIOPRO                 0x0162 /* Microsoft Corporation */
+#define  WAVE_FORMAT_WMAUDIO_LOSSLESS           0x0163 /* Microsoft Corporation */
+#define  WAVE_FORMAT_UNISYS_NAP_ADPCM           0x0170 /* Unisys Corp. */
+#define  WAVE_FORMAT_UNISYS_NAP_ULAW            0x0171 /* Unisys Corp. */
+#define  WAVE_FORMAT_UNISYS_NAP_ALAW            0x0172 /* Unisys Corp. */
+#define  WAVE_FORMAT_UNISYS_NAP_16K             0x0173 /* Unisys Corp. */
+#define  WAVE_FORMAT_CREATIVE_ADPCM             0x0200 /* Creative Labs, Inc */
+#define  WAVE_FORMAT_CREATIVE_FASTSPEECH8       0x0202 /* Creative Labs, Inc */
+#define  WAVE_FORMAT_CREATIVE_FASTSPEECH10      0x0203 /* Creative Labs, Inc */
+#define  WAVE_FORMAT_UHER_ADPCM                 0x0210 /* UHER informatic GmbH */
+#define  WAVE_FORMAT_QUARTERDECK                0x0220 /* Quarterdeck Corporation */
+#define  WAVE_FORMAT_ILINK_VC                   0x0230 /* I-link Worldwide */
+#define  WAVE_FORMAT_RAW_SPORT                  0x0240 /* Aureal Semiconductor */
+#define  WAVE_FORMAT_ESST_AC3                   0x0241 /* ESS Technology, Inc. */
+#define  WAVE_FORMAT_IPI_HSX                    0x0250 /* Interactive Products, Inc. */
+#define  WAVE_FORMAT_IPI_RPELP                  0x0251 /* Interactive Products, Inc. */
+#define  WAVE_FORMAT_CS2                        0x0260 /* Consistent Software */
+#define  WAVE_FORMAT_SONY_SCX                   0x0270 /* Sony Corp. */
+#define  WAVE_FORMAT_FM_TOWNS_SND               0x0300 /* Fujitsu Corp. */
+#define  WAVE_FORMAT_BTV_DIGITAL                0x0400 /* Brooktree Corporation */
+#define  WAVE_FORMAT_QDESIGN_MUSIC              0x0450 /* QDesign Corporation */
+#define  WAVE_FORMAT_VME_VMPCM                  0x0680 /* AT&T Labs, Inc. */
+#define  WAVE_FORMAT_TPC                        0x0681 /* AT&T Labs, Inc. */
+#define  WAVE_FORMAT_OLIGSM                     0x1000 /* Ing C. Olivetti & C., S.p.A. */
+#define  WAVE_FORMAT_OLIADPCM                   0x1001 /* Ing C. Olivetti & C., S.p.A. */
+#define  WAVE_FORMAT_OLICELP                    0x1002 /* Ing C. Olivetti & C., S.p.A. */
+#define  WAVE_FORMAT_OLISBC                     0x1003 /* Ing C. Olivetti & C., S.p.A. */
+#define  WAVE_FORMAT_OLIOPR                     0x1004 /* Ing C. Olivetti & C., S.p.A. */
+#define  WAVE_FORMAT_LH_CODEC                   0x1100 /* Lernout & Hauspie */
+#define  WAVE_FORMAT_NORRIS                     0x1400 /* Norris Communications, Inc. */
+#define  WAVE_FORMAT_SOUNDSPACE_MUSICOMPRESS    0x1500 /* AT&T Labs, Inc. */
+#define  WAVE_FORMAT_DVM                        0x2000 /* FAST Multimedia AG */
+#define  WAVE_FORMAT_AAC                        0x706D /* AAC */
+
+#if !defined(WAVE_FORMAT_EXTENSIBLE)
+#define  WAVE_FORMAT_EXTENSIBLE                 0xFFFE /* Microsoft */
+#endif // !defined(WAVE_FORMAT_EXTENSIBLE)
+
+#if !defined(WAVE_FORMAT_PCM)
+#define WAVE_FORMAT_PCM        0x0001
+#endif // !defined(WAVE_FORMAT_PCM)
+
+#endif /* VC_CONTAINERS_WAVEFORMAT_H */
diff --git a/containers/core/containers_writer_utils.c b/containers/core/containers_writer_utils.c
new file mode 100755 (executable)
index 0000000..583ad93
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "containers/containers.h"
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_writer_utils.h"
+#include "vcos.h"
+
+#include <stdio.h>
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T vc_container_writer_extraio_create(VC_CONTAINER_T *context, const char *uri,
+   VC_CONTAINER_WRITER_EXTRAIO_T *extraio)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_PARAM_UNUSED(context);
+
+   extraio->io = vc_container_io_open( uri, VC_CONTAINER_IO_MODE_WRITE, &status );
+   extraio->refcount = 0;
+   extraio->temp = 0;
+   return status;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_writer_extraio_create_null(VC_CONTAINER_T *context, VC_CONTAINER_WRITER_EXTRAIO_T *extraio)
+{
+   return vc_container_writer_extraio_create(context, "null://", extraio);
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_writer_extraio_create_temp(VC_CONTAINER_T *context, VC_CONTAINER_WRITER_EXTRAIO_T *extraio)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   unsigned int length = strlen(context->priv->io->uri) + 5;
+   char *uri = malloc(length);
+   if(!uri) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+
+   snprintf(uri, length, "%s.tmp", context->priv->io->uri);
+   status = vc_container_writer_extraio_create(context, uri, extraio);
+   free(uri);
+   extraio->temp = true;
+
+   if(status == VC_CONTAINER_SUCCESS && !context->priv->tmp_io)
+      context->priv->tmp_io = extraio->io;
+
+   return status;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_writer_extraio_delete(VC_CONTAINER_T *context, VC_CONTAINER_WRITER_EXTRAIO_T *extraio)
+{
+   VC_CONTAINER_STATUS_T status;
+   char *uri = extraio->temp ? vcos_strdup(extraio->io->uri) : 0;
+
+   while(extraio->refcount) vc_container_writer_extraio_disable(context, extraio);
+   status = vc_container_io_close( extraio->io );
+
+   /* coverity[check_return] On failure the worst case is a file or directory is not removed */
+   if(uri) remove(uri);
+   if(uri) free(uri);
+
+   if(context->priv->tmp_io == extraio->io)
+      context->priv->tmp_io = 0;
+
+   return status;
+}
+
+/*****************************************************************************/
+int64_t vc_container_writer_extraio_enable(VC_CONTAINER_T *context, VC_CONTAINER_WRITER_EXTRAIO_T *extraio)
+{
+   VC_CONTAINER_IO_T *tmp;
+
+   if(!extraio->refcount)
+   {
+      vc_container_io_seek(extraio->io, INT64_C(0));
+      tmp = context->priv->io;
+      context->priv->io = extraio->io;
+      extraio->io = tmp;
+   }
+   return extraio->refcount++;
+}
+
+/*****************************************************************************/
+int64_t vc_container_writer_extraio_disable(VC_CONTAINER_T *context, VC_CONTAINER_WRITER_EXTRAIO_T *extraio)
+{
+   VC_CONTAINER_IO_T *tmp;
+
+   if(extraio->refcount)
+   {
+      extraio->refcount--;
+      if(!extraio->refcount)
+      {
+         tmp = context->priv->io;
+         context->priv->io = extraio->io;
+         extraio->io = tmp;
+      }
+   }
+   return extraio->refcount;
+}
diff --git a/containers/core/containers_writer_utils.h b/containers/core/containers_writer_utils.h
new file mode 100755 (executable)
index 0000000..e2ccf9e
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef VC_CONTAINERS_WRITER_UTILS_H
+#define VC_CONTAINERS_WRITER_UTILS_H
+
+/** \file containers_writer_utils.h
+ * Helper functions and macros for container writers
+ */
+
+#include "containers/containers.h" 
+#include "containers/containers_codecs.h"
+#include "containers/core/containers_io_helpers.h"
+
+/*****************************************************************************
+ * Helper inline functions to write format specific structus to an i/o stream
+ *****************************************************************************/
+
+STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_write_waveformatex( VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_ES_FORMAT_T *format)
+{
+   /* Write waveformatex structure */
+   WRITE_U16(p_ctx, codec_to_waveformat(format->codec), "Codec ID");
+   WRITE_U16(p_ctx, format->type->audio.channels, "Number of Channels");
+   WRITE_U32(p_ctx, format->type->audio.sample_rate, "Samples per Second");
+   WRITE_U32(p_ctx, format->bitrate >> 3, "Average Number of Bytes Per Second");
+   WRITE_U16(p_ctx, format->type->audio.block_align, "Block Alignment");
+   WRITE_U16(p_ctx, format->type->audio.bits_per_sample, "Bits Per Sample");
+   WRITE_U16(p_ctx, format->extradata_size, "Codec Specific Data Size");
+   WRITE_BYTES(p_ctx, format->extradata, format->extradata_size);
+
+   return STREAM_STATUS(p_ctx);
+}
+
+STATIC_INLINE VC_CONTAINER_STATUS_T vc_container_write_bitmapinfoheader( VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_ES_FORMAT_T *format)
+{
+   VC_CONTAINER_FOURCC_T fourcc;
+
+   /* Write bitmapinfoheader structure */
+   WRITE_U32(p_ctx, 40, "Format Data Size");
+   WRITE_U32(p_ctx, format->type->video.width, "Image Width");
+   WRITE_U32(p_ctx, format->type->video.height, "Image Height");
+   WRITE_U16(p_ctx, 0, "Reserved");
+   WRITE_U16(p_ctx, 0, "Bits Per Pixel Count");
+   fourcc = codec_to_vfw_fourcc(format->codec);
+   WRITE_BYTES(p_ctx, (char *)&fourcc, 4); /* Compression ID */
+   LOG_FORMAT(p_ctx, "Compression ID: %4.4s", (char *)&fourcc);
+   WRITE_U32(p_ctx, 0, "Image Size");
+   WRITE_U32(p_ctx, 0, "Horizontal Pixels Per Meter");
+   WRITE_U32(p_ctx, 0, "Vertical Pixels Per Meter");
+   WRITE_U32(p_ctx, 0, "Colors Used Count");
+   WRITE_U32(p_ctx, 0, "Important Colors Count");
+
+   WRITE_BYTES(p_ctx, format->extradata, format->extradata_size);
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/* Helper functions to create and use extra i/o */
+typedef struct VC_CONTAINER_WRITER_EXTRAIO_T {
+   VC_CONTAINER_IO_T *io;
+   unsigned int refcount;
+   bool temp;
+} VC_CONTAINER_WRITER_EXTRAIO_T;
+
+VC_CONTAINER_STATUS_T vc_container_writer_extraio_create_null(VC_CONTAINER_T *context, VC_CONTAINER_WRITER_EXTRAIO_T *null);
+VC_CONTAINER_STATUS_T vc_container_writer_extraio_create_temp(VC_CONTAINER_T *context, VC_CONTAINER_WRITER_EXTRAIO_T *null);
+VC_CONTAINER_STATUS_T vc_container_writer_extraio_delete(VC_CONTAINER_T *context, VC_CONTAINER_WRITER_EXTRAIO_T *null);
+int64_t vc_container_writer_extraio_enable(VC_CONTAINER_T *context, VC_CONTAINER_WRITER_EXTRAIO_T *null);
+int64_t vc_container_writer_extraio_disable(VC_CONTAINER_T *context, VC_CONTAINER_WRITER_EXTRAIO_T *null);
+
+#endif /* VC_CONTAINERS_WRITER_UTILS_H */
diff --git a/containers/core/packetizers.c b/containers/core/packetizers.c
new file mode 100755 (executable)
index 0000000..abfb2d7
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "containers/packetizers.h"
+#include "containers/core/packetizers_private.h"
+#include "containers/core/containers_common.h"
+#include "containers/core/containers_logging.h"
+#include "containers/core/containers_utils.h"
+
+/** List of registered packetizers. */
+static VC_PACKETIZER_REGISTRY_ENTRY_T *registry;
+
+/*****************************************************************************/
+void vc_packetizer_register(VC_PACKETIZER_REGISTRY_ENTRY_T *entry)
+{
+   LOG_DEBUG(0, "registering packetizer %s", entry->name);
+   entry->next = registry;
+   registry = entry;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T vc_packetizer_load(VC_PACKETIZER_T *p_ctx)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   VC_PACKETIZER_REGISTRY_ENTRY_T *entry;
+
+   /* Try all the packetizers until we find the right one */
+   for (entry = registry; entry; entry = entry->next)
+   {
+      status = entry->open(p_ctx);
+      if(status != VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED)
+         break;
+   }
+
+   return status;
+}
+
+/*****************************************************************************/
+static void vc_packetizer_unload(VC_PACKETIZER_T *p_ctx)
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+}
+
+/*****************************************************************************/
+VC_PACKETIZER_T *vc_packetizer_open( VC_CONTAINER_ES_FORMAT_T *in,
+   VC_CONTAINER_FOURCC_T out_variant, VC_CONTAINER_STATUS_T *p_status )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_PACKETIZER_T *p_ctx = 0;
+
+   /* Allocate our context before trying out the different packetizers */
+   p_ctx = malloc( sizeof(*p_ctx) + sizeof(*p_ctx->priv));
+   if(!p_ctx) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(p_ctx, 0, sizeof(*p_ctx) + sizeof(*p_ctx->priv));
+   p_ctx->priv = (VC_PACKETIZER_PRIVATE_T *)(p_ctx + 1);
+   bytestream_init( &p_ctx->priv->stream );
+
+   p_ctx->in = vc_container_format_create(in->extradata_size);
+   if(!p_ctx->in) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   p_ctx->out = vc_container_format_create(in->extradata_size);
+   if(!p_ctx->out) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+
+   vc_container_format_copy( p_ctx->in, in, in->extradata_size );
+   p_ctx->in->extradata_size = 0;
+   vc_container_format_copy( p_ctx->out, p_ctx->in, in->extradata_size );
+   p_ctx->in->extradata_size = in->extradata_size;
+   p_ctx->out->extradata = p_ctx->in->extradata;
+   p_ctx->out->extradata_size = p_ctx->in->extradata_size;
+   p_ctx->out->codec_variant = out_variant;
+
+   vc_container_time_init(&p_ctx->priv->time, 1000000);
+
+   status = vc_packetizer_load(p_ctx);
+   if(status != VC_CONTAINER_SUCCESS)
+      goto error;
+
+ end:
+   if(p_status) *p_status = status;
+   return p_ctx;
+
+ error:
+   if(p_ctx) vc_packetizer_close(p_ctx);
+   p_ctx = NULL;
+   goto end;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_packetizer_close( VC_PACKETIZER_T *p_ctx )
+{
+   VC_CONTAINER_BYTESTREAM_T *stream;
+   VC_CONTAINER_PACKET_T *packet, *next;
+
+   if(!p_ctx) return VC_CONTAINER_SUCCESS;
+
+   stream = &p_ctx->priv->stream;
+
+   if(p_ctx->in) vc_container_format_delete(p_ctx->in);
+   if(p_ctx->out) vc_container_format_delete(p_ctx->out);
+   if(p_ctx->priv->pf_close) p_ctx->priv->pf_close(p_ctx);
+   if(p_ctx->priv->module_handle) vc_packetizer_unload(p_ctx);
+
+   /* Free the bytestream  */
+   for(packet = stream->first; packet; packet = next)
+   {
+      next = packet->next;
+      if(packet->framework_data) free(packet);
+   }
+
+   free(p_ctx);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_packetizer_push( VC_PACKETIZER_T *p_ctx,
+   VC_CONTAINER_PACKET_T *in)
+{
+   /* Do some sanity checking on packet ? */
+
+   in->framework_data = 0;
+   bytestream_push(&p_ctx->priv->stream, in);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_packetizer_pop( VC_PACKETIZER_T *p_ctx,
+   VC_CONTAINER_PACKET_T **in, VC_PACKETIZER_FLAGS_T flags)
+{
+   VC_CONTAINER_BYTESTREAM_T *stream = &p_ctx->priv->stream;
+   VC_CONTAINER_PACKET_T *packet, *new, **prev;
+
+   /* Release the packets which have been read */
+   while((*in = bytestream_pop(stream)) != NULL)
+   {
+      if(*in && (*in)->framework_data)
+      {
+         free(*in);
+         continue;
+      }
+
+      if(*in)
+         return VC_CONTAINER_SUCCESS;
+   }
+
+   if(!(flags & VC_PACKETIZER_FLAG_FORCE_RELEASE_INPUT))
+      return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
+
+   /* Look for the 1st non-framework packet */
+   for (packet = stream->first, prev = &stream->first;
+        packet && packet->framework_data; prev = &packet->next, packet = packet->next);
+
+   if (!packet || (packet && packet->framework_data))
+      return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
+
+   /* We'll currently alloc an internal packet for each packet the client forcefully releases.
+    * We could probably do something a bit more clever than that though. */
+   /* Replace the packet with a newly allocated one */
+   new = malloc(sizeof(*packet) + packet->size);
+   if(!new)
+      return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+
+   *new = *packet;
+   new->framework_data = new;
+   if(!new->next)
+      stream->last = &new->next;
+   if(stream->current == packet)
+      stream->current = new;
+   *prev = new;
+   new->data = (uint8_t *)&new[1];
+   memcpy(new->data, packet->data, packet->size);
+   *in = packet;
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_packetizer_read( VC_PACKETIZER_T *p_ctx,
+   VC_CONTAINER_PACKET_T *packet, VC_PACKETIZER_FLAGS_T flags)
+{
+   if(!packet && !(flags & VC_CONTAINER_READ_FLAG_SKIP))
+      return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+   if(!packet && (flags & VC_CONTAINER_READ_FLAG_INFO))
+      return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+   if(packet && !packet->data &&
+      (!(flags & VC_CONTAINER_READ_FLAG_INFO) &&
+       !(flags & VC_CONTAINER_READ_FLAG_SKIP)))
+      return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+
+   /* Always having a packet structure to work with simplifies things */
+   if(!packet)
+      packet = &p_ctx->priv->packet;
+
+   return p_ctx->priv->pf_packetize(p_ctx, packet, flags);
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_packetizer_reset( VC_PACKETIZER_T *p_ctx )
+{
+   VC_CONTAINER_BYTESTREAM_T *stream = &p_ctx->priv->stream;
+
+   bytestream_skip( stream, stream->bytes - stream->current_offset - stream->offset );
+
+   if (p_ctx->priv->pf_reset)
+      return p_ctx->priv->pf_reset(p_ctx);
+   else
+      return VC_CONTAINER_SUCCESS;
+}
diff --git a/containers/core/packetizers_private.h b/containers/core/packetizers_private.h
new file mode 100755 (executable)
index 0000000..ad5f8f5
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef VC_PACKETIZERS_PRIVATE_H
+#define VC_PACKETIZERS_PRIVATE_H
+
+/** \file
+ * Private interface for packetizers
+ */
+
+#include <stdarg.h>
+#include "containers/packetizers.h"
+#include "containers/core/containers_common.h"
+#include "containers/core/containers_bytestream.h"
+#include "containers/core/containers_time.h"
+
+/** \defgroup VcPacketizerModuleApi Packetizer Module API
+ * Private interface for modules implementing packetizers */
+/* @{ */
+
+/** Context private to the packetizer instance. This private context is used to
+ * store data which shouldn't be exported by the public API. */
+typedef struct VC_PACKETIZER_PRIVATE_T
+{
+   /** Pointer to the private data of the packetizer module in use */
+   struct VC_PACKETIZER_MODULE_T *module;
+
+   /** Bytestream abstraction layer */
+   struct VC_CONTAINER_BYTESTREAM_T stream;
+
+   /** Current stream time */
+   VC_CONTAINER_TIME_T time;
+
+   /** Packetize the bytestream.
+    *
+    * \param  context   Pointer to the context of the instance of the packetizer
+    * \param  out       Pointer to the output packet structure which needs to be filled
+    * \param  flags     Miscellaneous flags controlling the packetizing
+    * \return           the status of the operation
+    */
+   VC_CONTAINER_STATUS_T (*pf_packetize)( VC_PACKETIZER_T *context,
+      VC_CONTAINER_PACKET_T *out, VC_PACKETIZER_FLAGS_T flags );
+
+   /** Reset packetizer state.
+    *
+    * \param  context   Pointer to the context of the instance of the packetizer
+    * \return           the status of the operation
+    */
+   VC_CONTAINER_STATUS_T (*pf_reset)( VC_PACKETIZER_T *context );
+
+   /** Closes a packetizer module.
+    *
+    * \param  context   Pointer to the context of the instance to close
+    * \return           the status of the operation
+    */
+   VC_CONTAINER_STATUS_T (*pf_close)( struct VC_PACKETIZER_T *context );
+
+   /** Pointer to the packetizer module code and symbols*/
+   void *module_handle;
+
+   /** Temporary packet structure used when the caller does not provide one */
+   VC_CONTAINER_PACKET_T packet;
+
+} VC_PACKETIZER_PRIVATE_T;
+
+/** Structure used by packetizers to register themselves with the core. */
+typedef struct VC_PACKETIZER_REGISTRY_ENTRY_T
+{
+   struct VC_PACKETIZER_REGISTRY_ENTRY_T *next; /**< To link entries together */
+   const char *name; /**< Name of the packetizer */
+   VC_CONTAINER_STATUS_T (*open)( VC_PACKETIZER_T * ); /**< Called to open packetizer */
+} VC_PACKETIZER_REGISTRY_ENTRY_T;
+
+/** Register a packetizer with the core.
+ *
+ * \param entry Entry to register with the core
+ */
+void vc_packetizer_register(VC_PACKETIZER_REGISTRY_ENTRY_T *entry);
+
+/** Utility macro used to register a packetizer with the core */
+#define VC_PACKETIZER_REGISTER(func, name) \
+VC_CONTAINER_CONSTRUCTOR(func##_register); \
+static VC_PACKETIZER_REGISTRY_ENTRY_T registry_entry = {0, name, func}; \
+void func##_register(void) { vc_packetizer_register(&registry_entry); }
+
+/* @} */
+
+#endif /* VC_PACKETIZERS_PRIVATE_H */
diff --git a/containers/dummy/CMakeLists.txt b/containers/dummy/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..4643438
--- /dev/null
@@ -0,0 +1,12 @@
+# Container module needs to go in as a plugins so different prefix
+# and install path
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+
+# Make sure the compiler can find the necessary include files
+include_directories (../..)
+
+add_library(writer_dummy ${LIBRARY_TYPE} dummy_writer.c)
+
+target_link_libraries(writer_dummy containers)
+
+install(TARGETS writer_dummy DESTINATION ${VMCS_PLUGIN_DIR})
diff --git a/containers/dummy/dummy_writer.c b/containers/dummy/dummy_writer.c
new file mode 100755 (executable)
index 0000000..0430b98
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <string.h>
+
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_logging.h"
+
+/******************************************************************************
+Type definitions
+******************************************************************************/
+typedef struct VC_CONTAINER_MODULE_T
+{
+   VC_CONTAINER_TRACK_T *track[2];
+
+} VC_CONTAINER_MODULE_T;
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+VC_CONTAINER_STATUS_T dummy_writer_open( VC_CONTAINER_T * );
+
+/*****************************************************************************
+Functions exported as part of the Container Module API
+ *****************************************************************************/
+static VC_CONTAINER_STATUS_T dummy_writer_close( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   for(; p_ctx->tracks_num > 0; p_ctx->tracks_num--)
+      vc_container_free_track(p_ctx, p_ctx->tracks[p_ctx->tracks_num-1]);
+   free(module);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T dummy_writer_write( VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_PACKET_T *packet )
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+   VC_CONTAINER_PARAM_UNUSED(packet);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T dummy_writer_control( VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_CONTROL_T operation, va_list args )
+{
+   VC_CONTAINER_TRACK_T *track;
+   VC_CONTAINER_PARAM_UNUSED(args);
+
+   switch(operation)
+   {
+   case VC_CONTAINER_CONTROL_TRACK_ADD:
+      if(p_ctx->tracks_num >= 2) return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+
+      /* Allocate and initialise track data */
+      p_ctx->tracks[p_ctx->tracks_num] = track = vc_container_allocate_track(p_ctx, 0);
+      if(!track) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+
+      p_ctx->tracks_num++;
+      return VC_CONTAINER_SUCCESS;
+
+   case VC_CONTAINER_CONTROL_TRACK_ADD_DONE:
+      return VC_CONTAINER_SUCCESS;
+
+   default: return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+   }
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T dummy_writer_open( VC_CONTAINER_T *p_ctx )
+{
+   const char *extension = vc_uri_path_extension(p_ctx->priv->uri);
+   VC_CONTAINER_MODULE_T *module = 0;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_INVALID;
+
+   /* Check if the user has specified a container */
+   vc_uri_find_query(p_ctx->priv->uri, 0, "container", &extension);
+
+   /* Check we're the right writer for this */
+   if(!extension)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   if(strcasecmp(extension, "dummy"))
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   /* Allocate our context */
+   module = malloc(sizeof(*module));
+   if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(module, 0, sizeof(*module));
+   p_ctx->priv->module = module;
+   p_ctx->tracks = module->track;
+
+   p_ctx->capabilities |= VC_CONTAINER_CAPS_DYNAMIC_TRACK_ADD;
+
+   p_ctx->priv->pf_close = dummy_writer_close;
+   p_ctx->priv->pf_write = dummy_writer_write;
+   p_ctx->priv->pf_control = dummy_writer_control;
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+   LOG_DEBUG(p_ctx, "dummy: error opening stream (%i)", status);
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+ ********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak writer_open dummy_writer_open
+#endif
diff --git a/containers/flash/CMakeLists.txt b/containers/flash/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..bf53935
--- /dev/null
@@ -0,0 +1,13 @@
+# Container module needs to go in as a plugins so different prefix
+# and install path
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+
+# Make sure the compiler can find the necessary include files
+include_directories (../..)
+
+add_library(reader_flv ${LIBRARY_TYPE} flv_reader.c)
+
+target_link_libraries(reader_flv containers)
+
+install(TARGETS reader_flv DESTINATION ${VMCS_PLUGIN_DIR})
+
diff --git a/containers/flash/flv_reader.c b/containers/flash/flv_reader.c
new file mode 100755 (executable)
index 0000000..6e15e6b
--- /dev/null
@@ -0,0 +1,1174 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <string.h>
+
+/* Work-around for MSVC debugger issue */
+#define VC_CONTAINER_MODULE_T VC_CONTAINER_MODULE_FLV_READER_T
+#define VC_CONTAINER_TRACK_MODULE_T VC_CONTAINER_TRACK_MODULE_FLV_READER_T
+
+//#define ENABLE_FLV_EXTRA_LOGGING
+#define CONTAINER_IS_BIG_ENDIAN
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_index.h"
+#include "containers/core/containers_logging.h"
+#undef CONTAINER_HELPER_LOG_INDENT
+#define CONTAINER_HELPER_LOG_INDENT(a) 0
+
+VC_CONTAINER_STATUS_T flv_reader_open( VC_CONTAINER_T *p_ctx );
+
+/******************************************************************************
+Defines.
+******************************************************************************/
+#define FLV_TRACKS_MAX 2
+
+#define FLV_TAG_TYPE_AUDIO 8
+#define FLV_TAG_TYPE_VIDEO 9
+#define FLV_TAG_TYPE_METADATA 18
+#define FLV_TAG_HEADER_SIZE 15
+
+#define FLV_SCRIPT_DATA_TYPE_NUMBER      0
+#define FLV_SCRIPT_DATA_TYPE_BOOL        1
+#define FLV_SCRIPT_DATA_TYPE_STRING      2
+#define FLV_SCRIPT_DATA_TYPE_ECMA        8
+#define FLV_SCRIPT_DATA_TYPE_LONGSTRING 12
+
+#define FLV_FLAG_DISCARD    1
+#define FLV_FLAG_KEYFRAME   2
+#define FLV_FLAG_INTERFRAME 4
+
+/******************************************************************************
+Type definitions.
+******************************************************************************/
+typedef struct
+{
+   VC_CONTAINER_STATUS_T status;
+
+   int64_t tag_position; /* position of the current tag we're reading */
+   int64_t data_position; /* position to the start of the data within the tag */
+   int     data_offset; /* current position inside the tag's data */
+   int     data_size; /* size of the data from the current tag */
+   int     tag_prev_size; /* size of the previous tag in the stream */
+   int     flags; /* flags for the current tag */
+   uint32_t timestamp; /* timestamp for the current tag */
+   uint32_t track; /* track the current tag belongs to */
+   VC_CONTAINER_INDEX_T *index; /* index of key frames */
+
+} FLV_READER_STATE_T;
+
+typedef struct VC_CONTAINER_TRACK_MODULE_T
+{
+   FLV_READER_STATE_T *state;
+   FLV_READER_STATE_T track_state;
+
+} VC_CONTAINER_TRACK_MODULE_T;
+
+typedef struct VC_CONTAINER_MODULE_T
+{
+   VC_CONTAINER_TRACK_T *tracks[FLV_TRACKS_MAX];
+
+   int64_t data_offset; /*< offset to the first FLV tag in the stream */
+
+   FLV_READER_STATE_T state; /*< global state of the reader */
+
+   int audio_track;
+   int video_track;
+
+   uint32_t meta_videodatarate;
+   uint32_t meta_audiodatarate;
+   float meta_framerate;
+   uint32_t meta_width;
+   uint32_t meta_height;
+
+} VC_CONTAINER_MODULE_T;
+
+/******************************************************************************
+Static functions within this file.
+******************************************************************************/
+/** Reads an FLV tag header
+  *
+  * @param p_ctx              pointer to our context
+  * @param[out] p_prev_size   size of the previous tag
+  * @param[out] p_type        type of the tag
+  * @param[out] p_type        size of the tag
+  * @param[out] p_type        timestamp for the tag
+  * @return                   VC_CONTAINER_SUCCESS on success
+  */
+static VC_CONTAINER_STATUS_T flv_read_tag_header(VC_CONTAINER_T *p_ctx, int *p_prev_size,
+                                                 int *p_type, int *p_size, uint32_t *p_timestamp)
+{
+   int prev_size, type, size;
+   uint32_t timestamp;
+
+   prev_size = READ_U32(p_ctx, "PreviousTagSize");
+   type = READ_U8(p_ctx, "TagType");
+   size = READ_U24(p_ctx, "DataSize");
+   timestamp = READ_U24(p_ctx, "Timestamp");
+   timestamp |= (READ_U8(p_ctx, "TimestampExtended") << 24);
+   SKIP_U24(p_ctx, "StreamID");
+
+   if(p_prev_size) *p_prev_size = prev_size + 4;
+   if(p_type) *p_type = type;
+   if(p_size) *p_size = size;
+   if(p_timestamp) *p_timestamp = timestamp;
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/** Reads an FLV video data header.
+  * This contains the codec id and the current frame type.
+  *
+  * @param p_ctx              pointer to our context
+  * @param[out] codec         video codec
+  * @param[out] frame_type    type of the current frame
+  * @return                   VC_CONTAINER_SUCCESS on success
+  */
+static VC_CONTAINER_STATUS_T flv_read_videodata_header(VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_FOURCC_T *codec, int *frame_type)
+{
+   uint8_t header = READ_U8(p_ctx, "FrameType/CodecID");
+
+   if(frame_type)
+      *frame_type = (header >> 4) == 1 ? FLV_FLAG_KEYFRAME :
+         (header >> 4) == 3 ? FLV_FLAG_INTERFRAME : 0;
+
+   switch(header &0xF)
+   {
+   case 2: *codec = VC_CONTAINER_CODEC_SPARK; break;
+   case 3: *codec = VC_FOURCC('s','c','r','1'); break; /* screen video */
+   case 4: *codec = VC_CONTAINER_CODEC_VP6; break;
+   case 5: *codec = VC_FOURCC('v','p','6','a'); break; /* vp6 alpha */
+   case 6: *codec = VC_FOURCC('s','c','r','2'); break; /* screen video 2 */
+   case 7: *codec = VC_CONTAINER_CODEC_H264; break;
+   default: *codec = 0; break;
+   }
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/** Get the properties of a video frame
+  * This is only really useful at setup time when trying to detect
+  * the type of content we are dealing with.
+  * This will try to get some of the properties of the video stream
+  * as well as codec configuration data if there is any.
+  *
+  * @param p_ctx              pointer to our context
+  * @param track              track number this data/tag belongs to
+  * @param size               size of the data we are parsing
+  * @return                   VC_CONTAINER_SUCCESS on success
+  */
+static VC_CONTAINER_STATUS_T flv_read_videodata_properties(VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_TRACK_T *track, int size)
+{
+   VC_CONTAINER_STATUS_T status;
+   int width = 0, height = 0;
+
+   if(track->format->codec == VC_CONTAINER_CODEC_VP6 ||
+      track->format->codec == VC_FOURCC('v','p','6','a'))
+   {
+      /* Just extract the width / height */
+      uint8_t data = _READ_U8(p_ctx);
+      _SKIP_U16(p_ctx);
+      height = _READ_U8(p_ctx) * 16;
+      width = _READ_U8(p_ctx) * 16;
+      width -= data >> 4;
+      height -= data & 0xf;
+   }
+   else if(track->format->codec == VC_CONTAINER_CODEC_H264)
+   {
+      uint8_t type = _READ_U8(p_ctx); size--;
+      if(type || size <= 8) return VC_CONTAINER_ERROR_CORRUPTED;
+      _SKIP_U24(p_ctx); size-=3;
+
+      track->format->codec_variant = VC_FOURCC('a','v','c','C');
+      status = vc_container_track_allocate_extradata(p_ctx, track, size);
+      if(status != VC_CONTAINER_SUCCESS) return status;
+      track->format->extradata_size = READ_BYTES(p_ctx, track->format->extradata, size);
+   }
+
+   track->format->type->video.width = width;
+   track->format->type->video.height = height;
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/** Reads an FLV audio data header.
+  * This contains the codec id, samplerate, number of channels and bitrate.
+  *
+  * @param p_ctx              pointer to our context
+  * @param[out] codec         audio codec
+  * @param[out] p_samplerate  audio sampling rate
+  * @param[out] p_channels    number of audio channels
+  * @param[out] p_bps         bits per sample
+  * @return                   VC_CONTAINER_SUCCESS on success
+  */
+static VC_CONTAINER_STATUS_T flv_read_audiodata_header(VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_FOURCC_T *codec, int *p_samplerate, int *p_channels, int *p_bps)
+{
+   int samplerate, channels, bps;
+   uint8_t header = _READ_U8(p_ctx);
+
+   switch((header >> 2) & 0x3)
+   {
+   case 0: samplerate = 5512; break;
+   case 1: samplerate = 11025; break;
+   case 2: samplerate = 22050; break;
+   default:
+   case 3: samplerate = 44100; break;
+   }
+
+   channels = 1 << (header & 1);
+   bps = 8 << ((header >> 1) & 1);
+
+   switch(header >> 4)
+   {
+   case 0: *codec = bps == 8 ? VC_CONTAINER_CODEC_PCM_UNSIGNED : VC_CONTAINER_CODEC_PCM_SIGNED; break;
+   case 1: *codec = VC_CONTAINER_CODEC_ADPCM_SWF; break;
+   case 2: *codec = VC_CONTAINER_CODEC_MPGA; break;
+   case 3: *codec = bps == 8 ? VC_CONTAINER_CODEC_PCM_UNSIGNED : VC_CONTAINER_CODEC_PCM_SIGNED_LE; break;
+   case 4: *codec = VC_CONTAINER_CODEC_NELLYMOSER; samplerate = 8000; channels = 1; break;
+   case 5: *codec = VC_CONTAINER_CODEC_NELLYMOSER; samplerate = 16000; channels = 1; break;
+   case 6: *codec = VC_CONTAINER_CODEC_NELLYMOSER; channels = 1; break;
+   case 7: *codec = VC_CONTAINER_CODEC_ALAW; break;
+   case 8: *codec = VC_CONTAINER_CODEC_MULAW; break;
+   case 10: *codec = VC_CONTAINER_CODEC_MP4A; samplerate = 44100; channels = 2; break;
+   case 11: *codec = VC_CONTAINER_CODEC_SPEEX; break;
+   case 14: *codec = VC_CONTAINER_CODEC_MPGA; samplerate = 8000; break;
+   default: *codec = 0; break;
+   }
+
+   if(p_samplerate) *p_samplerate = samplerate;
+   if(p_channels) *p_channels = channels;
+   if(p_bps) *p_bps = bps;
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/** Get the properties of an audio frame
+  * This is only really useful at setup time when trying to detect
+  * the type of content we are dealing with.
+  * This will try to get some of the properties of the audio stream
+  * as well as codec configuration data if there is any.
+  *
+  * @param p_ctx              pointer to our context
+  * @param track              track number this data/tag belongs to
+  * @param size               size of the data we are parsing
+  * @param samplerate         sampling rate of the audio data
+  * @param channels           number of channels of the audio data
+  * @param bps                bits per sample
+  * @return                   VC_CONTAINER_SUCCESS on success
+  */
+static VC_CONTAINER_STATUS_T flv_read_audiodata_properties(VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_TRACK_T *track, int size, int samplerate, int channels, int bps)
+{
+   static const int aac_freq[16] = {96000, 88200, 64000, 48000, 44100, 32000, 24000,
+                                    22050, 16000, 12000, 11025, 8000, 7350};
+   VC_CONTAINER_STATUS_T status;
+
+   if(track->format->codec == VC_CONTAINER_CODEC_MP4A)
+   {
+      uint8_t *p_data, data = _READ_U8(p_ctx);
+      size--;
+      if(data || size <= 0) return VC_CONTAINER_ERROR_FAILED;
+
+      /* Read the AudioSpecificConfig */
+      status = vc_container_track_allocate_extradata(p_ctx, track, size);
+      if(status != VC_CONTAINER_SUCCESS) return status;
+      track->format->extradata_size = READ_BYTES(p_ctx, track->format->extradata, size);
+
+      if(track->format->extradata_size >= 2)
+      {
+         p_data = track->format->extradata;
+         data = ((p_data[0] & 0x7) << 1) | (p_data[1] >> 7);
+         if(data >= countof(aac_freq))
+            return VC_CONTAINER_ERROR_FAILED;
+
+         samplerate = aac_freq[data];
+         channels = (p_data[1] >> 3) & 0xf;
+         if(track->format->extradata_size >= 5 && data == 0xf)
+         {
+            samplerate = ((p_data[1] & 0x7f) << 17) | (p_data[2] << 9) |
+                          (p_data[3] << 1) | (p_data[4] >> 7);
+            channels = (p_data[4] >> 3) & 0xf;
+         }
+      }
+   }
+
+   track->format->type->audio.sample_rate = samplerate;
+   track->format->type->audio.channels = channels;
+   track->format->type->audio.bits_per_sample = bps;
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/** Reads an FLV metadata tag.
+  * This contains metadata information about the stream.
+  * All the data we extract from this will be placed directly in the context.
+  *
+  * @param p_ctx              pointer to our context
+  * @param size               size of the tag
+  * @return                   FLV_FILE_NO_ERROR on success
+  */
+static int flv_read_metadata(VC_CONTAINER_T *p_ctx, int size)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+#define MAX_METADATA_STRING_SIZE 25
+   char psz_string[MAX_METADATA_STRING_SIZE+1];
+   uint16_t length, num_values;
+   double f_value;
+   uint64_t u_value;
+   uint8_t type;
+
+   /* We're looking for an onMetaData script */
+   type = READ_U8(p_ctx, "Type"); size--;
+   if(type != FLV_SCRIPT_DATA_TYPE_STRING) return VC_CONTAINER_SUCCESS;
+   length = READ_U16(p_ctx, "StringLength"); size -= 2;
+   if(!length || length > size || length > MAX_METADATA_STRING_SIZE) return VC_CONTAINER_SUCCESS;
+   if(READ_BYTES(p_ctx, psz_string, length) != length) return VC_CONTAINER_SUCCESS;
+   psz_string[length] = 0; size -= length;
+   if(strcmp(psz_string, "onMetaData")) return VC_CONTAINER_SUCCESS;
+   if(size < 5) return VC_CONTAINER_SUCCESS;
+   type = READ_U8(p_ctx, "Type"); size--;
+   if(type != FLV_SCRIPT_DATA_TYPE_ECMA) return VC_CONTAINER_SUCCESS;
+   num_values = READ_U32(p_ctx, "ECMAArrayLength"); size -= 4;
+
+   /* We found our script, now extract the metadata values */
+   while(num_values-- && size >= 2)
+   {
+      uint16_t length = _READ_U16(p_ctx); size -= 2;
+      if(!length || length >= size || length > MAX_METADATA_STRING_SIZE) break;
+      if(READ_BYTES(p_ctx, psz_string, length) != length) break;
+      psz_string[length] = 0; size -= length;
+      type = _READ_U8(p_ctx); size--;
+
+      switch(type)
+      {
+      case FLV_SCRIPT_DATA_TYPE_NUMBER:
+         /* We only cope with DOUBLE types*/
+         if(size < 8) return VC_CONTAINER_SUCCESS;
+
+         u_value = _READ_U64(p_ctx); size -= 8;
+         /* Convert value into a double */
+         {
+            int64_t value = ((u_value & ((UINT64_C(1)<<52)-1)) + (UINT64_C(1)<<52)) * ((((int64_t)u_value)>>63)|1);
+            int exp = ((u_value>>52)&0x7FF)-1075 + 16;
+            if(exp >= 0) value <<= exp;
+            else value >>= -exp;
+            f_value = ((double)value) / (1 << 16);
+         }
+
+         LOG_DEBUG(p_ctx, "metadata (%s=%i.%i)", psz_string,
+                   ((int)(f_value*100))/100, ((int)(f_value*100))%100);
+
+         if(!strcmp(psz_string, "duration"))
+            p_ctx->duration = (int64_t)(f_value*INT64_C(1000000));
+         if(!strcmp(psz_string, "videodatarate"))
+            module->meta_videodatarate = (uint32_t)f_value;
+         if(!strcmp(psz_string, "width"))
+            module->meta_width = (uint32_t)f_value;
+         if(!strcmp(psz_string, "height"))
+            module->meta_height = (uint32_t)f_value;
+         if(!strcmp(psz_string, "framerate"))
+            module->meta_framerate = f_value;
+         if(!strcmp(psz_string, "audiodatarate"))
+            module->meta_audiodatarate = (uint32_t)f_value;
+         continue;
+
+      /* We skip these */
+      case FLV_SCRIPT_DATA_TYPE_BOOL:
+         if(size < 1) return VC_CONTAINER_SUCCESS;
+         u_value = _READ_U8(p_ctx); size -= 1;
+         LOG_DEBUG(p_ctx, "metadata (%s=%i)", psz_string, (int)u_value);
+         continue;
+
+      case FLV_SCRIPT_DATA_TYPE_STRING:
+         if(size < 2) return VC_CONTAINER_SUCCESS;
+         length = _READ_U16(p_ctx); size -= 2;
+         if(length > size) return VC_CONTAINER_SUCCESS;
+         SKIP_BYTES(p_ctx, length); size -= length;
+         LOG_DEBUG(p_ctx, "metadata skipping (%s)", psz_string);
+         continue;
+
+      /* We can't cope with anything else */
+      default:
+         LOG_DEBUG(p_ctx, "unknown amf type (%s,%i)", psz_string, type);
+         return VC_CONTAINER_SUCCESS;
+      }
+   }
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/** Reads an FLV frame header.
+  * This reads the current tag header and matches the contained frame
+  * with one of the tracks we have. If no match can be found, the frame is marked
+  * for discarding. The current read position will be updated to the start
+  * of the data (i.e. the frame) contained within the FLV tag.
+  *
+  * @param p_ctx              pointer to our context
+  * @param[out] p_track       track this frame belongs to
+  * @param[out] p_size        size of the frame
+  * @param[out] p_timestamp   timestamp of the frame
+  * @param[out] p_flags       flags associated with the frame
+  * @param b_extra_check      whether to perform extra sanity checking on the tag
+  * @return                   VC_CONTAINER_SUCCESS on success
+  */
+static int flv_read_frame_header(VC_CONTAINER_T *p_ctx, int *p_prev_size,
+   int *p_track, int *p_size, uint32_t *p_timestamp, int *p_flags,
+   int b_extra_check)
+{
+   int64_t position = STREAM_POSITION(p_ctx);
+   int type, size, flags = 0, frametype = 0;
+   VC_CONTAINER_STATUS_T status;
+   VC_CONTAINER_ES_TYPE_T es_type = VC_CONTAINER_ES_TYPE_UNKNOWN;
+   unsigned int track = p_ctx->tracks_num;
+   uint32_t codec = 0;
+
+   status = flv_read_tag_header(p_ctx, p_prev_size, &type, &size, p_timestamp);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   if(STREAM_STATUS(p_ctx) != VC_CONTAINER_SUCCESS) return status;
+   if(position == STREAM_POSITION(p_ctx)) return VC_CONTAINER_ERROR_EOS;
+   if(type == 0) return VC_CONTAINER_ERROR_CORRUPTED;
+
+   /* Sanity checking */
+   if(b_extra_check && type != FLV_TAG_TYPE_AUDIO &&
+      type != FLV_TAG_TYPE_VIDEO && type != FLV_TAG_TYPE_METADATA)
+      return VC_CONTAINER_ERROR_CORRUPTED;
+
+   /* We're only interested in audio / video */
+   if((type != FLV_TAG_TYPE_AUDIO && type != FLV_TAG_TYPE_VIDEO) || !size)
+   {
+      flags |= FLV_FLAG_DISCARD;
+      goto end;
+   }
+
+   if(type == FLV_TAG_TYPE_AUDIO)
+   {
+      flv_read_audiodata_header(p_ctx, &codec, 0, 0, 0);
+      es_type = VC_CONTAINER_ES_TYPE_AUDIO;
+   }
+   else if(type == FLV_TAG_TYPE_VIDEO)
+   {
+      flv_read_videodata_header(p_ctx, &codec, &frametype);
+      es_type = VC_CONTAINER_ES_TYPE_VIDEO;
+   }
+   size--;
+
+   /* Find which track this belongs to */
+   for(track = 0; track < p_ctx->tracks_num; track++)
+      if(es_type == p_ctx->tracks[track]->format->es_type) break;
+   if(track == p_ctx->tracks_num)
+      flags |= FLV_FLAG_DISCARD;
+
+   /* Sanity checking */
+   if(b_extra_check && codec != p_ctx->tracks[track]->format->codec)
+      return VC_CONTAINER_ERROR_CORRUPTED;
+
+ end:
+   // add to the index if we have one, and we're not discarding this frame.
+   // also require that we either have no video track or this is a video frame marked as a key frame.
+   if(p_ctx->priv->module->state.index && !(flags & FLV_FLAG_DISCARD) &&
+      (p_ctx->priv->module->video_track < 0 || (es_type == VC_CONTAINER_ES_TYPE_VIDEO && (frametype & FLV_FLAG_KEYFRAME))))
+      vc_container_index_add(p_ctx->priv->module->state.index, (int64_t) (*p_timestamp) * 1000LL, position);
+
+   *p_flags = flags | frametype;
+   *p_size = size;
+   *p_track = track;
+   return VC_CONTAINER_SUCCESS;
+}
+
+/** Validate the data contained within the frame and update the read
+  * position to the start of the frame data that we want to feed to the codec.
+  *
+  * Each codec is packed slightly differently so this function is necessary
+  * to prepare for reading the actual codec data.
+  *
+  * @param p_ctx              pointer to our context
+  * @param track              track this frame belongs to
+  * @param[in] p_size         size of the frame
+  * @param[out] p_size        updated size of the frame
+  * @param[in] p_timestamp    timestamp for the frame
+  * @param[out] p_timestamp   updated timestamp for the frame
+  * @return                   VC_CONTAINER_SUCCESS on success
+  */
+static VC_CONTAINER_STATUS_T flv_validate_frame_data(VC_CONTAINER_T *p_ctx,
+   int track, int *p_size, uint32_t *p_timestamp)
+{
+   int32_t time_offset;
+
+   if(track >= (int)p_ctx->tracks_num)
+      return *p_size ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_CONTINUE;
+
+   switch(p_ctx->tracks[track]->format->codec)
+   {
+   case VC_CONTAINER_CODEC_VP6:
+      if(*p_size < 1) return VC_CONTAINER_ERROR_CORRUPTED;
+      _READ_U8(p_ctx); *p_size -= 1;
+      break;
+   case VC_CONTAINER_CODEC_MP4A:
+      if(*p_size < 1) return VC_CONTAINER_ERROR_CORRUPTED;
+      *p_size -= 1;
+      if(_READ_U8(p_ctx)!=1) return VC_CONTAINER_ERROR_CONTINUE; /* empty frame*/
+      break;
+   case VC_CONTAINER_CODEC_H264:
+      if(*p_size < 4) return VC_CONTAINER_ERROR_CORRUPTED;
+      *p_size -= 1;
+      if(_READ_U8(p_ctx)!=1) return VC_CONTAINER_ERROR_CONTINUE; /* empty frame*/
+      time_offset = _READ_U24(p_ctx);
+      time_offset <<= 8; time_offset >>= 8; /* change to signed */
+      *p_timestamp += time_offset;
+      *p_size -= 3;
+      break;
+   default:
+      break;
+   }
+
+   return *p_size ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_CONTINUE;
+}
+
+/** Small utility function to update the reading position of a track
+  */
+static void flv_update_track_position(VC_CONTAINER_T *p_ctx, int track,
+   int64_t tag_position, int tag_prev_size, int64_t data_position,
+   int data_size, uint32_t timestamp, int flags)
+{
+   VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[track]->priv->module;
+   track_module->state->tag_position = tag_position;
+   track_module->state->tag_prev_size = tag_prev_size;
+   track_module->state->data_position = data_position;
+   track_module->state->data_size = data_size;
+   track_module->state->data_offset = 0;
+   track_module->state->timestamp = timestamp;
+   track_module->state->flags = flags;
+   track_module->state->track = track;
+}
+
+/** Utility function to find the next frame of a given track in the stream.
+  *
+  * This will basically walk through all the tags in the file until it
+  * finds a tag/frame which belongs to the given track.
+  *
+  * @param p_ctx              pointer to our context
+  * @param track              track wanted
+  * @param[out] p_size        size of the frame
+  * @param[out] p_timestamp   timestamp of the frame
+  * @param[out] p_flags       flags associated with the frame
+  * @param b_keyframe         whether we specifically want a keyframe or not
+  * @param b_extra_check      whether to perform extra sanity checking on the tag
+  * @return                   VC_CONTAINER_SUCCESS on success
+  */
+static VC_CONTAINER_STATUS_T flv_find_next_frame(VC_CONTAINER_T *p_ctx, int track, int *p_size,
+   uint32_t *p_timestamp, int *p_flags, int b_keyframe, int b_extra_check)
+{
+   int frame_track, prev_size, size, flags;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   FLV_READER_STATE_T *state = p_ctx->tracks[track]->priv->module->state;
+   uint32_t timestamp;
+   int64_t position;
+   VC_CONTAINER_PARAM_UNUSED(b_extra_check);
+
+   /* Seek to the next tag in the stream or the current position
+    * if none of its data has been consumed */
+   position = state->tag_position;
+   if(state->data_offset)
+      position = state->data_position + state->data_size;
+   status = SEEK(p_ctx, position);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   /* Look for the next frame we want */
+   while (status == VC_CONTAINER_SUCCESS)
+   {
+      position = STREAM_POSITION(p_ctx);
+      status = flv_read_frame_header(p_ctx, &prev_size, &frame_track,
+                                     &size, &timestamp, &flags, 0);
+      if(status != VC_CONTAINER_SUCCESS) break;
+
+      if(flags & FLV_FLAG_DISCARD) goto skip;
+      if(frame_track != track) goto skip;
+
+      if(b_keyframe && p_ctx->tracks[track]->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO &&
+         !(flags & FLV_FLAG_KEYFRAME)) goto skip;
+
+      if(flv_validate_frame_data(p_ctx, track, &size, &timestamp) != VC_CONTAINER_SUCCESS)
+         goto skip;
+
+      /* We have what we need */
+      flv_update_track_position(p_ctx, track, position, prev_size, STREAM_POSITION(p_ctx),
+                                size, timestamp, flags);
+      break;
+
+   skip:
+      flv_update_track_position(p_ctx, track, position, prev_size, STREAM_POSITION(p_ctx),
+                                size, timestamp, 0);
+      state->data_offset = size; /* consume data */
+
+      if(SKIP_BYTES(p_ctx, size) != (size_t)size) status = STREAM_STATUS(p_ctx);
+   }
+
+   if(!status)
+   {
+      if(p_size) *p_size = size;
+      if(p_timestamp) *p_timestamp = timestamp;
+      if(p_flags) *p_flags = flags;
+   }
+
+   return status;
+}
+
+/** Utility function to find the previous frame of a given track in the stream.
+  *
+  * This will basically walk back through all the tags in the file until it
+  * finds a tag/frame which belongs to the given track.
+  *
+  * @param p_ctx              pointer to our context
+  * @param track              track wanted
+  * @param[out] p_size        size of the frame
+  * @param[out] p_timestamp   timestamp of the frame
+  * @param[out] p_flags       flags associated with the frame
+  * @param b_keyframe         whether we specifically want a keyframe or not
+  * @param b_extra_check      whether to perform extra sanity checking on the tag
+  * @return                   VC_CONTAINER_SUCCESS on success
+  */
+static VC_CONTAINER_STATUS_T flv_find_previous_frame(VC_CONTAINER_T *p_ctx, int track, int *p_size,
+   uint32_t *p_timestamp, int *p_flags, int b_keyframe, int b_extra_check)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   FLV_READER_STATE_T *state = p_ctx->tracks[track]->priv->module->state;
+   int frame_track, prev_size, size, flags;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   uint32_t timestamp;
+   int64_t position;
+
+   /* Look for the previous frame we want */
+   while (status == VC_CONTAINER_SUCCESS)
+   {
+      /* Seek to the previous tag in the stream */
+      position = state->tag_position - state->tag_prev_size;
+      if(position < module->data_offset) position = module->data_offset;
+      status = SEEK(p_ctx, position);
+      if(status != VC_CONTAINER_SUCCESS) return status;
+
+      status = flv_read_frame_header(p_ctx, &prev_size, &frame_track,
+                                     &size, &timestamp, &flags, 0);
+      if(status) break;
+
+      if(flags & FLV_FLAG_DISCARD) goto skip;
+      if(frame_track != track) goto skip;
+
+      if(b_keyframe && p_ctx->tracks[track]->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO &&
+         !(flags & FLV_FLAG_KEYFRAME)) goto skip;
+
+      if(flv_validate_frame_data(p_ctx, track, &size, &timestamp) != VC_CONTAINER_SUCCESS)
+         goto skip;
+
+      /* We have what we need */
+      flv_update_track_position(p_ctx, track, position, prev_size, STREAM_POSITION(p_ctx),
+                                size, timestamp, flags);
+      break;
+
+   skip:
+      if(position <= module->data_offset)
+      {
+         /* We're back at the beginning but we still want to return something */
+         flv_update_track_position(p_ctx, track, (int64_t)module->data_offset, 0,
+                                   (int64_t)module->data_offset, 0, 0, 0);
+         return flv_find_next_frame(p_ctx, track, p_size, p_timestamp, p_flags, b_keyframe, b_extra_check);
+      }
+      flv_update_track_position(p_ctx, track, position, prev_size, STREAM_POSITION(p_ctx),
+                                size, timestamp, 0);
+      state->data_offset = size; /* consume data */
+   }
+
+   if(!status)
+   {
+      if(p_size) *p_size = size;
+      if(p_timestamp) *p_timestamp = timestamp;
+      if(p_flags) *p_flags = flags;
+   }
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T flv_reader_close( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   unsigned int i;
+
+   for(i = 0; i < p_ctx->tracks_num; i++)
+      vc_container_free_track(p_ctx, p_ctx->tracks[i]);
+
+   if(module->state.index)
+      vc_container_index_free(module->state.index);
+
+   free(module);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T flv_read_sample_header( VC_CONTAINER_T *p_ctx,
+   FLV_READER_STATE_T *state)
+{
+   int track, prev_size, size, flags;
+   uint32_t timestamp;
+   int64_t position;
+
+   /* Check if we still have some data left to read from the current frame */
+   if(state->data_offset < state->data_size)
+      return state->status;
+
+   /* Read the next tag header */
+   position = STREAM_POSITION(p_ctx);
+   state->status = flv_read_frame_header(p_ctx, &prev_size, &track,
+                                         &size, &timestamp, &flags, 0);
+   if(state->status != VC_CONTAINER_SUCCESS)
+      return state->status;
+
+   state->status = flv_validate_frame_data(p_ctx, track, &size, &timestamp);
+   if(state->status == VC_CONTAINER_ERROR_CONTINUE)
+   {
+      /* Skip it */
+      state->status = VC_CONTAINER_SUCCESS;
+      track = p_ctx->tracks_num;
+   }
+   if(state->status != VC_CONTAINER_SUCCESS)
+      return state->status;
+
+   state->tag_position = position;
+   state->data_position = STREAM_POSITION(p_ctx);
+   state->data_size = size;
+   state->data_offset = 0;
+   state->flags = flags;
+   state->tag_prev_size = prev_size;
+   state->timestamp = timestamp;
+   state->track = track;
+   return state->status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T flv_read_sample_data( VC_CONTAINER_T *p_ctx,
+   FLV_READER_STATE_T *state, uint8_t *data, unsigned int *data_size )
+{
+   unsigned int size = state->data_size - state->data_offset;
+
+   if(state->status != VC_CONTAINER_SUCCESS) return state->status;
+
+   if(data_size && *data_size < size) size = *data_size;
+
+   if(!data) size = SKIP_BYTES(p_ctx, size);
+   else size = READ_BYTES(p_ctx, data, size);
+   state->data_offset += size;
+
+   if(data_size) *data_size = size;
+   state->status = STREAM_STATUS(p_ctx);
+
+   return state->status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T flv_reader_read( VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_PACKET_T *packet, uint32_t flags )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   FLV_READER_STATE_T *state = &module->state;
+   unsigned int data_size;
+
+   /* TODO: select right state */
+
+   status = flv_read_sample_header(p_ctx, state);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+#ifdef ENABLE_FLV_EXTRA_LOGGING
+   LOG_DEBUG(p_ctx, "read_sample_header (%i,%i,%i/%i/%i/%i)", state->timestamp, state->flags,
+         (int)state->tag_position, (int)(state->data_position-state->tag_position), state->data_offset, state->data_size);
+#endif
+
+   if(state->track >= p_ctx->tracks_num || !p_ctx->tracks[state->track]->is_enabled)
+   {
+      /* Skip packet */
+      status = flv_read_sample_data(p_ctx, state, 0, 0);
+      if(status != VC_CONTAINER_SUCCESS) return status;
+      return VC_CONTAINER_ERROR_CONTINUE;
+   }
+
+   if((flags & VC_CONTAINER_READ_FLAG_SKIP) && !(flags & VC_CONTAINER_READ_FLAG_INFO)) /* Skip packet */
+      return flv_read_sample_data(p_ctx, state, 0, 0);
+
+   packet->dts = packet->pts = state->timestamp * (int64_t)1000;
+   packet->flags = VC_CONTAINER_PACKET_FLAG_FRAME_END;
+   if(state->flags & FLV_FLAG_KEYFRAME) packet->flags |= VC_CONTAINER_PACKET_FLAG_KEYFRAME;
+   if(!state->data_offset) packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
+   packet->track = state->track;
+
+   // The frame size is all the data
+   packet->frame_size = state->data_size;
+
+   // the size is what's left
+   packet->size = state->data_size - state->data_offset;
+
+   if(flags & VC_CONTAINER_READ_FLAG_SKIP)
+      return flv_read_sample_data(p_ctx, state, 0, 0);
+   else if(flags & VC_CONTAINER_READ_FLAG_INFO)
+      return VC_CONTAINER_SUCCESS;
+
+   data_size = packet->buffer_size;
+   status = flv_read_sample_data(p_ctx, state, packet->data, &data_size);
+   if(status != VC_CONTAINER_SUCCESS)
+   {
+      /* FIXME */
+      return status;
+   }
+
+   packet->size = data_size;
+   if(state->data_offset != state->data_size)
+      packet->flags &= ~VC_CONTAINER_PACKET_FLAG_FRAME_END;
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T flv_reader_seek(VC_CONTAINER_T *p_ctx,
+   int64_t *offset, VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   FLV_READER_STATE_T last_state = {0};
+   FLV_READER_STATE_T *state;
+   uint32_t time = (*offset / 1000), timestamp, previous_time;
+   unsigned int i, track;
+   int size, past = 0;
+   int64_t position;
+   VC_CONTAINER_PARAM_UNUSED(mode);
+
+   /* If we have a video track, then we want to find the keyframe closest to
+    * the requested time, otherwise we just look for the tag with the
+    * closest timestamp */
+
+   /* Select the track on which we'll do our seeking */
+   for(i = 0, track = 0; i < p_ctx->tracks_num; i++)
+   {
+      if(p_ctx->tracks[i]->format->es_type != VC_CONTAINER_ES_TYPE_VIDEO) continue;
+      track = i;
+      break;
+   }
+   if(track >= p_ctx->tracks_num) return VC_CONTAINER_ERROR_CORRUPTED;
+   state = p_ctx->tracks[track]->priv->module->state;
+   previous_time = state->timestamp;
+
+   LOG_DEBUG(p_ctx, "seek (%i, prev %i)", time, previous_time);
+
+   if(state->index && vc_container_index_get(state->index, flags & VC_CONTAINER_SEEK_FLAG_FORWARD,
+                                             offset, &position, &past) == VC_CONTAINER_SUCCESS)
+   {
+      flv_update_track_position(p_ctx, track, position, 0, position, 0, (uint32_t) (*offset / 1000LL), 0);
+   }
+   else
+   {
+      if(time < state->timestamp / 2)
+         flv_update_track_position(p_ctx, track, (int64_t)module->data_offset, 0,
+                                   (int64_t)module->data_offset, 0, 0, 0);
+      past = 1;
+   }
+
+   /* If past it clear then we're done, otherwise we need to find our point from here */
+   if(past == 0)
+   {
+      status = flv_find_next_frame(p_ctx, track, &size, &timestamp, 0, 1 /*keyframe*/, 0);
+   }
+   else
+   {
+      if(time > previous_time)
+      {
+         while(!status)
+         {
+            status = flv_find_next_frame(p_ctx, track, &size, &timestamp, 0, 1 /*keyframe*/, 0);
+            if(status) break;
+
+            /* Check if we have our frame */
+            if(time <= timestamp) break;
+
+            last_state = *state;
+            state->data_offset = size; /* consume data */
+         }
+      }
+      else
+      {
+         while(!status)
+         {
+            status = flv_find_previous_frame(p_ctx, track, &size, &timestamp, 0, 1 /*keyframe*/, 0);
+            if(status) break;
+
+            /* Check if we have our frame */
+            if(time >= timestamp) break;
+
+            /* Detect when we've reached the 1st keyframe to avoid an infinite loop */
+            if(state->timestamp == last_state.timestamp) break;
+
+            last_state = *state;
+            state->data_offset = size; /* consume data */
+         }
+      }
+   }
+
+   if(status != VC_CONTAINER_SUCCESS && (flags & VC_CONTAINER_SEEK_FLAG_FORWARD))
+   {
+      LOG_DEBUG(p_ctx, "seek failed (%i)", status);
+      return status;
+   }
+   else if(status != VC_CONTAINER_SUCCESS)
+   {
+      LOG_DEBUG(p_ctx, "seek failed (%i), look for previous frame", status);
+      if(last_state.tag_position) *state = last_state;
+      else status = flv_find_previous_frame(p_ctx, track, &size, &timestamp, 0, 1 /*keyframe*/, 0);
+   }
+
+   LOG_DEBUG(p_ctx, "seek done (%i)", timestamp);
+   state->status = VC_CONTAINER_SUCCESS;
+   last_state.status = VC_CONTAINER_SUCCESS;
+
+   if(past == 1)
+   {
+      /* Make adjustment based on seek mode */
+      if((flags & VC_CONTAINER_SEEK_FLAG_FORWARD) && timestamp < time && timestamp < previous_time)
+      {
+         if(last_state.tag_position) *state = last_state;
+         else status = flv_find_next_frame(p_ctx, track, &size, &timestamp, 0, 1 /*keyframe*/, 0);
+      }
+      else if(!(flags & VC_CONTAINER_SEEK_FLAG_FORWARD) && timestamp > time)
+      {
+         if(last_state.tag_position) *state = last_state;
+         else status = flv_find_previous_frame(p_ctx, track, &size, &timestamp, 0, 1 /*keyframe*/, 0);
+      }
+
+      LOG_DEBUG(p_ctx, "seek adjustment (%i)", timestamp);
+   }
+
+   if(state->data_position == last_state.data_position)
+      status = SEEK(p_ctx, state->data_position);
+
+   *offset = timestamp * INT64_C(1000);
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/******************************************************************************
+Global function definitions.
+******************************************************************************/
+
+VC_CONTAINER_STATUS_T flv_reader_open( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_MODULE_T *module = 0;
+   uint8_t buffer[4], type_flags;
+   unsigned int i, frames, audio_present, video_present;
+   uint32_t data_offset;
+
+   /* Check the FLV marker */
+   if( PEEK_BYTES(p_ctx, buffer, 4) < 4 ) goto error;
+   if( buffer[0] != 'F' || buffer[1] != 'L' || buffer[2] != 'V' )
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   /* Check FLV version */
+   if( buffer[3] > 4 )
+   {
+      LOG_DEBUG(p_ctx, "Version too high: %d", buffer[3]);
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   }
+
+   SKIP_BYTES(p_ctx, 4); /* FLV marker and version */
+
+   /* Find out which tracks should be available.
+    * FLV can only have up to 1 audio track and 1 video track. */
+   type_flags = READ_U8(p_ctx, "TypeFlags");
+   audio_present = !!(type_flags & 0x04);
+   video_present = !!(type_flags & 0x01);
+
+   /* Sanity check DataOffset */
+   data_offset = READ_U32(p_ctx, "DataOffset");
+   if(data_offset < 9) goto error;
+
+   /*
+    *  We are dealing with an FLV file
+    */
+
+   LOG_DEBUG(p_ctx, "using flv reader");
+
+   /* Allocate our context */
+   module = malloc(sizeof(*module));
+   if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(module, 0, sizeof(*module));
+   p_ctx->priv->module = module;
+   p_ctx->tracks = module->tracks;
+   module->data_offset = data_offset;
+   module->audio_track = -1;
+   module->video_track = -1;
+
+   /* Skip to the start of the actual data */
+   SKIP_BYTES(p_ctx, data_offset - 9);
+
+   /* We'll start parsing a few of the FLV tags to find out the
+    * metadata / audio / video properties.
+    * The first tag we should see is the metadata one which will give us all the
+    * properties of the stream. However we do not rely on that being there and we
+    * actually look at the first audio / video tags as well. */
+   for(frames = 0; frames < 20; frames++)
+   {
+      VC_CONTAINER_TRACK_T *track;
+      int64_t offset, skip;
+      int prev_size, type, size, channels, samplerate, bps;
+      uint32_t codec, timestamp;
+
+      /* Stop there if we have everything we want */
+      if(audio_present == (module->audio_track >= 0) &&
+         video_present == (module->video_track >= 0)) break;
+      if(module->audio_track >= 0 && module->video_track >= 0) break;
+
+      /* Start reading the next tag */
+      if(flv_read_tag_header(p_ctx, &prev_size, &type, &size, &timestamp)) break;
+      if(!size) continue;
+
+      offset = STREAM_POSITION(p_ctx); /* to keep track of how much data we read */
+
+      switch(type)
+      {
+      case FLV_TAG_TYPE_AUDIO:
+         if(module->audio_track >= 0) break; /* We already have our audio track */
+         flv_read_audiodata_header(p_ctx, &codec, &samplerate, &channels, &bps);
+
+         p_ctx->tracks[p_ctx->tracks_num] = track =
+            vc_container_allocate_track(p_ctx, sizeof(*p_ctx->tracks[0]->priv->module));
+         if(!track) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+
+         track->format->es_type = VC_CONTAINER_ES_TYPE_AUDIO;
+         track->format->codec = codec;
+         flv_read_audiodata_properties(p_ctx, track, size - 1, samplerate, channels, bps);
+
+         module->audio_track = p_ctx->tracks_num++;
+         track->is_enabled = 1;
+         track->format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
+         break;
+
+      case FLV_TAG_TYPE_VIDEO:
+         if(module->video_track >= 0) break; /* We already have our video track */
+         flv_read_videodata_header(p_ctx, &codec, 0);
+
+         p_ctx->tracks[p_ctx->tracks_num] = track =
+            vc_container_allocate_track(p_ctx, sizeof(*p_ctx->tracks[0]->priv->module));
+         if(!track) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+
+         track->format->es_type = VC_CONTAINER_ES_TYPE_VIDEO;
+         track->format->codec = codec;
+
+         status = flv_read_videodata_properties(p_ctx, track, size - 1);
+         if(status != VC_CONTAINER_SUCCESS) { vc_container_free_track(p_ctx, track); break; }
+
+         module->video_track = p_ctx->tracks_num++;
+         track->is_enabled = 1;
+         track->format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
+         break;
+
+      case FLV_TAG_TYPE_METADATA:
+         flv_read_metadata(p_ctx, size);
+         break;
+
+      default: break;
+      }
+
+      /* Skip any data that's left unparsed from the current tag */
+      skip = size - (STREAM_POSITION(p_ctx) - offset);
+      if(skip < 0) break;
+      SKIP_BYTES(p_ctx, (size_t)skip);
+   }
+
+   /* Make sure we found something we can play */
+   if(!p_ctx->tracks_num) {LOG_DEBUG(p_ctx, "didn't find any track"); goto error;}
+
+   /* Try and create an index.  All times are signed, so adding a base timestamp
+    * of zero means that we will always seek back to the start of the file, even if
+    * the actual frame timestamps start at some higher number. */
+   if(vc_container_index_create(&module->state.index, 512) == VC_CONTAINER_SUCCESS)
+      vc_container_index_add(module->state.index, 0LL, (int64_t) data_offset);
+
+   /* Use the metadata we read */
+   if(module->audio_track >= 0)
+   {
+      VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->audio_track];
+      track->format->bitrate = module->meta_audiodatarate;
+   }
+   if(module->video_track >= 0)
+   {
+      VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->video_track];
+      track->format->bitrate = module->meta_videodatarate;
+      if(module->meta_framerate)
+      {
+         track->format->type->video.frame_rate_num = (uint32_t)(100 * module->meta_framerate);
+         track->format->type->video.frame_rate_den = 100;
+      }
+
+      if(module->meta_width && module->meta_width > track->format->type->video.width)
+         track->format->type->video.width = module->meta_width;
+      if(module->meta_height && module->meta_height > track->format->type->video.height)
+         track->format->type->video.height = module->meta_height;
+   }
+
+   status = SEEK(p_ctx, data_offset);
+   if(status != VC_CONTAINER_SUCCESS) goto error;
+
+   /* Some initialisation */
+   module->state.tag_position = data_offset;
+   module->state.data_position = data_offset;
+   for(i = 0; i < p_ctx->tracks_num; i++)
+   {
+      VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[i]->priv->module;
+      track_module->state = &module->state;
+   }
+
+   if(STREAM_SEEKABLE(p_ctx))
+      p_ctx->capabilities |= VC_CONTAINER_CAPS_CAN_SEEK;
+
+   p_ctx->priv->pf_close = flv_reader_close;
+   p_ctx->priv->pf_read = flv_reader_read;
+   p_ctx->priv->pf_seek = flv_reader_seek;
+
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+   if(status == VC_CONTAINER_SUCCESS) status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   LOG_DEBUG(p_ctx, "flv: error opening stream");
+   if(module) flv_reader_close(p_ctx);
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+ ********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak reader_open flv_reader_open
+#endif
diff --git a/containers/h264/avc1_packetizer.c b/containers/h264/avc1_packetizer.c
new file mode 100755 (executable)
index 0000000..8082f0b
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file
+ * Implementation of an ISO 14496-15 to Annexe-B AVC video packetizer.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "containers/packetizers.h"
+#include "containers/core/packetizers_private.h"
+#include "containers/core/containers_common.h"
+#include "containers/core/containers_logging.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_bytestream.h"
+
+#ifndef ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
+//#define ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
+#endif
+
+/** Arbitrary number which should be sufficiently high so that no sane frame will
+ * be bigger than that. */
+#define MAX_FRAME_SIZE (1920*1088*2)
+
+VC_CONTAINER_STATUS_T avc1_packetizer_open( VC_PACKETIZER_T * );
+
+/*****************************************************************************/
+typedef struct VC_PACKETIZER_MODULE_T {
+   enum {
+      STATE_FRAME_WAIT = 0,
+      STATE_BUFFER_INIT,
+      STATE_NAL_START,
+      STATE_NAL_DATA,
+   } state;
+
+   unsigned int length_size;
+
+   unsigned int frame_size;
+   unsigned int bytes_read;
+   unsigned int start_code_bytes_left;
+   unsigned int nal_bytes_left;
+
+} VC_PACKETIZER_MODULE_T;
+
+static const uint8_t h264_start_code[] = {0, 0, 0, 1};
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avc1_packetizer_close( VC_PACKETIZER_T *p_ctx )
+{
+   free(p_ctx->priv->module);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avc1_packetizer_reset( VC_PACKETIZER_T *p_ctx )
+{
+   VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
+   module->state = STATE_FRAME_WAIT;
+   module->frame_size = 0;
+   module->bytes_read = 0;
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avc1_packetizer_packetize( VC_PACKETIZER_T *p_ctx,
+   VC_CONTAINER_PACKET_T *out, VC_PACKETIZER_FLAGS_T flags)
+{
+   VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_BYTESTREAM_T *stream = &p_ctx->priv->stream;
+   VC_CONTAINER_PACKET_T *packet;
+   unsigned int offset, size, nal_num;
+   uint8_t data[4];
+   VC_CONTAINER_PARAM_UNUSED(nal_num);
+
+   while(1) switch (module->state)
+   {
+   case STATE_FRAME_WAIT:
+      for (packet = stream->current, size = 0;
+           packet && !(packet->flags & VC_CONTAINER_PACKET_FLAG_FRAME_END);
+           packet = packet->next)
+         size += packet->size;
+      if (!packet)
+         return VC_CONTAINER_ERROR_INCOMPLETE_DATA; /* We need more data */
+
+      size += packet->size;
+
+      /* We now have a complete frame available */
+
+      module->nal_bytes_left = 0;
+      module->start_code_bytes_left = 0;
+
+      /* Find out the number of NAL units and size of the frame */
+      for (offset = nal_num = 0; offset + module->length_size < size; nal_num++)
+      {
+         unsigned int nal_size;
+
+         bytestream_peek_at(stream, offset, data, module->length_size);
+         offset += module->length_size;
+
+         nal_size = data[0];
+         if (module->length_size > 1)
+            nal_size = (nal_size << 8)|data[1];
+         if (module->length_size > 2)
+            nal_size = (nal_size << 8)|data[2];
+         if (module->length_size > 3)
+            nal_size = (nal_size << 8)|data[3];
+         if (offset + nal_size > size)
+            nal_size = size - offset;
+
+         offset += nal_size;
+         module->frame_size += nal_size + sizeof(h264_start_code);
+#ifdef ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
+         LOG_DEBUG(0, "nal unit size %u", nal_size);
+#endif
+      }
+      LOG_DEBUG(0, "frame size: %u(%u/%u), pts: %"PRIi64, module->frame_size,
+         size, nal_num, stream->current->pts);
+
+      /* fall through to the next state */
+      module->state = STATE_BUFFER_INIT;
+
+   case STATE_BUFFER_INIT:
+      packet = stream->current;
+      out->size = module->frame_size - module->bytes_read;
+      out->pts = out->dts = VC_CONTAINER_TIME_UNKNOWN;
+      out->flags = VC_CONTAINER_PACKET_FLAG_FRAME_END;
+
+      if (!module->bytes_read)
+      {
+         out->pts = packet->pts;
+         out->dts = packet->dts;
+         out->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
+      }
+
+      if (flags & VC_PACKETIZER_FLAG_INFO)
+         return VC_CONTAINER_SUCCESS;
+
+      if (flags & VC_PACKETIZER_FLAG_SKIP)
+      {
+         /* The easiest is to just drop all the packets belonging to the frame */
+         while (!(stream->current->flags & VC_CONTAINER_PACKET_FLAG_FRAME_END))
+            bytestream_skip_packet(stream);
+         bytestream_skip_packet(stream);
+
+         module->frame_size = 0;
+         module->bytes_read = 0;
+         return VC_CONTAINER_SUCCESS;
+      }
+
+      /* We now know that we'll have to read some data so reset the output size */
+      out->size = 0;
+
+      /* Go to the next relevant state */
+      module->state = STATE_NAL_START;
+      if (module->nal_bytes_left || module->bytes_read == module->frame_size)
+         module->state = STATE_NAL_DATA;
+      break;
+
+   case STATE_NAL_START:
+      /* Extract the size of the current NAL */
+      bytestream_get(stream, data, module->length_size);
+
+      module->nal_bytes_left = data[0];
+      if (module->length_size > 1)
+         module->nal_bytes_left = (module->nal_bytes_left << 8)|data[1];
+      if (module->length_size > 2)
+         module->nal_bytes_left = (module->nal_bytes_left << 8)|data[2];
+      if (module->length_size > 3)
+        module->nal_bytes_left = (module->nal_bytes_left << 8)|data[3];
+
+      if (module->bytes_read + module->nal_bytes_left + sizeof(h264_start_code) >
+          module->frame_size)
+      {
+         LOG_ERROR(0, "truncating nal (%u/%u)", module->nal_bytes_left,
+            module->frame_size - module->bytes_read - sizeof(h264_start_code));
+         module->nal_bytes_left = module->frame_size - sizeof(h264_start_code);
+      }
+
+#ifdef ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
+      LOG_DEBUG(0, "nal unit size %u", module->nal_bytes_left);
+#endif
+
+      module->start_code_bytes_left = sizeof(h264_start_code);
+
+      /* fall through to the next state */
+      module->state = STATE_NAL_DATA;
+
+   case STATE_NAL_DATA:
+      /* Start by adding the start code */
+      if (module->start_code_bytes_left)
+      {
+         size = MIN(out->buffer_size - out->size, module->start_code_bytes_left);
+         memcpy(out->data + out->size, h264_start_code + sizeof(h264_start_code) -
+                module->start_code_bytes_left, size);
+         module->start_code_bytes_left -= size;
+         module->bytes_read += size;
+         out->size += size;
+      }
+
+      /* Then append the NAL unit itself */
+      if (module->nal_bytes_left)
+      {
+         size = MIN(out->buffer_size - out->size, module->nal_bytes_left);
+         bytestream_get( stream, out->data + out->size, size );
+         module->nal_bytes_left -= size;
+         module->bytes_read += size;
+         out->size += size;
+      }
+
+      /* Check whether we're done */
+      if (module->bytes_read == module->frame_size)
+      {
+         bytestream_skip_packet(stream);
+         module->state = STATE_FRAME_WAIT;
+         module->frame_size = 0;
+         module->bytes_read = 0;
+         return VC_CONTAINER_SUCCESS;
+      }
+      else if (out->buffer_size == out->size)
+      {
+         out->flags &= ~VC_CONTAINER_PACKET_FLAG_FRAME_END;
+         module->state = STATE_BUFFER_INIT;
+         return VC_CONTAINER_SUCCESS;
+      }
+
+      /* We're not done, go to the next relevant state */
+      module->state = STATE_NAL_START;
+      break;
+
+   default:
+      break;
+   };
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T avc1_packetizer_codecconfig( VC_PACKETIZER_T *p_ctx )
+{
+   VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status;
+   uint8_t *out, *extra = p_ctx->in->extradata + 5;
+   uint8_t *extra_end = extra + p_ctx->in->extradata_size - 5;
+   unsigned int i, j, nal_size, out_size = 0;
+
+   if (p_ctx->in->extradata_size <= 5 ||
+       p_ctx->in->extradata[0] != 1 /* configurationVersion */)
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+
+   status = vc_container_format_extradata_alloc(p_ctx->out, p_ctx->in->extradata_size);
+   if (status != VC_CONTAINER_SUCCESS)
+      return status;
+
+   out = p_ctx->out->extradata;
+   module->length_size = (*(p_ctx->in->extradata + 4) & 0x3) + 1;
+
+   for (i = 0; i < 2 && extra < extra_end - 1; i++)
+   {
+      j = *(extra++) & (!i ? 0x1F : 0xFF);
+      for (; j > 0 && extra < extra_end - 2; j--)
+      {
+         nal_size = (extra[0] << 8) | extra[1]; extra += 2;
+         if (extra + nal_size > extra_end)
+         {
+            extra = extra_end;
+            break;
+         }
+
+         out[0] = out[1] = out[2] = 0; out[3] = 1;
+         memcpy(out + 4, extra, nal_size);
+         out += nal_size + 4; extra += nal_size;
+         out_size += nal_size + 4;
+      }
+   }
+
+   p_ctx->out->extradata_size = out_size;
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T avc1_packetizer_open( VC_PACKETIZER_T *p_ctx )
+{
+   VC_PACKETIZER_MODULE_T *module;
+   VC_CONTAINER_STATUS_T status;
+
+   if(p_ctx->in->codec != VC_CONTAINER_CODEC_H264 &&
+      p_ctx->out->codec != VC_CONTAINER_CODEC_H264)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   if(p_ctx->in->codec_variant != VC_CONTAINER_VARIANT_H264_AVC1 &&
+      p_ctx->out->codec_variant != VC_CONTAINER_VARIANT_H264_DEFAULT)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   if(!(p_ctx->in->flags & VC_CONTAINER_ES_FORMAT_FLAG_FRAMED))
+     return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   p_ctx->priv->module = module = malloc(sizeof(*module));
+   if(!module)
+      return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+   memset(module, 0, sizeof(*module));
+
+   vc_container_format_copy(p_ctx->out, p_ctx->in, 0);
+   status = avc1_packetizer_codecconfig(p_ctx);
+   if (status != VC_CONTAINER_SUCCESS)
+   {
+      free(module);
+      return status;
+   }
+
+   p_ctx->out->codec_variant = VC_CONTAINER_VARIANT_H264_DEFAULT;
+   p_ctx->max_frame_size = MAX_FRAME_SIZE;
+   p_ctx->priv->pf_close = avc1_packetizer_close;
+   p_ctx->priv->pf_packetize = avc1_packetizer_packetize;
+   p_ctx->priv->pf_reset = avc1_packetizer_reset;
+   LOG_DEBUG(0, "using avc1 video packetizer");
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_PACKETIZER_REGISTER(avc1_packetizer_open,  "avc1");
diff --git a/containers/io/io_file.c b/containers/io/io_file.c
new file mode 100755 (executable)
index 0000000..ea4b945
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <limits.h>
+
+#include "containers/containers.h"
+#include "containers/core/containers_common.h"
+#include "containers/core/containers_io.h"
+#include "containers/core/containers_uri.h"
+
+typedef struct VC_CONTAINER_IO_MODULE_T
+{
+   FILE *stream;
+
+} VC_CONTAINER_IO_MODULE_T;
+
+VC_CONTAINER_STATUS_T vc_container_io_file_open( VC_CONTAINER_IO_T *, const char *,
+   VC_CONTAINER_IO_MODE_T );
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T io_file_close( VC_CONTAINER_IO_T *p_ctx )
+{
+   VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
+   fclose(module->stream);
+   free(module);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static size_t io_file_read(VC_CONTAINER_IO_T *p_ctx, void *buffer, size_t size)
+{
+   size_t ret = fread(buffer, 1, size, p_ctx->module->stream);
+   if(ret != size)
+   {
+      /* Sanity check return value. Some platforms (e.g. Android) can return -1 */
+      if( ((int)ret) < 0 ) ret = 0;
+
+      if( feof(p_ctx->module->stream) ) p_ctx->status = VC_CONTAINER_ERROR_EOS;
+      else p_ctx->status = VC_CONTAINER_ERROR_FAILED;
+   }
+   return ret;
+}
+
+/*****************************************************************************/
+static size_t io_file_write(VC_CONTAINER_IO_T *p_ctx, const void *buffer, size_t size)
+{
+   return fwrite(buffer, 1, size, p_ctx->module->stream);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T io_file_seek(VC_CONTAINER_IO_T *p_ctx, int64_t offset)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   int ret;
+
+   //FIXME: large file support
+#ifdef _VIDEOCORE
+   extern int fseek64(FILE *fp, int64_t offset, int whence);
+   ret = fseek64(p_ctx->module->stream, offset, SEEK_SET);
+#else
+   if (offset > (int64_t)UINT_MAX)
+   {
+      p_ctx->status = VC_CONTAINER_ERROR_EOS;
+      return VC_CONTAINER_ERROR_EOS;
+   }
+   ret = fseek(p_ctx->module->stream, (long)offset, SEEK_SET);
+#endif   
+   if(ret)
+   {
+      if( feof(p_ctx->module->stream) ) status = VC_CONTAINER_ERROR_EOS;
+      else status = VC_CONTAINER_ERROR_FAILED;
+   }
+
+   p_ctx->status = status;
+   return status;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_io_file_open( VC_CONTAINER_IO_T *p_ctx,
+   const char *unused, VC_CONTAINER_IO_MODE_T mode )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_IO_MODULE_T *module = 0;
+   const char *psz_mode = mode == VC_CONTAINER_IO_MODE_WRITE ? "wb+" : "rb";
+   const char *uri = p_ctx->uri;
+   FILE *stream = 0;
+   VC_CONTAINER_PARAM_UNUSED(unused);
+
+   if(vc_uri_path(p_ctx->uri_parts))
+      uri = vc_uri_path(p_ctx->uri_parts);
+
+   stream = fopen(uri, psz_mode);
+   if(!stream) { status = VC_CONTAINER_ERROR_URI_NOT_FOUND; goto error; }
+
+   /* Turn off buffering. The container layer will provide its own cache */
+   setvbuf(stream, NULL, _IONBF, 0);
+
+   module = malloc( sizeof(*module) );
+   if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(module, 0, sizeof(*module));
+
+   p_ctx->module = module;
+   module->stream = stream;
+   p_ctx->pf_close = io_file_close;
+   p_ctx->pf_read = io_file_read;
+   p_ctx->pf_write = io_file_write;
+   p_ctx->pf_seek = io_file_seek;
+
+   if(mode == VC_CONTAINER_IO_MODE_WRITE)
+   {
+      p_ctx->max_size = (1UL<<31)-1; /* For now limit to 2GB */
+   }
+   else
+   {
+      //FIXME: large file support, platform-specific file size
+      fseek(p_ctx->module->stream, 0, SEEK_END);
+      p_ctx->size = ftell(p_ctx->module->stream);
+      fseek(p_ctx->module->stream, 0, SEEK_SET);
+   }
+
+   p_ctx->capabilities = VC_CONTAINER_IO_CAPS_NO_CACHING;
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+   if(stream) fclose(stream);
+   return status;
+}
diff --git a/containers/io/io_http.c b/containers/io/io_http.c
new file mode 100755 (executable)
index 0000000..48d8661
--- /dev/null
@@ -0,0 +1,898 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "containers/containers.h"
+#include "containers/core/containers_common.h"
+#include "containers/core/containers_io.h"
+#include "containers/core/containers_uri.h"
+#include "containers/core/containers_logging.h"
+#include "containers/core/containers_list.h"
+#include "containers/core/containers_utils.h"
+#include "containers/net/net_sockets.h"
+
+/* Set to 1 if you want to log all HTTP requests */
+#define ENABLE_HTTP_EXTRA_LOGGING 0
+
+/******************************************************************************
+Defines and constants.
+******************************************************************************/
+
+#define IO_HTTP_DEFAULT_PORT     "80"
+
+/** Space for sending requests and receiving responses */
+#define COMMS_BUFFER_SIZE              4000
+
+/** Largest allowed HTTP URI. Must be substantially smaller than COMMS_BUFFER_SIZE
+ * to allow for the headers that may be sent. */
+#define HTTP_URI_LENGTH_MAX            1024
+
+/** Initial capacity of header list */
+#define HEADER_LIST_INITIAL_CAPACITY   16
+
+/** Format of the first line of an HTTP request */
+#define HTTP_REQUEST_LINE_FORMAT       "%s %s HTTP/1.1\r\nHost: %s\r\n"
+
+/** Format of a range request */
+#define HTTP_RANGE_REQUEST             "Range: bytes=%"PRId64"-%"PRId64"\r\n"
+
+/** Format string for common headers used with all request methods.
+ * Note: includes double new line to terminate headers */
+#define TRAILING_HEADERS_FORMAT        "User-Agent: Broadcom/1.0\r\n\r\n"
+
+/** \name HTTP methods, used as the first item in the request line
+ * @{ */
+#define GET_METHOD                     "GET"
+#define HEAD_METHOD                    "HEAD"
+/* @} */
+
+/** \name Names of headers used by the code
+ * @{ */
+#define CONTENT_LENGTH_NAME            "Content-Length"
+#define CONTENT_BASE_NAME              "Content-Base"
+#define CONTENT_LOCATION_NAME          "Content-Location"
+#define ACCEPT_RANGES_NAME             "Accept-Ranges"
+#define CONNECTION_NAME                "Connection"
+/* @} */
+
+/** Supported HTTP major version number */
+#define HTTP_MAJOR_VERSION             1
+/** Supported HTTP minor version number */
+#define HTTP_MINOR_VERSION             1
+
+/** Lowest successful status code value */
+#define HTTP_STATUS_OK                 200
+#define HTTP_STATUS_PARTIAL_CONTENT    206
+
+typedef struct http_header_tag {
+   const char *name;
+   char *value;
+} HTTP_HEADER_T;
+
+
+/******************************************************************************
+Type definitions
+******************************************************************************/
+typedef struct VC_CONTAINER_IO_MODULE_T
+{
+   VC_CONTAINER_NET_T *sock;
+   VC_CONTAINERS_LIST_T *header_list;           /**< Parsed response headers, pointing into comms buffer */
+
+   bool persistent;
+   int64_t cur_offset;
+   bool reconnecting;
+
+   /* Buffer used for sending and receiving HTTP messages */
+   char comms_buffer[COMMS_BUFFER_SIZE];
+} VC_CONTAINER_IO_MODULE_T;
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+
+static int io_http_header_comparator(const HTTP_HEADER_T *first, const HTTP_HEADER_T *second);
+static VC_CONTAINER_STATUS_T io_http_send(VC_CONTAINER_IO_T *p_ctx);
+
+VC_CONTAINER_STATUS_T vc_container_io_http_open(VC_CONTAINER_IO_T *, const char *,
+   VC_CONTAINER_IO_MODE_T);
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+
+/**************************************************************************//**
+ * Trim whitespace from the end and start of the string
+ *
+ * \param   str   String to be trimmed
+ * \return        Trimmed string
+ */
+static char *io_http_trim(char *str)
+{
+   char *s = str + strlen(str);
+
+   /* Search backwards for first non-whitespace */
+   while (--s >= str &&(*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r'))
+      ;     /* Everything done in the while */
+   s[1] = '\0';
+
+   /* Now move start of string forwards to first non-whitespace */
+   s = str;
+   while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r')
+      s++;
+
+   return s;
+}
+
+/**************************************************************************//**
+ * Header comparison function.
+ * Compare two header structures and return whether the first is less than,
+ * equal to or greater than the second.
+ *
+ * @param first   The first structure to be compared.
+ * @param second  The second structure to be compared.
+ * @return  Negative if first is less than second, positive if first is greater
+ *          and zero if they are equal.
+ */
+static int io_http_header_comparator(const HTTP_HEADER_T *first, const HTTP_HEADER_T *second)
+{
+   return strcasecmp(first->name, second->name);
+}
+
+/**************************************************************************//**
+ * Check a response status line to see if the response is usable or not.
+ * Reasons for invalidity include:
+ *    - Incorrectly formatted
+ *    - Unsupported version
+ *    - Status code is not in the 2xx range
+ *
+ * @param status_line   The response status line.
+ * @return  The resulting status of the function.
+ */
+static bool io_http_successful_response_status(const char *status_line)
+{
+   unsigned int major_version, minor_version, status_code;
+
+   /* coverity[secure_coding] String is null-terminated */
+   if (sscanf(status_line, "HTTP/%u.%u %u", &major_version, &minor_version, &status_code) != 3)
+   {
+      LOG_ERROR(NULL, "HTTP: Invalid response status line:\n%s", status_line);
+      return false;
+   }
+
+   if (major_version != HTTP_MAJOR_VERSION || minor_version != HTTP_MINOR_VERSION)
+   {
+      LOG_ERROR(NULL, "HTTP: Unexpected response HTTP version: %u.%u", major_version, minor_version);
+      return false;
+   }
+
+   if (status_code != HTTP_STATUS_OK && status_code != HTTP_STATUS_PARTIAL_CONTENT)
+   {
+      LOG_ERROR(NULL, "HTTP: Response status unsuccessful:\n%s", status_line);
+      return false;
+   }
+
+   return true;
+}
+
+/**************************************************************************//**
+ * Get the content length header from the response headers as an unsigned
+ * 64-bit integer.
+ * If the content length header is not found or badly formatted, zero is
+ * returned.
+ *
+ * @param header_list   The response headers.
+ * @return  The content length.
+ */
+static uint64_t io_http_get_content_length(VC_CONTAINERS_LIST_T *header_list)
+{
+   uint64_t content_length = 0;
+   HTTP_HEADER_T header;
+
+   header.name = CONTENT_LENGTH_NAME;
+   if (header_list && vc_containers_list_find_entry(header_list, &header))
+      /* coverity[secure_coding] String is null-terminated */
+      sscanf(header.value, "%"PRIu64, &content_length);
+
+   return content_length;
+}
+
+/**************************************************************************//**
+ * Get the accept ranges header from the response headers and verify that
+ * the server accepts byte ranges..
+ * If the accept ranges header is not found false is returned.
+ *
+ * @param header_list   The response headers.
+ * @return  The resulting status of the function.
+ */
+static bool io_http_check_accept_range(VC_CONTAINERS_LIST_T *header_list)
+{
+   HTTP_HEADER_T header;
+
+   header.name = ACCEPT_RANGES_NAME;
+   if (header_list && vc_containers_list_find_entry(header_list, &header))
+   {
+      /* coverity[secure_coding] String is null-terminated */
+      if (!strcasecmp(header.value, "bytes"))
+         return true;
+   }
+
+   return false;
+}
+
+/**************************************************************************//**
+ * Check whether the server supports persistent connections.
+ *
+ * @param header_list   The response headers.
+ * @return  The resulting status of the function.
+ */
+static bool io_http_check_persistent_connection(VC_CONTAINERS_LIST_T *header_list)
+{
+   HTTP_HEADER_T header;
+
+   header.name = CONNECTION_NAME;
+   if (header_list && vc_containers_list_find_entry(header_list, &header))
+   {
+      /* coverity[secure_coding] String is null-terminated */
+      if (!strcasecmp(header.value, "close"))
+         return false;
+   }
+
+   return true;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T translate_net_status_to_container_status(vc_container_net_status_t net_status)
+{
+   switch (net_status)
+   {
+   case VC_CONTAINER_NET_SUCCESS:                  return VC_CONTAINER_SUCCESS;
+   case VC_CONTAINER_NET_ERROR_INVALID_SOCKET:     return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+   case VC_CONTAINER_NET_ERROR_NOT_ALLOWED:        return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+   case VC_CONTAINER_NET_ERROR_INVALID_PARAMETER:  return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+   case VC_CONTAINER_NET_ERROR_NO_MEMORY:          return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+   case VC_CONTAINER_NET_ERROR_IN_USE:             return VC_CONTAINER_ERROR_URI_OPEN_FAILED;
+   case VC_CONTAINER_NET_ERROR_NETWORK:            return VC_CONTAINER_ERROR_EOS;
+   case VC_CONTAINER_NET_ERROR_CONNECTION_LOST:    return VC_CONTAINER_ERROR_EOS;
+   case VC_CONTAINER_NET_ERROR_NOT_CONNECTED:      return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+   case VC_CONTAINER_NET_ERROR_TIMED_OUT:          return VC_CONTAINER_ERROR_ABORTED;
+   case VC_CONTAINER_NET_ERROR_CONNECTION_REFUSED: return VC_CONTAINER_ERROR_NOT_FOUND;
+   case VC_CONTAINER_NET_ERROR_HOST_NOT_FOUND:     return VC_CONTAINER_ERROR_NOT_FOUND;
+   case VC_CONTAINER_NET_ERROR_TRY_AGAIN:          return VC_CONTAINER_ERROR_CONTINUE;
+   default:                                        return VC_CONTAINER_ERROR_FAILED;
+   }
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T io_http_open_socket(VC_CONTAINER_IO_T *ctx)
+{
+   VC_CONTAINER_IO_MODULE_T *module = ctx->module;
+   VC_CONTAINER_STATUS_T status;
+   const char *host, *port;
+
+   /* Treat empty host or port strings as not defined */
+   port = vc_uri_port(ctx->uri_parts);
+   if (port && !*port)
+      port = NULL;
+
+   /* Require the port to be defined */
+   if (!port)
+   {
+      status = VC_CONTAINER_ERROR_URI_OPEN_FAILED;
+      goto error;
+   }
+
+   host = vc_uri_host(ctx->uri_parts);
+   if (host && !*host)
+      host = NULL;
+
+   if (!host)
+   {
+      status = VC_CONTAINER_ERROR_URI_OPEN_FAILED;
+      goto error;
+   }
+
+   module->sock = vc_container_net_open(host, port, VC_CONTAINER_NET_OPEN_FLAG_STREAM, NULL);
+   if (!module->sock)
+   {
+      status = VC_CONTAINER_ERROR_URI_NOT_FOUND;
+      goto error;
+   }
+
+   return VC_CONTAINER_SUCCESS;
+
+error:
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T io_http_close_socket(VC_CONTAINER_IO_MODULE_T *module)
+{
+   if (module->sock)
+   {
+      vc_container_net_close(module->sock);
+      module->sock = NULL;
+   }
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static size_t io_http_read_from_net(VC_CONTAINER_IO_T *p_ctx, void *buffer, size_t size)
+{
+   size_t ret;
+   vc_container_net_status_t net_status;
+
+   ret           = vc_container_net_read(p_ctx->module->sock, buffer, size);
+   net_status    = vc_container_net_status(p_ctx->module->sock);
+   p_ctx->status = translate_net_status_to_container_status(net_status);
+
+   return ret;
+}
+
+/**************************************************************************//**
+ * Reads an HTTP response and parses it into headers and content.
+ * The headers and content remain stored in the comms buffer, but referenced
+ * by the module's header list. Content uses a special header name that cannot
+ * occur in the real headers.
+ *
+ * @param p_ctx   The HTTP reader context.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T io_http_read_response(VC_CONTAINER_IO_T *p_ctx)
+{
+   VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
+   char *next_read = module->comms_buffer;
+   size_t space_available = sizeof(module->comms_buffer) - 1; /* Allow for a NUL */
+   char *ptr = next_read;
+   bool end_response = false;
+   HTTP_HEADER_T header;
+   const char endstr[] = "\r\n\r\n";
+   int endcount = sizeof(endstr) - 1;
+   int endchk = 0;
+
+   vc_containers_list_reset(module->header_list);
+
+   /* Response status line doesn't need to be stored, just checked */
+   header.name = NULL;
+   header.value = next_read;
+
+   /*
+    * We need to read just a byte at a time to make sure that we just read the HTTP response and
+    * no more. For example, if a GET operation was requested the file being fetched will also
+    * be waiting to be read on the socket.
+    */
+
+   while (space_available)
+   {
+      if (io_http_read_from_net(p_ctx, next_read, 1) != 1)
+         break;
+
+      next_read++;
+      space_available--;
+
+      if (next_read[-1] == endstr[endchk])
+      {
+         if (++endchk == endcount)
+            break;
+      }
+      else
+         endchk = 0;
+   }
+   if (!space_available)
+   {
+      LOG_ERROR(NULL, "comms buffer too small for complete HTTP message (%d)",
+                sizeof(module->comms_buffer));
+      return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+
+   *next_read = '\0';
+
+   if (endchk == endcount)
+   {
+      if (ENABLE_HTTP_EXTRA_LOGGING)
+         LOG_DEBUG(NULL, "READ FROM SERVER: %d bytes\n%s\n-----------------------------------------",
+                   sizeof(module->comms_buffer) - 1 - space_available, module->comms_buffer);
+
+      while (!end_response && ptr < next_read)
+      {
+         switch (*ptr)
+         {
+            case ':':
+               if (header.value)
+               {
+                  /* Just another character in the value */
+                  ptr++;
+               } else {
+                  /* End of name, expect value next */
+                  *ptr++ = '\0';
+                  header.value = ptr;
+               }
+               break;
+
+            case '\n':
+               if (header.value)
+               {
+                  /* End of line while parsing the value part of the header, add name/value pair to list */
+                  *ptr++ = '\0';
+                  header.value = io_http_trim(header.value);
+                  if (header.name)
+                  {
+                     if (!vc_containers_list_insert(module->header_list, &header, false))
+                     {
+                        LOG_ERROR(NULL, "HTTP: Failed to add <%s> header to list", header.name);
+                        return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+                     }
+                  } else {
+                     /* Check response status line */
+                     if (!io_http_successful_response_status(header.value))
+                        return VC_CONTAINER_ERROR_FORMAT_INVALID;
+                  }
+                  /* Ready for next header */
+                  header.name  = ptr;
+                  header.value = NULL;
+               } else {
+                  /* End of line while parsing the name of a header */
+                  *ptr++ = '\0';
+                  if (*header.name && *header.name != '\r')
+                  {
+                     /* A non-empty name is invalid, so fail */
+                     LOG_ERROR(NULL, "HTTP: Invalid name in header - no colon:\n%s", header.name);
+                     return VC_CONTAINER_ERROR_FORMAT_INVALID;
+                  }
+
+                  /* An empty name signifies the end of the HTTP response */
+                  end_response = true;
+               }
+               break;
+
+            default:
+               /* Just another character in either the name or the value */
+               ptr++;
+         }
+      }
+   }
+
+   if (!space_available && !end_response)
+   {
+      /* Ran out of buffer space */
+      LOG_ERROR(NULL, "HTTP: Response header section too big");
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+
+   return p_ctx->status;
+}
+
+/**************************************************************************//**
+ * Send a GET request to the HTTP server.
+ *
+ * @param p_ctx      The reader context.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T io_http_send_get_request(VC_CONTAINER_IO_T *p_ctx, size_t size)
+{
+   VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
+   char *ptr = module->comms_buffer, *end = ptr + sizeof(module->comms_buffer);
+   int64_t end_offset;
+
+   ptr += snprintf(ptr, end - ptr, HTTP_REQUEST_LINE_FORMAT, GET_METHOD,
+                   vc_uri_path(p_ctx->uri_parts), vc_uri_host(p_ctx->uri_parts));
+
+   end_offset = module->cur_offset + size - 1;
+   if (end_offset >= p_ctx->size)
+      end_offset = p_ctx->size - 1;
+
+   if (ptr < end)
+      ptr += snprintf(ptr, end - ptr, HTTP_RANGE_REQUEST, module->cur_offset, end_offset);
+
+   if (ptr < end)
+      ptr += snprintf(ptr, end - ptr, TRAILING_HEADERS_FORMAT);
+
+   if (ptr >= end)
+   {
+      LOG_ERROR(0, "comms buffer too small (%i/%u)", (int)(end - ptr),
+                sizeof(module->comms_buffer));
+      return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+   }
+
+   if (ENABLE_HTTP_EXTRA_LOGGING)
+      LOG_DEBUG(NULL, "Sending server read request:\n%s\n---------------------\n", module->comms_buffer);
+   return io_http_send(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T io_http_seek(VC_CONTAINER_IO_T *p_ctx, int64_t offset)
+{
+   VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
+
+   /*
+    * No seeking past the end of the file.
+    */
+
+   if (offset < 0 || offset > p_ctx->size)
+   {
+      p_ctx->status = VC_CONTAINER_ERROR_EOS;
+      return VC_CONTAINER_ERROR_EOS;
+   }
+
+   module->cur_offset = offset;
+   p_ctx->status = VC_CONTAINER_SUCCESS;
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T io_http_close(VC_CONTAINER_IO_T *p_ctx)
+{
+   VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
+
+   if (!module)
+      return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+
+   io_http_close_socket(module);
+   if (module->header_list)
+      vc_containers_list_destroy(module->header_list);
+
+   free(module);
+   p_ctx->module = NULL;
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static size_t io_http_read(VC_CONTAINER_IO_T *p_ctx, void *buffer, size_t size)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
+   size_t content_length;
+   size_t bytes_read;
+   size_t ret = 0;
+   char *ptr = buffer;
+
+   /*
+    * Are we at the end of the file?
+    */
+
+   if (module->cur_offset >= p_ctx->size)
+   {
+      p_ctx->status = VC_CONTAINER_ERROR_EOS;
+      return 0;
+   }
+
+   if (!module->persistent)
+   {
+      status = io_http_open_socket(p_ctx);
+      if (status != VC_CONTAINER_SUCCESS)
+      {
+         LOG_ERROR(NULL, "Error opening socket for GET request");
+         return status;
+      }
+   }
+
+   /* Send GET request and get response */
+   status = io_http_send_get_request(p_ctx, size);
+   if (status != VC_CONTAINER_SUCCESS)
+   {
+      LOG_ERROR(NULL, "Error sending GET request");
+      goto error;
+   }
+
+   status = io_http_read_response(p_ctx);
+   if (status == VC_CONTAINER_ERROR_EOS && !module->reconnecting)
+   {
+      LOG_DEBUG(NULL, "reconnecting");
+      io_http_close_socket(module);
+      status = io_http_open_socket(p_ctx);
+      if (status == VC_CONTAINER_SUCCESS)
+      {
+         module->reconnecting = true;
+         status = io_http_read(p_ctx, buffer, size);
+         module->reconnecting = false;
+         return status;
+      }
+   }
+   if (status != VC_CONTAINER_SUCCESS)
+   {
+      LOG_ERROR(NULL, "Error reading GET response");
+      goto error;
+   }
+
+   /*
+    * How much data is the server offering us?
+    */
+
+   content_length = (size_t)io_http_get_content_length(module->header_list);
+   if (content_length > size)
+   {
+      LOG_ERROR(NULL, "received too much data (%i/%i)",
+                (int)content_length, (int)size);
+      status = VC_CONTAINER_ERROR_CORRUPTED;
+      goto error;
+   }
+
+   bytes_read = 0;
+   while (bytes_read < content_length && p_ctx->status == VC_CONTAINER_SUCCESS)
+   {
+      ret = io_http_read_from_net(p_ctx, ptr, content_length - bytes_read);
+      if (p_ctx->status == VC_CONTAINER_SUCCESS)
+      {
+         bytes_read += ret;
+         ptr += ret;
+      }
+   }
+
+   if (p_ctx->status == VC_CONTAINER_SUCCESS)
+   {
+      module->cur_offset += bytes_read;
+      ret = bytes_read;
+   }
+
+   if (!module->persistent)
+      io_http_close_socket(module);
+
+   return ret;
+
+error:
+   if (!module->persistent)
+      io_http_close_socket(module);
+
+   return status;
+}
+
+/*****************************************************************************/
+static size_t io_http_write(VC_CONTAINER_IO_T *p_ctx, const void *buffer, size_t size)
+{
+   size_t ret = vc_container_net_write(p_ctx->module->sock, buffer, size);
+   vc_container_net_status_t net_status;
+
+   net_status = vc_container_net_status(p_ctx->module->sock);
+   p_ctx->status = translate_net_status_to_container_status(net_status);
+
+   return ret;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T io_http_control(struct VC_CONTAINER_IO_T *p_ctx,
+      VC_CONTAINER_CONTROL_T operation,
+      va_list args)
+{
+   vc_container_net_status_t net_status;
+   VC_CONTAINER_STATUS_T status;
+
+   switch (operation)
+   {
+   case VC_CONTAINER_CONTROL_IO_SET_READ_BUFFER_SIZE:
+      net_status = vc_container_net_control(p_ctx->module->sock, VC_CONTAINER_NET_CONTROL_SET_READ_BUFFER_SIZE, args);
+      break;
+   case VC_CONTAINER_CONTROL_IO_SET_READ_TIMEOUT_MS:
+      net_status = vc_container_net_control(p_ctx->module->sock, VC_CONTAINER_NET_CONTROL_SET_READ_TIMEOUT_MS, args);
+      break;
+   default:
+      net_status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED;
+   }
+
+   status = translate_net_status_to_container_status(net_status);
+   p_ctx->status = status;
+
+   return status;
+}
+
+/**************************************************************************//**
+ * Send out the data in the comms buffer.
+ *
+ * @param p_ctx      The reader context.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T io_http_send(VC_CONTAINER_IO_T *p_ctx)
+{
+   VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
+   size_t to_write;
+   size_t written;
+   const char *buffer = module->comms_buffer;
+
+   to_write = strlen(buffer);
+
+   while (to_write)
+   {
+      written = io_http_write(p_ctx, buffer, to_write);
+      if (p_ctx->status != VC_CONTAINER_SUCCESS)
+         break;
+
+      to_write -= written;
+      buffer   += written;
+   }
+
+   return p_ctx->status;
+}
+
+/**************************************************************************//**
+ * Send a HEAD request to the HTTP server.
+ *
+ * @param p_ctx      The reader context.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T io_http_send_head_request(VC_CONTAINER_IO_T *p_ctx)
+{
+   VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
+   char *ptr = module->comms_buffer, *end = ptr + sizeof(module->comms_buffer);
+
+   ptr += snprintf(ptr, end - ptr, HTTP_REQUEST_LINE_FORMAT, HEAD_METHOD,
+                   vc_uri_path(p_ctx->uri_parts), vc_uri_host(p_ctx->uri_parts));
+   if (ptr < end)
+      ptr += snprintf(ptr, end - ptr, TRAILING_HEADERS_FORMAT);
+
+   if (ptr >= end)
+   {
+      LOG_ERROR(0, "comms buffer too small (%i/%u)", (int)(end - ptr),
+                sizeof(module->comms_buffer));
+      return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+   }
+
+   return io_http_send(p_ctx);
+}
+
+static VC_CONTAINER_STATUS_T io_http_head(VC_CONTAINER_IO_T *p_ctx)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
+   uint64_t content_length;
+
+   /* Send HEAD request and get response */
+   status = io_http_send_head_request(p_ctx);
+   if (status != VC_CONTAINER_SUCCESS)
+      return status;
+   status = io_http_read_response(p_ctx);
+   if (status != VC_CONTAINER_SUCCESS)
+      return status;
+
+   /*
+    * Save the content length since that's our file size.
+    */
+
+   content_length = io_http_get_content_length(module->header_list);
+   if (content_length)
+   {
+      p_ctx->size = content_length;
+      LOG_DEBUG(NULL, "File size is %"PRId64, p_ctx->size);
+   }
+
+   /*
+    * Now make sure that the server supports byte range requests.
+    */
+
+   if (!io_http_check_accept_range(module->header_list))
+   {
+      LOG_ERROR(NULL, "Server doesn't support byte range requests");
+      return VC_CONTAINER_ERROR_FAILED;
+   }
+
+   /*
+    * Does it support persistent connections?
+    */
+
+   if (io_http_check_persistent_connection(module->header_list))
+   {
+      module->persistent = true;
+   }
+   else
+   {
+      LOG_DEBUG(NULL, "Server does not support persistent connections");
+      io_http_close_socket(module);
+   }
+
+   module->cur_offset = 0;
+
+   return status;
+}
+
+/*****************************************************************************
+Functions exported as part of the I/O Module API
+ *****************************************************************************/
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_io_http_open(VC_CONTAINER_IO_T *p_ctx,
+   const char *unused, VC_CONTAINER_IO_MODE_T mode)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_IO_MODULE_T *module = 0;
+   VC_CONTAINER_PARAM_UNUSED(unused);
+
+   /* Check the URI to see if we're dealing with an http stream */
+   if (!vc_uri_scheme(p_ctx->uri_parts) ||
+       strcasecmp(vc_uri_scheme(p_ctx->uri_parts), "http"))
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   /*
+    * Some basic error checking.
+    */
+
+   if (mode == VC_CONTAINER_IO_MODE_WRITE)
+   {
+      status = VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+      goto error;
+   }
+
+   if (strlen(p_ctx->uri) > HTTP_URI_LENGTH_MAX)
+   {
+      status = VC_CONTAINER_ERROR_URI_OPEN_FAILED;
+      goto error;
+   }
+
+   module = calloc(1, sizeof(*module));
+   if (!module)
+   {
+      status = VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+      goto error;
+   }
+   p_ctx->module = module;
+
+   /* header_list will contain pointers into the response_buffer, so take care in re-use */
+   module->header_list = vc_containers_list_create(HEADER_LIST_INITIAL_CAPACITY, sizeof(HTTP_HEADER_T),
+                                           (VC_CONTAINERS_LIST_COMPARATOR_T)io_http_header_comparator);
+   if (!module->header_list)
+   {
+      status = VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+      goto error;
+   }
+
+   /*
+    * Make sure that we have a port number.
+    */
+
+   if (vc_uri_port(p_ctx->uri_parts) == NULL)
+      vc_uri_set_port(p_ctx->uri_parts, IO_HTTP_DEFAULT_PORT);
+
+   status = io_http_open_socket(p_ctx);
+   if (status != VC_CONTAINER_SUCCESS)
+      goto error;
+
+   /*
+    * Whoo hoo! Our socket is open. Now let's send a HEAD request.
+    */
+
+   status = io_http_head(p_ctx);
+   if (status != VC_CONTAINER_SUCCESS)
+      goto error;
+
+   p_ctx->pf_close   = io_http_close;
+   p_ctx->pf_read    = io_http_read;
+   p_ctx->pf_write   = NULL;
+   p_ctx->pf_control = io_http_control;
+   p_ctx->pf_seek    = io_http_seek;
+
+   p_ctx->capabilities = VC_CONTAINER_IO_CAPS_NO_CACHING;
+   p_ctx->capabilities |= VC_CONTAINER_IO_CAPS_SEEK_SLOW;
+
+   return VC_CONTAINER_SUCCESS;
+
+error:
+   io_http_close(p_ctx);
+   return status;
+}
diff --git a/containers/io/io_net.c b/containers/io/io_net.c
new file mode 100755 (executable)
index 0000000..a1912e5
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "containers/containers.h"
+#include "containers/core/containers_common.h"
+#include "containers/core/containers_io.h"
+#include "containers/core/containers_uri.h"
+#include "containers/net/net_sockets.h"
+
+/* Uncomment this macro definition to capture data read and written through this interface */
+/* #define IO_NET_CAPTURE_PACKETS */
+
+#ifdef IO_NET_CAPTURE_PACKETS
+#include <stdio.h>
+
+#ifdef ENABLE_CONTAINERS_STANDALONE
+#ifdef _MSC_VER
+#define IO_NET_CAPTURE_PREFIX          "C:\\"
+#else /* !_MSC_VER */
+#define IO_NET_CAPTURE_PREFIX          "~/"
+#endif
+#else /* !ENABLE_CONTAINERS_STANDALONE */
+#define IO_NET_CAPTURE_PREFIX          "/mfs/sd/"
+#endif
+
+#define IO_NET_CAPTURE_READ_FILE       "capture_read_%s_%s%c.pkt"
+#define IO_NET_CAPTURE_WRITE_FILE      "capture_write_%s_%s%c.pkt"
+#define IO_NET_CAPTURE_READ_FORMAT     IO_NET_CAPTURE_PREFIX IO_NET_CAPTURE_READ_FILE
+#define IO_NET_CAPTURE_WRITE_FORMAT    IO_NET_CAPTURE_PREFIX IO_NET_CAPTURE_WRITE_FILE
+
+#define CAPTURE_FILENAME_BUFFER_SIZE   300
+
+#define CAPTURE_BUFFER_SIZE            65536
+
+/** Native byte order word */
+#define NATIVE_BYTE_ORDER  0x50415753
+#endif
+
+/******************************************************************************
+Defines and constants.
+******************************************************************************/
+
+/******************************************************************************
+Type definitions
+******************************************************************************/
+typedef struct VC_CONTAINER_IO_MODULE_T
+{
+   VC_CONTAINER_NET_T *sock;
+#ifdef IO_NET_CAPTURE_PACKETS
+   FILE *read_capture_file;
+   FILE *write_capture_file;
+#endif
+} VC_CONTAINER_IO_MODULE_T;
+
+/** List of recognised network URI schemes (TCP or UDP).
+ * Note: always use lower case for the scheme name. */
+static struct
+{
+   const char *scheme;
+   bool is_udp;
+} recognised_schemes[] = {
+   { "rtp:", true },
+   { "rtsp:", false },
+};
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_io_net_open( VC_CONTAINER_IO_T *, const char *,
+   VC_CONTAINER_IO_MODE_T );
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+
+#ifdef IO_NET_CAPTURE_PACKETS
+/*****************************************************************************/
+static FILE *io_net_open_capture_file(const char *host_str,
+      const char *port_str,
+      bool is_udp,
+      VC_CONTAINER_IO_MODE_T mode)
+{
+   char filename[CAPTURE_FILENAME_BUFFER_SIZE];
+   const char *format;
+   FILE *stream = NULL;
+   uint32_t byte_order = NATIVE_BYTE_ORDER;
+
+   switch (mode)
+   {
+   case VC_CONTAINER_IO_MODE_WRITE:
+      format = IO_NET_CAPTURE_WRITE_FORMAT;
+      break;
+   case VC_CONTAINER_IO_MODE_READ:
+      format = IO_NET_CAPTURE_READ_FORMAT;
+      break;
+   default:
+      /* Invalid mode */
+      return NULL;
+   }
+
+   if (!host_str)
+      host_str = "";
+   if (!port_str)
+      port_str = "";
+
+   /* Check filename will fit in buffer */
+   if (strlen(format) + strlen(host_str) + strlen(port_str) - 4 > CAPTURE_FILENAME_BUFFER_SIZE)
+      return NULL;
+
+   /* Create the file */
+   sprintf(filename, format, host_str, port_str, is_udp ? 'u' : 't');
+   stream = fopen(filename, "wb");
+   if (!stream)
+      return NULL;
+
+   /* Buffer plenty of data at a time, if possible */
+   setvbuf(stream, NULL, _IOFBF, CAPTURE_BUFFER_SIZE);
+
+   /* Start file with a byte order marker */
+   if (fwrite(&byte_order, 1, sizeof(byte_order), stream) != sizeof(byte_order))
+   {
+      /* Failed to write even just the byte order mark - abort */
+      fclose(stream);
+      stream = NULL;
+      remove(filename);
+   }
+
+   return stream;
+}
+
+/*****************************************************************************/
+static void io_net_capture_write_packet( FILE *stream,
+      const char *buffer,
+      uint32_t buffer_size )
+{
+   if (stream && buffer && buffer_size)
+   {
+      fwrite(&buffer_size, 1, sizeof(buffer_size), stream);
+      fwrite(buffer, 1, buffer_size, stream);
+   }
+}
+#endif
+
+/*****************************************************************************/
+static bool io_net_recognise_scheme(const char *uri, bool *is_udp)
+{
+   size_t ii;
+   const char *scheme;
+
+   if (!uri)
+      return false;
+
+   for (ii = 0; ii < countof(recognised_schemes); ii++)
+   {
+      scheme = recognised_schemes[ii].scheme;
+      if (strncmp(scheme, uri, strlen(scheme)) == 0)
+      {
+         *is_udp = recognised_schemes[ii].is_udp;
+         return true;
+      }
+   }
+
+   return false;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T translate_net_status_to_container_status(vc_container_net_status_t net_status)
+{
+   switch (net_status)
+   {
+   case VC_CONTAINER_NET_SUCCESS:                  return VC_CONTAINER_SUCCESS;
+   case VC_CONTAINER_NET_ERROR_INVALID_SOCKET:     return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+   case VC_CONTAINER_NET_ERROR_NOT_ALLOWED:        return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+   case VC_CONTAINER_NET_ERROR_INVALID_PARAMETER:  return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+   case VC_CONTAINER_NET_ERROR_NO_MEMORY:          return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+   case VC_CONTAINER_NET_ERROR_IN_USE:             return VC_CONTAINER_ERROR_URI_OPEN_FAILED;
+   case VC_CONTAINER_NET_ERROR_NETWORK:            return VC_CONTAINER_ERROR_EOS;
+   case VC_CONTAINER_NET_ERROR_CONNECTION_LOST:    return VC_CONTAINER_ERROR_EOS;
+   case VC_CONTAINER_NET_ERROR_NOT_CONNECTED:      return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+   case VC_CONTAINER_NET_ERROR_TIMED_OUT:          return VC_CONTAINER_ERROR_ABORTED;
+   case VC_CONTAINER_NET_ERROR_CONNECTION_REFUSED: return VC_CONTAINER_ERROR_NOT_FOUND;
+   case VC_CONTAINER_NET_ERROR_HOST_NOT_FOUND:     return VC_CONTAINER_ERROR_NOT_FOUND;
+   case VC_CONTAINER_NET_ERROR_TRY_AGAIN:          return VC_CONTAINER_ERROR_CONTINUE;
+   default:                                        return VC_CONTAINER_ERROR_FAILED;
+   }
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T io_net_close( VC_CONTAINER_IO_T *p_ctx )
+{
+   VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
+
+   if (!module)
+      return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+
+   if (module->sock)
+      vc_container_net_close(module->sock);
+#ifdef IO_NET_CAPTURE_PACKETS
+   if (module->read_capture_file)
+      fclose(module->read_capture_file);
+   if (module->write_capture_file)
+      fclose(module->write_capture_file);
+#endif
+   free(module);
+   p_ctx->module = NULL;
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static size_t io_net_read(VC_CONTAINER_IO_T *p_ctx, void *buffer, size_t size)
+{
+   size_t ret = vc_container_net_read(p_ctx->module->sock, buffer, size);
+   vc_container_net_status_t net_status;
+
+   net_status = vc_container_net_status(p_ctx->module->sock);
+   p_ctx->status = translate_net_status_to_container_status(net_status);
+
+#ifdef IO_NET_CAPTURE_PACKETS
+   if (p_ctx->status == VC_CONTAINER_SUCCESS)
+      io_net_capture_write_packet(p_ctx->module->read_capture_file, (const char *)buffer, ret);
+#endif
+
+   return ret;
+}
+
+/*****************************************************************************/
+static size_t io_net_write(VC_CONTAINER_IO_T *p_ctx, const void *buffer, size_t size)
+{
+   size_t ret = vc_container_net_write(p_ctx->module->sock, buffer, size);
+   vc_container_net_status_t net_status;
+
+   net_status = vc_container_net_status(p_ctx->module->sock);
+   p_ctx->status = translate_net_status_to_container_status(net_status);
+
+#ifdef IO_NET_CAPTURE_PACKETS
+   if (p_ctx->status == VC_CONTAINER_SUCCESS)
+      io_net_capture_write_packet(p_ctx->module->write_capture_file, (const char *)buffer, ret);
+#endif
+
+   return ret;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T io_net_control(struct VC_CONTAINER_IO_T *p_ctx, 
+      VC_CONTAINER_CONTROL_T operation,
+      va_list args)
+{
+   vc_container_net_status_t net_status;
+   VC_CONTAINER_STATUS_T status;
+
+   switch (operation)
+   {
+   case VC_CONTAINER_CONTROL_IO_SET_READ_BUFFER_SIZE:
+      net_status = vc_container_net_control(p_ctx->module->sock, VC_CONTAINER_NET_CONTROL_SET_READ_BUFFER_SIZE, args);
+      break;
+   case VC_CONTAINER_CONTROL_IO_SET_READ_TIMEOUT_MS:
+      net_status = vc_container_net_control(p_ctx->module->sock, VC_CONTAINER_NET_CONTROL_SET_READ_TIMEOUT_MS, args);
+      break;
+   default:
+      net_status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED;
+   }
+
+   status = translate_net_status_to_container_status(net_status);
+   p_ctx->status = status;
+
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T io_net_open_socket(VC_CONTAINER_IO_T *ctx,
+   VC_CONTAINER_IO_MODE_T mode, bool is_udp)
+{
+   VC_CONTAINER_IO_MODULE_T *module = ctx->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   const char *host, *port;
+
+   /* Treat empty host or port strings as not defined */
+   port = vc_uri_port(ctx->uri_parts);
+   if (port && !*port)
+      port = NULL;
+
+   /* Require the port to be defined */
+   if (!port) { status = VC_CONTAINER_ERROR_URI_OPEN_FAILED; goto error; }
+
+   host = vc_uri_host(ctx->uri_parts);
+   if (host && !*host)
+      host = NULL;
+
+   if (!host)
+   {
+      /* TCP servers cannot be handled by this interface and UDP senders need a target */
+      if (!is_udp || mode == VC_CONTAINER_IO_MODE_WRITE)
+      {
+         status = VC_CONTAINER_ERROR_URI_OPEN_FAILED;
+         goto error;
+      }
+   }
+
+   module->sock = vc_container_net_open(host, port, is_udp ? 0 : VC_CONTAINER_NET_OPEN_FLAG_STREAM, NULL);
+   if (!module->sock) { status = VC_CONTAINER_ERROR_URI_NOT_FOUND; goto error; }
+
+#ifdef IO_NET_CAPTURE_PACKETS
+   if (!is_udp || mode == VC_CONTAINER_IO_MODE_READ)
+      module->read_capture_file = io_net_open_capture_file(host, port, is_udp, VC_CONTAINER_IO_MODE_READ);
+   if (!is_udp || mode == VC_CONTAINER_IO_MODE_WRITE)
+      module->write_capture_file = io_net_open_capture_file(host, port, is_udp, VC_CONTAINER_IO_MODE_WRITE);
+#endif
+
+error:
+   return status;
+}
+
+/*****************************************************************************
+Functions exported as part of the I/O Module API
+ *****************************************************************************/
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_io_net_open( VC_CONTAINER_IO_T *p_ctx,
+   const char *unused, VC_CONTAINER_IO_MODE_T mode )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_IO_MODULE_T *module = 0;
+   bool is_udp;
+   VC_CONTAINER_PARAM_UNUSED(unused);
+
+   if (!io_net_recognise_scheme(p_ctx->uri, &is_udp))
+   { status = VC_CONTAINER_ERROR_URI_NOT_FOUND; goto error; }
+
+   module = (VC_CONTAINER_IO_MODULE_T *)malloc( sizeof(*module) );
+   if (!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(module, 0, sizeof(*module));
+   p_ctx->module = module;
+
+   status = io_net_open_socket(p_ctx, mode, is_udp);
+   if (status != VC_CONTAINER_SUCCESS)
+      goto error;
+
+   p_ctx->pf_close = io_net_close;
+   p_ctx->pf_read = io_net_read;
+   p_ctx->pf_write = io_net_write;
+   p_ctx->pf_control = io_net_control;
+
+   /* Disable caching, as this will block waiting for enough data to fill the cache or an error */
+   p_ctx->capabilities = VC_CONTAINER_IO_CAPS_CANT_SEEK;
+
+   return VC_CONTAINER_SUCCESS;
+
+error:
+   io_net_close(p_ctx);
+   return status;
+}
diff --git a/containers/io/io_null.c b/containers/io/io_null.c
new file mode 100755 (executable)
index 0000000..cd83bb8
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "containers/containers.h"
+#include "containers/core/containers_common.h"
+#include "containers/core/containers_io.h"
+#include "containers/core/containers_uri.h"
+
+VC_CONTAINER_STATUS_T vc_container_io_null_open( VC_CONTAINER_IO_T *, const char *,
+   VC_CONTAINER_IO_MODE_T );
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T io_null_close( VC_CONTAINER_IO_T *p_ctx )
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static size_t io_null_read(VC_CONTAINER_IO_T *p_ctx, void *buffer, size_t size)
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+   VC_CONTAINER_PARAM_UNUSED(buffer);
+   VC_CONTAINER_PARAM_UNUSED(size);
+   return size;
+}
+
+/*****************************************************************************/
+static size_t io_null_write(VC_CONTAINER_IO_T *p_ctx, const void *buffer, size_t size)
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+   VC_CONTAINER_PARAM_UNUSED(buffer);
+   VC_CONTAINER_PARAM_UNUSED(size);
+   return size;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T io_null_seek(VC_CONTAINER_IO_T *p_ctx, int64_t offset)
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+   VC_CONTAINER_PARAM_UNUSED(offset);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_io_null_open( VC_CONTAINER_IO_T *p_ctx,
+   const char *unused, VC_CONTAINER_IO_MODE_T mode )
+{
+   VC_CONTAINER_PARAM_UNUSED(unused);
+   VC_CONTAINER_PARAM_UNUSED(mode);
+
+   /* Check the URI */
+   if (!vc_uri_scheme(p_ctx->uri_parts) ||
+       (strcasecmp(vc_uri_scheme(p_ctx->uri_parts), "null") &&
+        strcasecmp(vc_uri_scheme(p_ctx->uri_parts), "null")))
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   p_ctx->pf_close = io_null_close;
+   p_ctx->pf_read = io_null_read;
+   p_ctx->pf_write = io_null_write;
+   p_ctx->pf_seek = io_null_seek;
+   return VC_CONTAINER_SUCCESS;
+}
diff --git a/containers/io/io_pktfile.c b/containers/io/io_pktfile.c
new file mode 100755 (executable)
index 0000000..7f4defb
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <limits.h>
+
+#include "containers/containers.h"
+#include "containers/core/containers_common.h"
+#include "containers/core/containers_io.h"
+#include "containers/core/containers_uri.h"
+
+/** Native byte order word */
+#define NATIVE_BYTE_ORDER  0x50415753
+/** Reverse of native byte order - need to swap bytes around */
+#define SWAP_BYTE_ORDER    0x53574150
+
+typedef struct VC_CONTAINER_IO_MODULE_T
+{
+   FILE *stream;
+   bool is_native_order;
+} VC_CONTAINER_IO_MODULE_T;
+
+/** List of recognised schemes.
+ * Note: always use lower case for the scheme name. */
+static const char * recognised_schemes[] = {
+   "rtp", "rtppkt", "rtsp", "rtsppkt", "pktfile",
+};
+
+VC_CONTAINER_STATUS_T vc_container_io_pktfile_open( VC_CONTAINER_IO_T *, const char *,
+   VC_CONTAINER_IO_MODE_T );
+
+/*****************************************************************************/
+static bool recognise_scheme(const char *scheme)
+{
+   size_t ii;
+
+   if (!scheme)
+      return false;
+
+   for (ii = 0; ii < countof(recognised_schemes); ii++)
+   {
+      if (strcmp(recognised_schemes[ii], scheme) == 0)
+         return true;
+   }
+
+   return false;
+}
+
+/*****************************************************************************/
+static uint32_t swap_byte_order( uint32_t value )
+{
+   /* Reverse the order of the bytes in the word */
+   return ((value << 24) | ((value & 0xFF00) << 8) | ((value >> 8) & 0xFF00) | (value >> 24));
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T io_pktfile_close( VC_CONTAINER_IO_T *p_ctx )
+{
+   VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
+   fclose(module->stream);
+   free(module);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static size_t io_pktfile_read(VC_CONTAINER_IO_T *p_ctx, void *buffer, size_t size)
+{
+   VC_CONTAINER_IO_MODULE_T *module = p_ctx->module;
+   uint32_t length = 0;
+   size_t ret;
+   
+   ret = fread(&length, 1, sizeof(length), module->stream);
+   if (ret != sizeof(length))
+   {
+      if( feof(module->stream) ) p_ctx->status = VC_CONTAINER_ERROR_EOS;
+      else p_ctx->status = VC_CONTAINER_ERROR_FAILED;
+      return 0;
+   }
+
+   if (!module->is_native_order)
+      length = swap_byte_order(length);
+
+   if (length > 1<<20)
+   {
+      p_ctx->status = VC_CONTAINER_ERROR_FAILED;
+      return 0;
+   }
+
+   if (size > length)
+      size = length;
+   ret = fread(buffer, 1, size, module->stream);
+   if(ret != size)
+   {
+      if( feof(module->stream) ) p_ctx->status = VC_CONTAINER_ERROR_EOS;
+      else p_ctx->status = VC_CONTAINER_ERROR_FAILED;
+   }
+   else if (length > size)
+   {
+      /* Not enough space to read all the packet, so skip to the next one. */
+      length -= size;
+      vc_container_assert((long)length > 0);
+      fseek(module->stream, (long)length, SEEK_CUR);
+   }
+
+   return ret;
+}
+
+/*****************************************************************************/
+static size_t io_pktfile_write(VC_CONTAINER_IO_T *p_ctx, const void *buffer, size_t size)
+{
+   uint32_t size_word;
+   size_t ret;
+   
+   if (size >= 0xFFFFFFFFUL)
+      size_word = 0xFFFFFFFFUL;
+   else
+      size_word = (uint32_t)size;
+
+   ret = fwrite(&size_word, 1, sizeof(size_word), p_ctx->module->stream);
+   if (ret != sizeof(size_word))
+   {
+      p_ctx->status = VC_CONTAINER_ERROR_FAILED;
+      return 0;
+   }
+
+   ret = fwrite(buffer, 1, size_word, p_ctx->module->stream);
+   if (ret != size_word)
+      p_ctx->status = VC_CONTAINER_ERROR_FAILED;
+   if (fflush(p_ctx->module->stream) != 0)
+      p_ctx->status = VC_CONTAINER_ERROR_FAILED;
+   
+   return ret;
+}
+
+/*****************************************************************************/
+static FILE *open_file(VC_CONTAINER_IO_T *ctx, VC_CONTAINER_IO_MODE_T mode,
+   VC_CONTAINER_STATUS_T *p_status)
+{
+   const char *psz_mode = mode == VC_CONTAINER_IO_MODE_WRITE ? "wb+" : "rb";
+   FILE *stream = 0;
+   const char *port, *path;
+
+   /* Treat empty port or path strings as not defined */
+   port = vc_uri_port(ctx->uri_parts);
+   if (port && !*port)
+      port = NULL;
+
+   path = vc_uri_path(ctx->uri_parts);
+   if (path && !*path)
+      path = NULL;
+
+   /* Require the port to be undefined and the path to be defined */
+   if (port || !path) { *p_status = VC_CONTAINER_ERROR_URI_OPEN_FAILED; goto error; }
+
+   if (!recognise_scheme(vc_uri_scheme(ctx->uri_parts)))
+   { *p_status = VC_CONTAINER_ERROR_URI_NOT_FOUND; goto error; }
+
+   stream = fopen(path, psz_mode);
+   if(!stream) { *p_status = VC_CONTAINER_ERROR_URI_NOT_FOUND; goto error; }
+
+   *p_status = VC_CONTAINER_SUCCESS;
+   return stream;
+
+error:
+   return NULL;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T write_byte_order(FILE *stream)
+{
+   /* Simple byte order header word */
+   uint32_t value = NATIVE_BYTE_ORDER;
+
+   if (fwrite(&value, 1, sizeof(value), stream) != sizeof(value))
+      return VC_CONTAINER_ERROR_OUT_OF_SPACE;
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T read_byte_order(FILE *stream, bool *is_native)
+{
+   uint32_t value;
+
+   if (fread(&value, 1, sizeof(value), stream) != sizeof(value))
+      return VC_CONTAINER_ERROR_EOS;
+
+   switch (value)
+   {
+   case NATIVE_BYTE_ORDER: *is_native = true; break;
+   case SWAP_BYTE_ORDER:   *is_native = false; break;
+   default: return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T vc_container_io_pktfile_open( VC_CONTAINER_IO_T *p_ctx,
+   const char *unused, VC_CONTAINER_IO_MODE_T mode )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_IO_MODULE_T *module = 0;
+   FILE *stream = 0;
+   bool is_native_order = true;
+   VC_CONTAINER_PARAM_UNUSED(unused);
+
+   stream = open_file(p_ctx, mode, &status);
+   if (status != VC_CONTAINER_SUCCESS) goto error;
+
+   if (mode == VC_CONTAINER_IO_MODE_WRITE)
+      status = write_byte_order(stream);
+   else
+      status = read_byte_order(stream, &is_native_order);
+   if (status != VC_CONTAINER_SUCCESS) goto error;
+
+   module = malloc( sizeof(*module) );
+   if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(module, 0, sizeof(*module));
+
+   p_ctx->module = module;
+   module->stream = stream;
+   module->is_native_order = is_native_order;
+   p_ctx->pf_close = io_pktfile_close;
+   p_ctx->pf_read = io_pktfile_read;
+   p_ctx->pf_write = io_pktfile_write;
+
+   /* Do not allow caching by I/O core, as this will merge packets in the cache. */
+   p_ctx->capabilities = VC_CONTAINER_IO_CAPS_CANT_SEEK;
+   return VC_CONTAINER_SUCCESS;
+
+error:
+   if(stream) fclose(stream);
+   return status;
+}
diff --git a/containers/metadata/id3/CMakeLists.txt b/containers/metadata/id3/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..30178f8
--- /dev/null
@@ -0,0 +1,13 @@
+# Container module needs to go in as a plugins so different prefix
+# and install path
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+
+# Make sure the compiler can find the necessary include files
+include_directories (../..)
+
+add_library(reader_metadata_id3 ${LIBRARY_TYPE} id3_metadata_reader.c)
+
+target_link_libraries(reader_metadata_id3 containers)
+
+install(TARGETS reader_metadata_id3 DESTINATION ${VMCS_PLUGIN_DIR})
+
diff --git a/containers/metadata/id3/id3_metadata_reader.c b/containers/metadata/id3/id3_metadata_reader.c
new file mode 100755 (executable)
index 0000000..549273b
--- /dev/null
@@ -0,0 +1,450 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define CONTAINER_IS_BIG_ENDIAN
+//#define ENABLE_CONTAINERS_LOG_FORMAT
+//#define ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
+#define CONTAINER_HELPER_LOG_INDENT(a) 0
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_logging.h"
+
+#include "id3_metadata_strings.h"
+
+/******************************************************************************
+Defines
+******************************************************************************/
+#define ID3_SYNC_SAFE(x) ((((x >> 24) & 0x7f) << 21) | (((x >> 16) & 0x7f) << 14) | \
+                          (((x >>  8) & 0x7f) <<  7) | (((x >>  0) & 0x7f) <<  0))
+      
+/******************************************************************************
+Type definitions
+******************************************************************************/
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+VC_CONTAINER_STATUS_T id3_metadata_reader_open( VC_CONTAINER_T * );
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+static VC_CONTAINER_METADATA_T *id3_metadata_append( VC_CONTAINER_T *p_ctx,
+                                                     VC_CONTAINER_METADATA_KEY_T key,
+                                                     unsigned int size )
+{
+   VC_CONTAINER_METADATA_T *meta, **p_meta;
+   unsigned int i;
+   
+   for (i = 0; i != p_ctx->meta_num; ++i)
+   {
+      if (key == p_ctx->meta[i]->key) break;
+   }
+   
+   /* Avoid duplicate entries for now */
+   if (i < p_ctx->meta_num) return NULL;
+     
+   /* Sanity check size, truncate if necessary */
+   size = MIN(size, 512);
+
+   /* Allocate a new metadata entry */
+   if((meta = malloc(sizeof(VC_CONTAINER_METADATA_T) + size)) == NULL)
+      return NULL;
+
+   /* We need to grow the array holding the metadata entries somehow, ideally,
+      we'd like to use a linked structure of some sort but realloc is probably 
+      okay in this case */
+   if((p_meta = realloc(p_ctx->meta, sizeof(VC_CONTAINER_METADATA_T *) * (p_ctx->meta_num + 1))) == NULL)
+   {
+      free(meta);
+      return NULL;
+   }
+
+   p_ctx->meta = p_meta;
+   memset(meta, 0, sizeof(VC_CONTAINER_METADATA_T) + size);
+   p_ctx->meta[p_ctx->meta_num] = meta;
+   meta->key = key;
+   meta->value = (char *)&meta[1];
+   meta->size = size;
+   p_ctx->meta_num++;
+      
+   return meta;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_METADATA_T *id3_read_metadata_entry( VC_CONTAINER_T *p_ctx, 
+   VC_CONTAINER_METADATA_KEY_T key, unsigned int len )
+{
+   VC_CONTAINER_METADATA_T *meta;
+      
+   if ((meta = id3_metadata_append(p_ctx, key, len + 1)) != NULL)
+   {
+      unsigned int size = meta->size - 1;
+      READ_BYTES(p_ctx, meta->value, size);
+   
+      if (len > size)
+      {
+         LOG_DEBUG(p_ctx, "metadata value truncated (%d characters lost)", len - size);
+         SKIP_BYTES(p_ctx, len - size);
+      }
+   }
+   else
+   {
+      SKIP_BYTES(p_ctx, len);
+   }
+   
+   return meta;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_METADATA_T *id3_read_metadata_entry_ex( VC_CONTAINER_T *p_ctx, 
+   VC_CONTAINER_METADATA_KEY_T key, unsigned int len, const char *encoding )
+{
+   VC_CONTAINER_METADATA_T *meta;
+      
+   if ((meta = id3_metadata_append(p_ctx, key, encoding ? len + 2 : len + 1)) != NULL)
+   {
+      unsigned int size;
+      
+      if (encoding)
+      {
+         size = meta->size - 2;
+         READ_STRING_UTF16(p_ctx, meta->value, size, "ID3v2 data");
+      }
+      else
+      {
+         size = meta->size - 1;
+         READ_STRING(p_ctx, meta->value, size, "ID3v2 data");
+      }
+
+      if (len > size)
+      {
+         LOG_DEBUG(p_ctx, "metadata value truncated (%d characters lost)", len - size);
+         SKIP_BYTES(p_ctx, len - size);
+      }
+   }
+   
+   return meta;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_METADATA_T *id3_add_metadata_entry( VC_CONTAINER_T *p_ctx, 
+   VC_CONTAINER_METADATA_KEY_T key, const char *value )
+{
+   VC_CONTAINER_METADATA_T *meta;
+   unsigned int len = strlen(value);
+
+   if ((meta = id3_metadata_append(p_ctx, key, len + 1)) != NULL)
+   {
+      unsigned int size = meta->size - 1;
+      
+      if (len > size)
+      {
+         LOG_DEBUG(p_ctx, "metadata value truncated (%d characters lost)", len - size);
+      }
+      
+      strncpy(meta->value, value, size);
+   }
+
+   return meta;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T id3_read_id3v2_frame( VC_CONTAINER_T *p_ctx, 
+   VC_CONTAINER_FOURCC_T frame_id, uint32_t frame_size )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_METADATA_KEY_T key;
+   VC_CONTAINER_METADATA_T *meta = NULL;
+   uint8_t encoding;
+   const char *charset = NULL;
+
+   if(frame_size < 1) return VC_CONTAINER_ERROR_CORRUPTED;
+
+   switch (frame_id)
+   {
+      case VC_FOURCC('T','A','L','B'): key = VC_CONTAINER_METADATA_KEY_ALBUM; break;
+      case VC_FOURCC('T','I','T','2'): key = VC_CONTAINER_METADATA_KEY_TITLE; break;
+      case VC_FOURCC('T','R','C','K'): key = VC_CONTAINER_METADATA_KEY_TRACK; break;
+      case VC_FOURCC('T','P','E','1'): key = VC_CONTAINER_METADATA_KEY_ARTIST; break;
+      case VC_FOURCC('T','C','O','N'): key = VC_CONTAINER_METADATA_KEY_GENRE; break;
+      default: key = VC_CONTAINER_METADATA_KEY_UNKNOWN; break;
+   }
+
+   if (key == VC_CONTAINER_METADATA_KEY_UNKNOWN) return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   encoding = READ_U8(p_ctx, "ID3v2 text encoding byte");
+   frame_size -= 1;
+
+   switch(encoding)
+   {
+      case 0: /* ISO-8859-1 */
+      case 3: /* UTF-8 */
+         break;
+      case 1: /* UTF-16 with BOM */
+         if(frame_size < 2) return VC_CONTAINER_ERROR_CORRUPTED;
+         SKIP_U16(p_ctx, "ID3v2 text encoding BOM"); /* FIXME: Check BOM, 0xFFFE vs 0xFEFFF */
+         frame_size -= 2;
+         charset = "UTF16-LE";
+         break;
+      case 2: /* UTF-16BE */
+         charset = "UTF16-BE";
+         break;
+      default:
+         LOG_DEBUG(p_ctx, "skipping frame, text encoding %x not supported", encoding);
+         SKIP_BYTES(p_ctx, frame_size);
+         return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   }
+
+   if ((meta = id3_read_metadata_entry_ex(p_ctx, key, frame_size, charset)) != NULL)
+   {
+      if (charset)
+      {
+         utf8_from_charset(charset, meta->value, meta->size, meta->value, meta->size);
+      }
+
+      meta->encoding = VC_CONTAINER_CHAR_ENCODING_UTF8; /* Okay for ISO-8859-1 as well? */
+
+      status = VC_CONTAINER_SUCCESS;
+   }
+   else
+   {
+      SKIP_BYTES(p_ctx, frame_size);
+   }
+
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T id3_read_id3v2_tag( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   uint8_t maj_version, flags;
+   uint32_t tag_size, size = 0;
+   uint8_t peek_buf[10];
+   
+   SKIP_STRING(p_ctx, 3, "ID3v2 identifier");
+   maj_version = READ_U8(p_ctx, "ID3v2 version (major)");
+   SKIP_U8(p_ctx, "ID3v2 version (minor)");
+   flags = READ_U8(p_ctx, "ID3v2 flags");
+   tag_size = READ_U32(p_ctx, "ID3v2 syncsafe tag size");
+   tag_size = ID3_SYNC_SAFE(tag_size);
+   LOG_DEBUG(p_ctx, "ID3v2 tag size: %d", tag_size);
+
+   /* Check that we support this major version */
+   if (!(maj_version == 4 || maj_version == 3 || maj_version == 2))
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   /* We can't currently handle unsynchronisation */
+   if ((flags >> 7) & 1)
+   {
+      LOG_DEBUG(p_ctx, "skipping unsynchronised tag, not supported");
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   }
+
+   /* FIXME: check for version 2.2 and extract iTunes gapless playback information */
+   if (maj_version == 2) return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   if ((flags >> 6) & 1)
+   {
+      /* Skip extended header, we don't support it */
+      uint32_t ext_hdr_size;
+      LOG_DEBUG(p_ctx, "skipping ID3v2 extended header, not supported");
+      ext_hdr_size = READ_U32(p_ctx, "ID3v2 syncsafe extended header size");
+      ext_hdr_size = ID3_SYNC_SAFE(ext_hdr_size);
+      LOG_DEBUG(p_ctx, "ID3v2 extended header size: %d", ext_hdr_size);
+      SKIP_BYTES(p_ctx, MIN(tag_size, ext_hdr_size));
+      size += ext_hdr_size;
+   }
+   
+   while (PEEK_BYTES(p_ctx, peek_buf, 10) == 10 && size < tag_size)
+   {
+      VC_CONTAINER_FOURCC_T frame_id;
+      uint32_t frame_size;
+      uint8_t format_flags;
+      
+      frame_id = READ_FOURCC(p_ctx, "Frame ID");
+      frame_size = READ_U32(p_ctx, "Frame Size");
+     
+      if (maj_version >= 4)
+      {
+         frame_size = ID3_SYNC_SAFE(frame_size);
+         LOG_DEBUG(p_ctx, "ID3v2 actual frame size: %d", frame_size);
+      }
+
+      SKIP_U8(p_ctx, "ID3v2 status message flags");
+      format_flags = READ_U8(p_ctx, "ID3v2 format description flags");
+
+      size += 10;
+
+      if((status = STREAM_STATUS(p_ctx)) != VC_CONTAINER_SUCCESS || !frame_id) 
+         break;
+
+      /* Early exit if we detect an invalid tag size */
+      if (size + frame_size > tag_size)
+      {
+         status = VC_CONTAINER_ERROR_FORMAT_INVALID;
+         break;
+      }
+     
+      /* We can't currently handle unsynchronised frames */
+      if ((format_flags >> 1) & 1)
+      {
+         LOG_DEBUG(p_ctx, "skipping unsynchronised frame, not supported");
+         SKIP_BYTES(p_ctx, frame_size);
+         continue;
+      }
+      
+      if ((status = id3_read_id3v2_frame(p_ctx, frame_id, frame_size)) != VC_CONTAINER_SUCCESS)
+      {
+         LOG_DEBUG(p_ctx, "skipping unsupported frame");
+         SKIP_BYTES(p_ctx, frame_size);
+      }
+
+      size += frame_size;
+   }
+
+   /* Try to skip to end of tag in case we bailed out early */
+   if (size < tag_size) SKIP_BYTES(p_ctx, tag_size - size);
+      
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T id3_read_id3v1_tag( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   uint8_t track, genre;
+   char track_num[4] = {0};
+
+   SKIP_STRING(p_ctx, 3, "ID3v1 identifier");
+   /* ID3v1 title */
+   id3_read_metadata_entry(p_ctx, VC_CONTAINER_METADATA_KEY_TITLE, 30);
+   /* ID3v1 artist */
+   id3_read_metadata_entry(p_ctx, VC_CONTAINER_METADATA_KEY_ARTIST, 30);
+   /* ID3v1 album */
+   id3_read_metadata_entry(p_ctx, VC_CONTAINER_METADATA_KEY_ALBUM, 30);
+   /* ID3v1 year */
+   id3_read_metadata_entry(p_ctx, VC_CONTAINER_METADATA_KEY_YEAR, 4);
+   SKIP_STRING(p_ctx, 28, "ID3v1 comment");
+   if (READ_U8(p_ctx, "ID3v1 zero-byte") == 0)
+   {
+      track = READ_U8(p_ctx, "ID3v1 track");
+      snprintf(track_num, sizeof(track_num) - 1, "%02d", track);
+      id3_add_metadata_entry(p_ctx, VC_CONTAINER_METADATA_KEY_TRACK, track_num);
+   }
+   else
+   {
+      SKIP_BYTES(p_ctx, 1);
+   }
+   genre = READ_U8(p_ctx, "ID3v1 genre");
+   if (genre < countof(id3_genres))
+   {
+      id3_add_metadata_entry(p_ctx, VC_CONTAINER_METADATA_KEY_GENRE, id3_genres[genre]);
+   }
+
+   status = STREAM_STATUS(p_ctx);
+
+   return status;
+}
+
+/*****************************************************************************
+Functions exported as part of the Container Module API
+ *****************************************************************************/
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T id3_metadata_reader_close( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T id3_metadata_reader_open( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_INVALID;
+   uint8_t peek_buf[10];
+   int64_t data_offset;
+
+   if (PEEK_BYTES(p_ctx, peek_buf, 10) != 10)
+     return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   
+   /* Initial ID3v2 tag(s), variable size */
+   while ((peek_buf[0] == 'I') && (peek_buf[1] == 'D') && (peek_buf[2] == '3'))
+   {
+      if ((status = id3_read_id3v2_tag(p_ctx)) != VC_CONTAINER_SUCCESS)
+      {
+         LOG_DEBUG(p_ctx, "error reading ID3v2 tag (%i)", status);
+      }
+
+      if (PEEK_BYTES(p_ctx, peek_buf, 10) != 10) break;
+   }
+
+   data_offset = STREAM_POSITION(p_ctx);
+
+   /* ID3v1 tag, 128 bytes at the end of a file */
+   if (p_ctx->priv->io->size >= INT64_C(128) && STREAM_SEEKABLE(p_ctx))
+   {
+      SEEK(p_ctx, p_ctx->priv->io->size - INT64_C(128));
+      if (PEEK_BYTES(p_ctx, peek_buf, 3) != 3) goto end;
+        
+      if ((peek_buf[0] == 'T') && (peek_buf[1] == 'A') && (peek_buf[2] == 'G'))
+      {
+         if ((status = id3_read_id3v1_tag(p_ctx)) != VC_CONTAINER_SUCCESS)
+         {
+            LOG_DEBUG(p_ctx, "error reading ID3v1 tag (%i)", status);
+         }
+      }
+   }
+
+end:
+   /* Restore position to start of data */
+   if (STREAM_POSITION(p_ctx) != data_offset)
+      SEEK(p_ctx, data_offset);
+
+   p_ctx->priv->pf_close = id3_metadata_reader_close;
+
+   if((status = STREAM_STATUS(p_ctx)) != VC_CONTAINER_SUCCESS) goto error;   
+   
+   return VC_CONTAINER_SUCCESS;
+
+error:
+   LOG_DEBUG(p_ctx, "error opening stream (%i)", status);
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+ ********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak reader_open id3_metadata_reader_open
+#endif
diff --git a/containers/metadata/id3/id3_metadata_strings.h b/containers/metadata/id3/id3_metadata_strings.h
new file mode 100755 (executable)
index 0000000..1c953d9
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* ID3 genre byte translation table */
+static const char* id3_genres[] =
+{
+   "Blues",
+   "Classic Rock",
+   "Country",
+   "Dance",
+   "Disco",
+   "Funk",
+   "Grunge",
+   "Hip-Hop",
+   "Jazz",
+   "Metal",
+   "New Age",
+   "Oldies",
+   "Other",
+   "Pop",
+   "R&B",
+   "Rap",
+   "Reggae",
+   "Rock",
+   "Techno",
+   "Industrial",
+   "Alternative",
+   "Ska",
+   "Death Metal",
+   "Pranks",
+   "Soundtrack",
+   "Euro-Techno",
+   "Ambient",
+   "Trip-Hop",
+   "Vocal",
+   "Jazz+Funk",
+   "Fusion",
+   "Trance",
+   "Classical",
+   "Instrumental",
+   "Acid",
+   "House",
+   "Game",
+   "Sound Clip",
+   "Gospel",
+   "Noise",
+   "Alternative Rock",
+   "Bass",
+   "Soul",
+   "Punk",
+   "Space",
+   "Meditative",
+   "Instrumental Pop",
+   "Instrumental Rock",
+   "Ethnic",
+   "Gothic",
+   "Darkwave",
+   "Techno-Industrial",
+   "Electronic",
+   "Pop-Folk",
+   "Eurodance",
+   "Dream",
+   "Southern Rock",
+   "Comedy",
+   "Cult",
+   "Gangsta",
+   "Top 40",
+   "Christian Rap",
+   "Pop/Funk",
+   "Jungle",
+   "Native American",
+   "Cabaret",
+   "New Wave",
+   "Psychadelic",
+   "Rave",
+   "Showtunes",
+   "Trailer",
+   "Lo-Fi",
+   "Tribal",
+   "Acid Punk",
+   "Acid Jazz",
+   "Polka",
+   "Retro",
+   "Musical",
+   "Rock & Roll",
+   "Hard Rock",
+   "Folk",
+   "Folk-Rock",
+   "National Folk",
+   "Swing",
+   "Fast Fusion",
+   "Bebob",
+   "Latin",
+   "Revival",
+   "Celtic",
+   "Bluegrass",
+   "Avantgarde",
+   "Gothic Rock",
+   "Progressive Rock",
+   "Psychedelic Rock",
+   "Symphonic Rock",
+   "Slow Rock",
+   "Big Band",
+   "Chorus",
+   "Easy Listening",
+   "Acoustic",
+   "Humour",
+   "Speech",
+   "Chanson",
+   "Opera",
+   "Chamber Music",
+   "Sonata",
+   "Symphony",
+   "Booty Bass",
+   "Primus",
+   "Porn Groove",
+   "Satire",
+   "Slow Jam",
+   "Club",
+   "Tango",
+   "Samba",
+   "Folklore",
+   "Ballad",
+   "Power Ballad",
+   "Rhythmic Soul",
+   "Freestyle",
+   "Duet",
+   "Punk Rock",
+   "Drum Solo",
+   "A capella",
+   "Euro-House",
+   "Dance Hall",
+   "Goa",
+   "Drum & Bass",
+   "Club-House",
+   "Hardcore",
+   "Terror",
+   "Indie",
+   "BritPop",
+   "Negerpunk",
+   "Polsk Punk",
+   "Beat",
+   "Christian Gangsta Rap",
+   "Heavy Metal",
+   "Black Metal",
+   "Crossover",
+   "Contemporary Christian",
+   "Christian Rock",
+   "Merengue",
+   "Salsa",
+   "Thrash Metal",
+   "Anime",
+   "JPop",
+   "SynthPop"
+};
diff --git a/containers/mkv/CMakeLists.txt b/containers/mkv/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..0c31a30
--- /dev/null
@@ -0,0 +1,13 @@
+# Container module needs to go in as a plugins so different prefix
+# and install path
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+
+# Make sure the compiler can find the necessary include files
+include_directories (../..)
+
+add_library(reader_mkv ${LIBRARY_TYPE} matroska_reader.c)
+
+target_link_libraries(reader_mkv containers)
+
+install(TARGETS reader_mkv DESTINATION ${VMCS_PLUGIN_DIR})
+
diff --git a/containers/mkv/matroska_reader.c b/containers/mkv/matroska_reader.c
new file mode 100755 (executable)
index 0000000..8625d0c
--- /dev/null
@@ -0,0 +1,2323 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <string.h>
+
+//#define ENABLE_MKV_EXTRA_LOGGING
+#define CONTAINER_IS_BIG_ENDIAN
+#define CONTAINER_HELPER_LOG_INDENT(a) (a)->priv->module->element_level
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_logging.h"
+
+/******************************************************************************
+Defines.
+******************************************************************************/
+#define MKV_TRACKS_MAX 16
+#define MKV_CODECID_MAX 32
+#define MKV_MAX_LACING_NUM 64
+
+#define MKV_MAX_ENCODINGS 1
+#define MKV_MAX_ENCODING_DATA 256
+
+#define MKV_MAX_ELEMENT_LEVEL 8
+#define MKV_MAX_CONSECUTIVE_UNKNOWN_ELEMENTS 5
+#define MKV_MAX_ELEMENT_SIZE  (1<<29) /* Does not apply to the data element */
+#define MKV_MAX_STRING_SIZE 256
+#define MKV_ELEMENT_MIN_HEADER_SIZE 2
+
+#define MKV_MAX_READER_STATE_LEVEL 4
+
+#define MKV_SKIP_U8(ctx,n)   (size -= 1, SKIP_U8(ctx,n))
+#define MKV_SKIP_U16(ctx,n)  (size -= 2, SKIP_U16(ctx,n))
+#define MKV_SKIP_U24(ctx,n)  (size -= 3, SKIP_U24(ctx,n))
+#define MKV_SKIP_U32(ctx,n)  (size -= 4, SKIP_U32(ctx,n))
+#define MKV_SKIP_U64(ctx,n)  (size -= 8, SKIP_U64(ctx,n))
+#define MKV_READ_U8(ctx,n)   (size -= 1, READ_U8(ctx,n))
+#define MKV_READ_U16(ctx,n)  (size -= 2, READ_U16(ctx,n))
+#define MKV_READ_U24(ctx,n)  (size -= 3, READ_U24(ctx,n))
+#define MKV_READ_U32(ctx,n)  (size -= 4, READ_U32(ctx,n))
+#define MKV_READ_U64(ctx,n)  (size -= 8, READ_U64(ctx,n))
+#define MKV_READ_BYTES(ctx,buffer,sz) (size -= sz, READ_BYTES(ctx,buffer,sz))
+#define MKV_SKIP_BYTES(ctx,sz) (size -= sz, SKIP_BYTES(ctx,sz))
+
+#define CHECK_POINT(a) do { \
+   /*if(size < 0 && size != INT64_C(-1)) return VC_CONTAINER_ERROR_CORRUPTED;*/ \
+   if(STREAM_STATUS(p_ctx)) return STREAM_STATUS(p_ctx); } while(0)
+
+static uint32_t mkv_io_read_id(VC_CONTAINER_IO_T *io, int64_t *size)
+{
+   uint32_t value, mask;
+
+   value = vc_container_io_read_uint8(io); (*size)--;
+   for(mask = 0x80; mask; mask <<= 7)
+   {
+      if(value & mask) return value;
+      value = (value << 8) | vc_container_io_read_uint8(io); (*size)--;
+   }
+   return 0;
+}
+
+static int64_t mkv_io_read_uint(VC_CONTAINER_IO_T *io, int64_t *size)
+{
+   uint64_t value, mask;
+
+   value = vc_container_io_read_uint8(io); (*size)--;
+   if(value == 0xFF) return -1;
+
+   for(mask = 0x80; mask; mask <<= 7)
+   {
+      if(value & mask) return value & ~mask;
+      value = (value << 8) | vc_container_io_read_uint8(io); (*size)--;
+   }
+   return 0;
+}
+
+static int64_t mkv_io_read_sint(VC_CONTAINER_IO_T *io, int64_t *size)
+{
+   int64_t value, count = io->offset;
+   value = mkv_io_read_uint(io, size);
+   count = io->offset - count;
+
+   switch(count)
+   {
+   case 1: value -= 0x3F; break;
+   case 2: value -= 0x1FFF; break;
+   case 3: value -= 0xFFFFF; break;
+   case 4: value -= 0x7FFFFFF; break;
+   default: break;
+   }
+   return value;
+}
+
+#define MKV_READ_ID(ctx, n) mkv_io_read_id((ctx)->priv->io, &size)
+#define MKV_READ_UINT(ctx, n) mkv_io_read_uint((ctx)->priv->io, &size)
+#define MKV_READ_SINT(ctx, n) mkv_io_read_sint((ctx)->priv->io, &size)
+
+/******************************************************************************
+Type definitions.
+******************************************************************************/
+
+typedef enum
+{
+   MKV_ELEMENT_ID_UNKNOWN = 0,
+
+   /* EBML Basics */
+   MKV_ELEMENT_ID_EBML = 0x1A45DFA3,
+   MKV_ELEMENT_ID_EBML_VERSION = 0x4286,
+   MKV_ELEMENT_ID_EBML_READ_VERSION = 0x42F7,
+   MKV_ELEMENT_ID_EBML_MAX_ID_LENGTH = 0x42F2,
+   MKV_ELEMENT_ID_EBML_MAX_SIZE_LENGTH = 0x42F3,
+   MKV_ELEMENT_ID_DOCTYPE = 0x4282,
+   MKV_ELEMENT_ID_DOCTYPE_VERSION = 0x4287,
+   MKV_ELEMENT_ID_DOCTYPE_READ_VERSION = 0x4285,
+
+   /* Global Elements */
+   MKV_ELEMENT_ID_CRC32 = 0xBF,
+   MKV_ELEMENT_ID_VOID = 0xEC,
+
+   /* Segment */
+   MKV_ELEMENT_ID_SEGMENT = 0x18538067,
+
+   /* Meta Seek Information */
+   MKV_ELEMENT_ID_SEEK_HEAD = 0x114D9B74,
+   MKV_ELEMENT_ID_SEEK = 0x4DBB,
+   MKV_ELEMENT_ID_SEEK_ID = 0x53AB,
+   MKV_ELEMENT_ID_SEEK_POSITION = 0x53AC,
+
+   /* Segment Information */
+   MKV_ELEMENT_ID_INFO = 0x1549A966,
+   MKV_ELEMENT_ID_SEGMENT_UID = 0x73A4,
+   MKV_ELEMENT_ID_SEGMENT_FILENAME = 0x7384,
+   MKV_ELEMENT_ID_PREV_UID = 0x3CB923,
+   MKV_ELEMENT_ID_PREV_FILENAME = 0x3C83AB,
+   MKV_ELEMENT_ID_NEXT_UID = 0x3EB923,
+   MKV_ELEMENT_ID_NEXT_FILENAME = 0x3E83BB,
+   MKV_ELEMENT_ID_SEGMENT_FAMILY = 0x4444,
+   MKV_ELEMENT_ID_CHAPTER_TRANSLATE = 0x6924,
+   MKV_ELEMENT_ID_CHAPTER_TRANSLATE_EDITION_UID = 0x69FC,
+   MKV_ELEMENT_ID_CHAPTER_TRANSLATE_CODEC = 0x69BF,
+   MKV_ELEMENT_ID_CHAPTER_TRANSLATE_ID = 0x69A5,
+   MKV_ELEMENT_ID_TIMECODE_SCALE = 0x2AD7B1,
+   MKV_ELEMENT_ID_DURATION = 0x4489,
+   MKV_ELEMENT_ID_DATE_UTC = 0x4461,
+   MKV_ELEMENT_ID_TITLE = 0x7BA9,
+   MKV_ELEMENT_ID_MUXING_APP = 0x4D80,
+   MKV_ELEMENT_ID_WRITING_APP = 0x5741,
+
+   /* Cluster */
+   MKV_ELEMENT_ID_CLUSTER = 0x1F43B675,
+   MKV_ELEMENT_ID_TIMECODE = 0xE7,
+   MKV_ELEMENT_ID_SILENT_TRACKS = 0x5854,
+   MKV_ELEMENT_ID_SILENT_TRACK_NUMBER = 0x58D7,
+   MKV_ELEMENT_ID_POSITION = 0xA7,
+   MKV_ELEMENT_ID_PREV_SIZE = 0xAB,
+   MKV_ELEMENT_ID_BLOCKGROUP = 0xA0,
+   MKV_ELEMENT_ID_BLOCK = 0xA1,
+   MKV_ELEMENT_ID_BLOCK_ADDITIONS = 0x75A1,
+   MKV_ELEMENT_ID_BLOCK_MORE = 0xA6,
+   MKV_ELEMENT_ID_BLOCK_ADD_ID = 0xEE,
+   MKV_ELEMENT_ID_BLOCK_ADDITIONAL = 0xA5,
+   MKV_ELEMENT_ID_BLOCK_DURATION = 0x9B,
+   MKV_ELEMENT_ID_REFERENCE_PRIORITY = 0xFA,
+   MKV_ELEMENT_ID_REFERENCE_BLOCK = 0xFB,
+   MKV_ELEMENT_ID_CODEC_STATE = 0xA4,
+   MKV_ELEMENT_ID_SLICES = 0x8E,
+   MKV_ELEMENT_ID_TIME_SLICE = 0xE8,
+   MKV_ELEMENT_ID_LACE_NUMBER = 0xCC,
+   MKV_ELEMENT_ID_SIMPLE_BLOCK = 0xA3,
+
+   /* Track */
+   MKV_ELEMENT_ID_TRACKS = 0x1654AE6B,
+   MKV_ELEMENT_ID_TRACK_ENTRY = 0xAE,
+   MKV_ELEMENT_ID_TRACK_NUMBER = 0xD7,
+   MKV_ELEMENT_ID_TRACK_UID = 0x73C5,
+   MKV_ELEMENT_ID_TRACK_TYPE = 0x83,
+   MKV_ELEMENT_ID_FLAG_ENABLED = 0xB9,
+   MKV_ELEMENT_ID_FLAG_DEFAULT = 0x88,
+   MKV_ELEMENT_ID_FLAG_FORCED = 0x55AA,
+   MKV_ELEMENT_ID_FLAG_LACING = 0x9C,
+   MKV_ELEMENT_ID_MIN_CACHE = 0x6DE7,
+   MKV_ELEMENT_ID_MAX_CACHE = 0x6DF8,
+   MKV_ELEMENT_ID_DEFAULT_DURATION = 0x23E383,
+   MKV_ELEMENT_ID_TRACK_TIMECODE_SCALE = 0x23314F,
+   MKV_ELEMENT_ID_MAX_BLOCK_ADDITION_ID = 0x55EE,
+   MKV_ELEMENT_ID_NAME = 0x536E,
+   MKV_ELEMENT_ID_LANGUAGE = 0x22B59C,
+   MKV_ELEMENT_ID_TRACK_CODEC_ID = 0x86,
+   MKV_ELEMENT_ID_TRACK_CODEC_PRIVATE = 0x63A2,
+   MKV_ELEMENT_ID_TRACK_CODEC_NAME = 0x258688,
+   MKV_ELEMENT_ID_ATTACHMENT_LINK = 0x7446,
+   MKV_ELEMENT_ID_CODEC_DECODE_ALL = 0xAA,
+   MKV_ELEMENT_ID_TRACK_OVERLAY = 0x6FAB,
+   MKV_ELEMENT_ID_TRACK_TRANSLATE = 0x6624,
+   MKV_ELEMENT_ID_TRACK_TRANSLATE_EDITION_UID = 0x66FC,
+   MKV_ELEMENT_ID_TRACK_TRANSLATE_CODEC = 0x66BF,
+   MKV_ELEMENT_ID_TRACK_TRANSLATE_TRACK_ID = 0x66A5,
+
+   /* Video */
+   MKV_ELEMENT_ID_VIDEO = 0xE0,
+   MKV_ELEMENT_ID_FLAG_INTERLACED = 0x9A,
+   MKV_ELEMENT_ID_STEREO_MODE = 0x53B8,
+   MKV_ELEMENT_ID_PIXEL_WIDTH = 0xB0,
+   MKV_ELEMENT_ID_PIXEL_HEIGHT = 0xBA,
+   MKV_ELEMENT_ID_PIXEL_CROP_BOTTOM = 0x54AA,
+   MKV_ELEMENT_ID_PIXEL_CROP_TOP = 0x54BB,
+   MKV_ELEMENT_ID_PIXEL_CROP_LEFT = 0x54CC,
+   MKV_ELEMENT_ID_PIXEL_CROP_RIGHT = 0x54DD,
+   MKV_ELEMENT_ID_DISPLAY_WIDTH = 0x54B0,
+   MKV_ELEMENT_ID_DISPLAY_HEIGHT = 0x54BA,
+   MKV_ELEMENT_ID_DISPLAY_UNIT = 0x54B2,
+   MKV_ELEMENT_ID_ASPECT_RATIO_TYPE = 0x54B3,
+   MKV_ELEMENT_ID_COLOUR_SPACE = 0x2EB524,
+   MKV_ELEMENT_ID_FRAME_RATE = 0x2383E3,
+
+   /* Audio */
+   MKV_ELEMENT_ID_AUDIO = 0xE1,
+   MKV_ELEMENT_ID_SAMPLING_FREQUENCY = 0xB5,
+   MKV_ELEMENT_ID_OUTPUT_SAMPLING_FREQUENCY = 0x78B5,
+   MKV_ELEMENT_ID_CHANNELS = 0x9F,
+   MKV_ELEMENT_ID_BIT_DEPTH = 0x6264,
+
+   /* Content Encoding */
+   MKV_ELEMENT_ID_CONTENT_ENCODINGS = 0x6D80,
+   MKV_ELEMENT_ID_CONTENT_ENCODING = 0x6240,
+   MKV_ELEMENT_ID_CONTENT_ENCODING_ORDER = 0x5031,
+   MKV_ELEMENT_ID_CONTENT_ENCODING_SCOPE = 0x5032,
+   MKV_ELEMENT_ID_CONTENT_ENCODING_TYPE = 0x5033,
+   MKV_ELEMENT_ID_CONTENT_COMPRESSION = 0x5034,
+   MKV_ELEMENT_ID_CONTENT_COMPRESSION_ALGO = 0x4254,
+   MKV_ELEMENT_ID_CONTENT_COMPRESSION_SETTINGS = 0x4255,
+   MKV_ELEMENT_ID_CONTENT_ENCRYPTION = 0x5035,
+   MKV_ELEMENT_ID_CONTENT_ENCRYPTION_ALGO = 0x47E1,
+   MKV_ELEMENT_ID_CONTENT_ENCRYPTION_KEY_ID = 0x47E2,
+   MKV_ELEMENT_ID_CONTENT_SIGNATURE = 0x47E3,
+   MKV_ELEMENT_ID_CONTENT_SIGNATURE_KEY_ID = 0x47E4,
+   MKV_ELEMENT_ID_CONTENT_SIGNATURE_ALGO = 0x47E5,
+   MKV_ELEMENT_ID_CONTENT_SIGNATURE_HASH_ALGO = 0x47E6,
+
+   /* Cueing Data */
+   MKV_ELEMENT_ID_CUES = 0x1C53BB6B,
+   MKV_ELEMENT_ID_CUE_POINT = 0xBB,
+   MKV_ELEMENT_ID_CUE_TIME = 0xB3,
+   MKV_ELEMENT_ID_CUE_TRACK_POSITIONS = 0xB7,
+   MKV_ELEMENT_ID_CUE_TRACK = 0xF7,
+   MKV_ELEMENT_ID_CUE_CLUSTER_POSITION = 0xF1,
+   MKV_ELEMENT_ID_CUE_BLOCK_NUMBER = 0x5378,
+
+   /* Attachments */
+   MKV_ELEMENT_ID_ATTACHMENTS = 0x1941A469,
+
+   /* Chapters */
+   MKV_ELEMENT_ID_CHAPTERS = 0x1043A770,
+
+   /* Tagging */
+   MKV_ELEMENT_ID_TAGS = 0x1254C367,
+   MKV_ELEMENT_ID_TAG = 0x7373,
+   MKV_ELEMENT_ID_TAG_TARGETS = 0x63C0,
+   MKV_ELEMENT_ID_TAG_TARGET_TYPE_VALUE = 0x68CA,
+   MKV_ELEMENT_ID_TAG_TARGET_TYPE = 0x63CA,
+   MKV_ELEMENT_ID_TAG_TRACK_UID = 0x63C5,
+   MKV_ELEMENT_ID_TAG_EDITION_UID = 0x63C9,
+   MKV_ELEMENT_ID_TAG_CHAPTER_UID = 0x63C4,
+   MKV_ELEMENT_ID_TAG_ATTACHMENT_UID = 0x63C6,
+   MKV_ELEMENT_ID_TAG_SIMPLE_TAG = 0x67C8,
+   MKV_ELEMENT_ID_TAG_NAME = 0x45A3,
+   MKV_ELEMENT_ID_TAG_LANGUAGE = 0x447A,
+   MKV_ELEMENT_ID_TAG_DEFAULT = 0x4484,
+   MKV_ELEMENT_ID_TAG_STRING = 0x4487,
+   MKV_ELEMENT_ID_TAG_BINARY = 0x4485,
+
+   MKV_ELEMENT_ID_INVALID = 0xFFFFFFFF
+} MKV_ELEMENT_ID_T;
+
+/** Context for our reader
+ */
+
+typedef struct
+{
+   unsigned int track;
+   unsigned int flags;
+   int64_t pts;
+   int64_t cluster_timecode;
+   int64_t prev_cluster_size; /* Size of the previous cluster if available */
+   int64_t frame_duration;
+
+   int level;
+   struct {
+      int64_t offset;
+      int64_t data_start;
+      int64_t data_offset;
+      int64_t size;
+      MKV_ELEMENT_ID_T id;
+   } levels[MKV_MAX_READER_STATE_LEVEL];
+
+   bool     eos;
+   bool     corrupted;
+   bool     seen_ref_block;
+
+   uint32_t lacing_num_frames;
+   uint32_t lacing_size;
+   uint16_t lacing_sizes[MKV_MAX_LACING_NUM];
+   uint32_t lacing_current_size;
+
+   /* For header stripping compression */
+   uint32_t header_size;
+   uint8_t *header_data;
+   uint32_t header_size_backup;
+} MKV_READER_STATE_T;
+
+typedef struct
+{
+   const MKV_ELEMENT_ID_T id;
+   const MKV_ELEMENT_ID_T parent_id;
+   const char *psz_name;
+   VC_CONTAINER_STATUS_T (*pf_func)(VC_CONTAINER_T *, MKV_ELEMENT_ID_T, int64_t);
+
+} MKV_ELEMENT_T;
+
+typedef struct VC_CONTAINER_TRACK_MODULE_T
+{
+   MKV_READER_STATE_T *state;
+   MKV_READER_STATE_T track_state;
+
+   /* Information extracted from the track entry */
+   uint32_t number;
+   uint32_t type;
+   int64_t  timecode_scale;
+   uint32_t duration;
+   int64_t  frame_duration;
+   char codecid[MKV_CODECID_MAX];
+
+   union {
+      /* video specific */
+      struct {
+         unsigned int interlaced:1;
+         unsigned int stereo_mode:2;
+         uint32_t pixel_width;
+         uint32_t pixel_height;
+         uint32_t pixel_crop_bottom;
+         uint32_t pixel_crop_top;
+         uint32_t pixel_crop_left;
+         uint32_t pixel_crop_right;
+         uint32_t display_width;
+         uint32_t display_height;
+         uint32_t display_unit;
+         uint32_t aspect_ratio_type;
+         float frame_rate;
+      } video;
+
+      /* audio specific */
+      struct {
+         uint32_t sampling_frequency;
+         uint32_t output_sampling_frequency;
+         uint32_t channels;
+         uint32_t bit_depth;
+      } audio;
+   } es_type;
+
+   /* content encoding (i.e. lossless compression and encryption) */
+   unsigned int encodings_num;
+   struct {
+      enum {
+         MKV_CONTENT_ENCODING_COMPRESSION_ZLIB,
+         MKV_CONTENT_ENCODING_COMPRESSION_HEADER,
+         MKV_CONTENT_ENCODING_ENCRYPTION,
+         MKV_CONTENT_ENCODING_UNKNOWN
+      } type;
+      unsigned int data_size;
+      uint8_t *data;
+   } encodings[MKV_MAX_ENCODINGS];
+
+} VC_CONTAINER_TRACK_MODULE_T;
+
+typedef struct VC_CONTAINER_MODULE_T
+{
+   MKV_ELEMENT_T *elements_list;
+   int element_level;
+   MKV_ELEMENT_ID_T parent_id;
+
+   uint64_t element_offset; /**< Offset to the start of the current element */
+
+   uint64_t segment_offset; /**< Offset to the start of the data packets */
+   int64_t segment_size;
+
+   int tracks_num;
+   VC_CONTAINER_TRACK_T *tracks[MKV_TRACKS_MAX];
+
+   MKV_READER_STATE_T state;
+   int64_t timecode_scale;
+   float duration;
+
+   uint64_t cluster_offset; /**< Offset to the first cluster */
+   uint64_t cues_offset; /**< Offset to the start of the seeking cues */
+   uint64_t tags_offset; /**< Offset to the start of the tags */
+
+   /*
+    * Variables only used during parsing of the header
+    */
+
+   VC_CONTAINER_TRACK_T *parsing; /**< Current track being parsed */
+   bool is_doctype_valid;
+
+   MKV_ELEMENT_ID_T seekhead_elem_id;
+   int64_t seekhead_elem_offset;
+
+   /* Cues */
+   unsigned int cue_track;
+   int64_t cue_timecode;
+   uint64_t cue_cluster_offset;
+   unsigned int cue_block;
+
+} VC_CONTAINER_MODULE_T;
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+VC_CONTAINER_STATUS_T mkv_reader_open( VC_CONTAINER_T * );
+
+/******************************************************************************
+Prototypes for local functions
+******************************************************************************/
+static VC_CONTAINER_STATUS_T mkv_read_element( VC_CONTAINER_T *p_ctx, int64_t size, MKV_ELEMENT_ID_T parent_id );
+static VC_CONTAINER_STATUS_T mkv_read_elements( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size );
+static VC_CONTAINER_STATUS_T mkv_read_element_data_uint( VC_CONTAINER_T *p_ctx, int64_t size, uint64_t *value );
+static VC_CONTAINER_STATUS_T mkv_read_element_data_float( VC_CONTAINER_T *p_ctx, int64_t size, double *value );
+static VC_CONTAINER_STATUS_T mkv_read_element_ebml( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size );
+static VC_CONTAINER_STATUS_T mkv_read_subelements_ebml( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size );
+static VC_CONTAINER_STATUS_T mkv_read_element_segment( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size );
+static VC_CONTAINER_STATUS_T mkv_read_element_track_entry( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size );
+static VC_CONTAINER_STATUS_T mkv_read_subelements_track_entry( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size );
+static VC_CONTAINER_STATUS_T mkv_read_subelements_video( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size );
+static VC_CONTAINER_STATUS_T mkv_read_subelements_audio( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size );
+static VC_CONTAINER_STATUS_T mkv_read_subelements_info( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size );
+static VC_CONTAINER_STATUS_T mkv_read_element_encoding( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size );
+static VC_CONTAINER_STATUS_T mkv_read_subelements_encoding( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size );
+static VC_CONTAINER_STATUS_T mkv_read_subelements_compression( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size );
+static VC_CONTAINER_STATUS_T mkv_read_subelements_seek_head( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size );
+static VC_CONTAINER_STATUS_T mkv_read_element_cues( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size );
+static VC_CONTAINER_STATUS_T mkv_read_subelements_cue_point( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size );
+
+static VC_CONTAINER_STATUS_T mkv_read_subelements_cluster( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size );
+
+/******************************************************************************
+List of element IDs and their associated processing functions
+******************************************************************************/
+MKV_ELEMENT_T mkv_elements_list[] =
+{
+   /* EBML Basics */
+   {MKV_ELEMENT_ID_EBML, MKV_ELEMENT_ID_UNKNOWN, "EBML", mkv_read_element_ebml},
+   {MKV_ELEMENT_ID_EBML_VERSION, MKV_ELEMENT_ID_EBML, "EBMLVersion", mkv_read_subelements_ebml},
+   {MKV_ELEMENT_ID_EBML_READ_VERSION, MKV_ELEMENT_ID_EBML, "EBMLReadVersion", mkv_read_subelements_ebml},
+   {MKV_ELEMENT_ID_EBML_MAX_ID_LENGTH, MKV_ELEMENT_ID_EBML, "EBMLMaxIDLength", mkv_read_subelements_ebml},
+   {MKV_ELEMENT_ID_EBML_MAX_SIZE_LENGTH, MKV_ELEMENT_ID_EBML, "EBMLMaxSizeLength", mkv_read_subelements_ebml},
+   {MKV_ELEMENT_ID_DOCTYPE, MKV_ELEMENT_ID_EBML, "DocType", mkv_read_subelements_ebml},
+   {MKV_ELEMENT_ID_DOCTYPE_VERSION, MKV_ELEMENT_ID_EBML, "DocTypeVersion", mkv_read_subelements_ebml},
+   {MKV_ELEMENT_ID_DOCTYPE_READ_VERSION, MKV_ELEMENT_ID_EBML, "DocTypeReadVersion", mkv_read_subelements_ebml},
+
+   /* Global Elements */
+   {MKV_ELEMENT_ID_CRC32, MKV_ELEMENT_ID_INVALID, "CRC-32", 0},
+   {MKV_ELEMENT_ID_VOID, MKV_ELEMENT_ID_INVALID, "Void", 0},
+
+   /* Segment */
+   {MKV_ELEMENT_ID_SEGMENT, MKV_ELEMENT_ID_UNKNOWN, "Segment", mkv_read_element_segment},
+
+   /* Meta Seek Information */
+   {MKV_ELEMENT_ID_SEEK_HEAD, MKV_ELEMENT_ID_SEGMENT, "SeekHead", mkv_read_elements},
+   {MKV_ELEMENT_ID_SEEK, MKV_ELEMENT_ID_SEEK_HEAD, "Seek", mkv_read_subelements_seek_head},
+   {MKV_ELEMENT_ID_SEEK_ID, MKV_ELEMENT_ID_SEEK, "SeekID", mkv_read_subelements_seek_head},
+   {MKV_ELEMENT_ID_SEEK_POSITION, MKV_ELEMENT_ID_SEEK, "SeekPosition", mkv_read_subelements_seek_head},
+
+   /* Segment Information */
+   {MKV_ELEMENT_ID_INFO, MKV_ELEMENT_ID_SEGMENT, "Info", mkv_read_elements},
+   {MKV_ELEMENT_ID_SEGMENT_UID, MKV_ELEMENT_ID_INFO, "SegmentUID", 0},
+   {MKV_ELEMENT_ID_SEGMENT_FILENAME, MKV_ELEMENT_ID_INFO, "SegmentFilename", 0},
+   {MKV_ELEMENT_ID_PREV_UID, MKV_ELEMENT_ID_INFO, "PrevUID", 0},
+   {MKV_ELEMENT_ID_PREV_FILENAME, MKV_ELEMENT_ID_INFO, "PrevFilename", 0},
+   {MKV_ELEMENT_ID_NEXT_UID, MKV_ELEMENT_ID_INFO, "NextUID", 0},
+   {MKV_ELEMENT_ID_NEXT_FILENAME, MKV_ELEMENT_ID_INFO, "NextFilename", 0},
+   {MKV_ELEMENT_ID_SEGMENT_FAMILY, MKV_ELEMENT_ID_INFO, "SegmentFamily", 0},
+   {MKV_ELEMENT_ID_CHAPTER_TRANSLATE, MKV_ELEMENT_ID_INFO, "ChapterTranslate", 0},
+   {MKV_ELEMENT_ID_CHAPTER_TRANSLATE_EDITION_UID, MKV_ELEMENT_ID_INFO, "ChapterTranslateEditionUID", 0},
+   {MKV_ELEMENT_ID_CHAPTER_TRANSLATE_CODEC, MKV_ELEMENT_ID_INFO, "ChapterTranslateCodec", 0},
+   {MKV_ELEMENT_ID_CHAPTER_TRANSLATE_ID, MKV_ELEMENT_ID_INFO, "ChapterTranslateID", 0},
+   {MKV_ELEMENT_ID_TIMECODE_SCALE, MKV_ELEMENT_ID_INFO, "TimecodeScale", mkv_read_subelements_info},
+   {MKV_ELEMENT_ID_DURATION, MKV_ELEMENT_ID_INFO, "Duration", mkv_read_subelements_info},
+   {MKV_ELEMENT_ID_DATE_UTC, MKV_ELEMENT_ID_INFO, "DateUTC", 0},
+   {MKV_ELEMENT_ID_TITLE, MKV_ELEMENT_ID_INFO, "Title", mkv_read_subelements_info},
+   {MKV_ELEMENT_ID_MUXING_APP, MKV_ELEMENT_ID_INFO, "MuxingApp", mkv_read_subelements_info},
+   {MKV_ELEMENT_ID_WRITING_APP, MKV_ELEMENT_ID_INFO, "WritingApp", mkv_read_subelements_info},
+
+   /* Cluster */
+   {MKV_ELEMENT_ID_CLUSTER, MKV_ELEMENT_ID_SEGMENT, "Cluster", 0},
+   {MKV_ELEMENT_ID_TIMECODE, MKV_ELEMENT_ID_CLUSTER, "Timecode", 0},
+   {MKV_ELEMENT_ID_SILENT_TRACKS, MKV_ELEMENT_ID_CLUSTER, "SilentTracks", 0},
+   {MKV_ELEMENT_ID_SILENT_TRACK_NUMBER, MKV_ELEMENT_ID_CLUSTER, "SilentTrackNumber", 0},
+   {MKV_ELEMENT_ID_POSITION, MKV_ELEMENT_ID_CLUSTER, "Position", 0},
+   {MKV_ELEMENT_ID_PREV_SIZE, MKV_ELEMENT_ID_CLUSTER, "PrevSize", 0},
+   {MKV_ELEMENT_ID_BLOCKGROUP, MKV_ELEMENT_ID_CLUSTER, "BlockGroup", 0},
+   {MKV_ELEMENT_ID_BLOCK, MKV_ELEMENT_ID_BLOCKGROUP, "Block", 0},
+   {MKV_ELEMENT_ID_BLOCK_ADDITIONS, MKV_ELEMENT_ID_BLOCKGROUP, "BlockAdditions", 0},
+   {MKV_ELEMENT_ID_BLOCK_MORE, MKV_ELEMENT_ID_BLOCK_ADDITIONS, "BlockMore", 0},
+   {MKV_ELEMENT_ID_BLOCK_ADD_ID, MKV_ELEMENT_ID_BLOCK_MORE, "BlockAddId", 0},
+   {MKV_ELEMENT_ID_BLOCK_ADDITIONAL, MKV_ELEMENT_ID_BLOCK_MORE, "BlockAdditional", 0},
+   {MKV_ELEMENT_ID_BLOCK_DURATION, MKV_ELEMENT_ID_BLOCKGROUP, "BlockDuration", 0},
+   {MKV_ELEMENT_ID_REFERENCE_PRIORITY, MKV_ELEMENT_ID_BLOCKGROUP, "ReferencePriority", 0},
+   {MKV_ELEMENT_ID_REFERENCE_BLOCK, MKV_ELEMENT_ID_BLOCKGROUP, "ReferenceBlock", 0},
+   {MKV_ELEMENT_ID_CODEC_STATE, MKV_ELEMENT_ID_BLOCKGROUP, "CodecState", 0},
+   {MKV_ELEMENT_ID_SLICES, MKV_ELEMENT_ID_BLOCKGROUP, "Slices", 0},
+   {MKV_ELEMENT_ID_TIME_SLICE, MKV_ELEMENT_ID_SLICES, "TimeSlice", 0},
+   {MKV_ELEMENT_ID_LACE_NUMBER, MKV_ELEMENT_ID_TIME_SLICE, "LaceNumber", 0},
+   {MKV_ELEMENT_ID_SIMPLE_BLOCK, MKV_ELEMENT_ID_CLUSTER, "SimpleBlock", 0},
+
+   /* Track */
+   {MKV_ELEMENT_ID_TRACKS, MKV_ELEMENT_ID_SEGMENT, "Tracks", mkv_read_elements},
+   {MKV_ELEMENT_ID_TRACK_ENTRY, MKV_ELEMENT_ID_TRACKS, "TrackEntry", mkv_read_element_track_entry},
+   {MKV_ELEMENT_ID_TRACK_NUMBER, MKV_ELEMENT_ID_TRACK_ENTRY, "TrackNumber", mkv_read_subelements_track_entry},
+   {MKV_ELEMENT_ID_TRACK_UID, MKV_ELEMENT_ID_TRACK_ENTRY, "TrackUID", mkv_read_subelements_track_entry},
+   {MKV_ELEMENT_ID_TRACK_TYPE, MKV_ELEMENT_ID_TRACK_ENTRY, "TrackType", mkv_read_subelements_track_entry},
+   {MKV_ELEMENT_ID_FLAG_ENABLED, MKV_ELEMENT_ID_TRACK_ENTRY, "FlagEnabled", mkv_read_subelements_track_entry},
+   {MKV_ELEMENT_ID_FLAG_DEFAULT, MKV_ELEMENT_ID_TRACK_ENTRY, "FlagDefault", mkv_read_subelements_track_entry},
+   {MKV_ELEMENT_ID_FLAG_FORCED, MKV_ELEMENT_ID_TRACK_ENTRY, "FlagForced", mkv_read_subelements_track_entry},
+   {MKV_ELEMENT_ID_FLAG_LACING, MKV_ELEMENT_ID_TRACK_ENTRY, "FlagLacing", mkv_read_subelements_track_entry},
+   {MKV_ELEMENT_ID_MIN_CACHE, MKV_ELEMENT_ID_TRACK_ENTRY, "MinCache", 0},
+   {MKV_ELEMENT_ID_MAX_CACHE, MKV_ELEMENT_ID_TRACK_ENTRY, "MaxCache", 0},
+   {MKV_ELEMENT_ID_DEFAULT_DURATION, MKV_ELEMENT_ID_TRACK_ENTRY, "DefaultDuration", mkv_read_subelements_track_entry},
+   {MKV_ELEMENT_ID_TRACK_TIMECODE_SCALE, MKV_ELEMENT_ID_TRACK_ENTRY, "TrackTimecodeScale", mkv_read_subelements_track_entry},
+   {MKV_ELEMENT_ID_MAX_BLOCK_ADDITION_ID, MKV_ELEMENT_ID_TRACK_ENTRY, "MaxBlockAdditionID", 0},
+   {MKV_ELEMENT_ID_NAME, MKV_ELEMENT_ID_TRACK_ENTRY, "Name", mkv_read_subelements_track_entry},
+   {MKV_ELEMENT_ID_LANGUAGE, MKV_ELEMENT_ID_TRACK_ENTRY, "Language", mkv_read_subelements_track_entry},
+   {MKV_ELEMENT_ID_TRACK_CODEC_ID, MKV_ELEMENT_ID_TRACK_ENTRY, "CodecID", mkv_read_subelements_track_entry},
+   {MKV_ELEMENT_ID_TRACK_CODEC_PRIVATE, MKV_ELEMENT_ID_TRACK_ENTRY, "CodecPrivate", mkv_read_subelements_track_entry},
+   {MKV_ELEMENT_ID_TRACK_CODEC_NAME, MKV_ELEMENT_ID_TRACK_ENTRY, "CodecName", mkv_read_subelements_track_entry},
+   {MKV_ELEMENT_ID_ATTACHMENT_LINK, MKV_ELEMENT_ID_TRACK_ENTRY, "AttachmentLink", 0},
+   {MKV_ELEMENT_ID_CODEC_DECODE_ALL, MKV_ELEMENT_ID_TRACK_ENTRY, "DecodeAll", 0},
+   {MKV_ELEMENT_ID_TRACK_OVERLAY, MKV_ELEMENT_ID_TRACK_ENTRY, "TrackOverlay", 0},
+   {MKV_ELEMENT_ID_TRACK_TRANSLATE, MKV_ELEMENT_ID_TRACK_ENTRY, "TrackTranslate", 0},
+   {MKV_ELEMENT_ID_TRACK_TRANSLATE_EDITION_UID, MKV_ELEMENT_ID_TRACK_TRANSLATE, "TrackTranslateEditionUID", 0},
+   {MKV_ELEMENT_ID_TRACK_TRANSLATE_CODEC, MKV_ELEMENT_ID_TRACK_TRANSLATE, "TrackTranslateCodec", 0},
+   {MKV_ELEMENT_ID_TRACK_TRANSLATE_TRACK_ID, MKV_ELEMENT_ID_TRACK_TRANSLATE, "TrackTranslateTrackID", 0},
+
+   /* Video */
+   {MKV_ELEMENT_ID_VIDEO, MKV_ELEMENT_ID_TRACK_ENTRY, "Video", mkv_read_elements},
+   {MKV_ELEMENT_ID_FLAG_INTERLACED, MKV_ELEMENT_ID_VIDEO, "FlagInterlaced", mkv_read_subelements_video},
+   {MKV_ELEMENT_ID_STEREO_MODE, MKV_ELEMENT_ID_VIDEO, "StereoMode", mkv_read_subelements_video},
+   {MKV_ELEMENT_ID_PIXEL_WIDTH, MKV_ELEMENT_ID_VIDEO, "PixelWidth", mkv_read_subelements_video},
+   {MKV_ELEMENT_ID_PIXEL_HEIGHT, MKV_ELEMENT_ID_VIDEO, "PixelHeight", mkv_read_subelements_video},
+   {MKV_ELEMENT_ID_PIXEL_CROP_BOTTOM, MKV_ELEMENT_ID_VIDEO, "PixelCropBottom", mkv_read_subelements_video},
+   {MKV_ELEMENT_ID_PIXEL_CROP_TOP, MKV_ELEMENT_ID_VIDEO, "PixelCropTop", mkv_read_subelements_video},
+   {MKV_ELEMENT_ID_PIXEL_CROP_LEFT, MKV_ELEMENT_ID_VIDEO, "PixelCropLeft", mkv_read_subelements_video},
+   {MKV_ELEMENT_ID_PIXEL_CROP_RIGHT, MKV_ELEMENT_ID_VIDEO, "PixelCropRight", mkv_read_subelements_video},
+   {MKV_ELEMENT_ID_DISPLAY_WIDTH, MKV_ELEMENT_ID_VIDEO, "DisplayWidth", mkv_read_subelements_video},
+   {MKV_ELEMENT_ID_DISPLAY_HEIGHT, MKV_ELEMENT_ID_VIDEO, "DisplayHeight", mkv_read_subelements_video},
+   {MKV_ELEMENT_ID_DISPLAY_UNIT, MKV_ELEMENT_ID_VIDEO, "DisplayUnit", mkv_read_subelements_video},
+   {MKV_ELEMENT_ID_ASPECT_RATIO_TYPE, MKV_ELEMENT_ID_VIDEO, "AspectRatioType", mkv_read_subelements_video},
+   {MKV_ELEMENT_ID_COLOUR_SPACE, MKV_ELEMENT_ID_VIDEO, "ColourSpace", mkv_read_subelements_video},
+   {MKV_ELEMENT_ID_FRAME_RATE, MKV_ELEMENT_ID_VIDEO, "FrameRate", mkv_read_subelements_video},
+
+   /* Audio */
+   {MKV_ELEMENT_ID_AUDIO, MKV_ELEMENT_ID_TRACK_ENTRY, "Audio", mkv_read_elements},
+   {MKV_ELEMENT_ID_SAMPLING_FREQUENCY, MKV_ELEMENT_ID_AUDIO, "SamplingFrequency", mkv_read_subelements_audio},
+   {MKV_ELEMENT_ID_OUTPUT_SAMPLING_FREQUENCY, MKV_ELEMENT_ID_AUDIO, "OutputSamplingFrequency", mkv_read_subelements_audio},
+   {MKV_ELEMENT_ID_CHANNELS, MKV_ELEMENT_ID_AUDIO, "Channels", mkv_read_subelements_audio},
+   {MKV_ELEMENT_ID_BIT_DEPTH, MKV_ELEMENT_ID_AUDIO, "BitDepth", mkv_read_subelements_audio},
+
+   /* Content Encoding */
+   {MKV_ELEMENT_ID_CONTENT_ENCODINGS, MKV_ELEMENT_ID_TRACK_ENTRY, "ContentEncodings", mkv_read_elements},
+   {MKV_ELEMENT_ID_CONTENT_ENCODING, MKV_ELEMENT_ID_CONTENT_ENCODINGS, "ContentEncoding", mkv_read_element_encoding},
+   {MKV_ELEMENT_ID_CONTENT_ENCODING_ORDER, MKV_ELEMENT_ID_CONTENT_ENCODING, "ContentEncodingOrder", mkv_read_subelements_encoding},
+   {MKV_ELEMENT_ID_CONTENT_ENCODING_SCOPE, MKV_ELEMENT_ID_CONTENT_ENCODING, "ContentEncodingScope", mkv_read_subelements_encoding},
+   {MKV_ELEMENT_ID_CONTENT_ENCODING_TYPE, MKV_ELEMENT_ID_CONTENT_ENCODING, "ContentEncodingType", mkv_read_subelements_encoding},
+   {MKV_ELEMENT_ID_CONTENT_COMPRESSION, MKV_ELEMENT_ID_CONTENT_ENCODING, "ContentCompression", mkv_read_elements},
+   {MKV_ELEMENT_ID_CONTENT_COMPRESSION_ALGO, MKV_ELEMENT_ID_CONTENT_COMPRESSION, "ContentCompAlgo", mkv_read_subelements_compression},
+   {MKV_ELEMENT_ID_CONTENT_COMPRESSION_SETTINGS, MKV_ELEMENT_ID_CONTENT_COMPRESSION, "ContentCompSettings", mkv_read_subelements_compression},
+   {MKV_ELEMENT_ID_CONTENT_ENCRYPTION, MKV_ELEMENT_ID_CONTENT_ENCODING, "ContentEncryption", mkv_read_elements},
+   {MKV_ELEMENT_ID_CONTENT_ENCRYPTION_ALGO, MKV_ELEMENT_ID_CONTENT_ENCRYPTION, "ContentEncAlgo", 0},
+   {MKV_ELEMENT_ID_CONTENT_ENCRYPTION_KEY_ID, MKV_ELEMENT_ID_CONTENT_ENCRYPTION, "ContentEncKeyID", 0},
+   {MKV_ELEMENT_ID_CONTENT_SIGNATURE, MKV_ELEMENT_ID_CONTENT_ENCRYPTION, "ContentSignature", 0},
+   {MKV_ELEMENT_ID_CONTENT_SIGNATURE_KEY_ID, MKV_ELEMENT_ID_CONTENT_ENCRYPTION, "ContentSigKeyID", 0},
+   {MKV_ELEMENT_ID_CONTENT_SIGNATURE_ALGO, MKV_ELEMENT_ID_CONTENT_ENCRYPTION, "ContentSigAlgo", 0},
+   {MKV_ELEMENT_ID_CONTENT_SIGNATURE_HASH_ALGO, MKV_ELEMENT_ID_CONTENT_ENCRYPTION, "ContentSigHashAlgo", 0},
+
+   /* Cueing data */
+   {MKV_ELEMENT_ID_CUES, MKV_ELEMENT_ID_SEGMENT, "Cues", mkv_read_element_cues},
+   {MKV_ELEMENT_ID_CUE_POINT, MKV_ELEMENT_ID_CUES, "Cue Point", mkv_read_elements},
+   {MKV_ELEMENT_ID_CUE_TIME, MKV_ELEMENT_ID_CUE_POINT, "Cue Time", 0},
+   {MKV_ELEMENT_ID_CUE_TRACK_POSITIONS, MKV_ELEMENT_ID_CUE_POINT, "Cue Track Positions", mkv_read_elements},
+   {MKV_ELEMENT_ID_CUE_TRACK, MKV_ELEMENT_ID_CUE_TRACK_POSITIONS, "Cue Track", 0},
+   {MKV_ELEMENT_ID_CUE_CLUSTER_POSITION, MKV_ELEMENT_ID_CUE_TRACK_POSITIONS, "Cue Cluster Position", 0},
+   {MKV_ELEMENT_ID_CUE_BLOCK_NUMBER, MKV_ELEMENT_ID_CUE_TRACK_POSITIONS, "Cue Block Number", 0},
+
+   /* Attachments */
+   {MKV_ELEMENT_ID_ATTACHMENTS, MKV_ELEMENT_ID_SEGMENT, "Attachments", 0},
+
+   /* Chapters */
+   {MKV_ELEMENT_ID_CHAPTERS, MKV_ELEMENT_ID_SEGMENT, "Chapters", 0},
+
+   /* Tagging */
+   {MKV_ELEMENT_ID_TAGS, MKV_ELEMENT_ID_SEGMENT, "Tags", mkv_read_elements},
+   {MKV_ELEMENT_ID_TAG, MKV_ELEMENT_ID_TAGS, "Tag", mkv_read_elements},
+   {MKV_ELEMENT_ID_TAG_TARGETS, MKV_ELEMENT_ID_TAG, "Tag Targets", mkv_read_elements},
+   {MKV_ELEMENT_ID_TAG_TARGET_TYPE_VALUE, MKV_ELEMENT_ID_TAG_TARGETS, "Tag Target Type Value", 0},
+   {MKV_ELEMENT_ID_TAG_TARGET_TYPE, MKV_ELEMENT_ID_TAG_TARGETS, "Tag Target Type", 0},
+   {MKV_ELEMENT_ID_TAG_TRACK_UID, MKV_ELEMENT_ID_TAG_TARGETS, "Tag Track UID", 0},
+   {MKV_ELEMENT_ID_TAG_EDITION_UID, MKV_ELEMENT_ID_TAG_TARGETS, "Tag Edition UID", 0},
+   {MKV_ELEMENT_ID_TAG_CHAPTER_UID, MKV_ELEMENT_ID_TAG_TARGETS, "Tag Chapter UID", 0},
+   {MKV_ELEMENT_ID_TAG_ATTACHMENT_UID, MKV_ELEMENT_ID_TAG_TARGETS, "Tag Attachment UID", 0},
+   {MKV_ELEMENT_ID_TAG_SIMPLE_TAG, MKV_ELEMENT_ID_TAG, "Simple Tag", mkv_read_elements},
+   {MKV_ELEMENT_ID_TAG_NAME, MKV_ELEMENT_ID_TAG_SIMPLE_TAG, "Tag Name", 0},
+   {MKV_ELEMENT_ID_TAG_LANGUAGE, MKV_ELEMENT_ID_TAG_SIMPLE_TAG, "Tag Language", 0},
+   {MKV_ELEMENT_ID_TAG_DEFAULT, MKV_ELEMENT_ID_TAG_SIMPLE_TAG, "Tag Default", 0},
+   {MKV_ELEMENT_ID_TAG_STRING, MKV_ELEMENT_ID_TAG_SIMPLE_TAG, "Tag String", 0},
+   {MKV_ELEMENT_ID_TAG_BINARY, MKV_ELEMENT_ID_TAG_SIMPLE_TAG, "Tag Binary", 0},
+
+   {MKV_ELEMENT_ID_UNKNOWN, MKV_ELEMENT_ID_INVALID, "unknown", 0}
+};
+
+MKV_ELEMENT_T mkv_cluster_elements_list[] =
+{
+   /* Cluster */
+   {MKV_ELEMENT_ID_CLUSTER, MKV_ELEMENT_ID_SEGMENT, "Cluster", 0},
+   {MKV_ELEMENT_ID_TIMECODE, MKV_ELEMENT_ID_CLUSTER, "Timecode", mkv_read_subelements_cluster},
+   {MKV_ELEMENT_ID_SILENT_TRACKS, MKV_ELEMENT_ID_CLUSTER, "SilentTracks", 0},
+   {MKV_ELEMENT_ID_SILENT_TRACK_NUMBER, MKV_ELEMENT_ID_CLUSTER, "SilentTrackNumber", 0},
+   {MKV_ELEMENT_ID_POSITION, MKV_ELEMENT_ID_CLUSTER, "Position", 0},
+   {MKV_ELEMENT_ID_PREV_SIZE, MKV_ELEMENT_ID_CLUSTER, "PrevSize", 0},
+   {MKV_ELEMENT_ID_BLOCKGROUP, MKV_ELEMENT_ID_CLUSTER, "BlockGroup", 0},
+   {MKV_ELEMENT_ID_BLOCK, MKV_ELEMENT_ID_BLOCKGROUP, "Block", 0},
+   {MKV_ELEMENT_ID_BLOCK_ADDITIONS, MKV_ELEMENT_ID_BLOCKGROUP, "BlockAdditions", 0},
+   {MKV_ELEMENT_ID_BLOCK_MORE, MKV_ELEMENT_ID_BLOCK_ADDITIONS, "BlockMore", 0},
+   {MKV_ELEMENT_ID_BLOCK_ADD_ID, MKV_ELEMENT_ID_BLOCK_MORE, "BlockAddId", 0},
+   {MKV_ELEMENT_ID_BLOCK_ADDITIONAL, MKV_ELEMENT_ID_BLOCK_MORE, "BlockAdditional", 0},
+   {MKV_ELEMENT_ID_BLOCK_DURATION, MKV_ELEMENT_ID_BLOCKGROUP, "BlockDuration", mkv_read_subelements_cluster},
+   {MKV_ELEMENT_ID_REFERENCE_PRIORITY, MKV_ELEMENT_ID_BLOCKGROUP, "ReferencePriority", 0},
+   {MKV_ELEMENT_ID_REFERENCE_BLOCK, MKV_ELEMENT_ID_BLOCKGROUP, "ReferenceBlock", 0},
+   {MKV_ELEMENT_ID_CODEC_STATE, MKV_ELEMENT_ID_BLOCKGROUP, "CodecState", 0},
+   {MKV_ELEMENT_ID_SLICES, MKV_ELEMENT_ID_BLOCKGROUP, "Slices", 0},
+   {MKV_ELEMENT_ID_TIME_SLICE, MKV_ELEMENT_ID_SLICES, "TimeSlice", 0},
+   {MKV_ELEMENT_ID_LACE_NUMBER, MKV_ELEMENT_ID_TIME_SLICE, "LaceNumber", 0},
+   {MKV_ELEMENT_ID_SIMPLE_BLOCK, MKV_ELEMENT_ID_CLUSTER, "SimpleBlock", 0},
+
+   /* Global Elements */
+   {MKV_ELEMENT_ID_CRC32, MKV_ELEMENT_ID_INVALID, "CRC-32", 0},
+   {MKV_ELEMENT_ID_VOID, MKV_ELEMENT_ID_INVALID, "Void", 0},
+
+   {MKV_ELEMENT_ID_UNKNOWN, MKV_ELEMENT_ID_INVALID, "unknown", 0}
+};
+
+MKV_ELEMENT_T mkv_cue_elements_list[] =
+{
+   /* Cueing data */
+   {MKV_ELEMENT_ID_CUES, MKV_ELEMENT_ID_SEGMENT, "Cues", 0},
+   {MKV_ELEMENT_ID_CUE_POINT, MKV_ELEMENT_ID_CUES, "Cue Point", mkv_read_elements},
+   {MKV_ELEMENT_ID_CUE_TIME, MKV_ELEMENT_ID_CUE_POINT, "Cue Time", mkv_read_subelements_cue_point},
+   {MKV_ELEMENT_ID_CUE_TRACK_POSITIONS, MKV_ELEMENT_ID_CUE_POINT, "Cue Track Positions", mkv_read_elements},
+   {MKV_ELEMENT_ID_CUE_TRACK, MKV_ELEMENT_ID_CUE_TRACK_POSITIONS, "Cue Track", mkv_read_subelements_cue_point},
+   {MKV_ELEMENT_ID_CUE_CLUSTER_POSITION, MKV_ELEMENT_ID_CUE_TRACK_POSITIONS, "Cue Cluster Position", mkv_read_subelements_cue_point},
+   {MKV_ELEMENT_ID_CUE_BLOCK_NUMBER, MKV_ELEMENT_ID_CUE_TRACK_POSITIONS, "Cue Block Number", mkv_read_subelements_cue_point},
+
+   /* Global Elements */
+   {MKV_ELEMENT_ID_CRC32, MKV_ELEMENT_ID_INVALID, "CRC-32", 0},
+   {MKV_ELEMENT_ID_VOID, MKV_ELEMENT_ID_INVALID, "Void", 0},
+
+   {MKV_ELEMENT_ID_UNKNOWN, MKV_ELEMENT_ID_INVALID, "unknown", 0}
+};
+
+/******************************************************************************
+List of codec mapping
+******************************************************************************/
+static const struct {
+   VC_CONTAINER_FOURCC_T fourcc;
+   const char *codecid;
+   VC_CONTAINER_FOURCC_T variant;
+} codecid_to_fourcc_table[] =
+{
+   /* Video */
+   {VC_CONTAINER_CODEC_MP1V,    "V_MPEG1", 0},
+   {VC_CONTAINER_CODEC_MP2V,    "V_MPEG2", 0},
+   {VC_CONTAINER_CODEC_MP4V,    "V_MPEG4/ISO/ASP", 0},
+   {VC_CONTAINER_CODEC_MP4V,    "V_MPEG4/ISO/SP", 0},
+   {VC_CONTAINER_CODEC_MP4V,    "V_MPEG4/ISO/AP", 0},
+   {VC_CONTAINER_CODEC_DIV3,    "V_MPEG4/MS/V3", 0},
+   {VC_CONTAINER_CODEC_H264,    "V_MPEG4/ISO/AVC", VC_CONTAINER_VARIANT_H264_AVC1},
+   {VC_CONTAINER_CODEC_MJPEG,   "V_MJPEG", 0},
+   {VC_CONTAINER_CODEC_RV10,    "V_REAL/RV10", 0},
+   {VC_CONTAINER_CODEC_RV20,    "V_REAL/RV20", 0},
+   {VC_CONTAINER_CODEC_RV30,    "V_REAL/RV30", 0},
+   {VC_CONTAINER_CODEC_RV40,    "V_REAL/RV40", 0},
+   {VC_CONTAINER_CODEC_THEORA,  "V_THEORA", 0},
+   {VC_CONTAINER_CODEC_DIRAC,   "V_DIRAC", 0},
+   {VC_CONTAINER_CODEC_VP8,     "V_VP8", 0},
+
+   /* Audio */
+   {VC_CONTAINER_CODEC_MPGA,    "A_MPEG/L3", VC_CONTAINER_VARIANT_MPGA_L3},
+   {VC_CONTAINER_CODEC_MPGA,    "A_MPEG/L2", VC_CONTAINER_VARIANT_MPGA_L2},
+   {VC_CONTAINER_CODEC_MPGA,    "A_MPEG/L1", VC_CONTAINER_VARIANT_MPGA_L1},
+   {VC_CONTAINER_CODEC_MP4A,    "A_AAC", 0},
+   {VC_CONTAINER_CODEC_MP4A,    "A_AAC/MPEG2/MAIN", 0},
+   {VC_CONTAINER_CODEC_MP4A,    "A_AAC/MPEG2/LC", 0},
+   {VC_CONTAINER_CODEC_MP4A,    "A_AAC/MPEG2/SSR", 0},
+   {VC_CONTAINER_CODEC_MP4A,    "A_AAC/MPEG2/LC/SBR", 0},
+   {VC_CONTAINER_CODEC_MP4A,    "A_AAC/MPEG4/MAIN", 0},
+   {VC_CONTAINER_CODEC_MP4A,    "A_AAC/MPEG4/LC", 0},
+   {VC_CONTAINER_CODEC_MP4A,    "A_AAC/MPEG4/SSR", 0},
+   {VC_CONTAINER_CODEC_MP4A,    "A_AAC/MPEG4/LC/SBR", 0},
+   {VC_CONTAINER_CODEC_AC3,     "A_AC3", 0},
+   {VC_CONTAINER_CODEC_EAC3,    "A_EAC3", 0},
+   {VC_CONTAINER_CODEC_DTS,     "A_DTS", 0},
+   {VC_CONTAINER_CODEC_MLP,     "A_MLP", 0},
+   {0,                          "A_TRUEHD", 0},
+   {VC_CONTAINER_CODEC_VORBIS,  "A_VORBIS", 0},
+   {VC_CONTAINER_CODEC_FLAC,    "A_FLAC", 0},
+   {VC_CONTAINER_CODEC_PCM_SIGNED_LE, "A_PCM/INT/LIT", 0},
+   {VC_CONTAINER_CODEC_PCM_SIGNED_BE, "A_PCM/INT/BIG", 0},
+   {VC_CONTAINER_CODEC_PCM_FLOAT_LE,  "A_PCM/FLOAT/IEEE", 0},
+   {0,                          "A_REAL/xyzt", 0},
+   {0,                          "A_REAL/14_4", 0},
+
+   /* Text */
+   {VC_CONTAINER_CODEC_TEXT,    "S_TEXT/ASCII", 0},
+   {VC_CONTAINER_CODEC_TEXT,    "S_TEXT/UTF8", 0},
+   {VC_CONTAINER_CODEC_SSA,     "S_TEXT/ASS", 0},
+   {VC_CONTAINER_CODEC_SSA,     "S_TEXT/SSA", 0},
+   {VC_CONTAINER_CODEC_SSA,     "S_ASS", 0},
+   {VC_CONTAINER_CODEC_SSA,     "S_SSA", 0},
+   {VC_CONTAINER_CODEC_USF,     "S_TEXT/USF", 0},
+   {VC_CONTAINER_CODEC_VOBSUB,  "S_VOBSUB", 0},
+
+   {0, 0}
+};
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+
+static VC_CONTAINER_FOURCC_T mkv_codecid_to_fourcc(const char *codecid,
+   VC_CONTAINER_FOURCC_T *variant)
+{
+   unsigned int i;
+   for(i = 0; codecid_to_fourcc_table[i].codecid; i++)
+      if(!strcmp(codecid_to_fourcc_table[i].codecid, codecid)) break;
+   if (variant) *variant = codecid_to_fourcc_table[i].variant;
+   return codecid_to_fourcc_table[i].fourcc;
+}
+
+#if 0
+/** Find the track associated with an MKV track number */
+static VC_CONTAINER_TRACK_T *mkv_reader_find_track( VC_CONTAINER_T *p_ctx, unsigned int mkv_track_num)
+{
+   VC_CONTAINER_TRACK_T *p_track = 0;
+   unsigned int i;
+
+   for(i = 0; i < p_ctx->tracks_num; i++)
+      if(p_ctx->tracks[i]->priv->module->number == mkv_track_num) break;
+
+   if(i < p_ctx->tracks_num) /* We found it */
+      p_track = p_ctx->tracks[i];
+
+   return p_track;
+}
+#endif
+
+/** Base function used to read an MKV/EBML element header.
+ * This will read the element header do lots of sanity checking and return the element id
+ * and the size of the data contained in the element */
+static VC_CONTAINER_STATUS_T mkv_read_element_header(VC_CONTAINER_T *p_ctx, int64_t size,
+   MKV_ELEMENT_ID_T *id, int64_t *element_size, MKV_ELEMENT_ID_T parent_id,
+   MKV_ELEMENT_T **elem)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   MKV_ELEMENT_T *element;
+
+   module->element_offset = STREAM_POSITION(p_ctx);
+
+   *id = MKV_READ_ID(p_ctx, "Element ID");
+   CHECK_POINT(p_ctx);
+   if(!*id)
+   {
+      LOG_DEBUG(p_ctx, "invalid element id %i", *id);
+      return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+
+   if(elem) element = *elem;
+   else element = mkv_elements_list;
+
+   /* Find out which Element we are dealing with */
+   while(element->id && *id != element->id) element++;
+
+   *element_size = MKV_READ_UINT(p_ctx, "Element Size");
+   CHECK_POINT(p_ctx);
+   LOG_FORMAT(p_ctx, "- Element %s (ID 0x%x), Size: %"PRIi64", Offset: %"PRIi64,
+              element->psz_name, *id, *element_size, module->element_offset);
+
+   /* Sanity check the element size */
+   if(*element_size + 1 < 0 /* Shouldn't ever get that big */ ||
+      /* Only the segment / cluster elements can really be massive */
+      (*id != MKV_ELEMENT_ID_SEGMENT && *id != MKV_ELEMENT_ID_CLUSTER &&
+       *element_size > MKV_MAX_ELEMENT_SIZE))
+   {
+      LOG_DEBUG(p_ctx, "element %s has an invalid size (%"PRIi64")",
+                element->psz_name, *element_size);
+      return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+   if(size >= 0 && *element_size > size)
+   {
+      LOG_DEBUG(p_ctx, "element %s is bigger than it should (%"PRIi64" > %"PRIi64")",
+                element->psz_name, *element_size, size);
+      return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+
+   /* Sanity check that the element has the right parent */
+   if(element->id && element->parent_id != MKV_ELEMENT_ID_INVALID &&
+      parent_id != MKV_ELEMENT_ID_INVALID && parent_id != element->parent_id)
+   {
+      LOG_FORMAT(p_ctx, "Ignoring mis-placed element %s (ID 0x%x)", element->psz_name, *id);
+      while(element->id != MKV_ELEMENT_ID_UNKNOWN) element++;
+   }
+
+   /* Sanity check that the element isn't too deeply nested */
+   if(module->element_level >= MKV_MAX_ELEMENT_LEVEL)
+   {
+      LOG_DEBUG(p_ctx, "element %s is too deep. skipping", element->psz_name);
+      while(element->id != MKV_ELEMENT_ID_UNKNOWN) element++;
+   }
+
+   if(elem) *elem = element;
+   return STREAM_STATUS(p_ctx);
+}
+
+static VC_CONTAINER_STATUS_T mkv_read_element_data(VC_CONTAINER_T *p_ctx,
+   MKV_ELEMENT_T *element, int64_t element_size, int64_t size)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   int64_t offset;
+
+   offset = STREAM_POSITION(p_ctx);
+   if (size < 0) size = element_size;
+   if (size < 0) size = INT64_C(1) << 62;
+
+   /* Call the element specific parsing function */
+   if(element->pf_func)
+      status = element->pf_func(p_ctx, element->id, element_size < 0 ? size : element_size);
+
+   if(status != VC_CONTAINER_SUCCESS)
+      LOG_DEBUG(p_ctx, "element %s appears to be corrupted (%i)", element->psz_name, status);
+
+   if(element_size < 0) return STREAM_STATUS(p_ctx); /* Unknown size */
+
+   /* Skip the rest of the element */
+   element_size -= (STREAM_POSITION(p_ctx) - offset);
+   if(element_size < 0) /* Check for overruns */
+   {
+      /* Things have gone really bad here and we ended up reading past the end of the
+       * element. We could maybe try to be clever and recover by seeking back to the end
+       * of the element. However if we get there, the file is clearly corrupted so there's
+       * no guarantee it would work anyway. */
+      LOG_DEBUG(p_ctx, "%"PRIi64" bytes overrun past the end of element %s",
+                -element_size, element->psz_name);
+      return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+
+   if(element_size)
+      LOG_FORMAT(p_ctx, "%"PRIi64" bytes left unread in element %s", element_size, element->psz_name);
+
+   if(element_size < MKV_MAX_ELEMENT_SIZE) SKIP_BYTES(p_ctx, element_size);
+   else SEEK(p_ctx, STREAM_POSITION(p_ctx) + element_size);
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/** Base function used to read an MKV/EBML element.
+ * This will read the element header do lots of sanity checking and pass on the rest
+ * of the reading to the element specific reading function */
+static VC_CONTAINER_STATUS_T mkv_read_element(VC_CONTAINER_T *p_ctx,
+   int64_t size, MKV_ELEMENT_ID_T parent_id)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   MKV_ELEMENT_T *element = p_ctx->priv->module->elements_list;
+   int64_t element_size;
+   MKV_ELEMENT_ID_T id;
+
+   status = mkv_read_element_header(p_ctx, size, &id, &element_size, parent_id, &element);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+   return mkv_read_element_data(p_ctx, element, element_size, size);
+}
+
+/** Reads an unsigned integer element */
+static VC_CONTAINER_STATUS_T mkv_read_element_data_uint(VC_CONTAINER_T *p_ctx,
+   int64_t size, uint64_t *value)
+{
+   switch(size)
+   {
+   case 1: *value = READ_U8(p_ctx, "u8-integer"); break;
+   case 2: *value = READ_U16(p_ctx, "u16-integer"); break;
+   case 3: *value = READ_U24(p_ctx, "u24-integer"); break;
+   case 4: *value = READ_U32(p_ctx, "u32-integer"); break;
+   case 5: *value = READ_U40(p_ctx, "u40-integer"); break;
+   case 6: *value = READ_U48(p_ctx, "u48-integer"); break;
+   case 7: *value = READ_U56(p_ctx, "u56-integer"); break;
+   case 8: *value = READ_U64(p_ctx, "u64-integer"); break;
+   default: return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+   return STREAM_STATUS(p_ctx);
+}
+
+/** Reads a float element */
+static VC_CONTAINER_STATUS_T mkv_read_element_data_float(VC_CONTAINER_T *p_ctx,
+   int64_t size, double *value)
+{
+   union {
+      uint32_t  u32;
+      uint64_t  u64;
+      float     f;
+      double    d;
+   } u;
+
+   switch(size)
+   {
+   case 4: u.u32 = READ_U32(p_ctx, "f32-float"); *value = u.f; break;
+   case 8: u.u64 = READ_U64(p_ctx, "f64-float"); *value = u.d; break;
+   default: return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+   LOG_FORMAT(p_ctx, "float: %f", *value);
+   return STREAM_STATUS(p_ctx);
+}
+
+/** Reads an MKV EBML element */
+static VC_CONTAINER_STATUS_T mkv_read_element_ebml(VC_CONTAINER_T *p_ctx,
+   MKV_ELEMENT_ID_T id, int64_t size)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   int64_t offset = STREAM_POSITION(p_ctx);
+
+   /* Read contained elements */
+   module->element_level++;
+   while(status == VC_CONTAINER_SUCCESS && size >= MKV_ELEMENT_MIN_HEADER_SIZE)
+   {
+      offset = STREAM_POSITION(p_ctx);
+      status = mkv_read_element(p_ctx, size, id);
+      size -= (STREAM_POSITION(p_ctx) - offset);
+   }
+   module->element_level--;
+   return status;
+}
+
+/** Reads the MKV EBML sub-element */
+static VC_CONTAINER_STATUS_T mkv_read_subelements_ebml( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   uint64_t value;
+
+   /* Deal with DocType first since it's a special case */
+   if(id == MKV_ELEMENT_ID_DOCTYPE)
+   {
+      char doctype[] = "matroska doctype";
+
+      /* Check we've got the right doctype string for matroska */
+      if(size <= 0) goto unknown_doctype;
+      if(size > (int)sizeof(doctype)) goto unknown_doctype;
+      if((int)READ_STRING(p_ctx, doctype, size, "string") != size) return STREAM_STATUS(p_ctx);
+      if((size != sizeof("matroska")-1 || strncmp(doctype, "matroska", (int)size)) &&
+         (size != sizeof("webm")-1 || strncmp(doctype, "webm", (int)size)))
+         goto unknown_doctype;
+
+      module->is_doctype_valid = true;
+      return VC_CONTAINER_SUCCESS;
+
+ unknown_doctype:
+      LOG_DEBUG(p_ctx, "invalid doctype");
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   }
+
+   /* The rest are just unsigned integers */
+   status = mkv_read_element_data_uint(p_ctx, size, &value);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   switch(id)
+   {
+   case MKV_ELEMENT_ID_EBML_VERSION:
+   case MKV_ELEMENT_ID_EBML_READ_VERSION:
+      if(value != 1) return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+      break;
+   case MKV_ELEMENT_ID_EBML_MAX_ID_LENGTH:
+      if(value > 4) return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+      break;
+   case MKV_ELEMENT_ID_EBML_MAX_SIZE_LENGTH:
+      if(value > 8) return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+      break;
+   case MKV_ELEMENT_ID_DOCTYPE_VERSION:
+   case MKV_ELEMENT_ID_DOCTYPE_READ_VERSION:
+   default: break;
+   }
+
+   return STREAM_STATUS(p_ctx);
+}
+
+static VC_CONTAINER_STATUS_T mkv_read_elements( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   int64_t offset = STREAM_POSITION(p_ctx);
+   bool unknown_size = size < 0;
+
+   /* Read contained elements */
+   module->element_level++;
+   while(status == VC_CONTAINER_SUCCESS &&
+         (unknown_size || size >= MKV_ELEMENT_MIN_HEADER_SIZE))
+   {
+      offset = STREAM_POSITION(p_ctx);
+      status = mkv_read_element(p_ctx, size, id);
+      if(!unknown_size) size -= (STREAM_POSITION(p_ctx) - offset);
+   }
+   module->element_level--;
+   return status;
+}
+
+static VC_CONTAINER_STATUS_T mkv_read_element_segment( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   int64_t offset = STREAM_POSITION(p_ctx);
+   bool unknown_size = size < 0;
+
+   /* Read contained elements */
+   /* Initialise state used by reader */
+   module->state.level = 0;
+   module->state.levels[0].offset = STREAM_POSITION(p_ctx);
+   module->state.levels[0].size = size;
+   module->state.levels[0].id = MKV_ELEMENT_ID_SEGMENT;
+   module->state.levels[0].data_start = 0;
+   module->state.levels[0].data_offset = 0;
+   module->timecode_scale = 1000000;
+   module->duration = 0.0;
+   module->segment_offset = STREAM_POSITION(p_ctx);
+   module->segment_size = size;
+
+   /* Read contained elements until we have all the information we need to start
+    * playing the stream */
+   module->element_level++;
+   while(status == VC_CONTAINER_SUCCESS &&
+         (unknown_size || size >= MKV_ELEMENT_MIN_HEADER_SIZE))
+   {
+      MKV_ELEMENT_T *child = mkv_elements_list;
+      MKV_ELEMENT_ID_T child_id;
+      int64_t child_size;
+
+      offset = STREAM_POSITION(p_ctx);
+
+      status = mkv_read_element_header(p_ctx, size, &child_id, &child_size, id, &child);
+      if(status != VC_CONTAINER_SUCCESS) break;
+
+      if(child_id == MKV_ELEMENT_ID_CLUSTER)
+      {
+         /* We found the start of the data */
+         module->cluster_offset = module->element_offset;
+         module->state.level = 1;
+         module->state.levels[1].offset = STREAM_POSITION(p_ctx);
+         module->state.levels[1].size = child_size;
+         module->state.levels[1].id = MKV_ELEMENT_ID_CLUSTER;
+         module->state.levels[1].data_start = 0;
+         module->state.levels[1].data_offset = 0;
+         break;
+      }
+
+      status = mkv_read_element_data(p_ctx, child, child_size, size);
+      if(!unknown_size) size -= (STREAM_POSITION(p_ctx) - offset);
+   }
+
+   module->element_level--;
+   return status;
+}
+
+static VC_CONTAINER_STATUS_T mkv_read_element_track_entry( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_ES_TYPE_T es_type = VC_CONTAINER_ES_TYPE_UNKNOWN;
+   VC_CONTAINER_TRACK_MODULE_T *track_module;
+   VC_CONTAINER_TRACK_T *track;
+   VC_CONTAINER_FOURCC_T fourcc = 0, variant = 0;
+   unsigned int i, extra_size = 0, extra_offset = 0, is_wf = 0, is_bmih = 0;
+
+   /* Allocate and initialise track data */
+   if(p_ctx->tracks_num >= MKV_TRACKS_MAX) return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+   p_ctx->tracks[p_ctx->tracks_num] = track =
+      vc_container_allocate_track(p_ctx, sizeof(*p_ctx->tracks[0]->priv->module));
+   if(!track) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+
+   module->parsing = track;
+   track_module = track->priv->module;
+   track->is_enabled = true;
+   track->format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
+   track_module->timecode_scale = 1.0;
+   track_module->es_type.video.frame_rate = 0;
+
+   status = mkv_read_elements( p_ctx, id, size );
+   if(status != VC_CONTAINER_SUCCESS) goto error;
+
+   /* Sanity check the data we got from the track entry */
+   if(!track_module->number || !track_module->type)
+   { status = VC_CONTAINER_ERROR_FORMAT_INVALID; goto error; }
+
+   /* Check the encodings for the track are supported */
+   if(track_module->encodings_num > MKV_MAX_ENCODINGS)
+   { status = VC_CONTAINER_ERROR_TRACK_FORMAT_NOT_SUPPORTED; goto error; }
+   for(i = 0; i < track_module->encodings_num; i++)
+   {
+      if(track_module->encodings[i].type != MKV_CONTENT_ENCODING_COMPRESSION_HEADER ||
+         !track_module->encodings[i].data_size)
+      { status = VC_CONTAINER_ERROR_TRACK_FORMAT_NOT_SUPPORTED; goto error; }
+   }
+
+   /* Find out the track type */
+   if(track_module->type == 0x1)
+      es_type = VC_CONTAINER_ES_TYPE_VIDEO;
+   else if(track_module->type == 0x2)
+      es_type = VC_CONTAINER_ES_TYPE_AUDIO;
+   else if(track_module->type == 0x11)
+      es_type = VC_CONTAINER_ES_TYPE_SUBPICTURE;
+
+   if(es_type == VC_CONTAINER_ES_TYPE_UNKNOWN)
+   { status = VC_CONTAINER_ERROR_TRACK_FORMAT_NOT_SUPPORTED; goto error; }
+
+   if(!strcmp(track_module->codecid, "V_MS/VFW/FOURCC"))
+   {
+      if(vc_container_bitmapinfoheader_to_es_format(track->format->extradata,
+            track->format->extradata_size, &extra_offset, &extra_size,
+            track->format) == VC_CONTAINER_SUCCESS)
+      {
+         fourcc = track->format->codec;
+         is_bmih = 1;
+      }
+      track->format->extradata += extra_offset;
+      track->format->extradata_size = extra_size;
+   }
+   else if(!strcmp(track_module->codecid, "A_MS/ACM"))
+   {
+      if(vc_container_waveformatex_to_es_format(track->format->extradata,
+            track->format->extradata_size, &extra_offset, &extra_size,
+            track->format) == VC_CONTAINER_SUCCESS)
+      {
+         fourcc = track->format->codec;
+         is_wf = 1;
+      }
+      track->format->extradata += extra_offset;
+      track->format->extradata_size = extra_size;
+   }
+   else if((!strncmp(track_module->codecid, "A_AAC/MPEG2/", sizeof("A_AAC/MPEG2/")-1) ||
+            !strncmp(track_module->codecid, "A_AAC/MPEG4/", sizeof("A_AAC/MPEG4/")-1)) &&
+            !track->format->extradata_size)
+   {
+      static const unsigned int sample_rates[16] =
+      {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350};
+      unsigned int samplerate, samplerate_idx, profile, sbr = 0;
+      uint8_t *extra;
+
+      fourcc = mkv_codecid_to_fourcc(track_module->codecid, &variant);
+
+      /* Create extra data */
+      if( !strcmp( &track_module->codecid[12], "MAIN" ) ) profile = 0;
+      else if( !strcmp( &track_module->codecid[12], "LC" ) ) profile = 1;
+      else if( !strcmp( &track_module->codecid[12], "SSR" ) ) profile = 2;
+      else if( !strcmp( &track_module->codecid[12], "LC/SBR" ) ) { profile = 1; sbr = 1; }
+      else profile = 3;
+
+      samplerate = track_module->es_type.audio.sampling_frequency;
+      for( samplerate_idx = 0; samplerate_idx < 13; samplerate_idx++ )
+         if( sample_rates[samplerate_idx] == samplerate ) break;
+
+      status = vc_container_track_allocate_extradata(p_ctx, track, sbr ? 5 : 2);
+      if(status != VC_CONTAINER_SUCCESS) goto error;
+      track->format->extradata_size = sbr ? 5 : 2;
+      extra = track->format->extradata;
+
+      extra[0] = ((profile + 1) << 3) | ((samplerate_idx & 0xe) >> 1);
+      extra[1] = ((samplerate_idx & 0x1) << 7) | (track_module->es_type.audio.channels << 3);
+
+      if(sbr)
+      {
+         unsigned int sync_extension_type = 0x2B7;
+         samplerate = track_module->es_type.audio.output_sampling_frequency;
+         for(samplerate_idx = 0; samplerate_idx < 13; samplerate_idx++) 
+            if(sample_rates[samplerate_idx] == samplerate) break;
+         extra[2] = (sync_extension_type >> 3) & 0xFF;
+         extra[3] = ((sync_extension_type & 0x7) << 5) | 5;
+         extra[4] = (1 << 7) | (samplerate_idx << 3);
+      }
+   }
+   else fourcc = mkv_codecid_to_fourcc(track_module->codecid, &variant);
+
+   if(!fourcc)
+   {
+      LOG_DEBUG(p_ctx, "codec id %s is not supported", track_module->codecid);
+   }
+
+   LOG_DEBUG(p_ctx, "found track %4.4s", (char *)&fourcc);
+   track->format->codec = fourcc;
+   track->format->codec_variant = variant;
+   track->format->es_type = es_type;
+
+   switch(es_type)
+   {
+   case VC_CONTAINER_ES_TYPE_VIDEO:
+      if(!is_bmih)
+      {
+         track->format->type->video.width = track_module->es_type.video.pixel_width;
+         track->format->type->video.height = track_module->es_type.video.pixel_height;
+      }
+      track->format->type->video.visible_width = track->format->type->video.width;
+      track->format->type->video.visible_height = track->format->type->video.height;
+      if(track_module->es_type.video.pixel_crop_left < track->format->type->video.visible_width &&
+         track_module->es_type.video.pixel_crop_top < track->format->type->video.visible_height)
+      {
+         track->format->type->video.x_offset = track_module->es_type.video.pixel_crop_left;
+         track->format->type->video.y_offset = track_module->es_type.video.pixel_crop_right;
+         track->format->type->video.visible_width -= track->format->type->video.x_offset;
+         track->format->type->video.visible_height -= track->format->type->video.y_offset;
+      }
+      if(track_module->es_type.video.pixel_crop_right < track->format->type->video.visible_width &&
+         track_module->es_type.video.pixel_crop_bottom < track->format->type->video.visible_height)
+      {
+         track->format->type->video.visible_width -= track_module->es_type.video.pixel_crop_right;
+         track->format->type->video.visible_height -= track_module->es_type.video.pixel_crop_bottom;
+      }
+      if(track_module->es_type.video.frame_rate)
+      {
+         track->format->type->video.frame_rate_den = 100;
+         track->format->type->video.frame_rate_num = 100 * track_module->es_type.video.frame_rate;
+      }
+      if(track_module->es_type.video.display_width && track_module->es_type.video.display_height)
+      {
+         track->format->type->video.par_num = track_module->es_type.video.display_width *
+            track->format->type->video.visible_height;
+         track->format->type->video.par_den = track_module->es_type.video.display_height *
+            track->format->type->video.visible_width;
+         vc_container_maths_rational_simplify(&track->format->type->video.par_num,
+                                              &track->format->type->video.par_den);
+      }
+      break;
+   case VC_CONTAINER_ES_TYPE_AUDIO:
+      if(is_wf) break;
+      track->format->type->audio.sample_rate = track_module->es_type.audio.sampling_frequency;
+      if(track_module->es_type.audio.output_sampling_frequency)
+         track->format->type->audio.sample_rate = track_module->es_type.audio.output_sampling_frequency;
+      track->format->type->audio.channels = track_module->es_type.audio.channels;
+      track->format->type->audio.bits_per_sample = track_module->es_type.audio.bit_depth;
+      break;
+   default:
+   case VC_CONTAINER_ES_TYPE_SUBPICTURE:
+      track->format->type->subpicture.encoding = VC_CONTAINER_CHAR_ENCODING_UTF8;
+      if(!strcmp(track_module->codecid, "S_TEXT/ASCII"))
+         track->format->type->subpicture.encoding = VC_CONTAINER_CHAR_ENCODING_UNKNOWN;
+   }
+
+   track->is_enabled = true;
+
+   p_ctx->tracks_num++;
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+   for(i = 0; i < MKV_MAX_ENCODINGS; i++) free(track_module->encodings[i].data);
+   vc_container_free_track(p_ctx, track);
+   return status;
+}
+
+static VC_CONTAINER_STATUS_T mkv_read_subelements_track_entry( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = module->parsing;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = track->priv->module;
+   uint64_t value;
+
+   /* Deal with string elements */
+   if( id == MKV_ELEMENT_ID_NAME ||
+       id == MKV_ELEMENT_ID_LANGUAGE ||
+       id == MKV_ELEMENT_ID_TRACK_CODEC_ID ||
+       id == MKV_ELEMENT_ID_TRACK_CODEC_NAME )
+   {
+      char stringbuf[MKV_MAX_STRING_SIZE+1];
+
+      if(size > MKV_MAX_STRING_SIZE)
+      {
+         LOG_DEBUG(p_ctx, "string truncated (%i>%i)", (int)size, MKV_MAX_STRING_SIZE);
+         size = MKV_MAX_STRING_SIZE;
+      }
+      if(READ_BYTES(p_ctx, stringbuf, size) != (size_t)size)
+      {
+         //XXX do sane thing
+         return STREAM_STATUS(p_ctx);
+      }
+      stringbuf[size] = 0; /* null terminate */
+
+      LOG_FORMAT(p_ctx, "%s", stringbuf);
+
+      if(id == MKV_ELEMENT_ID_TRACK_CODEC_ID)
+         strncpy(track_module->codecid, stringbuf, MKV_CODECID_MAX-1);
+
+      return VC_CONTAINER_SUCCESS;
+   }
+
+   /* Deal with codec private data */
+   if( id == MKV_ELEMENT_ID_TRACK_CODEC_PRIVATE )
+   {
+      status = vc_container_track_allocate_extradata(p_ctx, track, (unsigned int)size);
+      if(status != VC_CONTAINER_SUCCESS) return status;
+      track->format->extradata_size = READ_BYTES(p_ctx, track->format->extradata, size);
+      return STREAM_STATUS(p_ctx);
+   }
+
+   /* The rest are just unsigned integers */
+   status = mkv_read_element_data_uint(p_ctx, size, &value);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   switch(id)
+   {
+   case MKV_ELEMENT_ID_TRACK_NUMBER:
+      track_module->number = value; break;
+   case MKV_ELEMENT_ID_TRACK_TYPE:
+      track_module->type = value; break;
+   case MKV_ELEMENT_ID_DEFAULT_DURATION:
+      track_module->frame_duration = value; break;
+   default: break;
+   }
+
+   return status;
+}
+
+static VC_CONTAINER_STATUS_T mkv_read_subelements_video( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = module->parsing->priv->module;
+   uint64_t value;
+
+   /* Deal with floating point values first */
+   if(id == MKV_ELEMENT_ID_FRAME_RATE)
+   {
+      double fvalue;
+      status = mkv_read_element_data_float(p_ctx, size, &fvalue);
+      if(status != VC_CONTAINER_SUCCESS) return status;
+      track_module->es_type.video.frame_rate = fvalue;
+      return status;
+   }
+
+   /* The rest are just unsigned integers */
+   status = mkv_read_element_data_uint(p_ctx, size, &value);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   switch(id)
+   {
+   case MKV_ELEMENT_ID_PIXEL_WIDTH: track_module->es_type.video.pixel_width = value; break;
+   case MKV_ELEMENT_ID_PIXEL_HEIGHT: track_module->es_type.video.pixel_height = value; break;
+   case MKV_ELEMENT_ID_PIXEL_CROP_BOTTOM: track_module->es_type.video.pixel_crop_bottom = value; break;
+   case MKV_ELEMENT_ID_PIXEL_CROP_TOP: track_module->es_type.video.pixel_crop_top = value; break;
+   case MKV_ELEMENT_ID_PIXEL_CROP_LEFT: track_module->es_type.video.pixel_crop_left = value; break;
+   case MKV_ELEMENT_ID_PIXEL_CROP_RIGHT: track_module->es_type.video.pixel_crop_right = value; break;
+   case MKV_ELEMENT_ID_DISPLAY_WIDTH: track_module->es_type.video.display_width = value; break;
+   case MKV_ELEMENT_ID_DISPLAY_HEIGHT: track_module->es_type.video.display_height = value; break;
+   case MKV_ELEMENT_ID_DISPLAY_UNIT: track_module->es_type.video.display_unit = value; break;
+   case MKV_ELEMENT_ID_ASPECT_RATIO_TYPE: track_module->es_type.video.aspect_ratio_type = value; break;
+   default: break;
+   }
+
+   return status;
+}
+
+static VC_CONTAINER_STATUS_T mkv_read_subelements_audio( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = module->parsing->priv->module;
+   uint64_t value;
+
+   /* Deal with floating point values first */
+   if(id == MKV_ELEMENT_ID_SAMPLING_FREQUENCY ||
+      id == MKV_ELEMENT_ID_OUTPUT_SAMPLING_FREQUENCY)
+   {
+      double fvalue;
+      status = mkv_read_element_data_float(p_ctx, size, &fvalue);
+      if(status != VC_CONTAINER_SUCCESS) return status;
+
+      if(id == MKV_ELEMENT_ID_SAMPLING_FREQUENCY)
+         track_module->es_type.audio.sampling_frequency = fvalue;
+
+      if(id == MKV_ELEMENT_ID_OUTPUT_SAMPLING_FREQUENCY)
+         track_module->es_type.audio.output_sampling_frequency = fvalue;
+   
+      return status;
+   }
+
+   /* The rest are just unsigned integers */
+   status = mkv_read_element_data_uint(p_ctx, size, &value);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   switch(id)
+   {
+   case MKV_ELEMENT_ID_CHANNELS: track_module->es_type.audio.channels = value; break;
+   case MKV_ELEMENT_ID_BIT_DEPTH: track_module->es_type.audio.bit_depth = value; break;
+   default: break;
+   }
+
+   return status;
+}
+
+static VC_CONTAINER_STATUS_T mkv_read_element_encoding( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = module->parsing->priv->module;
+   VC_CONTAINER_STATUS_T status;
+   status = mkv_read_elements(p_ctx, id, size);
+   track_module->encodings_num++;
+   return status;
+}
+
+static VC_CONTAINER_STATUS_T mkv_read_subelements_encoding( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = module->parsing->priv->module;
+   VC_CONTAINER_STATUS_T status;
+   uint64_t value;
+
+   /* These are just unsigned integers */
+   status = mkv_read_element_data_uint(p_ctx, size, &value);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   if(track_module->encodings_num >= MKV_MAX_ENCODINGS) return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+
+   switch(id)
+   {
+   case MKV_ELEMENT_ID_CONTENT_ENCODING_TYPE:
+      if(value == 0) track_module->encodings[track_module->encodings_num].type = MKV_CONTENT_ENCODING_COMPRESSION_ZLIB;
+      if(value == 1) track_module->encodings[track_module->encodings_num].type = MKV_CONTENT_ENCODING_ENCRYPTION;
+      else track_module->encodings[track_module->encodings_num].type = MKV_CONTENT_ENCODING_UNKNOWN;
+      break;
+   default: break;
+   }
+
+   return status;
+}
+
+static VC_CONTAINER_STATUS_T mkv_read_subelements_compression( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = module->parsing->priv->module;
+   VC_CONTAINER_STATUS_T status;
+   uint64_t value;
+   uint8_t *data;
+
+   if(id == MKV_ELEMENT_ID_CONTENT_COMPRESSION_ALGO)
+   {
+      status = mkv_read_element_data_uint(p_ctx, size, &value);
+      if(status != VC_CONTAINER_SUCCESS) return status;
+
+      if(value == 0) track_module->encodings[track_module->encodings_num].type = MKV_CONTENT_ENCODING_COMPRESSION_ZLIB;
+      if(value == 3) track_module->encodings[track_module->encodings_num].type = MKV_CONTENT_ENCODING_COMPRESSION_HEADER;
+      else track_module->encodings[track_module->encodings_num].type = MKV_CONTENT_ENCODING_UNKNOWN;
+      return status;
+   }
+
+   if(id == MKV_ELEMENT_ID_CONTENT_COMPRESSION_SETTINGS)
+   {
+      if(track_module->encodings[track_module->encodings_num].type == MKV_CONTENT_ENCODING_COMPRESSION_HEADER)
+      {
+         if(size > MKV_MAX_ENCODING_DATA) return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+
+         data = malloc((int)size);
+         if(!data) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+
+         track_module->encodings[track_module->encodings_num].data = data;
+         track_module->encodings[track_module->encodings_num].data_size = READ_BYTES(p_ctx, data, size);
+         if(track_module->encodings[track_module->encodings_num].data_size != size)
+            track_module->encodings[track_module->encodings_num].data_size = 0;
+         return STREAM_STATUS(p_ctx);
+      }
+      else
+      {
+         SKIP_BYTES(p_ctx, size);
+      }
+      return STREAM_STATUS(p_ctx);
+   }
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+static VC_CONTAINER_STATUS_T mkv_read_subelements_info( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   uint64_t value;
+   double fvalue;
+
+   switch(id)
+   {
+   case MKV_ELEMENT_ID_TIMECODE_SCALE:
+      status = mkv_read_element_data_uint(p_ctx, size, &value);
+      if(status != VC_CONTAINER_SUCCESS) break;
+      module->timecode_scale = value;
+      break;
+   case MKV_ELEMENT_ID_DURATION:
+      status = mkv_read_element_data_float(p_ctx, size, &fvalue);
+      if(status != VC_CONTAINER_SUCCESS) break;
+      module->duration = fvalue;
+      break;
+   case MKV_ELEMENT_ID_TITLE:
+   case MKV_ELEMENT_ID_MUXING_APP:
+   case MKV_ELEMENT_ID_WRITING_APP:
+      SKIP_STRING(p_ctx, size, "string");
+      break;
+
+   default: break;
+   }
+
+   return status;
+}
+
+static VC_CONTAINER_STATUS_T mkv_read_subelements_seek_head( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   uint64_t value;
+
+   if(id == MKV_ELEMENT_ID_SEEK)
+   {
+      module->seekhead_elem_id = MKV_ELEMENT_ID_UNKNOWN;
+      module->seekhead_elem_offset = -1;
+      status = mkv_read_elements(p_ctx, id, size);
+      if(status == VC_CONTAINER_SUCCESS && !module->cues_offset &&
+         module->seekhead_elem_id == MKV_ELEMENT_ID_CUES && module->seekhead_elem_offset)
+         module->cues_offset = module->seekhead_elem_offset;
+      if(status == VC_CONTAINER_SUCCESS && !module->tags_offset &&
+         module->seekhead_elem_id == MKV_ELEMENT_ID_TAGS && module->seekhead_elem_offset)
+         module->tags_offset = module->seekhead_elem_offset;
+      return status;
+   }
+
+   if(id == MKV_ELEMENT_ID_SEEK_ID)
+   {
+      MKV_ELEMENT_T *element = mkv_elements_list;
+      id = MKV_READ_ID(p_ctx, "Element ID");
+      module->seekhead_elem_id = id;
+
+      /* Find out which Element we are dealing with */
+      while(element->id && id != element->id) element++;
+      LOG_FORMAT(p_ctx, "element: %s (ID 0x%x)", element->psz_name, id);
+   }
+   else if(id == MKV_ELEMENT_ID_SEEK_POSITION)
+   {
+      status = mkv_read_element_data_uint(p_ctx, size, &value);
+      if(status != VC_CONTAINER_SUCCESS) return status;
+      LOG_FORMAT(p_ctx, "offset: %"PRIi64, value + module->segment_offset);
+      module->seekhead_elem_offset = value + module->segment_offset;
+   }
+
+   return status;
+}
+
+static VC_CONTAINER_STATUS_T mkv_read_element_cues( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_PARAM_UNUSED(id);
+   VC_CONTAINER_PARAM_UNUSED(size);
+   module->cues_offset = module->element_offset;
+   return VC_CONTAINER_SUCCESS;
+}
+
+static VC_CONTAINER_STATUS_T mkv_read_subelements_cue_point( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status;
+   uint64_t value;
+
+   /* All the values are unsigned integers */
+   status = mkv_read_element_data_uint(p_ctx, size, &value);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   switch(id)
+   {
+   case MKV_ELEMENT_ID_CUE_TIME:
+      module->cue_timecode = value; break;
+   case MKV_ELEMENT_ID_CUE_TRACK:
+      module->cue_track = value; break;
+   case MKV_ELEMENT_ID_CUE_CLUSTER_POSITION:
+      module->cue_cluster_offset = value; break;
+   case MKV_ELEMENT_ID_CUE_BLOCK_NUMBER:
+      module->cue_block = value; break;
+   default: break;
+   }
+
+   return status;
+}
+
+static VC_CONTAINER_STATUS_T mkv_read_subelements_cluster( VC_CONTAINER_T *p_ctx, MKV_ELEMENT_ID_T id, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status;
+   uint64_t value;
+
+   /* The rest are just unsigned integers */
+   status = mkv_read_element_data_uint(p_ctx, size, &value);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   switch(id)
+   {
+   //XXX
+   case MKV_ELEMENT_ID_TIMECODE: module->state.cluster_timecode = value; break;
+   case MKV_ELEMENT_ID_BLOCK_DURATION: module->state.frame_duration = value; break;
+   default: break;
+   }
+
+   return status;
+}
+
+/*******************************/
+
+static VC_CONTAINER_STATUS_T mkv_skip_element(VC_CONTAINER_T *p_ctx,
+      MKV_READER_STATE_T *state)
+{
+   /* Skip any trailing data from the current element */
+   int64_t skip = state->levels[state->level].offset +
+      state->levels[state->level].size - STREAM_POSITION(p_ctx);
+
+   if(skip < 0) /* Check for overruns */
+   {
+      /* Things have gone really bad here and we ended up reading past the end of the
+       * element. We could maybe try to be clever and recover by seeking back to the end
+       * of the element. However if we get there, the file is clearly corrupted so there's
+       * no guarantee it would work anyway. */
+      LOG_DEBUG(p_ctx, "%"PRIi64" bytes overrun past the end of the element", -skip);
+      return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+
+   if(skip)
+      LOG_FORMAT(p_ctx, "%"PRIi64" bytes left unread at the end of element", skip);
+
+   state->level--;
+
+   if (skip >= MKV_MAX_ELEMENT_SIZE)
+      return SEEK(p_ctx, STREAM_POSITION(p_ctx) + skip);
+   SKIP_BYTES(p_ctx, skip);
+   return STREAM_STATUS(p_ctx);
+}
+
+static VC_CONTAINER_STATUS_T mkv_find_next_element(VC_CONTAINER_T *p_ctx,
+      MKV_READER_STATE_T *state, MKV_ELEMENT_ID_T element_id)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   int64_t element_size, element_offset;
+   MKV_ELEMENT_ID_T id;
+
+   /* Skip all elements until we find the next requested element */
+   do
+   {
+      MKV_ELEMENT_T *element = mkv_cluster_elements_list;
+
+      /* Check whether we've reach the end of the parent element */
+      if(STREAM_POSITION(p_ctx) >= state->levels[state->level].offset +
+         state->levels[state->level].size)
+         return VC_CONTAINER_ERROR_NOT_FOUND;
+
+      status = mkv_read_element_header(p_ctx, INT64_C(1) << 30, &id,
+            &element_size, state->levels[state->level].id, &element);
+      element_offset = STREAM_POSITION(p_ctx);
+      if(status != VC_CONTAINER_SUCCESS) return status;
+      if(id == element_id) break;
+      if(element_id == MKV_ELEMENT_ID_BLOCKGROUP && id == MKV_ELEMENT_ID_SIMPLE_BLOCK) break;
+
+      if(element_id == MKV_ELEMENT_ID_BLOCK && id == MKV_ELEMENT_ID_REFERENCE_BLOCK)
+         state->seen_ref_block = 1;
+
+      /* Check whether we've reached the end of the parent element */
+      if(STREAM_POSITION(p_ctx) + element_size >= state->levels[state->level].offset +
+         state->levels[state->level].size)
+         return VC_CONTAINER_ERROR_NOT_FOUND;
+
+      status = mkv_read_element_data(p_ctx, element, element_size, INT64_C(1) << 30);
+#if 0
+      if(element_size < MKV_MAX_ELEMENT_SIZE) SKIP_BYTES(p_ctx, element_size);
+      else SEEK(p_ctx, STREAM_POSITION(p_ctx) + element_size);
+#endif
+   } while (status == VC_CONTAINER_SUCCESS && STREAM_STATUS(p_ctx) == VC_CONTAINER_SUCCESS);
+
+   if(STREAM_STATUS(p_ctx) != VC_CONTAINER_SUCCESS)
+      return STREAM_STATUS(p_ctx);
+
+   state->level++;
+   state->levels[state->level].offset = element_offset;
+   state->levels[state->level].size = element_size;
+   state->levels[state->level].id = id;
+   return VC_CONTAINER_SUCCESS;
+}
+
+static VC_CONTAINER_STATUS_T mkv_find_next_segment(VC_CONTAINER_T *p_ctx,
+      MKV_READER_STATE_T *state)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   int64_t element_size, element_offset;
+   MKV_ELEMENT_ID_T id;
+
+   /* Skip all elements until we find the next segment */
+   do
+   {
+      MKV_ELEMENT_T *element = mkv_cluster_elements_list;
+
+      status = mkv_read_element_header(p_ctx, INT64_C(-1), &id,
+            &element_size, MKV_ELEMENT_ID_INVALID, &element);
+
+      element_offset = STREAM_POSITION(p_ctx);
+      if(status != VC_CONTAINER_SUCCESS) return status;
+      if(id == MKV_ELEMENT_ID_SEGMENT) break;
+
+      status = mkv_read_element_data(p_ctx, element, element_size, INT64_C(-1));
+   } while (status == VC_CONTAINER_SUCCESS && STREAM_STATUS(p_ctx) == VC_CONTAINER_SUCCESS);
+
+   if(STREAM_STATUS(p_ctx) != VC_CONTAINER_SUCCESS)
+      return STREAM_STATUS(p_ctx);
+
+   state->level++;
+   state->levels[state->level].offset = element_offset;
+   state->levels[state->level].size = element_size;
+   state->levels[state->level].id = id;
+   return VC_CONTAINER_SUCCESS;
+}
+
+static VC_CONTAINER_STATUS_T mkv_find_next_block(VC_CONTAINER_T *p_ctx, MKV_READER_STATE_T *state)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_NOT_FOUND;
+
+   do
+   {
+      if(state->level < 0)
+      {
+#ifdef ENABLE_MKV_EXTRA_LOGGING
+         LOG_DEBUG(p_ctx, "find segment");
+#endif
+         status = mkv_find_next_segment(p_ctx, state);
+         if(status == VC_CONTAINER_SUCCESS)
+         {
+            LOG_ERROR(p_ctx, "multi-segment files not supported");
+            status = VC_CONTAINER_ERROR_EOS;
+            break;
+         }
+      }
+      if(state->levels[state->level].id == MKV_ELEMENT_ID_BLOCK ||
+         state->levels[state->level].id == MKV_ELEMENT_ID_SIMPLE_BLOCK)
+      {
+         status = mkv_skip_element(p_ctx, state);
+      }
+      if(state->levels[state->level].id == MKV_ELEMENT_ID_BLOCKGROUP)
+      {
+#ifdef ENABLE_MKV_EXTRA_LOGGING
+         LOG_DEBUG(p_ctx, "find block");
+#endif
+         state->seen_ref_block = 0;
+         state->frame_duration = 0;
+         status = mkv_find_next_element(p_ctx, state, MKV_ELEMENT_ID_BLOCK);
+         if(status == VC_CONTAINER_SUCCESS) break;
+
+         if(status == VC_CONTAINER_ERROR_NOT_FOUND)
+            status = mkv_skip_element(p_ctx, state);
+      }
+      if(state->levels[state->level].id == MKV_ELEMENT_ID_CLUSTER)
+      {
+#ifdef ENABLE_MKV_EXTRA_LOGGING
+         LOG_DEBUG(p_ctx, "find blockgroup or simpleblock");
+#endif
+         state->frame_duration = 0;
+         status = mkv_find_next_element(p_ctx, state, MKV_ELEMENT_ID_BLOCKGROUP);
+         if(status == VC_CONTAINER_SUCCESS &&
+            state->levels[state->level].id == MKV_ELEMENT_ID_SIMPLE_BLOCK) break;
+         if(status == VC_CONTAINER_ERROR_NOT_FOUND)
+            status = mkv_skip_element(p_ctx, state);
+      }
+      if(state->levels[state->level].id == MKV_ELEMENT_ID_SEGMENT)
+      {
+#ifdef ENABLE_MKV_EXTRA_LOGGING
+         LOG_DEBUG(p_ctx, "find cluster");
+#endif
+         status = mkv_find_next_element(p_ctx, state, MKV_ELEMENT_ID_CLUSTER);
+         if(status == VC_CONTAINER_ERROR_NOT_FOUND)
+            status = mkv_skip_element(p_ctx, state);
+      }
+
+   } while(status == VC_CONTAINER_SUCCESS && STREAM_STATUS(p_ctx) == VC_CONTAINER_SUCCESS);
+
+   return status == VC_CONTAINER_SUCCESS ? STREAM_STATUS(p_ctx) : status;
+}
+
+static VC_CONTAINER_STATUS_T mkv_read_next_frame_header(VC_CONTAINER_T *p_ctx,
+      MKV_READER_STATE_T *state, uint32_t *pi_track, uint32_t *pi_length)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = 0;
+   unsigned int i, track, flags, is_first_lace = 0;
+   int64_t size, pts;
+
+   if ((state->levels[state->level].id == MKV_ELEMENT_ID_BLOCK ||
+        state->levels[state->level].id == MKV_ELEMENT_ID_SIMPLE_BLOCK) &&
+       state->levels[state->level].data_start + state->levels[state->level].data_offset <
+          state->levels[state->level].size)
+      goto end;
+
+   status = mkv_find_next_block(p_ctx, state);
+   if (status != VC_CONTAINER_SUCCESS) return status;
+
+   /* We have a block */
+   size = state->levels[state->level].size;
+   track = MKV_READ_UINT(p_ctx, "Track Number"); LOG_FORMAT(p_ctx, "Track Number: %u", track);
+   pts = (int16_t)MKV_READ_U16(p_ctx, "Timecode");
+   flags = MKV_READ_U8(p_ctx, "Flags");
+   if(state->levels[state->level].id == MKV_ELEMENT_ID_BLOCK) flags &= 0x0F;
+
+   //TODO improve sanity checking
+   /* Sanity checking */
+   if(size < 0) return VC_CONTAINER_ERROR_CORRUPTED;
+   if(STREAM_STATUS(p_ctx)) return STREAM_STATUS(p_ctx);
+
+   for (i = 0; i < p_ctx->tracks_num; i++)
+      if (p_ctx->tracks[i]->priv->module->number == track)
+      { track_module = p_ctx->tracks[i]->priv->module; break; }
+
+   /* Finding out if we have a keyframe when dealing with an MKV_ELEMENT_ID_BLOCK is tricky */
+   if(state->levels[state->level].id == MKV_ELEMENT_ID_BLOCK &&
+      i < p_ctx->tracks_num && p_ctx->tracks[i]->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO)
+   {
+      /* The absence of a ReferenceBlock element tells us if we are a keyframe or not.
+       * The problem we have is that this element can appear before as well as after the block element.
+       * To avoid seeking to look for this element, we do some guess work. */
+      if(!state->seen_ref_block && state->level &&
+         state->levels[state->level].offset + state->levels[state->level].size >=
+            state->levels[state->level-1].offset + state->levels[state->level-1].size)
+         flags |= 0x80;
+   }
+
+   /* Take care of the lacing */
+   state->lacing_num_frames = 0;
+   if(i < p_ctx->tracks_num && (flags & 0x06))
+   {
+      unsigned int i, value = 0;
+      int32_t fs = 0;
+
+      state->lacing_num_frames = MKV_READ_U8(p_ctx, "Lacing Head");
+      state->lacing_size = 0;
+      switch((flags & 0x06)>>1)
+      {
+      case 1:  /* Xiph lacing */
+         for(i = 0; i < state->lacing_num_frames; i++, fs = 0)
+         {
+            do {
+               value = vc_container_io_read_uint8(p_ctx->priv->io);
+               fs += value; size--;
+            } while(value == 255);
+            LOG_FORMAT(p_ctx, "Frame Size: %i", (int)fs);
+            if(state->lacing_num_frames > MKV_MAX_LACING_NUM) continue;
+            state->lacing_sizes[state->lacing_num_frames-(i+1)] = fs;
+         }
+         break;
+      case 3:  /* EBML lacing */
+         for(i = 0; i < state->lacing_num_frames; i++)
+         {
+            if(!i) fs = MKV_READ_UINT(p_ctx, "Frame Size");
+            else fs += MKV_READ_SINT(p_ctx, "Frame Size");
+            LOG_FORMAT(p_ctx, "Frame Size: %i", (int)fs);
+            if(state->lacing_num_frames > MKV_MAX_LACING_NUM) continue;
+            state->lacing_sizes[state->lacing_num_frames-(i+1)] = fs;
+         }
+         break;
+      default: /* Fixed-size lacing */
+         state->lacing_size = size / (state->lacing_num_frames+1);
+         break;
+      }
+
+      /* There is a max number of laced frames we can support but after we can still give back
+       * all the other frames in 1 packet */
+      if(state->lacing_num_frames > MKV_MAX_LACING_NUM)
+         state->lacing_num_frames = MKV_MAX_LACING_NUM;
+
+      /* Sanity check the size of the frames */
+      if(size < 0) return VC_CONTAINER_ERROR_CORRUPTED;
+      if(STREAM_STATUS(p_ctx)) return STREAM_STATUS(p_ctx);
+      state->lacing_current_size = state->lacing_size;
+      if(!state->lacing_size)
+      {
+         int64_t frames_size = 0;
+         for(i = state->lacing_num_frames; i > 0; i--)
+         {
+            if(frames_size + state->lacing_sizes[i-1] > size) /* return error ? */
+               state->lacing_sizes[i-1] = size - frames_size;
+            frames_size += state->lacing_sizes[i-1];
+         }
+      }
+      state->lacing_current_size = 0;
+      state->lacing_num_frames++; /* Will be decremented further down */
+      is_first_lace = 1;
+   }
+
+   state->track = i;
+   state->pts = (state->cluster_timecode + pts) * module->timecode_scale;
+   if(track_module) state->pts *= track_module->timecode_scale;
+   state->pts /= 1000;
+   state->flags = flags;
+
+   state->frame_duration = state->frame_duration * module->timecode_scale / 1000;
+   if(state->lacing_num_frames) state->frame_duration /= state->lacing_num_frames;
+   if(!state->frame_duration && track_module)
+      state->frame_duration = track_module->frame_duration / 1000;
+
+   state->levels[state->level].data_start = STREAM_POSITION(p_ctx) -
+      state->levels[state->level].offset;
+   state->levels[state->level].data_offset = 0;
+
+   /* Deal with header stripping compression */
+   state->header_size = 0;
+   if(track_module && track_module->encodings_num)
+   {
+      state->header_size = track_module->encodings[0].data_size;
+      state->header_data = track_module->encodings[0].data;
+   }
+   state->header_size_backup = state->header_size;
+
+ end:
+   *pi_length = state->levels[state->level].size - state->levels[state->level].data_start -
+      state->levels[state->level].data_offset + state->header_size;
+   *pi_track = state->track;
+
+   /* Special case for lacing */
+   if(state->lacing_num_frames &&
+      state->levels[state->level].data_offset >= state->lacing_current_size)
+   {
+      /* We need to switch to the next lace */
+      if(--state->lacing_num_frames)
+      {
+         unsigned int lace_size = state->lacing_size;
+         if(!state->lacing_size) lace_size = state->lacing_sizes[state->lacing_num_frames-1];
+         state->lacing_current_size = lace_size;
+      }
+      state->levels[state->level].data_start += state->levels[state->level].data_offset;
+      state->levels[state->level].data_offset = 0;
+      if(!is_first_lace && state->frame_duration)
+         state->pts += state->frame_duration;
+      else if(!is_first_lace)
+         state->pts = VC_CONTAINER_TIME_UNKNOWN;
+
+      /* Deal with header stripping compression */
+      state->header_data -= (state->header_size_backup - state->header_size);
+      state->header_size = state->header_size_backup;
+   }
+   if(state->lacing_num_frames)
+      *pi_length = state->lacing_current_size - state->levels[state->level].data_offset + state->header_size;
+
+   return status == VC_CONTAINER_SUCCESS ? STREAM_STATUS(p_ctx) : status;
+}
+
+static VC_CONTAINER_STATUS_T mkv_read_frame_data(VC_CONTAINER_T *p_ctx,
+      MKV_READER_STATE_T *state, uint8_t *p_data, uint32_t *pi_length)
+{
+   uint64_t size;
+   uint32_t header_size;
+
+   size = state->levels[state->level].size - state->levels[state->level].data_start -
+      state->levels[state->level].data_offset;
+
+   /* Special case for lacing */
+   if(state->lacing_num_frames)
+   {
+      size = state->lacing_current_size - state->levels[state->level].data_offset;
+
+      if(!p_data)
+      {
+         size = SKIP_BYTES(p_ctx, size);
+         state->levels[state->level].data_offset += size;
+         return STREAM_STATUS(p_ctx);
+      }
+   }
+
+   size += state->header_size;
+
+   if(!p_data) return mkv_skip_element(p_ctx, state);
+   if(size > *pi_length) size = *pi_length;
+
+   header_size = state->header_size;
+   if(header_size)
+   {
+      if(header_size > size) header_size = size;
+      memcpy(p_data, state->header_data, header_size);
+      state->header_size -= header_size;
+      state->header_data += header_size;
+      size -= header_size;
+   }
+
+   size = READ_BYTES(p_ctx, p_data + header_size, size);
+   state->levels[state->level].data_offset += size;
+   *pi_length = size + header_size;
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************
+ Functions exported as part of the Container Module API
+ *****************************************************************************/
+
+static VC_CONTAINER_STATUS_T mkv_reader_read(VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_PACKET_T *p_packet, uint32_t flags)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *p_track = 0;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   uint32_t buffer_size = 0, track = 0, data_size;
+   MKV_READER_STATE_T *state = &module->state;
+
+   /* If a specific track has been selected, we need to use the track packet state */
+   if(flags & VC_CONTAINER_READ_FLAG_FORCE_TRACK)
+   {
+      p_track = p_ctx->tracks[p_packet->track];
+      state = p_track->priv->module->state;
+   }
+
+   /**/
+   if(state->eos) return VC_CONTAINER_ERROR_EOS;
+   if(state->corrupted) return VC_CONTAINER_ERROR_CORRUPTED;
+
+   /* Look at the next frame header */
+   status = mkv_read_next_frame_header(p_ctx, state, &track, &data_size);
+   if(status == VC_CONTAINER_ERROR_EOS) state->eos = true;
+   if(status == VC_CONTAINER_ERROR_CORRUPTED) state->corrupted = true;
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   if(track >= p_ctx->tracks_num || !p_ctx->tracks[track]->is_enabled)
+   {
+      /* Skip frame */
+      status = mkv_read_frame_data(p_ctx, state, 0, &data_size);
+      if (status != VC_CONTAINER_SUCCESS) return status;
+      return VC_CONTAINER_ERROR_CONTINUE;
+   }
+
+   if((flags & VC_CONTAINER_READ_FLAG_SKIP) && !(flags & VC_CONTAINER_READ_FLAG_INFO)) /* Skip packet */
+      return mkv_read_frame_data(p_ctx, state, 0, &data_size);
+
+   p_packet->dts = p_packet->pts = state->pts;
+   p_packet->flags = 0;
+   if(state->flags & 0x80) p_packet->flags |= VC_CONTAINER_PACKET_FLAG_KEYFRAME;
+   if(!state->levels[state->level].data_offset) p_packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
+   p_packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
+   p_packet->size = data_size;
+   p_packet->track = track;
+
+   if(flags & VC_CONTAINER_READ_FLAG_SKIP)
+      return mkv_read_frame_data(p_ctx, state, 0, &data_size );
+   else if(flags & VC_CONTAINER_READ_FLAG_INFO)
+      return VC_CONTAINER_SUCCESS;
+
+   /* Read the frame data */
+   buffer_size = p_packet->buffer_size;
+   status = mkv_read_frame_data(p_ctx, state, p_packet->data, &buffer_size);
+   if(status != VC_CONTAINER_SUCCESS)
+   {
+      /* FIXME */
+      return status;
+   }
+
+   p_packet->size = buffer_size;
+   if(buffer_size != data_size)
+      p_packet->flags &= ~VC_CONTAINER_PACKET_FLAG_FRAME_END;
+
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mkv_reader_seek(VC_CONTAINER_T *p_ctx,
+   int64_t *p_offset, VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   MKV_READER_STATE_T *state = &module->state;
+   uint64_t offset = 0, prev_offset = 0, position = STREAM_POSITION(p_ctx);
+   int64_t time_offset = 0, prev_time_offset = 0;
+   unsigned int i, video_track;
+   MKV_ELEMENT_T *element = mkv_cue_elements_list;
+   int64_t size, element_size;
+   MKV_ELEMENT_ID_T id;
+   VC_CONTAINER_PARAM_UNUSED(mode);
+   VC_CONTAINER_PARAM_UNUSED(flags);
+
+   /* Find out if we have a video track */
+   for(video_track = 0; video_track < p_ctx->tracks_num; video_track++)
+      if(p_ctx->tracks[video_track]->is_enabled &&
+         p_ctx->tracks[video_track]->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO) break;
+
+   if(!*p_offset) goto end; /* Nothing much to do */
+   if(!module->cues_offset) {status = VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION; goto error;}
+
+   /* We need to do a search in the cue list */
+   status = SEEK(p_ctx, module->cues_offset);
+   if(status != VC_CONTAINER_SUCCESS) goto error;
+
+   /* First read the header of the cues element */
+   status = mkv_read_element_header(p_ctx, INT64_C(-1) /* TODO */, &id, &element_size,
+                                    MKV_ELEMENT_ID_SEGMENT, &element);
+   if(status != VC_CONTAINER_SUCCESS || id != MKV_ELEMENT_ID_CUES) goto error;
+   size = element_size;
+
+   module->elements_list = mkv_cue_elements_list;
+   do
+   {
+      MKV_ELEMENT_T *element = mkv_cue_elements_list;
+      int64_t element_offset = STREAM_POSITION(p_ctx);
+
+      /* Exit condition for when we've scanned the whole cues list */
+      if(size <= 0)
+      {
+         if(!(flags & VC_CONTAINER_SEEK_FLAG_FORWARD))
+            break; /* Just use the last valid entry in that case */
+         status = VC_CONTAINER_ERROR_EOS;
+         goto error;
+      }
+
+      status = mkv_read_element_header(p_ctx, size, &id, &element_size,
+                                       MKV_ELEMENT_ID_CUES, &element);
+      size -= STREAM_POSITION(p_ctx) - element_offset;
+      if(status == VC_CONTAINER_SUCCESS && element->id != MKV_ELEMENT_ID_UNKNOWN)
+         status = mkv_read_element_data(p_ctx, element, element_size, size);
+
+      if(status != VC_CONTAINER_SUCCESS || element->id == MKV_ELEMENT_ID_UNKNOWN)
+      {
+         if(!(flags & VC_CONTAINER_SEEK_FLAG_FORWARD))
+            break; /* Just use the last valid entry in that case */
+         goto error;
+      }
+
+      size -= element_size;
+      if(id != MKV_ELEMENT_ID_CUE_POINT) continue;
+
+      /* Ignore cue points which don't belong to the track we want */
+      if(video_track != p_ctx->tracks_num &&
+         p_ctx->tracks[video_track]->priv->module->number != module->cue_track) continue;
+
+      time_offset = module->cue_timecode * module->timecode_scale / 1000;
+      offset = module->cue_cluster_offset;
+      LOG_DEBUG(p_ctx, "INDEX: %"PRIi64, time_offset);
+      if( time_offset > *p_offset )
+      {
+         if(!(flags & VC_CONTAINER_SEEK_FLAG_FORWARD))
+         {
+            time_offset = prev_time_offset;
+            offset = prev_offset;
+         }
+         break;
+      }
+      prev_time_offset = time_offset;
+      prev_offset = offset;
+   } while( 1 );
+   module->elements_list = mkv_elements_list;
+   *p_offset = time_offset;
+
+ end:
+   /* Try seeking to the requested position */
+   status = SEEK(p_ctx, module->segment_offset + offset);
+   if(status != VC_CONTAINER_SUCCESS && status != VC_CONTAINER_ERROR_EOS) goto error;
+
+   /* Reinitialise the state */
+   memset(state, 0, sizeof(*state));
+   state->levels[0].offset = module->segment_offset;
+   state->levels[0].size = module->segment_size;
+   state->levels[0].id = MKV_ELEMENT_ID_SEGMENT;
+   if(status == VC_CONTAINER_ERROR_EOS) state->eos = true;
+   for(i = 0; i < p_ctx->tracks_num; i++)
+   {
+      VC_CONTAINER_TRACK_T *p_track = p_ctx->tracks[i];
+      p_track->priv->module->state = state;
+   }
+
+   /* If we have a video track, we skip frames until the next keyframe */
+   for(i = 0; video_track != p_ctx->tracks_num && i < 200 /* limit search */; )
+   {
+      uint32_t track, data_size;
+      status = mkv_read_next_frame_header(p_ctx, state, &track, &data_size);
+      if(status != VC_CONTAINER_SUCCESS) break; //FIXME
+      if(track == video_track) i++;
+      if(track == video_track && (state->flags & 0x80) &&
+         state->pts >= time_offset) break;
+
+      /* Skip frame */
+      status = mkv_read_frame_data(p_ctx, state, 0, &data_size);
+   }
+
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+     /* Reset everything as it was before the seek */
+     SEEK(p_ctx, position);
+     if(status == VC_CONTAINER_SUCCESS) status = VC_CONTAINER_ERROR_FAILED;
+     return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mkv_reader_close(VC_CONTAINER_T *p_ctx)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   unsigned int i, j;
+
+   for(i = 0; i < p_ctx->tracks_num; i++)
+   {
+      for(j = 0; j < MKV_MAX_ENCODINGS; j++)
+         free(p_ctx->tracks[i]->priv->module->encodings[j].data);
+      vc_container_free_track(p_ctx, p_ctx->tracks[i]);
+   }
+   free(module);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T mkv_reader_open(VC_CONTAINER_T *p_ctx)
+{
+   VC_CONTAINER_MODULE_T *module = 0;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_INVALID;
+   uint8_t buffer[4];
+
+   // Can start with ASCII strings ????
+
+   /* Check for an EBML element */
+   if(PEEK_BYTES(p_ctx, buffer, 4) < 4 ||
+      buffer[0] != 0x1A || buffer[1] != 0x45 || buffer[2] != 0xDF || buffer[3] != 0xA3)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   /*
+    *  We are dealing with an MKV file
+    */
+
+   /* Allocate our context */
+   module = malloc(sizeof(*module));
+   if(!module) {status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error;}
+   memset(module, 0, sizeof(*module));
+   p_ctx->priv->module = module;
+   p_ctx->tracks = module->tracks;
+   module->elements_list = mkv_elements_list;
+
+   /* Read and sanity check the EBML header */
+   status = mkv_read_element(p_ctx, INT64_C(-1), MKV_ELEMENT_ID_UNKNOWN);
+   if(status != VC_CONTAINER_SUCCESS) goto error;
+   if(!module->is_doctype_valid) {status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; goto error;}
+
+   /* Read the other elements until we find the start of the data */
+   do
+   {
+      status = mkv_read_element(p_ctx, INT64_C(-1), MKV_ELEMENT_ID_UNKNOWN);
+      if(status != VC_CONTAINER_SUCCESS) break;
+
+      if(module->cluster_offset) break;
+   } while(1);
+
+   /* Bail out if we didn't find a track */
+   if(!p_ctx->tracks_num)
+   {
+      status = VC_CONTAINER_ERROR_NO_TRACK_AVAILABLE;
+      goto error;
+   }
+
+   /*
+    *  We now have all the information we really need to start playing the stream
+    */
+
+   p_ctx->priv->pf_close = mkv_reader_close;
+   p_ctx->priv->pf_read = mkv_reader_read;
+   p_ctx->priv->pf_seek = mkv_reader_seek;
+   p_ctx->duration = module->duration / 1000 * module->timecode_scale;
+
+   /* Check if we're done */
+   if(!STREAM_SEEKABLE(p_ctx))
+      return VC_CONTAINER_SUCCESS;
+
+   if(module->cues_offset && (int64_t)module->cues_offset < p_ctx->size)
+      p_ctx->capabilities |= VC_CONTAINER_CAPS_CAN_SEEK;
+
+   if(module->tags_offset)
+   {
+      status = SEEK(p_ctx, module->tags_offset);
+      if(status == VC_CONTAINER_SUCCESS)
+         status = mkv_read_element(p_ctx, INT64_C(-1) /*FIXME*/, MKV_ELEMENT_ID_SEGMENT);
+   }
+
+   /* Seek back to the start of the data */
+   return SEEK(p_ctx, module->state.levels[1].offset);
+
+ error:
+   LOG_DEBUG(p_ctx, "mkv: error opening stream (%i)", status);
+   if(module) mkv_reader_close(p_ctx);
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+ ********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak reader_open mkv_reader_open
+#endif
diff --git a/containers/mp4/CMakeLists.txt b/containers/mp4/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..87892c2
--- /dev/null
@@ -0,0 +1,19 @@
+# Container module needs to go in as a plugins so different prefix
+# and install path
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+
+# Make sure the compiler can find the necessary include files
+include_directories (../..)
+
+add_library(reader_mp4 ${LIBRARY_TYPE} mp4_reader.c)
+
+target_link_libraries(reader_mp4 containers)
+
+install(TARGETS reader_mp4 DESTINATION ${VMCS_PLUGIN_DIR})
+
+add_library(writer_mp4 ${LIBRARY_TYPE} mp4_writer.c)
+
+target_link_libraries(writer_mp4 containers)
+
+install(TARGETS writer_mp4 DESTINATION ${VMCS_PLUGIN_DIR})
+
diff --git a/containers/mp4/mp4_common.h b/containers/mp4/mp4_common.h
new file mode 100755 (executable)
index 0000000..8718535
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef MP4_COMMON_H
+#define MP4_COMMON_H
+
+/******************************************************************************
+Type definitions.
+******************************************************************************/
+typedef enum {
+   MP4_BOX_TYPE_UNKNOWN           = 0,
+   MP4_BOX_TYPE_ROOT              = VC_FOURCC('r','o','o','t'),
+   MP4_BOX_TYPE_FTYP              = VC_FOURCC('f','t','y','p'),
+   MP4_BOX_TYPE_MDAT              = VC_FOURCC('m','d','a','t'),
+   MP4_BOX_TYPE_MOOV              = VC_FOURCC('m','o','o','v'),
+   MP4_BOX_TYPE_MVHD              = VC_FOURCC('m','v','h','d'),
+   MP4_BOX_TYPE_TRAK              = VC_FOURCC('t','r','a','k'),
+   MP4_BOX_TYPE_TKHD              = VC_FOURCC('t','k','h','d'),
+   MP4_BOX_TYPE_MDIA              = VC_FOURCC('m','d','i','a'),
+   MP4_BOX_TYPE_MDHD              = VC_FOURCC('m','d','h','d'),
+   MP4_BOX_TYPE_HDLR              = VC_FOURCC('h','d','l','r'),
+   MP4_BOX_TYPE_MINF              = VC_FOURCC('m','i','n','f'),
+   MP4_BOX_TYPE_VMHD              = VC_FOURCC('v','m','h','d'),
+   MP4_BOX_TYPE_SMHD              = VC_FOURCC('s','m','h','d'),
+   MP4_BOX_TYPE_DINF              = VC_FOURCC('d','i','n','f'),
+   MP4_BOX_TYPE_DREF              = VC_FOURCC('d','r','e','f'),
+   MP4_BOX_TYPE_STBL              = VC_FOURCC('s','t','b','l'),
+   MP4_BOX_TYPE_STSD              = VC_FOURCC('s','t','s','d'),
+   MP4_BOX_TYPE_STTS              = VC_FOURCC('s','t','t','s'),
+   MP4_BOX_TYPE_CTTS              = VC_FOURCC('c','t','t','s'),
+   MP4_BOX_TYPE_STSC              = VC_FOURCC('s','t','s','c'),
+   MP4_BOX_TYPE_STSZ              = VC_FOURCC('s','t','s','z'),
+   MP4_BOX_TYPE_STCO              = VC_FOURCC('s','t','c','o'),
+   MP4_BOX_TYPE_CO64              = VC_FOURCC('c','o','6','4'),
+   MP4_BOX_TYPE_STSS              = VC_FOURCC('s','t','s','s'),
+   MP4_BOX_TYPE_VIDE              = VC_FOURCC('v','i','d','e'),
+   MP4_BOX_TYPE_SOUN              = VC_FOURCC('s','o','u','n'),
+   MP4_BOX_TYPE_TEXT              = VC_FOURCC('t','e','x','t'),
+   MP4_BOX_TYPE_FREE              = VC_FOURCC('f','r','e','e'),
+   MP4_BOX_TYPE_SKIP              = VC_FOURCC('s','k','i','p'),
+   MP4_BOX_TYPE_WIDE              = VC_FOURCC('w','i','d','e'),
+   MP4_BOX_TYPE_PNOT              = VC_FOURCC('p','m','o','t'),
+   MP4_BOX_TYPE_PICT              = VC_FOURCC('P','I','C','T'),
+   MP4_BOX_TYPE_UDTA              = VC_FOURCC('u','d','t','a'),
+   MP4_BOX_TYPE_UUID              = VC_FOURCC('u','u','i','d'),
+   MP4_BOX_TYPE_ESDS              = VC_FOURCC('e','s','d','s'),
+   MP4_BOX_TYPE_AVCC              = VC_FOURCC('a','v','c','C'),
+   MP4_BOX_TYPE_D263              = VC_FOURCC('d','2','6','3'),
+   MP4_BOX_TYPE_DAMR              = VC_FOURCC('d','a','m','r'),
+   MP4_BOX_TYPE_DAWP              = VC_FOURCC('d','a','w','p'),
+   MP4_BOX_TYPE_DEVC              = VC_FOURCC('d','e','v','c'),
+   MP4_BOX_TYPE_WAVE              = VC_FOURCC('w','a','v','e'),
+   MP4_BOX_TYPE_ZERO              = 0
+} MP4_BOX_TYPE_T;
+
+typedef enum {
+   MP4_BRAND_ISOM                 = VC_FOURCC('i','s','o','m'),
+   MP4_BRAND_MP42                 = VC_FOURCC('m','p','4','2'),
+   MP4_BRAND_3GP4                 = VC_FOURCC('3','g','p','4'),
+   MP4_BRAND_3GP5                 = VC_FOURCC('3','g','p','5'),
+   MP4_BRAND_3GP6                 = VC_FOURCC('3','g','p','6'),
+   MP4_BRAND_SKM2                 = VC_FOURCC('s','k','m','2'),
+   MP4_BRAND_SKM3                 = VC_FOURCC('s','k','m','3'),
+   MP4_BRAND_QT                   = VC_FOURCC('q','t',' ',' '),
+   MP4_BRAND_NUM
+} MP4_BRAND_T;
+
+typedef enum
+{
+   MP4_SAMPLE_TABLE_STTS = 0,  /* decoding time to sample */
+   MP4_SAMPLE_TABLE_STSZ = 1,  /* sample size */
+   MP4_SAMPLE_TABLE_STSC = 2,  /* sample to chunk */
+   MP4_SAMPLE_TABLE_STCO = 3,  /* sample to chunk-offset */
+   MP4_SAMPLE_TABLE_STSS = 4,  /* sync sample */
+   MP4_SAMPLE_TABLE_CO64 = 5,  /* sample to chunk-offset */
+   MP4_SAMPLE_TABLE_CTTS = 6,  /* composite time to sample */
+   MP4_SAMPLE_TABLE_NUM
+} MP4_SAMPLE_TABLE_T;
+
+/* Values for object_type_indication (mp4_decoder_config_descriptor)
+ * see ISO/IEC 14496-1:2001(E) section 8.6.6.2 table 8 p. 30
+ * see ISO/IEC 14496-15:2003 (draft) section 4.2.2 table 3 p. 11
+ * see SKT Spec 8.2.3 p. 107
+ * see 3GPP2 Spec v1.0 p. 22 */
+#define MP4_MPEG4_VISUAL_OBJECT_TYPE    0x20  /* visual ISO/IEC 14496-2 */
+#define MP4_MPEG4_H264_OBJECT_TYPE      0x21  /* visual ISO/IEC 14496-10 */
+#define MP4_MPEG4_H264_PS_OBJECT_TYPE   0x22  /* visual ISO/IEC 14496-10 (used for parameter ES) */
+#define MP4_MPEG4_AAC_LC_OBJECT_TYPE    0x40  /* audio ISO/IEC 14496-3 */
+#define MP4_MPEG2_SP_OBJECT_TYPE        0x60  /* visual ISO/IEC 13818-2 Simple Profile */
+#define MP4_MPEG2_MP_OBJECT_TYPE        0x61  /* visual ISO/IEC 13818-2 Main Profile */
+#define MP4_MPEG2_SNR_OBJECT_TYPE       0x62  /* visual ISO/IEC 13818-2 SNR Profile */
+#define MP4_MPEG2_AAC_LC_OBJECT_TYPE    0x67  /* audio ISO/IEC 13818-7 LowComplexity Profile */
+#define MP4_MP3_OBJECT_TYPE             0x69  /* audio ISO/IEC 13818-3 */
+#define MP4_MPEG1_VISUAL_OBJECT_TYPE    0x6A  /* visual ISO/IEC 11172-2 */
+#define MP4_MPEG1_AUDIO_OBJECT_TYPE     0x6B  /* audio ISO/IEC 11172-3 */
+#define MP4_JPEG_OBJECT_TYPE            0x6C  /* visual ISO/IEC 10918-1 */
+#define MP4_SKT_EVRC_2V1_OBJECT_TYPE    0x82  /* SKT spec V2.1 for EVRC */
+#define MP4_KTF_EVRC_OBJECT_TYPE        0xC2  /* KTF spec V1.2 for EVRC */
+#define MP4_KTF_AMR_OBJECT_TYPE         0xC4  /* KTF spec V1.2 for AMR */
+#define MP4_KTF_MP3_OBJECT_TYPE         0xC5  /* KTF spec V1.2 for MP3 */
+#define MP4_SKT_TEXT_OBJECT_TYPE        0xD0  /* SKT spec V2.2 for Text */
+#define MP4_SKT_EVRC_OBJECT_TYPE        0xD1  /* SKT spec V2.2 for EVRC */
+#define MP4_3GPP2_QCELP_OBJECT_TYPE     0xE1  /* 3GPP2 spec V1.0 for QCELP13K */
+
+#endif /* MP4_COMMON_H */
diff --git a/containers/mp4/mp4_reader.c b/containers/mp4/mp4_reader.c
new file mode 100755 (executable)
index 0000000..08341f5
--- /dev/null
@@ -0,0 +1,1879 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <string.h>
+
+/* Work-around for MSVC debugger issue */
+#define VC_CONTAINER_MODULE_T VC_CONTAINER_MODULE_MP4_READER_T
+#define VC_CONTAINER_TRACK_MODULE_T VC_CONTAINER_TRACK_MODULE_MP4_READER_T
+
+#define CONTAINER_IS_BIG_ENDIAN
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_logging.h"
+#include "containers/mp4/mp4_common.h"
+#undef CONTAINER_HELPER_LOG_INDENT
+#define CONTAINER_HELPER_LOG_INDENT(a) (a)->priv->module->box_level
+
+VC_CONTAINER_STATUS_T mp4_reader_open( VC_CONTAINER_T *p_ctx );
+
+/******************************************************************************
+TODO:
+- aspect ratio
+- itunes gapless
+- edit list
+- subpicture track
+******************************************************************************/
+
+/******************************************************************************
+Defines.
+******************************************************************************/
+#define MP4_TRACKS_MAX 16
+
+#define MP4_BOX_MIN_HEADER_SIZE 8
+#define MP4_MAX_BOX_SIZE  (1<<29) /* Does not apply to the mdat box */
+#define MP4_MAX_BOX_LEVEL 10
+
+#define MP4_MAX_SAMPLES_BATCH_SIZE (16*1024)
+
+#define MP4_SKIP_U8(ctx,n)   (size -= 1, SKIP_U8(ctx,n))
+#define MP4_SKIP_U16(ctx,n)  (size -= 2, SKIP_U16(ctx,n))
+#define MP4_SKIP_U24(ctx,n)  (size -= 3, SKIP_U24(ctx,n))
+#define MP4_SKIP_U32(ctx,n)  (size -= 4, SKIP_U32(ctx,n))
+#define MP4_SKIP_U64(ctx,n)  (size -= 8, SKIP_U64(ctx,n))
+#define MP4_READ_U8(ctx,n)   (size -= 1, READ_U8(ctx,n))
+#define MP4_READ_U16(ctx,n)  (size -= 2, READ_U16(ctx,n))
+#define MP4_READ_U24(ctx,n)  (size -= 3, READ_U24(ctx,n))
+#define MP4_READ_U32(ctx,n)  (size -= 4, READ_U32(ctx,n))
+#define MP4_READ_U64(ctx,n)  (size -= 8, READ_U64(ctx,n))
+#define MP4_READ_FOURCC(ctx,n)  (size -= 4, READ_FOURCC(ctx,n))
+#define MP4_SKIP_FOURCC(ctx,n)  (size -= 4, SKIP_FOURCC(ctx,n))
+#define MP4_READ_BYTES(ctx,buffer,sz) (size -= sz, READ_BYTES(ctx,buffer,sz))
+#define MP4_SKIP_BYTES(ctx,sz) (size -= sz, SKIP_BYTES(ctx,sz))
+#define MP4_SKIP_STRING(ctx,sz,n) (size -= sz, SKIP_STRING(ctx,sz,n))
+
+/******************************************************************************
+Type definitions.
+******************************************************************************/
+typedef struct
+{
+   VC_CONTAINER_STATUS_T status;
+
+   int64_t  duration;
+   int64_t  pts;
+   int64_t  dts;
+
+   uint32_t sample;
+   int64_t offset;
+   unsigned int sample_offset;
+   unsigned int sample_size;
+
+   uint32_t sample_duration;
+   uint32_t sample_duration_count;
+   int32_t sample_composition_offset;
+   uint32_t sample_composition_count;
+
+   uint32_t next_sync_sample;
+   bool keyframe;
+
+   uint32_t samples_per_chunk;
+   uint32_t chunks;
+   uint32_t samples_in_chunk;
+
+   struct {
+      uint32_t entry;
+   } sample_table[MP4_SAMPLE_TABLE_NUM];
+
+} MP4_READER_STATE_T;
+
+typedef struct VC_CONTAINER_TRACK_MODULE_T
+{
+   MP4_READER_STATE_T state;
+
+   int64_t timescale;
+   uint8_t object_type_indication;
+
+   uint32_t sample_size;
+   struct {
+      int64_t offset;
+      uint32_t entries;
+      uint32_t entry_size;
+   } sample_table[MP4_SAMPLE_TABLE_NUM];
+
+   uint32_t samples_batch_size;
+
+} VC_CONTAINER_TRACK_MODULE_T;
+
+typedef struct VC_CONTAINER_MODULE_T
+{
+   int64_t box_offset;
+   int box_level;
+
+   MP4_BRAND_T brand;
+
+   int64_t timescale;
+
+   VC_CONTAINER_TRACK_T *tracks[MP4_TRACKS_MAX];
+   unsigned int current_track;
+
+   bool found_moov;
+   int64_t data_offset;
+   int64_t data_size;
+
+} VC_CONTAINER_MODULE_T;
+
+/******************************************************************************
+Static functions within this file.
+******************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box( VC_CONTAINER_T *p_ctx, int64_t size, MP4_BOX_TYPE_T parent_type );
+static VC_CONTAINER_STATUS_T mp4_read_boxes( VC_CONTAINER_T *p_ctx, int64_t size, MP4_BOX_TYPE_T type );
+static VC_CONTAINER_STATUS_T mp4_read_box_ftyp( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_moov( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_mvhd( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_trak( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_tkhd( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_mdia( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_mdhd( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_hdlr( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_minf( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_vmhd( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_smhd( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_dinf( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_dref( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_stbl( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_stsd( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_stts( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_ctts( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_stsc( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_stsz( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_stco( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_co64( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_stss( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_vide( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_soun( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_text( VC_CONTAINER_T *p_ctx, int64_t size );
+
+static VC_CONTAINER_STATUS_T mp4_read_box_esds( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_vide_avcC( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_vide_d263( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_soun_damr( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_soun_dawp( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_soun_devc( VC_CONTAINER_T *p_ctx, int64_t size );
+static VC_CONTAINER_STATUS_T mp4_read_box_soun_wave( VC_CONTAINER_T *p_ctx, int64_t size );
+
+static struct {
+  const MP4_BOX_TYPE_T type;
+  VC_CONTAINER_STATUS_T (*pf_func)( VC_CONTAINER_T *, int64_t );
+  const MP4_BOX_TYPE_T parent_type;
+} mp4_box_list[] =
+{
+   {MP4_BOX_TYPE_FTYP, mp4_read_box_ftyp, MP4_BOX_TYPE_ROOT},
+   {MP4_BOX_TYPE_MDAT, 0,                 MP4_BOX_TYPE_ROOT},
+   {MP4_BOX_TYPE_MOOV, mp4_read_box_moov, MP4_BOX_TYPE_ROOT},
+   {MP4_BOX_TYPE_MVHD, mp4_read_box_mvhd, MP4_BOX_TYPE_MOOV},
+   {MP4_BOX_TYPE_TRAK, mp4_read_box_trak, MP4_BOX_TYPE_MOOV},
+   {MP4_BOX_TYPE_TKHD, mp4_read_box_tkhd, MP4_BOX_TYPE_TRAK},
+   {MP4_BOX_TYPE_MDIA, mp4_read_box_mdia, MP4_BOX_TYPE_TRAK},
+   {MP4_BOX_TYPE_MDHD, mp4_read_box_mdhd, MP4_BOX_TYPE_MDIA},
+   {MP4_BOX_TYPE_HDLR, mp4_read_box_hdlr, MP4_BOX_TYPE_MDIA},
+   {MP4_BOX_TYPE_MINF, mp4_read_box_minf, MP4_BOX_TYPE_MDIA},
+   {MP4_BOX_TYPE_VMHD, mp4_read_box_vmhd, MP4_BOX_TYPE_MINF},
+   {MP4_BOX_TYPE_SMHD, mp4_read_box_smhd, MP4_BOX_TYPE_MINF},
+   {MP4_BOX_TYPE_DINF, mp4_read_box_dinf, MP4_BOX_TYPE_MINF},
+   {MP4_BOX_TYPE_DREF, mp4_read_box_dref, MP4_BOX_TYPE_DINF},
+   {MP4_BOX_TYPE_STBL, mp4_read_box_stbl, MP4_BOX_TYPE_MINF},
+   {MP4_BOX_TYPE_STSD, mp4_read_box_stsd, MP4_BOX_TYPE_STBL},
+   {MP4_BOX_TYPE_STTS, mp4_read_box_stts, MP4_BOX_TYPE_STBL},
+   {MP4_BOX_TYPE_CTTS, mp4_read_box_ctts, MP4_BOX_TYPE_STBL},
+   {MP4_BOX_TYPE_STSC, mp4_read_box_stsc, MP4_BOX_TYPE_STBL},
+   {MP4_BOX_TYPE_STSZ, mp4_read_box_stsz, MP4_BOX_TYPE_STBL},
+   {MP4_BOX_TYPE_STCO, mp4_read_box_stco, MP4_BOX_TYPE_STBL},
+   {MP4_BOX_TYPE_CO64, mp4_read_box_co64, MP4_BOX_TYPE_STBL},
+   {MP4_BOX_TYPE_STSS, mp4_read_box_stss, MP4_BOX_TYPE_STBL},
+   {MP4_BOX_TYPE_VIDE, mp4_read_box_vide, MP4_BOX_TYPE_STSD},
+   {MP4_BOX_TYPE_SOUN, mp4_read_box_soun, MP4_BOX_TYPE_STSD},
+   {MP4_BOX_TYPE_TEXT, mp4_read_box_text, MP4_BOX_TYPE_STSD},
+
+   /* Codec specific boxes */
+   {MP4_BOX_TYPE_AVCC, mp4_read_box_vide_avcC, MP4_BOX_TYPE_VIDE},
+   {MP4_BOX_TYPE_D263, mp4_read_box_vide_d263, MP4_BOX_TYPE_VIDE},
+   {MP4_BOX_TYPE_ESDS, mp4_read_box_esds, MP4_BOX_TYPE_VIDE},
+   {MP4_BOX_TYPE_DAMR, mp4_read_box_soun_damr, MP4_BOX_TYPE_SOUN},
+   {MP4_BOX_TYPE_DAWP, mp4_read_box_soun_dawp, MP4_BOX_TYPE_SOUN},
+   {MP4_BOX_TYPE_DEVC, mp4_read_box_soun_devc, MP4_BOX_TYPE_SOUN},
+   {MP4_BOX_TYPE_WAVE, mp4_read_box_soun_wave, MP4_BOX_TYPE_SOUN},
+   {MP4_BOX_TYPE_ESDS, mp4_read_box_esds, MP4_BOX_TYPE_SOUN},
+
+   {MP4_BOX_TYPE_UNKNOWN, 0,              MP4_BOX_TYPE_UNKNOWN}
+};
+
+static struct {
+  const VC_CONTAINER_FOURCC_T type;
+  const VC_CONTAINER_FOURCC_T codec;
+  bool batch;
+} mp4_codec_mapping[] =
+{
+  {VC_FOURCC('a','v','c','1'), VC_CONTAINER_CODEC_H264, 0},
+  {VC_FOURCC('m','p','4','v'), VC_CONTAINER_CODEC_MP4V, 0},
+  {VC_FOURCC('s','2','6','3'), VC_CONTAINER_CODEC_H263, 0},
+  {VC_FOURCC('m','p','e','g'), VC_CONTAINER_CODEC_MP2V, 0},
+  {VC_FOURCC('m','j','p','a'), VC_CONTAINER_CODEC_MJPEGA, 0},
+  {VC_FOURCC('m','j','p','b'), VC_CONTAINER_CODEC_MJPEGB, 0},
+
+  {VC_FOURCC('j','p','e','g'), VC_CONTAINER_CODEC_JPEG, 0},
+
+  {VC_FOURCC('m','p','4','a'), VC_CONTAINER_CODEC_MP4A, 0},
+  {VC_FOURCC('s','a','m','r'), VC_CONTAINER_CODEC_AMRNB, 0},
+  {VC_FOURCC('s','a','w','b'), VC_CONTAINER_CODEC_AMRWB, 0},
+  {VC_FOURCC('s','a','w','p'), VC_CONTAINER_CODEC_AMRWBP, 0},
+  {VC_FOURCC('a','c','-','3'), VC_CONTAINER_CODEC_AC3, 0},
+  {VC_FOURCC('e','c','-','3'), VC_CONTAINER_CODEC_EAC3, 0},
+  {VC_FOURCC('s','e','v','c'), VC_CONTAINER_CODEC_EVRC, 0},
+  {VC_FOURCC('e','v','r','c'), VC_CONTAINER_CODEC_EVRC, 0},
+  {VC_FOURCC('s','q','c','p'), VC_CONTAINER_CODEC_QCELP, 0},
+  {VC_FOURCC('a','l','a','w'), VC_CONTAINER_CODEC_ALAW, 1},
+  {VC_FOURCC('u','l','a','w'), VC_CONTAINER_CODEC_MULAW, 1},
+  {VC_FOURCC('t','w','o','s'), VC_CONTAINER_CODEC_PCM_SIGNED_BE, 1},
+  {VC_FOURCC('s','o','w','t'), VC_CONTAINER_CODEC_PCM_SIGNED_LE, 1},
+
+  {0, 0},
+};
+static VC_CONTAINER_FOURCC_T mp4_box_type_to_codec(VC_CONTAINER_FOURCC_T type)
+{
+   int i;
+   for(i = 0; mp4_codec_mapping[i].type; i++ )
+      if(mp4_codec_mapping[i].type == type) break;
+   return mp4_codec_mapping[i].codec;
+}
+
+static bool codec_needs_batch_mode(VC_CONTAINER_FOURCC_T codec)
+{
+   int i;
+   for(i = 0; mp4_codec_mapping[i].codec; i++ )
+      if(mp4_codec_mapping[i].codec == codec) break;
+   return mp4_codec_mapping[i].batch;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_header( VC_CONTAINER_T *p_ctx, int64_t size,
+   MP4_BOX_TYPE_T *box_type, int64_t *box_size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   int64_t offset = STREAM_POSITION(p_ctx);
+
+   module->box_offset = offset;
+
+   *box_size = _READ_U32(p_ctx);
+   *box_type = _READ_FOURCC(p_ctx);
+   if(!*box_type) return VC_CONTAINER_ERROR_CORRUPTED;
+
+   if(*box_size == 1) *box_size = _READ_U64(p_ctx);
+   LOG_FORMAT(p_ctx, "- Box %4.4s, Size: %"PRIi64", Offset: %"PRIi64,
+              (const char *)box_type, *box_size, offset);
+
+   /* Sanity check the box size */
+   if(*box_size < 0 /* Shouldn't ever get that big */ ||
+      /* Only the mdat box can really be massive */
+      (*box_type != MP4_BOX_TYPE_MDAT && *box_size > MP4_MAX_BOX_SIZE))
+   {
+      LOG_DEBUG(p_ctx, "box %4.4s has an invalid size (%"PRIi64")",
+                (const char *)box_type, *box_size);
+      return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+
+#if 0
+   /* It is valid for a box to have a zero size (i.e unknown) if it is the last one */
+   if(*box_size == 0 && size >= 0) *box_size = size;
+   else if(*box_size == 0) *box_size = INT64_C(-1);
+#else
+   if(*box_size <= 0)
+   {
+      LOG_DEBUG(p_ctx, "box %4.4s has an invalid size (%"PRIi64")",
+                (const char *)box_type, *box_size);
+      return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+#endif
+
+   /* Sanity check box size against parent */
+   if(size >= 0 && *box_size > size)
+   {
+      LOG_DEBUG(p_ctx, "box %4.4s is bigger than it should (%"PRIi64" > %"PRIi64")",
+            (const char *)box_type, *box_size, size);
+      return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+
+   *box_size -= (STREAM_POSITION(p_ctx) - offset);
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_data( VC_CONTAINER_T *p_ctx,
+   MP4_BOX_TYPE_T box_type, int64_t box_size, MP4_BOX_TYPE_T parent_type )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   int64_t offset = STREAM_POSITION(p_ctx);
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   unsigned int i;
+
+   /* Check if the box is a recognised one */
+   for(i = 0; mp4_box_list[i].type; i++)
+      if(mp4_box_list[i].type == box_type &&
+         mp4_box_list[i].parent_type == parent_type) break;
+   if(mp4_box_list[i].type == MP4_BOX_TYPE_UNKNOWN)
+      for(i = 0; mp4_box_list[i].type; i++)
+         if(mp4_box_list[i].type == box_type) break;
+
+   /* Sanity check that the box has the right parent */
+   if(mp4_box_list[i].type != MP4_BOX_TYPE_UNKNOWN &&
+      mp4_box_list[i].parent_type != MP4_BOX_TYPE_UNKNOWN &&
+      parent_type != MP4_BOX_TYPE_UNKNOWN && parent_type != mp4_box_list[i].parent_type)
+   {
+      LOG_FORMAT(p_ctx, "Ignoring mis-placed box %4.4s", (const char *)&box_type);
+      goto skip;
+   }
+
+   /* Sanity check that the element isn't too deeply nested */
+   if(module->box_level >= 2 * MP4_MAX_BOX_LEVEL)
+   {
+      LOG_DEBUG(p_ctx, "box %4.4s is too deep. skipping", (const char *)&box_type);
+      goto skip;
+   }
+
+   module->box_level++;
+
+   /* Call the box specific parsing function */
+   if(mp4_box_list[i].pf_func)
+      status = mp4_box_list[i].pf_func(p_ctx, box_size);
+
+   module->box_level--;
+
+   if(status != VC_CONTAINER_SUCCESS)
+      LOG_DEBUG(p_ctx, "box %4.4s appears to be corrupted (%i)", (const char *)&box_type, status);
+
+ skip:
+   /* Skip the rest of the box */
+   box_size -= (STREAM_POSITION(p_ctx) - offset);
+   if(box_size < 0) /* Check for overruns */
+   {
+      /* Things have gone really bad here and we ended up reading past the end of the
+       * box. We could maybe try to be clever and recover by seeking back to the end
+       * of the box. However if we get there, the file is clearly corrupted so there's
+       * no guarantee it would work anyway. */
+      LOG_DEBUG(p_ctx, "%"PRIi64" bytes overrun past the end of box %4.4s",
+                -box_size, (const char *)&box_type);
+      return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+
+   if(box_size)
+      LOG_FORMAT(p_ctx, "%"PRIi64" bytes left unread in box %4.4s",
+                 box_size, (const char *)&box_type );
+
+   if(box_size < MP4_MAX_BOX_SIZE) box_size = SKIP_BYTES(p_ctx, box_size);
+   else SEEK(p_ctx, STREAM_POSITION(p_ctx) + box_size);
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box( VC_CONTAINER_T *p_ctx, int64_t size,
+   MP4_BOX_TYPE_T parent_type )
+{
+   VC_CONTAINER_STATUS_T status;
+   MP4_BOX_TYPE_T box_type;
+   int64_t box_size;
+
+   status = mp4_read_box_header( p_ctx, size, &box_type, &box_size );
+   if(status != VC_CONTAINER_SUCCESS) return status;
+   return mp4_read_box_data( p_ctx, box_type, box_size, parent_type );
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_boxes( VC_CONTAINER_T *p_ctx, int64_t size,
+   MP4_BOX_TYPE_T type)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   int64_t offset = STREAM_POSITION(p_ctx);
+   bool unknown_size = size < 0;
+
+   /* Read contained boxes */
+   module->box_level++;
+   while(status == VC_CONTAINER_SUCCESS &&
+         (unknown_size || size >= MP4_BOX_MIN_HEADER_SIZE))
+   {
+      offset = STREAM_POSITION(p_ctx);
+      status = mp4_read_box(p_ctx, size, type);
+      if(!unknown_size) size -= (STREAM_POSITION(p_ctx) - offset);
+   }
+   module->box_level--;
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_ftyp( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+
+   module->brand = MP4_READ_FOURCC(p_ctx, "major_brand");
+   MP4_SKIP_U32(p_ctx, "minor_version");
+   while(size >= 4) MP4_SKIP_FOURCC(p_ctx, "compatible_brands");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_moov( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   return mp4_read_boxes( p_ctx, size, MP4_BOX_TYPE_MOOV);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_mvhd( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   uint32_t version, i;
+   int64_t duration;
+
+   version = MP4_READ_U8(p_ctx, "version");
+   MP4_SKIP_U24(p_ctx, "flags");
+
+   if(version)
+   {
+      MP4_SKIP_U64(p_ctx, "creation_time");
+      MP4_SKIP_U64(p_ctx, "modification_time");
+      module->timescale = MP4_READ_U32(p_ctx, "timescale");
+      duration = MP4_READ_U64(p_ctx, "duration");
+   }
+   else
+   {
+      MP4_SKIP_U32(p_ctx, "creation_time");
+      MP4_SKIP_U32(p_ctx, "modification_time");
+      module->timescale = MP4_READ_U32(p_ctx, "timescale");
+      duration = MP4_READ_U32(p_ctx, "duration");
+   }
+
+   if(module->timescale)
+      p_ctx->duration = duration * 1000000 / module->timescale;
+
+   MP4_SKIP_U32(p_ctx, "rate");
+   MP4_SKIP_U16(p_ctx, "volume");
+   MP4_SKIP_U16(p_ctx, "reserved");
+   for(i = 0; i < 2; i++) MP4_SKIP_U32(p_ctx, "reserved");
+   for(i = 0; i < 9; i++) MP4_SKIP_U32(p_ctx, "matrix");
+   for(i = 0; i < 6; i++) MP4_SKIP_U32(p_ctx, "pre_defined");
+   MP4_SKIP_U32(p_ctx, "next_track_ID");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_trak( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track;
+
+   /* We have a new track. Allocate and initialise our track context */
+   if(p_ctx->tracks_num >= MP4_TRACKS_MAX) return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+   p_ctx->tracks[p_ctx->tracks_num] = track =
+      vc_container_allocate_track(p_ctx, sizeof(*p_ctx->tracks[0]->priv->module));
+   if(!track) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+
+   track->priv->module->sample_table[MP4_SAMPLE_TABLE_STTS].entry_size = 8;
+   track->priv->module->sample_table[MP4_SAMPLE_TABLE_STSZ].entry_size = 4;
+   track->priv->module->sample_table[MP4_SAMPLE_TABLE_STSC].entry_size = 12;
+   track->priv->module->sample_table[MP4_SAMPLE_TABLE_STCO].entry_size = 4;
+   track->priv->module->sample_table[MP4_SAMPLE_TABLE_STSS].entry_size = 4;
+   track->priv->module->sample_table[MP4_SAMPLE_TABLE_CO64].entry_size = 8;
+   track->priv->module->sample_table[MP4_SAMPLE_TABLE_CTTS].entry_size = 8;
+
+   status = mp4_read_boxes( p_ctx, size, MP4_BOX_TYPE_TRAK);
+
+   /* TODO: Sanity check track */
+
+   track->is_enabled = true;
+   track->format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
+   module->current_track++;
+   p_ctx->tracks_num++;
+
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_tkhd( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   uint32_t i, version;
+   int64_t duration;
+
+   version = MP4_READ_U8(p_ctx, "version");
+   MP4_SKIP_U24(p_ctx, "flags");
+
+   if(version)
+   {
+      MP4_SKIP_U64(p_ctx, "creation_time");
+      MP4_SKIP_U64(p_ctx, "modification_time");
+      MP4_SKIP_U32(p_ctx, "track_ID");
+      MP4_SKIP_U32(p_ctx, "reserved");
+      duration = MP4_READ_U64(p_ctx, "duration");
+   }
+   else
+   {
+      MP4_SKIP_U32(p_ctx, "creation_time");
+      MP4_SKIP_U32(p_ctx, "modification_time");
+      MP4_SKIP_U32(p_ctx, "track_ID");
+      MP4_SKIP_U32(p_ctx, "reserved");
+      duration = MP4_READ_U32(p_ctx, "duration");
+   }
+
+   if(module->timescale)
+      duration = duration * 1000000 / module->timescale;
+
+   for(i = 0; i < 2; i++) MP4_SKIP_U32(p_ctx, "reserved");
+   MP4_SKIP_U16(p_ctx, "layer");
+   MP4_SKIP_U16(p_ctx, "alternate_group");
+   MP4_SKIP_U16(p_ctx, "volume");
+   MP4_SKIP_U16(p_ctx, "reserved");
+   for(i = 0; i < 9; i++) MP4_SKIP_U32(p_ctx, "matrix");
+
+   MP4_SKIP_U32(p_ctx, "width");
+   MP4_SKIP_U32(p_ctx, "height");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_mdia( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   return mp4_read_boxes( p_ctx, size, MP4_BOX_TYPE_MDIA);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_mdhd( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[module->current_track]->priv->module;
+   uint32_t version, timescale;
+   int64_t duration;
+
+   version = MP4_READ_U8(p_ctx, "version");
+   MP4_SKIP_U24(p_ctx, "flags");
+
+   if(version)
+   {
+      MP4_SKIP_U64(p_ctx, "creation_time");
+      MP4_SKIP_U64(p_ctx, "modification_time");
+      timescale = MP4_READ_U32(p_ctx, "timescale");
+      duration = MP4_READ_U64(p_ctx, "duration");
+   }
+   else
+   {
+      MP4_SKIP_U32(p_ctx, "creation_time");
+      MP4_SKIP_U32(p_ctx, "modification_time");
+      timescale = MP4_READ_U32(p_ctx, "timescale");
+      duration = MP4_READ_U32(p_ctx, "duration");
+   }
+
+   if(timescale) duration = duration * 1000000 / timescale;
+   track_module->timescale = timescale;
+
+   MP4_SKIP_U16(p_ctx, "language"); /* ISO-639-2/T language code */
+   MP4_SKIP_U16(p_ctx, "pre_defined");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_hdlr( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
+   uint32_t i, fourcc, string_size;
+   VC_CONTAINER_ES_TYPE_T es_type = VC_CONTAINER_ES_TYPE_UNKNOWN;
+
+   if(size <= 24) return VC_CONTAINER_ERROR_CORRUPTED;
+
+   MP4_SKIP_U8(p_ctx, "version");
+   MP4_SKIP_U24(p_ctx, "flags");
+
+   MP4_SKIP_U32(p_ctx, "pre-defined");
+
+   fourcc = MP4_READ_FOURCC(p_ctx, "handler_type");
+   if(fourcc == MP4_BOX_TYPE_VIDE) es_type = VC_CONTAINER_ES_TYPE_VIDEO;
+   if(fourcc == MP4_BOX_TYPE_SOUN) es_type = VC_CONTAINER_ES_TYPE_AUDIO;
+   if(fourcc == MP4_BOX_TYPE_TEXT) es_type = VC_CONTAINER_ES_TYPE_SUBPICTURE;
+   track->format->es_type = es_type;
+
+   for(i = 0; i < 3; i++) MP4_SKIP_U32(p_ctx, "reserved");
+
+   string_size = size;
+   if(module->brand == MP4_BRAND_QT)
+      string_size = MP4_READ_U8(p_ctx, "string_size");
+
+   if(size < 0) return VC_CONTAINER_ERROR_CORRUPTED;
+   if(string_size > size) string_size = size;
+
+   MP4_SKIP_STRING(p_ctx, string_size, "name");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_minf( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   return mp4_read_boxes( p_ctx, size, MP4_BOX_TYPE_MINF);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_vmhd( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   MP4_SKIP_U8(p_ctx, "version");
+   MP4_SKIP_U24(p_ctx, "flags");
+
+   MP4_SKIP_U16(p_ctx, "graphicsmode");
+   MP4_SKIP_U16(p_ctx, "opcolor");
+   MP4_SKIP_U16(p_ctx, "opcolor");
+   MP4_SKIP_U16(p_ctx, "opcolor");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_smhd( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   MP4_SKIP_U8(p_ctx, "version");
+   MP4_SKIP_U24(p_ctx, "flags");
+
+   MP4_SKIP_U16(p_ctx, "balance");
+   MP4_SKIP_U16(p_ctx, "reserved");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_dinf( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   return mp4_read_boxes( p_ctx, size, MP4_BOX_TYPE_DINF);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_dref( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   MP4_SKIP_U8(p_ctx, "version");
+   MP4_SKIP_U24(p_ctx, "flags");
+
+   MP4_SKIP_U32(p_ctx, "entry_count");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_stbl( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   return mp4_read_boxes( p_ctx, size, MP4_BOX_TYPE_STBL);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_stsd( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
+   VC_CONTAINER_STATUS_T status;
+   MP4_BOX_TYPE_T box_type;
+   int64_t box_size;
+   uint32_t count;
+
+   MP4_SKIP_U8(p_ctx, "version");
+   MP4_SKIP_U24(p_ctx, "flags");
+
+   count = MP4_READ_U32(p_ctx, "entry_count");
+   if(!count) return VC_CONTAINER_ERROR_CORRUPTED;
+
+   status = mp4_read_box_header( p_ctx, size, &box_type, &box_size );
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   track->format->codec = mp4_box_type_to_codec(box_type);
+   if(!track->format->codec) track->format->codec = box_type;
+
+   if(track->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO) box_type = MP4_BOX_TYPE_VIDE;
+   if(track->format->es_type == VC_CONTAINER_ES_TYPE_AUDIO) box_type = MP4_BOX_TYPE_SOUN;
+   if(track->format->es_type == VC_CONTAINER_ES_TYPE_SUBPICTURE) box_type = MP4_BOX_TYPE_TEXT;
+   status = mp4_read_box_data( p_ctx, box_type, box_size, MP4_BOX_TYPE_STSD );
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   /* Special treatment for MPEG4 */
+   if(track->format->codec == VC_CONTAINER_CODEC_MP4A)
+   {
+      switch (track->priv->module->object_type_indication)
+      {
+      case MP4_MPEG4_AAC_LC_OBJECT_TYPE:
+      case MP4_MPEG2_AAC_LC_OBJECT_TYPE:
+         track->format->codec = VC_CONTAINER_CODEC_MP4A; break;
+      case MP4_MP3_OBJECT_TYPE:
+      case MP4_MPEG1_AUDIO_OBJECT_TYPE:
+      case MP4_KTF_MP3_OBJECT_TYPE:
+         track->format->codec = VC_CONTAINER_CODEC_MPGA; break;
+      case MP4_SKT_EVRC_2V1_OBJECT_TYPE:
+      case MP4_SKT_EVRC_OBJECT_TYPE:
+         track->format->codec = VC_CONTAINER_CODEC_EVRC; break;
+      case MP4_3GPP2_QCELP_OBJECT_TYPE:
+         track->format->codec = VC_CONTAINER_CODEC_QCELP; break;
+      default:
+         track->format->codec = VC_CONTAINER_CODEC_UNKNOWN; break;
+      }
+   }
+   else if(track->format->codec == VC_CONTAINER_CODEC_MP4V)
+   {
+      switch (track->priv->module->object_type_indication)
+      {
+      case MP4_MPEG4_VISUAL_OBJECT_TYPE:
+         track->format->codec = VC_CONTAINER_CODEC_MP4V; break;
+      case MP4_JPEG_OBJECT_TYPE:
+         track->format->codec = VC_CONTAINER_CODEC_JPEG; break;
+      case MP4_MPEG2_SP_OBJECT_TYPE:
+      case MP4_MPEG2_SNR_OBJECT_TYPE:
+      case MP4_MPEG2_AAC_LC_OBJECT_TYPE:
+      case MP4_MPEG2_MP_OBJECT_TYPE:
+         track->format->codec = VC_CONTAINER_CODEC_MP2V; break;
+      case MP4_MPEG1_VISUAL_OBJECT_TYPE:
+         track->format->codec = VC_CONTAINER_CODEC_MP1V; break;
+      default:
+         track->format->codec = VC_CONTAINER_CODEC_UNKNOWN; break;
+      }
+   }
+
+   /* For some codecs we process the samples in batches to be more efficient */
+   if(codec_needs_batch_mode(track->format->codec))
+      track->priv->module->samples_batch_size = MP4_MAX_SAMPLES_BATCH_SIZE;
+
+   /* Fix-up some of the data */
+   switch(track->format->codec)
+   {
+   case VC_CONTAINER_CODEC_ALAW:
+   case VC_CONTAINER_CODEC_MULAW:
+      track->format->type->audio.bits_per_sample = 8;
+      track->priv->module->sample_size = track->format->type->audio.channels;
+      break;
+   case VC_CONTAINER_CODEC_PCM_SIGNED_LE:
+   case VC_CONTAINER_CODEC_PCM_SIGNED_BE:
+      track->priv->module->sample_size = (track->format->type->audio.bits_per_sample + 7) /
+         8 * track->format->type->audio.channels;
+      break;
+   case VC_CONTAINER_CODEC_MP4A:
+      /* samplerate / channels is sometimes invalid so sanity check it using the codec config data */
+      if(track->format->extradata_size >= 2)
+      {
+         static unsigned int rate[] =
+         { 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+           16000, 12000, 11025, 8000, 7350 };
+         unsigned int samplerate = 0, channels = 0;
+         uint8_t *p = track->format->extradata;
+         uint32_t index = (p[0] & 7) << 1 | (p[1] >> 7);
+         if(index == 15 && track->format->extradata_size >= 5)
+         {
+            samplerate = (p[1] & 0x7f) << 17 | (p[2] << 9) | (p[3] << 1) | (p[4] >> 7);
+            channels = (p[4] >> 3) & 15;
+         }
+         else if(index < 13)
+         {
+            samplerate = rate[index];
+            channels = (p[1] >> 3) & 15;;
+         }
+
+         if(samplerate && samplerate != track->format->type->audio.sample_rate &&
+               2 * samplerate != track->format->type->audio.sample_rate)
+            track->format->type->audio.sample_rate = samplerate;
+         if(channels && channels != track->format->type->audio.channels &&
+               2 * channels != track->format->type->audio.channels)
+            track->format->type->audio.channels = channels;
+      }
+      break;
+   default: break;
+   }
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_cache_table( VC_CONTAINER_T *p_ctx, MP4_SAMPLE_TABLE_T table,
+   uint32_t entries, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[module->current_track]->priv->module;
+   uint32_t available_entries, entries_size;
+
+   if(size < 0) return VC_CONTAINER_ERROR_CORRUPTED;
+
+   track_module->sample_table[table].offset = STREAM_POSITION(p_ctx);
+   track_module->sample_table[table].entries = entries;
+
+   available_entries = size / track_module->sample_table[table].entry_size;
+   if(available_entries < entries)
+   {
+      LOG_DEBUG(p_ctx, "table has less entries than advertised (%i/%i)", available_entries, entries);
+      entries = available_entries;
+   }
+
+   entries_size = entries * track_module->sample_table[table].entry_size;
+   size = vc_container_io_cache(p_ctx->priv->io, entries_size );
+   if(size != entries_size)
+   {
+      available_entries = size / track_module->sample_table[table].entry_size;
+      LOG_DEBUG(p_ctx, "cached less table entries than advertised (%i/%i)", available_entries, entries);
+      track_module->sample_table[table].entries = available_entries;
+   }
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_stts( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   uint32_t entries;
+
+   MP4_SKIP_U8(p_ctx, "version");
+   MP4_SKIP_U24(p_ctx, "flags");
+
+   entries = MP4_READ_U32(p_ctx, "entry_count");
+   return mp4_cache_table( p_ctx, MP4_SAMPLE_TABLE_STTS, entries, size );
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_ctts( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   uint32_t entries;
+
+   MP4_SKIP_U8(p_ctx, "version");
+   MP4_SKIP_U24(p_ctx, "flags");
+
+   entries = MP4_READ_U32(p_ctx, "entry_count");
+   return mp4_cache_table( p_ctx, MP4_SAMPLE_TABLE_CTTS, entries, size );
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_stsc( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   uint32_t entries;
+
+   MP4_SKIP_U8(p_ctx, "version");
+   MP4_SKIP_U24(p_ctx, "flags");
+
+   entries = MP4_READ_U32(p_ctx, "entry_count");
+   return mp4_cache_table( p_ctx, MP4_SAMPLE_TABLE_STSC, entries, size );
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_stsz( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[module->current_track]->priv->module;
+   uint32_t entries;
+
+   MP4_SKIP_U8(p_ctx, "version");
+   MP4_SKIP_U24(p_ctx, "flags");
+
+   track_module->sample_size = READ_U32(p_ctx, "sample_size");
+   if(track_module->sample_size) return STREAM_STATUS(p_ctx);
+
+   entries = MP4_READ_U32(p_ctx, "sample_count");
+   return mp4_cache_table( p_ctx, MP4_SAMPLE_TABLE_STSZ, entries, size );
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_stco( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   uint32_t entries;
+
+   MP4_SKIP_U8(p_ctx, "version");
+   MP4_SKIP_U24(p_ctx, "flags");
+
+   entries = MP4_READ_U32(p_ctx, "entry_count");
+   return mp4_cache_table( p_ctx, MP4_SAMPLE_TABLE_STCO, entries, size );
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_co64( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   uint32_t entries;
+
+   MP4_SKIP_U8(p_ctx, "version");
+   MP4_SKIP_U24(p_ctx, "flags");
+
+   entries = MP4_READ_U32(p_ctx, "entry_count");
+   return mp4_cache_table( p_ctx, MP4_SAMPLE_TABLE_CO64, entries, size );
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_stss( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   uint32_t entries;
+
+   MP4_SKIP_U8(p_ctx, "version");
+   MP4_SKIP_U24(p_ctx, "flags");
+
+   entries = MP4_READ_U32(p_ctx, "entry_count");
+   return mp4_cache_table( p_ctx, MP4_SAMPLE_TABLE_STSS, entries, size );
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_esds_descriptor_header(VC_CONTAINER_T *p_ctx, int64_t *size,
+   uint32_t *descriptor_length, uint8_t *descriptor_type)
+{
+   uint32_t byte, length = 0;
+
+   if(*size <= 0) return VC_CONTAINER_ERROR_CORRUPTED;
+
+   *descriptor_type = _READ_U8(p_ctx);
+   (*size)--;
+
+   /* Read descriptor size */
+   while(*size)
+   {
+      byte = _READ_U8(p_ctx);
+      (*size)--;
+      length = (length << 7) | (byte&0x7F);
+      if(!(byte & 0x80)) break;
+   }
+
+   if(*size <= 0 || length > *size)
+   {
+      LOG_FORMAT(p_ctx, "esds descriptor is corrupted");
+      return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+
+   *descriptor_length = length;
+   LOG_FORMAT(p_ctx, "esds descriptor %x, size %i", *descriptor_type, *descriptor_length);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_esds( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
+   VC_CONTAINER_STATUS_T status;
+   uint32_t descriptor_length;
+   uint8_t descriptor_type;
+
+   MP4_SKIP_U8(p_ctx, "version");
+   MP4_SKIP_U24(p_ctx, "flags");
+
+   status = mp4_read_esds_descriptor_header(p_ctx, &size, &descriptor_length, &descriptor_type);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   if(descriptor_type == 0x3) /* ES descriptor */
+   {
+      uint8_t flags;
+
+      MP4_SKIP_U16(p_ctx, "es_id");
+      flags = MP4_READ_U8(p_ctx, "flags");
+
+      if(flags & 0x80) /* Stream dependence */
+         MP4_SKIP_U16(p_ctx, "depend_on_es_id");
+
+      if(flags & 0x40) /* URL */
+      {
+         uint32_t url_size = MP4_READ_U8(p_ctx, "url_size");
+         MP4_SKIP_STRING(p_ctx, url_size, "url");
+      }
+
+      if(flags & 0x20) /* OCR_stream*/
+         MP4_SKIP_U16(p_ctx, "OCR_es_id");
+
+      status = mp4_read_esds_descriptor_header(p_ctx, &size, &descriptor_length, &descriptor_type);
+      if(status != VC_CONTAINER_SUCCESS) return status;
+   }
+
+   if(descriptor_type == 0x4) /* Decoder Config descriptor */
+   {
+      track->priv->module->object_type_indication = MP4_READ_U8(p_ctx, "object_type_indication");
+      MP4_SKIP_U8(p_ctx, "stream_type");
+      MP4_SKIP_U24(p_ctx, "buffer_size_db");
+      MP4_SKIP_U32(p_ctx, "max_bitrate");
+      track->format->bitrate = MP4_READ_U32(p_ctx, "avg_bitrate");
+
+      if(size <= 0 || descriptor_length <= 13) return STREAM_STATUS(p_ctx);
+
+      status = mp4_read_esds_descriptor_header(p_ctx, &size, &descriptor_length, &descriptor_type);
+      if(status != VC_CONTAINER_SUCCESS) return status;
+      if(descriptor_type == 0x05 && descriptor_length)
+      {
+         status = vc_container_track_allocate_extradata(p_ctx, track, descriptor_length);
+         if(status != VC_CONTAINER_SUCCESS) return status;
+         track->format->extradata_size = MP4_READ_BYTES(p_ctx, track->format->extradata, descriptor_length);
+      }
+   }
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_vide( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
+   unsigned int i;
+
+   for(i = 0; i < 6; i++) MP4_SKIP_U8(p_ctx, "reserved");
+   MP4_SKIP_U16(p_ctx, "data_reference_index");
+
+   MP4_SKIP_U16(p_ctx, "pre_defined");
+   MP4_SKIP_U16(p_ctx, "reserved");
+   for(i = 0; i < 3; i++) MP4_SKIP_U32(p_ctx, "pre_defined");
+   track->format->type->video.width = MP4_READ_U16(p_ctx, "width");
+   track->format->type->video.height = MP4_READ_U16(p_ctx, "height");
+   MP4_SKIP_U32(p_ctx, "horizresolution"); /* dpi */
+   MP4_SKIP_U32(p_ctx, "vertresolution"); /* dpi */
+   MP4_SKIP_U32(p_ctx, "reserved");
+   MP4_SKIP_U16(p_ctx, "frame_count");
+   MP4_SKIP_BYTES(p_ctx, 32);
+   MP4_SKIP_U16(p_ctx, "depth");
+   MP4_SKIP_U16(p_ctx, "pre_defined");
+
+   if(size > 0)
+      return mp4_read_boxes( p_ctx, size, MP4_BOX_TYPE_VIDE );
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_vide_avcC( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
+   VC_CONTAINER_STATUS_T status;
+
+   if(track->format->codec != VC_CONTAINER_CODEC_H264 || size <= 0)
+      return VC_CONTAINER_ERROR_CORRUPTED;
+
+   track->format->codec_variant = VC_FOURCC('a','v','c','C');
+
+   status = vc_container_track_allocate_extradata(p_ctx, track, (unsigned int)size);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+   track->format->extradata_size = READ_BYTES(p_ctx, track->format->extradata, size);
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_vide_d263( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   MP4_SKIP_FOURCC(p_ctx, "vendor");
+   MP4_SKIP_U8(p_ctx, "version");
+   MP4_SKIP_U8(p_ctx, "level");
+   MP4_SKIP_U8(p_ctx, "profile");
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_soun( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
+   unsigned int i, version = 0;
+
+   for(i = 0; i < 6; i++) MP4_SKIP_U8(p_ctx, "reserved");
+   MP4_SKIP_U16(p_ctx, "data_reference_index");
+
+   version = MP4_READ_U16(p_ctx, "version");
+   MP4_SKIP_U16(p_ctx, "revision_level");
+   MP4_SKIP_U32(p_ctx, "vendor");
+
+   track->format->type->audio.channels = MP4_READ_U16(p_ctx, "channelcount");
+   track->format->type->audio.bits_per_sample = MP4_READ_U16(p_ctx, "samplesize");
+   MP4_SKIP_U16(p_ctx, "pre_defined");
+   MP4_SKIP_U16(p_ctx, "reserved");
+   track->format->type->audio.sample_rate = MP4_READ_U16(p_ctx, "samplerate");
+   MP4_SKIP_U16(p_ctx, "samplerate_fp_low");
+
+   if(version == 1)
+   {
+      MP4_SKIP_U32(p_ctx, "samples_per_packet");
+      MP4_SKIP_U32(p_ctx, "bytes_per_packet");
+      MP4_SKIP_U32(p_ctx, "bytes_per_frame");
+      MP4_SKIP_U32(p_ctx, "bytes_per_sample");
+   }
+
+   if(size > 0)
+      return mp4_read_box( p_ctx, size, MP4_BOX_TYPE_SOUN );
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_soun_damr( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
+
+   MP4_SKIP_FOURCC(p_ctx, "vendor");
+   MP4_SKIP_U8(p_ctx, "version");
+   MP4_SKIP_U8(p_ctx, "mode_set");
+   MP4_SKIP_U8(p_ctx, "mode_change_period");
+   MP4_SKIP_U8(p_ctx, "frame_per_second");
+
+   track->format->type->audio.channels = 1;
+   if(track->format->codec == VC_CONTAINER_CODEC_AMRNB)
+      track->format->type->audio.sample_rate = 8000;
+   else if(track->format->codec == VC_CONTAINER_CODEC_AMRWB)
+      track->format->type->audio.sample_rate = 16000;
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_soun_dawp( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
+
+   MP4_SKIP_FOURCC(p_ctx, "vendor");
+   MP4_SKIP_U8(p_ctx, "version");
+
+   track->format->type->audio.channels = 2;
+   track->format->type->audio.sample_rate = 16000;
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_soun_devc( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
+
+   MP4_SKIP_FOURCC(p_ctx, "vendor");
+   MP4_SKIP_U8(p_ctx, "version");
+   MP4_SKIP_U8(p_ctx, "samples_per_frame");
+
+   track->format->type->audio.channels = 1;
+   track->format->type->audio.sample_rate = 8000;
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_soun_wave( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   return mp4_read_boxes( p_ctx, size, MP4_BOX_TYPE_SOUN);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_box_text( VC_CONTAINER_T *p_ctx, int64_t size )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_PARAM_UNUSED(module);
+
+   /* TODO */if(1) return VC_CONTAINER_ERROR_FAILED;
+
+   if(size > 0)
+      return mp4_read_box( p_ctx, size, MP4_BOX_TYPE_TEXT );
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_reader_close( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   unsigned int i;
+
+   for(i = 0; i < p_ctx->tracks_num; i++)
+      vc_container_free_track(p_ctx, p_ctx->tracks[i]);
+   free(module);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+#ifdef ENABLE_MP4_READER_LOG_STATE
+static void mp4_log_state( VC_CONTAINER_T *p_ctx, MP4_READER_STATE_T *state )
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+
+   LOG_DEBUG(p_ctx, "state:");
+   LOG_DEBUG(p_ctx, "duration: %i, pts %i, dts %i", (int)state->duration,
+             (int)state->pts, (int)state->dts);
+   LOG_DEBUG(p_ctx, "sample: %i, offset %i, sample_offset %i, sample_size %i",
+             state->sample, (int)state->offset, state->sample_offset,
+             state->sample_size);
+   LOG_DEBUG(p_ctx, "sample_duration: %i, count %i",
+             state->sample_duration, state->sample_duration_count);
+   LOG_DEBUG(p_ctx, "sample_composition_offset: %i, count %i",
+             state->sample_composition_offset, state->sample_composition_count);
+   LOG_DEBUG(p_ctx, "next_sync_sample: %i, keyframe %i",
+             state->next_sync_sample, state->keyframe);
+   LOG_DEBUG(p_ctx, "samples_per_chunk: %i, chunks %i, samples_in_chunk %i",
+             state->samples_per_chunk, state->chunks, state->samples_in_chunk);
+   LOG_DEBUG(p_ctx, "MP4_SAMPLE_TABLE_STTS %i", state->sample_table[MP4_SAMPLE_TABLE_STTS].entry);
+   LOG_DEBUG(p_ctx, "MP4_SAMPLE_TABLE_STSZ %i", state->sample_table[MP4_SAMPLE_TABLE_STSZ].entry);
+   LOG_DEBUG(p_ctx, "MP4_SAMPLE_TABLE_STSC %i", state->sample_table[MP4_SAMPLE_TABLE_STSC].entry);
+   LOG_DEBUG(p_ctx, "MP4_SAMPLE_TABLE_STCO %i", state->sample_table[MP4_SAMPLE_TABLE_STCO].entry);
+   LOG_DEBUG(p_ctx, "MP4_SAMPLE_TABLE_CO64 %i", state->sample_table[MP4_SAMPLE_TABLE_CO64].entry);
+   LOG_DEBUG(p_ctx, "MP4_SAMPLE_TABLE_CTTS %i", state->sample_table[MP4_SAMPLE_TABLE_CTTS].entry);
+}
+#endif /* ENABLE_MP4_READER_LOG_STATE */
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_seek_sample_table( VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_TRACK_MODULE_T *track_module, MP4_READER_STATE_T *state,
+   MP4_SAMPLE_TABLE_T table)
+{
+   int64_t seek_offset;
+
+   /* Seek to the next entry in the table */
+   if(state->sample_table[table].entry >= track_module->sample_table[table].entries)
+      return VC_CONTAINER_ERROR_EOS;
+
+   seek_offset = track_module->sample_table[table].offset +
+      track_module->sample_table[table].entry_size * state->sample_table[table].entry;
+
+   return SEEK(p_ctx, seek_offset);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_sample_table( VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_TRACK_MODULE_T *track_module, MP4_READER_STATE_T *state,
+   MP4_SAMPLE_TABLE_T table, unsigned int seek)
+{
+   uint32_t value;
+
+   if(table == MP4_SAMPLE_TABLE_STSZ && track_module->sample_size)
+   {
+      state->sample_size = track_module->sample_size;
+      return state->status;
+   }
+
+   /* CO64 support */
+   if(table == MP4_SAMPLE_TABLE_STCO &&
+      track_module->sample_table[MP4_SAMPLE_TABLE_CO64].entries)
+      table = MP4_SAMPLE_TABLE_CO64;
+
+   /* Seek to the next entry in the table */
+   if(seek)
+   {
+      state->status = mp4_seek_sample_table( p_ctx, track_module, state, table );
+      if(state->status != VC_CONTAINER_SUCCESS) return state->status;
+   }
+
+   switch(table)
+   {
+   case MP4_SAMPLE_TABLE_STSZ:
+      state->sample_size = _READ_U32(p_ctx);
+      state->status = STREAM_STATUS(p_ctx);
+      break;
+
+   case MP4_SAMPLE_TABLE_STTS:
+      state->sample_duration_count = _READ_U32(p_ctx);
+      state->sample_duration = _READ_U32(p_ctx);
+      state->status = STREAM_STATUS(p_ctx);
+      if(state->status != VC_CONTAINER_SUCCESS) break;
+      if(!state->sample_duration_count) state->status = VC_CONTAINER_ERROR_CORRUPTED;
+      break;
+
+   case MP4_SAMPLE_TABLE_CTTS:
+      state->sample_composition_count = _READ_U32(p_ctx);
+      state->sample_composition_offset = _READ_U32(p_ctx); /* Converted to signed */
+      state->status = STREAM_STATUS(p_ctx);
+      if(state->status != VC_CONTAINER_SUCCESS) break;
+      if(!state->sample_composition_count) state->status = VC_CONTAINER_ERROR_CORRUPTED;
+      break;
+
+   case MP4_SAMPLE_TABLE_STSC:
+      state->chunks = _READ_U32(p_ctx);
+      state->samples_per_chunk = _READ_U32(p_ctx);
+      _SKIP_U32(p_ctx);
+      state->status = STREAM_STATUS(p_ctx);
+      if(state->status != VC_CONTAINER_SUCCESS) break;
+
+      if(state->sample_table[table].entry + 1 <
+         track_module->sample_table[MP4_SAMPLE_TABLE_STSC].entries) value = _READ_U32(p_ctx);
+      else value = -1;
+
+      if(!state->chunks || !state->samples_per_chunk || state->chunks >= value )
+      {state->status = VC_CONTAINER_ERROR_CORRUPTED; break;}
+      state->chunks = value - state->chunks;
+      state->samples_in_chunk = state->samples_per_chunk;
+      break;
+
+   case MP4_SAMPLE_TABLE_STCO:
+   case MP4_SAMPLE_TABLE_CO64:
+      state->offset = table == MP4_SAMPLE_TABLE_STCO ? _READ_U32(p_ctx) : _READ_U64(p_ctx);
+      state->status = STREAM_STATUS(p_ctx);
+      if(state->status != VC_CONTAINER_SUCCESS) break;
+      if(!state->offset) state->status = VC_CONTAINER_ERROR_CORRUPTED;
+      state->samples_in_chunk = state->samples_per_chunk;
+      break;
+
+   case MP4_SAMPLE_TABLE_STSS:
+      state->next_sync_sample = _READ_U32(p_ctx);
+      state->status = STREAM_STATUS(p_ctx);
+      break;
+
+   default: break;
+   }
+
+   state->sample_table[table].entry++;
+   return state->status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_sample_header( VC_CONTAINER_T *p_ctx, uint32_t track,
+   MP4_READER_STATE_T *state )
+{
+   VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[track]->priv->module;
+
+   if(state->status != VC_CONTAINER_SUCCESS) return state->status;
+
+   if(state->sample_offset < state->sample_size)
+      return state->status; /* We still have data left from the current sample */
+
+   /* Switch to the next sample */
+   state->offset += state->sample_size;
+   state->sample_offset = 0;
+   state->sample_size = 0;
+   state->sample++;
+
+   if(!state->samples_in_chunk)
+   {
+      /* We're switching to the next chunk */
+      if(!state->chunks)
+      {
+         /* Seek to the next entry in the STSC */
+         state->status = mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STSC, 1 );
+         if(state->status != VC_CONTAINER_SUCCESS) goto error;
+      }
+
+      /* Get the offset of the new chunk */
+      state->status = mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STCO, 1 );
+      if(state->status != VC_CONTAINER_SUCCESS) goto error;
+
+      state->chunks--;
+   }
+   state->samples_in_chunk--;
+
+   /* Get the new sample size */
+   state->status = mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STSZ, 1 );
+   if(state->status != VC_CONTAINER_SUCCESS) goto error;
+
+   /* Get the timestamp */
+   if(track_module->timescale)
+      state->pts = state->dts = state->duration * 1000000 / track_module->timescale;
+   if(!state->sample_duration_count)
+   {
+      state->status = mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STTS, 1 );
+      if(state->status != VC_CONTAINER_SUCCESS) goto error;
+   }
+   state->sample_duration_count--;
+
+   /* Get the composition time */
+   if(track_module->sample_table[MP4_SAMPLE_TABLE_CTTS].entries)
+   {
+      if(!state->sample_composition_count)
+      {
+         state->status = mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_CTTS, 1 );
+         if(state->status != VC_CONTAINER_SUCCESS) goto error;
+      }
+      if(track_module->timescale)
+         state->pts = (state->duration + state->sample_composition_offset) * 1000000 / track_module->timescale;
+      state->sample_composition_count--;
+   }
+   state->duration += state->sample_duration;
+
+   /* Get the keyframe flag */
+   if(state->sample_table[MP4_SAMPLE_TABLE_STSS].entry <
+         track_module->sample_table[MP4_SAMPLE_TABLE_STSS].entries &&
+      !state->next_sync_sample)
+   {
+      mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STSS, 1 );
+      state->status = VC_CONTAINER_SUCCESS; /* This isn't a critical error */
+   }
+
+   state->keyframe = 
+      track_module->sample_table[MP4_SAMPLE_TABLE_STSS].entries &&
+      state->sample == state->next_sync_sample;
+   if(state->keyframe)
+      state->next_sync_sample = 0;
+
+   /* Try to batch several samples together if requested. We'll always stop at the chunk boundary */
+   if(track_module->samples_batch_size)
+   {
+      uint32_t size = state->sample_size;
+      while(state->samples_in_chunk && size < track_module->samples_batch_size)
+      {
+         if(mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STSZ, 1 )) break;
+
+         if(!state->sample_duration_count)
+            if(mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STTS, 1 )) break;
+
+         state->sample_duration_count--;
+         state->duration += state->sample_duration;
+
+         size += state->sample_size;
+         state->samples_in_chunk--;
+         state->sample++;
+      }
+      state->sample_size = size;
+   }
+
+#ifdef ENABLE_MP4_READER_LOG_STATE
+   mp4_log_state(p_ctx, state);
+#endif
+
+ error:
+   return state->status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_read_sample_data( VC_CONTAINER_T *p_ctx, uint32_t track,
+   MP4_READER_STATE_T *state, uint8_t *data, unsigned int *data_size )
+{
+   VC_CONTAINER_STATUS_T status;
+   unsigned int size = state->sample_size - state->sample_offset;
+
+   if(state->status != VC_CONTAINER_SUCCESS) return state->status;
+
+   if(data_size && *data_size < size) size = *data_size;
+
+   if(data)
+   {
+      state->status = SEEK(p_ctx, state->offset + state->sample_offset);
+      if(state->status != VC_CONTAINER_SUCCESS) return state->status;
+
+      size = READ_BYTES(p_ctx, data, size);
+   }
+   state->sample_offset += size;
+
+   if(data_size) *data_size = size;
+   state->status = STREAM_STATUS(p_ctx);
+   if(state->status != VC_CONTAINER_SUCCESS) return state->status;
+
+   status = state->status;
+
+   /* Switch to the start of the next sample */
+   if(state->sample_offset >= state->sample_size)
+      mp4_read_sample_header(p_ctx, track, state);
+
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_reader_read( VC_CONTAINER_T *p_ctx,
+                                              VC_CONTAINER_PACKET_T *packet, uint32_t flags )
+{
+   VC_CONTAINER_TRACK_MODULE_T *track_module;
+   VC_CONTAINER_STATUS_T status;
+   MP4_READER_STATE_T *state;
+   uint32_t i, track;
+   unsigned int data_size;
+   uint8_t *data = 0;
+   int64_t offset;
+
+   /* Select the track to read from. If no specific track is requested by the caller, this
+    * will be the track to which the next bit of data in the mdat belongs to */
+   if(!(flags & VC_CONTAINER_READ_FLAG_FORCE_TRACK))
+   {
+      for(i = 0, track = 0, offset = -1; i < p_ctx->tracks_num; i++)
+      {
+         track_module = p_ctx->tracks[i]->priv->module;
+
+         /* Ignore tracks which have no more readable data */
+         if(track_module->state.status != VC_CONTAINER_SUCCESS) continue;
+
+         if(offset >= 0 && track_module->state.offset >= offset) continue;
+         offset = track_module->state.offset;
+         track = i;
+      }
+   }
+   else track = packet->track;
+
+   if(track >= p_ctx->tracks_num) return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+
+   track_module = p_ctx->tracks[track]->priv->module;
+   state = &track_module->state;
+
+   status = mp4_read_sample_header(p_ctx, track, state);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   if(!packet) /* Skip packet */
+      return mp4_read_sample_data(p_ctx, track, state, 0, 0);
+
+   packet->dts = state->dts;
+   packet->pts = state->pts;
+   packet->flags = VC_CONTAINER_PACKET_FLAG_FRAME_END;
+   if(state->keyframe) packet->flags |= VC_CONTAINER_PACKET_FLAG_KEYFRAME;
+   if(!state->sample_offset) packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
+   packet->track = track;
+   packet->frame_size = state->sample_size;
+   packet->size = state->sample_size - state->sample_offset;
+
+   if(flags & VC_CONTAINER_READ_FLAG_SKIP)
+      return mp4_read_sample_data(p_ctx, track, state, 0, 0);
+   else if((flags & VC_CONTAINER_READ_FLAG_INFO) || !packet->data)
+      return VC_CONTAINER_SUCCESS;
+
+   data = packet->data;
+   data_size = packet->buffer_size;
+
+   status = mp4_read_sample_data(p_ctx, track, state, data, &data_size);
+   if(status != VC_CONTAINER_SUCCESS)
+   {
+      /* FIXME */
+      return status;
+   }
+
+   packet->size = data_size;
+   if(state->sample_offset) //?
+      packet->flags &= ~VC_CONTAINER_PACKET_FLAG_FRAME_END;
+
+   return status;
+}
+
+/*****************************************************************************/
+static uint32_t mp4_find_sample( VC_CONTAINER_T *p_ctx, uint32_t track,
+   MP4_READER_STATE_T *state, int64_t seek_time, VC_CONTAINER_STATUS_T *p_status )
+{
+   VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[track]->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   uint32_t sample = 0, sample_duration_count;
+   int64_t sample_duration, seek_time_up = seek_time + 1;
+   unsigned int i;
+   VC_CONTAINER_PARAM_UNUSED(state);
+
+   seek_time = seek_time * track_module->timescale / 1000000;
+   /* We also need to check against the time rounded up to account for
+    * rounding errors in the timestamp (because of the timescale conversion) */
+   seek_time_up = seek_time_up * track_module->timescale / 1000000;
+
+   status = SEEK(p_ctx, track_module->sample_table[MP4_SAMPLE_TABLE_STTS].offset);
+   if(status != VC_CONTAINER_SUCCESS) goto end;
+
+   /* Find the sample which corresponds to the requested time */
+   for(i = 0; i < track_module->sample_table[MP4_SAMPLE_TABLE_STTS].entries; i++)
+   {
+      sample_duration_count = _READ_U32(p_ctx);
+      sample_duration = _READ_U32(p_ctx);
+      status = STREAM_STATUS(p_ctx);
+      if(status != VC_CONTAINER_SUCCESS) break;
+
+      if(sample_duration_count * sample_duration <= seek_time)
+      {
+         seek_time -= sample_duration_count * sample_duration;
+         seek_time_up -= sample_duration_count * sample_duration;
+         sample += sample_duration_count;
+         continue;
+      }
+      if(!sample_duration) break;
+
+      seek_time /= sample_duration;
+      seek_time_up /= sample_duration;
+      sample += MAX(seek_time, seek_time_up);
+      break;
+   }
+
+ end:
+   if(p_status) *p_status = status;
+   return sample;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_seek_track( VC_CONTAINER_T *p_ctx, uint32_t track,
+   MP4_READER_STATE_T *state, uint32_t sample )
+{
+   VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[track]->priv->module;
+   uint32_t chunk = 0, samples;
+   unsigned int i;
+
+   memset(state, 0, sizeof(*state));
+
+   /* Find the right chunk */
+   for(i = 0, samples = sample; i < track_module->sample_table[MP4_SAMPLE_TABLE_STSC].entries; i++)
+   {
+      state->status = mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STSC, 1 );
+      if(state->status != VC_CONTAINER_SUCCESS) goto error;
+
+      if(state->chunks * state->samples_per_chunk <= samples)
+      {
+         samples -= state->chunks * state->samples_per_chunk;
+         chunk += state->chunks;
+         continue;
+      }
+
+      while(samples >= state->samples_per_chunk)
+      {
+         samples -= state->samples_per_chunk;
+         state->chunks--;
+         chunk++;
+      }
+
+      state->chunks--;
+      break;
+   }
+
+   /* Get the offset of the selected chunk */
+   state->sample_table[MP4_SAMPLE_TABLE_STCO].entry = chunk;
+   state->sample_table[MP4_SAMPLE_TABLE_CO64].entry = chunk;
+   state->status = mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STCO, 1 );
+   if(state->status != VC_CONTAINER_SUCCESS) goto error;
+
+   /* Find the sample offset within the chunk */
+   state->sample_table[MP4_SAMPLE_TABLE_STSZ].entry = sample - samples;
+   for(i = 0; i < samples; i++)
+   {
+      state->status = mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STSZ, !i );
+      if(state->status != VC_CONTAINER_SUCCESS) goto error;
+      state->offset += state->sample_size;
+      state->samples_in_chunk--;
+   }
+
+   /* Get the timestamp */
+   for(i = 0, samples = sample; i < track_module->sample_table[MP4_SAMPLE_TABLE_STTS].entries; i++)
+   {
+      state->status = mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STTS, !i );
+      if(state->status != VC_CONTAINER_SUCCESS) goto error;
+
+      if(state->sample_duration_count <= samples)
+      {
+         samples -= state->sample_duration_count;
+         state->duration += state->sample_duration * state->sample_duration_count;
+         continue;
+      }
+
+      state->sample_duration_count -= samples;
+      state->duration += samples * state->sample_duration;
+      break;
+   }
+
+   /* Find the right place in the sample composition table */
+   for(i = 0, samples = sample; i < track_module->sample_table[MP4_SAMPLE_TABLE_CTTS].entries; i++)
+   {
+      state->status = mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_CTTS, !i );
+      if(state->status != VC_CONTAINER_SUCCESS) goto error;
+
+      if(state->sample_composition_count <= samples)
+      {
+         samples -= state->sample_composition_count;
+         continue;
+      }
+
+      state->sample_composition_count -= samples;
+      break;
+   }
+
+   /* Find the right place in the synchronisation table */
+   for(i = 0; i < track_module->sample_table[MP4_SAMPLE_TABLE_STSS].entries; i++)
+   {
+      state->status = mp4_read_sample_table( p_ctx, track_module, state, MP4_SAMPLE_TABLE_STSS, !i );
+      if(state->status != VC_CONTAINER_SUCCESS) goto error;
+
+      if(state->next_sync_sample >= sample + 1) break;
+   }
+
+   state->sample = sample;
+   state->sample_size = 0;
+   mp4_read_sample_header(p_ctx, track, state);
+
+ error:
+   return state->status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_reader_seek(VC_CONTAINER_T *p_ctx,
+   int64_t *offset, VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module;
+   VC_CONTAINER_STATUS_T status;
+   uint32_t i, track, sample, prev_sample, next_sample;
+   int64_t seek_time = *offset;
+   VC_CONTAINER_PARAM_UNUSED(module);
+   VC_CONTAINER_PARAM_UNUSED(mode);
+
+   /* Reset the states */
+   for(i = 0; i < p_ctx->tracks_num; i++)
+      memset(&p_ctx->tracks[i]->priv->module->state, 0, sizeof(p_ctx->tracks[i]->priv->module->state));
+
+   /* Deal with the easy case first */
+   if(!*offset)
+   {
+      /* Initialise tracks */
+      for(i = 0; i < p_ctx->tracks_num; i++)
+      {
+         /* FIXME: we should check we've got at least one success */
+        mp4_read_sample_header(p_ctx, i, &p_ctx->tracks[i]->priv->module->state);
+      }
+      return VC_CONTAINER_SUCCESS;
+   }
+
+   /* Find the first enabled video track */
+   for(track = 0; track < p_ctx->tracks_num; track++)
+      if(p_ctx->tracks[track]->is_enabled &&
+         p_ctx->tracks[track]->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO) break;
+   if(track == p_ctx->tracks_num) goto seek_time_found; /* No video track found */
+   track_module = p_ctx->tracks[track]->priv->module;
+
+   /* Find the sample number for the requested time */
+   sample = mp4_find_sample( p_ctx, track, &track_module->state, seek_time, &status );
+   if(status != VC_CONTAINER_SUCCESS) goto seek_time_found;
+
+   /* Find the closest sync sample */
+   status = mp4_seek_sample_table( p_ctx, track_module, &track_module->state, MP4_SAMPLE_TABLE_STSS );
+   if(status != VC_CONTAINER_SUCCESS) goto seek_time_found;
+   for(i = 0, prev_sample = 0, next_sample = 0;
+       i < track_module->sample_table[MP4_SAMPLE_TABLE_STSS].entries; i++)
+   {
+      next_sample = _READ_U32(p_ctx) - 1;
+      if(next_sample > sample)
+      {
+         sample = (flags & VC_CONTAINER_SEEK_FLAG_FORWARD) ? next_sample : prev_sample;
+         break;
+      }
+      prev_sample = next_sample;
+   }
+
+   /* Do the seek on this track and use its timestamp as the new seek point */
+   status = mp4_seek_track(p_ctx, track, &track_module->state, sample);
+   if(status != VC_CONTAINER_SUCCESS) goto seek_time_found;
+   seek_time = track_module->state.pts;
+
+ seek_time_found:
+
+   for(i = 0; i < p_ctx->tracks_num; i++)
+   {
+      uint32_t sample;
+      track_module = p_ctx->tracks[i]->priv->module;
+      if(track_module->state.offset) continue;
+      sample = mp4_find_sample( p_ctx, i, &track_module->state, seek_time, &status );
+      if(status != VC_CONTAINER_SUCCESS) return status; //FIXME
+
+      status = mp4_seek_track(p_ctx, i, &track_module->state, sample);
+   }
+
+   *offset = seek_time;
+   return VC_CONTAINER_SUCCESS;
+}
+
+/******************************************************************************
+Global function definitions.
+******************************************************************************/
+
+VC_CONTAINER_STATUS_T mp4_reader_open( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   VC_CONTAINER_MODULE_T *module = 0;
+   unsigned int i;
+   uint8_t h[8];
+
+   /* Check for a known box type to see if we're dealing with mp4 */
+   if( PEEK_BYTES(p_ctx, h, 8) != 8 )
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   switch(VC_FOURCC(h[4],h[5],h[6],h[7]))
+   {
+   case MP4_BOX_TYPE_FTYP:
+   case MP4_BOX_TYPE_MDAT:
+   case MP4_BOX_TYPE_MOOV:
+   case MP4_BOX_TYPE_FREE:
+   case MP4_BOX_TYPE_SKIP:
+   case MP4_BOX_TYPE_WIDE:
+   case MP4_BOX_TYPE_PNOT:
+   case MP4_BOX_TYPE_PICT:
+   case MP4_BOX_TYPE_UDTA:
+   case MP4_BOX_TYPE_UUID:
+      break;
+   default:
+      /* Couldn't recognize the box type. This doesn't look like an mp4. */
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   }
+
+   /*
+    *  We are dealing with an MP4 file
+    */
+
+   LOG_DEBUG(p_ctx, "using mp4 reader");
+
+   /* Allocate our context */
+   module = malloc(sizeof(*module));
+   if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(module, 0, sizeof(*module));
+   p_ctx->priv->module = module;
+   p_ctx->tracks = module->tracks;
+
+   while(STREAM_STATUS(p_ctx) == VC_CONTAINER_SUCCESS)
+   {
+      MP4_BOX_TYPE_T box_type;
+      int64_t box_size;
+
+      status = mp4_read_box_header( p_ctx, INT64_C(-1), &box_type, &box_size );
+      if(status != VC_CONTAINER_SUCCESS) goto error;
+
+      if(box_type == MP4_BOX_TYPE_MDAT)
+      {
+         module->data_offset = STREAM_POSITION(p_ctx);
+         module->data_size = box_size;
+         if(module->found_moov) break; /* We've got everything we want */
+      }
+      else if(box_type == MP4_BOX_TYPE_MOOV)
+         module->found_moov = true;
+
+      status = mp4_read_box_data( p_ctx, box_type, box_size, MP4_BOX_TYPE_ROOT );
+      if(status != VC_CONTAINER_SUCCESS) goto error;
+
+      if(module->found_moov && module->data_offset) break; /* We've got everything we want */
+   }
+
+   /* Initialise tracks */
+   for(i = 0; i < p_ctx->tracks_num; i++)
+   {
+      /* FIXME: we should check we've got at least one success */
+      status = mp4_read_sample_header(p_ctx, i, &p_ctx->tracks[i]->priv->module->state);
+   }
+
+   status = SEEK(p_ctx, module->data_offset);
+   if(status != VC_CONTAINER_SUCCESS) goto error;
+
+   p_ctx->priv->pf_close = mp4_reader_close;
+   p_ctx->priv->pf_read = mp4_reader_read;
+   p_ctx->priv->pf_seek = mp4_reader_seek;
+
+   if(STREAM_SEEKABLE(p_ctx))
+      p_ctx->capabilities |= VC_CONTAINER_CAPS_CAN_SEEK;
+
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+   LOG_DEBUG(p_ctx, "mp4: error opening stream");
+   if(module) mp4_reader_close(p_ctx);
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+ ********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak reader_open mp4_reader_open
+#endif
diff --git a/containers/mp4/mp4_writer.c b/containers/mp4/mp4_writer.c
new file mode 100755 (executable)
index 0000000..5b33e01
--- /dev/null
@@ -0,0 +1,1441 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <string.h>
+
+#define CONTAINER_IS_BIG_ENDIAN
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_writer_utils.h"
+#include "containers/core/containers_logging.h"
+#include "containers/mp4/mp4_common.h"
+#undef CONTAINER_HELPER_LOG_INDENT
+#define CONTAINER_HELPER_LOG_INDENT(a) (a)->priv->module->box_level
+
+VC_CONTAINER_STATUS_T mp4_writer_open( VC_CONTAINER_T *p_ctx );
+
+/******************************************************************************
+Defines.
+******************************************************************************/
+#define MP4_TRACKS_MAX 16
+#define MP4_TIMESCALE 1000
+
+#define MP4_64BITS_TIME 0 /* 0 to disable / 1 to enable */
+
+/******************************************************************************
+Type definitions.
+******************************************************************************/
+typedef struct VC_CONTAINER_TRACK_MODULE_T
+{
+   uint32_t fourcc;
+   uint32_t samples;
+   uint32_t chunks;
+
+   int64_t offset;
+   int64_t timestamp;
+   int64_t delta_timestamp;
+   int64_t samples_in_chunk;
+   int64_t samples_in_prev_chunk;
+   struct {
+      uint32_t entries;
+      uint32_t entry_size;
+   } sample_table[MP4_SAMPLE_TABLE_NUM];
+
+   int64_t first_pts;
+   int64_t last_pts;
+
+} VC_CONTAINER_TRACK_MODULE_T;
+
+typedef struct VC_CONTAINER_MODULE_T
+{
+   int box_level;
+   MP4_BRAND_T brand;
+
+   VC_CONTAINER_TRACK_T *tracks[MP4_TRACKS_MAX];
+   bool tracks_add_done;
+
+   VC_CONTAINER_WRITER_EXTRAIO_T null;
+
+   unsigned int current_track;
+
+   unsigned moov_size;
+   int64_t mdat_offset;
+   int64_t data_offset;
+
+   uint32_t samples;
+   VC_CONTAINER_WRITER_EXTRAIO_T temp;
+   VC_CONTAINER_PACKET_T sample;
+   int64_t sample_offset;
+   int64_t prev_sample_dts;
+
+   int64_t duration;
+   /**/
+
+} VC_CONTAINER_MODULE_T;
+
+/******************************************************************************
+Static functions within this file.
+******************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_extended( VC_CONTAINER_T *p_ctx, MP4_BOX_TYPE_T box_type, uint32_t fourcc );
+static VC_CONTAINER_STATUS_T mp4_write_box( VC_CONTAINER_T *p_ctx, MP4_BOX_TYPE_T box_type );
+static VC_CONTAINER_STATUS_T mp4_write_box_ftyp( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_moov( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_mvhd( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_trak( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_tkhd( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_mdia( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_mdhd( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_hdlr( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_minf( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_vmhd( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_smhd( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_dinf( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_dref( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_stbl( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_stsd( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_stts( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_ctts( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_stsc( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_stsz( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_stco( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_co64( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_stss( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_vide( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_soun( VC_CONTAINER_T *p_ctx );
+static VC_CONTAINER_STATUS_T mp4_write_box_esds( VC_CONTAINER_T *p_ctx );
+
+static struct {
+  const MP4_BOX_TYPE_T type;
+  VC_CONTAINER_STATUS_T (*pf_func)( VC_CONTAINER_T * );
+} mp4_box_list[] =
+{
+   {MP4_BOX_TYPE_FTYP, mp4_write_box_ftyp},
+   {MP4_BOX_TYPE_MOOV, mp4_write_box_moov},
+   {MP4_BOX_TYPE_MVHD, mp4_write_box_mvhd},
+   {MP4_BOX_TYPE_TRAK, mp4_write_box_trak},
+   {MP4_BOX_TYPE_TKHD, mp4_write_box_tkhd},
+   {MP4_BOX_TYPE_MDIA, mp4_write_box_mdia},
+   {MP4_BOX_TYPE_MDHD, mp4_write_box_mdhd},
+   {MP4_BOX_TYPE_HDLR, mp4_write_box_hdlr},
+   {MP4_BOX_TYPE_MINF, mp4_write_box_minf},
+   {MP4_BOX_TYPE_VMHD, mp4_write_box_vmhd},
+   {MP4_BOX_TYPE_SMHD, mp4_write_box_smhd},
+   {MP4_BOX_TYPE_DINF, mp4_write_box_dinf},
+   {MP4_BOX_TYPE_DREF, mp4_write_box_dref},
+   {MP4_BOX_TYPE_STBL, mp4_write_box_stbl},
+   {MP4_BOX_TYPE_STSD, mp4_write_box_stsd},
+   {MP4_BOX_TYPE_STTS, mp4_write_box_stts},
+   {MP4_BOX_TYPE_CTTS, mp4_write_box_ctts},
+   {MP4_BOX_TYPE_STSC, mp4_write_box_stsc},
+   {MP4_BOX_TYPE_STSZ, mp4_write_box_stsz},
+   {MP4_BOX_TYPE_STCO, mp4_write_box_stco},
+   {MP4_BOX_TYPE_CO64, mp4_write_box_co64},
+   {MP4_BOX_TYPE_STSS, mp4_write_box_stss},
+   {MP4_BOX_TYPE_VIDE, mp4_write_box_vide},
+   {MP4_BOX_TYPE_SOUN, mp4_write_box_soun},
+   {MP4_BOX_TYPE_ESDS, mp4_write_box_esds},
+   {MP4_BOX_TYPE_UNKNOWN, 0}
+};
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_extended( VC_CONTAINER_T *p_ctx, MP4_BOX_TYPE_T type, uint32_t fourcc )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   int64_t box_size = 0;
+   unsigned int i;
+
+   /* Find out which object we want to write */
+   for( i = 0; mp4_box_list[i].type && mp4_box_list[i].type != type; i++ );
+
+   /* Check we found the requested type */
+   if(!mp4_box_list[i].type)
+   {
+      vc_container_assert(0);
+      return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+
+   /* We need to find out the size of the object we're going to write it. */
+   if(!vc_container_writer_extraio_enable(p_ctx, &module->null))
+   {
+      status = mp4_write_box_extended( p_ctx, type, fourcc );
+      box_size = STREAM_POSITION(p_ctx);
+   }
+   vc_container_writer_extraio_disable(p_ctx, &module->null);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   /* Write the object header */
+   LOG_FORMAT(p_ctx, "- Box %4.4s, size: %"PRIi64, (const char *)&fourcc, box_size);
+   _WRITE_U32(p_ctx, (uint32_t)box_size);
+   _WRITE_FOURCC(p_ctx, fourcc);
+
+   module->box_level++;
+
+   /* Call the object specific writing function */
+   status = mp4_box_list[i].pf_func(p_ctx);
+
+   module->box_level--;
+
+   if(status != VC_CONTAINER_SUCCESS)
+      LOG_DEBUG(p_ctx, "box %4.4s appears to be corrupted", (char *)mp4_box_list[i].type);
+
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box( VC_CONTAINER_T *p_ctx, MP4_BOX_TYPE_T type )
+{
+   return mp4_write_box_extended( p_ctx, type, type );
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_ftyp( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+
+   WRITE_FOURCC(p_ctx, module->brand, "major_brand");
+   WRITE_U32(p_ctx, 512, "minor_version");
+   if(module->brand == MP4_BRAND_QT)
+   {
+      WRITE_FOURCC(p_ctx, MP4_BRAND_QT, "compatible_brands");
+      return STREAM_STATUS(p_ctx);
+   }
+
+   if(module->brand == MP4_BRAND_SKM2)
+      WRITE_FOURCC(p_ctx, MP4_BRAND_SKM2, "compatible_brands");
+   WRITE_FOURCC(p_ctx, MP4_BRAND_ISOM, "compatible_brands");
+   WRITE_FOURCC(p_ctx, MP4_BRAND_MP42, "compatible_brands");
+   WRITE_FOURCC(p_ctx, MP4_BRAND_3GP4, "compatible_brands");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_moov( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   unsigned int i;
+
+   status = mp4_write_box(p_ctx, MP4_BOX_TYPE_MVHD);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   for(i = 0; i < p_ctx->tracks_num; i++)
+   {
+      module->current_track = i;
+      status = mp4_write_box(p_ctx, MP4_BOX_TYPE_TRAK);
+      if(status != VC_CONTAINER_SUCCESS) return status;
+   }
+
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_mvhd( VC_CONTAINER_T *p_ctx )
+{
+   static uint32_t matrix[] = { 0x10000,0,0,0,0x10000,0,0,0,0x40000000 };
+   unsigned int version = MP4_64BITS_TIME;
+   unsigned int i;
+
+   WRITE_U8(p_ctx,  version, "version");
+   WRITE_U24(p_ctx, 0, "flags");
+
+   /**/
+   p_ctx->duration = 0;
+   for(i = 0; i < p_ctx->tracks_num; i++)
+   {
+      VC_CONTAINER_TRACK_T *track = p_ctx->tracks[i];
+      VC_CONTAINER_TRACK_MODULE_T *track_module = track->priv->module;
+      int64_t track_duration = track_module->last_pts - track_module->first_pts;
+      if(track_duration > p_ctx->duration)
+         p_ctx->duration = track_duration;
+   }
+
+   if(version)
+   {
+      WRITE_U64(p_ctx, 0, "creation_time");
+      WRITE_U64(p_ctx, 0, "modification_time");
+      WRITE_U32(p_ctx, MP4_TIMESCALE, "timescale");
+      WRITE_U64(p_ctx, p_ctx->duration * MP4_TIMESCALE / 1000000, "duration");
+   }
+   else
+   {
+      WRITE_U32(p_ctx, 0, "creation_time");
+      WRITE_U32(p_ctx, 0, "modification_time");
+      WRITE_U32(p_ctx, MP4_TIMESCALE, "timescale");
+      WRITE_U32(p_ctx, p_ctx->duration * MP4_TIMESCALE / 1000000, "duration");
+   }
+
+   WRITE_U32(p_ctx, 0x10000, "rate"); /* 1.0 */
+   WRITE_U16(p_ctx, 0x100, "volume"); /* full volume */
+   WRITE_U16(p_ctx, 0, "reserved");
+   for(i = 0; i < 2; i++)
+      WRITE_U32(p_ctx, 0, "reserved");
+   for(i = 0; i < 9; i++) /* unity matrix */
+      WRITE_U32(p_ctx, matrix[i], "matrix");
+   for(i = 0; i < 6; i++)
+      WRITE_U32(p_ctx, 0, "pre_defined");
+   WRITE_U32(p_ctx, p_ctx->tracks_num + 1, "next_track_ID");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_trak( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_STATUS_T status;
+
+   status = mp4_write_box(p_ctx, MP4_BOX_TYPE_TKHD);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   status = mp4_write_box(p_ctx, MP4_BOX_TYPE_MDIA);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_tkhd( VC_CONTAINER_T *p_ctx )
+{
+   static uint32_t matrix[] = { 0x10000,0,0,0,0x10000,0,0,0,0x40000000 };
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
+   unsigned int version = MP4_64BITS_TIME;
+   uint32_t i, width = 0, height = 0;
+
+   WRITE_U8(p_ctx,  version, "version");
+   WRITE_U24(p_ctx, 0x7, "flags"); /* track enabled */
+
+   if(version)
+   {
+      WRITE_U64(p_ctx, 0, "creation_time");
+      WRITE_U64(p_ctx, 0, "modification_time");
+      WRITE_U32(p_ctx, module->current_track + 1, "track_ID");
+      WRITE_U32(p_ctx, 0, "reserved");
+      WRITE_U64(p_ctx, p_ctx->duration * MP4_TIMESCALE / 1000000, "duration");
+   }
+   else
+   {
+      WRITE_U32(p_ctx, 0, "creation_time");
+      WRITE_U32(p_ctx, 0, "modification_time");
+      WRITE_U32(p_ctx, module->current_track + 1, "track_ID");
+      WRITE_U32(p_ctx, 0, "reserved");
+      WRITE_U32(p_ctx, p_ctx->duration * MP4_TIMESCALE / 1000000, "duration");
+   }
+
+   for(i = 0; i < 2; i++)
+      WRITE_U32(p_ctx, 0, "reserved");
+   WRITE_U16(p_ctx, 0, "layer");
+   WRITE_U16(p_ctx, 0, "alternate_group");
+   WRITE_U16(p_ctx, track->format->es_type == VC_CONTAINER_ES_TYPE_AUDIO ? 0x100 : 0, "volume");
+   WRITE_U16(p_ctx, 0, "reserved");
+   for(i = 0; i < 9; i++) /* unity matrix */
+      WRITE_U32(p_ctx, matrix[i], "matrix");
+
+   if(track->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO)
+   {
+      width = track->format->type->video.width << 16;
+      height = track->format->type->video.height << 16;
+      if(track->format->type->video.par_num && track->format->type->video.par_den)
+         width = width * (uint64_t)track->format->type->video.par_num /
+            track->format->type->video.par_den;
+   }
+   else if(track->format->es_type == VC_CONTAINER_ES_TYPE_SUBPICTURE)
+   {
+      /* FIXME */
+   }
+
+   WRITE_U32(p_ctx, width, "width");
+   WRITE_U32(p_ctx, height, "height");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_mdia( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+
+   status = mp4_write_box(p_ctx, MP4_BOX_TYPE_MDHD);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   status = mp4_write_box(p_ctx, MP4_BOX_TYPE_HDLR);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   status = mp4_write_box(p_ctx, MP4_BOX_TYPE_MINF);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_mdhd( VC_CONTAINER_T *p_ctx )
+{
+   unsigned int version = MP4_64BITS_TIME;
+
+   WRITE_U8(p_ctx,  version, "version");
+   WRITE_U24(p_ctx, 0, "flags");
+
+   // FIXME: take a better timescale ??
+   if(version)
+   {
+      WRITE_U64(p_ctx, 0, "creation_time");
+      WRITE_U64(p_ctx, 0, "modification_time");
+      WRITE_U32(p_ctx, MP4_TIMESCALE, "timescale");
+      WRITE_U64(p_ctx, p_ctx->duration * MP4_TIMESCALE / 1000000, "duration");
+   }
+   else
+   {
+      WRITE_U32(p_ctx, 0, "creation_time");
+      WRITE_U32(p_ctx, 0, "modification_time");
+      WRITE_U32(p_ctx, MP4_TIMESCALE, "timescale");
+      WRITE_U32(p_ctx, p_ctx->duration * MP4_TIMESCALE / 1000000, "duration");
+   }
+
+   WRITE_U16(p_ctx, 0x55c4, "language"); /* ISO-639-2/T language code */
+   WRITE_U16(p_ctx, 0, "pre_defined");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_hdlr( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
+   uint32_t i, handler_size, fourcc = 0;
+   const char *handler_name;
+
+   if(track->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO) fourcc = VC_FOURCC('v','i','d','e');
+   if(track->format->es_type == VC_CONTAINER_ES_TYPE_AUDIO) fourcc = VC_FOURCC('s','o','u','n');
+   if(track->format->es_type == VC_CONTAINER_ES_TYPE_SUBPICTURE) fourcc = VC_FOURCC('t','e','x','t');
+
+   WRITE_U8(p_ctx,  0, "version");
+   WRITE_U24(p_ctx, 0, "flags");
+
+   if(module->brand == MP4_BRAND_QT)
+      WRITE_FOURCC(p_ctx,  VC_FOURCC('m','h','l','r'), "component_type");
+   else
+      WRITE_U32(p_ctx,  0, "pre-defined");
+
+   WRITE_FOURCC(p_ctx,  fourcc, "handler_type");
+   for(i = 0; i < 3; i++)
+      WRITE_U32(p_ctx,  0, "reserved");
+
+   if(track->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO)
+   { handler_name = "Video Media Handler"; handler_size = sizeof("Video Media Handler"); }
+   else if(track->format->es_type == VC_CONTAINER_ES_TYPE_AUDIO)
+   { handler_name = "Audio Media Handler"; handler_size = sizeof("Audio Media Handler"); }
+   else if(track->format->es_type == VC_CONTAINER_ES_TYPE_SUBPICTURE)
+   { handler_name = "Text Media Handler"; handler_size = sizeof("Text Media Handler"); }
+   else { handler_name = ""; handler_size = sizeof(""); }
+
+   if(module->brand == MP4_BRAND_QT)
+   { handler_size--; WRITE_U8(p_ctx, handler_size, "string_size"); }
+
+   WRITE_STRING(p_ctx, handler_name, handler_size, "name");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_minf( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+
+   if(track->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO)
+      status = mp4_write_box(p_ctx, MP4_BOX_TYPE_VMHD);
+   else if(track->format->es_type == VC_CONTAINER_ES_TYPE_AUDIO)
+      status = mp4_write_box(p_ctx, MP4_BOX_TYPE_SMHD);
+#if 0
+   else if(track->format->es_type == VC_CONTAINER_ES_TYPE_SUBPICTURE)
+      /*FIXME */;
+#endif
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   status = mp4_write_box(p_ctx, MP4_BOX_TYPE_DINF);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   status = mp4_write_box(p_ctx, MP4_BOX_TYPE_STBL);
+
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_vmhd( VC_CONTAINER_T *p_ctx )
+{
+   WRITE_U8(p_ctx,  0, "version");
+   WRITE_U24(p_ctx, 1, "flags");
+
+   WRITE_U16(p_ctx,  0, "graphicsmode");
+   WRITE_U16(p_ctx,  0, "opcolor");
+   WRITE_U16(p_ctx,  0, "opcolor");
+   WRITE_U16(p_ctx,  0, "opcolor");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_smhd( VC_CONTAINER_T *p_ctx )
+{
+   WRITE_U8(p_ctx,  0, "version");
+   WRITE_U24(p_ctx, 0, "flags");
+
+   WRITE_U16(p_ctx,  0, "balance");
+   WRITE_U16(p_ctx,  0, "reserved");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_dinf( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+
+   status = mp4_write_box(p_ctx, MP4_BOX_TYPE_DREF);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_dref( VC_CONTAINER_T *p_ctx )
+{
+   WRITE_U8(p_ctx,  0, "version");
+   WRITE_U24(p_ctx, 0, "flags");
+
+   WRITE_U32(p_ctx,  1, "entry_count");
+
+   /* Add a URL box */
+   WRITE_U32(p_ctx,  12, "box_size");
+   WRITE_FOURCC(p_ctx,  VC_FOURCC('u','r','l',' '), "box_type");
+   WRITE_U8(p_ctx,  0, "version");
+   WRITE_U24(p_ctx, 0x1, "flags");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_stbl( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
+
+   status = mp4_write_box(p_ctx, MP4_BOX_TYPE_STSD);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   status = mp4_write_box(p_ctx, MP4_BOX_TYPE_STTS);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   if( 0 && track->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO)
+   {
+      status = mp4_write_box(p_ctx, MP4_BOX_TYPE_CTTS);
+      if(status != VC_CONTAINER_SUCCESS) return status;
+   }
+
+   status = mp4_write_box(p_ctx, MP4_BOX_TYPE_STSC);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   status = mp4_write_box(p_ctx, MP4_BOX_TYPE_STSZ);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   if(1)
+      status = mp4_write_box(p_ctx, MP4_BOX_TYPE_STCO);
+   else
+      status = mp4_write_box(p_ctx, MP4_BOX_TYPE_CO64);
+
+   if(track->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO)
+   {
+      status = mp4_write_box(p_ctx, MP4_BOX_TYPE_STSS);
+      if(status != VC_CONTAINER_SUCCESS) return status;
+   }
+
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_stsd( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+
+   WRITE_U8(p_ctx,  0, "version");
+   WRITE_U24(p_ctx, 0, "flags");
+
+   WRITE_U32(p_ctx, 1, "entry_count");
+
+   if(track->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO)
+      status = mp4_write_box_extended(p_ctx, MP4_BOX_TYPE_VIDE, track->priv->module->fourcc);
+   else if(track->format->es_type == VC_CONTAINER_ES_TYPE_AUDIO)
+      status = mp4_write_box_extended(p_ctx, MP4_BOX_TYPE_SOUN, track->priv->module->fourcc);
+#if 0
+   else if(track->format->es_type == VC_CONTAINER_ES_TYPE_SUBPICTURE)
+      /*FIXME*/;
+#endif
+
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_writer_write_sample_to_temp( VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_PACKET_T *packet)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   int32_t dts_diff = packet->dts - module->prev_sample_dts;
+   uint8_t keyframe = (packet->flags & VC_CONTAINER_PACKET_FLAG_KEYFRAME) ? 0x80 : 0;
+
+   vc_container_io_write_be_uint32(module->temp.io, packet->size);
+   vc_container_io_write_be_uint32(module->temp.io, dts_diff);
+   vc_container_io_write_be_uint24(module->temp.io, (uint32_t)(packet->pts - packet->dts));
+   vc_container_io_write_uint8(module->temp.io, packet->track | keyframe);
+   module->prev_sample_dts = packet->dts;
+   return module->temp.io->status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_writer_read_sample_from_temp( VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_PACKET_T *packet)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+
+   packet->size = vc_container_io_read_be_uint32(module->temp.io);
+   packet->dts += (int32_t)vc_container_io_read_be_uint32(module->temp.io);
+   packet->pts = packet->dts + vc_container_io_read_be_uint24(module->temp.io);
+   packet->track = vc_container_io_read_uint8(module->temp.io);
+   packet->flags = (packet->track & 0x80) ? VC_CONTAINER_PACKET_FLAG_KEYFRAME : 0;
+   packet->track &= 0x7F;
+   return module->temp.io->status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_stts( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[module->current_track]->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_PACKET_T sample;
+   unsigned int entries = 0;
+   int64_t last_dts = 0, delta;
+
+   WRITE_U8(p_ctx,  0, "version");
+   WRITE_U24(p_ctx, 0, "flags");
+
+   WRITE_U32(p_ctx, track_module->sample_table[MP4_SAMPLE_TABLE_STTS].entries, "entry_count");
+
+   if(module->null.refcount)
+   {
+      /* We're not actually writing the data, we just want the size */
+      WRITE_BYTES(p_ctx, 0, track_module->sample_table[MP4_SAMPLE_TABLE_STTS].entries * 8);
+      return STREAM_STATUS(p_ctx);
+   }
+
+   /* Go through all the samples written */
+   vc_container_io_seek(module->temp.io, INT64_C(0));
+   sample.dts = 0;
+
+   status = mp4_writer_read_sample_from_temp(p_ctx, &sample);
+   while(status == VC_CONTAINER_SUCCESS)
+   {
+      if(sample.track != module->current_track) goto skip;
+
+      delta = sample.dts * MP4_TIMESCALE / 1000000 - last_dts;
+      if(delta < 0) delta = 0;
+      WRITE_U32(p_ctx, 1, "sample_count");
+      WRITE_U32(p_ctx, delta, "sample_delta");
+      entries++;
+      last_dts += delta;
+
+     skip:
+      status = mp4_writer_read_sample_from_temp(p_ctx, &sample);
+   }
+   vc_container_assert(entries == track_module->sample_table[MP4_SAMPLE_TABLE_STTS].entries);
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_ctts( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[module->current_track]->priv->module;
+
+   WRITE_U8(p_ctx,  0, "version");
+   WRITE_U24(p_ctx, 0, "flags");
+   WRITE_U32(p_ctx, track_module->sample_table[MP4_SAMPLE_TABLE_CTTS].entries, "entry_count");
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_stsc( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[module->current_track]->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_PACKET_T sample;
+   int64_t offset = 0, track_offset = -1;
+   unsigned int entries = 0, chunks = 0, first_chunk = 0, samples_in_chunk = 0;
+
+   memset(&sample, 0, sizeof(VC_CONTAINER_PACKET_T));
+
+   WRITE_U8(p_ctx,  0, "version");
+   WRITE_U24(p_ctx, 0, "flags");
+   WRITE_U32(p_ctx, track_module->sample_table[MP4_SAMPLE_TABLE_STSC].entries, "entry_count");
+
+   if(module->null.refcount)
+   {
+      /* We're not actually writing the data, we just want the size */
+      WRITE_BYTES(p_ctx, 0, track_module->sample_table[MP4_SAMPLE_TABLE_STSC].entries * 12);
+      return STREAM_STATUS(p_ctx);
+   }
+
+   /* Go through all the samples written */
+   vc_container_io_seek(module->temp.io, INT64_C(0));
+
+   status = mp4_writer_read_sample_from_temp(p_ctx, &sample);
+   while(status == VC_CONTAINER_SUCCESS)
+   {
+      if(sample.track != module->current_track) goto skip;
+
+      /* Is it a new chunk ? */
+      if(track_offset != offset)
+      {
+         chunks++;
+         if(samples_in_chunk)
+         {
+            WRITE_U32(p_ctx,  first_chunk, "first_chunk");
+            WRITE_U32(p_ctx,  samples_in_chunk, "samples_per_chunk");
+            WRITE_U32(p_ctx,  1, "sample_description_index");
+            entries++;
+         }
+         first_chunk = chunks;
+         samples_in_chunk = 0;
+      }
+      track_offset = offset + sample.size;
+      samples_in_chunk++;
+
+     skip:
+      offset += sample.size;
+      status = mp4_writer_read_sample_from_temp(p_ctx, &sample);
+   }
+
+   if(samples_in_chunk)
+   {
+      WRITE_U32(p_ctx,  first_chunk, "first_chunk");
+      WRITE_U32(p_ctx,  samples_in_chunk, "samples_per_chunk");
+      WRITE_U32(p_ctx,  1, "sample_description_index");
+      entries++;
+   }
+
+   vc_container_assert(entries == track_module->sample_table[MP4_SAMPLE_TABLE_STSC].entries);
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_stsz( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[module->current_track]->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_PACKET_T sample;
+   unsigned int entries = 0;
+
+   memset(&sample, 0, sizeof(VC_CONTAINER_PACKET_T));
+
+   WRITE_U8(p_ctx,  0, "version");
+   WRITE_U24(p_ctx, 0, "flags");
+
+   WRITE_U32(p_ctx, 0, "sample_size");
+   WRITE_U32(p_ctx, track_module->sample_table[MP4_SAMPLE_TABLE_STSZ].entries, "sample_count");
+
+   if(module->null.refcount)
+   {
+      /* We're not actually writing the data, we just want the size */
+      WRITE_BYTES(p_ctx, 0, track_module->sample_table[MP4_SAMPLE_TABLE_STSZ].entries * 4);
+      return STREAM_STATUS(p_ctx);
+   }
+
+   /* Go through all the samples written */
+   vc_container_io_seek(module->temp.io, INT64_C(0));
+
+   status = mp4_writer_read_sample_from_temp(p_ctx, &sample);
+   while(status == VC_CONTAINER_SUCCESS)
+   {
+      if(sample.track != module->current_track) goto skip;
+
+      WRITE_U32(p_ctx, sample.size, "entry_size");
+      entries++;
+
+     skip:
+      status = mp4_writer_read_sample_from_temp(p_ctx, &sample);
+   }
+   vc_container_assert(entries == track_module->sample_table[MP4_SAMPLE_TABLE_STSZ].entries);
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_stco( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[module->current_track]->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_PACKET_T sample;
+   int64_t offset = module->data_offset, track_offset = -1;
+   unsigned int entries = 0;
+
+   memset(&sample, 0, sizeof(VC_CONTAINER_PACKET_T));
+
+   WRITE_U8(p_ctx,  0, "version");
+   WRITE_U24(p_ctx, 0, "flags");
+   WRITE_U32(p_ctx, track_module->sample_table[MP4_SAMPLE_TABLE_STCO].entries, "entry_count");
+
+   if(module->null.refcount)
+   {
+      /* We're not actually writing the data, we just want the size */
+      WRITE_BYTES(p_ctx, 0, track_module->sample_table[MP4_SAMPLE_TABLE_STCO].entries * 4);
+      return STREAM_STATUS(p_ctx);
+   }
+
+   /* Go through all the samples written */
+   vc_container_io_seek(module->temp.io, INT64_C(0));
+
+   status = mp4_writer_read_sample_from_temp(p_ctx, &sample);
+   while(status == VC_CONTAINER_SUCCESS)
+   {
+      if(sample.track != module->current_track) goto skip;
+
+      /* Is it a new chunk ? */
+      if(track_offset != offset)
+      {
+         WRITE_U32(p_ctx, offset, "chunk_offset");
+         entries++;
+      }
+      track_offset = offset + sample.size;
+
+     skip:
+      offset += sample.size;
+      status = mp4_writer_read_sample_from_temp(p_ctx, &sample);
+   }
+   vc_container_assert(entries == track_module->sample_table[MP4_SAMPLE_TABLE_STCO].entries);
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_co64( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[module->current_track]->priv->module;
+
+   WRITE_U8(p_ctx,  0, "version");
+   WRITE_U24(p_ctx, 0, "flags");
+   WRITE_U32(p_ctx, track_module->sample_table[MP4_SAMPLE_TABLE_CO64].entries, "entry_count");
+
+   if(module->null.refcount)
+   {
+      /* We're not actually writing the data, we just want the size */
+      WRITE_BYTES(p_ctx, 0, track_module->sample_table[MP4_SAMPLE_TABLE_CO64].entries * 8);
+      return STREAM_STATUS(p_ctx);
+   }
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_stss( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module = p_ctx->tracks[module->current_track]->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_PACKET_T sample;
+   unsigned int entries = 0, samples = 0;
+
+   memset(&sample, 0, sizeof(VC_CONTAINER_PACKET_T));
+
+   WRITE_U8(p_ctx,  0, "version");
+   WRITE_U24(p_ctx, 0, "flags");
+   WRITE_U32(p_ctx, track_module->sample_table[MP4_SAMPLE_TABLE_STSS].entries, "entry_count");
+
+   if(module->null.refcount)
+   {
+      /* We're not actually writing the data, we just want the size */
+      WRITE_BYTES(p_ctx, 0, track_module->sample_table[MP4_SAMPLE_TABLE_STSS].entries * 4);
+      return STREAM_STATUS(p_ctx);
+   }
+
+   /* Go through all the samples written */
+   vc_container_io_seek(module->temp.io, INT64_C(0));
+
+   status = mp4_writer_read_sample_from_temp(p_ctx, &sample);
+   while(status == VC_CONTAINER_SUCCESS)
+   {
+      if(sample.track != module->current_track) goto skip;
+
+      samples++;
+      if(sample.flags & VC_CONTAINER_PACKET_FLAG_KEYFRAME)
+      {
+         WRITE_U32(p_ctx, samples, "sample_number");
+         entries++;
+      }
+
+     skip:
+      status = mp4_writer_read_sample_from_temp(p_ctx, &sample);
+   }
+   vc_container_assert(entries == track_module->sample_table[MP4_SAMPLE_TABLE_STSS].entries);
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_vide_avcC( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
+
+   WRITE_U32(p_ctx, track->format->extradata_size + 8, "size");
+   WRITE_FOURCC(p_ctx, VC_FOURCC('a','v','c','C'), "type");
+   WRITE_BYTES(p_ctx, track->format->extradata, track->format->extradata_size);
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_vide_d263( VC_CONTAINER_T *p_ctx )
+{
+   WRITE_U32(p_ctx, 8 + 7, "size");
+   WRITE_FOURCC(p_ctx, VC_FOURCC('d','2','6','3'), "type");
+   WRITE_FOURCC(p_ctx, VC_FOURCC('B','R','C','M'), "vendor");
+   WRITE_U8(p_ctx, 0, "version");
+   WRITE_U8(p_ctx, 10, "level");
+   WRITE_U8(p_ctx, 0, "profile");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_vide( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
+   unsigned int i;
+
+   for(i = 0; i < 6; i++) WRITE_U8(p_ctx, 0, "reserved");
+   WRITE_U16(p_ctx, 1, "data_reference_index");
+
+   WRITE_U16(p_ctx, 0, "pre_defined");
+   WRITE_U16(p_ctx, 0, "reserved");
+   for(i = 0; i < 3; i++) WRITE_U32(p_ctx, 0, "pre_defined");
+   WRITE_U16(p_ctx, track->format->type->video.width, "width");
+   WRITE_U16(p_ctx, track->format->type->video.height, "height");
+   WRITE_U32(p_ctx, 0x480000, "horizresolution"); /* 72 dpi */
+   WRITE_U32(p_ctx, 0x480000, "vertresolution"); /* 72 dpi */
+   WRITE_U32(p_ctx, 0, "reserved");
+   WRITE_U16(p_ctx, 1, "frame_count");
+   for(i = 0; i < 32; i++) _WRITE_U8(p_ctx, 0);
+   WRITE_U16(p_ctx, 0x18, "depth");
+   WRITE_U16(p_ctx, -1, "pre_defined");
+
+   switch(track->format->codec)
+   {
+   case VC_CONTAINER_CODEC_H264: return mp4_write_box_vide_avcC(p_ctx);
+   case VC_CONTAINER_CODEC_H263: return mp4_write_box_vide_d263(p_ctx);
+   case VC_CONTAINER_CODEC_MP4V: return mp4_write_box(p_ctx, MP4_BOX_TYPE_ESDS);
+   default: break;
+   }
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_soun_damr( VC_CONTAINER_T *p_ctx )
+{
+   WRITE_U32(p_ctx, 8 + 8, "size");
+   WRITE_FOURCC(p_ctx, VC_FOURCC('d','a','m','r'), "type");
+   WRITE_FOURCC(p_ctx, VC_FOURCC('B','R','C','M'), "vendor");
+   WRITE_U8(p_ctx, 0, "version");
+   WRITE_U8(p_ctx, 0x80, "mode_set");
+   WRITE_U8(p_ctx, 0, "mode_change_period");
+   WRITE_U8(p_ctx, 1, "frame_per_second");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_soun_dawp( VC_CONTAINER_T *p_ctx )
+{
+   WRITE_U32(p_ctx, 8 + 5, "size");
+   WRITE_FOURCC(p_ctx, VC_FOURCC('d','a','w','p'), "type");
+   WRITE_FOURCC(p_ctx, VC_FOURCC('B','R','C','M'), "vendor");
+   WRITE_U8(p_ctx, 0, "version");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_soun_devc( VC_CONTAINER_T *p_ctx )
+{
+   WRITE_U32(p_ctx, 8 + 6, "size");
+   WRITE_FOURCC(p_ctx, VC_FOURCC('d','e','v','c'), "type");
+   WRITE_FOURCC(p_ctx, VC_FOURCC('B','R','C','M'), "vendor");
+   WRITE_U8(p_ctx, 0, "version");
+   WRITE_U8(p_ctx, 1, "samples_per_frame");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_soun( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
+   unsigned int i, version = 0;
+
+   for(i = 0; i < 6; i++) WRITE_U8(p_ctx, 0, "reserved");
+   WRITE_U16(p_ctx, 1, "data_reference_index");
+
+   if(module->brand == MP4_BRAND_QT)
+   {
+      if(track->format->codec == VC_CONTAINER_CODEC_MP4A) version = 1;
+      WRITE_U16(p_ctx, version, "version");
+      WRITE_U16(p_ctx, 0, "revision_level");
+      WRITE_U32(p_ctx, 0, "vendor");
+   }
+   else
+   {
+      for(i = 0; i < 2; i++) WRITE_U32(p_ctx, 0, "reserved");
+   }
+
+   WRITE_U16(p_ctx, track->format->type->audio.channels, "channelcount");
+   WRITE_U16(p_ctx, 0, "samplesize");
+   WRITE_U16(p_ctx, 0, "pre_defined");
+   WRITE_U16(p_ctx, 0, "reserved");
+   WRITE_U32(p_ctx, track->format->type->audio.sample_rate << 16, "samplerate");
+
+   if(module->brand == MP4_BRAND_QT && version == 1) /* FIXME */
+   {
+      WRITE_U32(p_ctx, 1024, "samples_per_packet");
+      WRITE_U32(p_ctx, 1536, "bytes_per_packet");
+      WRITE_U32(p_ctx, 2, "bytes_per_frame");
+      WRITE_U32(p_ctx, 2, "bytes_per_sample");
+   }
+
+   switch(track->format->codec)
+   {
+   case VC_CONTAINER_CODEC_AMRNB:
+   case VC_CONTAINER_CODEC_AMRWB:
+      return mp4_write_box_soun_damr(p_ctx);
+   case VC_CONTAINER_CODEC_AMRWBP:
+      return mp4_write_box_soun_dawp(p_ctx);
+   case VC_CONTAINER_CODEC_EVRC:
+      return mp4_write_box_soun_devc(p_ctx);
+   case VC_CONTAINER_CODEC_MP4A:
+   case VC_CONTAINER_CODEC_MPGA:
+      return mp4_write_box(p_ctx, MP4_BOX_TYPE_ESDS);
+   default: break;
+   }
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_write_box_esds( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[module->current_track];
+   unsigned int decoder_specific_size = 0, decoder_config_size, sl_size;
+   unsigned int stream_type, object_type;
+
+#define MP4_GET_DESCRIPTOR_SIZE(size) \
+   ((size) < 0x0080) ? 2 + (size) : ((size) < 0x4000) ? 3 + (size) : 4 + (size)
+#define MP4_WRITE_DESCRIPTOR_HEADER(type, size) \
+   LOG_FORMAT(p_ctx, "descriptor %x, size %i", type, size); _WRITE_U8(p_ctx, type); \
+   if((size) >= 0x4000) _WRITE_U8(p_ctx, (((size) >> 14) & 0x7F) | 0x80); \
+   if((size) >= 0x80  ) _WRITE_U8(p_ctx, (((size) >> 7 ) & 0x7F) | 0x80); \
+   _WRITE_U8(p_ctx, (size) & 0x7F)
+
+   /* We only support small size descriptors */
+   if(track->format->extradata_size > 0x200000 - 100)
+      return VC_CONTAINER_ERROR_TRACK_FORMAT_NOT_SUPPORTED;
+
+   switch(track->format->es_type)
+   {
+   case VC_CONTAINER_ES_TYPE_VIDEO: stream_type = 0x4; break;
+   case VC_CONTAINER_ES_TYPE_AUDIO: stream_type = 0x5; break;
+   case VC_CONTAINER_ES_TYPE_SUBPICTURE: stream_type = 0x20; break;
+   default: return VC_CONTAINER_ERROR_TRACK_FORMAT_NOT_SUPPORTED;
+   }
+   switch(track->format->codec)
+   {
+   case VC_CONTAINER_CODEC_MP4V: object_type = 0x20; break;
+   case VC_CONTAINER_CODEC_MP1V: object_type = 0x6B; break;
+   case VC_CONTAINER_CODEC_MP2V: object_type = 0x60; break;
+   case VC_CONTAINER_CODEC_JPEG: object_type = 0x6C; break;
+   case VC_CONTAINER_CODEC_MP4A: object_type = 0x40; break;
+   case VC_CONTAINER_CODEC_MPGA:
+      object_type = track->format->type->audio.sample_rate < 32000 ? 0x69 : 0x6B; break;
+   default: return VC_CONTAINER_ERROR_TRACK_FORMAT_NOT_SUPPORTED;
+   }
+
+   decoder_specific_size = MP4_GET_DESCRIPTOR_SIZE(track->format->extradata_size);
+   decoder_config_size = MP4_GET_DESCRIPTOR_SIZE(13 + decoder_specific_size);
+   sl_size = MP4_GET_DESCRIPTOR_SIZE(1);
+
+   WRITE_U8(p_ctx,  0, "version");
+   WRITE_U24(p_ctx, 0, "flags");
+
+   /* Write the ES descriptor */
+   MP4_WRITE_DESCRIPTOR_HEADER(0x3, 3 + decoder_config_size + sl_size);
+   WRITE_U16(p_ctx, module->current_track + 1, "es_id");
+   WRITE_U8(p_ctx, 0x1f, "flags"); /* stream_priority = 0x1f */
+
+   /* Write the Decoder Config descriptor */
+   MP4_WRITE_DESCRIPTOR_HEADER(0x4, 13 + decoder_specific_size);
+   WRITE_U8(p_ctx, object_type, "object_type_indication");
+   WRITE_U8(p_ctx, (stream_type << 2) | 1, "stream_type");
+   WRITE_U24(p_ctx, 8000, "buffer_size_db");
+   WRITE_U32(p_ctx, track->format->bitrate, "max_bitrate");
+   WRITE_U32(p_ctx, track->format->bitrate, "avg_bitrate");
+   if(track->format->extradata_size)
+   {
+      MP4_WRITE_DESCRIPTOR_HEADER(0x5, track->format->extradata_size);
+      WRITE_BYTES(p_ctx, track->format->extradata, track->format->extradata_size);
+   }
+
+   /* Write the SL descriptor */
+   MP4_WRITE_DESCRIPTOR_HEADER(0x6, 1);
+   WRITE_U8(p_ctx, 0x2, "flags");
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_writer_close( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status;
+   int64_t mdat_size;
+
+   mdat_size = STREAM_POSITION(p_ctx) - module->mdat_offset;
+
+   /* Write the moov box */
+   status = mp4_write_box(p_ctx, MP4_BOX_TYPE_MOOV);
+
+   /* Finalise the mdat box */
+   SEEK(p_ctx, module->mdat_offset);
+   WRITE_U32(p_ctx, (uint32_t)mdat_size, "mdat size" );
+
+   for(; p_ctx->tracks_num > 0; p_ctx->tracks_num--)
+      vc_container_free_track(p_ctx, p_ctx->tracks[p_ctx->tracks_num-1]);
+
+   vc_container_writer_extraio_delete(p_ctx, &module->temp);
+   vc_container_writer_extraio_delete(p_ctx, &module->null);
+   free(module);
+
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_writer_add_track( VC_CONTAINER_T *p_ctx, VC_CONTAINER_ES_FORMAT_T *format )
+{
+   VC_CONTAINER_STATUS_T status;
+   VC_CONTAINER_TRACK_T *track;
+   uint32_t type = 0;
+
+   if(!(format->flags & VC_CONTAINER_ES_FORMAT_FLAG_FRAMED))
+      return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+
+   /* Check we support this format */
+   switch(format->codec)
+   {
+   case VC_CONTAINER_CODEC_AMRNB:  type = VC_FOURCC('s','a','m','r'); break;
+   case VC_CONTAINER_CODEC_AMRWB:  type = VC_FOURCC('s','a','w','b'); break;
+   case VC_CONTAINER_CODEC_AMRWBP: type = VC_FOURCC('s','a','w','p'); break;
+   case VC_CONTAINER_CODEC_EVRC:   type = VC_FOURCC('s','e','v','c'); break;
+   case VC_CONTAINER_CODEC_MP4A:   type = VC_FOURCC('m','p','4','a'); break;
+   case VC_CONTAINER_CODEC_MPGA:   type = VC_FOURCC('m','p','4','a'); break;
+
+   case VC_CONTAINER_CODEC_MP4V:   type = VC_FOURCC('m','p','4','v'); break;
+   case VC_CONTAINER_CODEC_JPEG:   type = VC_FOURCC('m','p','4','v'); break;
+   case VC_CONTAINER_CODEC_H263:   type = VC_FOURCC('s','2','6','3'); break;
+   case VC_CONTAINER_CODEC_H264:
+      if(format->codec_variant == VC_FOURCC('a','v','c','C')) type = VC_FOURCC('a','v','c','1'); break;
+   case VC_CONTAINER_CODEC_MJPEG:  type = VC_FOURCC('j','p','e','g'); break;
+   case VC_CONTAINER_CODEC_MJPEGA: type = VC_FOURCC('m','j','p','a'); break;
+   case VC_CONTAINER_CODEC_MJPEGB: type = VC_FOURCC('m','j','p','b'); break;
+   case VC_CONTAINER_CODEC_MP1V:   type = VC_FOURCC('m','p','e','g'); break;
+   case VC_CONTAINER_CODEC_MP2V:   type = VC_FOURCC('m','p','e','g'); break;
+
+   default: type = 0; break;
+   }
+
+   if(!type) return VC_CONTAINER_ERROR_TRACK_FORMAT_NOT_SUPPORTED;
+
+   /* Allocate and initialise track data */
+   if(p_ctx->tracks_num >= MP4_TRACKS_MAX) return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+   p_ctx->tracks[p_ctx->tracks_num] = track =
+      vc_container_allocate_track(p_ctx, sizeof(*p_ctx->tracks[0]->priv->module));
+   if(!track) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+
+   if(format->extradata_size)
+   {
+      status = vc_container_track_allocate_extradata( p_ctx, track, format->extradata_size );
+      if(status) goto error;
+   }
+
+   vc_container_format_copy(track->format, format, format->extradata_size);
+   track->priv->module->fourcc = type;
+   track->priv->module->offset = -1;
+   track->priv->module->sample_table[MP4_SAMPLE_TABLE_STTS].entry_size = 8;
+   track->priv->module->sample_table[MP4_SAMPLE_TABLE_STSZ].entry_size = 4;
+   track->priv->module->sample_table[MP4_SAMPLE_TABLE_STSC].entry_size = 12;
+   track->priv->module->sample_table[MP4_SAMPLE_TABLE_STCO].entry_size = 4;
+   track->priv->module->sample_table[MP4_SAMPLE_TABLE_STSS].entry_size = 4;
+   track->priv->module->sample_table[MP4_SAMPLE_TABLE_CO64].entry_size = 8;
+   track->priv->module->sample_table[MP4_SAMPLE_TABLE_CTTS].entry_size = 8;
+
+   p_ctx->tracks_num++;
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+   vc_container_free_track(p_ctx, track);
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_writer_add_track_done( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   if(module->tracks_add_done) return status;
+
+   /* We need to find out the size of the object we're going to write it. */
+   if(!vc_container_writer_extraio_enable(p_ctx, &module->null))
+   {
+      status = mp4_write_box(p_ctx, MP4_BOX_TYPE_MOOV);
+      module->moov_size = STREAM_POSITION(p_ctx);
+      p_ctx->size = module->moov_size;
+   }
+   vc_container_writer_extraio_disable(p_ctx, &module->null);
+
+   if(status == VC_CONTAINER_SUCCESS) module->tracks_add_done = true;
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_writer_control( VC_CONTAINER_T *p_ctx, VC_CONTAINER_CONTROL_T operation, va_list args )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+
+   switch(operation)
+   {
+   case VC_CONTAINER_CONTROL_TRACK_ADD:
+      {
+         VC_CONTAINER_ES_FORMAT_T *p_format =
+            (VC_CONTAINER_ES_FORMAT_T *)va_arg( args, VC_CONTAINER_ES_FORMAT_T * );
+         if(module->tracks_add_done) return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+         return mp4_writer_add_track(p_ctx, p_format);
+      }
+
+   case VC_CONTAINER_CONTROL_TRACK_ADD_DONE:
+      return mp4_writer_add_track_done(p_ctx);
+
+   default: return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+   }
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_writer_add_sample( VC_CONTAINER_T *p_ctx,
+                                                    VC_CONTAINER_PACKET_T *packet )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[packet->track];
+   VC_CONTAINER_TRACK_MODULE_T *track_module = track->priv->module;
+
+   track_module->last_pts = packet->pts;
+   if(!track_module->samples) track_module->first_pts = packet->pts;
+
+   track_module->samples++;
+   track_module->sample_table[MP4_SAMPLE_TABLE_STSZ].entries++; /* sample size */
+   p_ctx->size += track_module->sample_table[MP4_SAMPLE_TABLE_STSZ].entry_size;
+   track_module->sample_table[MP4_SAMPLE_TABLE_STTS].entries++; /* time to sample */
+   p_ctx->size += track_module->sample_table[MP4_SAMPLE_TABLE_STTS].entry_size;
+
+   #if 0
+   delta_ts = packet->dts - track_module->timestamp;
+   track_module->timestamp = packet->dts;
+   if(!track_module->samples) track_module->delta_ts =
+   if()
+#endif
+
+   /* Is it a new chunk ? */
+   if(module->sample_offset != track_module->offset)
+   {
+      track_module->chunks++;
+      track_module->sample_table[MP4_SAMPLE_TABLE_STCO].entries++; /* chunk offset */
+      p_ctx->size += track_module->sample_table[MP4_SAMPLE_TABLE_STCO].entry_size;
+      track_module->sample_table[MP4_SAMPLE_TABLE_STSC].entries++; /* sample to chunk */
+      p_ctx->size += track_module->sample_table[MP4_SAMPLE_TABLE_STSC].entry_size;
+   }
+   track_module->offset = module->sample_offset + packet->size;
+
+   if(track->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO &&
+      (packet->flags & VC_CONTAINER_PACKET_FLAG_KEYFRAME))
+   {
+      track_module->sample_table[MP4_SAMPLE_TABLE_STSS].entries++; /* sync sample */
+      p_ctx->size += track_module->sample_table[MP4_SAMPLE_TABLE_STSS].entry_size;
+   }
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mp4_writer_write( VC_CONTAINER_T *p_ctx,
+                                               VC_CONTAINER_PACKET_T *packet )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_PACKET_T *sample = &module->sample;
+   VC_CONTAINER_STATUS_T status;
+
+   if(!module->tracks_add_done)
+   {
+      status = mp4_writer_add_track_done(p_ctx);
+      if(status != VC_CONTAINER_SUCCESS) return status;
+   }
+
+   if(packet->flags & VC_CONTAINER_PACKET_FLAG_FRAME_START)
+      ++module->samples; /* Switching to a new sample */
+
+   if(packet->flags & VC_CONTAINER_PACKET_FLAG_FRAME_START)
+   {
+      module->sample_offset = STREAM_POSITION(p_ctx);
+      sample->size = packet->size;
+      sample->pts = packet->pts;
+      sample->dts = packet->pts;
+      sample->track = packet->track;
+      sample->flags = packet->flags;
+   }
+   else
+   {
+      sample->size += packet->size;
+      sample->flags |= packet->flags;
+   }
+
+   if(WRITE_BYTES(p_ctx, packet->data, packet->size) != packet->size)
+      return STREAM_STATUS(p_ctx); // TODO do something
+   p_ctx->size += packet->size;
+
+   //
+   if(packet->flags & VC_CONTAINER_PACKET_FLAG_FRAME_END)
+   {
+      status = mp4_writer_write_sample_to_temp(p_ctx, sample);
+      status = mp4_writer_add_sample(p_ctx, sample);
+   }
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/******************************************************************************
+Global function definitions.
+******************************************************************************/
+
+VC_CONTAINER_STATUS_T mp4_writer_open( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   const char *extension = vc_uri_path_extension(p_ctx->priv->uri);
+   VC_CONTAINER_MODULE_T *module = 0;
+   MP4_BRAND_T brand;
+
+   /* Check if the user has specified a container */
+   vc_uri_find_query(p_ctx->priv->uri, 0, "container", &extension);
+
+   /* Check we're the right writer for this */
+   if(!extension)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   if(strcasecmp(extension, "3gp") && strcasecmp(extension, "skm") &&
+      strcasecmp(extension, "mov") && strcasecmp(extension, "mp4") &&
+      strcasecmp(extension, "m4v") && strcasecmp(extension, "m4a"))
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   /* Allocate our context */
+   module = malloc(sizeof(*module));
+   if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(module, 0, sizeof(*module));
+   p_ctx->priv->module = module;
+   p_ctx->tracks = module->tracks;
+
+   /* Find out which brand we're going write */
+   if(!strcasecmp(extension, "3gp")) brand = MP4_BRAND_3GP5;
+   else if(!strcasecmp(extension, "skm")) brand = MP4_BRAND_SKM2;
+   else if(!strcasecmp(extension, "mov")) brand = MP4_BRAND_QT;
+   else brand = MP4_BRAND_ISOM;
+   module->brand = brand;
+
+   /* Create a null i/o writer to help us out in writing our data */
+   status = vc_container_writer_extraio_create_null(p_ctx, &module->null);
+   if(status != VC_CONTAINER_SUCCESS) goto error;
+
+   /* Create a temporary i/o writer to help us out in writing our data */
+   status = vc_container_writer_extraio_create_temp(p_ctx, &module->temp);
+   if(status != VC_CONTAINER_SUCCESS) goto error;
+
+   status = mp4_write_box(p_ctx, MP4_BOX_TYPE_FTYP);
+   if(status != VC_CONTAINER_SUCCESS) goto error;
+
+   /* Start the mdat box */
+   module->mdat_offset = STREAM_POSITION(p_ctx);
+   WRITE_U32(p_ctx, 0, "size");
+   WRITE_FOURCC(p_ctx, VC_FOURCC('m','d','a','t'), "type");
+   module->data_offset = STREAM_POSITION(p_ctx);
+
+   p_ctx->priv->pf_close = mp4_writer_close;
+   p_ctx->priv->pf_write = mp4_writer_write;
+   p_ctx->priv->pf_control = mp4_writer_control;
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+   LOG_DEBUG(p_ctx, "mp4: error opening stream");
+   if(module)
+   {
+      if(module->null.io) vc_container_writer_extraio_delete(p_ctx, &module->null);
+      free(module);
+   }
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+ ********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak writer_open mp4_writer_open
+#endif
diff --git a/containers/mpeg/CMakeLists.txt b/containers/mpeg/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..5afe585
--- /dev/null
@@ -0,0 +1,13 @@
+# Container module needs to go in as a plugins so different prefix
+# and install path
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+
+# Make sure the compiler can find the necessary include files
+include_directories (../..)
+
+add_library(reader_ps ${LIBRARY_TYPE} ps_reader.c)
+
+target_link_libraries(reader_ps containers)
+
+install(TARGETS reader_ps DESTINATION ${VMCS_PLUGIN_DIR})
+
diff --git a/containers/mpeg/ps_reader.c b/containers/mpeg/ps_reader.c
new file mode 100755 (executable)
index 0000000..1394300
--- /dev/null
@@ -0,0 +1,1268 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <string.h>
+
+#define CONTAINER_IS_BIG_ENDIAN
+//#define ENABLE_CONTAINERS_LOG_FORMAT
+//#define ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
+#include "containers/core/containers_bits.h"
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_logging.h"
+#undef CONTAINER_HELPER_LOG_INDENT
+#define CONTAINER_HELPER_LOG_INDENT(a) (2*(a)->priv->module->level)
+
+/******************************************************************************
+Defines.
+******************************************************************************/
+#define PS_TRACKS_MAX 2
+#define PS_EXTRADATA_MAX 256
+
+#define PS_SYNC_FAIL_MAX 65536 /** Maximum number of byte-wise sync attempts,
+                                   should be enough to stride at least one
+                                   PES packet (length encoded using 16 bits). */
+
+/** Maximum number of pack/packet start codes scanned when searching for tracks
+    at open time or when resyncing. */
+#define PS_PACK_SCAN_MAX 128
+
+/******************************************************************************
+Type definitions.
+******************************************************************************/
+typedef struct VC_CONTAINER_TRACK_MODULE_T
+{
+   /** Coding and elementary stream id of the track */
+   uint32_t stream_id;
+
+   /** Sub-stream id (for private_stream_1 only) */
+   uint32_t substream_id;
+      
+   /** PES packet payload offset (for private_stream_1) */
+   unsigned int payload_offset;
+   
+   uint8_t extradata[PS_EXTRADATA_MAX];
+
+} VC_CONTAINER_TRACK_MODULE_T;
+
+typedef struct VC_CONTAINER_MODULE_T
+{
+   /** Logging indentation level */
+   uint32_t level;
+   
+   /** Track data */
+   int tracks_num;
+   VC_CONTAINER_TRACK_T *tracks[PS_TRACKS_MAX];
+
+   /** State flag denoting whether or not we are searching
+       for tracks (at open time) */
+   bool searching_tracks;
+
+   /** Size of program stream data (if known) */
+   uint64_t data_size;
+
+   /** Offset to the first pack or PES packet start code we've seen */
+   uint64_t data_offset;
+
+   /** The first system_clock_reference value we've seen, in (27MHz ticks) */
+   int64_t scr_offset;
+   
+   /** Most recent system_clock_reference value we've seen, in (27MHz ticks) */
+   int64_t scr;
+
+   /** Global offset we add to PES timestamps to make them zero based and 
+       to work around discontinuity in the system_clock_reference */
+   int64_t scr_bias;
+
+   /** Most recent program stream mux rate (in units of 50 bytes/second). */
+   uint32_t mux_rate;
+
+   /** Offset to the most recent pack start code we've seen */
+   uint64_t pack_offset;
+   
+   /** Program stream mux rate is often incorrect or fixed to 25200 (10.08 
+       Mbit/s) which yields inaccurate duration estimate for most files. We
+       maintain a moving average data rate (in units of bytes/second) based 
+       on the system_clock_reference to give better estimates. */
+   int64_t data_rate;
+
+   /** Offset to the most recent PES packet start code prefix we've seen */
+   unsigned int packet_data_size;
+   unsigned int packet_data_left;
+   int64_t packet_pts;
+   int64_t packet_dts;
+   int packet_track;
+   
+} VC_CONTAINER_MODULE_T;
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+
+VC_CONTAINER_STATUS_T ps_reader_open( VC_CONTAINER_T * );
+
+/******************************************************************************
+Prototypes for local functions
+******************************************************************************/
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+
+/** Find the track associated with a PS stream_id */
+static VC_CONTAINER_TRACK_T *ps_find_track( VC_CONTAINER_T *ctx, uint32_t stream_id,
+   uint32_t substream_id, bool b_create )
+{
+   VC_CONTAINER_TRACK_T *track = 0;
+   unsigned int i;
+
+   for(i = 0; i < ctx->tracks_num; i++)
+      if(ctx->tracks[i]->priv->module->stream_id == stream_id && 
+         ctx->tracks[i]->priv->module->substream_id == substream_id) break;
+
+   if(i < ctx->tracks_num) /* We found it */
+      track = ctx->tracks[i];
+
+   if(!track && b_create && i < PS_TRACKS_MAX)
+   {
+      /* Allocate and initialise a new track */
+      ctx->tracks[i] = track =
+         vc_container_allocate_track(ctx, sizeof(*ctx->tracks[0]->priv->module));
+      if(track)
+      {
+         track->priv->module->stream_id = stream_id;
+         track->priv->module->substream_id = substream_id;
+         ctx->tracks_num++;
+      }
+   }
+
+   if(!track && b_create)
+      LOG_DEBUG(ctx, "could not create track for stream id: %i", stream_id);
+
+   return track;
+}
+
+/*****************************************************************************/
+STATIC_INLINE VC_CONTAINER_STATUS_T ps_find_start_code( VC_CONTAINER_T *ctx, uint8_t *buffer )
+{
+   unsigned int i;
+
+   /* Scan for a pack or PES packet start code prefix */
+   for (i = 0; i < PS_SYNC_FAIL_MAX; ++i)
+   {
+      if(PEEK_BYTES(ctx, buffer, 4) < 4)
+         return VC_CONTAINER_ERROR_EOS;
+
+      if(buffer[0] == 0x0 && buffer[1] == 0x0 && buffer[2] == 0x1 && buffer[3] >= 0xB9) 
+         break;
+
+      if (SKIP_BYTES(ctx, 1) != 1)
+         return VC_CONTAINER_ERROR_EOS;
+   }
+
+   if(i == PS_SYNC_FAIL_MAX) /* We didn't find a valid pack or PES packet */
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   if (buffer[3] == 0xB9) /* MPEG_program_end_code */
+      return VC_CONTAINER_ERROR_EOS;
+      
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T ps_read_system_header( VC_CONTAINER_T *ctx )
+{
+   uint8_t header[8];
+   uint32_t length;
+   VC_CONTAINER_BITS_T bits;
+
+   if(_READ_U32(ctx) != 0x1BB) return VC_CONTAINER_ERROR_CORRUPTED;
+   LOG_FORMAT(ctx, "system_header");
+   ctx->priv->module->level++;
+
+   length = READ_U16(ctx, "header_length");
+   if(length < 6) return VC_CONTAINER_ERROR_CORRUPTED;
+   if(READ_BYTES(ctx, header, 6) != 6) return VC_CONTAINER_ERROR_EOS;
+
+   BITS_INIT(ctx, &bits, header, 6);
+
+   if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+   BITS_SKIP(ctx, &bits, 22, "rate_bound");
+   if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+   BITS_SKIP(ctx, &bits, 6, "audio_bound");
+   BITS_SKIP(ctx, &bits, 1, "fixed_flag");
+   BITS_SKIP(ctx, &bits, 1, "CSPS_flag");
+   BITS_SKIP(ctx, &bits, 1, "system_audio_lock_flag");
+   BITS_SKIP(ctx, &bits, 1, "system_video_lock_flag");
+   if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+   BITS_SKIP(ctx, &bits, 5, "video_bound");
+   BITS_SKIP(ctx, &bits, 1, "packet_rate_restriction_flag");
+   BITS_SKIP(ctx, &bits, 7, "reserved_bits");
+   length -= 6;
+
+   while(length >= 3 && (PEEK_U8(ctx) & 0x80))
+   {
+      SKIP_U8(ctx, "stream_id");
+      SKIP_BYTES(ctx, 2);
+      length -= 3;
+   }
+   SKIP_BYTES(ctx, length);
+
+   ctx->priv->module->level--;
+   return STREAM_STATUS(ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T ps_read_pack_header( VC_CONTAINER_T *ctx )
+{
+   VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+   uint8_t header[10];
+   int64_t scr, scr_base, scr_ext = INT64_C(0);
+   uint64_t pack_offset = STREAM_POSITION(ctx);
+   uint32_t mux_rate, stuffing;
+   VC_CONTAINER_BITS_T bits;
+   VC_CONTAINER_STATUS_T status;
+
+   if(_READ_U32(ctx) != 0x1BA) return VC_CONTAINER_ERROR_CORRUPTED;
+   LOG_FORMAT(ctx, "pack_header");
+   
+   module->level++;
+
+   if (PEEK_U8(ctx) & 0x40)  /* program stream */
+   {
+      if(READ_BYTES(ctx, header, 10) != 10) return VC_CONTAINER_ERROR_EOS;
+      BITS_INIT(ctx, &bits, header, 10);
+      if(BITS_READ_U32(ctx, &bits, 2, "'01' marker bits") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      scr_base = BITS_READ_U32(ctx, &bits, 3, "system_clock_reference_base [32..30]") << 30;
+      if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      scr_base |= BITS_READ_U32(ctx, &bits, 15, "system_clock_reference_base [29..15]") << 15;
+      if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      scr_base |= BITS_READ_U32(ctx, &bits, 15, "system_clock_reference_base [14..0]");
+      LOG_FORMAT(ctx, "system_clock_reference_base %"PRId64, scr_base);
+      if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      scr_ext = BITS_READ_U32(ctx, &bits, 9, "system_clock_reference_extension");
+      if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      mux_rate = BITS_READ_U32(ctx, &bits, 22, "program_mux_rate");
+      if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      BITS_SKIP(ctx, &bits, 5, "reserved");
+      stuffing = BITS_READ_U32(ctx, &bits, 3, "pack_stuffing_length");
+      SKIP_BYTES(ctx, stuffing);
+   }
+   else /* system stream */
+   {
+      if(READ_BYTES(ctx, header, 8) != 8) return VC_CONTAINER_ERROR_EOS;
+      BITS_INIT(ctx, &bits, header, 8);
+      if(BITS_READ_U32(ctx, &bits, 4, "'0010' marker bits") != 0x2) return VC_CONTAINER_ERROR_CORRUPTED;
+      scr_base = BITS_READ_U32(ctx, &bits, 3, "system_clock_reference_base [32..30]") << 30;
+      if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      scr_base |= BITS_READ_U32(ctx, &bits, 15, "system_clock_reference_base [29..15]") << 15;
+      if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      scr_base |= BITS_READ_U32(ctx, &bits, 15, "system_clock_reference_base [14..0]");
+      LOG_FORMAT(ctx, "system_clock_reference_base %"PRId64, scr_base);
+      if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      mux_rate = BITS_READ_U32(ctx, &bits, 22, "program_mux_rate");
+      if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+
+   if ((status = STREAM_STATUS(ctx)) != VC_CONTAINER_SUCCESS) return status;
+   
+   module->level--;
+
+   /* Set or update system_clock_reference, adjust bias if necessary */
+   scr = scr_base * INT64_C(300) + scr_ext;
+
+   if (module->scr_offset == VC_CONTAINER_TIME_UNKNOWN)
+      module->scr_offset = scr;
+
+   if (module->scr == VC_CONTAINER_TIME_UNKNOWN)
+      module->scr_bias = -scr;
+   else if (scr < module->scr)
+      module->scr_bias = module->scr - scr;
+
+   if (module->scr != VC_CONTAINER_TIME_UNKNOWN)
+   {
+      /* system_clock_reference is not necessarily continuous across the entire stream */
+      if (scr > module->scr)
+      {
+         int64_t data_rate;
+         data_rate = INT64_C(27000000) * (pack_offset - module->pack_offset) / (scr - module->scr);
+
+         if (module->data_rate)
+         {
+            /* Simple moving average over data rate seen so far */
+            module->data_rate = (module->data_rate * 31 + data_rate) >> 5;
+         }
+         else
+         {
+            module->data_rate = mux_rate * 50;
+         }
+      }
+
+      module->pack_offset = pack_offset;
+   }
+
+   module->scr = scr;
+   module->mux_rate = mux_rate;
+
+   /* Check for a system header */
+   if(PEEK_U32(ctx) == 0x1BB)
+      return ps_read_system_header(ctx);
+
+   return STREAM_STATUS(ctx);
+}
+
+/*****************************************************************************/
+static void ps_get_stream_coding( VC_CONTAINER_T *ctx, unsigned int stream_id, 
+   VC_CONTAINER_ES_TYPE_T *p_type, VC_CONTAINER_FOURCC_T *p_codec,
+   VC_CONTAINER_FOURCC_T *p_variant)
+{
+   VC_CONTAINER_ES_TYPE_T type = VC_CONTAINER_ES_TYPE_UNKNOWN;
+   VC_CONTAINER_FOURCC_T codec = VC_CONTAINER_CODEC_UNKNOWN;
+   VC_CONTAINER_FOURCC_T variant = 0;
+
+   VC_CONTAINER_PARAM_UNUSED(ctx);
+
+   if (stream_id == 0xE2) /* FIXME: why is this stream number reserved for H264? */
+   {
+      type = VC_CONTAINER_ES_TYPE_VIDEO;
+      codec = VC_CONTAINER_CODEC_H264;
+   }
+   else if ((stream_id & 0xF0) == 0xE0)
+   {
+      type = VC_CONTAINER_ES_TYPE_VIDEO;
+      codec = VC_CONTAINER_CODEC_MP2V;
+   }
+   else if ((stream_id & 0xE0) == 0xC0)
+   {
+      type = VC_CONTAINER_ES_TYPE_AUDIO;
+      codec = VC_CONTAINER_CODEC_MPGA;
+      variant = VC_CONTAINER_VARIANT_MPGA_L2;
+   }   
+
+   /* FIXME: PRIVATE_EVOB_PES_PACKET with stream_id 0xFD ? */
+   
+   *p_type = type;
+   *p_codec = codec;
+   *p_variant = variant;
+}
+
+/*****************************************************************************/
+static int64_t ps_pes_time_to_us( VC_CONTAINER_T *ctx, int64_t time )
+{
+   VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+   
+   if (time == VC_CONTAINER_TIME_UNKNOWN)
+      return VC_CONTAINER_TIME_UNKNOWN;
+
+   /* Need to wait for system_clock_reference first */
+   if (module->scr_bias == VC_CONTAINER_TIME_UNKNOWN)
+      return VC_CONTAINER_TIME_UNKNOWN;
+
+   /* Can't have valid bias without known system_clock_reference */
+   vc_container_assert(module->scr != VC_CONTAINER_TIME_UNKNOWN);
+   
+   /* 90kHz (PES) clock --> (zero based) 27MHz system clock --> microseconds */
+   return (INT64_C(300) * time + module->scr_bias) / INT64_C(27);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T ps_read_pes_time( VC_CONTAINER_T *ctx,
+   uint32_t *p_length, unsigned int pts_dts, int64_t *p_pts, int64_t *p_dts )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   uint8_t header[10];
+   uint32_t length = *p_length;
+   VC_CONTAINER_BITS_T bits;
+   int64_t pts, dts;
+
+   if (p_pts) *p_pts = VC_CONTAINER_TIME_UNKNOWN;
+   if (p_dts) *p_dts = VC_CONTAINER_TIME_UNKNOWN;
+
+   if (pts_dts == 0x2)
+   {
+      /* PTS only */
+      LOG_FORMAT(ctx, "PTS");
+      ctx->priv->module->level++;
+      if(length < 5) return VC_CONTAINER_ERROR_CORRUPTED;
+      if(READ_BYTES(ctx, header, 5) != 5) return VC_CONTAINER_ERROR_EOS;
+      BITS_INIT(ctx, &bits, header, 5);
+
+      if(BITS_READ_U32(ctx, &bits, 4, "'0010' marker bits") != 0x2) return VC_CONTAINER_ERROR_CORRUPTED;
+      pts = BITS_READ_U32(ctx, &bits, 3, "PTS [32..30]") << 30;
+      if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      pts |= BITS_READ_U32(ctx, &bits, 15, "PTS [29..15]") << 15;
+      if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      pts |= BITS_READ_U32(ctx, &bits, 15, "PTS [14..0]");
+      if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      LOG_FORMAT(ctx, "PTS %"PRId64, pts);
+      if (p_pts) *p_pts = pts;
+      length -= 5;
+      ctx->priv->module->level--;
+   }
+   else if (pts_dts == 0x3)
+   {
+      /* PTS & DTS */
+      LOG_FORMAT(ctx, "PTS DTS");
+      ctx->priv->module->level++;
+      if(length < 10) return VC_CONTAINER_ERROR_CORRUPTED;
+      if(READ_BYTES(ctx, header, 10) != 10) return VC_CONTAINER_ERROR_EOS;
+      BITS_INIT(ctx, &bits, header, 10);
+
+      /* PTS */
+      if(BITS_READ_U32(ctx, &bits, 4, "'0011' marker bits") != 0x3) return VC_CONTAINER_ERROR_CORRUPTED;
+      pts = BITS_READ_U32(ctx, &bits, 3, "PTS [32..30]") << 30;
+      if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      pts |= BITS_READ_U32(ctx, &bits, 15, "PTS [29..15]") << 15;
+      if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      pts |= BITS_READ_U32(ctx, &bits, 15, "PTS [14..0]");
+      if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      
+      /* DTS */
+      if(BITS_READ_U32(ctx, &bits, 4, "'0001' marker bits") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      dts = BITS_READ_U32(ctx, &bits, 3, "DTS [32..30]") << 30;
+      if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      dts |= BITS_READ_U32(ctx, &bits, 15, "DTS [29..15]") << 15;
+      if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      dts |= BITS_READ_U32(ctx, &bits, 15, "DTS [14..0]");
+      if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      LOG_FORMAT(ctx, "PTS %"PRId64, pts);
+      LOG_FORMAT(ctx, "DTS %"PRId64, dts);
+      if (p_pts) *p_pts = pts;
+      if (p_dts) *p_dts = dts;
+      length -= 10;
+      ctx->priv->module->level--;
+   }
+   else
+   {
+      status = VC_CONTAINER_ERROR_NOT_FOUND;
+   }
+   
+   *p_length = *p_length - length;
+   
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T ps_read_pes_extension( VC_CONTAINER_T *ctx,
+   uint32_t *p_length )
+{
+   unsigned int pes_private_data, pack_header, packet_seq_counter, pstd_buffer, extension2;
+   uint8_t header[2];
+   uint32_t length = *p_length;
+   VC_CONTAINER_BITS_T bits;
+   unsigned int i;
+
+   LOG_FORMAT(ctx, "PES_extension");
+   ctx->priv->module->level++;
+   if(length < 1) return VC_CONTAINER_ERROR_CORRUPTED;
+   if(READ_BYTES(ctx, header, 1) != 1) return VC_CONTAINER_ERROR_EOS;
+   BITS_INIT(ctx, &bits, header, 1);
+
+   pes_private_data = BITS_READ_U32(ctx, &bits, 1, "PES_private_data_flag");
+   pack_header = BITS_READ_U32(ctx, &bits, 1, "pack_header_field_flag");
+   packet_seq_counter = BITS_READ_U32(ctx, &bits, 1, "program_packet_sequence_counter_flag");
+   pstd_buffer = BITS_READ_U32(ctx, &bits, 1, "P-STD_buffer_flag");
+   BITS_SKIP(ctx, &bits, 3, "3 reserved_bits");
+   extension2 = BITS_READ_U32(ctx, &bits, 1, "PES_extension_flag_2");
+   length -= 1;
+
+   if (pes_private_data) 
+   {
+      if(length < 16) return VC_CONTAINER_ERROR_CORRUPTED;
+      SKIP_BYTES(ctx, 16); /* PES_private_data */
+      length -= 16;
+   }
+
+   if (pack_header) 
+   {
+      unsigned int pack_field_len;
+      if(length < 1) return VC_CONTAINER_ERROR_CORRUPTED;
+      pack_field_len = READ_U8(ctx, "pack_field_length");
+      length -= 1;
+      if(length < pack_field_len) return VC_CONTAINER_ERROR_CORRUPTED;
+      SKIP_BYTES(ctx, pack_field_len); /* pack_header */
+      length -= pack_field_len;
+   }
+
+   if (packet_seq_counter)
+   {
+      if(length < 2) return VC_CONTAINER_ERROR_CORRUPTED;
+      if(READ_BYTES(ctx, header, 2) != 2) return VC_CONTAINER_ERROR_EOS;
+      BITS_INIT(ctx, &bits, header, 2);
+
+      if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      BITS_SKIP(ctx, &bits, 7, "program_packet_sequence_counter");
+      if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      BITS_SKIP(ctx, &bits, 1, "MPEG1_MPEG2_identifier");
+      BITS_SKIP(ctx, &bits, 6, "original_stuff_length");
+      length -= 2;
+   }
+
+   if (pstd_buffer) 
+   {
+      if(length < 2) return VC_CONTAINER_ERROR_CORRUPTED;
+      if(READ_BYTES(ctx, header, 2) != 2) return VC_CONTAINER_ERROR_EOS;
+      BITS_INIT(ctx, &bits, header, 2);
+
+      if(BITS_READ_U32(ctx, &bits, 2, "'01' marker bits") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+      BITS_SKIP(ctx, &bits, 1, "P-STD_buffer_scale");
+      BITS_SKIP(ctx, &bits, 13, "P-STD_buffer_size");
+      length -= 2;
+   }
+
+   if (extension2)
+   {
+      uint8_t ext_field_len;
+      
+      if(length < 1) return VC_CONTAINER_ERROR_CORRUPTED;
+      if(READ_BYTES(ctx, &ext_field_len, 1) != 1) return VC_CONTAINER_ERROR_EOS;
+      length -= 1;
+
+      if((ext_field_len & 0x80) != 0x80) return VC_CONTAINER_ERROR_CORRUPTED; /* marker_bit */
+      ext_field_len &= ~0x80;  
+      LOG_FORMAT(ctx, "PES_extension_field_length %d", ext_field_len);
+
+      for (i = 0; i < ext_field_len; i++) 
+      {
+         SKIP_U8(ctx, "reserved");
+         length--;
+      }
+   }
+
+   ctx->priv->module->level--;
+   
+   *p_length = *p_length - length; /* Number of bytes read from stream */
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T ps_read_pes_packet_header( VC_CONTAINER_T *ctx,
+   uint32_t *p_length, int64_t *p_pts, int64_t *p_dts )
+{
+   VC_CONTAINER_STATUS_T status;
+   VC_CONTAINER_BITS_T bits;
+   uint32_t size, length = *p_length;
+   unsigned int pts_dts;
+   uint8_t header[10];
+   
+   if(length < 3) return VC_CONTAINER_ERROR_CORRUPTED;
+    
+   if ((PEEK_U8(ctx) & 0xC0) == 0x80) /* program stream */
+   {
+      unsigned int escr, es_rate, dsm_trick_mode, additional_copy_info, pes_crc, pes_extension;
+      unsigned int header_length;
+      
+      if(READ_BYTES(ctx, header, 3) != 3) return VC_CONTAINER_ERROR_EOS;
+      BITS_INIT(ctx, &bits, header, 3);
+     
+      if (BITS_READ_U32(ctx, &bits, 2, "'10' marker bits") != 0x2) return VC_CONTAINER_ERROR_CORRUPTED;
+      BITS_SKIP(ctx, &bits, 2, "PES_scrambling_control");
+      BITS_SKIP(ctx, &bits, 1, "PES_priority");
+      BITS_SKIP(ctx, &bits, 1, "data_alignment_indicator");
+      BITS_SKIP(ctx, &bits, 1, "copyright");
+      BITS_SKIP(ctx, &bits, 1, "original_or_copy");
+      pts_dts = BITS_READ_U32(ctx, &bits, 2, "PTS_DTS_flags");
+      escr = BITS_READ_U32(ctx, &bits, 1, "ESCR_flag");
+      es_rate = BITS_READ_U32(ctx, &bits, 1, "ES_rate_flag");
+      dsm_trick_mode = BITS_READ_U32(ctx, &bits, 1, "DSM_trick_mode_flag");
+      additional_copy_info = BITS_READ_U32(ctx, &bits, 1, "additional_copy_info_flag");
+      pes_crc = BITS_READ_U32(ctx, &bits, 1, "PES_CRC_flag");
+      pes_extension = BITS_READ_U32(ctx, &bits, 1, "PES_extension_flag");
+      header_length = BITS_READ_U32(ctx, &bits, 8, "PES_header_data_length");
+      length -= 3;
+
+      size = length;
+      status = ps_read_pes_time(ctx, &size, pts_dts, p_pts, p_dts);
+      if (status && status != VC_CONTAINER_ERROR_NOT_FOUND) return status;
+      length -= size;
+      header_length -= size;
+
+      if (escr)
+      {
+         /* Elementary stream clock reference */
+         int64_t escr;
+         
+         ctx->priv->module->level++;
+         if(length < 6) return VC_CONTAINER_ERROR_CORRUPTED;
+         if(READ_BYTES(ctx, header, 6) != 6) return VC_CONTAINER_ERROR_EOS;
+         BITS_INIT(ctx, &bits, header, 6);
+         
+         BITS_SKIP(ctx, &bits, 2, "reserved_bits");
+         escr = BITS_READ_U32(ctx, &bits, 3, "ESCR_base [32..30]") << 30;
+         if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+         escr |= BITS_READ_U32(ctx, &bits, 15, "ESCR_base [29..15]") << 15;
+         if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+         escr |= BITS_READ_U32(ctx, &bits, 15, "ESCR_base [14..0]");
+         if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+         BITS_READ_U32(ctx, &bits, 9, "ESCR_extension");
+         if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+            
+         LOG_FORMAT(ctx, "ESCR_base %"PRId64, escr);
+         length -= 6;
+         header_length -= 6;
+         ctx->priv->module->level--;
+      }
+   
+      if (es_rate) 
+      {
+         /* Elementary stream rate */
+         if(length < 3) return VC_CONTAINER_ERROR_CORRUPTED;
+         if(READ_BYTES(ctx, header, 3) != 3) return VC_CONTAINER_ERROR_EOS;
+         BITS_INIT(ctx, &bits, header, 3);
+   
+         if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+         BITS_READ_U32(ctx, &bits, 22, "ES_rate");
+         if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+         length -= 3;
+         header_length -= 3;
+      }
+      
+      if (dsm_trick_mode)
+      {
+         unsigned int trick_mode;
+   
+         if(length < 1) return VC_CONTAINER_ERROR_CORRUPTED;
+         if(READ_BYTES(ctx, header, 1) != 1) return VC_CONTAINER_ERROR_EOS;
+         BITS_INIT(ctx, &bits, header, 1);
+   
+         trick_mode = BITS_READ_U32(ctx, &bits, 3, "trick_mode_control");
+         if (trick_mode == 0x0 /* fast_forward */)
+         {
+            BITS_SKIP(ctx, &bits, 2, "field_id");
+            BITS_SKIP(ctx, &bits, 1, "intra_slice_refresh");
+            BITS_SKIP(ctx, &bits, 2, "frequency_truncation");
+         }
+         else if (trick_mode == 0x1 /* slow_motion */) 
+         {
+            BITS_SKIP(ctx, &bits, 5, "rep_cntrl");
+         }
+         else if (trick_mode == 0x2 /* freeze_frame */)
+         {
+            BITS_SKIP(ctx, &bits, 2, "field_id");
+            BITS_SKIP(ctx, &bits, 3, "reserved_bits");
+         }
+         else if (trick_mode == 0x3 /* fast_reverse */)
+         {
+            BITS_SKIP(ctx, &bits, 2, "field_id");
+            BITS_SKIP(ctx, &bits, 1, "intra_slice_refresh");
+            BITS_SKIP(ctx, &bits, 2, "frequency_truncation");
+         }
+         else if (trick_mode == 0x4 /* slow_reverse */)
+            BITS_SKIP(ctx, &bits, 5, "rep_cntrl");
+         else
+            BITS_SKIP(ctx, &bits, 5, "5 reserved_bits");
+            
+         length -= 1;
+         header_length -= 1;
+      }
+      
+      if (additional_copy_info)
+      {
+         if(length < 1) return VC_CONTAINER_ERROR_CORRUPTED;
+         if(READ_BYTES(ctx, header, 1) != 1) return VC_CONTAINER_ERROR_EOS;
+         BITS_INIT(ctx, &bits, header, 1);
+   
+         if(BITS_READ_U32(ctx, &bits, 1, "marker_bit") != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+         BITS_SKIP(ctx, &bits, 7, "additional_copy_info");
+         
+         length -= 1;
+         header_length -= 1;
+      }
+   
+      if (pes_crc) 
+      {
+         SKIP_U16(ctx, "previous_PES_packet_CRC");
+         length -= 2;
+         header_length -= 2;
+      }
+   
+      if (pes_extension)
+      {
+         size = length;
+         if ((status = ps_read_pes_extension(ctx, &size)) != VC_CONTAINER_SUCCESS) return status;
+         length -= size;
+         header_length -= size;
+      }
+      
+      if (header_length <= length)
+      {
+         SKIP_BYTES(ctx, header_length); /* header stuffing */
+         length -= header_length;
+      }
+   }
+   else /* MPEG 1 PES header */
+   {
+      if(length < 12) return VC_CONTAINER_ERROR_CORRUPTED;
+
+      while (PEEK_U8(ctx) == 0xFF && length > 0)
+      {
+         SKIP_U8(ctx, "stuffing");
+         length--;
+      }
+      
+      if (length == 0) return VC_CONTAINER_ERROR_CORRUPTED;
+
+      if ((PEEK_U8(ctx) & 0xC0) == 0x40)
+      {
+         if(length < 2) return VC_CONTAINER_ERROR_CORRUPTED;
+         SKIP_U8(ctx, "???");
+         SKIP_U8(ctx, "???");
+         length -= 2;
+      }
+
+      pts_dts = (PEEK_U8(ctx) & 0x30) >> 4;
+      size = length;
+      status = ps_read_pes_time(ctx, &size, pts_dts, p_pts, p_dts);
+      if (status && status != VC_CONTAINER_ERROR_NOT_FOUND) 
+         return status;
+      length -= size;
+
+      if (status == VC_CONTAINER_ERROR_NOT_FOUND)
+      {
+         if(length < 1) return VC_CONTAINER_ERROR_CORRUPTED;
+         SKIP_U8(ctx, "???");
+         length -= 1;
+      }
+   }
+
+   *p_length = length;
+   return STREAM_STATUS(ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T ps_read_private_stream_1_coding( VC_CONTAINER_T *ctx,
+   VC_CONTAINER_ES_TYPE_T *p_type, VC_CONTAINER_FOURCC_T *p_codec,
+   uint32_t *substream_id, uint32_t *p_length )
+{
+   VC_CONTAINER_ES_TYPE_T type = VC_CONTAINER_ES_TYPE_UNKNOWN;
+   VC_CONTAINER_FOURCC_T codec = VC_CONTAINER_CODEC_UNKNOWN;
+   uint32_t length;
+   uint8_t id = 0;
+   
+   length = *p_length;
+
+   if(length < 1) return VC_CONTAINER_ERROR_CORRUPTED;
+   if(READ_BYTES(ctx, &id, 1) != 1) return VC_CONTAINER_ERROR_EOS;
+   length -= 1;
+
+   LOG_FORMAT(ctx, "private_stream_1 byte: 0x%x (%u)", id, id);
+
+   if (id >= 0x20 && id <= 0x3f)
+   {
+      type = VC_CONTAINER_ES_TYPE_SUBPICTURE;
+      codec = VC_CONTAINER_CODEC_UNKNOWN;
+   } 
+   else if ((id >= 0x80 && id <= 0x87) || (id >= 0xC0 && id <= 0xCF)) 
+   {
+      type = VC_CONTAINER_ES_TYPE_AUDIO;
+      codec = VC_CONTAINER_CODEC_AC3;
+   } 
+   else if ((id >= 0x88 && id <= 0x8F) || (id >= 0x98 && id <= 0x9F)) 
+   {
+      type = VC_CONTAINER_ES_TYPE_AUDIO;
+      codec = VC_CONTAINER_CODEC_DTS;
+   } 
+   else if (id >= 0xA0 && id <= 0xBF) 
+   {
+      type = VC_CONTAINER_ES_TYPE_AUDIO;
+      codec = VC_CONTAINER_CODEC_PCM_SIGNED;
+   }
+   else
+   {
+      LOG_FORMAT(ctx, "Unknown private_stream_1 byte: 0x%x (%u)", id, id);
+   }
+   
+   *substream_id = id;
+   *p_type = type;
+   *p_codec = codec;
+   *p_length = length;
+   
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T ps_read_private_stream_1_format( VC_CONTAINER_T *ctx,
+    VC_CONTAINER_ES_FORMAT_T *format, uint32_t *length )
+{
+   uint8_t header[8];
+   VC_CONTAINER_BITS_T bits;
+
+   if (format->codec == VC_CONTAINER_CODEC_PCM_SIGNED)
+   {
+      static const unsigned fs_tab[4] = { 48000, 96000, 44100, 32000 };
+      static const unsigned bps_tab[] = {16, 20, 24, 0};
+      
+      unsigned fs, bps, nchan;
+      
+      if(*length < 6) return VC_CONTAINER_ERROR_CORRUPTED;
+      if(READ_BYTES(ctx, header, 6) != 6) return VC_CONTAINER_ERROR_EOS;
+      BITS_INIT(ctx, &bits, header, 6);
+   
+      BITS_SKIP(ctx, &bits, 8, "???");
+      BITS_SKIP(ctx, &bits, 8, "???");
+      BITS_SKIP(ctx, &bits, 8, "???");
+      BITS_SKIP(ctx, &bits, 1, "emphasis");
+      BITS_SKIP(ctx, &bits, 1, "mute");
+      BITS_SKIP(ctx, &bits, 1, "reserved");
+      BITS_SKIP(ctx, &bits, 5, "frame number");
+      bps = BITS_READ_U32(ctx, &bits, 2, "quant");
+      fs = BITS_READ_U32(ctx, &bits, 2, "freq");
+      BITS_SKIP(ctx, &bits, 1, "reserved");
+      nchan = BITS_READ_U32(ctx, &bits, 3, "channels");
+      *length -= 6;
+      
+      format->type->audio.sample_rate = fs_tab[fs];
+      format->type->audio.bits_per_sample = bps_tab[bps];
+      format->type->audio.channels = nchan + 1;
+      format->type->audio.block_align = 
+         (format->type->audio.channels * format->type->audio.bits_per_sample + 7 ) / 8;
+   }
+   else
+   {
+      if(*length < 3) return VC_CONTAINER_ERROR_CORRUPTED;
+      SKIP_U8(ctx, "num of frames");
+      SKIP_U8(ctx, "start pos hi");
+      SKIP_U8(ctx, "start pos lo");
+      *length -= 3;
+   }
+   
+   return STREAM_STATUS(ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T ps_read_pes_packet( VC_CONTAINER_T *ctx )
+{
+   VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+   VC_CONTAINER_STATUS_T status;
+   uint8_t header[10];
+   VC_CONTAINER_BITS_T bits;
+   uint32_t length, stream_id, substream_id = 0;
+   VC_CONTAINER_ES_TYPE_T type;
+   VC_CONTAINER_FOURCC_T codec, variant = 0;
+   VC_CONTAINER_TRACK_T *track;
+   int64_t pts, dts;
+   
+   if(_READ_U24(ctx) != 0x1) return VC_CONTAINER_ERROR_CORRUPTED;
+   if(READ_BYTES(ctx, header, 3) != 3) return VC_CONTAINER_ERROR_EOS;
+   LOG_FORMAT(ctx, "pes_packet_header");
+   module->level++;
+
+   BITS_INIT(ctx, &bits, header, 3);
+   stream_id = BITS_READ_U32(ctx, &bits, 8, "stream_id");
+   length = BITS_READ_U32(ctx, &bits, 16, "PES_packet_length");
+
+   if (stream_id < 0xBC) return VC_CONTAINER_ERROR_CORRUPTED;
+
+   if (stream_id == 0xBC /* program_stream_map */ || stream_id == 0xBE /* padding_stream */ ||
+       stream_id == 0xBF /* private_stream_2 */ || stream_id == 0xF0 /* ECM */ ||
+       stream_id == 0xF1 /* EMM */ || stream_id == 0xFF /* program_stream_directory */ ||
+       stream_id == 0xF2 /* DSMCC_stream */ || stream_id == 0xF8 /* ITU-T Rec. H.222.1 type E */)
+       goto skip;
+
+   /* Parse PES packet header */
+   if ((status = ps_read_pes_packet_header(ctx, &length, &pts, &dts)) != VC_CONTAINER_SUCCESS) 
+      return status;
+
+   /* For private_stream_1, encoding format is stored in the payload */
+   if (stream_id == 0xBD)
+   {
+      status = ps_read_private_stream_1_coding(ctx, &type, &codec, &substream_id, &length);
+      if (status) return status;
+   }
+   else
+      ps_get_stream_coding(ctx, stream_id, &type, &codec, &variant);
+
+   /* Check that we know what to do with this track */
+   if(type == VC_CONTAINER_ES_TYPE_UNKNOWN || codec == VC_CONTAINER_CODEC_UNKNOWN)
+      goto skip;
+   
+   track = ps_find_track(ctx, stream_id, substream_id, module->searching_tracks);
+   if(!track) goto skip;
+
+   if (module->searching_tracks)
+   {
+      track->is_enabled = true;
+      track->format->es_type = type;
+      track->format->codec = codec;
+      track->format->codec_variant = variant;
+
+      /* For private_stream_1, we need to parse payload further to get elementary stream
+         format */
+      if (stream_id == 0xBD)
+      {
+         uint32_t current_length = length;
+         status = ps_read_private_stream_1_format(ctx, track->format, &length);
+         if (status) return status;
+         track->priv->module->payload_offset = current_length - length;
+      }
+
+      goto skip;
+   }
+   else
+   {
+      unsigned i;
+      SKIP_BYTES(ctx, track->priv->module->payload_offset);
+      length -= track->priv->module->payload_offset;
+
+      /* Find track index */
+      for(i = 0; i < ctx->tracks_num; i++)
+         if(ctx->tracks[i] == track) break;
+      vc_container_assert(i < ctx->tracks_num);
+
+      module->packet_track = i;
+      module->packet_data_size = length;
+      module->packet_pts = pts;
+      module->packet_dts = dts;
+   }
+
+end:
+   module->level--;
+   return STREAM_STATUS(ctx);
+
+skip:
+   SKIP_BYTES(ctx, length); /* remaining PES_packet_data */
+   goto end;
+}
+
+/*****************************************************************************/
+STATIC_INLINE VC_CONTAINER_STATUS_T ps_find_pes_packet( VC_CONTAINER_T *ctx )
+{
+   VC_CONTAINER_STATUS_T status;
+   VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+   uint8_t buffer[4];
+   unsigned int i;
+
+   module->packet_data_size = 0;
+
+   for (i = 0; i != PS_PACK_SCAN_MAX; ++i)
+   {
+      if((status = ps_find_start_code(ctx, buffer)) != VC_CONTAINER_SUCCESS)
+         break;
+
+      if (buffer[3] == 0xBA && ((status = ps_read_pack_header(ctx)) != VC_CONTAINER_SUCCESS))
+         continue; /* pack start code but parsing failed, goto resync */
+
+      if ((status = ps_read_pes_packet(ctx)) == VC_CONTAINER_SUCCESS)
+         break;
+   }
+
+   return status;
+}
+
+/*****************************************************************************
+Functions exported as part of the Container Module API
+*****************************************************************************/
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T ps_reader_read( VC_CONTAINER_T *ctx,
+   VC_CONTAINER_PACKET_T *p_packet, uint32_t flags )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+
+   vc_container_assert(!module->searching_tracks);
+
+   while(!module->packet_data_left)
+   {
+      if(ps_find_pes_packet(ctx) != VC_CONTAINER_SUCCESS)
+      {
+         status = VC_CONTAINER_ERROR_EOS;
+         goto error;
+      }
+
+      module->packet_data_left = module->packet_data_size;
+   }
+
+   p_packet->track = module->packet_track;
+   p_packet->size = module->packet_data_left;
+   p_packet->flags = 0;
+   p_packet->pts = ps_pes_time_to_us(ctx, module->packet_pts);
+   p_packet->dts = ps_pes_time_to_us(ctx, module->packet_dts);
+
+   if (flags & VC_CONTAINER_READ_FLAG_SKIP)
+   {
+      SKIP_BYTES(ctx, module->packet_data_left);
+      module->packet_data_left = 0;
+      return VC_CONTAINER_SUCCESS;
+   }
+
+   if (flags & VC_CONTAINER_READ_FLAG_INFO)
+      return VC_CONTAINER_SUCCESS;
+
+   p_packet->size = MIN(p_packet->buffer_size, module->packet_data_left);
+   p_packet->size = READ_BYTES(ctx, p_packet->data, p_packet->size);
+   module->packet_data_left -= p_packet->size;
+
+   /* Temporary work-around for lpcm audio */
+   {
+      VC_CONTAINER_TRACK_T *track = ctx->tracks[module->packet_track];
+      if (track->format->codec == VC_CONTAINER_CODEC_PCM_SIGNED)
+      {
+         unsigned i;
+         uint16_t *ptr = (uint16_t *)p_packet->data;
+
+         for (i = 0; i < p_packet->size / 2; i ++)
+         {
+            uint32_t v = *ptr;
+            *ptr++ = v >> 8 | ( (v & 0xFF) << 8 );
+         }
+      }
+   }
+
+   if (module->packet_data_left)
+      module->packet_pts = module->packet_dts = VC_CONTAINER_TIME_UNKNOWN;
+
+   return STREAM_STATUS(ctx);
+
+error:
+   if (status == VC_CONTAINER_ERROR_EOS)
+   {
+      /* Reset time reference and calculation state */
+      ctx->priv->module->scr = VC_CONTAINER_TIME_UNKNOWN;
+      ctx->priv->module->scr_bias = -module->scr_offset;
+   }
+   
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T ps_reader_seek( VC_CONTAINER_T *ctx,
+   int64_t *p_offset, VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags )
+{
+   VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   uint64_t seekpos, position;
+   int64_t scr;
+   
+   VC_CONTAINER_PARAM_UNUSED(flags);
+
+   if (mode != VC_CONTAINER_SEEK_MODE_TIME || !STREAM_SEEKABLE(ctx))
+      return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+
+   position = STREAM_POSITION(ctx);
+   scr = module->scr;
+
+   if (*p_offset == INT64_C(0))
+      seekpos = module->data_offset;
+   else
+   {
+      if (!ctx->duration)
+         return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+
+      /* The following is an estimate that might be quite inaccurate */
+      seekpos = module->data_offset + (*p_offset * module->data_size) / ctx->duration;
+   }
+
+   SEEK(ctx, seekpos);
+   module->scr = module->scr_offset;
+   status = ps_find_pes_packet(ctx);
+   if (status && status != VC_CONTAINER_ERROR_EOS)
+      goto error;
+
+   module->packet_data_left = module->packet_data_size;
+
+   if (module->packet_pts != VC_CONTAINER_TIME_UNKNOWN)
+      *p_offset = ps_pes_time_to_us(ctx, module->packet_pts);
+   else if (module->data_size)
+      *p_offset = (STREAM_POSITION(ctx) - module->data_offset) * ctx->duration / module->data_size;
+
+   return STREAM_STATUS(ctx);
+
+error:
+   module->scr = scr;
+   SEEK(ctx, position);
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T ps_reader_close( VC_CONTAINER_T *ctx )
+{
+   VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+   unsigned int i;
+
+   for(i = 0; i < ctx->tracks_num; i++)
+      vc_container_free_track(ctx, ctx->tracks[i]);
+   free(module);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T ps_reader_open( VC_CONTAINER_T *ctx )
+{
+   const char *extension = vc_uri_path_extension(ctx->priv->uri);
+   VC_CONTAINER_MODULE_T *module = 0;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   uint8_t buffer[4];
+   unsigned int i;
+
+   /* Check if the user has specified a container */
+   vc_uri_find_query(ctx->priv->uri, 0, "container", &extension);
+
+   /* Since MPEG is difficult to auto-detect, we use the extension as
+      part of the autodetection */
+   if(!extension)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   if(strcasecmp(extension, "ps") && strcasecmp(extension, "vob") &&
+      strcasecmp(extension, "mpg") && strcasecmp(extension, "mp2") &&
+      strcasecmp(extension, "mp3") && strcasecmp(extension, "mpeg"))
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   if((status = ps_find_start_code(ctx, buffer)) != VC_CONTAINER_SUCCESS)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;  /* We didn't find a valid pack or PES packet  */
+
+   LOG_DEBUG(ctx, "using ps reader");
+
+   /* We are probably dealing with a PS file */
+   LOG_FORMAT(ctx, "MPEG PS reader, found start code: 0x%02x%02x%02x%02x",
+      buffer[0], buffer[1], buffer[2], buffer[3]);
+
+   /* Need to allocate context before searching for streams */
+   module = malloc(sizeof(*module));
+   if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(module, 0, sizeof(*module));
+   ctx->priv->module = module;
+   ctx->tracks = module->tracks;
+
+   /* Store offset so we can get back to what we consider the first pack or
+      packet */
+   module->data_offset = STREAM_POSITION(ctx);
+
+   /* Search for tracks, reset time reference and calculation state first */
+   ctx->priv->module->scr_offset = ctx->priv->module->scr = VC_CONTAINER_TIME_UNKNOWN;
+   ctx->priv->module->searching_tracks = true;
+
+   for (i = 0; i != PS_PACK_SCAN_MAX; ++i)
+   {
+      if (buffer[3] == 0xBA && (ps_read_pack_header(ctx) != VC_CONTAINER_SUCCESS))
+         goto resync;
+
+      if (ps_read_pes_packet(ctx) == VC_CONTAINER_SUCCESS)
+         continue;
+
+resync:
+      LOG_DEBUG(ctx, "Lost sync, scanning for start code");
+      if((status = ps_find_start_code(ctx, buffer)) != VC_CONTAINER_SUCCESS)
+         return VC_CONTAINER_ERROR_CORRUPTED;
+      LOG_DEBUG(ctx, "MPEG PS reader, found start code: 0x%"PRIx64" (%"PRId64"): 0x%02x%02x%02x%02x",
+         STREAM_POSITION(ctx), STREAM_POSITION(ctx), buffer[0], buffer[1], buffer[2], buffer[3]);
+   }
+
+   /* Seek back to the start of data */
+   SEEK(ctx, module->data_offset);
+
+   /* Bail out if we didn't find any tracks */
+   if(!ctx->tracks_num)
+   {
+      status = VC_CONTAINER_ERROR_NO_TRACK_AVAILABLE;
+      goto error;
+   }
+
+   /* Set data size (necessary for seeking) */
+   module->data_size = MAX(ctx->priv->io->size - module->data_offset, INT64_C(0));
+
+   /* Estimate data rate (necessary for seeking) */
+   if(STREAM_SEEKABLE(ctx))
+   {
+      /* Estimate data rate by jumping in the stream */
+      #define PS_PACK_SEARCH_MAX 64
+      uint64_t position = module->data_offset;
+      for (i = 0; i != PS_PACK_SEARCH_MAX; ++i)
+      {
+         position += (module->data_size / (PS_PACK_SEARCH_MAX + 1));
+         SEEK(ctx, position);
+
+         for(;;)
+         {
+            if(ps_find_start_code(ctx, buffer) != VC_CONTAINER_SUCCESS)
+               break;
+   
+            if (buffer[3] == 0xBA)
+            {
+               if (ps_read_pack_header(ctx) == VC_CONTAINER_SUCCESS)
+                  break;
+            }
+            else
+            {
+               /* Skip PES packet */
+               unsigned length;
+               SKIP_U32(ctx, "PES packet startcode");
+               length = READ_U16(ctx, "PES packet length");
+               SKIP_BYTES(ctx, length);
+            }
+         }
+      }
+
+      ctx->duration = (INT64_C(1000000) * module->data_size) / (module->data_rate);
+      
+      if (module->scr > module->scr_offset)
+      {
+         int64_t delta = (module->scr - module->scr_offset) / INT64_C(27);
+      
+         if (delta > ctx->duration)
+            ctx->duration = delta;
+      }
+
+      /* Seek back to the start of data */
+      SEEK(ctx, module->data_offset);
+   }
+   else
+   {
+      /* For most files, program_mux_rate is not reliable at all */
+      ctx->duration = (INT64_C(100000) * module->data_size) / (INT64_C(5) * module->mux_rate);
+   }
+
+   /* Reset time reference and calculation state, we're now ready to read data */
+   module->scr = VC_CONTAINER_TIME_UNKNOWN;
+   module->scr_bias = VC_CONTAINER_TIME_UNKNOWN;
+
+   ctx->priv->module->searching_tracks = false;
+
+   if(STREAM_SEEKABLE(ctx)) ctx->capabilities |= VC_CONTAINER_CAPS_CAN_SEEK;
+
+   ctx->priv->pf_close = ps_reader_close;
+   ctx->priv->pf_read = ps_reader_read;
+   ctx->priv->pf_seek = ps_reader_seek;
+
+   return STREAM_STATUS(ctx);
+
+ error:
+   LOG_DEBUG(ctx, "ps: error opening stream (%i)", status);
+   if(module) ps_reader_close(ctx);
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+ ********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak reader_open ps_reader_open
+#endif
diff --git a/containers/mpga/CMakeLists.txt b/containers/mpga/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..79cf39a
--- /dev/null
@@ -0,0 +1,13 @@
+# Container module needs to go in as a plugins so different prefix
+# and install path
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+
+# Make sure the compiler can find the necessary include files
+include_directories (../..)
+
+add_library(reader_mpga ${LIBRARY_TYPE} mpga_reader.c)
+
+target_link_libraries(reader_mpga containers)
+
+install(TARGETS reader_mpga DESTINATION ${VMCS_PLUGIN_DIR})
+
diff --git a/containers/mpga/mpga_common.h b/containers/mpga/mpga_common.h
new file mode 100755 (executable)
index 0000000..b8ba8e5
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#define MPGA_HEADER_SIZE 6
+
+#define MPGA_MODE_STEREO  0
+#define MPGA_MODE_JSTEREO 1
+#define MPGA_MODE_DUAL    2
+#define MPGA_MODE_MONO    3
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mpga_read_header( uint8_t frame_header[MPGA_HEADER_SIZE],
+   uint32_t *p_frame_size, unsigned int *p_frame_bitrate, unsigned int *p_version,
+   unsigned int *p_layer, unsigned int *p_sample_rate, unsigned int *p_channels,
+   unsigned int *p_frame_size_samples, unsigned int *p_offset )
+{
+   static const uint16_t mpga_bitrate[2][3][15] =
+   {{{0, 32,  64,  96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448}, /* MPEG1, Layer 1 */
+     {0, 32,  48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320, 384}, /* MPEG1, Layer 2 */
+     {0, 32,  40,  48,  56,  64,  80,  96, 112, 128, 160, 192, 224, 256, 320}},/* MPEG1, Layer 3 */
+    {{0, 32,  48,  56,  64,  80,  96, 112, 128, 144, 160, 176, 192, 224, 256}, /* MPEG2 and MPEG2.5, Layer 1 */
+     {0,  8,  16,  24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160}, /* MPEG2 and MPEG2.5, Layer 2 */
+     {0,  8,  16,  24,  32,  40,  48,  56,  64,  80,  96, 112, 128, 144, 160}} /* MPEG2 and MPEG2.5, Layer 3 */};
+   static const uint16_t mpga_sample_rate[] = {44100, 48000, 32000};
+   static const uint16_t mpga_frame_size[] = {384, 1152, 576};
+
+   unsigned int version, layer, br_id, sr_id, emphasis;
+   unsigned int bitrate, sample_rate, padding, mode;
+
+   /* Check frame sync, 11 bits as we want to allow for MPEG2.5 */
+   if (frame_header[0] != 0xff || (frame_header[1] & 0xe0) != 0xe0)
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+
+   version = 4 - ((frame_header[1] >> 3) & 3);
+   layer = 4 - ((frame_header[1] >> 1) & 3 );
+   br_id = (frame_header[2] >> 4) & 0xf;
+   sr_id = (frame_header[2] >> 2) & 3;
+   padding = (frame_header[2] >> 1) & 1;
+   mode = (frame_header[3] >> 6) & 3;
+   emphasis = (frame_header[3]) & 3;
+
+   /* Check for invalid values */
+   if (version == 3 || layer == 4 || br_id == 15 || sr_id == 3 || emphasis == 2)
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+
+   if (version == 4) version = 3;
+
+   bitrate = mpga_bitrate[version == 1 ? 0 : 1][layer-1][br_id];
+   bitrate *= 1000;
+
+   sample_rate = mpga_sample_rate[sr_id];
+   sample_rate >>= (version - 1);
+
+   if (p_version) *p_version = version;
+   if (p_layer) *p_layer = layer;
+   if (p_sample_rate) *p_sample_rate = sample_rate;
+   if (p_channels) *p_channels = mode == MPGA_MODE_MONO ? 1 : 2;
+   if (p_frame_bitrate) *p_frame_bitrate = bitrate;
+   if (p_offset) *p_offset = 0;
+
+   if (p_frame_size_samples)
+   {
+      *p_frame_size_samples = mpga_frame_size[layer - 1];
+      if (version == 1 && layer == 3) *p_frame_size_samples <<= 1;
+   }
+
+   if (!p_frame_size)
+      return VC_CONTAINER_SUCCESS;
+
+   if (!bitrate)
+      *p_frame_size = 0;
+   else if (layer == 1)
+      *p_frame_size = (padding + bitrate * 12 / sample_rate) * 4;
+   else if (layer == 2)
+      *p_frame_size = padding + bitrate * 144 / sample_rate;
+   else
+      *p_frame_size = padding + bitrate * (version == 1 ? 144 : 72) / sample_rate;
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T adts_read_header( uint8_t frame_header[MPGA_HEADER_SIZE],
+   uint32_t *p_frame_size, unsigned int *p_frame_bitrate, unsigned int *p_version,
+   unsigned int *p_layer, unsigned int *p_sample_rate, unsigned int *p_channels,
+   unsigned int *p_frame_size_samples, unsigned int *p_offset )
+{
+   static const unsigned int adts_sample_rate[16] =
+   {96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350};
+   unsigned int profile, sr_id, bitrate, sample_rate, frame_size, channels, crc;
+   unsigned int frame_size_samples = 1024;
+
+   /* Check frame sync (12 bits) */
+   if (frame_header[0] != 0xff || (frame_header[1] & 0xf0) != 0xf0)
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+
+   /* Layer must be 0 */
+   if ((frame_header[1] >> 1) & 3)
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+
+   crc = !(frame_header[1] & 0x1);
+   profile = (frame_header[2] >> 6) + 1; /* MPEG-4 Audio Object Type */
+
+   sr_id = (frame_header[2] >> 2) & 0xf;
+   sample_rate = adts_sample_rate[sr_id];
+   channels = ((frame_header[2] & 0x1) << 2) | ((frame_header[3] >> 6) & 0x3);
+   frame_size = ((frame_header[3] & 0x03) << 11) | (frame_header[4] << 3) | (frame_header[5] >> 5);
+
+   if (!sample_rate || !channels || !frame_size)
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+
+   bitrate = frame_size * 8 * sample_rate / frame_size_samples;
+
+   if (p_version) *p_version = profile;
+   if (p_layer) *p_layer = 0;
+   if (p_sample_rate) *p_sample_rate = sample_rate;
+   if (p_channels) *p_channels = channels;
+   if (p_frame_bitrate) *p_frame_bitrate = bitrate;
+   if (p_frame_size) *p_frame_size = frame_size;
+   if (p_frame_size_samples) *p_frame_size_samples = frame_size_samples;
+   if (p_offset) *p_offset = crc ? 9 : 7;
+
+   return VC_CONTAINER_SUCCESS;
+}
diff --git a/containers/mpga/mpga_packetizer.c b/containers/mpga/mpga_packetizer.c
new file mode 100755 (executable)
index 0000000..1d7b7bf
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file
+ * Implementation of an MPEG1/2/2.5 audio Layer I/II/III and AAC ADTS packetizer.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "containers/packetizers.h"
+#include "containers/core/packetizers_private.h"
+#include "containers/core/containers_common.h"
+#include "containers/core/containers_logging.h"
+#include "containers/core/containers_time.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_bytestream.h"
+#include "mpga_common.h"
+
+#define MAX_FRAME_SIZE 2881 /* MPEG 2.5 Layer II, 8000 Hz, 160 kbps */
+
+VC_CONTAINER_STATUS_T mpga_packetizer_open( VC_PACKETIZER_T * );
+
+/*****************************************************************************/
+typedef struct VC_PACKETIZER_MODULE_T {
+   enum {
+      STATE_SYNC = 0,
+      STATE_SYNC_LOST,
+      STATE_SYNC_NEXT,
+      STATE_SYNC_DONE,
+      STATE_HEADER,
+      STATE_DATA,
+   } state;
+
+   VC_CONTAINER_STATUS_T (*pf_read_header)( uint8_t frame_header[MPGA_HEADER_SIZE],
+      uint32_t *p_frame_size, unsigned int *p_frame_bitrate, unsigned int *p_version,
+      unsigned int *p_layer, unsigned int *p_sample_rate, unsigned int *p_channels,
+      unsigned int *p_frame_size_samples, unsigned int *p_offset);
+
+   uint32_t frame_size;
+   unsigned int frame_bitrate;
+   unsigned int version;
+   unsigned int layer;
+   unsigned int sample_rate;
+   unsigned int channels;
+   unsigned int frame_size_samples;
+   unsigned int offset;
+
+   unsigned int lost_sync;
+
+   unsigned int stream_version;
+   unsigned int stream_layer;
+
+   uint32_t bytes_read;
+
+} VC_PACKETIZER_MODULE_T;
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mpga_packetizer_close( VC_PACKETIZER_T *p_ctx )
+{
+   free(p_ctx->priv->module);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mpga_packetizer_reset( VC_PACKETIZER_T *p_ctx )
+{
+   VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
+   module->lost_sync = 0;
+   module->state = STATE_SYNC;
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mpga_packetizer_packetize( VC_PACKETIZER_T *p_ctx,
+   VC_CONTAINER_PACKET_T *out, VC_PACKETIZER_FLAGS_T flags )
+{
+   VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_BYTESTREAM_T *stream = &p_ctx->priv->stream;
+   VC_CONTAINER_TIME_T *time = &p_ctx->priv->time;
+   uint8_t header[MPGA_HEADER_SIZE];
+   VC_CONTAINER_STATUS_T status;
+   unsigned int version, layer;
+   int64_t pts, dts;
+
+   while(1) switch (module->state)
+   {
+   case STATE_SYNC_LOST:
+      bytestream_skip_byte( stream );
+      if( !module->lost_sync++ )
+         LOG_DEBUG(0, "lost sync");
+      module->state = STATE_SYNC;
+
+   case STATE_SYNC:
+      while( bytestream_peek( stream, header, 2 ) == VC_CONTAINER_SUCCESS )
+      {
+          /* 11 bits sync work (0xffe) */
+          if( header[0] == 0xff && (header[1] & 0xe0) == 0xe0 )
+          {
+             module->state = STATE_HEADER;
+             break;
+          }
+          bytestream_skip_byte( stream );
+          module->lost_sync++;
+      }
+      if( module->state != STATE_HEADER )
+         return VC_CONTAINER_ERROR_INCOMPLETE_DATA; /* We need more data */
+
+   case STATE_HEADER:
+      if( bytestream_peek( stream, header, MPGA_HEADER_SIZE ) != VC_CONTAINER_SUCCESS )
+         return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
+
+      status = mpga_read_header( header,
+         &module->frame_size, &module->frame_bitrate, &module->version,
+         &module->layer, &module->sample_rate, &module->channels,
+         &module->frame_size_samples, &module->offset );
+      if (status != VC_CONTAINER_SUCCESS)
+      {
+         LOG_ERROR(0, "invalid header");
+         module->state = STATE_SYNC_LOST;
+         break;
+      }
+
+      /* Version and layer are not allowed to change mid-stream */
+      if ((module->stream_version && module->stream_version != module->version) ||
+          (module->stream_layer && module->stream_layer != module->layer))
+      {
+         LOG_ERROR(0, "invalid header");
+         module->state = STATE_SYNC_LOST;
+         break;
+      }
+      /* We currently do not support free format streams  */
+      if (!module->frame_size)
+      {
+         LOG_ERROR(0, "free format not supported");
+         module->state = STATE_SYNC_LOST;
+         break;
+      }
+      module->state = STATE_SYNC_NEXT;
+      /* fall through to the next state */
+
+   case STATE_SYNC_NEXT:
+      /* To avoid being caught by emulated start codes, we also look at where the next frame is supposed to be */
+      if( bytestream_peek_at( stream, module->frame_size, header, MPGA_HEADER_SIZE ) != VC_CONTAINER_SUCCESS )
+      {
+         /* If we know there won't be anymore data then we can just assume
+          * we've got the frame we're looking for */
+         if (flags & VC_PACKETIZER_FLAG_FLUSH)
+         {
+            module->state = STATE_SYNC_DONE;
+            break;
+         }
+         return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
+      }
+
+      status = mpga_read_header( header, 0, 0, &version, &layer, 0, 0, 0, 0 );
+      if (status != VC_CONTAINER_SUCCESS)
+      {
+         LOG_ERROR(0, "invalid next header");
+         module->state = STATE_SYNC_LOST;
+         break;
+      }
+
+      /* Version and layer are not allowed to change mid-stream */
+      if (module->version != version || module->layer != layer)
+      {
+         LOG_ERROR(0, "invalid header");
+         module->state = STATE_SYNC_LOST;
+         break;
+      }
+
+      module->state = STATE_SYNC_DONE;
+      /* fall through to the next state */
+
+   case STATE_SYNC_DONE:
+      if( module->lost_sync )
+         LOG_DEBUG(0, "recovered sync after %i bytes", module->lost_sync);
+      module->lost_sync = 0;
+
+      bytestream_skip( stream, module->offset );
+      module->stream_version = module->version;
+      module->stream_layer = module->layer;
+
+      vc_container_time_set_samplerate(time, module->sample_rate, 1);
+      bytestream_get_timestamps(stream, &pts, &dts, true);
+
+      vc_container_time_set(time, pts);
+
+      module->bytes_read = 0;
+      module->state = STATE_DATA;
+      /* fall through to the next state */
+
+   case STATE_DATA:
+      if( bytestream_size( stream ) < module->frame_size)
+         return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
+
+      out->size = module->frame_size - module->bytes_read;
+      out->pts = out->dts = VC_CONTAINER_TIME_UNKNOWN;
+      out->flags = VC_CONTAINER_PACKET_FLAG_FRAME_END;
+
+      if(!module->bytes_read)
+      {
+         out->pts = out->dts = vc_container_time_get(time);
+         out->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
+      }
+
+      if(flags & VC_PACKETIZER_FLAG_INFO)
+         return VC_CONTAINER_SUCCESS;
+
+      if(flags & VC_PACKETIZER_FLAG_SKIP)
+      {
+         bytestream_skip( stream, out->size );
+      }
+      else
+      {
+         out->size = MIN(out->size, out->buffer_size);
+         bytestream_get( stream, out->data, out->size );
+      }
+      module->bytes_read += out->size;
+
+      if(module->bytes_read == module->frame_size)
+      {
+         vc_container_time_add(time, module->frame_size_samples);
+         module->state = STATE_HEADER;
+      }
+      return VC_CONTAINER_SUCCESS;
+
+   default:
+      break;
+   };
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T mpga_packetizer_open( VC_PACKETIZER_T *p_ctx )
+{
+   VC_PACKETIZER_MODULE_T *module;
+
+   if(p_ctx->in->codec != VC_CONTAINER_CODEC_MPGA &&
+      p_ctx->in->codec != VC_CONTAINER_CODEC_MP4A)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   p_ctx->priv->module = module = malloc(sizeof(*module));
+   if(!module)
+      return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+   memset(module, 0, sizeof(*module));
+
+   if(p_ctx->in->codec == VC_CONTAINER_CODEC_MPGA)
+      module->pf_read_header = mpga_read_header;
+   else
+      module->pf_read_header = adts_read_header;
+
+   vc_container_format_copy( p_ctx->out, p_ctx->in, 0);
+   p_ctx->max_frame_size = MAX_FRAME_SIZE;
+   p_ctx->priv->pf_close = mpga_packetizer_close;
+   p_ctx->priv->pf_packetize = mpga_packetizer_packetize;
+   p_ctx->priv->pf_reset = mpga_packetizer_reset;
+   LOG_DEBUG(0, "using mpeg audio packetizer");
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_PACKETIZER_REGISTER(mpga_packetizer_open,  "mpga");
diff --git a/containers/mpga/mpga_reader.c b/containers/mpga/mpga_reader.c
new file mode 100755 (executable)
index 0000000..da5df83
--- /dev/null
@@ -0,0 +1,618 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <string.h>
+
+#define CONTAINER_IS_BIG_ENDIAN
+//#define ENABLE_CONTAINERS_LOG_FORMAT
+//#define ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
+#define CONTAINER_HELPER_LOG_INDENT(a) 0
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_logging.h"
+#include "mpga_common.h"
+
+/******************************************************************************
+Defines and constants.
+******************************************************************************/
+#define MPGA_XING_HAS_FRAMES   0x00000001
+#define MPGA_XING_HAS_BYTES    0x00000002
+#define MPGA_XING_HAS_TOC      0x00000004
+#define MPGA_XING_HAS_QUALITY  0x00000008
+
+#define MPGA_MAX_BAD_FRAMES    4096 /*< Maximum number of failed byte-wise syncs,
+                                        should be at least 2881+4 to cover the largest 
+                                        frame size (MPEG2.5 Layer 2, 160kbit/s 8kHz) 
+                                        + next frame header */
+
+static const unsigned int mpga_sample_rate_adts[16] =
+{96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000, 12000, 11025, 8000, 7350};
+
+static const GUID_T asf_guid_header =
+{0x75B22630, 0x668E, 0x11CF, {0xA6, 0xD9, 0x00, 0xAA, 0x00, 0x62, 0xCE, 0x6C}};
+
+/******************************************************************************
+Type definitions
+******************************************************************************/
+typedef struct VC_CONTAINER_MODULE_T
+{ 
+   VC_CONTAINER_TRACK_T *track;
+   uint64_t data_offset;
+   uint64_t data_size;
+   uint64_t num_frames;             /**< Total number of frames (if known) */
+   unsigned int frame_size_samples; /**< Frame size in samples */
+   unsigned int bitrate;            /**< Bitrate (might change on a per-frame basis if VBR) */
+   unsigned int sample_rate;
+   unsigned int channels;
+
+   /* MPEG audio header information */
+   unsigned int version; /**< 1 for MPEG1, 2 for MPEG2, etc. */
+   unsigned int layer;
+   
+   /* VBR header information */
+   uint8_t xing_toc[100];
+   int xing_toc_valid;
+         
+   /* Per-frame state (updated upon a read or a seek) */
+   unsigned int frame_size;
+   unsigned int frame_data_left;
+   uint64_t frame_index;
+   int64_t frame_offset;
+   int64_t  frame_time_pos;         /**< pts of current frame */
+   unsigned int frame_bitrate;      /**< bitrate of current frame */
+
+   VC_CONTAINER_STATUS_T (*pf_parse_header)( uint8_t frame_header[MPGA_HEADER_SIZE],
+      uint32_t *p_frame_size, unsigned int *p_frame_bitrate, unsigned int *p_version,
+      unsigned int *p_layer, unsigned int *p_sample_rate, unsigned int *p_channels,
+      unsigned int *p_frame_size_samples, unsigned int *p_offset);
+
+   uint8_t extradata[2];            /**< codec extra data for aac */
+
+} VC_CONTAINER_MODULE_T;
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+VC_CONTAINER_STATUS_T mpga_reader_open( VC_CONTAINER_T * );
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+static uint32_t PEEK_BYTES_AT( VC_CONTAINER_T *p_ctx, int64_t offset, uint8_t *buffer, int size )
+{
+   int ret;
+   int64_t current_position = STREAM_POSITION(p_ctx);
+   SEEK(p_ctx, current_position + offset);
+   ret = PEEK_BYTES(p_ctx, buffer, size);
+   SEEK(p_ctx, current_position);   
+   return ret;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mpga_check_frame_header( VC_CONTAINER_T *p_ctx, 
+   VC_CONTAINER_MODULE_T *module, uint8_t frame_header[MPGA_HEADER_SIZE] )
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+   return module->pf_parse_header(frame_header, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mpga_sync( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status;
+   uint8_t frame_header[MPGA_HEADER_SIZE];
+   uint32_t frame_size;
+   unsigned int frame_bitrate, version, layer, sample_rate, channels;
+   unsigned int frame_size_samples, offset;
+   int sync_count = 0;
+
+   /* If we can't see a full frame header, we treat this as EOS although it
+      could be a bad stream as well, the caller should distinct between
+      these two cases */
+   if (PEEK_BYTES(p_ctx, (uint8_t*)frame_header, MPGA_HEADER_SIZE) != MPGA_HEADER_SIZE)
+      return VC_CONTAINER_ERROR_EOS;
+
+   while (sync_count++ < MPGA_MAX_BAD_FRAMES)
+   {
+      status = module->pf_parse_header(frame_header, &frame_size, &frame_bitrate,
+                                       &version, &layer, &sample_rate, &channels,
+                                       &frame_size_samples, &offset);
+      if (status == VC_CONTAINER_SUCCESS &&
+          frame_size /* We do not support free format streams */)
+      {
+         LOG_DEBUG(p_ctx, "MPEGv%d, layer %d, %d bps, %d Hz",
+                   version, layer, frame_bitrate, sample_rate);
+         if (PEEK_BYTES_AT(p_ctx, (int64_t)frame_size, frame_header, MPGA_HEADER_SIZE) != MPGA_HEADER_SIZE ||
+             mpga_check_frame_header(p_ctx, module, frame_header) == VC_CONTAINER_SUCCESS)
+            break;
+
+         /* If we've reached an ID3 tag then the frame is valid as well */
+         if((frame_header[0] == 'I' && frame_header[1] == 'D' && frame_header[2] == '3') ||
+            (frame_header[0] == 'T' && frame_header[1] == 'A' && frame_header[2] == 'G'))
+            break;
+      }
+      else if (status == VC_CONTAINER_SUCCESS)
+      {
+         LOG_DEBUG(p_ctx, "free format not supported");
+      }
+
+      if (SKIP_BYTES(p_ctx, 1) != 1 || PEEK_BYTES(p_ctx, (uint8_t*)frame_header, MPGA_HEADER_SIZE) != MPGA_HEADER_SIZE)
+         return VC_CONTAINER_ERROR_EOS;
+   }
+
+   if(sync_count > MPGA_MAX_BAD_FRAMES) /* We didn't find a valid frame */
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+
+   if (module->version)
+   {
+      /* FIXME: we don't currently care whether or not the number of channels changes mid-stream */
+      if (version != module->version || layer != module->layer)
+      {
+         LOG_DEBUG(p_ctx, "version or layer not allowed to change mid-stream");
+         return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+      }
+   }
+   else
+   {
+      module->version = version;
+      module->layer = layer;
+      module->sample_rate = sample_rate;
+      module->channels = channels;
+      module->frame_size_samples = frame_size_samples;
+   }
+
+   if(offset) SKIP_BYTES(p_ctx, offset);
+   module->frame_data_left = module->frame_size = frame_size - offset;
+   module->frame_bitrate = frame_bitrate;
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static int64_t mpga_calculate_frame_time( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   int64_t time;
+   time = INT64_C(1000000) * module->frame_index * 
+      module->frame_size_samples / module->sample_rate;
+   return time;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mpga_read_vbr_headers( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[0];
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_NOT_FOUND;
+   uint32_t peek_buf[1];
+   int64_t offset, start = STREAM_POSITION(p_ctx);
+
+   /* Look for XING header (immediately after layer 3 side information) */
+   offset = (module->version == 1) ? ((module->channels == 1) ?  INT64_C(21) :  INT64_C(36)) :
+      ((module->channels == 1) ?  INT64_C(13) :  INT64_C(21));
+   
+   if (PEEK_BYTES_AT(p_ctx, offset, (uint8_t*)peek_buf, 4) != 4)
+      return VC_CONTAINER_ERROR_FORMAT_INVALID; /* File would be way too small */
+
+   if (peek_buf[0] == VC_FOURCC('X','i','n','g') || peek_buf[0] == VC_FOURCC('I','n','f','o')) 
+   {
+      uint32_t flags = 0, num_frames = 0, data_size = 0;
+
+      /* If the first frame has a XING header then we know it's a valid (but empty) audio 
+         frame so we safely parse the header whilst skipping to the next frame */
+      SKIP_BYTES(p_ctx, offset); /* FIXME: we don't care about layer 3 side information? */
+
+      SKIP_FOURCC(p_ctx, "XING");
+      flags = READ_U32(p_ctx, "XING flags");
+
+      if (flags & MPGA_XING_HAS_FRAMES)
+         num_frames = READ_U32(p_ctx, "XING frames");
+
+      if (flags & MPGA_XING_HAS_BYTES)
+         data_size = READ_U32(p_ctx, "XING bytes");
+   
+      if (flags & MPGA_XING_HAS_TOC)
+      {
+         READ_BYTES(p_ctx, module->xing_toc, sizeof(module->xing_toc));
+         /* TOC is useful only if we know the number of frames */
+         if (num_frames) module->xing_toc_valid = 1;
+         /* Ensure time zero points to first frame even if TOC is broken */
+         module->xing_toc[0] = 0;
+      }
+      
+      if (flags & MPGA_XING_HAS_QUALITY)
+         SKIP_U32(p_ctx, "XING quality");
+
+      module->data_size = data_size;
+      module->num_frames = num_frames;
+      
+      if (module->num_frames && module->data_size)
+      {
+         /* We can calculate average bitrate */
+         module->bitrate =
+            module->data_size * module->sample_rate * 8 / (module->num_frames * module->frame_size_samples);
+      }
+      
+      p_ctx->duration = (module->num_frames * module->frame_size_samples * 1000000LL) / module->sample_rate;
+   
+      /* Look for additional LAME header (follows XING) */
+      if (PEEK_BYTES(p_ctx, (uint8_t*)peek_buf, 4) != 4)
+         return VC_CONTAINER_ERROR_FORMAT_INVALID; /* File would still be way too small */
+
+      if (peek_buf[0] == VC_FOURCC('L','A','M','E'))
+      {
+         uint32_t encoder_delay;
+
+         SKIP_FOURCC(p_ctx, "LAME");
+         SKIP_STRING(p_ctx, 5, "LAME encoder version");
+         SKIP_U8(p_ctx, "LAME tag revision/VBR method");
+         SKIP_U8(p_ctx, "LAME LP filter value");
+         SKIP_U32(p_ctx, "LAME peak signal amplitude");
+         SKIP_U16(p_ctx, "LAME radio replay gain");
+         SKIP_U16(p_ctx, "LAME audiophile replay gain");
+         SKIP_U8(p_ctx, "LAME encoder flags");
+         SKIP_U8(p_ctx, "LAME ABR/minimal bitrate");
+         encoder_delay = READ_U24(p_ctx, "LAME encoder delay/padding");
+         SKIP_U8(p_ctx, "LAME misc");
+         SKIP_U8(p_ctx, "LAME MP3 gain");
+         SKIP_U16(p_ctx, "LAME presets and surround info");
+         SKIP_U32(p_ctx, "LAME music length");
+         SKIP_U16(p_ctx, "LAME music CRC");
+         SKIP_U16(p_ctx, "LAME tag CRC");
+         track->format->type->audio.gap_delay = (encoder_delay >> 12) + module->frame_size_samples;
+         track->format->type->audio.gap_padding  = encoder_delay & 0xfff;
+      }
+      
+      SEEK(p_ctx, start);
+      status = VC_CONTAINER_SUCCESS;
+   }
+   
+   /* FIXME: if not success, try to read 'VBRI' header */
+   
+   return status;
+}
+
+/*****************************************************************************
+Functions exported as part of the Container Module API
+ *****************************************************************************/
+static VC_CONTAINER_STATUS_T mpga_reader_read( VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_PACKET_T *p_packet, uint32_t flags )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = p_ctx->tracks[0];
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+
+   if (module->frame_data_left == 0)
+   {
+      status = mpga_sync(p_ctx);
+      if (status != VC_CONTAINER_SUCCESS) goto error;
+   }
+
+   if (module->bitrate)
+   {
+      /* Simple moving average over bitrate values seen so far */
+      module->bitrate = (module->bitrate * 31 + module->frame_bitrate) >> 5;
+   }
+   else
+   {
+      module->bitrate = module->frame_bitrate;
+   }
+
+   /* Check if we can skip the frame straight-away */
+   if (!track->is_enabled ||
+       ((flags & VC_CONTAINER_READ_FLAG_SKIP) && !(flags & VC_CONTAINER_READ_FLAG_INFO)))
+   {
+      /* Just skip the frame */
+      SKIP_BYTES(p_ctx, module->frame_size);
+      module->frame_data_left = 0;
+      if(!track->is_enabled)
+         status = VC_CONTAINER_ERROR_CONTINUE;
+      goto end;
+   }
+
+   /* Fill in packet information */
+   p_packet->flags = p_packet->track = 0;
+   if (module->frame_data_left == module->frame_size)
+      p_packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME;
+   else
+      p_packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
+
+   p_packet->size = module->frame_data_left;
+
+   p_packet->pts = module->frame_time_pos;
+   p_packet->dts = VC_CONTAINER_TIME_UNKNOWN;
+
+   if ((flags & VC_CONTAINER_READ_FLAG_SKIP))
+   {
+      SKIP_BYTES(p_ctx, module->frame_size);
+      module->frame_data_left = 0;
+      goto end;
+   }
+
+   if (flags & VC_CONTAINER_READ_FLAG_INFO)
+      return VC_CONTAINER_SUCCESS;
+
+   p_packet->size = MIN(p_packet->buffer_size, module->frame_data_left);
+   p_packet->size = READ_BYTES(p_ctx, p_packet->data, p_packet->size);
+   module->frame_data_left -= p_packet->size;
+
+ end:
+   if (module->frame_data_left == 0)
+   {
+      module->frame_index++;
+      module->frame_offset += module->frame_size;
+      module->frame_time_pos = mpga_calculate_frame_time(p_ctx);
+
+#if 0 /* FIXME: is this useful e.g. progressive download? */
+      module->num_frames = MAX(module->num_frames, module->frame_index);
+      module->data_size = MAX(module->data_size, module->frame_offset);
+      p_ctx->duration = MAX(p_ctx->duration, mpga_calculate_frame_time(p_ctx));
+#endif
+   }
+   
+   return status == VC_CONTAINER_SUCCESS ? STREAM_STATUS(p_ctx) : status;
+   
+error:
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mpga_reader_seek( VC_CONTAINER_T *p_ctx, 
+                                               int64_t *p_offset,
+                                               VC_CONTAINER_SEEK_MODE_T mode, 
+                                               VC_CONTAINER_SEEK_FLAGS_T flags)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   uint64_t seekpos, position = STREAM_POSITION(p_ctx);
+   VC_CONTAINER_PARAM_UNUSED(flags);
+
+   if (mode != VC_CONTAINER_SEEK_MODE_TIME || !STREAM_SEEKABLE(p_ctx))
+      return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+
+   if (*p_offset != INT64_C(0))
+   {
+      if (!p_ctx->duration)
+         return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+
+      if (module->xing_toc_valid)
+      {
+         int64_t ppm;
+         int percent, lower, upper, delta;
+      
+         ppm = (*p_offset * module->sample_rate) / (module->num_frames * module->frame_size_samples);
+         ppm = MIN(ppm, INT64_C(999999));
+      
+         percent = ppm / 10000;
+         delta   = ppm % 10000;
+      
+         lower = module->xing_toc[percent];
+         upper = percent < 99 ? module->xing_toc[percent + 1] : 256;
+      
+         seekpos = module->data_offset + 
+            (((module->data_size * lower) + (module->data_size * (upper - lower) * delta) / 10000) >> 8);
+      }
+      else
+      {
+         /* The following will be accurate for CBR only */
+         seekpos = module->data_offset + (*p_offset * module->data_size) / p_ctx->duration;
+      }
+   }
+   else
+   {
+      seekpos = module->data_offset;
+   }
+
+   SEEK(p_ctx, seekpos);
+   status = mpga_sync(p_ctx);
+   if (status && status != VC_CONTAINER_ERROR_EOS) 
+      goto error;
+            
+   module->frame_index = (*p_offset * module->num_frames + (p_ctx->duration >> 1)) / p_ctx->duration;
+   module->frame_offset = STREAM_POSITION(p_ctx) - module->data_offset;
+     
+   *p_offset = module->frame_time_pos = mpga_calculate_frame_time(p_ctx);
+
+   return STREAM_STATUS(p_ctx);
+
+error:
+   SEEK(p_ctx, position);
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mpga_reader_close( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+
+   if (p_ctx->tracks_num != 0)
+      vc_container_free_track(p_ctx, p_ctx->tracks[0]);
+   p_ctx->tracks = NULL;
+   p_ctx->tracks_num = 0;
+   free(module);
+   p_ctx->priv->module = 0;  
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T mpga_reader_open( VC_CONTAINER_T *p_ctx )
+{
+   const char *extension = vc_uri_path_extension(p_ctx->priv->uri);
+   VC_CONTAINER_MODULE_T *module = 0;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_TRACK_T *track = NULL;
+   unsigned int i;
+   GUID_T guid;
+
+   /* Check if the user has specified a container */
+   vc_uri_find_query(p_ctx->priv->uri, 0, "container", &extension);
+
+   /* Since mpeg audio is difficult to auto-detect, we use the extension as
+      part of the autodetection */
+   if(!extension)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   if(strcasecmp(extension, "mp3") && strcasecmp(extension, "mp2") &&
+      strcasecmp(extension, "aac") && strcasecmp(extension, "adts"))
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   /* Check we're not in fact dealing with an ASF file */
+   if(PEEK_BYTES(p_ctx, (uint8_t *)&guid, sizeof(guid)) == sizeof(guid) &&
+      !memcmp(&guid, &asf_guid_header, sizeof(guid)))
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   LOG_DEBUG(p_ctx, "using mpga reader");
+
+   /* Allocate our context */
+   if ((module = malloc(sizeof(*module))) == NULL)
+   {
+      status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; 
+      goto error; 
+   }
+
+   memset(module, 0, sizeof(*module));
+   p_ctx->priv->module = module;
+   p_ctx->tracks = &module->track;
+   
+   p_ctx->tracks[0] = vc_container_allocate_track(p_ctx, 0);
+   if(!p_ctx->tracks[0])
+   {
+      status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; 
+      goto error; 
+   }
+   p_ctx->tracks_num = 1;
+
+   module->pf_parse_header = mpga_read_header;
+   if(!strcasecmp(extension, "aac") || !strcasecmp(extension, "adts"))
+      module->pf_parse_header = adts_read_header;
+
+   if ((status = mpga_sync(p_ctx)) != VC_CONTAINER_SUCCESS)
+   {
+      /* An error here probably means it's not an mpga file at all */
+      if(status == VC_CONTAINER_ERROR_FORMAT_INVALID)
+         status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+      goto error;
+   }
+
+   /* If we got this far, we're probably dealing with an mpeg audio file */
+   track = p_ctx->tracks[0];
+   track->format->es_type = VC_CONTAINER_ES_TYPE_AUDIO;
+   track->format->codec = VC_CONTAINER_CODEC_MPGA;
+   if(module->pf_parse_header == adts_read_header)
+   {
+      uint8_t *extra = track->format->extradata = module->extradata;
+      unsigned int sr_id;
+      for( sr_id = 0; sr_id < 13; sr_id++ )
+         if( mpga_sample_rate_adts[sr_id] == module->sample_rate ) break;
+      extra[0] = (module->version << 3) | ((sr_id & 0xe) >> 1);
+      extra[1] = ((sr_id & 0x1) << 7) | (module->channels << 3);
+      track->format->extradata_size = 2;
+      track->format->codec = VC_CONTAINER_CODEC_MP4A;
+   }
+   track->format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
+   track->is_enabled = true;
+   track->format->type->audio.channels = module->channels;
+   track->format->type->audio.sample_rate = module->sample_rate;
+   track->format->type->audio.bits_per_sample = 0;
+   track->format->type->audio.block_align = 1;
+
+   module->data_offset = STREAM_POSITION(p_ctx);
+
+   /* Look for VBR headers within the first frame */
+   status = mpga_read_vbr_headers(p_ctx);
+   if (status && status != VC_CONTAINER_ERROR_NOT_FOUND) goto error;
+   
+   /* If we couldn't get this information from VBR headers, try to determine 
+      file size, bitrate, number of frames and duration */
+   if (!module->data_size)
+      module->data_size = MAX(p_ctx->priv->io->size - module->data_offset, INT64_C(0));
+
+   if (!module->bitrate)
+   {
+      if (STREAM_SEEKABLE(p_ctx))
+      {
+         /* Scan past a few hundred frames (audio will often have 
+            silence in the beginning so we need to see more than
+            just a few frames) and estimate bitrate */
+         for (i = 0; i < 256; ++i) 
+            if (mpga_reader_read(p_ctx, NULL, VC_CONTAINER_READ_FLAG_SKIP)) break;
+         /* Seek back to start of data */
+         SEEK(p_ctx, module->data_offset);
+         module->frame_index = 0;
+         module->frame_offset = INT64_C(0);
+         module->frame_time_pos = mpga_calculate_frame_time(p_ctx);
+      }
+      else
+      {
+         /* Bitrate will be correct for CBR only */
+         module->bitrate = module->frame_bitrate;
+      }
+   }
+
+   track->format->bitrate = module->bitrate;
+  
+   if (!module->num_frames)
+   {
+      module->num_frames = (module->data_size * module->sample_rate * 8LL) /
+                              (module->bitrate * module->frame_size_samples);
+   }
+
+   if (!p_ctx->duration && module->bitrate)
+   {
+      p_ctx->duration = (INT64_C(8000000) * module->data_size) / module->bitrate;
+   }
+
+   p_ctx->priv->pf_close = mpga_reader_close;
+   p_ctx->priv->pf_read = mpga_reader_read;
+   p_ctx->priv->pf_seek = mpga_reader_seek;
+
+   if(STREAM_SEEKABLE(p_ctx)) p_ctx->capabilities |= VC_CONTAINER_CAPS_CAN_SEEK;
+
+   if(STREAM_STATUS(p_ctx) != VC_CONTAINER_SUCCESS) goto error;
+   return VC_CONTAINER_SUCCESS;
+
+error:
+   if(status == VC_CONTAINER_SUCCESS || status == VC_CONTAINER_ERROR_EOS) 
+      status = VC_CONTAINER_ERROR_FORMAT_INVALID;
+   LOG_DEBUG(p_ctx, "error opening stream (%i)", status);
+   if (p_ctx->tracks_num != 0)
+      vc_container_free_track(p_ctx, p_ctx->tracks[0]);
+   p_ctx->tracks = NULL;
+   p_ctx->tracks_num = 0;
+   if (module) free(module);
+   p_ctx->priv->module = NULL;
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+ ********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak reader_open mpga_reader_open
+#endif
diff --git a/containers/mpgv/mpgv_packetizer.c b/containers/mpgv/mpgv_packetizer.c
new file mode 100755 (executable)
index 0000000..79ccf78
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file
+ * Implementation of an MPEG1/2 video packetizer.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "containers/packetizers.h"
+#include "containers/core/packetizers_private.h"
+#include "containers/core/containers_common.h"
+#include "containers/core/containers_logging.h"
+#include "containers/core/containers_time.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_bytestream.h"
+
+/** Arbitrary number which should be sufficiently high so that no sane frame will
+ * be bigger than that. */
+#define MAX_FRAME_SIZE (1920*1088*2)
+
+static uint8_t mpgv_startcode[3] = {0x0, 0x0, 0x1};
+
+#define PICTURE_CODING_TYPE_I 0x1
+#define PICTURE_CODING_TYPE_P 0x2
+#define PICTURE_CODING_TYPE_B 0x3
+
+VC_CONTAINER_STATUS_T mpgv_packetizer_open( VC_PACKETIZER_T * );
+
+/*****************************************************************************/
+typedef struct VC_PACKETIZER_MODULE_T {
+   enum {
+      STATE_SYNC = 0,
+      STATE_SYNC_NEXT,
+      STATE_FRAME_DONE,
+      STATE_UNIT_HEADER,
+      STATE_UNIT_SEQUENCE,
+      STATE_UNIT_GROUP,
+      STATE_UNIT_PICTURE,
+      STATE_UNIT_SLICE,
+      STATE_UNIT_OTHER,
+      STATE_DATA,
+   } state;
+
+   size_t frame_size;
+   size_t unit_offset;
+
+   unsigned int seen_sequence_header;
+   unsigned int seen_picture_header;
+   unsigned int seen_slice;
+   unsigned int lost_sync;
+
+   unsigned int picture_type;
+   unsigned int picture_temporal_ref;
+   int64_t pts;
+   int64_t dts;
+
+   uint32_t bytes_read;
+
+   unsigned int width, height;
+   unsigned int frame_rate_num, frame_rate_den;
+   unsigned int aspect_ratio_num, aspect_ratio_den;
+   bool low_delay;
+
+} VC_PACKETIZER_MODULE_T;
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mpgv_packetizer_close( VC_PACKETIZER_T *p_ctx )
+{
+   free(p_ctx->priv->module);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mpgv_packetizer_reset( VC_PACKETIZER_T *p_ctx )
+{
+   VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
+   module->lost_sync = 0;
+   module->state = STATE_SYNC;
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mpgv_read_sequence_header(VC_CONTAINER_BYTESTREAM_T *stream,
+   size_t offset, unsigned int *width, unsigned int *height,
+   unsigned int *frame_rate_num, unsigned int *frame_rate_den,
+   unsigned int *aspect_ratio_num, unsigned int *aspect_ratio_den)
+{
+   static const int frame_rate[16][2] =
+   { {0, 0}, {24000, 1001}, {24, 1}, {25, 1}, {30000, 1001}, {30, 1}, {50, 1},
+     {60000, 1001}, {60, 1},
+     /* Unofficial values */
+     {15, 1001}, /* From Xing */
+     {5, 1001}, {10, 1001}, {12, 1001}, {15, 1001} /* From libmpeg3 */ };
+   static const int aspect_ratio[16][2] =
+   { {0, 0}, {1, 1}, {4, 3}, {16, 9}, {221, 100} };
+
+   VC_CONTAINER_STATUS_T status;
+   unsigned int w, h, fr, ar;
+   int64_t ar_num, ar_den, div;
+   uint8_t header[8];
+
+   status = bytestream_peek_at( stream, offset, header, sizeof(header));
+   if(status != VC_CONTAINER_SUCCESS)
+      return status;
+
+   w = (header[4] << 4) | (header[5] >> 4);
+   h = ((header[5]&0x0f) << 8) | header[6];
+   ar = header[7] >> 4;
+   fr = header[7]&0x0f;
+   if (!w || !h || !ar || !fr)
+      return VC_CONTAINER_ERROR_CORRUPTED;
+
+   *width = w;
+   *height = h;
+   *frame_rate_num = frame_rate[fr][0];
+   *frame_rate_den = frame_rate[fr][1];
+   ar_num = (int64_t)aspect_ratio[ar][0] * h;
+   ar_den = (int64_t)aspect_ratio[ar][1] * w;
+   div = vc_container_maths_gcd(ar_num, ar_den);
+   if (div)
+   {
+      ar_num /= div;
+      ar_den /= div;
+   }
+   *aspect_ratio_num = ar_num;
+   *aspect_ratio_den = ar_den;
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mpgv_read_picture_header(VC_CONTAINER_BYTESTREAM_T *stream,
+   size_t offset, unsigned int *type, unsigned int *temporal_ref)
+{
+   VC_CONTAINER_STATUS_T status;
+   uint8_t h[2];
+
+   status = bytestream_peek_at(stream, offset + sizeof(mpgv_startcode) + 1, h, sizeof(h));
+   if(status != VC_CONTAINER_SUCCESS)
+      return status;
+
+   *temporal_ref = (h[0] << 2) | (h[1] >> 6);
+   *type = (h[1] >> 3) & 0x7;
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mpgv_update_format( VC_PACKETIZER_T *p_ctx )
+{
+   VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
+
+   LOG_DEBUG(0, "mpgv format: width %i, height %i, rate %i/%i, ar %i/%i",
+             module->width, module->height, module->frame_rate_num, module->frame_rate_den,
+             module->aspect_ratio_num, module->aspect_ratio_den);
+
+   p_ctx->out->type->video.width = p_ctx->out->type->video.visible_width = module->width;
+   p_ctx->out->type->video.height = p_ctx->out->type->video.visible_height = module->height;
+   p_ctx->out->type->video.par_num = module->aspect_ratio_num;
+   p_ctx->out->type->video.par_den = module->aspect_ratio_den;
+   p_ctx->out->type->video.frame_rate_num = module->frame_rate_num;
+   p_ctx->out->type->video.frame_rate_den = module->frame_rate_den;
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T mpgv_packetizer_packetize( VC_PACKETIZER_T *p_ctx,
+   VC_CONTAINER_PACKET_T *out, VC_PACKETIZER_FLAGS_T flags)
+{
+   VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_BYTESTREAM_T *stream = &p_ctx->priv->stream;
+   VC_CONTAINER_TIME_T *time = &p_ctx->priv->time;
+   VC_CONTAINER_STATUS_T status;
+   uint8_t header[4];
+   size_t offset;
+
+   while(1) switch (module->state)
+   {
+   case STATE_SYNC:
+      offset = 0;
+      status = bytestream_find_startcode( stream, &offset,
+         mpgv_startcode, sizeof(mpgv_startcode) );
+
+      if(offset && !module->lost_sync)
+         LOG_DEBUG(0, "lost sync");
+
+      bytestream_skip(stream, offset);
+      module->lost_sync += offset;
+
+      if(status != VC_CONTAINER_SUCCESS)
+         return VC_CONTAINER_ERROR_INCOMPLETE_DATA; /* We need more data */
+
+      if(module->lost_sync)
+         LOG_DEBUG(0, "recovered sync after %i bytes", module->lost_sync);
+      module->lost_sync = 0;
+      module->state = STATE_UNIT_HEADER;
+      module->frame_size = 0;
+      module->unit_offset = 0;
+      /* fall through to the next state */
+
+   case STATE_UNIT_HEADER:
+      status = bytestream_peek_at( stream, module->unit_offset, header, sizeof(header));
+      if(status != VC_CONTAINER_SUCCESS)
+      {
+         if (!(flags & VC_PACKETIZER_FLAG_FLUSH) ||
+             !module->seen_picture_header || !module->seen_slice)
+            return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
+         module->state = STATE_FRAME_DONE;
+         break;
+      }
+
+#if defined(ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE)
+      LOG_DEBUG(0, "found unit (%x)", header[3]);
+#endif
+
+      /* Detect start of new frame */
+      if(module->seen_picture_header && module->seen_slice &&
+         (header[3] == 0x00 /* A picture header */ ||
+          (header[3] > 0xAF && header[3] != 0xB7) /* Not a slice or sequence end */))
+      {
+         module->state = STATE_FRAME_DONE;
+         break;
+      }
+
+      module->frame_size += sizeof(mpgv_startcode);
+      module->state = STATE_SYNC_NEXT;
+      /* fall through to the next state */
+
+   case STATE_SYNC_NEXT:
+      status = bytestream_find_startcode( stream, &module->frame_size,
+         mpgv_startcode, sizeof(mpgv_startcode) );
+
+      /* Sanity check the size of frames. This makes sure we don't endlessly accumulate data
+       * to make up a new frame. */
+      if(module->frame_size > p_ctx->max_frame_size)
+      {
+         LOG_ERROR(0, "frame too big (%i/%i), dropping", module->frame_size, p_ctx->max_frame_size);
+         bytestream_skip(stream, module->frame_size);
+         module->state = STATE_SYNC;
+         break;
+      }
+      if(status != VC_CONTAINER_SUCCESS)
+      {
+         if (!(flags & VC_PACKETIZER_FLAG_FLUSH) ||
+             !module->seen_picture_header || !module->seen_slice)
+            return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
+         module->state = STATE_FRAME_DONE;
+         break;
+      }
+
+      bytestream_peek_at( stream, module->unit_offset, header, sizeof(header));
+
+      /* Drop everything until we've seen a sequence header */
+      if(header[3] != 0xB3 && !module->seen_sequence_header)
+      {
+         LOG_DEBUG(0, "waiting for sequence header, dropping %i bytes", module->frame_size);
+         module->state = STATE_UNIT_HEADER;
+         bytestream_skip(stream, module->frame_size);
+         module->unit_offset = module->frame_size = 0;
+         break;
+      }
+
+      if(header[3] == 0x00)
+         module->state = STATE_UNIT_PICTURE;
+      else if(header[3] >= 0x01 && header[3] <= 0xAF)
+         module->state = STATE_UNIT_SLICE;
+      else if(header[3] == 0xB3)
+         module->state = STATE_UNIT_SEQUENCE;
+      else if(header[3] == 0xB8)
+         module->state = STATE_UNIT_GROUP;
+      else
+         module->state = STATE_UNIT_OTHER;
+      break;
+
+   case STATE_UNIT_SEQUENCE:
+      status = mpgv_read_sequence_header(stream, module->unit_offset, &module->width, &module->height,
+         &module->frame_rate_num, &module->frame_rate_den, &module->aspect_ratio_num, &module->aspect_ratio_den);
+      if(status != VC_CONTAINER_SUCCESS && !module->seen_sequence_header)
+      {
+         /* We need a sequence header so drop everything until we see one */
+         LOG_DEBUG(0, "invalid first sequence header, dropping %i bytes", module->frame_size);
+         bytestream_skip(stream, module->frame_size);
+         module->state = STATE_SYNC;
+         break;
+      }
+      mpgv_update_format(p_ctx);
+      module->seen_sequence_header = true;
+      vc_container_time_set_samplerate(time, module->frame_rate_num, module->frame_rate_den);
+      module->state = STATE_UNIT_HEADER;
+      module->unit_offset = module->frame_size;
+      break;
+
+   case STATE_UNIT_PICTURE:
+      status = mpgv_read_picture_header(stream, module->unit_offset, &module->picture_type, &module->picture_temporal_ref);
+      if(status != VC_CONTAINER_SUCCESS)
+         return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
+      module->seen_picture_header = true;
+      module->state = STATE_UNIT_HEADER;
+      module->unit_offset = module->frame_size;
+      break;
+
+   case STATE_UNIT_SLICE:
+      module->seen_slice = true;
+      module->state = STATE_UNIT_HEADER;
+      module->unit_offset = module->frame_size;
+      break;
+
+   case STATE_UNIT_GROUP:
+   case STATE_UNIT_OTHER:
+      module->state = STATE_UNIT_HEADER;
+      module->unit_offset = module->frame_size;
+      break;
+
+   case STATE_FRAME_DONE:
+      bytestream_get_timestamps(stream, &module->pts, &module->dts, false);
+
+      if(module->picture_type == PICTURE_CODING_TYPE_B || module->low_delay)
+      {
+         if(module->pts == VC_CONTAINER_TIME_UNKNOWN)
+            module->pts = module->dts;
+         if(module->dts == VC_CONTAINER_TIME_UNKNOWN)
+            module->dts = module->pts;
+      }
+      vc_container_time_set(time, module->pts);
+
+      module->bytes_read = 0;
+      module->state = STATE_DATA;
+      module->seen_slice = false;
+      module->seen_picture_header = false;
+
+#if defined(ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE)
+      LOG_DEBUG(0, "new frame, type %x, size %i, temp_ref %i)", module->picture_type,
+                module->frame_size, module->picture_temporal_ref);
+#endif
+      /* fall through to the next state */
+
+   case STATE_DATA:
+      out->size = module->frame_size - module->bytes_read;
+      out->pts = out->dts = VC_CONTAINER_TIME_UNKNOWN;
+      out->flags = VC_CONTAINER_PACKET_FLAG_FRAME_END;
+
+      if(!module->bytes_read)
+      {
+         out->pts = module->pts;
+         out->dts = module->dts;
+         out->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
+      }
+
+      if(flags & VC_PACKETIZER_FLAG_INFO)
+         return VC_CONTAINER_SUCCESS;
+
+      if(flags & VC_PACKETIZER_FLAG_SKIP)
+      {
+         bytestream_skip( stream, out->size );
+      }
+      else
+      {
+         out->size = MIN(out->size, out->buffer_size);
+         bytestream_get( stream, out->data, out->size );
+      }
+      module->bytes_read += out->size;
+
+      if(module->bytes_read == module->frame_size)
+      {
+         vc_container_time_add(time, 1);
+         module->state = STATE_UNIT_HEADER;
+         module->frame_size = 0;
+         module->unit_offset = 0;
+      }
+      else
+         out->flags &= ~VC_CONTAINER_PACKET_FLAG_FRAME_END;
+
+      return VC_CONTAINER_SUCCESS;
+
+   default:
+      break;
+   };
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T mpgv_packetizer_open( VC_PACKETIZER_T *p_ctx )
+{
+   VC_PACKETIZER_MODULE_T *module;
+
+   if(p_ctx->in->codec != VC_CONTAINER_CODEC_MP1V &&
+      p_ctx->in->codec != VC_CONTAINER_CODEC_MP2V)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   p_ctx->priv->module = module = malloc(sizeof(*module));
+   if(!module)
+      return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+   memset(module, 0, sizeof(*module));
+
+   vc_container_format_copy( p_ctx->out, p_ctx->in, 0);
+   p_ctx->max_frame_size = MAX_FRAME_SIZE;
+   p_ctx->priv->pf_close = mpgv_packetizer_close;
+   p_ctx->priv->pf_packetize = mpgv_packetizer_packetize;
+   p_ctx->priv->pf_reset = mpgv_packetizer_reset;
+   LOG_DEBUG(0, "using mpeg video packetizer");
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_PACKETIZER_REGISTER(mpgv_packetizer_open,  "mpgv");
diff --git a/containers/net/net_sockets.h b/containers/net/net_sockets.h
new file mode 100755 (executable)
index 0000000..e5a97a2
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VC_NET_SOCKETS_H
+#define VC_NET_SOCKETS_H
+
+/** \file net_sockets.h
+ * Abstraction layer for socket-style network communication, to enable porting
+ * between platforms.
+ *
+ * Does not support IPv6 multicast.
+ */
+
+#include "containers/containers_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Status codes that can occur in a socket instance. */
+typedef enum {
+   VC_CONTAINER_NET_SUCCESS = 0,                /**< No error */
+   VC_CONTAINER_NET_ERROR_GENERAL,              /**< An unrecognised error has occurred */
+   VC_CONTAINER_NET_ERROR_INVALID_SOCKET,       /**< Invalid socket passed to function */
+   VC_CONTAINER_NET_ERROR_NOT_ALLOWED,          /**< The operation requested is not allowed */
+   VC_CONTAINER_NET_ERROR_INVALID_PARAMETER,    /**< An invalid parameter was passed in */
+   VC_CONTAINER_NET_ERROR_NO_MEMORY,            /**< Failure due to lack of memory */
+   VC_CONTAINER_NET_ERROR_ACCESS_DENIED,        /**< Permission denied */
+   VC_CONTAINER_NET_ERROR_TOO_BIG,              /**< Too many handles already open */
+   VC_CONTAINER_NET_ERROR_WOULD_BLOCK,          /**< Asynchronous operation would block */
+   VC_CONTAINER_NET_ERROR_IN_PROGRESS,          /**< An operation is already in progress on this socket */
+   VC_CONTAINER_NET_ERROR_IN_USE,               /**< The address/port is already in use */
+   VC_CONTAINER_NET_ERROR_NETWORK,              /**< Network is unavailable */
+   VC_CONTAINER_NET_ERROR_CONNECTION_LOST,      /**< The connection has been lost, closed by network, etc. */
+   VC_CONTAINER_NET_ERROR_NOT_CONNECTED,        /**< The socket is not connected */
+   VC_CONTAINER_NET_ERROR_TIMED_OUT,            /**< Operation timed out */
+   VC_CONTAINER_NET_ERROR_CONNECTION_REFUSED,   /**< Connection was refused by target */
+   VC_CONTAINER_NET_ERROR_HOST_NOT_FOUND,       /**< Target address could not be resolved */
+   VC_CONTAINER_NET_ERROR_TRY_AGAIN,            /**< A temporary failure occurred that may clear */
+} vc_container_net_status_t;
+
+/** Operations that can be applied to sockets */
+typedef enum {
+   /** Set the buffer size used on the socket
+    * arg1: uint32_t - New buffer size in bytes */
+   VC_CONTAINER_NET_CONTROL_SET_READ_BUFFER_SIZE = 1,
+   /** Set the timeout to be used on read operations
+    * arg1: uint32_t - New timeout in milliseconds, or INFINITE_TIMEOUT_MS */
+   VC_CONTAINER_NET_CONTROL_SET_READ_TIMEOUT_MS,
+} vc_container_net_control_t;
+
+/** Container Input / Output Context.
+ * This is an opaque structure that defines the context for a socket instance.
+ * The details of the structure are contained within the platform implementation. */
+typedef struct vc_container_net_tag VC_CONTAINER_NET_T;
+
+/** \name Socket open flags
+ * The following flags can be used when opening a network socket. */
+/* @{ */
+typedef uint32_t vc_container_net_open_flags_t;
+/** Connected stream socket, rather than connectionless datagram socket */
+#define VC_CONTAINER_NET_OPEN_FLAG_STREAM 1
+/** Force use of IPv4 addressing */
+#define VC_CONTAINER_NET_OPEN_FLAG_FORCE_IP4 2
+/** Force use of IPv6 addressing */
+#define VC_CONTAINER_NET_OPEN_FLAG_FORCE_IP6 6
+/** Use IPv4 broadcast address for datagram delivery */
+#define VC_CONTAINER_NET_OPEN_FLAG_IP4_BROADCAST 8
+/* @} */
+
+/** Mask of bits used in forcing address type */
+#define VC_CONTAINER_NET_OPEN_FLAG_FORCE_MASK 6
+
+/** Blocks until data is available, or an error occurs.
+ * Used with the VC_CONTAINER_NET_CONTROL_SET_READ_TIMEOUT_MS control operation. */
+#define INFINITE_TIMEOUT_MS   0xFFFFFFFFUL
+
+
+/** Opens a network socket instance.
+ * The network address can be a host name, dotted IP4, hex IP6 address or NULL. Passing NULL
+ * signifies the socket is either to be used as a datagram receiver or a stream server,
+ * depending on the flags.
+ * \ref VC_CONTAINER_NET_OPEN_FLAG_STREAM will open the socket for connected streaming. The default
+ * is to use connectionless datagrams.
+ * \ref VC_CONTAINER_NET_OPEN_FLAG_FORCE_IP4 will force the use of IPv4 addressing or fail to open
+ * the socket. The default is to pick the first available.
+ * \ref VC_CONTAINER_NET_OPEN_FLAG_FORCE_IP6 will force the use of IPv6 addressing or fail to open
+ * the socket. The default is to pick the first available.
+ * \ref VC_CONTAINER_NET_OPEN_FLAG_IP4_BROADCAST will use IPv4 broadcast addressing for a datagram
+ * sender. Use with an IPv6 address, stream socket or datagram receiver will raise an error.
+ * If the p_status parameter is not NULL, the status code will be written to it to indicate the
+ * reason for failure, or VC_CONTAINER_NET_SUCCESS on success.
+ * Sockets shall be bound and connected as necessary. Stream server sockets shall further need
+ * to have vc_container_net_listen and vc_container_net_accept called on them before data can be transferred.
+ *
+ * \param address Network address or NULL.
+ * \param port Network port or well-known name. This is the local port for receivers/servers.
+ * \param flags Flags controlling socket type.
+ * \param p_status Optional pointer to variable to receive status of operation.
+ * \return The socket instance or NULL on error. */
+VC_CONTAINER_NET_T *vc_container_net_open( const char *address, const char *port,
+      vc_container_net_open_flags_t flags, vc_container_net_status_t *p_status );
+
+/** Closes a network socket instance.
+ * The p_ctx pointer must not be used after it has been closed.
+ *
+ * \param p_ctx The socket instance to close.
+ * \return The status code for closing the socket. */
+vc_container_net_status_t vc_container_net_close( VC_CONTAINER_NET_T *p_ctx );
+
+/** Query the latest status of the socket.
+ *
+ * \param p_ctx The socket instance.
+ * \return The status of the socket. */
+vc_container_net_status_t vc_container_net_status( VC_CONTAINER_NET_T *p_ctx );
+
+/** Read data from the socket.
+ * The function will read up to the requested number of bytes into the buffer.
+ * If there is no data immediately available to read, the function will block
+ * until data arrives, an error occurs or the timeout is reached (if set).
+ * When the function returns zero, the socket may have been closed, an error
+ * may have occurred, a zero length datagram received, or the timeout reached.
+ * Check vc_container_net_status() to differentiate.
+ * Attempting to read on a datagram sender socket will trigger an error.
+ *
+ * \param p_ctx The socket instance.
+ * \param buffer The buffer into which bytes will be read.
+ * \param size The maximum number of bytes to read.
+ * \return The number of bytes actually read. */
+size_t vc_container_net_read( VC_CONTAINER_NET_T *p_ctx, void *buffer, size_t size );
+
+/** Write data to the socket.
+ * If the socket cannot send the requested number of bytes in one go, the function
+ * will return a value smaller than size.
+ * Attempting to write on a datagram receiver socket will trigger an error.
+ *
+ * \param p_ctx The socket instance.
+ * \param buffer The buffer from which bytes will be written.
+ * \param size The maximum number of bytes to write.
+ * \return The number of bytes actually written. */
+size_t vc_container_net_write( VC_CONTAINER_NET_T *p_ctx, const void *buffer, size_t size );
+
+/** Start a stream server socket listening for connections from clients.
+ * Attempting to use this on anything other than a stream server socket shall
+ * trigger an error.
+ *
+ * \param p_ctx The socket instance.
+ * \param maximum_connections The maximum number of queued connections to allow.
+ * \return The status of the socket. */
+vc_container_net_status_t vc_container_net_listen( VC_CONTAINER_NET_T *p_ctx, uint32_t maximum_connections );
+
+/** Accept a client connection on a listening stream server socket.
+ * Attempting to use this on anything other than a listening stream server socket
+ * shall trigger an error.
+ * When a client connection is made, the new instance representing it is returned
+ * via pp_client_ctx.
+ *
+ * \param p_server ctx The server socket instance.
+ * \param pp_client_ctx The address where the pointer to the new client's socket
+ * instance is written.
+ * \return The status of the socket. */
+vc_container_net_status_t vc_container_net_accept( VC_CONTAINER_NET_T *p_server_ctx, VC_CONTAINER_NET_T **pp_client_ctx );
+
+/** Non-blocking check for data being available to read.
+ * If an error occurs, the function will return false and the error can be
+ * obtained using socket_status().
+ *
+ * \param p_ctx The socket instance.
+ * \return True if there is data available to read immediately. */
+bool vc_container_net_is_data_available( VC_CONTAINER_NET_T *p_ctx );
+
+/** Returns the maximum size of a datagram in bytes, for sending or receiving.
+ * The limit for reading from or writing to stream sockets will generally be
+ * greater than this value, although the call can also be made on such sockets.
+ *
+ * \param p_ctx The socket instance.
+ * \return The maximum size of a datagram in bytes. */
+size_t vc_container_net_maximum_datagram_size( VC_CONTAINER_NET_T *p_ctx );
+
+/** Get the DNS name or IP address of a stream server client, if connected.
+ * The length of the name will be limited by name_len, taking into account a
+ * terminating NUL character.
+ * Calling this function on a non-stream server instance, or one that is not
+ * connected to a client, will result in an error status.
+ * 
+ * \param p_ctx The socket instance.
+ * \param name Pointer where the name should be written.
+ * \param name_len Maximum number of characters to write to name.
+ * \return The status of the socket. */
+vc_container_net_status_t vc_container_net_get_client_name( VC_CONTAINER_NET_T *p_ctx, char *name, size_t name_len );
+
+/** Get the port of a stream server client, if connected.
+ * The port is written to the address in host order.
+ * Calling this function on a non-stream server instance, or one that is not
+ * connected to a client, will result in an error status.
+ * 
+ * \param p_ctx The socket instance.
+ * \param port Pointer where the port should be written.
+ * \return The status of the socket. */
+vc_container_net_status_t vc_container_net_get_client_port( VC_CONTAINER_NET_T *p_ctx , unsigned short *port );
+
+/** Perform a control operation on the socket.
+ * See vc_container_net_control_t for more details.
+ * 
+ * \param p_ctx The socket instance.
+ * \param operation The control operation to perform.
+ * \param args Variable list of additional arguments to the operation.
+ * \return The status of the socket. */
+vc_container_net_status_t vc_container_net_control( VC_CONTAINER_NET_T *p_ctx, vc_container_net_control_t operation, va_list args);
+
+/** Convert a 32-bit unsigned value from network order (big endian) to host order.
+ *
+ * \param value The value to be converted.
+ * \return The converted value. */
+uint32_t vc_container_net_to_host( uint32_t value );
+
+/** Convert a 32-bit unsigned value from host order to network order (big endian).
+ *
+ * \param value The value to be converted.
+ * \return The converted value. */
+uint32_t vc_container_net_from_host( uint32_t value );
+
+/** Convert a 16-bit unsigned value from network order (big endian) to host order.
+ *
+ * \param value The value to be converted.
+ * \return The converted value. */
+uint16_t vc_container_net_to_host_16( uint16_t value );
+
+/** Convert a 16-bit unsigned value from host order to network order (big endian).
+ *
+ * \param value The value to be converted.
+ * \return The converted value. */
+uint16_t vc_container_net_from_host_16( uint16_t value );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* VC_NET_SOCKETS_H */
diff --git a/containers/net/net_sockets_bsd.c b/containers/net/net_sockets_bsd.c
new file mode 100755 (executable)
index 0000000..4503a9a
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <errno.h>
+#include <unistd.h>
+
+#include "net_sockets.h"
+#include "net_sockets_priv.h"
+#include "containers/core/containers_common.h"
+
+/*****************************************************************************/
+
+/** Default maximum datagram size.
+ * This is based on the default Ethernet MTU size, less the IP and UDP headers.
+ */
+#define DEFAULT_MAXIMUM_DATAGRAM_SIZE (1500 - 20 - 8)
+
+/** Maximum socket buffer size to use. */
+#define MAXIMUM_BUFFER_SIZE   65536
+
+/*****************************************************************************/
+vc_container_net_status_t vc_container_net_private_last_error()
+{
+   switch (errno)
+   {
+   case EACCES:               return VC_CONTAINER_NET_ERROR_ACCESS_DENIED;
+   case EFAULT:               return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
+   case EINVAL:               return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
+   case EMFILE:               return VC_CONTAINER_NET_ERROR_TOO_BIG;
+   case EWOULDBLOCK:          return VC_CONTAINER_NET_ERROR_WOULD_BLOCK;
+   case EINPROGRESS:          return VC_CONTAINER_NET_ERROR_IN_PROGRESS;
+   case EALREADY:             return VC_CONTAINER_NET_ERROR_IN_PROGRESS;
+   case EADDRINUSE:           return VC_CONTAINER_NET_ERROR_IN_USE;
+   case EADDRNOTAVAIL:        return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
+   case ENETDOWN:             return VC_CONTAINER_NET_ERROR_NETWORK;
+   case ENETUNREACH:          return VC_CONTAINER_NET_ERROR_NETWORK;
+   case ENETRESET:            return VC_CONTAINER_NET_ERROR_CONNECTION_LOST;
+   case ECONNABORTED:         return VC_CONTAINER_NET_ERROR_CONNECTION_LOST;
+   case ECONNRESET:           return VC_CONTAINER_NET_ERROR_CONNECTION_LOST;
+   case ENOBUFS:              return VC_CONTAINER_NET_ERROR_NO_MEMORY;
+   case ENOTCONN:             return VC_CONTAINER_NET_ERROR_NOT_CONNECTED;
+   case ESHUTDOWN:            return VC_CONTAINER_NET_ERROR_CONNECTION_LOST;
+   case ETIMEDOUT:            return VC_CONTAINER_NET_ERROR_TIMED_OUT;
+   case ECONNREFUSED:         return VC_CONTAINER_NET_ERROR_CONNECTION_REFUSED;
+   case ELOOP:                return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
+   case ENAMETOOLONG:         return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
+   case EHOSTDOWN:            return VC_CONTAINER_NET_ERROR_NETWORK;
+   case EHOSTUNREACH:         return VC_CONTAINER_NET_ERROR_NETWORK;
+   case EUSERS:               return VC_CONTAINER_NET_ERROR_NO_MEMORY;
+   case EDQUOT:               return VC_CONTAINER_NET_ERROR_NO_MEMORY;
+   case ESTALE:               return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
+
+   /* All other errors are unexpected, so just map to a general purpose error code. */
+   default:
+      return VC_CONTAINER_NET_ERROR_GENERAL;
+   }
+}
+
+/*****************************************************************************/
+vc_container_net_status_t vc_container_net_private_init()
+{
+   /* No additional initialization required */
+   return VC_CONTAINER_NET_SUCCESS;
+}
+
+/*****************************************************************************/
+void vc_container_net_private_deinit()
+{
+   /* No additional deinitialization required */
+}
+
+/*****************************************************************************/
+void vc_container_net_private_close( SOCKET_T sock )
+{
+   close(sock);
+}
+
+/*****************************************************************************/
+void vc_container_net_private_set_reusable( SOCKET_T sock, bool enable )
+{
+   int opt = enable ? 1 : 0;
+
+   (void)setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt));
+}
+
+/*****************************************************************************/
+size_t vc_container_net_private_maximum_datagram_size( SOCKET_T sock )
+{
+   (void)sock;
+
+   /* No easy way to determine this, just use the default. */
+   return DEFAULT_MAXIMUM_DATAGRAM_SIZE;
+}
diff --git a/containers/net/net_sockets_bsd.h b/containers/net/net_sockets_bsd.h
new file mode 100755 (executable)
index 0000000..fd554c9
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _NET_SOCKETS_BSD_H_
+#define _NET_SOCKETS_BSD_H_
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+typedef int SOCKET_T;
+typedef socklen_t SOCKADDR_LEN_T;
+typedef void *SOCKOPT_CAST_T;
+#define INVALID_SOCKET -1
+#define SOCKET_ERROR -1
+
+#endif   /* _NET_SOCKETS_BSD_H_ */
diff --git a/containers/net/net_sockets_common.c b/containers/net/net_sockets_common.c
new file mode 100755 (executable)
index 0000000..b3815f3
--- /dev/null
@@ -0,0 +1,619 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "containers/containers.h"
+#include "containers/core/containers_common.h"
+#include "containers/core/containers_logging.h"
+#include "net_sockets.h"
+#include "net_sockets_priv.h"
+
+/*****************************************************************************/
+
+struct vc_container_net_tag
+{
+   /** The underlying socket */
+   SOCKET_T socket;
+   /** Last error raised on the socket instance. */
+   vc_container_net_status_t status;
+   /** Simple socket type */
+   vc_container_net_type_t type;
+   /** Socket address, used for sending datagrams. */
+   union {
+      struct sockaddr_storage storage;
+      struct sockaddr     sa;
+      struct sockaddr_in  in;
+      struct sockaddr_in6 in6;
+   } to_addr;
+   /** Number of bytes in to_addr that have been filled. */
+   SOCKADDR_LEN_T to_addr_len;
+   /** Maximum size of datagrams. */
+   size_t max_datagram_size;
+   /** Timeout to use when reading from a socket. INFINITE_TIMEOUT_MS waits forever. */
+   uint32_t read_timeout_ms;
+};
+
+/*****************************************************************************/
+static void socket_clear_address(struct sockaddr *p_addr)
+{
+   switch (p_addr->sa_family)
+   {
+   case AF_INET:
+      {
+         struct sockaddr_in *p_addr_v4 = (struct sockaddr_in *)p_addr;
+
+         memset(&p_addr_v4->sin_addr, 0, sizeof(p_addr_v4->sin_addr));
+      }
+      break;
+   case AF_INET6:
+      {
+         struct sockaddr_in6 *p_addr_v6 = (struct sockaddr_in6 *)p_addr;
+
+         memset(&p_addr_v6->sin6_addr, 0, sizeof(p_addr_v6->sin6_addr));
+      }
+      break;
+   default:
+      /* Invalid or unsupported address family */
+      vc_container_assert(0);
+   }
+}
+
+/*****************************************************************************/
+static vc_container_net_status_t socket_set_read_buffer_size(VC_CONTAINER_NET_T *p_ctx,
+      uint32_t buffer_size)
+{
+   int result;
+   const SOCKOPT_CAST_T optptr = (const SOCKOPT_CAST_T)&buffer_size;
+
+   result = setsockopt(p_ctx->socket, SOL_SOCKET, SO_RCVBUF, optptr, sizeof(buffer_size));
+
+   if (result == SOCKET_ERROR)
+      return vc_container_net_private_last_error();
+
+   return VC_CONTAINER_NET_SUCCESS;
+}
+
+/*****************************************************************************/
+static vc_container_net_status_t socket_set_read_timeout_ms(VC_CONTAINER_NET_T *p_ctx,
+      uint32_t timeout_ms)
+{
+   p_ctx->read_timeout_ms = timeout_ms;
+   return VC_CONTAINER_NET_SUCCESS;
+}
+
+/*****************************************************************************/
+static bool socket_wait_for_data( VC_CONTAINER_NET_T *p_ctx, uint32_t timeout_ms )
+{
+   int result;
+   fd_set set;
+   struct timeval tv;
+
+   if (timeout_ms == INFINITE_TIMEOUT_MS)
+      return true;
+
+   FD_ZERO(&set);
+   FD_SET(p_ctx->socket, &set);
+   tv.tv_sec = timeout_ms / 1000;
+   tv.tv_usec = (timeout_ms - tv.tv_sec * 1000) * 1000;
+   result = select(p_ctx->socket + 1, &set, NULL, NULL, &tv);
+
+   if (result == SOCKET_ERROR)
+      p_ctx->status = vc_container_net_private_last_error();
+   else
+      p_ctx->status = VC_CONTAINER_NET_SUCCESS;
+
+   return (result == 1);
+}
+
+/*****************************************************************************/
+VC_CONTAINER_NET_T *vc_container_net_open( const char *address, const char *port,
+      vc_container_net_open_flags_t flags, vc_container_net_status_t *p_status )
+{
+   VC_CONTAINER_NET_T *p_ctx;
+   struct addrinfo hints, *info, *p;
+   int result;
+   vc_container_net_status_t status;
+   SOCKET_T sock = INVALID_SOCKET;
+
+   status = vc_container_net_private_init();
+   if (status != VC_CONTAINER_NET_SUCCESS)
+   {
+      LOG_ERROR(NULL, "vc_container_net_open: platform initialization failure: %d", status);
+      if (p_status)
+         *p_status = status;
+      return NULL;
+   }
+
+   p_ctx = (VC_CONTAINER_NET_T *)malloc(sizeof(VC_CONTAINER_NET_T));
+   if (!p_ctx)
+   {
+      if (p_status)
+         *p_status = VC_CONTAINER_NET_ERROR_NO_MEMORY;
+
+      LOG_ERROR(NULL, "vc_container_net_open: malloc fail for VC_CONTAINER_NET_T");
+      vc_container_net_private_deinit();
+      return NULL;
+   }
+
+   /* Initialize the net socket instance structure */
+   memset(p_ctx, 0, sizeof(*p_ctx));
+   p_ctx->socket = INVALID_SOCKET;
+   if (flags & VC_CONTAINER_NET_OPEN_FLAG_STREAM)
+      p_ctx->type = address ? STREAM_CLIENT : STREAM_SERVER;
+   else
+      p_ctx->type = address ? DATAGRAM_SENDER : DATAGRAM_RECEIVER;
+
+   /* Create the address info linked list from the data provided */
+   memset(&hints, 0, sizeof(hints));
+   switch (flags & VC_CONTAINER_NET_OPEN_FLAG_FORCE_MASK)
+   {
+   case 0:
+      hints.ai_family = AF_UNSPEC;
+      break;
+   case VC_CONTAINER_NET_OPEN_FLAG_FORCE_IP4:
+      hints.ai_family = AF_INET;
+      break;
+   case VC_CONTAINER_NET_OPEN_FLAG_FORCE_IP6:
+      hints.ai_family = AF_INET6;
+      break;
+   default:
+      status = VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
+      LOG_ERROR(NULL, "vc_container_net_open: invalid address forcing flag");
+      goto error;
+   }
+   hints.ai_socktype = (flags & VC_CONTAINER_NET_OPEN_FLAG_STREAM) ? SOCK_STREAM : SOCK_DGRAM;
+
+   result = getaddrinfo(address, port, &hints, &info);
+   if (result)
+   {
+      status = vc_container_net_private_last_error();
+      LOG_ERROR(NULL, "vc_container_net_open: unable to get address info: %d", status);
+      goto error;
+   }
+
+   /* Not all address infos may be useable. Search for one that is by skipping any
+    * that provoke errors. */
+   for(p = info; (p != NULL) && (sock == INVALID_SOCKET) ; p = p->ai_next)
+   {
+      sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
+      if (sock == INVALID_SOCKET)
+      {
+         status = vc_container_net_private_last_error();
+         continue;
+      }
+
+      switch (p_ctx->type)
+      {
+      case STREAM_CLIENT:
+            /* Simply connect to the given address/port */
+            if (connect(sock, p->ai_addr, p->ai_addrlen) == SOCKET_ERROR) 
+               status = vc_container_net_private_last_error();
+            break;
+
+      case DATAGRAM_SENDER:
+            /* Nothing further to do */
+            break;
+
+      case STREAM_SERVER:
+            /* Try to avoid socket reuse timing issues on TCP server sockets */
+            vc_container_net_private_set_reusable(sock, true);
+
+            /* Allow any source address */
+            socket_clear_address(p->ai_addr);
+
+            if (bind(sock, p->ai_addr, p->ai_addrlen) == SOCKET_ERROR)
+               status = vc_container_net_private_last_error();
+            break;
+
+      case DATAGRAM_RECEIVER:
+            /* Allow any source address */
+            socket_clear_address(p->ai_addr);
+
+            if (bind(sock, p->ai_addr, p->ai_addrlen) == SOCKET_ERROR)
+               status = vc_container_net_private_last_error();
+            break;
+      }
+
+      if (status == VC_CONTAINER_NET_SUCCESS)
+      {
+         /* Save addressing information for later use */
+         p_ctx->to_addr_len = p->ai_addrlen;
+         memcpy(&p_ctx->to_addr, p->ai_addr, p->ai_addrlen);
+      } else {
+         vc_container_net_private_close(sock);   /* Try next entry in list */
+         sock = INVALID_SOCKET;
+      }
+   }
+
+   freeaddrinfo(info);
+
+   if (sock == INVALID_SOCKET)
+   {
+      LOG_ERROR(NULL, "vc_container_net_open: failed to open socket: %d", status);
+      goto error;
+   }
+
+   p_ctx->socket = sock;
+   p_ctx->max_datagram_size = vc_container_net_private_maximum_datagram_size(sock);
+   p_ctx->read_timeout_ms = INFINITE_TIMEOUT_MS;
+
+   if (p_status)
+      *p_status = VC_CONTAINER_NET_SUCCESS;
+
+   return p_ctx;
+
+error:
+   if (p_status)
+      *p_status = status;
+   (void)vc_container_net_close(p_ctx);
+   return NULL;
+}
+
+/*****************************************************************************/
+vc_container_net_status_t vc_container_net_close( VC_CONTAINER_NET_T *p_ctx )
+{
+   if (!p_ctx)
+      return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
+
+   if (p_ctx->socket != INVALID_SOCKET)
+   {
+      vc_container_net_private_close(p_ctx->socket);
+      p_ctx->socket = INVALID_SOCKET;
+   }
+   free(p_ctx);
+
+   vc_container_net_private_deinit();
+
+   return VC_CONTAINER_NET_SUCCESS;
+}
+
+/*****************************************************************************/
+vc_container_net_status_t vc_container_net_status( VC_CONTAINER_NET_T *p_ctx )
+{
+   if (!p_ctx)
+      return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
+   return p_ctx->status;
+}
+
+/*****************************************************************************/
+size_t vc_container_net_read( VC_CONTAINER_NET_T *p_ctx, void *buffer, size_t size )
+{
+   int result = 0;
+
+   if (!p_ctx)
+      return 0;
+
+   if (!buffer)
+   {
+      p_ctx->status = VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
+      return 0;
+   }
+
+   p_ctx->status = VC_CONTAINER_NET_SUCCESS;
+
+   switch (p_ctx->type)
+   {
+   case STREAM_CLIENT:
+   case STREAM_SERVER:
+      /* Receive data from the stream */
+      if (socket_wait_for_data(p_ctx, p_ctx->read_timeout_ms))
+      {
+         result = recv(p_ctx->socket, buffer, (int)size, 0);
+         if (!result)
+            p_ctx->status = VC_CONTAINER_NET_ERROR_CONNECTION_LOST;
+      } else
+         p_ctx->status = VC_CONTAINER_NET_ERROR_TIMED_OUT;
+      break;
+
+   case DATAGRAM_RECEIVER:
+      {
+         /* Receive the packet */
+         /* FIXME Potential for data loss, as rest of packet will be lost if buffer was not large enough */
+         if (socket_wait_for_data(p_ctx, p_ctx->read_timeout_ms))
+         {
+            result = recvfrom(p_ctx->socket, buffer, size, 0, &p_ctx->to_addr.sa, &p_ctx->to_addr_len);
+            if (!result)
+               p_ctx->status = VC_CONTAINER_NET_ERROR_CONNECTION_LOST;
+         } else
+            p_ctx->status = VC_CONTAINER_NET_ERROR_TIMED_OUT;
+      }
+      break;
+
+   default: /* DATAGRAM_SENDER */
+      p_ctx->status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED;
+      result = 0;
+      break;
+   }
+
+   if (result == SOCKET_ERROR)
+   {
+      p_ctx->status = vc_container_net_private_last_error();
+      result = 0;
+   }
+
+   return (size_t)result;
+}
+
+/*****************************************************************************/
+size_t vc_container_net_write( VC_CONTAINER_NET_T *p_ctx, const void *buffer, size_t size )
+{
+   int result;
+
+   if (!p_ctx)
+      return 0;
+
+   if (!buffer)
+   {
+      p_ctx->status = VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
+      return 0;
+   }
+
+   p_ctx->status = VC_CONTAINER_NET_SUCCESS;
+
+   switch (p_ctx->type)
+   {
+   case STREAM_CLIENT:
+   case STREAM_SERVER:
+      /* Send data to the stream */
+      result = send(p_ctx->socket, buffer, (int)size, 0);
+      break;
+
+   case DATAGRAM_SENDER:
+      /* Send the datagram */
+
+      if (size > p_ctx->max_datagram_size)
+         size = p_ctx->max_datagram_size;
+
+      result = sendto(p_ctx->socket, buffer, size, 0, &p_ctx->to_addr.sa, p_ctx->to_addr_len);
+      break;
+
+   default: /* DATAGRAM_RECEIVER */
+      p_ctx->status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED;
+      result = 0;
+      break;
+   }
+
+   if (result == SOCKET_ERROR)
+   {
+      p_ctx->status = vc_container_net_private_last_error();
+      result = 0;
+   }
+
+   return (size_t)result;
+}
+
+/*****************************************************************************/
+vc_container_net_status_t vc_container_net_listen( VC_CONTAINER_NET_T *p_ctx, uint32_t maximum_connections )
+{
+   if (!p_ctx)
+      return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
+
+   p_ctx->status = VC_CONTAINER_NET_SUCCESS;
+
+   if (p_ctx->type == STREAM_SERVER)
+   {
+      if (listen(p_ctx->socket, maximum_connections) == SOCKET_ERROR)
+         p_ctx->status = vc_container_net_private_last_error();
+   } else {
+      p_ctx->status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED;
+   }
+
+   return p_ctx->status;
+}
+
+/*****************************************************************************/
+vc_container_net_status_t vc_container_net_accept( VC_CONTAINER_NET_T *p_server_ctx, VC_CONTAINER_NET_T **pp_client_ctx )
+{
+   VC_CONTAINER_NET_T *p_client_ctx = NULL;
+
+   if (!p_server_ctx)
+      return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
+
+   if (!pp_client_ctx)
+      return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
+
+   *pp_client_ctx = NULL;
+
+   if (p_server_ctx->type != STREAM_SERVER)
+   {
+      p_server_ctx->status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED;
+      goto error;
+   }
+
+   p_client_ctx = (VC_CONTAINER_NET_T *)malloc(sizeof(VC_CONTAINER_NET_T));
+   if (!p_client_ctx)
+   {
+      p_server_ctx->status = VC_CONTAINER_NET_ERROR_NO_MEMORY;
+      goto error;
+   }
+
+   /* Initialise the new context with the address information from the server context */
+   memset(p_client_ctx, 0, sizeof(*p_client_ctx));
+   memcpy(&p_client_ctx->to_addr, &p_server_ctx->to_addr, p_server_ctx->to_addr_len);
+   p_client_ctx->to_addr_len = p_server_ctx->to_addr_len;
+
+   p_client_ctx->socket = accept(p_server_ctx->socket, &p_client_ctx->to_addr.sa, &p_client_ctx->to_addr_len);
+
+   if (p_client_ctx->socket == INVALID_SOCKET)
+   {
+      p_server_ctx->status = vc_container_net_private_last_error();
+      goto error;
+   }
+
+   /* Need to bump up the initialisation count, as a new context has been created */
+   p_server_ctx->status = vc_container_net_private_init();
+   if (p_server_ctx->status != VC_CONTAINER_NET_SUCCESS)
+      goto error;
+
+   p_client_ctx->type = STREAM_CLIENT;
+   p_client_ctx->max_datagram_size = vc_container_net_private_maximum_datagram_size(p_client_ctx->socket);
+   p_client_ctx->read_timeout_ms = INFINITE_TIMEOUT_MS;
+   p_client_ctx->status = VC_CONTAINER_NET_SUCCESS;
+
+   *pp_client_ctx = p_client_ctx;
+   return VC_CONTAINER_NET_SUCCESS;
+
+error:
+   if (p_client_ctx)
+      free(p_client_ctx);
+   return p_server_ctx->status;
+}
+
+/*****************************************************************************/
+bool vc_container_net_is_data_available( VC_CONTAINER_NET_T *p_ctx )
+{
+   if (!p_ctx)
+      return false;
+
+   if (p_ctx->type == DATAGRAM_SENDER)
+   {
+      p_ctx->status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED;
+      return false;
+   }
+
+   return socket_wait_for_data(p_ctx, 0);
+}
+
+/*****************************************************************************/
+size_t vc_container_net_maximum_datagram_size( VC_CONTAINER_NET_T *p_ctx )
+{
+   return p_ctx ? p_ctx->max_datagram_size : 0;
+}
+
+/*****************************************************************************/
+static vc_container_net_status_t translate_getnameinfo_error( int error )
+{
+   switch (error)
+   {
+   case EAI_AGAIN:   return VC_CONTAINER_NET_ERROR_TRY_AGAIN;
+   case EAI_FAIL:    return VC_CONTAINER_NET_ERROR_HOST_NOT_FOUND;
+   case EAI_MEMORY:  return VC_CONTAINER_NET_ERROR_NO_MEMORY;
+   case EAI_NONAME:  return VC_CONTAINER_NET_ERROR_HOST_NOT_FOUND;
+
+   /* All other errors are unexpected, so just map to a general purpose error code. */
+   default:
+      return VC_CONTAINER_NET_ERROR_GENERAL;
+   }
+}
+
+/*****************************************************************************/
+vc_container_net_status_t vc_container_net_get_client_name( VC_CONTAINER_NET_T *p_ctx, char *name, size_t name_len )
+{
+   int result;
+
+   if (!p_ctx)
+      return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
+
+   if (p_ctx->socket == INVALID_SOCKET)
+      p_ctx->status = VC_CONTAINER_NET_ERROR_NOT_CONNECTED;
+   else if (!name || !name_len)
+      p_ctx->status = VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
+   else if ((result = getnameinfo(&p_ctx->to_addr.sa, p_ctx->to_addr_len, name, name_len, NULL, 0, 0)) != 0)
+      p_ctx->status = translate_getnameinfo_error(result);
+   else
+      p_ctx->status = VC_CONTAINER_NET_SUCCESS;
+
+   return p_ctx->status;
+}
+
+/*****************************************************************************/
+vc_container_net_status_t vc_container_net_get_client_port( VC_CONTAINER_NET_T *p_ctx , unsigned short *port )
+{
+   if (!p_ctx)
+      return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
+
+   if (p_ctx->socket == INVALID_SOCKET)
+      p_ctx->status = VC_CONTAINER_NET_ERROR_NOT_CONNECTED;
+   else if (!port)
+      p_ctx->status = VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
+   else
+   {
+      p_ctx->status = VC_CONTAINER_NET_SUCCESS;
+      switch (p_ctx->to_addr.sa.sa_family)
+      {
+      case AF_INET:
+         *port = ntohs(p_ctx->to_addr.in.sin_port);
+         break;
+      case AF_INET6:
+         *port = ntohs(p_ctx->to_addr.in6.sin6_port);
+         break;
+      default:
+         /* Highly unexepcted address family! */
+         p_ctx->status = VC_CONTAINER_NET_ERROR_GENERAL;
+      }
+   }
+
+   return p_ctx->status;
+}
+
+/*****************************************************************************/
+vc_container_net_status_t vc_container_net_control( VC_CONTAINER_NET_T *p_ctx,
+      vc_container_net_control_t operation,
+      va_list args)
+{
+   vc_container_net_status_t status;
+
+   switch (operation)
+   {
+   case VC_CONTAINER_NET_CONTROL_SET_READ_BUFFER_SIZE:
+      status = socket_set_read_buffer_size(p_ctx, va_arg(args, uint32_t));
+      break;
+   case VC_CONTAINER_NET_CONTROL_SET_READ_TIMEOUT_MS:
+      status = socket_set_read_timeout_ms(p_ctx, va_arg(args, uint32_t));
+      break;
+   default:
+      status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED;
+   }
+
+   return status;
+}
+
+/*****************************************************************************/
+uint32_t vc_container_net_to_host( uint32_t value )
+{
+   return ntohl(value);
+}
+
+/*****************************************************************************/
+uint32_t vc_container_net_from_host( uint32_t value )
+{
+   return htonl(value);
+}
+
+/*****************************************************************************/
+uint16_t vc_container_net_to_host_16( uint16_t value )
+{
+   return ntohs(value);
+}
+
+/*****************************************************************************/
+uint16_t vc_container_net_from_host_16( uint16_t value )
+{
+   return htons(value);
+}
diff --git a/containers/net/net_sockets_null.c b/containers/net/net_sockets_null.c
new file mode 100755 (executable)
index 0000000..a8fe8fb
--- /dev/null
@@ -0,0 +1,175 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "net_sockets.h"
+#include "containers/core/containers_common.h"
+
+/*****************************************************************************/
+
+struct vc_container_net_tag
+{
+   uint32_t dummy;   /* C requires structs not to be empty. */
+};
+
+/*****************************************************************************/
+VC_CONTAINER_NET_T *vc_container_net_open( const char *address, const char *port,
+      vc_container_net_open_flags_t flags, vc_container_net_status_t *p_status )
+{
+   VC_CONTAINER_PARAM_UNUSED(address);
+   VC_CONTAINER_PARAM_UNUSED(port);
+   VC_CONTAINER_PARAM_UNUSED(flags);
+
+   if (p_status)
+      *p_status = VC_CONTAINER_NET_ERROR_NOT_ALLOWED;
+
+   return NULL;
+}
+
+/*****************************************************************************/
+vc_container_net_status_t vc_container_net_close( VC_CONTAINER_NET_T *p_ctx )
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+
+   return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
+}
+
+/*****************************************************************************/
+vc_container_net_status_t vc_container_net_status( VC_CONTAINER_NET_T *p_ctx )
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+
+   return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
+}
+
+/*****************************************************************************/
+size_t vc_container_net_read( VC_CONTAINER_NET_T *p_ctx, void *buffer, size_t size )
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+   VC_CONTAINER_PARAM_UNUSED(buffer);
+   VC_CONTAINER_PARAM_UNUSED(size);
+
+   return 0;
+}
+
+/*****************************************************************************/
+size_t vc_container_net_write( VC_CONTAINER_NET_T *p_ctx, const void *buffer, size_t size )
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+   VC_CONTAINER_PARAM_UNUSED(buffer);
+   VC_CONTAINER_PARAM_UNUSED(size);
+
+   return 0;
+}
+
+/*****************************************************************************/
+vc_container_net_status_t vc_container_net_listen( VC_CONTAINER_NET_T *p_ctx, uint32_t maximum_connections )
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+   VC_CONTAINER_PARAM_UNUSED(maximum_connections);
+
+   return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
+}
+
+/*****************************************************************************/
+vc_container_net_status_t vc_container_net_accept( VC_CONTAINER_NET_T *p_server_ctx, VC_CONTAINER_NET_T **pp_client_ctx )
+{
+   VC_CONTAINER_PARAM_UNUSED(p_server_ctx);
+   VC_CONTAINER_PARAM_UNUSED(pp_client_ctx);
+
+   return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
+}
+
+/*****************************************************************************/
+bool vc_container_net_is_data_available( VC_CONTAINER_NET_T *p_ctx )
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+
+   return false;
+}
+
+/*****************************************************************************/
+size_t vc_container_net_maximum_datagram_size( VC_CONTAINER_NET_T *p_ctx )
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+
+   return 0;
+}
+
+/*****************************************************************************/
+vc_container_net_status_t vc_container_net_get_client_name( VC_CONTAINER_NET_T *p_ctx, char *name, size_t name_len )
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+   VC_CONTAINER_PARAM_UNUSED(name);
+   VC_CONTAINER_PARAM_UNUSED(name_len);
+
+   return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
+}
+
+/*****************************************************************************/
+vc_container_net_status_t vc_container_net_get_client_port( VC_CONTAINER_NET_T *p_ctx , unsigned short *port )
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+   VC_CONTAINER_PARAM_UNUSED(port);
+
+   return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
+}
+
+/*****************************************************************************/
+vc_container_net_status_t vc_container_net_control( VC_CONTAINER_NET_T *p_ctx,
+      vc_container_net_control_t operation,
+      va_list args)
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+   VC_CONTAINER_PARAM_UNUSED(operation);
+   VC_CONTAINER_PARAM_UNUSED(args);
+
+   return VC_CONTAINER_NET_ERROR_NOT_ALLOWED;
+}
+
+/*****************************************************************************/
+uint32_t vc_container_net_to_host( uint32_t value )
+{
+   return value;
+}
+
+/*****************************************************************************/
+uint32_t vc_container_net_from_host( uint32_t value )
+{
+   return value;
+}
+
+/*****************************************************************************/
+uint16_t vc_container_net_to_host_16( uint16_t value )
+{
+   return value;
+}
+
+/*****************************************************************************/
+uint16_t vc_container_net_from_host_16( uint16_t value )
+{
+   return value;
+}
diff --git a/containers/net/net_sockets_priv.h b/containers/net/net_sockets_priv.h
new file mode 100755 (executable)
index 0000000..4186083
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _NET_SOCKETS_PRIV_H_
+#define _NET_SOCKETS_PRIV_H_
+
+#include "net_sockets.h"
+
+#ifdef WIN32
+#include "net_sockets_win32.h"
+#else
+#include "net_sockets_bsd.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum
+{
+   STREAM_CLIENT = 0,   /**< TCP client */
+   STREAM_SERVER,       /**< TCP server */
+   DATAGRAM_SENDER,     /**< UDP sender */
+   DATAGRAM_RECEIVER    /**< UDP receiver */
+} vc_container_net_type_t;
+
+
+/** Perform implementation-specific per-socket initialization.
+ *
+ * \return VC_CONTAINER_NET_SUCCESS or one of the error codes on failure. */
+vc_container_net_status_t vc_container_net_private_init( void );
+
+/** Perform implementation-specific per-socket deinitialization.
+ * This function is always called once for each successful call to socket_private_init(). */
+void vc_container_net_private_deinit( void );
+
+/** Return the last error from the socket implementation. */
+vc_container_net_status_t vc_container_net_private_last_error( void );
+
+/** Implementation-specific internal socket close.
+ *
+ * \param sock Internal socket to be closed. */
+void vc_container_net_private_close( SOCKET_T sock );
+
+/** Enable or disable socket address reusability.
+ *
+ * \param sock Internal socket to be closed.
+ * \param enable True to enable reusability, false to clear it. */
+void vc_container_net_private_set_reusable( SOCKET_T sock, bool enable );
+
+/** Query the maximum datagram size for the socket.
+ *
+ * \param sock The socket to query.
+ * \return The maximum supported datagram size on the socket. */
+size_t vc_container_net_private_maximum_datagram_size( SOCKET_T sock );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif   /* _NET_SOCKETS_PRIV_H_ */
diff --git a/containers/net/net_sockets_win32.c b/containers/net/net_sockets_win32.c
new file mode 100755 (executable)
index 0000000..e0dd374
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "net_sockets.h"
+#include "net_sockets_priv.h"
+#include "containers/core/containers_common.h"
+
+#pragma comment(lib, "Ws2_32.lib")
+
+/*****************************************************************************/
+
+/** Default maximum datagram size.
+ * This is based on the default Ethernet MTU size, less the IP and UDP headers.
+ */
+#define DEFAULT_MAXIMUM_DATAGRAM_SIZE (1500 - 20 - 8)
+
+/** Maximum socket buffer size to use. */
+#define MAXIMUM_BUFFER_SIZE   65536
+
+/*****************************************************************************/
+static vc_container_net_status_t translate_error_status( int error )
+{
+   switch (error)
+   {
+   case WSA_INVALID_HANDLE:      return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
+   case WSA_NOT_ENOUGH_MEMORY:   return VC_CONTAINER_NET_ERROR_NO_MEMORY;
+   case WSA_INVALID_PARAMETER:   return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
+   case WSAEACCES:               return VC_CONTAINER_NET_ERROR_ACCESS_DENIED;
+   case WSAEFAULT:               return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
+   case WSAEINVAL:               return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
+   case WSAEMFILE:               return VC_CONTAINER_NET_ERROR_TOO_BIG;
+   case WSAEWOULDBLOCK:          return VC_CONTAINER_NET_ERROR_WOULD_BLOCK;
+   case WSAEINPROGRESS:          return VC_CONTAINER_NET_ERROR_IN_PROGRESS;
+   case WSAEALREADY:             return VC_CONTAINER_NET_ERROR_IN_PROGRESS;
+   case WSAEADDRINUSE:           return VC_CONTAINER_NET_ERROR_IN_USE;
+   case WSAEADDRNOTAVAIL:        return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
+   case WSAENETDOWN:             return VC_CONTAINER_NET_ERROR_NETWORK;
+   case WSAENETUNREACH:          return VC_CONTAINER_NET_ERROR_NETWORK;
+   case WSAENETRESET:            return VC_CONTAINER_NET_ERROR_CONNECTION_LOST;
+   case WSAECONNABORTED:         return VC_CONTAINER_NET_ERROR_CONNECTION_LOST;
+   case WSAECONNRESET:           return VC_CONTAINER_NET_ERROR_CONNECTION_LOST;
+   case WSAENOBUFS:              return VC_CONTAINER_NET_ERROR_NO_MEMORY;
+   case WSAENOTCONN:             return VC_CONTAINER_NET_ERROR_NOT_CONNECTED;
+   case WSAESHUTDOWN:            return VC_CONTAINER_NET_ERROR_CONNECTION_LOST;
+   case WSAETIMEDOUT:            return VC_CONTAINER_NET_ERROR_TIMED_OUT;
+   case WSAECONNREFUSED:         return VC_CONTAINER_NET_ERROR_CONNECTION_REFUSED;
+   case WSAELOOP:                return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
+   case WSAENAMETOOLONG:         return VC_CONTAINER_NET_ERROR_INVALID_PARAMETER;
+   case WSAEHOSTDOWN:            return VC_CONTAINER_NET_ERROR_NETWORK;
+   case WSAEHOSTUNREACH:         return VC_CONTAINER_NET_ERROR_NETWORK;
+   case WSAEPROCLIM:             return VC_CONTAINER_NET_ERROR_NO_MEMORY;
+   case WSAEUSERS:               return VC_CONTAINER_NET_ERROR_NO_MEMORY;
+   case WSAEDQUOT:               return VC_CONTAINER_NET_ERROR_NO_MEMORY;
+   case WSAESTALE:               return VC_CONTAINER_NET_ERROR_INVALID_SOCKET;
+   case WSAEDISCON:              return VC_CONTAINER_NET_ERROR_CONNECTION_LOST;
+   case WSAHOST_NOT_FOUND:       return VC_CONTAINER_NET_ERROR_HOST_NOT_FOUND;
+   case WSATRY_AGAIN:            return VC_CONTAINER_NET_ERROR_TRY_AGAIN;
+   case WSANO_RECOVERY:          return VC_CONTAINER_NET_ERROR_HOST_NOT_FOUND;
+   case WSANO_DATA:              return VC_CONTAINER_NET_ERROR_HOST_NOT_FOUND;
+
+   /* All other errors are unexpected, so just map to a general purpose error code. */
+   default:
+      return VC_CONTAINER_NET_ERROR_GENERAL;
+   }
+}
+
+/*****************************************************************************/
+vc_container_net_status_t vc_container_net_private_last_error()
+{
+   return translate_error_status( WSAGetLastError() );
+}
+
+/*****************************************************************************/
+vc_container_net_status_t vc_container_net_private_init()
+{
+   WSADATA wsa_data;
+   int result;
+
+   result = WSAStartup(MAKEWORD(2,2), &wsa_data);
+   if (result)
+      return translate_error_status( result );
+
+   return VC_CONTAINER_NET_SUCCESS;
+}
+
+/*****************************************************************************/
+void vc_container_net_private_deinit()
+{
+   WSACleanup();
+}
+
+/*****************************************************************************/
+void vc_container_net_private_close( SOCKET_T sock )
+{
+   closesocket(sock);
+}
+
+/*****************************************************************************/
+void vc_container_net_private_set_reusable( SOCKET_T sock, bool enable )
+{
+   BOOL opt = enable ? TRUE : FALSE;
+
+   (void)setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&opt, sizeof(opt));
+}
+
+/*****************************************************************************/
+size_t vc_container_net_private_maximum_datagram_size( SOCKET_T sock )
+{
+   size_t max_datagram_size = DEFAULT_MAXIMUM_DATAGRAM_SIZE;
+   int opt_size = sizeof(max_datagram_size);
+
+   /* Ignore errors and use the default if necessary */
+   (void)getsockopt(sock, SOL_SOCKET, SO_MAX_MSG_SIZE, (char *)&max_datagram_size, &opt_size);
+
+   return max_datagram_size;
+}
diff --git a/containers/net/net_sockets_win32.h b/containers/net/net_sockets_win32.h
new file mode 100755 (executable)
index 0000000..86edc3a
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _NET_SOCKETS_WIN32_H_
+#define _NET_SOCKETS_WIN32_H_
+
+#include <winsock2.h>
+#include <ws2tcpip.h>
+
+typedef SOCKET SOCKET_T;
+typedef int SOCKADDR_LEN_T;
+typedef char *SOCKOPT_CAST_T;
+
+#endif   /* _NET_SOCKETS_WIN32_H_ */
diff --git a/containers/packetizers.h b/containers/packetizers.h
new file mode 100755 (executable)
index 0000000..735816d
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef VC_PACKETIZERS_H
+#define VC_PACKETIZERS_H
+
+/** \file packetizers.h
+ * Public API for packetizing data (i.e. framing and timestamping)
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "containers/containers.h"
+
+/** \defgroup VcPacketizerApi Packetizer API
+ *  API for packetizers */
+/* @{ */
+
+/** \name Packetizer flags
+ * \anchor packetizerflags
+ * The following flags describe properties of a packetizer */
+/* @{ */
+#define VC_PACKETIZER_FLAG_ES_CHANGED 0x1 /**< ES definition has changed */
+/* @} */
+
+/** Definition of the packetizer type */
+typedef struct VC_PACKETIZER_T
+{
+   struct VC_PACKETIZER_PRIVATE_T *priv; /**< Private member used by the implementation */
+   uint32_t flags;                       /**< Flags describing the properties of a packetizer.
+                                           * See \ref packetizerflags "Packetizer flags". */
+
+   VC_CONTAINER_ES_FORMAT_T *in;  /**< Format of the input elementary stream */
+   VC_CONTAINER_ES_FORMAT_T *out;  /**< Format of the output elementary stream */
+
+   uint32_t max_frame_size; /**< Maximum size of a packetized frame */
+
+} VC_PACKETIZER_T;
+
+/** Open a packetizer to convert the input format into the requested output format.
+ * This will create an an instance of a packetizer and its associated context.
+ *
+ * If no packetizer is found for the requested format, this will return a null pointer as well as
+ * an error code indicating why this failed.
+ *
+ * \param  in           Input elementary stream format
+ * \param  out_variant  Requested output variant for the output elementary stream format
+ * \param  status       Returns the status of the operation
+ * \return              A pointer to the context of the new instance of the packetizer.
+ *                      Returns NULL on failure.
+ */
+VC_PACKETIZER_T *vc_packetizer_open(VC_CONTAINER_ES_FORMAT_T *in, VC_CONTAINER_FOURCC_T out_variant,
+   VC_CONTAINER_STATUS_T *status);
+
+/** Closes an instance of a packetizer.
+ * This will free all the resources associated with the context.
+ *
+ * \param  context   Pointer to the context of the instance to close
+ * \return           the status of the operation
+ */
+VC_CONTAINER_STATUS_T vc_packetizer_close( VC_PACKETIZER_T *context );
+
+/** \name Packetizer flags
+ * The following flags can be passed during a packetize call */
+/* @{ */
+/** Type definition for the packetizer flags */
+typedef uint32_t VC_PACKETIZER_FLAGS_T;
+/** Ask the packetizer to only return information on the next packet without reading it */
+#define VC_PACKETIZER_FLAG_INFO   0x1
+/** Ask the packetizer to skip the next packet */
+#define VC_PACKETIZER_FLAG_SKIP   0x2
+/** Ask the packetizer to flush any data being processed */
+#define VC_PACKETIZER_FLAG_FLUSH   0x4
+/** Force the packetizer to release an input packet */
+#define VC_PACKETIZER_FLAG_FORCE_RELEASE_INPUT 0x8
+/* @} */
+
+/** Push a new packet of data to the packetizer.
+ * This is the mechanism used to feed data into the packetizer. Once a packet has been
+ * pushed into the packetizer it is owned by the packetizer until released by a call to
+ * \ref vc_packetizer_pop
+ *
+ * \param  context   Pointer to the context of the packetizer to use
+ * \param  packet    Pointer to the VC_CONTAINER_PACKET_T structure describing the data packet
+ *                   to push into the packetizer.
+ * \return           the status of the operation
+ */
+VC_CONTAINER_STATUS_T vc_packetizer_push( VC_PACKETIZER_T *context,
+   VC_CONTAINER_PACKET_T *packet);
+
+/** Pop a packet of data from the packetizer.
+ * This allows the client to retrieve consumed data from the packetizer. Packets returned by
+ * the packetizer in this manner can then be released / recycled by the client.
+ * It is possible for the client to retrieve non-consumed data by passing the
+ * VC_PACKETIZER_FLAG_FORCE_RELEASE_INPUT flag. This will however trigger some internal buffering
+ * inside the packetizer and thus is less efficient.
+ *
+ * \param  context   Pointer to the context of the packetizer to use
+ * \param  packet    Pointer used to return a consumed packet
+ * \param  flags     Miscellaneous flags controlling the operation
+ *
+ * \return           VC_CONTAINER_SUCCESS if a consumed packet was retrieved,
+ *                   VC_CONTAINER_ERROR_INCOMPLETE_DATA if none is available.
+ */
+VC_CONTAINER_STATUS_T vc_packetizer_pop( VC_PACKETIZER_T *context,
+   VC_CONTAINER_PACKET_T **packet, VC_PACKETIZER_FLAGS_T flags);
+
+/** Read packetized data out of the packetizer.
+ *
+ * \param  context   Pointer to the context of the packetizer to use
+ * \param  packet    Pointer to the VC_CONTAINER_PACKET_T structure describing the data packet
+ *                   This might need to be partially filled before the call (buffer, buffer_size)
+ *                   depending on the flags used.
+ * \param  flags     Miscellaneous flags controlling the operation
+ * \return           the status of the operation
+ */
+VC_CONTAINER_STATUS_T vc_packetizer_read( VC_PACKETIZER_T *context,
+   VC_CONTAINER_PACKET_T *out, VC_PACKETIZER_FLAGS_T flags);
+
+/** Reset packetizer state.
+ * This will reset the state of the packetizer as well as mark all data pushed to it as consumed.
+ *
+ * \param  context   Pointer to the context of the packetizer to reset
+ * \return           the status of the operation
+ */
+VC_CONTAINER_STATUS_T vc_packetizer_reset( VC_PACKETIZER_T *context );
+
+/* @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* VC_PACKETIZERS_H */
diff --git a/containers/pcm/pcm_packetizer.c b/containers/pcm/pcm_packetizer.c
new file mode 100755 (executable)
index 0000000..8dea398
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file
+ * Implementation of a PCM packetizer.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "containers/packetizers.h"
+#include "containers/core/packetizers_private.h"
+#include "containers/core/containers_common.h"
+#include "containers/core/containers_logging.h"
+#include "containers/core/containers_time.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_bytestream.h"
+
+#define FRAME_SIZE (16*1024) /**< Arbitrary value which is neither too small nor too big */
+#define FACTOR_SHIFT 4 /**< Shift applied to the conversion factor */
+
+VC_CONTAINER_STATUS_T pcm_packetizer_open( VC_PACKETIZER_T * );
+
+/*****************************************************************************/
+enum conversion {
+   CONVERSION_NONE = 0,
+   CONVERSION_U8_TO_S16L,
+   CONVERSION_UNKNOWN
+};
+
+typedef struct VC_PACKETIZER_MODULE_T {
+   enum {
+      STATE_NEW_PACKET = 0,
+      STATE_DATA
+   } state;
+
+   unsigned int samples_per_frame;
+   unsigned int bytes_per_sample;
+   unsigned int max_frame_size;
+
+   uint32_t bytes_read;
+   unsigned int frame_size;
+
+   enum conversion conversion;
+   unsigned int conversion_factor;
+} VC_PACKETIZER_MODULE_T;
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T pcm_packetizer_close( VC_PACKETIZER_T *p_ctx )
+{
+   free(p_ctx->priv->module);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T pcm_packetizer_reset( VC_PACKETIZER_T *p_ctx )
+{
+   VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
+   module->state = STATE_NEW_PACKET;
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static void convert_pcm_u8_to_s16l( uint8_t **p_out, uint8_t *in, size_t size)
+{
+   int16_t *out = (int16_t *)*p_out;
+   uint8_t tmp;
+
+   while(size--)
+   {
+      tmp = *in++;
+      *out++ = ((tmp - 128) << 8) | tmp;
+   }
+   *p_out = (uint8_t *)out;
+}
+
+/*****************************************************************************/
+static void convert_pcm( VC_PACKETIZER_T *p_ctx,
+   VC_CONTAINER_BYTESTREAM_T *stream, size_t size, uint8_t *out )
+{
+   VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
+   uint8_t tmp[256];
+   size_t tmp_size;
+
+   while(size)
+   {
+      tmp_size = MIN(sizeof(tmp), size);
+      bytestream_get(stream, tmp, tmp_size);
+      if (module->conversion == CONVERSION_U8_TO_S16L)
+         convert_pcm_u8_to_s16l(&out, tmp, tmp_size);
+      else
+         bytestream_skip(stream, tmp_size);
+      size -= tmp_size;
+   }
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T pcm_packetizer_packetize( VC_PACKETIZER_T *p_ctx,
+   VC_CONTAINER_PACKET_T *out, VC_PACKETIZER_FLAGS_T flags )
+{
+   VC_PACKETIZER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_BYTESTREAM_T *stream = &p_ctx->priv->stream;
+   VC_CONTAINER_TIME_T *time = &p_ctx->priv->time;
+   int64_t pts, dts;
+   size_t offset, size;
+
+   while(1) switch (module->state)
+   {
+   case STATE_NEW_PACKET:
+      /* Make sure we've got enough data */
+      if(bytestream_size(stream) < module->max_frame_size &&
+         !(flags & VC_PACKETIZER_FLAG_FLUSH))
+         return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
+      if(!bytestream_size(stream))
+         return VC_CONTAINER_ERROR_INCOMPLETE_DATA;
+
+      module->frame_size = bytestream_size(stream);
+      if(module->frame_size > module->max_frame_size)
+         module->frame_size = module->max_frame_size;
+      bytestream_get_timestamps_and_offset(stream, &pts, &dts, &offset, true);
+      vc_container_time_set(time, pts);
+      if(pts != VC_CONTAINER_TIME_UNKNOWN)
+         vc_container_time_add(time, offset / module->bytes_per_sample);
+
+      module->bytes_read = 0;
+      module->state = STATE_DATA;
+      /* fall through to the next state */
+
+   case STATE_DATA:
+      size = module->frame_size - module->bytes_read;
+      out->pts = out->dts = VC_CONTAINER_TIME_UNKNOWN;
+      out->flags = VC_CONTAINER_PACKET_FLAG_FRAME_END;
+      out->size = (size * module->conversion_factor) >> FACTOR_SHIFT;
+
+      if(!module->bytes_read)
+      {
+         out->pts = out->dts = vc_container_time_get(time);
+         out->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
+      }
+
+      if(flags & VC_PACKETIZER_FLAG_INFO)
+         return VC_CONTAINER_SUCCESS;
+
+      if(flags & VC_PACKETIZER_FLAG_SKIP)
+      {
+         bytestream_skip( stream, size );
+      }
+      else
+      {
+         out->size = MIN(out->size, out->buffer_size);
+         size = (out->size << FACTOR_SHIFT) / module->conversion_factor;
+         out->size = (size * module->conversion_factor) >> FACTOR_SHIFT;
+
+         if(module->conversion != CONVERSION_NONE)
+            convert_pcm(p_ctx, stream, size, out->data);
+         else
+            bytestream_get(stream, out->data, out->size);
+      }
+      module->bytes_read += size;
+
+      if(module->bytes_read == module->frame_size)
+      {
+         vc_container_time_add(time, module->samples_per_frame);
+         module->state = STATE_NEW_PACKET;
+      }
+      return VC_CONTAINER_SUCCESS;
+
+   default:
+      break;
+   };
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T pcm_packetizer_open( VC_PACKETIZER_T *p_ctx )
+{
+   VC_PACKETIZER_MODULE_T *module;
+   unsigned int bytes_per_sample = 0;
+   enum conversion conversion = CONVERSION_NONE;
+
+   if(p_ctx->in->codec != VC_CONTAINER_CODEC_PCM_UNSIGNED_BE &&
+      p_ctx->in->codec != VC_CONTAINER_CODEC_PCM_UNSIGNED_LE &&
+      p_ctx->in->codec != VC_CONTAINER_CODEC_PCM_SIGNED_BE &&
+      p_ctx->in->codec != VC_CONTAINER_CODEC_PCM_SIGNED_LE &&
+      p_ctx->in->codec != VC_CONTAINER_CODEC_PCM_FLOAT_BE &&
+      p_ctx->in->codec != VC_CONTAINER_CODEC_PCM_FLOAT_LE)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   if(p_ctx->in->type->audio.block_align)
+      bytes_per_sample = p_ctx->in->type->audio.block_align;
+   else if(p_ctx->in->type->audio.bits_per_sample && p_ctx->in->type->audio.channels)
+      bytes_per_sample = p_ctx->in->type->audio.bits_per_sample *
+         p_ctx->in->type->audio.channels / 8;
+
+   if(!bytes_per_sample)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   /* Check if we support any potential conversion we've been asked to do */
+   if(p_ctx->out->codec_variant)
+      conversion = CONVERSION_UNKNOWN;
+   if(p_ctx->out->codec_variant == VC_FOURCC('s','1','6','l') &&
+      p_ctx->in->codec == VC_CONTAINER_CODEC_PCM_SIGNED_LE &&
+      p_ctx->in->type->audio.bits_per_sample == 16)
+      conversion = CONVERSION_NONE;
+   if(p_ctx->out->codec_variant == VC_FOURCC('s','1','6','l') &&
+      (p_ctx->in->codec == VC_CONTAINER_CODEC_PCM_UNSIGNED_LE ||
+       p_ctx->in->codec == VC_CONTAINER_CODEC_PCM_UNSIGNED_BE) &&
+      p_ctx->in->type->audio.bits_per_sample == 8)
+      conversion = CONVERSION_U8_TO_S16L;
+   if(conversion == CONVERSION_UNKNOWN)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   p_ctx->priv->module = module = malloc(sizeof(*module));
+   if(!module)
+      return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+   memset(module, 0, sizeof(*module));
+   module->conversion = conversion;
+   module->conversion_factor = 1 << FACTOR_SHIFT;
+
+   p_ctx->out->codec_variant = 0;
+   if(conversion == CONVERSION_U8_TO_S16L)
+   {
+      module->conversion_factor = 2 << FACTOR_SHIFT;
+      p_ctx->out->type->audio.bits_per_sample *= 2;
+      p_ctx->out->type->audio.block_align *= 2;
+      p_ctx->out->codec = VC_CONTAINER_CODEC_PCM_SIGNED_LE;
+   }
+
+   vc_container_time_set_samplerate(&p_ctx->priv->time, p_ctx->in->type->audio.sample_rate, 1);
+
+   p_ctx->max_frame_size = FRAME_SIZE;
+   module->max_frame_size = (FRAME_SIZE << FACTOR_SHIFT) / module->conversion_factor;
+   module->bytes_per_sample = bytes_per_sample;
+   module->samples_per_frame = module->max_frame_size / bytes_per_sample;
+   p_ctx->priv->pf_close = pcm_packetizer_close;
+   p_ctx->priv->pf_packetize = pcm_packetizer_packetize;
+   p_ctx->priv->pf_reset = pcm_packetizer_reset;
+
+   LOG_DEBUG(0, "using pcm audio packetizer");
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_PACKETIZER_REGISTER(pcm_packetizer_open,  "pcm");
diff --git a/containers/qsynth/CMakeLists.txt b/containers/qsynth/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..b188e50
--- /dev/null
@@ -0,0 +1,13 @@
+# Container module needs to go in as a plugins so different prefix
+# and install path
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+
+# Make sure the compiler can find the necessary include files
+include_directories (../..)
+
+add_library(reader_qsynth ${LIBRARY_TYPE} qsynth_reader.c)
+
+target_link_libraries(reader_qsynth containers)
+
+install(TARGETS reader_qsynth DESTINATION ${VMCS_PLUGIN_DIR})
+
diff --git a/containers/qsynth/qsynth_reader.c b/containers/qsynth/qsynth_reader.c
new file mode 100755 (executable)
index 0000000..06a9d54
--- /dev/null
@@ -0,0 +1,482 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <string.h>
+
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_logging.h"
+
+/******************************************************************************
+Defines.
+******************************************************************************/
+
+#define BI32(b) (((b)[0]<<24)|((b)[1]<<16)|((b)[2]<<8)|((b)[3]))
+#define BI16(b) (((b)[0]<<8)|((b)[1]))
+
+#define HEADER_LENGTH 14
+#define MAX_TRACKS 128
+
+/******************************************************************************
+Type definitions
+******************************************************************************/
+struct _QSYNTH_SEGMENT_T {
+   struct _QSYNTH_SEGMENT_T *next;
+   uint32_t len;
+   uint8_t *data;
+};
+typedef struct _QSYNTH_SEGMENT_T QSYNTH_SEGMENT_T;
+
+typedef struct VC_CONTAINER_MODULE_T
+{
+   VC_CONTAINER_TRACK_T *track;
+   uint32_t filesize;
+   QSYNTH_SEGMENT_T *seg;
+   QSYNTH_SEGMENT_T *pass;
+   uint32_t sent;
+   int64_t timestamp;
+   uint32_t seek;
+} VC_CONTAINER_MODULE_T;
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+VC_CONTAINER_STATUS_T qsynth_reader_open( VC_CONTAINER_T * );
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+
+static VC_CONTAINER_STATUS_T qsynth_read_header(uint8_t *data, uint32_t *tracks,
+   uint32_t *division, uint8_t *fps, uint8_t *dpf)
+{
+   if(data[0] != 'M' || data[1] != 'T' || data[2] != 'h' || data[3] != 'd' ||
+      data[4] != 0   || data[5] != 0   || data[6] != 0   || data[7] != 6)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   if(data[12] < 0x80)
+   {
+      if(division) *division = BI16(data+12);
+   }
+   else
+   {
+      if(fps) *fps = 256-data[12];
+      if(dpf) *dpf = data[13];
+   }
+
+   if(tracks) *tracks = BI16(data+10);
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+static int qsynth_read_variable(uint8_t *data, uint32_t *val)
+{
+   int i = 0;
+   *val = 0;
+   do {
+      *val = (*val << 7) + (data[i] & 0x7f);
+   } while(data[i++] & 0x80);
+
+   return i;
+}
+
+static VC_CONTAINER_STATUS_T qsynth_read_event(uint8_t *data, uint32_t *used, uint8_t *last,
+                                               uint32_t *time, uint32_t *tempo, uint32_t *end)
+{
+   int read;
+
+   // need at least 4 bytes here
+   read = qsynth_read_variable(data, time);
+
+   if(data[read] == 0xff) // meta event
+   {
+      uint32_t len;
+      uint8_t type = data[read+1];
+
+      read += 2;
+      read += qsynth_read_variable(data+read, &len);
+
+      if(type == 0x2f) // end of track
+      {
+         if(len != 0)
+            return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+         *end = 1;
+      }
+      else if(type == 0x51) // tempo event
+      {
+         if(len != 3)
+            return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+         *tempo = (data[read]<<16) | (data[read+1]<<8) | data[read+2];
+      }
+
+      read += len;
+   }
+   else if(data[read] == 0xf0 || data[read] == 0xf7) // sysex events
+   {
+      uint32_t len;
+      read += 1;
+      read += qsynth_read_variable(data+read, &len) + len;
+   }
+   else // midi event
+   {
+      uint8_t type;
+
+      if(data[read] < 128)
+         type = *last;
+      else
+      {
+         type = data[read] >> 4;
+         *last = type;
+         read++;
+      }
+
+      switch(type) {
+      case 8: case 9: case 0xa: case 0xb: case 0xe:
+         read += 2;
+         break;
+      case 0xc: case 0xd:
+         read += 1;
+         break;
+      default:
+         return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+      }
+   }
+
+   *used = read;
+   return VC_CONTAINER_SUCCESS;
+}
+
+static VC_CONTAINER_STATUS_T qsynth_read_track(QSYNTH_SEGMENT_T *seg,
+                                               uint32_t *ticks, int64_t *time,
+                                               uint32_t *us_perclock, uint32_t *tempo_ticks)
+{
+   uint32_t total_ticks = 0;
+   uint32_t used = 8;
+   uint8_t last = 0;
+  
+   *time = 0LL;
+   *tempo_ticks = 0;
+
+   while(used < seg->len)
+   {
+      VC_CONTAINER_STATUS_T status;
+      uint32_t event_ticks, new_tempo = 0, end = 0, event_used;
+      if((status = qsynth_read_event(seg->data+used, &event_used, &last, &event_ticks, &new_tempo, &end)) != VC_CONTAINER_SUCCESS)
+         return status;
+
+      used += event_used;
+      total_ticks += event_ticks;
+
+      if(new_tempo != 0)
+      {
+         *time += ((int64_t) (total_ticks - *tempo_ticks)) * (*us_perclock);
+         *us_perclock = new_tempo;
+         *tempo_ticks = total_ticks;
+      }
+      
+      if(end)
+         break;
+   }
+   
+   *ticks = total_ticks;
+   return VC_CONTAINER_SUCCESS;
+}
+
+static VC_CONTAINER_STATUS_T qsynth_get_duration(VC_CONTAINER_T *p_ctx)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status;
+   QSYNTH_SEGMENT_T **seg = &(module->seg);
+   uint32_t i, tracks, division = 0, max_ticks = 0, us_perclock = 500000;
+   uint32_t end_uspc = 0, end_ticks = 0;
+   int64_t end_time = 0;
+   uint8_t fps = 1, dpf = 1;
+
+   if((*seg = malloc(sizeof(QSYNTH_SEGMENT_T) + HEADER_LENGTH)) == NULL)
+      return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+
+   (*seg)->next = NULL;
+   (*seg)->len = HEADER_LENGTH;
+   (*seg)->data = (uint8_t *) ((*seg) + 1);
+
+   if(PEEK_BYTES(p_ctx, (*seg)->data, HEADER_LENGTH) != HEADER_LENGTH)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   if((status = qsynth_read_header((*seg)->data, &tracks, &division, &fps, &dpf)) != VC_CONTAINER_SUCCESS)
+      return status;
+
+   // if we have a suspiciously large number of tracks, this is probably a bad file
+   if(tracks > MAX_TRACKS)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   SKIP_BYTES(p_ctx, HEADER_LENGTH);
+
+   seg = &((*seg)->next);
+   module->filesize = HEADER_LENGTH;
+
+   if(division == 0)
+   {
+      us_perclock = 1000000 / (fps * dpf);
+      division = 1;
+   }
+
+   for(i=0; i<tracks; i++)
+   {
+      uint32_t len, ticks, tempo_ticks;
+      int64_t time;
+      uint8_t dummy[8];
+
+      if(READ_BYTES(p_ctx, dummy, sizeof(dummy)) != sizeof(dummy) ||
+         dummy[0] != 'M' || dummy[1] != 'T' || dummy[2] != 'r' || dummy[3] != 'k')
+         return VC_CONTAINER_ERROR_FORMAT_INVALID;
+      
+      len = BI32(dummy+4);
+      
+      // impose a 1mb limit on track size
+      if(len > (1<<20) || (*seg = malloc(sizeof(QSYNTH_SEGMENT_T) + 8 + len)) == NULL)
+         return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+
+      module->filesize += len+8;
+      (*seg)->next = NULL;
+      (*seg)->len = len + 8;
+      (*seg)->data = (uint8_t *) ((*seg) + 1);
+
+      memcpy((*seg)->data, dummy, 8);
+      if(READ_BYTES(p_ctx, (*seg)->data+8, len) != len)
+         return VC_CONTAINER_ERROR_FORMAT_INVALID;
+
+      if((status = qsynth_read_track(*seg, &ticks, &time, &us_perclock, &tempo_ticks)) != VC_CONTAINER_SUCCESS)
+         return status; 
+
+      if(end_uspc == 0)
+      {
+         end_uspc = us_perclock;
+         end_ticks = tempo_ticks;
+         end_time = time;
+      }
+
+      if(ticks > max_ticks)
+         max_ticks = ticks;
+
+      seg = &((*seg)->next);
+   }
+
+   if(end_uspc == 0)
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+
+   module->pass = module->seg;
+   module->sent = 0;
+   p_ctx->duration = (end_time + (((int64_t) (max_ticks - end_ticks)) * end_uspc)) / division;
+   module->track->format->extradata = (uint8_t *) &module->filesize;
+   module->track->format->extradata_size = 4;
+   return VC_CONTAINER_SUCCESS;
+}
+
+
+/*****************************************************************************
+Functions exported as part of the Container Module API
+*****************************************************************************/
+static VC_CONTAINER_STATUS_T qsynth_reader_read( VC_CONTAINER_T *p_ctx,
+                                              VC_CONTAINER_PACKET_T *packet,
+                                              uint32_t flags )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+
+   if(module->pass)
+   {
+      packet->size = module->pass->len - module->sent;
+      packet->dts = packet->pts = 0;
+      packet->track = 0;
+      packet->flags = module->sent ? 0 : VC_CONTAINER_PACKET_FLAG_FRAME_START;
+   }
+   else
+   {
+      if(module->timestamp > p_ctx->duration)
+         return VC_CONTAINER_ERROR_EOS;
+
+      packet->size = 5;
+      packet->dts = packet->pts = module->timestamp;
+      packet->track = 0;
+      packet->flags = VC_CONTAINER_PACKET_FLAG_FRAME;
+   }
+
+   if(flags & VC_CONTAINER_READ_FLAG_SKIP)
+   {
+      if(module->pass)
+      {
+         module->pass = module->pass->next;
+         module->sent = 0;
+      }
+      else
+      {
+         // if we're playing then we can't really skip, but have to simulate a seek instead
+         module->seek = 1;
+         module->timestamp += 40;
+      }      
+
+      return VC_CONTAINER_SUCCESS;
+   }
+
+   if(flags & VC_CONTAINER_READ_FLAG_INFO)
+      return VC_CONTAINER_SUCCESS;
+
+   // read frame into packet->data
+   if(module->pass)
+   {
+      uint32_t copy = MIN(packet->size, packet->buffer_size);
+      memcpy(packet->data, module->pass->data + module->sent, copy);
+      packet->size = copy;
+
+      if((module->sent += copy) == module->pass->len)
+      {
+         module->pass = module->pass->next;
+         module->sent = 0;
+         packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
+      }
+   }
+   else
+   {
+      if(packet->buffer_size < packet->size)
+         return VC_CONTAINER_ERROR_BUFFER_TOO_SMALL;
+
+      if(module->seek)
+      {
+         uint32_t current_time = module->timestamp / 1000;
+
+         packet->data[0] = 'S';
+         packet->data[1] = (uint8_t)((current_time >> 24) & 0xFF);
+         packet->data[2] = (uint8_t)((current_time >> 16) & 0xFF);
+         packet->data[3] = (uint8_t)((current_time >>  8) & 0xFF);
+         packet->data[4] = (uint8_t)((current_time      ) & 0xFF);
+         module->seek = 0;
+      }
+      else
+      {
+         packet->data[0] = 'P';
+         packet->data[1] = 0;
+         packet->data[2] = 0;
+         packet->data[3] = 0;
+         packet->data[4] = 40;         
+         module->timestamp += 40 * 1000;
+      }
+   }
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T qsynth_reader_seek( VC_CONTAINER_T *p_ctx,
+                                              int64_t *offset,
+                                              VC_CONTAINER_SEEK_MODE_T mode,
+                                              VC_CONTAINER_SEEK_FLAGS_T flags)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_PARAM_UNUSED(flags);
+
+   if (mode != VC_CONTAINER_SEEK_MODE_TIME)
+      return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+
+   if(*offset < 0)
+      *offset = 0;
+   else if(*offset > p_ctx->duration)
+      *offset = p_ctx->duration;
+
+   module->timestamp = *offset;
+   module->seek = 1;
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T qsynth_reader_close( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   QSYNTH_SEGMENT_T *seg = module->seg;
+   for(; p_ctx->tracks_num > 0; p_ctx->tracks_num--)
+      vc_container_free_track(p_ctx, p_ctx->tracks[p_ctx->tracks_num-1]);
+   while(seg != NULL)
+   {
+      QSYNTH_SEGMENT_T *next = seg->next;
+      free(seg);
+      seg = next;
+   }
+   free(module);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T qsynth_reader_open( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = 0;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   uint8_t header[HEADER_LENGTH];
+
+   /* Check the file header */
+   if((PEEK_BYTES(p_ctx, header, HEADER_LENGTH) != HEADER_LENGTH) ||
+      qsynth_read_header(header, 0, 0, 0, 0) != VC_CONTAINER_SUCCESS)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   /* Allocate our context */
+   module = malloc(sizeof(*module));
+   if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(module, 0, sizeof(*module));
+   p_ctx->priv->module = module;
+   p_ctx->tracks_num = 1;
+   p_ctx->tracks = &module->track;
+   p_ctx->tracks[0] = vc_container_allocate_track(p_ctx, 0);
+   if(!p_ctx->tracks[0]) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   p_ctx->tracks[0]->format->es_type = VC_CONTAINER_ES_TYPE_AUDIO;
+   p_ctx->tracks[0]->format->codec = VC_CONTAINER_CODEC_MIDI;
+   p_ctx->tracks[0]->is_enabled = true;
+
+   if((status = qsynth_get_duration(p_ctx)) != VC_CONTAINER_SUCCESS) goto error;
+
+   LOG_DEBUG(p_ctx, "using qsynth reader");
+
+   p_ctx->capabilities = VC_CONTAINER_CAPS_CAN_SEEK;
+
+   p_ctx->priv->pf_close = qsynth_reader_close;
+   p_ctx->priv->pf_read = qsynth_reader_read;
+   p_ctx->priv->pf_seek = qsynth_reader_seek;
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+   LOG_DEBUG(p_ctx, "qsynth: error opening stream (%i)", status);
+   if(module) qsynth_reader_close(p_ctx);
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak reader_open qsynth_reader_open
+#endif
diff --git a/containers/raw/CMakeLists.txt b/containers/raw/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..0ada17e
--- /dev/null
@@ -0,0 +1,18 @@
+# Container module needs to go in as a plugins so different prefix
+# and install path
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+
+# Make sure the compiler can find the necessary include files
+include_directories (../..)
+
+add_library(reader_raw_video ${LIBRARY_TYPE} raw_video_reader.c)
+
+target_link_libraries(reader_raw_video containers)
+
+install(TARGETS reader_raw_video DESTINATION ${VMCS_PLUGIN_DIR})
+
+add_library(writer_raw_video ${LIBRARY_TYPE} raw_video_writer.c)
+
+target_link_libraries(writer_raw_video containers)
+
+install(TARGETS writer_raw_video DESTINATION ${VMCS_PLUGIN_DIR})
diff --git a/containers/raw/raw_video_common.h b/containers/raw/raw_video_common.h
new file mode 100755 (executable)
index 0000000..52d73ec
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef RAW_VIDEO_COMMON_H
+#define RAW_VIDEO_COMMON_H
+
+static struct {
+   const char *id;
+   VC_CONTAINER_FOURCC_T codec;
+   unsigned int size_num;
+   unsigned int size_den;
+} table[] = {
+   {"420", VC_CONTAINER_CODEC_I420, 3, 2},
+   {0, 0, 0, 0}
+};
+
+STATIC_INLINE bool from_yuv4mpeg2(const char *id, VC_CONTAINER_FOURCC_T *codec,
+   unsigned int *size_num, unsigned int *size_den)
+{
+   unsigned int i;
+   for (i = 0; table[i].id; i++)
+      if (!strcmp(id, table[i].id))
+         break;
+  if (codec) *codec = table[i].codec;
+  if (size_num) *size_num = table[i].size_num;
+  if (size_den) *size_den = table[i].size_den;
+  return !!table[i].id;
+}
+
+STATIC_INLINE bool to_yuv4mpeg2(VC_CONTAINER_FOURCC_T codec, const char **id,
+   unsigned int *size_num, unsigned int *size_den)
+{
+   unsigned int i;
+   for (i = 0; table[i].id; i++)
+      if (codec == table[i].codec)
+         break;
+  if (id) *id = table[i].id;
+  if (size_num) *size_num = table[i].size_num;
+  if (size_den) *size_den = table[i].size_den;
+  return !!table[i].id;
+}
+
+#endif /* RAW_VIDEO_COMMON_H */
diff --git a/containers/raw/raw_video_reader.c b/containers/raw/raw_video_reader.c
new file mode 100755 (executable)
index 0000000..00ac064
--- /dev/null
@@ -0,0 +1,465 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_logging.h"
+
+#include "raw_video_common.h"
+
+/******************************************************************************
+Defines.
+******************************************************************************/
+#define FILE_HEADER_SIZE_MAX 1024
+#define FRAME_HEADER_SIZE_MAX 256
+#define OPTION_SIZE_MAX 32
+
+/******************************************************************************
+Type definitions
+******************************************************************************/
+typedef struct VC_CONTAINER_MODULE_T
+{
+   VC_CONTAINER_TRACK_T *track;
+   VC_CONTAINER_STATUS_T status;
+
+   bool yuv4mpeg2;
+   bool non_standard;
+   char option[OPTION_SIZE_MAX];
+
+   bool frame_header;
+   unsigned int frame_header_size;
+
+   int64_t data_offset;
+   unsigned int block_size;
+   unsigned int block_offset;
+   unsigned int frames;
+
+} VC_CONTAINER_MODULE_T;
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+VC_CONTAINER_STATUS_T rawvideo_reader_open( VC_CONTAINER_T * );
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+static VC_CONTAINER_STATUS_T read_yuv4mpeg2_option( VC_CONTAINER_T *ctx,
+   unsigned int *bytes_left )
+{
+   VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+   unsigned int size, i;
+
+   /* Start by skipping spaces */
+   while (*bytes_left && PEEK_U8(ctx) == ' ')
+      (*bytes_left)--, _SKIP_U8(ctx);
+
+   size = PEEK_BYTES(ctx, module->option,
+      MIN(sizeof(module->option), *bytes_left));
+
+   /* The config option ends at next space or newline */
+   for (i = 0; i < size; i++)
+   {
+      if (module->option[i] == ' ' || module->option[i] == 0x0a)
+      {
+         module->option[i] = 0;
+         break;
+      }
+   }
+   if (i == 0)
+      return VC_CONTAINER_ERROR_NOT_FOUND;
+
+   *bytes_left -= i;
+   SKIP_BYTES(ctx, i);
+
+   /* If option is too long, we just discard it */
+   if (i == size)
+   {
+      while (*bytes_left && PEEK_U8(ctx) != ' ' && PEEK_U8(ctx) != 0x0a)
+         (*bytes_left)--, _SKIP_U8(ctx);
+      return VC_CONTAINER_ERROR_NOT_FOUND;
+   }
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+static VC_CONTAINER_STATUS_T read_yuv4mpeg2_file_header( VC_CONTAINER_T *ctx )
+{
+   VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+   unsigned int bytes_left = FILE_HEADER_SIZE_MAX - 10;
+   unsigned int value1, value2;
+   char codec[OPTION_SIZE_MAX] = "420";
+   uint8_t h[10];
+
+   /* Check for the YUV4MPEG2 signature */
+   if (READ_BYTES(ctx, h, sizeof(h)) != sizeof(h))
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   if (memcmp(h, "YUV4MPEG2 ", sizeof(h)))
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   /* Parse parameters */
+   while (read_yuv4mpeg2_option(ctx, &bytes_left) == VC_CONTAINER_SUCCESS)
+   {
+      if (sscanf(module->option, "W%i", &value1) == 1)
+         ctx->tracks[0]->format->type->video.width = value1;
+      else if (sscanf(module->option, "H%i", &value1) == 1)
+         ctx->tracks[0]->format->type->video.height = value1;
+      else if (sscanf(module->option, "S%i", &value1) == 1)
+         module->block_size = value1;
+      else if (sscanf(module->option, "F%i:%i", &value1, &value2) == 2)
+      {
+         ctx->tracks[0]->format->type->video.frame_rate_num = value1;
+         ctx->tracks[0]->format->type->video.frame_rate_den = value2;
+      }
+      else if (sscanf(module->option, "A%i:%i", &value1, &value2) == 2)
+      {
+         ctx->tracks[0]->format->type->video.par_num = value1;
+         ctx->tracks[0]->format->type->video.par_den = value2;
+      }
+      else if (module->option[0] == 'C')
+      {
+         strcpy(codec, module->option+1);
+      }
+   }
+
+   /* Check the end marker */
+   if (_READ_U8(ctx) != 0x0a)
+   {
+      LOG_ERROR(ctx, "missing end of header marker");
+      return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+
+   /* Find out which codec we are dealing with */
+   if (from_yuv4mpeg2(codec, &ctx->tracks[0]->format->codec, &value1, &value2))
+   {
+      module->block_size = ctx->tracks[0]->format->type->video.width *
+         ctx->tracks[0]->format->type->video.height * value1 / value2;
+   }
+   else
+   {
+      memcpy(&ctx->tracks[0]->format->codec, codec, 4);
+      module->non_standard = true;
+   }
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+static VC_CONTAINER_STATUS_T read_yuv4mpeg2_frame_header( VC_CONTAINER_T *ctx )
+{
+   VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+   unsigned int bytes_left = FRAME_HEADER_SIZE_MAX - 5;
+   unsigned int value1;
+   char header[5];
+
+   if (READ_BYTES(ctx, header, sizeof(header)) != sizeof(header) ||
+          memcmp(header, "FRAME", sizeof(header)))
+   {
+      LOG_ERROR(ctx, "missing frame marker");
+      return STREAM_STATUS(ctx) != VC_CONTAINER_SUCCESS ?
+         STREAM_STATUS(ctx) : VC_CONTAINER_ERROR_CORRUPTED;
+   }
+
+   /* Parse parameters */
+   while (read_yuv4mpeg2_option(ctx, &bytes_left) == VC_CONTAINER_SUCCESS)
+   {
+      if (module->non_standard && sscanf(module->option, "S%i", &value1) == 1)
+         module->block_size = value1;
+   }
+
+   /* Check the end marker */
+   if (_READ_U8(ctx) != 0x0a)
+   {
+      LOG_ERROR(ctx, "missing end of frame header marker");
+      return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+
+   module->frame_header_size = FRAME_HEADER_SIZE_MAX - bytes_left - 1;
+   return VC_CONTAINER_SUCCESS;
+}
+
+static VC_CONTAINER_STATUS_T rawvideo_parse_uri( VC_CONTAINER_T *ctx,
+   VC_CONTAINER_FOURCC_T *c, unsigned int *w, unsigned int *h,
+   unsigned int *fr_num, unsigned int *fr_den, unsigned *block_size )
+{
+   VC_CONTAINER_FOURCC_T codec = 0;
+   unsigned int i, matches, width = 0, height = 0, fn = 0, fd = 0, size = 0;
+   const char *uri = ctx->priv->io->uri;
+
+   /* Try and find a match for the string describing the format */
+   for (i = 0; uri[i]; i++)
+   {
+      if (uri[i] != '_' && uri[i+1] != 'C')
+         continue;
+
+      matches = sscanf(uri+i, "_C%4cW%iH%iF%i#%iS%i", (char *)&codec,
+         &width, &height, &fn, &fd, &size);
+      if (matches >= 3)
+         break;
+   }
+   if (!uri[i])
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   if (!size)
+   {
+      switch (codec)
+      {
+      case VC_CONTAINER_CODEC_I420:
+      case VC_CONTAINER_CODEC_YV12:
+         size = width * height * 3 / 2;
+         break;
+      default: break;
+      }
+   }
+
+   if (!width || !height || !size)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   if (block_size) *block_size = size;
+   if (c) *c = codec;
+   if (w) *w = width;
+   if (h) *h = height;
+   if (fr_num) *fr_num = fn;
+   if (fr_den) *fr_den = fd;
+   if (block_size) *block_size = size;
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************
+Functions exported as part of the Container Module API
+ *****************************************************************************/
+static VC_CONTAINER_STATUS_T rawvideo_reader_read( VC_CONTAINER_T *ctx,
+   VC_CONTAINER_PACKET_T *packet, uint32_t flags )
+{
+   VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+   unsigned int size;
+
+   if (module->status != VC_CONTAINER_SUCCESS)
+      return module->status;
+
+   if (module->yuv4mpeg2 && !module->block_offset &&
+         !module->frame_header)
+   {
+      module->status = read_yuv4mpeg2_frame_header(ctx);
+      if (module->status != VC_CONTAINER_SUCCESS)
+         return module->status;
+
+      module->frame_header = true;
+   }
+
+   if (!module->block_offset)
+      packet->pts = packet->dts = module->frames * INT64_C(1000000) *
+         ctx->tracks[0]->format->type->video.frame_rate_den /
+         ctx->tracks[0]->format->type->video.frame_rate_num;
+   else
+      packet->pts = packet->dts = VC_CONTAINER_TIME_UNKNOWN;
+   packet->flags = VC_CONTAINER_PACKET_FLAG_FRAME_END |
+      VC_CONTAINER_PACKET_FLAG_KEYFRAME;
+   if (!module->block_offset)
+      packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
+   packet->frame_size = module->block_size;
+   packet->size = module->block_size - module->block_offset;
+   packet->track = 0;
+
+   if (flags & VC_CONTAINER_READ_FLAG_SKIP)
+   {
+      size = SKIP_BYTES(ctx, packet->size);
+      module->block_offset = 0;
+      module->frames++;
+      module->frame_header = 0;
+      module->status = STREAM_STATUS(ctx);
+      return module->status;
+   }
+
+   if (flags & VC_CONTAINER_READ_FLAG_INFO)
+      return VC_CONTAINER_SUCCESS;
+
+   size = MIN(module->block_size - module->block_offset, packet->buffer_size);
+   size = READ_BYTES(ctx, packet->data, size);
+   module->block_offset += size;
+   packet->size = size;
+
+   if (module->block_offset == module->block_size)
+   {
+      module->block_offset = 0;
+      module->frame_header = 0;
+      module->frames++;
+   }
+
+   module->status = size ? VC_CONTAINER_SUCCESS : STREAM_STATUS(ctx);
+   return module->status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T rawvideo_reader_seek( VC_CONTAINER_T *ctx, int64_t *offset,
+   VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags)
+{
+   VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+   VC_CONTAINER_PARAM_UNUSED(mode);
+
+   module->frames = *offset *
+      ctx->tracks[0]->format->type->video.frame_rate_num /
+      ctx->tracks[0]->format->type->video.frame_rate_den / INT64_C(1000000);
+   module->block_offset = 0;
+
+   if ((flags & VC_CONTAINER_SEEK_FLAG_FORWARD) &&
+      module->frames * INT64_C(1000000) *
+         ctx->tracks[0]->format->type->video.frame_rate_den /
+         ctx->tracks[0]->format->type->video.frame_rate_num < *offset)
+      module->frames++;
+
+   module->frame_header = 0;
+
+   module->status =
+      SEEK(ctx, module->data_offset + module->frames *
+         (module->block_size + module->frame_header_size));
+
+   return module->status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T rawvideo_reader_close( VC_CONTAINER_T *ctx )
+{
+   VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+   for (; ctx->tracks_num > 0; ctx->tracks_num--)
+      vc_container_free_track(ctx, ctx->tracks[ctx->tracks_num-1]);
+   free(module);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T rawvideo_reader_open( VC_CONTAINER_T *ctx )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_INVALID;
+   const char *extension = vc_uri_path_extension(ctx->priv->uri);
+   VC_CONTAINER_MODULE_T *module = 0;
+   bool yuv4mpeg2 = false;
+   uint8_t h[10];
+
+   /* Check if the user has specified a container */
+   vc_uri_find_query(ctx->priv->uri, 0, "container", &extension);
+
+   /* Check for the YUV4MPEG2 signature */
+   if (PEEK_BYTES(ctx, h, sizeof(h)) != sizeof(h))
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   if (!memcmp(h, "YUV4MPEG2 ", sizeof(h)))
+      yuv4mpeg2 = true;
+
+   /* Or check if the extension is supported */
+   if (!yuv4mpeg2 &&
+       !(extension && !strcasecmp(extension, "yuv")))
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   LOG_DEBUG(ctx, "using raw video reader");
+
+   /* Allocate our context */
+   module = malloc(sizeof(*module));
+   if (!module) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+   memset(module, 0, sizeof(*module));
+   ctx->priv->module = module;
+   ctx->tracks_num = 1;
+   ctx->tracks = &module->track;
+   ctx->tracks[0] = vc_container_allocate_track(ctx, 0);
+   if (!ctx->tracks[0])
+   {
+      status = VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+      goto error;
+   }
+   ctx->tracks[0]->format->es_type = VC_CONTAINER_ES_TYPE_VIDEO;
+   ctx->tracks[0]->is_enabled = true;
+   ctx->tracks[0]->format->type->video.frame_rate_num = 25;
+   ctx->tracks[0]->format->type->video.frame_rate_den = 1;
+   ctx->tracks[0]->format->type->video.par_num = 1;
+   ctx->tracks[0]->format->type->video.par_den = 1;
+
+   if (yuv4mpeg2)
+   {
+      status = read_yuv4mpeg2_file_header(ctx);
+      if (status != VC_CONTAINER_SUCCESS)
+         goto error;
+
+      module->data_offset = STREAM_POSITION(ctx);
+
+      status = read_yuv4mpeg2_frame_header(ctx);
+      if (status != VC_CONTAINER_SUCCESS)
+         goto error;
+      module->frame_header = true;
+   }
+   else
+   {
+      VC_CONTAINER_FOURCC_T codec;
+      unsigned int width, height, fr_num, fr_den, block_size;
+
+      status = rawvideo_parse_uri(ctx, &codec, &width, &height,
+         &fr_num, &fr_den, &block_size);
+      if (status != VC_CONTAINER_SUCCESS)
+         goto error;
+      ctx->tracks[0]->format->codec = codec;
+      ctx->tracks[0]->format->type->video.width = width;
+      ctx->tracks[0]->format->type->video.height = height;
+      if (fr_num && fr_den)
+      {
+         ctx->tracks[0]->format->type->video.frame_rate_num = fr_num;
+         ctx->tracks[0]->format->type->video.frame_rate_den = fr_den;
+      }
+      module->block_size = block_size;
+   }
+
+   /*
+    *  We now have all the information we really need to start playing the stream
+    */
+
+   LOG_INFO(ctx, "rawvideo %4.4s/%ix%i/fps:%i:%i/size:%i",
+      (char *)&ctx->tracks[0]->format->codec,
+      ctx->tracks[0]->format->type->video.width,
+      ctx->tracks[0]->format->type->video.height,
+      ctx->tracks[0]->format->type->video.frame_rate_num,
+      ctx->tracks[0]->format->type->video.frame_rate_den, module->block_size);
+   ctx->priv->pf_close = rawvideo_reader_close;
+   ctx->priv->pf_read = rawvideo_reader_read;
+   ctx->priv->pf_seek = rawvideo_reader_seek;
+   module->yuv4mpeg2 = yuv4mpeg2;
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+   LOG_DEBUG(ctx, "rawvideo: error opening stream (%i)", status);
+   rawvideo_reader_close(ctx);
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+ ********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak reader_open rawvideo_reader_open
+#endif
diff --git a/containers/raw/raw_video_writer.c b/containers/raw/raw_video_writer.c
new file mode 100755 (executable)
index 0000000..49b7c7c
--- /dev/null
@@ -0,0 +1,264 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_logging.h"
+
+#include "raw_video_common.h"
+
+/******************************************************************************
+Defines.
+******************************************************************************/
+
+/******************************************************************************
+Type definitions
+******************************************************************************/
+typedef struct VC_CONTAINER_MODULE_T
+{
+   VC_CONTAINER_TRACK_T *track;
+   bool yuv4mpeg2;
+   bool header_done;
+   bool non_standard;
+
+} VC_CONTAINER_MODULE_T;
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+VC_CONTAINER_STATUS_T rawvideo_writer_open( VC_CONTAINER_T * );
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+static VC_CONTAINER_STATUS_T rawvideo_write_header( VC_CONTAINER_T *ctx )
+{
+   VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+   unsigned int size;
+   char line[128];
+   const char *id;
+
+   size = snprintf(line, sizeof(line), "YUV4MPEG2 W%i H%i",
+      ctx->tracks[0]->format->type->video.width,
+      ctx->tracks[0]->format->type->video.height);
+   if (size >= sizeof(line))
+      return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+   WRITE_BYTES(ctx, line, size);
+
+   if (ctx->tracks[0]->format->type->video.frame_rate_num &&
+       ctx->tracks[0]->format->type->video.frame_rate_den)
+   {
+      size = snprintf(line, sizeof(line), " F%i:%i",
+         ctx->tracks[0]->format->type->video.frame_rate_num,
+         ctx->tracks[0]->format->type->video.frame_rate_den);
+      if (size >= sizeof(line))
+         return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+      WRITE_BYTES(ctx, line, size);
+   }
+
+   if (ctx->tracks[0]->format->type->video.par_num &&
+       ctx->tracks[0]->format->type->video.par_den)
+   {
+      size = snprintf(line, sizeof(line), " A%i:%i",
+         ctx->tracks[0]->format->type->video.par_num,
+         ctx->tracks[0]->format->type->video.par_den);
+      if (size >= sizeof(line))
+         return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+      WRITE_BYTES(ctx, line, size);
+   }
+
+   if (to_yuv4mpeg2(ctx->tracks[0]->format->codec, &id, 0, 0))
+   {
+      size = snprintf(line, sizeof(line), " C%s", id);
+   }
+   else
+   {
+      module->non_standard = true;
+      size = snprintf(line, sizeof(line), " C%4.4s",
+         (char *)&ctx->tracks[0]->format->codec);
+   }
+   if (size >= sizeof(line))
+      return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+   WRITE_BYTES(ctx, line, size);
+
+   _WRITE_U8(ctx, 0x0a);
+   module->header_done = true;
+   return STREAM_STATUS(ctx);
+}
+
+static VC_CONTAINER_STATUS_T simple_write_add_track( VC_CONTAINER_T *ctx,
+   VC_CONTAINER_ES_FORMAT_T *format )
+{
+   VC_CONTAINER_STATUS_T status;
+
+   /* Sanity check that we support the type of track being created */
+   if (ctx->tracks_num)
+      return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+   if (format->es_type != VC_CONTAINER_ES_TYPE_VIDEO)
+      return VC_CONTAINER_ERROR_TRACK_FORMAT_NOT_SUPPORTED;
+
+   /* Allocate and initialise track data */
+   ctx->tracks[0] = vc_container_allocate_track(ctx, 0);
+   if (!ctx->tracks[0])
+      return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+
+   status = vc_container_track_allocate_extradata(ctx,
+      ctx->tracks[0], format->extradata_size);
+   if(status != VC_CONTAINER_SUCCESS)
+      return status;
+
+   vc_container_format_copy(ctx->tracks[0]->format, format,
+      format->extradata_size);
+   ctx->tracks_num++;
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************
+Functions exported as part of the Container Module API
+ *****************************************************************************/
+static VC_CONTAINER_STATUS_T rawvideo_writer_close( VC_CONTAINER_T *ctx )
+{
+   VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+   for (; ctx->tracks_num > 0; ctx->tracks_num--)
+      vc_container_free_track(ctx, ctx->tracks[ctx->tracks_num-1]);
+   free(module);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T rawvideo_writer_write( VC_CONTAINER_T *ctx,
+   VC_CONTAINER_PACKET_T *packet )
+{
+   VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+   VC_CONTAINER_STATUS_T status;
+
+   if (module->yuv4mpeg2 && !module->header_done)
+   {
+      status = rawvideo_write_header(ctx);
+      if (status != VC_CONTAINER_SUCCESS)
+         return status;
+   }
+
+   if (module->yuv4mpeg2 &&
+       (packet->flags & VC_CONTAINER_PACKET_FLAG_FRAME_START))
+   {
+      /* Write the metadata */
+      WRITE_BYTES(ctx, "FRAME", sizeof("FRAME")-1);
+
+      /* For formats not supported by the YUV4MPEG2 spec, we prepend
+       * each frame with its size */
+      if (module->non_standard)
+      {
+         unsigned int size;
+         char line[32];
+         size = snprintf(line, sizeof(line), " S%i",
+            packet->frame_size ? packet->frame_size : packet->size);
+         if (size < sizeof(line))
+            WRITE_BYTES(ctx, line, size);
+      }
+
+      _WRITE_U8(ctx, 0x0a);
+   }
+
+   /* Write the elementary stream */
+   WRITE_BYTES(ctx, packet->data, packet->size);
+
+   return STREAM_STATUS(ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T rawvideo_writer_control( VC_CONTAINER_T *ctx,
+   VC_CONTAINER_CONTROL_T operation, va_list args )
+{
+    VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+    VC_CONTAINER_ES_FORMAT_T *format;
+
+   switch (operation)
+   {
+   case VC_CONTAINER_CONTROL_TRACK_ADD:
+      format = (VC_CONTAINER_ES_FORMAT_T *)va_arg(args, VC_CONTAINER_ES_FORMAT_T *);
+      return simple_write_add_track(ctx, format);
+
+   case VC_CONTAINER_CONTROL_TRACK_ADD_DONE:
+      return module->yuv4mpeg2 ?
+         rawvideo_write_header( ctx ) : VC_CONTAINER_SUCCESS;
+
+   default: return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+   }
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T rawvideo_writer_open( VC_CONTAINER_T *ctx )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_INVALID;
+   const char *extension = vc_uri_path_extension(ctx->priv->uri);
+   VC_CONTAINER_MODULE_T *module;
+   bool yuv4mpeg2 = false;
+
+   /* Check if the user has specified a container */
+   vc_uri_find_query(ctx->priv->uri, 0, "container", &extension);
+
+   /* Check we're the right writer for this */
+   if(!extension)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   if(!strcasecmp(extension, "y4m") || !strcasecmp(extension, "yuv4mpeg2"))
+      yuv4mpeg2 = true;
+   if(!yuv4mpeg2 && strcasecmp(extension, "yuv"))
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   LOG_DEBUG(ctx, "using rawvideo writer");
+
+   /* Allocate our context */
+   module = malloc(sizeof(*module));
+   if (!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(module, 0, sizeof(*module));
+   ctx->priv->module = module;
+   ctx->tracks = &module->track;
+   module->yuv4mpeg2 = yuv4mpeg2;
+
+   ctx->priv->pf_close = rawvideo_writer_close;
+   ctx->priv->pf_write = rawvideo_writer_write;
+   ctx->priv->pf_control = rawvideo_writer_control;
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+   LOG_DEBUG(ctx, "rawvideo: error opening stream (%i)", status);
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+ ********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak writer_open rawvideo_writer_open
+#endif
diff --git a/containers/rcv/CMakeLists.txt b/containers/rcv/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..9407f58
--- /dev/null
@@ -0,0 +1,13 @@
+# Container module needs to go in as a plugins so different prefix
+# and install path
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+
+# Make sure the compiler can find the necessary include files
+include_directories (../..)
+
+add_library(reader_rcv ${LIBRARY_TYPE} rcv_reader.c)
+
+target_link_libraries(reader_rcv containers)
+
+install(TARGETS reader_rcv DESTINATION ${VMCS_PLUGIN_DIR})
+
diff --git a/containers/rcv/rcv_reader.c b/containers/rcv/rcv_reader.c
new file mode 100755 (executable)
index 0000000..4d4db27
--- /dev/null
@@ -0,0 +1,358 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <string.h>
+
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_index.h"
+#include "containers/core/containers_logging.h"
+
+/******************************************************************************
+Defines.
+******************************************************************************/
+
+#define LI32(b) (((b)[3]<<24)|((b)[2]<<16)|((b)[1]<<8)|((b)[0]))
+#define LI24(b) (((b)[2]<<16)|((b)[1]<<8)|((b)[0]))
+
+/******************************************************************************
+Type definitions
+******************************************************************************/
+typedef struct { 
+   unsigned int num_frames : 24;
+   unsigned int constant_c5 : 8;
+   int constant_4;
+   uint32_t struct_c;
+   uint32_t vert_size;
+   uint32_t horiz_size;
+   int constant_c;
+   uint32_t struct_b[2];
+   uint32_t framerate;
+} RCV_FILE_HEADER_T;
+
+typedef struct {
+   unsigned int framesize : 24;
+   unsigned int res : 7;
+   unsigned int keyframe : 1;
+   uint32_t timestamp;
+} RCV_FRAME_HEADER_T;
+
+typedef struct VC_CONTAINER_MODULE_T
+{
+   VC_CONTAINER_TRACK_T *track;
+   uint8_t extradata[4];
+   uint8_t mid_frame;
+   uint32_t frame_read;
+   RCV_FRAME_HEADER_T frame;
+   VC_CONTAINER_INDEX_T *index; /* index of key frames */
+
+} VC_CONTAINER_MODULE_T;
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+VC_CONTAINER_STATUS_T rcv_reader_open( VC_CONTAINER_T * );
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+
+static VC_CONTAINER_STATUS_T rcv_read_header(VC_CONTAINER_T *p_ctx)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   RCV_FILE_HEADER_T header;
+   uint8_t dummy[36];
+
+   if(PEEK_BYTES(p_ctx, dummy, sizeof(dummy)) != sizeof(dummy)) return VC_CONTAINER_ERROR_EOS;
+
+   header.num_frames = LI24(dummy);
+   header.constant_c5 = dummy[3];
+   header.constant_4 = LI32(dummy+4);
+   
+   // extradata is just struct_c from the header
+   memcpy(module->extradata, dummy+8, 4);
+   module->track->format->extradata = module->extradata;
+   module->track->format->extradata_size = 4;
+
+   module->track->format->type->video.height = LI32(dummy+12);
+   module->track->format->type->video.width = LI32(dummy+16);
+   
+   header.constant_c = LI32(dummy+20);
+   memcpy(header.struct_b, dummy+24, 8);
+   header.framerate = LI32(dummy+32);
+   if(header.constant_c5 != 0xc5 || header.constant_4 != 0x4 || header.constant_c != 0xc)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   if(header.framerate != 0 && header.framerate != 0xffffffffUL)
+   {
+      module->track->format->type->video.frame_rate_num = header.framerate;
+      module->track->format->type->video.frame_rate_den = 1;
+   }
+
+   // fill in general information
+   if(header.num_frames != (1<<24)-1 && header.framerate != 0 && header.framerate != 0xffffffffUL)
+      p_ctx->duration = ((int64_t) header.num_frames * 1000000LL) / (int64_t) header.framerate;
+
+   // we're happy that this is an rcv file
+   SKIP_BYTES(p_ctx, sizeof(dummy));
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************
+ * Utility function to seek to the keyframe nearest the given timestamp.
+ *
+ * @param p_ctx     Pointer to the container context.
+ * @param timestamp The requested time.  On success, this is updated with the time of the selected keyframe.
+ * @param later     If true, the selected frame is the earliest keyframe with a time greater or equal to timestamp.
+ *                  If false, the selected frame is the latest keyframe with a time earlier or equal to timestamp.
+ * @return          Status code.
+ */
+static VC_CONTAINER_STATUS_T rcv_seek_nearest_keyframe(VC_CONTAINER_T *p_ctx, int64_t *timestamp, int later)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   int64_t prev_keyframe_offset = sizeof(RCV_FILE_HEADER_T); /* set to very first frame */
+   int64_t prev_keyframe_timestamp = 0;
+   int use_prev_keyframe = !later;
+
+   if(use_prev_keyframe || (module->frame.timestamp * 1000LL > *timestamp))
+   {
+      /* A seek has been requested to an earlier keyframe, so rewind to the beginning
+       * of the stream since there's no information available on previous frames */
+      SEEK(p_ctx, sizeof(RCV_FILE_HEADER_T));
+      memset(&module->frame, 0, sizeof(RCV_FRAME_HEADER_T));
+      module->mid_frame = 0;
+      module->frame_read = 0;
+   }
+
+   if(module->mid_frame)
+   {
+      /* Seek back to the start of the current frame */
+      SEEK(p_ctx, STREAM_POSITION(p_ctx) - module->frame_read - sizeof(RCV_FILE_HEADER_T));
+      module->mid_frame = 0;
+      module->frame_read = 0;
+   }
+
+   while(1)
+   {
+      if(PEEK_BYTES(p_ctx, &module->frame, sizeof(RCV_FRAME_HEADER_T)) != sizeof(RCV_FRAME_HEADER_T))
+      {
+         status = VC_CONTAINER_ERROR_EOS;
+         break;
+      }
+
+      if(module->frame.keyframe)
+      {
+         if(module->index)
+            vc_container_index_add(module->index, module->frame.timestamp * 1000LL, STREAM_POSITION(p_ctx));
+
+         if((module->frame.timestamp * 1000LL) >= *timestamp)
+         {
+            if((module->frame.timestamp * 1000LL) == *timestamp)
+               use_prev_keyframe = 0;
+
+            *timestamp = module->frame.timestamp * 1000LL;
+
+            break;
+         }
+
+         prev_keyframe_offset = STREAM_POSITION(p_ctx);
+         prev_keyframe_timestamp = module->frame.timestamp * 1000LL;
+      }
+
+      SKIP_BYTES(p_ctx, module->frame.framesize + sizeof(RCV_FRAME_HEADER_T));
+   }
+
+   if(use_prev_keyframe)
+   {
+      *timestamp = prev_keyframe_timestamp;
+      status = SEEK(p_ctx, prev_keyframe_offset);
+   }
+
+   return status;
+}
+
+/*****************************************************************************
+Functions exported as part of the Container Module API
+*****************************************************************************/
+static VC_CONTAINER_STATUS_T rcv_reader_read( VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_PACKET_T *packet, uint32_t flags )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   unsigned int size;
+
+   if(!module->mid_frame)
+   {
+      /* Save the current position for updating the indexer */
+      int64_t position = STREAM_POSITION(p_ctx);
+
+      if(READ_BYTES(p_ctx, &module->frame, sizeof(RCV_FRAME_HEADER_T)) != sizeof(RCV_FRAME_HEADER_T))
+         return VC_CONTAINER_ERROR_EOS;
+      module->mid_frame = 1;
+      module->frame_read = 0;
+
+      if(module->index && module->frame.keyframe)
+         vc_container_index_add(module->index, (int64_t)module->frame.timestamp * 1000LL, position);
+   }
+
+   packet->size = module->frame.framesize;
+   packet->dts = packet->pts = module->frame.timestamp * 1000LL;
+   packet->track = 0;
+   packet->flags = 0;
+   if(module->frame_read == 0)
+      packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
+   if(module->frame.keyframe)
+      packet->flags |= VC_CONTAINER_PACKET_FLAG_KEYFRAME;
+
+   if(flags & VC_CONTAINER_READ_FLAG_SKIP)
+   {
+      size = SKIP_BYTES(p_ctx, module->frame.framesize - module->frame_read);
+      if((module->frame_read += size) == module->frame.framesize)
+      {
+         module->frame_read = 0;
+         module->mid_frame = 0;
+      }      
+      return STREAM_STATUS(p_ctx);
+   }
+
+   if(flags & VC_CONTAINER_READ_FLAG_INFO)
+      return VC_CONTAINER_SUCCESS;
+
+   size = MIN(module->frame.framesize - module->frame_read, packet->buffer_size);
+   size = READ_BYTES(p_ctx, packet->data, size);
+   if((module->frame_read += size) == module->frame.framesize)
+   {
+      module->frame_read = 0;
+      module->mid_frame = 0;
+      packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
+   }      
+   packet->size = size;
+
+   return size ? VC_CONTAINER_SUCCESS : STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T rcv_reader_seek( VC_CONTAINER_T *p_ctx, int64_t *offset,
+   VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags)
+{
+   int past = 1;
+   int64_t position;
+   int64_t timestamp = *offset;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FAILED;
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_PARAM_UNUSED(mode);
+
+   if(module->index)
+      status = vc_container_index_get(module->index, flags & VC_CONTAINER_SEEK_FLAG_FORWARD, &timestamp, &position, &past);
+
+   if(status == VC_CONTAINER_SUCCESS && !past)
+   {
+      /* Indexed keyframe found */
+      module->frame_read = 0;
+      module->mid_frame = 0;
+      *offset = timestamp;
+      status = SEEK(p_ctx, position);
+   }
+   else
+   {
+      /* No indexed keyframe found, so seek through all frames */
+      status = rcv_seek_nearest_keyframe(p_ctx, offset, flags & VC_CONTAINER_SEEK_FLAG_FORWARD);
+   }
+
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T rcv_reader_close( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   for(; p_ctx->tracks_num > 0; p_ctx->tracks_num--)
+      vc_container_free_track(p_ctx, p_ctx->tracks[p_ctx->tracks_num-1]);
+
+   if(module->index)
+      vc_container_index_free(module->index);
+
+   free(module);
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T rcv_reader_open( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = 0;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   uint8_t dummy[8];
+
+   /* Quick check for a valid file header */
+   if((PEEK_BYTES(p_ctx, dummy, sizeof(dummy)) != sizeof(dummy)) ||
+      dummy[3] != 0xc5 || LI32(dummy+4) != 0x4)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   /* Allocate our context */
+   module = malloc(sizeof(*module));
+   if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(module, 0, sizeof(*module));
+   p_ctx->priv->module = module;
+   p_ctx->tracks_num = 1;
+   p_ctx->tracks = &module->track;
+   p_ctx->tracks[0] = vc_container_allocate_track(p_ctx, 0);
+   if(!p_ctx->tracks[0]) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   p_ctx->tracks[0]->format->es_type = VC_CONTAINER_ES_TYPE_VIDEO;
+   p_ctx->tracks[0]->format->codec = VC_CONTAINER_CODEC_WMV3;
+   p_ctx->tracks[0]->is_enabled = true;
+
+   if((status = rcv_read_header(p_ctx)) != VC_CONTAINER_SUCCESS) goto error;
+
+   LOG_DEBUG(p_ctx, "using rcv reader");
+
+   if(vc_container_index_create(&module->index, 512) == VC_CONTAINER_SUCCESS)
+      vc_container_index_add(module->index, 0LL, STREAM_POSITION(p_ctx));
+
+   if(STREAM_SEEKABLE(p_ctx))
+      p_ctx->capabilities |= VC_CONTAINER_CAPS_CAN_SEEK;
+
+   p_ctx->priv->pf_close = rcv_reader_close;
+   p_ctx->priv->pf_read = rcv_reader_read;
+   p_ctx->priv->pf_seek = rcv_reader_seek;
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+   if(module) rcv_reader_close(p_ctx);
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak reader_open rcv_reader_open
+#endif
diff --git a/containers/rtp/CMakeLists.txt b/containers/rtp/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..e6ba3a9
--- /dev/null
@@ -0,0 +1,17 @@
+# Container module needs to go in as a plugins so different prefix
+# and install path
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+
+# Make sure the compiler can find the necessary include files
+include_directories (../..)
+
+set(rtp_SRCS ${rtp_SRCS} rtp_reader.c)
+set(rtp_SRCS ${rtp_SRCS} rtp_h264.c)
+set(rtp_SRCS ${rtp_SRCS} rtp_mpeg4.c)
+set(rtp_SRCS ${rtp_SRCS} rtp_base64.c)
+add_library(reader_rtp ${LIBRARY_TYPE} ${rtp_SRCS})
+
+target_link_libraries(reader_rtp containers)
+
+install(TARGETS reader_rtp DESTINATION ${VMCS_PLUGIN_DIR})
+
diff --git a/containers/rtp/rtp_base64.c b/containers/rtp/rtp_base64.c
new file mode 100755 (executable)
index 0000000..f0e873f
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "rtp_base64.h"
+
+/******************************************************************************
+Defines and constants.
+******************************************************************************/
+
+#define LOWEST_BASE64_CHAR '+'
+#define HIGHEST_BASE64_CHAR 'z'
+#define IN_BASE64_RANGE(C) ((C) >= LOWEST_BASE64_CHAR && (C) <= HIGHEST_BASE64_CHAR)
+
+/** Used as a marker in the lookup table to indicate an invalid Base64 character */
+#define INVALID 0xFF
+
+/* Reduced lookup table for translating a character to a 6-bit value. The
+ * table starts at the lowest Base64 character, '+' */
+uint8_t base64_decode_lookup[] = {
+   62, INVALID, 62, INVALID, 63,                                              /* '+' to '/' */
+   52, 53, 54, 55, 56, 57, 58, 59, 60, 61,                                    /* '0' to '9' */
+   INVALID, INVALID, INVALID, INVALID, INVALID, INVALID, INVALID,             /* ':' to '@' */
+   0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,      /* 'A' to 'T' */
+   20, 21, 22, 23, 24, 25,                                                    /* 'U' to 'Z' */
+   INVALID, INVALID, INVALID, INVALID, 63, INVALID,                           /* '[' to '`' */
+   26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43,    /* 'a' to 'r' */
+   44, 45, 46, 47, 48, 49, 50, 51                                             /* 's' to 'z' */
+};
+
+/******************************************************************************
+Type definitions
+******************************************************************************/
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+
+/*****************************************************************************
+Functions exported as part of the Base64 API
+ *****************************************************************************/
+
+/*****************************************************************************/
+uint32_t rtp_base64_byte_length(const char *str, uint32_t str_len)
+{
+   uint32_t character_count = 0;
+   uint32_t ii;
+   char cc;
+
+   /* Scan through string until either a pad ('=') character or the end is
+    * reached. Ignore characters that are not part of the Base64 alphabet.
+    * Number of bytes should then be 3/4 of the character count. */
+
+   for (ii = 0; ii < str_len; ii++)
+   {
+      cc = *str++;
+      if (cc == '=')
+         break;         /* Found a pad character: stop */
+
+      if (!IN_BASE64_RANGE(cc))
+         continue;      /* Ignore invalid character */
+
+      if (base64_decode_lookup[cc - LOWEST_BASE64_CHAR] != INVALID)
+         character_count++;
+   }
+
+   return (character_count * 3) >> 2;
+}
+
+/*****************************************************************************/
+uint8_t *rtp_base64_decode(const char *str, uint32_t str_len, uint8_t *buffer, uint32_t buffer_len)
+{
+   uint32_t character_count = 0;
+   uint32_t value = 0;
+   uint32_t ii;
+   char cc;
+   uint8_t lookup;
+
+   /* Build up sets of four characters (ignoring invalid ones) to generate
+    * triplets of bytes, until either the end of the string or the pad ('=')
+    * characters are reached. */
+
+   for (ii = 0; ii < str_len; ii++)
+   {
+      cc = *str++;
+      if (cc == '=')
+         break;         /* Found a pad character: stop */
+
+      if (!IN_BASE64_RANGE(cc))
+         continue;      /* Ignore invalid character */
+
+      lookup = base64_decode_lookup[cc - LOWEST_BASE64_CHAR];
+      if (lookup == INVALID)
+         continue;      /* Ignore invalid character */
+
+      value = (value << 6) | lookup;
+      character_count++;
+
+      if (character_count == 4)
+      {
+         if (buffer_len < 3)
+            return NULL;   /* Not enough room in the output buffer */
+
+         *buffer++ = (uint8_t)(value >> 16);
+         *buffer++ = (uint8_t)(value >>  8);
+         *buffer++ = (uint8_t)(value      );
+         buffer_len -= 3;
+
+         character_count = 0;
+         value = 0;
+      }
+   }
+
+   /* If there were extra characters on the end, these need to be handled to get
+    * the last one or two bytes. */
+
+   switch (character_count)
+   {
+   case 0:  /* Nothing more to do, the final bytes were converted in the loop */
+      break;
+   case 2:  /* One additional byte, padded with four zero bits */
+      if (!buffer_len)
+         return NULL;
+      *buffer++ = (uint8_t)(value >> 4);
+      break;
+   case 3:  /* Two additional bytes, padded with two zero bits */
+      if (buffer_len < 2)
+         return NULL;
+      *buffer++ = (uint8_t)(value >> 10);
+      *buffer++ = (uint8_t)(value >> 2);
+      break;
+   default: /* This is an invalid Base64 encoding */
+      return NULL;
+   }
+
+   /* Return number of bytes written to the buffer */
+   return buffer;
+}
diff --git a/containers/rtp/rtp_base64.h b/containers/rtp/rtp_base64.h
new file mode 100755 (executable)
index 0000000..2cb6a76
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _RTP_BASE64_H_
+#define _RTP_BASE64_H_
+
+#include "containers/containers.h"
+
+/** Returns the number of bytes encoded by the given Base64 encoded string.
+ *
+ * \param str The Base64 encoded string.
+ * \param str_len The number of characters in the string.
+ * \return The number of bytes that can be decoded. */
+uint32_t rtp_base64_byte_length(const char *str, uint32_t str_len);
+
+/** Decodes a Base64 encoded string into a byte buffer.
+ *
+ * \param str The Base64 encoded string.
+ * \param str_len The number of characters in the string.
+ * \param buffer The buffer to receive the decoded output.
+ * \param buffer_len The maximum number of bytes to put in the buffer.
+ * \return Pointer to byte after the last one converted, or NULL on error. */
+uint8_t *rtp_base64_decode(const char *str, uint32_t str_len, uint8_t *buffer, uint32_t buffer_len);
+
+#endif /* _RTP_BASE64_H_ */
diff --git a/containers/rtp/rtp_h264.c b/containers/rtp/rtp_h264.c
new file mode 100755 (executable)
index 0000000..e7f0f83
--- /dev/null
@@ -0,0 +1,803 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "containers/containers.h"
+
+#include "containers/core/containers_logging.h"
+#include "containers/core/containers_list.h"
+#include "containers/core/containers_bits.h"
+#include "rtp_priv.h"
+#include "rtp_base64.h"
+#include "rtp_h264.h"
+
+/******************************************************************************
+Defines and constants.
+******************************************************************************/
+
+/** H.264 payload flag bits */
+typedef enum
+{
+   H264F_NEXT_PACKET_IS_START = 0,
+   H264F_INSIDE_FRAGMENT,
+   H264F_OUTPUT_NAL_HEADER,
+} h264_flag_bit_t;
+
+/** Bit mask to extract F zero bit from NAL unit header */
+#define NAL_UNIT_FZERO_MASK 0x80
+/** Bit mask to extract NAL unit type from NAL unit header */
+#define NAL_UNIT_TYPE_MASK 0x1F
+
+/** NAL unit type codes */
+enum
+{
+   /* 0 unspecified */
+   NAL_UNIT_NON_IDR = 1,
+   NAL_UNIT_PARTITION_A = 2,
+   NAL_UNIT_PARTITION_B = 3,
+   NAL_UNIT_PARTITION_C = 4,
+   NAL_UNIT_IDR = 5,
+   NAL_UNIT_SEI = 6,
+   NAL_UNIT_SEQUENCE_PARAMETER_SET = 7,
+   NAL_UNIT_PICTURE_PARAMETER_SET = 8,
+   NAL_UNIT_ACCESS_UNIT_DELIMITER = 9,
+   NAL_UNIT_END_OF_SEQUENCE = 10,
+   NAL_UNIT_END_OF_STREAM = 11,
+   NAL_UNIT_FILLER = 12,
+   NAL_UNIT_EXT_SEQUENCE_PARAMETER_SET = 13,
+   NAL_UNIT_PREFIX = 14,
+   NAL_UNIT_SUBSET_SEQUENCE_PARAMETER_SET = 15,
+   /* 16 to 18 reserved */
+   NAL_UNIT_AUXILIARY = 19,
+   NAL_UNIT_EXTENSION = 20,
+   /* 21 to 23 reserved */
+   NAL_UNIT_STAP_A = 24,
+   NAL_UNIT_STAP_B = 25,
+   NAL_UNIT_MTAP16 = 26,
+   NAL_UNIT_MTAP24 = 27,
+   NAL_UNIT_FU_A = 28,
+   NAL_UNIT_FU_B = 29,
+   /* 30 to 31 unspecified */
+};
+
+/** Fragment unit header indicator bits */
+typedef enum
+{
+   FRAGMENT_UNIT_HEADER_RESERVED = 5,
+   FRAGMENT_UNIT_HEADER_END = 6,
+   FRAGMENT_UNIT_HEADER_START = 7,
+} fragment_unit_header_bit_t;
+
+#define MACROBLOCK_WIDTH   16
+#define MACROBLOCK_HEIGHT  16
+
+/** H.264 RTP timestamp clock rate */
+#define H264_TIMESTAMP_CLOCK    90000
+
+typedef enum
+{
+   CHROMA_FORMAT_MONO = 0,
+   CHROMA_FORMAT_YUV_420 = 1,
+   CHROMA_FORMAT_YUV_422 = 2,
+   CHROMA_FORMAT_YUV_444 = 3,
+   CHROMA_FORMAT_YUV_444_PLANAR = 4,
+   CHROMA_FORMAT_RGB = 5,
+} CHROMA_FORMAT_T;
+
+uint32_t chroma_sub_width[] = {
+   1, 2, 2, 1, 1, 1
+};
+
+uint32_t chroma_sub_height[] = {
+   1, 2, 1, 1, 1, 1
+};
+
+/******************************************************************************
+Type definitions
+******************************************************************************/
+
+typedef struct h264_payload_tag
+{
+   uint32_t nal_unit_size;          /**< Number of NAL unit bytes left to write */
+   uint8_t flags;                   /**< H.264 payload flags */
+   uint8_t header_bytes_to_write;   /**< Number of start code bytes left to write */
+   uint8_t nal_header;              /**< Header for next NAL unit */
+} H264_PAYLOAD_T;
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+VC_CONTAINER_STATUS_T h264_parameter_handler(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track, const VC_CONTAINERS_LIST_T *params);
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+
+/**************************************************************************//**
+ * Remove emulation prevention bytes from a buffer.
+ * These are 0x03 bytes inserted to prevent misinterprentation of a byte
+ * sequence in a buffer as a start code.
+ *
+ * @param sprop      The buffer from which bytes are to be removed.
+ * @param sprop_size The number of bytes in the buffer.
+ * @return  The new number of bytes in the buffer.
+ */
+static uint32_t h264_remove_emulation_prevention_bytes(uint8_t *sprop,
+      uint32_t sprop_size)
+{
+   uint32_t offset = 0;
+   uint8_t nal_unit_type = sprop[offset++];
+   uint32_t new_sprop_size = sprop_size;
+   uint8_t first_byte, second_byte;
+
+   nal_unit_type &= 0x1F;  /* Just keep NAL unit type bits */
+
+   /* Certain NAL unit types need a byte triplet passed first */
+   if (nal_unit_type == NAL_UNIT_PREFIX || nal_unit_type == NAL_UNIT_EXTENSION)
+      offset += 3;
+
+   /* Make sure there is enough data for there to be a 0x00 0x00 0x03 sequence */
+   if (offset + 2 >= new_sprop_size)
+      return new_sprop_size;
+
+   /* Keep a rolling set of the last couple of bytes */
+   first_byte = sprop[offset++];
+   second_byte = sprop[offset++];
+
+   while (offset < new_sprop_size)
+   {
+      uint8_t next_byte = sprop[offset];
+
+      if (!first_byte && !second_byte && next_byte == 0x03)
+      {
+         /* Remove the emulation prevention byte (0x03) */
+         new_sprop_size--;
+         if (offset == new_sprop_size) /* No more data to check */
+            break;
+         memmove(&sprop[offset], &sprop[offset + 1], new_sprop_size - offset);
+         next_byte = sprop[offset];
+      } else
+         offset++;
+
+      first_byte = second_byte;
+      second_byte = next_byte;
+   }
+
+   return new_sprop_size;
+}
+
+/**************************************************************************//**
+ * Skip a scaling list in a bit stream.
+ *
+ * @param p_ctx                  The container context.
+ * @param sprop                  The bit stream containing the scaling list.
+ * @param size_of_scaling_list   The size of the scaling list.
+ */
+static void h264_skip_scaling_list(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_BITS_T *sprop,
+      uint32_t size_of_scaling_list)
+{
+   uint32_t last_scale = 8;
+   uint32_t next_scale = 8;
+   int32_t delta_scale;
+   uint32_t jj;
+
+   /* Algorithm taken from H.264 section 7.3.2.1.1.1 */
+   for (jj = 0; jj < size_of_scaling_list; jj++)
+   {
+      if (next_scale)
+      {
+         delta_scale = BITS_READ_S32_EXP(p_ctx, sprop, "delta_scale");
+         next_scale = (last_scale + delta_scale + 256) & 0xFF;
+
+         if (next_scale)
+            last_scale = next_scale;
+      }
+   }
+}
+
+/**************************************************************************//**
+ * Get the chroma format from the bit stream.
+ *
+ * @param p_ctx   The container context.
+ * @param sprop   The bit stream containing the scaling list.
+ * @return  The chroma format index.
+ */
+static uint32_t h264_get_chroma_format(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_BITS_T *sprop)
+{
+   uint32_t chroma_format_idc;
+
+   chroma_format_idc = BITS_READ_U32_EXP(p_ctx, sprop, "chroma_format_idc");
+   if (chroma_format_idc == 3 && BITS_READ_U32(p_ctx, sprop, 1, "separate_colour_plane_flag"))
+      chroma_format_idc = CHROMA_FORMAT_YUV_444_PLANAR;
+
+   BITS_SKIP_EXP(p_ctx, sprop, "bit_depth_luma_minus8");
+   BITS_SKIP_EXP(p_ctx, sprop, "bit_depth_chroma_minus8");
+   BITS_SKIP(p_ctx, sprop, 1, "qpprime_y_zero_transform_bypass_flag");
+
+   if (BITS_READ_U32(p_ctx, sprop, 1, "seq_scaling_matrix_present_flag"))
+   {
+      uint32_t scaling_lists = (chroma_format_idc == 3) ? 12 : 8;
+      uint32_t ii;
+
+      for (ii = 0; ii < scaling_lists; ii++)
+      {
+         if (BITS_READ_U32(p_ctx, sprop, 1, "seq_scaling_list_present_flag"))
+            h264_skip_scaling_list(p_ctx, sprop, (ii < 6) ? 16 : 64);
+      }
+   }
+
+   return chroma_format_idc;
+}
+
+/**************************************************************************//**
+ * Decode an H.264 sequence parameter set and update track information.
+ *
+ * @param p_ctx   The RTP container context.
+ * @param track   The track to be updated.
+ * @param sprop   The bit stream containing the sequence parameter set.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T h264_decode_sequence_parameter_set(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      VC_CONTAINER_BITS_T *sprop)
+{
+   VC_CONTAINER_VIDEO_FORMAT_T *video = &track->format->type->video;
+   uint32_t pic_order_cnt_type, chroma_format_idc;
+   uint32_t pic_width_in_mbs_minus1, pic_height_in_map_units_minus1, frame_mbs_only_flag;
+   uint32_t frame_crop_left_offset, frame_crop_right_offset, frame_crop_top_offset, frame_crop_bottom_offset;
+   uint8_t profile_idc;
+
+   /* This structure is defined by H.264 section 7.3.2.1.1 */
+   profile_idc = BITS_READ_U8(p_ctx, sprop, 8, "profile_idc");
+   BITS_SKIP(p_ctx, sprop, 16, "Rest of profile_level_id");
+
+   BITS_READ_U32_EXP(p_ctx, sprop, "seq_parameter_set_id");
+
+   chroma_format_idc = CHROMA_FORMAT_RGB;
+   if (profile_idc == 100 || profile_idc == 110 || profile_idc == 122 ||
+         profile_idc == 244 || profile_idc == 44 || profile_idc == 83 ||
+         profile_idc == 86 || profile_idc == 118 || profile_idc == 128)
+   {
+      chroma_format_idc = h264_get_chroma_format(p_ctx, sprop);
+      if (chroma_format_idc > CHROMA_FORMAT_YUV_444_PLANAR)
+         goto error;
+   }
+
+   BITS_SKIP_EXP(p_ctx, sprop, "log2_max_frame_num_minus4");
+   pic_order_cnt_type = BITS_READ_U32_EXP(p_ctx, sprop, "pic_order_cnt_type");
+   if (pic_order_cnt_type == 0)
+   {
+      BITS_SKIP_EXP(p_ctx, sprop, "log2_max_pic_order_cnt_lsb_minus4");
+   }
+   else if (pic_order_cnt_type == 1)
+   {
+      uint32_t num_ref_frames_in_pic_order_cnt_cycle;
+      uint32_t ii;
+
+      BITS_SKIP(p_ctx, sprop, 1, "delta_pic_order_always_zero_flag");
+      BITS_SKIP_EXP(p_ctx, sprop, "offset_for_non_ref_pic");
+      BITS_SKIP_EXP(p_ctx, sprop, "offset_for_top_to_bottom_field");
+      num_ref_frames_in_pic_order_cnt_cycle = BITS_READ_U32_EXP(p_ctx, sprop, "num_ref_frames_in_pic_order_cnt_cycle");
+
+      for (ii = 0; ii < num_ref_frames_in_pic_order_cnt_cycle; ii++)
+         BITS_SKIP_EXP(p_ctx, sprop, "offset_for_ref_frame");
+   }
+
+   BITS_SKIP_EXP(p_ctx, sprop, "max_num_ref_frames");
+   BITS_SKIP(p_ctx, sprop, 1, "gaps_in_frame_num_value_allowed_flag");
+
+   pic_width_in_mbs_minus1 = BITS_READ_U32_EXP(p_ctx, sprop, "pic_width_in_mbs_minus1");
+   pic_height_in_map_units_minus1 = BITS_READ_U32_EXP(p_ctx, sprop, "pic_height_in_map_units_minus1");
+   frame_mbs_only_flag = BITS_READ_U32(p_ctx, sprop, 1, "frame_mbs_only_flag");
+
+   /* Can now set the overall width and height in pixels */
+   video->width = (pic_width_in_mbs_minus1 + 1) * MACROBLOCK_WIDTH;
+   video->height = (2 - frame_mbs_only_flag) * (pic_height_in_map_units_minus1 + 1) * MACROBLOCK_HEIGHT;
+
+   if (!frame_mbs_only_flag)
+      BITS_SKIP(p_ctx, sprop, 1, "mb_adaptive_frame_field_flag");
+   BITS_SKIP(p_ctx, sprop, 1, "direct_8x8_inference_flag");
+
+   if (BITS_READ_U32(p_ctx, sprop, 1, "frame_cropping_flag"))
+   {
+      /* Visible area is restricted */
+      frame_crop_left_offset = BITS_READ_U32_EXP(p_ctx, sprop, "frame_crop_left_offset");
+      frame_crop_right_offset = BITS_READ_U32_EXP(p_ctx, sprop, "frame_crop_right_offset");
+      frame_crop_top_offset = BITS_READ_U32_EXP(p_ctx, sprop, "frame_crop_top_offset");
+      frame_crop_bottom_offset = BITS_READ_U32_EXP(p_ctx, sprop, "frame_crop_bottom_offset");
+
+      /* Need to adjust offsets for 4:2:0 and 4:2:2 chroma formats and field/frame flag */
+      frame_crop_left_offset *= chroma_sub_width[chroma_format_idc];
+      frame_crop_right_offset *= chroma_sub_width[chroma_format_idc];
+      frame_crop_top_offset *= chroma_sub_height[chroma_format_idc] * (2 - frame_mbs_only_flag);
+      frame_crop_bottom_offset *= chroma_sub_height[chroma_format_idc] * (2 - frame_mbs_only_flag);
+
+      if ((frame_crop_left_offset + frame_crop_right_offset) >= video->width ||
+            (frame_crop_top_offset + frame_crop_bottom_offset) >= video->height)
+      {
+         LOG_ERROR(p_ctx, "H.264: frame crop offsets (%u, %u, %u, %u) larger than frame (%u, %u)",
+               frame_crop_left_offset, frame_crop_right_offset, frame_crop_top_offset,
+               frame_crop_bottom_offset, video->width, video->height);
+         goto error;
+      }
+
+      video->x_offset = frame_crop_left_offset;
+      video->y_offset = frame_crop_top_offset;
+      video->visible_width = video->width - frame_crop_left_offset - frame_crop_right_offset;
+      video->visible_height = video->height - frame_crop_top_offset - frame_crop_bottom_offset;
+   } else {
+      video->visible_width = video->width;
+      video->visible_height = video->height;
+   }
+
+   /* vui_parameters may follow, but these will not be decoded */
+
+   if (!BITS_VALID(p_ctx, sprop))
+      goto error;
+
+   return VC_CONTAINER_SUCCESS;
+
+error:
+   LOG_ERROR(p_ctx, "H.264: sequence_parameter_set failed to decode");
+   return VC_CONTAINER_ERROR_FORMAT_INVALID;
+}
+
+/**************************************************************************//**
+ * Decode an H.264 sprop and update track information.
+ *
+ * @param p_ctx   The RTP container context.
+ * @param track   The track to be updated.
+ * @param sprop   The bit stream containing the sprop.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T h264_decode_sprop(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      VC_CONTAINER_BITS_T *sprop)
+{
+   switch (BITS_READ_U32(p_ctx, sprop, 8, "nal_unit_header") & NAL_UNIT_TYPE_MASK)
+   {
+   case NAL_UNIT_SEQUENCE_PARAMETER_SET:
+      return h264_decode_sequence_parameter_set(p_ctx, track, sprop);
+   case NAL_UNIT_PICTURE_PARAMETER_SET:
+      /* Not handled, but valid */
+      return VC_CONTAINER_SUCCESS;
+   default:
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+}
+
+/**************************************************************************//**
+ * Decode the sprop parameter sets URI parameter and update track information.
+ *
+ * @param p_ctx   The RTP container context.
+ * @param track   The track to be updated.
+ * @param params  The URI parameter list.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T h264_get_sprop_parameter_sets(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      const VC_CONTAINERS_LIST_T *params)
+{
+   VC_CONTAINER_STATUS_T status;
+   PARAMETER_T param;
+   size_t str_len;
+   uint32_t extradata_size = 0;
+   uint8_t *sprop;
+   const char *set;
+   const char *comma;
+
+   /* Get the value of sprop-parameter-sets, base64 decode the (comma separated)
+    * sets, store all of them in track->priv->extradata and also decode to
+    * validate and fill in video format info. */
+
+   param.name = "sprop-parameter-sets";
+   if (!vc_containers_list_find_entry(params, &param) || !param.value)
+   {
+      LOG_ERROR(p_ctx, "H.264: sprop-parameter-sets is required, but not found");
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+
+   /* First pass, calculate total size of buffer needed */
+   set = param.value;
+   do {
+      comma = strchr(set, ',');
+      str_len = comma ? (size_t)(comma - set) : strlen(set);
+      /* Allow space for the NAL unit and a start code */
+      extradata_size += rtp_base64_byte_length(set, str_len) + 4;
+      set = comma + 1;
+   } while (comma);
+
+   if (!extradata_size)
+   {
+      LOG_ERROR(p_ctx, "H.264: sprop-parameter-sets doesn't contain useful data");
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+
+   status = vc_container_track_allocate_extradata(p_ctx, track, extradata_size);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   track->format->extradata_size = extradata_size;
+   sprop = track->priv->extradata;
+
+   /* Now decode the data into the buffer, and validate / use it to fill in format */
+   set = param.value;
+   do {
+      uint8_t *next_sprop;
+      uint32_t sprop_size;
+      VC_CONTAINER_BITS_T sprop_stream;
+
+      comma = strchr(set, ',');
+      str_len = comma ? (size_t)(comma - set) : strlen(set);
+
+      /* Insert a start code (0x00000001 in network order) */
+      *sprop++ = 0x00; *sprop++ = 0x00; *sprop++ = 0x00; *sprop++ = 0x01;
+      extradata_size -= 4;
+
+      next_sprop = rtp_base64_decode(set, str_len, sprop, extradata_size);
+      if (!next_sprop)
+      {
+         LOG_ERROR(p_ctx, "H.264: sprop-parameter-sets failed to decode");
+         return VC_CONTAINER_ERROR_FORMAT_INVALID;
+      }
+
+      sprop_size = next_sprop - sprop;
+      if (sprop_size)
+      {
+         uint32_t new_sprop_size;
+
+         /* Need to remove emulation prevention bytes before decoding */
+         new_sprop_size = h264_remove_emulation_prevention_bytes(sprop, sprop_size);
+
+         BITS_INIT(p_ctx, &sprop_stream, sprop, new_sprop_size);
+         status = h264_decode_sprop(p_ctx, track, &sprop_stream);
+         if(status != VC_CONTAINER_SUCCESS) return status;
+
+         /* If necessary, decode sprop again, to put back the emulation prevention bytes */
+         if (new_sprop_size != sprop_size)
+            rtp_base64_decode(set, str_len, sprop, sprop_size);
+
+         extradata_size -= sprop_size;
+         sprop = next_sprop;
+      }
+
+      set = comma + 1;
+   } while (comma);
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/**************************************************************************//**
+ * Check URI parameter list for unsupported features.
+ *
+ * @param p_ctx   The RTP container context.
+ * @param params  The URI parameter list.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T h264_check_unsupported_features(VC_CONTAINER_T *p_ctx,
+      const VC_CONTAINERS_LIST_T *params)
+{
+   uint32_t u32_unused;
+
+   /* Limitation: interleaving not yet supported */
+   if (rtp_get_parameter_u32(params, "sprop-interleaving-depth", &u32_unused) ||
+         rtp_get_parameter_u32(params, "sprop-deint-buf-req", &u32_unused) ||
+         rtp_get_parameter_u32(params, "sprop-init-buf-time", &u32_unused) ||
+         rtp_get_parameter_u32(params, "sprop-max-don-diff", &u32_unused))
+   {
+      LOG_ERROR(p_ctx, "H.264: Interleaved packetization is not supported");
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   }
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/**************************************************************************//**
+ * Get and check the packetization mode URI parameter.
+ *
+ * @param p_ctx   The RTP container context.
+ * @param params  The URI parameter list.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T h264_get_packetization_mode(VC_CONTAINER_T *p_ctx,
+      const VC_CONTAINERS_LIST_T *params)
+{
+   uint32_t packetization_mode;
+
+   if (rtp_get_parameter_u32(params, "packetization-mode", &packetization_mode))
+   {
+      /* Only modes 0 and 1 are supported, no interleaving */
+      if (packetization_mode > 1)
+      {
+         LOG_ERROR(p_ctx, "H.264: Unsupported packetization mode: %u", packetization_mode);
+         return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+      }
+   }
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/**************************************************************************//**
+ * Initialise payload bit stream for a new RTP packet.
+ *
+ * @param p_ctx      The RTP container context.
+ * @param t_module   The track module with the new RTP packet.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T h264_new_rtp_packet(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_MODULE_T *t_module)
+{
+   VC_CONTAINER_BITS_T *payload = &t_module->payload;
+   H264_PAYLOAD_T *extra = (H264_PAYLOAD_T *)t_module->extra;
+   uint8_t unit_header;
+   uint8_t fragment_header;
+
+   /* Read the NAL unit type and process as necessary */
+   unit_header = BITS_READ_U8(p_ctx, payload, 8, "nal_unit_header");
+
+   /* When the top bit is set, the NAL unit is invalid */
+   if (unit_header & NAL_UNIT_FZERO_MASK)
+   {
+      LOG_DEBUG(p_ctx, "H.264: Invalid NAL unit (top bit of header set)");
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+
+   /* In most cases, a new packet means a new NAL unit, which will need a start code and the header */
+   extra->header_bytes_to_write = 5;
+   extra->nal_header = unit_header;
+   extra->nal_unit_size = BITS_BYTES_AVAILABLE(p_ctx, payload);
+
+   switch (unit_header & NAL_UNIT_TYPE_MASK)
+   {
+   case NAL_UNIT_STAP_A:
+      /* Single Time Aggregation Packet A */
+      CLEAR_BIT(extra->flags, H264F_INSIDE_FRAGMENT);
+      /* Trigger reading NAL unit length and header */
+      extra->nal_unit_size = 0;
+      break;
+
+   case NAL_UNIT_FU_A:
+      /* Fragementation Unit A */
+      fragment_header = BITS_READ_U8(p_ctx, payload, 8, "fragment_header");
+      extra->nal_unit_size--;
+
+      if (BIT_IS_CLEAR(fragment_header, FRAGMENT_UNIT_HEADER_START) ||
+            BIT_IS_SET(extra->flags, H264F_INSIDE_FRAGMENT))
+      {
+         /* This is a continuation packet, prevent start code and header from being output */
+         extra->header_bytes_to_write = 0;
+
+         /* If this is the end of a fragment, the next FU will be a new one */
+         if (BIT_IS_SET(fragment_header, FRAGMENT_UNIT_HEADER_END))
+            CLEAR_BIT(extra->flags, H264F_INSIDE_FRAGMENT);
+      } else {
+         /* Start of a new fragment. */
+         SET_BIT(extra->flags, H264F_INSIDE_FRAGMENT);
+
+         /* Merge type from fragment header and the rest from NAL unit header to form real NAL unit header */
+         fragment_header &= NAL_UNIT_TYPE_MASK;
+         fragment_header |= (unit_header & ~NAL_UNIT_TYPE_MASK);
+         extra->nal_header = fragment_header;
+      }
+      break;
+
+   case NAL_UNIT_STAP_B:
+   case NAL_UNIT_MTAP16:
+   case NAL_UNIT_MTAP24:
+   case NAL_UNIT_FU_B:
+      LOG_ERROR(p_ctx, "H.264: Unsupported RTP NAL unit type: %u", unit_header & NAL_UNIT_TYPE_MASK);
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   default:
+      /* Single NAL unit case */
+      CLEAR_BIT(extra->flags, H264F_INSIDE_FRAGMENT);
+   }
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/**************************************************************************//**
+ * H.264 payload handler.
+ * Extracts/skips data from the payload according to the NAL unit headers.
+ *
+ * @param p_ctx      The RTP container context.
+ * @param track      The track being read.
+ * @param p_packet   The container packet information, or NULL.
+ * @param flags      The container read flags.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T h264_payload_handler(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      VC_CONTAINER_PACKET_T *p_packet,
+      uint32_t flags)
+{
+   VC_CONTAINER_TRACK_MODULE_T *t_module = track->priv->module;
+   VC_CONTAINER_BITS_T *payload = &t_module->payload;
+   H264_PAYLOAD_T *extra = (H264_PAYLOAD_T *)t_module->extra;
+   uint32_t packet_flags = 0;
+   uint8_t header_bytes_to_write;
+   uint32_t size, offset;
+   uint8_t *data_ptr;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   bool last_nal_unit_in_packet = false;
+
+   if (BIT_IS_SET(t_module->flags, TRACK_NEW_PACKET))
+   {
+      status = h264_new_rtp_packet(p_ctx, t_module);
+      if (status != VC_CONTAINER_SUCCESS)
+         return status;
+   }
+
+   if (BIT_IS_SET(extra->flags, H264F_NEXT_PACKET_IS_START))
+   {
+      packet_flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
+
+      if (!(flags & VC_CONTAINER_READ_FLAG_INFO))
+         CLEAR_BIT(extra->flags, H264F_NEXT_PACKET_IS_START);
+   }
+
+   if (!extra->nal_unit_size && BITS_BYTES_AVAILABLE(p_ctx, payload))
+   {
+      uint32_t stap_unit_header;
+
+      /* STAP-A packet: read NAL unit size and header from payload */
+      stap_unit_header = BITS_READ_U32(p_ctx, payload, 24, "STAP unit header");
+      extra->nal_unit_size = stap_unit_header >> 8;
+      if (extra->nal_unit_size > BITS_BYTES_AVAILABLE(p_ctx, payload))
+      {
+         LOG_ERROR(p_ctx, "H.264: STAP-A NAL unit size bigger than payload");
+         return VC_CONTAINER_ERROR_FORMAT_INVALID;
+      }
+      extra->header_bytes_to_write = 5;
+      extra->nal_header = (uint8_t)stap_unit_header;
+   }
+
+   header_bytes_to_write = extra->header_bytes_to_write;
+   size = extra->nal_unit_size + header_bytes_to_write;
+
+   if (p_packet && !(flags & VC_CONTAINER_READ_FLAG_SKIP))
+   {
+      if (flags & VC_CONTAINER_READ_FLAG_INFO)
+      {
+         /* In order to set the frame end flag correctly, need to work out if this
+          * is the only NAL unit or last in an aggregated packet */
+         last_nal_unit_in_packet = (extra->nal_unit_size == BITS_BYTES_AVAILABLE(p_ctx, payload));
+      } else {
+         offset = 0;
+         data_ptr = p_packet->data;
+
+         if (size > p_packet->buffer_size)
+         {
+            /* Buffer not big enough */
+            size = p_packet->buffer_size;
+         }
+
+         /* Insert start code and header into the data stream */
+         while (offset < size && header_bytes_to_write)
+         {
+            uint8_t header_byte;
+
+            switch (header_bytes_to_write)
+            {
+            case 2: header_byte = 0x01; break;
+            case 1: header_byte = extra->nal_header; break;
+            default: header_byte = 0x00;
+            }
+            data_ptr[offset++] = header_byte;
+            header_bytes_to_write--;
+         }
+         extra->header_bytes_to_write = header_bytes_to_write;
+
+         if (offset < size)
+         {
+            BITS_COPY_BYTES(p_ctx, payload, size - offset, data_ptr + offset, "Packet data");
+            extra->nal_unit_size -= (size - offset);
+         }
+
+         /* If we've read the final bytes of the packet, this must be the last (or only)
+          * NAL unit in it */
+         last_nal_unit_in_packet = !BITS_BYTES_AVAILABLE(p_ctx, payload);
+      }
+      p_packet->size = size;
+   } else {
+      extra->header_bytes_to_write = 0;
+      BITS_SKIP_BYTES(p_ctx, payload, extra->nal_unit_size, "Packet data");
+      last_nal_unit_in_packet = !BITS_BYTES_AVAILABLE(p_ctx, payload);
+      extra->nal_unit_size = 0;
+   }
+
+   /* The marker bit on an RTP packet indicates the frame ends at the end of packet */
+   if (last_nal_unit_in_packet && BIT_IS_SET(t_module->flags, TRACK_HAS_MARKER))
+   {
+      packet_flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
+
+      /* If this was the last packet of a frame, the next one must be the start */
+      if (!(flags & VC_CONTAINER_READ_FLAG_INFO))
+         SET_BIT(extra->flags, H264F_NEXT_PACKET_IS_START);
+   }
+
+   if (p_packet)
+      p_packet->flags = packet_flags;
+
+   return status;
+}
+
+/*****************************************************************************
+Functions exported as part of the RTP parameter handler API
+ *****************************************************************************/
+
+/**************************************************************************//**
+ * H.264 parameter handler.
+ * Parses the URI parameters to set up the track for an H.264 stream.
+ *
+ * @param p_ctx   The reader context.
+ * @param track   The track to be updated.
+ * @param params  The URI parameter list.
+ * @return  The resulting status of the function.
+ */
+VC_CONTAINER_STATUS_T h264_parameter_handler(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      const VC_CONTAINERS_LIST_T *params)
+{
+   H264_PAYLOAD_T *extra;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+   VC_CONTAINER_PARAM_UNUSED(params);
+
+   /* See RFC3984, section 8.1, for parameter names and details. */
+   extra = (H264_PAYLOAD_T *)malloc(sizeof(H264_PAYLOAD_T));
+   if (!extra)
+      return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+   track->priv->module->extra = extra;
+   memset(extra, 0, sizeof(H264_PAYLOAD_T));
+
+   /* Mandatory parameters */
+   status = h264_get_sprop_parameter_sets(p_ctx, track, params);
+   if (status != VC_CONTAINER_SUCCESS) return status;
+
+   /* Unsupported parameters */
+   status = h264_check_unsupported_features(p_ctx, params);
+   if (status != VC_CONTAINER_SUCCESS) return status;
+
+   /* Optional parameters */
+   status = h264_get_packetization_mode(p_ctx, params);
+   if (status != VC_CONTAINER_SUCCESS) return status;
+
+   track->priv->module->payload_handler = h264_payload_handler;
+   SET_BIT(extra->flags, H264F_NEXT_PACKET_IS_START);
+
+   track->format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
+   track->priv->module->timestamp_clock = H264_TIMESTAMP_CLOCK;
+
+   return status;
+}
+
diff --git a/containers/rtp/rtp_h264.h b/containers/rtp/rtp_h264.h
new file mode 100755 (executable)
index 0000000..ffd51da
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _RTP_H264_H_
+#define _RTP_H264_H_
+
+#include "containers/containers.h"
+#include "containers/core/containers_list.h"
+
+/** H.264 parameter handler
+ *
+ * \param p_ctx Container context.
+ * \param track Track data.
+ * \param params Parameter list.
+ * \return Status of decoding the H.264 parameters. */
+VC_CONTAINER_STATUS_T h264_parameter_handler(VC_CONTAINER_T *p_ctx, VC_CONTAINER_TRACK_T *track, const VC_CONTAINERS_LIST_T *params);
+
+#endif /* _RTP_H264_H_ */
diff --git a/containers/rtp/rtp_mpeg4.c b/containers/rtp/rtp_mpeg4.c
new file mode 100755 (executable)
index 0000000..6a968e4
--- /dev/null
@@ -0,0 +1,788 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "containers/containers.h"
+
+#include "containers/core/containers_logging.h"
+#include "containers/core/containers_bits.h"
+#include "containers/core/containers_list.h"
+#include "rtp_priv.h"
+#include "rtp_mpeg4.h"
+
+#ifdef _DEBUG
+#define RTP_DEBUG 1
+#endif
+
+/******************************************************************************
+Defines and constants.
+******************************************************************************/
+
+/******************************************************************************
+Type definitions
+******************************************************************************/
+
+/** MPEG-4 stream types, ISO/IEC 14496-1:2010 Table 6 */
+typedef enum
+{
+   MPEG4_OBJECT_DESCRIPTOR_STREAM = 1,
+   MPEG4_CLOCK_REFERENCE_STREAM = 2,
+   MPEG4_SCENE_DESCRIPTION_STREAM = 3,
+   MPEG4_VISUAL_STREAM = 4,
+   MPEG4_AUDIO_STREAM = 5,
+   MPEG4_MPEG7_STREAM = 6,
+   MPEG4_IPMP_STREAM = 7,
+   MPEG4_OBJECT_CONTENT_INFO_STREAM = 8,
+   MPEG4_MPEGJ_STREAM = 9,
+   MPEG4_INTERACTION_STREAM = 10,
+   MPEG4_IPMP_TOOL_STREAM = 11,
+} mp4_stream_type_t;
+
+/** MPEG-4 audio object types, ISO/IEC 14496-3:2009 Table 1.17 */
+typedef enum
+{
+   MPEG4A_AAC_MAIN = 1,
+   MPEG4A_AAC_LC = 2,
+   MPEG4A_AAC_SSR = 3,
+   MPEG4A_AAC_LTP = 4,
+   MPEG4A_SBR = 5,
+   MPEG4A_AAC_SCALABLE = 6,
+   MPEG4A_TWIN_VQ = 7,
+   MPEG4A_CELP = 8,
+   MPEG4A_HVXC = 9,
+   MPEG4A_TTSI = 12,
+   MPEG4A_MAIN_SYNTHETIC = 13,
+   MPEG4A_WAVETABLE_SYNTHESIS = 14,
+   MPEG4A_GENERAL_MIDI = 15,
+   MPEG4A_ALGORITHMIC_SYNTHESIS = 16,
+   MPEG4A_ER_AAC_LC = 17,
+   MPEG4A_ER_AAC_LTP = 19,
+   MPEG4A_ER_AAC_SCALABLE = 20,
+   MPEG4A_ER_TWIN_VQ = 21,
+   MPEG4A_ER_BSAC = 22,
+   MPEG4A_ER_AAC_LD = 23,
+   MPEG4A_ER_CELP = 24,
+   MPEG4A_ER_HVXC = 25,
+   MPEG4A_ER_HILN = 26,
+   MPEG4A_ER_PARAMETERIC = 27,
+   MPEG4A_SSC = 28,
+   MPEG4A_PS = 29,
+   MPEG4A_MPEG_SURROUND = 30,
+   MPEG4A_LAYER_1 = 32,
+   MPEG4A_LAYER_2 = 33,
+   MPEG4A_LAYER_3 = 34,
+   MPEG4A_DST = 35,
+   MPEG4A_ALS = 36,
+   MPEG4A_SLS = 37,
+   MPEG4A_SLS_NON_CORE = 38,
+   MPEG4A_ER_AAC_ELD = 39,
+   MPEG4A_SMR_SIMPLE = 40,
+   MPEG4A_SMR_MAIN = 41,
+} mp4_audio_object_type_t;
+
+/** RTP MPEG-4 modes */
+typedef enum
+{
+   MP4_GENERIC_MODE = 0,
+   MP4_CELP_CBR_MODE,
+   MP4_CELP_VBR_MODE,
+   MP4_AAC_LBR_MODE,
+   MP4_AAC_HBR_MODE
+} mp4_mode_t;
+
+typedef struct mp4_mode_detail_tag
+{
+   const char *name;
+   mp4_mode_t mode;
+} MP4_MODE_ENTRY_T;
+
+/* RTP MPEG-4 mode look-up table.
+ * Note: case-insensitive sort by name */
+static MP4_MODE_ENTRY_T mp4_mode_array[] = {
+   { "aac-hbr", MP4_AAC_HBR_MODE },
+   { "aac-lbr", MP4_AAC_LBR_MODE },
+   { "celp-cbr", MP4_CELP_CBR_MODE },
+   { "celp-vbr", MP4_CELP_VBR_MODE },
+   { "generic", MP4_GENERIC_MODE },
+};
+
+static int mp4_mode_comparator(const MP4_MODE_ENTRY_T *a, const MP4_MODE_ENTRY_T *b);
+
+VC_CONTAINERS_STATIC_LIST(mp4_mode_lookup, mp4_mode_array, mp4_mode_comparator);
+
+typedef struct au_info_tag
+{
+   uint32_t available;
+   uint32_t index;
+   int32_t cts_delta;
+   int32_t dts_delta;
+} AU_INFO_T;
+
+typedef struct mp4_payload_tag
+{
+   mp4_stream_type_t stream_type;
+   uint32_t profile_level_id;
+   mp4_mode_t mode;
+   uint32_t size_length;
+   uint32_t index_length;
+   uint32_t index_delta_length;
+   uint32_t cts_delta_length;
+   uint32_t dts_delta_length;
+   uint32_t object_type;
+   uint32_t constant_size;
+   uint32_t constant_duration;
+   uint32_t auxiliary_length;
+   VC_CONTAINER_BITS_T au_headers;
+   AU_INFO_T au_info;
+} MP4_PAYLOAD_T;
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+VC_CONTAINER_STATUS_T mp4_parameter_handler(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track, const VC_CONTAINERS_LIST_T *params);
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+
+/**************************************************************************//**
+ * Convert a hexadecimal character to a value between 0 and 15.
+ * Upper and lower case characters are supported. An invalid chacter return zero.
+ *
+ * @param hex  The character to convert.
+ * @return  The value of the character.
+ */
+static uint8_t hex_to_nybble(char hex)
+{
+   if (hex >= '0' && hex <= '9')
+      return hex - '0';
+   if (hex >= 'A' && hex <= 'F')
+      return hex - 'A' + 10;
+   if (hex >= 'a' && hex <= 'f')
+      return hex - 'a' + 10;
+   return 0;   /* Illegal character (not hex) */
+}
+
+/**************************************************************************//**
+ * Convert a sequence of hexadecimal characters to consecutive entries in a
+ * byte array.
+ * The string must contain at least twice as many characters as the number of
+ * bytes to convert.
+ *
+ * @param hex              The hexadecimal string.
+ * @param buffer           The buffer into which bytes are to be stored.
+ * @param bytes_to_convert The number of bytes in the array to be filled.
+ */
+static void hex_to_byte_buffer(const char *hex,
+      uint8_t *buffer,
+      uint32_t bytes_to_convert)
+{
+   uint8_t value;
+
+   while (bytes_to_convert--)
+   {
+      value = hex_to_nybble(*hex++) << 4;
+      value |= hex_to_nybble(*hex++);
+      *buffer++ = value;
+   }
+}
+
+/**************************************************************************//**
+ * Retrieves and checks the stream type in the URI parameters.
+ *
+ * @param p_ctx   The RTP container context.
+ * @param track   The track being constructed.
+ * @param params  The URI parameter list.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T mp4_get_stream_type(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      const VC_CONTAINERS_LIST_T *params)
+{
+   MP4_PAYLOAD_T *extra = (MP4_PAYLOAD_T *)track->priv->module->extra;
+   uint32_t stream_type;
+   VC_CONTAINER_ES_TYPE_T expected_es_type;
+
+   if (!rtp_get_parameter_u32(params, "streamType", &stream_type))
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+
+   switch (stream_type)
+   {
+   case MPEG4_AUDIO_STREAM:
+      extra->stream_type = MPEG4_AUDIO_STREAM;
+      expected_es_type = VC_CONTAINER_ES_TYPE_AUDIO;
+      break;
+   default:
+      LOG_ERROR(p_ctx, "Unsupported MPEG-4 stream type: %u", stream_type);
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+
+   if (track->format->es_type != expected_es_type)
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/**************************************************************************//**
+ * Decode and store audio configuration information from an MP4 audio
+ * configuration bit stream.
+ *
+ * @param p_ctx      The RTP container context.
+ * @param track      The track being constructed.
+ * @param bit_stream The bit stream containing the audio configuration.
+ * @return  True if the configuration was decoded successfully, false otherwise.
+ */
+static bool mp4_decode_audio_config(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      VC_CONTAINER_BITS_T *bit_stream)
+{
+   static uint32_t mp4_audio_sample_rate[] =
+         { 96000, 88200, 64000, 48000, 44100, 32000, 24000,
+           22050, 16000, 12000, 11025, 8000, 7350, 0, 0 };
+
+   VC_CONTAINER_AUDIO_FORMAT_T *audio = &track->format->type->audio;
+   uint32_t audio_object_type;
+   uint32_t sampling_frequency_index;
+   uint32_t channel_configuration;
+
+   audio_object_type = BITS_READ_U32(p_ctx, bit_stream, 5, "audioObjectType");
+   if (audio_object_type == 31)
+      audio_object_type = BITS_READ_U32(p_ctx, bit_stream, 6, "audioObjectTypeExt") + 32;
+
+   sampling_frequency_index = BITS_READ_U32(p_ctx, bit_stream, 4, "samplingFrequencyIndex");
+   if (sampling_frequency_index == 0xF)
+      audio->sample_rate = BITS_READ_U32(p_ctx, bit_stream, 24, "samplingFrequency");
+   else
+      audio->sample_rate = mp4_audio_sample_rate[sampling_frequency_index];
+   if (!audio->sample_rate) return false;
+
+   track->priv->module->timestamp_clock = audio->sample_rate;
+
+   channel_configuration = BITS_READ_U32(p_ctx, bit_stream, 4, "channelConfiguration");
+   switch (channel_configuration)
+   {
+   case 1:  /* 1 channel, centre front */
+   case 2:  /* 2 channel, stereo front */
+   case 3:  /* 3 channel, centre and stereo front */
+   case 4:  /* 4 channel, centre and stereo front, mono surround */
+   case 5:  /* 5 channel, centre and stereo front, stereo surround */
+   case 6:  /* 5.1 channel, centre and stereo front, stereo surround, low freq */
+      audio->channels = channel_configuration;
+      break;
+   case 7:  /* 7.1 channel, centre, stereo and stereo outside front, stereo surround, low freq */
+      audio->channels = channel_configuration + 1;
+      break;
+   default:
+      LOG_DEBUG(p_ctx, "MPEG-4: Unsupported channel configuration (%u)", channel_configuration);
+      return false;
+   }
+
+   switch (audio_object_type)
+   {
+   case MPEG4A_AAC_LC:
+      {
+         uint32_t ga_specific_config = BITS_READ_U32(p_ctx, bit_stream, 3, "GASpecificConfig");
+
+         /* Make sure there are no unexpected (and unsupported) additional configuration elements */
+         if (ga_specific_config != 0)
+         {
+            LOG_DEBUG(p_ctx, "MPEG-4: Unexpected additional configuration data (%u)", ga_specific_config);
+            return false;
+         }
+      }
+      break;
+   /* Add any further supported codecs here */
+   default:
+      LOG_DEBUG(p_ctx, "MPEG-4: Unsupported Audio Object Type (%u)", audio_object_type);
+      return false;
+   }
+
+   return true;
+}
+
+/**************************************************************************//**
+ * Get, store and decode the configuration information from the URI parameters.
+ *
+ * @param p_ctx   The RTP container context.
+ * @param track   The track being constructed.
+ * @param params  The URI parameter list.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T mp4_get_config(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      const VC_CONTAINERS_LIST_T *params)
+{
+   MP4_PAYLOAD_T *extra = (MP4_PAYLOAD_T *)track->priv->module->extra;
+   PARAMETER_T param;
+   uint32_t config_len;
+   VC_CONTAINER_STATUS_T status;
+   uint8_t *config;
+   VC_CONTAINER_BITS_T bit_stream;
+
+   param.name = "config";
+   if (!vc_containers_list_find_entry(params, &param) || !param.value)
+   {
+      LOG_ERROR(p_ctx, "MPEG-4: config parameter missing");
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+
+   config_len = strlen(param.value);
+   if (config_len & 1)
+   {
+      LOG_ERROR(p_ctx, "MPEG-4: config parameter invalid");
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+   config_len /= 2;
+
+   /* Copy AudioSpecificConfig into track extradata, to be decoded by client */
+   status = vc_container_track_allocate_extradata(p_ctx, track, config_len);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   config = track->priv->extradata;
+   track->format->extradata_size = config_len;
+   hex_to_byte_buffer(param.value, config, config_len);
+
+   /* Decode config locally, to determine sample rate, etc. */
+   BITS_INIT(p_ctx, &bit_stream, config, config_len);
+
+   switch (extra->stream_type)
+   {
+   case MPEG4_AUDIO_STREAM:
+      if (!mp4_decode_audio_config(p_ctx, track, &bit_stream))
+         return VC_CONTAINER_ERROR_FORMAT_INVALID;
+      break;
+   default:
+      /* Other stream types not yet supported */
+      LOG_ERROR(p_ctx, "MPEG-4: stream type %d not supported", extra->stream_type);
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/**************************************************************************//**
+ * MP4 mode comparison function.
+ * Compare two MP4 mode structures and return whether the first is less than,
+ * equal to or greater than the second.
+ *
+ * @param first   The first structure to be compared.
+ * @param second  The second structure to be compared.
+ * @return  Negative if first is less than second, positive if first is greater
+ *          and zero if they are equal.
+ */
+static int mp4_mode_comparator(const MP4_MODE_ENTRY_T *a, const MP4_MODE_ENTRY_T *b)
+{
+   return strcasecmp(a->name, b->name);
+}
+
+/**************************************************************************//**
+ * Get and store the MP4 mode, if recognised, from the URI parameters.
+ *
+ * @param p_ctx   The RTP container context.
+ * @param track   The track being constructed.
+ * @param params  The URI parameter list.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T mp4_get_mode(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      const VC_CONTAINERS_LIST_T *params)
+{
+   MP4_PAYLOAD_T *extra = (MP4_PAYLOAD_T *)track->priv->module->extra;
+   PARAMETER_T param;
+   MP4_MODE_ENTRY_T mode_entry;
+
+   param.name = "mode";
+   if (!vc_containers_list_find_entry(params, &param) || !param.value)
+   {
+      LOG_ERROR(p_ctx, "MPEG-4: mode parameter missing");
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+
+#ifdef RTP_DEBUG
+   vc_containers_list_validate(&mp4_mode_lookup);
+#endif
+
+   mode_entry.name = param.value;
+   if (!vc_containers_list_find_entry(&mp4_mode_lookup, &mode_entry))
+   {
+      LOG_ERROR(p_ctx, "MPEG-4: Unrecognised mode parameter \"%s\"", mode_entry.name);
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+
+   extra->mode = mode_entry.mode;
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/**************************************************************************//**
+ * Check URI parameters for unsupported features.
+ *
+ * @param p_ctx   The RTP container context.
+ * @param track   The track being constructed.
+ * @param params  The URI parameter list.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T mp4_check_unsupported_features(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      const VC_CONTAINERS_LIST_T *params)
+{
+   uint32_t u32_unused;
+
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+   VC_CONTAINER_PARAM_UNUSED(track);
+
+   /* Limitation: RAP flag not yet supported */
+   if (rtp_get_parameter_u32(params, "randomAccessIndication", &u32_unused))
+   {
+      LOG_ERROR(p_ctx, "MPEG-4: random access not supported");
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   }
+
+   /* Limitation: interleaving not yet supported */
+   if (rtp_get_parameter_u32(params, "maxDisplacement", &u32_unused) ||
+         rtp_get_parameter_u32(params, "de-interleaveBufferSize", &u32_unused))
+   {
+      LOG_ERROR(p_ctx, "MPEG-4: interleaved packetization not supported");
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   }
+
+   /* Limitation: system streams not supported */
+   if (rtp_get_parameter_u32(params, "streamStateIndication", &u32_unused))
+   {
+      LOG_ERROR(p_ctx, "MPEG-4: system streams not supported");
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   }
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/**************************************************************************//**
+ * Validate parameters that have been read form the URI parameter list.
+ *
+ * @param p_ctx   The RTP container context.
+ * @param track   The track being constructed.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T mp4_check_parameters(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track)
+{
+   MP4_PAYLOAD_T *extra = (MP4_PAYLOAD_T *)track->priv->module->extra;
+
+   switch (extra->mode)
+   {
+   case MP4_CELP_CBR_MODE:
+      if (!extra->constant_size)
+      {
+         LOG_ERROR(p_ctx, "MPEG-4: CELP-cbr requires constantSize parameter.");
+         return VC_CONTAINER_ERROR_FORMAT_INVALID;
+      }
+      break;
+   case MP4_CELP_VBR_MODE:
+   case MP4_AAC_LBR_MODE:
+      if (extra->size_length != 6 || extra->index_length != 2 || extra->index_delta_length != 2)
+      {
+         LOG_ERROR(p_ctx, "MPEG-4: CELP-vbr/AAC-lbr invalid lengths (%u/%u/%u)",
+               extra->size_length, extra->index_length, extra->index_delta_length);
+         return VC_CONTAINER_ERROR_FORMAT_INVALID;
+      }
+      break;
+   case MP4_AAC_HBR_MODE:
+      if (extra->size_length != 13 || extra->index_length != 3 || extra->index_delta_length != 3)
+      {
+         LOG_ERROR(p_ctx, "MPEG-4: AAC-hbr invalid lengths (%u/%u/%u)",
+               extra->size_length, extra->index_length, extra->index_delta_length);
+         return VC_CONTAINER_ERROR_FORMAT_INVALID;
+      }
+      break;
+   default: /* MP4_GENERIC_MODE */
+      if (extra->size_length > 32 || extra->index_length > 32 || extra->index_delta_length > 32)
+      {
+         LOG_ERROR(p_ctx, "MPEG-4: generic invalid lengths (%u/%u/%u)",
+               extra->size_length, extra->index_length, extra->index_delta_length);
+         return VC_CONTAINER_ERROR_FORMAT_INVALID;
+      }
+   }
+
+   if (extra->cts_delta_length > 32 || extra->dts_delta_length > 32)
+   {
+      LOG_ERROR(p_ctx, "MPEG-4: CTS/DTS invalid lengths (%u/%u)",
+            extra->cts_delta_length, extra->dts_delta_length);
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/**************************************************************************//**
+ * Initialise payload bit stream for a new RTP packet.
+ *
+ * @param p_ctx      The RTP container context.
+ * @param t_module   The track module with the new RTP packet.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T mp4_new_rtp_packet(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_MODULE_T *t_module)
+{
+   VC_CONTAINER_BITS_T *payload = &t_module->payload;
+   MP4_PAYLOAD_T *extra = (MP4_PAYLOAD_T *)t_module->extra;
+   VC_CONTAINER_BITS_T *au_headers = &extra->au_headers;
+
+   /* There will be an AU header section if any of its fields are non-zero. */
+   if (extra->size_length || extra->index_length || extra->cts_delta_length || extra->dts_delta_length)
+   {
+      uint32_t au_headers_length;
+
+      /* Calculate how far to advance the payload, to get past the AU headers */
+      au_headers_length = BITS_READ_U32(p_ctx, payload, 16, "AU headers length");
+      au_headers_length = BITS_TO_BYTES(au_headers_length); /* Round up to bytes */
+
+      /* Record where the AU headers are in the payload */
+      BITS_INIT(p_ctx, au_headers, BITS_CURRENT_POINTER(p_ctx, payload), au_headers_length);
+      BITS_SKIP_BYTES(p_ctx, &t_module->payload, au_headers_length, "Move payload past AU headers");
+   }
+
+   /* Skip the auxiliary section, if present */
+   if (extra->auxiliary_length)
+   {
+      uint32_t auxiliary_data_size;
+
+      auxiliary_data_size = BITS_READ_U32(p_ctx, payload, extra->auxiliary_length, "Auxiliary length");
+      auxiliary_data_size = BITS_TO_BYTES(auxiliary_data_size); /* Round up to bytes */
+      BITS_SKIP_BYTES(p_ctx, payload, auxiliary_data_size, "Auxiliary data");
+   }
+
+   return BITS_VALID(p_ctx, payload) ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FORMAT_INVALID;
+}
+
+/**************************************************************************//**
+ * Read a flagged delta from an AU header bit stream.
+ * A flagged delta is an optional value in the stream that is preceded by a
+ * flag bit that indicates whether the value is present in the stream. If the
+ * length of the value is zero bits, the flag is never present.
+ *
+ * @pre The delta_length must be 32 or less.
+ *
+ * @param p_ctx         The container context.
+ * @param au_headers    The AU header bit stream.
+ * @param delta_length  The number of bits in the delta value.
+ * @return  The delta value, or zero if not present.
+ */
+static int32_t mp4_flagged_delta(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_BITS_T *au_headers,
+      uint32_t delta_length)
+{
+   uint32_t value = 0;
+
+   /* Flag is only present if the delta length is non-zero */
+   if (delta_length && BITS_READ_U32(p_ctx, au_headers, 1, "CTS/DTS delta present"))
+   {
+      value = BITS_READ_U32(p_ctx, au_headers, delta_length, "CTS/DTS delta");
+
+      /* Sign extend value based on bit length */
+      if (value & (1 << (delta_length - 1)))
+         value |= ~((1 << delta_length) - 1);
+   }
+
+   return (int32_t)value;
+}
+
+/**************************************************************************//**
+ * Read next AU header from the bit stream.
+ *
+ * @param p_ctx         The RTP container context.
+ * @param extra         The MP4-specific track module information.
+ * @param is_first_au   True if the first AU header in the packet is being read.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T mp4_next_au_header(VC_CONTAINER_T *p_ctx,
+      MP4_PAYLOAD_T *extra,
+      bool is_first_au)
+{
+   VC_CONTAINER_BITS_T *au_headers = &extra->au_headers;
+   AU_INFO_T *au_info = &extra->au_info;
+
+   /* See RFC3550 section 3.2.1.1 */
+
+   if (extra->constant_size)
+      au_info->available = extra->constant_size;
+   else
+      au_info->available = BITS_READ_U32(p_ctx, au_headers, extra->size_length, "AU size");
+
+   if (is_first_au)
+      au_info->index = BITS_READ_U32(p_ctx, au_headers, extra->index_length, "AU index");
+   else
+      au_info->index += BITS_READ_U32(p_ctx, au_headers, extra->index_delta_length, "AU index delta") + 1;
+
+   au_info->cts_delta = mp4_flagged_delta(p_ctx, au_headers, extra->cts_delta_length);
+   au_info->dts_delta = mp4_flagged_delta(p_ctx, au_headers, extra->dts_delta_length);
+
+   /* RAP and stream state not supported yet */
+
+   return BITS_VALID(p_ctx, au_headers) ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FORMAT_INVALID;
+}
+
+/**************************************************************************//**
+ * MP4 payload handler.
+ * Extracts/skips data from the payload according to the AU headers.
+ *
+ * @param p_ctx      The RTP container context.
+ * @param track      The track being read.
+ * @param p_packet   The container packet information, or NULL.
+ * @param flags      The container read flags.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T mp4_payload_handler(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      VC_CONTAINER_PACKET_T *p_packet,
+      uint32_t flags)
+{
+   VC_CONTAINER_TRACK_MODULE_T *t_module = track->priv->module;
+   VC_CONTAINER_BITS_T *payload = &t_module->payload;
+   MP4_PAYLOAD_T *extra = (MP4_PAYLOAD_T *)t_module->extra;
+   AU_INFO_T *au_info = &extra->au_info;
+   bool is_new_packet = BIT_IS_SET(t_module->flags, TRACK_NEW_PACKET);
+   uint32_t bytes_left_in_payload;
+   uint32_t size;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+
+   if (is_new_packet)
+   {
+      status = mp4_new_rtp_packet(p_ctx, t_module);
+      if (status != VC_CONTAINER_SUCCESS)
+         return status;
+   }
+
+   if (!au_info->available)
+   {
+      status = mp4_next_au_header(p_ctx, extra, is_new_packet);
+      if (status != VC_CONTAINER_SUCCESS)
+         return status;
+   }
+
+   if (p_packet)
+   {
+      /* Adjust the packet time stamps using deltas */
+      p_packet->pts += au_info->cts_delta;
+      p_packet->dts += au_info->dts_delta;
+   }
+
+   size = au_info->available;
+   bytes_left_in_payload = BITS_BYTES_AVAILABLE(p_ctx, payload);
+   if (size > bytes_left_in_payload)
+   {
+      /* AU is fragmented across RTP packets */
+      size = bytes_left_in_payload;
+   }
+
+   if (p_packet && !(flags & VC_CONTAINER_READ_FLAG_SKIP))
+   {
+      if (!(flags & VC_CONTAINER_READ_FLAG_INFO))
+      {
+         if (size > p_packet->buffer_size)
+            size = p_packet->buffer_size;
+
+         BITS_COPY_BYTES(p_ctx, payload, size, p_packet->data, "Packet data");
+      }
+      p_packet->size = size;
+   } else {
+      BITS_SKIP_BYTES(p_ctx, payload, size, "Packet data");
+   }
+
+   if (!(flags & VC_CONTAINER_READ_FLAG_INFO))
+      au_info->available -= size;
+
+   return BITS_VALID(p_ctx, payload) ? VC_CONTAINER_SUCCESS : VC_CONTAINER_ERROR_FORMAT_INVALID;
+}
+
+/*****************************************************************************
+Functions exported as part of the RTP parameter handler API
+ *****************************************************************************/
+
+/**************************************************************************//**
+ * MP4 parameter handler.
+ * Parses the URI parameters to set up the track for an MP4 stream.
+ *
+ * @param p_ctx   The reader context.
+ * @param track   The track to be updated.
+ * @param params  The URI parameter list.
+ * @return  The resulting status of the function.
+ */
+VC_CONTAINER_STATUS_T mp4_parameter_handler(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      const VC_CONTAINERS_LIST_T *params)
+{
+   MP4_PAYLOAD_T *extra;
+   VC_CONTAINER_STATUS_T status;
+
+   /* See RFC3640, section 4.1, for parameter names and details. */
+   extra = (MP4_PAYLOAD_T *)malloc(sizeof(MP4_PAYLOAD_T));
+   if (!extra)
+      return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+   track->priv->module->extra = extra;
+   memset(extra, 0, sizeof(MP4_PAYLOAD_T));
+
+   /* Mandatory parameters */
+   status = mp4_get_stream_type(p_ctx, track, params);
+   if (status != VC_CONTAINER_SUCCESS) return status;
+
+   status = mp4_get_config(p_ctx, track, params);
+   if (status != VC_CONTAINER_SUCCESS) return status;
+
+   status = mp4_get_mode(p_ctx, track, params);
+   if (status != VC_CONTAINER_SUCCESS) return status;
+
+   /* Unsupported parameters */
+   status = mp4_check_unsupported_features(p_ctx, track, params);
+   if (status != VC_CONTAINER_SUCCESS) return status;
+
+   /* Optional parameters */
+   rtp_get_parameter_u32(params, "sizeLength", &extra->size_length);
+   rtp_get_parameter_u32(params, "indexLength", &extra->index_length);
+   rtp_get_parameter_u32(params, "indexDeltaLength", &extra->index_delta_length);
+   rtp_get_parameter_u32(params, "CTSDeltaLength", &extra->cts_delta_length);
+   rtp_get_parameter_u32(params, "DTSDeltaLength", &extra->dts_delta_length);
+   rtp_get_parameter_u32(params, "objectType", &extra->object_type);
+   rtp_get_parameter_u32(params, "constantSize", &extra->constant_size);
+   rtp_get_parameter_u32(params, "constantDuration", &extra->constant_duration);
+   rtp_get_parameter_u32(params, "auxiliaryDataSizeLength", &extra->auxiliary_length);
+
+   if (extra->constant_size && extra->size_length)
+   {
+      LOG_ERROR(p_ctx, "MPEG4: constantSize and sizeLength cannot both be set.");
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+
+   status = mp4_check_parameters(p_ctx, track);
+   if (status != VC_CONTAINER_SUCCESS) return status;
+
+   track->priv->module->payload_handler = mp4_payload_handler;
+
+   return VC_CONTAINER_SUCCESS;
+}
diff --git a/containers/rtp/rtp_mpeg4.h b/containers/rtp/rtp_mpeg4.h
new file mode 100755 (executable)
index 0000000..99181bb
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _RTP_MPEG4_H_
+#define _RTP_MPEG4_H_
+
+#include "containers/containers.h"
+#include "containers/core/containers_list.h"
+
+/** MPEG-4 parameter handler
+ *
+ * \param p_ctx Container context.
+ * \param track Track data.
+ * \param params Parameter list.
+ * \return Status of decoding the MPEG-4 parameters. */
+VC_CONTAINER_STATUS_T mp4_parameter_handler(VC_CONTAINER_T *p_ctx, VC_CONTAINER_TRACK_T *track, const VC_CONTAINERS_LIST_T *params);
+
+#endif /* _RTP_MPEG4_H_ */
diff --git a/containers/rtp/rtp_priv.h b/containers/rtp/rtp_priv.h
new file mode 100755 (executable)
index 0000000..c54bfe8
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _RTP_PRIV_H_
+#define _RTP_PRIV_H_
+
+#include "containers/containers.h"
+
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_bits.h"
+#include "containers/core/containers_list.h"
+
+typedef VC_CONTAINER_STATUS_T (*PAYLOAD_HANDLER_T)(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track, VC_CONTAINER_PACKET_T *p_packet, uint32_t flags);
+
+/** Parameter list entry type. */
+typedef struct parameter_tag
+{
+   const char *name;
+   const char *value;
+} PARAMETER_T;
+
+/** Prototype for MIME parameter handling.
+ * Each MIME type has a certain set of parameter names it uses, so a handler is
+ * needed for each type. This is that handler's prototype.
+ */
+typedef VC_CONTAINER_STATUS_T (*PARAMETER_HANDLER_T)(VC_CONTAINER_T *p_ctx, VC_CONTAINER_TRACK_T *track, const VC_CONTAINERS_LIST_T *params);
+
+/** Track module flag bit numbers (up to seven) */
+typedef enum
+{
+   TRACK_SSRC_SET = 0,
+   TRACK_HAS_MARKER,
+   TRACK_NEW_PACKET,
+} track_module_flag_bit_t;
+
+/** RTP track data */
+typedef struct VC_CONTAINER_TRACK_MODULE_T
+{
+   PAYLOAD_HANDLER_T payload_handler;  /**< Extracts the data from the payload */
+   uint8_t *buffer;              /**< Buffer into which the RTP packet is read */
+   VC_CONTAINER_BITS_T payload;  /**< Payload bit bit_stream */
+   uint8_t flags;                /**< Combination of track module flags */
+   uint8_t payload_type;         /**< The expected payload type */
+   uint16_t max_seq_num;         /**< Highest seq. number seen */
+   uint32_t timestamp;           /**< RTP timestamp of packet */
+   uint32_t timestamp_base;      /**< RTP timestamp value that equates to time zero */
+   uint32_t last_timestamp_top;  /**< Top two bits of RTP timestamp of previous packet */
+   uint32_t timestamp_wraps;     /**< Count of the times that the timestamp has wrapped */
+   uint32_t timestamp_clock;     /**< Clock frequency of RTP timestamp values */
+   uint32_t expected_ssrc;       /**< The expected SSRC, if set */
+   uint32_t base_seq;            /**< Base seq number */
+   uint32_t bad_seq;             /**< Last 'bad' seq number + 1 */
+   uint32_t probation;           /**< Sequential packets till source is valid */
+   uint32_t received;            /**< RTP packets received */
+   void *extra;                  /**< Payload specific data */
+} VC_CONTAINER_TRACK_MODULE_T;
+
+/** Determine minimum number of bytes needed to hold a number of bits */
+#define BITS_TO_BYTES(X)   (((X) + 7) >> 3)
+
+/** Collection of bit manipulation routines */
+/* @{ */
+#define SET_BIT(V, B)         V |= (1 << (B))
+#define CLEAR_BIT(V, B)       V &= ~(1 << (B))
+#define BIT_IS_SET(V, B)      (!(!((V) & (1 << (B)))))
+#define BIT_IS_CLEAR(V, B)    (!((V) & (1 << (B))))
+/* }@ */
+
+
+/** Get a parameter's value as a decimal number.
+ *
+ * \param param_list The list of parameter name/value pairs.
+ * \param name The paramter's name.
+ * \param value Where to put the converted value.
+ * \return True if successful, false if the parameter was not found or didn't convert. */
+bool rtp_get_parameter_u32(const VC_CONTAINERS_LIST_T *param_list, const char *name, uint32_t *value);
+
+/** Get a parameter's value as a hexadecimal number.
+ *
+ * \param param_list The list of parameter name/value pairs.
+ * \param name The paramter's name.
+ * \param value Where to put the converted value.
+ * \return True if successful, false if the parameter was not found or didn't convert. */
+bool rtp_get_parameter_x32(const VC_CONTAINERS_LIST_T *param_list, const char *name, uint32_t *value);
+
+#endif /* _RTP_PRIV_H_ */
diff --git a/containers/rtp/rtp_reader.c b/containers/rtp/rtp_reader.c
new file mode 100755 (executable)
index 0000000..9ce4a59
--- /dev/null
@@ -0,0 +1,1158 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#define CONTAINER_IS_BIG_ENDIAN
+//#define ENABLE_CONTAINERS_LOG_FORMAT
+//#define ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
+#define CONTAINER_HELPER_LOG_INDENT(a) 0
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_uri.h"
+#include "containers/core/containers_logging.h"
+#include "containers/core/containers_bits.h"
+#include "containers/core/containers_list.h"
+
+#include "rtp_priv.h"
+#include "rtp_mpeg4.h"
+#include "rtp_h264.h"
+
+#ifdef _DEBUG
+/* Validates static sorted lists are correctly constructed */
+#define RTP_DEBUG 1
+#endif
+
+/******************************************************************************
+Configurable defines and constants.
+******************************************************************************/
+
+/** Maximum size of an RTP packet */
+#define MAXIMUM_PACKET_SIZE   2048
+
+/** Maximum number of RTP packets that can be missed without restarting. */
+#define MAX_DROPOUT           3000
+/** Maximum number of out of sequence RTP packets that are accepted. */
+#define MAX_MISORDER          0
+/** Minimum number of sequential packets required for an acceptable connection
+ * when restarting. */
+#define MIN_SEQUENTIAL        2
+
+/******************************************************************************
+Defines and constants.
+******************************************************************************/
+
+#define RTP_SCHEME                     "rtp:"
+
+/** The RTP PKT scheme is used with test pkt files */
+#define RTP_PKT_SCHEME                     "rtppkt:"
+
+/** \name RTP URI parameter names
+ * @{ */
+#define PAYLOAD_TYPE_NAME              "rtppt"
+#define MIME_TYPE_NAME                 "mime-type"
+#define CHANNELS_NAME                  "channels"
+#define RATE_NAME                      "rate"
+#define SSRC_NAME                      "ssrc"
+#define SEQ_NAME                       "seq"
+/* @} */
+
+/** A sentinel codec that is not supported */
+#define UNSUPPORTED_CODEC              VC_FOURCC(0,0,0,0)
+
+/** Evaluates to true if the given payload type is in the supported static audio range. */
+#define IS_STATIC_AUDIO_TYPE(PT)       ((PT) < countof(static_audio_payload_types))
+
+/** Payload type number for the first static video type */
+#define FIRST_STATIC_VIDEO_TYPE   24
+/** Evaluates to true if the given payload type is in the supported static video range. */
+#define IS_STATIC_VIDEO_TYPE(PT)       ((PT) >= FIRST_STATIC_VIDEO_TYPE && \
+                                        (PT) < (FIRST_STATIC_VIDEO_TYPE + countof(static_video_payload_types)))
+
+/** Evaluates to true if the given payload type is in the dynamic range. */
+#define IS_DYNAMIC_TYPE(PT)            ((PT) >= 96 && (PT) < 128)
+
+/** All sequence numbers are modulo this value. */
+#define RTP_SEQ_MOD                    (1 << 16)
+
+/** All the static video payload types use a 90kHz timestamp clock */
+#define STATIC_VIDEO_TIMESTAMP_CLOCK   90000
+
+/** Number of microseconds in a second, used to convert RTP timestamps to microseconds */
+#define MICROSECONDS_PER_SECOND        1000000
+
+/******************************************************************************
+Type definitions
+******************************************************************************/
+
+/** \name MIME type parameter handlers
+ * Function prototypes for payload parameter handlers */
+/* @{ */
+static VC_CONTAINER_STATUS_T audio_parameter_handler(VC_CONTAINER_T *p_ctx, VC_CONTAINER_TRACK_T *track, const VC_CONTAINERS_LIST_T *params);
+static VC_CONTAINER_STATUS_T l8_parameter_handler(VC_CONTAINER_T *p_ctx, VC_CONTAINER_TRACK_T *track, const VC_CONTAINERS_LIST_T *params);
+static VC_CONTAINER_STATUS_T l16_parameter_handler(VC_CONTAINER_T *p_ctx, VC_CONTAINER_TRACK_T *track, const VC_CONTAINERS_LIST_T *params);
+/* @} */
+
+/** \name MIME type payload handlers */
+/* @{ */
+static VC_CONTAINER_STATUS_T l16_payload_handler(VC_CONTAINER_T *p_ctx, VC_CONTAINER_TRACK_T *track,
+      VC_CONTAINER_PACKET_T *p_packet, uint32_t flags);
+/* @} */
+
+/** Static audio payload type data */
+typedef struct audio_payload_type_data_tag
+{
+   VC_CONTAINER_FOURCC_T codec;        /**< FourCC codec for this payload type */
+   uint32_t channels;                  /**< Number of audio channels */
+   uint32_t sample_rate;               /**< Sample rate */
+   uint32_t bits_per_sample;           /**< Bits per sample, or 1 if not applicable */
+   PARAMETER_HANDLER_T param_handler;  /**< Optional parameter handler */
+   PAYLOAD_HANDLER_T payload_handler;  /**< Optional payload handler */
+} AUDIO_PAYLOAD_TYPE_DATA_T;
+
+/** The details for the statically defined audio payload types from RFC3551 */
+static AUDIO_PAYLOAD_TYPE_DATA_T static_audio_payload_types[] =
+{
+   { VC_CONTAINER_CODEC_MULAW, 1, 8000,  8,  audio_parameter_handler, NULL },                /*  0 - PCMU */
+   { UNSUPPORTED_CODEC },                                                                    /*  1 - reserved */
+   { UNSUPPORTED_CODEC },                                                                    /*  2 - reserved */
+   { UNSUPPORTED_CODEC,        1, 8000,  1,  NULL,                    NULL },                /*  3 - GSM */
+   { UNSUPPORTED_CODEC,        1, 8000,  1,  NULL,                    NULL },                /*  4 - G723 */
+   { UNSUPPORTED_CODEC,        1, 8000,  4,  NULL,                    NULL },                /*  5 - DVI4 */
+   { UNSUPPORTED_CODEC,        1, 16000, 4,  NULL,                    NULL },                /*  6 - DVI4 */
+   { UNSUPPORTED_CODEC,        1, 8000,  1,  NULL,                    NULL },                /*  7 - LPC */
+   { VC_CONTAINER_CODEC_ALAW,  1, 8000,  8,  audio_parameter_handler, NULL },                /*  8 - PCMA */
+   { UNSUPPORTED_CODEC,        1, 8000,  8,  NULL,                    NULL },                /*  9 - G722 */
+   { VC_CONTAINER_CODEC_PCM_SIGNED,   2, 44100, 16, audio_parameter_handler, l16_payload_handler }, /* 10 - L16 */
+   { VC_CONTAINER_CODEC_PCM_SIGNED,   1, 44100, 16, audio_parameter_handler, l16_payload_handler }, /* 11 - L16 */
+   { VC_CONTAINER_CODEC_QCELP, 1, 8000,  16, NULL,                    NULL },                /* 12 - QCELP */
+   { UNSUPPORTED_CODEC,        1, 8000,  1,  NULL,                    NULL },                /* 13 - CN */
+   { VC_CONTAINER_CODEC_MPGA,  1, 90000, 1,  NULL,                    NULL },                /* 14 - MPA */
+   { UNSUPPORTED_CODEC,        1, 8000,  1,  NULL,                    NULL },                /* 15 - G728 */
+   { UNSUPPORTED_CODEC,        1, 11025, 4,  NULL,                    NULL },                /* 16 - DVI4 */
+   { UNSUPPORTED_CODEC,        1, 22050, 4,  NULL,                    NULL },                /* 17 - DVI4 */
+   { UNSUPPORTED_CODEC,        1, 8000,  1,  NULL,                    NULL },                /* 18 - G729 */
+};
+
+/** Static video payload type data */
+typedef struct video_payload_type_data_tag
+{
+   VC_CONTAINER_FOURCC_T codec;        /**< FourCC codec for this payload type */
+   PARAMETER_HANDLER_T param_handler;  /**< Optional parameter handler */
+   PAYLOAD_HANDLER_T payload_handler;  /**< Optional payload handler */
+} VIDEO_PAYLOAD_TYPE_DATA_T;
+
+/** The details for the statically defined video payload types from RFC3551 */
+static VIDEO_PAYLOAD_TYPE_DATA_T static_video_payload_types[] =
+{
+   { UNSUPPORTED_CODEC },                    /* 24 - unassigned */
+   { UNSUPPORTED_CODEC },                    /* 25 - CelB */
+   { UNSUPPORTED_CODEC },                    /* 26 - JPEG */
+   { UNSUPPORTED_CODEC },                    /* 27 - unassigned */
+   { UNSUPPORTED_CODEC },                    /* 28 - nv */
+   { UNSUPPORTED_CODEC },                    /* 29 - unassigned */
+   { UNSUPPORTED_CODEC },                    /* 30 - unassigned */
+   { UNSUPPORTED_CODEC },                    /* 31 - H261 */
+   { VC_CONTAINER_CODEC_MP2V, NULL, NULL },  /* 32 - MPV */
+   { UNSUPPORTED_CODEC },                    /* 33 - MP2T */
+   { VC_CONTAINER_CODEC_H263, NULL, NULL }   /* 34 - H263 */
+};
+
+/** MIME type details */
+typedef struct mime_type_data_tag
+{
+   const char *name;                   /**< Name of MIME type */
+   VC_CONTAINER_ES_TYPE_T es_type;     /**< Elementary stream type */
+   VC_CONTAINER_FOURCC_T codec;        /**< Codec to be used */
+   PARAMETER_HANDLER_T param_handler;  /**< Parameter handler for this MIME type */
+} MIME_TYPE_DATA_T;
+
+/** Comparator for MIME type details. */
+static int mime_type_data_comparator(const MIME_TYPE_DATA_T *a, const MIME_TYPE_DATA_T *b);
+
+/** Dynamic audio payload details
+ * Note: case-insensitive sort by name */
+static MIME_TYPE_DATA_T dynamic_mime_details[] = {
+   { "audio/l16", VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_PCM_SIGNED, l16_parameter_handler },
+   { "audio/l8", VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_PCM_SIGNED, l8_parameter_handler },
+   { "audio/mpeg4-generic", VC_CONTAINER_ES_TYPE_AUDIO, VC_CONTAINER_CODEC_MP4A, mp4_parameter_handler },
+   { "video/h264", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_H264, h264_parameter_handler },
+   { "video/mpeg4-generic", VC_CONTAINER_ES_TYPE_VIDEO, VC_CONTAINER_CODEC_MP4V, mp4_parameter_handler },
+};
+
+/** Sorted list of dynamic MIME type details */
+VC_CONTAINERS_STATIC_LIST(dynamic_mime, dynamic_mime_details, mime_type_data_comparator);
+
+/** RTP reader data. */
+typedef struct VC_CONTAINER_MODULE_T
+{
+   VC_CONTAINER_TRACK_T *track;
+} VC_CONTAINER_MODULE_T;
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+VC_CONTAINER_STATUS_T rtp_reader_open( VC_CONTAINER_T * );
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+
+/**************************************************************************//**
+ * Parameter comparison function.
+ * Compare two parameter structures and return whether the first is less than,
+ * equal to or greater than the second.
+ *
+ * @param first   The first structure to be compared.
+ * @param second  The second structure to be compared.
+ * @return  Negative if first is less than second, positive if first is greater
+ *          and zero if they are equal.
+ */
+static int parameter_comparator(const PARAMETER_T *first, const PARAMETER_T *second)
+{
+   return strcasecmp(first->name, second->name);
+}
+
+/**************************************************************************//**
+ * Creates and populates a parameter list from a URI structure.
+ * The list does not copy the parameter strings themselves, so the URI structure
+ * must be retained (and its parameters unmodified) while the list is in use.
+ *
+ * @param uri  The URI containing the parameters.
+ * @return  List created from the parameters of the URI, or NULL on error.
+ */
+static VC_CONTAINERS_LIST_T *fill_parameter_list(VC_URI_PARTS_T *uri)
+{
+   uint32_t num_parameters = vc_uri_num_queries(uri);
+   VC_CONTAINERS_LIST_T *parameters;
+   uint32_t ii;
+
+   parameters = vc_containers_list_create(num_parameters, sizeof(PARAMETER_T), (VC_CONTAINERS_LIST_COMPARATOR_T)parameter_comparator);
+   if (!parameters)
+      return NULL;
+
+   for (ii = 0; ii < num_parameters; ii++)
+   {
+      PARAMETER_T param;
+
+      vc_uri_query(uri, ii, &param.name, &param.value);
+      if (!vc_containers_list_insert(parameters, &param, false))
+      {
+         vc_containers_list_destroy(parameters);
+         return NULL;
+      }
+   }
+
+#ifdef RTP_DEBUG
+   vc_containers_list_validate(parameters);
+#endif
+
+   return parameters;
+}
+
+/**************************************************************************//**
+ * Decodes a static audio payload type into track information.
+ * The static parameters may be overridden by URI parameters.
+ *
+ * @param p_ctx         The reader context.
+ * @param track         The track to be populated.
+ * @param param_list    The URI parameter list.
+ * @param payload_type  The static payload type.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T decode_static_audio_type(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      const VC_CONTAINERS_LIST_T *param_list,
+      uint32_t payload_type)
+{
+   VC_CONTAINER_ES_FORMAT_T *format = track->format;
+   AUDIO_PAYLOAD_TYPE_DATA_T *data = &static_audio_payload_types[payload_type];
+
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+   VC_CONTAINER_PARAM_UNUSED(param_list);
+
+   vc_container_assert(payload_type < countof(static_audio_payload_types));
+
+   if (data->codec == UNSUPPORTED_CODEC)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   format->es_type = VC_CONTAINER_ES_TYPE_AUDIO;
+   format->codec = data->codec;
+   format->type->audio.channels = data->channels;
+   format->type->audio.sample_rate = data->sample_rate;
+   format->type->audio.bits_per_sample = data->bits_per_sample;
+   format->type->audio.block_align = data->channels * BITS_TO_BYTES(data->bits_per_sample);
+   track->priv->module->timestamp_clock = format->type->audio.sample_rate;
+   track->priv->module->payload_handler = data->payload_handler;
+
+   if (data->param_handler)
+      data->param_handler(p_ctx, track, param_list);
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/**************************************************************************//**
+ * Decodes a static video payload type into track information.
+ * The static parameters may be overridden by URI parameters.
+ *
+ * @param p_ctx         The reader context.
+ * @param track         The track to be populated.
+ * @param param_list    The URI parameter list.
+ * @param payload_type  The static payload type.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T decode_static_video_type(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      const VC_CONTAINERS_LIST_T *param_list,
+      uint32_t payload_type)
+{
+   VC_CONTAINER_ES_FORMAT_T *format = track->format;
+   VIDEO_PAYLOAD_TYPE_DATA_T *data = &static_video_payload_types[payload_type - FIRST_STATIC_VIDEO_TYPE];
+
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+   VC_CONTAINER_PARAM_UNUSED(param_list);
+
+   vc_container_assert(payload_type >= FIRST_STATIC_VIDEO_TYPE);
+   vc_container_assert(payload_type < FIRST_STATIC_VIDEO_TYPE + countof(static_video_payload_types));
+
+   if (data->codec == UNSUPPORTED_CODEC)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   format->es_type = VC_CONTAINER_ES_TYPE_VIDEO;
+   format->codec = data->codec;
+   track->priv->module->timestamp_clock = STATIC_VIDEO_TIMESTAMP_CLOCK;
+   track->priv->module->payload_handler = data->payload_handler;
+
+   if (data->param_handler)
+      data->param_handler(p_ctx, track, param_list);
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/**************************************************************************//**
+ * Compare two MIME type structures and return whether the first is less than,
+ * equal to or greater than the second.
+ *
+ * @param a The first parameter structure to be compared.
+ * @param b The second parameter structure to be compared.
+ * @return  Negative if a is less than b, positive if a is greater and zero if
+ *          they are equal.
+ */
+static int mime_type_data_comparator(const MIME_TYPE_DATA_T *a, const MIME_TYPE_DATA_T *b)
+{
+   return strcasecmp(a->name, b->name);
+}
+
+/**************************************************************************//**
+ * Generic audio parameter handler.
+ * Updates the track information with generic audio parameters, such as "rate"
+ * and "channels".
+ *
+ * @param p_ctx   The reader context.
+ * @param track   The track to be updated.
+ * @param params  The URI parameter list.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T audio_parameter_handler(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      const VC_CONTAINERS_LIST_T *params)
+{
+   VC_CONTAINER_AUDIO_FORMAT_T *audio = &track->format->type->audio;
+
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+
+   /* See RFC3555. Generic audio parameters that can override static payload
+    * type defaults. */
+   if (rtp_get_parameter_u32(params, RATE_NAME, &audio->sample_rate))
+      track->priv->module->timestamp_clock = audio->sample_rate;
+   if (rtp_get_parameter_u32(params, CHANNELS_NAME, &audio->channels))
+      audio->block_align = audio->channels * BITS_TO_BYTES(audio->bits_per_sample);
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/**************************************************************************//**
+ * L8 specific audio parameter handler.
+ * Updates the track information with audio parameters needed by the audio/L8
+ * MIME type. For example, the "rate" parameter is mandatory.
+ *
+ * @param p_ctx   The reader context.
+ * @param track   The track to be updated.
+ * @param params  The URI parameter list.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T l8_parameter_handler(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      const VC_CONTAINERS_LIST_T *params)
+{
+   VC_CONTAINER_AUDIO_FORMAT_T *audio = &track->format->type->audio;
+
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+
+   /* See RFC3555, section 4.1.14, for parameter names and details. */
+   if (!rtp_get_parameter_u32(params, RATE_NAME, &audio->sample_rate))
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   if (!rtp_get_parameter_u32(params, CHANNELS_NAME, &audio->channels))
+      audio->channels = 1;
+   audio->bits_per_sample = 8;
+   audio->block_align = audio->channels;
+   track->priv->module->timestamp_clock = audio->sample_rate;
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/**************************************************************************//**
+ * L16 specific audio parameter handler.
+ * Updates the track information with audio parameters needed by the audio/L16
+ * MIME type. For example, the "rate" parameter is mandatory.
+ *
+ * @param p_ctx   The reader context.
+ * @param track   The track to be updated.
+ * @param params  The URI parameter list.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T l16_parameter_handler(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      const VC_CONTAINERS_LIST_T *params)
+{
+   VC_CONTAINER_AUDIO_FORMAT_T *audio = &track->format->type->audio;
+
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+
+   /* See RFC3555, section 4.1.15, for parameter names and details. */
+   if (!rtp_get_parameter_u32(params, RATE_NAME, &audio->sample_rate))
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   if (!rtp_get_parameter_u32(params, CHANNELS_NAME, &audio->channels))
+      audio->channels = 1;
+   audio->bits_per_sample = 16;
+   audio->block_align = audio->channels * 2;
+   track->priv->module->timestamp_clock = audio->sample_rate;
+   track->priv->module->payload_handler = l16_payload_handler;
+
+   /* TODO: add support for "channel-order" to set channel mapping */
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/**************************************************************************//**
+ * Decode a dynamic payload type from parameters.
+ * Populates the track information with data for supported dynamic media types.
+ *
+ * @param p_ctx      The reader context.
+ * @param track      The track to be updated.
+ * @param param_list The URI parameter list.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T decode_dynamic_type(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      const VC_CONTAINERS_LIST_T *param_list)
+{
+   VC_CONTAINER_ES_FORMAT_T *format = track->format;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   PARAMETER_T mime_type;
+   MIME_TYPE_DATA_T mime_details;
+
+   /* Get MIME type parameter */
+   mime_type.name = MIME_TYPE_NAME;
+   if (!vc_containers_list_find_entry(param_list, &mime_type))
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+
+#ifdef RTP_DEBUG
+   vc_containers_list_validate(&dynamic_mime);
+#endif
+
+   /* Look up MIME type to see if it can be handled */
+   mime_details.name = mime_type.value;
+   if (!vc_containers_list_find_entry(&dynamic_mime, &mime_details))
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   format->codec = mime_details.codec;
+   format->es_type = mime_details.es_type;
+
+   /* Default number of channels for audio is one */
+   if (mime_details.es_type == VC_CONTAINER_ES_TYPE_AUDIO)
+      format->type->audio.channels = 1;
+
+   /* Lete MIME type specific parameter handler deal with any other parameters */
+   status = mime_details.param_handler(p_ctx, track, param_list);
+
+   /* Ensure that the sample rate has been set for audio formats */
+   if (mime_details.es_type == VC_CONTAINER_ES_TYPE_AUDIO && !format->type->audio.sample_rate)
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+
+   return status;
+}
+
+/**************************************************************************//**
+ * Decode the RTP payload type.
+ * Populates track information with data from static tables and the URI
+ * parameter list, according to the payload and MIME types.
+ *
+ * @param p_ctx   The reader context.
+ * @param track   The track to be updated.
+ * @param params  The URI parameter list.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T  decode_payload_type(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      const VC_CONTAINERS_LIST_T *param_list,
+      uint32_t payload_type)
+{
+   VC_CONTAINER_TRACK_MODULE_T *module = track->priv->module;
+   VC_CONTAINER_STATUS_T status;
+
+   if (IS_STATIC_AUDIO_TYPE(payload_type))
+      status = decode_static_audio_type(p_ctx, track, param_list, payload_type);
+   else if (IS_STATIC_VIDEO_TYPE(payload_type))
+      status = decode_static_video_type(p_ctx, track, param_list, payload_type);
+   else if (IS_DYNAMIC_TYPE(payload_type))
+      status = decode_dynamic_type(p_ctx, track, param_list);
+   else
+      status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   module->payload_type = (uint8_t)payload_type;
+
+   return status;
+}
+
+/**************************************************************************//**
+ * Initialises the RTP sequence number algorithm with a new sequence number.
+ *
+ * @param t_module   The track module.
+ * @param seq        The new sequence number.
+ */
+static void init_sequence_number(VC_CONTAINER_TRACK_MODULE_T *t_module,
+      uint16_t seq)
+{
+   t_module->base_seq = seq;
+   t_module->max_seq_num = seq;
+   t_module->bad_seq = RTP_SEQ_MOD + 1;   /* so seq == bad_seq is false */
+   t_module->received = 0;
+}
+
+/**************************************************************************//**
+ * Checks whether the sequence number for a packet is acceptable or not.
+ * The packet will be unacceptable if it is out of sequence by some degree, or
+ * if the packet sequence is still being established.
+ *
+ * @param t_module   The track module.
+ * @param seq        The new sequence number.
+ * @return  True if the sequence number indicates the packet is acceptable
+ */
+static bool update_sequence_number(VC_CONTAINER_TRACK_MODULE_T *t_module,
+      uint16_t seq)
+{
+   uint16_t udelta = seq - t_module->max_seq_num;
+
+   /* NOTE: This source is derived from the example code in RFC3550, section A.1 */
+
+   /* Source is not valid until MIN_SEQUENTIAL packets with
+    * sequential sequence numbers have been received. */
+   if (t_module->probation)
+   {
+      /* packet is in sequence */
+      if (seq == t_module->max_seq_num + 1)
+      {
+         t_module->probation--;
+         t_module->max_seq_num = seq;
+         LOG_INFO(0, "RTP: Probation, %u more packet(s) to go at 0x%4.4hx", t_module->probation, seq);
+
+         if (!t_module->probation)
+         {
+            init_sequence_number(t_module, seq);
+            t_module->received++;
+            return 1;
+         }
+      } else {
+         t_module->probation = MIN_SEQUENTIAL - 1;
+         t_module->max_seq_num = seq;
+         LOG_INFO(0, "RTP: Probation reset, wait for %u packet(s) at 0x%4.4hx", t_module->probation, seq);
+      }
+      return 0;
+   } else if (udelta < MAX_DROPOUT)
+   {
+      if (!udelta)
+      {
+         /* Duplicate packet, drop it */
+         LOG_INFO(0, "RTP: Drop duplicate packet at 0x%4.4hx", seq);
+         return 0;
+      }
+      if (udelta > 1)
+      {
+         LOG_INFO(0, "RTP: Jumped by %hu packets to 0x%4.4hx", udelta, seq);
+      }
+      /* in order, with permissible gap */
+      t_module->max_seq_num = seq;
+   } else
+#if (MAX_MISORDER != 0)
+      /* When MAX_MISORDER is zero, always treat as out of order */
+      if (udelta <= RTP_SEQ_MOD - MAX_MISORDER)
+#endif
+      {
+         /* the sequence number made a very large jump */
+         if (seq == t_module->bad_seq)
+         {
+            LOG_INFO(0, "RTP: Misorder restart at 0x%4.4hx", seq);
+            /* Two sequential packets -- assume that the other side
+             * restarted without telling us so just re-sync
+             * (i.e., pretend this was the first packet). */
+            init_sequence_number(t_module, seq);
+         } else {
+            LOG_INFO(0, "RTP: Misorder at 0x%4.4hx, expected 0x%4.4hx", seq, t_module->max_seq_num);
+            t_module->bad_seq = (seq + 1) & (RTP_SEQ_MOD-1);
+            return 0;
+         }
+      }
+#if (MAX_MISORDER != 0)
+   else {
+      /* duplicate or reordered packet */
+
+      /* TODO: handle out of order packets */
+   }
+#endif
+   t_module->received++;
+   return 1;
+}
+
+/**************************************************************************//**
+ * Extract the fields of an RTP packet and validate it.
+ *
+ * @param p_ctx      The reader context.
+ * @param t_module   The track module.
+ * @return  True if successful, false if there were not enough bits in the
+ *          packet or the packet was invalid.
+ */
+static void decode_rtp_packet_header(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_MODULE_T *t_module)
+{
+   VC_CONTAINER_BITS_T *payload = &t_module->payload;
+   uint32_t version, has_padding, has_extension, csrc_count, has_marker;
+   uint32_t payload_type, ssrc;
+   uint16_t seq_num;
+
+   /* Break down fixed header area into component parts */
+   version              = BITS_READ_U32(p_ctx, payload, 2, "Version");
+   has_padding          = BITS_READ_U32(p_ctx, payload, 1, "Has padding");
+   has_extension        = BITS_READ_U32(p_ctx, payload, 1, "Has extension");
+   csrc_count           = BITS_READ_U32(p_ctx, payload, 4, "CSRC count");
+   has_marker           = BITS_READ_U32(p_ctx, payload, 1, "Has marker");
+   payload_type         = BITS_READ_U32(p_ctx, payload, 7, "Payload type");
+   seq_num              = BITS_READ_U16(p_ctx, payload, 16, "Sequence number");
+   t_module->timestamp  = BITS_READ_U32(p_ctx, payload, 32, "Timestamp");
+   ssrc                 = BITS_READ_U32(p_ctx, payload, 32, "SSRC");
+
+   /* If there was only a partial header, abort immediately */
+   if (!BITS_VALID(p_ctx, payload))
+      return;
+
+   /* Validate version, payload type, sequence number and SSRC, if set */
+   if (version != 2 || payload_type != t_module->payload_type)
+   {
+      BITS_INVALIDATE(p_ctx, payload);
+      return;
+   }
+   if (BIT_IS_SET(t_module->flags, TRACK_SSRC_SET) && (ssrc != t_module->expected_ssrc))
+   {
+      LOG_DEBUG(p_ctx, "RTP: Unexpected SSRC (0x%8.8X)", ssrc);
+      BITS_INVALIDATE(p_ctx, payload);
+      return;
+   }
+
+   /* Check sequence number indicates packet is usable */
+   if (!update_sequence_number(t_module, seq_num))
+   {
+      BITS_INVALIDATE(p_ctx, payload);
+      return;
+   }
+
+   /* Adjust to account for padding, CSRCs and extension */
+   if (has_padding)
+   {
+      VC_CONTAINER_BITS_T bit_stream;
+      uint32_t available = BITS_BYTES_AVAILABLE(p_ctx, payload);
+      uint8_t padding;
+
+      BITS_COPY_STREAM(p_ctx, &bit_stream, payload);
+      /* The last byte of the payload is the number of padding bytes, including itself */
+      BITS_SKIP_BYTES(p_ctx, &bit_stream, available - 1, "Skip to padding length");
+      padding = BITS_READ_U8(p_ctx, &bit_stream, 8, "Padding length");
+
+      BITS_REDUCE_BYTES(p_ctx, payload, padding, "Remove padding");
+   }
+
+   /* Each CSRC is 32 bits, so shift count up to skip the right number of bits */
+   BITS_SKIP(p_ctx, payload, csrc_count << 5, "CSRC section");
+
+   if (has_extension)
+   {
+      uint32_t extension_bits;
+
+      /* Extension header is 16-bit ID (which isn't needed), then 16-bit length in 32-bit words */
+      BITS_SKIP(p_ctx, payload, 16, "Extension ID");
+      extension_bits = BITS_READ_U32(p_ctx, payload, 16, "Extension length") << 5;
+      BITS_SKIP(p_ctx, payload, extension_bits, "Extension data");
+   }
+
+   /* Record whether or not this RTP packet had the marker bit set */
+   if (has_marker)
+      SET_BIT(t_module->flags, TRACK_HAS_MARKER);
+   else
+      CLEAR_BIT(t_module->flags, TRACK_HAS_MARKER);
+
+   /* If it hasn't been set independently, use the first timestamp as a baseline */
+   if (!t_module->timestamp_base)
+      t_module->timestamp_base = t_module->timestamp;
+   t_module->timestamp -= t_module->timestamp_base;
+}
+
+/**************************************************************************//**
+ * Generic payload handler.
+ * Copies/skips data verbatim from the packet payload.
+ *
+ * @param p_ctx      The reader context.
+ * @param track      The track being read.
+ * @param p_packet   The container packet information, or NULL.
+ * @param flags      The container read flags.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T generic_payload_handler(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      VC_CONTAINER_PACKET_T *p_packet,
+      uint32_t flags)
+{
+   VC_CONTAINER_TRACK_MODULE_T *t_module = track->priv->module;
+   VC_CONTAINER_BITS_T *payload = &t_module->payload;
+   uint32_t size;
+
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+
+   if (!p_packet)
+   {
+      /* Skip the rest of this RTP packet */
+      BITS_INVALIDATE(p_ctx, payload);
+      return VC_CONTAINER_SUCCESS;
+   }
+
+   /* Copy as much as possible into the client packet buffer */
+   size = BITS_BYTES_AVAILABLE(p_ctx, payload);
+
+   if (flags & VC_CONTAINER_READ_FLAG_SKIP)
+      BITS_SKIP_BYTES(p_ctx, payload, size, "Packet data");
+   else {
+      if (!(flags & VC_CONTAINER_READ_FLAG_INFO))
+      {
+         if (size > p_packet->buffer_size)
+            size = p_packet->buffer_size;
+
+         BITS_COPY_BYTES(p_ctx, payload, size, p_packet->data, "Packet data");
+      }
+      p_packet->size = size;
+   }
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/**************************************************************************//**
+ * L16 payload handler.
+ * Copies/skips data from the packet payload. On copy, swaps consecutive bytes
+ * in the data in order to get expected byte order.
+ *
+ * @param p_ctx      The reader context.
+ * @param track      The track being read.
+ * @param p_packet   The container packet information, or NULL.
+ * @param flags      The container read flags.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T l16_payload_handler(VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      VC_CONTAINER_PACKET_T *p_packet,
+      uint32_t flags)
+{
+   VC_CONTAINER_STATUS_T status;
+
+   /* Most aspects are handled adequately by the generic handler */
+   status = generic_payload_handler(p_ctx, track, p_packet, flags);
+   if (status != VC_CONTAINER_SUCCESS)
+      return status;
+
+   if (p_packet && !(flags & (VC_CONTAINER_READ_FLAG_SKIP | VC_CONTAINER_READ_FLAG_INFO)))
+   {
+      uint8_t *ptr, *end_ptr;
+
+      /* Ensure packet size is even */
+      p_packet->size &= ~1;
+
+      /* Swap bytes of each sample, to get host order instead of network order */
+      for (ptr = p_packet->data, end_ptr = ptr + p_packet->size; ptr < end_ptr; ptr += 2)
+      {
+         uint8_t high_byte = ptr[0];
+         ptr[0] = ptr[1];
+         ptr[1] = high_byte;
+      }
+   }
+
+   return status;
+}
+
+
+/*****************************************************************************
+Utility functions for use by RTP payload handlers
+ *****************************************************************************/
+
+/**************************************************************************//**
+ * Gets the value of a parameter as an unsigned 32-bit decimal integer.
+ *
+ * @param param_list The URI parameter list.
+ * @param name       The name of the parameter.
+ * @param value      Pointer to the variable to receive the value.
+ * @return  True if the parameter value was read and stored correctly, false
+ *          otherwise.
+ */
+bool rtp_get_parameter_u32(const VC_CONTAINERS_LIST_T *param_list,
+      const char *name,
+      uint32_t *value)
+{
+   PARAMETER_T param;
+
+   param.name = name;
+   if (vc_containers_list_find_entry(param_list, &param) && param.value)
+   {
+      char *end;
+
+      *value = strtoul(param.value, &end, 10);
+      return (end != param.value) && (*end == '\0');
+   }
+
+   return false;
+}
+
+/**************************************************************************//**
+ * Gets the value of a parameter as an unsigned 32-bit hexadecimal integer.
+ *
+ * @param param_list The URI parameter list.
+ * @param name       The name of the parameter.
+ * @param value      Pointer to the variable to receive the value.
+ * @return  True if the parameter value was read and stored correctly, false
+ *          otherwise.
+ */
+bool rtp_get_parameter_x32(const VC_CONTAINERS_LIST_T *param_list,
+      const char *name,
+      uint32_t *value)
+{
+   PARAMETER_T param;
+
+   param.name = name;
+   if (vc_containers_list_find_entry(param_list, &param) && param.value)
+   {
+      char *end;
+
+      *value = strtoul(param.value, &end, 16);
+      return (end != param.value) && (*end == '\0');
+   }
+
+   return false;
+}
+
+/*****************************************************************************
+Functions exported as part of the Container Module API
+ *****************************************************************************/
+
+/**************************************************************************//**
+ * Read/skip data from the container.
+ * Can also be used to query information about the next block of data.
+ *
+ * @param p_ctx      The reader context.
+ * @param p_packet   The container packet information, or NULL.
+ * @param flags      The container read flags.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtp_reader_read( VC_CONTAINER_T *p_ctx,
+                                               VC_CONTAINER_PACKET_T *p_packet,
+                                               uint32_t flags )
+{
+   VC_CONTAINER_TRACK_T *track;
+   VC_CONTAINER_TRACK_MODULE_T *t_module;
+   VC_CONTAINER_STATUS_T status;
+
+   if((flags & VC_CONTAINER_READ_FLAG_FORCE_TRACK) && p_packet->track)
+      return VC_CONTAINER_ERROR_INVALID_ARGUMENT;
+
+   track = p_ctx->tracks[0];
+   t_module = track->priv->module;
+
+   CLEAR_BIT(t_module->flags, TRACK_NEW_PACKET);
+
+   while (!BITS_AVAILABLE(p_ctx, &t_module->payload))
+   {
+      uint32_t bytes_read;
+
+      /* No data left from last RTP packet, get another one */
+      bytes_read = READ_BYTES(p_ctx, t_module->buffer, MAXIMUM_PACKET_SIZE);
+      if (!bytes_read)
+         return STREAM_STATUS(p_ctx);
+
+      BITS_INIT(p_ctx, &t_module->payload, t_module->buffer, bytes_read);
+
+      decode_rtp_packet_header(p_ctx, t_module);
+      SET_BIT(t_module->flags, TRACK_NEW_PACKET);
+   }
+
+   if (p_packet)
+   {
+      uint32_t timestamp_top = t_module->timestamp >> 30;
+
+      /* Determine whether timestamp has wrapped forwards or backwards around zero */
+      if ((timestamp_top == 0) && (t_module->last_timestamp_top == 3))
+         t_module->timestamp_wraps++;
+      else if ((timestamp_top == 3) && (t_module->last_timestamp_top == 0))
+         t_module->timestamp_wraps--;
+      t_module->last_timestamp_top = timestamp_top;
+
+      p_packet->dts = p_packet->pts = ((int64_t)t_module->timestamp_wraps << 32) | t_module->timestamp;
+      p_packet->track = 0;
+      p_packet->flags = 0;
+   }
+
+   status = t_module->payload_handler(p_ctx, track, p_packet, flags);
+   if (p_packet && status == VC_CONTAINER_SUCCESS)
+   {
+      /* Adjust timestamps from RTP clock rate to microseconds */
+      p_packet->pts = p_packet->pts * MICROSECONDS_PER_SECOND / t_module->timestamp_clock;
+      p_packet->dts = p_packet->dts * MICROSECONDS_PER_SECOND / t_module->timestamp_clock;
+   }
+
+   STREAM_STATUS(p_ctx) = status;
+   return status;
+}
+
+/**************************************************************************//**
+ * Seek over data in the container.
+ *
+ * @param p_ctx      The reader context.
+ * @param p_offset   The seek offset.
+ * @param mode       The seek mode.
+ * @param flags      The seek flags.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtp_reader_seek( VC_CONTAINER_T *p_ctx,
+                                               int64_t *p_offset,
+                                               VC_CONTAINER_SEEK_MODE_T mode,
+                                               VC_CONTAINER_SEEK_FLAGS_T flags)
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+   VC_CONTAINER_PARAM_UNUSED(p_offset);
+   VC_CONTAINER_PARAM_UNUSED(mode);
+   VC_CONTAINER_PARAM_UNUSED(flags);
+
+   /* RTP is a non-seekable container */
+   return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+}
+
+/**************************************************************************//**
+ * Apply a control operation to the container.
+ *
+ * @param p_ctx      The reader context.
+ * @param operation  The control operation.
+ * @param args       Optional additional arguments for the operation.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtp_reader_control( VC_CONTAINER_T *p_ctx,
+                                                VC_CONTAINER_CONTROL_T operation,
+                                                va_list args)
+{
+   VC_CONTAINER_STATUS_T status;
+   VC_CONTAINER_TRACK_MODULE_T *t_module = p_ctx->tracks[0]->priv->module;
+
+   switch (operation)
+   {
+   case VC_CONTAINER_CONTROL_SET_TIMESTAMP_BASE:
+      {
+         t_module->timestamp_base = va_arg(args, uint32_t);
+         if (!t_module->timestamp_base)
+            t_module->timestamp_base = 1;    /* Zero is used to mean "not set" */
+         status = VC_CONTAINER_SUCCESS;
+      }
+      break;
+   case VC_CONTAINER_CONTROL_SET_NEXT_SEQUENCE_NUMBER:
+      {
+         init_sequence_number(t_module, (uint16_t)va_arg(args, uint32_t));
+         t_module->probation = 0;
+         status = VC_CONTAINER_SUCCESS;
+      }
+      break;
+   case VC_CONTAINER_CONTROL_SET_SOURCE_ID:
+      {
+         t_module->expected_ssrc = va_arg(args, uint32_t);
+         SET_BIT(t_module->flags, TRACK_SSRC_SET);
+         status = VC_CONTAINER_SUCCESS;
+      }
+      break;
+   default:
+      status = VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+   }
+
+   return status;
+}
+
+/**************************************************************************//**
+ * Close the container.
+ *
+ * @param p_ctx   The reader context.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtp_reader_close( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+
+   vc_container_assert(p_ctx->tracks_num < 2);
+
+   if (p_ctx->tracks_num)
+   {
+      void *payload_extra;
+
+      vc_container_assert(module);
+      vc_container_assert(module->track);
+      vc_container_assert(module->track->priv);
+      vc_container_assert(module->track->priv->module);
+
+      payload_extra = module->track->priv->module->extra;
+      if (payload_extra)
+         free(payload_extra);
+      vc_container_free_track(p_ctx, module->track);
+   }
+   p_ctx->tracks = NULL;
+   p_ctx->tracks_num = 0;
+   if (module) free(module);
+   p_ctx->priv->module = 0;
+   return VC_CONTAINER_SUCCESS;
+}
+
+/**************************************************************************//**
+ * Open the container.
+ * Uses the I/O URI and/or data to configure the container.
+ *
+ * @param p_ctx   The reader context.
+ * @return  The resulting status of the function.
+ */
+VC_CONTAINER_STATUS_T rtp_reader_open( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = 0;
+   VC_CONTAINER_TRACK_T *track = 0;
+   VC_CONTAINER_TRACK_MODULE_T *t_module = 0;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINERS_LIST_T *parameters = NULL;
+   uint32_t payload_type;
+   uint32_t initial_seq_num;
+
+   /* Check the URI scheme looks valid */
+   if (!vc_uri_scheme(p_ctx->priv->uri) ||
+       (strcasecmp(vc_uri_scheme(p_ctx->priv->uri), RTP_SCHEME) &&
+        strcasecmp(vc_uri_scheme(p_ctx->priv->uri), RTP_PKT_SCHEME)))
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   /* Make the query/parameter list more easily searchable */
+   parameters = fill_parameter_list(p_ctx->priv->uri);
+   if (!parameters) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+
+   /* Payload type parameter is mandatory and must fit in 7 bits */
+   if (!rtp_get_parameter_u32(parameters, PAYLOAD_TYPE_NAME, &payload_type) || payload_type > 127)
+   {
+      status = VC_CONTAINER_ERROR_FORMAT_INVALID;
+      goto error;
+   }
+
+   /* Allocate our context */
+   module = (VC_CONTAINER_MODULE_T *)malloc(sizeof(VC_CONTAINER_MODULE_T));
+   if (!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+
+   memset(module, 0, sizeof(*module));
+   p_ctx->priv->module = module;
+   p_ctx->tracks = &module->track;
+
+   /* Allocate the track, including space for reading an RTP packet on the end */
+   track = vc_container_allocate_track(p_ctx, sizeof(VC_CONTAINER_TRACK_MODULE_T) + MAXIMUM_PACKET_SIZE);
+   if (!track)
+   {
+      status = VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+      goto error;
+   }
+   module->track = track;
+   p_ctx->tracks_num = 1;
+   t_module = track->priv->module;
+
+   /* Initialise the track data */
+   t_module->buffer = (uint8_t *)(t_module + 1);
+   status = decode_payload_type(p_ctx, track, parameters, payload_type);
+   if (status != VC_CONTAINER_SUCCESS)
+      goto error;
+
+   vc_container_assert(t_module->timestamp_clock != 0);
+
+   /* Default to a generic, unstructured payload handler */
+   if (!t_module->payload_handler)
+      t_module->payload_handler = generic_payload_handler;
+
+   if (rtp_get_parameter_x32(parameters, SSRC_NAME, &t_module->expected_ssrc))
+      SET_BIT(t_module->flags, TRACK_SSRC_SET);
+
+   t_module->probation = MIN_SEQUENTIAL;
+   if (rtp_get_parameter_u32(parameters, SEQ_NAME, &initial_seq_num))
+   {
+      /* If an initial sequence number is provided, avoid probation period */
+      t_module->max_seq_num = (uint16_t)initial_seq_num;
+      t_module->probation = 0;
+   }
+
+   track->is_enabled = true;
+
+   vc_containers_list_destroy(parameters);
+
+   p_ctx->priv->pf_close = rtp_reader_close;
+   p_ctx->priv->pf_read = rtp_reader_read;
+   p_ctx->priv->pf_seek = rtp_reader_seek;
+   p_ctx->priv->pf_control = rtp_reader_control;
+
+   return VC_CONTAINER_SUCCESS;
+
+error:
+   if (parameters) vc_containers_list_destroy(parameters);
+   if(status == VC_CONTAINER_SUCCESS || status == VC_CONTAINER_ERROR_EOS)
+      status = VC_CONTAINER_ERROR_FORMAT_INVALID;
+   LOG_DEBUG(p_ctx, "error opening RTP (%i)", status);
+   rtp_reader_close(p_ctx);
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+ ********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak reader_open rtp_reader_open
+#endif
diff --git a/containers/rtsp/CMakeLists.txt b/containers/rtsp/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..5c386f6
--- /dev/null
@@ -0,0 +1,14 @@
+# Container module needs to go in as a plugins so different prefix
+# and install path
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+
+# Make sure the compiler can find the necessary include files
+include_directories (../..)
+
+set(rtsp_SRCS ${rtsp_SRCS} rtsp_reader.c)
+add_library(reader_rtsp ${LIBRARY_TYPE} ${rtsp_SRCS})
+
+target_link_libraries(reader_rtsp containers)
+
+install(TARGETS reader_rtsp DESTINATION ${VMCS_PLUGIN_DIR})
+
diff --git a/containers/rtsp/rtsp_reader.c b/containers/rtsp/rtsp_reader.c
new file mode 100755 (executable)
index 0000000..2d96234
--- /dev/null
@@ -0,0 +1,1983 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#define CONTAINER_IS_BIG_ENDIAN
+//#define ENABLE_CONTAINERS_LOG_FORMAT
+//#define ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
+#define CONTAINER_HELPER_LOG_INDENT(a) 0
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_logging.h"
+#include "containers/core/containers_list.h"
+#include "containers/core/containers_uri.h"
+
+/******************************************************************************
+Configurable defines and constants.
+******************************************************************************/
+
+/** Maximum number of tracks allowed in an RTSP reader */
+#define RTSP_TRACKS_MAX                4
+
+/** Space for sending requests and receiving responses */
+#define COMMS_BUFFER_SIZE              2048
+
+/** Largest allowed RTSP URI. Must be substantially smaller than COMMS_BUFFER_SIZE
+ * to allow for the headers that may be sent. */
+#define RTSP_URI_LENGTH_MAX            1024
+
+/** Maximum allowed length for the Session: header recevied in a SETUP response,
+ * This is to ensure comms buffer is not overflowed. */
+#define SESSION_HEADER_LENGTH_MAX      100
+
+/** Number of milliseconds to block trying to read from the RTSP stream when no
+ * data is available from any of the tracks */
+#define DATA_UNAVAILABLE_READ_TIMEOUT_MS  1
+
+/** Size of buffer for each track to use when receiving packets */
+#define UDP_READ_BUFFER_SIZE           520000
+
+/* Arbitrary number of different dynamic ports to try */
+#define DYNAMIC_PORT_ATTEMPTS_MAX      16
+
+/******************************************************************************
+Defines and constants.
+******************************************************************************/
+
+#define RTSP_SCHEME                    "rtsp:"
+#define RTP_SCHEME                     "rtp"
+
+/** The RTSP PKT scheme is used with test pkt files */
+#define RTSP_PKT_SCHEME                "rtsppkt:"
+
+#define RTSP_NETWORK_URI_START         "rtsp://"
+#define RTSP_NETWORK_URI_START_LENGTH  (sizeof(RTSP_NETWORK_URI_START)-1)
+
+/** Initial capacity of header list */
+#define HEADER_LIST_INITIAL_CAPACITY   16
+
+/** Format of the first line of an RTSP request */
+#define RTSP_REQUEST_LINE_FORMAT       "%s %s RTSP/1.0\r\n"
+
+/** Format string for common headers used with all request methods.
+ * Note: includes double new line to terminate headers */
+#define TRAILING_HEADERS_FORMAT        "CSeq: %u\r\nConnection: Keep-Alive\r\nUser-Agent: Broadcom/1.0\r\n\r\n"
+
+/** Format for the Transport: header */
+#define TRANSPORT_HEADER_FORMAT        "Transport: RTP/AVP;unicast;client_port=%hu-%hu;mode=play\r\n"
+
+/** Format for including Session: header. */
+#define SESSION_HEADER_FORMAT          "Session: %s\r\n"
+
+/** \name RTSP methods, used as the first item in the request line
+ * @{ */
+#define DESCRIBE_METHOD                "DESCRIBE"
+#define SETUP_METHOD                   "SETUP"
+#define PLAY_METHOD                    "PLAY"
+#define TEARDOWN_METHOD                "TEARDOWN"
+/* @} */
+
+/** \name Names of headers used by the code
+ * @{ */
+#define CONTENT_PSEUDOHEADER_NAME      ":"
+#define CONTENT_LENGTH_NAME            "Content-Length"
+#define CONTENT_BASE_NAME              "Content-Base"
+#define CONTENT_LOCATION_NAME          "Content-Location"
+#define RTP_INFO_NAME                  "RTP-Info"
+#define SESSION_NAME                   "Session"
+/* @} */
+
+/** Supported RTSP major version number */
+#define RTSP_MAJOR_VERSION             1
+/** Supported RTSP minor version number */
+#define RTSP_MINOR_VERSION             0
+
+/** Lowest successful status code value */
+#define RTSP_STATUS_OK                 200
+/** Next failure status code after the set of successful ones */
+#define RTSP_STATUS_MULTIPLE_CHOICES   300
+
+/** Maximum size of a decimal string representation of a uint16_t, plus NUL */
+#define PORT_BUFFER_SIZE               6
+/** Start of private / dynamic port region */
+#define FIRST_DYNAMIC_PORT             0xC000
+/** End of private / dynamic port region */
+#define LAST_DYNAMIC_PORT              0xFFF0
+
+/** Format of RTP track file extension */
+#define RTP_PATH_EXTENSION_FORMAT      ".t%u.pkt"
+/** Extra space need for creating an RTP track file name from an RTSP URI path */
+#define RTP_PATH_EXTRA                 17
+
+/** \name RTP URI parameter names
+ * @{ */
+#define PAYLOAD_TYPE_NAME              "rtppt"
+#define MIME_TYPE_NAME                 "mime-type"
+#define SAMPLE_RATE_NAME               "rate"
+#define CHANNELS_NAME                  "channels"
+/* @} */
+
+/** Largest signed 64-bit integer */
+#define MAXIMUM_INT64                  (int64_t)((1ULL << 63) - 1)
+
+/******************************************************************************
+Type definitions
+******************************************************************************/
+
+typedef int (*PARSE_IS_DELIMITER_FN_T)(int char_to_test);
+
+typedef struct rtsp_header_tag
+{
+   const char *name;
+   char *value;
+} RTSP_HEADER_T;
+
+typedef struct VC_CONTAINER_TRACK_MODULE_T
+{
+   VC_CONTAINER_T *reader;          /**< RTP reader for track */
+   VC_URI_PARTS_T *reader_uri;      /**< URI built up from SDP and used to open reader */
+   char *control_uri;               /**< URI used to control track playback */
+   char *session_header;            /**< Session header to be used when sending control requests */
+   char *payload_type;              /**< RTP payload type for track */
+   char *media_type;                /**< MIME type for track */
+   VC_CONTAINER_PACKET_T info;      /**< Latest track packet info block */
+   unsigned short rtp_port;       /**< UDP listener port being used in RTP reader */
+} VC_CONTAINER_TRACK_MODULE_T;
+
+typedef struct VC_CONTAINER_MODULE_T
+{
+   VC_CONTAINER_TRACK_T *tracks[RTSP_TRACKS_MAX];
+   char *comms_buffer;                          /**< Buffer used for sending and receiving RTSP messages */
+   VC_CONTAINERS_LIST_T *header_list;           /**< Parsed response headers, pointing into comms buffer */
+   uint32_t cseq_value;                         /**< CSeq header value for next request */
+   uint16_t next_rtp_port;                      /**< Next RTP port to use when opening track reader */
+   uint16_t media_item;                         /**< Current media item number during initialization */
+   bool uri_has_network_info;                   /**< True if the RTSP URI contains network info */
+   int64_t ts_base;                             /**< Base value for dts and pts */
+   VC_CONTAINER_TRACK_MODULE_T *current_track;  /**< Next track to be read, to keep info/data on same track */
+} VC_CONTAINER_MODULE_T;
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+static int rtsp_header_comparator(const RTSP_HEADER_T *first, const RTSP_HEADER_T *second);
+
+VC_CONTAINER_STATUS_T rtsp_reader_open( VC_CONTAINER_T * );
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+
+/**************************************************************************//**
+ * Trim whitespace from the end and start of the string
+ *
+ * \param   str   String to be trimmed
+ * \return        Trimmed string
+ */
+static char *rtsp_trim( char *str )
+{
+   char *trim = str + strlen(str);
+
+   /* Search backwards for first non-whitespace */
+   while (--trim >= str && isspace((int)*trim))
+      ;     /* Everything done in the while */
+   trim[1] = '\0';
+
+   /* Now move start of string forwards to first non-whitespace */
+   trim = str;
+   while (isspace((int)*trim))
+      trim++;
+
+   return trim;
+}
+
+/**************************************************************************//**
+ * Send out the data in the comms buffer.
+ *
+ * @param p_ctx      The reader context.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_send( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   uint32_t to_write;
+   uint32_t written;
+   const char *buffer = module->comms_buffer;
+
+   /* When reading from a captured file, do not attempt to send data */
+   if (!module->uri_has_network_info)
+      return VC_CONTAINER_SUCCESS;
+
+   to_write = strlen(buffer);
+
+   while (to_write)
+   {
+      written = vc_container_io_write(p_ctx->priv->io, buffer, to_write);
+      if (!written)
+         break;
+      to_write -= written;
+      buffer += written;
+   }
+
+   return p_ctx->priv->io->status;
+}
+
+/**************************************************************************//**
+ * Send a DESCRIBE request to the RTSP server.
+ *
+ * @param p_ctx      The reader context.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_send_describe_request( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   char *ptr = module->comms_buffer, *end = ptr + COMMS_BUFFER_SIZE;
+   char *uri = p_ctx->priv->io->uri;
+
+   if (strlen(uri) > RTSP_URI_LENGTH_MAX)
+   {
+      LOG_ERROR(p_ctx, "RTSP: URI is too long (%d>%d)", strlen(uri), RTSP_URI_LENGTH_MAX);
+      return VC_CONTAINER_ERROR_URI_OPEN_FAILED;
+   }
+
+   ptr += snprintf(ptr, end - ptr, RTSP_REQUEST_LINE_FORMAT, DESCRIBE_METHOD, uri);
+   if (ptr < end)
+      ptr += snprintf(ptr, end - ptr, TRAILING_HEADERS_FORMAT, module->cseq_value++);
+   vc_container_assert(ptr < end);
+
+   return rtsp_send(p_ctx);
+}
+
+/**************************************************************************//**
+ * Send a SETUP request to the RTSP server.
+ *
+ * @param p_ctx      The reader context.
+ * @param t_module   The track module relating to the SETUP.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_send_setup_request( VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_MODULE_T *t_module)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   char *ptr = module->comms_buffer, *end = ptr + COMMS_BUFFER_SIZE;
+   char *uri = t_module->control_uri;
+
+   if (strlen(uri) > RTSP_URI_LENGTH_MAX)
+   {
+      LOG_ERROR(p_ctx, "RTSP: Control URI is too long (%d>%d)", strlen(uri), RTSP_URI_LENGTH_MAX);
+      return VC_CONTAINER_ERROR_URI_OPEN_FAILED;
+   }
+
+   ptr += snprintf(ptr, end - ptr, RTSP_REQUEST_LINE_FORMAT, SETUP_METHOD, uri);
+   if (ptr < end)
+      ptr += snprintf(ptr, end - ptr, TRANSPORT_HEADER_FORMAT, t_module->rtp_port, t_module->rtp_port + 1);
+   if (ptr < end)
+      ptr += snprintf(ptr, end - ptr, TRAILING_HEADERS_FORMAT, module->cseq_value++);
+   vc_container_assert(ptr < end);
+
+   return rtsp_send(p_ctx);
+}
+
+/**************************************************************************//**
+ * Send a PLAY request to the RTSP server.
+ *
+ * @param p_ctx      The reader context.
+ * @param t_module   The track module relating to the PLAY.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_send_play_request( VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_MODULE_T *t_module )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   char *ptr = module->comms_buffer, *end = ptr + COMMS_BUFFER_SIZE;
+   char *uri = t_module->control_uri;
+
+   if (strlen(uri) > RTSP_URI_LENGTH_MAX)
+   {
+      LOG_ERROR(p_ctx, "RTSP: Control URI is too long (%d>%d)", strlen(uri), RTSP_URI_LENGTH_MAX);
+      return VC_CONTAINER_ERROR_URI_OPEN_FAILED;
+   }
+
+   ptr += snprintf(ptr, end - ptr, RTSP_REQUEST_LINE_FORMAT, PLAY_METHOD, uri);
+   if (ptr < end)
+      ptr += snprintf(ptr, end - ptr, SESSION_HEADER_FORMAT, t_module->session_header);
+   if (ptr < end)
+      ptr += snprintf(ptr, end - ptr, TRAILING_HEADERS_FORMAT, module->cseq_value++);
+   vc_container_assert(ptr < end);
+
+   return rtsp_send(p_ctx);
+}
+
+/**************************************************************************//**
+ * Send a TEARDOWN request to the RTSP server.
+ *
+ * @param p_ctx      The reader context.
+ * @param t_module   The track module relating to the SETUP.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_send_teardown_request( VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_MODULE_T *t_module )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   char *ptr = module->comms_buffer, *end = ptr + COMMS_BUFFER_SIZE;
+   char *uri = t_module->control_uri;
+
+   if (strlen(uri) > RTSP_URI_LENGTH_MAX)
+   {
+      LOG_ERROR(p_ctx, "RTSP: Control URI is too long (%d>%d)", strlen(uri), RTSP_URI_LENGTH_MAX);
+      return VC_CONTAINER_ERROR_URI_OPEN_FAILED;
+   }
+
+   ptr += snprintf(ptr, end - ptr, RTSP_REQUEST_LINE_FORMAT, TEARDOWN_METHOD, uri);
+   if (ptr < end)
+      ptr += snprintf(ptr, end - ptr, SESSION_HEADER_FORMAT, t_module->session_header);
+   if (ptr < end)
+      ptr += snprintf(ptr, end - ptr, TRAILING_HEADERS_FORMAT, module->cseq_value++);
+   vc_container_assert(ptr < end);
+
+   return rtsp_send(p_ctx);
+}
+
+/**************************************************************************//**
+ * Check a response status line to see if the response is usable or not.
+ * Reasons for invalidity include:
+ *    - Incorrectly formatted
+ *    - Unsupported version
+ *    - Status code is not in the 2xx range
+ *
+ * @param p_ctx         The reader context.
+ * @param status_line   The response status line.
+ * @return  The resulting status of the function.
+ */
+static bool rtsp_successful_response_status( VC_CONTAINER_T *p_ctx,
+      const char *status_line)
+{
+   unsigned int major_version, minor_version, status_code;
+
+   /* coverity[secure_coding] String is null-terminated */
+   if (sscanf(status_line, "RTSP/%u.%u %u", &major_version, &minor_version, &status_code) != 3)
+   {
+      LOG_ERROR(p_ctx, "RTSP: Invalid response status line:\n%s", status_line);
+      return false;
+   }
+
+   if (major_version != RTSP_MAJOR_VERSION || minor_version != RTSP_MINOR_VERSION)
+   {
+      LOG_ERROR(p_ctx, "RTSP: Unexpected response RTSP version: %u.%u", major_version, minor_version);
+      return false;
+   }
+
+   if (status_code < RTSP_STATUS_OK || status_code >= RTSP_STATUS_MULTIPLE_CHOICES)
+   {
+      LOG_ERROR(p_ctx, "RTSP: Response status unsuccessful:\n%s", status_line);
+      return false;
+   }
+
+   return true;
+}
+
+/**************************************************************************//**
+ * Get the content length header from the response headers as an unsigned
+ * 32-bit integer.
+ * If the content length header is not found or badly formatted, zero is
+ * returned.
+ *
+ * @param header_list   The response headers.
+ * @return  The content length.
+ */
+static uint32_t rtsp_get_content_length( VC_CONTAINERS_LIST_T *header_list )
+{
+   unsigned int content_length = 0;
+   RTSP_HEADER_T header;
+
+   header.name = CONTENT_LENGTH_NAME;
+   if (header_list && vc_containers_list_find_entry(header_list, &header))
+      /* coverity[secure_coding] String is null-terminated */
+      sscanf(header.value, "%u", &content_length);
+
+   return content_length;
+}
+
+/**************************************************************************//**
+ * Get the session header from the response headers.
+ * If the session header is not found, the empty string is returned.
+ *
+ * @param header_list   The response headers.
+ * @return  The session header.
+ */
+static const char *rtsp_get_session_header(VC_CONTAINERS_LIST_T *header_list)
+{
+   RTSP_HEADER_T header;
+
+   header.name = SESSION_NAME;
+   if (header_list && vc_containers_list_find_entry(header_list, &header))
+      return header.value;
+
+   return "";
+}
+
+/**************************************************************************//**
+ * Returns pointer to the string with any leading whitespace trimmed and
+ * terminated by a delimiter, as determined by is_delimiter_fn. The delimiter
+ * character replaced by NUL (to terminate the string) is returned in the
+ * variable pointed at by p_delimiter_replaced, if it is not NULL.
+ *
+ * The parse_str pointer is moved on to the character after the delimiter, or
+ * the end of the string if it is reached first.
+ *
+ * @param parse_str              Pointer to the string pointer to parse.
+ * @param is_delimiter_fn        Function to test if a character is a delimiter or not.
+ * @param p_delimiter_replaced   Pointer to variable to receive delimiter character, or NULL.
+ * @return  Pointer to extracted string.
+ */
+static char *rtsp_parse_extract(char **parse_str,
+      PARSE_IS_DELIMITER_FN_T is_delimiter_fn,
+      char *p_delimiter_replaced)
+{
+   char *ptr;
+   char *result;
+
+   vc_container_assert(parse_str);
+   vc_container_assert(*parse_str);
+   vc_container_assert(is_delimiter_fn);
+
+   ptr = *parse_str;
+
+   while (isspace((int)*ptr))
+      ptr++;
+
+   result = ptr;
+
+   while (*ptr && !(*is_delimiter_fn)(*ptr))
+      ptr++;
+   if (p_delimiter_replaced)
+      *p_delimiter_replaced = *ptr;
+   if (*ptr)
+      *ptr++ = '\0';
+
+   *parse_str = ptr;
+   return result;
+}
+
+/**************************************************************************//**
+ * Specialised form of rtsp_parse_extract() where the delimiter is whitespace.
+ * Returns pointer to the string with any leading whitespace trimmed and
+ * terminated by further whitespace.
+ *
+ * The parse_str pointer is moved on to the character after the delimiter, or
+ * the end of the string if it is reached first.
+ *
+ * @param parse_str  Pointer to the string pointer to parse.
+ * @return  Pointer to extracted string.
+ */
+static char *rtsp_parse_extract_ws(char **parse_str)
+{
+   char *ptr;
+   char *result;
+
+   vc_container_assert(parse_str);
+   vc_container_assert(*parse_str);
+
+   ptr = *parse_str;
+
+   while (isspace((int)*ptr))
+      ptr++;
+
+   result = ptr;
+
+   while (*ptr && !isspace((int)*ptr))
+      ptr++;
+   if (*ptr)
+      *ptr++ = '\0';
+
+   *parse_str = ptr;
+   return result;
+}
+
+/**************************************************************************//**
+ * Returns whether the given character is a parameter name delimiter or not.
+ *
+ * @param char_to_test  The character under test.
+ * @return  True if the character is a name delimiter, false if not.
+ */
+static int name_delimiter_fn(int char_to_test)
+{
+   switch (char_to_test)
+   {
+   case ' ':
+   case '\t':
+   case '=':
+   case ';':
+      return true;
+   default:
+      return false;
+   }
+}
+
+/**************************************************************************//**
+ * Returns whether the given character is a parameter value delimiter or not.
+ *
+ * @param char_to_test  The character under test.
+ * @return  True if the character is a value delimiter, false if not.
+ */
+static int value_delimiter_fn(int char_to_test)
+{
+   switch (char_to_test)
+   {
+   case ' ':
+   case '\t':
+   case ';':
+      return true;
+   default:
+      return false;
+   }
+}
+
+/**************************************************************************//**
+ * Extract a name/value pair from a given string.
+ * Each pair consists of a name, optionally followed by '=' and a value, with
+ * optional whitespace around either or both name and value. The parameter is
+ * terminated by a semi-colon, ';'.
+ *
+ * The parse_str pointer is moved on to the next parameter, or the end of the
+ * string if that is reached first.
+ *
+ * Name can be empty if there are two consecutive semi-colons, or a trailing
+ * semi-colon.
+ *
+ * @param parse_str  Pointer to the string pointer to be parsed.
+ * @param p_name     Pointer to where name string pointer shall be written.
+ * @param p_value    Pointer to where value string pointer shall be written.
+ * @return  True if the name is not empty.
+ */
+static bool rtsp_parse_extract_parameter(char **parse_str, char **p_name, char **p_value)
+{
+   char delimiter;
+
+   vc_container_assert(parse_str);
+   vc_container_assert(*parse_str);
+   vc_container_assert(p_name);
+   vc_container_assert(p_value);
+
+   /* General form of each parameter:
+      *    <name>[=<value>]
+      * but allow for spaces before and after name and value */
+   *p_name = rtsp_parse_extract(parse_str, name_delimiter_fn, &delimiter);
+   if (isspace((int)delimiter))
+   {
+      /* Skip further spaces after parameter name */
+      do {
+         delimiter = **parse_str;
+         if (delimiter)
+            (*parse_str)++;
+      } while (isspace((int)delimiter));
+   }
+
+   if (delimiter == '=')
+   {
+      /* Parameter value present (although may be empty) */
+      *p_value = rtsp_parse_extract(parse_str, value_delimiter_fn, &delimiter);
+      if (isspace((int)delimiter))
+      {
+         /* Skip spaces after parameter value */
+         do {
+            delimiter = **parse_str;
+            if (delimiter)
+               (*parse_str)++;
+         } while (isspace((int)delimiter));
+      }
+   } else {
+      *p_value = NULL;
+   }
+
+   return (**p_name != '\0');
+}
+
+/**************************************************************************//**
+ * Parses RTP-Info header and stores relevant parts.
+ *
+ * @param header_list   The response header list.
+ * @param t_module      The track module relating to the response headers.
+ */
+static void rtsp_store_rtp_info(VC_CONTAINERS_LIST_T *header_list,
+      VC_CONTAINER_TRACK_MODULE_T *t_module )
+{
+   RTSP_HEADER_T header;
+   char *ptr;
+
+   header.name = RTP_INFO_NAME;
+   if (!vc_containers_list_find_entry(header_list, &header))
+      return;
+
+   ptr = header.value;
+   while (ptr && *ptr)
+   {
+      char *name;
+      char *value;
+
+      if (!rtsp_parse_extract_parameter(&ptr, &name, &value))
+         continue;
+
+      if (strcasecmp(name, "rtptime") == 0)
+      {
+         unsigned int timestamp_base = 0;
+
+         /* coverity[secure_coding] String is null-terminated */
+         if (sscanf(value, "%u", &timestamp_base) == 1)
+            (void)vc_container_control(t_module->reader, VC_CONTAINER_CONTROL_SET_TIMESTAMP_BASE, timestamp_base);
+      }
+      else if (strcasecmp(name, "seq") == 0)
+      {
+         unsigned short int sequence_number = 0;
+
+         /* coverity[secure_coding] String is null-terminated */
+         if (sscanf(value, "%hu", &sequence_number) == 1)
+            (void)vc_container_control(t_module->reader, VC_CONTAINER_CONTROL_SET_NEXT_SEQUENCE_NUMBER, (uint32_t)sequence_number);
+      }
+   }
+}
+
+/**************************************************************************//**
+ * Reads an RTSP response and parses it into headers and content.
+ * The headers and content remain stored in the comms buffer, but referenced
+ * by the module's header list. Content uses a special header name that cannot
+ * occur in the real headers.
+ *
+ * @param p_ctx   The RTSP reader context.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_read_response( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_IO_T *p_ctx_io = p_ctx->priv->io;
+   char *next_read = module->comms_buffer;
+   uint32_t space_available = COMMS_BUFFER_SIZE - 1;     /* Allow for a NUL */
+   uint32_t received;
+   char *ptr = next_read;
+   bool found_content = false;
+   RTSP_HEADER_T header;
+
+   vc_containers_list_reset(module->header_list);
+
+   /* Response status line doesn't need to be stored, just checked */
+   header.name = NULL;
+   header.value = next_read;
+
+   while (space_available)
+   {
+      received = vc_container_io_read(p_ctx_io, next_read, space_available);
+      if (p_ctx_io->status != VC_CONTAINER_SUCCESS)
+         break;
+
+      next_read += received;
+      space_available -= received;
+
+      while (!found_content && ptr < next_read)
+      {
+         switch (*ptr)
+         {
+         case ':':
+            if (header.value)
+            {
+               /* Just another character in the value */
+               ptr++;
+            } else {
+               /* End of name, expect value next */
+               *ptr++ = '\0';
+               header.value = ptr;
+            }
+            break;
+
+         case '\n':
+            if (header.value)
+            {
+               /* End of line while parsing the value part of the header, add name/value pair to list */
+               *ptr++ = '\0';
+               header.value = rtsp_trim(header.value);
+               if (header.name)
+               {
+                  if (!vc_containers_list_insert(module->header_list, &header, false))
+                  {
+                     LOG_ERROR(p_ctx, "RTSP: Failed to add <%s> header to list", header.name);
+                     return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+                  }
+               } else {
+                  /* Check response status line */
+                  if (!rtsp_successful_response_status(p_ctx, header.value))
+                     return VC_CONTAINER_ERROR_FORMAT_INVALID;
+               }
+               /* Ready for next header */
+               header.name = ptr;
+               header.value = NULL;
+            } else {
+               uint32_t content_length;
+
+               /* End of line while parsing the name of a header */
+               *ptr++ = '\0';
+               if (*header.name && *header.name != '\r')
+               {
+                  /* A non-empty name is invalid, so fail */
+                  LOG_ERROR(p_ctx, "RTSP: Invalid name in header - no colon:\n%s", header.name);
+                  return VC_CONTAINER_ERROR_FORMAT_INVALID;
+               }
+
+               /* An empty name signifies the start of the content has been found */
+               found_content = true;
+
+               /* Make a pseudo-header for the content and add it to the list */
+               header.name = CONTENT_PSEUDOHEADER_NAME;
+               header.value = ptr;
+               if (!vc_containers_list_insert(module->header_list, &header, false))
+               {
+                  LOG_ERROR(p_ctx, "RTSP: Failed to add content pseudoheader to list");
+                  return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+               }
+
+               /* Calculate how much content there is left to read, based on Content-Length header */
+               content_length = rtsp_get_content_length(module->header_list);
+               if (ptr + content_length < next_read)
+               {
+                  /* Final content byte already present, with extra data after it */
+                  space_available = 0;
+               } else {
+                  uint32_t content_to_read = content_length - (next_read - ptr);
+
+                  if (content_to_read >= space_available)
+                  {
+                     LOG_ERROR(p_ctx, "RTSP: Not enough room to read content");
+                     return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+                  }
+
+                  /* Restrict further reading to the number of content bytes left */
+                  space_available = content_to_read;
+               }
+            }
+            break;
+
+         default:
+            /* Just another character in either the name or the value */
+            ptr++;
+         }
+      }
+   }
+
+   if (!space_available)
+   {
+      if (found_content)
+      {
+         /* Terminate content region */
+         *next_read = '\0';
+      } else {
+         /* Ran out of buffer space and never found the content */
+         LOG_ERROR(p_ctx, "RTSP: Response header section too big / content missing");
+         return VC_CONTAINER_ERROR_FORMAT_INVALID;
+      }
+   }
+
+   return p_ctx_io->status;
+}
+
+/**************************************************************************//**
+ * Creates a new track from an SDP media field.
+ * Limitation: only the first payload type of the field is used.
+ *
+ * @param p_ctx   The RTSP reader context.
+ * @param media   The media field.
+ * @param p_track Pointer to the variable to receive the new track pointer.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_create_track_for_media_field(VC_CONTAINER_T *p_ctx,
+      char *media,
+      VC_CONTAINER_TRACK_T **p_track )
+{
+   VC_CONTAINER_TRACK_T *track = NULL;
+   VC_CONTAINER_TRACK_MODULE_T *t_module = NULL;
+   char *ptr = media;
+   char *media_type;
+   char *rtp_port;
+   char *transport_type;
+   char *payload_type;
+
+   *p_track = NULL;
+   if (p_ctx->tracks_num == RTSP_TRACKS_MAX)
+   {
+      LOG_DEBUG(p_ctx, "RTSP: Too many media items in SDP data, only %d are supported.", RTSP_TRACKS_MAX);
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+
+   /* Format of media item:
+    *    m=<media type> <port> <transport> <payload type(s)>
+    * Only RTP/AVP transport and the first payload type are supported */
+   media_type = rtsp_parse_extract_ws(&ptr);
+   rtp_port = rtsp_parse_extract_ws(&ptr);
+   transport_type = rtsp_parse_extract_ws(&ptr);
+   payload_type = rtsp_parse_extract_ws(&ptr);
+   if (!*media_type || !*rtp_port || strcmp(transport_type, "RTP/AVP") || !*payload_type)
+   {
+      LOG_ERROR(p_ctx, "RTSP: Failure to parse media field");
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+
+   track = vc_container_allocate_track(p_ctx, sizeof(VC_CONTAINER_TRACK_MODULE_T));
+   if (!track) goto out_of_memory_error;
+   t_module = track->priv->module;
+
+   /* If the port specifier is invalid, treat it as if it were zero */
+   /* coverity[secure_coding] String is null-terminated */
+   sscanf(rtp_port, "%hu", &t_module->rtp_port);
+   t_module->payload_type = payload_type;
+   t_module->media_type = media_type;
+
+   t_module->reader_uri = vc_uri_create();
+   if (!t_module->reader_uri) goto out_of_memory_error;
+   if (!vc_uri_set_scheme(t_module->reader_uri, RTP_SCHEME)) goto out_of_memory_error;
+   if (!vc_uri_add_query(t_module->reader_uri, PAYLOAD_TYPE_NAME, payload_type)) goto out_of_memory_error;
+
+   p_ctx->tracks[p_ctx->tracks_num++] = track;
+   *p_track = track;
+   return VC_CONTAINER_SUCCESS;
+
+out_of_memory_error:
+   if (track)
+   {
+      if (t_module->reader_uri)
+         vc_uri_release(t_module->reader_uri);
+      vc_container_free_track(p_ctx, track);
+   }
+   LOG_ERROR(p_ctx, "RTSP: Memory allocation failure creating track");
+   return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+}
+
+/**************************************************************************//**
+ * Returns whether the given character is a slash or not.
+ *
+ * @param char_to_test  The character under test.
+ * @return  True if the character is a slash, false if not.
+ */
+static int slash_delimiter_fn(int char_to_test)
+{
+   return char_to_test == '/';
+}
+
+/**************************************************************************//**
+ * Parse an rtpmap attribute and store values in the related track.
+ *
+ * @param p_ctx      The RTSP reader context.
+ * @param track      The track relating to the rtpmap.
+ * @param attribute  The rtpmap attribute value.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_parse_rtpmap_attribute( VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      char *attribute )
+{
+   VC_CONTAINER_TRACK_MODULE_T *t_module = track->priv->module;
+   char *ptr = attribute;
+   char *payload_type;
+   char *mime_sub_type;
+   char *sample_rate;
+   char *full_mime_type;
+   char *channels;
+
+   /* rtpmap attribute format:
+    *    <payload type> <MIME type>/<sample rate>[/<channels>]
+    * Payload type must match the one used in the media field */
+   payload_type = rtsp_parse_extract_ws(&ptr);
+   if (strcmp(payload_type, t_module->payload_type))
+   {
+      /* Ignore any unsupported secondary payload type attributes */
+      LOG_DEBUG(p_ctx, "RTSP: Secondary payload type attribute - not supported");
+      return VC_CONTAINER_SUCCESS;
+   }
+
+   mime_sub_type = rtsp_parse_extract(&ptr, slash_delimiter_fn, NULL);
+   if (!*mime_sub_type)
+   {
+      LOG_ERROR(p_ctx, "RTSP: rtpmap: MIME type missing");
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+
+   sample_rate = rtsp_parse_extract(&ptr, slash_delimiter_fn, NULL);
+   if (!*sample_rate)
+   {
+      LOG_ERROR(p_ctx, "RTSP: rtpmap: sample rate missing");
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+
+   full_mime_type = (char *)malloc(strlen(t_module->media_type) + strlen(mime_sub_type) + 2);
+   if (!full_mime_type)
+   {
+      LOG_ERROR(p_ctx, "RTSP: Failed to allocate space for full MIME type");
+      return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+   }
+   /* coverity[secure_coding] String has been allocated of the right size */
+   sprintf(full_mime_type, "%s/%s", t_module->media_type, mime_sub_type);
+   if (!vc_uri_add_query(t_module->reader_uri, MIME_TYPE_NAME, full_mime_type))
+   {
+      free(full_mime_type);
+      LOG_ERROR(p_ctx, "RTSP: Failed to add MIME type to URI");
+      return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+   }
+   free(full_mime_type);
+
+   if (!vc_uri_add_query(t_module->reader_uri, SAMPLE_RATE_NAME, sample_rate))
+   {
+      LOG_ERROR(p_ctx, "RTSP: Failed to add sample rate to URI");
+      return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+   }
+
+   /* Optional channels specifier */
+   channels = rtsp_parse_extract_ws(&ptr);
+   if (*channels)
+   {
+      if (!vc_uri_add_query(t_module->reader_uri, CHANNELS_NAME, channels))
+      {
+         LOG_ERROR(p_ctx, "RTSP: Failed to add channels to URI");
+         return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+      }
+   }
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/**************************************************************************//**
+ * Parse an fmtp attribute and store values in the related track.
+ *
+ * @param p_ctx      The RTSP reader context.
+ * @param track      The track relating to the fmtp.
+ * @param attribute  The fmtp attribute value.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_parse_fmtp_attribute( VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track,
+      char *attribute )
+{
+   VC_CONTAINER_TRACK_MODULE_T *t_module = track->priv->module;
+   char *ptr = attribute;
+   char *payload_type;
+
+   /* fmtp attribute format:
+    *    <payload type> <parameters>
+    * The payload type must match the first one in the media field, parameters
+    * are semi-colon separated and may have additional whitespace around them. */
+
+   payload_type = rtsp_parse_extract_ws(&ptr);
+   if (strcmp(payload_type, t_module->payload_type))
+   {
+      /* Ignore any unsupported secondary payload type attributes */
+      LOG_DEBUG(p_ctx, "RTSP: Secondary payload type attribute - not supported");
+      return VC_CONTAINER_SUCCESS;
+   }
+
+   while (*ptr)
+   {
+      char *name;
+      char *value;
+
+      /* Only add the parameter if the name was not empty. This avoids problems with
+       * strings like ";;", ";" or ";=value;" */
+      if (rtsp_parse_extract_parameter(&ptr, &name, &value))
+      {
+         if (!vc_uri_add_query(t_module->reader_uri, name, value))
+         {
+            if (value)
+               LOG_ERROR(p_ctx, "RTSP: Failed to add <%s>=<%s> query to URI", name, value);
+            else
+               LOG_ERROR(p_ctx, "RTSP: Failed to add <%s> query to URI", name);
+            return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+         }
+      }
+   }
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/**************************************************************************//**
+ * Merge base URI and relative URI strings into a merged URI string.
+ * Always creates a new string, even if the relative URI is actually absolute.
+ *
+ * @param p_ctx            The RTSP reader context.
+ * @param base_uri_str     The base URI string.
+ * @param relative_uri_str The relative URI string.
+ * @param p_merged_uri_str Pointer to where to put the merged string pointer.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_merge_uris( VC_CONTAINER_T *p_ctx,
+      const char *base_uri_str,
+      const char *relative_uri_str,
+      char **p_merged_uri_str)
+{
+   VC_URI_PARTS_T *base_uri = NULL;
+   VC_URI_PARTS_T *relative_uri = NULL;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+   uint32_t merged_size;
+
+   *p_merged_uri_str = NULL;
+   relative_uri = vc_uri_create();
+   if (!relative_uri) goto tidy_up;
+   if (!vc_uri_parse(relative_uri, relative_uri_str))
+   {
+      status = VC_CONTAINER_ERROR_FORMAT_INVALID;
+      goto tidy_up;
+   }
+
+   if (vc_uri_scheme(relative_uri) != NULL)
+   {
+      /* URI is absolute, not relative, so return it as the merged URI */
+      size_t len = strlen(relative_uri_str);
+
+      *p_merged_uri_str = (char *)malloc(len + 1);
+      if (!*p_merged_uri_str) goto tidy_up;
+
+      strncpy(*p_merged_uri_str, relative_uri_str, len);
+      status = VC_CONTAINER_SUCCESS;
+      goto tidy_up;
+   }
+
+   base_uri = vc_uri_create();
+   if (!base_uri) goto tidy_up;
+   if (!vc_uri_parse(base_uri, base_uri_str))
+   {
+      status = VC_CONTAINER_ERROR_FORMAT_INVALID;
+      goto tidy_up;
+   }
+
+   /* Build up merged URI in relative_uri, using base_uri as necessary */
+   if (!vc_uri_merge(base_uri, relative_uri)) goto tidy_up;
+
+   merged_size = vc_uri_build(relative_uri, NULL, 0) + 1;
+   *p_merged_uri_str = (char *)malloc(merged_size);
+   if (!*p_merged_uri_str) goto tidy_up;
+
+   vc_uri_build(relative_uri, *p_merged_uri_str, merged_size);
+
+   status = VC_CONTAINER_SUCCESS;
+
+tidy_up:
+   if (base_uri) vc_uri_release(base_uri);
+   if (relative_uri) vc_uri_release(relative_uri);
+   if (status != VC_CONTAINER_SUCCESS)
+      LOG_ERROR(p_ctx, "RTSP: Error merging URIs: %d", (int)status);
+   return status;
+}
+
+/**************************************************************************//**
+ * Parse a control attribute and store it as an absolute URI.
+ *
+ * @param p_ctx               The RTSP reader context.
+ * @param attribute           The control attribute value.
+ * @param base_uri_str        The base URI string.
+ * @param p_control_uri_str   Pointer to where to put the control string pointer.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_parse_control_attribute( VC_CONTAINER_T *p_ctx,
+      const char *attribute,
+      const char *base_uri_str,
+      char **p_control_uri_str)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+
+   /* control attribute format:
+    *    <control URI>
+    * The control URI is either absolute or relative to the base URI. If the
+    * control URI is just an asterisk, the control URI matches the base URI. */
+
+   if (!*attribute || strcmp(attribute, "*") == 0)
+   {
+      size_t len = strlen(base_uri_str);
+
+      *p_control_uri_str = (char *)malloc(len + 1);
+      if (!*p_control_uri_str)
+      {
+         LOG_ERROR(p_ctx, "RTSP: Failed to allocate control URI");
+         return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+      }
+      strncpy(*p_control_uri_str, base_uri_str, len);
+   } else {
+      status = rtsp_merge_uris(p_ctx, base_uri_str, attribute, p_control_uri_str);
+   }
+
+   return status;
+}
+
+/**************************************************************************//**
+ * Open a reader for the track using the URI that has been generated.
+ *
+ * @param p_ctx      The RTSP reader context.
+ * @param t_module   The track module for which a reader is needed.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_open_track_reader( VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_MODULE_T *t_module )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   uint32_t uri_buffer_size;
+   char *uri_buffer;
+
+   uri_buffer_size = vc_uri_build(t_module->reader_uri, NULL, 0) + 1;
+   uri_buffer = (char *)malloc(uri_buffer_size);
+   if (!uri_buffer)
+   {
+      LOG_ERROR(p_ctx, "RTSP: Failed to build RTP URI");
+      return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+   }
+   vc_uri_build(t_module->reader_uri, uri_buffer, uri_buffer_size);
+
+   t_module->reader = vc_container_open_reader(uri_buffer, &status, NULL, NULL);
+   free(uri_buffer);
+
+   return status;
+}
+
+/**************************************************************************//**
+ * Open a reader for the track using the network URI that has been generated.
+ *
+ * @param p_ctx      The RTSP reader context.
+ * @param t_module   The track module for which a reader is needed.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_open_network_reader( VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_MODULE_T *t_module )
+{
+   char port[PORT_BUFFER_SIZE] = {0};
+
+   if (!t_module->rtp_port)
+   {
+      VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+
+      t_module->rtp_port = module->next_rtp_port;
+      if (t_module->rtp_port > LAST_DYNAMIC_PORT)
+      {
+         LOG_ERROR(p_ctx, "RTSP: Out of dynamic ports");
+         return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+      }
+
+      module->next_rtp_port += 2;
+   }
+
+   snprintf(port, sizeof(port)-1, "%hu", t_module->rtp_port);
+   if (!vc_uri_set_port(t_module->reader_uri, port))
+   {
+      LOG_ERROR(p_ctx, "RTSP: Failed to set track reader URI port");
+      return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+   }
+
+   return rtsp_open_track_reader(p_ctx, t_module);
+}
+
+/**************************************************************************//**
+ * Open a reader for the track using the file URI that has been generated.
+ *
+ * @param p_ctx      The RTSP reader context.
+ * @param t_module   The track module for which a reader is needed.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_open_file_reader( VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_MODULE_T *t_module )
+{
+   VC_CONTAINER_STATUS_T status;
+   VC_URI_PARTS_T *rtsp_uri = NULL;
+   const char *rtsp_path;
+   int len;
+   char *new_path = NULL;
+   char *extension;
+
+   /* Use the RTSP URI's path, with the extension changed to ".t<track>.pkt"
+    * where <track> is the zero-based media item number. */
+
+   rtsp_uri = vc_uri_create();
+   if (!rtsp_uri)
+   {
+      LOG_ERROR(p_ctx, "RTSP: Failed to create RTSP URI");
+      status = VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+      goto tidy_up;
+   }
+
+   if (!vc_uri_parse(rtsp_uri, p_ctx->priv->io->uri))
+   {
+      LOG_ERROR(p_ctx, "RTSP: Failed to parse RTSP URI <%s>", p_ctx->priv->io->uri);
+      status = VC_CONTAINER_ERROR_FORMAT_INVALID;
+      goto tidy_up;
+   }
+
+   rtsp_path = vc_uri_path(rtsp_uri);
+   if (!rtsp_path || !*rtsp_path)
+   {
+      LOG_ERROR(p_ctx, "RTSP: RTSP URI path missing <%s>", p_ctx->priv->io->uri);
+      status = VC_CONTAINER_ERROR_FORMAT_INVALID;
+      goto tidy_up;
+   }
+
+   len = strlen(rtsp_path);
+   new_path = (char *)calloc(1, len + RTP_PATH_EXTRA + 1);
+   if (!rtsp_uri)
+   {
+      LOG_ERROR(p_ctx, "RTSP: Failed to create buffer for RTP path");
+      status = VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+      goto tidy_up;
+   }
+
+   strncpy(new_path, rtsp_path, len);
+   extension = strrchr(new_path, '.');          /* Find extension, to replace it */
+   if (!extension)
+      extension = new_path + strlen(new_path);  /* No extension, so append instead */
+
+   snprintf(extension, len + RTP_PATH_EXTRA - (extension - new_path),
+            RTP_PATH_EXTENSION_FORMAT, p_ctx->priv->module->media_item);
+   if (!vc_uri_set_path(t_module->reader_uri, new_path))
+   {
+      LOG_ERROR(p_ctx, "RTSP: Failed to store RTP path <%s>", new_path);
+      status = VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+      goto tidy_up;
+   }
+
+   free(new_path);
+   vc_uri_release(rtsp_uri);
+
+   return rtsp_open_track_reader(p_ctx, t_module);
+
+tidy_up:
+   if (new_path) free(new_path);
+   if (rtsp_uri) vc_uri_release(rtsp_uri);
+   return status;
+}
+
+/**************************************************************************//**
+ * Copy track information from the encapsulated track reader's track to the
+ * RTSP track.
+ *
+ * @param p_ctx   The RTSP reader context.
+ * @param track   The RTSP track requiring its information to be filled in.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_copy_track_data_from_reader( VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track )
+{
+   VC_CONTAINER_T *reader = track->priv->module->reader;
+   VC_CONTAINER_ES_FORMAT_T *src_format, *dst_format;
+
+   if (reader->tracks_num != 1)
+   {
+      LOG_ERROR(p_ctx, "RTSP: Expected track reader to have one track, has %d", reader->tracks_num);
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+
+   if (reader->tracks[0]->meta_num)
+   {
+      LOG_DEBUG(p_ctx, "RTSP: Track reader has meta data - not supported");
+   }
+
+   src_format = reader->tracks[0]->format;
+   dst_format = track->format;
+
+   /* Copy fields individually to avoid problems with pointers (type and extradata). */
+   dst_format->es_type        = src_format->es_type;
+   dst_format->codec          = src_format->codec;
+   dst_format->codec_variant  = src_format->codec_variant;
+   *dst_format->type          = *src_format->type;
+   dst_format->bitrate        = src_format->bitrate;
+   memcpy(dst_format->language, src_format->language, sizeof(dst_format->language));
+   dst_format->group_id       = src_format->group_id;
+   dst_format->flags          = src_format->flags;
+
+   if (src_format->extradata)
+   {
+      VC_CONTAINER_STATUS_T status;
+      uint32_t extradata_size = src_format->extradata_size;
+
+      status = vc_container_track_allocate_extradata(p_ctx, track, extradata_size);
+      if (status != VC_CONTAINER_SUCCESS)
+         return status;
+
+      memcpy(dst_format->extradata, src_format->extradata, extradata_size);
+      dst_format->extradata_size = extradata_size;
+   }
+
+   track->is_enabled = reader->tracks[0]->is_enabled;
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/**************************************************************************//**
+ * Finalise the creation of the RTSP track by opening its reader and filling in
+ * the track information.
+ *
+ * @param p_ctx   The RTSP reader context.
+ * @param track   The RTSP track being finalised.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_complete_track( VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_T *track )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *t_module = track->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+
+   if (!t_module->control_uri)
+   {
+      LOG_ERROR(p_ctx, "RTSP: Track control URI is missing");
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+
+   if (module->uri_has_network_info)
+   {
+      int ii;
+
+      if (!vc_uri_set_host(t_module->reader_uri, ""))
+      {
+         LOG_ERROR(p_ctx, "RTSP: Failed to set track reader URI host");
+         return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+      }
+
+      status = rtsp_open_network_reader(p_ctx, t_module);
+
+      for (ii = 0; status == VC_CONTAINER_ERROR_URI_OPEN_FAILED && ii < DYNAMIC_PORT_ATTEMPTS_MAX; ii++)
+      {
+         /* Reset port to pick up next dynamic port */
+         t_module->rtp_port = 0;
+         status = rtsp_open_network_reader(p_ctx, t_module);
+      }
+
+      /* Change I/O to non-blocking, so that tracks can be polled */
+      if (status == VC_CONTAINER_SUCCESS)
+         status = vc_container_control(t_module->reader, VC_CONTAINER_CONTROL_IO_SET_READ_TIMEOUT_MS, 0);
+      /* Set a large read buffer, to avoid dropping bursts of large packets (e.g. hi-def video) */
+      if (status == VC_CONTAINER_SUCCESS)
+         status = vc_container_control(t_module->reader, VC_CONTAINER_CONTROL_IO_SET_READ_BUFFER_SIZE, UDP_READ_BUFFER_SIZE);
+   } else {
+      status = rtsp_open_file_reader(p_ctx, t_module);
+   }
+
+   vc_uri_release(t_module->reader_uri);
+   t_module->reader_uri = NULL;
+
+   if (status == VC_CONTAINER_SUCCESS)
+      status = rtsp_copy_track_data_from_reader(p_ctx, track);
+
+   return status;
+}
+
+/**************************************************************************//**
+ * Returns whether the given character is an attribute name delimiter or not.
+ *
+ * @param char_to_test  The character under test.
+ * @return  True if the character is an attribute name delimiter, false if not.
+ */
+static int attribute_name_delimiter_fn(int char_to_test)
+{
+   return (char_to_test == ':');
+}
+
+/**************************************************************************//**
+ * Create RTSP tracks from media fields in SDP formatted data.
+ *
+ * @param p_ctx      The RTSP reader context.
+ * @param sdp_buffer The SDP data.
+ * @param base_uri   The RTSP base URI.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_create_tracks_from_sdp( VC_CONTAINER_T *p_ctx,
+      char *sdp_buffer,
+      char *base_uri )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_TRACK_T *track = NULL;
+   char *session_base_uri = base_uri;
+   char *ptr;
+   char *next_line_ptr;
+   char *attribute;
+
+   for (ptr = sdp_buffer; status == VC_CONTAINER_SUCCESS && *ptr; ptr = next_line_ptr)
+   {
+      /* Find end of line */
+      char field = *ptr;
+
+      next_line_ptr = ptr;
+      while (*next_line_ptr && *next_line_ptr != '\n')
+         next_line_ptr++;
+
+      /* Terminate line */
+      if (*next_line_ptr)
+         *next_line_ptr++ = '\0';
+
+      /* The format of the line has to be "<field>=<value>" where <field> is a single
+       * character. Ignore anything else. */
+      if (ptr[1] != '=')
+         continue;
+      ptr = rtsp_trim(ptr + 2);
+
+      switch (field)
+      {
+      case 'm':
+         /* Start of media item */
+         if (track)
+         {
+            /* Finish previous track */
+            status = rtsp_complete_track(p_ctx, track);
+            track = NULL;
+            p_ctx->priv->module->media_item++;
+            if (status != VC_CONTAINER_SUCCESS)
+               break;
+         }
+
+         status = rtsp_create_track_for_media_field(p_ctx, ptr, &track);
+         break;
+      case 'a':   /* Attribute (either session or media level) */
+         /* Attributes of the form "a=<name>:<value>" */
+         attribute = rtsp_parse_extract(&ptr, attribute_name_delimiter_fn, NULL);
+
+         if (track)
+         {
+            /* Media level attribute */
+
+            /* Look for known attributes */
+            if (strcmp(attribute, "rtpmap") == 0)
+               status = rtsp_parse_rtpmap_attribute(p_ctx, track, ptr);
+            else if (strcmp(attribute, "fmtp") == 0)
+               status = rtsp_parse_fmtp_attribute(p_ctx, track, ptr);
+            else if (strcmp(attribute, "control") == 0)
+            {
+               char **track_control_uri = &track->priv->module->control_uri;
+
+               if (*track_control_uri)
+               {
+                  free(*track_control_uri);
+                  *track_control_uri = NULL;
+               }
+               status = rtsp_parse_control_attribute(p_ctx, ptr, session_base_uri, track_control_uri);
+            }
+            /* Any other attributes are ignored */
+         } else {
+            /* Session level attribute */
+            if (strcmp(attribute, "control") == 0)
+            {
+               /* Only need to change the session_base_uri if it differs from the base URI */
+               ptr = rtsp_trim(ptr);
+               if (session_base_uri != base_uri)
+               {
+                  free(session_base_uri);
+                  session_base_uri = base_uri;
+               }
+               if (strcmp(ptr, base_uri) != 0)
+                  status = rtsp_parse_control_attribute(p_ctx, ptr, base_uri, &session_base_uri);
+            }
+         }
+         break;
+      default:    /* Ignore any other field names */
+         ;
+      }
+   }
+
+   if (session_base_uri && session_base_uri != base_uri)
+      free(session_base_uri);
+
+   /* Having no media fields is an error, since there will be nothing to play back */
+   if (status == VC_CONTAINER_SUCCESS)
+   {
+      if (!p_ctx->tracks_num)
+         status = VC_CONTAINER_ERROR_FORMAT_INVALID;
+      else if (track)
+      {
+         /* Finish final track */
+         status = rtsp_complete_track(p_ctx, track);
+         p_ctx->priv->module->media_item++;
+      }
+   }
+
+   return status;
+}
+
+/**************************************************************************//**
+ * Create RTSP tracks from the response to a DESCRIBE request.
+ * The response must have already been filled into the comms buffer and header
+ * list.
+ *
+ * @param p_ctx   The RTSP reader context.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_create_tracks_from_response( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINERS_LIST_T *header_list = p_ctx->priv->module->header_list;
+   RTSP_HEADER_T header;
+   char *base_uri;
+   char *content;
+
+   header.name = CONTENT_PSEUDOHEADER_NAME;
+   if (!vc_containers_list_find_entry(header_list, &header))
+   {
+      LOG_ERROR(p_ctx, "RTSP: Content missing");
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   }
+   content = header.value;
+
+   /* The control URI may be relative to a base URI which is the first of these
+    * that is available:
+    *    1. Content-Base header
+    *    2. Content-Location header
+    *    3. Request URI
+    */
+   header.name = CONTENT_BASE_NAME;
+   if (vc_containers_list_find_entry(header_list, &header))
+      base_uri = header.value;
+   else {
+      header.name = CONTENT_LOCATION_NAME;
+      if (vc_containers_list_find_entry(header_list, &header))
+         base_uri = header.value;
+      else
+         base_uri = p_ctx->priv->io->uri;
+   }
+
+   return rtsp_create_tracks_from_sdp(p_ctx, content, base_uri);
+}
+
+/**************************************************************************//**
+ * Header comparison function.
+ * Compare two header structures and return whether the first is less than,
+ * equal to or greater than the second.
+ *
+ * @param first   The first structure to be compared.
+ * @param second  The second structure to be compared.
+ * @return  Negative if first is less than second, positive if first is greater
+ *          and zero if they are equal.
+ */
+static int rtsp_header_comparator(const RTSP_HEADER_T *first, const RTSP_HEADER_T *second)
+{
+   return strcasecmp(first->name, second->name);
+}
+
+/**************************************************************************//**
+ * Make a DESCRIBE request to the server and create tracks from the response.
+ *
+ * @param p_ctx   The RTSP reader context.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_describe( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+
+   /* Send DESCRIBE request and get response */
+   status = rtsp_send_describe_request(p_ctx);
+   if (status != VC_CONTAINER_SUCCESS) return status;
+   status = rtsp_read_response(p_ctx);
+   if (status != VC_CONTAINER_SUCCESS) return status;
+
+   /* Create tracks from SDP content */
+   status = rtsp_create_tracks_from_response(p_ctx);
+
+   return status;
+}
+
+/**************************************************************************//**
+ * Make a SETUP request to the server and get session from response.
+ *
+ * @param p_ctx      The RTSP reader context.
+ * @param t_module   The track module to be set up.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_setup( VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_MODULE_T *t_module )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   const char *session_header;
+   size_t session_header_len;
+
+   status = rtsp_send_setup_request(p_ctx, t_module);
+   if (status != VC_CONTAINER_SUCCESS) return status;
+   status = rtsp_read_response(p_ctx);
+   if (status != VC_CONTAINER_SUCCESS) return status;
+
+   session_header = rtsp_get_session_header(module->header_list);
+   session_header_len = strlen(session_header);
+   if (session_header_len > SESSION_HEADER_LENGTH_MAX) return VC_CONTAINER_ERROR_FORMAT_INVALID;
+
+   t_module->session_header = (char *)malloc(session_header_len + 1);
+   if (!t_module->session_header) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+   strncpy(t_module->session_header, session_header, session_header_len);
+
+   return status;
+}
+
+/**************************************************************************//**
+ * Make a SETUP request to the server and get session from response.
+ *
+ * @param p_ctx      The RTSP reader context.
+ * @param t_module   The track module to be set up.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_play( VC_CONTAINER_T *p_ctx,
+      VC_CONTAINER_TRACK_MODULE_T *t_module )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+
+   status = rtsp_send_play_request(p_ctx, t_module);
+   if (status != VC_CONTAINER_SUCCESS) return status;
+   status = rtsp_read_response(p_ctx);
+   if (status != VC_CONTAINER_SUCCESS) return status;
+
+   rtsp_store_rtp_info(module->header_list, t_module);
+
+   return status;
+}
+
+/**************************************************************************//**
+ * Blocking read/skip data from a container.
+ * Can also be used to query information about the next block of data.
+ *
+ * @pre The container is set to non-blocking.
+ * @post The container is set to non-blocking.
+ *
+ * @param p_ctx      The reader context.
+ * @param p_packet   The container packet information, or NULL.
+ * @param flags      The container read flags.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_blocking_track_read(VC_CONTAINER_T *p_ctx,
+                                               VC_CONTAINER_PACKET_T *p_packet,
+                                               uint32_t flags)
+{
+   VC_CONTAINER_STATUS_T status;
+
+   status = vc_container_read(p_ctx, p_packet, flags);
+
+   /* The ..._ABORTED status corresponds to a timeout waiting for data */
+   if (status == VC_CONTAINER_ERROR_ABORTED)
+   {
+      /* So switch to blocking temporarily to wait for some */
+      (void)vc_container_control(p_ctx, VC_CONTAINER_CONTROL_IO_SET_READ_TIMEOUT_MS, VC_CONTAINER_READ_TIMEOUT_BLOCK);
+      status = vc_container_read(p_ctx, p_packet, flags);
+      (void)vc_container_control(p_ctx, VC_CONTAINER_CONTROL_IO_SET_READ_TIMEOUT_MS, 0);
+   }
+
+   return status;
+}
+
+/**************************************************************************//**
+ * Update the cached packet info blocks for all tracks.
+ * If one or more of the tracks has data, set the current track to the one with
+ * the earliest decode timestamp.
+ *
+ * @pre The track readers must not block when data is requested from them.
+ *
+ * @param p_ctx   The RTSP reader context.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_update_track_info( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   uint32_t tracks_num = p_ctx->tracks_num;
+   uint32_t track_idx;
+   int64_t earliest_dts = MAXIMUM_INT64;
+   VC_CONTAINER_TRACK_MODULE_T *earliest_track = NULL;
+
+   /* Reset current track to unknown */
+   p_ctx->priv->module->current_track = NULL;
+
+   /* Collect each track's info and return the one with earliest timestamp. */
+   for (track_idx = 0; track_idx < tracks_num; track_idx++)
+   {
+      VC_CONTAINER_TRACK_MODULE_T *t_module = p_ctx->tracks[track_idx]->priv->module;
+      VC_CONTAINER_PACKET_T *info = &t_module->info;
+
+      /* If this track has no data available, request more */
+      if (!info->size)
+      {
+         /* This is a non-blocking read, so status will be ..._ABORTED if nothing available */
+         status = vc_container_read(t_module->reader, info, VC_CONTAINER_READ_FLAG_INFO);
+         /* Adjust track index to be the RTSP index instead of the RTP one */
+         info->track = track_idx;
+      }
+
+      if (status == VC_CONTAINER_SUCCESS)
+      {
+         if (info->dts < earliest_dts)
+         {
+            earliest_dts = info->dts;
+            earliest_track = t_module;
+         }
+      }
+      else if (status != VC_CONTAINER_ERROR_ABORTED)
+      {
+         /* Not a time-out failure, so abort */
+         return status;
+      }
+   }
+
+   p_ctx->priv->module->current_track = earliest_track;
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************
+Functions exported as part of the Container Module API
+ *****************************************************************************/
+
+/**************************************************************************//**
+ * Read/skip data from the container.
+ * Can also be used to query information about the next block of data.
+ *
+ * @param p_ctx      The reader context.
+ * @param p_packet   The container packet information, or NULL.
+ * @param flags      The container read flags.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_reader_read( VC_CONTAINER_T *p_ctx,
+                                               VC_CONTAINER_PACKET_T *p_packet,
+                                               uint32_t flags )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_TRACK_MODULE_T *current_track = module->current_track;
+   VC_CONTAINER_PACKET_T *info;
+
+   if (flags & VC_CONTAINER_READ_FLAG_FORCE_TRACK)
+   {
+      vc_container_assert(p_packet);
+      vc_container_assert(p_packet->track < p_ctx->tracks_num);
+      current_track = p_ctx->tracks[p_packet->track]->priv->module;
+      module->current_track = current_track;
+
+      if (!current_track->info.size)
+      {
+         status = rtsp_blocking_track_read(current_track->reader, &current_track->info, VC_CONTAINER_READ_FLAG_INFO);
+         if (status != VC_CONTAINER_SUCCESS)
+            goto error;
+      }
+   }
+   else if (!current_track || !current_track->info.size)
+   {
+      status = rtsp_update_track_info(p_ctx);
+      if (status != VC_CONTAINER_SUCCESS)
+         goto error;
+
+      while (!module->current_track)
+      {
+         /* Check RTSP stream to see if it has closed */
+         status = rtsp_read_response(p_ctx);
+         if (status == VC_CONTAINER_SUCCESS || status == VC_CONTAINER_ERROR_ABORTED)
+         {
+            /* No data from any track yet, so keep checking */
+            status = rtsp_update_track_info(p_ctx);
+         }
+         if (status != VC_CONTAINER_SUCCESS)
+            goto error;
+      }
+
+      current_track = module->current_track;
+   }
+
+   info = &current_track->info;
+   vc_container_assert(info->size);
+
+   if (flags & VC_CONTAINER_READ_FLAG_INFO)
+   {
+      vc_container_assert(p_packet);
+      memcpy(p_packet, info, sizeof(*info));
+   } else {
+      status = rtsp_blocking_track_read(current_track->reader, p_packet, flags);
+      if (status != VC_CONTAINER_SUCCESS)
+         goto error;
+
+      if (p_packet)
+      {
+         p_packet->track = info->track;
+
+         if (flags & VC_CONTAINER_READ_FLAG_SKIP)
+         {
+            info->size = 0;
+         } else {
+            vc_container_assert(info->size >= p_packet->size);
+            info->size -= p_packet->size;
+         }
+      } else {
+         info->size = 0;
+      }
+   }
+
+   if (p_packet)
+   {
+      /* Adjust timestamps to be relative to zero */
+      if (!module->ts_base)
+         module->ts_base = p_packet->dts;
+      p_packet->dts -= module->ts_base;
+      p_packet->pts -= module->ts_base;
+   }
+
+error:
+   STREAM_STATUS(p_ctx) = status;
+   return status;
+}
+
+/**************************************************************************//**
+ * Seek over data in the container.
+ *
+ * @param p_ctx      The reader context.
+ * @param p_offset   The seek offset.
+ * @param mode       The seek mode.
+ * @param flags      The seek flags.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_reader_seek( VC_CONTAINER_T *p_ctx,
+                                               int64_t *p_offset,
+                                               VC_CONTAINER_SEEK_MODE_T mode,
+                                               VC_CONTAINER_SEEK_FLAGS_T flags)
+{
+   VC_CONTAINER_PARAM_UNUSED(p_ctx);
+   VC_CONTAINER_PARAM_UNUSED(p_offset);
+   VC_CONTAINER_PARAM_UNUSED(mode);
+   VC_CONTAINER_PARAM_UNUSED(flags);
+
+   /* RTSP is a non-seekable container */
+   return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+}
+
+/**************************************************************************//**
+ * Close the container.
+ *
+ * @param p_ctx   The reader context.
+ * @return  The resulting status of the function.
+ */
+static VC_CONTAINER_STATUS_T rtsp_reader_close( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   unsigned int i;
+
+   for(i = 0; i < p_ctx->tracks_num; i++)
+   {
+      VC_CONTAINER_TRACK_MODULE_T *t_module = p_ctx->tracks[i]->priv->module;
+
+      if (t_module->control_uri && t_module->session_header)
+      {
+         /* Send the teardown message and wait for a response, although it
+          * isn't important whether it was successful or not. */
+         if (rtsp_send_teardown_request(p_ctx, t_module) == VC_CONTAINER_SUCCESS)
+            (void)rtsp_read_response(p_ctx);
+      }
+
+      if (t_module->reader)
+         vc_container_close(t_module->reader);
+      if (t_module->reader_uri)
+         vc_uri_release(t_module->reader_uri);
+      if (t_module->control_uri)
+         free(t_module->control_uri);
+      if (t_module->session_header)
+         free(t_module->session_header);
+      vc_container_free_track(p_ctx, p_ctx->tracks[i]);  /* Also need to close track's reader */
+   }
+   p_ctx->tracks = NULL;
+   p_ctx->tracks_num = 0;
+   if (module)
+   {
+      if (module->comms_buffer)
+         free(module->comms_buffer);
+      if (module->header_list)
+         vc_containers_list_destroy(module->header_list);
+      free(module);
+   }
+   p_ctx->priv->module = 0;
+   return VC_CONTAINER_SUCCESS;
+}
+
+/**************************************************************************//**
+ * Open the container.
+ * Uses the I/O URI and/or data to configure the container.
+ *
+ * @param p_ctx   The reader context.
+ * @return  The resulting status of the function.
+ */
+VC_CONTAINER_STATUS_T rtsp_reader_open( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = 0;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   uint32_t ii;
+
+   /* Check the URI scheme looks valid */
+   if (!vc_uri_scheme(p_ctx->priv->uri) ||
+       (strcasecmp(vc_uri_scheme(p_ctx->priv->uri), RTSP_SCHEME) &&
+        strcasecmp(vc_uri_scheme(p_ctx->priv->uri), RTSP_PKT_SCHEME)))
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   /* Allocate our context */
+   if ((module = (VC_CONTAINER_MODULE_T *)malloc(sizeof(VC_CONTAINER_MODULE_T))) == NULL)
+   {
+      status = VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+      goto error;
+   }
+
+   memset(module, 0, sizeof(*module));
+   p_ctx->priv->module = module;
+   p_ctx->tracks = module->tracks;
+   module->next_rtp_port = FIRST_DYNAMIC_PORT;
+   module->cseq_value = 0;
+   module->uri_has_network_info =
+         (strncasecmp(p_ctx->priv->io->uri, RTSP_NETWORK_URI_START, RTSP_NETWORK_URI_START_LENGTH) == 0);
+   module->comms_buffer = (char *)calloc(1, COMMS_BUFFER_SIZE+1);
+   if (!module->comms_buffer) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+
+   /* header_list will contain pointers into the response_buffer, so take care in re-use */
+   module->header_list = vc_containers_list_create(HEADER_LIST_INITIAL_CAPACITY, sizeof(RTSP_HEADER_T),
+         (VC_CONTAINERS_LIST_COMPARATOR_T)rtsp_header_comparator);
+   if (!module->header_list) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+
+   status = rtsp_describe(p_ctx);
+   for (ii = 0; status == VC_CONTAINER_SUCCESS && ii < p_ctx->tracks_num; ii++)
+      status = rtsp_setup(p_ctx, p_ctx->tracks[ii]->priv->module);
+   for (ii = 0; status == VC_CONTAINER_SUCCESS && ii < p_ctx->tracks_num; ii++)
+      status = rtsp_play(p_ctx, p_ctx->tracks[ii]->priv->module);
+   if (status != VC_CONTAINER_SUCCESS)
+      goto error;
+
+   /* Set the RTSP stream to block briefly, to allow polling for closure as well as to avoid spinning CPU */
+   vc_container_control(p_ctx, VC_CONTAINER_CONTROL_IO_SET_READ_TIMEOUT_MS, DATA_UNAVAILABLE_READ_TIMEOUT_MS);
+
+   p_ctx->priv->pf_close = rtsp_reader_close;
+   p_ctx->priv->pf_read = rtsp_reader_read;
+   p_ctx->priv->pf_seek = rtsp_reader_seek;
+
+   if(STREAM_STATUS(p_ctx) != VC_CONTAINER_SUCCESS) goto error;
+   return VC_CONTAINER_SUCCESS;
+
+error:
+   if(status == VC_CONTAINER_SUCCESS || status == VC_CONTAINER_ERROR_EOS)
+      status = VC_CONTAINER_ERROR_FORMAT_INVALID;
+   LOG_DEBUG(p_ctx, "error opening RTSP stream (%i)", status);
+   rtsp_reader_close(p_ctx);
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+ ********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak reader_open rtsp_reader_open
+#endif
diff --git a/containers/rv9/CMakeLists.txt b/containers/rv9/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..f65a7af
--- /dev/null
@@ -0,0 +1,13 @@
+# Container module needs to go in as a plugins so different prefix
+# and install path
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+
+# Make sure the compiler can find the necessary include files
+include_directories (../..)
+
+add_library(reader_rv9 ${LIBRARY_TYPE} rv9_reader.c)
+
+target_link_libraries(reader_rv9 containers)
+
+install(TARGETS reader_rv9 DESTINATION ${VMCS_PLUGIN_DIR})
+
diff --git a/containers/rv9/rv9_reader.c b/containers/rv9/rv9_reader.c
new file mode 100755 (executable)
index 0000000..cb4ca40
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <string.h>
+
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_logging.h"
+
+/******************************************************************************
+Defines.
+******************************************************************************/
+
+#define BI32(b) (((b)[0]<<24)|((b)[1]<<16)|((b)[2]<<8)|((b)[3]))
+#define BI16(b) (((b)[0]<<8)|((b)[1]))
+
+#define FRAME_HEADER_LEN 20
+#define MAX_NUM_SEGMENTS 64
+
+/******************************************************************************
+Type definitions
+******************************************************************************/
+typedef struct {
+   uint32_t len;
+   uint32_t timestamp;
+   uint16_t sequence;
+   uint16_t flags;
+   uint32_t num_segments;
+   uint32_t seg_offset;
+} RV9_FRAME_HEADER_T;
+
+typedef struct VC_CONTAINER_MODULE_T
+{
+   VC_CONTAINER_TRACK_T *track;
+   uint8_t mid_frame;
+   uint32_t frame_read;
+   uint32_t frame_len;
+   RV9_FRAME_HEADER_T hdr;
+   uint8_t data[FRAME_HEADER_LEN + (MAX_NUM_SEGMENTS<<3) + 1];
+   uint32_t data_len;
+   uint8_t type;
+} VC_CONTAINER_MODULE_T;
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+VC_CONTAINER_STATUS_T rv9_reader_open( VC_CONTAINER_T * );
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+
+static VC_CONTAINER_STATUS_T rv9_read_file_header(VC_CONTAINER_T *p_ctx,
+   VC_CONTAINER_TRACK_T *track)
+{
+   VC_CONTAINER_STATUS_T status;
+   VC_CONTAINER_FOURCC_T codec;
+   uint8_t dummy[12];
+   uint32_t length;
+
+   if(PEEK_BYTES(p_ctx, dummy, sizeof(dummy)) != sizeof(dummy)) return VC_CONTAINER_ERROR_EOS;
+
+   length = BI32(dummy);
+   if(length < 12 || length > 1024) return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   if(dummy[4] != 'V' || dummy[5] != 'I' || dummy[6] != 'D' || dummy[7] != 'O' ||
+      dummy[8] != 'R' || dummy[9] != 'V' ||                    dummy[11] != '0')
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   switch(dummy[10]) {
+   case '4': codec = VC_CONTAINER_CODEC_RV40; break;
+   case '3': codec = VC_CONTAINER_CODEC_RV30; break;
+   case '2': codec = VC_CONTAINER_CODEC_RV20; break;
+   case '1': codec = VC_CONTAINER_CODEC_RV10; break;
+   default: return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   }
+
+   if (!track)
+      return VC_CONTAINER_SUCCESS;
+
+   status = vc_container_track_allocate_extradata(p_ctx, track, length);
+   if(status != VC_CONTAINER_SUCCESS) return status;
+
+   if(READ_BYTES(p_ctx, track->format->extradata, length) != length) return VC_CONTAINER_ERROR_EOS;
+   track->format->extradata_size = length;
+
+   track->format->codec = codec;
+   return STREAM_STATUS(p_ctx);
+}
+
+static VC_CONTAINER_STATUS_T rv9_read_frame_header(VC_CONTAINER_T *p_ctx)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   uint32_t seg_offset = (uint32_t) -1;
+   uint8_t *buffer = module->data + FRAME_HEADER_LEN;
+
+   if(READ_BYTES(p_ctx, module->data, FRAME_HEADER_LEN) != FRAME_HEADER_LEN) return VC_CONTAINER_ERROR_EOS;
+   module->data_len = FRAME_HEADER_LEN;
+
+   module->hdr.len = BI32(module->data);
+   module->hdr.timestamp = BI32(module->data+4);
+   module->hdr.sequence = BI16(module->data+8);
+   module->hdr.flags = BI16(module->data+10);
+   module->hdr.num_segments = BI32(module->data+16);
+
+   module->frame_len = FRAME_HEADER_LEN + (module->hdr.num_segments * 8) + module->hdr.len;
+
+   // if we have space, we store up the segments in memory so we can tell the frame
+   // type, since most streams have their type byte as the first follow the segment information.
+   // if we don't have space, then we just don't know the frame type, so will not emit timestamp
+   // information as we don't know if it's reliable.
+   if(module->hdr.num_segments <= MAX_NUM_SEGMENTS)
+   {
+      uint32_t i;
+
+      if(READ_BYTES(p_ctx, buffer, 8*module->hdr.num_segments) != 8*module->hdr.num_segments) return VC_CONTAINER_ERROR_EOS;
+      module->data_len += (module->hdr.num_segments * 8);
+
+      for (i=0; i<module->hdr.num_segments; i++)
+      {
+         uint32_t valid_seg;
+         uint32_t offset;
+         
+         valid_seg = BI32(buffer);
+         offset = BI32(buffer+4);
+         
+         if (valid_seg && seg_offset > offset)
+            seg_offset = offset;
+         
+         // this boolean field should have only 0 or 1 values
+         if(valid_seg > 1) return VC_CONTAINER_ERROR_FORMAT_INVALID;
+         
+         buffer += 8;
+      }
+   }
+
+   if(seg_offset == 0)
+   {
+      if (READ_BYTES(p_ctx, buffer, 1) != 1) return VC_CONTAINER_ERROR_EOS;
+      module->data_len += 1;
+
+      module->type = (*buffer >> 5) & 3;
+   }
+   else
+      module->type = (uint8_t) -1;
+
+   return VC_CONTAINER_SUCCESS;
+}
+
+static uint32_t rv9_get_frame_data(VC_CONTAINER_T *p_ctx, uint32_t len, uint8_t *dest)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   uint32_t ret = 0;
+
+   // we may have read some data before into the data array, so 
+   // check whether we've copied all this data out first.
+   if(module->frame_read < module->data_len)
+   {
+      uint32_t copy = MIN(len, module->data_len - module->frame_read);
+      if(dest)
+      {
+         memcpy(dest, module->data + module->frame_read, copy);
+         dest += copy;
+      }
+      ret += copy;
+      len -= copy;
+   }
+
+   // if there is still more to do, we need to access the IO to do this.
+   if(len > 0)
+   {
+      if(dest)
+         ret += READ_BYTES(p_ctx, dest, len);
+      else
+         ret += SKIP_BYTES(p_ctx, len);
+   } 
+   
+   module->frame_read += ret;
+   return ret;
+}
+
+/*****************************************************************************
+Functions exported as part of the Container Module API
+*****************************************************************************/
+static VC_CONTAINER_STATUS_T rv9_reader_read( VC_CONTAINER_T *p_ctx,
+                                              VC_CONTAINER_PACKET_T *packet,
+                                              uint32_t flags )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_STATUS_T status;
+   unsigned int size;
+
+   if(!module->mid_frame)
+   {
+      if((status = rv9_read_frame_header(p_ctx)) != VC_CONTAINER_SUCCESS) return status;
+      
+      module->mid_frame = 1;
+      module->frame_read = 0;
+   }
+
+   packet->size = module->frame_len;
+   packet->pts = module->type < 3 ? module->hdr.timestamp * 1000LL : VC_CONTAINER_TIME_UNKNOWN;
+   packet->dts = packet->pts;
+   packet->track = 0;
+   packet->flags = module->type < 2 ? VC_CONTAINER_PACKET_FLAG_KEYFRAME : 0;
+   if(module->frame_read == 0)
+      packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
+
+   if(flags & VC_CONTAINER_READ_FLAG_SKIP)
+   {
+      size = rv9_get_frame_data(p_ctx, module->frame_len - module->frame_read, NULL);
+      if(module->frame_read == module->frame_len)
+      {
+         module->frame_read = 0;
+         module->mid_frame = 0;
+      }      
+      return STREAM_STATUS(p_ctx);
+   }
+
+   if(flags & VC_CONTAINER_READ_FLAG_INFO)
+      return VC_CONTAINER_SUCCESS;
+
+   size = MIN(module->frame_len - module->frame_read, packet->buffer_size);
+   size = rv9_get_frame_data(p_ctx, size, packet->data);
+   if(module->frame_read == module->frame_len)
+   {
+      module->frame_read = 0;
+      module->mid_frame = 0;
+      packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
+   }      
+   packet->size = size;
+
+   return size ? VC_CONTAINER_SUCCESS : STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T rv9_reader_seek( VC_CONTAINER_T *p_ctx,
+                                              int64_t *offset,
+                                              VC_CONTAINER_SEEK_MODE_T mode,
+                                              VC_CONTAINER_SEEK_FLAGS_T flags)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   VC_CONTAINER_PARAM_UNUSED(flags);
+
+   if(*offset == 0LL && mode == VC_CONTAINER_SEEK_MODE_TIME)
+   {
+      SEEK(p_ctx, module->track->format->extradata_size);
+      module->mid_frame = 0;
+      module->frame_read = 0;
+      return STREAM_STATUS(p_ctx);
+   }
+   else
+      return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T rv9_reader_close( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   for(; p_ctx->tracks_num > 0; p_ctx->tracks_num--)
+      vc_container_free_track(p_ctx, p_ctx->tracks[p_ctx->tracks_num-1]);
+   free(module);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T rv9_reader_open( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = 0;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   /* Check the file header */
+   if(rv9_read_file_header(p_ctx, 0) != VC_CONTAINER_SUCCESS)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   /* Allocate our context */
+   module = malloc(sizeof(*module));
+   if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(module, 0, sizeof(*module));
+   p_ctx->priv->module = module;
+   p_ctx->tracks_num = 1;
+   p_ctx->tracks = &module->track;
+   p_ctx->tracks[0] = vc_container_allocate_track(p_ctx, 0);
+   if(!p_ctx->tracks[0]) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   p_ctx->tracks[0]->format->es_type = VC_CONTAINER_ES_TYPE_VIDEO;
+   p_ctx->tracks[0]->format->codec = VC_CONTAINER_CODEC_RV40;
+   p_ctx->tracks[0]->is_enabled = true;
+
+   if((status = rv9_read_file_header(p_ctx, p_ctx->tracks[0])) != VC_CONTAINER_SUCCESS) goto error;
+
+   LOG_DEBUG(p_ctx, "using rv9 reader");
+
+   p_ctx->priv->pf_close = rv9_reader_close;
+   p_ctx->priv->pf_read = rv9_reader_read;
+   p_ctx->priv->pf_seek = rv9_reader_seek;
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+   LOG_DEBUG(p_ctx, "rv9: error opening stream (%i)", status);
+   if(module) rv9_reader_close(p_ctx);
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak reader_open rv9_reader_open
+#endif
diff --git a/containers/simple/CMakeLists.txt b/containers/simple/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..0fbdc11
--- /dev/null
@@ -0,0 +1,18 @@
+# Container module needs to go in as a plugins so different prefix
+# and install path
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+
+# Make sure the compiler can find the necessary include files
+include_directories (../..)
+
+add_library(reader_simple ${LIBRARY_TYPE} simple_reader.c)
+
+target_link_libraries(reader_simple containers)
+
+install(TARGETS reader_simple DESTINATION ${VMCS_PLUGIN_DIR})
+
+add_library(writer_simple ${LIBRARY_TYPE} simple_writer.c)
+
+target_link_libraries(writer_simple containers)
+
+install(TARGETS writer_simple DESTINATION ${VMCS_PLUGIN_DIR})
diff --git a/containers/simple/simple_common.h b/containers/simple/simple_common.h
new file mode 100755 (executable)
index 0000000..b75242c
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef SIMPLE_COMMON_H
+#define SIMPLE_COMMON_H
+
+#define SIGNATURE_STRING "S1MPL3"
+#define SIGNATURE_END_STRING "3LPM1S"
+
+/** List of configuration options supported in the header */
+#define CONFIG_VARIANT                  "VARIANT"
+#define CONFIG_URI                      "URI"
+#define CONFIG_CODEC_VARIANT            "CODEC_VARIANT"
+#define CONFIG_BITRATE                  "BITRATE"
+#define CONFIG_UNFRAMED                 "UNFRAMED"
+#define CONFIG_VIDEO_CROP               "VIDEO_CROP"
+#define CONFIG_VIDEO_ASPECT             "VIDEO_ASPECT"
+
+#endif /* SIMPLE_COMMON_H */
diff --git a/containers/simple/simple_reader.c b/containers/simple/simple_reader.c
new file mode 100755 (executable)
index 0000000..f0ef55a
--- /dev/null
@@ -0,0 +1,599 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_logging.h"
+
+#include "simple_common.h"
+
+/******************************************************************************
+Defines.
+******************************************************************************/
+#define MAX_LINE_SIZE 512
+#define LINE_PADDING 3 /* 2 for newline + 1 for null */
+
+#define MAX_TRACKS 4
+#define MAX_HEADER_LINES 512
+
+typedef enum SIMPLE_VARIANT_T
+{
+   VARIANT_DEFAULT = 0,
+   VARIANT_MMAL,
+   VARIANT_OMX
+} SIMPLE_VARIANT_T;
+
+/******************************************************************************
+Type definitions
+******************************************************************************/
+typedef struct SIMPLE_PACKET_STATE_T
+{
+   unsigned int track_num;
+   unsigned int flags;
+
+   uint64_t metadata_offset; /* Offset in metadata stream */
+   uint32_t data_size;       /* Size of current data packet */
+   uint32_t data_left;       /* Data left to read in current packet */
+
+   int64_t pts;
+
+} SIMPLE_PACKET_STATE_T;
+
+typedef struct VC_CONTAINER_TRACK_MODULE_T
+{
+   SIMPLE_PACKET_STATE_T *state;
+   SIMPLE_PACKET_STATE_T local_state;
+
+   VC_CONTAINER_IO_T *io;
+   uint64_t data_offset;     /* Current offset in data stream */
+   char uri[MAX_LINE_SIZE+1];
+
+   SIMPLE_VARIANT_T variant;
+
+} VC_CONTAINER_TRACK_MODULE_T;
+
+typedef struct VC_CONTAINER_MODULE_T
+{
+   VC_CONTAINER_TRACK_T *tracks[MAX_TRACKS];
+
+   char line[MAX_LINE_SIZE + LINE_PADDING];
+
+   int64_t metadata_offset;
+
+   /* Shared packet state. This is used when the tracks are in sync,
+    * and for the track at the earliest position in the file when they are
+    * not in sync */
+   SIMPLE_PACKET_STATE_T state;
+
+} VC_CONTAINER_MODULE_T;
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+VC_CONTAINER_STATUS_T simple_reader_open( VC_CONTAINER_T * );
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+static VC_CONTAINER_STATUS_T simple_read_line( VC_CONTAINER_T *ctx )
+{
+   VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+   unsigned int i, bytes = PEEK_BYTES(ctx, module->line, sizeof(module->line)-1);
+
+   if (!bytes)
+      return VC_CONTAINER_ERROR_EOS;
+
+   /* Find new-line marker */
+   for (i = 0; i < bytes; i++)
+      if (module->line[i] == '\n')
+         break;
+
+   /* Bail out if line is bigger than the maximum allowed */
+   if (i == sizeof(module->line)-1)
+   {
+      LOG_ERROR(ctx, "line too big");
+      return VC_CONTAINER_ERROR_CORRUPTED;
+   }
+
+   if (i < bytes)
+   {
+      module->line[i++] = 0;
+      if (i < bytes && module->line[i] == '\r')
+         i++;
+   }
+   module->line[i] = 0; /* Make sure the line is null terminated */
+
+   SKIP_BYTES(ctx, i);
+   return VC_CONTAINER_SUCCESS;
+}
+
+static VC_CONTAINER_STATUS_T simple_read_header( VC_CONTAINER_T *ctx )
+{
+   VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+   VC_CONTAINER_TRACK_T *track = NULL;
+   VC_CONTAINER_FOURCC_T fourcc;
+   int matches, width, height, channels, samplerate, bps, blockalign, value;
+   unsigned int lines = 1;
+
+   /* Skip the signature */
+   if (simple_read_line(ctx) != VC_CONTAINER_SUCCESS)
+      return VC_CONTAINER_ERROR_CORRUPTED;
+
+   while (lines++ < MAX_HEADER_LINES &&
+          simple_read_line(ctx) == VC_CONTAINER_SUCCESS)
+   {
+      /* Our exit condition is the end signature */
+      if (!memcmp(module->line, SIGNATURE_END_STRING, sizeof(SIGNATURE_STRING)-1))
+      {
+         if (track) ctx->tracks[ctx->tracks_num++] = track;
+         return VC_CONTAINER_SUCCESS;
+      }
+
+      /* Start of track description */
+      if (!memcmp(module->line, "TRACK ", sizeof("TRACK ")-1))
+      {
+         /* Add track we were constructing */
+         if (track) ctx->tracks[ctx->tracks_num++] = track;
+         track = NULL;
+
+         if (ctx->tracks_num >= MAX_TRACKS)
+         {
+            LOG_ERROR(ctx, "too many tracks, ignoring: %s", module->line);
+            continue;
+         }
+         track = vc_container_allocate_track(ctx, sizeof(*track->priv->module));
+         if (!track)
+            return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+
+         track->is_enabled = true;
+         track->format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
+
+         if ((matches = sscanf(module->line,
+                 "TRACK video, %4c, %i, %i",
+                 (char *)&fourcc, &width, &height)) > 0)
+         {
+            track->format->es_type = VC_CONTAINER_ES_TYPE_VIDEO;
+            track->format->codec = fourcc;
+            if (matches > 1) track->format->type->video.width = width;
+            if (matches > 2) track->format->type->video.height = height;
+         }
+         else if ((matches = sscanf(module->line,
+                 "TRACK audio, %4c, %i, %i, %i, %i",
+                 (char *)&fourcc, &channels, &samplerate, &bps,
+                 &blockalign)) > 0)
+         {
+            track->format->es_type = VC_CONTAINER_ES_TYPE_AUDIO;
+            track->format->codec = fourcc;
+            if (matches > 1) track->format->type->audio.channels = channels;
+            if (matches > 2) track->format->type->audio.sample_rate = samplerate;
+            if (matches > 3) track->format->type->audio.bits_per_sample = bps;
+            if (matches > 4) track->format->type->audio.block_align = blockalign;
+         }
+         if ((matches = sscanf(module->line,
+                 "TRACK subpicture, %4c, %i",
+                 (char *)&fourcc, &value)) > 0)
+         {
+            track->format->es_type = VC_CONTAINER_ES_TYPE_SUBPICTURE;
+            track->format->codec = fourcc;
+            if (matches > 1) track->format->type->subpicture.encoding = value;
+         }
+      }
+
+      if (!track)
+         continue; /* Nothing interesting */
+
+      /* VARIANT of the syntax */
+      if (sscanf(module->line, CONFIG_VARIANT" %i", &value) == 1)
+      {
+         track->priv->module->variant = value;
+         LOG_FORMAT(ctx, CONFIG_VARIANT": %i", value);
+      }
+      /* URI for elementary stream */
+      else if (sscanf(module->line, CONFIG_URI" %s", track->priv->module->uri) == 1)
+         LOG_FORMAT(ctx, CONFIG_URI": %s", track->priv->module->uri);
+      /* COCDEC_VARIANT of elementary stream */
+      else if (sscanf(module->line, CONFIG_CODEC_VARIANT" %4c", (char *)&fourcc) == 1)
+      {
+         track->format->codec_variant = fourcc;
+         LOG_FORMAT(ctx, CONFIG_CODEC_VARIANT": %4.4s", (char *)&fourcc);
+      }
+      /* BITRATE of elementary stream */
+      else if (sscanf(module->line, CONFIG_BITRATE" %i", &value) == 1)
+      {
+         track->format->bitrate = value;
+         LOG_FORMAT(ctx, CONFIG_BITRATE": %i", value);
+      }
+      /* UNFRAMED elementary stream */
+      else if (!memcmp(module->line, CONFIG_UNFRAMED, sizeof(CONFIG_UNFRAMED)-1))
+      {
+         track->format->flags &= ~VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
+         LOG_FORMAT(ctx, CONFIG_UNFRAMED);
+      }
+      /* VIDEO_CROP information */
+      else if (track->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO &&
+         sscanf(module->line, CONFIG_VIDEO_CROP" %i, %i", &width, &height) == 2)
+      {
+         track->format->type->video.visible_width = width;
+         track->format->type->video.visible_height = height;
+         LOG_FORMAT(ctx, CONFIG_VIDEO_CROP": %i, %i", width, height);
+      }
+      /* VIDEO_ASPECT information */
+      else if (track->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO &&
+         sscanf(module->line, CONFIG_VIDEO_ASPECT" %i, %i", &width, &height) == 2)
+      {
+         track->format->type->video.par_num = width;
+         track->format->type->video.par_den = height;
+         LOG_FORMAT(ctx, CONFIG_VIDEO_ASPECT": %i, %i", width, height);
+      }
+   }
+
+   if (track) vc_container_free_track(ctx, track);
+   return VC_CONTAINER_ERROR_CORRUPTED;
+}
+
+static uint32_t simple_convert_packet_flags(VC_CONTAINER_T *ctx,
+   unsigned int track_num, uint32_t flags)
+{
+   typedef struct { uint32_t from; uint32_t to; } convert_from_t;
+   const convert_from_t convert_from_mmal[] =
+   { {1<<1, VC_CONTAINER_PACKET_FLAG_FRAME_START},
+     {1<<2, VC_CONTAINER_PACKET_FLAG_FRAME_END},
+     {1<<3, VC_CONTAINER_PACKET_FLAG_KEYFRAME},
+     {1<<4, VC_CONTAINER_PACKET_FLAG_DISCONTINUITY},
+     {1<<5, VC_CONTAINER_PACKET_FLAG_CONFIG},
+     {1<<6, VC_CONTAINER_PACKET_FLAG_ENCRYPTED},
+     {0, 0} };
+   const convert_from_t convert_from_omx[] =
+   { {0x10, VC_CONTAINER_PACKET_FLAG_FRAME_END},
+     {0x20, VC_CONTAINER_PACKET_FLAG_KEYFRAME},
+     {0x80, VC_CONTAINER_PACKET_FLAG_CONFIG},
+     {0, 0} };
+   const convert_from_t *convert_from = NULL;
+   int i;
+
+   switch (ctx->tracks[track_num]->priv->module->variant)
+   {
+      case VARIANT_MMAL: convert_from = convert_from_mmal; break;
+      case VARIANT_OMX: convert_from = convert_from_omx; break;
+      default: break;
+   }
+
+   if (convert_from)
+   {
+      uint32_t new_flags = 0;
+      for (i = 0; convert_from[i].from; i++)
+         if (convert_from[i].from & flags)
+            new_flags |= convert_from[i].to;
+      return new_flags;
+   }
+
+   return flags;
+}
+
+static int64_t simple_convert_packet_pts(VC_CONTAINER_T *ctx,
+   unsigned int track_num, int64_t pts, uint32_t flags)
+{
+   if (ctx->tracks[track_num]->priv->module->variant == VARIANT_OMX &&
+       flags & 0x100)
+      return VC_CONTAINER_TIME_UNKNOWN;
+
+   return pts;
+}
+
+/*****************************************************************************
+Functions exported as part of the Container Module API
+ *****************************************************************************/
+static VC_CONTAINER_STATUS_T simple_reader_read( VC_CONTAINER_T *ctx,
+   VC_CONTAINER_PACKET_T *packet, uint32_t flags )
+{
+   VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+   VC_CONTAINER_TRACK_MODULE_T *track_module;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   SIMPLE_PACKET_STATE_T *state;
+
+   /* If a specific track has been selected, use the track packet state */
+   if (flags & VC_CONTAINER_READ_FLAG_FORCE_TRACK)
+      state = ctx->tracks[packet->track]->priv->module->state;
+   else
+      state = &module->state;
+
+   /* Switch to the next packet when the current one is empty */
+   if (!state->data_left)
+   {
+      unsigned int track_num, size;
+      int64_t pts;
+      int flags;
+
+      SEEK(ctx, state->metadata_offset);
+      status = simple_read_line(ctx);
+      if (status != VC_CONTAINER_SUCCESS)
+         return status;
+
+      if (sscanf(module->line, "%u %u %"PRIi64" %i",
+             &track_num, &size, &pts, &flags) != 4 &&
+           (track_num = 0, sscanf(module->line, "%u %"PRIi64" %i",
+             &size, &pts, &flags)) != 3)
+      {
+         LOG_ERROR(ctx, "invalid metadata: %s", module->line);
+         return VC_CONTAINER_ERROR_CORRUPTED;
+      }
+      state->metadata_offset = STREAM_POSITION(ctx);
+
+      if (track_num >= ctx->tracks_num)
+      {
+         LOG_DEBUG(ctx, "skipping %i bytes for track %d/%d",
+            size, track_num, ctx->tracks_num);
+         return VC_CONTAINER_ERROR_CONTINUE;
+      }
+
+      /* If we are reading from the global state (i.e. normal read or forced
+         read from the track on the global state), and the track we found is
+         not on the global state, reconnect the two */
+      if (state == &module->state &&
+         ctx->tracks[track_num]->priv->module->state != &module->state)
+      {
+         LOG_DEBUG(ctx, "reconnect track %u to the global state", track_num);
+         ctx->tracks[track_num]->priv->module->state = &module->state;
+         module->state = ctx->tracks[track_num]->priv->module->local_state;
+         return VC_CONTAINER_ERROR_CONTINUE;
+      }
+
+      state->data_size = state->data_left = size;
+      state->track_num = track_num;
+      state->flags = simple_convert_packet_flags(ctx, track_num, flags);
+      state->pts = simple_convert_packet_pts(ctx, track_num, pts, flags);
+
+      /* Discard empty packets */
+      if (!state->data_size && !state->flags)
+         return VC_CONTAINER_ERROR_CONTINUE;
+   }
+
+   /* If there is data from another track skip past it */
+   if ((flags & VC_CONTAINER_READ_FLAG_FORCE_TRACK) &&
+       state->track_num != packet->track)
+   {
+      LOG_DEBUG(ctx, "skipping track %d/%d as we are ignoring it",
+         state->track_num, ctx->tracks_num);
+
+      track_module = ctx->tracks[packet->track]->priv->module;
+
+      /* Handle disconnection from global state */
+      if (state == &module->state &&
+         ctx->tracks[state->track_num]->priv->module->state == &module->state)
+      {
+         /* Make a copy of the global state */
+         LOG_DEBUG(ctx, "using local state on track %d", packet->track);
+         track_module->local_state = module->state;
+         track_module->state = &track_module->local_state;
+      }
+
+      track_module->state->data_left = 0;
+      return VC_CONTAINER_ERROR_CONTINUE;
+   }
+
+   /*
+    * From this point we know we have the packet which was requested
+    */
+
+   /* !!!! If we aren't in the right position in the file go there now. */
+
+   track_module = ctx->tracks[state->track_num]->priv->module;
+   packet->track = state->track_num;
+   packet->size = state->data_left;
+   packet->frame_size = (state->flags & VC_CONTAINER_PACKET_FLAG_FRAME) ?
+      state->data_size : 0;
+   packet->flags = state->flags;
+   packet->pts = state->pts;
+   packet->dts = VC_CONTAINER_TIME_UNKNOWN;
+   if (state->data_left != state->data_size)
+      packet->flags &= ~VC_CONTAINER_PACKET_FLAG_FRAME_START;
+
+   if (flags & VC_CONTAINER_READ_FLAG_SKIP)
+   {
+      track_module->data_offset += state->data_left;
+      state->data_left = 0;
+      return VC_CONTAINER_SUCCESS;
+   }
+
+   if (flags & VC_CONTAINER_READ_FLAG_INFO)
+   {
+      return VC_CONTAINER_SUCCESS;
+   }
+
+   /* Now try to read data into buffer */
+   vc_container_io_seek(track_module->io, track_module->data_offset);
+
+   packet->size = vc_container_io_read(track_module->io, packet->data,
+      MIN(packet->buffer_size, state->data_left));
+   state->data_left -= packet->size;
+   track_module->data_offset += packet->size;
+
+   if (state->data_left)
+      packet->flags &= ~VC_CONTAINER_PACKET_FLAG_FRAME_END;
+
+   return track_module->io->status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T simple_reader_seek( VC_CONTAINER_T *ctx, int64_t *offset,
+   VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags)
+{
+   VC_CONTAINER_PARAM_UNUSED(ctx);
+   VC_CONTAINER_PARAM_UNUSED(offset);
+   VC_CONTAINER_PARAM_UNUSED(mode);
+   VC_CONTAINER_PARAM_UNUSED(flags);
+   return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T simple_reader_close( VC_CONTAINER_T *ctx )
+{
+   VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+
+   for (; ctx->tracks_num > 0; ctx->tracks_num--)
+   {
+      VC_CONTAINER_TRACK_T *track = ctx->tracks[ctx->tracks_num-1];
+      if (track->priv->module->io)
+         vc_container_io_close(track->priv->module->io);
+      vc_container_free_track(ctx, track);
+   }
+
+   free(module);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T simple_reader_open( VC_CONTAINER_T *ctx )
+{
+   VC_CONTAINER_MODULE_T *module = 0;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_INVALID;
+   uint8_t h[sizeof(SIGNATURE_STRING)];
+   unsigned int i;
+
+   /* Check for the signature */
+   if (PEEK_BYTES(ctx, h, sizeof(h)) != sizeof(h) ||
+      memcmp(h, SIGNATURE_STRING, sizeof(SIGNATURE_STRING)-1))
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   LOG_DEBUG(ctx, "using simple reader");
+
+   /* Allocate our context */
+   module = malloc(sizeof(*module));
+   if (!module) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+   memset(module, 0, sizeof(*module));
+   ctx->priv->module = module;
+   ctx->tracks = module->tracks;
+
+   status = simple_read_header(ctx);
+   if (status != VC_CONTAINER_SUCCESS)
+      goto error;
+
+   /* Open all the elementary streams */
+   for (i = 0; i < ctx->tracks_num; i++)
+   {
+      VC_CONTAINER_TRACK_T *track = ctx->tracks[i];
+      char *uri;
+
+      track->priv->module->io = vc_container_io_open(track->priv->module->uri,
+         VC_CONTAINER_IO_MODE_READ, &status);
+
+      /* URI might be relative to the path of the metadata file so
+       * try again with that new path */
+      if (!track->priv->module->io &&
+          (uri = malloc(strlen(ctx->priv->io->uri) +
+              strlen(track->priv->module->uri) + 1)) != NULL)
+      {
+         char *end;
+
+         strcpy(uri, ctx->priv->io->uri);
+
+         /* Find the last directory separator */
+         for (end = uri + strlen(ctx->priv->io->uri) + 1; end != uri; end--)
+            if (*(end-1) == '/' || *(end-1) == '\\')
+               break;
+         strcpy(end, track->priv->module->uri);
+
+         track->priv->module->io = vc_container_io_open(uri,
+            VC_CONTAINER_IO_MODE_READ, &status);
+         if (!track->priv->module->io)
+            LOG_ERROR(ctx, "could not open elementary stream: %s", uri);
+         free(uri);
+      }
+      if (!track->priv->module->io)
+      {
+         LOG_ERROR(ctx, "could not open elementary stream: %s",
+            track->priv->module->uri);
+         goto error;
+      }
+   }
+
+   /*
+    *  We now have all the information we really need to start playing the stream
+    */
+
+   module->metadata_offset = STREAM_POSITION(ctx);
+
+   /* Initialise state for all tracks */
+   module->state.metadata_offset = module->metadata_offset;
+   for (i = 0; i < ctx->tracks_num; i++)
+   {
+      VC_CONTAINER_TRACK_T *track = ctx->tracks[i];
+      track->priv->module->state = &module->state;
+   }
+
+   /* Look for the codec configuration data for each track so
+    * we can store it in the track format */
+   for (i = 0; i < ctx->tracks_num; i++)
+   {
+      VC_CONTAINER_TRACK_T *track = ctx->tracks[i];
+      VC_CONTAINER_PACKET_T packet;
+      packet.track = i;
+      status = VC_CONTAINER_ERROR_CONTINUE;
+
+      while (status == VC_CONTAINER_ERROR_CONTINUE)
+         status = simple_reader_read(ctx, &packet,
+            VC_CONTAINER_READ_FLAG_INFO | VC_CONTAINER_READ_FLAG_FORCE_TRACK);
+      if (status != VC_CONTAINER_SUCCESS)
+         continue;
+
+      status = vc_container_track_allocate_extradata(ctx, track, packet.size);
+      if (status != VC_CONTAINER_SUCCESS)
+         continue;
+
+      packet.data = track->format->extradata;
+      packet.buffer_size = packet.size;
+      packet.size = 0;
+      status = simple_reader_read(ctx, &packet,
+         VC_CONTAINER_READ_FLAG_FORCE_TRACK);
+      if (status != VC_CONTAINER_SUCCESS)
+         continue;
+
+      track->format->extradata_size = packet.size;
+   }
+
+   ctx->priv->pf_close = simple_reader_close;
+   ctx->priv->pf_read = simple_reader_read;
+   ctx->priv->pf_seek = simple_reader_seek;
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+   LOG_ERROR(ctx, "simple: error opening stream (%i)", status);
+   simple_reader_close(ctx);
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+ ********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak reader_open simple_reader_open
+#endif
diff --git a/containers/simple/simple_writer.c b/containers/simple/simple_writer.c
new file mode 100755 (executable)
index 0000000..e0cf0f5
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_logging.h"
+
+#include "simple_common.h"
+
+/******************************************************************************
+Defines.
+******************************************************************************/
+#define MAX_TRACKS 4
+#define MAX_LINE_SIZE 512
+
+#define ES_SUFFIX "%s.%2.2i.%4.4s"
+#define ES_SUFFIX_SIZE 8
+
+/******************************************************************************
+Type definitions
+******************************************************************************/
+typedef struct VC_CONTAINER_TRACK_MODULE_T
+{
+   VC_CONTAINER_IO_T *io;
+   char *uri;
+
+   bool config_done;
+
+} VC_CONTAINER_TRACK_MODULE_T;
+
+typedef struct VC_CONTAINER_MODULE_T
+{
+   char line[MAX_LINE_SIZE + 1];
+
+   VC_CONTAINER_TRACK_T *tracks[MAX_TRACKS];
+   bool header_done;
+
+} VC_CONTAINER_MODULE_T;
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+VC_CONTAINER_STATUS_T simple_writer_open( VC_CONTAINER_T * );
+static VC_CONTAINER_STATUS_T simple_writer_write( VC_CONTAINER_T *ctx,
+   VC_CONTAINER_PACKET_T *packet );
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+static VC_CONTAINER_STATUS_T simple_write_line( VC_CONTAINER_T *ctx,
+   const char *format, ...)
+{
+   VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+   va_list args;
+   int result;
+
+   va_start(args, format);
+   result = vsnprintf(module->line, sizeof(module->line), format, args);
+   va_end(args);
+
+   if (result >= (int)sizeof(module->line))
+      return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+
+   WRITE_BYTES(ctx, module->line, result);
+   _WRITE_U8(ctx, '\n');
+   return STREAM_STATUS(ctx);
+}
+
+static VC_CONTAINER_STATUS_T simple_write_header( VC_CONTAINER_T *ctx )
+{
+   unsigned int i;
+
+   simple_write_line(ctx, SIGNATURE_STRING);
+
+   for (i = 0; i < ctx->tracks_num; i++)
+   {
+      VC_CONTAINER_TRACK_T *track = ctx->tracks[i];
+
+      if (track->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO)
+      {
+         simple_write_line(ctx, "TRACK video, %4.4s, %i, %i",
+            (char *)&track->format->codec,
+            (int)track->format->type->video.width,
+            (int)track->format->type->video.height);
+         if ((track->format->type->video.visible_width &&
+              track->format->type->video.visible_width !=
+                 track->format->type->video.width) ||
+             (track->format->type->video.visible_height &&
+              track->format->type->video.visible_height !=
+                 track->format->type->video.height))
+            simple_write_line(ctx, CONFIG_VIDEO_CROP" %i, %i",
+               track->format->type->video.visible_width,
+               track->format->type->video.visible_height);
+         if (track->format->type->video.par_num &&
+             track->format->type->video.par_den)
+            simple_write_line(ctx, CONFIG_VIDEO_ASPECT" %i, %i",
+               track->format->type->video.par_num,
+               track->format->type->video.par_den);
+      }
+      else if (track->format->es_type == VC_CONTAINER_ES_TYPE_AUDIO)
+      {
+         simple_write_line(ctx, "TRACK audio, %4.4s, %i, %i, %i, %i",
+            (char *)&track->format->codec,
+            (int)track->format->type->audio.channels,
+            (int)track->format->type->audio.sample_rate,
+            (int)track->format->type->audio.bits_per_sample,
+            (int)track->format->type->audio.block_align);
+      }
+      else if (track->format->es_type == VC_CONTAINER_ES_TYPE_AUDIO)
+      {
+         simple_write_line(ctx, "TRACK subpicture, %4.4s, %i",
+            (char *)&track->format->codec,
+            (int)track->format->type->subpicture.encoding);
+      }
+      else
+      {
+         simple_write_line(ctx, "TRACK unknown, %4.4s",
+            (char *)&track->format->codec);
+      }
+
+      simple_write_line(ctx, CONFIG_URI" %s", track->priv->module->io->uri);
+      if (track->format->codec_variant)
+         simple_write_line(ctx, CONFIG_CODEC_VARIANT" %4.4s",
+            (char *)&track->format->codec_variant);
+      if (track->format->bitrate)
+         simple_write_line(ctx, CONFIG_BITRATE" %i", track->format->bitrate);
+      if (!(track->format->flags & VC_CONTAINER_ES_FORMAT_FLAG_FRAMED))
+         simple_write_line(ctx, CONFIG_UNFRAMED);
+   }
+
+   simple_write_line(ctx, SIGNATURE_END_STRING);
+
+   ctx->priv->module->header_done = true;
+   return STREAM_STATUS(ctx);
+}
+
+static VC_CONTAINER_STATUS_T simple_write_config( VC_CONTAINER_T *ctx,
+   unsigned int track_num, VC_CONTAINER_PACKET_T *pkt)
+{
+   VC_CONTAINER_TRACK_T *track = ctx->tracks[track_num];
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_PACKET_T packet;
+
+   track->priv->module->config_done = true;
+
+   if (track->format->extradata_size)
+   {
+      packet.size = track->format->extradata_size;
+      packet.data = track->format->extradata;
+      packet.track = track_num;
+      packet.pts = pkt ? pkt->pts : VC_CONTAINER_TIME_UNKNOWN;
+      packet.flags = 0;
+      packet.flags |= VC_CONTAINER_PACKET_FLAG_CONFIG;
+
+      status = simple_writer_write(ctx, &packet);
+   }
+
+   return status;
+}
+
+static VC_CONTAINER_STATUS_T simple_write_add_track( VC_CONTAINER_T *ctx,
+   VC_CONTAINER_ES_FORMAT_T *format )
+{
+   VC_CONTAINER_TRACK_T *track = NULL;
+   VC_CONTAINER_STATUS_T status;
+   const char *uri = vc_uri_path(ctx->priv->uri);
+   unsigned int uri_size = strlen(uri);
+
+   /* Allocate and initialise track data */
+   if (ctx->tracks_num >= MAX_TRACKS)
+      return VC_CONTAINER_ERROR_OUT_OF_RESOURCES;
+
+   ctx->tracks[ctx->tracks_num] = track =
+      vc_container_allocate_track(ctx, sizeof(VC_CONTAINER_TRACK_MODULE_T) +
+         uri_size + ES_SUFFIX_SIZE + 1);
+   if (!track)
+      return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+
+   if (format->extradata_size)
+   {
+      status = vc_container_track_allocate_extradata(ctx, track, format->extradata_size);
+      if (status != VC_CONTAINER_SUCCESS)
+         goto error;
+   }
+   vc_container_format_copy(track->format, format, format->extradata_size);
+
+   track->priv->module->uri = (char *)&track->priv->module[1];
+   snprintf(track->priv->module->uri, uri_size + ES_SUFFIX_SIZE + 1,
+      ES_SUFFIX, uri, ctx->tracks_num, (char *)&track->format->codec);
+
+   LOG_DEBUG(ctx, "opening elementary stream: %s", track->priv->module->uri);
+   track->priv->module->io = vc_container_io_open(track->priv->module->uri,
+      VC_CONTAINER_IO_MODE_WRITE, &status);
+   if (status != VC_CONTAINER_SUCCESS)
+   {
+      LOG_ERROR(ctx, "error opening elementary stream: %s",
+         track->priv->module->uri);
+      goto error;
+   }
+
+   ctx->tracks_num++;
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+   if (track)
+      vc_container_free_track(ctx, track);
+   return status;
+}
+
+/*****************************************************************************
+Functions exported as part of the Container Module API
+ *****************************************************************************/
+static VC_CONTAINER_STATUS_T simple_writer_close( VC_CONTAINER_T *ctx )
+{
+   VC_CONTAINER_MODULE_T *module = ctx->priv->module;
+   for (; ctx->tracks_num > 0; ctx->tracks_num--)
+   {
+      vc_container_io_close(ctx->tracks[ctx->tracks_num-1]->priv->module->io);
+      vc_container_free_track(ctx, ctx->tracks[ctx->tracks_num-1]);
+   }
+   free(module);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T simple_writer_write( VC_CONTAINER_T *ctx,
+   VC_CONTAINER_PACKET_T *packet )
+{
+   VC_CONTAINER_STATUS_T status;
+
+   if (!ctx->priv->module->header_done)
+   {
+      status = simple_write_header(ctx);
+      if (status != VC_CONTAINER_SUCCESS)
+         return status;
+   }
+
+   if (!ctx->tracks[packet->track]->priv->module->config_done)
+   {
+      status = simple_write_config(ctx, packet->track, packet);
+      if (status != VC_CONTAINER_SUCCESS)
+         return status;
+   }
+
+   /* Write the metadata */
+   status = simple_write_line(ctx, "%i %i %"PRIi64" 0x%x",
+      (int)packet->track, (int)packet->size, packet->pts, packet->flags);
+   if (status != VC_CONTAINER_SUCCESS)
+      return status;
+
+   /* Write the elementary stream */
+   vc_container_io_write(ctx->tracks[packet->track]->priv->module->io,
+      packet->data, packet->size);
+
+   return STREAM_STATUS(ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T simple_writer_control( VC_CONTAINER_T *ctx,
+   VC_CONTAINER_CONTROL_T operation, va_list args )
+{
+   VC_CONTAINER_ES_FORMAT_T *format;
+
+   switch (operation)
+   {
+   case VC_CONTAINER_CONTROL_TRACK_ADD:
+      format = (VC_CONTAINER_ES_FORMAT_T *)va_arg(args, VC_CONTAINER_ES_FORMAT_T *);
+      return simple_write_add_track(ctx, format);
+
+   case VC_CONTAINER_CONTROL_TRACK_ADD_DONE:
+      simple_write_header( ctx );
+      return VC_CONTAINER_SUCCESS;
+
+   default: return VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION;
+   }
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T simple_writer_open( VC_CONTAINER_T *ctx )
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FORMAT_INVALID;
+   const char *extension = vc_uri_path_extension(ctx->priv->uri);
+   VC_CONTAINER_MODULE_T *module;
+
+   /* Check if the user has specified a container */
+   vc_uri_find_query(ctx->priv->uri, 0, "container", &extension);
+
+   /* Check we're the right writer for this */
+   if(!extension)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   if(strcasecmp(extension, "smpl") && strcasecmp(extension, "simple"))
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   LOG_DEBUG(ctx, "using simple writer");
+
+   /* Allocate our context */
+   module = malloc(sizeof(*module));
+   if (!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(module, 0, sizeof(*module));
+   ctx->priv->module = module;
+   ctx->tracks = module->tracks;
+
+   ctx->priv->pf_close = simple_writer_close;
+   ctx->priv->pf_write = simple_writer_write;
+   ctx->priv->pf_control = simple_writer_control;
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+   LOG_DEBUG(ctx, "simple: error opening stream (%i)", status);
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+ ********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak writer_open simple_writer_open
+#endif
diff --git a/containers/test/CMakeLists.txt b/containers/test/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..7d36352
--- /dev/null
@@ -0,0 +1,66 @@
+# Generate test application
+add_executable(containers_test test.c)
+target_link_libraries(containers_test -Wl,--no-whole-archive containers)
+install(TARGETS containers_test DESTINATION bin)
+
+# Generate test application
+add_executable(containers_check_frame_int check_frame_int.c)
+target_link_libraries(containers_check_frame_int -Wl,--no-whole-archive containers)
+install(TARGETS containers_check_frame_int DESTINATION bin)
+
+# Generate autotest application
+#add_executable(containers_autotest autotest.cpp crc_32.c)
+#target_link_libraries(containers_autotest -Wl,--no-whole-archive containers})
+#install(TARGETS containers_autotest DESTINATION bin)
+
+# Helper code to provide non-blocking console input
+if (WIN32)
+set( NB_IO_SOURCE nb_io_win32.c )
+elseif (UNIX)
+set( NB_IO_SOURCE nb_io_unix.c )
+endif (WIN32)
+set(extra_test_SRCS nb_io_win32.c autotest.cpp crc_32.c)
+add_custom_target(containers_test_extra
+    COMMAND touch ${extra_test_SRCS}
+    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/containers/test)
+add_dependencies(containers_test containers_test_extra)
+
+# Generate net test applications
+add_executable(containers_stream_client stream_client.c ${NB_IO_SOURCE})
+target_link_libraries(containers_stream_client containers)
+install(TARGETS containers_stream_client DESTINATION bin)
+
+add_executable(containers_stream_server stream_server.c)
+target_link_libraries(containers_stream_server containers)
+install(TARGETS containers_stream_server DESTINATION bin)
+
+add_executable(containers_datagram_sender datagram_sender.c)
+target_link_libraries(containers_datagram_sender containers)
+install(TARGETS containers_datagram_sender DESTINATION bin)
+
+add_executable(containers_datagram_receiver datagram_receiver.c)
+target_link_libraries(containers_datagram_receiver containers)
+install(TARGETS containers_datagram_receiver DESTINATION bin)
+
+add_executable(containers_rtp_decoder rtp_decoder.c ${NB_IO_SOURCE})
+target_link_libraries(containers_rtp_decoder containers)
+install(TARGETS containers_rtp_decoder DESTINATION bin)
+
+# Generate URI test application
+add_executable(containers_test_uri test_uri.c)
+target_link_libraries(containers_test_uri containers)
+install(TARGETS containers_test_uri DESTINATION bin)
+
+# Generate URI pipe application
+add_executable(containers_uri_pipe uri_pipe.c ${NB_IO_SOURCE})
+target_link_libraries(containers_uri_pipe containers)
+install(TARGETS containers_uri_pipe DESTINATION bin)
+
+# Generate bit stream test application
+add_executable(containers_test_bits test_bits.c)
+target_link_libraries(containers_test_bits containers)
+install(TARGETS containers_test_bits DESTINATION bin)
+
+# Generate packet file dump application
+add_executable(containers_dump_pktfile dump_pktfile.c)
+install(TARGETS containers_dump_pktfile DESTINATION bin)
diff --git a/containers/test/autotest.cpp b/containers/test/autotest.cpp
new file mode 100755 (executable)
index 0000000..2a9a3cb
--- /dev/null
@@ -0,0 +1,1958 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <string>
+#include <map>
+#include <set>
+#include <vector>
+#include <list>
+#include <algorithm>
+#include <iomanip>
+
+// MS compilers require __cdecl calling convention on some callbacks. Other compilers reject it.
+#if (!defined(_MSC_VER) && !defined(__cdecl))
+#define __cdecl
+#endif
+
+extern "C"
+{
+#include "containers/containers.h"
+#include "containers/core/containers_common.h"
+#include "containers/core/containers_logging.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_io.h"
+
+// Declare the CRC32 function from Snippets.org (obtained from the wayback machine, see crc_32.c)
+   uint32_t crc32buf(const uint8_t *buf, size_t len);
+}
+
+// Error logger. It looks a little like std::cout, but it will stop the program if required on an end-of-line,
+// returning an error to the caller. This is intended to allow automated tests to run to first fail,
+// but interactive tests to run all the way through (using -k)
+class ERROR_LOGGER_T
+{
+public:
+   ERROR_LOGGER_T(): error_is_fatal(true), had_any_error(false)
+   {}
+
+   ~ERROR_LOGGER_T()
+   {
+      // Flush out any bits of message that have been assembled, but not yet flushed out.
+      std::cerr << stream.str();
+
+      if (had_any_error)
+      {
+         exit(VC_CONTAINER_ERROR_FAILED);
+      }
+   }
+
+   // Tell the logger that we're going to keep going after an error if we possibly can
+   void set_errors_not_fatal()
+   {
+      error_is_fatal = false;
+   }
+
+   // Tell the error logger to redirect its output to this stream instead of the default stderr.
+   // This is used when dumping is enabled, so that errors become part of the stream description.
+   void set_output(std::ostream* new_stream)
+   {
+      output_stream = new_stream;
+   }
+
+   // Generic inserter. Always calls through to the inserter for the base class.
+   template <typename T> ERROR_LOGGER_T& operator<<(const T& object)
+   {
+      stream << object;
+      had_any_error = true;
+      return *this;
+   }
+
+   // specialised inserter for iomanip type objects. Ensures that this object, and not the contained stream,
+   // is passed to the object.
+   ERROR_LOGGER_T& operator<<(ERROR_LOGGER_T& (__cdecl *_Pfn)(ERROR_LOGGER_T&))
+   {
+      return _Pfn(*this);
+   }
+
+   // implementation of flush. This is called by endl, and if the flags are set the program will stop.
+   ERROR_LOGGER_T& flush()
+   {
+      // If required send it to the quoted stream
+      if (output_stream)
+      {
+         *output_stream << stream.str();
+      }
+      else
+      {
+         // just send it to stderr
+         std::cerr << stream.str();
+      }
+
+      stream.clear();               // reset any odd flags
+      stream.str("");               // empty the string
+
+      if (error_is_fatal)
+      {
+         exit(VC_CONTAINER_ERROR_FAILED);
+      }
+
+      return *this;
+   }
+
+private:
+   // set true if should stop on first error (usual for smoke testing)
+   // or keep going (usual if you want to look at the logs). Controlled by config -k flag (as for make)
+   bool error_is_fatal;
+
+   // Set true if we've ever had an error. This way the app will return an error even if it kept going after it.
+   bool had_any_error;
+
+   // The current error message
+   std::ostringstream stream;
+
+   // The output stream, if not defaulted
+   std::ostream* output_stream;
+};
+
+namespace std
+{
+   // GCC insists I say this twice:
+   ERROR_LOGGER_T& ends(ERROR_LOGGER_T& logger);
+
+   // implementation of std::ends for the error logger - flushes the message.
+   ERROR_LOGGER_T& ends(ERROR_LOGGER_T& logger)
+   {
+      logger << "\n";
+      logger.flush();
+      return logger;
+   }
+}
+
+// Internal to this file, PTS is stored in one of these. other code uses int64_t directly.
+typedef int64_t PTS_T;
+
+struct PACKET_DATA_T
+{
+   VC_CONTAINER_PACKET_T info;      // copy of the API's data
+   std::vector<uint8_t> buffer;     // copy of the data contained, or empty if we have exceeded configuration.mem_max
+   uint32_t crc;                    // CRC32 of the data.
+
+   // Constructor. Zeroes the whole content.
+   PACKET_DATA_T(): /* info((VC_CONTAINER_PACKET_T){0}), */ buffer(), crc(0)
+   {
+      // The syntax above for initialising info is probably correct according to C++ 0x.
+      // Unfortunately the MS C++ compiler in VS2012 isn't really C++0x compliant.
+      memset(&info, 0, sizeof(info));
+   }
+};
+
+typedef uint32_t STREAM_T;
+
+// Packets in a file in an arbitrary order, usually the order they were read.
+typedef std::list<PACKET_DATA_T> ALL_PACKETS_T;
+
+// Packets keyed by time (excludes packets with no PTS). This collection must be on a per-stream basis.
+typedef std::map<PTS_T, ALL_PACKETS_T::const_iterator> TIMED_PACKETS_T;
+
+// Packets with times. Must be split per-stream as multiple streams may have the same PTS.
+// (It's actually unusual for more than one stream to have key frames)
+typedef std::map<STREAM_T, TIMED_PACKETS_T> STREAM_TIMED_PACKETS_T;
+
+// structure parsing and holding configuration information for the program.
+struct CONFIGURATION_T
+{
+   // maximum size of in-memory buffers holding file data. Set by -m
+   size_t mem_max;
+
+   // The source file or URL being processed
+   std::string source_name;
+
+   // trace verbosity, to reflect the older test application. Set by -v.
+   int32_t verbosity, verbosity_input, verbosity_output;
+
+   // fatal errors flag set by -k
+   bool errors_not_fatal;
+
+   // dump-path for packet summary set by -d. May be std::cout.
+   mutable std::ostream* dump_packets;
+
+   // tolerance values set by -t.
+   // Ideally when we seek to a time all the tracks would be right on it, but that's not always possible.
+   // When we don't have seek_forwards set:
+   // - The video must not be after the requested time
+   // - The video must not be more than
+   PTS_T tolerance_video_early;
+   //   microseconds before the desired time. A 'good' container will hit it bang on if the supplied time is a video key frame.
+   PTS_T tolerance_video_late;
+
+   // - The other tracks must not be more than
+   PTS_T tolerance_other_early;
+   PTS_T tolerance_other_late;
+   //   from the time of the video frame. If forcing is not supported we have to take what's in the file.
+
+   // If set by -p  a test is performed re-reading the file using a packet buffer smaller than the expected packet:
+   // If <1 it's a proportion (e.g 0.5 will read half the packet, then the other half on a subsequent read)
+   // If 1 or more it's a size (1 will read 1 byte at a time; 100 not more than 100 bytes in each read)
+   // Defaults to -ve value, which means don't do this test.
+   double packet_buffer_size;
+
+   // Constructor
+   CONFIGURATION_T(int argc, char** argv)
+      : mem_max(0x40000000)   // 1Gb for 32-bit system friendliness.
+      , verbosity(0)          // no trace
+      , verbosity_input(0)
+      , verbosity_output(0)
+      , errors_not_fatal(false)
+      , dump_packets(nullptr)
+      , tolerance_video_early(100000)   // 100k uS = 100mS
+      , tolerance_video_late(0)
+      , tolerance_other_early(100000)   // 100k uS = 100mS
+      , tolerance_other_late(1000000)   // 1000k uS = 1S
+      , packet_buffer_size(-1)
+   {
+      if (argc < 2)
+      {
+         std::cout <<
+            "-d     produce packet dump (to file if specified)" << std::endl <<
+            "-k     keep going on errors" << std::endl <<
+            "-m     max memory buffer for packet data (default 1Gb). If the file is large not all will be validated properly." << std::endl <<
+            "-p     re-read using a small packet buffer. If >= 1 this is a size; if < 1 a proportion of the packet" << std::endl <<
+            "-v     verbose mode." << std::endl <<
+            "         -vi input verbosity only" << std::endl <<
+            "         -vo output verbosity only" << std::endl <<
+            "         add more vvv to make it more verbose" << std::endl <<
+            "-t     seek error tolerance in microseconds" << std::endl <<
+            "         tv video streams" << std::endl <<
+            "         to other streams" << std::endl <<
+            "         te, tl all streams earliness, lateness" << std::endl <<
+            "         tvl, tol video, other lateness" << std::endl <<
+            "         toe, tve video, other earliness" << std::endl << std::endl <<
+
+            "example: autotest -k 1-128.wmv -vvvvv -t1000000" << std::endl <<
+            "  tests 1-128.wmv. Keeps going on errors. Very verbose. Tolerant of errors up to 1s in seeks." << std::endl;
+         exit(0);
+      }
+      // Parse each argument
+      for (int arg = 1; arg <argc; ++arg)
+      {
+         std::string argstr(argv[arg]);
+
+         // We don't expect empty argument strings from either the Windows or Linux shells
+         if (argstr.empty())
+         {
+            std::cerr << "Argument" << arg << " is a zero-length string";
+            exit(VC_CONTAINER_ERROR_INVALID_ARGUMENT);
+         }
+
+         // If the string does not start with a - it must be the input file
+         if (argstr.front() != '-')
+         {
+            if (source_name.empty())
+            {
+               source_name = argstr;
+            }
+            else
+            {
+               std::cerr << "Two source names supplied:" << std::endl << source_name << std::endl << argstr;
+               exit(VC_CONTAINER_ERROR_INVALID_ARGUMENT);
+            }
+         }
+         else
+         {
+            // throw away the hyphen
+            argstr.erase(0,1);
+
+            if (argstr.empty())
+            {
+               error(arg, argstr, "is too short");
+            }
+
+            // examine the char after the hyphen
+            switch (argstr.at(0))
+            {
+            case 'd':
+               // produce packet dump
+               if (argstr.size() == 1)
+               {
+                  dump_packets = &std::cout;
+               }
+               else
+               {
+                  // Allocate a new ostream into it.
+                  // Note: This new is not matched by a free - but this will be cleaned up at process end.
+                  dump_packets = new std::ofstream(std::string(argstr.begin() + 1, argstr.end()), std::ios_base::out);
+               }
+               break;
+
+            case 'k':
+               // keep going on errors.
+               if (argstr.size() == 1)
+               {
+                  errors_not_fatal = true;   // don't set the error logger's own flag yet. Command line parsing errors are ALWAYS fatal!
+               }
+               else
+               {
+                  error(arg, argstr, "-k has no valid following chars");
+               }
+               break;
+
+               // memory size parameter
+            case 'm':
+               {
+                  std::istringstream number(argstr);
+
+                  // throw away the m
+                  number.ignore(1);
+
+                  if (number.eof())
+                  {
+                     error(arg, argstr, "Memory size not supplied");
+                  }
+
+                  // read the number
+                  number >> mem_max;
+                  if (!number.eof())
+                  {
+                     error(arg, argstr, "Size cannot be parsed");
+                  }
+               }
+               break;
+
+            case 'p':
+               {
+                  std::istringstream number(argstr);
+
+                  // throw away the p
+                  number.ignore(1);
+
+                  if (number.eof())
+                  {
+                     error(arg, argstr, "Packet re-read size not supplied");
+                  }
+
+                  // read the number
+                  number >> packet_buffer_size;
+                  if (!number.eof())
+                  {
+                     error(arg, argstr, "Size cannot be parsed");
+                  }
+               }
+               break;
+
+            case 't':
+               // error tolerance
+               {
+                  std::istringstream stream(argstr);
+
+                  stream.ignore(1);    // throw away the t
+
+                  // flags for which tolerance we are processing.
+                  bool video = true, other = true, earliness=true, lateness = true;
+                  int64_t tolerance;
+
+                  // If there's a v or an o it's video or other only
+                  if (!stream.eof())
+                  {
+                     switch (stream.peek())
+                     {
+                     case 'v':
+                        other = false; // if he said video we don't touch the other params
+                        stream.ignore(1);    // throw away the letter
+                        break;
+
+                     case 'o':
+                        video = false;
+                        stream.ignore(1);    // throw away the letter
+                        break;
+
+                        // do nothing on other chars.
+                     }
+                  }
+
+                  // If there's an l or an e it's late or early only
+                  if (!stream.eof())
+                  {
+                     switch (stream.peek())
+                     {
+                     case 'l':
+                        earliness = false;
+                        stream.ignore(1);    // throw away the letter
+                        break;
+
+                     case 'e':
+                        lateness = false;
+                        stream.ignore(1);    // throw away the letter
+                        break;
+
+                        // do nothing on other chars.
+                     }
+                  }
+
+                  // read the number that follows
+                  if (stream.eof())
+                  {
+                     error(arg, argstr, "tolerance not supplied");
+                  }
+                  else
+                  {
+                     // read the number
+                     stream >> tolerance;
+                     if (!stream.eof())
+                     {
+                        error(arg, argstr, "Number cannot be parsed");
+                     }
+
+                     if (video && earliness)
+                     {
+                        tolerance_video_early = tolerance;
+                     }
+                     if (video && lateness)
+                     {
+                        tolerance_video_late = tolerance;
+                     }
+                     if (other && earliness)
+                     {
+                        tolerance_other_early = tolerance;
+                     }
+                     if (other && lateness)
+                     {
+                        tolerance_other_late = tolerance;
+                     }
+                  }
+               }
+               break;
+
+               // verbosity. v, vi or vo followed by zero or more extra v.
+            case 'v':
+               process_vees(arg, argstr);
+               break;
+
+               // anything else
+            default:
+               error(arg, argstr, "is not understood");
+            }
+         }
+      }
+
+      if (source_name.empty())
+      {
+         std::cerr << "No source name supplied";
+         exit(VC_CONTAINER_ERROR_URI_NOT_FOUND);
+      }
+
+      if (verbosity != 0)
+      {
+         if (verbosity_input == 0)
+         {
+            verbosity_input = verbosity;
+         }
+
+         if (verbosity_output == 0)
+         {
+            verbosity_output = verbosity;
+         }
+      }
+
+      std::cout << "Source: " << source_name << std::endl;
+      std::cout << "Max buffer size:    " << mem_max << " 0x" << std::hex << mem_max << std::dec << std::endl;
+      std::cout << "Verbosity:          " << verbosity                        << std::endl;
+      std::cout << "Input verbosity:    " << verbosity_input                  << std::endl;
+      std::cout << "Output verbosity:   " << verbosity_output                 << std::endl;
+      std::cout << "Continue on errors: " << (errors_not_fatal ? 'Y' : 'N')   << std::endl;
+      std::cout << "Seek tolerance (uS)"                                      << std::endl;
+      std::cout << " Video Early:       " << tolerance_video_early            << std::endl;
+      std::cout << " Video Late:        " << tolerance_video_late             << std::endl;
+      std::cout << " Other Early:       " << tolerance_other_early            << std::endl;
+      std::cout << " Other Late:        " << tolerance_other_late             << std::endl;
+      std::cout << "Dump Summary:       " << (dump_packets ? 'Y' : 'N')       << std::endl;
+   }
+private:
+
+   // processing for -v parameter.
+   void process_vees(int arg, const std::string& argstr)
+   {
+      std::istringstream vees(argstr);
+
+      // we know we have v, so we can drop it.
+      vees.ignore(1);
+
+      int32_t* which_param = &verbosity;
+      int32_t value = VC_CONTAINER_LOG_ERROR|VC_CONTAINER_LOG_INFO;
+
+      // process the rest of the characters, if any
+      switch (vees.peek())
+      {
+      case 'v':
+         // do nothing yet
+         break;
+
+      case 'i':
+         which_param = &verbosity_input;
+         vees.ignore(1);
+         break;
+
+      case 'o':
+         which_param = &verbosity_output;
+         vees.ignore(1);
+         break;
+
+      default:
+         if (vees.peek() != std::char_traits<char>::eof())
+         {
+            error(arg, argstr, "verbosity is not understood");
+         }
+         break;
+      }
+
+      while (1)
+      {
+         int next = vees.get();
+         if (next == 'v')
+         {
+            // add verbosity
+            value = (value << 1) | 1;
+         }
+         else if (next == std::char_traits<char>::eof())
+         {
+            break;
+         }
+         else
+         {
+            error(arg, argstr, "verbosity is not understood");
+         }
+      }
+
+      // store what we parsed.
+      *which_param = value;
+   }
+
+   // error handling function. Does not return.
+   void error(int arg, const std::string& argstr, const std::string& msg)
+   {
+      std::cerr << "Argument " << arg << " \"" << argstr << "\" " << msg;
+      exit(VC_CONTAINER_ERROR_INVALID_ARGUMENT);
+   }
+};
+
+// Most of the functionality of the program is in this class, or its subsidiaries.
+class TESTER_T
+{
+public:
+   // Construct, passing command line parameters
+   TESTER_T(int argc, char**argv)
+      : configuration(argc, argv)
+      , video_stream(std::numeric_limits<STREAM_T>::max())
+   {
+      // If the configuration said keep going on errors tell the logger.
+      if (configuration.errors_not_fatal)
+      {
+         error_logger.set_errors_not_fatal();
+      }
+
+      // Tell it where any -d routed the file summary
+      error_logger.set_output(configuration.dump_packets);
+   }
+
+   // Run the tests
+   VC_CONTAINER_STATUS_T run()
+   {
+      /* Set the verbosity */
+      vc_container_log_set_verbosity(0, configuration.verbosity_input);
+
+      // Open the container
+      p_ctx = vc_container_open_reader(configuration.source_name.c_str(), &status, 0, 0);
+
+      if(!p_ctx || (status != VC_CONTAINER_SUCCESS))
+      {
+        error_logger << "error opening file " << configuration.source_name << " Code " << status << std::ends;
+      }
+
+      // Find the video stream.
+      for(size_t i = 0; i < p_ctx->tracks_num; i++)
+      {
+         if (p_ctx->tracks[i]->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO)
+         {
+            if (video_stream == std::numeric_limits<STREAM_T>::max())
+            {
+               video_stream = i;
+            }
+            else
+            {
+               // we've found two video streams. This is not necessarily an error, but it's certainly odd - perhaps it's the angles
+               // from a DVD. We don't expect to see it, but report it anyway. Don't stop, just assume that the first one is the one we want.
+               error_logger << "Both track " << video_stream << " and " << i << " are marked as video streams" << std::ends;
+            }
+         }
+      }
+
+      if (video_stream == std::numeric_limits<STREAM_T>::max())
+      {
+         error_logger << "No video track found" << std::ends;
+      }
+
+      // Read all the packets sequentially. This will gve us all the metadata of the packets,
+      // and (up to configuration.mem_max) will also store the packet data.
+      read_sequential();
+
+      // Now we have some packets we can initialise our internal RNG.
+      init_crg();
+
+      // Find all the keyframes in the collection we just read.
+      find_key_packets();
+
+      // Seeking tests. Only if the container supports it.
+      // We do this first, because one of the checks is whether or not the container supports seeking,
+      // and we want to be able to seek back between tests.
+      if (p_ctx->capabilities & VC_CONTAINER_CAPS_CAN_SEEK)
+      {
+         /// Seek to PTS 0 (this ought to be the beginning)
+         PTS_T beginning = 0;
+         status = vc_container_seek(p_ctx, &beginning, VC_CONTAINER_SEEK_MODE_TIME, 0);
+         if (status != VC_CONTAINER_SUCCESS)
+         {
+            error_logger << "Container failed to seek to the beginning - status " << status << std::ends;
+
+            // This is fatal.
+            exit(status);
+         }
+
+         // Ask for info about the first packet
+         PACKET_DATA_T actual;
+         status = vc_container_read(p_ctx, &actual.info, VC_CONTAINER_READ_FLAG_INFO);
+
+         if (status != VC_CONTAINER_SUCCESS)
+         {
+            error_logger << "Read info failed after seek to the beginning - status " << status << std::ends;
+         }
+         else
+         {
+            PACKET_DATA_T& expected = all_packets.front();
+            // Compare some selected data to check that this genuinely is the first packet.
+            // We don't actually do a read.
+            if ((expected.info.pts != actual.info.pts)
+               || (expected.info.dts != actual.info.dts)
+               || (expected.info.size != actual.info.size)
+               || (expected.info.frame_size != actual.info.frame_size)
+               || (expected.info.track != actual.info.track)
+               || (expected.info.flags != actual.info.flags))
+            {
+               // Copy the CRC from the expected value. That will stop compare_packets whinging.
+               actual.crc = expected.crc;
+
+               // report the discrepancy
+               error_logger << "Seek to time zero did not arrive at beginning: "
+                  << compare_packets(expected, actual) << std::ends;
+            }
+         }
+
+         // Perform seeks to find all the packets that a seek will go to.
+         check_indices(0);
+         check_indices(VC_CONTAINER_SEEK_FLAG_FORWARD);
+
+         // If it supports forcing then seek to each of those locations, and force read all the tracks.
+         if (p_ctx->capabilities & VC_CONTAINER_CAPS_FORCE_TRACK)
+         {
+            check_seek_then_force(0);
+            check_seek_then_force(VC_CONTAINER_SEEK_FLAG_FORWARD);
+         }
+
+         seek_randomly(0);
+         seek_randomly(VC_CONTAINER_SEEK_FLAG_FORWARD);
+
+         // todo more?
+      }
+      else
+      {
+         // The file claims not to support seeking. Perform a seek, just to check this out.
+         PTS_T beginning = 0;
+
+         status = vc_container_seek(p_ctx, &beginning, VC_CONTAINER_SEEK_MODE_TIME, 0);
+
+         if (status != VC_CONTAINER_ERROR_UNSUPPORTED_OPERATION)
+         {
+            error_logger << "Container did not reject seek when its capabilities said it is not supported" << std::ends;
+         }
+      }
+
+      // If the config didn't ask for this test don't do it.
+      if (configuration.packet_buffer_size > 0)
+      {
+         re_seek_to_beginning();
+
+         // Read through the file, reading the packet in several bites (bite size controlled by -p parameter)
+         check_partial_reads();
+
+         // Check forcing (this doesn't require seek)
+         if (p_ctx->capabilities & VC_CONTAINER_CAPS_FORCE_TRACK)
+         {
+            re_seek_to_beginning();
+            check_forcing();
+         }
+      }
+
+      std::cout << "Test Complete" << std::endl;
+
+      // If anything failed then the error logger will replace this error code. So always return 0 from here.
+      return VC_CONTAINER_SUCCESS;
+   }
+private:
+   // read packets from the file, and stash them away.
+   void read_sequential()
+   {
+      // Use the same buffer for reading each of the packets. It's cheaper to copy the (usually small) data
+      // from this buffer than to create a new one for each packet, then resize it.
+      // 256k is the size used in the other program, and is bigger than any known packet. Increase it
+      // if a bigger one is found.
+      std::vector<uint8_t> buffer(256*1024, 0);
+
+      std::map<uint32_t, size_t> packet_counts;
+
+      // Count of memory used for packet buffers.
+      size_t memory_buffered = 0;
+
+      if (configuration.dump_packets)
+      {
+         *configuration.dump_packets << "pts" << ",\t" << "track" << ",\t" << "size" << ",\t" << "crc" << std::endl;
+      }
+
+      while (1)   //  We break out at EOF.
+      {
+         // Packet object
+         PACKET_DATA_T packet;
+
+         // Use the shared buffer for the moment,
+         packet.info.data = &buffer[0];
+         packet.info.buffer_size = buffer.size();
+
+         // Read data.
+         status = vc_container_read(p_ctx, &packet.info, 0);
+
+         if (packet.info.size >= buffer.size())
+         {
+            std::cerr << "Packet size limit exceeeded. Increase internal buffer size!";
+            exit(VC_CONTAINER_ERROR_FAILED);
+         }
+
+         if (status == VC_CONTAINER_SUCCESS)
+         {
+            // Calculate the CRC of the packet
+            packet.crc = crc32buf(&buffer[0], packet.info.size);
+
+            // If there is any data, and we haven't exceeded our size limit...
+            if ((packet.info.size > 0) && (memory_buffered < configuration.mem_max))
+            {
+               // Copy the data we read across from the big buffer to our local one
+               packet.buffer.assign(buffer.begin(), buffer.begin() + packet.info.size);
+
+               // count how much we have buffered
+               memory_buffered += packet.info.size;
+
+               // wipe the bit of the big buffer we used
+               memset(&buffer[0], 0, packet.info.size);
+            }
+            else
+            {
+               // not storing any data, either because there is none or we have no space.
+               packet.buffer.clear();
+            }
+
+            // Clear the pointer in our data. It won't be valid later.
+            packet.info.data = 0;
+
+            // Set the size of the buffer to match what is really there.
+            packet.info.buffer_size = packet.info.size;
+
+            // count the packet
+            ++packet_counts[packet.info.track];
+
+            // store it
+            all_packets.push_back(packet);
+
+            // perhaps dump it
+            if (configuration.dump_packets)
+            {
+               if (packet.info.pts < 0)
+               {
+                  *configuration.dump_packets << "-";
+               }
+               else
+               {
+                  *configuration.dump_packets << packet.info.pts;
+               }
+
+               *configuration.dump_packets
+                  << ",\t" << packet.info.track << ",\t" << packet.info.size << ",\t" << packet.crc << std::endl;
+            }
+         }
+         else if (status == VC_CONTAINER_ERROR_EOS)
+         {
+            break;
+         }
+         else
+         {
+            error_logger << "error reading file " << configuration.source_name << " Code " << status << std::ends;
+         }
+      }
+
+      std::cout << std::dec << "File has " << packet_counts.size() << " tracks." << std::endl;
+
+      // Print the packet count for each stream. Also, while iterating, save all the stream numbers.
+      for(std::map<uint32_t, size_t>::const_iterator stream = packet_counts.begin(); stream != packet_counts.end(); ++stream)
+      {
+         // Print the packet count
+         std::cout << "Stream " << stream->first << " has " << stream->second << " packets." << std::endl;
+
+         // Note that we have a stream with this number.
+         all_streams.insert(stream->first);
+      };
+
+      if (p_ctx->tracks_num != packet_counts.size())
+      {
+         error_logger << "The file header claims " << p_ctx->tracks_num
+            << " but " << packet_counts.size() << " streams were found" << std::ends;
+      }
+   }
+
+   // Search the all_packets collection for key frames, and store them in all_key_packets
+   void find_key_packets()
+   {
+      // The last known PTS for each stream.
+      std::map<STREAM_T, PTS_T> last_pts_in_stream;
+
+      for (ALL_PACKETS_T::const_iterator packet = all_packets.begin(); packet != all_packets.end(); ++packet)
+      {
+         PTS_T pts = packet->info.pts;
+         STREAM_T stream = packet->info.track;
+
+         // If it has a PTS check they are an ascending sequence.
+         if (pts >= 0)
+         {
+            // Find the last PTS, if any, for this stream
+            std::map<STREAM_T, PTS_T>::const_iterator last_known_pts = last_pts_in_stream.find(stream);
+
+            if ((last_known_pts != last_pts_in_stream.end()) && (pts <= last_known_pts->second))
+            {
+               // the PTS isn't bigger than the previous best. This is an error.
+               error_logger << "Out of sequence PTS " << pts << " found. Previous largest was "
+                  << last_pts_in_stream[stream] << std::ends;
+            }
+
+            // store it (even if bad)
+            last_pts_in_stream[stream] = pts;
+
+            // Store in the collection of packets with PTSes
+            all_pts_packets[stream].insert(std::make_pair(pts, packet));
+
+            // if it is also a keyframe
+            if (packet->info.flags & VC_CONTAINER_PACKET_FLAG_KEYFRAME)
+            {
+               // Put it into the collection for its track.
+               all_key_packets[stream].insert(std::make_pair(pts, packet));
+            }
+         }
+      }
+   }
+
+   // Check which locations can be accessed by a seek, with or without VC_CONTAINER_SEEK_FLAG_FORWARD.
+   void check_indices(VC_CONTAINER_SEEK_FLAGS_T direction)
+   {
+      STREAM_TIMED_PACKETS_T& index_positions = direction == 0 ? reverse_index_positions : forward_index_positions;
+      // Go through each stream that contains key packets (usually only one)
+      for (STREAM_TIMED_PACKETS_T::const_iterator stream_keys = all_key_packets.begin();
+         stream_keys != all_key_packets.end();
+         ++stream_keys)
+      {
+         // Start with a PTS just after the last key packet, and repeat until we fall off the beginning.
+         for (PTS_T target_pts = stream_keys->second.rbegin()->first + 1; target_pts >= 0; /* no decrement */)
+         {
+            // copy the PTS value to pass to vc_container_seek
+            PTS_T actual_pts = target_pts;
+
+            // Seek to that position in the file.
+            status = vc_container_seek(p_ctx, &actual_pts, VC_CONTAINER_SEEK_MODE_TIME, direction);
+
+            if (status != VC_CONTAINER_SUCCESS)
+            {
+               error_logger << "Error " << status << " seeking to PTS " << target_pts << std::ends;
+               continue;   // if errors are not fatal we'll try again 1uS earlier.
+            }
+
+            // Check whether this seek reported that it went somewhere sensible
+            check_correct_seek(direction, actual_pts, target_pts);
+
+            // Validate that the place it said we arrived at is correct - read info for the first packet in any stream
+            {
+               PACKET_DATA_T packet;
+               status = vc_container_read(p_ctx, &packet.info, VC_CONTAINER_READ_FLAG_INFO);
+
+               if (status != VC_CONTAINER_SUCCESS)
+               {
+                  error_logger << "Error " << status << " reading info for packet at PTS " << target_pts << std::ends;
+                  continue;   // stop trying to read at this PTS.
+               }
+
+               if (packet.info.pts != actual_pts)
+               {
+                  error_logger << "Incorrect seek. Container claimed to have arrived at "
+                     << actual_pts << " but first packet ";
+
+                  if (packet.info.pts < 0)
+                  {
+                     error_logger << " had no PTS";
+                  }
+                  else
+                  {
+                        error_logger << "was at " << packet.info.pts;
+                  }
+
+                  error_logger << std::ends;
+               }
+            }
+
+            // We'll perform reads until we've had a packet with PTS from every stream.
+            for (std::set<STREAM_T> unfound_streams = all_streams;
+               !unfound_streams.empty();
+               /* unfound_streams.erase(packet.info.track) */ )
+            {
+               // Read a packet. We can't be sure what track it will be from, so first read the info...
+               PACKET_DATA_T packet;
+               status = vc_container_read(p_ctx, &packet.info, VC_CONTAINER_READ_FLAG_INFO);
+
+               if (status != VC_CONTAINER_SUCCESS)
+               {
+                  error_logger << "Error " << status << " reading info for packet following PTS " << target_pts << std::ends;
+                  break;   // stop trying to read at this PTS.
+               }
+
+               // allocate a buffer.
+               packet.buffer.resize(packet.info.size);
+               packet.info.data = &packet.buffer[0];
+               packet.info.buffer_size = packet.info.size;
+
+               // perform the read
+               status = vc_container_read(p_ctx, &packet.info, 0);
+
+               if (status != VC_CONTAINER_SUCCESS)
+               {
+                  error_logger << "Error " << status << " reading packet following PTS " << target_pts << std::ends;
+                  break;   // stop trying to read at this PTS.
+               }
+
+               STREAM_T stream = packet.info.track;
+
+               // If it has no PTS we can't use it. Read another one.
+               if (packet.info.pts < 0)
+               {
+                  // The first packet we found for a stream has no PTS.
+                  // That's odd, because we wouldn't be able to play it. However,
+                  // if the stream doesn't permit forcing it may be inevitable.
+                  if ((unfound_streams.find(stream) != unfound_streams.end())
+                     && ((p_ctx->capabilities & VC_CONTAINER_CAPS_FORCE_TRACK) != 0))
+                  {
+                     error_logger << "Packet in stream " << stream
+                        << " has no PTS after seeking to PTS " << target_pts << std::ends;
+                  }
+                  continue;
+               }
+
+               // Search for the PTS collection for this stream
+               STREAM_TIMED_PACKETS_T::iterator stream_packets = all_pts_packets.find(stream);
+
+               if (stream_packets == all_pts_packets.end())
+               {
+                  error_logger << "Packet from unknown stream " << stream
+                     << "found when reading packet at PTS " << target_pts << std::ends;
+                  continue;      // try reading another packet.
+               }
+
+               // Look for the packet for this PTS in this stream.
+               TIMED_PACKETS_T::const_iterator expected_packet = stream_packets->second.find(packet.info.pts);
+
+               if (expected_packet == stream_packets->second.end())
+               {
+                  error_logger << "Read packet from stream " << stream << " has unknown PTS " << packet.info.pts << std::ends;
+                  continue;
+               }
+
+               // calculate the CRC
+               packet.crc = crc32buf(&packet.buffer[0], packet.info.size);
+
+               // Validate that the data is the data we found when we did the sequential reads.
+               std::string anyerror = compare_packets(*expected_packet->second, packet);
+
+               if (!anyerror.empty())
+               {
+                  error_logger << "Incorrect data found at PTS " << actual_pts << anyerror << std::ends;
+               }
+
+               // If this is the first packet we found for this stream
+               if (unfound_streams.find(stream) != unfound_streams.end())
+               {
+                  // Store the packet we found. Note we key it by the PTS we used for the seek,
+                  // not its own PTS. This should mean next time we seek to that PTS we'll get this packet.
+                  index_positions[stream].insert(std::make_pair(target_pts, expected_packet->second));
+
+                  // Check whether the time on the packet is reasonable - it ought to be close to the time achieved.
+                  check_seek_tolerance(packet, actual_pts);
+
+                  // Now we've found a packet from this stream we're done with it, so note we don't care about it any more.
+                  unfound_streams.erase(stream);
+               }
+            }  // repeat until we've had a packet for every track
+
+            // Adjust the target location
+            if (actual_pts > target_pts)
+            {
+               // Find the next packet down from where we looked, and try there.
+               TIMED_PACKETS_T this_stream_keys = stream_keys->second;
+               TIMED_PACKETS_T::const_iterator next_packet = this_stream_keys.lower_bound(target_pts);
+
+               // If there is such a packet that it has more than this PTS, and it isn't the first packet
+               if ((next_packet != this_stream_keys.begin()) &&
+                  (next_packet != this_stream_keys.end()))
+               {
+                  // pull out the PTS from the one before, and ask for a microsecond past it.
+                  PTS_T new_target_pts = (--next_packet)->first + 1;
+                  if (new_target_pts >= target_pts)
+                  {
+                     --target_pts;
+                  }
+                  else
+                  {
+                     target_pts = new_target_pts;
+                  }
+               }
+               else
+               {
+                  // There's no packet earlier than where we are looking.
+                  // First time try 1 next time try zero.
+                  target_pts = target_pts != 1 ? 1 : 0;
+               }
+            }
+            else if (actual_pts < (target_pts - 1))
+            {
+               // The place we arrived at is well before where we wanted.
+               // Next time go just after where we arrived.
+               target_pts = actual_pts + 1;
+            }
+            else
+            {
+               // If the place we asked for is where we arrived, next time try one microsecond down.
+               --target_pts;
+            }
+         }
+      }
+   }
+
+   // Seek to all feasible locations and perform force reads on all possible tracks
+   void check_seek_then_force(VC_CONTAINER_SEEK_FLAGS_T direction)
+   {
+      // Depending on whether we are doing forward or reverse seeks pick a collection of places a seek can go to.
+      STREAM_TIMED_PACKETS_T index_positions = direction == 0 ? reverse_index_positions : forward_index_positions;
+
+      // Go through all the streams
+      for (STREAM_TIMED_PACKETS_T::const_iterator index_stream = index_positions.begin();
+         index_stream != index_positions.end();
+          ++index_stream)
+      {
+         // Go through all the packets in each stream that can be indexed
+         for (TIMED_PACKETS_T::const_iterator location = index_stream->second.begin();
+            location != index_stream->second.end();
+            ++location
+            )
+         {
+            // This is the time we expect
+            PTS_T actual_pts = location->first;
+
+            // Seek to that position in the file.
+            status = vc_container_seek(p_ctx, &actual_pts, VC_CONTAINER_SEEK_MODE_TIME, direction);
+
+            if (status != VC_CONTAINER_SUCCESS)
+            {
+               error_logger << "Error " << status << " seeking to PTS " << location->first << std::ends;
+               continue;   // if errors are not fatal we'll try the next position.
+            }
+
+            // We'll perform force-reads until we've had a packet from every stream that has any PTS in it.
+            for (STREAM_TIMED_PACKETS_T::const_iterator stream = all_pts_packets.begin(); stream != all_pts_packets.end(); ++stream)
+            {
+               // Read a packet.
+               PACKET_DATA_T packet;
+               packet.info.track = stream->first;
+
+               // This loop repeats occasionally with a continue, but usually stops on the break at the end first time around.
+               while(true)
+               {
+                  status = vc_container_read(p_ctx, &packet.info, VC_CONTAINER_READ_FLAG_INFO | VC_CONTAINER_READ_FLAG_FORCE_TRACK);
+
+                  if (status != VC_CONTAINER_SUCCESS)
+                  {
+                     error_logger << "Error " << status << " force-reading info for stream "
+                        << location->first << " after seeking to PTS " << stream->first << std::ends;
+
+                     // If we can't read the info there's no point in anything else on this stream
+                     break;
+                  }
+
+                  // allocate a buffer.
+                  packet.buffer.resize(packet.info.size);
+                  packet.info.data = &packet.buffer[0];
+                  packet.info.buffer_size = packet.info.size;
+
+                  // perform the actual read
+                  status = vc_container_read(p_ctx, &packet.info, VC_CONTAINER_READ_FLAG_FORCE_TRACK);
+
+                  if (status != VC_CONTAINER_SUCCESS)
+                  {
+                     error_logger << "Error " << status << " force-reading stream "
+                        << location->first << " after seeking to PTS " << stream->first << std::ends;
+
+                     // If we didn't read successfully we can't check the data. Try the next stream.
+                     break;
+                  }
+
+                  // If it has no PTS we can't use it - and it can't be played either.
+                  if (packet.info.pts < 0)
+                  {
+                     error_logger << "Packet force-read on stream " << stream->first
+                        << " has no PTS after seeking to PTS " << location->first << std::ends;
+
+                     // Try force-reading another.
+                     continue;
+                  }
+
+                  // Make sure that the packet is near the time we wanted.
+                  check_seek_tolerance(packet, actual_pts);
+
+                  // Look for the packet for this PTS in this stream.
+                  TIMED_PACKETS_T::const_iterator expected_packet = stream->second.find(packet.info.pts);
+
+                  if (expected_packet == stream->second.end())
+                  {
+                     error_logger << "Packet force-read on stream " << stream->first
+                        << " has unknown PTS " << packet.info.pts << std::ends;
+
+                     // Try force-reading another.
+                     continue;
+                  }
+
+                  packet.crc = crc32buf(packet.info.data, packet.info.size);
+
+                  // Validate that the data is the data we found when we did the sequential reads.
+                  std::string anyerror = compare_packets(*expected_packet->second, packet);
+
+                  if (!anyerror.empty())
+                  {
+                     error_logger << "Incorrect data found at PTS " << actual_pts << anyerror << std::ends;
+                  }
+
+                  // If we arrive here we're done for this stream.
+                  break;
+               }
+            }
+            // repeat until we've had a packet for every stream at this index position
+         }
+         // repeat for every index position in the stream
+      }
+      // repeat for every stream that has index positions
+   }
+
+   // seek to a random selection of places, and see if we get the correct data
+   void seek_randomly(VC_CONTAINER_SEEK_FLAGS_T direction)
+   {
+      // Depending on whether we are doing forward or reverse seeks pick a collection of places a seek can go to.
+      const STREAM_TIMED_PACKETS_T& index_positions = direction == 0 ? reverse_index_positions : forward_index_positions;
+
+      // Go through each stream in that collection
+      for (STREAM_TIMED_PACKETS_T::const_iterator i_all_index_packets = index_positions.begin();
+         i_all_index_packets != index_positions.end();
+         ++i_all_index_packets)
+      {
+         // These are the index packets in the stream.
+         const TIMED_PACKETS_T& all_index_packets = i_all_index_packets->second;
+
+         // this is the number of seeks we'll perform.
+         size_t seek_count = all_index_packets.size();
+
+         // If there are more than 100 locations limit it to 100.
+         if (seek_count > 100)
+         {
+            seek_count = 100;
+         }
+
+         // We want an unsorted list of PTSes.
+         std::list<TIMED_PACKETS_T::value_type> selected_index_packets;
+         {
+            // Picking 100 at random out of a potentially large collection of timestamps in a set is going
+            // to be an expensive operation - search by key is really fast, but search by position is not.
+            // This is an attempt to come up with something reasonably efficient even if the collection is large.
+            std::vector<PTS_T> all_ptses;
+
+            // Reserve enough memory to hold every PTS. This collection should be several orders of magnitude smaller than the file.
+            all_ptses.reserve(all_index_packets.size());
+
+            // Copy all the PTS values into the vector
+            std::transform(
+               all_index_packets.begin(),
+               all_index_packets.end(),
+               std::back_inserter(all_ptses),
+               [](const TIMED_PACKETS_T::value_type& source){ return source.first; }
+            );
+
+            // Based roughly on the Knuth shuffle, get a random subset of the PTS to the front of the collection.
+            std::vector<PTS_T>::iterator some_pts;
+            size_t count;
+            for (count = 0, some_pts = all_ptses.begin(); count < seek_count; ++count, ++some_pts)
+            {
+               // Swap some random PTS into one of the first seek_count locations.
+               // Note this may well be another of the first seek_count locations, especially if this is most of them
+               std::iter_swap(some_pts, (all_ptses.begin() + rand() % seek_count));
+            }
+
+            // Throw away the ones we don't want
+            all_ptses.resize(seek_count);
+
+            // Copy the iterators for each packet with a selected PTS into the list.
+            std::transform(
+               all_ptses.begin(),
+               all_ptses.end(),
+               std::back_inserter(selected_index_packets),
+               [&all_index_packets](PTS_T time){ return *all_index_packets.find(time); });
+
+            // End scope. That will free the rest of all_ptses.
+         }
+
+         // Loop through the selected packets.
+         for (std::list<TIMED_PACKETS_T::value_type>::iterator expected = selected_index_packets.begin();
+            expected != selected_index_packets.end();
+            ++expected)
+         {
+            // Seek to their position & check we got there
+            const PACKET_DATA_T& target = *expected->second;
+            PTS_T target_pts = expected->first;
+
+            status = vc_container_seek(p_ctx, &target_pts, VC_CONTAINER_SEEK_MODE_TIME, direction);
+            check_correct_seek(direction, target_pts, expected->first);
+
+            // Start by initialising the new packet object to match the old one - it's mostly right.
+            PACKET_DATA_T found_packet = target;
+
+            // If forcing is supported, read the first packet & check it's OK.
+            if (p_ctx->capabilities & VC_CONTAINER_CAPS_FORCE_TRACK)
+            {
+               // There might not be a buffer if we ran out of memory
+               found_packet.buffer.resize(found_packet.info.size);
+
+               // Set the address
+               found_packet.info.data = &found_packet.buffer[0];
+
+               // Perform the read
+               status = vc_container_read(p_ctx, &found_packet.info, VC_CONTAINER_READ_FLAG_FORCE_TRACK);
+            }
+            else
+            {
+               // as forcing is not supported repeat reads until a packet is found for this track.
+               do
+               {
+                  status = vc_container_read(p_ctx, &found_packet.info, VC_CONTAINER_READ_FLAG_INFO);
+
+                  // Give up on any error
+                  if (status != VC_CONTAINER_SUCCESS) break;
+
+                  // Set the buffer to match the actual packet
+                  found_packet.info.buffer_size = found_packet.info.size;
+                  found_packet.buffer.resize(found_packet.info.size);
+                  found_packet.info.data = &found_packet.buffer[0];
+                  status = vc_container_read(p_ctx, &found_packet.info, 0);
+
+                  if (status != VC_CONTAINER_SUCCESS) break;
+               }
+               while (found_packet.info.track != target.info.track);
+            }
+
+            if (status != VC_CONTAINER_SUCCESS)
+            {
+               error_logger << "Error " << status << " after random seek to PTS " << target_pts << std::ends;
+            }
+            else
+            {
+               found_packet.crc = crc32buf(&found_packet.buffer[0], found_packet.info.size);
+
+               // We now have a packet from the right stream - it ought to be the one we asked for.
+               const std::string& compare_result = compare_packets(found_packet, target);
+
+               if (!compare_result.empty())
+               {
+                  error_logger << "Incorrect result from reading packet after random seek: " << compare_result << std::ends;
+               }
+            }
+         }
+      }
+   }
+
+   // Seek back to the beginning of the file, either with a seek or by closing and re-opening it
+   void re_seek_to_beginning()
+   {
+      // If the container supports seek do it.
+      if (p_ctx->capabilities & VC_CONTAINER_CAPS_CAN_SEEK)
+      {
+         PTS_T beginning = 0;
+
+         status = vc_container_seek(p_ctx, &beginning, VC_CONTAINER_SEEK_MODE_TIME, 0);
+
+         if (status != VC_CONTAINER_SUCCESS)
+         {
+            error_logger << "Failed to seek back to the beginning" << std::ends;
+         }
+      }
+      else
+      {
+         // The file claims not to support seeking. Close it, and re-open - this should do it.
+         status = vc_container_close(p_ctx);
+
+         if (status != VC_CONTAINER_SUCCESS)
+         {
+            error_logger << "Error " << status << " Failed to close the container." << std::ends;
+         }
+
+         p_ctx = vc_container_open_reader(configuration.source_name.c_str(), &status, 0, 0);
+         if (status != VC_CONTAINER_SUCCESS)
+         {
+            error_logger << "Error " << status << " Failed to re-open the container." << std::ends;
+
+            // Even with -k this is a fatal error. Give up.
+            exit(status);
+         }
+      }
+   }
+
+   // Read through the file, checking to see that the packets we get match the ones we read first time around -
+   // given that we're going to read with a buffer of a different size, either a fixed value or a proportion
+   // of the actual packet size.
+   void check_partial_reads()
+   {
+      // This is used for some reads, and for compares.
+      PACKET_DATA_T actual;
+
+      // Repeat until we meet EOF, which will be in the middle of the loop somewhere.
+      ALL_PACKETS_T::const_iterator expected;
+      for (expected = all_packets.begin(); expected != all_packets.end(); ++expected)
+      {
+         // Ask for info about the first packet
+         status = vc_container_read(p_ctx, &actual.info, VC_CONTAINER_READ_FLAG_INFO);
+
+         if (status != VC_CONTAINER_SUCCESS)
+         {
+            error_logger << "Error " << status << " reading info for partial packet" << std::ends;
+            // Not much point in carrying on if we can't read - but usually this is the end-of-file break.
+            break;
+         }
+
+         size_t whole_packet = actual.info.size;
+
+         // Work out how big a read we want to do.
+         size_t wanted_read_size = (configuration.packet_buffer_size >= 1.0)
+            ? (size_t)configuration.packet_buffer_size
+            : (size_t)(configuration.packet_buffer_size * (double)whole_packet);
+
+         // Make sure it's at least 1 byte (a small proportion of a small packet might round down to zero)
+         if (wanted_read_size == 0)
+         {
+            wanted_read_size = 1;
+         }
+
+         // Ensure our buffer is at least big enough to contain the _whole_ packet.
+         if (whole_packet > actual.buffer.size())
+         {
+            actual.buffer.resize(whole_packet);
+         }
+
+         // We'll need to collect some data from the bits of the packet as they go by.
+         PTS_T first_valid_pts = std::numeric_limits<PTS_T>::min();
+         PTS_T first_valid_dts = std::numeric_limits<PTS_T>::min();
+         uint32_t total_flags = 0;
+
+         size_t amount_read;
+
+         // Loop around several times, reading part of the packet each time
+         for (amount_read = 0; amount_read < whole_packet; /* increment elsewhere */)
+         {
+            // Somewhere in the buffer
+            actual.info.data = &actual.buffer[amount_read];
+
+            // Not more than our calculated size
+            actual.info.buffer_size = wanted_read_size;
+
+            // read some data.
+            status = vc_container_read(p_ctx, &actual.info, 0);
+
+            if (status != VC_CONTAINER_SUCCESS)
+            {
+               error_logger << "Unable to read " << wanted_read_size << " bytes from packet of size "
+                  << expected->info.size << " error " << status << std::ends;
+
+               // Guess we're at end of packet. We _might_ be able to recover from this.
+               break;
+            }
+
+            amount_read += actual.info.size;
+
+            // validate the amount read is less than the request
+            if (actual.info.size > wanted_read_size)
+            {
+               error_logger << "Too much data read from packet. Request size was " << whole_packet
+                  << " but " << actual.info.size << "read in" << std::ends;
+            }
+
+            // and that the total amount read for this packet is not too much
+            if (amount_read > whole_packet)
+            {
+               error_logger << "Too much data read from packet. Total size is " << whole_packet
+                  << " but " << amount_read << "read in" << std::ends;
+            }
+
+            // OR all the flags together
+            total_flags |= actual.info.flags;
+
+            // Save the PTS if we don't have one yet
+            if (first_valid_pts < 0)
+            {
+               first_valid_pts = actual.info.pts;
+            }
+
+            // Ditto the DTS
+            if (first_valid_dts < 0)
+            {
+               first_valid_dts = actual.info.dts;
+            }
+         }
+
+         // The buffer should now contain all the correct data. However, the size field
+         // reflects the last read only - so correct it before the compare.
+         actual.info.size = amount_read;
+
+         // store back the other stuff we got in the loop
+         actual.info.flags = total_flags;
+         actual.info.pts = first_valid_pts;
+         actual.info.dts = first_valid_dts;
+
+         // Calculate the CRC of the whole lot of data
+         actual.crc = crc32buf(&actual.buffer[0], amount_read);
+
+         // It's possible that the packet read isn't the one we expected.
+         // (This happens with the Supremecy3_20sec_WMV_MainProfile_VGA@29.97fps_2mbps_WMA9.2.wmv sample,
+         // where the first packet has no PTS and is not a key frame - seek won't go there)
+         if ((expected->info.pts != actual.info.pts)
+            && (actual.info.pts >= 0))
+         {
+            ALL_PACKETS_T::const_iterator candidate = std::find_if
+               (all_packets.begin(),
+               all_packets.end(),
+               [&actual](ALL_PACKETS_T::value_type& expected) -> bool
+            {
+               // If we find one with the correct track and PTS, that will do.
+               return (expected.info.pts == actual.info.pts)
+                  && (expected.info.track == actual.info.track);
+            });
+
+            if (candidate != all_packets.end())
+            {
+               // We've seen the packet before
+               error_logger << "Partial read returned an unexpected packet. Expect PTS " << expected->info.pts
+                  << " but got PTS " << actual.info.pts << std::ends;
+
+               // switch to expecting this packet
+               expected = candidate;
+            }
+
+            // If we didn't find the packet anywhere in the expected list do nothing, and let the compare fail.
+         }
+
+         const std::string& compare_result = compare_packets(*expected, actual);
+
+         if (!compare_result.empty())
+         {
+            error_logger << "Incorrect result from reading packet in parts: " << compare_result << std::ends;
+         }
+      }
+
+      // check end reached if we were OK this far
+      if (status == VC_CONTAINER_SUCCESS)
+      {
+         // We should be at the end of the expected collection
+         if (expected != all_packets.end())
+         {
+            error_logger << "Failed to read entire file when reading partial packets" << std::ends;
+         }
+
+         // We should not be able to read any more.
+         status = vc_container_read(p_ctx, &actual.info, VC_CONTAINER_READ_FLAG_INFO);
+
+         if (status == VC_CONTAINER_ERROR_EOS)
+         {
+            status = VC_CONTAINER_SUCCESS;
+         }
+         else
+         {
+            error_logger << "Should have reached end of stream, but got status "
+               << status << " while reading partial packets." << std::ends;
+         }
+      }
+   }
+
+   // Information used in the next function about where we are in each stream.
+   struct FORCING_INFO : public PACKET_DATA_T
+   {
+      void new_packet()
+      {
+         first_valid_pts = std::numeric_limits<PTS_T>::min();
+         first_valid_dts = std::numeric_limits<PTS_T>::min();
+         total_flags = 0;
+
+         // Adjust the buffer to hold the amount we want.
+         // (note - resize smaller does not re-allocate,
+         // it'll grow until it reaches the biggest packet then stay at that size)
+         buffer.resize(info.buffer_size);
+
+         info.data = &buffer[0];
+      }
+
+      PTS_T first_valid_pts;
+      PTS_T first_valid_dts;
+      uint32_t total_flags;
+      ALL_PACKETS_T::const_iterator position;
+   };
+
+   // Check forcing. Read bits of the streams so that they get out of sync, and make sure the data is correct.
+   void check_forcing()
+   {
+      // Data for each stream
+      std::map<STREAM_T, FORCING_INFO> stream_positions;
+      std::map<STREAM_T, FORCING_INFO>::iterator stream_pos;
+
+      // Set stream_positions to the first packet for each stream
+      for (std::set<STREAM_T>::const_iterator stream = all_streams.begin();
+         stream != all_streams.end();
+         ++stream)
+      {
+         const STREAM_T stream_number = *stream;
+         FORCING_INFO stream_data;
+         stream_data.position = all_packets.begin();
+
+         // Insert an entry for this stream, starting at the beginning
+         stream_pos = stream_positions.insert(std::make_pair(stream_number, stream_data)).first;
+
+         // Then search for a packet in this stream.
+         next_in_stream(stream_pos);
+
+         stream_pos->second.info.track = stream_number;
+      }
+
+      // Repeat until explicit break when all have reached last packet
+      bool alldone = false;
+      while (!alldone)
+      {
+         // go through each stream in turn and get some data. At end of packet check it.
+         for (stream_pos = stream_positions.begin(); stream_pos != stream_positions.end(); ++stream_pos)
+         {
+            FORCING_INFO& stream_data = stream_pos->second;
+            if (stream_data.position == all_packets.end())
+            {
+               // This stream has reached the end of the expected packets. Force-read an info,
+               // to make sure it really is at the end.
+               status = vc_container_read(p_ctx, &stream_data.info,
+                  VC_CONTAINER_READ_FLAG_INFO | VC_CONTAINER_READ_FLAG_FORCE_TRACK);
+
+               if (status != VC_CONTAINER_ERROR_EOS)
+               {
+                  error_logger << "Reading from stream " << stream_pos->first
+                     << " after end gave error " << status << "instead of EOS" << std::ends;
+
+                  // Erase the buffer so we don't repeat the check. We'd just end up with loads of errors.
+                  stream_positions.erase(stream_pos);
+
+                  // Then reset the iterator, as that made it invalid.
+                  stream_pos = stream_positions.begin();
+               }
+            }
+            else
+            {
+               // This stream has not reached the end. Read some more, maybe check it.
+
+               // If we haven't read anything in yet
+               if (stream_data.info.size == 0)
+               {
+                  if (configuration.packet_buffer_size <= 0)
+                  {
+                     // if unspecified read whole packets.
+                     stream_data.info.buffer_size = stream_data.position->info.size;
+                  }
+                  else if (configuration.packet_buffer_size < 1.0)
+                  {
+                     // If a proportion work it out
+                     stream_data.info.buffer_size
+                        = (uint32_t)(configuration.packet_buffer_size * stream_data.position->info.size);
+
+                     if (stream_data.info.buffer_size < 1)
+                     {
+                        // but never less than 1 byte
+                        stream_data.info.buffer_size = 1;
+                     }
+                  }
+                  else
+                  {
+                     // Use the amount specified
+                     stream_data.info.buffer_size = (uint32_t)configuration.packet_buffer_size;
+                  }
+
+                  stream_data.new_packet();
+               }
+               else
+               {
+                  // We've already read part of the packet. Read some more.
+                  size_t read_so_far = stream_data.buffer.size();
+
+                  // expand the buffer to hold another lump of data
+                  stream_data.buffer.resize(read_so_far + stream_data.info.buffer_size);
+
+                  // point the read at the new part.
+                  stream_data.info.data = &stream_data.buffer[read_so_far];
+               }
+
+               // Read some data
+               status = vc_container_read(p_ctx, &stream_data.info, VC_CONTAINER_READ_FLAG_FORCE_TRACK);
+
+               stream_data.total_flags |= stream_data.info.flags;
+               // Save the PTS if we don't have one yet
+               if (stream_data.first_valid_pts < 0)
+               {
+                  stream_data.first_valid_pts = stream_data.info.pts;
+               }
+
+               // Ditto the DTS
+               if (stream_data.first_valid_dts < 0)
+               {
+                  stream_data.first_valid_dts = stream_data.info.dts;
+               }
+
+               // work out how much we have.
+               uint32_t total_read = (stream_data.info.data + stream_data.info.size) - &stream_data.buffer[0];
+
+               if (total_read > stream_data.position->info.size)
+               {
+                  // we've read more than a packet. That's an error.
+                  error_logger << "Read more data than expected from a packet - read " << total_read
+                     << " Expect " << stream_data.position->info.size;
+               }
+
+               if (total_read < stream_data.position->info.size)
+               {
+                  // more to read. Just go back around the loop.
+                  continue;
+               }
+
+               stream_data.info.size = total_read;
+
+               stream_data.crc = crc32buf(&stream_data.buffer[0], total_read);
+
+               stream_data.info.flags = stream_data.total_flags;
+               stream_data.info.pts = stream_data.first_valid_pts;
+               stream_data.info.dts = stream_data.first_valid_dts;
+
+               // Validate that the data is the data we found when we did the sequential reads.
+               std::string anyerror = compare_packets(*stream_data.position, stream_data);
+
+               if (!anyerror.empty())
+               {
+                  error_logger << "Incorrect data found at PTS " << stream_data.info.pts << anyerror << std::ends;
+               }
+
+               // Move to the next packet
+               ++stream_data.position;
+
+               // Then search until we get one for this stream, or end.
+               next_in_stream(stream_pos);
+
+               // Note we've read nothing of the new packet yet.
+               stream_data.info.size = 0;
+            }
+         }
+
+         // go through each stream in turn. If they have all reached the end we are complete.
+         for (alldone = true, stream_pos = stream_positions.begin(); alldone && stream_pos != stream_positions.end(); ++stream_pos)
+         {
+            if (stream_pos->second.position != all_packets.end())
+            {
+               // If any stream has not reached the end we have more to do
+               alldone = false;
+            }
+         }
+      }
+   }
+
+   // Helper for the above: Advance the supplied FORCING_INFO to the next packet in the stream
+   void next_in_stream(std::map<STREAM_T, FORCING_INFO>::iterator& pos)
+   {
+      // We're searching for this stream
+      const STREAM_T track = pos->first;
+
+      ALL_PACKETS_T::const_iterator& position = pos->second.position;
+
+      // Loop until no more packets, or found one for this stream
+      while ((position != all_packets.end())
+         && (position->info.track != track))
+      {
+         // advance this iterator to the next packet.
+         ++position;
+      }
+   };
+
+   // Compare two packets, and return a non-empty string if they don't match
+   std::string compare_packets(const PACKET_DATA_T& expected, const PACKET_DATA_T& actual)
+   {
+      std::ostringstream errors;
+
+      // Check the fields in the structure
+      if (expected.info.size != actual.info.size)
+      {
+         errors << "size mismatch. Expect " << expected.info.size << " actual " << actual.info.size << std::endl;
+      }
+
+      if (expected.info.frame_size != actual.info.frame_size)
+      {
+         errors << "frame_size mismatch. Expect " << expected.info.frame_size << " actual " << actual.info.frame_size << std::endl;
+      }
+
+      if (expected.info.pts != actual.info.pts)
+      {
+         errors << "pts mismatch. Expect " << expected.info.pts << " actual " << actual.info.pts << std::endl;
+      }
+
+      if (expected.info.dts != actual.info.dts)
+      {
+         errors << "dts mismatch. Expect " << expected.info.dts << " actual " << actual.info.dts << std::endl;
+      }
+
+      if (expected.info.track != actual.info.track)
+      {
+         errors << "track mismatch. Expect " << expected.info.track << " actual " << actual.info.track << std::endl;
+      }
+
+      if (expected.info.flags != actual.info.flags)
+      {
+         errors << "flags mismatch. Expect " << expected.info.flags << " actual " << actual.info.flags << std::endl;
+      }
+
+      // check the buffer. We won't bother if there isn't one in either - if the expected hasn't got one,
+      // it's probably because we hit our memory limit. If the actual hasn't, the there should be a size error.
+      for (size_t i = 0, err_count = 0; i < expected.buffer.size() && i < actual.buffer.size(); ++i)
+      {
+         if (expected.buffer[i] != actual.buffer[i])
+         {
+            errors << "Data mismatch at "
+               << std::setw(8) << std::hex << i
+               << std::setw(3) << (unsigned)expected.buffer[i]
+               << std::setw(3)<< (unsigned)actual.buffer[i] << std::endl;
+
+            if (++err_count > 20)
+            {
+               errors << "Too many errors to report" << std::endl;
+               break;
+            }
+         }
+      }
+
+      if (expected.crc != actual.crc)
+      {
+         errors << "CRC mismatch. Expect " << expected.crc << " actual " << actual.crc << std::endl;
+      }
+
+      // If there were errors put a new line on the front. This aids formatting.
+      const std::string& error_list = errors.str();
+
+      if (error_list.empty())
+      {
+         // There were no errors
+         return error_list;
+      }
+      else
+      {
+         return std::string("\n") + error_list;
+      }
+   }
+
+   void check_correct_seek(VC_CONTAINER_SEEK_FLAGS_T direction, PTS_T actual_pts, PTS_T target_pts)
+   {
+      if (status != VC_CONTAINER_SUCCESS)
+      {
+         error_logger << "Error " << status << " returned by seek" << std::ends;
+      }
+      if (direction)
+      {
+         if (actual_pts < target_pts)
+         {
+            // We shouldn't normally arrive at a time earlier than we requested.
+            // However there's a special case - when the time requested is after the last keyframe
+            PTS_T highest_pts_in_video = all_key_packets.at(video_stream).rbegin()->first;
+
+            if (actual_pts < highest_pts_in_video)
+            {
+               error_logger << "Incorrect forward seek. Should not be before "
+                  << target_pts << " but arrived at " << actual_pts << std::ends;
+            }
+         }
+      }
+      else
+      {
+         if (actual_pts > target_pts)
+         {
+            // We shouldn't normally arrive at a time later than we requested.
+            // However there's a special case - when the time requested is before the first keyframe in the file.
+            PTS_T lowest_pts_in_video = all_key_packets.at(video_stream).begin()->first;
+
+            if (actual_pts > lowest_pts_in_video)
+            {
+               error_logger << "Incorrect reverse seek. Should not be after "
+                  << target_pts << " but arrived at " << actual_pts << std::ends;
+            }
+         }
+      }
+   }
+
+   // Check whether a packet is close enough to the PTS supplied. Used after a seek.
+   void check_seek_tolerance(const PACKET_DATA_T& packet, PTS_T actual_pts)
+   {
+      // Check whether the time on the packet is reasonable - it ought to be close to the time achieved.
+      if (packet.info.track == video_stream)
+      {
+         if ((packet.info.pts + configuration.tolerance_video_early) < actual_pts)
+         {
+            error_logger << "Video stream seek location is bad " << actual_pts - packet.info.pts << "uS early" << std::ends;
+         }
+
+         if ((packet.info.pts - configuration.tolerance_video_late) > actual_pts)
+         {
+            // We shouldn't normally arrive at a time later than we requested.
+            // However there's a special case - when the time requested is before the first PTS in the file.
+            PTS_T lowest_pts_in_video = all_pts_packets.at(video_stream).begin()->first;
+
+            if (actual_pts > lowest_pts_in_video)
+            {
+               error_logger << "Video stream seek location is bad " <<  packet.info.pts - actual_pts << "uS late" << std::ends;
+            }
+         }
+      }
+      else
+      {
+         if ((packet.info.pts + configuration.tolerance_other_early) < actual_pts)
+         {
+            error_logger << "Non-video stream seek location is bad " << actual_pts - packet.info.pts << "uS early" << std::ends;
+         }
+
+         if ((packet.info.pts - configuration.tolerance_other_late) > actual_pts)
+         {
+            error_logger << "Non-video stream seek location is bad " <<  packet.info.pts - actual_pts << "uS late" << std::ends;
+         }
+      }
+   }
+
+   // Initialise a Congruential Random Number Generator from the file contents.
+   // Used rather than rand() for the complete control that this offers - this app
+   // should behave the same regardless of the platform and word size.
+   void init_crg()
+   {
+      if (all_packets.empty())
+      {
+         static const char* msg = "You must read some packets before initialising the RNG";
+         assert(!msg);
+         std::cerr << msg;
+         exit(1);
+      }
+
+      rng_value = 0;
+
+      // XOR all the CRCs together to act as a file-specific seed.
+      for (ALL_PACKETS_T::const_iterator packet = all_packets.begin(); packet != all_packets.end(); ++packet)
+      {
+         rng_value ^= packet->crc;
+      }
+   }
+
+   // Get a pseudo-random number.
+   uint32_t rand()
+   {
+      // Constants from "Numerical recipes in 'C'"
+      return rng_value = 1664525 * rng_value + 1013904223;
+   }
+
+   // configuration
+   const CONFIGURATION_T configuration;
+
+   // Error logger.
+   class ERROR_LOGGER_T error_logger;
+
+   // The status from the last call made
+   VC_CONTAINER_STATUS_T status;
+
+   // Pointer to the file being processed
+   VC_CONTAINER_T *p_ctx;
+
+   // All the packets in the file
+   ALL_PACKETS_T all_packets;
+
+   // All the streams
+   std::set<STREAM_T> all_streams;
+
+   // All the streams and all the packets in them with a PTS, whether or not they are keyframes.
+   STREAM_TIMED_PACKETS_T all_pts_packets;
+
+   // Subset of the above that hold key frames.
+   STREAM_TIMED_PACKETS_T all_key_packets;
+
+   // Places where a seek without VC_CONTAINER_SEEK_FLAG_FORWARD can go to. A subset of all_key_packets.
+   STREAM_TIMED_PACKETS_T reverse_index_positions;
+
+   // Places where a seek with VC_CONTAINER_SEEK_FLAG_FORWARD can go to.
+   STREAM_TIMED_PACKETS_T forward_index_positions;
+
+   // The first stream containing video packets
+   STREAM_T video_stream;
+
+   // The stored value of the RNG
+   uint32_t rng_value;
+};
+
+int main(int argc, char** argv)
+{
+   // Read and parse the configuration information from the command line.
+   TESTER_T test(argc, argv);
+
+   // Run the tests and return their error code
+   return test.run();
+}
diff --git a/containers/test/check_frame_int.c b/containers/test/check_frame_int.c
new file mode 100755 (executable)
index 0000000..1819c47
--- /dev/null
@@ -0,0 +1,348 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include "containers/containers.h"
+#include "containers/core/containers_common.h"
+#include "containers/core/containers_logging.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_io.h"
+
+#define BUFFER_SIZE 256*1024
+#define MAX_TRACKS 16
+#define MAX_SEEKS 16
+
+static int container_test_info(VC_CONTAINER_T *ctx, bool b_reader);
+static int container_test_parse_cmdline(int argc, char **argv);
+
+static const char *psz_in = 0;
+static long packets_num = 0;
+static long track_num = -1;
+static int fps = 30;
+static int margin = 5; // margin for frame interval, percent
+
+static struct
+{
+   uint32_t mapping;
+   uint32_t frames;
+   uint32_t packets;
+   uint64_t bytes;
+   uint32_t frame_size;
+   int64_t first_dts;
+   int64_t first_pts;
+   int64_t last_dts;
+   int64_t last_pts;
+} tracks[MAX_TRACKS];
+
+static int32_t verbosity = VC_CONTAINER_LOG_ERROR|VC_CONTAINER_LOG_INFO;
+
+/*****************************************************************************/
+int main(int argc, char **argv)
+{
+   int retval = 0;
+   VC_CONTAINER_T *p_ctx = 0;
+   VC_CONTAINER_STATUS_T status;
+   unsigned int i;
+   uint8_t *buffer = malloc(BUFFER_SIZE);
+   int32_t interval;
+   int64_t last_packet_pts = -1;
+   int32_t max_interval = 0, max_interval_after_first = 0;
+   int fail = 0;
+
+   if(container_test_parse_cmdline(argc, argv))
+      goto error_silent;
+
+   LOG_INFO (0, "Require that no frame interval greater than 1/%d seconds (%d%% margin)", fps, margin);
+
+   /* Set the general verbosity */
+   vc_container_log_set_verbosity(0, verbosity);
+   vc_container_log_set_default_verbosity(verbosity);
+
+   p_ctx = vc_container_open_reader(psz_in, &status, 0, 0);
+
+   if(!p_ctx)
+   {
+     LOG_ERROR(0, "error opening file %s (%i)", psz_in, status);
+     goto error;
+   }
+
+   if (verbosity & VC_CONTAINER_LOG_DEBUG)
+   {
+      container_test_info(p_ctx, true);
+   }
+   LOG_INFO (0, "Search for video track only");
+
+   /* Disabling tracks which are not requested and enable packetisation if requested */
+   for(i = 0; i < p_ctx->tracks_num; i++)
+   {
+      VC_CONTAINER_TRACK_T *track = p_ctx->tracks[i];
+      track->is_enabled =  (track->format->es_type == VC_CONTAINER_ES_TYPE_VIDEO);
+   }
+
+
+   LOG_DEBUG(0, "TEST start reading");
+   for(i = 0; !packets_num || (long)i < packets_num; i++)
+   {
+      VC_CONTAINER_PACKET_T packet = {0};
+      int32_t frame_num = 0;
+
+      status = vc_container_read(p_ctx, &packet, VC_CONTAINER_READ_FLAG_INFO);
+      if(status != VC_CONTAINER_SUCCESS) {LOG_DEBUG(0, "TEST info status: %i", status); break;}
+
+      if(packet.track < MAX_TRACKS)
+      {
+         if((packet.flags & VC_CONTAINER_PACKET_FLAG_FRAME_START))
+         {
+            tracks[packet.track].frames++;
+            tracks[packet.track].frame_size = 0;
+         }
+         frame_num = tracks[packet.track].frames;
+      }
+
+      tracks[packet.track].frame_size += packet.size;
+
+//      LOG_DEBUG(0, "packet info: track %i, size %i/%i/%i, pts %"PRId64", flags %x%s, num %i",
+//                packet.track, packet.size, packet.frame_size, tracks[packet.track].frame_size, packet.pts, packet.flags,
+//                (packet.flags & VC_CONTAINER_PACKET_FLAG_KEYFRAME) ? " (keyframe)" : "",
+//                frame_num-1);
+
+      if (last_packet_pts != -1)
+         interval = packet.pts - last_packet_pts;
+      else
+         interval = 0; // packet.pts;
+      last_packet_pts = packet.pts;
+      max_interval = MAX (max_interval, interval);
+      if (i >= 2)
+         max_interval_after_first = MAX (max_interval_after_first, interval);
+
+      /* Check if interval (in us) exceeds 1/fps, with percentage margin */
+      if (interval * fps > 1e4 * (100+margin))
+      {
+         LOG_INFO (0, "Frame %d, interval %.3f FAILED", i, interval / 1000.0f);
+         fail = 1;
+      }
+
+      LOG_DEBUG (0, "Frame %d, interval %.3f", i, interval / 1000.0f);
+
+      if(track_num >= 0 && packet.track != (uint32_t)track_num)
+      {
+         status = vc_container_read(p_ctx, 0, VC_CONTAINER_READ_FLAG_SKIP);
+         if(status != VC_CONTAINER_SUCCESS) {LOG_DEBUG(0, "TEST skip status: %i", status); break;}
+         continue;
+      }
+
+      packet.buffer_size = BUFFER_SIZE;
+      packet.data = buffer;
+      packet.size = 0;
+      status = vc_container_read(p_ctx, &packet, 0);
+      if(status != VC_CONTAINER_SUCCESS) {LOG_DEBUG(0, "TEST read status: %i", status); break;}
+
+      //      LOG_DEBUG(0, "packet: track %i, size %i, pts %"PRId64", flags %x", packet.track, packet.size, packet.pts, packet.flags);
+
+      if (tracks[packet.track].packets)
+      {
+         tracks[packet.track].last_dts = packet.dts;
+         tracks[packet.track].last_pts = packet.pts;
+      } else {
+         tracks[packet.track].first_dts = packet.dts;
+         tracks[packet.track].first_pts = packet.pts;
+      }
+
+      if(packet.track < MAX_TRACKS)
+      {
+         tracks[packet.track].packets++;
+         tracks[packet.track].bytes += packet.size;
+      }
+
+   }
+   LOG_DEBUG(0, "TEST stop reading");
+
+   /* Output stats */
+   for(i = 0; i < p_ctx->tracks_num; i++)
+   {
+      LOG_INFO(0, "track %u: read %u samples in %u packets for a total of %"PRIu64" bytes",
+               i, tracks[i].frames, tracks[i].packets, tracks[i].bytes);
+      LOG_INFO(0, "Starting at %"PRId64"us (decode at %"PRId64"us), ending at %"PRId64"us (decode at %"PRId64"us)",
+               tracks[i].first_pts, tracks[i].first_dts, tracks[i].last_pts, tracks[i].last_dts);
+   }
+
+   LOG_INFO (0, "---\nMax interval = %.3f ms; max interval (after first) = %.3f ms\n", (float) max_interval / 1000.0, (float) max_interval_after_first / 1000.0);
+
+ end:
+   if(p_ctx) vc_container_close(p_ctx);
+   free(buffer);
+
+#ifdef _MSC_VER
+   getchar();
+#endif
+
+   retval = fail;
+   if (fail)
+   {
+      LOG_INFO (0, "TEST FAILED: highest frame interval = %.3f ms", max_interval / 1000.0f);
+   }
+   else
+      LOG_INFO (0, "TEST PASSED");
+   return retval;
+
+ error:
+   LOG_ERROR(0, "TEST FAILED TO RUN");
+ error_silent:
+   retval = -1;
+   goto end;
+}
+
+static int container_test_parse_cmdline(int argc, char **argv)
+{
+   int i, j, k;
+   int32_t *p_verbosity;
+
+   /* Parse the command line arguments */
+   for(i = 1; i < argc; i++)
+   {
+      if(!argv[i]) continue;
+
+      if(argv[i][0] != '-')
+      {
+         /* Not an option argument so will be the input URI */
+         psz_in = argv[i];
+         continue;
+      }
+
+      /* We are now dealing with command line options */
+      switch(argv[i][1])
+      {
+      case 'v':
+         j = 2;
+         p_verbosity = &verbosity;
+         *p_verbosity = VC_CONTAINER_LOG_ERROR|VC_CONTAINER_LOG_INFO;
+         for(k = 0; k < 2 && argv[i][j+k] == 'v'; k++)
+            *p_verbosity = (*p_verbosity << 1) | 1 ;
+         break;
+      case 'f':
+         if(i+1 == argc || !argv[i+1]) goto invalid_option;
+         fps = strtol(argv[++i], 0, 0);
+         break;
+      case 'h': goto usage;
+      default: goto invalid_option;
+      }
+      continue;
+   }
+
+   /* Sanity check that we have at least an input uri */
+   if(!psz_in)
+   {
+     LOG_ERROR(0, "missing uri argument");
+     goto usage;
+   }
+
+   return 0;
+
+ invalid_option:
+   LOG_ERROR(0, "invalid command line option (%s)", argv[i]);
+
+ usage:
+   psz_in = strrchr(argv[0], '\\'); if(psz_in) psz_in++;
+   if(!psz_in) {psz_in = strrchr(argv[0], '/'); if(psz_in) psz_in++;}
+   if(!psz_in) psz_in = argv[0];
+   LOG_INFO(0, "");
+   LOG_INFO(0, "usage: %s [options] uri", psz_in);
+   LOG_INFO(0, "options list:");
+   LOG_INFO(0, " -vxx  : general verbosity level (replace xx with a number of \'v\')");
+   LOG_INFO(0, " -f    : required frame rate/second (frame interval must not exceed 1/f)");
+   LOG_INFO(0, " -h    : help");
+   return 1;
+}
+
+static int container_test_info(VC_CONTAINER_T *ctx, bool b_reader)
+{
+   const char *name_type;
+   unsigned int i;
+
+   LOG_INFO(0, "");
+   if(b_reader) LOG_INFO(0, "----Reader Information----");
+   else LOG_INFO(0, "----Writer Information----");
+
+   LOG_INFO(0, "duration: %2.2fs, size: %"PRId64, ctx->duration/1000000.0, ctx->size);
+   LOG_INFO(0, "capabilities: %x", ctx->capabilities);
+   LOG_INFO(0, "");
+
+   for(i = 0; i < ctx->tracks_num; i++)
+   {
+      VC_CONTAINER_TRACK_T *track = ctx->tracks[i];
+
+      switch(track->format->es_type)
+      {
+      case VC_CONTAINER_ES_TYPE_AUDIO: name_type = "audio"; break;
+      case VC_CONTAINER_ES_TYPE_VIDEO: name_type = "video"; break;
+      case VC_CONTAINER_ES_TYPE_SUBPICTURE: name_type = "subpicture"; break;
+      default: name_type = "unknown"; break;
+      }
+
+      if (!strcmp (name_type, "video"))
+      {
+         LOG_INFO(0, "track: %i, type: %s, fourcc: %4.4s", i, name_type, (char *)&track->format->codec);
+         LOG_INFO(0, " bitrate: %i, framed: %i, enabled: %i", track->format->bitrate,
+                  !!(track->format->flags & VC_CONTAINER_ES_FORMAT_FLAG_FRAMED), track->is_enabled);
+         LOG_INFO(0, " extra data: %i, %p", track->format->extradata_size, track->format->extradata);
+         switch(track->format->es_type)
+         {
+         case VC_CONTAINER_ES_TYPE_VIDEO:
+            LOG_INFO(0, " width: %i, height: %i, (%i,%i,%i,%i)",
+                     track->format->type->video.width, track->format->type->video.height,
+                     track->format->type->video.x_offset, track->format->type->video.y_offset,
+                     track->format->type->video.visible_width, track->format->type->video.visible_height);
+            LOG_INFO(0, " pixel aspect ratio: %i/%i, frame rate: %i/%i",
+                     track->format->type->video.par_num, track->format->type->video.par_den,
+                     track->format->type->video.frame_rate_num, track->format->type->video.frame_rate_den);
+            break;
+
+         default: break;
+         }
+      }
+   }
+
+   for (i = 0; i < ctx->meta_num; ++i)
+   {
+      const char *name, *value;
+      if (i == 0) LOG_INFO(0, "");
+      name = vc_container_metadata_id_to_string(ctx->meta[i]->key);
+      value = ctx->meta[i]->value;
+      if(!name) continue;
+      LOG_INFO(0, "metadata(%i) : %s : %s", i, name, value);
+   }
+
+   LOG_INFO(0, "--------------------------");
+   LOG_INFO(0, "");
+
+   return 0;
+}
+
+
diff --git a/containers/test/crc_32.c b/containers/test/crc_32.c
new file mode 100755 (executable)
index 0000000..1d2dbaa
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+
+#include <stdint.h>
+
+#ifndef Boolean_T
+typedef unsigned Boolean_T;
+#endif
+#ifndef Error_
+#define Error_ 1
+#endif
+
+#ifndef Success_
+#define Success_ 0
+#endif
+
+#define UPDC32(octet,crc) (crc_32_tab[((crc)\
+     ^ ((uint8_t)octet)) & 0xff] ^ ((crc) >> 8))
+
+#ifdef __TURBOC__
+ #pragma warn -cln
+#endif
+
+/**********************************************************************\
+|* Demonstration program to compute the 32-bit CRC used as the frame  *|
+|* check sequence in ADCCP (ANSI X3.66, also known as FIPS PUB 71     *|
+|* and FED-STD-1003, the U.S. versions of CCITT's X.25 link-level     *|
+|* protocol).  The 32-bit FCS was added via the Federal Register,     *|
+|* 1 June 1982, p.23798.  I presume but don't know for certain that   *|
+|* this polynomial is or will be included in CCITT V.41, which        *|
+|* defines the 16-bit CRC (often called CRC-CCITT) polynomial.  FIPS  *|
+|* PUB 78 says that the 32-bit FCS reduces otherwise undetected       *|
+|* errors by a factor of 10^-5 over 16-bit FCS.                       *|
+\**********************************************************************/
+
+/* Need an unsigned type capable of holding 32 bits; */
+
+typedef uint32_t UNS_32_BITS;
+
+/* Copyright (C) 1986 Gary S. Brown.  You may use this program, or
+   code or tables extracted from it, as desired without restriction.*/
+
+/* First, the polynomial itself and its table of feedback terms.  The  */
+/* polynomial is                                                       */
+/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */
+/* Note that we take it "backwards" and put the highest-order term in  */
+/* the lowest-order bit.  The X^32 term is "implied"; the LSB is the   */
+/* X^31 term, etc.  The X^0 term (usually shown as "+1") results in    */
+/* the MSB being 1.                                                    */
+
+/* Note that the usual hardware shift register implementation, which   */
+/* is what we're using (we're merely optimizing it by doing eight-bit  */
+/* chunks at a time) shifts bits into the lowest-order term.  In our   */
+/* implementation, that means shifting towards the right.  Why do we   */
+/* do it this way?  Because the calculated CRC must be transmitted in  */
+/* order from highest-order term to lowest-order term.  UARTs transmit */
+/* characters in order from LSB to MSB.  By storing the CRC this way,  */
+/* we hand it to the UART in the order low-byte to high-byte; the UART */
+/* sends each low-bit to hight-bit; and the result is transmission bit */
+/* by bit from highest- to lowest-order term without requiring any bit */
+/* shuffling on our part.  Reception works similarly.                  */
+
+/* The feedback terms table consists of 256, 32-bit entries.  Notes:   */
+/*                                                                     */
+/*  1. The table can be generated at runtime if desired; code to do so */
+/*     is shown later.  It might not be obvious, but the feedback      */
+/*     terms simply represent the results of eight shift/xor opera-    */
+/*     tions for all combinations of data and CRC register values.     */
+/*                                                                     */
+/*  2. The CRC accumulation logic is the same for all CRC polynomials, */
+/*     be they sixteen or thirty-two bits wide.  You simply choose the */
+/*     appropriate table.  Alternatively, because the table can be     */
+/*     generated at runtime, you can start by generating the table for */
+/*     the polynomial in question and use exactly the same "updcrc",   */
+/*     if your application needn't simultaneously handle two CRC       */
+/*     polynomials.  (Note, however, that XMODEM is strange.)          */
+/*                                                                     */
+/*  3. For 16-bit CRCs, the table entries need be only 16 bits wide;   */
+/*     of course, 32-bit entries work OK if the high 16 bits are zero. */
+/*                                                                     */
+/*  4. The values must be right-shifted by eight bits by the "updcrc"  */
+/*     logic; the shift must be unsigned (bring in zeroes).  On some   */
+/*     hardware you could probably optimize the shift in assembler by  */
+/*     using byte-swap instructions.                                   */
+
+static UNS_32_BITS crc_32_tab[] = { /* CRC polynomial 0xedb88320 */
+0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
+0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
+0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
+0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
+0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
+0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
+0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
+0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
+0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
+0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
+0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
+0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
+0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
+0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
+0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
+0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
+0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
+0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
+};
+
+uint32_t updateCRC32(unsigned char ch, uint32_t crc)
+{
+      return UPDC32(ch, crc);
+}
+
+Boolean_T crc32file(char *name, uint32_t *crc, long *charcnt)
+{
+      register FILE *fin;
+      register uint32_t oldcrc32;
+      register int c;
+
+      oldcrc32 = 0xFFFFFFFF; *charcnt = 0;
+#ifdef MSDOS
+      if ((fin=fopen(name, "rb"))==NULL)
+#else
+      if ((fin=fopen(name, "r"))==NULL)
+#endif
+      {
+            perror(name);
+            return Error_;
+      }
+      while ((c=getc(fin))!=EOF)
+      {
+            ++*charcnt;
+            oldcrc32 = UPDC32(c, oldcrc32);
+      }
+
+      if (ferror(fin))
+      {
+            perror(name);
+            *charcnt = -1;
+      }
+      fclose(fin);
+
+      *crc = oldcrc32 = ~oldcrc32;
+
+      return Success_;
+}
+
+uint32_t crc32buf(const uint8_t *buf, size_t len)
+{
+      register uint32_t oldcrc32;
+
+      oldcrc32 = 0xFFFFFFFF;
+
+      for ( ; len; --len, ++buf)
+      {
+            oldcrc32 = UPDC32(*buf, oldcrc32);
+      }
+
+      return ~oldcrc32;
+}
+
+#ifdef TEST
+
+main(int argc, char *argv[])
+{
+      uint32_t crc;
+      long charcnt;
+      register errors = 0;
+
+      while(--argc > 0)
+      {
+            errors |= crc32file(*++argv, &crc, &charcnt);
+            printf("%08lX %7ld %s\n", crc, charcnt, *argv);
+      }
+      return(errors != 0);
+}
+
+#endif /* TEST */
diff --git a/containers/test/datagram_receiver.c b/containers/test/datagram_receiver.c
new file mode 100755 (executable)
index 0000000..30d661f
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "containers/net/net_sockets.h"
+
+int main(int argc, char **argv)
+{
+   VC_CONTAINER_NET_T *sock;
+   vc_container_net_status_t status;
+   char *buffer;
+   size_t buffer_size;
+   size_t received;
+
+   if (argc < 2)
+   {
+      printf("Usage:\n%s <port>\n", argv[0]);
+      return 1;
+   }
+
+   sock = vc_container_net_open(NULL, argv[1], 0, &status);
+   if (!sock)
+   {
+      printf("vc_container_net_open failed: %d\n", status);
+      return 2;
+   }
+
+   buffer_size = vc_container_net_maximum_datagram_size(sock);
+   buffer = (char *)malloc(buffer_size);
+   if (!buffer)
+   {
+      vc_container_net_close(sock);
+      printf("Failure allocating buffer\n");
+      return 3;
+   }
+
+   while ((received = vc_container_net_read(sock, buffer, buffer_size)) != 0)
+   {
+      char *ptr = buffer;
+
+      while (received--)
+         putchar(*ptr++);
+   }
+
+   if (vc_container_net_status(sock) != VC_CONTAINER_NET_SUCCESS)
+   {
+      printf("vc_container_net_read failed: %d\n", vc_container_net_status(sock));
+   }
+
+   vc_container_net_close(sock);
+
+   return 0;
+}
diff --git a/containers/test/datagram_sender.c b/containers/test/datagram_sender.c
new file mode 100755 (executable)
index 0000000..6ed7b15
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "containers/net/net_sockets.h"
+
+int main(int argc, char **argv)
+{
+   VC_CONTAINER_NET_T *sock;
+   vc_container_net_status_t status;
+   char *buffer;
+   size_t buffer_size;
+
+   if (argc < 3)
+   {
+      printf("Usage:\n%s <address> <port>\n", argv[0]);
+      return 1;
+   }
+
+   sock = vc_container_net_open(argv[1], argv[2], 0, &status);
+   if (!sock)
+   {
+      printf("vc_container_net_open failed: %d\n", status);
+      return 2;
+   }
+
+   buffer_size = vc_container_net_maximum_datagram_size(sock);
+   buffer = (char *)malloc(buffer_size);
+   if (!buffer)
+   {
+      vc_container_net_close(sock);
+      printf("Failure allocating buffer\n");
+      return 3;
+   }
+
+   printf("Don't enter more than %d characters in one line!\n", (int)buffer_size);
+
+   while (fgets(buffer, buffer_size, stdin))
+   {
+      if (!vc_container_net_write(sock, buffer, strlen(buffer)))
+      {
+         printf("vc_container_net_write failed: %d\n", vc_container_net_status(sock));
+         break;
+      }
+   }
+
+   vc_container_net_close(sock);
+
+   return 0;
+}
diff --git a/containers/test/dump_pktfile.c b/containers/test/dump_pktfile.c
new file mode 100755 (executable)
index 0000000..eddf197
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#define PACKET_BUFFER_SIZE    32768
+
+enum {
+   SUCCESS = 0,
+   SHOWED_USAGE,
+   FAILED_TO_OPEN_PKTFILE,
+   FAILED_TO_OPEN_OUTPUT_FILE,
+   BYTE_ORDER_MARK_MISSING,
+   INVALID_BYTE_ORDER_MARK,
+   MEMORY_ALLOCATION_FAILURE,
+   PACKET_TOO_BIG,
+};
+
+/** Native byte order word */
+#define NATIVE_BYTE_ORDER  0x50415753U
+/** Reverse of native byte order - need to swap bytes around */
+#define SWAP_BYTE_ORDER    0x53574150U
+
+static unsigned long reverse_byte_order( unsigned long value )
+{
+   /* Reverse the order of the bytes in the word */
+   return ((value << 24) | ((value & 0xFF00) << 8) | ((value >> 8) & 0xFF00) | (value >> 24));
+}
+
+int main(int argc, char **argv)
+{
+   int status = SUCCESS;
+   FILE *pktfile = NULL, *output_file = NULL;
+   uint32_t byte_order, packet_size, packet_read;
+   char *buffer = NULL;
+
+   if (argc < 2)
+   {
+      printf("\
+Usage:\n\
+  %s <pkt file> [<output file>]\n\
+<pkt file> is the file to read.\n\
+<output file>, if given, will receive the unpacketized data.\n", argv[0]);
+      status = SHOWED_USAGE;
+      goto end_program;
+   }
+
+   pktfile = fopen(argv[1], "rb");
+   if (!pktfile)
+   {
+      printf("Failed to open pkt file <%s> for reading.\n", argv[1]);
+      status = FAILED_TO_OPEN_PKTFILE;
+      goto end_program;
+   }
+
+   if (fread(&byte_order, 1, sizeof(byte_order), pktfile) != sizeof(byte_order))
+   {
+      printf("Failed to read byte order header from pkt file.\n");
+      status = BYTE_ORDER_MARK_MISSING;
+      goto end_program;
+   }
+
+   if (byte_order != NATIVE_BYTE_ORDER && byte_order != SWAP_BYTE_ORDER)
+   {
+      printf("Invalid byte order header: 0x%08x (%u)\n", byte_order, byte_order);
+      status = INVALID_BYTE_ORDER_MARK;
+      goto end_program;
+   }
+
+   buffer = (char *)malloc(PACKET_BUFFER_SIZE);
+   if (!buffer)
+   {
+      printf("Memory allocation failed\n");
+      status = MEMORY_ALLOCATION_FAILURE;
+      goto end_program;
+   }
+
+   if (argc > 2)
+   {
+      output_file = fopen(argv[2], "wb");
+      if (!output_file)
+      {
+         printf("Failed to open <%s> for output.\n", argv[2]);
+         status = FAILED_TO_OPEN_OUTPUT_FILE;
+         goto end_program;
+      }
+   }
+
+   while (fread(&packet_size, 1, sizeof(packet_size), pktfile) == sizeof(packet_size))
+   {
+      if (byte_order == SWAP_BYTE_ORDER)
+         packet_size = reverse_byte_order(packet_size);
+
+      if (packet_size >= PACKET_BUFFER_SIZE)
+      {
+         printf("*** Packet size is bigger than buffer (%u > %u)\n", packet_size, PACKET_BUFFER_SIZE - 1);
+         status = PACKET_TOO_BIG;
+         goto end_program;
+      }
+
+      packet_read = fread(buffer, 1, packet_size, pktfile);
+
+      if (output_file)
+      {
+         fwrite(buffer, 1, packet_size, output_file);
+      } else {
+         buffer[packet_size] = '\0';
+         printf("%s", buffer);
+         getchar();
+      }
+
+      if (packet_read != packet_size)
+         printf("*** Invalid packet size (expected %u, got %u)\n", packet_size, packet_read);
+   }
+
+end_program:
+   if (pktfile) fclose(pktfile);
+   if (output_file) fclose(output_file);
+   if (buffer) free(buffer);
+   return -status;
+}
diff --git a/containers/test/nb_io.h b/containers/test/nb_io.h
new file mode 100755 (executable)
index 0000000..2058fe6
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _NB_IO_H_
+#define _NB_IO_H_
+
+/** Set whether console input is non-blocking or not.
+ *
+ * \param enable Pass true to set input as non-blocking, false to set it as blocking again.*/
+void nb_set_nonblocking_input(int enable);
+
+/** \return Non-zero when there is a character available to read using nb_get_char(). */
+int nb_char_available(void);
+
+/** \return The next character available from the console, or zero. */
+char nb_get_char(void);
+
+/** Put the character out to the console.
+ *
+ * \param ch The character to be output. */
+void nb_put_char(char ch);
+
+#endif /* _NB_IO_H_ */
diff --git a/containers/test/nb_io_unix.c b/containers/test/nb_io_unix.c
new file mode 100755 (executable)
index 0000000..63e1a1f
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <termios.h>
+
+#include "nb_io.h"
+
+void nb_set_nonblocking_input(int enable)
+{
+   struct termios ttystate;
+
+    //get the terminal state
+    tcgetattr(STDIN_FILENO, &ttystate);
+
+    if (enable)
+    {
+        //turn off canonical mode
+        ttystate.c_lflag &= ~ICANON;
+        //minimum of number input read.
+        ttystate.c_cc[VMIN] = 1;
+    }
+    else
+    {
+        //turn on canonical mode
+        ttystate.c_lflag |= ICANON;
+    }
+
+    //set the terminal attributes.
+    tcsetattr(STDIN_FILENO, TCSANOW, &ttystate);
+}
+
+int nb_char_available(void)
+{
+  struct timeval tv;
+  fd_set fds;
+  tv.tv_sec = 0;
+  tv.tv_usec = 0;
+  FD_ZERO(&fds);
+  FD_SET(STDIN_FILENO, &fds);
+  select(STDIN_FILENO+1, &fds, NULL, NULL, &tv);
+  return (FD_ISSET(0, &fds));
+}
+
+char nb_get_char(void)
+{
+   return getchar();
+}
+
+void nb_put_char(char ch)
+{
+   putchar(ch);
+}
diff --git a/containers/test/nb_io_win32.c b/containers/test/nb_io_win32.c
new file mode 100755 (executable)
index 0000000..a402bcb
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <conio.h>   /* For _kbhit() */
+
+#include "nb_io.h"
+
+void nb_set_nonblocking_input(int enable)
+{
+   /* No need to do anything in Win32 */
+   (void)enable;
+}
+
+int nb_char_available()
+{
+   return _kbhit();
+}
+
+char nb_get_char()
+{
+   char c = _getch();
+   _putch(c);   /* Echo back */
+   return c;
+}
+
+void nb_put_char(char ch)
+{
+   _putch(ch);
+}
diff --git a/containers/test/rtp_decoder.c b/containers/test/rtp_decoder.c
new file mode 100755 (executable)
index 0000000..c089576
--- /dev/null
@@ -0,0 +1,449 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "containers/containers.h"
+#include "containers/core/containers_logging.h"
+#include "containers/core/containers_io.h"
+
+#include "nb_io.h"
+
+#define MAXIMUM_BUFFER_SIZE   65000
+#define MINIMUM_BUFFER_SPACE  1500
+
+#define INITIAL_READ_BUFFER_SIZE 8000
+#define MAXIMUM_READ_BUFFER_SIZE 64000
+
+#define BYTES_PER_ROW   32
+
+#define HAS_PADDING        0x20
+#define HAS_EXTENSION      0x10
+#define CSRC_COUNT_MASK    0x0F
+
+#define HAS_MARKER         0x80
+#define PAYLOAD_TYPE_MASK  0x7F
+
+#define EXTENSION_LENGTH_MASK 0x0000FFFF
+#define EXTENSION_ID_SHIFT 16
+
+#define LOWEST_VERBOSITY         1
+#define BASIC_HEADER_VERBOSITY   2
+#define FULL_HEADER_VERBOSITY    3
+#define FULL_PACKET_VERBOSITY    4
+
+#define ESCAPE_CHARACTER   0x1B
+
+static bool seen_first_packet;
+static uint16_t expected_next_seq_num;
+
+static bool do_print_usage;
+static uint32_t verbosity;
+static const char *read_uri;
+static const char *packet_save_file;
+static bool packet_save_is_pktfile;
+
+static uint16_t network_to_host_16(const uint8_t *buffer)
+{
+   return (buffer[0] << 8) | buffer[1];
+}
+
+static uint32_t network_to_host_32(const uint8_t *buffer)
+{
+   return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
+}
+
+/** Avoid alignment problems when writing a word value to the buffer */
+static void store_u32(uint8_t *buffer, uint32_t value)
+{
+   buffer[0] = (uint8_t)value;
+   buffer[1] = (uint8_t)(value >> 8);
+   buffer[2] = (uint8_t)(value >> 16);
+   buffer[3] = (uint8_t)(value >> 24);
+}
+
+/** Avoid alignment problems when reading a word value from the buffer */
+static uint32_t fetch_u32(uint8_t *buffer)
+{
+   return (buffer[3] << 24) | (buffer[2] << 16) | (buffer[1] << 8) | buffer[0];
+}
+
+static bool marker_bit_set(const uint8_t *buffer, size_t buffer_len)
+{
+   if (buffer_len < 2)
+      return false;
+
+   return (buffer[1] & HAS_MARKER);
+}
+
+static void dump_bytes(const uint8_t *buffer, size_t buffer_len)
+{
+   char dump_str[3 * BYTES_PER_ROW + 1];
+   int in_row = 0;
+
+   while (buffer_len--)
+   {
+      sprintf(dump_str + 3 * in_row, "%2.2X ", *buffer++);
+      if (++in_row == BYTES_PER_ROW)
+      {
+         LOG_INFO(NULL, dump_str);
+         in_row = 0;
+      }
+   }
+   
+   if (in_row)
+   {
+      LOG_INFO(NULL, dump_str);
+   }
+}
+
+static bool decode_packet(const uint8_t *buffer, size_t buffer_len)
+{
+   uint8_t flags;
+   uint8_t payload_type;
+   uint16_t seq_num;
+   uint32_t timestamp;
+   uint32_t ssrc;
+   uint32_t csrc_count;
+   
+   if (buffer_len < 12)
+   {
+      LOG_ERROR(NULL, "Packet too small: basic header missing");
+      return false;
+   }
+   
+   flags = buffer[0];
+   payload_type = buffer[1];
+   seq_num = network_to_host_16(buffer + 2);
+   timestamp = network_to_host_32(buffer + 4);
+   ssrc = network_to_host_32(buffer + 8);
+
+   if (seen_first_packet && seq_num != expected_next_seq_num)
+   {
+      int16_t missing_packets = seq_num - expected_next_seq_num;
+
+      LOG_INFO(NULL, "*** Sequence break, expected %hu, got %hu ***", expected_next_seq_num, seq_num);
+      if (missing_packets > 0)
+         LOG_INFO(NULL, "*** Jumped forward %hd packets ***", missing_packets);
+      else
+         LOG_INFO(NULL, "*** Jumped backward %hd packets ***", -missing_packets);
+   }
+   seen_first_packet = true;
+   expected_next_seq_num = seq_num + 1;
+
+   /* Dump the basic header information */
+   if (verbosity >= BASIC_HEADER_VERBOSITY)
+   {
+      LOG_INFO(NULL, "Version: %d\nPayload type: %d%s\nSequence: %d\nTimestamp: %u\nSSRC: 0x%8.8X",
+            flags >> 6, payload_type & PAYLOAD_TYPE_MASK,
+            (const char *)((payload_type & HAS_MARKER) ? " (M)" : ""),
+            seq_num, timestamp, ssrc);
+   }
+
+   buffer += 12;
+   buffer_len -= 12;
+
+   if (verbosity >= FULL_HEADER_VERBOSITY)
+   {
+      /* Dump the CSRCs, if any */
+      csrc_count = flags & CSRC_COUNT_MASK;
+      if (csrc_count)
+      {
+         uint32_t ii;
+      
+         if (buffer_len < (csrc_count * 4))
+         {
+            LOG_ERROR(NULL, "Packet too small: CSRCs missing");
+            return false;
+         }
+
+         LOG_INFO(NULL, "CSRCs:");
+         for (ii = 0; ii < csrc_count; ii++)
+         {
+            LOG_INFO(NULL, " 0x%8.8X", network_to_host_32(buffer));
+            buffer += 4;
+            buffer_len -= 4;
+         }
+      }
+
+      /* Dump any extension, if present */
+      if (flags & HAS_EXTENSION)
+      {
+         uint32_t extension_hdr;
+         uint32_t extension_id;
+         size_t extension_len;
+
+         if (buffer_len < 4)
+         {
+            LOG_ERROR(NULL, "Packet too small: extension header missing");
+            return false;
+         }
+      
+         extension_hdr = network_to_host_32(buffer);
+         buffer += 4;
+         buffer_len -= 4;
+      
+         extension_len = (size_t)(extension_hdr & EXTENSION_LENGTH_MASK);
+         extension_id = extension_hdr >> EXTENSION_ID_SHIFT;
+      
+         if (buffer_len < extension_len)
+         {
+            LOG_ERROR(NULL, "Packet too small: extension content missing");
+            return false;
+         }
+      
+         LOG_INFO(NULL, "Extension: 0x%4.4X (%u bytes)", extension_id, (unsigned)extension_len);
+         dump_bytes(buffer, extension_len);
+         buffer += extension_len;
+         buffer_len -= extension_len;
+      }
+   }
+
+   /* And finally the payload data */
+   if (verbosity >= FULL_PACKET_VERBOSITY)
+   {
+      LOG_INFO(NULL, "Data: (%u bytes)", (unsigned)buffer_len);
+      dump_bytes(buffer, buffer_len);
+   }
+
+   return true;
+}
+
+static void increase_read_buffer_size(VC_CONTAINER_IO_T *p_ctx)
+{
+   uint32_t buffer_size = INITIAL_READ_BUFFER_SIZE;
+
+   /* Iteratively enlarge read buffer until either operation fails or maximum is reached. */
+   while (vc_container_io_control(p_ctx, VC_CONTAINER_CONTROL_IO_SET_READ_BUFFER_SIZE, buffer_size) == VC_CONTAINER_SUCCESS)
+   {
+      buffer_size <<= 1;   /* Double and try again */
+      if (buffer_size > MAXIMUM_READ_BUFFER_SIZE)
+         break;
+   }
+}
+
+static void parse_command_line(int argc, char **argv)
+{
+   int arg = 1;
+
+   while (arg < argc)
+   {
+      if (*argv[arg] != '-')  /* End of options, next should be URI */
+         break;
+
+      switch (argv[arg][1])
+      {
+      case 'h':
+         do_print_usage = true;
+         break;
+      case 's':
+         arg++;
+         if (arg >= argc)
+            break;
+         packet_save_file = argv[arg];
+         packet_save_is_pktfile = (strncmp(packet_save_file, "pktfile:", 8) == 0);
+         break;
+      case 'v':
+         {
+            const char *ptr = &argv[arg][2];
+
+            verbosity = 1;
+            while (*ptr++ == 'v')
+               verbosity++;
+         }
+         break;
+      default: LOG_ERROR(NULL, "Unrecognised option: %s", argv[arg]); return;
+      }
+
+      arg++;
+   }
+
+   if (arg < argc)
+      read_uri = argv[arg];
+}
+
+static void print_usage(char *program_name)
+{
+   LOG_INFO(NULL, "Usage:");
+   LOG_INFO(NULL, "  %s [opts] <uri>", program_name);
+   LOG_INFO(NULL, "Reads RTP packets from <uri>, decodes to standard output.");
+   LOG_INFO(NULL, "Press the escape key to terminate the program.");
+   LOG_INFO(NULL, "Options:");
+   LOG_INFO(NULL, "  -h   Print this information");
+   LOG_INFO(NULL, "  -s x Save packets to URI x");
+   LOG_INFO(NULL, "  -v   Dump standard packet header");
+   LOG_INFO(NULL, "  -vv  Dump entire header");
+   LOG_INFO(NULL, "  -vvv Dump entire header and data");
+}
+
+int main(int argc, char **argv)
+{
+   int result = 0;
+   uint8_t *buffer = NULL;
+   VC_CONTAINER_IO_T *read_io = NULL;
+   VC_CONTAINER_IO_T *write_io = NULL;
+   VC_CONTAINER_STATUS_T status;
+   size_t received_bytes;
+   bool ready = true;
+   uint32_t available_bytes;
+   uint8_t *packet_ptr;
+
+   parse_command_line(argc, argv);
+
+   if (do_print_usage || !read_uri)
+   {
+      print_usage(argv[0]);
+      result = 1; goto tidyup;
+   }
+
+   buffer = (uint8_t *)malloc(MAXIMUM_BUFFER_SIZE);
+   if (!buffer)
+   {
+      LOG_ERROR(NULL, "Allocating %d bytes for the buffer failed", MAXIMUM_BUFFER_SIZE);
+      result = 2; goto tidyup;
+   }
+
+   read_io = vc_container_io_open(read_uri, VC_CONTAINER_IO_MODE_READ, &status);
+   if (!read_io)
+   {
+      LOG_ERROR(NULL, "Opening <%s> for read failed: %d", read_uri, status);
+      result = 3; goto tidyup;
+   }
+
+   increase_read_buffer_size(read_io);
+
+   if (packet_save_file)
+   {
+      write_io = vc_container_io_open(packet_save_file, VC_CONTAINER_IO_MODE_WRITE, &status);
+      if (!write_io)
+      {
+         LOG_ERROR(NULL, "Opening <%s> for write failed: %d", packet_save_file, status);
+         result = 4; goto tidyup;
+      }
+      if (!packet_save_is_pktfile)
+      {
+         store_u32(buffer, 0x50415753);
+         vc_container_io_write(write_io, buffer, sizeof(uint32_t));
+      }
+   }
+
+   /* Use non-blocking I/O for both network and console */
+   vc_container_io_control(read_io, VC_CONTAINER_CONTROL_IO_SET_READ_TIMEOUT_MS, 20);
+   nb_set_nonblocking_input(1);
+
+   packet_ptr = buffer;
+   available_bytes = MAXIMUM_BUFFER_SIZE - sizeof(uint32_t);
+   while (ready)
+   {
+      /* Read a packet and store its length in the word before it */
+      received_bytes = vc_container_io_read(read_io, packet_ptr + sizeof(uint32_t), available_bytes);
+      if (received_bytes)
+      {
+         bool packet_has_marker;
+
+         store_u32(packet_ptr, received_bytes);
+         packet_ptr += sizeof(uint32_t);
+         packet_has_marker = marker_bit_set(packet_ptr, received_bytes);
+         packet_ptr += received_bytes;
+         available_bytes -= received_bytes + sizeof(uint32_t);
+
+         if (packet_has_marker || (available_bytes < MINIMUM_BUFFER_SPACE))
+         {
+            uint8_t *decode_ptr;
+
+            if (write_io && !packet_save_is_pktfile)
+            {
+               uint32_t total_bytes = packet_ptr - buffer;
+               if (vc_container_io_write(write_io, buffer, total_bytes) != total_bytes)
+               {
+                  LOG_ERROR(NULL, "Error saving packets to file");
+                  break;
+               }
+               if (verbosity >= LOWEST_VERBOSITY)
+                  LOG_INFO(NULL, "Written %u bytes to file", total_bytes);
+            }
+
+            for (decode_ptr = buffer; decode_ptr < packet_ptr;)
+            {
+               received_bytes = fetch_u32(decode_ptr);
+               decode_ptr += sizeof(uint32_t);
+
+               if (write_io && packet_save_is_pktfile)
+               {
+                  if (vc_container_io_write(write_io, buffer, received_bytes) != received_bytes)
+                  {
+                     LOG_ERROR(NULL, "Error saving packets to file");
+                     break;
+                  }
+                  if (verbosity >= LOWEST_VERBOSITY)
+                     LOG_INFO(NULL, "Written %u bytes to file", received_bytes);
+               }
+
+               if (!decode_packet(decode_ptr, received_bytes))
+               {
+                  LOG_ERROR(NULL, "Failed to decode packet");
+                  break;
+               }
+               decode_ptr += received_bytes;
+            }
+
+            /* Reset to start of buffer */
+            packet_ptr = buffer;
+            available_bytes = MAXIMUM_BUFFER_SIZE - sizeof(uint32_t);
+         }
+      }
+
+      if (nb_char_available())
+      {
+         if (nb_get_char() == ESCAPE_CHARACTER) 
+            ready = false;
+      }
+
+      switch (read_io->status)
+      {
+      case VC_CONTAINER_SUCCESS:
+      case VC_CONTAINER_ERROR_CONTINUE:
+         break;
+      default:
+         ready = false;
+      }
+   }
+
+   nb_set_nonblocking_input(0);
+
+tidyup:
+   if (write_io)
+      vc_container_io_close(write_io);
+   if (read_io)
+      vc_container_io_close(read_io);
+   if (buffer)
+      free(buffer);
+
+   return result;
+}
diff --git a/containers/test/stream_client.c b/containers/test/stream_client.c
new file mode 100755 (executable)
index 0000000..b1c015e
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "containers/net/net_sockets.h"
+
+#include "nb_io.h"
+
+#define MAX_BUFFER_LEN  1024
+/* Time in milliseconds to yield when nothing is happening */
+#define YIELD_PERIOD_MS 33
+
+
+static vc_container_net_status_t local_net_control(VC_CONTAINER_NET_T *sock,
+      vc_container_net_control_t operation, ...)
+{
+   vc_container_net_status_t result;
+   va_list args;
+
+   va_start(args, operation);
+   result = vc_container_net_control(sock, operation, args);
+   va_end(args);
+
+   return result;
+}
+
+int main(int argc, char **argv)
+{
+   VC_CONTAINER_NET_T *sock;
+   vc_container_net_status_t status;
+   char send_buffer[MAX_BUFFER_LEN];
+   char recv_buffer[MAX_BUFFER_LEN];
+   int ready = 1;
+   int to_send = 0;
+   size_t received;
+
+   if (argc < 3)
+   {
+      printf("Usage:\n%s <address> <port>\n", argv[0]);
+      return 1;
+   }
+
+   sock = vc_container_net_open(argv[1], argv[2], VC_CONTAINER_NET_OPEN_FLAG_STREAM, &status);
+   if (!sock)
+   {
+      printf("vc_container_net_open failed: %d\n", status);
+      return 2;
+   }
+
+   /* Use non-blocking I/O for both network and console */
+   local_net_control(sock, VC_CONTAINER_NET_CONTROL_SET_READ_TIMEOUT_MS, YIELD_PERIOD_MS);
+   nb_set_nonblocking_input(1);
+
+   while (ready)
+   {
+      if (nb_char_available())
+      {
+         char c = nb_get_char();
+
+         if (c == 26)   /* CTRL+Z */
+            break;
+
+         send_buffer[to_send++] = c;
+
+         if (c == '\r') /* Translate CR into CRLF */
+         {
+            c = '\n';
+            nb_put_char(c);
+            send_buffer[to_send++] = c;
+         }
+
+         if (c == '\n' || to_send == sizeof(send_buffer) - 1)  /* Allow for next character needing translation */
+         {
+            int already_sent = 0, sent;
+
+            /* Send a line at a time */
+            while (to_send)
+            {
+               sent = vc_container_net_write(sock, send_buffer + already_sent, to_send);
+               if (!sent)
+               {
+                  printf("vc_container_net_write failed: %d\n", vc_container_net_status(sock));
+                  to_send = 0;
+                  ready = 0;
+                  break;
+               }
+               to_send -= sent;
+               already_sent += sent;
+            }
+         }
+      }
+
+      /* Read back and print any data from the server */
+      received = vc_container_net_read(sock, recv_buffer, sizeof(recv_buffer) - 1);
+      if (received)
+      {
+         char *ptr = recv_buffer;
+
+         while (received--)
+            nb_put_char(*ptr++);
+      } else {
+         vc_container_net_status_t net_status = vc_container_net_status(sock);
+
+         if (net_status != VC_CONTAINER_NET_ERROR_TIMED_OUT && net_status != VC_CONTAINER_NET_SUCCESS)
+         {
+            printf("vc_container_net_read failed: %d\n", net_status);
+            ready = 0;
+         }
+      }
+   }
+
+   nb_set_nonblocking_input(0);
+
+   vc_container_net_close(sock);
+
+   return 0;
+}
diff --git a/containers/test/stream_server.c b/containers/test/stream_server.c
new file mode 100755 (executable)
index 0000000..8dead8f
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "containers/net/net_sockets.h"
+
+#define MAX_BUFFER_LEN  1024
+#define MAX_NAME_LEN    256
+#define MAX_PORT_LEN    32
+
+int main(int argc, char **argv)
+{
+   VC_CONTAINER_NET_T *server_sock, *sock;
+   vc_container_net_status_t status;
+   char buffer[MAX_BUFFER_LEN];
+   char name[MAX_NAME_LEN];
+   unsigned short port;
+   int ii, connections = 1;
+   size_t received;
+
+   if (argc < 2)
+   {
+      printf("Usage:\n%s <port> [<connections>]\n", argv[0]);
+      return 1;
+   }
+
+   server_sock = vc_container_net_open(NULL, argv[1], VC_CONTAINER_NET_OPEN_FLAG_STREAM, &status);
+   if (!server_sock)
+   {
+      printf("vc_container_net_open failed: %d\n", status);
+      return 2;
+   }
+
+   if (argc > 2)
+   {
+      sscanf(argv[2], "%d", &connections);
+   }
+
+   status = vc_container_net_listen(server_sock, connections);
+   if (status != VC_CONTAINER_NET_SUCCESS)
+   {
+      printf("vc_container_net_listen failed: %d\n", status);
+      vc_container_net_close(server_sock);
+      return 3;
+   }
+
+   for (ii = 0; ii < connections; ii++)
+   {
+      status = vc_container_net_accept(server_sock, &sock);
+      if (status != VC_CONTAINER_NET_SUCCESS)
+      {
+         printf("vc_container_net_accept failed: %d\n", status);
+         vc_container_net_close(server_sock);
+         return 3;
+      }
+
+      strcpy(name, "<unknown>");
+      vc_container_net_get_client_name(sock, name, sizeof(name));
+      vc_container_net_get_client_port(sock, &port);
+      printf("Connection from %s:%hu\n", name, port);
+
+      while ((received = vc_container_net_read(sock, buffer, sizeof(buffer) - 1)) != 0)
+      {
+         char *ptr = buffer;
+         size_t jj;
+
+         printf("Rx:");
+
+         /* Flip case and echo data back to client */
+         for (jj = 0; jj < received; jj++, ptr++)
+         {
+            char c = *ptr;
+
+            putchar(c);
+            if (isalpha((unsigned char)c))
+               *ptr ^= 0x20;  /* Swaps case of ASCII alphabetic characters */
+         }
+
+         ptr = buffer;
+
+         printf("Tx:");
+         while (received)
+         {
+            size_t sent;
+
+            sent = vc_container_net_write(sock, ptr, received);
+            if (!sent)
+            {
+               status = vc_container_net_status(sock);
+               printf("vc_container_net_write failed: %d\n", status);
+               break;
+            }
+
+            /* Print out bytes actually sent */
+            while (sent--)
+            {
+               received--;
+               putchar(*ptr++);
+            }
+         }
+      }
+
+      status = vc_container_net_status(sock);
+
+      if (status != VC_CONTAINER_NET_SUCCESS && status != VC_CONTAINER_NET_ERROR_CONNECTION_LOST)
+         break;
+
+      vc_container_net_close(sock);
+   }
+
+   if (status != VC_CONTAINER_NET_SUCCESS)
+   {
+      printf("vc_container_net_read failed: %d\n", status);
+   }
+
+   vc_container_net_close(server_sock);
+
+   return 0;
+}
diff --git a/containers/test/test.c b/containers/test/test.c
new file mode 100755 (executable)
index 0000000..f6a5b08
--- /dev/null
@@ -0,0 +1,623 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include "containers/containers.h"
+#include "containers/core/containers_common.h"
+#include "containers/core/containers_logging.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_io.h"
+
+#define BUFFER_SIZE 256*1024
+#define MAX_TRACKS 16
+#define MAX_SEEKS 16
+
+static int container_test_info(VC_CONTAINER_T *ctx, bool b_reader);
+static int container_test_parse_cmdline(int argc, char **argv);
+
+/* Client i/o wrapper */
+static VC_CONTAINER_IO_T *client_io_open(const char *, VC_CONTAINER_STATUS_T *);
+
+static bool b_info = 0, b_seek = 0, b_dump = 0;
+static bool b_audio = 1, b_video = 1, b_subs = 1, b_errorcode = 1;
+static const char *psz_in = 0, *psz_out = 0;
+static long packets_num = 0;
+static long track_num = -1;
+static FILE *dump_file = 0;
+static bool b_client_io = 0;
+static bool b_packetize = 0;
+
+static struct
+{
+   uint32_t mapping;
+   uint32_t frames;
+   uint32_t packets;
+   uint64_t bytes;
+   uint32_t frame_size;
+   int64_t first_dts;
+   int64_t first_pts;
+   int64_t last_dts;
+   int64_t last_pts;
+} tracks[MAX_TRACKS];
+
+static unsigned int seeks = 0;
+static long seek_offsets[MAX_SEEKS];
+static long seek_flags[MAX_SEEKS];
+static int32_t verbosity = VC_CONTAINER_LOG_ERROR|VC_CONTAINER_LOG_INFO;
+static int32_t verbosity_input = -1, verbosity_output = -1;
+
+/*****************************************************************************/
+int main(int argc, char **argv)
+{
+   int retval = 0;
+   VC_CONTAINER_T *p_ctx = 0, *p_writer_ctx = 0;
+   VC_CONTAINER_STATUS_T status;
+   unsigned int i, j;
+   uint8_t *buffer = malloc(BUFFER_SIZE);
+   int64_t seek_time;
+
+   if(container_test_parse_cmdline(argc, argv))
+      goto error_silent;
+
+   /* Set the general verbosity */
+   vc_container_log_set_verbosity(0, verbosity);
+
+   if(verbosity_input < 0) verbosity_input = verbosity;
+   if(verbosity_output < 0) verbosity_output = verbosity;
+
+   /* Open a dump file if it was requested */
+   if(b_dump)
+   {
+      char *psz_dump;
+
+      if (psz_out)
+      {
+         psz_dump = vcos_strdup(psz_out);
+      } else {
+         psz_dump = strrchr(psz_in, '\\'); if(psz_dump) psz_dump++;
+         if(!psz_dump) {psz_dump = strrchr(psz_in, '/'); if(psz_dump) psz_dump++;}
+         if(!psz_dump) psz_dump = vcos_strdup(psz_in);
+         else psz_dump = vcos_strdup(psz_dump);
+         psz_dump[strlen(psz_dump)-1] = '1';
+      }
+      dump_file = fopen(psz_dump, "wb");
+      if(!dump_file) LOG_ERROR(0, "error opening dump file %s", psz_dump);
+      else LOG_INFO(0, "data packets will dumped to %s", psz_dump);
+      free(psz_dump);
+      if(!dump_file) goto error;
+   }
+
+   /* Open a writer if an output was requested */
+   if(psz_out && !b_dump)
+   {
+      vc_container_log_set_default_verbosity(verbosity_output);
+      p_writer_ctx = vc_container_open_writer(psz_out, &status, 0, 0);
+      if(!p_writer_ctx)
+      {
+         LOG_ERROR(0, "error opening file %s (%i)", psz_out, status);
+         goto error;
+      }
+   }
+
+   vc_container_log_set_default_verbosity(verbosity_input);
+
+   /* Open the container */
+   if(b_client_io)
+   {
+      VC_CONTAINER_IO_T *p_io;
+
+      LOG_INFO(0, "Using client I/O for %s", psz_in);
+      p_io = client_io_open(psz_in, &status);
+      if(!p_io)
+      {
+        LOG_ERROR(0, "error creating io for %s (%i)", psz_in, status);
+        goto error;
+      }
+
+      p_ctx = vc_container_open_reader_with_io(p_io, psz_in, &status, 0, 0);
+      if(!p_ctx)
+         vc_container_io_close(p_io);
+   }
+   else
+   {
+      p_ctx = vc_container_open_reader(psz_in, &status, 0, 0);
+   }
+
+   if(!p_ctx)
+   {
+     LOG_ERROR(0, "error opening file %s (%i)", psz_in, status);
+     goto error;
+   }
+
+   /* Disabling tracks which are not requested and enable packetisation if requested */
+   for(i = 0; i < p_ctx->tracks_num; i++)
+   {
+      VC_CONTAINER_TRACK_T *track = p_ctx->tracks[i];
+      unsigned int disable = 0;
+
+      switch(track->format->es_type)
+      {
+      case VC_CONTAINER_ES_TYPE_VIDEO: if(!b_video) disable = 1; break;
+      case VC_CONTAINER_ES_TYPE_AUDIO: if(!b_audio) disable = 1; break;
+      case VC_CONTAINER_ES_TYPE_SUBPICTURE: if(!b_subs) disable = 1; break;
+      default: break;
+      }
+      if(disable)
+      {
+         track->is_enabled = 0;
+         LOG_INFO(0, "disabling track: %i, fourcc: %4.4s", i, (char *)&track->format->codec);
+      }
+
+      if(track->is_enabled && b_packetize && !(track->format->flags & VC_CONTAINER_ES_FORMAT_FLAG_FRAMED))
+      {
+         status = vc_container_control(p_ctx, VC_CONTAINER_CONTROL_TRACK_PACKETIZE, i, track->format->codec_variant);
+         if(status != VC_CONTAINER_SUCCESS)
+         {
+            LOG_ERROR(0, "packetization not supported on track: %i, fourcc: %4.4s", i, (char *)&track->format->codec);
+            track->is_enabled = 0;
+         }
+      }
+   }
+
+   container_test_info(p_ctx, true);
+   if(b_info) goto end;
+
+   if(p_writer_ctx)
+   {
+      LOG_INFO(0, "----Writer Information----");
+      for(i = 0; i < p_ctx->tracks_num; i++)
+      {
+         VC_CONTAINER_TRACK_T *track = p_ctx->tracks[i];
+         if(!track->is_enabled) continue;
+         tracks[p_writer_ctx->tracks_num].mapping = i;
+         LOG_INFO(0, "adding track: %i, fourcc: %4.4s", i, (char *)&track->format->codec);
+         status = vc_container_control(p_writer_ctx, VC_CONTAINER_CONTROL_TRACK_ADD, track->format);
+         if(status)
+         {
+            LOG_INFO(0, "unsupported track type (%i, %i)", status, i);
+            track->is_enabled = 0; /* disable track */
+         }
+      }
+      if(p_writer_ctx->tracks_num)
+      {
+         status = vc_container_control(p_writer_ctx, VC_CONTAINER_CONTROL_TRACK_ADD_DONE);
+         if(status) LOG_INFO(0, "could not add tracks (%i)", status);
+      }
+      LOG_INFO(0, "--------------------------");
+      LOG_INFO(0, "");
+   }
+
+   for(i = 0; i < seeks; i++)
+   {
+      LOG_DEBUG(0, "TEST seek to %ims", seek_offsets[i]);
+      seek_time = ((int64_t)(seek_offsets[i])) * 1000;
+      status = vc_container_seek(p_ctx, &seek_time, VC_CONTAINER_SEEK_MODE_TIME, seek_flags[i]);
+      LOG_DEBUG(0, "TEST seek done (%i) to %ims", status, (int)(seek_time/1000));
+   }
+
+   LOG_DEBUG(0, "TEST start reading");
+   for(i = 0; !packets_num || (long)i < packets_num; i++)
+   {
+      VC_CONTAINER_PACKET_T packet = {0};
+      int32_t frame_num = 0;
+
+      status = vc_container_read(p_ctx, &packet, VC_CONTAINER_READ_FLAG_INFO);
+      if(status != VC_CONTAINER_SUCCESS) {LOG_DEBUG(0, "TEST info status: %i", status); break;}
+
+      if(packet.track < MAX_TRACKS)
+      {
+         if((packet.flags & VC_CONTAINER_PACKET_FLAG_FRAME_START))
+         {
+            tracks[packet.track].frames++;
+            tracks[packet.track].frame_size = 0;
+         }
+         frame_num = tracks[packet.track].frames;
+      }
+
+      tracks[packet.track].frame_size += packet.size;
+
+      LOG_DEBUG(0, "packet info: track %i, size %i/%i/%i, pts %"PRId64", flags %x%s, num %i",
+                packet.track, packet.size, packet.frame_size, tracks[packet.track].frame_size, packet.pts, packet.flags,
+                (packet.flags & VC_CONTAINER_PACKET_FLAG_KEYFRAME) ? " (keyframe)" : "",
+                frame_num-1);
+
+      if(track_num >= 0 && packet.track != (uint32_t)track_num)
+      {
+         status = vc_container_read(p_ctx, 0, VC_CONTAINER_READ_FLAG_SKIP);
+         if(status != VC_CONTAINER_SUCCESS) {LOG_DEBUG(0, "TEST skip status: %i", status); break;}
+         continue;
+      }
+
+      packet.buffer_size = BUFFER_SIZE;
+      packet.data = buffer;
+      packet.size = 0;
+      status = vc_container_read(p_ctx, &packet, 0);
+      if(status != VC_CONTAINER_SUCCESS) {LOG_DEBUG(0, "TEST read status: %i", status); break;}
+
+      LOG_DEBUG(0, "packet: track %i, size %i, pts %"PRId64", flags %x", packet.track, packet.size, packet.pts, packet.flags);
+
+      if (tracks[packet.track].packets)
+      {
+         tracks[packet.track].last_dts = packet.dts;
+         tracks[packet.track].last_pts = packet.pts;
+      } else {
+         tracks[packet.track].first_dts = packet.dts;
+         tracks[packet.track].first_pts = packet.pts;
+      }
+
+      if(packet.track < MAX_TRACKS)
+      {
+         tracks[packet.track].packets++;
+         tracks[packet.track].bytes += packet.size;
+      }
+
+      if(dump_file) fwrite(packet.data, packet.size, 1, dump_file);
+
+      if(p_writer_ctx)
+      {
+         packet.track = tracks[packet.track].mapping;
+         status = vc_container_write(p_writer_ctx, &packet);
+         if(status != VC_CONTAINER_SUCCESS) {LOG_DEBUG(0, "TEST write status: %i", status); break;}
+      }
+   }
+   LOG_DEBUG(0, "TEST stop reading");
+
+   if(b_seek)
+   {
+      LOG_DEBUG(0, "TEST start seeking");
+      for(j = 0, seek_time = 100; j < 20; j++)
+      {
+         LOG_DEBUG(0, "seeking to %ims", (int)(seek_time/1000));
+         status = vc_container_seek(p_ctx, &seek_time, VC_CONTAINER_SEEK_MODE_TIME, VC_CONTAINER_SEEK_FLAG_FORWARD);
+         LOG_DEBUG(0, "seek done (%i) to %ims", status, (int)(seek_time/1000));
+
+         for(i = 0; i < 1; i++)
+         {
+            VC_CONTAINER_PACKET_T packet = {0};
+            packet.buffer_size = BUFFER_SIZE;
+            packet.data = buffer;
+
+            status = vc_container_read(p_ctx, &packet, 0);
+            if(status) LOG_DEBUG(0, "TEST read status: %i", status);
+            if(status == VC_CONTAINER_ERROR_EOS) break;
+            if(status == VC_CONTAINER_ERROR_CORRUPTED) break;
+            if(status == VC_CONTAINER_ERROR_FORMAT_INVALID) break;
+            seek_time = packet.pts + 800000;
+         }
+      }
+      LOG_DEBUG(0, "TEST stop seeking");
+   }
+
+   /* Output stats */
+   for(i = 0; i < p_ctx->tracks_num; i++)
+   {
+      LOG_INFO(0, "track %u: read %u samples in %u packets for a total of %"PRIu64" bytes",
+               i, tracks[i].frames, tracks[i].packets, tracks[i].bytes);
+      LOG_INFO(0, "Starting at %"PRId64"us (decode at %"PRId64"us), ending at %"PRId64"us (decode at %"PRId64"us)",
+               tracks[i].first_pts, tracks[i].first_dts, tracks[i].last_pts, tracks[i].last_dts);
+   }
+
+ end:
+   if(p_ctx) vc_container_close(p_ctx);
+   if(p_writer_ctx)
+   {
+      container_test_info(p_writer_ctx, false);
+      vc_container_close(p_writer_ctx);
+   }
+   if(dump_file) fclose(dump_file);
+   free(buffer);
+
+#ifdef _MSC_VER
+   getchar();
+#endif
+
+   LOG_ERROR(0, "TEST ENDED (%i)", retval);
+   return b_errorcode ? retval : 0;
+
+ error:
+   LOG_ERROR(0, "TEST FAILED");
+ error_silent:
+   retval = -1;
+   goto end;
+}
+
+static int container_test_parse_cmdline(int argc, char **argv)
+{
+   int i, j, k;
+   int32_t *p_verbosity;
+
+   /* Parse the command line arguments */
+   for(i = 1; i < argc; i++)
+   {
+      if(!argv[i]) continue;
+
+      if(argv[i][0] != '-')
+      {
+         /* Not an option argument so will be the input URI */
+         psz_in = argv[i];
+         continue;
+      }
+
+      /* We are now dealing with command line options */
+      switch(argv[i][1])
+      {
+      case 'i': b_info = 1; break;
+      case 'S': b_seek = 1; break;
+      case 'd': b_dump = 1; break;
+      case 'c': b_client_io = 1; break;
+      case 'v':
+         if(argv[i][2] == 'i') {j = 3; p_verbosity = &verbosity_input;}
+         else if(argv[i][2] == 'o') {j = 3; p_verbosity = &verbosity_output;}
+         else {j = 2; p_verbosity = &verbosity;}
+         *p_verbosity = VC_CONTAINER_LOG_ERROR|VC_CONTAINER_LOG_INFO;
+         for(k = 0; k < 2 && argv[i][j+k] == 'v'; k++)
+            *p_verbosity = (*p_verbosity << 1) | 1 ;
+         break;
+      case 's':
+         if(i+1 == argc || !argv[i+1]) goto invalid_option;
+         if(seeks >= MAX_SEEKS) goto invalid_option;
+         seek_flags[seeks] = argv[i][2] == 'f' ? VC_CONTAINER_SEEK_FLAG_FORWARD : 0;
+         seek_offsets[seeks] = strtol(argv[++i], 0, 0);
+         if(seek_offsets[seeks] < 0 || seek_offsets[seeks] == LONG_MAX) goto invalid_option;
+         seeks++;
+         break;
+      case 'n':
+         if(argv[i][2] == 'a') b_audio = 0;
+         else if(argv[i][2] == 'v') b_video = 0;
+         else if(argv[i][2] == 's') b_subs = 0;
+         else if(argv[i][2] == 'r') b_errorcode = 0;
+         else goto invalid_option;
+         break;
+      case 'e':
+         if(argv[i][2] == 'p') b_packetize = 1;
+         else goto invalid_option;
+         break;
+      case 'o':
+         if(i+1 == argc || !argv[i+1] || argv[i+1][0] == '-') goto invalid_option;
+         psz_out = argv[++i];
+         break;
+      case 'p':
+         if(i+1 == argc || !argv[i+1]) goto invalid_option;
+         packets_num = strtol(argv[++i], 0, 0);
+         if(packets_num < 0 || packets_num == LONG_MAX) goto invalid_option;
+         break;
+      case 't':
+         if(i+1 == argc || !argv[i+1]) goto invalid_option;
+         track_num = strtol(argv[++i], 0, 0);
+         if(track_num == LONG_MIN || track_num == LONG_MAX) goto invalid_option;
+         break;
+      case 'h': goto usage;
+      default: goto invalid_option;
+      }
+      continue;
+   }
+
+   /* Sanity check that we have at least an input uri */
+   if(!psz_in)
+   {
+     LOG_ERROR(0, "missing uri argument");
+     goto usage;
+   }
+
+   return 0;
+
+ invalid_option:
+   LOG_ERROR(0, "invalid command line option (%s)", argv[i]);
+
+ usage:
+   psz_in = strrchr(argv[0], '\\'); if(psz_in) psz_in++;
+   if(!psz_in) {psz_in = strrchr(argv[0], '/'); if(psz_in) psz_in++;}
+   if(!psz_in) psz_in = argv[0];
+   LOG_INFO(0, "");
+   LOG_INFO(0, "usage: %s [options] uri", psz_in);
+   LOG_INFO(0, "options list:");
+   LOG_INFO(0, " -i    : only print information on the container");
+   LOG_INFO(0, " -p X  : read only X packets from the container");
+   LOG_INFO(0, " -t X  : read only packets from track X");
+   LOG_INFO(0, " -s X  : seek to X milliseconds before starting reading");
+   LOG_INFO(0, " -sf X : seek forward to X milliseconds before starting reading");
+   LOG_INFO(0, " -S    : do seek testing");
+   LOG_INFO(0, " -d    : dump the data read from the container to files (-o to name file)");
+   LOG_INFO(0, " -o uri: output to another uri (i.e. re-muxing)");
+   LOG_INFO(0, " -na   : disable audio");
+   LOG_INFO(0, " -nv   : disable video");
+   LOG_INFO(0, " -ns   : disable subtitles");
+   LOG_INFO(0, " -nr   : always return an error code of 0 (even in case of failure)");
+   LOG_INFO(0, " -ep   : enable packetization if data is not already packetized");
+   LOG_INFO(0, " -c    : use the client i/o functions");
+   LOG_INFO(0, " -vxx  : general verbosity level (replace xx with a number of \'v\')");
+   LOG_INFO(0, " -vixx : verbosity specific to the input container");
+   LOG_INFO(0, " -voxx : verbosity specific to the output container");
+   LOG_INFO(0, " -h    : help");
+   return 1;
+}
+
+static int container_test_info(VC_CONTAINER_T *ctx, bool b_reader)
+{
+   const char *name_type;
+   unsigned int i;
+
+   LOG_INFO(0, "");
+   if(b_reader) LOG_INFO(0, "----Reader Information----");
+   else LOG_INFO(0, "----Writer Information----");
+
+   LOG_INFO(0, "duration: %2.2fs, size: %"PRId64, ctx->duration/1000000.0, ctx->size);
+   LOG_INFO(0, "capabilities: %x", ctx->capabilities);
+   LOG_INFO(0, "");
+
+   for(i = 0; i < ctx->tracks_num; i++)
+   {
+      VC_CONTAINER_TRACK_T *track = ctx->tracks[i];
+
+      switch(track->format->es_type)
+      {
+      case VC_CONTAINER_ES_TYPE_AUDIO: name_type = "audio"; break;
+      case VC_CONTAINER_ES_TYPE_VIDEO: name_type = "video"; break;
+      case VC_CONTAINER_ES_TYPE_SUBPICTURE: name_type = "subpicture"; break;
+      default: name_type = "unknown"; break;
+      }
+
+      LOG_INFO(0, "track: %i, type: %s, fourcc: %4.4s", i, name_type, (char *)&track->format->codec);
+      LOG_INFO(0, " bitrate: %i, framed: %i, enabled: %i", track->format->bitrate,
+               !!(track->format->flags & VC_CONTAINER_ES_FORMAT_FLAG_FRAMED), track->is_enabled);
+      LOG_INFO(0, " extra data: %i, %p", track->format->extradata_size, track->format->extradata);
+      switch(track->format->es_type)
+      {
+      case VC_CONTAINER_ES_TYPE_AUDIO:
+         LOG_INFO(0, " samplerate: %i, channels: %i, bps: %i, block align: %i",
+                  track->format->type->audio.sample_rate, track->format->type->audio.channels,
+                  track->format->type->audio.bits_per_sample, track->format->type->audio.block_align);
+         LOG_INFO(0, " gapless delay: %i gapless padding: %i",
+                  track->format->type->audio.gap_delay, track->format->type->audio.gap_padding);
+         LOG_INFO(0, " language: %4.4s", track->format->language);
+         break;
+
+      case VC_CONTAINER_ES_TYPE_VIDEO:
+         LOG_INFO(0, " width: %i, height: %i, (%i,%i,%i,%i)",
+                  track->format->type->video.width, track->format->type->video.height,
+                  track->format->type->video.x_offset, track->format->type->video.y_offset,
+                  track->format->type->video.visible_width, track->format->type->video.visible_height);
+         LOG_INFO(0, " pixel aspect ratio: %i/%i, frame rate: %i/%i",
+                  track->format->type->video.par_num, track->format->type->video.par_den,
+                  track->format->type->video.frame_rate_num, track->format->type->video.frame_rate_den);
+         break;
+
+      case VC_CONTAINER_ES_TYPE_SUBPICTURE:
+         LOG_INFO(0, " language: %4.4s, encoding: %i", track->format->language,
+                  track->format->type->subpicture.encoding);
+         break;
+
+      default: break;
+      }
+   }
+
+   for (i = 0; i < ctx->meta_num; ++i)
+   {
+      const char *name, *value;
+      if (i == 0) LOG_INFO(0, "");
+      name = vc_container_metadata_id_to_string(ctx->meta[i]->key);
+      value = ctx->meta[i]->value;
+      if(!name) continue;
+      LOG_INFO(0, "metadata(%i) : %s : %s", i, name, value);
+   }
+
+   LOG_INFO(0, "--------------------------");
+   LOG_INFO(0, "");
+
+   return 0;
+}
+
+/*****************************************************************************
+ * Client I/O wrapper. Only used when the right cmd line option is passed.
+ *****************************************************************************/
+static VC_CONTAINER_STATUS_T client_io_close( VC_CONTAINER_IO_T *p_ctx )
+{
+   FILE *fd = (FILE *)p_ctx->module;
+   fclose(fd);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+static size_t client_io_read(VC_CONTAINER_IO_T *p_ctx, void *buffer, size_t size)
+{
+   FILE *fd = (FILE *)p_ctx->module;
+   size_t ret = fread(buffer, 1, size, fd);
+   if(ret != size)
+   {
+      /* Sanity check return value. Some platforms (e.g. Android) can return -1 */
+      if( ((int)ret) < 0 ) ret = 0;
+
+      if( feof(fd) ) p_ctx->status = VC_CONTAINER_ERROR_EOS;
+      else p_ctx->status = VC_CONTAINER_ERROR_FAILED;
+   }
+   LOG_DEBUG( 0, "read: %i", ret );
+   return ret;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T client_io_seek(VC_CONTAINER_IO_T *p_ctx, int64_t offset)
+{
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   FILE *fd = (FILE *)p_ctx->module;
+   int ret;
+
+   //FIXME: no large file support
+   if (offset > (int64_t)UINT_MAX)
+   {
+      LOG_ERROR( 0, "no large file support");
+      p_ctx->status = VC_CONTAINER_ERROR_EOS;
+      return VC_CONTAINER_ERROR_EOS;
+   }
+
+   ret = fseek(fd, (long)offset, SEEK_SET);
+   if(ret)
+   {
+      if( feof(fd) ) status = VC_CONTAINER_ERROR_EOS;
+      else status = VC_CONTAINER_ERROR_FAILED;
+   }
+
+   p_ctx->status = status;
+   return status;
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_IO_T *client_io_open( const char *psz_uri, VC_CONTAINER_STATUS_T *status )
+{
+   VC_CONTAINER_IO_T *p_io;
+   VC_CONTAINER_IO_CAPABILITIES_T capabilities = VC_CONTAINER_IO_CAPS_NO_CACHING;
+   FILE *fd;
+
+   fd = fopen(psz_uri, "rb");
+   if (!fd)
+   {
+      *status = VC_CONTAINER_ERROR_URI_OPEN_FAILED;
+      return NULL;
+   }
+
+   p_io = vc_container_io_create( psz_uri, 0, capabilities, status );
+   if(!p_io)
+   {
+     LOG_ERROR(0, "error creating io (%i)", *status);
+     fclose(fd);
+     return NULL;
+   }
+
+   p_io->module = (struct VC_CONTAINER_IO_MODULE_T *)fd;
+   p_io->pf_close = client_io_close;
+   p_io->pf_read = client_io_read;
+   p_io->pf_seek = client_io_seek;
+
+   //FIXME: no large file support
+   fseek(fd, 0, SEEK_END);
+   p_io->size = ftell(fd);
+   fseek(fd, 0, SEEK_SET);
+
+   *status = VC_CONTAINER_SUCCESS;
+   return p_io;
+}
diff --git a/containers/test/test_bits.c b/containers/test/test_bits.c
new file mode 100755 (executable)
index 0000000..7ce1651
--- /dev/null
@@ -0,0 +1,600 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+
+#define BITS_LOG_INDENT(ctx) indent_level
+#include "containers/containers.h"
+#include "containers/core/containers_common.h"
+#include "containers/core/containers_logging.h"
+#include "containers/core/containers_bits.h"
+
+uint32_t indent_level;
+
+/** Bit stream containing the values 0 to 10, with each value in that many bits.
+ * At the end there is one further zero bit before the end of the stream. */
+static uint8_t bits_0_to_10[] = {
+   0xCD, 0x0A, 0x30, 0x70, 0x80, 0x48, 0x14
+};
+
+/** Bit stream containing the values 0 to 10, encoded using Exp-Golomb.
+ * At the end there is one further one bit before the end of the stream. */
+static uint8_t exp_golomb_0_to_10[] = {
+   0xA6, 0x42, 0x98, 0xE2, 0x04, 0x8A, 0x17
+};
+
+/** Array of signed values for the Exp-Golomb encoding of each index. */
+static int32_t exp_golomb_values[] = {
+   0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5
+};
+
+/** Bit stream containing two large 32-bit values, encoded using Exp-Golomb. */
+static uint8_t exp_golomb_large[] = {
+   0x00, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFE, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00
+};
+
+/** Bit stream containing a 33-bit value, encoded using Exp-Golomb. */
+static uint8_t exp_golomb_oversize[] = {
+   0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80
+};
+
+
+static const char *plural_ext(uint32_t val)
+{
+   return (val == 1) ? "" : "s";
+}
+
+static int test_reset_and_available(void)
+{
+   VC_CONTAINER_BITS_T bit_stream;
+   int error_count = 0;
+
+   LOG_DEBUG(NULL, "Testing vc_container_bits_reset and vc_container_bits_available");
+   BITS_INIT(NULL, &bit_stream, bits_0_to_10, countof(bits_0_to_10));
+
+   if (!BITS_AVAILABLE(NULL, &bit_stream))
+   {
+      LOG_ERROR(NULL, "Expected initialised stream to contain bits");
+      error_count++;
+   }
+
+   BITS_RESET(NULL, &bit_stream);
+
+   if (BITS_AVAILABLE(NULL, &bit_stream))
+   {
+      LOG_ERROR(NULL, "Expected reset stream not to contain bits");
+      error_count++;
+   }
+
+   return error_count;
+}
+
+static int test_read_u32(void)
+{
+   VC_CONTAINER_BITS_T bit_stream;
+   uint32_t ii, value;
+   int error_count = 0;
+
+   LOG_DEBUG(NULL, "Testing vc_container_bits_get_u32");
+   BITS_INIT(NULL, &bit_stream, bits_0_to_10, countof(bits_0_to_10));
+
+   for (ii = 0; ii < 11; ii++)
+   {
+      value = BITS_READ_U32(NULL, &bit_stream, ii, "test_read_u32");
+      if (value != ii)
+      {
+         LOG_ERROR(NULL, "Expected %u, got %u", ii, value);
+         error_count++;
+      }
+   }
+
+   value = BITS_READ_U32(NULL, &bit_stream, 1, "Final bit");
+   if (!BITS_VALID(NULL, &bit_stream) || value)
+   {
+      LOG_ERROR(NULL, "Failed to get final bit");
+      error_count++;
+   }
+   value = BITS_READ_U32(NULL, &bit_stream, 1, "Beyond final bit");
+   if (BITS_VALID(NULL, &bit_stream) || value)
+   {
+      LOG_ERROR(NULL, "Unexpectedly succeeded reading beyond expected end of stream");
+      error_count++;
+   }
+
+   return error_count;
+}
+
+static int test_skip(void)
+{
+   VC_CONTAINER_BITS_T bit_stream;
+   uint32_t ii;
+   int error_count = 0;
+   uint32_t last_bits_left, bits_left;
+
+   LOG_DEBUG(NULL, "Testing vc_container_bits_skip");
+   BITS_INIT(NULL, &bit_stream, bits_0_to_10, countof(bits_0_to_10));
+
+   last_bits_left = BITS_AVAILABLE(NULL, &bit_stream);
+   for (ii = 0; ii < 11; ii++)
+   {
+      BITS_SKIP(NULL, &bit_stream, ii, "test_skip");
+      bits_left = BITS_AVAILABLE(NULL, &bit_stream);
+      if (bits_left + ii != last_bits_left)
+      {
+         int32_t actual = last_bits_left - bits_left;
+         LOG_ERROR(NULL, "Tried to skip %u bit%s, actually skipped %d bit%s",
+               ii, plural_ext(ii), actual, plural_ext(actual));
+         error_count++;
+      }
+      last_bits_left = bits_left;
+   }
+
+   BITS_SKIP(NULL, &bit_stream, 1, "Final bit");
+   if (!BITS_VALID(NULL, &bit_stream))
+   {
+      LOG_ERROR(NULL, "Failed to skip final bit");
+      error_count++;
+   }
+   if (BITS_AVAILABLE(NULL, &bit_stream))
+   {
+      LOG_ERROR(NULL, "End of stream not reached by skipping");
+      error_count++;
+   }
+
+   BITS_SKIP(NULL, &bit_stream, 1, "Beyond final bit");
+   if (BITS_VALID(NULL, &bit_stream))
+   {
+      LOG_ERROR(NULL, "Unexpectedly succeeded skipping beyond expected end of stream");
+      error_count++;
+   }
+   return error_count;
+}
+
+static int test_ptr_and_skip_bytes(void)
+{
+   VC_CONTAINER_BITS_T bit_stream;
+   uint32_t ii;
+   const uint8_t *expected_ptr;
+   int error_count = 0;
+   uint32_t last_bytes_left, bytes_left;
+
+   LOG_DEBUG(NULL, "Testing vc_container_bits_current_pointer, vc_container_bits_skip_bytes and vc_container_bits_bytes_available");
+   BITS_INIT(NULL, &bit_stream, bits_0_to_10, countof(bits_0_to_10));
+
+   last_bytes_left = BITS_BYTES_AVAILABLE(NULL, &bit_stream);
+   if (last_bytes_left != countof(bits_0_to_10))
+   {
+      LOG_ERROR(NULL, "Expected bytes available to initially match given size");
+      error_count++;
+   }
+
+   if (BITS_CURRENT_POINTER(NULL, &bit_stream) != bits_0_to_10)
+   {
+      LOG_ERROR(NULL, "Expected initial current pointer to match original buffer");
+      error_count++;
+   }
+
+   expected_ptr = bits_0_to_10;
+   for (ii = 0; ii < 4; ii++)
+   {
+      BITS_SKIP_BYTES(NULL, &bit_stream, ii, "test_ptr_and_skip_bytes");
+
+      expected_ptr += ii;
+      if (BITS_CURRENT_POINTER(NULL, &bit_stream) != expected_ptr)
+      {
+         LOG_ERROR(NULL, "Expected current pointer to have moved by %u byte%s", ii, plural_ext(ii));
+         error_count++;
+      }
+
+      bytes_left = BITS_BYTES_AVAILABLE(NULL, &bit_stream);
+      if (bytes_left + ii != last_bytes_left)
+      {
+         int32_t actual = last_bytes_left - bytes_left;
+         LOG_ERROR(NULL, "Tried to skip %u byte%s, actually skipped %d byte%s",
+               ii, plural_ext(ii), actual, plural_ext(actual));
+         error_count++;
+      }
+
+      last_bytes_left = bytes_left;
+   }
+
+   if (!bytes_left)
+   {
+      LOG_ERROR(NULL, "Reached end of stream too soon");
+      error_count++;
+   }
+   if (!BITS_VALID(NULL, &bit_stream))
+   {
+      LOG_ERROR(NULL, "Expected stream to be valid");
+      error_count++;
+   }
+
+   BITS_SKIP_BYTES(NULL, &bit_stream, bytes_left + 1, "Beyond end of stream");
+   if (BITS_VALID(NULL, &bit_stream))
+   {
+      LOG_ERROR(NULL, "Unexpectedly succeeded skipping bytes beyond end of stream");
+      error_count++;
+   }
+   if (BITS_BYTES_AVAILABLE(NULL, &bit_stream))
+   {
+      LOG_ERROR(NULL, "Expected stream to have been reset");
+      error_count++;
+   }
+
+   return error_count;
+}
+
+static int test_reduce_bytes(void)
+{
+   VC_CONTAINER_BITS_T bit_stream;
+   uint32_t ii;
+   int error_count = 0;
+   uint32_t last_bytes_left, bytes_left;
+
+   LOG_DEBUG(NULL, "Testing vc_container_bits_reduce_bytes");
+   BITS_INIT(NULL, &bit_stream, bits_0_to_10, countof(bits_0_to_10));
+
+   last_bytes_left = BITS_BYTES_AVAILABLE(NULL, &bit_stream);
+   if (last_bytes_left != countof(bits_0_to_10))
+   {
+      LOG_ERROR(NULL, "Expected bytes available to initially match given size");
+      error_count++;
+   }
+
+   if (BITS_CURRENT_POINTER(NULL, &bit_stream) != bits_0_to_10)
+   {
+      LOG_ERROR(NULL, "Expected initial current pointer to match original buffer");
+      error_count++;
+   }
+
+   for (ii = 0; ii < 4; ii++)
+   {
+      BITS_REDUCE_BYTES(NULL, &bit_stream, ii, "test_reduce_bytes");
+
+      if (BITS_CURRENT_POINTER(NULL, &bit_stream) != bits_0_to_10)
+      {
+         LOG_ERROR(NULL, "Did not expect current pointer to have moved");
+         error_count++;
+      }
+
+      bytes_left = BITS_BYTES_AVAILABLE(NULL, &bit_stream);
+      if (bytes_left + ii != last_bytes_left)
+      {
+         int32_t actual = last_bytes_left - bytes_left;
+         LOG_ERROR(NULL, "Tried to reduce by %u byte%s, actually reduced by %d byte%s",
+               ii, plural_ext(ii), actual, plural_ext(actual));
+         error_count++;
+      }
+
+      last_bytes_left = bytes_left;
+   }
+
+   if (!bytes_left)
+   {
+      LOG_ERROR(NULL, "Reached end of stream too soon");
+      error_count++;
+   }
+   if (!BITS_VALID(NULL, &bit_stream))
+   {
+      LOG_ERROR(NULL, "Expected stream to be valid");
+      error_count++;
+   }
+
+   BITS_REDUCE_BYTES(NULL, &bit_stream, bytes_left + 1, "Reducing an empty stream");
+   if (BITS_VALID(NULL, &bit_stream))
+   {
+      LOG_ERROR(NULL, "Unexpectedly succeeded reducing by too many bytes");
+      error_count++;
+   }
+   if (BITS_AVAILABLE(NULL, &bit_stream))
+   {
+      LOG_ERROR(NULL, "Expected stream to have been reset");
+      error_count++;
+   }
+
+   return error_count;
+}
+
+static int test_copy_bytes(void)
+{
+   VC_CONTAINER_BITS_T bit_stream;
+   int error_count = 0;
+   uint8_t buffer[countof(bits_0_to_10)];
+   uint32_t ii;
+
+   LOG_DEBUG(NULL, "Testing vc_container_bits_copy_bytes");
+   BITS_INIT(NULL, &bit_stream, bits_0_to_10, countof(bits_0_to_10));
+   memset(buffer, 0, sizeof(buffer));
+
+   /* Copy whole buffer in one go */
+   BITS_COPY_BYTES(NULL, &bit_stream, countof(buffer), buffer, "Copy whole buffer");
+
+   if (!BITS_VALID(NULL, &bit_stream))
+   {
+      LOG_ERROR(NULL, "Failed to copy the whole buffer");
+      error_count++;
+   }
+
+   if (memcmp(buffer, bits_0_to_10, countof(bits_0_to_10)) != 0)
+   {
+      LOG_ERROR(NULL, "Single copy doesn't match original");
+      error_count++;
+   }
+
+   BITS_INIT(NULL, &bit_stream, bits_0_to_10, countof(bits_0_to_10));
+   memset(buffer, 0, sizeof(buffer));
+
+   /* Copy whole buffer one byte at a time */
+   for (ii = 0; ii < countof(bits_0_to_10); ii++)
+   {
+      BITS_COPY_BYTES(NULL, &bit_stream, 1, buffer + ii, "Copy buffer piecemeal");
+   }
+
+   if (!BITS_VALID(NULL, &bit_stream))
+   {
+      LOG_ERROR(NULL, "Failed to copy the buffer piecemeal");
+      error_count++;
+   }
+
+   if (memcmp(buffer, bits_0_to_10, countof(bits_0_to_10)) != 0)
+   {
+      LOG_ERROR(NULL, "Multiple copy doesn't match original");
+      error_count++;
+   }
+
+   BITS_INIT(NULL, &bit_stream, bits_0_to_10, countof(bits_0_to_10));
+   memset(buffer, 0, sizeof(buffer));
+
+   /* Copy part of buffer */
+   BITS_SKIP_BYTES(NULL, &bit_stream, 1, "Copy part of buffer");
+   BITS_REDUCE_BYTES(NULL, &bit_stream, 1, "Copy part of buffer");
+   BITS_COPY_BYTES(NULL, &bit_stream, countof(buffer) - 2, buffer, "Copy part of buffer");
+
+   if (!BITS_VALID(NULL, &bit_stream))
+   {
+      LOG_ERROR(NULL, "Failed to copy part of buffer");
+      error_count++;
+   }
+
+   if (memcmp(buffer, bits_0_to_10 + 1, countof(bits_0_to_10) - 2) != 0)
+   {
+      LOG_ERROR(NULL, "Partial copy doesn't match original");
+      error_count++;
+   }
+
+   return error_count;
+}
+
+static int test_skip_exp_golomb(void)
+{
+   VC_CONTAINER_BITS_T bit_stream;
+   uint32_t ii;
+   int error_count = 0;
+
+   LOG_DEBUG(NULL, "Testing vc_container_bits_skip_exp_golomb");
+   BITS_INIT(NULL, &bit_stream, exp_golomb_0_to_10, countof(exp_golomb_0_to_10));
+
+   for (ii = 0; ii < 12; ii++)
+   {
+      BITS_SKIP_EXP(NULL, &bit_stream, "test_skip_exp_golomb");
+   }
+
+   if (!BITS_VALID(NULL, &bit_stream))
+   {
+      LOG_ERROR(NULL, "Failed to skip through buffer");
+      error_count++;
+   }
+
+   BITS_SKIP_EXP(NULL, &bit_stream, "Skip beyond end of stream");
+   if (BITS_VALID(NULL, &bit_stream))
+   {
+      LOG_ERROR(NULL, "Unexpectedly succeeded skipping beyond expected end of stream");
+      error_count++;
+   }
+
+   return error_count;
+}
+
+static int test_read_u32_exp_golomb(void)
+{
+   VC_CONTAINER_BITS_T bit_stream;
+   uint32_t ii, value;
+   int error_count = 0;
+
+   LOG_DEBUG(NULL, "Testing vc_container_bits_get_u32_exp_golomb");
+   BITS_INIT(NULL, &bit_stream, exp_golomb_0_to_10, countof(exp_golomb_0_to_10));
+
+   for (ii = 0; ii < 11; ii++)
+   {
+      value = BITS_READ_U32_EXP(NULL, &bit_stream, "test_read_u32_exp_golomb");
+      if (value != ii)
+      {
+         LOG_ERROR(NULL, "Expected %u, got %u", ii, value);
+         error_count++;
+      }
+   }
+
+   value = BITS_READ_U32(NULL, &bit_stream, 1, "Final bit");
+   if (!BITS_VALID(NULL, &bit_stream) || !value)
+   {
+      LOG_ERROR(NULL, "Failed to get final bit (expected a 1)");
+      error_count++;
+   }
+   value = BITS_READ_U32_EXP(NULL, &bit_stream, "Beyond end of stream");
+   if (BITS_VALID(NULL, &bit_stream) || value)
+   {
+      LOG_ERROR(NULL, "Unexpectedly succeeded reading beyond expected end of stream");
+      error_count++;
+   }
+
+   /* Test getting two large (32 bit) Exp-Golomb values */
+   BITS_INIT(NULL, &bit_stream, exp_golomb_large, countof(exp_golomb_large));
+
+   value = BITS_READ_U32_EXP(NULL, &bit_stream, "Second largest 32-bit value");
+   if (value != 0xFFFFFFFE)
+   {
+      LOG_ERROR(NULL, "Failed to get second largest 32-bit value");
+      error_count++;
+   }
+
+   value = BITS_READ_U32_EXP(NULL, &bit_stream, "Largest 32-bit value");
+   if (value != 0xFFFFFFFF)
+   {
+      LOG_ERROR(NULL, "Failed to get largest 32-bit value");
+      error_count++;
+   }
+
+   /* Test getting an oversize (33 bit) Exp-Golomb value */
+   BITS_INIT(NULL, &bit_stream, exp_golomb_oversize, countof(exp_golomb_oversize));
+
+   value = BITS_READ_U32_EXP(NULL, &bit_stream, "Unsigned 33-bit value");
+   if (BITS_VALID(NULL, &bit_stream) || value)
+   {
+      LOG_ERROR(NULL, "Unexpectedly got 33-bit value: %u", value);
+      error_count++;
+   }
+
+   return error_count;
+}
+
+static int test_read_s32_exp_golomb(void)
+{
+   VC_CONTAINER_BITS_T bit_stream;
+   uint32_t ii;
+   int32_t value;
+   int error_count = 0;
+
+   LOG_DEBUG(NULL, "Testing vc_container_bits_get_s32_exp_golomb");
+   BITS_INIT(NULL, &bit_stream, exp_golomb_0_to_10, countof(exp_golomb_0_to_10));
+
+   for (ii = 0; ii < 11; ii++)
+   {
+      value = BITS_READ_S32_EXP(NULL, &bit_stream, "test_read_s32_exp_golomb");
+      if (value != exp_golomb_values[ii])
+      {
+         LOG_ERROR(NULL, "Expected %u, got %u", ii, value);
+         error_count++;
+      }
+   }
+
+   value = BITS_READ_S32_EXP(NULL, &bit_stream, "Final bit");
+   if (!BITS_VALID(NULL, &bit_stream) || value)
+   {
+      LOG_ERROR(NULL, "Failed to get final Exp-Golomb value (expected a zero)");
+      error_count++;
+   }
+   value = BITS_READ_S32_EXP(NULL, &bit_stream, "Beyond final bit");
+   if (BITS_VALID(NULL, &bit_stream) || value)
+   {
+      LOG_ERROR(NULL, "Unexpectedly succeeded reading beyond expected end of stream");
+      error_count++;
+   }
+
+   /* Test getting two large (32 bit) Exp-Golomb values */
+   BITS_INIT(NULL, &bit_stream, exp_golomb_large, countof(exp_golomb_large));
+
+   value = BITS_READ_S32_EXP(NULL, &bit_stream, "Largest signed 32-bit value");
+   if (!BITS_VALID(NULL, &bit_stream) || value != -0x7FFFFFFF)
+   {
+      LOG_ERROR(NULL, "Failed to get largest signed 32-bit value: %d", value);
+      error_count++;
+   }
+
+   value = BITS_READ_S32_EXP(NULL, &bit_stream, "Just too large signed 33-bit value");
+   if (BITS_VALID(NULL, &bit_stream) || value)
+   {
+      LOG_ERROR(NULL, "Unexpectedly got slightly too large signed 32-bit value: %d", value);
+      error_count++;
+   }
+
+   /* Test getting an oversize (33 bit) Exp-Golomb value */
+   BITS_INIT(NULL, &bit_stream, exp_golomb_oversize, countof(exp_golomb_oversize));
+
+   value = BITS_READ_S32_EXP(NULL, &bit_stream, "Larger signed 33-bit value");
+   if (BITS_VALID(NULL, &bit_stream) || value)
+   {
+      LOG_ERROR(NULL, "Unexpectedly got signed 33-bit value: %d", value);
+      error_count++;
+   }
+
+   return error_count;
+}
+
+#ifdef ENABLE_CONTAINERS_LOG_FORMAT
+static int test_indentation(void)
+{
+   VC_CONTAINER_BITS_T bit_stream;
+   uint32_t ii;
+
+   LOG_DEBUG(NULL, "Testing logging indentation");
+   BITS_INIT(NULL, &bit_stream, bits_0_to_10, countof(bits_0_to_10));
+
+   for (ii = 0; ii < 11; ii++)
+   {
+      indent_level = ii;
+      BITS_READ_U32(NULL, &bit_stream, ii, "test_indentation (unit)");
+   }
+
+   BITS_INIT(NULL, &bit_stream, bits_0_to_10, countof(bits_0_to_10));
+
+   for (ii = 0; ii < 11; ii++)
+   {
+      indent_level = ii * 10;
+      BITS_READ_U32(NULL, &bit_stream, ii, "test_indentation (tens)");
+   }
+   return 0;
+}
+#endif
+
+int main(int argc, char **argv)
+{
+   int error_count = 0;
+
+   VC_CONTAINER_PARAM_UNUSED(argc);
+   VC_CONTAINER_PARAM_UNUSED(argv);
+
+   error_count += test_reset_and_available();
+   error_count += test_read_u32();
+   error_count += test_skip();
+   error_count += test_ptr_and_skip_bytes();
+   error_count += test_reduce_bytes();
+   error_count += test_copy_bytes();
+   error_count += test_skip_exp_golomb();
+   error_count += test_read_u32_exp_golomb();
+   error_count += test_read_s32_exp_golomb();
+#ifdef ENABLE_CONTAINERS_LOG_FORMAT
+   error_count += test_indentation();
+#endif
+
+   if (error_count)
+   {
+      LOG_ERROR(NULL, "*** %d errors reported", error_count);
+      getchar();
+   }
+
+   return error_count;
+}
diff --git a/containers/test/test_uri.c b/containers/test/test_uri.c
new file mode 100755 (executable)
index 0000000..0586182
--- /dev/null
@@ -0,0 +1,824 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+
+#include "containers/containers.h"
+#include "containers/core/containers_common.h"
+#include "containers/core/containers_logging.h"
+#include "containers/core/containers_uri.h"
+
+#define TEST_CHAR       '.'
+#define TEST_STRING     "test"
+#define TEST_NAME       "name"
+#define TEST_VALUE      "value"
+
+#define ARRAY_SIZE(X)   (sizeof(X)/sizeof(*(X)))
+
+struct
+{
+   const char *before;
+   const char *after;
+} test_parse_uris[] = {
+   {"", NULL},
+   {"C:\\test\\filename", NULL},
+   {"/usr/local/nix/filename", NULL},
+   {"scheme-only:", NULL},
+   {"scheme:/and/path", NULL},
+   {"scheme:/and/path#with_fragment", NULL},
+   {"scheme:/and/path?query=true", NULL},
+   {"scheme:/and/path?multiple+queries=true&more=false", NULL},
+   {"scheme:/and/path?multiple+queries=true&more=false#and+a+fragment,+too", NULL},
+   {"scheme:C:\\Windows\\path", "scheme:C:%5CWindows%5Cpath"},
+   {"scheme:C:\\Windows\\path#with_fragment", "scheme:C:%5CWindows%5Cpath#with_fragment"},
+   {"scheme:C:\\Windows\\path?query=true", "scheme:C:%5CWindows%5Cpath?query=true"},
+   {"scheme:C:\\Windows\\path?query#and+fragment", "scheme:C:%5CWindows%5Cpath?query#and+fragment"},
+   {"scheme://just.host", NULL},
+   {"scheme://host/and/path", NULL},
+   {"scheme://host:port", NULL},
+   {"scheme://host:port/and/path", NULL},
+   {"scheme://127.0.0.1:port/and/path", NULL},
+   {"scheme://userinfo@host:port/and/path?query#fragment", NULL},
+   {"HTTP://www.EXAMPLE.com/", "http://www.example.com/"},
+   {"%48%54%54%50://%54%45%53%54/", "http://test/"},
+   {"scheme:esc%", "scheme:esc%25"},
+   {"scheme:esc%%", "scheme:esc%25%25"},
+   {"scheme:esc%%%", "scheme:esc"},
+   {"scheme:esc%1%", "scheme:esc%10"},
+   {"scheme:esc%%1", "scheme:esc%01"},
+   {"s+-.1234567890:", NULL},
+   {"scheme:///", NULL},
+   {"scheme://:just_port", NULL},
+   {"scheme://:port/and/path", NULL},
+   {"scheme://just_userinfo@", NULL},
+   {"scheme://userinfo@/and/path", NULL},
+   {"scheme://userinfo@:port/and/path", NULL},
+   {"%01%02%03%04%05%06%07%08%09%0a%0b%0c%0d%0e%0f%10%11%12%13%14%15%16%17%18%19%1a%1b%1c%1d%1e%1f:", "%01%02%03%04%05%06%07%08%09%0A%0B%0C%0D%0E%0F%10%11%12%13%14%15%16%17%18%19%1A%1B%1C%1D%1E%1F:"},
+   {"%20%21%22%23%24%25%26%27%28%29%2A%2B%2C%2D%2E%2F%3A%3B%3C%3D%3E%3F%40%5B%5C%5D%5E%5F%60%7B%7C%7D%7E%7F:", "%20%21%22%23%24%25%26%27%28%29%2A+%2C-.%2F%3A%3B%3C%3D%3E%3F%40%5B%5C%5D%5E_%60%7B%7C%7D~%7F:"},
+   {"scheme://%20%21%22%23%24%25%26%27%28%29%2A%2B%2C%2D%2E%2F%3A%3B%3C%3D%3E%3F%40%5B%5C%5D%5E%5F%60%7B%7C%7D%7E%7F@", "scheme://%20!%22%23$%25&'()*+,-.%2F:;%3C=%3E%3F%40%5B%5C%5D%5E_%60%7B%7C%7D~%7F@"},
+   {"scheme://%20%21%22%23%24%25%26%27%28%29%2A%2B%2C%2D%2E%2F%3A%3B%3C%3D%3E%3F%40%5B%5C%5D%5E%5F%60%7B%7C%7D%7E%7F", "scheme://%20!%22%23$%25&'()*+,-.%2F:;%3C=%3E%3F%40[%5C]%5E_%60%7B%7C%7D~%7F"},
+   {"scheme://:%20%21%22%23%24%25%26%27%28%29%2A%2B%2C%2D%2E%2F%3A%3B%3C%3D%3E%3F%40%5B%5C%5D%5E%5F%60%7B%7C%7D%7E%7F", "scheme://:%20%21%22%23%24%25%26%27%28%29%2A%2B%2C-.%2F%3A%3B%3C%3D%3E%3F%40%5B%5C%5D%5E_%60%7B%7C%7D~%7F"},
+   {"scheme:///%20%21%22%23%24%25%26%27%28%29%2A%2B%2C%2D%2E%2F%3A%3B%3C%3D%3E%3F%40%5B%5C%5D%5E%5F%60%7B%7C%7D%7E%7F", "scheme:///%20!%22%23$%25&'()*+,-./:;%3C=%3E%3F@%5B%5C%5D%5E_%60%7B%7C%7D~%7F"},
+   {"scheme://?%20%21%22%23%24%25%26%27%28%29%2A%2B%2C%2D%2E%2F%3A%3B%3C%3D%3E%3F%40%5B%5C%5D%5E%5F%60%7B%7C%7D%7E%7F", "scheme://?%20!%22%23$%25&'()*+,-./:;%3C=%3E?@%5B%5C%5D%5E_%60%7B%7C%7D~%7F"},
+   {"scheme://#%20%21%22%23%24%25%26%27%28%29%2A%2B%2C%2D%2E%2F%3A%3B%3C%3D%3E%3F%40%5B%5C%5D%5E%5F%60%7B%7C%7D%7E%7F", "scheme://#%20!%22%23$%25&'()*+,-./:;%3C=%3E?@%5B%5C%5D%5E_%60%7B%7C%7D~%7F"},
+   {"scheme://[v6.1234:5678]/", NULL},
+   {"scheme://[::1]/", NULL},
+   {"scheme://[1234:5678:90ab:cdef:1234:5678:90ab:cdef]/", NULL},
+   {"scheme://[::1]:1/", NULL},
+   {"scheme://?", "scheme://"},
+   {"scheme://?#", "scheme://#"},
+   {"scheme://?q&&;&n=&=v&=&n=v", "scheme://?q&n=&n=v"},
+   {"ldap://[2001:db8::7]/c=GB?objectClass?one", NULL},
+   {"mailto:John.Doe@example.com", NULL},
+   {"news:comp.infosystems.www.servers.unix", NULL},
+   {"tel:+1-816-555-1212", NULL},
+   {"urn:oasis:names:specification:docbook:dtd:xml:4.1.2", NULL},
+};
+
+typedef struct build_uri_tag
+{
+   const char *expected_uri;
+   const char *scheme;
+   const char *userinfo;
+   const char *host;
+   const char *port;
+   const char *path;
+   const char *fragment;
+   const char **queries; /* Held as name then value. NULL values allowed. NULL name terminates list */
+} BUILD_URI_T;
+
+/* Test query lists */
+const char *no_queries[] = { NULL };
+const char *query_true[] = { "query", "true", NULL };
+const char *multiple_queries[] = { "multiple+queries", "true", "more", "false", NULL };
+const char *just_query[] = {"query", NULL, NULL};
+const char *complex_query[] = { "q", NULL, "n", "", "n", "v", NULL };
+const char *objectClass_one[] = { "objectClass?one", NULL, NULL };
+
+BUILD_URI_T test_build_uris[] = {
+   {"", NULL, NULL, NULL, NULL, NULL, NULL, no_queries },
+   {"C:\\test\\filename", NULL, NULL, NULL, NULL, "C:\\test\\filename", NULL, no_queries},
+   {"/usr/local/nix/filename", NULL, NULL, NULL, NULL, "/usr/local/nix/filename", NULL, no_queries},
+   {"scheme-only:", "scheme-only", NULL, NULL, NULL, NULL, NULL, no_queries},
+   {"scheme:/and/path", "scheme", NULL, NULL, NULL, "/and/path", NULL, no_queries},
+   {"scheme:/and/path#with_fragment", "scheme", NULL, NULL, NULL, "/and/path", "with_fragment", no_queries},
+   {"scheme:/and/path?query=true", "scheme", NULL, NULL, NULL, "/and/path", NULL, query_true},
+   {"scheme:/and/path?multiple+queries=true&more=false", "scheme", NULL, NULL, NULL, "/and/path", NULL, multiple_queries},
+   {"scheme:/and/path?multiple+queries=true&more=false#and+a+fragment,+too", "scheme", NULL, NULL, NULL, "/and/path", "and+a+fragment,+too", multiple_queries},
+   {"scheme://just.host", "scheme", NULL, "just.host", NULL, NULL, NULL, no_queries},
+   {"scheme://host/and/path", "scheme", NULL, "host", NULL, "/and/path", NULL, no_queries},
+   {"scheme://host:port", "scheme", NULL, "host", "port", NULL, NULL, no_queries},
+   {"scheme://host:port/and/path", "scheme", NULL, "host", "port", "/and/path", NULL, no_queries},
+   {"scheme://127.0.0.1:port/and/path", "scheme", NULL, "127.0.0.1", "port", "/and/path", NULL, no_queries},
+   {"scheme://userinfo@host:port/and/path?query#fragment", "scheme", "userinfo", "host", "port", "/and/path", "fragment", just_query},
+   {"scheme:///", "scheme", NULL, "", NULL, "/", NULL, no_queries },
+   {"scheme://:just_port", "scheme", NULL, "", "just_port", NULL, NULL, no_queries },
+   {"scheme://:port/and/path", "scheme", NULL, "", "port", "/and/path", NULL, no_queries },
+   {"scheme://just_userinfo@", "scheme", "just_userinfo", "", NULL, NULL, NULL, no_queries },
+   {"scheme://userinfo@/and/path", "scheme", "userinfo", "", NULL, "/and/path", NULL, no_queries },
+   {"scheme://userinfo@:port/and/path", "scheme", "userinfo", "", "port", "/and/path", NULL, no_queries },
+   {"scheme://", "scheme", NULL, "", NULL, NULL, NULL, no_queries },
+   {"scheme://#", "scheme", NULL, "", NULL, NULL, "", no_queries },
+   {"scheme://?q&n=&n=v", "scheme", NULL, "", NULL, NULL, NULL, complex_query},
+   {"ldap://[2001:db8::7]/c=GB?objectClass?one", "ldap", NULL, "[2001:db8::7]", NULL, "/c=GB", NULL, objectClass_one},
+   {"mailto:John.Doe@example.com", "mailto", NULL, NULL, NULL, "John.Doe@example.com", NULL, no_queries },
+   {"news:comp.infosystems.www.servers.unix", "news", NULL, NULL, NULL, "comp.infosystems.www.servers.unix", NULL, no_queries },
+   {"tel:+1-816-555-1212", "tel", NULL, NULL, NULL, "+1-816-555-1212", NULL, no_queries },
+   {"urn:oasis:names:specification:docbook:dtd:xml:4.1.2", "urn", NULL, NULL, NULL, "oasis:names:specification:docbook:dtd:xml:4.1.2", NULL, no_queries },
+};
+
+typedef struct merge_uri_tag
+{
+   const char *base;
+   const char *relative;
+   const char *merged;
+} MERGE_URI_T;
+
+MERGE_URI_T test_merge_uris[] = {
+   /* Normal examples */
+   { "http://a/b/c/d;p?q#f", "ftp:h",     "ftp:h" },
+   { "http://a/b/c/d;p?q#f", "g",         "http://a/b/c/g" },
+   { "http://a/b/c/d;p?q#f", "./g",       "http://a/b/c/g" },
+   { "http://a/b/c/d;p?q#f", "g/",        "http://a/b/c/g/" },
+   { "http://a/b/c/d;p?q#f", "/g",        "http://a/g" },
+   { "http://a/b/c/d;p?q#f", "//g",       "http://g" },
+   { "http://a/b/c/d;p?q#f", "?y",        "http://a/b/c/d;p?y" },
+   { "http://a/b/c/d;p?q#f", "g?y",       "http://a/b/c/g?y" },
+   { "http://a/b/c/d;p?q#f", "g?y/./x",   "http://a/b/c/g?y/./x" },
+   { "http://a/b/c/d;p?q#f", "#s",        "http://a/b/c/d;p?q#s" },
+   { "http://a/b/c/d;p?q#f", "g#s",       "http://a/b/c/g#s" },
+   { "http://a/b/c/d;p?q#f", "g#s/./x",   "http://a/b/c/g#s/./x" },
+   { "http://a/b/c/d;p?q#f", "g?y#s",     "http://a/b/c/g?y#s" },
+   { "http://a/b/c/d;p?q#f", ";x",        "http://a/b/c/d;x" },
+   { "http://a/b/c/d;p?q#f", "g;x",       "http://a/b/c/g;x" },
+   { "http://a/b/c/d;p?q#f", "g;x?y#s",   "http://a/b/c/g;x?y#s" },
+   { "http://a/b/c/d;p?q#f", ".",         "http://a/b/c/" },
+   { "http://a/b/c/d;p?q#f", "./",        "http://a/b/c/" },
+   { "http://a/b/c/d;p?q#f", "..",        "http://a/b/" },
+   { "http://a/b/c/d;p?q#f", "../",       "http://a/b/" },
+   { "http://a/b/c/d;p?q#f", "../g",      "http://a/b/g" },
+   { "http://a/b/c/d;p?q#f", "../..",     "http://a/" },
+   { "http://a/b/c/d;p?q#f", "../../",    "http://a/" },
+   { "http://a/b/c/d;p?q#f", "../../g",   "http://a/g" },
+   /* Normal examples, without base network info */
+   { "http:/b/c/d;p?q#f",    "g",         "http:/b/c/g" },
+   { "http:/b/c/d;p?q#f",    "./g",       "http:/b/c/g" },
+   { "http:/b/c/d;p?q#f",    "g/",        "http:/b/c/g/" },
+   { "http:/b/c/d;p?q#f",    "/g",        "http:/g" },
+   { "http:/b/c/d;p?q#f",    "//g",       "http://g" },
+   { "http:/b/c/d;p?q#f",    "?y",        "http:/b/c/d;p?y" },
+   { "http:/b/c/d;p?q#f",    "g?y",       "http:/b/c/g?y" },
+   { "http:/b/c/d;p?q#f",    "g?y/./x",   "http:/b/c/g?y/./x" },
+   { "http:/b/c/d;p?q#f",    "#s",        "http:/b/c/d;p?q#s" },
+   { "http:/b/c/d;p?q#f",    "g#s",       "http:/b/c/g#s" },
+   { "http:/b/c/d;p?q#f",    "g#s/./x",   "http:/b/c/g#s/./x" },
+   { "http:/b/c/d;p?q#f",    "g?y#s",     "http:/b/c/g?y#s" },
+   { "http:/b/c/d;p?q#f",    ";x",        "http:/b/c/d;x" },
+   { "http:/b/c/d;p?q#f",    "g;x",       "http:/b/c/g;x" },
+   { "http:/b/c/d;p?q#f",    "g;x?y#s",   "http:/b/c/g;x?y#s" },
+   { "http:/b/c/d;p?q#f",    ".",         "http:/b/c/" },
+   { "http:/b/c/d;p?q#f",    "./",        "http:/b/c/" },
+   { "http:/b/c/d;p?q#f",    "..",        "http:/b/" },
+   { "http:/b/c/d;p?q#f",    "../",       "http:/b/" },
+   { "http:/b/c/d;p?q#f",    "../g",      "http:/b/g" },
+   { "http:/b/c/d;p?q#f",    "../..",     "http:/" },
+   { "http:/b/c/d;p?q#f",    "../../",    "http:/" },
+   { "http:/b/c/d;p?q#f",    "../../g",   "http:/g" },
+   /* Normal examples, without base network info or path root */
+   { "http:b/c/d;p?q#f",     "g",         "http:b/c/g" },
+   { "http:b/c/d;p?q#f",     "./g",       "http:b/c/g" },
+   { "http:b/c/d;p?q#f",     "g/",        "http:b/c/g/" },
+   { "http:b/c/d;p?q#f",     "/g",        "http:/g" },
+   { "http:b/c/d;p?q#f",     "//g",       "http://g" },
+   { "http:b/c/d;p?q#f",     "?y",        "http:b/c/d;p?y" },
+   { "http:b/c/d;p?q#f",     "g?y",       "http:b/c/g?y" },
+   { "http:b/c/d;p?q#f",     "g?y/./x",   "http:b/c/g?y/./x" },
+   { "http:b/c/d;p?q#f",     "#s",        "http:b/c/d;p?q#s" },
+   { "http:b/c/d;p?q#f",     "g#s",       "http:b/c/g#s" },
+   { "http:b/c/d;p?q#f",     "g#s/./x",   "http:b/c/g#s/./x" },
+   { "http:b/c/d;p?q#f",     "g?y#s",     "http:b/c/g?y#s" },
+   { "http:b/c/d;p?q#f",     ";x",        "http:b/c/d;x" },
+   { "http:b/c/d;p?q#f",     "g;x",       "http:b/c/g;x" },
+   { "http:b/c/d;p?q#f",     "g;x?y#s",   "http:b/c/g;x?y#s" },
+   { "http:b/c/d;p?q#f",     ".",         "http:b/c/" },
+   { "http:b/c/d;p?q#f",     "./",        "http:b/c/" },
+   { "http:b/c/d;p?q#f",     "..",        "http:b/" },
+   { "http:b/c/d;p?q#f",     "../",       "http:b/" },
+   { "http:b/c/d;p?q#f",     "../g",      "http:b/g" },
+   { "http:b/c/d;p?q#f",     "../..",     "http:" },
+   { "http:b/c/d;p?q#f",     "../../",    "http:" },
+   { "http:b/c/d;p?q#f",     "../../g",   "http:g" },
+   /* Normal examples, without base path */
+   { "http://a?q#f",         "g",         "http://a/g" },
+   { "http://a?q#f",         "./g",       "http://a/g" },
+   { "http://a?q#f",         "g/",        "http://a/g/" },
+   { "http://a?q#f",         "/g",        "http://a/g" },
+   { "http://a?q#f",         "//g",       "http://g" },
+   { "http://a?q#f",         "?y",        "http://a?y" },
+   { "http://a?q#f",         "g?y",       "http://a/g?y" },
+   { "http://a?q#f",         "g?y/./x",   "http://a/g?y/./x" },
+   { "http://a?q#f",         "#s",        "http://a?q#s" },
+   { "http://a?q#f",         "g#s",       "http://a/g#s" },
+   { "http://a?q#f",         "g#s/./x",   "http://a/g#s/./x" },
+   { "http://a?q#f",         "g?y#s",     "http://a/g?y#s" },
+   { "http://a?q#f",         ";x",        "http://a/;x" },
+   { "http://a?q#f",         "g;x",       "http://a/g;x" },
+   { "http://a?q#f",         "g;x?y#s",   "http://a/g;x?y#s" },
+   { "http://a?q#f",         ".",         "http://a/" },
+   { "http://a?q#f",         "./",        "http://a/" },
+   /* Normal examples, without base network info or path */
+   { "http:?q#f",            "g",         "http:g" },
+   { "http:?q#f",            "./g",       "http:g" },
+   { "http:?q#f",            "g/",        "http:g/" },
+   { "http:?q#f",            "/g",        "http:/g" },
+   { "http:?q#f",            "//g",       "http://g" },
+   { "http:?q#f",            "?y",        "http:?y" },
+   { "http:?q#f",            "g?y",       "http:g?y" },
+   { "http:?q#f",            "g?y/./x",   "http:g?y/./x" },
+   { "http:?q#f",            "#s",        "http:?q#s" },
+   { "http:?q#f",            "g#s",       "http:g#s" },
+   { "http:?q#f",            "g#s/./x",   "http:g#s/./x" },
+   { "http:?q#f",            "g?y#s",     "http:g?y#s" },
+   { "http:?q#f",            ";x",        "http:;x" },
+   { "http:?q#f",            "g;x",       "http:g;x" },
+   { "http:?q#f",            "g;x?y#s",   "http:g;x?y#s" },
+   /* Abnormal (but valid) examples */
+   { "http://a/b/c/d;p?q#f", "../../../g", "http://a/../g" },
+   { "http://a/b/c/d;p?q#f", "../../../../g", "http://a/../../g" },
+   { "http://a/b/c/d;p?q#f", "/./g",      "http://a/./g" },
+   { "http://a/b/c/d;p?q#f", "/../g",     "http://a/../g" },
+   { "http://a/b/c/d;p?q#f", "g.",        "http://a/b/c/g." },
+   { "http://a/b/c/d;p?q#f", ".g",        "http://a/b/c/.g" },
+   { "http://a/b/c/d;p?q#f", "g..",       "http://a/b/c/g.." },
+   { "http://a/b/c/d;p?q#f", "..g",       "http://a/b/c/..g" },
+   { "http://a/b/c/d;p?q#f", "./../g",    "http://a/b/g" },
+   { "http://a/b/c/d;p?q#f", "./g/.",     "http://a/b/c/g/" },
+   { "http://a/b/c/d;p?q#f", "g/./h",     "http://a/b/c/g/h" },
+   { "http://a/b/c/d;p?q#f", "g/../h",    "http://a/b/c/h" },
+   { "http://a/b/c/d;p?q#f", "./g:h",     "http://a/b/c/g:h" },
+   { "http://a/b/c/d;p?q#f", "g/..",      "http://a/b/c/" },
+   /* Abnormal examples without base path */
+   { "http://a?q#f",         "../g",      "http://a/../g" },
+   { "http://a?q#f",         "./../g",    "http://a/../g" },
+   /* Abnormal examples without base network info or path */
+   { "http:?q#f",            "../g",      "http:../g" },
+   { "http:?q#f",            "./../g",    "http:../g" },
+   { "http:?q#f",            ".",         "http:" },
+   { "http:?q#f",            "./",        "http:" },
+};
+
+
+/** Dump a URI structure to the log.
+ *
+ * \param uri URI structure to be dumped. */
+static void dump_uri(VC_URI_PARTS_T *uri)
+{
+   const char *str;
+   uint32_t query_count, ii;
+
+   str = vc_uri_scheme(uri);
+   if (str)
+      LOG_DEBUG(NULL, "Scheme: <%s>", str);
+
+   str = vc_uri_userinfo(uri);
+   if (str)
+      LOG_DEBUG(NULL, "Userinfo: <%s>", str);
+
+   str = vc_uri_host(uri);
+   if (str)
+      LOG_DEBUG(NULL, "Host: <%s>", str);
+
+   str = vc_uri_port(uri);
+   if (str)
+      LOG_DEBUG(NULL, "Port: <%s>", str);
+
+   str = vc_uri_path(uri);
+   if (str)
+      LOG_DEBUG(NULL, "Path: <%s>", str);
+
+   query_count = vc_uri_num_queries(uri);
+   for (ii = 0; ii < query_count; ii++)
+   {
+      const char *value;
+
+      vc_uri_query(uri, ii, &str, &value);
+      if (str)
+      {
+         if (value)
+            LOG_DEBUG(NULL, "Query %d: <%s>=<%s>", ii, str, value);
+         else
+            LOG_DEBUG(NULL, "Query %d: <%s>", ii, str);
+      }
+   }
+
+   str = vc_uri_fragment(uri);
+   if (str)
+      LOG_DEBUG(NULL, "Fragment: <%s>", str);
+}
+
+static int check_uri(VC_URI_PARTS_T *uri, const char *expected)
+{
+   uint32_t built_len;
+   char *built;
+
+   built_len = vc_uri_build(uri, NULL, 0) + 1;
+   built = (char *)malloc(built_len);
+   if (!built)
+   {
+      LOG_ERROR(NULL, "*** Unexpected memory allocation failure: %d bytes", built_len);
+      return 1;
+   }
+
+   vc_uri_build(uri, built, built_len);
+
+   if (strcmp(built, expected) != 0)
+   {
+      LOG_ERROR(NULL, "*** Built URI <%s>\nexpected  <%s>", built, expected);
+      free(built);
+      return 1;
+   }
+
+   free(built);
+
+   return 0;
+}
+
+static int check_null_uri_pointer(void)
+{
+   int error_count = 0;
+   char buffer[1];
+
+   /* Check NULL URI can be passed without failure to all routines */
+   vc_uri_release( NULL );
+   vc_uri_clear( NULL );
+   if (vc_uri_parse( NULL, NULL ))
+      error_count++;
+   if (vc_uri_parse( NULL, "" ))
+      error_count++;
+   if (vc_uri_build( NULL, NULL, 0 ) != 0)
+      error_count++;
+   buffer[0] = TEST_CHAR;
+   if (vc_uri_build( NULL, buffer, sizeof(buffer) ) != 0)
+      error_count++;
+   if (buffer[0] != TEST_CHAR)
+      error_count++;
+   if (vc_uri_scheme( NULL ))
+      error_count++;
+   if (vc_uri_userinfo( NULL ))
+      error_count++;
+   if (vc_uri_host( NULL ))
+      error_count++;
+   if (vc_uri_port( NULL ))
+      error_count++;
+   if (vc_uri_path( NULL ))
+      error_count++;
+   if (vc_uri_fragment( NULL ))
+      error_count++;
+   if (vc_uri_num_queries( NULL ) != 0)
+      error_count++;
+   vc_uri_query( NULL, 0, NULL, NULL );
+   if (vc_uri_set_scheme( NULL, NULL ))
+      error_count++;
+   if (vc_uri_set_userinfo( NULL, NULL ))
+      error_count++;
+   if (vc_uri_set_host( NULL, NULL ))
+      error_count++;
+   if (vc_uri_set_port( NULL, NULL ))
+      error_count++;
+   if (vc_uri_set_path( NULL, NULL ))
+      error_count++;
+   if (vc_uri_set_fragment( NULL, NULL ))
+      error_count++;
+   if (vc_uri_add_query( NULL, NULL, NULL ))
+      error_count++;
+
+   if (error_count)
+      LOG_ERROR(NULL, "NULL URI parameter testing failed");
+
+   return error_count;
+}
+
+static int check_parse_parameters(VC_URI_PARTS_T *uri)
+{
+   int error_count = 0;
+
+   if (vc_uri_parse( uri, NULL ))
+   {
+      LOG_ERROR(NULL, "Parsing NULL URI failed");
+      error_count++;
+   }
+
+   return error_count;
+}
+
+static int check_build_parameters(VC_URI_PARTS_T *uri)
+{
+   int error_count = 0;
+   char buffer[1];
+
+   vc_uri_set_path( uri, TEST_STRING );
+
+   if (vc_uri_build( uri, NULL, 0 ) != strlen(TEST_STRING))
+   {
+      LOG_ERROR(NULL, "Retrieving URI length failed");
+      error_count++;
+   }
+
+   buffer[0] = TEST_CHAR;
+   if (vc_uri_build( uri, buffer, 1 ) != strlen(TEST_STRING))
+   {
+      LOG_ERROR(NULL, "Building URI to small buffer failed");
+      error_count++;
+   }
+   if (buffer[0] != TEST_CHAR)
+   {
+      LOG_ERROR(NULL, "Building URI to small buffer modified buffer");
+      error_count++;
+   }
+
+   vc_uri_set_path( uri, NULL );    /* Reset uri */
+
+   return error_count;
+}
+
+static int check_get_defaults(VC_URI_PARTS_T *uri)
+{
+   int error_count = 0;
+   const char *name = NULL, *value = NULL;
+   char buffer[1];
+
+   if (vc_uri_scheme( uri ))
+      error_count++;
+   if (vc_uri_userinfo( uri ))
+      error_count++;
+   if (vc_uri_host( uri ))
+      error_count++;
+   if (vc_uri_port( uri ))
+      error_count++;
+   if (vc_uri_path( uri ))
+      error_count++;
+   if (vc_uri_fragment( uri ))
+      error_count++;
+   if (vc_uri_num_queries( uri ) != 0)
+      error_count++;
+
+   vc_uri_query( uri, 0, &name, &value );
+   if (name != NULL || value != NULL)
+      error_count++;
+
+   if (vc_uri_build(uri, NULL, 0) != 0)
+      error_count++;
+   buffer[0] = ~*TEST_STRING;    /* Initialize with something */
+   vc_uri_build(uri, buffer, sizeof(buffer));
+   if (buffer[0] != '\0')        /* Expect empty string */
+      error_count++;
+
+   if (error_count)
+      LOG_ERROR(NULL, "Getting default values gave unexpected values");
+
+   return error_count;
+}
+
+static int check_accessors(VC_URI_PARTS_T *uri)
+{
+   int error_count = 0;
+   const char *str;
+
+   if (vc_uri_set_scheme( uri, TEST_STRING ))
+   {
+      str = vc_uri_scheme(uri);
+      if (!str || strcmp(TEST_STRING, str))
+         error_count++;
+      if (!vc_uri_set_scheme( uri, NULL ))
+         error_count++;
+      if (vc_uri_scheme(uri))
+         error_count++;
+   } else
+      error_count++;
+
+   if (vc_uri_set_userinfo( uri, TEST_STRING ))
+   {
+      str = vc_uri_userinfo(uri);
+      if (!str || strcmp(TEST_STRING, str))
+         error_count++;
+      if (!vc_uri_set_userinfo( uri, NULL ))
+         error_count++;
+      if (vc_uri_userinfo(uri))
+         error_count++;
+   } else
+      error_count++;
+
+   if (vc_uri_set_host( uri, TEST_STRING ))
+   {
+      str = vc_uri_host(uri);
+      if (!str || strcmp(TEST_STRING, str))
+         error_count++;
+      if (!vc_uri_set_host( uri, NULL ))
+         error_count++;
+      if (vc_uri_host(uri))
+         error_count++;
+   } else
+      error_count++;
+
+   if (vc_uri_set_port( uri, TEST_STRING ))
+   {
+      str = vc_uri_port(uri);
+      if (!str || strcmp(TEST_STRING, str))
+         error_count++;
+      if (!vc_uri_set_port( uri, NULL ))
+         error_count++;
+      if (vc_uri_port(uri))
+         error_count++;
+   } else
+      error_count++;
+
+   if (vc_uri_set_path( uri, TEST_STRING ))
+   {
+      str = vc_uri_path(uri);
+      if (!str || strcmp(TEST_STRING, str))
+         error_count++;
+      if (!vc_uri_set_path( uri, NULL ))
+         error_count++;
+      if (vc_uri_path(uri))
+         error_count++;
+   } else
+      error_count++;
+
+   if (vc_uri_set_fragment( uri, TEST_STRING ))
+   {
+      str = vc_uri_fragment(uri);
+      if (!str || strcmp(TEST_STRING, str))
+         error_count++;
+      if (!vc_uri_set_fragment( uri, NULL ))
+         error_count++;
+      if (vc_uri_fragment(uri))
+         error_count++;
+   } else
+      error_count++;
+
+   if (vc_uri_add_query( uri, NULL, NULL ))
+      error_count++;
+   if (vc_uri_add_query( uri, NULL, TEST_VALUE ))
+      error_count++;
+   if (!vc_uri_add_query( uri, TEST_STRING, NULL ))
+      error_count++;
+   if (!vc_uri_add_query( uri, TEST_NAME, TEST_VALUE ))
+      error_count++;
+
+   if (vc_uri_num_queries(uri) == 2)
+   {
+      const char *name = NULL, *value = NULL;
+
+      vc_uri_query(uri, 0, &name, &value);
+      if (!name || strcmp(TEST_STRING, name))
+         error_count++;
+      if (value)
+         error_count++;
+
+      vc_uri_query(uri, 1, &name, &value);
+      if (!name || strcmp(TEST_NAME, name))
+         error_count++;
+      if (!value || strcmp(TEST_VALUE, value))
+         error_count++;
+   } else
+      error_count++;
+
+   if (error_count)
+      LOG_ERROR(NULL, "Accessors failed");
+
+   return error_count;
+}
+
+/** Test parameter validation
+ *
+ * \param uri Pre-created URI structure.
+ * \return 1 on error, 0 on success. */
+static int test_parameter_validation(VC_URI_PARTS_T *uri)
+{
+   int error_count = 0;
+
+   error_count += check_null_uri_pointer();
+   error_count += check_get_defaults(uri);
+   error_count += check_parse_parameters(uri);
+   error_count += check_build_parameters(uri);
+   error_count += check_accessors(uri);
+
+   return error_count;
+}
+
+/** Test parsing and rebuilding a URI.
+ *
+ * \param uri Pre-created URI structure.
+ * \param original The original URI string.
+ * \param expected The expected, re-built string, or NULL if original is expected.
+ * \return 1 on error, 0 on success. */
+static int test_parsing_uri(VC_URI_PARTS_T *uri, const char *original, const char *expected)
+{
+   bool parsed;
+
+   LOG_INFO(NULL, "URI: <%s>", original);
+
+   parsed = vc_uri_parse( uri, original );
+   if (!parsed)
+   {
+      LOG_ERROR(NULL, "*** Expected <%s> to parse, but it didn't", original);
+      return 1;
+   }
+
+   dump_uri(uri);
+
+   return check_uri(uri, expected ? expected : original);
+}
+
+/** Test building a URI from component parts.
+ *
+ * \param uri Pre-created URI structure.
+ * \param uri_data The data for building the URI and the expected output.
+ * \return 1 on error, 0 on success. */
+static int test_building_uri(VC_URI_PARTS_T *uri, BUILD_URI_T *uri_data)
+{
+   const char **p_str;
+   const char *name, *value;
+
+   LOG_INFO(NULL, "Building URI <%s>", uri_data->expected_uri);
+
+   vc_uri_clear(uri);
+
+   if (!vc_uri_set_scheme(uri, uri_data->scheme))
+   {
+      LOG_ERROR(NULL, "*** Failed to set scheme");
+      return 1;
+   }
+
+   if (!vc_uri_set_userinfo(uri, uri_data->userinfo))
+   {
+      LOG_ERROR(NULL, "*** Failed to set userinfo");
+      return 1;
+   }
+
+   if (!vc_uri_set_host(uri, uri_data->host))
+   {
+      LOG_ERROR(NULL, "*** Failed to set host");
+      return 1;
+   }
+
+   if (!vc_uri_set_port(uri, uri_data->port))
+   {
+      LOG_ERROR(NULL, "*** Failed to set port");
+      return 1;
+   }
+
+   if (!vc_uri_set_path(uri, uri_data->path))
+   {
+      LOG_ERROR(NULL, "*** Failed to set path");
+      return 1;
+   }
+
+   if (!vc_uri_set_fragment(uri, uri_data->fragment))
+   {
+      LOG_ERROR(NULL, "*** Failed to set fragment");
+      return 1;
+   }
+
+   p_str = uri_data->queries;
+   name = *p_str++;
+
+   while (name)
+   {
+      value = *p_str++;
+      if (!vc_uri_add_query(uri, name, value))
+      {
+         LOG_ERROR(NULL, "*** Failed to add query");
+         return 1;
+      }
+      name = *p_str++;
+   }
+
+   dump_uri(uri);
+
+   return check_uri(uri, uri_data->expected_uri);
+}
+
+/** Test merging a relative URI with a base URI.
+ *
+ * \param uri Pre-created URI structure.
+ * \param uri_data The nase and relative URIs and the expected output.
+ * \return 1 on error, 0 on success. */
+static int test_merging_uri(VC_URI_PARTS_T *uri, MERGE_URI_T *uri_data)
+{
+   VC_URI_PARTS_T *base_uri;
+
+   LOG_INFO(NULL, "Base <%s>, relative <%s>, expect <%s>", uri_data->base, uri_data->relative, uri_data->merged);
+
+   vc_uri_clear(uri);
+   base_uri = vc_uri_create();
+   if (!base_uri)
+   {
+      LOG_ERROR(NULL, "*** Failed to allocate base URI structure");
+      return 1;
+   }
+
+   if (!vc_uri_parse(base_uri, uri_data->base))
+   {
+      LOG_ERROR(NULL, "*** Failed to parse base URI structure");
+      return 1;
+   }
+   if (!vc_uri_parse(uri, uri_data->relative))
+   {
+      LOG_ERROR(NULL, "*** Failed to parse relative URI structure");
+      return 1;
+   }
+
+   if (!vc_uri_merge(base_uri, uri))
+   {
+      LOG_ERROR(NULL, "*** Failed to merge base and relative URIs");
+      return 1;
+   }
+
+   vc_uri_release(base_uri);
+
+   return check_uri(uri, uri_data->merged);
+}
+
+int main(int argc, char **argv)
+{
+   VC_URI_PARTS_T *uri;
+   int error_count = 0;
+   size_t ii;
+
+   uri = vc_uri_create();
+   if (!uri)
+   {
+      LOG_ERROR(NULL, "*** Failed to create URI structure.");
+      return 1;
+   }
+
+   LOG_INFO(NULL, "Test parameter validation");
+   error_count +=  test_parameter_validation(uri);
+
+   LOG_INFO(NULL, "Test parsing URIs:");
+   for (ii = 0; ii < ARRAY_SIZE(test_parse_uris); ii++)
+   {
+      error_count += test_parsing_uri(uri, test_parse_uris[ii].before, test_parse_uris[ii].after);
+   }
+
+   LOG_INFO(NULL, "Test building URIs:");
+   for (ii = 0; ii < ARRAY_SIZE(test_build_uris); ii++)
+   {
+      error_count += test_building_uri(uri, &test_build_uris[ii]);
+   }
+
+   LOG_INFO(NULL, "Test merging URIs:");
+   for (ii = 0; ii < ARRAY_SIZE(test_merge_uris); ii++)
+   {
+      error_count += test_merging_uri(uri, &test_merge_uris[ii]);
+   }
+
+   if (argc > 1)
+   {
+      LOG_INFO(NULL, "Test parsing URIs from command line:");
+
+      while (argc-- > 1)
+      {
+         /* Test URIs passed on the command line are expected to parse and to
+          * match themselves when rebuilt. */
+         error_count += test_parsing_uri(uri, argv[argc], NULL);
+      }
+   }
+
+   vc_uri_release(uri);
+
+   if (error_count)
+      LOG_ERROR(NULL, "*** %d errors reported", error_count);
+
+#ifdef _MSC_VER
+   LOG_INFO(NULL, "Press return to complete test.");
+   getchar();
+#endif
+
+   return error_count;
+}
diff --git a/containers/test/uri_pipe.c b/containers/test/uri_pipe.c
new file mode 100755 (executable)
index 0000000..6dd6072
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+
+#include "containers/containers.h"
+#include "containers/core/containers_logging.h"
+#include "containers/core/containers_io.h"
+
+#include "nb_io.h"
+
+#define MAX_BUFFER_SIZE 2048
+
+int main(int argc, char **argv)
+{
+   char buffer[MAX_BUFFER_SIZE];
+   VC_CONTAINER_IO_T *read_io, *write_io;
+   VC_CONTAINER_STATUS_T status;
+   size_t received;
+   bool ready = true;
+
+   if (argc < 3)
+   {
+      LOG_INFO(NULL, "Usage:\n%s <read URI> <write URI>\n", argv[0]);
+      return 1;
+   }
+
+   read_io = vc_container_io_open(argv[1], VC_CONTAINER_IO_MODE_READ, &status);
+   if (!read_io)
+   {
+      LOG_INFO(NULL, "Opening <%s> for read failed: %d\n", argv[1], status);
+      return 2;
+   }
+
+   write_io = vc_container_io_open(argv[2], VC_CONTAINER_IO_MODE_WRITE, &status);
+   if (!write_io)
+   {
+      vc_container_io_close(read_io);
+      LOG_INFO(NULL, "Opening <%s> for write failed: %d\n", argv[2], status);
+      return 3;
+   }
+
+   nb_set_nonblocking_input(1);
+
+   while (ready)
+   {
+      size_t total_written = 0;
+
+      received = vc_container_io_read(read_io, buffer, sizeof(buffer));
+      while (ready && total_written < received)
+      {
+         total_written += vc_container_io_write(write_io, buffer + total_written, received - total_written);
+         ready &= (write_io->status == VC_CONTAINER_SUCCESS);
+      }
+      ready &= (read_io->status == VC_CONTAINER_SUCCESS);
+
+      if (nb_char_available())
+      {
+         char c = nb_get_char();
+
+         switch (c)
+         {
+         case 'q':
+         case 'Q':
+         case 0x04:  /* CTRL+D */
+         case 0x1A:  /* CTRL+Z */
+         case 0x1B:  /* Escape */
+            ready = false;
+            break;
+         default:
+            ;/* Do nothing */
+         }
+      }
+   }
+
+   if (read_io->status != VC_CONTAINER_SUCCESS && read_io->status != VC_CONTAINER_ERROR_EOS)
+   {
+      LOG_INFO(NULL, "Read failed: %d\n", read_io->status);
+   }
+
+   if (write_io->status != VC_CONTAINER_SUCCESS)
+   {
+      LOG_INFO(NULL, "Write failed: %d\n", write_io->status);
+   }
+
+   vc_container_io_close(read_io);
+   vc_container_io_close(write_io);
+
+   nb_set_nonblocking_input(0);
+
+   return 0;
+}
diff --git a/containers/wav/CMakeLists.txt b/containers/wav/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..aed61c6
--- /dev/null
@@ -0,0 +1,13 @@
+# Container module needs to go in as a plugins so different prefix
+# and install path
+set(CMAKE_SHARED_LIBRARY_PREFIX "")
+
+# Make sure the compiler can find the necessary include files
+include_directories (../..)
+
+add_library(reader_wav ${LIBRARY_TYPE} wav_reader.c)
+
+target_link_libraries(reader_wav containers)
+
+install(TARGETS reader_wav DESTINATION ${VMCS_PLUGIN_DIR})
+
diff --git a/containers/wav/wav_reader.c b/containers/wav/wav_reader.c
new file mode 100755 (executable)
index 0000000..0b279ba
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <string.h>
+
+#define CONTAINER_IS_LITTLE_ENDIAN
+//#define ENABLE_CONTAINERS_LOG_FORMAT
+//#define ENABLE_CONTAINERS_LOG_FORMAT_VERBOSE
+#define CONTAINER_HELPER_LOG_INDENT(a) 0
+#include "containers/core/containers_private.h"
+#include "containers/core/containers_io_helpers.h"
+#include "containers/core/containers_utils.h"
+#include "containers/core/containers_logging.h"
+#include "containers/core/containers_waveformat.h"
+
+/******************************************************************************
+Defines.
+******************************************************************************/
+#define WAV_EXTRADATA_MAX 16
+#define BLOCK_SIZE (16*1024)
+
+/******************************************************************************
+GUID list for the different codecs
+******************************************************************************/
+static const GUID_T atracx_guid = {0xbfaa23e9, 0x58cb, 0x7144, {0xa1, 0x19, 0xff, 0xfa, 0x01, 0xe4, 0xce, 0x62}};
+static const GUID_T pcm_guid = {0x00000001, 0x0000, 0x0010, {0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}};
+
+/******************************************************************************
+Type definitions
+******************************************************************************/
+typedef struct VC_CONTAINER_MODULE_T
+{
+   uint64_t data_offset; /**< Offset to the start of the data packets */
+   int64_t data_size;    /**< Size of the data contained in the data element */
+   uint32_t block_size;   /**< Size of a block of audio data */
+   int64_t position;
+   uint64_t frame_data_left;
+
+   VC_CONTAINER_TRACK_T *track;
+   uint8_t extradata[WAV_EXTRADATA_MAX];
+
+} VC_CONTAINER_MODULE_T;
+
+/******************************************************************************
+Function prototypes
+******************************************************************************/
+VC_CONTAINER_STATUS_T wav_reader_open( VC_CONTAINER_T * );
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+
+/*****************************************************************************
+Functions exported as part of the Container Module API
+ *****************************************************************************/
+
+static VC_CONTAINER_STATUS_T wav_reader_read( VC_CONTAINER_T *p_ctx,
+                                              VC_CONTAINER_PACKET_T *p_packet, uint32_t flags )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   uint32_t packet_flags = 0, size, data_size;
+   int64_t pts;
+
+   pts = module->position * 8000000 / p_ctx->tracks[0]->format->bitrate;
+   data_size = module->frame_data_left;
+   if(!data_size)
+   {
+      data_size = module->block_size;
+      packet_flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
+   }
+   module->frame_data_left = 0;
+
+   if(module->position + data_size > module->data_size)
+      data_size = module->data_size - module->position;
+   if(data_size == 0) return VC_CONTAINER_ERROR_EOS;
+
+   if((flags & VC_CONTAINER_READ_FLAG_SKIP) && !(flags & VC_CONTAINER_READ_FLAG_INFO)) /* Skip packet */
+   {
+      size = SKIP_BYTES(p_ctx, data_size);
+      module->frame_data_left = data_size - size;
+      module->position += size;
+      return STREAM_STATUS(p_ctx);
+   }
+
+   p_packet->flags = packet_flags;
+   p_packet->dts = p_packet->pts = pts;
+   p_packet->track = 0;
+
+   if(flags & VC_CONTAINER_READ_FLAG_SKIP)
+   {
+      size = SKIP_BYTES(p_ctx, data_size);
+      module->frame_data_left = data_size - size;
+      if(!module->frame_data_left) p_packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
+      module->position += size;
+      p_packet->size += size;
+      return STREAM_STATUS(p_ctx);
+   }
+
+   if(flags & VC_CONTAINER_READ_FLAG_INFO)
+      return VC_CONTAINER_SUCCESS;
+
+   size = MIN(data_size, p_packet->buffer_size - p_packet->size);
+   size = READ_BYTES(p_ctx, p_packet->data, size);
+   module->frame_data_left = data_size - size;
+   if(!module->frame_data_left) p_packet->flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
+   module->position += size;
+   p_packet->size += size;
+
+   return STREAM_STATUS(p_ctx);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T wav_reader_seek( VC_CONTAINER_T *p_ctx, int64_t *p_offset,
+   VC_CONTAINER_SEEK_MODE_T mode, VC_CONTAINER_SEEK_FLAGS_T flags)
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   int64_t position;
+   VC_CONTAINER_PARAM_UNUSED(mode);
+   VC_CONTAINER_PARAM_UNUSED(flags);
+
+   position = *p_offset * p_ctx->tracks[0]->format->bitrate / 8000000;
+   if(p_ctx->tracks[0]->format->type->audio.block_align)
+      position = position / p_ctx->tracks[0]->format->type->audio.block_align *
+         p_ctx->tracks[0]->format->type->audio.block_align;
+   if(position > module->data_size) position = module->data_size;
+
+   module->position = position;
+   module->frame_data_left = 0;
+
+   if(position >= module->data_size) return VC_CONTAINER_ERROR_EOS;
+   return SEEK(p_ctx, module->data_offset + position);
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_STATUS_T wav_reader_close( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = p_ctx->priv->module;
+   unsigned int i;
+
+   for(i = 0; i < p_ctx->tracks_num; i++)
+      vc_container_free_track(p_ctx, p_ctx->tracks[i]);
+   free(module);
+   return VC_CONTAINER_SUCCESS;
+}
+
+/*****************************************************************************/
+VC_CONTAINER_STATUS_T wav_reader_open( VC_CONTAINER_T *p_ctx )
+{
+   VC_CONTAINER_MODULE_T *module = 0;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_SUCCESS;
+   VC_CONTAINER_FOURCC_T codec;
+   int64_t chunk_size, chunk_pos;
+   uint32_t format, channels, samplerate, bitrate, block_align, bps, cbsize = 0;
+   uint8_t buffer[12];
+
+   /* Check the RIFF chunk descriptor */
+   if( PEEK_BYTES(p_ctx, buffer, 12) != 12 )
+     return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   if( VC_FOURCC(buffer[0], buffer[1], buffer[2], buffer[3]) !=
+       VC_FOURCC('R','I','F','F') )
+     return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+   if( VC_FOURCC(buffer[8], buffer[9], buffer[10], buffer[11]) !=
+       VC_FOURCC('W','A','V','E') )
+     return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+
+   /*
+    *  We are dealing with a WAV file
+    */
+   SKIP_FOURCC(p_ctx, "Chunk ID");
+   SKIP_U32(p_ctx, "Chunk size");
+   SKIP_FOURCC(p_ctx, "WAVE ID");
+
+   /* We're looking for the 'fmt' sub-chunk */
+   do {
+      chunk_pos = STREAM_POSITION(p_ctx) + 8;
+      if( READ_FOURCC(p_ctx, "Chunk ID") == VC_FOURCC('f','m','t',' ') ) break;
+
+      /* Not interested in this chunk. Skip it. */
+      chunk_size = READ_U32(p_ctx, "Chunk size");
+      SKIP_BYTES(p_ctx, chunk_size);
+   } while(STREAM_STATUS(p_ctx) == VC_CONTAINER_SUCCESS);
+
+   if(STREAM_STATUS(p_ctx) != VC_CONTAINER_SUCCESS)
+      return VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED; /* 'fmt' not found */
+
+   /* Parse the 'fmt' sub-chunk */
+   chunk_size  = READ_U32(p_ctx, "Chunk size");
+   format      = READ_U16(p_ctx, "wFormatTag");
+   channels    = READ_U16(p_ctx, "nChannels");
+   samplerate  = READ_U32(p_ctx, "nSamplesPerSec");
+   bitrate     = READ_U32(p_ctx, "nAvgBytesPerSec") * 8;
+   block_align = READ_U16(p_ctx, "nBlockAlign");
+   bps         = READ_U16(p_ctx, "wBitsPerSample");
+
+   if(STREAM_POSITION(p_ctx) - chunk_pos <= chunk_size - 2)
+      cbsize = READ_U16(p_ctx, "cbSize");
+
+   if(format == WAVE_FORMAT_EXTENSIBLE &&
+      chunk_size >= 18 + 22 && cbsize >= 22)
+   {
+      GUID_T guid;
+      codec = VC_CONTAINER_CODEC_UNKNOWN;
+
+      SKIP_U16(p_ctx, "wValidBitsPerSample");
+      SKIP_U32(p_ctx, "dwChannelMask");
+      READ_GUID(p_ctx, &guid, "SubFormat");
+
+      if(!memcmp(&guid, &pcm_guid, sizeof(guid)))
+         codec = VC_CONTAINER_CODEC_PCM_SIGNED_LE;
+      else if(!memcmp(&guid, &atracx_guid, sizeof(guid)))
+         codec = VC_CONTAINER_CODEC_ATRAC3;
+
+      cbsize -= 22;
+
+      /* TODO: deal with channel mapping */
+   }
+   else
+   {
+      codec = waveformat_to_codec(format);
+   }
+
+   /* Bail out if we don't recognise the codec */
+   if(codec == VC_CONTAINER_CODEC_UNKNOWN)
+      return VC_CONTAINER_ERROR_FORMAT_FEATURE_NOT_SUPPORTED;
+
+   /* Do some sanity checking on the info we got */
+   if(!channels || !samplerate || !block_align || !bitrate)
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+   if(codec == VC_CONTAINER_CODEC_ATRAC3 && channels > 2)
+      return VC_CONTAINER_ERROR_FORMAT_INVALID;
+
+   /* Allocate our context */
+   module = malloc(sizeof(*module));
+   if(!module) { status = VC_CONTAINER_ERROR_OUT_OF_MEMORY; goto error; }
+   memset(module, 0, sizeof(*module));
+   p_ctx->priv->module = module;
+   p_ctx->tracks_num = 1;
+   p_ctx->tracks = &module->track;
+   p_ctx->tracks[0] = vc_container_allocate_track(p_ctx, 0);
+   if(!p_ctx->tracks[0]) return VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+
+   p_ctx->tracks[0]->format->es_type = VC_CONTAINER_ES_TYPE_AUDIO;
+   p_ctx->tracks[0]->format->codec = codec;
+   p_ctx->tracks[0]->format->type->audio.channels = channels;
+   p_ctx->tracks[0]->format->type->audio.sample_rate = samplerate;
+   p_ctx->tracks[0]->format->type->audio.block_align = block_align;
+   p_ctx->tracks[0]->format->type->audio.bits_per_sample = bps;
+   p_ctx->tracks[0]->format->bitrate = bitrate;
+   p_ctx->tracks[0]->is_enabled = true;
+   p_ctx->tracks[0]->format->extradata_size = 0;
+   p_ctx->tracks[0]->format->extradata = module->extradata;
+   module->block_size = block_align;
+
+   /* Prepare the codec extradata */
+   if(codec == VC_CONTAINER_CODEC_ATRAC3)
+   {
+      uint16_t h, mode;
+
+      SKIP_U16(p_ctx, "len");
+      SKIP_U16(p_ctx, "layer");
+      SKIP_U32(p_ctx, "bytes_per_frame");
+      mode = READ_U16(p_ctx, "mode");
+      SKIP_U16(p_ctx, "mode_ext");
+      SKIP_U16(p_ctx, "num_subframes");
+      SKIP_U16(p_ctx, "flags");
+
+      h = (1 << 15);
+      if(channels == 2)
+      {
+         h |= (1 << 13);
+         if(mode == 1) h |= (1 << 14);
+      }
+      h |= block_align & 0x7ff;
+
+      p_ctx->tracks[0]->format->extradata[0] = h >> 8;
+      p_ctx->tracks[0]->format->extradata[1] = h & 255;
+      p_ctx->tracks[0]->format->extradata_size = 2;
+   }
+   else if(codec == VC_CONTAINER_CODEC_ATRACX && cbsize >= 6)
+   {
+      SKIP_BYTES(p_ctx, 2);
+      p_ctx->tracks[0]->format->extradata_size =
+         READ_BYTES(p_ctx, p_ctx->tracks[0]->format->extradata, 6);
+   }
+   else if(codec == VC_CONTAINER_CODEC_PCM_SIGNED_LE)
+   {
+      /* Audioplus can no longer be given anything other than a multiple-of-16 number of samples */
+      block_align *= 16;
+      module->block_size = (BLOCK_SIZE / block_align) * block_align;
+   }
+
+   /* Skip the rest of the 'fmt' sub-chunk */
+   SKIP_BYTES(p_ctx, chunk_pos + chunk_size - STREAM_POSITION(p_ctx));
+
+   /* We also need the 'data' sub-chunk */
+   do {
+      chunk_pos = STREAM_POSITION(p_ctx) + 8;
+      if( READ_FOURCC(p_ctx, "Chunk ID") == VC_FOURCC('d','a','t','a') ) break;
+
+      /* Not interested in this chunk. Skip it. */
+      chunk_size = READ_U32(p_ctx, "Chunk size");
+      SKIP_BYTES(p_ctx, chunk_size);
+   } while(STREAM_STATUS(p_ctx) == VC_CONTAINER_SUCCESS);
+
+   if(STREAM_STATUS(p_ctx) != VC_CONTAINER_SUCCESS)
+   {
+      status = VC_CONTAINER_ERROR_FORMAT_INVALID; /* 'data' not found */;
+      goto error;
+   }
+
+   module->data_offset = chunk_pos;
+   module->data_size = READ_U32(p_ctx, "Chunk size");
+   p_ctx->duration = module->data_size * 8000000 / bitrate;
+   if(STREAM_SEEKABLE(p_ctx))
+      p_ctx->capabilities |= VC_CONTAINER_CAPS_CAN_SEEK;
+
+   /*
+    *  We now have all the information we really need to start playing the stream
+    */
+
+   p_ctx->priv->pf_close = wav_reader_close;
+   p_ctx->priv->pf_read = wav_reader_read;
+   p_ctx->priv->pf_seek = wav_reader_seek;
+
+   /* Seek back to the start of the data */
+   status = SEEK(p_ctx, module->data_offset);
+   if(status != VC_CONTAINER_SUCCESS) goto error;
+   return VC_CONTAINER_SUCCESS;
+
+ error:
+   LOG_DEBUG(p_ctx, "wav: error opening stream (%i)", status);
+   if(module) wav_reader_close(p_ctx);
+   return status;
+}
+
+/********************************************************************************
+ Entrypoint function
+ ********************************************************************************/
+
+#if !defined(ENABLE_CONTAINERS_STANDALONE) && defined(__HIGHC__)
+# pragma weak reader_open wav_reader_open
+#endif
diff --git a/helpers/dtoverlay/CMakeLists.txt b/helpers/dtoverlay/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..b3bd30f
--- /dev/null
@@ -0,0 +1,25 @@
+# =============================================================================
+# Copyright (c) 2016 Raspberry Pi (Trading) Ltd.
+# All rights reserved.
+#
+# FILE DESCRIPTION
+# CMake build file for dtoverlay library.
+# =============================================================================
+
+cmake_minimum_required (VERSION 2.8)
+
+include_directories (${VIDEOCORE_ROOT}
+                     ${VIDEOCORE_ROOT}/helpers
+                     ${VIDEOCORE_ROOT}/opensrc/helpers/libfdt
+                     ${VIDEOCORE_HEADERS_BUILD_DIR})
+
+if (CMAKE_COMPILER_IS_GNUCC)
+   add_definitions (-ffunction-sections)
+endif ()
+
+add_library (dtovl ${SHARED}
+             dtoverlay.c)
+
+target_link_libraries(dtovl fdt)
+
+install (TARGETS dtovl DESTINATION lib)
diff --git a/helpers/dtoverlay/dtoverlay.c b/helpers/dtoverlay/dtoverlay.c
new file mode 100755 (executable)
index 0000000..29e1195
--- /dev/null
@@ -0,0 +1,2006 @@
+/*
+Copyright (c) 2016 Raspberry Pi (Trading) Ltd.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <libfdt.h>
+#include <assert.h>
+
+#include "dtoverlay.h"
+
+#define ARRAY_SIZE(a)   (sizeof(a) / sizeof(a[0]))
+
+typedef enum
+{
+   FIXUP_ABSOLUTE,
+   FIXUP_RELATIVE
+} fixup_type_t;
+
+#define DTOVERRIDE_END     0
+#define DTOVERRIDE_INTEGER 1
+#define DTOVERRIDE_BOOLEAN 2
+#define DTOVERRIDE_STRING  3
+#define DTOVERRIDE_OVERLAY 4
+
+static int dtoverlay_extract_override(const char *override_name,
+                                      int *phandle_ptr,
+                                      const char **data_ptr, int *len_ptr,
+                                      const char **namep, int *namelenp,
+                                      int *offp, int *sizep);
+
+static int dtoverlay_set_node_name(DTBLOB_T *dtb, int node_off,
+                                  const char *name);
+
+static void dtoverlay_stdio_logging(dtoverlay_logging_type_t type,
+                                    const char *fmt, va_list args);
+
+#define phandle_debug if (0) dtoverlay_debug
+
+static DTOVERLAY_LOGGING_FUNC *dtoverlay_logging_func = dtoverlay_stdio_logging;
+static int dtoverlay_debug_enabled = 0;
+
+static uint32_t dtoverlay_read_u32(const void *src, int off)
+{
+   const unsigned char *p = src;
+   return (p[off + 0] << 24) | (p[off + 1] << 16) |
+          (p[off + 2] << 8)  | (p[off + 3] << 0);
+}
+
+static void dtoverlay_write_u8(void *dst, int off, uint32_t val)
+{
+   unsigned char *p = dst;
+   p[off] = (val >> 0) & 0xff;
+}
+
+static void dtoverlay_write_u16(void *dst, int off, uint32_t val)
+{
+   unsigned char *p = dst;
+   p[off + 0] = (val >> 8) & 0xff;
+   p[off + 1] = (val >> 0) & 0xff;
+}
+
+static void dtoverlay_write_u32(void *dst, int off, uint32_t val)
+{
+   unsigned char *p = dst;
+   p[off + 0] = (val >> 24) & 0xff;
+   p[off + 1] = (val >> 16) & 0xff;
+   p[off + 2] = (val >> 8) & 0xff;
+   p[off + 3] = (val >> 0) & 0xff;
+}
+
+static void dtoverlay_write_u64(void *dst, int off, uint64_t val)
+{
+   unsigned char *p = dst;
+   p[off + 0] = (val >> 56) & 0xff;
+   p[off + 1] = (val >> 48) & 0xff;
+   p[off + 2] = (val >> 40) & 0xff;
+   p[off + 3] = (val >> 32) & 0xff;
+   p[off + 4] = (val >> 24) & 0xff;
+   p[off + 5] = (val >> 16) & 0xff;
+   p[off + 6] = (val >> 8) & 0xff;
+   p[off + 7] = (val >> 0) & 0xff;
+}
+
+// Returns the offset of the node indicated by the absolute path, creating
+// it and any intermediates as necessary, or a negative error code.
+int dtoverlay_create_node(DTBLOB_T *dtb, const char *node_path, int path_len)
+{
+   const char *path_ptr;
+   const char *path_end;
+   int node_off = 0;
+
+   if (!path_len)
+      path_len = strlen(node_path);
+
+   path_ptr = node_path;
+   path_end = node_path + path_len;
+
+   if ((path_len > 0) && (path_ptr[path_len - 1] == '/'))
+       path_end--;
+
+   while (path_ptr < path_end)
+   {
+      const char *path_next;
+      int subnode_off;
+
+      if (*path_ptr != '/')
+         return -FDT_ERR_BADPATH;
+
+      // find the next path separator (or the end of the string)
+      path_ptr++;
+      for (path_next = path_ptr;
+           (path_next != path_end) && (*path_next != '/');
+           path_next++)
+         continue;
+
+      subnode_off = fdt_subnode_offset_namelen(dtb->fdt, node_off, path_ptr,
+                                               path_next - path_ptr);
+      if (subnode_off >= 0)
+         node_off = subnode_off;
+      else
+         node_off = fdt_add_subnode_namelen(dtb->fdt, node_off, path_ptr,
+                                            path_next - path_ptr);
+      if (node_off < 0)
+         break;
+
+      path_ptr = path_next;
+   }
+
+   if ((node_off >= 0) && (path_ptr != path_end))
+      return -FDT_ERR_BADPATH;
+
+   return node_off;
+}
+
+// Returns 0 on success, otherwise <0 error code
+int dtoverlay_delete_node(DTBLOB_T *dtb, const char *node_path, int path_len)
+{
+   int node_off = 0;
+   if (!path_len)
+      path_len = strlen(node_path);
+
+   dtoverlay_debug("delete_node(%.*s)", path_len, node_path);
+   node_off = fdt_path_offset_namelen(dtb->fdt, node_path, path_len);
+   if (node_off < 0)
+      return node_off;
+   return fdt_del_node(dtb->fdt, node_off);
+}
+
+// Returns the offset of the node indicated by the absolute path or a negative
+// error code.
+int dtoverlay_find_node(DTBLOB_T *dtb, const char *node_path, int path_len)
+{
+   if (!path_len)
+      path_len = strlen(node_path);
+   return fdt_path_offset_namelen(dtb->fdt, node_path, path_len);
+}
+
+// Returns 0 on success, otherwise <0 error code
+int dtoverlay_set_node_properties(DTBLOB_T *dtb, const char *node_path,
+                                  DTOVERLAY_PARAM_T *properties,
+                                  unsigned int num_properties)
+{
+   int err = 0;
+   int node_off;
+
+   node_off = fdt_path_offset(dtb->fdt, node_path);
+   if (node_off < 0)
+      node_off = dtoverlay_create_node(dtb, node_path, 0);
+   if (node_off >= 0)
+   {
+      int i;
+      for (i = 0; (i < num_properties) && (err == 0); i++)
+      {
+         DTOVERLAY_PARAM_T *p;
+
+         p = properties + i;
+         err = fdt_setprop(dtb->fdt, node_off, p->param, p->b, p->len);
+      }
+   }
+   else
+      err = node_off;
+   return err;
+}
+
+struct dynstring
+{
+   char *buf;
+   int size;
+   int len;
+};
+
+static void dynstring_init(struct dynstring *ds)
+{
+   ds->size = 0;
+   ds->len = 0;
+   ds->buf = NULL;
+}
+
+static int dynstring_init_size(struct dynstring *ds, int initial_size)
+{
+   if (initial_size < 32)
+      initial_size = 32;
+   ds->size = initial_size;
+   ds->len = 0;
+   ds->buf = malloc(initial_size);
+   if (!ds->buf)
+   {
+      dtoverlay_error("  out of memory");
+      return -FDT_ERR_NOSPACE;
+   }
+   return 0;
+}
+
+static int dynstring_set_size(struct dynstring *ds, int size)
+{
+   if (size > ds->size)
+   {
+      size = (size * 5)/4; // Add a 25% headroom
+      ds->buf = realloc(ds->buf, size);
+      if (!ds->buf)
+      {
+         dtoverlay_error("  out of memory");
+         return -FDT_ERR_NOSPACE;
+      }
+      ds->size = size;
+   }
+   return 0;
+}
+
+static int dynstring_dup(struct dynstring *ds, const char *src, int len)
+{
+   int err = 0;
+
+   if (!len)
+      len = strlen(src);
+
+   err = dynstring_set_size(ds, len + 1);
+   if (!err)
+   {
+      memcpy(ds->buf, src, len + 1);
+      ds->len = len;
+   }
+
+   return err;
+}
+
+static int dynstring_patch(struct dynstring *ds, int pos, int width,
+                           const char *src, int len)
+{
+   int newlen = ds->len + (len - width);
+   int err = dynstring_set_size(ds, newlen + 1);
+   if (!err)
+   {
+      if (width != len)
+      {
+         // Move any data following the patch
+         memmove(ds->buf + pos + len, ds->buf + pos + width,
+                 ds->len + 1 - (pos + width));
+         ds->len = newlen;
+      }
+      memcpy(ds->buf + pos, src, len);
+   }
+   return err;
+}
+
+static int dynstring_grow(struct dynstring *ds)
+{
+   return dynstring_set_size(ds, (3*ds->size)/2);
+}
+
+static void dynstring_free(struct dynstring *ds)
+{
+   free(ds->buf);
+   dynstring_init(ds);
+}
+
+static int dtoverlay_set_node_name(DTBLOB_T *dtb, int node_off,
+                                  const char *name)
+{
+   struct dynstring path_buf;
+   struct dynstring prop_buf;
+   char *old_path;
+   const char *old_name;
+   const char *fixup_nodes[] =
+   {
+      "/__fixups__",
+      "/__local_fixups__", // For old-style dtbos
+      "/__symbols__"       // Just in case the kernel cares
+   };
+   int old_name_len;
+   int old_path_len; // All of it
+   int dir_len; // Excluding the node name, but with the trailling slash
+   int name_len;
+   int offset;
+   int fixup_idx;
+   int err = 0;
+
+   // Fixups and local-fixups both use node names, so this
+   // function must be patch them up when a node is renamed
+   // unless the fixups have already been applied.
+   // Calculating a node's name is expensive, so only do it if
+   // necessary. Since renaming a node can move things around,
+   // don't use node_off afterwards.
+   err = dynstring_init_size(&path_buf, 100);
+   if (err)
+      return err;
+
+   if (!dtb->fixups_applied)
+   {
+      while (1)
+      {
+         err = fdt_get_path(dtb->fdt, node_off, path_buf.buf, path_buf.size);
+         if (!err)
+            break;
+         if (err != -FDT_ERR_NOSPACE)
+            return err;
+         dynstring_grow(&path_buf);
+      }
+   }
+   old_path = path_buf.buf;
+
+   err = fdt_set_name(dtb->fdt, node_off, name);
+   if (err || dtb->fixups_applied)
+      goto clean_up;
+
+   // Find the node name in old_path
+   old_name = strrchr(old_path, '/');
+   assert(old_name);
+   if (!old_name)
+      return -FDT_ERR_INTERNAL;
+   old_name++;
+   old_name_len = strlen(old_name);
+   dir_len = old_name - old_path;
+   old_path_len = dir_len + old_name_len;
+
+   // Short-circuit the case where the name isn't changing
+   if (strcmp(name, old_name) == 0)
+      goto clean_up;
+
+   name_len = strlen(name);
+
+   // Search the fixups and symbols for the old path (including as
+   // a parent)  and replace with the new name
+
+   dynstring_init(&prop_buf);
+   for (fixup_idx = 0; fixup_idx < ARRAY_SIZE(fixup_nodes); fixup_idx++)
+   {
+      int prop_off;
+
+      offset = fdt_path_offset(dtb->fdt, fixup_nodes[fixup_idx]);
+      if (offset > 0)
+      {
+
+         // Iterate through the properties
+         for (prop_off = fdt_first_property_offset(dtb->fdt, offset);
+              (prop_off >= 0) && (err == 0);
+              prop_off = fdt_next_property_offset(dtb->fdt, prop_off))
+         {
+            const char *prop_name;
+            const char *prop_val;
+            int prop_len;
+            int pos;
+            int changed = 0;
+
+            prop_val = fdt_getprop_by_offset(dtb->fdt, prop_off,
+                                             &prop_name, &prop_len);
+            err = dynstring_dup(&prop_buf, prop_val, prop_len);
+            if (err)
+               break;
+
+            // Scan each property for matching paths
+            pos = 0;
+            while (pos < prop_len)
+            {
+               if ((pos + old_path_len < prop_len) &&
+                   (memcmp(prop_buf.buf + pos, old_path, old_path_len) == 0) &&
+                   ((prop_buf.buf[pos + old_path_len] == ':') ||
+                    (prop_buf.buf[pos + old_path_len] == '/') ||
+                    (prop_buf.buf[pos + old_path_len] == '\0')))
+               {
+                  // Patch the string, replacing old name with new
+                  err = dynstring_patch(&prop_buf, pos + dir_len, old_name_len,
+                                        name, name_len);
+                  if (err)
+                     break;
+
+                  prop_len += name_len - old_name_len;
+                  changed = 1;
+               }
+               pos += strlen(prop_buf.buf + pos) + 1;
+            }
+
+            if (!err && changed)
+            {
+               // Caution - may change offsets, but only by shuffling everything
+               // afterwards, i.e. the offset to this node or property does not
+               // change.
+               err = fdt_setprop(dtb->fdt, offset, prop_name, prop_buf.buf,
+                                 prop_len);
+            }
+         }
+      }
+   }
+
+   dynstring_free(&prop_buf);
+
+   if (err)
+      goto clean_up;
+
+   // Then look for a "/__local_fixups__<old_path>" node, and rename
+   // that as well.
+   offset = fdt_path_offset(dtb->fdt, "/__local_fixups__");
+   if (offset > 0)
+   {
+      const char *p, *end;
+
+      p = old_path;
+      end = old_path + old_path_len;
+      while (p < end)
+      {
+         const char *q;
+
+         while (*p == '/') {
+            p++;
+            if (p == end)
+               break;
+         }
+         q = memchr(p, '/', end - p);
+         if (! q)
+            q = end;
+
+         offset = fdt_subnode_offset_namelen(dtb->fdt, offset, p, q-p);
+         if (offset < 0)
+            break;
+
+         p = q;
+      }
+
+      if (offset > 0)
+         err = fdt_set_name(dtb->fdt, offset, name);
+   }
+
+   // __overrides__ don't need patching because nodes are identified
+   // using phandles, which are unaffected by renaming and resizing nodes.
+
+clean_up:
+   dynstring_free(&path_buf);
+
+   return err;
+}
+
+// Returns 0 on success, otherwise <0 error code
+int dtoverlay_create_prop_fragment(DTBLOB_T *dtb, int idx, int target_phandle,
+                                   const char *prop_name, const void *prop_data,
+                                   int prop_len)
+{
+       char fragment_name[20];
+       int frag_off, ovl_off;
+       int ret;
+       snprintf(fragment_name, sizeof(fragment_name), "fragment@%u", idx);
+       frag_off = fdt_add_subnode(dtb->fdt, 0, fragment_name);
+       if (frag_off < 0)
+               return frag_off;
+       ret = fdt_setprop_u32(dtb->fdt, frag_off, "target", target_phandle);
+       if (ret < 0)
+               return ret;
+       ovl_off = fdt_add_subnode(dtb->fdt, frag_off, "__overlay__");
+       if (ovl_off < 0)
+               return ovl_off;
+       return fdt_setprop(dtb->fdt, ovl_off, prop_name, prop_data, prop_len);
+}
+
+// Returns 0 on success, otherwise <0 error code
+static int dtoverlay_merge_fragment(DTBLOB_T *base_dtb, int target_off,
+                                    const DTBLOB_T *overlay_dtb,
+                                    int overlay_off, int depth)
+{
+   int prop_off, subnode_off;
+   int err = 0;
+
+   if (dtoverlay_debug_enabled)
+   {
+      char base_path[256];
+      char overlay_path[256];
+      fdt_get_path(base_dtb->fdt, target_off, base_path, sizeof(base_path));
+      fdt_get_path(overlay_dtb->fdt, overlay_off, overlay_path,
+                   sizeof(overlay_path));
+
+      dtoverlay_debug("merge_fragment(%s,%s)", base_path,
+                      overlay_path);
+   }
+
+   // Merge each property of the node
+   for (prop_off = fdt_first_property_offset(overlay_dtb->fdt, overlay_off);
+        (prop_off >= 0) && (err == 0);
+        prop_off = fdt_next_property_offset(overlay_dtb->fdt, prop_off))
+   {
+      const char *prop_name;
+      const void *prop_val;
+      int prop_len;
+      struct fdt_property *target_prop;
+      int target_len;
+
+      prop_val = fdt_getprop_by_offset(overlay_dtb->fdt, prop_off,
+                                       &prop_name, &prop_len);
+
+      /* Skip these system properties (only phandles in the first level) */
+      if ((strcmp(prop_name, "name") == 0) ||
+          ((depth == 0) && ((strcmp(prop_name, "phandle") == 0) ||
+                           (strcmp(prop_name, "linux,phandle") == 0))))
+          continue;
+
+      dtoverlay_debug("  +prop(%s)", prop_name);
+
+      if ((strcmp(prop_name, "bootargs") == 0) &&
+         ((target_prop = fdt_get_property_w(base_dtb->fdt, target_off, prop_name, &target_len)) != NULL) &&
+         (target_len > 0) && *target_prop->data)
+      {
+         target_prop->data[target_len - 1] = ' ';
+         err = fdt_appendprop(base_dtb->fdt, target_off, prop_name, prop_val, prop_len);
+      }
+      else
+         err = fdt_setprop(base_dtb->fdt, target_off, prop_name, prop_val, prop_len);
+   }
+
+   // Merge each subnode of the node
+   for (subnode_off = fdt_first_subnode(overlay_dtb->fdt, overlay_off);
+        (subnode_off >= 0) && (err == 0);
+        subnode_off = fdt_next_subnode(overlay_dtb->fdt, subnode_off))
+   {
+      const char *subnode_name;
+      int name_len;
+      int subtarget_off;
+
+      subnode_name = fdt_get_name(overlay_dtb->fdt, subnode_off, &name_len);
+
+      subtarget_off = fdt_subnode_offset_namelen(base_dtb->fdt, target_off,
+                                                 subnode_name, name_len);
+      if (subtarget_off < 0)
+         subtarget_off = fdt_add_subnode_namelen(base_dtb->fdt, target_off,
+                                                 subnode_name, name_len);
+
+      if (subtarget_off >= 0)
+      {
+         err = dtoverlay_merge_fragment(base_dtb, subtarget_off,
+                                        overlay_dtb, subnode_off,
+                                        depth + 1);
+      }
+      else
+      {
+         err = subtarget_off;
+      }
+   }
+
+   dtoverlay_debug("merge_fragment() end");
+
+   return err;
+}
+
+static int dtoverlay_phandle_relocate(DTBLOB_T *dtb, int node_off,
+                                      const char *prop_name,
+                                      uint32_t phandle_increment)
+{
+   int len;
+   const fdt32_t *prop_val = fdt_getprop(dtb->fdt, node_off, prop_name, &len);
+   int err = 0; // The absence of the property is not an error
+
+   if (prop_val)
+   {
+      uint32_t phandle;
+
+      if (len < 4)
+      {
+         dtoverlay_error("%s property too small", prop_name);
+         return -FDT_ERR_BADSTRUCTURE;
+      }
+
+      phandle = fdt32_to_cpu(*prop_val) + phandle_increment;
+      phandle_debug("  phandle_relocate %d->%d", fdt32_to_cpu(*prop_val), phandle);
+
+      err = fdt_setprop_inplace_u32(dtb->fdt, node_off, prop_name, phandle);
+   }
+
+   return err;
+}
+
+// Returns 0 on success, or an FDT error code
+static int dtoverlay_apply_fixups(DTBLOB_T *dtb, const char *fixups_stringlist,
+                                  uint32_t phandle, fixup_type_t type)
+{
+   // The fixups arrive as a sequence of NUL-terminated strings, of the form:
+   //   "path:property:offset"
+   // Use an empty string as an end marker, since:
+   // 1) all tags begin 0x00 0x00 0x00,
+   // 2) all string properties must be followed by a tag,
+   // 3) an empty string is not a valid fixup, and
+   // 4) the code is simpler as a result.
+
+   const char *fixup = fixups_stringlist;
+
+   while  (fixup[0])
+   {
+      const char *prop_name, *offset_str;
+      char *offset_end;
+      const void *prop_ptr;
+      int prop_len;
+      int node_off;
+      unsigned long offset;
+      uint32_t patch;
+
+      prop_name = strchr(fixup, ':');
+      if (!prop_name)
+         return -FDT_ERR_BADSTRUCTURE;
+      prop_name++;
+
+      offset_str = strchr(prop_name, ':');
+      if (!offset_str)
+         return -FDT_ERR_BADSTRUCTURE;
+      offset_str++;
+
+      offset = strtoul(offset_str, &offset_end, 10);
+      if ((offset_end == offset_str) || (offset_end[0] != 0))
+         return -FDT_ERR_BADSTRUCTURE;
+
+      node_off = fdt_path_offset_namelen(dtb->fdt, fixup, prop_name - 1 - fixup);
+      if (node_off < 0)
+         return node_off;
+
+      prop_ptr = fdt_getprop_namelen(dtb->fdt, node_off, prop_name,
+                                     offset_str - 1 - prop_name, &prop_len);
+      if (!prop_ptr)
+         return prop_len;
+      if (offset > (prop_len - 4))
+         return -FDT_ERR_BADSTRUCTURE;
+
+      // Now apply the patch. Yes, prop_ptr is a const void *, but the
+      // alternative (copying the whole property, patching, then updating as
+      // a whole) is ridiculous.
+      if (type == FIXUP_RELATIVE)
+      {
+         patch = phandle + dtoverlay_read_u32(prop_ptr, offset);
+         phandle_debug("  phandle fixup %d+%d->%d", phandle, patch - phandle, patch);
+      }
+      else
+      {
+         patch = phandle;
+         phandle_debug("  phandle ref '%s'->%d", prop_name, patch);
+      }
+
+      dtoverlay_write_u32((void *)prop_ptr, offset, patch);
+
+      fixup = offset_end + 1;
+   }
+
+   return 0;
+}
+
+// Returns 0 on success, or an FDT error code
+static int dtoverlay_apply_fixups_node(DTBLOB_T *dtb, int fix_off,
+                                       int target_off, uint32_t phandle_offset)
+{
+   // The fixups are arranged as a subtree mirroring the structure of the
+   // overall tree. Walk this tree in order. Each property is an array of cells
+   // containing offsets to patch within the corresponding node/property of
+   // the target tree.
+   int err = 0;
+   int prop_off;
+   int subfix_off;
+
+   // Merge each property of the node
+   for (prop_off = fdt_first_property_offset(dtb->fdt, fix_off);
+        (prop_off >= 0) && (err == 0);
+        prop_off = fdt_next_property_offset(dtb->fdt, prop_off))
+   {
+      const char *prop_name;
+      const void *prop_val;
+      int prop_len;
+      void *target_ptr;
+      int target_len;
+      int off;
+
+      prop_val = fdt_getprop_by_offset(dtb->fdt, prop_off,
+                                       &prop_name, &prop_len);
+      if (!prop_val)
+         return -FDT_ERR_INTERNAL;
+
+      target_ptr = fdt_getprop_w(dtb->fdt, target_off, prop_name, &target_len);
+      if (!target_ptr)
+         return -FDT_ERR_BADSTRUCTURE;
+
+      for (off = 0; (off + 4) <= prop_len; off += 4)
+      {
+         uint32_t patch;
+         int patch_offset = dtoverlay_read_u32(prop_val, off);
+         if ((patch_offset + 4) > target_len)
+            return -FDT_ERR_BADSTRUCTURE;
+
+         patch = phandle_offset + dtoverlay_read_u32(target_ptr, patch_offset);
+         phandle_debug("  phandle fixup %d+%d->%d", phandle_offset, patch - phandle_offset, patch);
+
+         dtoverlay_write_u32(target_ptr, patch_offset, patch);
+      }
+   }
+
+   // Merge each subnode of the node
+   for (subfix_off = fdt_first_subnode(dtb->fdt, fix_off);
+        (subfix_off >= 0) && (err == 0);
+        subfix_off = fdt_next_subnode(dtb->fdt, subfix_off))
+   {
+      const char *subnode_name;
+      int name_len;
+      int subtarget_off;
+
+      subnode_name = fdt_get_name(dtb->fdt, subfix_off, &name_len);
+
+      subtarget_off = fdt_subnode_offset_namelen(dtb->fdt, target_off,
+                                                 subnode_name, name_len);
+
+      if (subtarget_off >= 0)
+      {
+         err = dtoverlay_apply_fixups_node(dtb, subfix_off, subtarget_off,
+                                           phandle_offset);
+      }
+      else
+      {
+         err = subtarget_off;
+      }
+   }
+
+   return err;
+}
+
+// Returns 0 on success, or a negative FDT error.
+static int dtoverlay_resolve_phandles(DTBLOB_T *base_dtb, DTBLOB_T *overlay_dtb)
+{
+   int local_fixups_off;
+   int node_off;
+   int err = 0;
+
+   // First find and update the phandles in the overlay
+
+   for (node_off = 0;
+        node_off >= 0;
+        node_off = fdt_next_node(overlay_dtb->fdt, node_off, NULL))
+   {
+      dtoverlay_phandle_relocate(overlay_dtb, node_off, "phandle",
+                                 base_dtb->max_phandle);
+      dtoverlay_phandle_relocate(overlay_dtb, node_off, "linux,phandle",
+                                 base_dtb->max_phandle);
+   }
+
+   local_fixups_off = fdt_path_offset(overlay_dtb->fdt, "/__local_fixups__");
+   if (local_fixups_off >= 0)
+   {
+      const char *fixups_stringlist;
+
+      // Update the references to local phandles using the local fixups.
+      // The property name is "fixup".
+      // The value is a NUL-separated stringlist of descriptors of the form:
+      //    path:property:offset
+      fixups_stringlist =
+         fdt_getprop(overlay_dtb->fdt, local_fixups_off, "fixup", &err);
+      if (fixups_stringlist)
+      {
+         // Relocate the overlay phandle references
+         err = dtoverlay_apply_fixups(overlay_dtb, fixups_stringlist,
+                                      base_dtb->max_phandle, FIXUP_RELATIVE);
+      }
+      else
+      {
+          err = dtoverlay_apply_fixups_node(overlay_dtb, local_fixups_off,
+                                            0, base_dtb->max_phandle);
+      }
+      if (err < 0)
+      {
+         dtoverlay_error("error applying local fixups");
+         return err;
+      }
+   }
+
+   overlay_dtb->max_phandle += base_dtb->max_phandle;
+   phandle_debug("  +overlay max phandle +%d -> %d", base_dtb->max_phandle, overlay_dtb->max_phandle);
+
+   return err;
+}
+
+// Returns 0 on success, or an FDT error code
+static int dtoverlay_resolve_fixups(DTBLOB_T *base_dtb, DTBLOB_T *overlay_dtb)
+{
+   int fixups_off;
+   int err = 0;
+
+   fixups_off = fdt_path_offset(overlay_dtb->fdt, "/__fixups__");
+
+   if (fixups_off >= 0)
+   {
+      int fixup_off, symbols_off = -1;
+
+      fixup_off = fdt_first_property_offset(overlay_dtb->fdt, fixups_off);
+
+      if (fixup_off >= 0)
+      {
+         // Find the symbols, which will be needed to resolve the fixups
+         symbols_off = fdt_path_offset(base_dtb->fdt, "/__symbols__");
+
+         if (symbols_off < 0)
+         {
+            dtoverlay_error("No symbols found");
+            return -FDT_ERR_NOTFOUND;
+         }
+      }
+
+      for (;
+           fixup_off >= 0;
+           fixup_off = fdt_next_property_offset(overlay_dtb->fdt, fixup_off))
+      {
+         const char *fixups_stringlist, *symbol_name, *target_path;
+         const char *ref_type;
+         int target_off;
+         uint32_t target_phandle;
+
+         // The property name identifies a symbol (or alias) in the base.
+         // The value is a comma-separated list of descriptors of the form:
+         //    path:property:offset
+         fixups_stringlist = fdt_getprop_by_offset(overlay_dtb->fdt, fixup_off,
+                                                   &symbol_name, &err);
+         if (!fixups_stringlist)
+         {
+            dtoverlay_error("__fixups__ are borked");
+            break;
+         }
+
+         // 1) Find the target node.
+         if (symbol_name[0] == '/')
+         {
+            /* This is a new-style path reference */
+            target_path = symbol_name;
+            ref_type = "path";
+         }
+         else
+         {
+            target_path = fdt_getprop(base_dtb->fdt, symbols_off, symbol_name,
+                                      &err);
+            if (!target_path)
+            {
+               dtoverlay_error("can't find symbol '%s'", symbol_name);
+               break;
+            }
+
+            ref_type = "symbol";
+         }
+
+         target_off = fdt_path_offset(base_dtb->fdt, target_path);
+         if (target_off < 0)
+         {
+            dtoverlay_error("%s '%s' is invalid", ref_type, symbol_name);
+            err = target_off;
+            break;
+         }
+
+         // 2) Ensure that the target node has a phandle.
+         target_phandle = fdt_get_phandle(base_dtb->fdt, target_off);
+         if (!target_phandle)
+         {
+            // It doesn't, so give it one
+            fdt32_t temp;
+            target_phandle = ++base_dtb->max_phandle;
+            temp = cpu_to_fdt32(target_phandle);
+
+            err = fdt_setprop(base_dtb->fdt, target_off, "phandle",
+                              &temp, 4);
+
+            if (err != 0)
+            {
+               dtoverlay_error("failed to add a phandle");
+               break;
+            }
+            phandle_debug("  phandle '%s'->%d", target_path, target_phandle);
+
+            // The symbols may have moved, so recalculate
+            symbols_off = fdt_path_offset(base_dtb->fdt, "/__symbols__");
+         }
+
+         // Now apply the valid target_phandle to the items in the fixup string
+
+         err = dtoverlay_apply_fixups(overlay_dtb, fixups_stringlist,
+                                      target_phandle, FIXUP_ABSOLUTE);
+         if (err)
+            break;
+      }
+   }
+
+   return err;
+}
+
+// Returns 0 on success, -ve for fatal errors and +ve for non-fatal errors
+int dtoverlay_merge_overlay(DTBLOB_T *base_dtb, DTBLOB_T *overlay_dtb)
+{
+   // Merge each fragment node
+   int frag_off;
+
+   for (frag_off = fdt_first_subnode(overlay_dtb->fdt, 0);
+        frag_off >= 0;
+        frag_off = fdt_next_subnode(overlay_dtb->fdt, frag_off))
+   {
+      const char *node_name, *target_path;
+      const char *frag_name;
+      int target_off, overlay_off;
+      int len, err;
+
+      node_name = fdt_get_name(overlay_dtb->fdt, frag_off, NULL);
+
+      if (strncmp(node_name, "fragment@", 9) != 0)
+         continue;
+      frag_name = node_name + 9;
+
+      dtoverlay_debug("Found fragment %s (offset %d)", frag_name, frag_off);
+
+      // Find the target and overlay nodes
+      overlay_off = fdt_subnode_offset(overlay_dtb->fdt, frag_off, "__overlay__");
+      if (overlay_off < 0)
+      {
+         if (fdt_subnode_offset(overlay_dtb->fdt, frag_off, "__dormant__"))
+            dtoverlay_debug("fragment %s disabled", frag_name);
+         else
+            dtoverlay_error("no overlay in fragment %s", frag_name);
+         continue;
+      }
+
+      target_path = fdt_getprop(overlay_dtb->fdt, frag_off, "target-path", &len);
+      if (target_path)
+      {
+         if (len && (target_path[len - 1] == '\0'))
+            len--;
+         target_off = fdt_path_offset_namelen(base_dtb->fdt, target_path, len);
+         if (target_off < 0)
+         {
+            dtoverlay_error("invalid target-path '%.*s'", len, target_path);
+            return NON_FATAL(target_off);
+         }
+      }
+      else
+      {
+         const void *target_prop;
+         target_prop = fdt_getprop(overlay_dtb->fdt, frag_off, "target", &len);
+         if (!target_prop)
+         {
+            dtoverlay_error("no target or target-path");
+            return NON_FATAL(len);
+         }
+
+         if (len != 4)
+            return NON_FATAL(FDT_ERR_BADSTRUCTURE);
+
+         target_off =
+            fdt_node_offset_by_phandle(base_dtb->fdt,
+                                       fdt32_to_cpu(*(fdt32_t *)target_prop));
+         if (target_off < 0)
+         {
+            dtoverlay_error("invalid target");
+            return NON_FATAL(target_off);
+         }
+      }
+
+      // Now do the merge
+      err = dtoverlay_merge_fragment(base_dtb, target_off, overlay_dtb,
+                                     overlay_off, 0);
+      if (err != 0)
+      {
+         dtoverlay_error("merge failed");
+         return err;
+      }
+   }
+
+   base_dtb->max_phandle = overlay_dtb->max_phandle;
+
+   return 0;
+}
+
+// Returns 0 on success, -ve for fatal errors and +ve for non-fatal errors
+int dtoverlay_fixup_overlay(DTBLOB_T *base_dtb, DTBLOB_T *overlay_dtb)
+{
+   int err;
+
+   // To do: Check the "compatible" string?
+
+   err = dtoverlay_resolve_fixups(base_dtb, overlay_dtb);
+
+   if (err >= 0)
+      err = dtoverlay_resolve_phandles(base_dtb, overlay_dtb);
+
+   overlay_dtb->fixups_applied = 1;
+
+   return NON_FATAL(err);
+}
+
+// Returns 0 on success, -ve for fatal errors and +ve for non-fatal errors
+int dtoverlay_merge_params(DTBLOB_T *dtb, const DTOVERLAY_PARAM_T *params,
+                           unsigned int num_params)
+{
+   int err = 0;
+   unsigned int i;
+
+   for (i=0; (i<num_params) && (err == 0); i++) {
+      const DTOVERLAY_PARAM_T *p;
+      const char *node_name, *slash;
+      int node_off, path_len;
+
+      p = params + i;
+      node_name = p->param;
+      slash = strrchr(node_name, '/');
+
+      if (!slash)
+      {
+         err = NON_FATAL(FDT_ERR_BADPATH);
+         break;
+      }
+
+      // Ensure that root properties ("/xxx") work
+      if (slash == node_name)
+         path_len = 1;
+      else
+         path_len = slash - node_name;
+
+      // find node, create if it does not exist yet
+      node_off = dtoverlay_create_node(dtb, node_name, path_len);
+      if (node_off >= 0)
+      {
+         const char *prop_name = slash + 1;
+         int prop_len;
+         struct fdt_property *prop;
+
+         if ((strcmp(prop_name, "bootargs") == 0) &&
+            ((prop = fdt_get_property_w(dtb->fdt, node_off, prop_name, &prop_len)) != NULL) &&
+            (prop_len > 0) && *prop->data)
+         {
+            prop->data[prop_len - 1] = ' ';
+            err = fdt_appendprop(dtb->fdt, node_off, prop_name, p->b, p->len);
+         }
+         else
+            err = fdt_setprop(dtb->fdt, node_off, prop_name, p->b, p->len);
+      }
+      else
+         err = node_off;
+   }
+
+   return err;
+}
+
+/* Returns a pointer to the override data and (through data_len) its length.
+   On error, sets *data_len to be the error code. */
+const char *dtoverlay_find_override(DTBLOB_T *dtb, const char *override_name,
+                                    int *data_len)
+{
+   int overrides_off;
+   const char *data;
+   int len;
+
+   // Find the table of overrides
+   overrides_off = fdt_path_offset(dtb->fdt, "/__overrides__");
+
+   if (overrides_off < 0)
+   {
+      dtoverlay_debug("/__overrides__ node not found");
+      *data_len = overrides_off;
+      return NULL;
+   }
+
+   // Locate the property
+   data = fdt_getprop(dtb->fdt, overrides_off, override_name, &len);
+   *data_len = len;
+   if (data)
+      dtoverlay_debug("Found override %s", override_name);
+   else
+      dtoverlay_debug("/__overrides__ has no %s property", override_name);
+
+   return data;
+}
+
+int dtoverlay_override_one_target(int override_type,
+                                 DTBLOB_T *dtb, int node_off,
+                                 const char *prop_name, int target_phandle,
+                                 int target_off, int target_size,
+                                 void *callback_value)
+{
+   const char *override_value = callback_value;
+   int err = 0;
+
+   if (override_type == DTOVERRIDE_STRING)
+   {
+      char *prop_val;
+      int prop_len;
+
+      /* Replace the whole property with the string */
+      if (strcmp(prop_name, "status") == 0)
+      {
+        /* Convert booleans to okay/disabled */
+        if ((strcmp(override_value, "y") == 0) ||
+            (strcmp(override_value, "yes") == 0) ||
+            (strcmp(override_value, "on") == 0) ||
+            (strcmp(override_value, "true") == 0) ||
+            (strcmp(override_value, "enable") == 0) ||
+            (strcmp(override_value, "1") == 0))
+                override_value = "okay";
+        else if ((strcmp(override_value, "n") == 0) ||
+                     (strcmp(override_value, "no") == 0) ||
+                     (strcmp(override_value, "off") == 0) ||
+                     (strcmp(override_value, "false") == 0) ||
+                     (strcmp(override_value, "0") == 0))
+                override_value = "disabled";
+      }
+
+      if ((strcmp(prop_name, "bootargs") == 0) &&
+         ((prop_val = fdt_getprop_w(dtb->fdt, node_off, prop_name,
+                                    &prop_len)) != NULL) &&
+         (prop_len > 0) && prop_val[0])
+      {
+        prop_val[prop_len - 1] = ' ';
+        err = fdt_appendprop_string(dtb->fdt, node_off, prop_name, override_value);
+      }
+      else
+        err = fdt_setprop_string(dtb->fdt, node_off, prop_name, override_value);
+   }
+   else if (override_type != DTOVERRIDE_END)
+   {
+      const char *p;
+      char *end;
+      char *prop_val;
+      char *prop_buf = NULL;
+      int prop_len;
+      int new_prop_len;
+      uint64_t override_int;
+      uint32_t frag_num;
+
+      /* Parse as an integer */
+      override_int = strtoull(override_value, &end, 0);
+      if (end[0] != '\0')
+      {
+        if ((strcmp(override_value, "y") == 0) ||
+            (strcmp(override_value, "yes") == 0) ||
+            (strcmp(override_value, "on") == 0) ||
+            (strcmp(override_value, "true") == 0) ||
+            (strcmp(override_value, "down") == 0))
+           override_int = 1;
+        else if ((strcmp(override_value, "n") == 0) ||
+                 (strcmp(override_value, "no") == 0) ||
+                 (strcmp(override_value, "off") == 0) ||
+                 (strcmp(override_value, "false") == 0))
+           override_int = 0;
+        else if (strcmp(override_value, "up") == 0)
+           override_int = 2;
+        else
+        {
+           dtoverlay_error("invalid override value '%s' - ignored",
+                           override_value);
+           return NON_FATAL(FDT_ERR_INTERNAL);
+        }
+      }
+
+      switch (override_type)
+      {
+      case DTOVERRIDE_INTEGER:
+        /* Patch a word within the property */
+        prop_val = (void *)fdt_getprop(dtb->fdt, node_off, prop_name,
+                                       &prop_len);
+        new_prop_len = target_off + target_size;
+        if (prop_len < new_prop_len)
+        {
+            /* This property either doesn't exist or isn't long enough.
+               Create a buffer containing any existing property data
+               with zero padding, which will later be patched and written
+               back. */
+            prop_buf = calloc(1, new_prop_len);
+            if (!prop_buf)
+            {
+                dtoverlay_error("  out of memory");
+                return NON_FATAL(FDT_ERR_NOSPACE);
+            }
+            if (prop_len > 0)
+                memcpy(prop_buf, prop_val, prop_len);
+            prop_val = prop_buf;
+        }
+
+        switch (target_size)
+        {
+        case 1:
+            dtoverlay_write_u8(prop_val, target_off, (uint32_t)override_int);
+            break;
+        case 2:
+            dtoverlay_write_u16(prop_val, target_off, (uint32_t)override_int);
+            break;
+        case 4:
+            dtoverlay_write_u32(prop_val, target_off, (uint32_t)override_int);
+            break;
+        case 8:
+            dtoverlay_write_u64(prop_val, target_off, override_int);
+            break;
+        default:
+            break;
+        }
+
+        if (prop_buf)
+        {
+            /* Add/extend the property by setting it */
+             err = fdt_setprop(dtb->fdt, node_off, prop_name, prop_buf, new_prop_len);
+            free(prop_buf);
+        }
+
+         if (strcmp(prop_name, "reg") == 0 && target_off == 0)
+         {
+            const char *old_name = fdt_get_name(dtb->fdt, node_off, NULL);
+            const char *atpos = strchr(old_name, '@');
+            if (atpos)
+            {
+               int name_len = (atpos - old_name);
+               char *new_name = malloc(name_len + 1 + 16 + 1);
+               if (!new_name)
+                  return -FDT_ERR_NOSPACE;
+               sprintf(new_name, "%.*s@%x", name_len, old_name, (uint32_t)override_int);
+               err = dtoverlay_set_node_name(dtb, node_off, new_name);
+               free(new_name);
+            }
+         }
+        break;
+
+      case DTOVERRIDE_BOOLEAN:
+        /* This is a boolean property (present->true, absent->false) */
+        if (override_int)
+           err = fdt_setprop(dtb->fdt, node_off, prop_name, NULL, 0);
+        else
+        {
+           err = fdt_delprop(dtb->fdt, node_off, prop_name);
+           if (err == -FDT_ERR_NOTFOUND)
+              err = 0;
+        }
+        break;
+
+      case DTOVERRIDE_OVERLAY:
+        /* Apply the overlay-wide override. The supported options are (<frag> is a fragment number):
+           +<frag>    Enable a fragment
+           -<frag>    Disable a fragment
+           =<frag>    Enable/disable the fragment according to the override value
+           !<frag>    Disable/enable the fragment according to the inverse of the override value */
+        p = prop_name;
+        while (*p && !err)
+        {
+           char type = *p;
+           int frag_off;
+           switch (type)
+           {
+           case '+':
+           case '-':
+           case '=':
+           case '!':
+              frag_num = strtoul(p + 1, &end, 0);
+              if (end != p)
+              {
+                 /* Change fragment@<frag_num>/__overlay__<->__dormant__ as necessary */
+                 const char *states[2] = { "__dormant__", "__overlay__" };
+                 char node_name[24];
+                 int active = (type == '+') ||
+                         ((type == '=') && (override_int != 0)) ||
+                         ((type == '!') && (override_int == 0));
+                 snprintf(node_name, sizeof(node_name), "/fragment@%u", frag_num);
+                 frag_off = fdt_path_offset(dtb->fdt, node_name);
+                 if (frag_off >= 0)
+                 {
+                    frag_off = fdt_subnode_offset(dtb->fdt, frag_off, states[!active]);
+                    if (frag_off >= 0)
+                       (void)dtoverlay_set_node_name(dtb, frag_off, states[active]);
+                 }
+                 else
+                 {
+                    dtoverlay_error("  fragment %u not found", frag_num);
+                    err = NON_FATAL(frag_off);
+                 }
+                 p = end;
+              }
+              else
+              {
+                 dtoverlay_error("  invalid overlay override '%s'", prop_name);
+                 err = NON_FATAL(FDT_ERR_BADVALUE);
+              }
+              break;
+           }
+        }
+        break;
+      }
+   }
+
+   return err;
+}
+
+// Returns 0 on success, -ve for fatal errors and +ve for non-fatal errors
+// After calling this, assume all node offsets are no longer valid
+int dtoverlay_foreach_override_target(DTBLOB_T *dtb, const char *override_name,
+                                     const char *override_data, int data_len,
+                                     override_callback_t callback,
+                                     void *callback_value)
+{
+   int err = 0;
+   int target_phandle = 0;
+   char *data;
+
+   /* Short-circuit the degenerate case of an empty parameter, avoiding an
+      apparent memory allocation failure. */
+   if (!data_len)
+      return 0;
+
+   /* Copy the override data in case it moves */
+   data = malloc(data_len);
+   if (!data)
+   {
+      dtoverlay_error("  out of memory");
+      return NON_FATAL(FDT_ERR_NOSPACE);
+   }
+
+   memcpy(data, override_data, data_len);
+   override_data = data;
+
+   while (err == 0)
+   {
+      const char *target_prop = NULL;
+      char *prop_name = NULL;
+      int name_len = 0;
+      int target_off = 0;
+      int target_size = 0;
+      int override_type;
+      int node_off = 0;
+
+      override_type = dtoverlay_extract_override(override_name,
+                                                &target_phandle,
+                                                &override_data, &data_len,
+                                                &target_prop, &name_len,
+                                                &target_off, &target_size);
+
+      /* Pass DTOVERRIDE_END to the callback, in case it is interested */
+
+      if (target_phandle != 0)
+      {
+         node_off = fdt_node_offset_by_phandle(dtb->fdt, target_phandle);
+         if (node_off < 0)
+         {
+            dtoverlay_error("  phandle %d not found", target_phandle);
+            err = NON_FATAL(node_off);
+            break;
+         }
+      }
+
+      if (target_prop)
+      {
+         /* Sadly there are no '_namelen' setprop variants, so a copy is required */
+         prop_name = malloc(name_len + 1);
+         if (!prop_name)
+         {
+            dtoverlay_error("  out of memory");
+            err = NON_FATAL(FDT_ERR_NOSPACE);
+            break;
+         }
+         memcpy(prop_name, target_prop, name_len);
+         prop_name[name_len] = '\0';
+      }
+
+      err = callback(override_type, dtb, node_off, prop_name,
+                    target_phandle, target_off, target_size,
+                    callback_value);
+
+      if (prop_name)
+         free(prop_name);
+
+      if (override_type == DTOVERRIDE_END)
+         break;
+   }
+
+   free(data);
+
+   return err;
+}
+
+// Returns 0 on success, -ve for fatal errors and +ve for non-fatal errors
+int dtoverlay_apply_override(DTBLOB_T *dtb, const char *override_name,
+                             const char *override_data, int data_len,
+                             const char *override_value)
+{
+   return dtoverlay_foreach_override_target(dtb, override_name,
+                                           override_data, data_len,
+                                           dtoverlay_override_one_target,
+                                           (void *)override_value);
+}
+
+/* Returns an override type (DTOVERRIDE_INTEGER, DTOVERRIDE_BOOLEAN, DTOVERRIDE_STRING, DTOVERRIDE_OVERLAY),
+   DTOVERRIDE_END (0) at the end, or an error code (< 0) */
+static int dtoverlay_extract_override(const char *override_name,
+                                      int *phandle_ptr,
+                                      const char **data_ptr, int *len_ptr,
+                                      const char **namep, int *namelenp,
+                                     int *offp, int *sizep)
+{
+   const char *data;
+   const char *prop_name, *override_end;
+   int len, override_len, name_len, phandle;
+   const char *offset_seps = ".;:#?";
+   int type;
+
+   data = *data_ptr;
+   len = *len_ptr;
+   if (len <= 0)
+   {
+      if (len < 0)
+        return len;
+      *phandle_ptr = 0;
+      *namep = NULL;
+      return DTOVERRIDE_END;
+   }
+
+   // Check for space for a phandle, a terminating NUL and at least one char
+   if (len < (sizeof(fdt32_t) + 1 + 1))
+   {
+      dtoverlay_error("  override %s: data is truncated or mangled",
+                      override_name);
+      return -FDT_ERR_BADSTRUCTURE;
+   }
+
+   phandle = dtoverlay_read_u32(data, 0);
+   *phandle_ptr = phandle;
+
+   data += sizeof(fdt32_t);
+   len -= sizeof(fdt32_t);
+
+   override_end = memchr(data, 0, len);
+   if (!override_end)
+   {
+      dtoverlay_error("  override %s: string is not NUL-terminated",
+                      override_name);
+      return -FDT_ERR_BADSTRUCTURE;
+   }
+
+   prop_name = data;
+
+   override_len = override_end - prop_name;
+   *data_ptr = data + (override_len + 1);
+   *len_ptr = len - (override_len + 1);
+
+   if (phandle <= 0)
+   {
+      if (phandle < 0)
+         return -FDT_ERR_BADPHANDLE;
+      /* This is an "overlay" override, signalled using <0> as the phandle. */
+      *namep = prop_name;
+      *namelenp = override_len;
+      return DTOVERRIDE_OVERLAY;
+   }
+
+   name_len = strcspn(prop_name, offset_seps);
+
+   *namep = prop_name;
+   *namelenp = name_len;
+   if (name_len < override_len)
+   {
+      /* There is a separator specified */
+      char sep = prop_name[name_len];
+      if (sep == '?')
+      {
+         /* The target is a boolean parameter (present->true, absent->false) */
+         *offp = 0;
+         *sizep = 0;
+         type = DTOVERRIDE_BOOLEAN;
+         dtoverlay_debug("  override %s: boolean target %.*s",
+                         override_name, name_len, prop_name);
+      }
+      else
+      {
+         /* The target is a cell/integer */
+         *offp = atoi(prop_name + name_len + 1);
+         *sizep = 1 << (strchr(offset_seps, sep) - offset_seps);
+         type = DTOVERRIDE_INTEGER;
+         dtoverlay_debug("  override %s: cell target %.*s @ offset %d (size %d)",
+                         override_name, name_len, prop_name, *offp, *sizep);
+      }
+   }
+   else
+   {
+      *offp = -1;
+      *sizep = 0;
+      type = DTOVERRIDE_STRING;
+      dtoverlay_debug("  override %s: string target '%.*s'",
+                      override_name, name_len, prop_name);
+   }
+
+   return type;
+}
+
+int dtoverlay_set_synonym(DTBLOB_T *dtb, const char *dst, const char *src)
+{
+   /* Add/update all aliases, symbols and overrides named dst
+      to be equivalent to those named src.
+      An absent src is ignored.
+   */
+   int err;
+
+   err = dtoverlay_dup_property(dtb, "/aliases", dst, src);
+   if (err == 0)
+      err = dtoverlay_dup_property(dtb, "/__symbols__", dst, src);
+   if (err == 0)
+      dtoverlay_dup_property(dtb, "/__overrides__", dst, src);
+   return err;
+}
+
+int dtoverlay_dup_property(DTBLOB_T *dtb, const char *node_name,
+                           const char *dst, const char *src)
+{
+   /* Find the node and src property */
+   const DTBLOB_T *src_prop;
+   int node_off;
+   int prop_len = 0;
+   int err = 0;
+
+   node_off = fdt_path_offset(dtb->fdt, node_name);
+   if (node_off < 0)
+      return 0;
+
+   src_prop = fdt_getprop(dtb->fdt, node_off, src, &prop_len);
+   if (!src_prop)
+      return 0;
+
+   err = fdt_setprop_inplace(dtb->fdt, node_off, dst, src_prop, prop_len);
+   if (err != 0)
+   {
+      void *prop_data;
+      /* Copy the src property, just in case things move */
+      prop_data = malloc(prop_len);
+      memcpy(prop_data, src_prop, prop_len);
+
+      err = fdt_setprop(dtb->fdt, node_off, dst, prop_data, prop_len);
+
+      free(prop_data);
+   }
+
+   if (err == 0)
+      dtoverlay_debug("%s:%s=%s", node_name, dst, src);
+   return err;
+}
+
+DTBLOB_T *dtoverlay_create_dtb(int max_size)
+{
+   DTBLOB_T *dtb = NULL;
+   void *fdt = NULL;
+
+   fdt = malloc(max_size);
+   if (!fdt)
+   {
+      dtoverlay_error("out of memory");
+      goto error_exit;
+   }
+
+   if (fdt_create_empty_tree(fdt, max_size) != 0)
+   {
+      dtoverlay_error("failed to create empty dtb");
+      goto error_exit;
+   }
+
+   dtb = calloc(1, sizeof(DTBLOB_T));
+   if (!dtb)
+   {
+      dtoverlay_error("out of memory");
+      goto error_exit;
+   }
+
+   dtb->fdt = fdt;
+   dtb->max_phandle = 0; // Not a valid phandle
+
+   return dtb;
+
+error_exit:
+   free(fdt);
+   if (dtb)
+      free(dtb->trailer);
+   free(dtb);
+   return NULL;
+
+}
+
+DTBLOB_T *dtoverlay_load_dtb_from_fp(FILE *fp, int max_size)
+{
+   DTBLOB_T *dtb = NULL;
+   void *fdt = NULL;
+
+   if (fp)
+   {
+      long len;
+      long bytes_read;
+      int dtb_len;
+
+      fseek(fp, 0, SEEK_END);
+      len = ftell(fp);
+      fseek(fp, 0, SEEK_SET);
+      if (max_size > 0)
+      {
+         if (max_size < len)
+         {
+            dtoverlay_error("file too large (%d bytes) for max_size", len);
+            goto error_exit;
+         }
+      }
+      else if (max_size < 0)
+      {
+         max_size = len - max_size;
+      }
+      else
+      {
+         max_size = len;
+      }
+
+      fdt = malloc(max_size);
+      if (!fdt)
+      {
+         dtoverlay_error("out of memory");
+         goto error_exit;
+      }
+
+      bytes_read = fread(fdt, 1, len, fp);
+      fclose(fp);
+
+      if (bytes_read != len)
+      {
+         dtoverlay_error("fread failed");
+         goto error_exit;
+      }
+
+      // Record the total size before any expansion
+      dtb_len = fdt_totalsize(fdt);
+
+      dtb = dtoverlay_import_fdt(fdt, max_size);
+      if (!dtb)
+         goto error_exit;
+
+      dtb->fdt_is_malloced = 1;
+
+      if (len > dtb_len)
+      {
+         /* Load the trailer */
+         dtb->trailer_len = len - dtb_len;
+         dtb->trailer = malloc(dtb->trailer_len);
+         if (!dtb->trailer)
+         {
+            dtoverlay_error("out of memory");
+            goto error_exit;
+         }
+         dtb->trailer_is_malloced = 1;
+         memcpy(dtb->trailer, (char *)fdt + dtb_len, dtb->trailer_len);
+      }
+   }
+
+   return dtb;
+
+error_exit:
+   free(fdt);
+   if (dtb)
+      free(dtb->trailer);
+   free(dtb);
+   return NULL;
+}
+
+DTBLOB_T *dtoverlay_load_dtb(const char *filename, int max_size)
+{
+   FILE *fp = fopen(filename, "rb");
+   if (fp)
+      return dtoverlay_load_dtb_from_fp(fp, max_size);
+   dtoverlay_error("Failed to open '%s'", filename);
+   return NULL;
+}
+
+DTBLOB_T *dtoverlay_import_fdt(void *fdt, int buf_size)
+{
+   DTBLOB_T *dtb = NULL;
+   int node_off;
+   int dtb_len;
+   int err;
+
+   err = fdt_check_header(fdt);
+   if (err != 0)
+   {
+      dtoverlay_error("not a valid FDT - err %d", err);
+      goto error_exit;
+   }
+
+   dtb_len = fdt_totalsize(fdt);
+
+   if (buf_size < dtb_len)
+   {
+      dtoverlay_error("fdt is too large");
+      err = -FDT_ERR_NOSPACE;
+      goto error_exit;
+   }
+
+   if (buf_size > dtb_len)
+         fdt_set_totalsize(fdt, buf_size);
+
+   dtb = calloc(1, sizeof(DTBLOB_T));
+   if (!dtb)
+   {
+      dtoverlay_error("out of memory");
+      goto error_exit;
+   }
+
+   dtb->fdt = fdt;
+   dtb->max_phandle = 0; // Not a valid phandle
+
+   // Find the minimum and maximum phandles, in case it is necessary to
+   // relocate existing ones or create new ones.
+
+   for (node_off = 0;
+        node_off >= 0;
+        node_off = fdt_next_node(fdt, node_off, NULL))
+   {
+      uint32_t phandle = fdt_get_phandle(fdt, node_off);
+      if (phandle > dtb->max_phandle)
+         dtb->max_phandle = phandle;
+   }
+
+error_exit:
+   return dtb;
+}
+
+int dtoverlay_save_dtb(const DTBLOB_T *dtb, const char *filename)
+{
+   FILE *fp = fopen(filename, "wb");
+   int err = 0;
+
+   if (fp)
+   {
+      long len = fdt_totalsize(dtb->fdt);
+      if (len != fwrite(dtb->fdt, 1, len, fp))
+      {
+         dtoverlay_error("fwrite failed");
+         err = -2;
+         goto error_exit;
+      }
+      if (dtb->trailer_len &&
+          (fwrite(dtb->trailer, 1, dtb->trailer_len, fp) != dtb->trailer_len))
+      {
+         dtoverlay_error("fwrite failed");
+         err = -2;
+         goto error_exit;
+      }
+
+      dtoverlay_debug("Wrote %ld bytes to '%s'", len, filename);
+      fclose(fp);
+   }
+   else
+   {
+      dtoverlay_debug("Failed to create '%s'", filename);
+      err = -1;
+   }
+
+error_exit:
+   return err;
+}
+
+int dtoverlay_extend_dtb(DTBLOB_T *dtb, int new_size)
+{
+   int size = fdt_totalsize(dtb->fdt);
+   int err = 0;
+
+   if (new_size < 0)
+      new_size = size - new_size;
+
+   if (new_size > size)
+   {
+      void *fdt;
+      fdt = malloc(new_size);
+      if (fdt)
+      {
+         memcpy(fdt, dtb->fdt, size);
+         fdt_set_totalsize(fdt, new_size);
+
+         if (dtb->fdt_is_malloced)
+            free(dtb->fdt);
+
+         dtb->fdt = fdt;
+         dtb->fdt_is_malloced = 1;
+      }
+      else
+      {
+         err = -FDT_ERR_NOSPACE;
+      }
+   }
+   else if (new_size < size)
+   {
+      /* Can't shrink it */
+      err = -FDT_ERR_NOSPACE;
+   }
+
+   return err;
+}
+
+int dtoverlay_dtb_totalsize(DTBLOB_T *dtb)
+{
+   return fdt_totalsize(dtb->fdt);
+}
+
+void dtoverlay_pack_dtb(DTBLOB_T *dtb)
+{
+   fdt_pack(dtb->fdt);
+}
+
+void dtoverlay_free_dtb(DTBLOB_T *dtb)
+{
+   if (dtb)
+   {
+      if (dtb->fdt_is_malloced)
+         free(dtb->fdt);
+      if (dtb->trailer_is_malloced)
+         free(dtb->trailer);
+      free(dtb);
+   }
+}
+
+int dtoverlay_find_phandle(DTBLOB_T *dtb, int phandle)
+{
+   return fdt_node_offset_by_phandle(dtb->fdt, phandle);
+}
+
+int dtoverlay_find_symbol(DTBLOB_T *dtb, const char *symbol_name)
+{
+   int symbols_off, path_len;
+   const char *node_path;
+
+   node_path = dtoverlay_get_alias(dtb, symbol_name);
+
+   if (node_path)
+   {
+      path_len = strlen(node_path);
+   }
+   else
+   {
+      symbols_off = fdt_path_offset(dtb->fdt, "/__symbols__");
+
+      if (symbols_off < 0)
+      {
+         dtoverlay_error("No symbols found");
+         return -FDT_ERR_NOTFOUND;
+      }
+
+      node_path = fdt_getprop(dtb->fdt, symbols_off, symbol_name, &path_len);
+      if (path_len < 0)
+         return -FDT_ERR_NOTFOUND;
+   }
+   return fdt_path_offset_namelen(dtb->fdt, node_path, path_len);
+}
+
+int dtoverlay_find_matching_node(DTBLOB_T *dtb, const char **node_names,
+                                 int pos)
+{
+   while (1)
+   {
+      const char *node_name;
+      pos = fdt_next_node(dtb->fdt, pos, NULL);
+      if (pos < 0)
+         break;
+      node_name = fdt_get_name(dtb->fdt, pos, NULL);
+      if (node_name)
+      {
+         int i;
+         for (i = 0; node_names[i]; i++)
+         {
+            const char *node = node_names[i];
+            int matchlen = strlen(node);
+            if ((strncmp(node_name, node, matchlen) == 0) &&
+                ((node[matchlen] == '\0') ||
+                 (node[matchlen] == '@')))
+               return pos;
+         }
+      }
+   }
+   return -1;
+}
+
+int dtoverlay_node_is_enabled(DTBLOB_T *dtb, int pos)
+{
+   if (pos >= 0)
+   {
+      const void *prop = dtoverlay_get_property(dtb, pos, "status", NULL);
+      if (prop &&
+          ((strcmp((const char *)prop, "okay") == 0) ||
+           (strcmp((const char *)prop, "ok") == 0)))
+         return 1;
+   }
+   return 0;
+}
+
+const void *dtoverlay_get_property(DTBLOB_T *dtb, int pos, const char *prop_name, int *prop_len)
+{
+   return fdt_getprop(dtb->fdt, pos, prop_name, prop_len);
+}
+
+int dtoverlay_set_property(DTBLOB_T *dtb, int pos,
+                           const char *prop_name, const void *prop, int prop_len)
+{
+   int err = fdt_setprop(dtb->fdt, pos, prop_name, prop, prop_len);
+   if (err < 0)
+      dtoverlay_error("Failed to set property '%s'", prop_name);
+   return err;
+}
+
+const char *dtoverlay_get_alias(DTBLOB_T *dtb, const char *alias_name)
+{
+   int node_off;
+   int prop_len;
+   const char *alias;
+
+   node_off = fdt_path_offset(dtb->fdt, "/aliases");
+
+   alias = fdt_getprop(dtb->fdt, node_off, alias_name, &prop_len);
+   if (alias && !prop_len)
+       alias = "";
+   return alias;
+}
+
+int dtoverlay_set_alias(DTBLOB_T *dtb, const char *alias_name, const char *value)
+{
+   int node_off;
+
+   node_off = fdt_path_offset(dtb->fdt, "/aliases");
+
+   return fdt_setprop_string(dtb->fdt, node_off, alias_name, value);
+}
+
+void dtoverlay_set_logging_func(DTOVERLAY_LOGGING_FUNC *func)
+{
+    dtoverlay_logging_func = func;
+}
+
+void dtoverlay_enable_debug(int enable)
+{
+   dtoverlay_debug_enabled = enable;
+}
+
+void dtoverlay_error(const char *fmt, ...)
+{
+   va_list args;
+   va_start(args, fmt);
+   (*dtoverlay_logging_func)(DTOVERLAY_ERROR, fmt, args);
+   va_end(args);
+}
+
+void dtoverlay_debug(const char *fmt, ...)
+{
+   va_list args;
+   if (dtoverlay_debug_enabled)
+   {
+      va_start(args, fmt);
+      (*dtoverlay_logging_func)(DTOVERLAY_DEBUG, fmt, args);
+      va_end(args);
+   }
+}
+
+static void dtoverlay_stdio_logging(dtoverlay_logging_type_t type,
+                                    const char *fmt, va_list args)
+{
+   const char *type_str;
+
+   switch (type)
+   {
+   case DTOVERLAY_ERROR:
+      type_str = "error";
+      break;
+
+   case DTOVERLAY_DEBUG:
+      type_str = "debug";
+      break;
+
+   default:
+      type_str = "?";
+   }
+
+   fprintf(stderr, "DTOVERLAY[%s]: ", type_str);
+   vfprintf(stderr, fmt, args);
+   fprintf(stderr, "\n");
+}
diff --git a/helpers/dtoverlay/dtoverlay.h b/helpers/dtoverlay/dtoverlay.h
new file mode 100755 (executable)
index 0000000..4602114
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+Copyright (c) 2016 Raspberry Pi (Trading) Ltd.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef DTOVERLAY_H
+#define DTOVERLAY_H
+
+#define BE4(x) ((x)>>24)&0xff, ((x)>>16)&0xff, ((x)>>8)&0xff, ((x)>>0)&0xff
+#define GETBE4(p, off) ((((unsigned char *)p)[off + 0]<<24) + (((unsigned char *)p)[off + 1]<<16) + \
+                  (((unsigned char *)p)[off + 2]<<8) + (((unsigned char *)p)[off + 3]<<0))
+#define SETBE4(p, off, x) do { \
+   ((unsigned char *)p)[off + 0] = ((x>>24) & 0xff); \
+   ((unsigned char *)p)[off + 1] = ((x>>16) & 0xff); \
+   ((unsigned char *)p)[off + 2] = ((x>>8) & 0xff); \
+   ((unsigned char *)p)[off + 3] = ((x>>0) & 0xff); \
+} while (0)
+
+#define NON_FATAL(err) (((err) < 0) ? -(err) : (err))
+#define IS_FATAL(err) ((err) < 0)
+#define ONLY_FATAL(err) (IS_FATAL(err) ? (err) : 0)
+
+#define DTOVERLAY_PADDING(size) (-(size))
+
+typedef enum
+{
+   DTOVERLAY_ERROR,
+   DTOVERLAY_DEBUG
+} dtoverlay_logging_type_t;
+
+typedef struct dtoverlay_struct
+{
+   const char *param;
+   int len;
+   const char *b;
+} DTOVERLAY_PARAM_T;
+
+typedef struct dtblob_struct
+{
+   void *fdt;
+   char fdt_is_malloced;
+   char trailer_is_malloced;
+   char fixups_applied;
+   int min_phandle;
+   int max_phandle;
+   void *trailer;
+   int trailer_len;
+} DTBLOB_T;
+
+
+typedef void DTOVERLAY_LOGGING_FUNC(dtoverlay_logging_type_t type,
+                                    const char *fmt, va_list args);
+
+typedef int (*override_callback_t)(int override_type,
+                                  DTBLOB_T *dtb, int node_off,
+                                  const char *prop_name, int target_phandle,
+                                  int target_off, int target_size,
+                                  void *callback_value);
+
+/* Return values: -ve = fatal error, positive = non-fatal error */
+int dtoverlay_create_node(DTBLOB_T *dtb, const char *node_name, int path_len);
+
+int dtoverlay_delete_node(DTBLOB_T *dtb, const char *node_name, int path_len);
+
+int dtoverlay_find_node(DTBLOB_T *dtb, const char *node_path, int path_len);
+
+int dtoverlay_set_node_properties(DTBLOB_T *dtb, const char *node_path,
+                                  DTOVERLAY_PARAM_T *properties,
+                                  unsigned int num_properties);
+
+int dtoverlay_create_prop_fragment(DTBLOB_T *dtb, int idx, int target_phandle,
+                                   const char *prop_name, const void *prop_data,
+                                   int prop_len);
+
+int dtoverlay_fixup_overlay(DTBLOB_T *base_dtb, DTBLOB_T *overlay_dtb);
+
+int dtoverlay_merge_overlay(DTBLOB_T *base_dtb, DTBLOB_T *overlay_dtb);
+
+int dtoverlay_merge_params(DTBLOB_T *dtb, const DTOVERLAY_PARAM_T *params,
+                           unsigned int num_params);
+
+const char *dtoverlay_find_override(DTBLOB_T *dtb, const char *override_name,
+                                    int *data_len);
+
+int dtoverlay_override_one_target(int override_type,
+                                  DTBLOB_T *dtb, int node_off,
+                                  const char *prop_name, int target_phandle,
+                                  int target_off, int target_size,
+                                  void *callback_value);
+
+int dtoverlay_foreach_override_target(DTBLOB_T *dtb, const char *override_name,
+                                      const char *override_data, int data_len,
+                                      override_callback_t callback,
+                                     void *callback_value);
+
+int dtoverlay_apply_override(DTBLOB_T *dtb, const char *override_name,
+                             const char *override_data, int data_len,
+                             const char *override_value);
+
+int dtoverlay_override_one_target(int override_type,
+                                 DTBLOB_T *dtb, int node_off,
+                                 const char *prop_name, int target_phandle,
+                                 int target_off, int target_size,
+                                 void *callback_value);
+
+int dtoverlay_set_synonym(DTBLOB_T *dtb, const char *dst, const char *src);
+
+int dtoverlay_dup_property(DTBLOB_T *dtb, const char *node_name,
+                           const char *dst, const char *src);
+
+DTBLOB_T *dtoverlay_create_dtb(int max_size);
+
+DTBLOB_T *dtoverlay_load_dtb_from_fp(FILE *fp, int max_size);
+
+DTBLOB_T *dtoverlay_load_dtb(const char *filename, int max_size);
+
+DTBLOB_T *dtoverlay_import_fdt(void *fdt, int max_size);
+
+int dtoverlay_save_dtb(const DTBLOB_T *dtb, const char *filename);
+
+int dtoverlay_extend_dtb(DTBLOB_T *dtb, int new_size);
+
+int dtoverlay_dtb_totalsize(DTBLOB_T *dtb);
+
+void dtoverlay_pack_dtb(DTBLOB_T *dtb);
+
+void dtoverlay_free_dtb(DTBLOB_T *dtb);
+
+static inline void *dtoverlay_dtb_trailer(DTBLOB_T *dtb)
+{
+    return dtb->trailer;
+}
+
+static inline int dtoverlay_dtb_trailer_len(DTBLOB_T *dtb)
+{
+    return dtb->trailer_len;
+}
+
+static inline void dtoverlay_dtb_set_trailer(DTBLOB_T *dtb,
+                                             void *trailer,
+                                             int trailer_len)
+{
+    dtb->trailer = trailer;
+    dtb->trailer_len = trailer_len;
+    dtb->trailer_is_malloced = 0;
+}
+
+int dtoverlay_find_phandle(DTBLOB_T *dtb, int phandle);
+
+int dtoverlay_find_symbol(DTBLOB_T *dtb, const char *symbol_name);
+
+int dtoverlay_find_matching_node(DTBLOB_T *dtb, const char **node_names,
+                                 int pos);
+
+int dtoverlay_node_is_enabled(DTBLOB_T *dtb, int pos);
+
+const void *dtoverlay_get_property(DTBLOB_T *dtb, int pos,
+                                   const char *prop_name, int *prop_len);
+
+int dtoverlay_set_property(DTBLOB_T *dtb, int pos,
+                           const char *prop_name, const void *prop, int prop_len);
+
+const char *dtoverlay_get_alias(DTBLOB_T *dtb, const char *alias_name);
+
+int dtoverlay_set_alias(DTBLOB_T *dtb, const char *alias_name, const char *value);
+
+void dtoverlay_set_logging_func(DTOVERLAY_LOGGING_FUNC *func);
+
+void dtoverlay_enable_debug(int enable);
+
+void dtoverlay_error(const char *fmt, ...);
+
+void dtoverlay_debug(const char *fmt, ...);
+
+#endif
diff --git a/helpers/v3d/v3d_common.h b/helpers/v3d/v3d_common.h
new file mode 100755 (executable)
index 0000000..61002b1
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef V3D_COMMON_H
+#define V3D_COMMON_H
+
+#include "helpers/v3d/v3d_ver.h"
+#include "interface/vcos/vcos_assert.h"
+#include "interface/vcos/vcos_stdbool.h"
+#include "interface/vcos/vcos_stdint.h"
+#include "interface/vcos/vcos_types.h" /* for vcos_unused and VCOS_STATIC_INLINE */
+
+typedef uint32_t V3D_ADDR_T;
+typedef uint16_t float16_t;
+
+#endif
diff --git a/helpers/v3d/v3d_ver.h b/helpers/v3d/v3d_ver.h
new file mode 100755 (executable)
index 0000000..967e55c
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef V3D_VER_H
+#define V3D_VER_H
+
+/* if V3D_TECH_VERSION/V3D_REVISION aren't defined, try to figure them out from
+ * other defines... */
+#ifndef V3D_TECH_VERSION
+   #define V3D_TECH_VERSION 2
+#endif
+#ifndef V3D_REVISION
+   #ifdef __BCM2708A0__
+      #ifdef HERA
+         /* bcg a1, hera */
+         #define V3D_REVISION 1
+      #else
+         /* 2708 a0 */
+         #define V3D_REVISION 0
+      #endif
+   #elif defined(__BCM2708B0__)
+      /* 2708 b0 */
+      #define V3D_REVISION 2
+   #elif defined(__BCM2708C0__) || defined(__BCM2708C1__)
+      /* 2708 c0/1 */
+      #define V3D_REVISION 3
+   #else
+      /* capri */
+      #define V3D_REVISION 6
+   #endif
+#endif
+
+#define V3D_MAKE_VER(TECH_VERSION, REVISION) (((TECH_VERSION) * 100) + (REVISION))
+#define V3D_VER (V3D_MAKE_VER(V3D_TECH_VERSION, V3D_REVISION))
+#define V3D_VER_AT_LEAST(TECH_VERSION, REVISION) (V3D_VER >= V3D_MAKE_VER(TECH_VERSION, REVISION))
+
+/* TODO this is temporary */
+#if V3D_VER == V3D_MAKE_VER(9, 9)
+#define V3D_VER_D3D
+#endif
+
+#endif
diff --git a/helpers/vc_image/metadata_fourcc.h b/helpers/vc_image/metadata_fourcc.h
new file mode 100755 (executable)
index 0000000..64bccf7
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _METADATA_FOURCC_H
+#define _METADATA_FOURCC_H
+
+/******************************************************************************
+Definition of 4CCs assigned to metadata items. This list acts more as a 
+central repository of 4CCs for different metadata items so as to avoid clashes. 
+They are not otherwise necessary for library to function correctly.
+******************************************************************************/
+
+/*
+   Note: Multi-character constants are not valid C and although supported by 
+   some compilers such as Metaware, they are ambiguous in how they should be 
+   packed into a long due to endian-ness (and also due to size for 2 and 3 
+   character constants).
+*/
+
+typedef enum {
+
+   METADATA_CDI                  = ('C'<<24)+('D'<<16)+('M'<<8)+('D'),   // 'CDMD'    struct CDI_METADATA_T in /middleware/camplus/cdi/cdi.h 
+   METADATA_CAM_CAL              = ('C'<<24)+('C'<<16)+('A'<<8)+('L'),   // 'CCAL'    struct CAMERA_CALIBRATION_METADATA_T in /middleware/camplus/cdi/cdi.h 
+   METADATA_TIMING               = ('T'<<24)+('I'<<16)+('M'<<8)+('E'),   // 'TIME'    struct TIMING_METADATA_T in /middleware/camplus/cdi/cdi.h
+   METADATA_CDI_FILE             = ( 0 <<24)+('C'<<16)+('D'<<8)+('F'),   // '\x00CDF' struct CDI_FILE_METADATA_T in /middleware/camplus/cdi/cdi_file.h
+   METADATA_CDI_RAW              = ('C'<<24)+('D'<<16)+('R'<<8)+('W'),   // 'CDRW'    struct CDI_FILE_RAW_METADATA_T in /middleware/camplus/cdi/cdi_file_raw.h
+   METADATA_STABILISE            = ('S'<<24)+('T'<<16)+('A'<<8)+('B'),   // 'STAB'    struct GLOBAL_MOTION_VECTOR_T in /middleware/camplus/sw/stabilise/stabilise.h
+   METADATA_LOCAL_MV1            = ('L'<<24)+('M'<<16)+('V'<<8)+('1'),   // 'LMV1'    struct ALL_LOCAL_MOTION_VECTORS_T in /middleware/camplus/sw/stabilise/stabilise.h
+   METADATA_LOCAL_MV2            = ('L'<<24)+('M'<<16)+('V'<<8)+('2'),   // 'LMV2'    struct ALL_LOCAL_MOTION_VECTORS_T in /middleware/camplus/sw/stabilise/stabilise.h
+   METADATA_TUNER_AGC            = ( 0 <<24)+('A'<<16)+('G'<<8)+('C'),   // '\x00AGC' struct ISP_AGC_METADATA_T in /middleware/ISP/tuner/isp_tuner_ctrl.h
+   METADATA_AGC_DEBUG            = ('A'<<24)+('G'<<16)+('C'<<8)+('D'),   // 'AGCD'    struct ISP_TUNER_BRCM_AGC_DEBUG_T in /middleware/ISP/tuner/isp_tuner_agc.h
+   METADATA_FOCUS_REGION         = ('F'<<24)+('R'<<16)+('G'<<8)+('N'),   // 'FRGN'    struct ISP_TUNER_BRCM_AF_STATISTICS_PARAMS_T in /middleware/ISP/tuner/isp_tuner_brcm_common.h
+   METADATA_FOCUS_WOI            = ('F'<<24)+('W'<<16)+('O'<<8)+('I'),   // 'FWOI'    struct ISP_WOI_METADATA_T in /middleware/ISP/tuner/isp_tuner_ctrl.h
+   METADATA_FOCUS_CAF            = ('F'<<24)+('C'<<16)+('A'<<8)+('F'),   // 'FCAF'    struct ISP_CAF_METADATA_T in /middleware/ISP/tuner/isp_tuner_ctrl.h
+   METADATA_AUTOFOCUS            = ( 0 <<24)+( 0 <<16)+('A'<<8)+('F'),   // '\x00\x00AF'  struct ISP_AF_METADATA_T in /middleware/ISP/tuner/isp_tuner_ctrl.h
+   METADATA_EV                   = ('E'<<24)+('V'<<16)+('M'<<8)+('D'),   // 'EVMD'    struct ISP_TUNER_BRCM_EV_METADATA_T in /middleware/ISP/tuner/isp_tuner_brcm_common.h
+   METADATA_ISP                  = ('I'<<24)+('S'<<16)+('P'<<8)+('M'),   // 'ISPM'    struct ISP_ISP_METADATA_T in /middleware/ISP/tuner/isp_tuner_ctrl.h
+   METADATA_FACETRACKING         = ('F'<<24)+('A'<<16)+('C'<<8)+('E'),   // 'FACE'    struct FACE_METADATA_T defined in /middleware/camplus/sw/face_metadata.h
+   METADATA_ANTISHAKE            = ('S'<<24)+('H'<<16)+('A'<<8)+('K'),   // 'SHAK'    struct SHAKE_METADATA_T defined in /middleware/camplus/sw/shake_metadata.h
+   METADATA_RER                  = ( 0 <<24)+('R'<<16)+('E'<<8)+('R'),   // '\x00RER'    struct RER_METADATA_T defined in /middleware/camplus/sw/rer_metadata.h
+   METADATA_SCENEDETECTION       = ( 0 <<24)+('A'<<16)+('S'<<8)+('D'),   // '\x00ASD'    struct ASD_METADATA_T defined in /middleware/camplus/sw/asd_metadata.h
+   METADATA_TUNER_SYNC           = ('S'<<24)+('Y'<<16)+('N'<<8)+('C'),   // 'SYNC'    NULL data, just adds the item header.   
+   METADATA_DARK_FRAME_CORRECT   = ('D'<<24)+('F'<<16)+('R'<<8)+('C'),   // 'DFRC'    5 byte literal string "dfrc"
+   METADATA_DARK_FRAME_SUB       = ('D'<<24)+('F'<<16)+('S'<<8)+('B'),   // 'DFSB'    3 byte literal string "on"
+   METADATA_TUNER_DROP_FRAME     = ('T'<<24)+('D'<<16)+('R'<<8)+('P'),
+   METADATA_ABL                  = ( 0 <<24)+('A'<<16)+('B'<<8)+('L'),   // '\x00ABL'    struct ISP_TUNER_BRCM_BLACK_LEVEL_ABL_T defined in /middleware/ISP/tuner/isp_tuner_brcm_black_level.h
+   METADATA_DRC                  = ( 0 <<24)+('D'<<16)+('R'<<8)+('C'),  // 'DRC'         struct DRC_METADATA_T defined in /middleware/camplus/sw/drc/drc.h
+   METADATA_REGISTRATION         = ( 0 <<24)+('R'<<16)+('E'<<8)+('G'),    // 'REG'         struct REGISTRATION_OFFSETS_T defined in /middleware/camplus/sw/registration/registration.h
+   METADATA_RAW_CAPTURE          = ('R'<<24)+('W'<<16)+('M'<<8)+('D'),    // 'RWMD'   struct RAW_CAPTURE_METADATA_T defined in /middleware/camplus/sw/raw_metadata.h
+   // structure definitions for IL metadata are
+   // in middleware/openmaxil/headers/ilmetadata.h
+   METADATA_IL_CAMERA_NAME         = ('I'<<24)+('L'<<16)+('C'<<8)+('A'), // 'ILCA'
+   METADATA_IL_CROP_RECTANGLE      = ('I'<<24)+('L'<<16)+('C'<<8)+('R'), // 'ILCR'
+   METADATA_IL_PIXEL_ASPECT_RATIO  = ('I'<<24)+('L'<<16)+('P'<<8)+('A'), // 'ILPA'
+   
+   METADATA_TUNER_FLASH_MONITOR    = ('F'<<24)+('L'<<16)+('M'<<8)+('N'), // 'FLMN'  Flash monitor - type ISP_TUNER_BRCM_FLASH_MONITOR_T from isp_tuner_brcm.h
+
+
+   // VoWIFI video analysis
+   METADATA_SPATIAL_ACT_A     = ( 'S'<<24)+('P'<<16)+('T'<<8)+('A'), // 'SPTA' : SPATIAL_ACTIVITY_METADATA_T defined in /middleware/camplus/sw/perceptual/spatial_activity.h
+   METADATA_TEMPORAL_ACT_A    = ( 'T'<<24)+('M'<<16)+('P'<<8)+('A'), // 'TMPA' : TEMPORAL_ACTIVITY_METADATA_T defined in /middleware/camplus/sw/perceptual/temporal_activity.h
+   METADATA_FILMGRAIN_NOISE_A = ( 'F'<<24)+('G'<<16)+('N'<<8)+('A'), // 'FGNA' : FILMGRAIN_NOISE_METADATA_T defined in /middleware/camplus/sw/perceptual/filmgrain_noise.h
+   METADATA_COLORSPACE_A     = ( 'C'<<24)+('L'<<16)+('R'<<8)+('A'), // 'CLRA' : COLORSPACE_METADATA_T defined in /middleware/camplus/sw/perceptual/colorspace.h
+   METADATA_FLAT_AREA_A      = ( 'F'<<24)+('L'<<16)+('T'<<8)+('A'), // 'FLTA' : FLAT_AREA_METADATA_T defined in /middleware/camplus/sw/perceptual/flatarea.h
+   METADATA_STILL_AREA_A     = ( 'S'<<24)+('T'<<16)+('L'<<8)+('A'), // 'STLA' : FLAT_AREA_METADATA_T defined in /middleware/camplus/sw/perceptual/stillarea.h
+   METADATA_DDITHER_A        = ( 'D'<<24)+('D'<<16)+('T'<<8)+('A'), // 'DDTA' : DDITHER_METADATA_T defined in /middleware/camplus/sw/perceptual/...
+   
+   METADATA_LINKED_MULTICHANN = ( 'I'<<24)+('L'<<16)+('M'<<8)+('C'), // 'ILMC' : VC_IMAGE_LINKED_MULTICHANN_T defined in /helpers/vc_image/vc_image.h
+
+   METADATA_HDR              = ( 0 <<24)+( 'H'<<16)+('D'<<8)+('R'), // 'HDR' : HDR_METADATA_T defined in /middleware/camplus/sw/hdr/hdr_metadata.h
+   METADATA_FOCUS_STATS_PREPROC   = ('F'<<24)+('S'<<16)+('P'<<8)+('M'), // 'FSPM' : FOCUS_STATS_PREPROC_METADATA defined in /middleware/camplus/sw/hdr/focus_stats_preproc/focus_stats_preproc.h
+   METADATA_ACUTE_AWB_LOG        = ('A'<<24)+('E'<<16)+('L'<<8)+('C'), // 'AELC' : ISP_ACUTE_AWB_LOG
+   METADATA_DF               = ( 0 <<24)+(   0<<16)+('D'<<8)+('F'), // '\x00\x00DF' : DF_METADATA_T defined in /middleware/camplus/sw/df/df_metadata.h
+   METADATA_MAGIC_MEASURE    = ('S'<<24)+('S'<<16)+('M'<<8) + ('M'), // 'SSMM' : A statistic from the ISP used to determine the JPEG quality setting for a certain customer.
+   METADATA_SNAPSHOT_JPEG_QUANTISER = ('S'<<24)+('S'<<16)+('J'<<8) + ('S'), // 'SSJQ' : The size of the snapshot frame when JPEG-encoded.
+
+   METADATA_SUPPLEMENTARY_INFO   = ('S'<<24)+('U'<<16)+('P'<<8) + ('P'), // 'SUPP' : Supplimentary info defined in /codecs/video/hw/enc/venc_supplementary_info.h
+   
+   METADATA_UNKNOWN        = ('U'<<24)+('N'<<16)+('K'<<8)+('N') // 'UNKN'
+
+} METADATA_CODE_T;
+
+#endif
diff --git a/helpers/vc_image/vc_image.h b/helpers/vc_image/vc_image.h
new file mode 100755 (executable)
index 0000000..f566348
--- /dev/null
@@ -0,0 +1,804 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * \file
+ *
+ * This file describes the public interfaces to the old vc_image library.
+ */
+
+#ifndef VC_IMAGE_H
+#define VC_IMAGE_H
+
+#if !defined(__VIDEOCORE__) && !defined(__vce__) && !defined(VIDEOCORE_CODE_IN_SIMULATION)
+#error This code is only for use on VideoCore. If it is being included
+#error on the host side, then you have done something wrong. Defining
+#error __VIDEOCORE__ is *not* the right answer!
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdio.h>
+
+/* Definition for VC_IMAGE_TYPE_T live in here */
+#include "vcinclude/vc_image_types.h"
+#include "helpers/vc_image/vc_image_helper.h"
+
+#if !defined __SYMBIAN32__
+
+#if !defined( _MSC_VER) && !defined(__WIN32__)
+   #include "vcfw/rtos/rtos.h"
+#endif
+#include "vcfw/rtos/common/rtos_common_mem.h"
+
+#include "helpers/vc_image/vc_image_metadata.h"
+
+#if defined(__VIDEOCORE3__) && !defined(RGB888)
+#ifdef __GNUC__
+#warning "RGB888 should be defined on all VideoCore3 platforms, please check your platform makefile."
+#else
+#  warn "RGB888 should be defined on all VideoCore3 platforms, please check your platform makefile."
+#endif
+#endif
+
+   /* Types of extra properties that can be passed to vc_image_configure() */
+
+   typedef enum
+   {
+      VC_IMAGE_PROP_END = 0,
+      VC_IMAGE_PROP_NONE = 0x57EAD400,
+      VC_IMAGE_PROP_ALIGN,
+      VC_IMAGE_PROP_STAGGER,
+      VC_IMAGE_PROP_PADDING,
+      VC_IMAGE_PROP_PRIORITY,
+      VC_IMAGE_PROP_MALLOCFN,
+      VC_IMAGE_PROP_CACHEALIAS,
+      VC_IMAGE_PROP_CLEARVALUE,
+
+      /* insert only allocation-related properties above this line */
+
+      VC_IMAGE_PROP_REF_IMAGE = 0x57EAD47f,
+      VC_IMAGE_PROP_ROTATED,
+      VC_IMAGE_PROP_PITCH,
+      VC_IMAGE_PROP_DATA,
+      VC_IMAGE_PROP_SIZE,
+      VC_IMAGE_PROP_PALETTE,
+      VC_IMAGE_PROP_MIPMAPS,
+      VC_IMAGE_PROP_BAYER_ORDER,
+      VC_IMAGE_PROP_BAYER_FORMAT,
+      VC_IMAGE_PROP_BAYER_BLOCK_SIZE,
+      VC_IMAGE_PROP_CODEC_FOURCC,
+      VC_IMAGE_PROP_CODEC_MAXSIZE,
+      VC_IMAGE_PROP_CUBEMAP,
+      VC_IMAGE_PROP_OPENGL_FORMAT_AND_TYPE,
+      VC_IMAGE_PROP_INFO,
+      VC_IMAGE_PROP_METADATA,
+      VC_IMAGE_PROP_NEW_LIST,
+      /* Multi-channel properties */
+      VC_IMAGE_PROP_NUM_CHANNELS,
+      VC_IMAGE_PROP_IS_TOP_BOTTOM,
+      VC_IMAGE_PROP_IS_DECIMATED,
+      VC_IMAGE_PROP_IS_PACKED,
+      VC_IMAGE_PROP_YUV_COLOURSPACE,
+      /* Linked-multichannel properties*/
+      VC_IMAGE_PROP_LINKED_MULTICHANN,
+      VC_IMAGE_PROP_VPITCH
+   } VC_IMAGE_PROPERTY_T;
+
+   /* A property key and value */
+   typedef struct
+   {
+      VC_IMAGE_PROPERTY_T prop;
+      unsigned long value;
+   } VC_IMAGE_PROPLIST_T;
+#define VC_IMAGE_PROPLIST_COUNT(x) (sizeof(x)/sizeof(x[0]))
+#define VC_IMAGE_PROPLIST_NULL   ((VC_IMAGE_PROPLIST_T*)0)
+
+
+   /* Useful bits that can be set, to check validity we'll assume that all other
+      bits should be zero and enforce this in vc_image functions to catch people
+      who aren't initialising the VC_IMAGE_T structure nicely; update when other
+      bits are added */
+#define VC_IMAGE_INFO_VALIDBITS    0x9F0F
+   /* Define the bits of info used to denote the colourspace */
+#define VC_IMAGE_INFO_COLOURSPACE  0x0F
+
+#endif //#if !defined __SYMBIAN32__
+
+#define is_valid_vc_image_hndl(_img, _type) ((_img) != NULL \
+                                 && (_img)->image_data == NULL \
+                                 && ((_img)->info.info & ~VC_IMAGE_INFO_VALIDBITS) == 0 \
+                                 && (_type) > VC_IMAGE_MIN && (_type) < VC_IMAGE_MAX \
+                                 && (_img)->type == (_type) \
+                                 )
+
+#define is_valid_vc_image_buf(_img, _type) ((_img) != NULL \
+                                 && (_img)->image_data != NULL \
+                                 && ((_img)->info.info & ~VC_IMAGE_INFO_VALIDBITS) == 0 \
+                                 && (_type) > VC_IMAGE_MIN && (_type) < VC_IMAGE_MAX \
+                                 && (_img)->type == (_type) \
+                                 )
+
+#define is_within_rectangle(x, y, w, h, cont_x, cont_y, cont_w, cont_h) ( \
+                              (x) >= (cont_x) \
+                              && (y) >= (cont_y) \
+                              && ((x) + (w)) <= ((cont_x) + (cont_w)) \
+                              && ((y) + (h)) <= ((cont_y) + (cont_h)) \
+                              )
+
+
+#if !defined __SYMBIAN32__
+
+
+   /**
+    * \brief storage for pointers to image headers of the previous and next channel
+    *
+    * 
+    * When linked-multichannel structure is being used, this structure stores the pointers 
+    * necessary to link the current image header in to make represent a multichannel image.
+    */
+   struct VC_IMAGE_LINKED_MULTICHANN_T {
+      VC_IMAGE_T* prev;
+      VC_IMAGE_T* next;
+   };
+   typedef struct VC_IMAGE_LINKED_MULTICHANN_T VC_IMAGE_LINKED_MULTICHANN_T;
+
+   /* Point type for use in polygon drawing. */
+   typedef struct vc_image_point_s {
+      int x, y;
+   } VC_IMAGE_POINT_T;
+
+   /* Useful for rectangular crop regions in a vc_image */
+   typedef struct vc_image_rect_s
+   {
+      unsigned int x, y;
+      unsigned int width;
+      unsigned int height;
+   } VC_IMAGE_RECT_T;
+
+   /* CRC type for the return of CRC results */
+   typedef struct VC_IMAGE_CRC_T_ {
+      unsigned int y;
+      unsigned int uv;
+   } VC_IMAGE_CRC_T;
+
+   /* To make stack-based initialisation convenient: */
+
+#define NULL_VC_IMAGE_T {0, 0, 0, 0, 0, 0}
+
+   /* Convenient constants that can be passed more readably to vc_image_text. */
+
+#define VC_IMAGE_COLOUR_TRANSPARENT -1
+#define VC_IMAGE_COLOUR_FADE -2
+
+#define CLIP_DEST(x_offset, y_offset, width, height, dest_width, dest_height) \
+   if (x_offset<0)                              \
+      width-=-x_offset, x_offset=0;             \
+   if (y_offset<0)                              \
+      height-=-y_offset, y_offset=0;            \
+   if (x_offset+width>dest_width)               \
+      width-=x_offset+width-dest_width;         \
+   if (y_offset+height>dest_height)             \
+      height-=y_offset+height-dest_height;      \
+
+
+   /* Publicly exported functions. */
+
+   /******************************************************************************
+   General functions.
+   ******************************************************************************/
+
+//routine to return a bitmask (bit referenced by VC_IMAGE_TYPE_T) of the supported image formats built in
+//this particular version of the vc_image library
+   unsigned int vc_image_get_supported_image_formats( void );
+
+   /******************************************************************************
+   Data member access.
+   ******************************************************************************/
+
+   /* Initialise all fields of a VC_IMAGE_T to zero. */
+
+   void vc_image_initialise(VC_IMAGE_T *image);
+
+   /* Return specified channel of a multi-channel VC_IMAGE_T as a single-channel VC_IMAGE_T. */
+
+   void vc_image_extract_channel(VC_IMAGE_T *extract, VC_IMAGE_T *image, uint8_t chan_idx);
+
+   /* Fill out all fields of a VC_IMAGE_T in the same way as vc_image_malloc(), but non-allocating. */
+
+#if defined(va_start) /* can't publish this without including <stdarg.h> */
+   int vc_image_vconfigure(VC_IMAGE_T *image, VC_IMAGE_TYPE_T type, long width, long height, va_list proplist);
+   int vc_image_vreconfigure(VC_IMAGE_T *image, VC_IMAGE_TYPE_T type, long width, long height, va_list proplist);
+#endif
+   int vc_image_configure_unwrapped(VC_IMAGE_T *image, VC_IMAGE_TYPE_T type, long width, long height, VC_IMAGE_PROPERTY_T prop, ...);
+   int vc_image_reconfigure_unwrapped(VC_IMAGE_T *image, VC_IMAGE_TYPE_T type, long width, long height, VC_IMAGE_PROPERTY_T prop, ...);
+   /* remaining arguments are a VC_IMAGE_PROPERTY_T list terminated with VC_IMAGE_END */
+
+   int vc_image_configure_proplist(VC_IMAGE_T *image, VC_IMAGE_TYPE_T type, long width, long height, VC_IMAGE_PROPLIST_T *props, unsigned long n_props);
+
+   void vc_image_lock( VC_IMAGE_BUF_T *dst, const VC_IMAGE_T *src );
+
+   void vc_image_lock_extract( VC_IMAGE_BUF_T *dst, const VC_IMAGE_T *src, uint8_t chan_idx );
+
+   void vc_image_lock_channel(VC_IMAGE_BUF_T *dst, const VC_IMAGE_T *chann);
+   void vc_image_lock_channel_perma(VC_IMAGE_BUF_T *dst, const VC_IMAGE_T *chann); //lightweight version of lock channel
+
+   void vc_image_unlock( VC_IMAGE_BUF_T *img );
+
+   void vc_image_lock_perma( VC_IMAGE_BUF_T *dst, const VC_IMAGE_T *src );
+
+   void vc_image_unlock_perma( VC_IMAGE_BUF_T *img );
+
+   /* Mipmap-related functions. Image must be brcm1. */
+
+   /* Take the base image of an image and scale it down into its mipmaps. */
+   /* The filter argument type is likely to change, but 0 should always be a
+    * reasonable value (even if it becomes a pointer). */
+   void vc_image_rebuild_mipmaps(VC_IMAGE_BUF_T *dst, int filter);
+
+   /******************************************************************************
+   Image/bitmap manipulation.
+   ******************************************************************************/
+
+   /* Fill a region of an image with solid colour. */
+
+   void vc_image_fill(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int width, int height, int value);
+
+   /* Blt a region of an image to another. */
+
+   void vc_image_blt(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int width, int height,
+                     VC_IMAGE_BUF_T *src, int src_x_offset, int src_y_offset);
+
+   /* Blt a region of an image to another, changing the format on the fly. */
+
+   void vc_image_convert_blt(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int width, int height,
+                             VC_IMAGE_BUF_T *src, int src_x_offset, int src_y_offset);
+
+   /* Expose the special cases of above */
+   void vc_image_yuv420_to_rgba32_part(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int width, int height, VC_IMAGE_BUF_T const *src, int src_x_offset, int src_y_offset, int alpha);
+
+   void vc_image_rgb565_to_rgba32_part(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int width, int height, VC_IMAGE_BUF_T const *src, int src_x_offset, int src_y_offset, int alpha);
+   /* Blt a region of an image to another with a nominated transparent colour. */
+
+   void vc_image_transparent_blt(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int width, int height,
+                                 VC_IMAGE_BUF_T *src, int src_x_offset, int src_y_offset, int transparent_colour);
+
+   /* Blt a region of an image to another but only overwriting pixels of a given colour. */
+
+   void vc_image_overwrite_blt(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int width, int height,
+                               VC_IMAGE_BUF_T *src, int src_x_offset, int src_y_offset, int overwrite_colour);
+
+   /* Blt a region of an image to another only where a mask bitmap has 1s. */
+
+   void vc_image_masked_blt (VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int width, int height,
+                             VC_IMAGE_BUF_T *src, int src_x_offset, int src_y_offset,
+                             VC_IMAGE_BUF_T *mask, int mask_x_offset, int mask_y_offset,
+                             int invert);
+
+   /* Masked fill a region with a solid colour. */
+
+   void vc_image_masked_fill(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int width, int height, int value,
+                             VC_IMAGE_BUF_T *mask, int mask_x_offset, int mask_y_offset,
+                             int invert);
+
+   /* Blt an image into 3 separate buffers, either YUV or RGB
+      Will always copy the entire image. In the case of RGB image:
+      Y = RGB, U = NULL, V = NULL */
+
+   void vc_image_fetch(VC_IMAGE_BUF_T *src, unsigned char* Y, unsigned char* U, unsigned char* V);
+
+   /* Blt the data in Y U V (or RGB) buffers into a VC_IMAGE structure
+      Opposite to vc_image_put above */
+
+   void vc_image_put(VC_IMAGE_BUF_T *src, unsigned char* Y, unsigned char* U, unsigned char* V);
+
+   /* NOT a region of an image. */
+
+   void vc_image_not(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int width, int height);
+
+   /* Fade (or brighten) a region of an image. fade is an 8.8 value. */
+
+   void vc_image_fade(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int width, int height, int fade);
+
+   /* OR two images together. */
+
+   void vc_image_or(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int width, int height,
+                    VC_IMAGE_BUF_T *src, int src_x_offset, int src_y_offset);
+
+   /* XOR two images together. */
+
+   void vc_image_xor(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int width, int height,
+                     VC_IMAGE_BUF_T *src, int src_x_offset, int src_y_offset);
+
+   /* Copy an image in its entirety (works on 1bpp images). */
+
+   void vc_image_copy(VC_IMAGE_BUF_T *dest, VC_IMAGE_BUF_T *src);
+
+   /* Transpose an image. */
+
+   void vc_image_transpose(VC_IMAGE_BUF_T *dest, VC_IMAGE_BUF_T *src);
+   int vc_image_transpose_ret(VC_IMAGE_T *dest, VC_IMAGE_T *src);
+
+   /* Transpose an image and subsample it by some integer factor */
+   void vc_image_transpose_and_subsample(VC_IMAGE_BUF_T *dest, VC_IMAGE_BUF_T *src, int factor);
+
+   /* Vertically flip an image (turn "upside down"). */
+
+   void vc_image_vflip(VC_IMAGE_BUF_T *dest, VC_IMAGE_BUF_T *src);
+
+   /* Horizontally flip an image ("mirror"). */
+
+   void vc_image_hflip(VC_IMAGE_BUF_T *dest, VC_IMAGE_BUF_T *src);
+
+   /* Transpose an image in place. Relies on being able to preserve the pitch. */
+
+   void vc_image_transpose_in_place(VC_IMAGE_BUF_T *dest);
+
+   /* Vertically flip an image (turn "upside down") in place. */
+
+   void vc_image_vflip_in_place(VC_IMAGE_BUF_T *dest);
+
+   /* Horizontally flip an image ("mirror") in place. */
+
+   void vc_image_hflip_in_place(VC_IMAGE_BUF_T *dest);
+
+   /* Add text string to an image. */
+
+   void vc_image_text(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int fg_colour, int bg_colour, const char *text,
+                      int *max_x, int *max_y);
+
+   void vc_image_small_text(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int fg_colour, int bg_colour, const char *text,
+                            int *max_x, int *max_y);
+
+   void vc_image_text_20(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int fg_colour, int bg_colour, const char *text,
+                         int *max_x, int *max_y);
+
+   void vc_image_text_24(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int fg_colour, int bg_colour, const char *text,
+                         int *max_x, int *max_y);
+
+   void vc_image_text_32(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int fg_colour, int bg_colour, const char *text,
+                         int *max_x, int *max_y);
+
+   /* Experimental vector font thingy */
+
+#define VC_IMAGE_ATEXT_FIXED (1<<16) // Add this to "size" if you want fixed-width
+
+   int vc_image_atext_measure(int size, const char * str);
+
+   int vc_image_atext_clip_length(int size, const char * str, int width);
+
+   int vc_image_atext(VC_IMAGE_BUF_T * dest, int x, int y, int fg, int bg, int size, const char * str);
+
+   /* Add optionally rotated text to an image */
+
+   void vc_image_textrotate(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int fg_colour, int bg_colour, const char *text, int rotate);
+
+
+   /* Line drawing. */
+
+   void vc_image_line(VC_IMAGE_BUF_T *dest, int x_start, int y_start, int x_end, int y_end, int fg_colour);
+
+   /* Unfilled Rect. */
+
+   void vc_image_rect(VC_IMAGE_BUF_T *dest, int x_start, int y_start, int width, int height, int fg_colour);
+
+   /* Add frame . */
+
+   void vc_image_frame(VC_IMAGE_BUF_T *dest, int x_start, int y_start, int width, int height);
+
+   void vc_image_aa_line(VC_IMAGE_BUF_T *dest, int x_start, int y_start, int x_end, int y_end, int thickness, int colour);
+   void vc_image_aa_ellipse(VC_IMAGE_BUF_T *dest, int cx, int cy, int a, int b, int thickness, int colour, int filled);
+   void vc_image_aa_polygon(VC_IMAGE_BUF_T *dest, VC_IMAGE_POINT_T *p, int n, int thickness, int colour, int filled);
+
+   /* Copy and convert image to 48bpp. WARNING: offsets, width and height must be 16-pixel aligned. */
+
+   void vc_image_convert_to_48bpp(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int width, int height,
+                                  VC_IMAGE_BUF_T *src, int src_x_offset, int src_y_offset);
+
+   /* Copy and convert image from 16bpp to 24bpp. WARNING: offsets, width and height must be 16-pixel aligned. */
+
+   void vc_image_convert_to_24bpp(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int width, int height,
+                                  VC_IMAGE_BUF_T *src, int src_x_offset, int src_y_offset);
+
+   /* Convert and overlay image from 16bpp to 24bpp with nominated transparent colour. WARNING: offsets, width and height must be 16-pixel aligned. */
+
+   void vc_image_overlay_to_24bpp(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int width, int height,
+                                  VC_IMAGE_BUF_T *src, int src_x_offset, int src_y_offset, int transparent_colour);
+
+   /* Copy and convert image from 24bpp to 16bpp. WARNING: offsets, width and height must be 16-pixel aligned. */
+
+   void vc_image_convert_to_16bpp(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int width, int height,
+                                  VC_IMAGE_BUF_T *src, int src_x_offset, int src_y_offset);
+
+   /* Copy all, or a portion of src to dest with resize. This function is specialized
+      for YUV images (other cases are not yet coded, and code could be rather large
+      to link all cases by default). All dimensions should be multiples of 2.
+      If smooth_flag nonzero, appropriate smoothing will be applied.                 */
+
+   void vc_image_resize_yuv(VC_IMAGE_BUF_T *dest,
+                            int dest_x_offset, int dest_y_offset,
+                            int dest_width, int dest_height,
+                            VC_IMAGE_BUF_T *src,
+                            int src_x_offset, int src_y_offset,
+                            int src_width, int src_height,
+                            int smooth_flag);
+
+   /* RGB565 resize. Pitch must be 32-byte aligned, dimensions need not be.
+      XXX kept YUV and RGB565 version separate to avoid unnecessary linking.
+      However if we're going down the DLL route they ought to be combined.   */
+
+   void vc_image_resize_rgb565(VC_IMAGE_BUF_T * dest,
+                               int dest_x_offset, int dest_y_offset,
+                               int dest_width, int dest_height,
+                               VC_IMAGE_BUF_T *src,
+                               int src_x_offset, int src_y_offset,
+                               int src_width, int src_height,
+                               int smooth_flag);
+
+   void vc_image_resize(VC_IMAGE_BUF_T *dest,
+                        int dest_x_offset, int dest_y_offset,
+                        int dest_width, int dest_height,
+                        VC_IMAGE_BUF_T *src,
+                        int src_x_offset, int src_y_offset,
+                        int src_width, int src_height,
+                        int smooth_flag);
+
+   /* Resize YUV in strips. XXX this function has rather bizarre arguments. */
+
+   void vc_image_resize_yuv_strip(VC_IMAGE_BUF_T * dest, VC_IMAGE_BUF_T * src,
+                                  int src_x_offset, int src_width,
+                                  int pos, int step, int smooth_flag,
+                                  void * tmp_buf, int tmp_buf_size);
+
+   /* Blit from a YUV image to an RGB image with optional mirroring followed
+   by optional clockwise rotation */
+   void vc_image_convert(VC_IMAGE_BUF_T *dest,VC_IMAGE_BUF_T *src,int mirror,int rotate);
+
+   /* Convert bitmap from one type to another, doing vertical flip as part of the conversion */
+   void vc_image_convert_vflip(VC_IMAGE_BUF_T *dest, VC_IMAGE_BUF_T *src);
+
+   /* Convert from YUV to RGB, with optional downsample by 2 in each direction. */
+   void vc_image_yuv2rgb(VC_IMAGE_BUF_T *dest, VC_IMAGE_BUF_T *src, int downsample);
+
+   void vc_image_convert_yuv2rgb(unsigned char *datay, unsigned char *datau
+                           , unsigned char *datav, int realwidth, int realheight
+                           , unsigned short *buffer, int screenwidth, int screenheight);
+
+   /* Frees up (using free_256bit) the source bytes and vc_image header */
+   void vc_image_free(VC_IMAGE_T *img);
+
+   /* Returns an image based on decompressing the given bytes (made by helpers/vc_image/runlength.m) */
+   VC_IMAGE_BUF_T *vc_runlength_decode(unsigned char *data);
+
+   /* Returns a 16bit image based on decompressing the given bytes (made by helpers/vc_image/covnertbmp2run.m) */
+   VC_IMAGE_BUF_T *vc_run_decode(VC_IMAGE_BUF_T *img,unsigned char *data);
+
+   /* Returns an image based on decompressing the given bytes (made by helpers/vc_image/runlength8.m) */
+   VC_IMAGE_BUF_T *vc_runlength_decode8(unsigned char *data);
+
+   /* Returns an image based on decompressing an image (made by helpers/vc_image/enc4by4.m)
+   Will place the decompressed data into an existing image if supplied */
+   VC_IMAGE_BUF_T *vc_4by4_decode(VC_IMAGE_BUF_T *img,unsigned short *data);
+
+   /* Deblocks a YUV image using a simple averaging scheme on 8 by 8 blocks */
+   void vc_image_deblock(VC_IMAGE_BUF_T *img);
+
+   /* Pack the bytes (i.e. remove the padding bytes) in a vc_image. */
+   void vc_image_pack(VC_IMAGE_BUF_T *img, int x, int y, int w, int h);
+
+   /* Pack bytes as above, but copy them to another memory block in the process. */
+   void vc_image_copy_pack (unsigned char *dest, VC_IMAGE_BUF_T *img, int x, int y, int w, int h);
+
+   /* Unpack bytes to have the correct padding. */
+   void vc_image_unpack(VC_IMAGE_BUF_T *img, int w, int h);
+
+   /* Unpack bytes as above, but also copy them to another memory block in the process. */
+   void vc_image_copy_unpack(VC_IMAGE_BUF_T *img, int dest_x_off, int dest_y_off, unsigned char *src, int w, int h);
+
+   /* swap red/blue */
+   void vc_image_swap_red_blue(VC_IMAGE_BUF_T *img);
+
+#if defined(va_start) /* can't publish this without including <stdarg.h> */
+   VC_IMAGE_BUF_T *vc_image_vparmalloc_unwrapped(VC_IMAGE_TYPE_T type, char const *description, long width, long height, va_list proplist);
+#endif
+   VC_IMAGE_BUF_T *vc_image_parmalloc_unwrapped(VC_IMAGE_TYPE_T type, char const *description, long width, long height, VC_IMAGE_PROPERTY_T prop, ...);
+
+   void vc_image_parfree(VC_IMAGE_BUF_T *p);
+
+   VC_IMAGE_BUF_T *vc_image_malloc( VC_IMAGE_TYPE_T type, long width, long height, int rotate );
+   VC_IMAGE_BUF_T *vc_image_prioritymalloc( VC_IMAGE_TYPE_T type, long width, long height, int rotate, int priority, char const *name);
+#define vc_image_priorityfree(p) vc_image_free(p)
+
+   VC_IMAGE_T *vc_image_relocatable_alloc(VC_IMAGE_TYPE_T type, const char *description, long width, long height, MEM_FLAG_T flags, VC_IMAGE_PROPERTY_T prop, ...);
+   void vc_image_relocatable_free(VC_IMAGE_T *img);
+
+   void vc_image_set_palette( short *colourmap );
+   short *vc_image_get_palette( VC_IMAGE_T *src );
+
+   void vc_image_convert_in_place(VC_IMAGE_BUF_T *image, VC_IMAGE_TYPE_T new_type);
+
+   /* Image transformations (flips and 90 degree rotations) */
+   VC_IMAGE_TRANSFORM_T vc_image_inverse_transform(VC_IMAGE_TRANSFORM_T transform);
+
+   VC_IMAGE_TRANSFORM_T vc_image_combine_transforms(VC_IMAGE_TRANSFORM_T transform1, VC_IMAGE_TRANSFORM_T transform2);
+
+   void vc_image_transform_point(int *pX, int *pY, int w, int h, VC_IMAGE_TRANSFORM_T transform);
+
+   void vc_image_transform_rect(int *pX, int *pY, int *pW, int *pH, int w, int h, VC_IMAGE_TRANSFORM_T transform);
+
+   void vc_image_transform_dimensions(int *pW, int *pH, VC_IMAGE_TRANSFORM_T transform);
+
+   void vc_image_transform(VC_IMAGE_BUF_T *dest, VC_IMAGE_BUF_T *src, VC_IMAGE_TRANSFORM_T transform);
+   int vc_image_transform_ret(VC_IMAGE_T *dest, VC_IMAGE_T *src, VC_IMAGE_TRANSFORM_T transform);
+
+   void vc_image_transform_in_place(VC_IMAGE_BUF_T *image, VC_IMAGE_TRANSFORM_T transform);
+
+   void vc_image_transform_brcm1s(VC_IMAGE_BUF_T *dest, VC_IMAGE_BUF_T *src, VC_IMAGE_TRANSFORM_T transform, int hdeci);
+
+   const char *vc_image_transform_string(VC_IMAGE_TRANSFORM_T xfm);
+
+   /* Blt a region of an image to another with a nominated transparent colour and alpha blending.
+   Alpha should be between 0 and 256 */
+   void vc_image_transparent_alpha_blt(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int width, int height,
+                                       VC_IMAGE_BUF_T *src, int src_x_offset, int src_y_offset, int transparent_colour, int alpha);
+
+   /* Blt a region of an image to another with a nominated transparent colour and alpha blending.
+   Alpha should be between 0 and 256 */
+   void vc_image_transparent_alpha_blt_rotated(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset,
+         VC_IMAGE_BUF_T *src, int transparent_colour, int alpha, int scale, int sin_theta, int cos_theta);
+
+   /* Blt a special 4.4 font image generated from a PNG file.
+   Only works with a 565 destination image.
+   Can choose a colour via red,green,blue arguments.  Each component should be between 0 and 255.
+   The alpha value present in the font image is scaled by the alpha argument given to the routine
+   Alpha should be between 0 and 256 */
+   void vc_image_font_alpha_blt(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int width, int height,
+                                VC_IMAGE_BUF_T *src, int src_x_offset, int src_y_offset, int red, int green, int blue, int alpha);
+
+   /* Utilities for image editor */
+   extern void im_split_components(VC_IMAGE_BUF_T *dest, VC_IMAGE_BUF_T *src,
+                                      int width, int height, int pitch);
+
+   extern void im_merge_components(VC_IMAGE_BUF_T *dest, VC_IMAGE_BUF_T *src,
+                                      int width, int height, int pitch);
+
+   extern void im_merge_components_adjacent(VC_IMAGE_BUF_T *dest, VC_IMAGE_BUF_T *src,
+            int width, int height, int pitch,
+            int badjacent);
+
+   /* Deflicker a YUV image using a simple low pass filter */
+   void vc_image_deflicker(VC_IMAGE_BUF_T *img, unsigned char *context);
+
+   /* Blend an Interlaced YUV image using a simple low pass filter which works on colour as well as luma*/
+   void vc_image_blend_interlaced(VC_IMAGE_BUF_T *img, unsigned char *context);
+
+   /* Stripe resizing. Resize a 16-high stripe horizontally to have the given width,
+      or a 16-wide column to have the given height. Work in place, uses bilinear filtering. */
+   void vc_image_resize_stripe_h(VC_IMAGE_BUF_T *image, int d_width, int s_width);
+   void vc_image_resize_stripe_v(VC_IMAGE_BUF_T *image, int d_height, int s_height);
+
+   /* Stripe resizing. Resize a horizontal stripe to 16-high, or a vertical stripe to 16 wide.
+      Work in place, uses bilinear filtering. */
+   void vc_image_decimate_stripe_h(VC_IMAGE_BUF_T *src, int offset, int step);
+   void vc_image_decimate_stripe_v(VC_IMAGE_BUF_T *src, int offset, int step);
+
+
+   extern int vc_image_set_alpha(VC_IMAGE_BUF_T *image,
+                                    const int x,
+                                    const int y,
+                                    const int width,
+                                    const int height,
+                                    const int alpha );
+
+   /* Make a horizontal alpha gradient mask for used in alpha blending below */
+   extern void vc_image_make_alpha_gradient(VC_IMAGE_BUF_T *pimage,
+            int start_alpha, int end_alpha);
+
+   /* Alpha blend two images together using an alpha mask */
+   extern void vc_image_alphablend(VC_IMAGE_BUF_T *dest, VC_IMAGE_BUF_T *src, VC_IMAGE_BUF_T *mask,
+                                      int dest_xoffset, int dest_yoffset,
+                                      int src_xoffset, int src_yoffset,
+                                      int width, int height);
+
+   typedef struct vc_image_pool_s * VC_IMAGE_POOL_HANDLE_T;
+   typedef VC_IMAGE_POOL_HANDLE_T VC_IMAGE_POOL_HANDLE; /* legacy */
+
+   /* Blt a region of an image onto a particular mipmap of a brcm1 image */
+   /* XXX do not use this function - the interface is likely to change as I decide
+    * what options are available here */
+   void vc_image_XXX_mipmap_blt_XXX(VC_IMAGE_BUF_T *dest, int x_offset, int y_offset, int width, int height,
+                                    VC_IMAGE_BUF_T *src, int src_x_offset, int src_y_offset, int miplvl, int cubeface, VC_IMAGE_TRANSFORM_T transform);
+
+   /* Function to calculate the crc of the VC_IMAGE */
+   VC_IMAGE_CRC_T vc_image_calc_crc_interlaced(VC_IMAGE_BUF_T *img, int cl, int cr, int ct, int cb, int field);
+
+   /* make compatible with old function */
+   #define vc_image_calc_crc(img,cl,cr,ct,cb) vc_image_calc_crc_interlaced((img),(cl),(cr),(ct),(cb),-1)
+
+#define vc_image_calc_crc_fast vc_image_calc_crc
+
+#if defined(NDEBUG)
+#  define vc_image_debugstr(x) NULL
+#else
+#  define vc_image_debugstr(x) (x)
+#endif
+
+#define vc_image_vparmalloc(type, desc, width, height, proplist) vc_image_vpmalloc(type, vc_image_debugstr(desc), width, height, proplist)
+#if __STDC_VERSION__ >= 199901L || _MSC_VER >= 1400
+#  define vc_image_parmalloc(type, desc, ...)         vc_image_parmalloc_unwrapped(type, vc_image_debugstr(desc), __VA_ARGS__, VC_IMAGE_PROP_END)
+#  define vc_image_configure(...)                     vc_image_configure_unwrapped(__VA_ARGS__, VC_IMAGE_PROP_END)
+#  define vc_image_reconfigure(...)                   vc_image_reconfigure_unwrapped(__VA_ARGS__, VC_IMAGE_PROP_END)
+#elif !defined(_MSC_VER) && !defined(VCMODS_LCC)
+#  define vc_image_parmalloc(type, desc, arglist...)  vc_image_parmalloc_unwrapped(type, vc_image_debugstr(desc), arglist, VC_IMAGE_PROP_END)
+#  define vc_image_configure(image, arglist...)       vc_image_configure_unwrapped(image, arglist, VC_IMAGE_PROP_END)
+#  define vc_image_reconfigure(image, arglist...)     vc_image_reconfigure_unwrapped(image, arglist, VC_IMAGE_PROP_END)
+#else
+   /*#  warning "Your compiler does not support variadic macros.  You'll have no vc_image_configure() or vc_image_parmalloc() functions."*/
+#endif
+
+// now included in vc_image.c as openmaxil uses it regardless of which formats are built for
+extern void vc_subsample(VC_IMAGE_BUF_T *sub,VC_IMAGE_BUF_T *cur);
+
+#ifdef USE_YUV_UV
+
+extern void vc_save_YUV( VC_IMAGE_BUF_T *frame,
+                            const char                * const sz_filename);
+
+extern void vc_save_YUV_1file( VC_IMAGE_BUF_T *frame, const char * const sz_filename, int framenum );
+
+extern void vc_load_YUVUV( VC_IMAGE_BUF_T *frame,
+                              const char                * const sz_filename,int yuvwidth,int yuvheight);
+
+extern void vc_load_YUV( VC_IMAGE_BUF_T *frame,
+                            const char                * const sz_filename,int framenum);
+
+extern void vc_endianreverse32(uint32_t *addr,int count);
+
+/*
+** This is my preferred function to load a YUV_UV image.  It works with either a collection of images
+** e.g. foo%03u.yuv or one giant concatenated file e.g. foo.yuv.
+** It will tile or truncate the output image to what you want which is why there are two heights & widths.
+** Return 0 if successful; -1 if the params are unsuitable, -2 if we couldn't open the file.
+*/
+extern int vc_load_image( const char         * const sz_file_fmt,          /* in     */
+                          const unsigned     iim,                          /* in     */
+                          const int          pitch,                        /* in     */
+                          const int          i_height,                     /* in     */ /* (i)nput image: i.e. raw file */
+                          const int          i_width,                      /* in     */
+                          const int          o_height,                     /* in     */ /* (o)utput image: i.e. framebuffer */
+                          const int          o_width,                      /* in     */
+                          const VC_IMAGE_BUF_T * const frame               /* in     */ );
+
+/* Modified version of vc_load_image (for maximum efficiency):
+ * - must be supplied with a buffer to read a whole YUV frame into
+ * - reads the next sequential image in an already-open file (no fopen/fseek/fclose).
+ * - no tiling: output size = input size.
+ */
+void vc_slurp_image (FILE            * fid,                          /* in     */
+                     const int          pitch,                       /* in     */
+                     const int          height,                      /* in     */
+                     const int          width,                       /* in     */
+                     const VC_IMAGE_T * const frame,                 /* in     */
+                     unsigned char    * frame_buf,                   /* in     */
+                     int                rewind);                     /* in     */
+
+extern int vc_load_image_vowifi( void * infile_fid,
+                           const unsigned     iim,                          /* in     */
+                           const int          pitch,                        /* in     */
+                           const int          i_height,                     /* in     */ /* (i)nput image: i.e. raw file */
+                           const int          i_width,                      /* in     */
+                           const int          o_height,                     /* in     */ /* (o)utput image: i.e. framebuffer */
+                           const int          o_width,                      /* in     */
+                           const VC_IMAGE_BUF_T * const frame               /* in     */ ) ;
+
+extern int vc_load_image_vowifi_brcm1d( void * infile_fid,
+                           const unsigned     iim,                          /* in     */
+                           const int          pitch,                        /* in     */
+                           const int          i_height,                     /* in     */ /* (i)nput image: i.e. raw file */
+                           const int          i_width,                      /* in     */
+                           const int          o_height,                     /* in     */ /* (o)utput image: i.e. framebuffer */
+                           const int          o_width,                      /* in     */
+                           const VC_IMAGE_BUF_T * const frame,               /* in     */
+                           const unsigned char *frame_buf) ;
+
+/*
+** Vector routine to difference a pair of images ( d |-|= a ).
+** Should probably dcache flush after this if using via uncached alias?
+*/
+extern
+void vc_image_difference( VC_IMAGE_BUF_T         * const d,          /* in/out */
+                          const VC_IMAGE_BUF_T   * const a,          /* in     */
+                          float                  * const psnr_y,     /*    out */
+                          float                  * const psnr_uv,    /*    out */
+                          unsigned               * const max_y,      /*    out */
+                          unsigned               * const max_uv      /*    out */ );
+
+
+/*
+** The h.263 Annex J deblocker.
+** ("dest" & "src" may point to the same storage.)
+*/
+extern
+void vc_image_deblock_h263( VC_IMAGE_BUF_T       * const dest,       /*(in)out */
+                            const VC_IMAGE_BUF_T * const src,        /* in     */
+                            const int            QUANT               /* in     */ );
+
+/*
+ *  Clone the top field of an interlaced image (lines 0,2,4,..) over the bottom field (lines 1,3,5,...)
+ *   or vice versa
+*/
+extern
+void vc_image_clone_field(VC_IMAGE_T * image, int clone_top_field);
+
+#endif
+
+
+   /* RGBA32 colour macros */
+#define RGBA_ALPHA_TRANSPARENT 0
+#define RGBA_ALPHA_OPAQUE 255
+
+#define RGBA32_TRANSPARENT_COLOUR 0x00000000
+#ifdef RGB888
+#define RGBA32_APIXEL(r, g, b, a) (((unsigned long)(a) << 24) | ((b) << 16) | ((g) << 8) | (r))
+#define RGBA32_SPIXEL(r, g, b, a) ((RGBA_ALPHA_OPAQUE << 24) | ((b) << 16) | ((g) << 8) | (r))
+#else
+#define RGBA32_APIXEL(r, g, b, a) (((unsigned long)(a) << 24) | ((r) << 16) | ((g) << 8) | (b))
+#define RGBA32_SPIXEL(r, g, b, a) (((unsigned long)RGBA_ALPHA_OPAQUE << 24) | ((r) << 16) | ((g) << 8) | (b))
+#endif
+#define RGBA32_PIXEL(r, g, b, a) ((a) >= 255 ? RGBA32_SPIXEL(r, g, b, a) : RGBA32_APIXEL(r, g, b, a))
+#define RGBA32_ALPHA(rgba) ((unsigned long)rgba >> 24)
+
+
+   /* RGBA16 colour macros */
+#define RGBA16_APIXEL(r, g, b, a) (((r) >> 4 << 12) | ((g) >> 4 << 8) | ((b) >> 4 << 4) | ((a) >> 4 << 0))
+#define RGBA16_SPIXEL(r, g, b) (((r) >> 4 << 12) | ((g) >> 4 << 8) | ((b) >> 4 << 4) | 0x000F)
+#define RGBA16_PIXEL(r, g, b, a) RGBA16_APIXEL(r, g, b, a)
+
+   /* RGBA565 colour macros */
+#define RGBA565_TRANSPARENTBITS  0x18DF
+#define RGBA565_TRANSPARENTKEY   0xE700
+#define RGBA565_ALPHABITS        0x001C
+
+#define RGBA565_TRANSPARENT_COLOUR RGBA565_TRANSPARENTKEY
+
+#define RGBA565_APIXEL(r, g, b, a) (((r) >> 6 << 11) | ((g) >> 6 << 6) | (((a)+16) >> 5 << 2) | ((b) >> 6) | RGBA565_TRANSPARENTKEY)
+#define RGBA565_SPIXEL(r, g, b) (((r) >> 3 << 11) | ((g) >> 2 << 5) | ((b) >> 3) | (((r) & (g) & 0xE0) == 0xE0 ? 0x20 : 0x00))
+#define RGBA565_PIXEL(r, g, b, a) ((a) >= 0xF0 ? RGBA565_SPIXEL(r, g, b) : RGBA565_APIXEL(r, g, b, a))
+
+#define RGBA565_FROM_RGB565(rgb) ((((rgb) & ~RGBA565_TRANSPARENTBITS) == RGBA565_TRANSPARENTKEY) ? (rgb) ^ 0x0020 : (rgb))
+#define RGBA565_TO_RGB565(rgba) ((((rgba) & ~RGBA565_TRANSPARENTBITS) == RGBA565_TRANSPARENTKEY) ? ((rgba) & (RGBA565_TRANSPARENTBITS ^ RGBA565_ALPHABITS)) * 10 : (rgba))
+#define RGBA565_ALPHA(rgba) ((((rgba) & ~RGBA565_TRANSPARENTBITS) == RGBA565_TRANSPARENTKEY) ? ((rgba) & RGBA565_ALPHABITS) << 3 : 0x100)
+
+#endif //#if !defined __SYMBIAN32__
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/helpers/vc_image/vc_image_helper.h b/helpers/vc_image/vc_image_helper.h
new file mode 100755 (executable)
index 0000000..f11d945
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VC_IMAGE_HELPER_H
+#define VC_IMAGE_HELPER_H
+
+#include "interface/vctypes/vc_image_structs.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \brief Image buffer object, with image data locked in memory and ready for access.
+ *
+ * This data type is fully compatible with \c VC_IMAGE_T for backwards
+ * compatibility.  New code should use this type where the object refers to
+ * a locked image.
+ */
+typedef VC_IMAGE_T VC_IMAGE_BUF_T;
+
+/* Macros to determine which format a vc_image is */
+
+typedef struct
+{
+   unsigned bits_per_pixel : 8,
+   is_rgb            : 1,
+   is_yuv            : 1,
+   is_raster_order   : 1,
+   is_tformat_order  : 1,
+   has_alpha         : 1;
+} VC_IMAGE_TYPE_INFO_T;
+
+#define VC_IMAGE_COMPONENT_ORDER(red_lsb, green_lsb, blue_lsb, alpha_lsb) \
+            ( (((red_lsb)   & 0x1f) <<  0) \
+            | (((green_lsb) & 0x1f) <<  6) \
+            | (((blue_lsb)  & 0x1f) << 12) \
+            | (((alpha_lsb) & 0x1f) << 18) )
+#define VC_IMAGE_RED_OFFSET(component_order)    (((component_order) >>  0) & 0x1f)
+#define VC_IMAGE_GREEN_OFFSET(component_order)  (((component_order) >>  6) & 0x1f)
+#define VC_IMAGE_BLUE_OFFSET(component_order)   (((component_order) >> 12) & 0x1f)
+#define VC_IMAGE_ALPHA_OFFSET(component_order)  (((component_order) >> 18) & 0x1f)
+
+extern const VC_IMAGE_TYPE_INFO_T vc_image_type_info[VC_IMAGE_MAX + 1];
+extern const unsigned int vc_image_rgb_component_order[VC_IMAGE_MAX + 1];
+
+#define VC_IMAGE_IS_YUV(type) (vc_image_type_info[type].is_yuv)
+#define VC_IMAGE_IS_RGB(type) (vc_image_type_info[type].is_rgb)
+#define VC_IMAGE_IS_RASTER(type) (vc_image_type_info[type].is_raster_order)
+#define VC_IMAGE_IS_TFORMAT(type) (vc_image_type_info[type].is_tformat_order)
+#define VC_IMAGE_BITS_PER_PIXEL(type) (vc_image_type_info[type].bits_per_pixel)
+#define VC_IMAGE_HAS_ALPHA(type) (vc_image_type_info[type].has_alpha)
+
+#define case_VC_IMAGE_ANY_YUV \
+   case VC_IMAGE_YUV420:      \
+   case VC_IMAGE_YUV420SP:    \
+   case VC_IMAGE_YUV422:      \
+   case VC_IMAGE_YUV_UV:      \
+   case VC_IMAGE_YUV_UV32:    \
+   case VC_IMAGE_YUV422PLANAR: \
+   case VC_IMAGE_YUV444PLANAR: \
+   case VC_IMAGE_YUV420_16:   \
+   case VC_IMAGE_YUV_UV_16
+
+#define case_VC_IMAGE_ANY_RGB \
+   case VC_IMAGE_RGB565:      \
+   case VC_IMAGE_RGB2X9:      \
+   case VC_IMAGE_RGB666:      \
+   case VC_IMAGE_RGBA32:      \
+   case VC_IMAGE_RGBX32:      \
+   case VC_IMAGE_RGBA16:      \
+   case VC_IMAGE_RGBA565:     \
+   case VC_IMAGE_RGB888:      \
+   case VC_IMAGE_TF_RGBA32:   \
+   case VC_IMAGE_TF_RGBX32:   \
+   case VC_IMAGE_TF_RGBA16:   \
+   case VC_IMAGE_TF_RGBA5551: \
+   case VC_IMAGE_TF_RGB565:   \
+   case VC_IMAGE_BGR888:      \
+   case VC_IMAGE_BGR888_NP:   \
+   case VC_IMAGE_ARGB8888:    \
+   case VC_IMAGE_XRGB8888
+
+#define case_VC_IMAGE_ANY_RGB_NOT_TF \
+   case VC_IMAGE_RGB565:      \
+   case VC_IMAGE_RGB2X9:      \
+   case VC_IMAGE_RGB666:      \
+   case VC_IMAGE_RGBA32:      \
+   case VC_IMAGE_RGBX32:      \
+   case VC_IMAGE_RGBA16:      \
+   case VC_IMAGE_RGBA565:     \
+   case VC_IMAGE_RGB888:      \
+   case VC_IMAGE_BGR888:      \
+   case VC_IMAGE_BGR888_NP:   \
+   case VC_IMAGE_ARGB8888:    \
+   case VC_IMAGE_XRGB8888:    \
+   case VC_IMAGE_RGBX8888:    \
+   case VC_IMAGE_BGRX8888
+
+#define case_VC_IMAGE_ANY_TFORMAT \
+   case VC_IMAGE_TF_RGBA32:   \
+   case VC_IMAGE_TF_RGBX32:   \
+   case VC_IMAGE_TF_FLOAT:    \
+   case VC_IMAGE_TF_RGBA16:   \
+   case VC_IMAGE_TF_RGBA5551: \
+   case VC_IMAGE_TF_RGB565:   \
+   case VC_IMAGE_TF_YA88:     \
+   case VC_IMAGE_TF_BYTE:     \
+   case VC_IMAGE_TF_PAL8:     \
+   case VC_IMAGE_TF_PAL4:     \
+   case VC_IMAGE_TF_ETC1:     \
+   case VC_IMAGE_TF_Y8:       \
+   case VC_IMAGE_TF_A8:       \
+   case VC_IMAGE_TF_SHORT:    \
+   case VC_IMAGE_TF_1BPP
+
+/******************************************************************************
+General functions.
+******************************************************************************/
+
+int vc_image_bits_per_pixel(VC_IMAGE_TYPE_T type);
+
+int calculate_pitch(VC_IMAGE_TYPE_T type, int width, int height, uint8_t num_channels, VC_IMAGE_INFO_T *info, VC_IMAGE_EXTRA_T *extra);
+
+/* Check if an image will use an alternate memory layout, in order to cope with
+ * codec limitation. Applies to YUV_UV images taller than 1344 lines. */
+int vc_image_is_tall_yuv_uv(VC_IMAGE_TYPE_T type, int height);
+
+/******************************************************************************
+Data member access.
+******************************************************************************/
+
+/* Set the type of the VC_IMAGE_T. */
+void vc_image_set_type(VC_IMAGE_T *image, VC_IMAGE_TYPE_T type);
+
+/* Set the image_data field, noting how big it is. */
+void vc_image_set_image_data(VC_IMAGE_BUF_T *image, int size, void *image_data);
+
+/* Set the image data with added u and v pointers */
+void vc_image_set_image_data_yuv(VC_IMAGE_BUF_T *image, int size, void *image_y, void *image_u, void *image_v);
+
+/* Set the dimensions of the image. */
+void vc_image_set_dimensions(VC_IMAGE_T *image, int width, int height);
+
+/* Check the integrity of a VC_IMAGE_T structure - checks structure values + data ptr */
+int vc_image_verify(const VC_IMAGE_T *image);
+
+/* Set the pitch (internal_width) of the image. */
+void vc_image_set_pitch(VC_IMAGE_T *image, int pitch);
+
+/* Specify the vertical pitch for YUV planar images */
+void vc_image_set_vpitch(VC_IMAGE_T *image, int vpitch);
+
+/* Specify that the YUV image is V/U interleaved. */
+void vc_image_set_is_vu(VC_IMAGE_T *image);
+
+/* Return 1 if the YUV image is V/U interleaved, else return 0. */
+int vc_image_get_is_vu(const VC_IMAGE_T *image);
+int vc_image_info_get_is_vu(const VC_IMAGE_INFO_T *info);
+
+/* Reset the shape of an image */
+int vc_image_reshape(VC_IMAGE_T *image, VC_IMAGE_TYPE_T type, int width, int height);
+
+/* Return the space required (in bytes) for an image of this type and dimensions. */
+int vc_image_required_size(VC_IMAGE_T *image);
+
+/* Return the space required (in bytes) for an image of this type's palette. */
+int vc_image_palette_size (VC_IMAGE_T *image);
+
+/* Return 1 if image is high-definition, else return 0. */
+int vc_image_is_high_definition(const VC_IMAGE_T *image);
+
+/* Return true if palette is 32bpp */
+int vc_image_palette_is_32bit(VC_IMAGE_T *image);
+
+/* Retrieve Y, U and V pointers from a YUV image. Note that these are macros. */
+
+#define vc_image_get_y(p) ((unsigned char *)((p)->image_data))
+
+// replaced with functions to allow assert - revert to #define when fixed
+//#define vc_image_get_u(p) ((unsigned char *)((p)->extra.uv.u))
+//#define vc_image_get_v(p) ((unsigned char *)((p)->extra.uv.v))
+unsigned char *vc_image_get_u(const VC_IMAGE_BUF_T *image);
+unsigned char *vc_image_get_v(const VC_IMAGE_BUF_T *image);
+
+/* Calculate the address of the given pixel coordinate -- the result may point
+ * to a word containing data for several pixels (ie., for sub-8bpp and
+ * compressed formats).
+ */
+void *vc_image_pixel_addr(VC_IMAGE_BUF_T *image, int x, int y);
+void *vc_image_pixel_addr_mm(VC_IMAGE_BUF_T *image, int x, int y, int miplevel);
+void *vc_image_pixel_addr_u(VC_IMAGE_BUF_T *image, int x, int y);
+void *vc_image_pixel_addr_v(VC_IMAGE_BUF_T *image, int x, int y);
+
+/* As above, but with (0,0) in the bottom-left corner */
+void *vc_image_pixel_addr_gl(VC_IMAGE_BUF_T *image, int x, int y, int miplevel);
+
+#define vc_image_get_y_422(p) vc_image_get_y(p)
+#define vc_image_get_u_422(p) vc_image_get_u(p)
+#define vc_image_get_v_422(p) vc_image_get_v(p)
+
+#define vc_image_get_y_422planar(p) vc_image_get_y(p)
+#define vc_image_get_u_422planar(p) vc_image_get_u(p)
+#define vc_image_get_v_422planar(p) vc_image_get_v(p)
+
+/* Mipmap-related functions. Image must be t-format. */
+
+/* Return the pitch of the selected mipmap */
+unsigned int vc_image_get_mipmap_pitch(VC_IMAGE_T *image, int miplvl);
+
+/* Return the padded height of the selected mipmap (mipmaps must be padded to a
+ * power of 2) */
+unsigned int vc_image_get_mipmap_padded_height(VC_IMAGE_T *image, int miplvl);
+
+/* Return the offset, in bytes, of the selected mipmap. */
+int vc_image_get_mipmap_offset(VC_IMAGE_T *image, int miplvl);
+
+/* Return whether the selected mipmap is stored in t-format or linear microtile
+ * format. */
+#define VC_IMAGE_MIPMAP_TFORMAT 0
+#define VC_IMAGE_MIPMAP_LINEAR_TILE 1
+int vc_image_get_mipmap_type(VC_IMAGE_T const *image, int miplvl);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/helpers/vc_image/vc_image_metadata.h b/helpers/vc_image/vc_image_metadata.h
new file mode 100755 (executable)
index 0000000..9521e49
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VC_IMAGE_METADATA_H
+#define VC_IMAGE_METADATA_H
+
+#include "vcfw/rtos/rtos.h"
+#include "helpers/vc_image/metadata_fourcc.h"
+
+#define VC_METADATA_ALIGN 3
+
+/******************************************************************************
+Types of metadata.
+******************************************************************************/
+typedef unsigned int VC_METADATA_TYPE_T;
+
+/******************************************************************************
+Metadata and item headers.
+******************************************************************************/
+typedef struct vc_metadata_item_s {
+   VC_METADATA_TYPE_T type;   
+   int len;
+} VC_METADATA_ITEM_T;
+
+
+typedef struct vc_metadata_header_s {
+   int size;
+#ifdef VCMODS_LCC
+   unsigned char readonly;
+#else
+   unsigned char readonly:1;
+#endif
+   int offset_next;
+   RTOS_LATCH_T latch;
+} VC_METADATA_HEADER_T;
+
+
+/******************************************************************************
+Public declarations.
+******************************************************************************/
+// Initialises a metadata header structure
+int vc_metadata_initialise(VC_METADATA_HEADER_T *header, int size);
+// Add a metadata entry to the buffer
+int vc_metadata_add(VC_METADATA_HEADER_T *header, void *data, VC_METADATA_TYPE_T type, int len);
+// Get a (pointer to a) particular metadata item from the buffer (optionally copy the data to dest), and return the length of the item
+void *vc_metadata_get_with_length(void *dest, VC_METADATA_HEADER_T *header, VC_METADATA_TYPE_T type, int *retcode, int *len);
+// Get a (pointer to a) particular metadata item from the buffer (optionally copy the data to dest)
+void *vc_metadata_get(void *dest, VC_METADATA_HEADER_T *header, VC_METADATA_TYPE_T type, int *retcode);
+// Clear the metadata buffer and reset the header (clears readonly flag)
+int vc_metadata_clear(VC_METADATA_HEADER_T *header);
+// Set or clear the read-only flag in the metadata buffer
+int vc_metadata_set_readonly(VC_METADATA_HEADER_T *header, int value);
+// Copies the contents of one metadata buffer to the other (appends the destination buffer)
+int vc_metadata_copy(VC_METADATA_HEADER_T *dest, VC_METADATA_HEADER_T *src);
+// Overwrites an item in the metadata buffer (caller must make sure the sizes match!)
+int vc_metadata_overwrite(VC_METADATA_HEADER_T *header, void *data, VC_METADATA_TYPE_T type);
+// Flush the metadata buffer out of the cache
+int vc_metadata_cache_flush(VC_METADATA_HEADER_T *header);
+// Locks the vc_metadata library semaphore
+int vc_metadata_lock(VC_METADATA_HEADER_T *header);
+// Unlocks the vc_metadata library semaphore
+int vc_metadata_unlock(VC_METADATA_HEADER_T *header);
+
+/******************************************************************************
+Wrappers for the above functions using VC_IMAGEs.
+******************************************************************************/
+#define vc_image_metadata_initialise(i, s)         vc_metadata_initialise((i)->metadata, s)
+#define vc_image_metadata_add(i, d, t, l)          vc_metadata_add((i)->metadata, d, t, l)
+#define vc_image_metadata_get(d, i, t, r)          vc_metadata_get(d, (i)->metadata, t, r)
+#define vc_image_metadata_clear(i)                 vc_metadata_clear((i)->metadata)
+#define vc_image_metadata_set_readonly(i, v)       vc_metadata_set_readonly((i)->metadata, v)
+#define vc_image_metadata_copy(d, s)               vc_metadata_copy((d)->metadata, (s)->metadata)
+#define vc_image_metadata_overwrite(i, d, t)       vc_metadata_overwrite((i)->metadata, d, t)
+#define vc_image_metadata_cache_flush(i)           vc_metadata_cache_flush((i)->metadata)
+#endif
diff --git a/host_applications/android/apps/vidtex/CMakeLists.txt b/host_applications/android/apps/vidtex/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..1f705ef
--- /dev/null
@@ -0,0 +1,12 @@
+cmake_minimum_required(VERSION 2.8)
+
+SET(COMPILE_DEFINITIONS -Werror -Wall)
+include_directories(${PROJECT_SOURCE_DIR}/host_applications/linux/libs/bcm_host/include)
+
+set (VIDTEX_SOURCES
+   main.cpp
+   launcher_rpi.c
+   svp.c
+   vidtex.c)
+add_executable(vidtex ${VIDTEX_SOURCES})
+target_link_libraries(vidtex GLESv2 EGL m bcm_host mmal_core mmal_components mmal_util mmal_vc_client vcos)
diff --git a/host_applications/android/apps/vidtex/applog.h b/host_applications/android/apps/vidtex/applog.h
new file mode 100755 (executable)
index 0000000..94cce06
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef APPLOG_H
+#define APPLOG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file Application support for VCOS logging.
+ * This header file is used to abstract the logging for files that are designed to be included
+ * in different applications. It should be included before any other VMCS header files.
+ */
+
+#define VCOS_LOG_CATEGORY (&app_log_category)
+#include "interface/vcos/vcos.h"
+extern VCOS_LOG_CAT_T app_log_category;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* APPLOG_H */
diff --git a/host_applications/android/apps/vidtex/launcher.h b/host_applications/android/apps/vidtex/launcher.h
new file mode 100755 (executable)
index 0000000..7169fa6
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef LAUNCHER_H
+#define LAUNCHER_H
+
+#include <utils/threads.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+#include <SurfaceComposerClient.h>
+#include <EGL/egl.h>
+
+/**
+ * Android-specific launcher for native graphical application.
+ * See runApp().
+ */
+class Launcher : public android::Thread
+{
+public:
+   /** Entry point function for application-specific code.
+    * @param params  Application-specific parameters.
+    * @param win     Native window/surface.
+    * @return 0 on success; -1 on failure.
+    */
+   typedef int (*RUN_APP_FN_T)(const void *params, EGLNativeWindowType win);
+
+   /** Run a function in a separate thread.
+    * A separate thread is launched to run the function, and a native surface created for
+    * that application. 
+    * @param name        Application name.
+    * @param run_app_fn  Entry point function for application.
+    * @param params      Application-specific parameters. This will be bitwise copyable, and
+    *                    between C and C++, so don't use pointers, bool or anything else liable
+    *                    for problems.
+    * @param param_size  Size, in bytes, of the application parameters.
+    * @return 0 on success; -1 on failure.
+    */
+   static int runApp(const char *name, RUN_APP_FN_T run_app_fn, const void *params,
+                     size_t param_size);
+
+   Launcher(const char *name, RUN_APP_FN_T run_fn, const void *params, size_t param_size);
+   virtual ~Launcher();
+
+   android::sp<android::SurfaceComposerClient> session() const;
+
+protected:
+   virtual android::status_t readyToRun();
+   virtual bool threadLoop();
+
+private:
+   virtual void onFirstRef();
+
+   android::sp<android::SurfaceComposerClient> m_session;
+   android::sp<android::SurfaceControl> m_sf_control;
+   android::sp<android::Surface> m_sf_surface;
+
+   android::String8 m_name;
+   RUN_APP_FN_T m_run_fn;
+   android::Vector<unsigned char> m_params;
+   int m_result;
+};
+
+#endif
diff --git a/host_applications/android/apps/vidtex/launcher_rpi.c b/host_applications/android/apps/vidtex/launcher_rpi.c
new file mode 100755 (executable)
index 0000000..f349836
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "launcher_rpi.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include  "bcm_host.h"
+
+static int create_native_window(EGL_DISPMANX_WINDOW_T *native_win)
+{
+   int32_t status = 0;
+   DISPMANX_DISPLAY_HANDLE_T disp;
+   DISPMANX_ELEMENT_HANDLE_T elem;
+   DISPMANX_UPDATE_HANDLE_T update;
+   VC_DISPMANX_ALPHA_T alpha = {DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS, 255, 0};
+   VC_RECT_T src_rect = {0};
+   VC_RECT_T dest_rect = {0};
+   uint32_t display_width, display_height;
+   uint32_t disp_num = 0; // Primary
+   uint32_t layer_num = 0;
+
+   status = graphics_get_display_size(0, &display_width, &display_height);
+   if (status != 0)
+      return status;
+
+   /* Fullscreen */
+   display_width = 1280;
+   display_height = 720;
+   dest_rect.width = display_width;
+   dest_rect.height = display_height;
+   src_rect.width = display_width << 16;
+   src_rect.height = display_height << 16;
+
+   disp = vc_dispmanx_display_open(disp_num);
+   update = vc_dispmanx_update_start(0);
+   elem = vc_dispmanx_element_add(update, disp, layer_num, &dest_rect, 0,
+         &src_rect, DISPMANX_PROTECTION_NONE, &alpha, NULL, DISPMANX_NO_ROTATE);
+
+   native_win->element = elem;
+   native_win->width = display_width;
+   native_win->height = display_height;
+   vc_dispmanx_update_submit_sync(update);
+
+   return 0;
+}
+
+int runApp(const char *name, RUN_APP_FN_T run_app_fn, const void *params, size_t param_size)
+{
+   EGL_DISPMANX_WINDOW_T win;
+   (void) param_size;
+
+
+   vcos_log_trace("Initialsing BCM HOST");
+   bcm_host_init();
+
+   vcos_log_trace("Starting '%s'", name);
+   if (create_native_window(&win) != 0)
+      return -1;
+
+   return run_app_fn(params, (EGLNativeWindowType *) &win);
+}
+
diff --git a/host_applications/android/apps/vidtex/launcher_rpi.h b/host_applications/android/apps/vidtex/launcher_rpi.h
new file mode 100755 (executable)
index 0000000..335fdc4
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef LAUNCHER_RPI_H
+#define LAUNCHER_RPI_H
+
+#include <GLES2/gl2.h>
+#include <EGL/egl.h>
+#include "applog.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Entry point function for application-specific code.
+ * @param params  Application-specific parameters.
+ * @param win     Native window/surface.
+ * @return 0 on success; -1 on failure.
+ */
+typedef int (*RUN_APP_FN_T)(const void *params, EGLNativeWindowType win);
+
+/** Create native window and runs the function.
+ *
+ * No need to run in a separate thread on Linux / RPI.
+ *
+ * @param name        Application name.
+ * @param run_app_fn  Entry point function for application.
+ * @param params      Application-specific parameters.
+ * @param param_size  Size, in bytes, of the application parameters.
+ * @return 0 on success; -1 on failure.
+ */
+int runApp(const char *name, RUN_APP_FN_T run_app_fn, const void *params, size_t param_size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/host_applications/android/apps/vidtex/main.cpp b/host_applications/android/apps/vidtex/main.cpp
new file mode 100755 (executable)
index 0000000..701574d
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "applog.h"
+#include "vidtex.h"
+
+#ifdef __ANDROID__
+#include "launcher.h"
+#else
+#include "launcher_rpi.h"
+#endif
+
+VCOS_LOG_CAT_T app_log_category;
+
+static int launch_vidtex(const void *params, EGLNativeWindowType win)
+{
+   return vidtex_run((const VIDTEX_PARAMS_T *)params, win);
+}
+
+static void usage(const char *argv0)
+{
+   fprintf(stderr, "Usage: %s [-d duration-ms] [-i] [uri]\n", argv0);
+}
+
+int main(int argc, char **argv)
+{
+   // Parse command line options/arguments.
+   VIDTEX_PARAMS_T params = {0};
+   int rc;
+   int status = 0;
+
+   opterr = 0;
+
+   while ((rc = getopt(argc, argv, "d:iuvy")) != -1)
+   {
+      switch (rc)
+      {
+      case 'd':
+         params.duration_ms = atoi(optarg);
+         break;
+
+      case 'i':
+         params.opts |= VIDTEX_OPT_IMG_PER_FRAME;
+         break;
+
+      case 'y':
+         params.opts |= VIDTEX_OPT_Y_TEXTURE;
+         break;
+
+      case 'u':
+         params.opts |= VIDTEX_OPT_U_TEXTURE;
+         break;
+
+      case 'v':
+         params.opts |= VIDTEX_OPT_V_TEXTURE;
+         break;
+
+      default:
+         usage(argv[0]);
+         return 2;
+      }
+   }
+
+   if (optind < argc - 1)
+   {
+      usage(argv[0]);
+      return 2;
+   }
+
+   if (optind < argc)
+   {
+      strncpy(params.uri, argv[optind], sizeof(params.uri) - 1);
+      params.uri[sizeof(params.uri) - 1] = '\0';
+   }
+
+   // Init vcos logging.
+   vcos_log_set_level(VCOS_LOG_CATEGORY, VCOS_LOG_INFO);
+   vcos_log_register("vidtex", VCOS_LOG_CATEGORY);
+
+   // Run video-on-texture application in a separate thread.
+#ifdef __ANDROID__
+   status = Launcher::runApp("vidtex", launch_vidtex, &params, sizeof(params));
+#else
+   status = runApp("vidtex", launch_vidtex, &params, sizeof(params));
+#endif
+   return (status == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/host_applications/android/apps/vidtex/svp.c b/host_applications/android/apps/vidtex/svp.c
new file mode 100755 (executable)
index 0000000..89b576a
--- /dev/null
@@ -0,0 +1,637 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stddef.h>
+#include "applog.h"
+#include "interface/vcos/vcos_stdbool.h"
+#include "interface/vcos/vcos_inttypes.h"
+#include "interface/mmal/mmal.h"
+#include "interface/mmal/mmal_logging.h"
+#include "interface/mmal/util/mmal_connection.h"
+#include "interface/mmal/util/mmal_util.h"
+#include "interface/mmal/util/mmal_default_components.h"
+#include "interface/mmal/util/mmal_util_params.h"
+#include "svp.h"
+
+#define CHECK_STATUS(s, m) \
+         if ((s) != MMAL_SUCCESS) { \
+            LOG_ERROR("%s: %s", (m), mmal_status_to_string((s))); \
+            goto error; \
+         }
+
+/* Flags specifying fields of SVP_T struct */
+#define SVP_CREATED_SEM       (1 << 0)
+#define SVP_CREATED_THREAD    (1 << 1)
+#define SVP_CREATED_MUTEX     (1 << 2)
+#define SVP_CREATED_TIMER     (1 << 3)
+#define SVP_CREATED_WD_TIMER  (1 << 4)
+
+/* Hard-coded camera parameters */
+#if 0
+#define SVP_CAMERA_WIDTH         1920
+#define SVP_CAMERA_HEIGHT        1080
+#else
+#define SVP_CAMERA_WIDTH         1280
+#define SVP_CAMERA_HEIGHT         720
+#endif
+#define SVP_CAMERA_FRAMERATE       30
+#define SVP_CAMERA_DURATION_MS  10000
+
+/* Watchdog timeout - elapsed time to allow for no video frames received */
+#define SVP_WATCHDOG_TIMEOUT_MS  5000
+
+/** Simple video player instance */
+struct SVP_T
+{
+   /* Player options */
+   SVP_OPTS_T opts;
+
+   /* Bitmask of SVP_CREATED_XXX values indicating which fields have been created.
+    * Only used for those fields which can't be (portably) determined from their
+    * own value.
+    */
+   uint32_t created;
+
+   /* Semaphore used for synchronising buffer handling for decoded frames */
+   VCOS_SEMAPHORE_T sema;
+
+   /* User supplied callbacks */
+   SVP_CALLBACKS_T callbacks;
+
+   /* Container reader component */
+   MMAL_COMPONENT_T *reader;
+
+   /* Video decoder component */
+   MMAL_COMPONENT_T *video_decode;
+
+   /* Camera component */
+   MMAL_COMPONENT_T *camera;
+
+   /* Connection: container reader -> video decoder */
+   MMAL_CONNECTION_T *connection;
+
+   /* Output port from video decoder or camera */
+   MMAL_PORT_T *video_output;
+
+   /* Pool of buffers for video decoder output */
+   MMAL_POOL_T *out_pool;
+
+   /* Queue to hold decoded video frames */
+   MMAL_QUEUE_T *queue;
+
+   /* Worker thread */
+   VCOS_THREAD_T thread;
+
+   /* Timer to trigger stop in camera preview case */
+   VCOS_TIMER_T timer;
+
+   /* Watchdog timer */
+   VCOS_TIMER_T wd_timer;
+
+   /* Mutex to synchronise access to all following fields */
+   VCOS_MUTEX_T mutex;
+
+   /* Stop control: 0 to process stream; bitmask of SVP_STOP_XXX values to stop */
+   uint32_t stop;
+
+   /* Player stats */
+   SVP_STATS_T stats;
+};
+
+/* Local function prototypes */
+static MMAL_STATUS_T svp_setup_reader(MMAL_COMPONENT_T *reader, const char *uri,
+                                      MMAL_PORT_T **video_port);
+static void svp_timer_cb(void *ctx);
+static void svp_watchdog_cb(void *ctx);
+static MMAL_STATUS_T svp_port_enable(SVP_T *svp, MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb);
+static void *svp_worker(void *arg);
+static void svp_bh_control_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
+static void svp_bh_output_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
+static void svp_reset_stop(SVP_T *svp);
+static void svp_set_stop(SVP_T *svp, uint32_t stop_flags);
+static uint32_t svp_get_stop(SVP_T *svp);
+
+/* Create Simple Video Player instance. */
+SVP_T *svp_create(const char *uri, SVP_CALLBACKS_T *callbacks, const SVP_OPTS_T *opts)
+{
+   SVP_T *svp;
+   MMAL_STATUS_T st;
+   VCOS_STATUS_T vst;
+   MMAL_PORT_T *reader_output = NULL;
+   MMAL_COMPONENT_T *video_decode = NULL;
+   MMAL_PORT_T *video_output = NULL;
+
+   LOG_TRACE("Creating player for %s", (uri ? uri : "camera preview"));
+
+   vcos_assert(callbacks->video_frame_cb);
+   vcos_assert(callbacks->stop_cb);
+
+   svp = vcos_calloc(1, sizeof(*svp), "svp");
+   CHECK_STATUS((svp ? MMAL_SUCCESS : MMAL_ENOMEM), "Failed to allocate context");
+
+   svp->opts = *opts;
+   svp->callbacks = *callbacks;
+
+   /* Semaphore used for synchronising buffer handling for decoded frames */
+   vst = vcos_semaphore_create(&svp->sema, "svp-sem", 0);
+   CHECK_STATUS((vst == VCOS_SUCCESS ? MMAL_SUCCESS : MMAL_ENOMEM), "Failed to create semaphore");
+   svp->created |= SVP_CREATED_SEM;
+
+   vst = vcos_mutex_create(&svp->mutex, "svp-mutex");
+   CHECK_STATUS((vst == VCOS_SUCCESS ? MMAL_SUCCESS : MMAL_ENOMEM), "Failed to create mutex");
+   svp->created |= SVP_CREATED_MUTEX;
+
+   vst = vcos_timer_create(&svp->timer, "svp-timer", svp_timer_cb, svp);
+   CHECK_STATUS((vst == VCOS_SUCCESS ? MMAL_SUCCESS : MMAL_ENOMEM), "Failed to create timer");
+   svp->created |= SVP_CREATED_TIMER;
+
+   vst = vcos_timer_create(&svp->wd_timer, "svp-wd-timer", svp_watchdog_cb, svp);
+   CHECK_STATUS((vst == VCOS_SUCCESS ? MMAL_SUCCESS : MMAL_ENOMEM), "Failed to create timer");
+   svp->created |= SVP_CREATED_WD_TIMER;
+
+   /* Create components */
+   svp->reader = NULL;
+   svp->video_decode = NULL;
+   svp->camera = NULL;
+   svp->connection = NULL;
+
+   if (uri)
+   {
+      /* Video from URI: setup container_reader -> video_decode */
+
+      /* Create and set up container reader */
+      st = mmal_component_create(MMAL_COMPONENT_DEFAULT_CONTAINER_READER, &svp->reader);
+      CHECK_STATUS(st, "Failed to create container reader");
+
+      st = svp_setup_reader(svp->reader, uri, &reader_output);
+      if (st != MMAL_SUCCESS)
+         goto error;
+
+      st = mmal_component_enable(svp->reader);
+      CHECK_STATUS(st, "Failed to enable container reader");
+
+      st = svp_port_enable(svp, svp->reader->control, svp_bh_control_cb);
+      CHECK_STATUS(st, "Failed to enable container reader control port");
+
+      /* Create and set up video decoder */
+      st = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, &svp->video_decode);
+      CHECK_STATUS(st, "Failed to create video decoder");
+
+      video_decode = svp->video_decode;
+      video_output = video_decode->output[0];
+
+      st = mmal_component_enable(video_decode);
+      CHECK_STATUS(st, "Failed to enable video decoder");
+
+      st = svp_port_enable(svp, video_decode->control, svp_bh_control_cb);
+      CHECK_STATUS(st, "Failed to enable video decoder control port");
+   }
+   else
+   {
+      /* Camera preview */
+      st = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &svp->camera);
+      CHECK_STATUS(st, "Failed to create camera");
+
+      st = mmal_component_enable(svp->camera);
+      CHECK_STATUS(st, "Failed to enable camera");
+
+      st = svp_port_enable(svp, svp->camera->control, svp_bh_control_cb);
+      CHECK_STATUS(st, "Failed to enable camera control port");
+
+      video_output = svp->camera->output[0]; /* Preview port */
+   }
+
+   st = mmal_port_parameter_set_boolean(video_output, MMAL_PARAMETER_ZERO_COPY, MMAL_TRUE);
+   CHECK_STATUS((st == MMAL_ENOSYS ? MMAL_SUCCESS : st), "Failed to enable zero copy");
+
+   if (uri)
+   {
+      /* Create connection: container_reader -> video_decoder */
+      st = mmal_connection_create(&svp->connection, reader_output, video_decode->input[0],
+                                  MMAL_CONNECTION_FLAG_TUNNELLING);
+      CHECK_STATUS(st, "Failed to create connection");
+   }
+
+   /* Set video output port format.
+    * Opaque encoding ensures we get buffer data as handles to relocatable heap. */
+   video_output->format->encoding = MMAL_ENCODING_OPAQUE;
+
+   if (!uri)
+   {
+      /* Set video format for camera preview */
+      MMAL_VIDEO_FORMAT_T *vfmt = &video_output->format->es->video;
+
+      CHECK_STATUS((video_output->format->type == MMAL_ES_TYPE_VIDEO) ? MMAL_SUCCESS : MMAL_EINVAL,
+                   "Output port isn't video format");
+
+      vfmt->width = SVP_CAMERA_WIDTH;
+      vfmt->height = SVP_CAMERA_HEIGHT;
+      vfmt->crop.x = 0;
+      vfmt->crop.y = 0;
+      vfmt->crop.width = vfmt->width;
+      vfmt->crop.height = vfmt->height;
+      vfmt->frame_rate.num = SVP_CAMERA_FRAMERATE;
+      vfmt->frame_rate.den = 1;
+   }
+
+   st = mmal_port_format_commit(video_output);
+   CHECK_STATUS(st, "Failed to set output port format");
+
+   /* Finally, set buffer num/size. N.B. For container_reader/video_decode, must be after
+    * connection created, in order for port format to propagate.
+    * Don't enable video output port until want to produce frames. */
+   video_output->buffer_num = video_output->buffer_num_recommended;
+   video_output->buffer_size = video_output->buffer_size_recommended;
+
+   /* Pool + queue to hold decoded video frames */
+   svp->out_pool = mmal_port_pool_create(video_output, video_output->buffer_num,
+                                         video_output->buffer_size);
+   CHECK_STATUS((svp->out_pool ? MMAL_SUCCESS : MMAL_ENOMEM), "Error allocating pool");
+   svp->queue = mmal_queue_create();
+   CHECK_STATUS((svp ? MMAL_SUCCESS : MMAL_ENOMEM), "Error allocating queue");
+
+   svp->video_output = video_output;
+
+   return svp;
+
+error:
+   svp_destroy(svp);
+   return NULL;
+}
+
+/**
+ * Setup container reader component.
+ * Sets URI, to initialize processing, and finds a video track.
+ * @param reader      Container reader component.
+ * @param uri         Media URI.
+ * @param video_port  On success, the output port for the first video track is returned here.
+ * @return MMAL_SUCCESS if the container reader was successfully set up and a video track located.
+ */
+static MMAL_STATUS_T svp_setup_reader(MMAL_COMPONENT_T *reader, const char *uri,
+                                      MMAL_PORT_T **video_port)
+{
+   MMAL_STATUS_T st;
+   uint32_t track;
+
+   st = mmal_util_port_set_uri(reader->control, uri);
+   if (st != MMAL_SUCCESS)
+   {
+      LOG_ERROR("%s: couldn't open uri %s", reader->name, uri);
+      return st;
+   }
+
+   /* Find a video track */
+   for (track = 0; track < reader->output_num; track++)
+   {
+      if (reader->output[track]->format->type == MMAL_ES_TYPE_VIDEO)
+      {
+         break;
+      }
+   }
+
+   if (track == reader->output_num)
+   {
+      LOG_ERROR("%s: no video track", uri);
+      return MMAL_EINVAL;
+   }
+
+   *video_port = reader->output[track];
+   return MMAL_SUCCESS;
+}
+
+/* Destroy SVP instance. svp may be NULL. */
+void svp_destroy(SVP_T *svp)
+{
+   if (svp)
+   {
+      MMAL_COMPONENT_T *components[] = { svp->reader, svp->video_decode, svp->camera };
+      MMAL_COMPONENT_T **comp;
+
+      /* Stop thread, disable connection and components */
+      svp_stop(svp);
+
+      for (comp = components; comp < components + vcos_countof(components); comp++)
+      {
+         mmal_component_disable(*comp);
+      }
+
+      /* Destroy connection + components */
+      if (svp->connection)
+      {
+         mmal_connection_destroy(svp->connection);
+      }
+
+      for (comp = components; comp < components + vcos_countof(components); comp++)
+      {
+         mmal_component_destroy(*comp);
+      }
+
+      /* Free remaining resources */
+      if (svp->out_pool)
+      {
+         mmal_pool_destroy(svp->out_pool);
+      }
+
+      if (svp->queue)
+      {
+         mmal_queue_destroy(svp->queue);
+      }
+
+      if (svp->created & SVP_CREATED_WD_TIMER)
+      {
+         vcos_timer_delete(&svp->wd_timer);
+      }
+
+      if (svp->created & SVP_CREATED_TIMER)
+      {
+         vcos_timer_delete(&svp->timer);
+      }
+
+      if (svp->created & SVP_CREATED_MUTEX)
+      {
+         vcos_mutex_delete(&svp->mutex);
+      }
+
+      if (svp->created & SVP_CREATED_SEM)
+      {
+         vcos_semaphore_delete(&svp->sema);
+      }
+
+      vcos_free(svp);
+   }
+}
+
+/* Start SVP. Enables MMAL connection + creates worker thread. */
+int svp_start(SVP_T *svp)
+{
+   MMAL_STATUS_T st;
+   VCOS_STATUS_T vst;
+
+   /* Ensure SVP is stopped first */
+   svp_stop(svp);
+
+   /* Reset the worker thread stop status, before enabling ports that might trigger a stop */
+   svp_reset_stop(svp);
+
+   if (svp->connection)
+   {
+      /* Enable reader->decoder connection */
+      st = mmal_connection_enable(svp->connection);
+      CHECK_STATUS(st, "Failed to create connection");
+   }
+
+   /* Enable video output port */
+   st = svp_port_enable(svp, svp->video_output, svp_bh_output_cb);
+   CHECK_STATUS(st, "Failed to enable output port");
+
+   /* Reset stats */
+   svp->stats.video_frame_count = 0;
+
+   /* Create worker thread */
+   vst = vcos_thread_create(&svp->thread, "svp-worker", NULL, svp_worker, svp);
+   CHECK_STATUS((vst == VCOS_SUCCESS ? MMAL_SUCCESS : MMAL_ENOMEM), "Failed to create connection");
+
+   svp->created |= SVP_CREATED_THREAD;
+
+   /* Set timer */
+   if (svp->camera)
+   {
+      unsigned ms = svp->opts.duration_ms;
+      vcos_timer_set(&svp->timer, ((ms == 0) ? SVP_CAMERA_DURATION_MS : ms));
+   }
+
+   /* Start watchdog timer */
+   vcos_timer_set(&svp->wd_timer, SVP_WATCHDOG_TIMEOUT_MS);
+
+   return 0;
+
+error:
+   return -1;
+}
+
+/* Stop SVP. Stops worker thread + disables MMAL connection. */
+void svp_stop(SVP_T *svp)
+{
+   vcos_timer_cancel(&svp->wd_timer);
+   vcos_timer_cancel(&svp->timer);
+
+   /* Stop worker thread */
+   if (svp->created & SVP_CREATED_THREAD)
+   {
+      svp_set_stop(svp, SVP_STOP_USER);
+      vcos_semaphore_post(&svp->sema);
+      vcos_thread_join(&svp->thread, NULL);
+      svp->created &= ~SVP_CREATED_THREAD;
+   }
+
+   if (svp->connection)
+   {
+      mmal_connection_disable(svp->connection);
+   }
+
+   mmal_port_disable(svp->video_output);
+}
+
+/* Get stats since last call to svp_start() */
+void svp_get_stats(SVP_T *svp, SVP_STATS_T *stats)
+{
+   vcos_mutex_lock(&svp->mutex);
+   *stats = svp->stats;
+   vcos_mutex_unlock(&svp->mutex);
+}
+
+/** Timer callback - stops playback */
+static void svp_timer_cb(void *ctx)
+{
+   SVP_T *svp = ctx;
+   svp_set_stop(svp, SVP_STOP_TIMEUP);
+   vcos_semaphore_post(&svp->sema);
+}
+
+/** Watchdog timer callback - stops playback */
+static void svp_watchdog_cb(void *ctx)
+{
+   SVP_T *svp = ctx;
+   LOG_ERROR("%s: no frames received for %d ms, aborting", svp->video_output->name,
+             SVP_WATCHDOG_TIMEOUT_MS);
+   svp_set_stop(svp, SVP_STOP_ERROR);
+   vcos_semaphore_post(&svp->sema);
+}
+
+/** Enable MMAL port, setting SVP instance as port userdata. */
+static MMAL_STATUS_T svp_port_enable(SVP_T *svp, MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
+{
+   port->userdata = (struct MMAL_PORT_USERDATA_T *)svp;
+   return mmal_port_enable(port, cb);
+}
+
+/** Process decoded buffers queued by video decoder output callback */
+static void svp_process_returned_bufs(SVP_T *svp)
+{
+   SVP_CALLBACKS_T *callbacks = &svp->callbacks;
+   MMAL_BUFFER_HEADER_T *buf;
+
+   while ((buf = mmal_queue_get(svp->queue)) != NULL)
+   {
+      if ((svp_get_stop(svp) & SVP_STOP_ERROR) == 0)
+      {
+         callbacks->video_frame_cb(callbacks->ctx, buf->data);
+      }
+
+      svp->stats.video_frame_count++;
+      mmal_buffer_header_release(buf);
+   }
+}
+
+/** Worker thread. Ensures video decoder output is supplied with buffers and sends decoded frames
+ * via user-supplied callback.
+ * @param arg  Pointer to SVP instance.
+ * @return NULL always.
+ */
+static void *svp_worker(void *arg)
+{
+   SVP_T *svp = arg;
+   MMAL_PORT_T *video_output = svp->video_output;
+   SVP_CALLBACKS_T *callbacks = &svp->callbacks;
+   MMAL_BUFFER_HEADER_T *buf;
+   MMAL_STATUS_T st;
+   uint32_t stop;
+
+   while (svp_get_stop(svp) == 0)
+   {
+      /* Send empty buffers to video decoder output port */
+      while ((buf = mmal_queue_get(svp->out_pool->queue)) != NULL)
+      {
+         st = mmal_port_send_buffer(video_output, buf);
+         if (st != MMAL_SUCCESS)
+         {
+            LOG_ERROR("Failed to send buffer to %s", video_output->name);
+         }
+      }
+
+      /* Process returned buffers */
+      svp_process_returned_bufs(svp);
+
+      /* Block for buffer release */
+      vcos_semaphore_wait(&svp->sema);
+   }
+
+   /* Might have the last few buffers queued */
+   svp_process_returned_bufs(svp);
+
+   /* Notify caller if we stopped unexpectedly */
+   stop = svp_get_stop(svp);
+   LOG_TRACE("Worker thread exiting: stop=0x%x", (unsigned)stop);
+   callbacks->stop_cb(callbacks->ctx, stop);
+
+   return NULL;
+}
+
+/** Callback from a control port. */
+static void svp_bh_control_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf)
+{
+   SVP_T *svp = (SVP_T *)port->userdata;
+
+   switch (buf->cmd)
+   {
+   case MMAL_EVENT_EOS:
+      LOG_TRACE("%s: EOS", port->name);
+      svp_set_stop(svp, SVP_STOP_EOS);
+      break;
+
+   case MMAL_EVENT_ERROR:
+      LOG_ERROR("%s: MMAL error: %s", port->name,
+                mmal_status_to_string(*(MMAL_STATUS_T *)buf->data));
+      svp_set_stop(svp, SVP_STOP_ERROR);
+      break;
+
+   default:
+      LOG_TRACE("%s: buf %p, event %4.4s", port->name, buf, (char *)&buf->cmd);
+      break;
+   }
+
+   mmal_buffer_header_release(buf);
+
+   vcos_semaphore_post(&svp->sema);
+}
+
+/** Callback from video decode output port. */
+static void svp_bh_output_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf)
+{
+   SVP_T *svp = (SVP_T *)port->userdata;
+
+   if (buf->length == 0)
+   {
+      LOG_TRACE("%s: zero-length buffer => EOS", port->name);
+      svp_set_stop(svp, SVP_STOP_EOS); // This shouldn't be necessary, but it is ...
+      mmal_buffer_header_release(buf);
+   }
+   else if (buf->data == NULL)
+   {
+      LOG_ERROR("%s: zero buffer handle", port->name);
+      mmal_buffer_header_release(buf);
+   }
+   else
+   {
+      /* Reset watchdog timer */
+      vcos_timer_set(&svp->wd_timer, SVP_WATCHDOG_TIMEOUT_MS);
+
+      /* Enqueue the decoded frame so we can return quickly to MMAL core */
+      mmal_queue_put(svp->queue, buf);
+   }
+
+   /* Notify worker */
+   vcos_semaphore_post(&svp->sema);
+}
+
+/** Reset svp->stop to 0, with locking. */
+static void svp_reset_stop(SVP_T *svp)
+{
+   vcos_mutex_lock(&svp->mutex);
+   svp->stop = 0;
+   vcos_mutex_unlock(&svp->mutex);
+}
+
+/** Set additional flags in svp->stop, with locking. */
+static void svp_set_stop(SVP_T *svp, uint32_t stop_flags)
+{
+   vcos_mutex_lock(&svp->mutex);
+   svp->stop |= stop_flags;
+   vcos_mutex_unlock(&svp->mutex);
+}
+
+/** Get value of svp->stop, with locking. */
+static uint32_t svp_get_stop(SVP_T *svp)
+{
+   uint32_t stop;
+
+   vcos_mutex_lock(&svp->mutex);
+   stop = svp->stop;
+   vcos_mutex_unlock(&svp->mutex);
+
+   return stop;
+}
diff --git a/host_applications/android/apps/vidtex/svp.h b/host_applications/android/apps/vidtex/svp.h
new file mode 100755 (executable)
index 0000000..80c2151
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef SVP_H
+#define SVP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file
+ * Simple video player using MMAL.
+ * Uses MMAL container reader plus video decode component, and provides callback to retrieve
+ * buffers of decoded video frames.
+ *
+ * Thread-safety: The public API functions must be called from the same thread for a given SVP_T
+ *                instance. The user is notified of decoded frames and other events from a separate
+ *                thread, started by svp_start().
+ */
+
+/** Flags indicating reason for processing stop */
+/** Stop on to user request */
+#define SVP_STOP_USER    (1 << 0)
+/** Stop on end-of-stream */
+#define SVP_STOP_EOS     (1 << 1)
+/** Stop on error */
+#define SVP_STOP_ERROR   (1 << 2)
+/** Stop on timer */
+#define SVP_STOP_TIMEUP  (1 << 3)
+
+/**
+ * Callback functions and context for player to communicate asynchronous data
+ * and events to user.
+ */
+typedef struct SVP_CALLBACKS_T
+{
+   /** Private pointer specified by caller, passed to callback functions.
+    * Not examined by svp_ functions, so may have any value, including NULL.
+    */
+   void *ctx;
+
+   /** Callback for decoded video frames.
+    * The buffer is released when this function returns, so the callback must either have processed
+    * the buffer or acquired a reference before returning.
+    * @param ctx  Caller's private context, as specified by SVP_CALLBACKS_T::ctx.
+    * @param ob   MMAL opaque buffer handle.
+    */
+   void (*video_frame_cb)(void *ctx, void *buf);
+
+   /** Callback for end of processing.
+    * @param ctx     Caller's private context, as specified by SVP_CALLBACKS_T::ctx.
+    * @param reason  Bitmask of SVP_STOP_XXX values giving reason for stopping.
+    */
+   void (*stop_cb)(void *ctx, uint32_t stop_reason);
+} SVP_CALLBACKS_T;
+
+/** Options to SVP playback */
+typedef struct SVP_OPTS_T
+{
+   /** Duration of playback, in milliseconds. 0 = default, which is full duration for media and
+    * a limited duration for camera.
+    */
+   unsigned duration_ms;
+} SVP_OPTS_T;
+
+/** Playback stats */
+typedef struct SVP_STATS_T
+{
+   /** Total number of video frames processed since the last call to svp_start().
+    * 0 if svp_start() has never been called. */
+   unsigned video_frame_count;
+} SVP_STATS_T;
+
+/** Simple Video Player instance. Opaque structure. */
+typedef struct SVP_T SVP_T;
+
+/**
+ * Create a simple video player instance.
+ * @param uri        URI to media, or NULL to use camera preview.
+ * @param callbacks  Callbacks for caller to receive notification of events,
+ *                   such as decoded buffers.
+ * @param opts       Player options.
+ * @return Newly created simple video player instance, or NULL on error.
+ */
+SVP_T *svp_create(const char *uri, SVP_CALLBACKS_T *callbacks, const SVP_OPTS_T *opts);
+
+/**
+ * Destroy a simple video player instance.
+ * @param svp  Simple video player instance. May be NULL, in which case this
+ *             function does nothing.
+ */
+void svp_destroy(SVP_T *svp);
+
+/**
+ * Start a simple video player instance.
+ * Decoded frames are returned to the SVP_CALLBACKS_T::video_frame_cb function
+ * passed to svp_create().
+ * @param svp  Simple video player instance.
+ * @return 0 on success; -1 on failure.
+ */
+int svp_start(SVP_T *svp);
+
+/**
+ * Stop a simple video player instance.
+ * If the player is not running, then this function does nothing.
+ * @param svp  Simple video player instance.
+ */
+void svp_stop(SVP_T *svp);
+
+/**
+ * Get player stats.
+ * @param svp    Simple video player instance.
+ * @param stats  Buffer in which stats are returned.
+ */
+void svp_get_stats(SVP_T *svp, SVP_STATS_T *stats);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* SVP_H */
diff --git a/host_applications/android/apps/vidtex/vidtex.c b/host_applications/android/apps/vidtex/vidtex.c
new file mode 100755 (executable)
index 0000000..c72a78c
--- /dev/null
@@ -0,0 +1,555 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <math.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include "applog.h"
+#include "interface/vcos/vcos.h"
+#include "interface/vcos/vcos_stdbool.h"
+#include "interface/khronos/include/EGL/eglext_brcm.h"
+#include "vidtex.h"
+
+/** Max number of simultaneous EGL images supported = max number of distinct video decoder
+ * buffers.
+ */
+#define VT_MAX_IMAGES  32
+
+/** Maximum permitted difference between the number of EGL buffer swaps and number of video
+ * frames.
+ */
+#define VT_MAX_FRAME_DISPARITY  2
+
+/** Mapping of MMAL opaque buffer handle to EGL image */
+typedef struct VIDTEX_IMAGE_SLOT_T
+{
+   /* Decoded video frame, as MMAL opaque buffer handle. NULL => unused slot. */
+   void *video_frame;
+
+   /* Corresponding EGL image */
+   EGLImageKHR image;
+} VIDTEX_IMAGE_SLOT_T;
+
+/**
+ * Video Texture. Displays video from a URI or camera onto an EGL surface.
+ */
+typedef struct VIDTEX_T
+{
+   /** Test options; bitmask of VIDTEX_OPT_XXX values */
+   uint32_t opts;
+
+   /* Semaphore to synchronise use of decoded frame (video_frame). */
+   VCOS_SEMAPHORE_T sem_decoded;
+
+   /* Semaphore to synchronise drawing of video frame. */
+   VCOS_SEMAPHORE_T sem_drawn;
+
+   /* Mutex to guard access to quit field. */
+   VCOS_MUTEX_T mutex;
+
+   /* Signal thread to quit. */
+   bool quit;
+
+   /* Reason for quitting */
+   uint32_t stop_reason;
+
+   /* EGL display/surface/context on which to render the video */
+   EGLDisplay display;
+   EGLSurface surface;
+   EGLContext context;
+
+   /* EGL texture name */
+   GLuint texture;
+
+   /* Table of EGL images corresponding to MMAL opaque buffer handles */
+   VIDTEX_IMAGE_SLOT_T slots[VT_MAX_IMAGES];
+
+   /* Current decoded video frame, as MMAL opaque buffer handle.
+    * NULL if no buffer currently available. */
+   void *video_frame;
+
+   /* Number of EGL buffer swaps */
+   unsigned num_swaps;
+} VIDTEX_T;
+
+/* Vertex co-ordinates:
+ *
+ * v0----v1
+ * |     |
+ * |     |
+ * |     |
+ * v3----v2
+ */
+
+static const GLfloat vt_vertices[] =
+{
+#define VT_V0  -0.8,  0.8,  0.8,
+#define VT_V1   0.8,  0.8,  0.8,
+#define VT_V2   0.8, -0.8,  0.8,
+#define VT_V3  -0.8, -0.8,  0.8,
+   VT_V0 VT_V3 VT_V2 VT_V2 VT_V1 VT_V0
+};
+
+/* Texture co-ordinates:
+ *
+ * (0,0) b--c
+ *       |  |
+ *       a--d
+ *
+ * b,a,d d,c,b
+ */
+static const GLfloat vt_tex_coords[] =
+{
+   0, 0, 0, 1, 1, 1,
+   1, 1, 1, 0, 0, 0
+};
+
+/* Local function prototypes */
+static VIDTEX_T *vidtex_create(EGLNativeWindowType win);
+static void vidtex_destroy(VIDTEX_T *vt);
+static int vidtex_gl_init(VIDTEX_T *vt, EGLNativeWindowType win);
+static void vidtex_gl_term(VIDTEX_T *vt);
+static void vidtex_destroy_images(VIDTEX_T *vt);
+static int vidtex_play(VIDTEX_T *vt, const VIDTEX_PARAMS_T *params);
+static void vidtex_check_gl(VIDTEX_T *vt, uint32_t line);
+static void vidtex_draw(VIDTEX_T *vt, void *video_frame);
+static void vidtex_flush_gl(VIDTEX_T *vt);
+static bool vidtex_set_quit(VIDTEX_T *vt, bool quit);
+static void vidtex_video_frame_cb(void *ctx, void *ob);
+static void vidtex_stop_cb(void *ctx, uint32_t stop_reason);
+
+#define VIDTEX_CHECK_GL(VT) vidtex_check_gl(VT, __LINE__)
+
+/** Create a new vidtex instance */
+static VIDTEX_T *vidtex_create(EGLNativeWindowType win)
+{
+   VIDTEX_T *vt;
+   VCOS_STATUS_T st;
+
+   vt = vcos_calloc(1, sizeof(*vt), "vidtex");
+   if (vt == NULL)
+   {
+      vcos_log_trace("Memory allocation failure");
+      return NULL;
+   }
+
+   st = vcos_semaphore_create(&vt->sem_decoded, "vidtex-dec", 0);
+   if (st != VCOS_SUCCESS)
+   {
+      vcos_log_trace("Error creating semaphore");
+      goto error_ctx;
+   }
+
+   st = vcos_semaphore_create(&vt->sem_drawn, "vidtex-drw", 0);
+   if (st != VCOS_SUCCESS)
+   {
+      vcos_log_trace("Error creating semaphore");
+      goto error_sem1;
+   }
+
+   st = vcos_mutex_create(&vt->mutex, "vidtex");
+   if (st != VCOS_SUCCESS)
+   {
+      vcos_log_trace("Error creating semaphore");
+      goto error_sem2;
+   }
+
+   if (vidtex_gl_init(vt, win) != 0)
+   {
+      vcos_log_trace("Error initialising EGL");
+      goto error_mutex;
+   }
+
+   vt->quit = false;
+   vt->stop_reason = 0;
+
+   return vt;
+
+error_mutex:
+   vcos_mutex_delete(&vt->mutex);
+error_sem2:
+   vcos_semaphore_delete(&vt->sem_drawn);
+error_sem1:
+   vcos_semaphore_delete(&vt->sem_decoded);
+error_ctx:
+   vcos_free(vt);
+   return NULL;
+}
+
+/** Destroy a vidtex instance */
+static void vidtex_destroy(VIDTEX_T *vt)
+{
+   vidtex_gl_term(vt);
+   vcos_mutex_delete(&vt->mutex);
+   vcos_semaphore_delete(&vt->sem_drawn);
+   vcos_semaphore_delete(&vt->sem_decoded);
+   vcos_free(vt);
+}
+
+/** Init GL using a native window */
+static int vidtex_gl_init(VIDTEX_T *vt, EGLNativeWindowType win)
+{
+   const EGLint attribs[] =
+   {
+      EGL_RED_SIZE,   8,
+      EGL_GREEN_SIZE, 8,
+      EGL_BLUE_SIZE,  8,
+      EGL_DEPTH_SIZE, 0,
+      EGL_NONE
+   };
+   EGLConfig config;
+   EGLint num_configs;
+
+   vt->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+   eglInitialize(vt->display, 0, 0);
+
+   eglChooseConfig(vt->display, attribs, &config, 1, &num_configs);
+
+   vt->surface = eglCreateWindowSurface(vt->display, config, win, NULL);
+   vt->context = eglCreateContext(vt->display, config, NULL, NULL);
+
+   if (!eglMakeCurrent(vt->display, vt->surface, vt->surface, vt->context))
+   {
+      vidtex_gl_term(vt);
+      return -1;
+   }
+
+   glGenTextures(1, &vt->texture);
+
+   glShadeModel(GL_FLAT);
+   glDisable(GL_DITHER);
+   glDisable(GL_SCISSOR_TEST);
+   glEnable(GL_TEXTURE_EXTERNAL_OES);
+   glDisable(GL_TEXTURE_2D);
+
+   return 0;
+}
+
+/** Terminate GL */
+static void vidtex_gl_term(VIDTEX_T *vt)
+{
+   vidtex_destroy_images(vt);
+
+   /* Delete texture name */
+   glDeleteTextures(1, &vt->texture);
+
+   /* Terminate EGL */
+   eglMakeCurrent(vt->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+   eglDestroyContext(vt->display, vt->context);
+   eglDestroySurface(vt->display, vt->surface);
+   eglTerminate(vt->display);
+}
+
+/** Destroy all EGL images */
+static void vidtex_destroy_images(VIDTEX_T *vt)
+{
+   VIDTEX_IMAGE_SLOT_T *slot;
+
+   for (slot = vt->slots; slot < vt->slots + vcos_countof(vt->slots); slot++)
+   {
+      slot->video_frame = NULL;
+
+      if (slot->image)
+      {
+         vcos_log_trace("Destroying EGL image %p", slot->image);
+         eglDestroyImageKHR(vt->display, slot->image);
+         slot->image = NULL;
+      }
+   }
+}
+
+/** Play video - from URI or camera - on EGL surface. */
+static int vidtex_play(VIDTEX_T *vt, const VIDTEX_PARAMS_T *params)
+{
+   const char *uri;
+   SVP_CALLBACKS_T callbacks;
+   SVP_T *svp;
+   SVP_OPTS_T opts;
+   SVP_STATS_T stats;
+   int rv = -1;
+
+   uri = (params->uri[0] == '\0') ? NULL : params->uri;
+   vt->opts = params->opts;
+   callbacks.ctx = vt;
+   callbacks.video_frame_cb = vidtex_video_frame_cb;
+   callbacks.stop_cb = vidtex_stop_cb;
+   opts.duration_ms = params->duration_ms;
+
+   svp = svp_create(uri, &callbacks, &opts);
+   if (svp)
+   {
+      /* Reset stats */
+      vt->num_swaps = 0;
+
+      /* Run video player until receive quit notification */
+      if (svp_start(svp) == 0)
+      {
+         while (!vidtex_set_quit(vt, false))
+         {
+            vcos_semaphore_wait(&vt->sem_decoded);
+
+            if (vt->video_frame)
+            {
+               vidtex_draw(vt, vt->video_frame);
+               vcos_semaphore_post(&vt->sem_drawn);
+            }
+         }
+
+         vcos_semaphore_post(&vt->sem_drawn);
+
+         /* Dump stats */
+         svp_get_stats(svp, &stats);
+         vcos_log_info("video frames decoded: %6u", stats.video_frame_count);
+         vcos_log_info("EGL buffer swaps:     %6u", vt->num_swaps);
+
+         /* Determine status of operation and log errors */
+         if (vt->stop_reason & SVP_STOP_ERROR)
+         {
+            vcos_log_error("vidtex exiting on error");
+         }
+         else if (vt->num_swaps == 0)
+         {
+            vcos_log_error("vidtex completed with no EGL buffer swaps");
+         }
+         else if (abs((int)vt->num_swaps - (int)stats.video_frame_count) > VT_MAX_FRAME_DISPARITY)
+         {
+            vcos_log_error("vidtex completed with %u EGL buffer swaps, but %u video frames",
+                           vt->num_swaps, (int)stats.video_frame_count);
+         }
+         else
+         {
+            rv = 0;
+         }
+      }
+
+      svp_destroy(svp);
+   }
+
+   vidtex_flush_gl(vt);
+
+   return rv;
+}
+
+/** Check for OpenGL errors - logs any errors and sets quit flag */
+static void vidtex_check_gl(VIDTEX_T *vt, uint32_t line)
+{
+   GLenum error = glGetError();
+   int abort = 0;
+   while (error != GL_NO_ERROR)
+   {
+      vcos_log_error("GL error: line %d error 0x%04x", line, error);
+      abort = 1;
+      error = glGetError();
+   }
+   if (abort)
+      vidtex_stop_cb(vt, SVP_STOP_ERROR);
+}
+
+/* Draw one video frame onto EGL surface.
+ * @param vt           vidtex instance.
+ * @param video_frame  MMAL opaque buffer handle for decoded video frame. Can't be NULL.
+ */
+static void vidtex_draw(VIDTEX_T *vt, void *video_frame)
+{
+   EGLImageKHR image;
+   VIDTEX_IMAGE_SLOT_T *slot;
+   static uint32_t frame_num = 0;
+
+   vcos_assert(video_frame);
+
+   glClearColor(0, 0, 0, 0);
+   glClearDepthf(1);
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+   glLoadIdentity();
+
+   glBindTexture(GL_TEXTURE_EXTERNAL_OES, vt->texture);
+   VIDTEX_CHECK_GL(vt);
+
+   /* Lookup or create EGL image corresponding to supplied buffer handle.
+    * N.B. Slot array is filled in sequentially, with the images all destroyed together on
+    *      vidtex termination; it never has holes. */
+   image = EGL_NO_IMAGE_KHR;
+
+   for (slot = vt->slots; slot < vt->slots + vcos_countof(vt->slots); slot++)
+   {
+      if (slot->video_frame == video_frame)
+      {
+         vcos_assert(slot->image);
+         image = slot->image;
+         break;
+      }
+
+      if (slot->video_frame == NULL)
+      {
+         EGLenum target;
+         vcos_assert(slot->image == NULL);
+
+         if (vt->opts & VIDTEX_OPT_Y_TEXTURE)
+            target = EGL_IMAGE_BRCM_MULTIMEDIA_Y;
+         else if (vt->opts & VIDTEX_OPT_U_TEXTURE)
+            target = EGL_IMAGE_BRCM_MULTIMEDIA_U;
+         else if (vt->opts & VIDTEX_OPT_V_TEXTURE)
+            target = EGL_IMAGE_BRCM_MULTIMEDIA_V;
+         else
+            target = EGL_IMAGE_BRCM_MULTIMEDIA;
+
+         image = eglCreateImageKHR(vt->display, EGL_NO_CONTEXT, target,
+               (EGLClientBuffer)video_frame, NULL);
+         if (image == EGL_NO_IMAGE_KHR)
+         {
+            vcos_log_error("EGL image conversion error");
+         }
+         else
+         {
+            vcos_log_trace("Created EGL image %p for buf %p", image, video_frame);
+            slot->video_frame = video_frame;
+            slot->image = image;
+         } 
+         VIDTEX_CHECK_GL(vt);
+
+         break;
+      }
+   }
+
+   if (slot == vt->slots + vcos_countof(vt->slots))
+   {
+      vcos_log_error("Exceeded configured max number of EGL images");
+   }
+
+   /* Draw the EGL image */
+   if (image != EGL_NO_IMAGE_KHR)
+   {
+      /* Assume 30fps */
+      int frames_per_rev = 30 * 15;
+      GLfloat angle = (frame_num * 360) / (GLfloat) frames_per_rev;
+      frame_num = (frame_num + 1) % frames_per_rev;
+
+      glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, image);
+      VIDTEX_CHECK_GL(vt);
+
+      glRotatef(angle, 0.0, 0.0, 1.0);
+      glEnableClientState(GL_VERTEX_ARRAY);
+      glVertexPointer(3, GL_FLOAT, 0, vt_vertices);
+      glDisableClientState(GL_COLOR_ARRAY);
+      glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+      glTexCoordPointer(2, GL_FLOAT, 0, vt_tex_coords);
+
+      glDrawArrays(GL_TRIANGLES, 0, vcos_countof(vt_tex_coords) / 2);
+
+      eglSwapBuffers(vt->display, vt->surface);
+
+      if (vt->opts & VIDTEX_OPT_IMG_PER_FRAME)
+      {
+         vidtex_destroy_images(vt);
+      }
+
+      vt->num_swaps++;
+   }
+
+   VIDTEX_CHECK_GL(vt);
+}
+
+/** Do some GL stuff in order to ensure that any multimedia-related GL buffers have been released
+ * if they are going to be released.
+ */
+static void vidtex_flush_gl(VIDTEX_T *vt)
+{
+   int i;
+
+   glFlush();
+   glClearColor(0, 0, 0, 0);
+
+   for (i = 0; i < 10; i++)
+   {
+      glClear(GL_COLOR_BUFFER_BIT);
+      eglSwapBuffers(vt->display, vt->surface);
+      VIDTEX_CHECK_GL(vt);
+   }
+
+   glFlush();
+   VIDTEX_CHECK_GL(vt);
+}
+
+/** Set quit flag, with locking.
+ * @param quit  New value of the quit flag: true - command thread to quit; false - command thread
+ *              to continue.
+ * @return Old value of the quit flag.
+ */
+static bool vidtex_set_quit(VIDTEX_T *vt, bool quit)
+{
+   vcos_mutex_lock(&vt->mutex);
+   bool old_quit = vt->quit;
+   vt->quit = quit;
+   vcos_mutex_unlock(&vt->mutex);
+
+   return old_quit;
+}
+
+/** Callback to receive decoded video frame */
+static void vidtex_video_frame_cb(void *ctx, void *ob)
+{
+   if (ob)
+   {
+      VIDTEX_T *vt = ctx;
+      /* coverity[missing_lock] Coverity gets confused by the semaphore locking scheme */
+      vt->video_frame = ob;
+      vcos_semaphore_post(&vt->sem_decoded);
+      vcos_semaphore_wait(&vt->sem_drawn);
+      vt->video_frame = NULL;
+   }
+}
+
+/** Callback to receive stop notification. Sets quit flag and posts semaphore.
+ * @param ctx          VIDTEX_T instance. Declared as void * in order to use as SVP callback.
+ * @param stop_reason  SVP stop reason.
+ */
+static void vidtex_stop_cb(void *ctx, uint32_t stop_reason)
+{
+   VIDTEX_T *vt = ctx;
+   vt->stop_reason = stop_reason;
+   vidtex_set_quit(vt, true);
+   vcos_semaphore_post(&vt->sem_decoded);
+}
+
+/* Convenience function to create/play/destroy */
+int vidtex_run(const VIDTEX_PARAMS_T *params, EGLNativeWindowType win)
+{
+   VIDTEX_T *vt;
+   int rv = -1;
+
+   vt = vidtex_create(win);
+   if (vt)
+   {
+      rv = vidtex_play(vt, params);
+      vidtex_destroy(vt);
+   }
+
+   return rv;
+}
diff --git a/host_applications/android/apps/vidtex/vidtex.h b/host_applications/android/apps/vidtex/vidtex.h
new file mode 100755 (executable)
index 0000000..4a55846
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VIDTEX_H
+#define VIDTEX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file Video-on-texture display.
+ * Displays video decoded from a media URI or from camera preview onto an EGL surface.
+ */
+#include <EGL/egl.h>
+#include "interface/vcos/vcos.h"
+#include "interface/vcos/vcos_stdint.h"
+#include "svp.h"
+
+/** Max length of a vidtex URI */
+#define VIDTEX_MAX_URI  256
+
+/** Test option - create + destroy EGL image every frame */
+#define VIDTEX_OPT_IMG_PER_FRAME  (1 << 0)
+
+/** Test option - display the Y' plane as greyscale texture */
+#define VIDTEX_OPT_Y_TEXTURE  (1 << 1)
+
+/** Test option - display the U plane as greyscale texture */
+#define VIDTEX_OPT_U_TEXTURE  (1 << 2)
+
+/** Test option - display the V plane as greyscale texture */
+#define VIDTEX_OPT_V_TEXTURE  (1 << 3)
+
+/** Parameters to vidtex run.
+ * N.B. Types need to be bitwise copyable, and between C and C++, so don't use pointers, bool
+ *      or anything else liable for problems.
+ */
+typedef struct VIDTEX_PARAMS_T
+{
+   /** Duration of playback, in milliseconds. 0 = default, which is full duration for media and
+    * a limited duration for camera.
+    */
+   uint32_t duration_ms;
+
+   /** Media URI, or empty string to use camera preview */
+   char uri[VIDTEX_MAX_URI];
+
+   /** Test options; bitmask of VIDTEX_OPT_XXX values */
+   uint32_t opts;
+} VIDTEX_PARAMS_T;
+
+/** Run video-on-texture.
+ * @param params  Parameters to video-on-texture display.
+ * @param win     Native window handle.
+ * @return 0 on success; -1 on failure.
+ *         It is considered successful if the video decode completed without error and at least
+ *         one EGL image was shown.
+ */
+int vidtex_run(const VIDTEX_PARAMS_T *params, EGLNativeWindowType win);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/host_applications/framework/common/host_ilcore.h b/host_applications/framework/common/host_ilcore.h
new file mode 100755 (executable)
index 0000000..d91a240
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef HOST_ILCORE_H
+#define HOST_ILCORE_H
+
+#ifdef WANT_OMX_NAME_MANGLE
+OMX_API OMX_ERRORTYPE OMX_APIENTRY host_OMX_Init(void);
+OMX_API OMX_ERRORTYPE OMX_APIENTRY host_OMX_Deinit(void);
+OMX_API OMX_ERRORTYPE OMX_APIENTRY host_OMX_ComponentNameEnum(
+   OMX_OUT OMX_STRING cComponentName,
+   OMX_IN  OMX_U32 nNameLength,
+   OMX_IN  OMX_U32 nIndex);
+OMX_API OMX_ERRORTYPE OMX_APIENTRY host_OMX_GetHandle(
+   OMX_OUT OMX_HANDLETYPE* pHandle,
+   OMX_IN  OMX_STRING cComponentName,
+   OMX_IN  OMX_PTR pAppData,
+   OMX_IN  OMX_CALLBACKTYPE* pCallBacks);
+OMX_API OMX_ERRORTYPE OMX_APIENTRY host_OMX_FreeHandle(
+   OMX_IN  OMX_HANDLETYPE hComponent);
+OMX_API OMX_ERRORTYPE OMX_APIENTRY host_OMX_SetupTunnel(
+   OMX_IN  OMX_HANDLETYPE hOutput,
+   OMX_IN  OMX_U32 nPortOutput,
+   OMX_IN  OMX_HANDLETYPE hInput,
+   OMX_IN  OMX_U32 nPortInput);
+OMX_API OMX_ERRORTYPE host_OMX_GetComponentsOfRole (
+   OMX_IN      OMX_STRING role,
+   OMX_INOUT   OMX_U32 *pNumComps,
+   OMX_INOUT   OMX_U8  **compNames);
+OMX_API OMX_ERRORTYPE host_OMX_GetRolesOfComponent (
+   OMX_IN      OMX_STRING compName,
+   OMX_INOUT   OMX_U32 *pNumRoles,
+   OMX_OUT     OMX_U8 **roles);
+OMX_ERRORTYPE host_OMX_GetDebugInformation (
+   OMX_OUT    OMX_STRING debugInfo,
+   OMX_INOUT  OMX_S32 *pLen);
+
+#define OMX_Init host_OMX_Init
+#define OMX_Deinit host_OMX_Deinit
+#define OMX_ComponentNameEnum host_OMX_ComponentNameEnum
+#define OMX_GetHandle host_OMX_GetHandle
+#define OMX_FreeHandle host_OMX_FreeHandle
+#define OMX_SetupTunnel host_OMX_SetupTunnel
+#define OMX_GetComponentsOfRole host_OMX_GetComponentsOfRole
+#define OMX_GetRolesOfComponent host_OMX_GetRolesOfComponent
+#define OMX_GetDebugInformation host_OMX_GetDebugInformation
+#else
+OMX_ERRORTYPE OMX_GetDebugInformation (
+   OMX_OUT    OMX_STRING debugInfo,
+   OMX_INOUT  OMX_S32 *pLen);
+#endif
+
+#endif // HOST_ILCORE_H
+
+
diff --git a/host_applications/framework/common/ilcore.c b/host_applications/framework/common/ilcore.c
new file mode 100755 (executable)
index 0000000..ebd13cc
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdio.h>
+#include <stdarg.h>
+
+//includes
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "interface/vmcs_host/khronos/IL/OMX_Component.h"
+#include "interface/vmcs_host/vcilcs.h"
+#include "interface/vmcs_host/vchost.h"
+#include "interface/vmcs_host/vcilcs_common.h"
+
+#include "host_ilcore.h"
+
+
+#ifdef WANT_OMX_NAME_MANGLE
+#define OMX_Deinit host_OMX_Deinit
+#define OMX_Init host_OMX_Init
+#define OMX_SetupTunnel host_OMX_SetupTunnel
+#define OMX_FreeHandle host_OMX_FreeHandle
+#define OMX_GetHandle host_OMX_GetHandle
+#define OMX_GetRolesOfComponent host_OMX_GetRolesOfComponent
+#define OMX_GetComponentsOfRole host_OMX_GetComponentsOfRole
+#define OMX_ComponentNameEnum host_OMX_ComponentNameEnum
+#define OMX_GetDebugInformation host_OMX_GetDebugInformation
+#endif
+
+#ifdef WANT_LOCAL_OMX
+   // xxx: we need to link to local OpenMAX IL core as well
+   OMX_API OMX_ERRORTYPE OMX_APIENTRY vc_OMX_Init(void);
+   OMX_API OMX_ERRORTYPE OMX_APIENTRY vc_OMX_Deinit(void);
+   OMX_API OMX_ERRORTYPE OMX_APIENTRY vc_OMX_GetHandle(
+      OMX_OUT OMX_HANDLETYPE* pHandle,
+      OMX_IN  OMX_STRING cComponentName,
+      OMX_IN  OMX_PTR pAppData,
+      OMX_IN  OMX_CALLBACKTYPE* pCallBacks);
+   OMX_API OMX_ERRORTYPE OMX_APIENTRY vc_OMX_FreeHandle(
+      OMX_IN  OMX_HANDLETYPE hComponent);
+#endif
+
+static int coreInit = 0;
+static int nActiveHandles = 0;
+static ILCS_SERVICE_T *ilcs_service = NULL;
+static VCOS_MUTEX_T lock;
+static VCOS_ONCE_T once = VCOS_ONCE_INIT;
+
+/* Atomic creation of lock protecting shared state */
+static void initOnce(void)
+{
+   VCOS_STATUS_T status;
+   status = vcos_mutex_create(&lock, VCOS_FUNCTION);
+   vcos_demand(status == VCOS_SUCCESS);
+}
+
+/* OMX_Init */
+OMX_ERRORTYPE OMX_APIENTRY OMX_Init(void)
+{
+   VCOS_STATUS_T status;
+   OMX_ERRORTYPE err = OMX_ErrorNone;
+
+   status = vcos_once(&once, initOnce);
+   vcos_demand(status == VCOS_SUCCESS);
+
+   vcos_mutex_lock(&lock);
+   
+#ifdef WANT_LOCAL_OMX
+   vc_OMX_Init(); // initialise local core first
+#endif
+
+   if(coreInit == 0)
+   {
+      // we need to connect via an ILCS connection to VideoCore
+      VCHI_INSTANCE_T initialise_instance;
+      VCHI_CONNECTION_T *connection;
+      ILCS_CONFIG_T config;
+
+      vc_host_get_vchi_state(&initialise_instance, &connection);
+
+      vcilcs_config(&config);
+#ifdef USE_VCHIQ_ARM
+      ilcs_service = ilcs_init((VCHIQ_INSTANCE_T) initialise_instance, (void **) &connection, &config, 0);
+#else
+      ilcs_service = ilcs_init((VCHIQ_STATE_T *) initialise_instance, (void **) &connection, &config, 0);
+#endif
+
+      if(ilcs_service == NULL)
+      {
+         err = OMX_ErrorHardware;
+         goto end;
+      }
+
+      coreInit = 1;
+   }
+#ifdef USE_VCHIQ_ARM
+   else
+      coreInit++;
+#endif
+
+end:
+   vcos_mutex_unlock(&lock);
+   return err;
+}
+
+/* OMX_Deinit */
+OMX_ERRORTYPE OMX_APIENTRY OMX_Deinit(void)
+{
+   if(coreInit == 0) // || (coreInit == 1 && nActiveHandles > 0))
+      return OMX_ErrorNotReady;
+
+   vcos_mutex_lock(&lock);
+
+#ifdef USE_VCHIQ_ARM
+   coreInit--;
+#endif
+
+   if(coreInit == 0)
+   {
+      // we need to teardown the ILCS connection to VideoCore
+      ilcs_deinit(ilcs_service);
+      ilcs_service = NULL;
+   }
+
+#ifdef WANT_LOCAL_OMX
+   vc_OMX_Deinit(); // deinitialise local core as well
+#endif
+
+   vcos_mutex_unlock(&lock);
+   
+   return OMX_ErrorNone;
+}
+
+
+/* OMX_ComponentNameEnum */
+OMX_ERRORTYPE OMX_APIENTRY OMX_ComponentNameEnum(
+   OMX_OUT OMX_STRING cComponentName,
+   OMX_IN  OMX_U32 nNameLength,
+   OMX_IN  OMX_U32 nIndex)
+{
+   if(ilcs_service == NULL)
+      return OMX_ErrorBadParameter;
+
+   return vcil_out_component_name_enum(ilcs_get_common(ilcs_service), cComponentName, nNameLength, nIndex);
+}
+
+
+/* OMX_GetHandle */
+OMX_ERRORTYPE OMX_APIENTRY OMX_GetHandle(
+   OMX_OUT OMX_HANDLETYPE* pHandle,
+   OMX_IN  OMX_STRING cComponentName,
+   OMX_IN  OMX_PTR pAppData,
+   OMX_IN  OMX_CALLBACKTYPE* pCallBacks)
+{
+   OMX_ERRORTYPE eError;
+   OMX_COMPONENTTYPE *pComp;
+   OMX_HANDLETYPE hHandle = 0;
+
+   if (pHandle == NULL || cComponentName == NULL || pCallBacks == NULL || ilcs_service == NULL)
+   {
+      if(pHandle)
+         *pHandle = NULL;
+      return OMX_ErrorBadParameter;
+   }
+
+#if defined(WANT_LOCAL_OMX) && 0
+   if ((eError = vc_OMX_GetHandle(pHandle, cComponentName, pAppData, pCallBacks)) != OMX_ErrorNone)
+#endif
+   {
+      pComp = (OMX_COMPONENTTYPE *)malloc(sizeof(OMX_COMPONENTTYPE));
+      if (!pComp)
+      {
+         vcos_assert(0);
+         return OMX_ErrorInsufficientResources;
+      }
+      memset(pComp, 0, sizeof(OMX_COMPONENTTYPE));
+      hHandle = (OMX_HANDLETYPE)pComp;
+      pComp->nSize = sizeof(OMX_COMPONENTTYPE);
+      pComp->nVersion.nVersion = OMX_VERSION;
+      eError = vcil_out_create_component(ilcs_get_common(ilcs_service), hHandle, cComponentName);
+
+      if (eError == OMX_ErrorNone) {
+         // Check that all function pointers have been filled in.
+         // All fields should be non-zero.
+         int i;
+         uint32_t *p = (uint32_t *) pComp;
+         for(i=0; i<sizeof(OMX_COMPONENTTYPE)>>2; i++)
+            if(*p++ == 0)
+               eError = OMX_ErrorInvalidComponent;
+
+         if(eError != OMX_ErrorNone && pComp->ComponentDeInit)
+            pComp->ComponentDeInit(hHandle);
+      }      
+
+      if (eError == OMX_ErrorNone) {
+         eError = pComp->SetCallbacks(hHandle,pCallBacks,pAppData);
+         if (eError != OMX_ErrorNone)
+            pComp->ComponentDeInit(hHandle);
+      }
+      if (eError == OMX_ErrorNone) {
+         *pHandle = hHandle;
+      }
+      else {
+         *pHandle = NULL;
+         free(pComp);
+      }
+   } 
+
+   if (eError == OMX_ErrorNone) {
+      vcos_mutex_lock(&lock);
+      nActiveHandles++;
+      vcos_mutex_unlock(&lock);
+   }
+
+   return eError;
+}
+
+/* OMX_FreeHandle */
+OMX_ERRORTYPE OMX_APIENTRY OMX_FreeHandle(
+   OMX_IN  OMX_HANDLETYPE hComponent)
+{
+   OMX_ERRORTYPE eError = OMX_ErrorNone;
+   OMX_COMPONENTTYPE *pComp;
+
+   if (hComponent == NULL || ilcs_service == NULL)
+      return OMX_ErrorBadParameter;
+
+   pComp = (OMX_COMPONENTTYPE*)hComponent;
+
+#ifdef WANT_LOCAL_OMX
+   // xxx: a bit of a bodge, we rely on knowing that
+   // the local core doesn't make use of this field but
+   // ILCS does...
+   if (pComp->pApplicationPrivate == NULL)
+      return vc_OMX_FreeHandle(hComponent);
+#endif
+
+   if (ilcs_service == NULL)
+      return OMX_ErrorBadParameter;
+
+   eError = (pComp->ComponentDeInit)(hComponent);
+   if (eError == OMX_ErrorNone) {
+      vcos_mutex_lock(&lock);
+      --nActiveHandles;
+      vcos_mutex_unlock(&lock);
+      free(pComp);
+   }
+
+   vcos_assert(nActiveHandles >= 0);
+
+   return eError;
+}
+
+/* OMX_SetupTunnel */
+OMX_ERRORTYPE OMX_APIENTRY OMX_SetupTunnel(
+   OMX_IN  OMX_HANDLETYPE hOutput,
+   OMX_IN  OMX_U32 nPortOutput,
+   OMX_IN  OMX_HANDLETYPE hInput,
+   OMX_IN  OMX_U32 nPortInput)
+{
+   OMX_ERRORTYPE eError = OMX_ErrorNone;
+   OMX_COMPONENTTYPE *pCompIn, *pCompOut;
+   OMX_TUNNELSETUPTYPE oTunnelSetup;
+
+   if ((hOutput == NULL && hInput == NULL) || ilcs_service == NULL)
+      return OMX_ErrorBadParameter;
+
+   oTunnelSetup.nTunnelFlags = 0;
+   oTunnelSetup.eSupplier = OMX_BufferSupplyUnspecified;
+
+   pCompOut = (OMX_COMPONENTTYPE*)hOutput;
+
+   if (hOutput){
+      eError = pCompOut->ComponentTunnelRequest(hOutput, nPortOutput, hInput, nPortInput, &oTunnelSetup);
+   }
+
+   if (eError == OMX_ErrorNone && hInput) {
+      pCompIn = (OMX_COMPONENTTYPE*)hInput;
+      eError = pCompIn->ComponentTunnelRequest(hInput, nPortInput, hOutput, nPortOutput, &oTunnelSetup);
+
+      if (eError != OMX_ErrorNone && hOutput) {
+         /* cancel tunnel request on output port since input port failed */
+         pCompOut->ComponentTunnelRequest(hOutput, nPortOutput, NULL, 0, NULL);
+      }
+   }
+   return eError;
+}
+
+/* OMX_GetComponentsOfRole */
+OMX_ERRORTYPE OMX_GetComponentsOfRole (
+   OMX_IN      OMX_STRING role,
+   OMX_INOUT   OMX_U32 *pNumComps,
+   OMX_INOUT   OMX_U8  **compNames)
+{
+   OMX_ERRORTYPE eError = OMX_ErrorNone;
+
+   *pNumComps = 0;
+   return eError;
+}
+
+/* OMX_GetRolesOfComponent */
+OMX_ERRORTYPE OMX_GetRolesOfComponent (
+   OMX_IN      OMX_STRING compName,
+   OMX_INOUT   OMX_U32 *pNumRoles,
+   OMX_OUT     OMX_U8 **roles)
+{
+   OMX_ERRORTYPE eError = OMX_ErrorNone;
+
+   *pNumRoles = 0;
+   return eError;
+}
+
+/* OMX_GetDebugInformation */
+OMX_ERRORTYPE OMX_GetDebugInformation (
+   OMX_OUT    OMX_STRING debugInfo,
+   OMX_INOUT  OMX_S32 *pLen)
+{
+   if(ilcs_service == NULL)
+      return OMX_ErrorBadParameter;
+
+   return vcil_out_get_debug_information(ilcs_get_common(ilcs_service), debugInfo, pLen);
+}
+
+
+
+/* File EOF */
+
diff --git a/host_applications/linux/CMakeLists.txt b/host_applications/linux/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..80a1908
--- /dev/null
@@ -0,0 +1,25 @@
+# linux apps
+
+if(NOT ARM64)
+   add_subdirectory(libs/bcm_host)
+   add_subdirectory(apps/hello_pi)
+endif()
+add_subdirectory(apps/gencmd)
+add_subdirectory(apps/tvservice)
+add_subdirectory(apps/vcmailbox)
+if(NOT ARM64)
+   add_subdirectory(apps/raspicam)
+   add_subdirectory(libs/sm)
+   add_subdirectory(apps/smem)
+endif()
+add_subdirectory(libs/debug_sym)
+add_subdirectory(apps/dtoverlay)
+add_subdirectory(apps/dtmerge)
+
+if(ALL_APPS)
+ add_subdirectory(apps/vcdbg)
+ add_subdirectory(libs/elftoolchain)
+ # add_subdirectory(apps/smct)
+ add_subdirectory(apps/edid_parser)
+ add_subdirectory(apps/hello_pi)
+endif()
diff --git a/host_applications/linux/apps/dtmerge/CMakeLists.txt b/host_applications/linux/apps/dtmerge/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..d173697
--- /dev/null
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 2.8)
+
+get_filename_component (VIDEOCORE_ROOT ../../../.. ABSOLUTE)
+include (${VIDEOCORE_ROOT}/makefiles/cmake/global_settings.cmake)
+
+if (NOT WIN32)
+   add_definitions(-Wall -Werror)
+endif ()
+
+include_directories (
+   ${VIDEOCORE_HEADERS_BUILD_DIR}
+   ${VIDEOCORE_ROOT}
+   ${VIDEOCORE_ROOT}/opensrc/helpers/libfdt
+   ${VIDEOCORE_ROOT}/helpers/dtoverlay
+)
+
+add_executable(dtmerge dtmerge.c)
+target_link_libraries(dtmerge dtovl)
+
+install(TARGETS dtmerge RUNTIME DESTINATION bin)
diff --git a/host_applications/linux/apps/dtmerge/dtmerge.c b/host_applications/linux/apps/dtmerge/dtmerge.c
new file mode 100755 (executable)
index 0000000..9243da1
--- /dev/null
@@ -0,0 +1,172 @@
+/*
+Copyright (c) 2016 Raspberry Pi (Trading) Ltd.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <libfdt.h>
+
+#include "dtoverlay.h"
+
+static void usage(void)
+{
+   printf("Usage:\n");
+   printf("    dtmerge [<options] <base dtb> <merged dtb> - [param=value] ...\n");
+   printf("        to apply a parameter to the base dtb (like dtparam)\n");
+   printf("    dtmerge [<options] <base dtb> <merged dtb> <overlay dtb> [param=value] ...\n");
+   printf("        to apply an overlay with parameters (like dtoverlay)\n");
+   printf("  where <options> is any of:\n");
+   printf("    -d      Enable debug output\n");
+   printf("    -h      Show this help message\n");
+   exit(1);
+}
+
+int main(int argc, char **argv)
+{
+   const char *base_file;
+   const char *merged_file;
+   const char *overlay_file;
+   DTBLOB_T *base_dtb;
+   DTBLOB_T *overlay_dtb;
+   int err;
+   int argn = 1;
+   int max_dtb_size = 100000;
+
+   while ((argn < argc) && (argv[argn][0] == '-'))
+   {
+      const char *arg = argv[argn++];
+      if ((strcmp(arg, "-d") == 0) ||
+          (strcmp(arg, "--debug") == 0))
+         dtoverlay_enable_debug(1);
+      else if ((strcmp(arg, "-h") == 0) ||
+          (strcmp(arg, "--help") == 0))
+         usage();
+      else
+      {
+         printf("* Unknown option '%s'\n", arg);
+         usage();
+      }
+   }
+
+   if (argc < (argn + 3))
+   {
+      usage();
+   }
+
+   base_file = argv[argn++];
+   merged_file = argv[argn++];
+   overlay_file = argv[argn++];
+
+   base_dtb = dtoverlay_load_dtb(base_file, max_dtb_size);
+   if (!base_dtb)
+   {
+       printf("* failed to load '%s'\n", base_file);
+       return -1;
+   }
+
+   err = dtoverlay_set_synonym(base_dtb, "i2c", "i2c0");
+   err = dtoverlay_set_synonym(base_dtb, "i2c_arm", "i2c0");
+   err = dtoverlay_set_synonym(base_dtb, "i2c_vc", "i2c1");
+   err = dtoverlay_set_synonym(base_dtb, "i2c_baudrate", "i2c0_baudrate");
+   err = dtoverlay_set_synonym(base_dtb, "i2c_arm_baudrate", "i2c0_baudrate");
+   err = dtoverlay_set_synonym(base_dtb, "i2c_vc_baudrate", "i2c1_baudrate");
+
+   if (strcmp(overlay_file, "-") == 0)
+   {
+      overlay_dtb = base_dtb;
+   }
+   else
+   {
+      overlay_dtb = dtoverlay_load_dtb(overlay_file, max_dtb_size);
+      if (overlay_dtb)
+         err = dtoverlay_fixup_overlay(base_dtb, overlay_dtb);
+      else
+         err = -1;
+   }
+
+   while (!err && (argn < argc))
+   {
+      char *param_name = argv[argn++];
+      char *param_value = param_name + strcspn(param_name, "=");
+      const void *override_data;
+      int data_len;
+
+      if (*param_value == '=')
+      {
+         *(param_value++) = '\0';
+      }
+      else
+      {
+         /* This isn't a well-formed parameter assignment, but it can be
+            treated as an assignment of true. */
+         param_value = "true";
+      }
+
+      override_data = dtoverlay_find_override(overlay_dtb, param_name,
+                                              &data_len);
+      if (override_data)
+      {
+         err = dtoverlay_apply_override(overlay_dtb, param_name,
+                                        override_data, data_len,
+                                        param_value);
+      }
+      else
+      {
+         override_data = dtoverlay_find_override(base_dtb, param_name, &data_len);
+         if (override_data)
+         {
+            err = dtoverlay_apply_override(base_dtb, param_name,
+                                           override_data, data_len,
+                                           param_value);
+         }
+         else
+         {
+            printf("* unknown param '%s'\n", param_name);
+            err = data_len;
+         }
+      }
+   }
+
+   if (!err && (overlay_dtb != base_dtb))
+   {
+      err = dtoverlay_merge_overlay(base_dtb, overlay_dtb);
+
+      dtoverlay_free_dtb(overlay_dtb);
+   }
+
+   if (!err)
+   {
+      dtoverlay_pack_dtb(base_dtb);
+      err = dtoverlay_save_dtb(base_dtb, merged_file);
+   }
+
+   dtoverlay_free_dtb(base_dtb);
+
+   if (err != 0)
+      printf("* Exiting with error code %d\n", err);
+
+   return err;
+}
diff --git a/host_applications/linux/apps/dtoverlay/CMakeLists.txt b/host_applications/linux/apps/dtoverlay/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..9009200
--- /dev/null
@@ -0,0 +1,33 @@
+cmake_minimum_required(VERSION 2.8)
+
+get_filename_component (VIDEOCORE_ROOT ../../../.. ABSOLUTE)
+include (${VIDEOCORE_ROOT}/makefiles/cmake/global_settings.cmake)
+
+if (NOT WIN32)
+   add_definitions(-Wall -Werror)
+endif ()
+
+include_directories (
+   ${VIDEOCORE_HEADERS_BUILD_DIR}
+   ${VIDEOCORE_ROOT}
+   ${VIDEOCORE_ROOT}/opensrc/helpers/libfdt
+   ${VIDEOCORE_ROOT}/helpers/dtoverlay
+)
+
+add_executable(dtoverlay dtoverlay_main.c utils.c)
+target_link_libraries(dtoverlay dtovl)
+install(TARGETS dtoverlay RUNTIME DESTINATION bin)
+
+add_custom_command(TARGET dtoverlay POST_BUILD COMMAND ln;-sf;dtoverlay;dtparam)
+install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dtparam DESTINATION bin)
+
+set(DTOVERLAY_SCRIPTS dtoverlay-pre dtoverlay-post)
+foreach(_script ${DTOVERLAY_SCRIPTS})
+   add_custom_command(
+     TARGET dtoverlay
+     COMMAND ${CMAKE_COMMAND}
+     -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${_script}
+     ${CMAKE_BINARY_DIR}/../../bin/${_script}
+   )
+endforeach()
+install(PROGRAMS ${DTOVERLAY_SCRIPTS} DESTINATION bin)
diff --git a/host_applications/linux/apps/dtoverlay/dtoverlay-post b/host_applications/linux/apps/dtoverlay/dtoverlay-post
new file mode 100755 (executable)
index 0000000..6d8c66d
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/bash
+if [ "$DISPLAY" == "" ]; then
+       export DISPLAY=":0.0"
+fi
+CMD="which lxpanelctl >/dev/null 2>&1 && lxpanelctl alsastart >/dev/null"
+if [ $EUID -eq 0 ]; then
+        exec su pi -c "$CMD"
+else
+        exec $CMD
+fi
diff --git a/host_applications/linux/apps/dtoverlay/dtoverlay-pre b/host_applications/linux/apps/dtoverlay/dtoverlay-pre
new file mode 100755 (executable)
index 0000000..5065fc5
--- /dev/null
@@ -0,0 +1,10 @@
+#!/bin/bash
+if [ "$DISPLAY" == "" ]; then
+       export DISPLAY=":0.0"
+fi
+CMD="which lxpanelctl >/dev/null 2>&1 && lxpanelctl alsastop >/dev/null"
+if [ $EUID -eq 0 ]; then
+       exec su pi -c "$CMD"
+else
+       exec $CMD
+fi
diff --git a/host_applications/linux/apps/dtoverlay/dtoverlay_main.c b/host_applications/linux/apps/dtoverlay/dtoverlay_main.c
new file mode 100755 (executable)
index 0000000..5f87e66
--- /dev/null
@@ -0,0 +1,1073 @@
+/*
+Copyright (c) 2016 Raspberry Pi (Trading) Ltd.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+
+#include <libfdt.h>
+
+#include "dtoverlay.h"
+#include "utils.h"
+
+
+#define CFG_DIR_1 "/sys/kernel/config"
+#define CFG_DIR_2 "/config"
+#define DT_SUBDIR "/device-tree"
+#define WORK_DIR "/tmp/.dtoverlays"
+#define OVERLAY_SRC_SUBDIR "overlays"
+#define README_FILE "README"
+#define DT_OVERLAYS_SUBDIR "overlays"
+#define DTOVERLAY_PATH_MAX 128
+#define DIR_MODE 0755
+
+
+enum {
+    OPT_ADD,
+    OPT_REMOVE,
+    OPT_REMOVE_FROM,
+    OPT_LIST,
+    OPT_LIST_ALL,
+    OPT_HELP
+};
+
+static const char *boot_dirs[] =
+{
+#ifdef FORCE_BOOT_DIR
+    FORCE_BOOT_DIR,
+#else
+    "/boot",
+    "/flash",
+#ifdef OTHER_BOOT_DIR
+    OTHER_BOOT_DIR,
+#endif
+#endif
+    NULL /* Terminator */
+};
+
+typedef struct state_struct
+{
+    int count;
+    struct dirent **namelist;
+} STATE_T;
+
+static int dtoverlay_add(STATE_T *state, const char *overlay,
+                         int argc, const char **argv);
+static int dtoverlay_remove(STATE_T *state, const char *overlay, int and_later);
+static int dtoverlay_list(STATE_T *state);
+static int dtoverlay_list_all(STATE_T *state);
+static void usage(void);
+static void root_check(void);
+
+static void overlay_help(const char *overlay, const char **params);
+
+static int apply_overlay(const char *overlay_file, const char *overlay);
+static int overlay_applied(const char *overlay_dir);
+
+static STATE_T *read_state(const char *dir);
+static void free_state(STATE_T *state);
+
+const char *cmd_name;
+
+const char *work_dir = WORK_DIR;
+const char *overlay_src_dir;
+const char *dt_overlays_dir;
+const char *error_file = NULL;
+int dry_run = 0;
+
+int main(int argc, const char **argv)
+{
+    int argn = 1;
+    int opt = OPT_ADD;
+    int is_dtparam;
+    const char *overlay = NULL;
+    const char **params = NULL;
+    int ret = 0;
+    STATE_T *state = NULL;
+    const char *cfg_dir;
+
+    cmd_name = argv[0];
+    if (strrchr(cmd_name, '/'))
+        cmd_name = strrchr(cmd_name, '/') + 1;
+    is_dtparam = (strcmp(cmd_name, "dtparam") == 0);
+
+    while ((argn < argc) && (argv[argn][0] == '-'))
+    {
+        const char *arg = argv[argn++];
+        if (strcmp(arg, "-r") == 0)
+        {
+            if (opt != OPT_ADD)
+                usage();
+            opt = OPT_REMOVE;
+        }
+        else if (strcmp(arg, "-R") == 0)
+        {
+            if (opt != OPT_ADD)
+                usage();
+            opt = OPT_REMOVE_FROM;
+        }
+        else if (strcmp(arg, "-D") == 0)
+        {
+            if (opt != OPT_ADD)
+                usage();
+            dry_run = 1;
+            work_dir = ".";
+        }
+        else if ((strcmp(arg, "-l") == 0) ||
+                 (strcmp(arg, "--list") == 0))
+        {
+            if (opt != OPT_ADD)
+                usage();
+            opt = OPT_LIST;
+        }
+        else if ((strcmp(arg, "-a") == 0) ||
+                 (strcmp(arg, "--listall") == 0) ||
+                 (strcmp(arg, "--all") == 0))
+        {
+           if (opt != OPT_ADD)
+               usage();
+           opt = OPT_LIST_ALL;
+       }
+       else if (strcmp(arg, "-d") == 0)
+       {
+           if (argn == argc)
+               usage();
+           overlay_src_dir = argv[argn++];
+       }
+       else if (strcmp(arg, "-v") == 0)
+       {
+           opt_verbose = 1;
+       }
+       else if (strcmp(arg, "-h") == 0)
+       {
+           opt = OPT_HELP;
+       }
+       else
+       {
+           fprintf(stderr, "* unknown option '%s'\n", arg);
+           usage();
+       }
+    }
+
+    if ((opt == OPT_ADD) || (opt == OPT_REMOVE) ||
+       (opt == OPT_REMOVE_FROM) || (opt == OPT_HELP))
+    {
+       if ((argn == argc) &&
+           ((!is_dtparam &&
+             ((opt == OPT_ADD) || (opt == OPT_HELP))) ||
+            (is_dtparam && (opt == OPT_HELP))))
+           usage();
+       if (is_dtparam && (opt == OPT_ADD) && (argn == argc))
+           opt = OPT_HELP;
+       if (is_dtparam &&
+           ((opt == OPT_ADD) || (opt == OPT_HELP)))
+           overlay = "dtparam";
+       else if (argn < argc)
+           overlay = argv[argn++];
+    }
+
+    if ((opt == OPT_HELP) && (argn < argc))
+    {
+       params = &argv[argn];
+       argn = argc;
+    }
+
+    if ((opt != OPT_ADD) && (argn != argc))
+       usage();
+
+    dtoverlay_enable_debug(opt_verbose);
+
+    if (!overlay_src_dir)
+    {
+       /* Find the overlays and README */
+       int i;
+
+       for (i = 0; boot_dirs[i]; i++)
+       {
+           overlay_src_dir = sprintf_dup("%s/" OVERLAY_SRC_SUBDIR,
+                                         boot_dirs[i]);
+           if (dir_exists(overlay_src_dir))
+               break;
+           free_string(overlay_src_dir);
+           overlay_src_dir = NULL;
+       }
+
+       if (!overlay_src_dir)
+           fatal_error("Failed to find overlays directory");
+    }
+
+    if (opt == OPT_HELP)
+    {
+       overlay_help(overlay, params);
+       goto orderly_exit;
+    }
+
+    if (!dir_exists(work_dir))
+    {
+       if (mkdir(work_dir, DIR_MODE) != 0)
+           fatal_error("Failed to create '%s' - %d", work_dir, errno);
+    }
+
+    error_file = sprintf_dup("%s/%s", work_dir, "error.dtb");
+
+    cfg_dir = CFG_DIR_1 DT_SUBDIR;
+    if (!dry_run && !dir_exists(cfg_dir))
+    {
+       root_check();
+
+       cfg_dir = CFG_DIR_2;
+       if (!dir_exists(cfg_dir))
+       {
+           if (mkdir(cfg_dir, DIR_MODE) != 0)
+               fatal_error("Failed to create '%s' - %d", cfg_dir, errno);
+       }
+
+       cfg_dir = CFG_DIR_2 DT_SUBDIR;
+       if (!dir_exists(cfg_dir) &&
+           (run_cmd("mount -t configfs none '%s'", cfg_dir) != 0))
+           fatal_error("Failed to mount configfs - %d", errno);
+    }
+
+    dt_overlays_dir = sprintf_dup("%s/%s", cfg_dir, DT_OVERLAYS_SUBDIR);
+    if (!dir_exists(dt_overlays_dir))
+       fatal_error("configfs overlays folder not found - incompatible kernel");
+
+    if (!dry_run)
+    {
+        state = read_state(work_dir);
+        if (!state)
+            fatal_error("Failed to read state");
+    }
+
+    switch (opt)
+    {
+    case OPT_ADD:
+    case OPT_REMOVE:
+    case OPT_REMOVE_FROM:
+        if (!dry_run)
+        {
+            root_check();
+            run_cmd("which dtoverlay-pre >/dev/null 2>&1 && dtoverlay-pre");
+        }
+        break;
+    default:
+       break;
+    }
+
+    switch (opt)
+    {
+    case OPT_ADD:
+       ret = dtoverlay_add(state, overlay, argc - argn, argv + argn);
+       break;
+    case OPT_REMOVE:
+       ret = dtoverlay_remove(state, overlay, 0);
+       break;
+    case OPT_REMOVE_FROM:
+       ret = dtoverlay_remove(state, overlay, 1);
+       break;
+    case OPT_LIST:
+       ret = dtoverlay_list(state);
+       break;
+    case OPT_LIST_ALL:
+       ret = dtoverlay_list_all(state);
+       break;
+    default:
+       ret = 1;
+       break;
+    }
+
+    switch (opt)
+    {
+    case OPT_ADD:
+    case OPT_REMOVE:
+    case OPT_REMOVE_FROM:
+       if (!dry_run)
+           run_cmd("which dtoverlay-post >/dev/null 2>&1 && dtoverlay-post");
+       break;
+    default:
+       break;
+    }
+
+orderly_exit:
+    if (state)
+       free_state(state);
+    free_strings();
+
+    if ((ret == 0) && error_file)
+       unlink(error_file);
+
+    return ret;
+}
+
+struct dtparam_state
+{
+    STRING_VEC_T *used_props;
+    const char *override_value;
+};
+
+int dtparam_callback(int override_type,
+                    DTBLOB_T *dtb, int node_off,
+                    const char *prop_name, int target_phandle,
+                    int target_off, int target_size,
+                    void *callback_value)
+{
+    struct dtparam_state *state = callback_value;
+    char prop_id[80];
+    int err;
+
+    err = dtoverlay_override_one_target(override_type,
+                                       dtb, node_off,
+                                       prop_name, target_phandle,
+                                       target_off, target_size,
+                                       (void *)state->override_value);
+
+    if ((err == 0) && (target_phandle != 0))
+    {
+       if (snprintf(prop_id, sizeof(prop_id), "%08x%s", target_phandle,
+                    prop_name) < 0)
+           err = FDT_ERR_INTERNAL;
+       else if (string_vec_find(state->used_props, prop_id, 0) < 0)
+           string_vec_add(state->used_props, prop_id, 0);
+    }
+
+    return err;
+}
+
+// Returns 0 on success, -ve for fatal errors and +ve for non-fatal errors
+int dtparam_apply(DTBLOB_T *dtb, const char *override_name,
+                 const char *override_data, int data_len,
+                 const char *override_value, STRING_VEC_T *used_props)
+{
+    struct dtparam_state state;
+    void *data;
+    int err;
+
+    state.used_props = used_props;
+    state.override_value = override_value;
+
+    /* Copy the override data in case it moves */
+    data = malloc(data_len);
+    if (data)
+    {
+       memcpy(data, override_data, data_len);
+       err = dtoverlay_foreach_override_target(dtb, override_name,
+                                               data, data_len,
+                                               dtparam_callback,
+                                               (void *)&state);
+       free(data);
+    }
+    else
+    {
+       dtoverlay_error("out of memory");
+       err = NON_FATAL(FDT_ERR_NOSPACE);
+    }
+
+    return err;
+}
+
+static int dtoverlay_add(STATE_T *state, const char *overlay,
+                        int argc, const char **argv)
+{
+    const char *overlay_name;
+    const char *overlay_file;
+    char *param_string = NULL;
+    int is_dtparam;
+    DTBLOB_T *base_dtb = NULL;
+    DTBLOB_T *overlay_dtb;
+    STRING_VEC_T used_props;
+    int err;
+    int len;
+    int i;
+
+    len = strlen(overlay) - 5;
+    is_dtparam = (strcmp(overlay, "dtparam") == 0);
+    if (is_dtparam)
+    {
+        /* Convert /proc/device-tree to a .dtb and load it */
+       overlay_file = sprintf_dup("%s/%s", work_dir, "base.dtb");
+       if (run_cmd("dtc -I fs -O dtb -o '%s' /proc/device-tree 1>/dev/null 2>&1",
+                   overlay_file) != 0)
+           return error("Failed to read active DTB");
+    }
+    else if ((len > 0) && (strcmp(overlay + len, ".dtbo") == 0))
+    {
+       const char *p;
+       overlay_file = overlay;
+       p = strrchr(overlay, '/');
+       if (p)
+       {
+           overlay = p + 1;
+           len = strlen(overlay) - 5;
+       }
+
+       overlay = sprintf_dup("%.*s", len, overlay);
+    }
+    else
+    {
+       overlay_file = sprintf_dup("%s/%s.dtbo", overlay_src_dir, overlay);
+    }
+
+    if (dry_run)
+        overlay_name = "dry_run";
+    else
+       overlay_name = sprintf_dup("%d_%s", state->count, overlay);
+    overlay_dtb = dtoverlay_load_dtb(overlay_file, DTOVERLAY_PADDING(4096));
+    if (!overlay_dtb)
+       return error("Failed to read '%s'", overlay_file);
+
+    if (is_dtparam)
+    {
+        base_dtb = overlay_dtb;
+       string_vec_init(&used_props);
+    }
+
+    /* Apply any parameters next */
+    for (i = 0; i < argc; i++)
+    {
+       const char *arg = argv[i];
+       const char *param_val = strchr(arg, '=');
+       const char *param, *override;
+       char *p = NULL;
+       int override_len;
+       if (param_val)
+       {
+           int len = (param_val - arg);
+           p = sprintf_dup("%.*s", len, arg);
+           param = p;
+           param_val++;
+       }
+       else
+       {
+           /* Use the default parameter value - true */
+           param = arg;
+           param_val = "true";
+       }
+
+       override = dtoverlay_find_override(overlay_dtb, param, &override_len);
+
+       if (!override)
+           return error("Unknown parameter '%s'", param);
+
+       if (is_dtparam)
+           err = dtparam_apply(overlay_dtb, param,
+                               override, override_len,
+                               param_val, &used_props);
+       else
+           err = dtoverlay_apply_override(overlay_dtb, param,
+                                          override, override_len,
+                                          param_val);
+       if (err != 0)
+           return error("Failed to set %s=%s", param, param_val);
+
+       param_string = sprintf_dup("%s %s=%s",
+                                  param_string ? param_string : "",
+                                  param, param_val);
+
+       free_string(p);
+    }
+
+    if (is_dtparam)
+    {
+        /* Build an overlay DTB */
+        overlay_dtb = dtoverlay_create_dtb(2048 + 256 * used_props.num_strings);
+
+        for (i = 0; i < used_props.num_strings; i++)
+        {
+            int phandle, node_off, prop_len;
+            const char *str, *prop_name;
+            const void *prop_data;
+
+            str = used_props.strings[i];
+            sscanf(str, "%8x", &phandle);
+            prop_name = str + 8;
+            node_off = dtoverlay_find_phandle(base_dtb, phandle);
+
+            prop_data = dtoverlay_get_property(base_dtb, node_off,
+                                               prop_name, &prop_len);
+            err = dtoverlay_create_prop_fragment(overlay_dtb, i, phandle,
+                                   prop_name, prop_data, prop_len);
+        }
+
+        dtoverlay_free_dtb(base_dtb);
+    }
+
+    if (param_string)
+       dtoverlay_dtb_set_trailer(overlay_dtb, param_string,
+                                 strlen(param_string) + 1);
+
+    /* Create a filename with the sequence number */
+    overlay_file = sprintf_dup("%s/%s.dtbo", work_dir, overlay_name);
+
+    /* then write the overlay to the file */
+    dtoverlay_pack_dtb(overlay_dtb);
+    dtoverlay_save_dtb(overlay_dtb, overlay_file);
+    dtoverlay_free_dtb(overlay_dtb);
+
+    if (!dry_run && !apply_overlay(overlay_file, overlay_name))
+    {
+       if (error_file)
+       {
+           rename(overlay_file, error_file);
+           free_string(error_file);
+       }
+       return 1;
+    }
+
+    return 0;
+}
+
+static int dtoverlay_remove(STATE_T *state, const char *overlay, int and_later)
+{
+    const char *overlay_dir;
+    const char *dir_name = NULL;
+    char *end;
+    int overlay_len;
+    int count = state->count;
+    int rmpos;
+    int i;
+
+    if (chdir(work_dir) != 0)
+       fatal_error("Failed to chdir to '%s'", work_dir);
+
+    if (overlay)
+    {
+       overlay_len = strlen(overlay);
+
+       rmpos = strtoul(overlay, &end, 10);
+       if (end && (*end == '\0'))
+       {
+           if (rmpos >= count)
+               return error("Overlay index (%d) too large", rmpos);
+           dir_name = state->namelist[rmpos]->d_name;
+       }
+       /* Locate the most recent reference to the overlay */
+       else for (rmpos = count - 1; rmpos >= 0; rmpos--)
+       {
+           const char *left, *right;
+           dir_name = state->namelist[rmpos]->d_name;
+           left = strchr(dir_name, '_');
+           if (!left)
+               return error("Internal error");
+           left++;
+           right = strchr(left, '.');
+           if (!right)
+               return error("Internal error");
+           if (((right - left) == overlay_len) &&
+               (memcmp(overlay, left, overlay_len) == 0))
+               break;
+           dir_name = NULL;
+       }
+
+       if (rmpos < 0)
+           return error("Overlay '%s' is not loaded", overlay);
+    }
+    else
+    {
+       if (!count)
+           return error("No overlays loaded");
+       rmpos = and_later ? 0 : (count - 1);
+       dir_name = state->namelist[rmpos]->d_name;
+    }
+
+    if (rmpos < count)
+    {
+       /* Unload it and all subsequent overlays in reverse order */
+       for (i = count - 1; i >= rmpos; i--)
+       {
+           const char *left, *right;
+           left = state->namelist[i]->d_name;
+           right = strrchr(left, '.');
+           if (!right)
+               return error("Internal error");
+
+           overlay_dir = sprintf_dup("%s/%.*s", dt_overlays_dir,
+                                     right - left, left);
+           if (rmdir(overlay_dir) != 0)
+               return error("Failed to remove directory '%s'", overlay_dir);
+
+           free_string(overlay_dir);
+       }
+
+       /* Replay the sequence, deleting files for the specified overlay,
+          and renumbering and reloading all other overlays. */
+       for (i = rmpos, state->count = rmpos; i < count; i++)
+       {
+           const char *left, *right;
+           const char *filename = state->namelist[i]->d_name;
+
+           left = strchr(filename, '_');
+           if (!left)
+               return error("Internal error");
+           left++;
+           right = strchr(left, '.');
+           if (!right)
+               return error("Internal error");
+
+            if (and_later || (i == rmpos))
+            {
+                /* This one is being deleted */
+                unlink(filename);
+            }
+            else
+            {
+                /* Keep this one - renumber and reload */
+                int len = right - left;
+                char *new_name = sprintf_dup("%d_%.*s", state->count,
+                                            len, left);
+               char *new_file = sprintf_dup("%s.dtbo", new_name);
+               int ret = 0;
+
+                if ((len == 7) && (memcmp(left, "dtparam", 7) == 0))
+               {
+                   /* Regenerate the overlay in case multiple overlays target
+                       different parts of the same property. */
+
+                   DTBLOB_T *dtb;
+                   char *params;
+                   const char **paramv;
+                   int paramc;
+                   int j;
+                   char *p;
+
+                    /* Extract the parameters */
+                   dtb = dtoverlay_load_dtb(filename, 0);
+                   unlink(filename);
+
+                   if (!dtb)
+                   {
+                       error("Failed to re-apply dtparam");
+                       continue;
+                   }
+
+                   params = (char *)dtoverlay_dtb_trailer(dtb);
+                   if (!params)
+                   {
+                       error("Failed to re-apply dtparam");
+                       dtoverlay_free_dtb(dtb);
+                       continue;
+                   }
+
+                   /* Count and NUL-separate the params */
+                   p = params;
+                   paramc = 0;
+                   while (*p)
+                   {
+                       int paramlen;
+                       *(p++) = '\0';
+                       paramlen = strcspn(p, " ");
+                       paramc++;
+                       p += paramlen;
+                   }
+
+                   paramv = malloc((paramc + 1) * sizeof(const char *));
+                   if (!paramv)
+                   {
+                       error("out of memory re-applying dtparam");
+                       dtoverlay_free_dtb(dtb);
+                       continue;
+                   }
+
+                   for (j = 0, p = params + 1; j < paramc; j++)
+                   {
+                       paramv[j] = p;
+                       p += strlen(p) + 1;
+                   }
+                   paramv[j] = NULL;
+
+                   /* Create the new overlay */
+                   ret = dtoverlay_add(state, "dtparam", paramc, paramv);
+                   free(paramv);
+                   dtoverlay_free_dtb(dtb);
+               }
+               else
+               {
+                   rename(filename, new_file);
+                   ret = !apply_overlay(new_file, new_name);
+               }
+               if (ret != 0)
+               {
+                   error("Failed to re-apply dtparam");
+                   continue;
+               }
+               state->count++;
+           }
+       }
+    }
+
+    return 0;
+}
+
+static int dtoverlay_list(STATE_T *state)
+{
+    if (state->count == 0)
+    {
+       printf("No overlays loaded\n");
+    }
+    else
+    {
+       int i;
+       printf("Overlays (in load order):\n");
+       for (i = 0; i < state->count; i++)
+       {
+           const char *name, *left, *right;
+           const char *saved_overlay;
+           DTBLOB_T *dtb;
+           name = state->namelist[i]->d_name;
+           left = strchr(name, '_');
+           if (!left)
+               return error("Internal error");
+           left++;
+           right = strchr(left, '.');
+           if (!right)
+               return error("Internal error");
+
+           saved_overlay = sprintf_dup("%s/%s", work_dir, name);
+           dtb = dtoverlay_load_dtb(saved_overlay, 0);
+
+           if (dtoverlay_dtb_trailer(dtb))
+               printf("%d:  %.*s %.*s\n", i, (int)(right - left), left,
+                      dtoverlay_dtb_trailer_len(dtb),
+                      (char *)dtoverlay_dtb_trailer(dtb));
+           else
+               printf("%d:  %.*s\n", i, (int)(right - left), left);
+
+           dtoverlay_free_dtb(dtb);
+       }
+    }
+
+    return 0;
+}
+
+static int dtoverlay_list_all(STATE_T *state)
+{
+    int i;
+    DIR *dh;
+    struct dirent *de;
+    STRING_VEC_T strings;
+
+    string_vec_init(&strings);
+
+    /* Enumerate .dtbo files in the /boot/overlays directory */
+    dh = opendir(overlay_src_dir);
+    while ((de = readdir(dh)) != NULL)
+    {
+       int len = strlen(de->d_name) - 5;
+       if ((len >= 0) && strcmp(de->d_name + len, ".dtbo") == 0)
+        {
+           char *str = string_vec_add(&strings, de->d_name, len + 2);
+            str[len] = '\0';
+            str[len + 1] = ' ';
+        }
+    }
+    closedir(dh);
+
+    /* Merge in active overlays, marking them */
+    for (i = 0; i < state->count; i++)
+    {
+       const char *left, *right;
+       char *str;
+       int len, idx;
+
+       left = strchr(state->namelist[i]->d_name, '_');
+       if (!left)
+           return error("Internal error");
+       left++;
+       right = strchr(left, '.');
+       if (!right)
+           return error("Internal error");
+
+        len = right - left;
+        if ((len == 7) && (memcmp(left, "dtparam", 7) == 0))
+            continue;
+       idx = string_vec_find(&strings, left, len);
+       if (idx >= 0)
+       {
+           str = strings.strings[idx];
+            len = strlen(str);
+       }
+       else
+        {
+           str = string_vec_add(&strings, left, len + 2);
+            str[len] = '\0';
+        }
+       str[len + 1] = '*';
+    }
+
+    if (strings.num_strings == 0)
+    {
+       printf("No overlays found\n");
+    }
+    else
+    {
+       /* Sort */
+       string_vec_sort(&strings);
+
+       /* Display */
+       printf("All overlays (* = loaded):\n");
+
+       for (i = 0; i < strings.num_strings; i++)
+       {
+            const char *str = strings.strings[i];
+           printf("%c %s\n", str[strlen(str)+1], str);
+       }
+    }
+
+    string_vec_uninit(&strings);
+
+    return 0;
+}
+
+static void usage(void)
+{
+    printf("Usage:\n");
+    if (strcmp(cmd_name, "dtparam") == 0)
+    {
+    printf("  %s                Display help on all parameters\n", cmd_name);
+    printf("  %s <param>=<val>...\n", cmd_name);
+    printf("  %*s                Add an overlay (with parameters)\n", (int)strlen(cmd_name), "");
+    printf("  %s -D [<idx>]     Dry-run (prepare overlay, but don't apply -\n",
+          cmd_name);
+    printf("  %*s                save it as dry-run.dtbo)\n", (int)strlen(cmd_name), "");
+    printf("  %s -r [<idx>]     Remove an overlay (by index, or the last)\n", cmd_name);
+    printf("  %s -R [<idx>]     Remove from an overlay (by index, or all)\n",
+          cmd_name);
+    printf("  %s -l             List active overlays/dtparams\n", cmd_name);
+    printf("  %s -a             List all overlays/dtparams (marking the active)\n", cmd_name);
+    printf("  %s -h             Show this usage message\n", cmd_name);
+    printf("  %s -h <param>...  Display help on the listed parameters\n", cmd_name);
+    }
+    else
+    {
+    printf("  %s <overlay> [<param>=<val>...]\n", cmd_name);
+    printf("  %*s                Add an overlay (with parameters)\n", (int)strlen(cmd_name), "");
+    printf("  %s -D [<idx>]     Dry-run (prepare overlay, but don't apply -\n",
+          cmd_name);
+    printf("  %*s                save it as dry-run.dtbo)\n", (int)strlen(cmd_name), "");
+    printf("  %s -r [<overlay>] Remove an overlay (by name, index or the last)\n", cmd_name);
+    printf("  %s -R [<overlay>] Remove from an overlay (by name, index or all)\n",
+          cmd_name);
+    printf("  %s -l             List active overlays/params\n", cmd_name);
+    printf("  %s -a             List all overlays (marking the active)\n", cmd_name);
+    printf("  %s -h             Show this usage message\n", cmd_name);
+    printf("  %s -h <overlay>   Display help on an overlay\n", cmd_name);
+    printf("  %s -h <overlay> <param>..  Or its parameters\n", cmd_name);
+    printf("    where <overlay> is the name of an overlay or 'dtparam' for dtparams\n");
+    }
+    printf("Options applicable to most variants:\n");
+    printf("    -d <dir>    Specify an alternate location for the overlays\n");
+    printf("                (defaults to /boot/overlays or /flash/overlays)\n");
+    printf("    -v          Verbose operation\n");
+    printf("\n");
+    printf("Adding or removing overlays and parameters requires root privileges.\n");
+
+    exit(1);
+}
+
+static void root_check(void)
+{
+    if (getuid() != 0)
+       fatal_error("Must be run as root - try 'sudo %s ...'", cmd_name);
+}
+
+static void overlay_help(const char *overlay, const char **params)
+{
+    OVERLAY_HELP_STATE_T *state;
+    const char *readme_path = sprintf_dup("%s/%s", overlay_src_dir,
+                                         README_FILE);
+
+    state = overlay_help_open(readme_path);
+    free_string(readme_path);
+
+    if (state)
+    {
+       if (strcmp(overlay, "dtparam") == 0)
+           overlay = "<The base DTB>";
+
+       if (overlay_help_find(state, overlay))
+       {
+           if (params && overlay_help_find_field(state, "Params"))
+           {
+               int in_param = 0;
+
+               while (1)
+               {
+                   const char *line = overlay_help_field_data(state);
+                   if (!line)
+                       break;
+                   if (line[0] == '\0')
+                       continue;
+                   if (line[0] != ' ')
+                   {
+                       /* This is a parameter name */
+                       int param_len = strcspn(line, " ");
+                       const char **p = params;
+                       in_param = 0;
+                       while (*p)
+                       {
+                           if ((param_len == strlen(*p)) &&
+                               (memcmp(line, *p, param_len) == 0))
+                           {
+                               in_param = 1;
+                               break;
+                           }
+                           p++;
+                       }
+                   }
+                   if (in_param)
+                       printf("%s\n", line);
+               }
+           }
+           else
+           {
+               printf("Name:   %s\n\n", overlay);
+               overlay_help_print_field(state, "Info", "Info:", 8, 0);
+               overlay_help_print_field(state, "Load", "Usage:", 8, 0);
+               overlay_help_print_field(state, "Params", "Params:", 8, 0);
+           }
+       }
+       else
+       {
+           fatal_error("No help found for overlay '%s'", overlay);
+       }
+       overlay_help_close(state);
+    }
+    else
+    {
+       fatal_error("Help file not found");
+    }
+}
+
+static int apply_overlay(const char *overlay_file, const char *overlay)
+{
+    const char *overlay_dir = sprintf_dup("%s/%s", dt_overlays_dir, overlay);
+    int ret = 0;
+    if (dir_exists(overlay_dir))
+    {
+       error("Overlay '%s' is already loaded", overlay);
+    }
+    else if (mkdir(overlay_dir, DIR_MODE) == 0)
+    {
+       DTBLOB_T *dtb = dtoverlay_load_dtb(overlay_file, 0);
+       if (!dtb)
+       {
+           error("Failed to apply overlay '%s' (load)", overlay);
+       }
+       else
+       {
+           const char *dest_file = sprintf_dup("%s/dtbo", overlay_dir);
+
+           /* then write the overlay to the file */
+           if (dtoverlay_save_dtb(dtb, dest_file) != 0)
+               error("Failed to apply overlay '%s' (save)", overlay);
+           else if (!overlay_applied(overlay_dir))
+               error("Failed to apply overlay '%s' (kernel)", overlay);
+           else
+               ret = 1;
+
+           free_string(dest_file);
+           dtoverlay_free_dtb(dtb);
+       }
+
+       if (!ret)
+               rmdir(overlay_dir);
+    }
+    else
+    {
+       error("Failed to create overlay directory");
+    }
+
+    return ret;
+}
+
+static int overlay_applied(const char *overlay_dir)
+{
+    char status[7] = { '\0' };
+    const char *status_path = sprintf_dup("%s/status", overlay_dir);
+    FILE *fp = fopen(status_path, "r");
+    int bytes = 0;
+    if (fp)
+    {
+       bytes = fread(status, 1, sizeof(status), fp);
+       fclose(fp);
+    }
+    free_string(status_path);
+    return (bytes == sizeof(status)) &&
+       (memcmp(status, "applied", sizeof(status)) == 0);
+}
+
+int seq_filter(const struct dirent *de)
+{
+    int num;
+    return (sscanf(de->d_name, "%d_", &num) == 1);
+}
+
+int seq_compare(const struct dirent **de1, const struct dirent **de2)
+{
+    int num1 = atoi((*de1)->d_name);
+    int num2 = atoi((*de2)->d_name);
+    if (num1 < num2)
+       return -1;
+    else if (num1 == num2)
+       return 0;
+    else
+       return 1;
+}
+
+static STATE_T *read_state(const char *dir)
+{
+    STATE_T *state = malloc(sizeof(STATE_T));
+    int i;
+
+    if (state)
+    {
+       state->count = scandir(dir, &state->namelist, seq_filter, seq_compare);
+
+       for (i = 0; i < state->count; i++)
+       {
+           int num = atoi(state->namelist[i]->d_name);
+           if (i != num)
+               error("Overlay sequence error");
+       }
+    }
+    return state;
+}
+
+static void free_state(STATE_T *state)
+{
+    int i;
+    for (i = 0; i < state->count; i++)
+    {
+       free(state->namelist[i]);
+    }
+    free(state->namelist);
+    free(state);
+}
diff --git a/host_applications/linux/apps/dtoverlay/utils.c b/host_applications/linux/apps/dtoverlay/utils.c
new file mode 100755 (executable)
index 0000000..511efd9
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+Copyright (c) 2016 Raspberry Pi (Trading) Ltd.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+#include "utils.h"
+
+#define OVERLAY_HELP_INDENT 8
+
+int opt_verbose;
+int opt_dry_run;
+static STRING_T *allocated_strings;
+
+struct overlay_help_state_struct
+{
+    FILE *fp;
+    long rec_pos;
+    int line_len;
+    int line_pos;
+    int blank_count;
+    int end_of_field;
+    char line_buf[82];
+};
+
+static int overlay_help_get_line(OVERLAY_HELP_STATE_T *state);
+
+OVERLAY_HELP_STATE_T *overlay_help_open(const char *helpfile)
+{
+    OVERLAY_HELP_STATE_T *state = NULL;
+    FILE *fp = fopen(helpfile, "r");
+    if (fp)
+    {
+        state = calloc(1, sizeof(OVERLAY_HELP_STATE_T));
+        if (!state)
+                fatal_error("Out of memory");
+        state->fp = fp;
+        state->line_pos = -1;
+        state->rec_pos = -1;
+    }
+
+    return state;
+}
+
+void overlay_help_close(OVERLAY_HELP_STATE_T *state)
+{
+    fclose(state->fp);
+    free(state);
+}
+
+int overlay_help_find(OVERLAY_HELP_STATE_T *state, const char *name)
+{
+    state->line_pos = -1;
+    state->rec_pos = -1;
+    state->blank_count = 0;
+
+    fseek(state->fp, 0, SEEK_SET);
+
+    while (overlay_help_find_field(state, "Name"))
+    {
+        const char *overlay = overlay_help_field_data(state);
+        if (overlay && (strcmp(overlay, name) == 0))
+        {
+            state->rec_pos = (long)ftell(state->fp);
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+int overlay_help_find_field(OVERLAY_HELP_STATE_T *state, const char *field)
+{
+    int field_len = strlen(field);
+    int found = 0;
+
+    if (state->rec_pos >= 0)
+        fseek(state->fp, state->rec_pos, SEEK_SET);
+
+    while (!found)
+    {
+        int line_len = overlay_help_get_line(state);
+        if (line_len < 0)
+            break;
+
+        /* Check for the "<field>:" prefix */
+        if ((line_len >= (field_len + 1)) &&
+            (state->line_buf[field_len] == ':') &&
+            (memcmp(state->line_buf, field, field_len) == 0))
+        {
+            /* Found it
+               If this initial line has no content then skip it */
+            if (line_len > OVERLAY_HELP_INDENT)
+                state->line_pos = OVERLAY_HELP_INDENT;
+            else
+                state->line_pos = -1;
+            state->end_of_field = 0;
+            found = 1;
+        }
+        else
+        {
+            state->line_pos = -1;
+        }
+    }
+
+    return found;
+}
+
+const char *overlay_help_field_data(OVERLAY_HELP_STATE_T *state)
+{
+    int line_len, pos;
+
+    if (state->end_of_field)
+        return NULL;
+
+    line_len = state->line_len;
+
+    if ((state->line_pos < 0) ||
+        (state->line_pos >= line_len))
+    {
+        line_len = overlay_help_get_line(state);
+
+        /* Fields end at the start of the next field or the end of the record */
+        if ((line_len < 0) || (state->line_buf[0] != ' '))
+        {
+            state->end_of_field = 1;
+            return NULL;
+        }
+
+        if (line_len == 0)
+            return "";
+    }
+
+    /* Return field data starting at OVERLAY_HELP_INDENT, if there is any */
+    pos = line_len;
+    if (pos > OVERLAY_HELP_INDENT)
+        pos = OVERLAY_HELP_INDENT;
+
+    state->line_pos = -1;
+    return &state->line_buf[pos];
+}
+
+void overlay_help_print_field(OVERLAY_HELP_STATE_T *state,
+                              const char *field, const char *label,
+                              int indent, int strip_blanks)
+{
+    if (!overlay_help_find_field(state, field))
+        return;
+
+    while (1)
+    {
+       const char *line = overlay_help_field_data(state);
+       if (!line)
+           break;
+
+       if (label)
+       {
+           int spaces = indent - strlen(label);
+           if (spaces < 0)
+               spaces = 0;
+
+           printf("%s%*s%s\n", label, spaces, "", line);
+           label = NULL;
+       }
+       else if (line[0])
+       {
+           printf("%*s%s\n", indent, "", line);
+       }
+       else if (!strip_blanks)
+       {
+           printf("\n");
+       }
+    }
+
+    if (!strip_blanks)
+       printf("\n");
+}
+
+/* Returns the length of the line, or -1 on end of file or record */
+static int overlay_help_get_line(OVERLAY_HELP_STATE_T *state)
+{
+    int line_len;
+
+    if (state->line_pos >= 0)
+       return state->line_len;
+
+get_next_line:
+    state->line_buf[sizeof(state->line_buf) - 1] = ' ';
+    line_len = -1;
+    if (fgets(state->line_buf, sizeof(state->line_buf), state->fp))
+    {
+       // Check for overflow
+
+       // Strip the newline
+       line_len = strlen(state->line_buf);
+       if (line_len && (state->line_buf[line_len - 1] == '\n'))
+       {
+           line_len--;
+           state->line_buf[line_len] = '\0';
+       }
+    }
+
+    if (state->rec_pos >= 0)
+    {
+       if (line_len == 0)
+       {
+           state->blank_count++;
+           if (state->blank_count >= 2)
+               return -1;
+           state->line_pos = 0;
+           goto get_next_line;
+       }
+       else if (state->blank_count)
+       {
+           /* Return a single blank line now - the non-empty line will be
+              returned next time */
+           state->blank_count = 0;
+           return 0;
+       }
+    }
+
+    state->line_len = line_len;
+    state->line_pos = (line_len >= 0) ? 0 : -1;
+    return line_len;
+}
+
+int run_cmd(const char *fmt, ...)
+{
+    va_list ap;
+    char *cmd;
+    int ret;
+    va_start(ap, fmt);
+    cmd = vsprintf_dup(fmt, ap);
+    va_end(ap);
+
+    if (opt_dry_run || opt_verbose)
+       fprintf(stderr, "run_cmd: %s\n", cmd);
+
+    ret = opt_dry_run ? 0 : system(cmd);
+
+    free_string(cmd);
+
+    return ret;
+}
+
+
+/* Not thread safe */
+void free_string(const char *string)
+{
+    STRING_T *str;
+
+    if (!string)
+       return;
+
+    str = (STRING_T *)(string - sizeof(STRING_T));
+    if (str == allocated_strings)
+    {
+       allocated_strings = str->next;
+       if (allocated_strings == str)
+           allocated_strings = NULL;
+    }
+    str->prev->next = str->next;
+    str->next->prev = str->prev;
+    free(str);
+}
+
+/* Not thread safe */
+void free_strings(void)
+{
+    if (allocated_strings)
+    {
+       STRING_T *str = allocated_strings;
+       do
+       {
+           STRING_T *t = str;
+           str = t->next;
+           free(t);
+       } while (str != allocated_strings);
+       allocated_strings = NULL;
+    }
+}
+
+/* Not thread safe */
+char *sprintf_dup(const char *fmt, ...)
+{
+    va_list ap;
+    char *str;
+    va_start(ap, fmt);
+    str = vsprintf_dup(fmt, ap);
+    va_end(ap);
+    return str;
+}
+
+/* Not thread safe */
+char *vsprintf_dup(const char *fmt, va_list ap)
+{
+    char scratch[512];
+    int len;
+    STRING_T *str;
+    len = vsnprintf(scratch, sizeof(scratch), fmt, ap) + 1;
+
+    if (len > sizeof(scratch))
+       fatal_error("Maximum string length exceeded");
+
+    str = malloc(sizeof(STRING_T) + len);
+    if (!str)
+       fatal_error("Out of memory");
+
+    memcpy(str->data, scratch, len);
+    if (allocated_strings)
+    {
+       str->next = allocated_strings;
+       str->prev = allocated_strings->prev;
+       str->next->prev = str;
+       str->prev->next = str;
+    }
+    else
+    {
+       str->next = str;
+       str->prev = str;
+       allocated_strings = str;
+    }
+
+    return str->data;
+}
+
+int dir_exists(const char *dirname)
+{
+    struct stat finfo;
+    return (stat(dirname, &finfo) == 0) && S_ISDIR(finfo.st_mode);
+}
+
+int file_exists(const char *dirname)
+{
+    struct stat finfo;
+    return (stat(dirname, &finfo) == 0) && S_ISREG(finfo.st_mode);
+}
+
+void string_vec_init(STRING_VEC_T *vec)
+{
+    vec->num_strings = 0;
+    vec->max_strings = 0;
+    vec->strings = NULL;
+}
+
+char *string_vec_add(STRING_VEC_T *vec, const char *str, int len)
+{
+    char *copy;
+    if (vec->num_strings == vec->max_strings)
+    {
+       if (vec->max_strings)
+           vec->max_strings *= 2;
+       else
+           vec->max_strings = 16;
+       vec->strings = realloc(vec->strings, vec->max_strings * sizeof(const char *));
+       if (!vec->strings)
+           fatal_error("Out of memory");
+    }
+
+    if (len)
+    {
+       copy = malloc(len + 1);
+       strncpy(copy, str, len);
+       copy[len] = '\0';
+    }
+    else
+       copy = strdup(str);
+
+    if (!copy)
+       fatal_error("Out of memory");
+
+    vec->strings[vec->num_strings++] = copy;
+
+    return copy;
+}
+
+int string_vec_find(STRING_VEC_T *vec, const char *str, int len)
+{
+    int i;
+
+    for (i = 0; i < vec->num_strings; i++)
+    {
+       if (len)
+       {
+           if ((strncmp(vec->strings[i], str, len) == 0) &&
+               (vec->strings[i][len] == '\0'))
+               return i;
+       }
+       else if (strcmp(vec->strings[i], str) == 0)
+           return i;
+    }
+
+    return -1;
+}
+
+int string_vec_compare(const void *a, const void *b)
+{
+    return strcmp(*(const char **)a, *(const char **)b);
+}
+
+void string_vec_sort(STRING_VEC_T *vec)
+{
+    qsort(vec->strings, vec->num_strings, sizeof(char *), &string_vec_compare);
+}
+
+void string_vec_uninit(STRING_VEC_T *vec)
+{
+    int i;
+    for (i = 0; i < vec->num_strings; i++)
+       free(vec->strings[i]);
+    free(vec->strings);
+}
+
+int error(const char *fmt, ...)
+{
+    va_list ap;
+    fprintf(stderr, "* ");
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+    fprintf(stderr, "\n");
+    return 1;
+}
+
+void fatal_error(const char *fmt, ...)
+{
+    va_list ap;
+    fprintf(stderr, "* ");
+    va_start(ap, fmt);
+    vfprintf(stderr, fmt, ap);
+    va_end(ap);
+    fprintf(stderr, "\n");
+    exit(1);
+}
diff --git a/host_applications/linux/apps/dtoverlay/utils.h b/host_applications/linux/apps/dtoverlay/utils.h
new file mode 100755 (executable)
index 0000000..3d3b59f
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+Copyright (c) 2016 Raspberry Pi (Trading) Ltd.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef UTILS_H
+#define UTILS_H
+
+typedef struct string_struct
+{
+    struct string_struct *prev;
+    struct string_struct *next;
+    char data[0];
+} STRING_T;
+
+typedef struct string_vec_struct
+{
+    int num_strings;
+    int max_strings;
+    char **strings;
+} STRING_VEC_T;
+
+typedef struct overlay_help_state_struct OVERLAY_HELP_STATE_T;
+
+extern int opt_verbose;
+extern int opt_dry_run;
+
+OVERLAY_HELP_STATE_T *overlay_help_open(const char *helpfile);
+void overlay_help_close(OVERLAY_HELP_STATE_T *state);
+int overlay_help_find(OVERLAY_HELP_STATE_T *state, const char *name);
+int overlay_help_find_field(OVERLAY_HELP_STATE_T *state, const char *field);
+const char *overlay_help_field_data(OVERLAY_HELP_STATE_T *state);
+void overlay_help_print_field(OVERLAY_HELP_STATE_T *state,
+                             const char *field, const char *label,
+                             int indent, int strip_blanks);
+
+int run_cmd(const char *fmt, ...);
+void free_string(const char *string); /* Not thread safe */
+void free_strings(void); /* Not thread safe */
+char *sprintf_dup(const char *fmt, ...); /* Not thread safe */
+char *vsprintf_dup(const char *fmt, va_list ap); /* Not thread safe */
+int dir_exists(const char *dirname);
+int file_exists(const char *dirname);
+void string_vec_init(STRING_VEC_T *vec);
+char *string_vec_add(STRING_VEC_T *vec, const char *str, int len);
+int string_vec_find(STRING_VEC_T *vec, const char *str, int len);
+void string_vec_sort(STRING_VEC_T *vec);
+void string_vec_uninit(STRING_VEC_T *vec);
+int error(const char *fmt, ...);
+void fatal_error(const char *fmt, ...);
+
+#endif
diff --git a/host_applications/linux/apps/gencmd/CMakeLists.txt b/host_applications/linux/apps/gencmd/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..f95d1a1
--- /dev/null
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 2.8)
+
+if (WIN32)
+   set(VCOS_PLATFORM win32)
+else ()
+   set(VCOS_PLATFORM pthreads)
+   add_definitions(-Wall -Werror)
+endif ()
+
+include_directories( ../../../.. 
+                     ../../../../interface/vcos
+                     ../../../../interface/vcos/${VCOS_PLATFORM} )
+
+#add_subdirectory( ../../../../interface/vcos/${VCOS_PLATFORM} vcos)
+#add_subdirectory( ../../bin/gencmd)
+
+add_executable(vcgencmd gencmd.c)
+target_link_libraries(vcgencmd vcos vchiq_arm vchostif)
+install(TARGETS vcgencmd RUNTIME DESTINATION bin)
+
diff --git a/host_applications/linux/apps/gencmd/gencmd.c b/host_applications/linux/apps/gencmd/gencmd.c
new file mode 100755 (executable)
index 0000000..9b48cf9
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+/* ---- Include Files ---------------------------------------------------- */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+
+#include "interface/vmcs_host/vc_vchi_gencmd.h"
+
+int main( int argc, char **argv )
+{
+   int instNum = 0;
+   VCHI_INSTANCE_T vchi_instance;
+   VCHI_CONNECTION_T *vchi_connection = NULL;
+
+   if ( argc > 1 )
+   {
+       if (( strcmp( argv[1], "0" ) == 0 ) || ( strcmp( argv[1], "1" ) == 0 ))
+       {
+           instNum = atoi( argv[1] );
+           argv++;
+           argc--;
+       }
+   }
+
+   vcos_init();
+
+    if ( vchi_initialise( &vchi_instance ) != 0)
+    {
+        printf( "VCHI initialization failed\n" );
+        return -1;
+    }
+
+    //create a vchi connection
+    if ( vchi_connect( NULL, 0, vchi_instance ) != 0)
+    {
+        printf( "VCHI connection failed\n" );
+        return -1;
+    }
+
+    vc_vchi_gencmd_init(vchi_instance, &vchi_connection, 1 );
+
+    if (argc > 1)
+    {
+      int i = 1;
+      char buffer[ 1024 ];
+      size_t buffer_offset = 0;
+      clock_t before=0, after=0;
+      double time_diff;
+      uint32_t show_time = 0;
+      int ret;
+
+      //reset the string
+      buffer[0] = '\0';
+
+      //first, strip out a potential leading -t
+      if( strcmp( argv[1], "-t" ) == 0 )
+      {
+         show_time = 1;
+         i++;
+      }
+
+      for (; i <= argc-1; i++)
+      {
+         buffer_offset = vcos_safe_strcpy( buffer, argv[i], sizeof(buffer), buffer_offset );
+         buffer_offset = vcos_safe_strcpy( buffer, " ", sizeof(buffer), buffer_offset );
+      }
+
+      if( show_time )
+         before = clock();
+
+      //send the gencmd for the argument
+      if (( ret = vc_gencmd_send( "%s", buffer )) != 0 )
+      {
+          printf( "vc_gencmd_send returned %d\n", ret );
+      }
+
+      //get + print out the response!
+      if (( ret = vc_gencmd_read_response( buffer, sizeof( buffer ) )) != 0 )
+      {
+          printf( "vc_gencmd_read_response returned %d\n", ret );
+      }
+
+      if( show_time )
+         after = clock();
+
+      if( show_time )
+      {
+         time_diff = ((double) (after - before)) / CLOCKS_PER_SEC;
+
+         printf( "Time took %f seconds (%f msecs) (%f usecs)\n", time_diff, time_diff * 1000, time_diff * 1000000 );
+      }
+
+      if ( buffer[0] != '\0' )
+      {
+          if ( buffer[ strlen( buffer) - 1] == '\n' )
+          {
+              fputs( buffer, stdout );
+          }
+          else
+          {
+              printf("%s\n", buffer );
+          }
+      }
+    }
+
+    vc_gencmd_stop();
+
+    //close the vchi connection
+    if ( vchi_disconnect( vchi_instance ) != 0)
+    {
+        printf( "VCHI disconnect failed\n" );
+        return -1;
+    }
+
+   return 0;
+}
+
diff --git a/host_applications/linux/apps/hello_pi/CMakeLists.txt b/host_applications/linux/apps/hello_pi/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..21b29f3
--- /dev/null
@@ -0,0 +1,31 @@
+set(BUILD_FONT FALSE)
+
+include_directories(${PROJECT_SOURCE_DIR})
+include_directories(${PROJECT_SOURCE_DIR}/host_applications/linux/libs/bcm_host/include)
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/libs/ilclient)
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/libs/vgfont)
+
+set(ILCLIENT_SRCS libs/ilclient/ilclient.c libs/ilclient/ilcore.c)
+add_library(ilclient ${ILCLIENT_SRCS})
+
+set(HELLO_PI_LIBS ilclient openmaxil bcm_host vcos vchiq_arm)
+
+add_subdirectory(hello_world)
+add_subdirectory(hello_video)
+add_subdirectory(hello_audio)
+#add_subdirectory(hello_triangle)
+#add_subdirectory(hello_triangle2)
+#add_subdirectory(hello_dispmanx)
+#add_subdirectory(hello_tiger)
+#add_subdirectory(hello_encode)
+#add_subdirectory(hello_jpeg)
+#add_subdirectory(hello_videocube)
+#add_subdirectory(hello_teapot)
+
+if(BUILD_FONT)
+set(VGFONT_SRCS libs/vgfont/font.c libs/vgfont/vgft.c libs/vgfont/graphics.c)
+set_source_files_properties(${VGFONT_SRCS} PROPERTIES COMPILE_DEFINITIONS)
+add_library(vgfont ${VGFONT_SRCS})
+
+add_subdirectory(hello_font)
+endif(BUILD_FONT)
diff --git a/host_applications/linux/apps/hello_pi/Makefile.include b/host_applications/linux/apps/hello_pi/Makefile.include
new file mode 100755 (executable)
index 0000000..fecf555
--- /dev/null
@@ -0,0 +1,28 @@
+
+CFLAGS+=-DSTANDALONE -D__STDC_CONSTANT_MACROS -D__STDC_LIMIT_MACROS -DTARGET_POSIX -D_LINUX -fPIC -DPIC -D_REENTRANT -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -U_FORTIFY_SOURCE -Wall -g -DHAVE_LIBOPENMAX=2 -DOMX -DOMX_SKIP64BIT -ftree-vectorize -pipe -DUSE_EXTERNAL_OMX -DHAVE_LIBBCM_HOST -DUSE_EXTERNAL_LIBBCM_HOST -DUSE_VCHIQ_ARM -Wno-psabi
+
+LDFLAGS+=-L$(SDKSTAGE)/opt/vc/lib/ -lbrcmGLESv2 -lbrcmEGL -lopenmaxil -lbcm_host -lvcos -lvchiq_arm -lpthread -lrt -lm -L$(SDKSTAGE)/opt/vc/src/hello_pi/libs/ilclient -L$(SDKSTAGE)/opt/vc/src/hello_pi/libs/vgfont
+
+INCLUDES+=-I$(SDKSTAGE)/opt/vc/include/ -I$(SDKSTAGE)/opt/vc/include/interface/vcos/pthreads -I$(SDKSTAGE)/opt/vc/include/interface/vmcs_host/linux -I./ -I$(SDKSTAGE)/opt/vc/src/hello_pi/libs/ilclient -I$(SDKSTAGE)/opt/vc/src/hello_pi/libs/vgfont
+
+all: $(BIN) $(LIB)
+
+%.o: %.c
+       @rm -f $@ 
+       $(CC) $(CFLAGS) $(INCLUDES) -g -c $< -o $@ -Wno-deprecated-declarations
+
+%.o: %.cpp
+       @rm -f $@ 
+       $(CXX) $(CFLAGS) $(INCLUDES) -g -c $< -o $@ -Wno-deprecated-declarations
+
+%.bin: $(OBJS)
+       $(CC) -o $@ -Wl,--whole-archive $(OBJS) $(LDFLAGS) -Wl,--no-whole-archive -rdynamic
+
+%.a: $(OBJS)
+       $(AR) r $@ $^
+
+clean:
+       for i in $(OBJS); do (if test -e "$$i"; then ( rm $$i ); fi ); done
+       @rm -f $(BIN) $(LIB)
+
+
diff --git a/host_applications/linux/apps/hello_pi/README b/host_applications/linux/apps/hello_pi/README
new file mode 100755 (executable)
index 0000000..7a91127
--- /dev/null
@@ -0,0 +1,21 @@
+Building on Pi
+++++++++++++++
+
+To build the test apps on the pi, first build the libs:
+make -C libs/ilclient
+make -C libs/vgfont
+
+then by entering each test app directory and run make. E.g.
+  cd hello_world
+  make
+  ./hello_world.bin
+
+Running ./rebuild.sh will rebuild the all libs and and apps.
+
+
+Building on a different PC
+++++++++++++++++++++++++++
+
+If you want to build the samples on a different machine (cross-compile) then set:
+SDKSTAGE=<path/to/firmware-directory> and CC=<path/to/cross-compiler>
+before running make.
diff --git a/host_applications/linux/apps/hello_pi/hello_audio/CMakeLists.txt b/host_applications/linux/apps/hello_pi/hello_audio/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..03207c5
--- /dev/null
@@ -0,0 +1,8 @@
+set(EXEC hello_audio.bin)
+set(SRCS audio.c sinewave.c)
+
+add_executable(${EXEC} ${SRCS})
+target_link_libraries(${EXEC} ${HELLO_PI_LIBS})
+
+install(TARGETS ${EXEC}
+        RUNTIME DESTINATION bin)
diff --git a/host_applications/linux/apps/hello_pi/hello_audio/Makefile b/host_applications/linux/apps/hello_pi/hello_audio/Makefile
new file mode 100755 (executable)
index 0000000..3c3c139
--- /dev/null
@@ -0,0 +1,6 @@
+OBJS=audio.o sinewave.o
+BIN=hello_audio.bin
+LDFLAGS+=-lilclient
+
+include ../Makefile.include
+
diff --git a/host_applications/linux/apps/hello_pi/hello_audio/audio.c b/host_applications/linux/apps/hello_pi/hello_audio/audio.c
new file mode 100755 (executable)
index 0000000..ebbcbce
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Audio output demo using OpenMAX IL though the ilcient helper library
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <unistd.h>
+#include <semaphore.h>
+
+#include "bcm_host.h"
+#include "ilclient.h"
+
+#define N_WAVE          1024    /* dimension of Sinewave[] */
+#define PI (1<<16>>1)
+#define SIN(x) Sinewave[((x)>>6) & (N_WAVE-1)]
+#define COS(x) SIN((x)+(PI>>1))
+#define OUT_CHANNELS(num_channels) ((num_channels) > 4 ? 8: (num_channels) > 2 ? 4: (num_channels))
+extern short Sinewave[];
+
+#ifndef countof
+   #define countof(arr) (sizeof(arr) / sizeof(arr[0]))
+#endif
+
+#define BUFFER_SIZE_SAMPLES 1024
+
+typedef int int32_t;
+
+typedef struct {
+   sem_t sema;
+   ILCLIENT_T *client;
+   COMPONENT_T *audio_render;
+   COMPONENT_T *list[2];
+   OMX_BUFFERHEADERTYPE *user_buffer_list; // buffers owned by the client
+   uint32_t num_buffers;
+   uint32_t bytes_per_sample;
+} AUDIOPLAY_STATE_T;
+
+static void input_buffer_callback(void *data, COMPONENT_T *comp)
+{
+   // do nothing - could add a callback to the user
+   // to indicate more buffers may be available.
+}
+
+int32_t audioplay_create(AUDIOPLAY_STATE_T **handle,
+                         uint32_t sample_rate,
+                         uint32_t num_channels,
+                         uint32_t bit_depth,
+                         uint32_t num_buffers,
+                         uint32_t buffer_size)
+{
+   uint32_t bytes_per_sample = (bit_depth * OUT_CHANNELS(num_channels)) >> 3;
+   int32_t ret = -1;
+
+   *handle = NULL;
+
+   // basic sanity check on arguments
+   if(sample_rate >= 8000 && sample_rate <= 192000 &&
+      (num_channels >= 1 && num_channels <= 8) &&
+      (bit_depth == 16 || bit_depth == 32) &&
+      num_buffers > 0 &&
+      buffer_size >= bytes_per_sample)
+   {
+      // buffer lengths must be 16 byte aligned for VCHI
+      int size = (buffer_size + 15) & ~15;
+      AUDIOPLAY_STATE_T *st;
+
+      // buffer offsets must also be 16 byte aligned for VCHI
+      st = calloc(1, sizeof(AUDIOPLAY_STATE_T));
+
+      if(st)
+      {
+         OMX_ERRORTYPE error;
+         OMX_PARAM_PORTDEFINITIONTYPE param;
+         OMX_AUDIO_PARAM_PCMMODETYPE pcm;
+         int32_t s;
+
+         ret = 0;
+         *handle = st;
+
+         // create and start up everything
+         s = sem_init(&st->sema, 0, 1);
+         assert(s == 0);
+
+         st->bytes_per_sample = bytes_per_sample;
+         st->num_buffers = num_buffers;
+
+         st->client = ilclient_init();
+         assert(st->client != NULL);
+
+         ilclient_set_empty_buffer_done_callback(st->client, input_buffer_callback, st);
+
+         error = OMX_Init();
+         assert(error == OMX_ErrorNone);
+
+         ilclient_create_component(st->client, &st->audio_render, "audio_render", ILCLIENT_ENABLE_INPUT_BUFFERS | ILCLIENT_DISABLE_ALL_PORTS);
+         assert(st->audio_render != NULL);
+
+         st->list[0] = st->audio_render;
+
+         // set up the number/size of buffers
+         memset(&param, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+         param.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
+         param.nVersion.nVersion = OMX_VERSION;
+         param.nPortIndex = 100;
+
+         error = OMX_GetParameter(ILC_GET_HANDLE(st->audio_render), OMX_IndexParamPortDefinition, &param);
+         assert(error == OMX_ErrorNone);
+
+         param.nBufferSize = size;
+         param.nBufferCountActual = num_buffers;
+
+         error = OMX_SetParameter(ILC_GET_HANDLE(st->audio_render), OMX_IndexParamPortDefinition, &param);
+         assert(error == OMX_ErrorNone);
+
+         // set the pcm parameters
+         memset(&pcm, 0, sizeof(OMX_AUDIO_PARAM_PCMMODETYPE));
+         pcm.nSize = sizeof(OMX_AUDIO_PARAM_PCMMODETYPE);
+         pcm.nVersion.nVersion = OMX_VERSION;
+         pcm.nPortIndex = 100;
+         pcm.nChannels = OUT_CHANNELS(num_channels);
+         pcm.eNumData = OMX_NumericalDataSigned;
+         pcm.eEndian = OMX_EndianLittle;
+         pcm.nSamplingRate = sample_rate;
+         pcm.bInterleaved = OMX_TRUE;
+         pcm.nBitPerSample = bit_depth;
+         pcm.ePCMMode = OMX_AUDIO_PCMModeLinear;
+
+         switch(num_channels) {
+         case 1:
+            pcm.eChannelMapping[0] = OMX_AUDIO_ChannelCF;
+            break;
+         case 3:
+            pcm.eChannelMapping[2] = OMX_AUDIO_ChannelCF;
+            pcm.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+            pcm.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+            break;
+         case 8:
+            pcm.eChannelMapping[7] = OMX_AUDIO_ChannelRS;
+         case 7:
+            pcm.eChannelMapping[6] = OMX_AUDIO_ChannelLS;
+         case 6:
+            pcm.eChannelMapping[5] = OMX_AUDIO_ChannelRR;
+         case 5:
+            pcm.eChannelMapping[4] = OMX_AUDIO_ChannelLR;
+         case 4:
+            pcm.eChannelMapping[3] = OMX_AUDIO_ChannelLFE;
+            pcm.eChannelMapping[2] = OMX_AUDIO_ChannelCF;
+         case 2:
+            pcm.eChannelMapping[1] = OMX_AUDIO_ChannelRF;
+            pcm.eChannelMapping[0] = OMX_AUDIO_ChannelLF;
+            break;
+         }
+
+         error = OMX_SetParameter(ILC_GET_HANDLE(st->audio_render), OMX_IndexParamAudioPcm, &pcm);
+         assert(error == OMX_ErrorNone);
+
+         ilclient_change_component_state(st->audio_render, OMX_StateIdle);
+         if(ilclient_enable_port_buffers(st->audio_render, 100, NULL, NULL, NULL) < 0)
+         {
+            // error
+            ilclient_change_component_state(st->audio_render, OMX_StateLoaded);
+            ilclient_cleanup_components(st->list);
+
+            error = OMX_Deinit();
+            assert(error == OMX_ErrorNone);
+
+            ilclient_destroy(st->client);
+
+            sem_destroy(&st->sema);
+            free(st);
+            *handle = NULL;
+            return -1;
+         }
+
+         ilclient_change_component_state(st->audio_render, OMX_StateExecuting);
+      }
+   }
+
+   return ret;
+}
+
+int32_t audioplay_delete(AUDIOPLAY_STATE_T *st)
+{
+   OMX_ERRORTYPE error;
+
+   ilclient_change_component_state(st->audio_render, OMX_StateIdle);
+
+   error = OMX_SendCommand(ILC_GET_HANDLE(st->audio_render), OMX_CommandStateSet, OMX_StateLoaded, NULL);
+   assert(error == OMX_ErrorNone);
+
+   ilclient_disable_port_buffers(st->audio_render, 100, st->user_buffer_list, NULL, NULL);
+   ilclient_change_component_state(st->audio_render, OMX_StateLoaded);
+   ilclient_cleanup_components(st->list);
+
+   error = OMX_Deinit();
+   assert(error == OMX_ErrorNone);
+
+   ilclient_destroy(st->client);
+
+   sem_destroy(&st->sema);
+   free(st);
+
+   return 0;
+}
+
+uint8_t *audioplay_get_buffer(AUDIOPLAY_STATE_T *st)
+{
+   OMX_BUFFERHEADERTYPE *hdr = NULL;
+
+   hdr = ilclient_get_input_buffer(st->audio_render, 100, 0);
+
+   if(hdr)
+   {
+      // put on the user list
+      sem_wait(&st->sema);
+
+      hdr->pAppPrivate = st->user_buffer_list;
+      st->user_buffer_list = hdr;
+
+      sem_post(&st->sema);
+   }
+
+   return hdr ? hdr->pBuffer : NULL;
+}
+
+int32_t audioplay_play_buffer(AUDIOPLAY_STATE_T *st,
+                              uint8_t *buffer,
+                              uint32_t length)
+{
+   OMX_BUFFERHEADERTYPE *hdr = NULL, *prev = NULL;
+   int32_t ret = -1;
+
+   if(length % st->bytes_per_sample)
+      return ret;
+
+   sem_wait(&st->sema);
+
+   // search through user list for the right buffer header
+   hdr = st->user_buffer_list;
+   while(hdr != NULL && hdr->pBuffer != buffer && hdr->nAllocLen < length)
+   {
+      prev = hdr;
+      hdr = hdr->pAppPrivate;
+   }
+
+   if(hdr) // we found it, remove from list
+   {
+      ret = 0;
+      if(prev)
+         prev->pAppPrivate = hdr->pAppPrivate;
+      else
+         st->user_buffer_list = hdr->pAppPrivate;
+   }
+
+   sem_post(&st->sema);
+
+   if(hdr)
+   {
+      OMX_ERRORTYPE error;
+
+      hdr->pAppPrivate = NULL;
+      hdr->nOffset = 0;
+      hdr->nFilledLen = length;
+
+      error = OMX_EmptyThisBuffer(ILC_GET_HANDLE(st->audio_render), hdr);
+      assert(error == OMX_ErrorNone);
+   }
+
+   return ret;
+}
+
+int32_t audioplay_set_dest(AUDIOPLAY_STATE_T *st, const char *name)
+{
+   int32_t success = -1;
+   OMX_CONFIG_BRCMAUDIODESTINATIONTYPE ar_dest;
+
+   if (name && strlen(name) < sizeof(ar_dest.sName))
+   {
+      OMX_ERRORTYPE error;
+      memset(&ar_dest, 0, sizeof(ar_dest));
+      ar_dest.nSize = sizeof(OMX_CONFIG_BRCMAUDIODESTINATIONTYPE);
+      ar_dest.nVersion.nVersion = OMX_VERSION;
+      strcpy((char *)ar_dest.sName, name);
+
+      error = OMX_SetConfig(ILC_GET_HANDLE(st->audio_render), OMX_IndexConfigBrcmAudioDestination, &ar_dest);
+      assert(error == OMX_ErrorNone);
+      success = 0;
+   }
+
+   return success;
+}
+
+
+uint32_t audioplay_get_latency(AUDIOPLAY_STATE_T *st)
+{
+   OMX_PARAM_U32TYPE param;
+   OMX_ERRORTYPE error;
+
+   memset(&param, 0, sizeof(OMX_PARAM_U32TYPE));
+   param.nSize = sizeof(OMX_PARAM_U32TYPE);
+   param.nVersion.nVersion = OMX_VERSION;
+   param.nPortIndex = 100;
+
+   error = OMX_GetConfig(ILC_GET_HANDLE(st->audio_render), OMX_IndexConfigAudioRenderingLatency, &param);
+   assert(error == OMX_ErrorNone);
+
+   return param.nU32;
+}
+
+#define CTTW_SLEEP_TIME 10
+#define MIN_LATENCY_TIME 20
+
+static const char *audio_dest[] = {"local", "hdmi"};
+void play_api_test(int samplerate, int bitdepth, int nchannels, int dest)
+{
+   AUDIOPLAY_STATE_T *st;
+   int32_t ret;
+   unsigned int i, j, n;
+   int phase = 0;
+   int inc = 256<<16;
+   int dinc = 0;
+   int buffer_size = (BUFFER_SIZE_SAMPLES * bitdepth * OUT_CHANNELS(nchannels))>>3;
+
+   assert(dest == 0 || dest == 1);
+
+   ret = audioplay_create(&st, samplerate, nchannels, bitdepth, 10, buffer_size);
+   assert(ret == 0);
+
+   ret = audioplay_set_dest(st, audio_dest[dest]);
+   assert(ret == 0);
+
+   // iterate for 5 seconds worth of packets
+   for (n=0; n<((samplerate * 1000)/ BUFFER_SIZE_SAMPLES); n++)
+   {
+      uint8_t *buf;
+      int16_t *p;
+      uint32_t latency;
+
+      while((buf = audioplay_get_buffer(st)) == NULL)
+         usleep(10*1000);
+
+      p = (int16_t *) buf;
+
+      // fill the buffer
+      for (i=0; i<BUFFER_SIZE_SAMPLES; i++)
+      {
+         int16_t val = SIN(phase);
+         phase += inc>>16;
+         inc += dinc;
+         if (inc>>16 < 512)
+            dinc++;
+         else
+            dinc--;
+
+         for(j=0; j<OUT_CHANNELS(nchannels); j++)
+         {
+            if (bitdepth == 32)
+               *p++ = 0;
+            *p++ = val;
+         }
+      }
+
+      // try and wait for a minimum latency time (in ms) before
+      // sending the next packet
+      while((latency = audioplay_get_latency(st)) > (samplerate * (MIN_LATENCY_TIME + CTTW_SLEEP_TIME) / 1000))
+         usleep(CTTW_SLEEP_TIME*1000);
+
+      ret = audioplay_play_buffer(st, buf, buffer_size);
+      assert(ret == 0);
+   }
+
+   audioplay_delete(st);
+}
+
+int main (int argc, char **argv)
+{
+   // 0=headphones, 1=hdmi
+   int audio_dest = 0;
+   // audio sample rate in Hz
+   int samplerate = 48000;
+   // numnber of audio channels
+   int channels = 2;
+   // number of bits per sample
+   int bitdepth = 16;
+   bcm_host_init();
+
+   if (argc > 1)
+      audio_dest = atoi(argv[1]);
+   if (argc > 2)
+      channels = atoi(argv[2]);
+   if (argc > 3)
+      samplerate = atoi(argv[3]);
+
+   printf("Outputting audio to %s\n", audio_dest==0 ? "analogue":"hdmi");
+
+   play_api_test(samplerate, bitdepth, channels, audio_dest);
+   return 0;
+}
+
diff --git a/host_applications/linux/apps/hello_pi/hello_audio/audioplay.h b/host_applications/linux/apps/hello_pi/hello_audio/audioplay.h
new file mode 100755 (executable)
index 0000000..9c96938
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+//  API for host applications to deliver raw PCM samples to rendered on VideoCore
+
+#ifndef AUDIOPLAY_H
+#define AUDIOPLAY_H
+
+/**
+ * \file 
+ *
+ * \brief This API allows the host to provide PCM samples to be
+ * rendered via <DFN>audio_render</DFN>.
+ * 
+ * This file describes a simple API for host applications to play sound
+ * using VideoCore.  It includes the functionality to:
+ * 
+ * \li open/close
+ * \li set pcm parameters
+ * \li set buffer size parameters
+ * \li retrieve empty buffer available to use
+ * \li send full buffer to be played
+ * \li retrieve current buffering level
+ * 
+ * This API has no thread context of it's own, so the caller must be
+ * aware that the IL API will be used in context.  This has
+ * implications on executing calls inside callback contexts, and on
+ * the minimum size of stack that the caller requires.  See the
+ * <DFN>ilclient_stack_size()</DFN> function for assistance.
+ * 
+ * This API will use a single <DFN>audio_render</DFN> IL component, and
+ * supply buffers to the input port using the OpenMAX IL base profile mode.
+ ********************************************************************************/
+
+struct AUDIOPLAY_STATE_T;
+
+/**
+ * The <DFN>AUDIOPLAY_STATE_T</DFN> is an opaque type that represents the
+ * audioplus engine handle.
+ *******************************************************************************/
+typedef struct AUDIOPLAY_STATE_T AUDIOPLAY_STATE_T;
+
+/**
+ * The <DFN>audioplay_create()</DFN> function creates the audioplay object.
+ * 
+ * @param  handle       On success, this is filled in with a handle to use in other
+ *                      API functions.
+ * 
+ * @param  sample_rate  The sample rate, in samples per second, for the PCM data.
+ *                      This shall be between 8000 and 96000.
+ * 
+ * @param  num_channels The number of channels for the PCM data.  Must be 1, 2, 4, or 8.
+ *                      Channels must be sent interleaved.
+ * 
+ * @param  bit_depth    The bitdepth per channel per sample.  Must be 16 or 32.
+ * 
+ * @param  num_buffers  The number of buffers that will be created to write PCM
+ *                      samples into.
+ * 
+ * @param  buffer_size  The size in bytes of each buffer that will be used to write
+ *                      PCM samples into.  Note that small buffers of less than a few
+ *                      Kb in size may be faster than larger buffers, although this is
+ *                      platform dependent.
+ *                     
+ * @return              0 on success, -1 on failure.
+ *********************************************************************************/
+VCHPRE_ int32_t VCHPOST_ audioplay_create(AUDIOPLAY_STATE_T **handle,
+                                          uint32_t sample_rate,
+                                          uint32_t num_channels,
+                                          uint32_t bit_depth,
+                                          uint32_t num_buffers,
+                                          uint32_t buffer_size);
+
+/**
+ * The <DFN>audioplay_delete()</DFN> function deletes the audioplay object.
+ * 
+ * @param  handle       Must be a handle previously created by
+ *                      <DFN>audioplay_create()</DFN>.  After calling this
+ *                      function that handle is no longer valid.  Any
+ *                      buffers provided by <DFN>audioplay_get_buffer()</DFN>
+ *                      are also no longer valid and must not be referenced.
+ * 
+ * @return              0 on success, -1 on failure.
+ ********************************************************************************/
+VCHPRE_ int32_t VCHPOST_ audioplay_delete(AUDIOPLAY_STATE_T *handle);
+
+/**
+ * The <DFN>audioplay_get_buffer()</DFN> function requests an empty
+ * buffer.  Any buffer returned will have the valid size indicated in
+ * the call to <DFN>audioplay_create()</DFN>.
+ * 
+ * @param handle        Must be a handle previously created by
+ *                      <DFN>audioplay_create()</DFN>.  
+ * 
+ * @return              A pointer to an available buffer.  If no buffers are
+ *                      available, then <DFN>NULL</DFN> will be returned.
+ *********************************************************************************/
+VCHPRE_ uint8_t * VCHPOST_ audioplay_get_buffer(AUDIOPLAY_STATE_T *handle);
+
+
+/**
+ * The <DFN>audioplay_play_buffer()</DFN> sends a buffer containing
+ * raw samples to be rendered.
+ * 
+ * @param handle         Must be a handle previously created by
+ *                       <DFN>audioplay_create()</DFN>.  
+ * 
+ * @param buffer         Must be a pointer previously returned by
+ *                       <DFN>audioplay_get_buffer()</DFN>.  After calling this function
+ *                       the buffer pointer must not be referenced until returned
+ *                       again by another call to <DFN>audioplay_get_buffer()</DFN>.
+ * 
+ * @param length         Length in bytes of valid data.  Must be a whole number of 
+ *                       samples, ie a multiple of (num_channels*bit_depth/8).
+ * 
+ * @return               0 on success, -1 on failure
+ ********************************************************************************/
+VCHPRE_ int32_t VCHPOST_ audioplay_play_buffer(AUDIOPLAY_STATE_T *handle,
+                                               uint8_t *buffer,
+                                               uint32_t length);
+
+/**
+ * The <DFN>audioplay_get_latency()</DFN> requests the current audio
+ * playout buffer size in samples, which is the latency until the next
+ * sample supplied is to be rendered.
+ * 
+ * @param handle         Must be a handle previously created by
+ *                       <DFN>audioplay_create()</DFN>.  
+ * 
+ * @return               Number of samples currently buffered.
+ *********************************************************************************/
+VCHPRE_ uint32_t VCHPOST_ audioplay_get_latency(AUDIOPLAY_STATE_T *handle);
+
+
+#endif /* AUDIOPLAY_H */
diff --git a/host_applications/linux/apps/hello_pi/hello_audio/sinewave.c b/host_applications/linux/apps/hello_pi/hello_audio/sinewave.c
new file mode 100755 (executable)
index 0000000..10668b5
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Lookup table for audio output demo
+
+short Sinewave[] = {
+   0,    201,    402,    603,    804,   1005,   1206,   1406,
+   1607,   1808,   2009,   2209,   2410,   2610,   2811,   3011,
+   3211,   3411,   3611,   3811,   4011,   4210,   4409,   4608,
+   4807,   5006,   5205,   5403,   5601,   5799,   5997,   6195,
+   6392,   6589,   6786,   6982,   7179,   7375,   7571,   7766,
+   7961,   8156,   8351,   8545,   8739,   8932,   9126,   9319,
+   9511,   9703,   9895,  10087,  10278,  10469,  10659,  10849,
+   11038,  11227,  11416,  11604,  11792,  11980,  12166,  12353,
+   12539,  12724,  12909,  13094,  13278,  13462,  13645,  13827,
+   14009,  14191,  14372,  14552,  14732,  14911,  15090,  15268,
+   15446,  15623,  15799,  15975,  16150,  16325,  16499,  16672,
+   16845,  17017,  17189,  17360,  17530,  17699,  17868,  18036,
+   18204,  18371,  18537,  18702,  18867,  19031,  19194,  19357,
+   19519,  19680,  19840,  20000,  20159,  20317,  20474,  20631,
+   20787,  20942,  21096,  21249,  21402,  21554,  21705,  21855,
+   22004,  22153,  22301,  22448,  22594,  22739,  22883,  23027,
+   23169,  23311,  23452,  23592,  23731,  23869,  24006,  24143,
+   24278,  24413,  24546,  24679,  24811,  24942,  25072,  25201,
+   25329,  25456,  25582,  25707,  25831,  25954,  26077,  26198,
+   26318,  26437,  26556,  26673,  26789,  26905,  27019,  27132,
+   27244,  27355,  27466,  27575,  27683,  27790,  27896,  28001,
+   28105,  28208,  28309,  28410,  28510,  28608,  28706,  28802,
+   28897,  28992,  29085,  29177,  29268,  29358,  29446,  29534,
+   29621,  29706,  29790,  29873,  29955,  30036,  30116,  30195,
+   30272,  30349,  30424,  30498,  30571,  30643,  30713,  30783,
+   30851,  30918,  30984,  31049,
+   31113,  31175,  31236,  31297,
+   31356,  31413,  31470,  31525,  31580,  31633,  31684,  31735,
+   31785,  31833,  31880,  31926,  31970,  32014,  32056,  32097,
+   32137,  32176,  32213,  32249,  32284,  32318,  32350,  32382,
+   32412,  32441,  32468,  32495,  32520,  32544,  32567,  32588,
+   32609,  32628,  32646,  32662,  32678,  32692,  32705,  32717,
+   32727,  32736,  32744,  32751,  32757,  32761,  32764,  32766,
+   32767,  32766,  32764,  32761,  32757,  32751,  32744,  32736,
+   32727,  32717,  32705,  32692,  32678,  32662,  32646,  32628,
+   32609,  32588,  32567,  32544,  32520,  32495,  32468,  32441,
+   32412,  32382,  32350,  32318,  32284,  32249,  32213,  32176,
+   32137,  32097,  32056,  32014,  31970,  31926,  31880,  31833,
+   31785,  31735,  31684,  31633,  31580,  31525,  31470,  31413,
+   31356,  31297,  31236,  31175,  31113,  31049,  30984,  30918,
+   30851,  30783,  30713,  30643,  30571,  30498,  30424,  30349,
+   30272,  30195,  30116,  30036,  29955,  29873,  29790,  29706,
+   29621,  29534,  29446,  29358,  29268,  29177,  29085,  28992,
+   28897,  28802,  28706,  28608,  28510,  28410,  28309,  28208,
+   28105,  28001,  27896,  27790,  27683,  27575,  27466,  27355,
+   27244,  27132,  27019,  26905,  26789,  26673,  26556,  26437,
+   26318,  26198,  26077,  25954,  25831,  25707,  25582,  25456,
+   25329,  25201,  25072,  24942,  24811,  24679,  24546,  24413,
+   24278,  24143,  24006,  23869,  23731,  23592,  23452,  23311,
+   23169,  23027,  22883,  22739,  22594,  22448,  22301,  22153,
+   22004,  21855,  21705,  21554,  21402,  21249,  21096,  20942,
+   20787,  20631,  20474,  20317,  20159,  20000,  19840,  19680,
+   19519,  19357,  19194,  19031,  18867,  18702,  18537,  18371,
+   18204,  18036,  17868,  17699,  17530,  17360,  17189,  17017,
+   16845,  16672,  16499,  16325,  16150,  15975,  15799,  15623,
+   15446,  15268,  15090,  14911,  14732,  14552,  14372,  14191,
+   14009,  13827,  13645,  13462,  13278,  13094,  12909,  12724,
+   12539,  12353,  12166,  11980,  11792,  11604,  11416,  11227,
+   11038,  10849,  10659,  10469,  10278,  10087,   9895,   9703,
+   9511,   9319,   9126,   8932,   8739,   8545,   8351,   8156,
+   7961,   7766,   7571,   7375,   7179,   6982,   6786,   6589,
+   6392,   6195,   5997,   5799,   5601,   5403,   5205,   5006,
+   4807,   4608,   4409,   4210,   4011,   3811,   3611,   3411,
+   3211,   3011,   2811,   2610,   2410,   2209,   2009,   1808,
+   1607,   1406,   1206,   1005,    804,    603,    402,    201,
+   0,   -201,   -402,   -603,   -804,  -1005,  -1206,  -1406,
+   -1607,  -1808,  -2009,  -2209,  -2410,  -2610,  -2811,  -3011,
+   -3211,  -3411,  -3611,  -3811,  -4011,  -4210,  -4409,  -4608,
+   -4807,  -5006,  -5205,  -5403,  -5601,  -5799,  -5997,  -6195,
+   -6392,  -6589,  -6786,  -6982,  -7179,  -7375,  -7571,  -7766,
+   -7961,  -8156,  -8351,  -8545,  -8739,  -8932,  -9126,  -9319,
+   -9511,  -9703,  -9895, -10087, -10278, -10469, -10659, -10849,
+   -11038, -11227, -11416, -11604, -11792, -11980, -12166, -12353,
+   -12539, -12724, -12909, -13094, -13278, -13462, -13645, -13827,
+   -14009, -14191, -14372, -14552, -14732, -14911, -15090, -15268,
+   -15446, -15623, -15799, -15975, -16150, -16325, -16499, -16672,
+   -16845, -17017, -17189, -17360, -17530, -17699, -17868, -18036,
+   -18204, -18371, -18537, -18702, -18867, -19031, -19194, -19357,
+   -19519, -19680, -19840, -20000, -20159, -20317, -20474, -20631,
+   -20787, -20942, -21096, -21249, -21402, -21554, -21705, -21855,
+   -22004, -22153, -22301, -22448, -22594, -22739, -22883, -23027,
+   -23169, -23311, -23452, -23592, -23731, -23869, -24006, -24143,
+   -24278, -24413, -24546, -24679, -24811, -24942, -25072, -25201,
+   -25329, -25456, -25582, -25707, -25831, -25954, -26077, -26198,
+   -26318, -26437, -26556, -26673, -26789, -26905, -27019, -27132,
+   -27244, -27355, -27466, -27575, -27683, -27790, -27896, -28001,
+   -28105, -28208, -28309, -28410, -28510, -28608, -28706, -28802,
+   -28897, -28992, -29085, -29177, -29268, -29358, -29446, -29534,
+   -29621, -29706, -29790, -29873, -29955, -30036, -30116, -30195,
+   -30272, -30349, -30424, -30498, -30571, -30643, -30713, -30783,
+   -30851, -30918, -30984, -31049, -31113, -31175, -31236, -31297,
+   -31356, -31413, -31470, -31525, -31580, -31633, -31684, -31735,
+   -31785, -31833, -31880, -31926, -31970, -32014, -32056, -32097,
+   -32137, -32176, -32213, -32249, -32284, -32318, -32350, -32382,
+   -32412, -32441, -32468, -32495, -32520, -32544, -32567, -32588,
+   -32609, -32628, -32646, -32662, -32678, -32692, -32705, -32717,
+   -32727, -32736, -32744, -32751, -32757, -32761, -32764, -32766,
+   -32767, -32766, -32764, -32761, -32757, -32751, -32744, -32736,
+   -32727, -32717, -32705, -32692, -32678, -32662, -32646, -32628,
+   -32609, -32588, -32567, -32544, -32520, -32495, -32468, -32441,
+   -32412, -32382, -32350, -32318, -32284, -32249, -32213, -32176,
+   -32137, -32097, -32056, -32014, -31970, -31926, -31880, -31833,
+   -31785, -31735, -31684, -31633, -31580, -31525, -31470, -31413,
+   -31356, -31297, -31236, -31175, -31113, -31049, -30984, -30918,
+   -30851, -30783, -30713, -30643, -30571, -30498, -30424, -30349,
+   -30272, -30195, -30116, -30036, -29955, -29873, -29790, -29706,
+   -29621, -29534, -29446, -29358, -29268, -29177, -29085, -28992,
+   -28897, -28802, -28706, -28608, -28510, -28410, -28309, -28208,
+   -28105, -28001, -27896, -27790, -27683, -27575, -27466, -27355,
+   -27244, -27132, -27019, -26905, -26789, -26673, -26556, -26437,
+   -26318, -26198, -26077, -25954, -25831, -25707, -25582, -25456,
+   -25329, -25201, -25072, -24942, -24811, -24679, -24546, -24413,
+   -24278, -24143, -24006, -23869, -23731, -23592, -23452, -23311,
+   -23169, -23027, -22883, -22739, -22594, -22448, -22301, -22153,
+   -22004, -21855, -21705, -21554, -21402, -21249, -21096, -20942,
+   -20787, -20631, -20474, -20317, -20159, -20000, -19840, -19680,
+   -19519, -19357, -19194, -19031, -18867, -18702, -18537, -18371,
+   -18204, -18036, -17868, -17699, -17530, -17360, -17189, -17017,
+   -16845, -16672, -16499, -16325, -16150, -15975, -15799, -15623,
+   -15446, -15268, -15090, -14911, -14732, -14552, -14372, -14191,
+   -14009, -13827, -13645, -13462, -13278, -13094, -12909, -12724,
+   -12539, -12353, -12166, -11980, -11792, -11604, -11416, -11227,
+   -11038, -10849, -10659, -10469, -10278, -10087,  -9895,  -9703,
+   -9511,  -9319,  -9126,  -8932,  -8739,  -8545,  -8351,  -8156,
+   -7961,  -7766,  -7571,  -7375,  -7179,  -6982,  -6786,  -6589,
+   -6392,  -6195,  -5997,  -5799,  -5601,  -5403,  -5205,  -5006,
+   -4807,  -4608,  -4409,  -4210,  -4011,  -3811,  -3611,  -3411,
+   -3211,  -3011,  -2811,  -2610,  -2410,  -2209,  -2009,  -1808,
+   -1607,  -1406,  -1206,  -1005,   -804,   -603,   -402,   -201,
+};
diff --git a/host_applications/linux/apps/hello_pi/hello_dispmanx/CMakeLists.txt b/host_applications/linux/apps/hello_pi/hello_dispmanx/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..0471a1d
--- /dev/null
@@ -0,0 +1,8 @@
+set(EXEC hello_dispmanx.bin)
+set(SRCS dispmanx.c)
+
+add_executable(${EXEC} ${SRCS})
+target_link_libraries(${EXEC} ${HELLO_PI_LIBS})
+
+install(TARGETS ${EXEC}
+        RUNTIME DESTINATION bin)
diff --git a/host_applications/linux/apps/hello_pi/hello_dispmanx/Makefile b/host_applications/linux/apps/hello_pi/hello_dispmanx/Makefile
new file mode 100755 (executable)
index 0000000..98dc5e9
--- /dev/null
@@ -0,0 +1,5 @@
+OBJS=dispmanx.o
+BIN=hello_dispmanx.bin
+
+include ../Makefile.include
+
diff --git a/host_applications/linux/apps/hello_pi/hello_dispmanx/dispmanx.c b/host_applications/linux/apps/hello_pi/hello_dispmanx/dispmanx.c
new file mode 100755 (executable)
index 0000000..1f23b32
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// A simple demo using dispmanx to display an overlay
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include "bcm_host.h"
+
+#define WIDTH   200
+#define HEIGHT  200
+
+#ifndef ALIGN_UP
+#define ALIGN_UP(x,y)  ((x + (y)-1) & ~((y)-1))
+#endif
+
+typedef struct
+{
+    DISPMANX_DISPLAY_HANDLE_T   display;
+    DISPMANX_MODEINFO_T         info;
+    void                       *image;
+    DISPMANX_UPDATE_HANDLE_T    update;
+    DISPMANX_RESOURCE_HANDLE_T  resource;
+    DISPMANX_ELEMENT_HANDLE_T   element;
+    uint32_t                    vc_image_ptr;
+
+} RECT_VARS_T;
+
+static RECT_VARS_T  gRectVars;
+
+static void FillRect( VC_IMAGE_TYPE_T type, void *image, int pitch, int aligned_height, int x, int y, int w, int h, int val )
+{
+    int         row;
+    int         col;
+
+    uint16_t *line = (uint16_t *)image + y * (pitch>>1) + x;
+
+    for ( row = 0; row < h; row++ )
+    {
+        for ( col = 0; col < w; col++ )
+        {
+            line[col] = val;
+        }
+        line += (pitch>>1);
+    }
+}
+
+int main(void)
+{
+    RECT_VARS_T    *vars;
+    uint32_t        screen = 0;
+    int             ret;
+    VC_RECT_T       src_rect;
+    VC_RECT_T       dst_rect;
+    VC_IMAGE_TYPE_T type = VC_IMAGE_RGB565;
+    int width = WIDTH, height = HEIGHT;
+    int pitch = ALIGN_UP(width*2, 32);
+    int aligned_height = ALIGN_UP(height, 16);
+    VC_DISPMANX_ALPHA_T alpha = { DISPMANX_FLAGS_ALPHA_FROM_SOURCE | DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS, 
+                             120, /*alpha 0->255*/
+                             0 };
+
+    vars = &gRectVars;
+
+    bcm_host_init();
+
+    printf("Open display[%i]...\n", screen );
+    vars->display = vc_dispmanx_display_open( screen );
+
+    ret = vc_dispmanx_display_get_info( vars->display, &vars->info);
+    assert(ret == 0);
+    printf( "Display is %d x %d\n", vars->info.width, vars->info.height );
+
+    vars->image = calloc( 1, pitch * height );
+    assert(vars->image);
+
+    FillRect( type, vars->image, pitch, aligned_height,  0,  0, width,      height,      0xFFFF );
+    FillRect( type, vars->image, pitch, aligned_height,  0,  0, width,      height,      0xF800 );
+    FillRect( type, vars->image, pitch, aligned_height, 20, 20, width - 40, height - 40, 0x07E0 );
+    FillRect( type, vars->image, pitch, aligned_height, 40, 40, width - 80, height - 80, 0x001F );
+
+    vars->resource = vc_dispmanx_resource_create( type,
+                                                  width,
+                                                  height,
+                                                  &vars->vc_image_ptr );
+    assert( vars->resource );
+    vc_dispmanx_rect_set( &dst_rect, 0, 0, width, height);
+    ret = vc_dispmanx_resource_write_data(  vars->resource,
+                                            type,
+                                            pitch,
+                                            vars->image,
+                                            &dst_rect );
+    assert( ret == 0 );
+    vars->update = vc_dispmanx_update_start( 10 );
+    assert( vars->update );
+
+    vc_dispmanx_rect_set( &src_rect, 0, 0, width << 16, height << 16 );
+
+    vc_dispmanx_rect_set( &dst_rect, ( vars->info.width - width ) / 2,
+                                     ( vars->info.height - height ) / 2,
+                                     width,
+                                     height );
+
+    vars->element = vc_dispmanx_element_add(    vars->update,
+                                                vars->display,
+                                                2000,               // layer
+                                                &dst_rect,
+                                                vars->resource,
+                                                &src_rect,
+                                                DISPMANX_PROTECTION_NONE,
+                                                &alpha,
+                                                NULL,             // clamp
+                                                VC_IMAGE_ROT0 );
+
+    ret = vc_dispmanx_update_submit_sync( vars->update );
+    assert( ret == 0 );
+
+    printf( "Sleeping for 10 seconds...\n" );
+    sleep( 10 );
+
+    vars->update = vc_dispmanx_update_start( 10 );
+    assert( vars->update );
+    ret = vc_dispmanx_element_remove( vars->update, vars->element );
+    assert( ret == 0 );
+    ret = vc_dispmanx_update_submit_sync( vars->update );
+    assert( ret == 0 );
+    ret = vc_dispmanx_resource_delete( vars->resource );
+    assert( ret == 0 );
+    ret = vc_dispmanx_display_close( vars->display );
+    assert( ret == 0 );
+
+    return 0;
+}
+
diff --git a/host_applications/linux/apps/hello_pi/hello_encode/CMakeLists.txt b/host_applications/linux/apps/hello_pi/hello_encode/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..147623b
--- /dev/null
@@ -0,0 +1,8 @@
+set(EXEC hello_encode.bin)
+set(SRCS encode.c)
+
+add_executable(${EXEC} ${SRCS})
+target_link_libraries(${EXEC} ${HELLO_PI_LIBS})
+
+install(TARGETS ${EXEC}
+        RUNTIME DESTINATION bin)
diff --git a/host_applications/linux/apps/hello_pi/hello_encode/Makefile b/host_applications/linux/apps/hello_pi/hello_encode/Makefile
new file mode 100755 (executable)
index 0000000..62d320e
--- /dev/null
@@ -0,0 +1,6 @@
+OBJS=encode.o
+BIN=hello_encode.bin
+LDFLAGS+=-lilclient
+
+include ../Makefile.include
+
diff --git a/host_applications/linux/apps/hello_pi/hello_encode/encode.c b/host_applications/linux/apps/hello_pi/hello_encode/encode.c
new file mode 100755 (executable)
index 0000000..7acb54b
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+Copyright (c) 2012, Kalle Vahlman <zuh@iki>
+                    Tuomas Kulve <tuomas@kulve.fi>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Video encode demo using OpenMAX IL though the ilcient helper library
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bcm_host.h"
+#include "ilclient.h"
+
+#define NUMFRAMES 300
+#define WIDTH     640
+#define PITCH     ((WIDTH+31)&~31)
+#define HEIGHT    ((WIDTH)*9/16)
+#define HEIGHT16  ((HEIGHT+15)&~15)
+#define SIZE      ((WIDTH * HEIGHT16 * 3)/2)
+
+// generate an animated test card in YUV format
+static int
+generate_test_card(void *buf, OMX_U32 * filledLen, int frame)
+{
+   int i, j;
+   char *y = buf, *u = y + PITCH * HEIGHT16, *v =
+      u + (PITCH >> 1) * (HEIGHT16 >> 1);
+
+   for (j = 0; j < HEIGHT / 2; j++) {
+      char *py = y + 2 * j * PITCH;
+      char *pu = u + j * (PITCH >> 1);
+      char *pv = v + j * (PITCH >> 1);
+      for (i = 0; i < WIDTH / 2; i++) {
+        int z = (((i + frame) >> 4) ^ ((j + frame) >> 4)) & 15;
+        py[0] = py[1] = py[PITCH] = py[PITCH + 1] = 0x80 + z * 0x8;
+        pu[0] = 0x00 + z * 0x10;
+        pv[0] = 0x80 + z * 0x30;
+        py += 2;
+        pu++;
+        pv++;
+      }
+   }
+   *filledLen = SIZE;
+   return 1;
+}
+
+static void
+print_def(OMX_PARAM_PORTDEFINITIONTYPE def)
+{
+   printf("Port %u: %s %u/%u %u %u %s,%s,%s %ux%u %ux%u @%u %u\n",
+         def.nPortIndex,
+         def.eDir == OMX_DirInput ? "in" : "out",
+         def.nBufferCountActual,
+         def.nBufferCountMin,
+         def.nBufferSize,
+         def.nBufferAlignment,
+         def.bEnabled ? "enabled" : "disabled",
+         def.bPopulated ? "populated" : "not pop.",
+         def.bBuffersContiguous ? "contig." : "not cont.",
+         def.format.video.nFrameWidth,
+         def.format.video.nFrameHeight,
+         def.format.video.nStride,
+         def.format.video.nSliceHeight,
+         def.format.video.xFramerate, def.format.video.eColorFormat);
+}
+
+static int
+video_encode_test(char *outputfilename)
+{
+   OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+   OMX_PARAM_PORTDEFINITIONTYPE def;
+   COMPONENT_T *video_encode = NULL;
+   COMPONENT_T *list[5];
+   OMX_BUFFERHEADERTYPE *buf;
+   OMX_BUFFERHEADERTYPE *out;
+   OMX_ERRORTYPE r;
+   ILCLIENT_T *client;
+   int status = 0;
+   int framenumber = 0;
+   FILE *outf;
+
+   memset(list, 0, sizeof(list));
+
+   if ((client = ilclient_init()) == NULL) {
+      return -3;
+   }
+
+   if (OMX_Init() != OMX_ErrorNone) {
+      ilclient_destroy(client);
+      return -4;
+   }
+
+   // create video_encode
+   r = ilclient_create_component(client, &video_encode, "video_encode",
+                                ILCLIENT_DISABLE_ALL_PORTS |
+                                ILCLIENT_ENABLE_INPUT_BUFFERS |
+                                ILCLIENT_ENABLE_OUTPUT_BUFFERS);
+   if (r != 0) {
+      printf
+        ("ilclient_create_component() for video_encode failed with %x!\n",
+         r);
+      exit(1);
+   }
+   list[0] = video_encode;
+
+   // get current settings of video_encode component from port 200
+   memset(&def, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+   def.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
+   def.nVersion.nVersion = OMX_VERSION;
+   def.nPortIndex = 200;
+
+   if (OMX_GetParameter
+       (ILC_GET_HANDLE(video_encode), OMX_IndexParamPortDefinition,
+       &def) != OMX_ErrorNone) {
+      printf("%s:%d: OMX_GetParameter() for video_encode port 200 failed!\n",
+            __FUNCTION__, __LINE__);
+      exit(1);
+   }
+
+   print_def(def);
+
+   // Port 200: in 1/1 115200 16 enabled,not pop.,not cont. 320x240 320x240 @1966080 20
+   def.format.video.nFrameWidth = WIDTH;
+   def.format.video.nFrameHeight = HEIGHT;
+   def.format.video.xFramerate = 30 << 16;
+   def.format.video.nSliceHeight = def.format.video.nFrameHeight;
+   def.format.video.nStride = def.format.video.nFrameWidth;
+   def.format.video.eColorFormat = OMX_COLOR_FormatYUV420PackedPlanar;
+
+   print_def(def);
+
+   r = OMX_SetParameter(ILC_GET_HANDLE(video_encode),
+                       OMX_IndexParamPortDefinition, &def);
+   if (r != OMX_ErrorNone) {
+      printf
+        ("%s:%d: OMX_SetParameter() for video_encode port 200 failed with %x!\n",
+         __FUNCTION__, __LINE__, r);
+      exit(1);
+   }
+
+   memset(&format, 0, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));
+   format.nSize = sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE);
+   format.nVersion.nVersion = OMX_VERSION;
+   format.nPortIndex = 201;
+   format.eCompressionFormat = OMX_VIDEO_CodingAVC;
+
+   printf("OMX_SetParameter for video_encode:201...\n");
+   r = OMX_SetParameter(ILC_GET_HANDLE(video_encode),
+                       OMX_IndexParamVideoPortFormat, &format);
+   if (r != OMX_ErrorNone) {
+      printf
+        ("%s:%d: OMX_SetParameter() for video_encode port 201 failed with %x!\n",
+         __FUNCTION__, __LINE__, r);
+      exit(1);
+   }
+
+   OMX_VIDEO_PARAM_BITRATETYPE bitrateType;
+   // set current bitrate to 1Mbit
+   memset(&bitrateType, 0, sizeof(OMX_VIDEO_PARAM_BITRATETYPE));
+   bitrateType.nSize = sizeof(OMX_VIDEO_PARAM_BITRATETYPE);
+   bitrateType.nVersion.nVersion = OMX_VERSION;
+   bitrateType.eControlRate = OMX_Video_ControlRateVariable;
+   bitrateType.nTargetBitrate = 1000000;
+   bitrateType.nPortIndex = 201;
+   r = OMX_SetParameter(ILC_GET_HANDLE(video_encode),
+                       OMX_IndexParamVideoBitrate, &bitrateType);
+   if (r != OMX_ErrorNone) {
+      printf
+        ("%s:%d: OMX_SetParameter() for bitrate for video_encode port 201 failed with %x!\n",
+         __FUNCTION__, __LINE__, r);
+      exit(1);
+   }
+
+
+   // get current bitrate
+   memset(&bitrateType, 0, sizeof(OMX_VIDEO_PARAM_BITRATETYPE));
+   bitrateType.nSize = sizeof(OMX_VIDEO_PARAM_BITRATETYPE);
+   bitrateType.nVersion.nVersion = OMX_VERSION;
+   bitrateType.nPortIndex = 201;
+
+   if (OMX_GetParameter
+       (ILC_GET_HANDLE(video_encode), OMX_IndexParamVideoBitrate,
+       &bitrateType) != OMX_ErrorNone) {
+      printf("%s:%d: OMX_GetParameter() for video_encode for bitrate port 201 failed!\n",
+            __FUNCTION__, __LINE__);
+      exit(1);
+   }
+   printf("Current Bitrate=%u\n",bitrateType.nTargetBitrate);
+
+
+
+   printf("encode to idle...\n");
+   if (ilclient_change_component_state(video_encode, OMX_StateIdle) == -1) {
+      printf
+        ("%s:%d: ilclient_change_component_state(video_encode, OMX_StateIdle) failed",
+         __FUNCTION__, __LINE__);
+   }
+
+   printf("enabling port buffers for 200...\n");
+   if (ilclient_enable_port_buffers(video_encode, 200, NULL, NULL, NULL) != 0) {
+      printf("enabling port buffers for 200 failed!\n");
+      exit(1);
+   }
+
+   printf("enabling port buffers for 201...\n");
+   if (ilclient_enable_port_buffers(video_encode, 201, NULL, NULL, NULL) != 0) {
+      printf("enabling port buffers for 201 failed!\n");
+      exit(1);
+   }
+
+   printf("encode to executing...\n");
+   ilclient_change_component_state(video_encode, OMX_StateExecuting);
+
+   outf = fopen(outputfilename, "w");
+   if (outf == NULL) {
+      printf("Failed to open '%s' for writing video\n", outputfilename);
+      exit(1);
+   }
+
+   printf("looping for buffers...\n");
+   do {
+      buf = ilclient_get_input_buffer(video_encode, 200, 1);
+      if (buf == NULL) {
+        printf("Doh, no buffers for me!\n");
+      }
+      else {
+        /* fill it */
+        generate_test_card(buf->pBuffer, &buf->nFilledLen, framenumber++);
+
+        if (OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_encode), buf) !=
+            OMX_ErrorNone) {
+           printf("Error emptying buffer!\n");
+        }
+
+        out = ilclient_get_output_buffer(video_encode, 201, 1);
+
+        r = OMX_FillThisBuffer(ILC_GET_HANDLE(video_encode), out);
+        if (r != OMX_ErrorNone) {
+           printf("Error filling buffer: %x\n", r);
+        }
+
+        if (out != NULL) {
+           if (out->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
+              int i;
+              for (i = 0; i < out->nFilledLen; i++)
+                 printf("%x ", out->pBuffer[i]);
+              printf("\n");
+           }
+
+           r = fwrite(out->pBuffer, 1, out->nFilledLen, outf);
+           if (r != out->nFilledLen) {
+              printf("fwrite: Error emptying buffer: %d!\n", r);
+           }
+           else {
+              printf("Writing frame %d/%d\n", framenumber, NUMFRAMES);
+           }
+           out->nFilledLen = 0;
+        }
+        else {
+           printf("Not getting it :(\n");
+        }
+
+      }
+   }
+   while (framenumber < NUMFRAMES);
+
+   fclose(outf);
+
+   printf("Teardown.\n");
+
+   printf("disabling port buffers for 200 and 201...\n");
+   ilclient_disable_port_buffers(video_encode, 200, NULL, NULL, NULL);
+   ilclient_disable_port_buffers(video_encode, 201, NULL, NULL, NULL);
+
+   ilclient_state_transition(list, OMX_StateIdle);
+   ilclient_state_transition(list, OMX_StateLoaded);
+
+   ilclient_cleanup_components(list);
+
+   OMX_Deinit();
+
+   ilclient_destroy(client);
+   return status;
+}
+
+int
+main(int argc, char **argv)
+{
+   if (argc < 2) {
+      printf("Usage: %s <filename>\n", argv[0]);
+      exit(1);
+   }
+   bcm_host_init();
+   return video_encode_test(argv[1]);
+}
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/gpu_fft.c b/host_applications/linux/apps/hello_pi/hello_fft/gpu_fft.c
new file mode 100755 (executable)
index 0000000..5bda67b
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+BCM2835 "GPU_FFT" release 3.0
+Copyright (c) 2015, Andrew Holme.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <string.h>
+
+#include "gpu_fft.h"
+
+#define GPU_FFT_BUSY_WAIT_LIMIT (5<<12) // ~1ms
+
+typedef struct GPU_FFT_COMPLEX COMPLEX;
+
+int gpu_fft_prepare(
+    int mb,         // mailbox file_desc
+    int log2_N,     // log2(FFT_length) = 8...22
+    int direction,  // GPU_FFT_FWD: fft(); GPU_FFT_REV: ifft()
+    int jobs,       // number of transforms in batch
+    struct GPU_FFT **fft) {
+
+    unsigned info_bytes, twid_bytes, data_bytes, code_bytes, unif_bytes, mail_bytes;
+    unsigned size, *uptr, vc_tw, vc_data;
+    int i, q, shared, unique, passes, ret;
+
+    struct GPU_FFT_BASE *base;
+    struct GPU_FFT_PTR ptr;
+    struct GPU_FFT *info;
+
+    if (gpu_fft_twiddle_size(log2_N, &shared, &unique, &passes)) return -2;
+
+    info_bytes = 4096;
+    data_bytes = (1+((sizeof(COMPLEX)<<log2_N)|4095));
+    code_bytes = gpu_fft_shader_size(log2_N);
+    twid_bytes = sizeof(COMPLEX)*16*(shared+GPU_FFT_QPUS*unique);
+    unif_bytes = sizeof(int)*GPU_FFT_QPUS*(5+jobs*2);
+    mail_bytes = sizeof(int)*GPU_FFT_QPUS*2;
+
+    size  = info_bytes +        // header
+            data_bytes*jobs*2 + // ping-pong data, aligned
+            code_bytes +        // shader, aligned
+            twid_bytes +        // twiddles
+            unif_bytes +        // uniforms
+            mail_bytes;         // mailbox message
+
+    ret = gpu_fft_alloc(mb, size, &ptr);
+    if (ret) return ret;
+
+    // Header
+    info = (struct GPU_FFT *) ptr.arm.vptr;
+    base = (struct GPU_FFT_BASE *) info;
+    gpu_fft_ptr_inc(&ptr, info_bytes);
+
+    // For transpose
+    info->x = 1<<log2_N;
+    info->y = jobs;
+
+    // Ping-pong buffers leave results in or out of place
+    info->in = info->out = ptr.arm.cptr;
+    info->step = data_bytes / sizeof(COMPLEX);
+    if (passes&1) info->out += info->step * jobs; // odd => out of place
+    vc_data = gpu_fft_ptr_inc(&ptr, data_bytes*jobs*2);
+
+    // Shader code
+    memcpy(ptr.arm.vptr, gpu_fft_shader_code(log2_N), code_bytes);
+    base->vc_code = gpu_fft_ptr_inc(&ptr, code_bytes);
+
+    // Twiddles
+    gpu_fft_twiddle_data(log2_N, direction, ptr.arm.fptr);
+    vc_tw = gpu_fft_ptr_inc(&ptr, twid_bytes);
+
+    uptr = ptr.arm.uptr;
+
+    // Uniforms
+    for (q=0; q<GPU_FFT_QPUS; q++) {
+        *uptr++ = vc_tw;
+        *uptr++ = vc_tw + sizeof(COMPLEX)*16*(shared + q*unique);
+        *uptr++ = q;
+        for (i=0; i<jobs; i++) {
+            *uptr++ = vc_data + data_bytes*i;
+            *uptr++ = vc_data + data_bytes*i + data_bytes*jobs;
+        }
+        *uptr++ = 0;
+        *uptr++ = (q==0); // For mailbox: IRQ enable, master only
+
+        base->vc_unifs[q] = gpu_fft_ptr_inc(&ptr, sizeof(int)*(5+jobs*2));
+    }
+
+    if ((jobs<<log2_N) <= GPU_FFT_BUSY_WAIT_LIMIT) {
+        // Direct register poking with busy wait
+        base->vc_msg = 0;
+    }
+    else {
+        // Mailbox message
+        for (q=0; q<GPU_FFT_QPUS; q++) {
+            *uptr++ = base->vc_unifs[q];
+            *uptr++ = base->vc_code;
+        }
+
+        base->vc_msg = ptr.vc;
+    }
+
+    *fft = info;
+    return 0;
+}
+
+unsigned gpu_fft_execute(struct GPU_FFT *info) {
+    return gpu_fft_base_exec(&info->base, GPU_FFT_QPUS);
+}
+
+void gpu_fft_release(struct GPU_FFT *info) {
+    gpu_fft_base_release(&info->base);
+}
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/gpu_fft.h b/host_applications/linux/apps/hello_pi/hello_fft/gpu_fft.h
new file mode 100755 (executable)
index 0000000..8b1cb08
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+BCM2835 "GPU_FFT" release 3.0
+Copyright (c) 2015, Andrew Holme.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __GPU_FFT__
+#define __GPU_FFT__
+
+#define GPU_FFT_QPUS 8
+
+#define GPU_FFT_PI 3.14159265358979323846
+
+#define GPU_FFT_FWD 0 // forward FFT
+#define GPU_FFT_REV 1 // inverse FFT
+
+struct GPU_FFT_COMPLEX {
+    float re, im;
+};
+
+struct GPU_FFT_PTR {
+    unsigned vc;
+    union { struct GPU_FFT_COMPLEX *cptr;
+            void                   *vptr;
+            char                   *bptr;
+            float                  *fptr;
+            unsigned               *uptr; } arm;
+};
+
+struct GPU_FFT_BASE {
+    int mb;
+    unsigned handle, size, vc_msg, vc_code, vc_unifs[GPU_FFT_QPUS], peri_size;
+    volatile unsigned *peri;
+};
+
+struct GPU_FFT {
+    struct GPU_FFT_BASE base;
+    struct GPU_FFT_COMPLEX *in, *out;
+    int x, y, step;
+};
+
+int gpu_fft_prepare(
+    int mb,         // mailbox file_desc
+    int log2_N,     // log2(FFT_length) = 8...22
+    int direction,  // GPU_FFT_FWD: fft(); GPU_FFT_REV: ifft()
+    int jobs,       // number of transforms in batch
+    struct GPU_FFT **fft);
+
+unsigned gpu_fft_execute(
+    struct GPU_FFT *info);
+
+void gpu_fft_release(
+    struct GPU_FFT *info);
+
+// private
+int           gpu_fft_twiddle_size(int, int *, int *, int *);
+void          gpu_fft_twiddle_data(int, int, float *);
+unsigned int  gpu_fft_shader_size(int);
+unsigned int *gpu_fft_shader_code(int);
+
+// gpu_fft_base:
+
+unsigned gpu_fft_base_exec (
+    struct GPU_FFT_BASE *base,
+    int num_qpus);
+
+int gpu_fft_alloc (
+    int mb,
+    unsigned size,
+    struct GPU_FFT_PTR *ptr);
+
+void gpu_fft_base_release(
+    struct GPU_FFT_BASE *base);
+
+unsigned gpu_fft_ptr_inc (
+    struct GPU_FFT_PTR *ptr,
+    int bytes);
+
+#endif // __GPU_FFT__
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/gpu_fft.txt b/host_applications/linux/apps/hello_pi/hello_fft/gpu_fft.txt
new file mode 100755 (executable)
index 0000000..49d65bf
--- /dev/null
@@ -0,0 +1,159 @@
+BCM2835 "GPU_FFT" release 3.0 by Andrew Holme, 2015.
+
+GPU_FFT is an FFT library for the Raspberry Pi which exploits the BCM2835 SoC
+3D hardware to deliver ten times more data throughput than is possible on the
+700 MHz ARM of the Pi 1.  Kernels are provided for all power-of-2 FFT lengths
+between 256 and 4,194,304 points inclusive.  A transpose function, which also
+uses the 3D hardware, is provided to support 2-dimensional transforms.
+
+
+*** Accuracy ***
+
+GPU_FFT uses single-precision floats for data and twiddle factors.  The output
+is not scaled.  The relative root-mean-square (rms) error in parts-per-million
+(ppm) for different transform lengths (N) is typically:
+
+log2(N) |  8    |  9    | 10    | 11    | 12    | 13    | 14    | 15
+ppm rms |  0.33 |  0.46 |  0.52 |  0.59 |  0.78 |  0.83 |  0.92 |  0.98
+
+log2(N) | 16    | 17    | 18    | 19    | 20    |  21   | 22
+ppm rms |  1.0  |  1.3  |  1.3  |  1.4  |  1.5  |  1.5  |  1.5
+
+Accuracy has improved significantly over previous releases at the expense of a
+small (2%) performance hit; however, FFTW is still one order of magnitude more
+accurate than GPU_FFT.
+
+
+*** Throughput ***
+
+GPU_FFT 1.0 had to be invoked through a "mailbox" which added a 100us overhead
+on every call.  To mitigate this, batches of transforms could be submitted via
+a single call.  GPU_FFT now avoids this 100us overhead by poking GPU registers
+directly from the ARM if total batch runtime will be short; but still uses the
+mailbox for longer jobs to avoid busy waiting at 100% CPU for too long.
+
+Typical per-transform runtimes for batch sizes of 1 and 10; and comparative
+figures for FFTW (FFTW_MEASURE mode) on a Pi 1 with L2 cache enabled are:
+
+log2(N) |   8   |   9   |  10   |  11   |  12  |  13  |  14  |  15
+      1 | 0.033 | 0.049 | 0.070 | 0.12  | 0.25 | 0.61 |  1.2 |  3.5
+     10 | 0.017 | 0.029 | 0.049 | 0.11  | 0.27 | 0.66 |  1.2 |  3.3
+   FFTW | 0.092 | 0.22  | 0.48  | 0.95  | 3.0  | 5.1  | 12   | 31
+
+log2(N) |  16  |  17 |  18 |  19 |   20 |   21 |   22        All times in
+      1 |  7.0 |  17 |  43 |  97 |  194 |  388 |  786        milliseconds
+   FFTW | 83   | 180 | 560 | 670 | 1600 | 3400 | 8800        2 sig. figs.
+
+
+*** API functions ***
+
+    gpu_fft_prepare()       Call once to allocate memory and initialise data
+                            structures.  Returns 0 for success.
+
+    gpu_fft_execute()       Call one or more times to execute a previously
+                            prepared FFT batch.  Returns 0 for success.
+
+    gpu_fft_release()       Call once to release resources after use.
+                            GPU memory is permanently lost if not freed.
+
+
+*** Parameters ***
+
+    int mb          Mailbox file descriptor obtained by calling mbox_open()
+
+    int log2_N      log2(FFT length) = 8 to 22
+
+    int direction   FFT direction:  GPU_FFT_FWD for forward FFT
+                                    GPU_FFT_REV for inverse FFT
+
+    int jobs        Number of transforms in batch = 1 or more
+
+    GPU_FFT **      Output parameter from prepare: control structure.
+    GPU_FFT *       Input parameter to execute and release
+
+
+*** Data format ***
+
+Complex data arrays are stored as alternate real and imaginary parts:
+
+    struct GPU_FFT_COMPLEX {
+        float re, im;
+    };
+
+The GPU_FFT struct created by gpu_fft_prepare() contains pointers to the input
+and output arrays:
+
+    struct GPU_FFT {
+       struct GPU_FFT_COMPLEX *in, *out;
+
+When executing a batch of transforms, buffer pointers are obtained as follows:
+
+    struct GPU_FFT *fft = gpu_fft_prepare( ... , jobs);
+    for (int j=0; j<jobs; j++) {
+       struct GPU_FFT_COMPLEX *in  = fft->in  + j*fft->step;
+       struct GPU_FFT_COMPLEX *out = fft->out + j*fft->step;
+
+GPU_FFT.step is greater than FFT length because a guard space is left between
+buffers for caching and alignment reasons.
+
+GPU_FFT performs multiple passes between ping-pong buffers.  The final output
+lands in the same buffer as input after an even number of passes.  Transforms
+where log2_N=12...16 use an odd number of passes and the final result is left
+out-of-place.  The input data is never preserved.
+
+
+*** Example program ***
+
+The code that produced the above accuracy and performance figures is included
+as a demo with the latest Raspbian distro.  Build and run it as follows:
+
+cd /opt/vc/src/hello_pi/hello_fft
+make
+sudo ./hello_fft.bin 12
+
+It accepts three optional command-line arguments: <log2_N> <batch> <loops>
+
+The special character device is required for the ioctl mailbox through which
+the ARM communicates with the Videocore GPU.
+
+
+*** With Open GL on Pi 1 ***
+
+GPU_FFT and Open GL will run concurrently on Pi 1 if GPU_FFT is configured not
+to use VC4 L2 cache by zeroing a define in file gpu_fft_base.c as follows:
+
+#define GPU_FFT_USE_VC4_L2_CACHE 0 // Pi 1 only: cached=1; direct=0
+
+Overall performance will probably be higher if GPU_FFT and Open GL take turns
+at using the 3D hardware.  Since eglSwapBuffers() returns immediately without
+waiting for rendering, call glFlush() and glFinish() afterwards as follows:
+
+    for (;;) {
+        ....
+        eglSwapBuffers(....); // non-blocking call returns immediately
+        glFlush();
+        glFinish(); // wait until V3D hardware is idle
+        ....
+        gpu_fft_execute(....); // blocking call
+        ....
+    }
+
+
+*** 2-dimensional FFT ***
+
+Please study the hello_fft_2d demo source, which is built and executed thus:
+
+make hello_fft_2d.bin
+sudo ./hello_fft_2d.bin
+
+This generates a Windows BMP file: "hello_fft_2d.bmp"
+
+The demo uses a square 512x512 array; however, rectangular arrays are allowed.
+The following lines in gpu_fft_trans.c will do what is safe:
+
+    ptr.arm.uptr[6] = src->x < dst->y? src->x : dst->y;
+    ptr.arm.uptr[7] = src->y < dst->x? src->y : dst->x;
+
+One may transpose the output from the second FFT pass back into the first pass
+input buffer, by preparing and executing a second transposition; however, this
+is probably unnecessary.  It depends on how the final output will be accessed.
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/gpu_fft_base.c b/host_applications/linux/apps/hello_pi/hello_fft/gpu_fft_base.c
new file mode 100755 (executable)
index 0000000..76656b8
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+BCM2835 "GPU_FFT" release 3.0
+Copyright (c) 2015, Andrew Holme.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <dlfcn.h>
+
+#include "gpu_fft.h"
+#include "mailbox.h"
+
+#define BUS_TO_PHYS(x) ((x)&~0xC0000000)
+
+// V3D spec: http://www.broadcom.com/docs/support/videocore/VideoCoreIV-AG100-R.pdf
+#define V3D_L2CACTL (0xC00020>>2)
+#define V3D_SLCACTL (0xC00024>>2)
+#define V3D_SRQPC   (0xC00430>>2)
+#define V3D_SRQUA   (0xC00434>>2)
+#define V3D_SRQCS   (0xC0043c>>2)
+#define V3D_DBCFG   (0xC00e00>>2)
+#define V3D_DBQITE  (0xC00e2c>>2)
+#define V3D_DBQITC  (0xC00e30>>2)
+
+// Setting this define to zero on Pi 1 allows GPU_FFT and Open GL
+// to co-exist and also improves performance of longer transforms:
+#define GPU_FFT_USE_VC4_L2_CACHE 1 // Pi 1 only: cached=1; direct=0
+
+#define GPU_FFT_NO_FLUSH 1
+#define GPU_FFT_TIMEOUT 2000 // ms
+
+struct GPU_FFT_HOST {
+    unsigned mem_flg, mem_map, peri_addr, peri_size;
+};
+
+int gpu_fft_get_host_info(struct GPU_FFT_HOST *info) {
+    void *handle;
+    unsigned (*bcm_host_get_sdram_address)     (void);
+    unsigned (*bcm_host_get_peripheral_address)(void);
+    unsigned (*bcm_host_get_peripheral_size)   (void);
+
+    // Pi 1 defaults
+    info->peri_addr = 0x20000000;
+    info->peri_size = 0x01000000;
+    info->mem_flg = GPU_FFT_USE_VC4_L2_CACHE? 0xC : 0x4;
+    info->mem_map = GPU_FFT_USE_VC4_L2_CACHE? 0x0 : 0x20000000; // Pi 1 only
+
+    handle = dlopen("libbcm_host.so", RTLD_LAZY);
+    if (!handle) return -1;
+
+    *(void **) (&bcm_host_get_sdram_address)      = dlsym(handle, "bcm_host_get_sdram_address");
+    *(void **) (&bcm_host_get_peripheral_address) = dlsym(handle, "bcm_host_get_peripheral_address");
+    *(void **) (&bcm_host_get_peripheral_size)    = dlsym(handle, "bcm_host_get_peripheral_size");
+
+    if (bcm_host_get_sdram_address && bcm_host_get_sdram_address()!=0x40000000) { // Pi 2?
+        info->mem_flg = 0x4; // ARM cannot see VC4 L2 on Pi 2
+        info->mem_map = 0x0;
+    }
+
+    if (bcm_host_get_peripheral_address) info->peri_addr = bcm_host_get_peripheral_address();
+    if (bcm_host_get_peripheral_size)    info->peri_size = bcm_host_get_peripheral_size();
+
+    dlclose(handle);
+    return 0;
+}
+
+unsigned gpu_fft_base_exec_direct (
+    struct GPU_FFT_BASE *base,
+    int num_qpus) {
+
+    unsigned q, t;
+
+    base->peri[V3D_DBCFG] = 0; // Disallow IRQ
+    base->peri[V3D_DBQITE] = 0; // Disable IRQ
+    base->peri[V3D_DBQITC] = -1; // Resets IRQ flags
+
+    base->peri[V3D_L2CACTL] =  1<<2; // Clear L2 cache
+    base->peri[V3D_SLCACTL] = -1; // Clear other caches
+
+    base->peri[V3D_SRQCS] = (1<<7) | (1<<8) | (1<<16); // Reset error bit and counts
+
+    for (q=0; q<num_qpus; q++) { // Launch shader(s)
+        base->peri[V3D_SRQUA] = base->vc_unifs[q];
+        base->peri[V3D_SRQPC] = base->vc_code;
+    }
+
+    // Busy wait polling
+    for (;;) {
+        if (((base->peri[V3D_SRQCS]>>16) & 0xff) == num_qpus) break; // All done?
+    }
+
+    return 0;
+}
+
+unsigned gpu_fft_base_exec(
+    struct GPU_FFT_BASE *base,
+    int num_qpus) {
+
+    if (base->vc_msg) {
+        // Use mailbox
+        // Returns: 0x0 for success; 0x80000000 for timeout
+        return execute_qpu(base->mb, num_qpus, base->vc_msg, GPU_FFT_NO_FLUSH, GPU_FFT_TIMEOUT);
+    }
+    else {
+        // Direct register poking
+        return gpu_fft_base_exec_direct(base, num_qpus);
+    }
+}
+
+int gpu_fft_alloc (
+    int mb,
+    unsigned size,
+    struct GPU_FFT_PTR *ptr) {
+
+    struct GPU_FFT_HOST host;
+    struct GPU_FFT_BASE *base;
+    volatile unsigned *peri;
+    unsigned handle;
+
+    if (gpu_fft_get_host_info(&host)) return -5;
+
+    if (qpu_enable(mb, 1)) return -1;
+
+    // Shared memory
+    handle = mem_alloc(mb, size, 4096, host.mem_flg);
+    if (!handle) {
+        qpu_enable(mb, 0);
+        return -3;
+    }
+
+    peri = (volatile unsigned *) mapmem(host.peri_addr, host.peri_size);
+    if (!peri) {
+        mem_free(mb, handle);
+        qpu_enable(mb, 0);
+        return -4;
+    }
+
+    ptr->vc = mem_lock(mb, handle);
+    ptr->arm.vptr = mapmem(BUS_TO_PHYS(ptr->vc+host.mem_map), size);
+
+    base = (struct GPU_FFT_BASE *) ptr->arm.vptr;
+    base->peri      = peri;
+    base->peri_size = host.peri_size;
+    base->mb        = mb;
+    base->handle    = handle;
+    base->size      = size;
+
+    return 0;
+}
+
+void gpu_fft_base_release(struct GPU_FFT_BASE *base) {
+    int mb = base->mb;
+    unsigned handle = base->handle, size = base->size;
+    unmapmem((void*)base->peri, base->peri_size);
+    unmapmem((void*)base, size);
+    mem_unlock(mb, handle);
+    mem_free(mb, handle);
+    qpu_enable(mb, 0);
+}
+
+unsigned gpu_fft_ptr_inc (
+    struct GPU_FFT_PTR *ptr,
+    int bytes) {
+
+    unsigned vc = ptr->vc;
+    ptr->vc += bytes;
+    ptr->arm.bptr += bytes;
+    return vc;
+}
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/gpu_fft_shaders.c b/host_applications/linux/apps/hello_pi/hello_fft/gpu_fft_shaders.c
new file mode 100755 (executable)
index 0000000..f8e3bfe
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+BCM2835 "GPU_FFT" release 3.0
+Copyright (c) 2015, Andrew Holme.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+static unsigned int shader_256[] = {
+    #include "hex/shader_256.hex"
+};
+static unsigned int shader_512[] = {
+    #include "hex/shader_512.hex"
+};
+static unsigned int shader_1k[] = {
+    #include "hex/shader_1k.hex"
+};
+static unsigned int shader_2k[] = {
+    #include "hex/shader_2k.hex"
+};
+static unsigned int shader_4k[] = {
+    #include "hex/shader_4k.hex"
+};
+static unsigned int shader_8k[] = {
+    #include "hex/shader_8k.hex"
+};
+static unsigned int shader_16k[] = {
+    #include "hex/shader_16k.hex"
+};
+static unsigned int shader_32k[] = {
+    #include "hex/shader_32k.hex"
+};
+static unsigned int shader_64k[] = {
+    #include "hex/shader_64k.hex"
+};
+static unsigned int shader_128k[] = {
+    #include "hex/shader_128k.hex"
+};
+static unsigned int shader_256k[] = {
+    #include "hex/shader_256k.hex"
+};
+static unsigned int shader_512k[] = {
+    #include "hex/shader_512k.hex"
+};
+static unsigned int shader_1024k[] = {
+    #include "hex/shader_1024k.hex"
+};
+static unsigned int shader_2048k[] = {
+    #include "hex/shader_2048k.hex"
+};
+static unsigned int shader_4096k[] = {
+    #include "hex/shader_4096k.hex"
+};
+
+static struct {
+    unsigned int size, *code;
+}
+shaders[] = {
+    {sizeof(shader_256), shader_256},
+    {sizeof(shader_512), shader_512},
+    {sizeof(shader_1k), shader_1k},
+    {sizeof(shader_2k), shader_2k},
+    {sizeof(shader_4k), shader_4k},
+    {sizeof(shader_8k), shader_8k},
+    {sizeof(shader_16k), shader_16k},
+    {sizeof(shader_32k), shader_32k},
+    {sizeof(shader_64k), shader_64k},
+    {sizeof(shader_128k), shader_128k},
+    {sizeof(shader_256k), shader_256k},
+    {sizeof(shader_512k), shader_512k},
+    {sizeof(shader_1024k), shader_1024k},
+    {sizeof(shader_2048k), shader_2048k},
+    {sizeof(shader_4096k), shader_4096k}
+};
+
+unsigned int  gpu_fft_shader_size(int log2_N) {
+    return shaders[log2_N-8].size;
+}
+
+unsigned int *gpu_fft_shader_code(int log2_N) {
+    return shaders[log2_N-8].code;
+}
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/gpu_fft_trans.c b/host_applications/linux/apps/hello_pi/hello_fft/gpu_fft_trans.c
new file mode 100755 (executable)
index 0000000..265c2b6
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+BCM2835 "GPU_FFT" release 2.0
+Copyright (c) 2014, Andrew Holme.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <string.h>
+
+#include "gpu_fft_trans.h"
+
+static unsigned int shader_trans[1024] = {
+    #include "hex/shader_trans.hex"
+};
+
+int gpu_fft_trans_prepare(
+    int mb,
+    struct GPU_FFT *src,
+    struct GPU_FFT *dst,
+    struct GPU_FFT_TRANS **out) {
+
+    unsigned size, info_bytes, code_bytes, unif_bytes, mail_bytes;
+    int ret;
+
+    struct GPU_FFT_TRANS *info;
+    struct GPU_FFT_BASE *base;
+    struct GPU_FFT_PTR ptr;
+
+    info_bytes = code_bytes = unif_bytes = mail_bytes = 4096; // 4k align
+
+    size  = info_bytes +        // control
+            code_bytes +        // shader, aligned
+            unif_bytes +        // uniforms
+            mail_bytes;         // mailbox message
+
+    ret = gpu_fft_alloc(mb, size, &ptr);
+    if (ret) return ret;
+
+    // Control header
+    info = (struct GPU_FFT_TRANS *) ptr.arm.vptr;
+    base = (struct GPU_FFT_BASE *) info;
+    gpu_fft_ptr_inc(&ptr, info_bytes);
+
+    // Shader code
+    memcpy(ptr.arm.vptr, shader_trans, code_bytes);
+    base->vc_code = gpu_fft_ptr_inc(&ptr, code_bytes);
+
+    // Uniforms
+    ptr.arm.uptr[0] = src->base.vc_msg;
+    ptr.arm.uptr[1] = ((char*)src->out) - ((char*)src->in); // output buffer offset
+    ptr.arm.uptr[2] = dst->base.vc_msg;
+    ptr.arm.uptr[3] = 0;
+    ptr.arm.uptr[4] = src->step * sizeof(struct GPU_FFT_COMPLEX);
+    ptr.arm.uptr[5] = dst->step * sizeof(struct GPU_FFT_COMPLEX);
+    ptr.arm.uptr[6] = src->x < dst->y? src->x : dst->y;
+    ptr.arm.uptr[7] = src->y < dst->x? src->y : dst->x;
+    base->vc_unifs[0] = gpu_fft_ptr_inc(&ptr, unif_bytes);
+
+    // Mailbox message
+    ptr.arm.uptr[0] = base->vc_unifs[0];
+    ptr.arm.uptr[1] = base->vc_code;
+    base->vc_msg = gpu_fft_ptr_inc(&ptr, mail_bytes);
+
+    *out = info;
+    return 0;
+}
+
+unsigned gpu_fft_trans_execute(struct GPU_FFT_TRANS *info) {
+    return gpu_fft_base_exec(&info->base, 1);
+}
+
+void gpu_fft_trans_release(struct GPU_FFT_TRANS *info) {
+    gpu_fft_base_release(&info->base);
+}
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/gpu_fft_trans.h b/host_applications/linux/apps/hello_pi/hello_fft/gpu_fft_trans.h
new file mode 100755 (executable)
index 0000000..682efc1
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+BCM2835 "GPU_FFT" release 2.0
+Copyright (c) 2014, Andrew Holme.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "gpu_fft.h"
+
+struct GPU_FFT_TRANS {
+    struct GPU_FFT_BASE base;
+};
+
+int gpu_fft_trans_prepare(
+    int mb,
+    struct GPU_FFT *src,
+    struct GPU_FFT *dst,
+    struct GPU_FFT_TRANS **out);
+
+unsigned gpu_fft_trans_execute( // src->out ==> T ==> dst->in
+    struct GPU_FFT_TRANS *info);
+
+void gpu_fft_trans_release(
+    struct GPU_FFT_TRANS *info);
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/gpu_fft_twiddles.c b/host_applications/linux/apps/hello_pi/hello_fft/gpu_fft_twiddles.c
new file mode 100755 (executable)
index 0000000..5323650
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+BCM2835 "GPU_FFT" release 3.0
+Copyright (c) 2015, Andrew Holme.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <math.h>
+
+#include "gpu_fft.h"
+
+#define ALPHA(dx) (2*pow(sin((dx)/2),2))
+#define  BETA(dx) (sin(dx))
+
+static double k[16] = {0,8,4,4,2,2,2,2,1,1,1,1,1,1,1,1};
+static double m[16] = {0,0,0,1,0,1,2,3,0,1,2,3,4,5,6,7};
+
+/****************************************************************************/
+
+static float *twiddles_base_16(double two_pi, float *out, double theta) {
+    int i;
+    for (i=0; i<16; i++) {
+        *out++ = cos(two_pi/16*k[i]*m[i] + theta*k[i]);
+        *out++ = sin(two_pi/16*k[i]*m[i] + theta*k[i]);
+    }
+    return out;
+}
+
+static float *twiddles_base_32(double two_pi, float *out, double theta) {
+    int i;
+    for (i=0; i<16; i++) {
+        *out++ = cos(two_pi/32*i + theta);
+        *out++ = sin(two_pi/32*i + theta);
+    }
+    return twiddles_base_16(two_pi, out, 2*theta);
+}
+
+static float *twiddles_base_64(double two_pi, float *out) {
+    int i;
+    for (i=0; i<32; i++) {
+        *out++ = cos(two_pi/64*i);
+        *out++ = sin(two_pi/64*i);
+    }
+    return twiddles_base_32(two_pi, out, 0);
+}
+
+/****************************************************************************/
+
+static float *twiddles_step_16(double two_pi, float *out, double theta) {
+    int i;
+    for (i=0; i<16; i++) {
+        *out++ = ALPHA(theta*k[i]);
+        *out++ =  BETA(theta*k[i]);
+    }
+    return out;
+}
+
+static float *twiddles_step_32(double two_pi, float *out, double theta) {
+    int i;
+    for (i=0; i<16; i++) {
+        *out++ = ALPHA(theta);
+        *out++ =  BETA(theta);
+    }
+    return twiddles_step_16(two_pi, out, 2*theta);
+}
+
+static float *twiddles_step_64(double two_pi, float *out, double theta) {
+    int i;
+    for (i=0; i<32; i++) {
+        *out++ = ALPHA(theta);
+        *out++ =  BETA(theta);
+    }
+    return twiddles_step_32(two_pi, out, 2*theta);
+}
+
+/****************************************************************************/
+
+static void twiddles_256(double two_pi, float *out) {
+    double N=256;
+    int q;
+
+    out = twiddles_base_16(two_pi, out, 0);
+    out = twiddles_step_16(two_pi, out, two_pi/N * GPU_FFT_QPUS);
+
+    for (q=0; q<GPU_FFT_QPUS; q++)
+        out = twiddles_base_16(two_pi, out, two_pi/N*q);
+}
+
+static void twiddles_512(double two_pi, float *out) {
+    double N=512;
+    int q;
+
+    out = twiddles_base_32(two_pi, out, 0);
+    out = twiddles_step_16(two_pi, out, two_pi/N * GPU_FFT_QPUS);
+
+    for (q=0; q<GPU_FFT_QPUS; q++)
+        out = twiddles_base_16(two_pi, out, two_pi/N*q);
+}
+
+static void twiddles_1k(double two_pi, float *out) {
+    double N=1024;
+    int q;
+
+    out = twiddles_base_32(two_pi, out, 0);
+    out = twiddles_step_32(two_pi, out, two_pi/N * GPU_FFT_QPUS);
+
+    for (q=0; q<GPU_FFT_QPUS; q++)
+        out = twiddles_base_32(two_pi, out, two_pi/N*q);
+}
+
+static void twiddles_2k(double two_pi, float *out) {
+    double N=2048;
+    int q;
+
+    out = twiddles_base_64(two_pi, out);
+    out = twiddles_step_32(two_pi, out, two_pi/N * GPU_FFT_QPUS);
+
+    for (q=0; q<GPU_FFT_QPUS; q++)
+        out = twiddles_base_32(two_pi, out, two_pi/N*q);
+}
+
+static void twiddles_4k(double two_pi, float *out) {
+    double N=4096;
+    int q;
+
+    out = twiddles_base_16(two_pi, out, 0);
+    out = twiddles_step_16(two_pi, out, two_pi/N * 16);
+    out = twiddles_step_16(two_pi, out, two_pi/N * GPU_FFT_QPUS);
+
+    for (q=0; q<GPU_FFT_QPUS; q++)
+        out = twiddles_base_16(two_pi, out, two_pi/N*q);
+}
+
+static void twiddles_8k(double two_pi, float *out) {
+    double N=8192;
+    int q;
+
+    out = twiddles_base_32(two_pi, out, 0);
+    out = twiddles_step_16(two_pi, out, two_pi/N * 16);
+    out = twiddles_step_16(two_pi, out, two_pi/N * GPU_FFT_QPUS);
+
+    for (q=0; q<GPU_FFT_QPUS; q++)
+        out = twiddles_base_16(two_pi, out, two_pi/N*q);
+}
+
+static void twiddles_16k(double two_pi, float *out) {
+    double N=16384;
+    int q;
+
+    out = twiddles_base_32(two_pi, out, 0);
+    out = twiddles_step_32(two_pi, out, two_pi/N * 16);
+    out = twiddles_step_16(two_pi, out, two_pi/N * GPU_FFT_QPUS);
+
+    for (q=0; q<GPU_FFT_QPUS; q++)
+        out = twiddles_base_16(two_pi, out, two_pi/N*q);
+}
+
+static void twiddles_32k(double two_pi, float *out) {
+    double N=32768;
+    int q;
+
+    out = twiddles_base_32(two_pi, out, 0);
+    out = twiddles_step_32(two_pi, out, two_pi/N * 32);
+    out = twiddles_step_32(two_pi, out, two_pi/N * GPU_FFT_QPUS);
+
+    for (q=0; q<GPU_FFT_QPUS; q++)
+        out = twiddles_base_32(two_pi, out, two_pi/N*q);
+}
+
+static void twiddles_64k(double two_pi, float *out) {
+    double N=65536;
+    int q;
+
+    out = twiddles_base_64(two_pi, out);
+    out = twiddles_step_32(two_pi, out, two_pi/N * 32);
+    out = twiddles_step_32(two_pi, out, two_pi/N * GPU_FFT_QPUS);
+
+    for (q=0; q<GPU_FFT_QPUS; q++)
+        out = twiddles_base_32(two_pi, out, two_pi/N*q);
+}
+
+static void twiddles_128k(double two_pi, float *out) {
+    double N=128*1024;
+    int q;
+
+    out = twiddles_base_32(two_pi, out, 0);
+    out = twiddles_step_16(two_pi, out, two_pi/N * 16*16);
+    out = twiddles_step_16(two_pi, out, two_pi/N * 16);
+    out = twiddles_step_16(two_pi, out, two_pi/N * GPU_FFT_QPUS);
+
+    for (q=0; q<GPU_FFT_QPUS; q++)
+        out = twiddles_base_16(two_pi, out, two_pi/N*q);
+}
+
+static void twiddles_256k(double two_pi, float *out) {
+    double N=256*1024;
+    int q;
+
+    out = twiddles_base_32(two_pi, out, 0);
+    out = twiddles_step_16(two_pi, out, two_pi/N * 32*16);
+    out = twiddles_step_16(two_pi, out, two_pi/N * 32);
+    out = twiddles_step_32(two_pi, out, two_pi/N * GPU_FFT_QPUS);
+
+    for (q=0; q<GPU_FFT_QPUS; q++)
+        out = twiddles_base_32(two_pi, out, two_pi/N*q);
+}
+
+static void twiddles_512k(double two_pi, float *out) {
+    double N=512*1024;
+    int q;
+
+    out = twiddles_base_32(two_pi, out, 0);
+    out = twiddles_step_16(two_pi, out, two_pi/N * 32*32);
+    out = twiddles_step_32(two_pi, out, two_pi/N * 32);
+    out = twiddles_step_32(two_pi, out, two_pi/N * GPU_FFT_QPUS);
+
+    for (q=0; q<GPU_FFT_QPUS; q++)
+        out = twiddles_base_32(two_pi, out, two_pi/N*q);
+}
+
+static void twiddles_1024k(double two_pi, float *out) {
+    double N=1024*1024;
+    int q;
+
+    out = twiddles_base_32(two_pi, out, 0);
+    out = twiddles_step_32(two_pi, out, two_pi/N * 32*32);
+    out = twiddles_step_32(two_pi, out, two_pi/N * 32);
+    out = twiddles_step_32(two_pi, out, two_pi/N * GPU_FFT_QPUS);
+
+    for (q=0; q<GPU_FFT_QPUS; q++)
+        out = twiddles_base_32(two_pi, out, two_pi/N*q);
+}
+
+static void twiddles_2048k(double two_pi, float *out) {
+    double N=2048*1024;
+    int q;
+
+    out = twiddles_base_64(two_pi, out);
+    out = twiddles_step_32(two_pi, out, two_pi/N * 32*32);
+    out = twiddles_step_32(two_pi, out, two_pi/N * 32);
+    out = twiddles_step_32(two_pi, out, two_pi/N * GPU_FFT_QPUS);
+
+    for (q=0; q<GPU_FFT_QPUS; q++)
+        out = twiddles_base_32(two_pi, out, two_pi/N*q);
+}
+
+static void twiddles_4096k(double two_pi, float *out) {
+    double N=4096*1024;
+    int q;
+
+    out = twiddles_base_64(two_pi, out);
+    out = twiddles_step_64(two_pi, out, two_pi/N * 32*32);
+    out = twiddles_step_32(two_pi, out, two_pi/N * 32);
+    out = twiddles_step_32(two_pi, out, two_pi/N * GPU_FFT_QPUS);
+
+    for (q=0; q<GPU_FFT_QPUS; q++)
+        out = twiddles_base_32(two_pi, out, two_pi/N*q);
+}
+
+/****************************************************************************/
+
+static struct {
+    int passes, shared, unique;
+    void (*twiddles)(double, float *);
+}
+shaders[] = {
+    {2, 2, 1, twiddles_256},
+    {2, 3, 1, twiddles_512},
+    {2, 4, 2, twiddles_1k},
+    {2, 6, 2, twiddles_2k},
+    {3, 3, 1, twiddles_4k},
+    {3, 4, 1, twiddles_8k},
+    {3, 5, 1, twiddles_16k},
+    {3, 6, 2, twiddles_32k},
+    {3, 8, 2, twiddles_64k},
+    {4, 5, 1, twiddles_128k},
+    {4, 6, 2, twiddles_256k},
+    {4, 7, 2, twiddles_512k},
+    {4, 8, 2, twiddles_1024k},
+    {4,10, 2, twiddles_2048k},
+    {4,12, 2, twiddles_4096k}
+};
+
+int gpu_fft_twiddle_size(int log2_N, int *shared, int *unique, int *passes) {
+    if (log2_N<8 || log2_N>22) return -1;
+    *shared = shaders[log2_N-8].shared;
+    *unique = shaders[log2_N-8].unique;
+    *passes = shaders[log2_N-8].passes;
+    return 0;
+}
+
+void gpu_fft_twiddle_data(int log2_N, int direction, float *out) {
+    shaders[log2_N-8].twiddles((direction==GPU_FFT_FWD?-2:2)*GPU_FFT_PI, out);
+}
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/hello_fft.c b/host_applications/linux/apps/hello_pi/hello_fft/hello_fft.c
new file mode 100755 (executable)
index 0000000..90317a4
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+BCM2835 "GPU_FFT" release 3.0
+Copyright (c) 2015, Andrew Holme.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <math.h>
+#include <time.h>
+
+#include "mailbox.h"
+#include "gpu_fft.h"
+
+char Usage[] =
+    "Usage: hello_fft.bin log2_N [jobs [loops]]\n"
+    "log2_N = log2(FFT_length),       log2_N = 8...22\n"
+    "jobs   = transforms per batch,   jobs>0,        default 1\n"
+    "loops  = number of test repeats, loops>0,       default 1\n";
+
+unsigned Microseconds(void) {
+    struct timespec ts;
+    clock_gettime(CLOCK_REALTIME, &ts);
+    return ts.tv_sec*1000000 + ts.tv_nsec/1000;
+}
+
+int main(int argc, char *argv[]) {
+    int i, j, k, ret, loops, freq, log2_N, jobs, N, mb = mbox_open();
+    unsigned t[2];
+    double tsq[2];
+
+    struct GPU_FFT_COMPLEX *base;
+    struct GPU_FFT *fft;
+
+    log2_N = argc>1? atoi(argv[1]) : 12; // 8 <= log2_N <= 22
+    jobs   = argc>2? atoi(argv[2]) : 1;  // transforms per batch
+    loops  = argc>3? atoi(argv[3]) : 1;  // test repetitions
+
+    if (argc<2 || jobs<1 || loops<1) {
+        printf(Usage);
+        return -1;
+    }
+
+    N = 1<<log2_N; // FFT length
+    ret = gpu_fft_prepare(mb, log2_N, GPU_FFT_REV, jobs, &fft); // call once
+
+    switch(ret) {
+        case -1: printf("Unable to enable V3D. Please check your firmware is up to date.\n"); return -1;
+        case -2: printf("log2_N=%d not supported.  Try between 8 and 22.\n", log2_N);         return -1;
+        case -3: printf("Out of memory.  Try a smaller batch or increase GPU memory.\n");     return -1;
+        case -4: printf("Unable to map Videocore peripherals into ARM memory space.\n");      return -1;
+        case -5: printf("Can't open libbcm_host.\n");                                         return -1;
+    }
+
+    for (k=0; k<loops; k++) {
+
+        for (j=0; j<jobs; j++) {
+            base = fft->in + j*fft->step; // input buffer
+            for (i=0; i<N; i++) base[i].re = base[i].im = 0;
+            freq = j+1;
+            base[freq].re = base[N-freq].re = 0.5;
+        }
+
+        usleep(1); // Yield to OS
+        t[0] = Microseconds();
+        gpu_fft_execute(fft); // call one or many times
+        t[1] = Microseconds();
+
+        tsq[0]=tsq[1]=0;
+        for (j=0; j<jobs; j++) {
+            base = fft->out + j*fft->step; // output buffer
+            freq = j+1;
+            for (i=0; i<N; i++) {
+                double re = cos(2*GPU_FFT_PI*freq*i/N);
+                tsq[0] += pow(re, 2);
+                tsq[1] += pow(re - base[i].re, 2) + pow(base[i].im, 2);
+            }
+        }
+
+        printf("rel_rms_err = %0.2g, usecs = %d, k = %d\n",
+            sqrt(tsq[1]/tsq[0]), (t[1]-t[0])/jobs, k);
+    }
+
+    gpu_fft_release(fft); // Videocore memory lost if not freed !
+    return 0;
+}
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/hello_fft_2d.c b/host_applications/linux/apps/hello_pi/hello_fft/hello_fft_2d.c
new file mode 100755 (executable)
index 0000000..5a35675
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+BCM2835 "GPU_FFT" release 2.0
+Copyright (c) 2014, Andrew Holme.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "gpu_fft_trans.h"
+#include "hello_fft_2d_bitmap.h"
+
+#define log2_N 9
+#define N (1<<log2_N)
+
+#define GPU_FFT_ROW(fft, io, y) ((fft)->io+(fft)->step*(y))
+
+unsigned Microseconds(void) {
+    struct timespec ts;
+    clock_gettime(CLOCK_REALTIME, &ts);
+    return ts.tv_sec*1000000 + ts.tv_nsec/1000;
+}
+
+int main(int argc, char *argv[]) {
+    int x, y, ret, mb = mbox_open();
+    unsigned t[4];
+
+    struct GPU_FFT_COMPLEX *row;
+    struct GPU_FFT_TRANS *trans;
+    struct GPU_FFT *fft_pass[2];
+
+    BITMAPFILEHEADER bfh;
+    BITMAPINFOHEADER bih;
+
+    // Create Windows bitmap file
+    FILE *fp = fopen("hello_fft_2d.bmp", "wb");
+    if (!fp) return -666;
+
+    // Write bitmap header
+    memset(&bfh, 0, sizeof(bfh));
+    bfh.bfType = 0x4D42; //"BM"
+    bfh.bfSize = N*N*3;
+    bfh.bfOffBits = sizeof(bfh) + sizeof(bih);
+    fwrite(&bfh, sizeof(bfh), 1, fp);
+
+    // Write bitmap info
+    memset(&bih, 0, sizeof(bih));
+    bih.biSize = sizeof(bih);
+    bih.biWidth = N;
+    bih.biHeight = N;
+    bih.biPlanes = 1;
+    bih.biBitCount = 24;
+    bih.biCompression = BI_RGB;
+    fwrite(&bih, sizeof(bih), 1, fp);
+
+    // Prepare 1st FFT pass
+    ret = gpu_fft_prepare(mb, log2_N, GPU_FFT_REV, N, fft_pass+0);
+    if (ret) {
+        return ret;
+    }
+    // Prepare 2nd FFT pass
+    ret = gpu_fft_prepare(mb, log2_N, GPU_FFT_REV, N, fft_pass+1);
+    if (ret) {
+        gpu_fft_release(fft_pass[0]);
+        return ret;
+    }
+    // Transpose from 1st pass output to 2nd pass input
+    ret = gpu_fft_trans_prepare(mb, fft_pass[0], fft_pass[1], &trans);
+    if (ret) {
+        gpu_fft_release(fft_pass[0]);
+        gpu_fft_release(fft_pass[1]);
+        return ret;
+    }
+
+    // Clear input array
+    for (y=0; y<N; y++) {
+        row = GPU_FFT_ROW(fft_pass[0], in, y);
+        for (x=0; x<N; x++) row[x].re = row[x].im = 0;
+    }
+
+    // Setup input data
+    GPU_FFT_ROW(fft_pass[0], in,   2)[  2].re = 60;
+    GPU_FFT_ROW(fft_pass[0], in, N-2)[N-2].re = 60;
+
+    // ==> FFT() ==> T() ==> FFT() ==>
+    usleep(1); /* yield to OS */   t[0] = Microseconds();
+    gpu_fft_execute(fft_pass[0]);  t[1] = Microseconds();
+    gpu_fft_trans_execute(trans);  t[2] = Microseconds();
+    gpu_fft_execute(fft_pass[1]);  t[3] = Microseconds();
+
+    // Write output to bmp file
+    for (y=0; y<N; y++) {
+        row = GPU_FFT_ROW(fft_pass[1], out, y);
+        for (x=0; x<N; x++) {
+            fputc(128+row[x].re, fp); // blue
+            fputc(128+row[x].re, fp); // green
+            fputc(128+row[x].re, fp); // red
+        }
+    }
+
+    printf( "1st FFT   %6d usecs\n"
+            "Transpose %6d usecs\n"
+            "2nd FFT   %6d usecs\n",
+            t[3]-t[2], t[2]-t[1], t[1]-t[0]);
+
+    // Clean-up properly.  Videocore memory lost if not freed !
+    gpu_fft_release(fft_pass[0]);
+    gpu_fft_release(fft_pass[1]);
+    gpu_fft_trans_release(trans);
+
+    return 0;
+}
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/hello_fft_2d_bitmap.h b/host_applications/linux/apps/hello_pi/hello_fft/hello_fft_2d_bitmap.h
new file mode 100755 (executable)
index 0000000..177ee89
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+typedef struct __attribute__((packed)) {
+    unsigned short bfType;           /* Magic number for file */
+    unsigned int   bfSize;           /* Size of file */
+    unsigned short bfReserved1;      /* Reserved */
+    unsigned short bfReserved2;      /* ... */
+    unsigned int   bfOffBits;        /* Offset to bitmap data */
+} BITMAPFILEHEADER;
+
+typedef struct __attribute__((packed)) {
+    unsigned int   biSize;           /* Size of info header */
+    int            biWidth;          /* Width of image */
+    int            biHeight;         /* Height of image */
+    unsigned short biPlanes;         /* Number of color planes */
+    unsigned short biBitCount;       /* Number of bits per pixel */
+    unsigned int   biCompression;    /* Type of compression to use */
+    unsigned int   biSizeImage;      /* Size of image data */
+    int            biXPelsPerMeter;  /* X pixels per meter */
+    int            biYPelsPerMeter;  /* Y pixels per meter */
+    unsigned int   biClrUsed;        /* Number of colors used */
+    unsigned int   biClrImportant;   /* Number of important colors */
+} BITMAPINFOHEADER;
+
+/*
+ * Constant for the biCompression field...
+ */
+
+#  define BI_RGB       0             /* No compression - straight BGR data */
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_1024k.hex b/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_1024k.hex
new file mode 100755 (executable)
index 0000000..bad96b5
--- /dev/null
@@ -0,0 +1,948 @@
+0x00000014, 0xe0021227, // mov rb_STAGES,  STAGES
+0x00000010, 0xe00216e7, // mov rb_0x10,    0x10
+0x00000040, 0xe0021727, // mov rb_0x40,    0x40
+0x00000080, 0xe0021767, // mov rb_0x80,    0x80
+0x000000f0, 0xe00217a7, // mov rb_0xF0,    0xF0
+0x00000100, 0xe00217e7, // mov rb_0x100,   0x100
+0x55555555, 0xe0020767, // mov rx_0x55555555, 0x55555555
+0x33333333, 0xe00207a7, // mov rx_0x33333333, 0x33333333
+0x0f0f0f0f, 0xe00207e7, // mov rx_0x0F0F0F0F, 0x0F0F0F0F
+0x00ff00ff, 0xe0021027, // mov rx_0x00FF00FF, 0x00FF00FF
+0x0000ffff, 0xe00216a7, // mov rx_0x0000FFFF, 0x0000FFFF
+0x80904000, 0xe0020727, // mov ra_vdw_32, vdw_setup_0(1, 16, dma_h32( 0,0))
+0x80905000, 0xe0021067, // mov rb_vdw_32, vdw_setup_0(1, 16, dma_h32(32,0))
+0x15827d80, 0x100202e7, // mov rx_tw_shared, unif
+0x15827d80, 0x100212e7, // mov rx_tw_unique, unif
+0x15827d80, 0x10021167, // mov rb_inst, unif
+0x00101200, 0xe0020827, // mov r0, vpm_setup(1, 1, v32( 0,0))
+0x00000010, 0xe0020867, // mov r1, vpm_setup(1, 1, v32(16,0)) - vpm_setup(1, 1, v32(0,0))
+0x00000002, 0xe00208a7, // mov r2, vpm_setup(1, 1, v32( 0,2)) - vpm_setup(1, 1, v32(0,0))
+0x409c5017, 0x100049e2, // nop; mul24 r2, r2, in_inst
+0xcc9e7081, 0x100246a0, // add out_0, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100246e0, // add out_1, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100250a0, // add out_2, r0, r2; v8adds r0, r0, r1
+0x0c9e7080, 0x100211e7, // add out_3, r0, r2
+0x000002e8, 0xf0f802a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x156a7d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x156e7d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x15727d80, 0x10020827, // mov r0, ra_vdw_32
+0x8c05cdf6, 0x10024061, // add ra_save_ptr, ra_save_ptr, rb_0x40; mov r1, ra_save_ptr
+0x00000080, 0xe00208a7, // mov r2, vdw_setup_0(1, 16, dma_h32(1,0)) - vdw_setup_0(1, 16, dma_h32(0,0))
+0x00040000, 0xe00208e7, // mov r3, PASS32_STRIDE
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000050, 0xf0f812a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x156a7d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x156e7d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x00000000, 0xf0f4c9e7, // bra -, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x156a7d80, 0x10020c67, // mov vr_setup, ra_vpm_lo
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x00000080, 0xf0f801a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x000005d8, 0xf0f811a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000009, 0xe80009e7, // mov -, srel(i+9)
+0x00000011, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000a, 0xe80009e7, // mov -, srel(i+9)
+0x00000012, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000b, 0xe80009e7, // mov -, srel(i+9)
+0x00000013, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000c, 0xe80009e7, // mov -, srel(i+9)
+0x00000014, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000d, 0xe80009e7, // mov -, srel(i+9)
+0x00000015, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000e, 0xe80009e7, // mov -, srel(i+9)
+0x00000016, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000f, 0xe80009e7, // mov -, srel(i+9)
+0x00000017, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x203a7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209ce039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208ecb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x203a7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819ff2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f1400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829ff609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f1449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x203e7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209cf039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208fcb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x203e7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fe2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f2400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fe609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f2449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20427030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d0039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22090cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20427031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fc2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f4400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fc609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f4449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20467030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d1039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22091cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20467031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819f82c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f8400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x00000000, 0xf0f409e7, // bra -, ra_link_0
+0x829f8609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f8449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x8c15edf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149c01c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149c01c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149da1c0, 0x10020867, // and r1, r0, mask
+0x0e9db1c0, 0x10020827, // shr r0, r0, shift
+0x149da1c0, 0x10020827, // and r0, r0, mask
+0x119db3c0, 0x10020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c91c0, 0xd0020827, // shr r0, r0, 32-STAGES-3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffd78, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149c01c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149c01c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149da1c0, 0x10020867, // and r1, r0, mask
+0x0e9db1c0, 0x10020827, // shr r0, r0, shift
+0x149da1c0, 0x10020827, // and r0, r0, mask
+0x119db3c0, 0x10020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c91c0, 0xd0020827, // shr r0, r0, 32-STAGES-3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffc30, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x204e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d300f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x204e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22093c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x00000000, 0xf0f549e7, // bra -, ra_save_32
+0x95682ff6, 0x10024682, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x956c7ff6, 0x100246c7, // mov ra_vpm_hi, rb_vpm_hi; mov rb_vpm_hi, ra_vpm_hi
+0x95701ff6, 0x10024701, // mov ra_vdw_32, rb_vdw_32; mov rb_vdw_32, ra_vdw_32
+0x8c15edf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffba0, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffb50, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x204e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d300f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x204e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22093c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x00000000, 0xf0f549e7, // bra -, ra_save_32
+0x95682ff6, 0x10024682, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x956c7ff6, 0x100246c7, // mov ra_vpm_hi, rb_vpm_hi; mov rb_vpm_hi, ra_vpm_hi
+0x95701ff6, 0x10024701, // mov ra_vdw_32, rb_vdw_32; mov rb_vdw_32, ra_vdw_32
+0x159c5fc0, 0x10022827, // mov.setf r0, rb_inst
+0x0d9c11c0, 0xd0020827, // sub r0, r0, 1
+0x119c51c0, 0xd0020827, // shl r0, r0, 5
+0x0c9c6e00, 0x100601a7, // add.ifnz ra_sync, rx_sync_slave, r0
+0x159cafc0, 0x100602a7, // mov.ifnz ra_save_32, rx_save_slave_32
+0x15827d80, 0x100220e7, // mov.setf ra_addr_x, unif
+0x15827d80, 0x100210e7, // mov      rb_addr_y, unif
+0x00001258, 0xf00809e7, // brr.allz -, r:end
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100204e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100214e7, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149c01c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149c01c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149da1c0, 0x10020867, // and r1, r0, mask
+0x0e9db1c0, 0x10020827, // shr r0, r0, shift
+0x149da1c0, 0x10020827, // and r0, r0, mask
+0x119db3c0, 0x10020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c91c0, 0xd0020827, // shr r0, r0, 32-STAGES-3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff998, 0xf0f80227, // brr ra_link_1, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x0e1c8dc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0xfffff970, 0xf00809e7, // brr.allz -, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100204e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100214e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000003, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020327, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021327, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000002, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020367, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021367, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff9d0, 0xf0f80227, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x00007fff, 0xe0020827, // mov r0, 0x7FFF
+0x141e7c00, 0x100229e7, // and.setf -, ra_points, r0
+0xfffff9a0, 0xf01809e7, // brr.allnz -, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100601e7, // add.ifnz ra_points, ra_points, rb_0x100
+0x954d3dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20367016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cd017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cd01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2136709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x024e7c80, 0x10020827, // fsub r0,  a, b
+0x024e7180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x024e7c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x01527380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025893, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x024e7c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10020527, // fadd a+1, r0, r1
+0x029d3ec0, 0x10020827, // fsub r0,  a, b
+0x029d31c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d3e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d43c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024893, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d3e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10021527, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20327016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cc017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cc01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2132709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02467c80, 0x10020827, // fsub r0,  a, b
+0x02467180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02467c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x014a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02467c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100204a7, // fadd a+1, r0, r1
+0x029d1ec0, 0x10020827, // fsub r0,  a, b
+0x029d11c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d1e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d23c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d1e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100214a7, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1c8dc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0xfffff710, 0xf00809e7, // brr.allz -, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100204e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100214e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000005, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020327, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021327, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000004, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020367, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021367, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff4a0, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0xfffff480, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0xfffff460, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0xfffff440, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x954d3dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20367016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cd017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cd01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2136709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x024e7c80, 0x10020827, // fsub r0,  a, b
+0x024e7180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x024e7c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x01527380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025893, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x024e7c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10020527, // fadd a+1, r0, r1
+0x029d3ec0, 0x10020827, // fsub r0,  a, b
+0x029d31c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d3e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d43c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024893, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d3e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10021527, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20327016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cc017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cc01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2132709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02467c80, 0x10020827, // fsub r0,  a, b
+0x02467180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02467c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x014a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02467c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100204a7, // fadd a+1, r0, r1
+0x029d1ec0, 0x10020827, // fsub r0,  a, b
+0x029d11c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d1e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d23c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d1e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100214a7, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1c8dc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0xfffff1b0, 0xf00809e7, // brr.allz -, r:pass_3
+0x00000060, 0xe0020827, // mov r0, 3*4*8
+0x0d227c00, 0x10020227, // sub ra_link_1, ra_link_1, r0
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9cbe00, 0x10020e27, // add t0s, ptr, r0
+0x0c9cbe40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9cbe00, 0x10020e27, // add t0s, ptr, r0
+0x0c9cbe40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100204e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100214e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000007, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020327, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021327, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000006, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020367, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021367, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xffffef40, 0xf0f80227, // brr ra_link_1, r:pass_4
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x954d3dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20367016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cd017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cd01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2136709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x024e7c80, 0x10020827, // fsub r0,  a, b
+0x024e7180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x024e7c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x01527380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025893, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x024e7c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10020527, // fadd a+1, r0, r1
+0x029d3ec0, 0x10020827, // fsub r0,  a, b
+0x029d31c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d3e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d43c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024893, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d3e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10021527, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20327016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cc017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cc01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2132709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02467c80, 0x10020827, // fsub r0,  a, b
+0x02467180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02467c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x014a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02467c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100204a7, // fadd a+1, r0, r1
+0x029d1ec0, 0x10020827, // fsub r0,  a, b
+0x029d11c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d1e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d23c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d1e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100214a7, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1c8dc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0xffffecb0, 0xf00809e7, // brr.allz -, r:pass_4
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0xffffed78, 0xf0f809e7, // brr -, r:loop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c3fc0, 0x100209a7, // mov interrupt, flag
+0x009e7000, 0x300009e7, // nop; nop; thrend
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_128k.hex b/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_128k.hex
new file mode 100755 (executable)
index 0000000..6b82f92
--- /dev/null
@@ -0,0 +1,735 @@
+0x00000011, 0xe0021227, // mov rb_STAGES,  STAGES
+0x00000010, 0xe00216a7, // mov rb_0x10,    0x10
+0x00000040, 0xe00216e7, // mov rb_0x40,    0x40
+0x00000080, 0xe0021727, // mov rb_0x80,    0x80
+0x000000f0, 0xe0021767, // mov rb_0xF0,    0xF0
+0x00000100, 0xe00217a7, // mov rb_0x100,   0x100
+0x00000fff, 0xe00217e7, // mov rb_0xFFF,   0xFFF
+0x55555555, 0xe0020767, // mov rx_0x55555555, 0x55555555
+0x33333333, 0xe00207a7, // mov rx_0x33333333, 0x33333333
+0x0f0f0f0f, 0xe00207e7, // mov rx_0x0F0F0F0F, 0x0F0F0F0F
+0x00ff00ff, 0xe0021627, // mov rx_0x00FF00FF, 0x00FF00FF
+0x0000ffff, 0xe0021667, // mov rx_0x0000FFFF, 0x0000FFFF
+0x88104000, 0xe00206e7, // mov ra_vdw_16, vdw_setup_0(16, 16, dma_h32( 0,0))
+0x88105000, 0xe0021027, // mov rb_vdw_16, vdw_setup_0(16, 16, dma_h32(32,0))
+0x90104000, 0xe0020727, // mov ra_vdw_32, vdw_setup_0(32, 16, dma_h32( 0,0))
+0x90105000, 0xe0021067, // mov rb_vdw_32, vdw_setup_0(32, 16, dma_h32(32,0))
+0x15827d80, 0x100202e7, // mov rx_tw_shared, unif
+0x15827d80, 0x100212e7, // mov rx_tw_unique, unif
+0x15827d80, 0x10021167, // mov rb_inst, unif
+0x00101200, 0xe0020827, // mov r0, vpm_setup(1, 1, v32( 0,0))
+0x00000010, 0xe0020867, // mov r1, vpm_setup(1, 1, v32(16,0)) - vpm_setup(1, 1, v32(0,0))
+0x00000002, 0xe00208a7, // mov r2, vpm_setup(1, 1, v32( 0,2)) - vpm_setup(1, 1, v32(0,0))
+0x409c5017, 0x100049e2, // nop; mul24 r2, r2, in_inst
+0xcc9e7081, 0x10024660, // add out_0, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100246a0, // add out_1, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100250a0, // add out_2, r0, r2; v8adds r0, r0, r1
+0x0c9e7080, 0x100211e7, // add out_3, r0, r2
+0x000000b0, 0xf0f80127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10021c67, // mov vw_setup, arg
+0x159e7000, 0x10020c27, // mov vpm, r0
+0x159e7240, 0x10020c27, // mov vpm, r1
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x156e7d80, 0x10021c67, // mov vw_setup, arg_vdw
+0xc000ffc0, 0xe0021c67, // mov vw_setup, vdw_setup_1(0) + PASS16_STRIDE-16*4
+0x8c05bdf6, 0x10024072, // add ra_save_ptr, ra_save_ptr, rb_0x40; mov vw_addr, ra_save_ptr
+0x00000038, 0xf0f81127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10021c67, // mov vw_setup, arg
+0x159e7000, 0x10020c27, // mov vpm, r0
+0x159e7240, 0x10020c27, // mov vpm, r1
+0x00000000, 0xf0f4c9e7, // bra -, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10020c67, // mov vr_setup, arg_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x000000c8, 0xf0f802a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x156a7d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x15727d80, 0x10021c67, // mov vw_setup, ra_vdw_32
+0xc0007fc0, 0xe0021c67, // mov vw_setup, vdw_setup_1(0) + PASS32_STRIDE-16*4
+0x8c05bdf6, 0x10024072, // add ra_save_ptr, ra_save_ptr, rb_0x40; mov vw_addr, ra_save_ptr
+0x00000050, 0xf0f812a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x156a7d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x00000000, 0xf0f4c9e7, // bra -, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10020c67, // mov vr_setup, ra_vpm_lo
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x00000080, 0xf0f801a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000560, 0xf0f811a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000009, 0xe80009e7, // mov -, srel(i+9)
+0x00000011, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000a, 0xe80009e7, // mov -, srel(i+9)
+0x00000012, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000b, 0xe80009e7, // mov -, srel(i+9)
+0x00000013, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000c, 0xe80009e7, // mov -, srel(i+9)
+0x00000014, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000d, 0xe80009e7, // mov -, srel(i+9)
+0x00000015, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000e, 0xe80009e7, // mov -, srel(i+9)
+0x00000016, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000f, 0xe80009e7, // mov -, srel(i+9)
+0x00000017, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x203a7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209ce039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208ecb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x203a7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819ff2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f1400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829ff609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f1449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x203e7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209cf039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208fcb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x203e7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fe2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f2400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fe609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f2449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20427030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d0039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22090cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20427031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fc2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f4400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fc609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f4449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20467030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d1039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22091cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20467031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819f82c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f8400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x00000000, 0xf0f409e7, // bra -, ra_link_0
+0x829f8609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f8449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x8c15ddf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149d81c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149d81c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149d91c0, 0x10020867, // and r1, r0, mask
+0x0e9da1c0, 0x10020827, // shr r0, r0, shift
+0x149d91c0, 0x10020827, // and r0, r0, mask
+0x119da3c0, 0x10020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9cc1c0, 0xd0020827, // shr r0, r0, 32-STAGES-3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffd78, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c15adf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149d81c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149d81c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149d91c0, 0x10020867, // and r1, r0, mask
+0x0e9da1c0, 0x10020827, // shr r0, r0, shift
+0x149d91c0, 0x10020827, // and r0, r0, mask
+0x119da3c0, 0x10020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9cc1c0, 0xd0020827, // shr r0, r0, 32-STAGES-3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffc30, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x204e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d300f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x204e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22093c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x00000000, 0xf0f549e7, // bra -, ra_save_32
+0x95642ff6, 0x10024642, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x95687ff6, 0x10024687, // mov ra_vpm_hi, rb_vpm_hi; mov rb_vpm_hi, ra_vpm_hi
+0x95701ff6, 0x10024701, // mov ra_vdw_32, rb_vdw_32; mov rb_vdw_32, ra_vdw_32
+0x8c15cdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffba0, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x00000000, 0xf0f489e7, // bra -, ra_save_16
+0x009e7000, 0x100009e7, // nop
+0x95642ff6, 0x10024642, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x956c0ff6, 0x100246c0, // mov ra_vdw_16, rb_vdw_16; mov rb_vdw_16, ra_vdw_16
+0x159c5fc0, 0x10022827, // mov.setf r0, rb_inst
+0x0d9c11c0, 0xd0020827, // sub r0, r0, 1
+0x119c51c0, 0xd0020827, // shl r0, r0, 5
+0x0c9c6e00, 0x100601a7, // add.ifnz ra_sync, rx_sync_slave, r0
+0x159c4fc0, 0x10060127, // mov.ifnz ra_save_16, rx_save_slave_16
+0x159cafc0, 0x100602a7, // mov.ifnz ra_save_32, rx_save_slave_32
+0x15827d80, 0x100220e7, // mov.setf ra_addr_x, unif
+0x15827d80, 0x100210e7, // mov      rb_addr_y, unif
+0x00000d00, 0xf00809e7, // brr.allz -, r:end
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100204e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100214e7, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15adf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149d81c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149d81c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149d91c0, 0x10020867, // and r1, r0, mask
+0x0e9da1c0, 0x10020827, // shr r0, r0, shift
+0x149d91c0, 0x10020827, // and r0, r0, mask
+0x119da3c0, 0x10020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9cc1c0, 0xd0020827, // shr r0, r0, 32-STAGES-3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffa08, 0xf0f80227, // brr ra_link_1, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dedc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x0e1c8dc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0xfffff9e0, 0xf00809e7, // brr.allz -, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dedc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000002, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020327, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021327, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c41c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15cdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffaf0, 0xf0f80227, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dcdc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x141dfdc0, 0x100229e7, // and.setf -, ra_points, rb_0xFFF
+0xfffffac8, 0xf01809e7, // brr.allnz -, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dcdc0, 0x100601e7, // add.ifnz ra_points, ra_points, rb_0x80
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20327016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cc017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cc01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2132709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02467c80, 0x10020827, // fsub r0,  a, b
+0x02467180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02467c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x014a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02467c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100204a7, // fadd a+1, r0, r1
+0x029d1ec0, 0x10020827, // fsub r0,  a, b
+0x029d11c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d1e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d23c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d1e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100214a7, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1c8dc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0xfffff938, 0xf00809e7, // brr.allz -, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dcdc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000003, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020327, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021327, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c41c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15cdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff778, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dcdc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0xfffff758, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dcdc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20327016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cc017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cc01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2132709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02467c80, 0x10020827, // fsub r0,  a, b
+0x02467180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02467c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x014a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02467c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100204a7, // fadd a+1, r0, r1
+0x029d1ec0, 0x10020827, // fsub r0,  a, b
+0x029d11c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d1e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d23c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d1e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100214a7, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1c8dc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0xfffff5c8, 0xf00809e7, // brr.allz -, r:pass_3
+0x00000020, 0xe0020827, // mov r0, 4*8
+0x0d227c00, 0x10020227, // sub ra_link_1, ra_link_1, r0
+0x0c1dcdc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9cbe00, 0x10020e27, // add t0s, ptr, r0
+0x0c9cbe40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000004, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020327, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021327, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c41c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15cdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff408, 0xf0f80227, // brr ra_link_1, r:pass_4
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dcdc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20327016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cc017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cc01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2132709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02467c80, 0x10020827, // fsub r0,  a, b
+0x02467180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02467c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x014a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02467c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100204a7, // fadd a+1, r0, r1
+0x029d1ec0, 0x10020827, // fsub r0,  a, b
+0x029d11c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d1e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d23c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d1e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100214a7, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1c8dc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0xfffff278, 0xf00809e7, // brr.allz -, r:pass_4
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dcdc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0xfffff2d0, 0xf0f809e7, // brr -, r:loop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c3fc0, 0x100209a7, // mov interrupt, flag
+0x009e7000, 0x300009e7, // nop; nop; thrend
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_16k.hex b/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_16k.hex
new file mode 100755 (executable)
index 0000000..160d783
--- /dev/null
@@ -0,0 +1,688 @@
+0x00000010, 0xe00216e7, // mov rb_0x10,    0x10
+0x00000040, 0xe0021727, // mov rb_0x40,    0x40
+0x00000080, 0xe0021767, // mov rb_0x80,    0x80
+0x000000f0, 0xe00217a7, // mov rb_0xF0,    0xF0
+0x00000100, 0xe00217e7, // mov rb_0x100,   0x100
+0x00005555, 0xe0020767, // mov rx_0x5555,  0x5555
+0x00003333, 0xe00207a7, // mov rx_0x3333,  0x3333
+0x00000f0f, 0xe00207e7, // mov rx_0x0F0F,  0x0F0F
+0x000000ff, 0xe00216a7, // mov rx_0x00FF,  0x00FF
+0x88104000, 0xe00206e7, // mov ra_vdw_16, vdw_setup_0(16, 16, dma_h32( 0,0))
+0x88105000, 0xe0021027, // mov rb_vdw_16, vdw_setup_0(16, 16, dma_h32(32,0))
+0x90104000, 0xe0020727, // mov ra_vdw_32, vdw_setup_0(32, 16, dma_h32( 0,0))
+0x90105000, 0xe0021067, // mov rb_vdw_32, vdw_setup_0(32, 16, dma_h32(32,0))
+0x15827d80, 0x100202e7, // mov rx_tw_shared, unif
+0x15827d80, 0x100212e7, // mov rx_tw_unique, unif
+0x15827d80, 0x10021167, // mov rb_inst, unif
+0x00101200, 0xe0020827, // mov r0, vpm_setup(1, 1, v32( 0,0))
+0x00000010, 0xe0020867, // mov r1, vpm_setup(1, 1, v32(16,0)) - vpm_setup(1, 1, v32(0,0))
+0x00000002, 0xe00208a7, // mov r2, vpm_setup(1, 1, v32( 0,2)) - vpm_setup(1, 1, v32(0,0))
+0x409c5017, 0x100049e2, // nop; mul24 r2, r2, in_inst
+0xcc9e7081, 0x10024660, // add out_0, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100246a0, // add out_1, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100250a0, // add out_2, r0, r2; v8adds r0, r0, r1
+0x0c9e7080, 0x100211e7, // add out_3, r0, r2
+0x000000b0, 0xf0f80127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10021c67, // mov vw_setup, arg
+0x159e7000, 0x10020c27, // mov vpm, r0
+0x159e7240, 0x10020c27, // mov vpm, r1
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x156e7d80, 0x10021c67, // mov vw_setup, arg_vdw
+0xc0001fc0, 0xe0021c67, // mov vw_setup, vdw_setup_1(0) + PASS16_STRIDE-16*4
+0x8c05cdf6, 0x10024072, // add ra_save_ptr, ra_save_ptr, rb_0x40; mov vw_addr, ra_save_ptr
+0x00000038, 0xf0f81127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10021c67, // mov vw_setup, arg
+0x159e7000, 0x10020c27, // mov vpm, r0
+0x159e7240, 0x10020c27, // mov vpm, r1
+0x00000000, 0xf0f4c9e7, // bra -, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10020c67, // mov vr_setup, arg_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x000000c8, 0xf0f802a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x156a7d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x15727d80, 0x10021c67, // mov vw_setup, ra_vdw_32
+0xc0000fc0, 0xe0021c67, // mov vw_setup, vdw_setup_1(0) + PASS32_STRIDE-16*4
+0x8c05cdf6, 0x10024072, // add ra_save_ptr, ra_save_ptr, rb_0x40; mov vw_addr, ra_save_ptr
+0x00000050, 0xf0f812a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x156a7d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x00000000, 0xf0f4c9e7, // bra -, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10020c67, // mov vr_setup, ra_vpm_lo
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x00000080, 0xf0f801a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x000005f0, 0xf0f811a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000009, 0xe80009e7, // mov -, srel(i+9)
+0x00000011, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000a, 0xe80009e7, // mov -, srel(i+9)
+0x00000012, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000b, 0xe80009e7, // mov -, srel(i+9)
+0x00000013, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000c, 0xe80009e7, // mov -, srel(i+9)
+0x00000014, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000d, 0xe80009e7, // mov -, srel(i+9)
+0x00000015, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000e, 0xe80009e7, // mov -, srel(i+9)
+0x00000016, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000f, 0xe80009e7, // mov -, srel(i+9)
+0x00000017, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x203a7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209ce039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208ecb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x203a7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819ff2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f1400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829ff609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f1449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x203e7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209cf039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208fcb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x203e7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fe2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f2400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fe609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f2449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20427030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d0039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22090cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20427031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fc2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f4400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fc609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f4449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20467030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d1039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22091cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20467031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819f82c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f8400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x00000000, 0xf0f409e7, // bra -, ra_link_0
+0x829f8609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f8449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x8c15edf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149da1c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149da1c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x119c11c0, 0xd0020827, // shl r0, r0, STAGES-13
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffda0, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149da1c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149da1c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x119c11c0, 0xd0020827, // shl r0, r0, STAGES-13
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffc80, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x204e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d300f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x204e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22093c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x00000000, 0xf0f549e7, // bra -, ra_save_32
+0x95642ff6, 0x10024642, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x95687ff6, 0x10024687, // mov ra_vpm_hi, rb_vpm_hi; mov rb_vpm_hi, ra_vpm_hi
+0x95701ff6, 0x10024701, // mov ra_vdw_32, rb_vdw_32; mov rb_vdw_32, ra_vdw_32
+0x8c15edf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffbf0, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffba0, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x204e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d300f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x204e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22093c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x00000000, 0xf0f549e7, // bra -, ra_save_32
+0x95642ff6, 0x10024642, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x95687ff6, 0x10024687, // mov ra_vpm_hi, rb_vpm_hi; mov rb_vpm_hi, ra_vpm_hi
+0x95701ff6, 0x10024701, // mov ra_vdw_32, rb_vdw_32; mov rb_vdw_32, ra_vdw_32
+0x8c15ddf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffb10, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x00000000, 0xf0f489e7, // bra -, ra_save_16
+0x009e7000, 0x100009e7, // nop
+0x95642ff6, 0x10024642, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x956c0ff6, 0x100246c0, // mov ra_vdw_16, rb_vdw_16; mov rb_vdw_16, ra_vdw_16
+0x159c5fc0, 0x10022827, // mov.setf r0, rb_inst
+0x0d9c11c0, 0xd0020827, // sub r0, r0, 1
+0x119c51c0, 0xd0020827, // shl r0, r0, 5
+0x0c9c6e00, 0x100601a7, // add.ifnz ra_sync, rx_sync_slave, r0
+0x159c4fc0, 0x10060127, // mov.ifnz ra_save_16, rx_save_slave_16
+0x159cafc0, 0x100602a7, // mov.ifnz ra_save_32, rx_save_slave_32
+0x15827d80, 0x100220e7, // mov.setf ra_addr_x, unif
+0x15827d80, 0x100210e7, // mov      rb_addr_y, unif
+0x00000b10, 0xf00809e7, // brr.allz -, r:end
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100204e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100214e7, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149da1c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149da1c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x119c11c0, 0xd0020827, // shl r0, r0, STAGES-13
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff9a0, 0xf0f80227, // brr ra_link_1, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x0e1cedc0, 0xd00229e7, // shr.setf -, ra_points, STAGES
+0xfffff978, 0xf00809e7, // brr.allz -, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100204e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100214e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000003, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020327, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021327, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000002, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020367, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021367, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff988, 0xf0f80227, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0xfffff968, 0xf0f80227, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x954d3dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20367016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cd017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cd01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2136709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x024e7c80, 0x10020827, // fsub r0,  a, b
+0x024e7180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x024e7c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x01527380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025893, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x024e7c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10020527, // fadd a+1, r0, r1
+0x029d3ec0, 0x10020827, // fsub r0,  a, b
+0x029d31c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d3e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d43c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024893, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d3e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10021527, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20327016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cc017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cc01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2132709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02467c80, 0x10020827, // fsub r0,  a, b
+0x02467180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02467c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x014a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02467c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100204a7, // fadd a+1, r0, r1
+0x029d1ec0, 0x10020827, // fsub r0,  a, b
+0x029d11c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d1e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d23c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d1e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100214a7, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1cedc0, 0xd00229e7, // shr.setf -, ra_points, STAGES
+0xfffff6d8, 0xf00809e7, // brr.allz -, r:pass_2
+0x00000020, 0xe0020827, // mov r0, 4*8
+0x0d227c00, 0x10020227, // sub ra_link_1, ra_link_1, r0
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9cbe00, 0x10020e27, // add t0s, ptr, r0
+0x0c9cbe40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000004, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020327, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021327, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c41c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15ddf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff5f8, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dddc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20327016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cc017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cc01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2132709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02467c80, 0x10020827, // fsub r0,  a, b
+0x02467180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02467c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x014a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02467c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100204a7, // fadd a+1, r0, r1
+0x029d1ec0, 0x10020827, // fsub r0,  a, b
+0x029d11c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d1e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d23c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d1e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100214a7, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1cedc0, 0xd00229e7, // shr.setf -, ra_points, STAGES
+0xfffff468, 0xf00809e7, // brr.allz -, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dddc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0xfffff4c0, 0xf0f809e7, // brr -, r:loop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c3fc0, 0x100209a7, // mov interrupt, flag
+0x009e7000, 0x300009e7, // nop; nop; thrend
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_1k.hex b/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_1k.hex
new file mode 100755 (executable)
index 0000000..7de3279
--- /dev/null
@@ -0,0 +1,523 @@
+0x00000010, 0xe00216e7, // mov rb_0x10,    0x10
+0x00000040, 0xe0021727, // mov rb_0x40,    0x40
+0x000000f0, 0xe0021767, // mov rb_0xF0,    0xF0
+0x00005555, 0xe00207a7, // mov rx_0x5555,  0x5555
+0x00003333, 0xe00217a7, // mov rx_0x3333,  0x3333
+0x00000f0f, 0xe00207e7, // mov rx_0x0F0F,  0x0F0F
+0x000000ff, 0xe00217e7, // mov rx_0x00FF,  0x00FF
+0x90104000, 0xe0020767, // mov ra_vdw_32, vdw_setup_0(32, 16, dma_h32( 0,0))
+0x90105000, 0xe0021067, // mov rb_vdw_32, vdw_setup_0(32, 16, dma_h32(32,0))
+0x15827d80, 0x100202a7, // mov rx_tw_shared, unif
+0x15827d80, 0x100212a7, // mov rx_tw_unique, unif
+0x15827d80, 0x10021167, // mov rb_inst, unif
+0x00101200, 0xe0020827, // mov r0, vpm_setup(1, 1, v32( 0,0))
+0x00000010, 0xe0020867, // mov r1, vpm_setup(1, 1, v32(16,0)) - vpm_setup(1, 1, v32(0,0))
+0x00000002, 0xe00208a7, // mov r2, vpm_setup(1, 1, v32( 0,2)) - vpm_setup(1, 1, v32(0,0))
+0x409c5017, 0x100049e2, // nop; mul24 r2, r2, in_inst
+0xcc9e7081, 0x100246e0, // add out_0, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x10024720, // add out_1, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100250a0, // add out_2, r0, r2; v8adds r0, r0, r1
+0x0c9e7080, 0x100211e7, // add out_3, r0, r2
+0x000000c8, 0xf0f80127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x156e7d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x15727d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x15767d80, 0x10021c67, // mov vw_setup, ra_vdw_32
+0xc00000c0, 0xe0021c67, // mov vw_setup, vdw_setup_1(0) + PASS32_STRIDE-16*4
+0x8c05cdf6, 0x10024072, // add ra_save_ptr, ra_save_ptr, rb_0x40; mov vw_addr, ra_save_ptr
+0x00000050, 0xf0f81127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x156e7d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x15727d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x00000000, 0xf0f4c9e7, // bra -, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x156e7d80, 0x10020c67, // mov vr_setup, ra_vpm_lo
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x00000080, 0xf0f801a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000588, 0xf0f811a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000009, 0xe80009e7, // mov -, srel(i+9)
+0x00000011, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000a, 0xe80009e7, // mov -, srel(i+9)
+0x00000012, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000b, 0xe80009e7, // mov -, srel(i+9)
+0x00000013, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000c, 0xe80009e7, // mov -, srel(i+9)
+0x00000014, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000d, 0xe80009e7, // mov -, srel(i+9)
+0x00000015, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000e, 0xe80009e7, // mov -, srel(i+9)
+0x00000016, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000f, 0xe80009e7, // mov -, srel(i+9)
+0x00000017, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20367030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209cd039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208dcb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20367031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819ff2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f1400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829ff609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f1449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x203a7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209ce039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208ecb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x203a7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fe2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f2400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fe609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f2449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x203e7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209cf039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208fcb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x203e7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fc2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f4400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fc609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f4449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20427030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d0039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22090cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20427031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819f82c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f8400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x00000000, 0xf0f409e7, // bra -, ra_link_0
+0x829f8609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f8449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x8c15ddf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149de1c0, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x149de1c0, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149df1c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149df1c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c31c0, 0xd0020827, // shr r0, r0, 13-STAGES
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffda0, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149de1c0, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x149de1c0, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149df1c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149df1c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c31c0, 0xd0020827, // shr r0, r0, 13-STAGES
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffc80, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x204a7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d200f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x204a700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22092c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x00000000, 0xf0f489e7, // bra -, ra_save_32
+0x956c2ff6, 0x100246c2, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x95707ff6, 0x10024707, // mov ra_vpm_hi, rb_vpm_hi; mov rb_vpm_hi, ra_vpm_hi
+0x95741ff6, 0x10024741, // mov ra_vdw_32, rb_vdw_32; mov rb_vdw_32, ra_vdw_32
+0x8c15ddf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffbf0, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffba0, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x204a7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d200f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x204a700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22092c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x00000000, 0xf0f489e7, // bra -, ra_save_32
+0x956c2ff6, 0x100246c2, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x95707ff6, 0x10024707, // mov ra_vpm_hi, rb_vpm_hi; mov rb_vpm_hi, ra_vpm_hi
+0x95741ff6, 0x10024741, // mov ra_vdw_32, rb_vdw_32; mov rb_vdw_32, ra_vdw_32
+0x159c5fc0, 0x10022827, // mov.setf r0, rb_inst
+0x0d9c11c0, 0xd0020827, // sub r0, r0, 1
+0x119c51c0, 0xd0020827, // shl r0, r0, 5
+0x0c9c6e00, 0x100601a7, // add.ifnz ra_sync, rx_sync_slave, r0
+0x159c4fc0, 0x10060127, // mov.ifnz ra_save_32, rx_save_slave_32
+0x15827d80, 0x100220e7, // mov.setf ra_addr_x, unif
+0x15827d80, 0x100210e7, // mov      rb_addr_y, unif
+0x000007a0, 0xf00809e7, // brr.allz -, r:end
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2a7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2a7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020427, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021427, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2a7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2a7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100204a7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100214a7, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024451, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe00244d3, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95410dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c362, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d363, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149de1c0, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x149de1c0, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149df1c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149df1c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c31c0, 0xd0020827, // shr r0, r0, 13-STAGES
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffa10, 0xf0f80227, // brr ra_link_1, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x0e1cadc0, 0xd00229e7, // shr.setf -, ra_points, STAGES
+0xfffff9e8, 0xf00809e7, // brr.allz -, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9cae00, 0x10020e27, // add t0s, ptr, r0
+0x0c9cae40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020427, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021427, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9cae00, 0x10020e27, // add t0s, ptr, r0
+0x0c9cae40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100204a7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100214a7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000003, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2a7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2a7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100202e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100212e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000002, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2a7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2a7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020327, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021327, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024451, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe00244d3, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95410dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c362, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d363, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff9f8, 0xf0f80227, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x95492dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20327016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cc017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cc01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2132709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x024a7c80, 0x10020827, // fsub r0,  a, b
+0x024a7180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x024a7c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x014e7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025892, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x024a7c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100204e7, // fadd a+1, r0, r1
+0x029d2ec0, 0x10020827, // fsub r0,  a, b
+0x029d21c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d2e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d33c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024892, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d2e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100214e7, // fadd a+1, r0, r1
+0x95410dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x202e7016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cb017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cb01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x212e709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02427c80, 0x10020827, // fsub r0,  a, b
+0x02427180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02427c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x01467380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025890, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02427c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10020467, // fadd a+1, r0, r1
+0x029d0ec0, 0x10020827, // fsub r0,  a, b
+0x029d01c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d0e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d13c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024890, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d0e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10021467, // fadd a+1, r0, r1
+0x95410dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c362, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d363, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1cadc0, 0xd00229e7, // shr.setf -, ra_points, STAGES
+0xfffff768, 0xf00809e7, // brr.allz -, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0xfffff830, 0xf0f809e7, // brr -, r:loop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c3fc0, 0x100209a7, // mov interrupt, flag
+0x009e7000, 0x300009e7, // nop; nop; thrend
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_2048k.hex b/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_2048k.hex
new file mode 100755 (executable)
index 0000000..c49cd94
--- /dev/null
@@ -0,0 +1,1353 @@
+0x00000010, 0xe0021227, // mov rb_0x10,    0x10
+0x000001d0, 0xe0021967, // mov r5rep,      0x1D0
+0x15827d80, 0x100203e7, // mov rx_tw_shared, unif
+0x15827d80, 0x100213e7, // mov rx_tw_unique, unif
+0x15827d80, 0x10021167, // mov rb_inst, unif
+0x00101200, 0xe0020827, // mov r0, vpm_setup(1, 1, v32( 0,0))
+0x00000010, 0xe0020867, // mov r1, vpm_setup(1, 1, v32(16,0)) - vpm_setup(1, 1, v32(0,0))
+0x00000002, 0xe00208a7, // mov r2, vpm_setup(1, 1, v32( 0,2)) - vpm_setup(1, 1, v32(0,0))
+0x409c5017, 0x100049e2, // nop; mul24 r2, r2, in_inst
+0xcc9e7081, 0x10025020, // add out_0, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x10025060, // add out_1, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100250a0, // add out_2, r0, r2; v8adds r0, r0, r1
+0x0c9e7080, 0x100211e7, // add out_3, r0, r2
+0x000002e8, 0xf0f80127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x152e7d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x15327d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x153a7d80, 0x10020827, // mov r0, ra_vdw_32
+0x8c04ddf6, 0x10024061, // add ra_save_ptr, ra_save_ptr, rb_0x40; mov r1, ra_save_ptr
+0x00000080, 0xe00208a7, // mov r2, vdw_setup_0(1, 16, dma_h32(1,0)) - vdw_setup_0(1, 16, dma_h32(0,0))
+0x00080000, 0xe00208e7, // mov r3, PASS32_STRIDE
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000050, 0xf0f81127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x152e7d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x15327d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x00000000, 0xf0f4c9e7, // bra -, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x152e7d80, 0x10020c67, // mov vr_setup, ra_vpm_lo
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x00000520, 0xf0f802a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x159c0fc0, 0x10021c67, // mov vw_setup, rb_vpm
+0x012cbdc0, 0x10020c27, // fadd vpm, ra_64+0, rb_64+0
+0x0130cdc0, 0x10020c27, // fadd vpm, ra_64+1, rb_64+1
+0x159c1fc0, 0x10021c67, // mov vw_setup, rb_vpm_16
+0x0134ddc0, 0x10020c27, // fadd vpm, ra_64+2, rb_64+2
+0x0138edc0, 0x10020c27, // fadd vpm, ra_64+3, rb_64+3
+0x159c2fc0, 0x10021c67, // mov vw_setup, rb_vpm_32
+0x022cbdc0, 0x10020c27, // fsub vpm, ra_64+0, rb_64+0
+0x0230cdc0, 0x10020c27, // fsub vpm, ra_64+1, rb_64+1
+0x159c7fc0, 0x10021c67, // mov vw_setup, rb_vpm_48
+0x0234ddc0, 0x10020c27, // fsub vpm, ra_64+2, rb_64+2
+0x0238edc0, 0x10020c27, // fsub vpm, ra_64+3, rb_64+3
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x80904000, 0xe0020827, // mov r0, vdw_setup_0(1, 16, dma_h32(0,0))
+0x00000040, 0xe0020867, // mov r1, 0x40
+0x8c067c76, 0x10024061, // add ra_save_ptr, ra_save_ptr, r1; mov r1, ra_save_ptr
+0x00000080, 0xe00208a7, // mov r2, vdw_setup_0(1, 16, dma_h32(1,0)) - vdw_setup_0(1, 16, dma_h32(0,0))
+0x00040000, 0xe00208e7, // mov r3, PASS64_STRIDE
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x000002b8, 0xf0f812a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd00200a7, // shl ra_temp, r0, 5
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0fc49e7, // brr -, ra_temp
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x000000e0, 0xf0f809e7, // brr -, r:2f
+0x00000010, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x000000c0, 0xf0f809e7, // brr -, r:2f
+0x00000011, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x000000a0, 0xf0f809e7, // brr -, r:2f
+0x00000012, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000080, 0xf0f809e7, // brr -, r:2f
+0x00000013, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000060, 0xf0f809e7, // brr -, r:2f
+0x00000014, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000040, 0xf0f809e7, // brr -, r:2f
+0x00000015, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000020, 0xf0f809e7, // brr -, r:2f
+0x00000016, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f809e7, // brr -, r:2f
+0x00000017, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c0fc0, 0x10021c67, // mov vw_setup, rb_vpm
+0x012cbdc0, 0x10020c27, // fadd vpm, ra_64+0, rb_64+0
+0x0130cdc0, 0x10020c27, // fadd vpm, ra_64+1, rb_64+1
+0x159c1fc0, 0x10021c67, // mov vw_setup, rb_vpm_16
+0x0134ddc0, 0x10020c27, // fadd vpm, ra_64+2, rb_64+2
+0x0138edc0, 0x10020c27, // fadd vpm, ra_64+3, rb_64+3
+0x159c2fc0, 0x10021c67, // mov vw_setup, rb_vpm_32
+0x022cbdc0, 0x10020c27, // fsub vpm, ra_64+0, rb_64+0
+0x0230cdc0, 0x10020c27, // fsub vpm, ra_64+1, rb_64+1
+0x159c7fc0, 0x10021c67, // mov vw_setup, rb_vpm_48
+0x0234ddc0, 0x10020c27, // fsub vpm, ra_64+2, rb_64+2
+0x0238edc0, 0x10020c27, // fsub vpm, ra_64+3, rb_64+3
+0x00000000, 0xf0fc49e7, // brr -, ra_temp
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x00000008, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x00000009, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000a, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000b, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000c, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000d, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000e, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000f, 0xe80009e7, // mov -, srel(i+8)
+0x00000080, 0xf0f801a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000998, 0xf0f811a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000009, 0xe80009e7, // mov -, srel(i+9)
+0x00000011, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000a, 0xe80009e7, // mov -, srel(i+9)
+0x00000012, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000b, 0xe80009e7, // mov -, srel(i+9)
+0x00000013, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000c, 0xe80009e7, // mov -, srel(i+9)
+0x00000014, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000d, 0xe80009e7, // mov -, srel(i+9)
+0x00000015, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000e, 0xe80009e7, // mov -, srel(i+9)
+0x00000016, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000f, 0xe80009e7, // mov -, srel(i+9)
+0x00000017, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x204a7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d2039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22092cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x204a7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819ff2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f1400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829ff609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f1449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x204e7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d3039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22093cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x204e7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fe2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f2400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fe609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f2449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20527030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d4039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22094cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20527031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fc2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f4400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fc609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f4449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20567030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d5039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22095cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20567031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819f82c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f8400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x00000000, 0xf0f409e7, // bra -, ra_link_0
+0x829f8609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f8449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x55555555, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x33333333, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0f0f0f0f, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x00ff00ff, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0000ffff, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c81c0, 0x10020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c83c0, 0x10020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c81c0, 0xd0020827, // shr r0, r0, 32-STAGES-3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffd50, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x55555555, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x33333333, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0f0f0f0f, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x00ff00ff, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0000ffff, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c81c0, 0x10020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c83c0, 0x10020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c81c0, 0xd0020827, // shr r0, r0, 32-STAGES-3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffbe0, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x205e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d700f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x205e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22097c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x01267c00, 0x100202e7, // fadd ra_64+0, ra_32_re, r0
+0x019c9e40, 0x10020327, // fadd ra_64+1, rb_32_im, r1
+0x02267c00, 0x10020367, // fsub ra_64+2, ra_32_re, r0
+0x029c9e40, 0x100203a7, // fsub ra_64+3, rb_32_im, r1
+0x8c167d76, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x55555555, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x33333333, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0f0f0f0f, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x00ff00ff, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0000ffff, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c81c0, 0x10020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c83c0, 0x10020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c81c0, 0xd0020827, // shr r0, r0, 32-STAGES-3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffa30, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x55555555, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x33333333, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0f0f0f0f, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x00ff00ff, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0000ffff, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c81c0, 0x10020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c83c0, 0x10020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c81c0, 0xd0020827, // shr r0, r0, 32-STAGES-3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffff8c0, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x205e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d700f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x205e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22097c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x029c9e40, 0x100208e7, // fsub r3, rb_32_im, r1
+0x02267c00, 0x100208a7, // fsub r2, ra_32_re, r0
+0x019c9e40, 0x10020867, // fadd r1, rb_32_im, r1
+0x01267c00, 0x10020827, // fadd r0, ra_32_re, r0
+0x2066700e, 0x100049c9, // nop;                        fmul rb_32_im, r1, ra_tw_re+TW48
+0x209d900f, 0x100059c9, // nop;                        fmul ra_32_re, r1, rb_tw_im+TW48
+0x209d9007, 0x100049e1, // nop;                        fmul r1,       r0, rb_tw_im+TW48
+0x216493c6, 0x10025320, // fadd rb_64+1, r1, rb_32_im; fmul r0,       r0, ra_tw_re+TW48
+0x2225a19f, 0x100252c9, // fsub rb_64+0, r0, ra_32_re; fmul ra_32_re, r3, rb_tw_im+TW64
+0x206a701e, 0x100049c9, // nop;                        fmul rb_32_im, r3, ra_tw_re+TW64
+0x00000000, 0xf0f549e7, // bra -, ra_save_64
+0x209da017, 0x100049e3, // nop;                        fmul r3,       r2, rb_tw_im+TW64
+0x216897d6, 0x100253a2, // fadd rb_64+3, r3, rb_32_im; fmul r2,       r2, ra_tw_re+TW64
+0x02267580, 0x10021367, // fsub rb_64+2, r2, ra_32_re
+0x8c14cdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff7e0, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff790, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x205e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d700f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x205e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22097c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x00000000, 0xf0f489e7, // bra -, ra_save_32
+0x952c2ff6, 0x100242c2, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x95307ff6, 0x10024307, // mov ra_vpm_hi, rb_vpm_hi; mov rb_vpm_hi, ra_vpm_hi
+0x9538eff6, 0x1002438e, // mov ra_vdw_32, rb_vdw_32; mov rb_vdw_32, ra_vdw_32
+0x159c5fc0, 0x10022827, // mov.setf r0, rb_inst
+0x0d9c11c0, 0xd0020827, // sub r0, r0, 1
+0x119c51c0, 0xd0020827, // shl r0, r0, 5
+0x0c9c6e00, 0x100601a7, // add.ifnz ra_sync, rx_sync_slave, r0
+0x159c4fc0, 0x10060127, // mov.ifnz ra_save_32, rx_save_slave_32
+0x159cafc0, 0x100602a7, // mov.ifnz ra_save_64, rx_save_slave_64
+0x15827d80, 0x100220e7, // mov.setf ra_addr_x, unif
+0x15827d80, 0x100210e7, // mov      rb_addr_y, unif
+0x00001378, 0xf00809e7, // brr.allz -, r:end
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000003, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020567, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021567, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000002, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100205e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100215e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020667, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021667, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100206a7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100216a7, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024596, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024618, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c562, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d563, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c522, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d523, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c4e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d4e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c4a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d4a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c61c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x55555555, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x33333333, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0f0f0f0f, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x00ff00ff, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0000ffff, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c81c0, 0x10020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c83c0, 0x10020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c81c0, 0xd0020827, // shr r0, r0, 32-STAGES-3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff4f8, 0xf0f80227, // brr ra_link_1, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x00000200, 0xe0020827, // mov r0, 0x200
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x00000015, 0xe0020867, // mov r1, STAGES
+0x0e1e7c40, 0x100229e7, // shr.setf -, ra_points, r1
+0xfffff4c8, 0xf00809e7, // brr.allz -, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x00000200, 0xe0020827, // mov r0, 0x200
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159c0fc0, 0x100202e7, // mov ra_vpm_lo, rb_vpm
+0x159c1fc0, 0x10020327, // mov ra_vpm_hi, rb_vpm_16
+0x80904000, 0xe00203a7, // mov ra_vdw_32, vdw_setup_0(1, 16, dma_h32( 0,0))
+0x80905000, 0xe00213a7, // mov rb_vdw_32, vdw_setup_0(1, 16, dma_h32(32,0))
+0x00000015, 0xe00212e7, // mov rb_STAGES, STAGES
+0x000000f0, 0xe0021327, // mov rb_0xF0, 0xF0
+0x00000040, 0xe0021367, // mov rb_0x40, 0x40
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000003, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020567, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021567, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000002, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100205e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100215e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000005, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020427, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021427, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000004, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024596, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024618, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c562, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d563, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c522, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d523, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c4e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d4e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c4a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d4a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff8b0, 0xf0f80227, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x00007fff, 0xe0020827, // mov r0, 0x7FFF
+0x141e7c00, 0x100229e7, // and.setf -, ra_points, r0
+0xfffff880, 0xf01809e7, // brr.allnz -, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100601e7, // add.ifnz ra_points, ra_points, r0
+0x955d7dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20467016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209d1017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209d101f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2146709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x025e7c80, 0x10020827, // fsub r0,  a, b
+0x025e7180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x025e7c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x01627380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025897, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x025e7c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10020627, // fadd a+1, r0, r1
+0x029d7ec0, 0x10020827, // fsub r0,  a, b
+0x029d71c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d7e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d83c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024897, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d7e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10021627, // fadd a+1, r0, r1
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20427016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209d0017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209d001f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2142709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02567c80, 0x10020827, // fsub r0,  a, b
+0x02567180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02567c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x015a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025895, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02567c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100205a7, // fadd a+1, r0, r1
+0x029d5ec0, 0x10020827, // fsub r0,  a, b
+0x029d51c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d5e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d63c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024895, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d5e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100215a7, // fadd a+1, r0, r1
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c562, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d563, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c522, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d523, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c4e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d4e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c4a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d4a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1cbdc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0xfffff5f0, 0xf00809e7, // brr.allz -, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000003, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020567, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021567, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000002, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100205e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100215e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000007, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020427, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021427, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000006, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024596, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024618, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c562, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d563, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c522, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d523, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c4e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d4e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c4a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d4a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff380, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0xfffff360, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0xfffff340, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0xfffff320, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x955d7dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20467016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209d1017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209d101f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2146709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x025e7c80, 0x10020827, // fsub r0,  a, b
+0x025e7180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x025e7c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x01627380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025897, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x025e7c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10020627, // fadd a+1, r0, r1
+0x029d7ec0, 0x10020827, // fsub r0,  a, b
+0x029d71c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d7e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d83c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024897, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d7e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10021627, // fadd a+1, r0, r1
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20427016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209d0017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209d001f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2142709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02567c80, 0x10020827, // fsub r0,  a, b
+0x02567180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02567c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x015a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025895, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02567c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100205a7, // fadd a+1, r0, r1
+0x029d5ec0, 0x10020827, // fsub r0,  a, b
+0x029d51c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d5e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d63c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024895, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d5e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100215a7, // fadd a+1, r0, r1
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c562, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d563, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c522, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d523, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c4e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d4e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c4a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d4a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1cbdc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0x00000100, 0xe0020827, // mov r0, 0x100
+0xfffff088, 0xf00809e7, // brr.allz -, r:pass_3
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x00000060, 0xe0020827, // mov r0, (4-1)*4*8
+0x0d227c00, 0x10020227, // sub ra_link_1, ra_link_1, r0
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9cfe00, 0x10020e27, // add t0s, ptr, r0
+0x0c9cfe40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020567, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021567, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9cfe00, 0x10020e27, // add t0s, ptr, r0
+0x0c9cfe40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100205e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100215e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000009, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020427, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021427, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000008, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024596, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024618, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c562, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d563, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c522, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d523, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c4e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d4e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c4a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d4a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xffffee18, 0xf0f80227, // brr ra_link_1, r:pass_4
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x955d7dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20467016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209d1017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209d101f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2146709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x025e7c80, 0x10020827, // fsub r0,  a, b
+0x025e7180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x025e7c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x01627380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025897, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x025e7c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10020627, // fadd a+1, r0, r1
+0x029d7ec0, 0x10020827, // fsub r0,  a, b
+0x029d71c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d7e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d83c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024897, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d7e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10021627, // fadd a+1, r0, r1
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20427016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209d0017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209d001f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2142709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02567c80, 0x10020827, // fsub r0,  a, b
+0x02567180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02567c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x015a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025895, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02567c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100205a7, // fadd a+1, r0, r1
+0x029d5ec0, 0x10020827, // fsub r0,  a, b
+0x029d51c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d5e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d63c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024895, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d5e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100215a7, // fadd a+1, r0, r1
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c562, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d563, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c522, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d523, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c4e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d4e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c4a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d4a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1cbdc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0xffffeb88, 0xf00809e7, // brr.allz -, r:pass_4
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0xffffec58, 0xf0f809e7, // brr -, r:loop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c3fc0, 0x100209a7, // mov interrupt, flag
+0x009e7000, 0x300009e7, // nop; nop; thrend
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_256.hex b/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_256.hex
new file mode 100755 (executable)
index 0000000..bfd5b45
--- /dev/null
@@ -0,0 +1,359 @@
+0x00000040, 0xe00217a7, // mov rb_0x40,    0x40
+0x00000080, 0xe00217e7, // mov rb_0x80,    0x80
+0x00005555, 0xe0020767, // mov rx_0x5555,  0x5555
+0x00003333, 0xe00207a7, // mov rx_0x3333,  0x3333
+0x00000f0f, 0xe00207e7, // mov rx_0x0F0F,  0x0F0F
+0x88104000, 0xe0020727, // mov ra_vdw, vdw_setup_0(16, 16, dma_h32( 0,0))
+0x88104800, 0xe0021727, // mov rb_vdw, vdw_setup_0(16, 16, dma_h32(16,0))
+0x15827d80, 0x10020227, // mov rx_tw_shared, unif
+0x15827d80, 0x10021227, // mov rx_tw_unique, unif
+0x15827d80, 0x10021167, // mov rb_inst, unif
+0x00101200, 0xe0020827, // mov r0, vpm_setup(1, 1, v32( 0,0))
+0x00000010, 0xe0020867, // mov r1, vpm_setup(1, 1, v32(16,0)) - vpm_setup(1, 1, v32(0,0))
+0x00000002, 0xe00208a7, // mov r2, vpm_setup(1, 1, v32( 0,2)) - vpm_setup(1, 1, v32(0,0))
+0x409c5017, 0x100049e2, // nop; mul24 r2, r2, in_inst
+0xcc9e7081, 0x100246e0, // add out_0, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100256e0, // add out_1, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100049e0, // add out_2, r0, r2; v8adds r0, r0, r1
+0x0c9e7080, 0x100009e7, // add out_3, r0, r2
+0x000000b0, 0xf0f80127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x156e7d80, 0x10021c67, // mov vw_setup, arg
+0x159e7000, 0x10020c27, // mov vpm, r0
+0x159e7240, 0x10020c27, // mov vpm, r1
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000000, 0xf0f409e7, // bra -, ra_link_1
+0x15727d80, 0x10021c67, // mov vw_setup, arg_vdw
+0xc0000040, 0xe0021c67, // mov vw_setup, vdw_setup_1(0) + PASS16_STRIDE-16*4
+0x8c05edf6, 0x10024072, // add ra_save_ptr, ra_save_ptr, rb_0x40; mov vw_addr, ra_save_ptr
+0x00000038, 0xf0f81127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x156e7d80, 0x10021c67, // mov vw_setup, arg
+0x159e7000, 0x10020c27, // mov vpm, r0
+0x159e7240, 0x10020c27, // mov vpm, r1
+0x00000000, 0xf0f4c9e7, // bra -, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x156e7d80, 0x10020c67, // mov vr_setup, arg_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x00000080, 0xf0f801a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000000, 0xf0f409e7, // bra -, ra_link_1
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000248, 0xf0f811a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f409e7, // bra -, ra_link_1
+0x00000009, 0xe80009e7, // mov -, srel(i+9)
+0x00000011, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f409e7, // bra -, ra_link_1
+0x0000000a, 0xe80009e7, // mov -, srel(i+9)
+0x00000012, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f409e7, // bra -, ra_link_1
+0x0000000b, 0xe80009e7, // mov -, srel(i+9)
+0x00000013, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f409e7, // bra -, ra_link_1
+0x0000000c, 0xe80009e7, // mov -, srel(i+9)
+0x00000014, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f409e7, // bra -, ra_link_1
+0x0000000d, 0xe80009e7, // mov -, srel(i+9)
+0x00000015, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f409e7, // bra -, ra_link_1
+0x0000000e, 0xe80009e7, // mov -, srel(i+9)
+0x00000016, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f409e7, // bra -, ra_link_1
+0x0000000f, 0xe80009e7, // mov -, srel(i+9)
+0x00000017, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x202a7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209ca039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208acb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x202a7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819ff2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f1400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829ff609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f1449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x202e7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209cb039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208bcb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x202e7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fe2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f2400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fe609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f2449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20327030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209cc039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208ccb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20327031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fc2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f4400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fc609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f4449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20367030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209cd039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208dcb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20367031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819f82c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f8400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x00000000, 0xf0f489e7, // bra -, ra_link_0
+0x829f8609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f8449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0xfffffe98, 0xf0f809e7, // brr -, r:fft_16
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x159c5fc0, 0x10022827, // mov.setf r0, rb_inst
+0x0d9c11c0, 0xd0020827, // sub r0, r0, 1
+0x119c51c0, 0xd0020827, // shl r0, r0, 5
+0x0c9c6e00, 0x100601a7, // add.ifnz ra_sync, rx_sync_slave, r0
+0x159c4fc0, 0x10060127, // mov.ifnz ra_save_16, rx_save_slave_16
+0x15827d80, 0x100220e7, // mov.setf ra_addr_x, unif
+0x15827d80, 0x100210e7, // mov      rb_addr_y, unif
+0x00000600, 0xf00809e7, // brr.allz -, r:end
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c227c00, 0x10020e27, // add t0s, ptr, r0
+0x0c227c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020367, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021367, // mov rb_tw_im+dst, r4
+0x00000000, 0xe002438e, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x9534ddbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c362, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d363, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c322, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d323, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c2e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d2e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c2a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d2a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c41c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15fdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x8c15fdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffd50, 0xf0f80027, // brr ra_link_1, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x956dbff6, 0x100246db, // mov ra_vpm, rb_vpm; mov rb_vpm, ra_vpm
+0x9571cff6, 0x1002471c, // mov ra_vdw, rb_vdw; mov rb_vdw, ra_vdw
+0xfffffd30, 0xf0f80027, // brr ra_link_1, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x956dbff6, 0x100246db, // mov ra_vpm, rb_vpm; mov rb_vpm, ra_vpm
+0x9571cff6, 0x1002471c, // mov ra_vdw, rb_vdw; mov rb_vdw, ra_vdw
+0x00000000, 0xf0f4c027, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9c8e00, 0x10020e27, // add t0s, ptr, r0
+0x0c9c8e40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020367, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021367, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c227c00, 0x10020e27, // add t0s, ptr, r0
+0x0c227c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020267, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021267, // mov rb_tw_im+dst, r4
+0x00000000, 0xe002438e, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x9534ddbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c362, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d363, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c322, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d323, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c2e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d2e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c2a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d2a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c41c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15fdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x8c15fdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffb50, 0xf0f80027, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x956dbff6, 0x100246db, // mov ra_vpm, rb_vpm; mov rb_vpm, ra_vpm
+0x9571cff6, 0x1002471c, // mov ra_vdw, rb_vdw; mov rb_vdw, ra_vdw
+0x9534ddbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20267016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209c9017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209c901f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2126709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02367c80, 0x10020827, // fsub r0,  a, b
+0x02367180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02367c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x013a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x1002588d, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02367c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100203a7, // fadd a+1, r0, r1
+0x029cdec0, 0x10020827, // fsub r0,  a, b
+0x029cd1c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029cde40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019ce3c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x1002488d, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029cde80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100213a7, // fadd a+1, r0, r1
+0x9534ddbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c362, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d363, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c322, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d323, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c2e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d2e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c2a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d2a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0xfffff9c8, 0xf0f80027, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x956dbff6, 0x100246db, // mov ra_vpm, rb_vpm; mov rb_vpm, ra_vpm
+0x9571cff6, 0x1002471c, // mov ra_vdw, rb_vdw; mov rb_vdw, ra_vdw
+0x00000000, 0xf0f4c027, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0xfffff9d0, 0xf0f809e7, // brr -, r:loop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c3fc0, 0x100209a7, // mov interrupt, flag
+0x009e7000, 0x300009e7, // nop; nop; thrend
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_256k.hex b/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_256k.hex
new file mode 100755 (executable)
index 0000000..d51e651
--- /dev/null
@@ -0,0 +1,861 @@
+0x00000012, 0xe0021227, // mov rb_STAGES,  STAGES
+0x00000010, 0xe00216a7, // mov rb_0x10,    0x10
+0x00000040, 0xe00216e7, // mov rb_0x40,    0x40
+0x00000080, 0xe0021727, // mov rb_0x80,    0x80
+0x000000f0, 0xe0021767, // mov rb_0xF0,    0xF0
+0x00000100, 0xe00217a7, // mov rb_0x100,   0x100
+0x00001fff, 0xe00217e7, // mov rb_0x1FFF,  0x1FFF
+0x55555555, 0xe0020767, // mov rx_0x55555555, 0x55555555
+0x33333333, 0xe00207a7, // mov rx_0x33333333, 0x33333333
+0x0f0f0f0f, 0xe00207e7, // mov rx_0x0F0F0F0F, 0x0F0F0F0F
+0x00ff00ff, 0xe0021627, // mov rx_0x00FF00FF, 0x00FF00FF
+0x0000ffff, 0xe0021667, // mov rx_0x0000FFFF, 0x0000FFFF
+0x80904000, 0xe00206e7, // mov ra_vdw_16, vdw_setup_0( 1, 16, dma_h32( 0,0))
+0x80905000, 0xe0021027, // mov rb_vdw_16, vdw_setup_0( 1, 16, dma_h32(32,0))
+0x90104000, 0xe0020727, // mov ra_vdw_32, vdw_setup_0(32, 16, dma_h32( 0,0))
+0x90105000, 0xe0021067, // mov rb_vdw_32, vdw_setup_0(32, 16, dma_h32(32,0))
+0x15827d80, 0x100202e7, // mov rx_tw_shared, unif
+0x15827d80, 0x100212e7, // mov rx_tw_unique, unif
+0x15827d80, 0x10021167, // mov rb_inst, unif
+0x00101200, 0xe0020827, // mov r0, vpm_setup(1, 1, v32( 0,0))
+0x00000010, 0xe0020867, // mov r1, vpm_setup(1, 1, v32(16,0)) - vpm_setup(1, 1, v32(0,0))
+0x00000002, 0xe00208a7, // mov r2, vpm_setup(1, 1, v32( 0,2)) - vpm_setup(1, 1, v32(0,0))
+0x409c5017, 0x100049e2, // nop; mul24 r2, r2, in_inst
+0xcc9e7081, 0x10024660, // add out_0, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100246a0, // add out_1, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100250a0, // add out_2, r0, r2; v8adds r0, r0, r1
+0x0c9e7080, 0x100211e7, // add out_3, r0, r2
+0x000001d0, 0xf0f80127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10021c67, // mov vw_setup, arg
+0x159e7000, 0x10020c27, // mov vpm, r0
+0x159e7240, 0x10020c27, // mov vpm, r1
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x156e7d80, 0x10020827, // mov r0, arg_vdw
+0x8c05bdf6, 0x10024061, // add ra_save_ptr, ra_save_ptr, rb_0x40; mov r1, ra_save_ptr
+0x00000080, 0xe00208a7, // mov r2, vdw_setup_0(1, 16, dma_h32(1,0)) - vdw_setup_0(1, 16, dma_h32(0,0))
+0x00020000, 0xe00208e7, // mov r3, PASS16_STRIDE
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000038, 0xf0f81127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10021c67, // mov vw_setup, arg
+0x159e7000, 0x10020c27, // mov vpm, r0
+0x159e7240, 0x10020c27, // mov vpm, r1
+0x00000000, 0xf0f4c9e7, // bra -, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10020c67, // mov vr_setup, arg_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x000000c8, 0xf0f802a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x156a7d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x15727d80, 0x10021c67, // mov vw_setup, ra_vdw_32
+0xc000ffc0, 0xe0021c67, // mov vw_setup, vdw_setup_1(0) + PASS32_STRIDE-16*4
+0x8c05bdf6, 0x10024072, // add ra_save_ptr, ra_save_ptr, rb_0x40; mov vw_addr, ra_save_ptr
+0x00000050, 0xf0f812a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x156a7d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x00000000, 0xf0f4c9e7, // bra -, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10020c67, // mov vr_setup, ra_vpm_lo
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x00000080, 0xf0f801a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000640, 0xf0f811a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000009, 0xe80009e7, // mov -, srel(i+9)
+0x00000011, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000a, 0xe80009e7, // mov -, srel(i+9)
+0x00000012, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000b, 0xe80009e7, // mov -, srel(i+9)
+0x00000013, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000c, 0xe80009e7, // mov -, srel(i+9)
+0x00000014, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000d, 0xe80009e7, // mov -, srel(i+9)
+0x00000015, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000e, 0xe80009e7, // mov -, srel(i+9)
+0x00000016, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000f, 0xe80009e7, // mov -, srel(i+9)
+0x00000017, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x203a7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209ce039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208ecb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x203a7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819ff2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f1400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829ff609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f1449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x203e7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209cf039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208fcb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x203e7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fe2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f2400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fe609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f2449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20427030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d0039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22090cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20427031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fc2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f4400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fc609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f4449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20467030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d1039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22091cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20467031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819f82c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f8400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x00000000, 0xf0f409e7, // bra -, ra_link_0
+0x829f8609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f8449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x8c15ddf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149d81c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149d81c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149d91c0, 0x10020867, // and r1, r0, mask
+0x0e9da1c0, 0x10020827, // shr r0, r0, shift
+0x149d91c0, 0x10020827, // and r0, r0, mask
+0x119da3c0, 0x10020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9cb1c0, 0xd0020827, // shr r0, r0, 32-STAGES-3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffd78, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c15adf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149d81c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149d81c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149d91c0, 0x10020867, // and r1, r0, mask
+0x0e9da1c0, 0x10020827, // shr r0, r0, shift
+0x149d91c0, 0x10020827, // and r0, r0, mask
+0x119da3c0, 0x10020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9cb1c0, 0xd0020827, // shr r0, r0, 32-STAGES-3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffc30, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x204e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d300f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x204e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22093c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x00000000, 0xf0f549e7, // bra -, ra_save_32
+0x95642ff6, 0x10024642, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x95687ff6, 0x10024687, // mov ra_vpm_hi, rb_vpm_hi; mov rb_vpm_hi, ra_vpm_hi
+0x95701ff6, 0x10024701, // mov ra_vdw_32, rb_vdw_32; mov rb_vdw_32, ra_vdw_32
+0x8c15cdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffba0, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x00000000, 0xf0f489e7, // bra -, ra_save_16
+0x009e7000, 0x100009e7, // nop
+0x95642ff6, 0x10024642, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x956c0ff6, 0x100246c0, // mov ra_vdw_16, rb_vdw_16; mov rb_vdw_16, ra_vdw_16
+0x8c15ddf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffb38, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c15adf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffae8, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x204e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d300f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x204e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22093c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x00000000, 0xf0f549e7, // bra -, ra_save_32
+0x95642ff6, 0x10024642, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x95687ff6, 0x10024687, // mov ra_vpm_hi, rb_vpm_hi; mov rb_vpm_hi, ra_vpm_hi
+0x95701ff6, 0x10024701, // mov ra_vdw_32, rb_vdw_32; mov rb_vdw_32, ra_vdw_32
+0x159c5fc0, 0x10022827, // mov.setf r0, rb_inst
+0x0d9c11c0, 0xd0020827, // sub r0, r0, 1
+0x119c51c0, 0xd0020827, // shl r0, r0, 5
+0x0c9c6e00, 0x100601a7, // add.ifnz ra_sync, rx_sync_slave, r0
+0x159c4fc0, 0x10060127, // mov.ifnz ra_save_16, rx_save_slave_16
+0x159cafc0, 0x100602a7, // mov.ifnz ra_save_32, rx_save_slave_32
+0x15827d80, 0x100220e7, // mov.setf ra_addr_x, unif
+0x15827d80, 0x100210e7, // mov      rb_addr_y, unif
+0x00000ef0, 0xf00809e7, // brr.allz -, r:end
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100204e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100214e7, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15adf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149d81c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149d81c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149d91c0, 0x10020867, // and r1, r0, mask
+0x0e9da1c0, 0x10020827, // shr r0, r0, shift
+0x149d91c0, 0x10020827, // and r0, r0, mask
+0x119da3c0, 0x10020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9cb1c0, 0xd0020827, // shr r0, r0, 32-STAGES-3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff928, 0xf0f80227, // brr ra_link_1, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dedc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x0e1c8dc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0xfffff900, 0xf00809e7, // brr.allz -, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dedc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000002, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020327, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021327, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c41c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15cdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffa10, 0xf0f80227, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dcdc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x141dfdc0, 0x100229e7, // and.setf -, ra_points, rb_0x1FFF
+0xfffff9e8, 0xf01809e7, // brr.allnz -, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dcdc0, 0x100601e7, // add.ifnz ra_points, ra_points, rb_0x80
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20327016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cc017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cc01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2132709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02467c80, 0x10020827, // fsub r0,  a, b
+0x02467180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02467c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x014a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02467c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100204a7, // fadd a+1, r0, r1
+0x029d1ec0, 0x10020827, // fsub r0,  a, b
+0x029d11c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d1e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d23c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d1e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100214a7, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1c8dc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0xfffff858, 0xf00809e7, // brr.allz -, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dcdc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000003, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020327, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021327, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c41c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15cdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff698, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dcdc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0xfffff678, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dcdc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0xfffff658, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dcdc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0xfffff638, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dcdc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20327016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cc017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cc01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2132709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02467c80, 0x10020827, // fsub r0,  a, b
+0x02467180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02467c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x014a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02467c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100204a7, // fadd a+1, r0, r1
+0x029d1ec0, 0x10020827, // fsub r0,  a, b
+0x029d11c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d1e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d23c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d1e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100214a7, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1c8dc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0xfffff4a8, 0xf00809e7, // brr.allz -, r:pass_3
+0x00000060, 0xe0020827, // mov r0, 3*4*8
+0x0d227c00, 0x10020227, // sub ra_link_1, ra_link_1, r0
+0x0c1dcdc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9cbe00, 0x10020e27, // add t0s, ptr, r0
+0x0c9cbe40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9cbe00, 0x10020e27, // add t0s, ptr, r0
+0x0c9cbe40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100204e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100214e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000005, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020327, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021327, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000004, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020367, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021367, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15adf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff2a0, 0xf0f80227, // brr ra_link_1, r:pass_4
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dedc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x954d3dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20367016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cd017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cd01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2136709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x024e7c80, 0x10020827, // fsub r0,  a, b
+0x024e7180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x024e7c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x01527380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025893, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x024e7c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10020527, // fadd a+1, r0, r1
+0x029d3ec0, 0x10020827, // fsub r0,  a, b
+0x029d31c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d3e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d43c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024893, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d3e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10021527, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20327016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cc017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cc01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2132709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02467c80, 0x10020827, // fsub r0,  a, b
+0x02467180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02467c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x014a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02467c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100204a7, // fadd a+1, r0, r1
+0x029d1ec0, 0x10020827, // fsub r0,  a, b
+0x029d11c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d1e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d23c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d1e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100214a7, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1c8dc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0xfffff010, 0xf00809e7, // brr.allz -, r:pass_4
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dedc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0xfffff0e0, 0xf0f809e7, // brr -, r:loop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c3fc0, 0x100209a7, // mov interrupt, flag
+0x009e7000, 0x300009e7, // nop; nop; thrend
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_2k.hex b/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_2k.hex
new file mode 100755 (executable)
index 0000000..bd30abb
--- /dev/null
@@ -0,0 +1,765 @@
+0x00000010, 0xe0021727, // mov rb_0x10,    0x10
+0x00000040, 0xe0021767, // mov rb_0x40,    0x40
+0x000000f0, 0xe00217a7, // mov rb_0xF0,    0xF0
+0x000001d0, 0xe00217e7, // mov rb_0x1D0,   0x1D0
+0x00005555, 0xe0020727, // mov rx_0x5555,  0x5555
+0x00003333, 0xe0020767, // mov rx_0x3333,  0x3333
+0x00000f0f, 0xe00207a7, // mov rx_0x0F0F,  0x0F0F
+0x000000ff, 0xe00207e7, // mov rx_0x00FF,  0x00FF
+0x15827d80, 0x100203e7, // mov rx_tw_shared, unif
+0x15827d80, 0x100213e7, // mov rx_tw_unique, unif
+0x15827d80, 0x10021167, // mov rb_inst, unif
+0x00101200, 0xe0020827, // mov r0, vpm_setup(1, 1, v32( 0,0))
+0x00000010, 0xe0020867, // mov r1, vpm_setup(1, 1, v32(16,0)) - vpm_setup(1, 1, v32(0,0))
+0x00000002, 0xe00208a7, // mov r2, vpm_setup(1, 1, v32( 0,2)) - vpm_setup(1, 1, v32(0,0))
+0x409c5017, 0x100049e2, // nop; mul24 r2, r2, in_inst
+0xcc9e7081, 0x10025020, // add out_0, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x10025060, // add out_1, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100250a0, // add out_2, r0, r2; v8adds r0, r0, r1
+0x0c9e7080, 0x100211e7, // add out_3, r0, r2
+0x000000c8, 0xf0f80127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x152e7d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x15327d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x15367d80, 0x10021c67, // mov vw_setup, ra_vdw_32
+0xc00001c0, 0xe0021c67, // mov vw_setup, vdw_setup_1(0) + PASS32_STRIDE-16*4
+0x8c05ddf6, 0x10024072, // add ra_save_ptr, ra_save_ptr, rb_0x40; mov vw_addr, ra_save_ptr
+0x00000050, 0xf0f81127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x152e7d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x15327d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x00000000, 0xf0f4c9e7, // bra -, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x152e7d80, 0x10020c67, // mov vr_setup, ra_vpm_lo
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x000000f8, 0xf0f802a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x159c0fc0, 0x10021c67, // mov vw_setup, rb_vpm
+0x012cbdc0, 0x10020c27, // fadd vpm, ra_64+0, rb_64+0
+0x0130cdc0, 0x10020c27, // fadd vpm, ra_64+1, rb_64+1
+0x159c1fc0, 0x10021c67, // mov vw_setup, rb_vpm_16
+0x0134ddc0, 0x10020c27, // fadd vpm, ra_64+2, rb_64+2
+0x0138edc0, 0x10020c27, // fadd vpm, ra_64+3, rb_64+3
+0x159c2fc0, 0x10021c67, // mov vw_setup, rb_vpm_32
+0x022cbdc0, 0x10020c27, // fsub vpm, ra_64+0, rb_64+0
+0x0230cdc0, 0x10020c27, // fsub vpm, ra_64+1, rb_64+1
+0x159c7fc0, 0x10021c67, // mov vw_setup, rb_vpm_48
+0x0234ddc0, 0x10020c27, // fsub vpm, ra_64+2, rb_64+2
+0x0238edc0, 0x10020c27, // fsub vpm, ra_64+3, rb_64+3
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0xa0104000, 0xe0021c67, // mov vw_setup, vdw_setup_0(64, 16, dma_h32(0,0))
+0xc00000c0, 0xe0021c67, // mov vw_setup, vdw_setup_1(PASS64_STRIDE-16*4)
+0x8c05ddf6, 0x10024072, // add ra_save_ptr, ra_save_ptr, step; mov vw_addr, ra_save_ptr
+0x000002b8, 0xf0f812a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd00200a7, // shl ra_temp, r0, 5
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0fc49e7, // brr -, ra_temp
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x000000e0, 0xf0f809e7, // brr -, r:2f
+0x00000010, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x000000c0, 0xf0f809e7, // brr -, r:2f
+0x00000011, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x000000a0, 0xf0f809e7, // brr -, r:2f
+0x00000012, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000080, 0xf0f809e7, // brr -, r:2f
+0x00000013, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000060, 0xf0f809e7, // brr -, r:2f
+0x00000014, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000040, 0xf0f809e7, // brr -, r:2f
+0x00000015, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000020, 0xf0f809e7, // brr -, r:2f
+0x00000016, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f809e7, // brr -, r:2f
+0x00000017, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c0fc0, 0x10021c67, // mov vw_setup, rb_vpm
+0x012cbdc0, 0x10020c27, // fadd vpm, ra_64+0, rb_64+0
+0x0130cdc0, 0x10020c27, // fadd vpm, ra_64+1, rb_64+1
+0x159c1fc0, 0x10021c67, // mov vw_setup, rb_vpm_16
+0x0134ddc0, 0x10020c27, // fadd vpm, ra_64+2, rb_64+2
+0x0138edc0, 0x10020c27, // fadd vpm, ra_64+3, rb_64+3
+0x159c2fc0, 0x10021c67, // mov vw_setup, rb_vpm_32
+0x022cbdc0, 0x10020c27, // fsub vpm, ra_64+0, rb_64+0
+0x0230cdc0, 0x10020c27, // fsub vpm, ra_64+1, rb_64+1
+0x159c7fc0, 0x10021c67, // mov vw_setup, rb_vpm_48
+0x0234ddc0, 0x10020c27, // fsub vpm, ra_64+2, rb_64+2
+0x0238edc0, 0x10020c27, // fsub vpm, ra_64+3, rb_64+3
+0x00000000, 0xf0fc49e7, // brr -, ra_temp
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x00000008, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x00000009, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000a, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000b, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000c, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000d, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000e, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000f, 0xe80009e7, // mov -, srel(i+8)
+0x00000080, 0xf0f801a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000858, 0xf0f811a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000009, 0xe80009e7, // mov -, srel(i+9)
+0x00000011, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000a, 0xe80009e7, // mov -, srel(i+9)
+0x00000012, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000b, 0xe80009e7, // mov -, srel(i+9)
+0x00000013, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000c, 0xe80009e7, // mov -, srel(i+9)
+0x00000014, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000d, 0xe80009e7, // mov -, srel(i+9)
+0x00000015, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000e, 0xe80009e7, // mov -, srel(i+9)
+0x00000016, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000f, 0xe80009e7, // mov -, srel(i+9)
+0x00000017, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x204a7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d2039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22092cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x204a7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819ff2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f1400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829ff609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f1449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x204e7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d3039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22093cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x204e7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fe2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f2400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fe609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f2449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20527030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d4039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22094cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20527031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fc2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f4400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fc609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f4449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20567030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d5039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22095cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20567031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819f82c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f8400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x00000000, 0xf0f409e7, // bra -, ra_link_0
+0x829f8609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f8449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x8c15cdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14727180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14727180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c21c0, 0xd0020827, // shr r0, r0, 13-STAGES
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffda0, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c15cdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14727180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14727180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c21c0, 0xd0020827, // shr r0, r0, 13-STAGES
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffc80, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x205e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d700f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x205e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22097c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x01267c00, 0x100202e7, // fadd ra_64+0, ra_32_re, r0
+0x019c9e40, 0x10020327, // fadd ra_64+1, rb_32_im, r1
+0x02267c00, 0x10020367, // fsub ra_64+2, ra_32_re, r0
+0x029c9e40, 0x100203a7, // fsub ra_64+3, rb_32_im, r1
+0x8c15fdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14727180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14727180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c21c0, 0xd0020827, // shr r0, r0, 13-STAGES
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffb20, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c15cdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14727180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14727180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c21c0, 0xd0020827, // shr r0, r0, 13-STAGES
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffa00, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x205e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d700f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x205e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22097c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x029c9e40, 0x100208e7, // fsub r3, rb_32_im, r1
+0x02267c00, 0x100208a7, // fsub r2, ra_32_re, r0
+0x019c9e40, 0x10020867, // fadd r1, rb_32_im, r1
+0x01267c00, 0x10020827, // fadd r0, ra_32_re, r0
+0x2066700e, 0x100049c9, // nop;                        fmul rb_32_im, r1, ra_tw_re+TW48
+0x209d900f, 0x100059c9, // nop;                        fmul ra_32_re, r1, rb_tw_im+TW48
+0x209d9007, 0x100049e1, // nop;                        fmul r1,       r0, rb_tw_im+TW48
+0x216493c6, 0x10025320, // fadd rb_64+1, r1, rb_32_im; fmul r0,       r0, ra_tw_re+TW48
+0x2225a19f, 0x100252c9, // fsub rb_64+0, r0, ra_32_re; fmul ra_32_re, r3, rb_tw_im+TW64
+0x206a701e, 0x100049c9, // nop;                        fmul rb_32_im, r3, ra_tw_re+TW64
+0x00000000, 0xf0f549e7, // bra -, ra_save_64
+0x209da017, 0x100049e3, // nop;                        fmul r3,       r2, rb_tw_im+TW64
+0x216897d6, 0x100253a2, // fadd rb_64+3, r3, rb_32_im; fmul r2,       r2, ra_tw_re+TW64
+0x02267580, 0x10021367, // fsub rb_64+2, r2, ra_32_re
+0x8c15edf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff920, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c15cdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff8d0, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x205e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d700f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x205e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22097c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x00000000, 0xf0f489e7, // bra -, ra_save_32
+0x952c2ff6, 0x100242c2, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x95307ff6, 0x10024307, // mov ra_vpm_hi, rb_vpm_hi; mov rb_vpm_hi, ra_vpm_hi
+0x9534dff6, 0x1002434d, // mov ra_vdw_32, rb_vdw_32; mov rb_vdw_32, ra_vdw_32
+0x159c5fc0, 0x10022827, // mov.setf r0, rb_inst
+0x0d9c11c0, 0xd0020827, // sub r0, r0, 1
+0x119c51c0, 0xd0020827, // shl r0, r0, 5
+0x0c9c6e00, 0x100601a7, // add.ifnz ra_sync, rx_sync_slave, r0
+0x159c4fc0, 0x10060127, // mov.ifnz ra_save_32, rx_save_slave_32
+0x159cafc0, 0x100602a7, // mov.ifnz ra_save_64, rx_save_slave_64
+0x15827d80, 0x100220e7, // mov.setf ra_addr_x, unif
+0x15827d80, 0x100210e7, // mov      rb_addr_y, unif
+0x00000870, 0xf00809e7, // brr.allz -, r:end
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000003, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020567, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021567, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000002, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100205e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100215e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020667, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021667, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100206a7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100216a7, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024596, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024618, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c562, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d563, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c522, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d523, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c4e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d4e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c4a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d4a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c61c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15cdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14727180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14727180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c21c0, 0xd0020827, // shr r0, r0, 13-STAGES
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff688, 0xf0f80227, // brr ra_link_1, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x00000200, 0xe0020827, // mov r0, 0x200
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x0e1cbdc0, 0xd00229e7, // shr.setf -, ra_points, STAGES
+0xfffff660, 0xf00809e7, // brr.allz -, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x00000200, 0xe0020827, // mov r0, 0x200
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159c0fc0, 0x100202e7, // mov ra_vpm_lo, rb_vpm
+0x159c1fc0, 0x10020327, // mov ra_vpm_hi, rb_vpm_16
+0x90104000, 0xe0020367, // mov ra_vdw_32, vdw_setup_0(32, 16, dma_h32( 0,0))
+0x90105000, 0xe0021367, // mov rb_vdw_32, vdw_setup_0(32, 16, dma_h32(32,0))
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9cfe00, 0x10020e27, // add t0s, ptr, r0
+0x0c9cfe40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020567, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021567, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9cfe00, 0x10020e27, // add t0s, ptr, r0
+0x0c9cfe40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100205e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100215e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000005, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020427, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021427, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000004, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024596, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024618, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c562, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d563, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c522, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d523, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c4e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d4e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c4a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d4a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15cdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff920, 0xf0f80227, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x955d7dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20467016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209d1017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209d101f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2146709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x025e7c80, 0x10020827, // fsub r0,  a, b
+0x025e7180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x025e7c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x01627380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025897, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x025e7c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10020627, // fadd a+1, r0, r1
+0x029d7ec0, 0x10020827, // fsub r0,  a, b
+0x029d71c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d7e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d83c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024897, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d7e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10021627, // fadd a+1, r0, r1
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20427016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209d0017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209d001f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2142709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02567c80, 0x10020827, // fsub r0,  a, b
+0x02567180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02567c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x015a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025895, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02567c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100205a7, // fadd a+1, r0, r1
+0x029d5ec0, 0x10020827, // fsub r0,  a, b
+0x029d51c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d5e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d63c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024895, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d5e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100215a7, // fadd a+1, r0, r1
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c562, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d563, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c522, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d523, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c4e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d4e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c4a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d4a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1cbdc0, 0xd00229e7, // shr.setf -, ra_points, STAGES
+0xfffff690, 0xf00809e7, // brr.allz -, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0xfffff760, 0xf0f809e7, // brr -, r:loop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c3fc0, 0x100209a7, // mov interrupt, flag
+0x009e7000, 0x300009e7, // nop; nop; thrend
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_32k.hex b/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_32k.hex
new file mode 100755 (executable)
index 0000000..3b6fd77
--- /dev/null
@@ -0,0 +1,697 @@
+0x00000010, 0xe00216e7, // mov rb_0x10,    0x10
+0x00000040, 0xe0021727, // mov rb_0x40,    0x40
+0x00000080, 0xe0021767, // mov rb_0x80,    0x80
+0x000000f0, 0xe00217a7, // mov rb_0xF0,    0xF0
+0x00000100, 0xe00217e7, // mov rb_0x100,   0x100
+0x00005555, 0xe0020767, // mov rx_0x5555,  0x5555
+0x00003333, 0xe00207a7, // mov rx_0x3333,  0x3333
+0x00000f0f, 0xe00207e7, // mov rx_0x0F0F,  0x0F0F
+0x000000ff, 0xe00216a7, // mov rx_0x00FF,  0x00FF
+0x90104000, 0xe0020727, // mov ra_vdw_32, vdw_setup_0(32, 16, dma_h32( 0,0))
+0x90105000, 0xe0021067, // mov rb_vdw_32, vdw_setup_0(32, 16, dma_h32(32,0))
+0x15827d80, 0x100202a7, // mov rx_tw_shared, unif
+0x15827d80, 0x100212a7, // mov rx_tw_unique, unif
+0x15827d80, 0x10021167, // mov rb_inst, unif
+0x00101200, 0xe0020827, // mov r0, vpm_setup(1, 1, v32( 0,0))
+0x00000010, 0xe0020867, // mov r1, vpm_setup(1, 1, v32(16,0)) - vpm_setup(1, 1, v32(0,0))
+0x00000002, 0xe00208a7, // mov r2, vpm_setup(1, 1, v32( 0,2)) - vpm_setup(1, 1, v32(0,0))
+0x409c5017, 0x100049e2, // nop; mul24 r2, r2, in_inst
+0xcc9e7081, 0x100246a0, // add out_0, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100246e0, // add out_1, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100250a0, // add out_2, r0, r2; v8adds r0, r0, r1
+0x0c9e7080, 0x100211e7, // add out_3, r0, r2
+0x000000c8, 0xf0f80127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x156a7d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x156e7d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x15727d80, 0x10021c67, // mov vw_setup, ra_vdw_32
+0xc0001fc0, 0xe0021c67, // mov vw_setup, vdw_setup_1(0) + PASS32_STRIDE-16*4
+0x8c05cdf6, 0x10024072, // add ra_save_ptr, ra_save_ptr, rb_0x40; mov vw_addr, ra_save_ptr
+0x00000050, 0xf0f81127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x156a7d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x156e7d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x00000000, 0xf0f4c9e7, // bra -, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x156a7d80, 0x10020c67, // mov vr_setup, ra_vpm_lo
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x00000080, 0xf0f801a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000588, 0xf0f811a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000009, 0xe80009e7, // mov -, srel(i+9)
+0x00000011, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000a, 0xe80009e7, // mov -, srel(i+9)
+0x00000012, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000b, 0xe80009e7, // mov -, srel(i+9)
+0x00000013, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000c, 0xe80009e7, // mov -, srel(i+9)
+0x00000014, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000d, 0xe80009e7, // mov -, srel(i+9)
+0x00000015, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000e, 0xe80009e7, // mov -, srel(i+9)
+0x00000016, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000f, 0xe80009e7, // mov -, srel(i+9)
+0x00000017, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20367030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209cd039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208dcb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20367031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819ff2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f1400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829ff609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f1449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x203a7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209ce039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208ecb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x203a7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fe2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f2400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fe609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f2449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x203e7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209cf039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208fcb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x203e7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fc2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f4400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fc609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f4449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20427030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d0039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22090cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20427031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819f82c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f8400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x00000000, 0xf0f409e7, // bra -, ra_link_0
+0x829f8609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f8449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x8c15edf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149da1c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149da1c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x119c21c0, 0xd0020827, // shl r0, r0, STAGES-13
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffda0, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149da1c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149da1c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x119c21c0, 0xd0020827, // shl r0, r0, STAGES-13
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffc80, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x204a7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d200f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x204a700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22092c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x00000000, 0xf0f489e7, // bra -, ra_save_32
+0x95682ff6, 0x10024682, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x956c7ff6, 0x100246c7, // mov ra_vpm_hi, rb_vpm_hi; mov rb_vpm_hi, ra_vpm_hi
+0x95701ff6, 0x10024701, // mov ra_vdw_32, rb_vdw_32; mov rb_vdw_32, ra_vdw_32
+0x8c15edf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffbf0, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffba0, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x204a7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d200f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x204a700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22092c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x00000000, 0xf0f489e7, // bra -, ra_save_32
+0x95682ff6, 0x10024682, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x956c7ff6, 0x100246c7, // mov ra_vpm_hi, rb_vpm_hi; mov rb_vpm_hi, ra_vpm_hi
+0x95701ff6, 0x10024701, // mov ra_vdw_32, rb_vdw_32; mov rb_vdw_32, ra_vdw_32
+0x159c5fc0, 0x10022827, // mov.setf r0, rb_inst
+0x0d9c11c0, 0xd0020827, // sub r0, r0, 1
+0x119c51c0, 0xd0020827, // shl r0, r0, 5
+0x0c9c6e00, 0x100601a7, // add.ifnz ra_sync, rx_sync_slave, r0
+0x159c4fc0, 0x10060127, // mov.ifnz ra_save_32, rx_save_slave_32
+0x15827d80, 0x100220e7, // mov.setf ra_addr_x, unif
+0x15827d80, 0x100210e7, // mov      rb_addr_y, unif
+0x00000d00, 0xf00809e7, // brr.allz -, r:end
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2a7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2a7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020427, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021427, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2a7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2a7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100204a7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100214a7, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024451, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe00244d3, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95410dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c362, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d363, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149da1c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149da1c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x119c21c0, 0xd0020827, // shl r0, r0, STAGES-13
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffa10, 0xf0f80227, // brr ra_link_1, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x0e1cfdc0, 0xd00229e7, // shr.setf -, ra_points, STAGES
+0xfffff9e8, 0xf00809e7, // brr.allz -, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2a7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2a7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020427, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021427, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2a7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2a7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100204a7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100214a7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000003, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2a7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2a7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100202e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100212e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000002, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2a7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2a7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020327, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021327, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024451, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe00244d3, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95410dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c362, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d363, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff9f8, 0xf0f80227, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0xfffff9d8, 0xf0f80227, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0xfffff9b8, 0xf0f80227, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0xfffff998, 0xf0f80227, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x95492dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20327016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cc017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cc01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2132709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x024a7c80, 0x10020827, // fsub r0,  a, b
+0x024a7180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x024a7c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x014e7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025892, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x024a7c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100204e7, // fadd a+1, r0, r1
+0x029d2ec0, 0x10020827, // fsub r0,  a, b
+0x029d21c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d2e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d33c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024892, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d2e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100214e7, // fadd a+1, r0, r1
+0x95410dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x202e7016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cb017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cb01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x212e709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02427c80, 0x10020827, // fsub r0,  a, b
+0x02427180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02427c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x01467380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025890, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02427c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10020467, // fadd a+1, r0, r1
+0x029d0ec0, 0x10020827, // fsub r0,  a, b
+0x029d01c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d0e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d13c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024890, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d0e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10021467, // fadd a+1, r0, r1
+0x95410dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c362, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d363, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1cfdc0, 0xd00229e7, // shr.setf -, ra_points, STAGES
+0xfffff708, 0xf00809e7, // brr.allz -, r:pass_2
+0x00000060, 0xe0020827, // mov r0, 3*4*8
+0x0d227c00, 0x10020227, // sub ra_link_1, ra_link_1, r0
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9cae00, 0x10020e27, // add t0s, ptr, r0
+0x0c9cae40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020427, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021427, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9cae00, 0x10020e27, // add t0s, ptr, r0
+0x0c9cae40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100204a7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100214a7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000005, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2a7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2a7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100202e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100212e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000004, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2a7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2a7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020327, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021327, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024451, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe00244d3, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95410dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c362, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d363, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff498, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x95492dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20327016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cc017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cc01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2132709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x024a7c80, 0x10020827, // fsub r0,  a, b
+0x024a7180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x024a7c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x014e7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025892, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x024a7c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100204e7, // fadd a+1, r0, r1
+0x029d2ec0, 0x10020827, // fsub r0,  a, b
+0x029d21c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d2e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d33c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024892, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d2e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100214e7, // fadd a+1, r0, r1
+0x95410dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x202e7016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cb017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cb01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x212e709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02427c80, 0x10020827, // fsub r0,  a, b
+0x02427180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02427c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x01467380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025890, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02427c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10020467, // fadd a+1, r0, r1
+0x029d0ec0, 0x10020827, // fsub r0,  a, b
+0x029d01c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d0e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d13c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024890, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d0e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10021467, // fadd a+1, r0, r1
+0x95410dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c362, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d363, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1cfdc0, 0xd00229e7, // shr.setf -, ra_points, STAGES
+0xfffff208, 0xf00809e7, // brr.allz -, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0xfffff2d0, 0xf0f809e7, // brr -, r:loop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c3fc0, 0x100209a7, // mov interrupt, flag
+0x009e7000, 0x300009e7, // nop; nop; thrend
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_4096k.hex b/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_4096k.hex
new file mode 100755 (executable)
index 0000000..f49df21
--- /dev/null
@@ -0,0 +1,1523 @@
+0x00000010, 0xe0021227, // mov rb_0x10,    0x10
+0x000001d0, 0xe0021967, // mov r5rep,      0x1D0
+0x15827d80, 0x100203e7, // mov rx_tw_shared, unif
+0x15827d80, 0x100213e7, // mov rx_tw_unique, unif
+0x15827d80, 0x10021167, // mov rb_inst, unif
+0x00101200, 0xe0020827, // mov r0, vpm_setup(1, 1, v32( 0,0))
+0x00000010, 0xe0020867, // mov r1, vpm_setup(1, 1, v32(16,0)) - vpm_setup(1, 1, v32(0,0))
+0x00000002, 0xe00208a7, // mov r2, vpm_setup(1, 1, v32( 0,2)) - vpm_setup(1, 1, v32(0,0))
+0x409c5017, 0x100049e2, // nop; mul24 r2, r2, in_inst
+0xcc9e7081, 0x10025020, // add out_0, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x10025060, // add out_1, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100250a0, // add out_2, r0, r2; v8adds r0, r0, r1
+0x0c9e7080, 0x100211e7, // add out_3, r0, r2
+0x000002e8, 0xf0f80127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x152e7d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x15327d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x153a7d80, 0x10020827, // mov r0, ra_vdw_32
+0x8c04ddf6, 0x10024061, // add ra_save_ptr, ra_save_ptr, rb_0x40; mov r1, ra_save_ptr
+0x00000080, 0xe00208a7, // mov r2, vdw_setup_0(1, 16, dma_h32(1,0)) - vdw_setup_0(1, 16, dma_h32(0,0))
+0x00100000, 0xe00208e7, // mov r3, PASS32_STRIDE
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000050, 0xf0f81127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x152e7d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x15327d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x00000000, 0xf0f4c9e7, // bra -, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x152e7d80, 0x10020c67, // mov vr_setup, ra_vpm_lo
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x00000520, 0xf0f802a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x159c0fc0, 0x10021c67, // mov vw_setup, rb_vpm
+0x012cbdc0, 0x10020c27, // fadd vpm, ra_64+0, rb_64+0
+0x0130cdc0, 0x10020c27, // fadd vpm, ra_64+1, rb_64+1
+0x159c1fc0, 0x10021c67, // mov vw_setup, rb_vpm_16
+0x0134ddc0, 0x10020c27, // fadd vpm, ra_64+2, rb_64+2
+0x0138edc0, 0x10020c27, // fadd vpm, ra_64+3, rb_64+3
+0x159c2fc0, 0x10021c67, // mov vw_setup, rb_vpm_32
+0x022cbdc0, 0x10020c27, // fsub vpm, ra_64+0, rb_64+0
+0x0230cdc0, 0x10020c27, // fsub vpm, ra_64+1, rb_64+1
+0x159c7fc0, 0x10021c67, // mov vw_setup, rb_vpm_48
+0x0234ddc0, 0x10020c27, // fsub vpm, ra_64+2, rb_64+2
+0x0238edc0, 0x10020c27, // fsub vpm, ra_64+3, rb_64+3
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x80904000, 0xe0020827, // mov r0, vdw_setup_0(1, 16, dma_h32(0,0))
+0x00000040, 0xe0020867, // mov r1, 0x40
+0x8c067c76, 0x10024061, // add ra_save_ptr, ra_save_ptr, r1; mov r1, ra_save_ptr
+0x00000080, 0xe00208a7, // mov r2, vdw_setup_0(1, 16, dma_h32(1,0)) - vdw_setup_0(1, 16, dma_h32(0,0))
+0x00080000, 0xe00208e7, // mov r3, PASS64_STRIDE
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x000002b8, 0xf0f812a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd00200a7, // shl ra_temp, r0, 5
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0fc49e7, // brr -, ra_temp
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x000000e0, 0xf0f809e7, // brr -, r:2f
+0x00000010, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x000000c0, 0xf0f809e7, // brr -, r:2f
+0x00000011, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x000000a0, 0xf0f809e7, // brr -, r:2f
+0x00000012, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000080, 0xf0f809e7, // brr -, r:2f
+0x00000013, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000060, 0xf0f809e7, // brr -, r:2f
+0x00000014, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000040, 0xf0f809e7, // brr -, r:2f
+0x00000015, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000020, 0xf0f809e7, // brr -, r:2f
+0x00000016, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f809e7, // brr -, r:2f
+0x00000017, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c0fc0, 0x10021c67, // mov vw_setup, rb_vpm
+0x012cbdc0, 0x10020c27, // fadd vpm, ra_64+0, rb_64+0
+0x0130cdc0, 0x10020c27, // fadd vpm, ra_64+1, rb_64+1
+0x159c1fc0, 0x10021c67, // mov vw_setup, rb_vpm_16
+0x0134ddc0, 0x10020c27, // fadd vpm, ra_64+2, rb_64+2
+0x0138edc0, 0x10020c27, // fadd vpm, ra_64+3, rb_64+3
+0x159c2fc0, 0x10021c67, // mov vw_setup, rb_vpm_32
+0x022cbdc0, 0x10020c27, // fsub vpm, ra_64+0, rb_64+0
+0x0230cdc0, 0x10020c27, // fsub vpm, ra_64+1, rb_64+1
+0x159c7fc0, 0x10021c67, // mov vw_setup, rb_vpm_48
+0x0234ddc0, 0x10020c27, // fsub vpm, ra_64+2, rb_64+2
+0x0238edc0, 0x10020c27, // fsub vpm, ra_64+3, rb_64+3
+0x00000000, 0xf0fc49e7, // brr -, ra_temp
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x00000008, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x00000009, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000a, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000b, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000c, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000d, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000e, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000f, 0xe80009e7, // mov -, srel(i+8)
+0x00000080, 0xf0f801a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000ba8, 0xf0f811a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000009, 0xe80009e7, // mov -, srel(i+9)
+0x00000011, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000a, 0xe80009e7, // mov -, srel(i+9)
+0x00000012, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000b, 0xe80009e7, // mov -, srel(i+9)
+0x00000013, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000c, 0xe80009e7, // mov -, srel(i+9)
+0x00000014, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000d, 0xe80009e7, // mov -, srel(i+9)
+0x00000015, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000e, 0xe80009e7, // mov -, srel(i+9)
+0x00000016, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000f, 0xe80009e7, // mov -, srel(i+9)
+0x00000017, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x204a7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d2039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22092cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x204a7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819ff2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f1400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829ff609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f1449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x204e7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d3039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22093cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x204e7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fe2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f2400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fe609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f2449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20527030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d4039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22094cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20527031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fc2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f4400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fc609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f4449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20567030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d5039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22095cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20567031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819f82c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f8400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x00000000, 0xf0f409e7, // bra -, ra_link_0
+0x829f8609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f8449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x55555555, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x33333333, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0f0f0f0f, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x00ff00ff, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0000ffff, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c81c0, 0x10020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c83c0, 0x10020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c71c0, 0xd0020827, // shr r0, r0, 32-STAGES-3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffd50, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x55555555, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x33333333, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0f0f0f0f, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x00ff00ff, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0000ffff, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c81c0, 0x10020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c83c0, 0x10020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c71c0, 0xd0020827, // shr r0, r0, 32-STAGES-3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffbe0, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x205e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d700f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x205e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22097c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x01267c00, 0x100202e7, // fadd ra_64+0, ra_32_re, r0
+0x019c9e40, 0x10020327, // fadd ra_64+1, rb_32_im, r1
+0x02267c00, 0x10020367, // fsub ra_64+2, ra_32_re, r0
+0x029c9e40, 0x100203a7, // fsub ra_64+3, rb_32_im, r1
+0x8c167d76, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x55555555, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x33333333, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0f0f0f0f, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x00ff00ff, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0000ffff, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c81c0, 0x10020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c83c0, 0x10020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c71c0, 0xd0020827, // shr r0, r0, 32-STAGES-3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffa30, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x55555555, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x33333333, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0f0f0f0f, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x00ff00ff, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0000ffff, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c81c0, 0x10020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c83c0, 0x10020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c71c0, 0xd0020827, // shr r0, r0, 32-STAGES-3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffff8c0, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x205e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d700f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x205e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22097c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x029c9e40, 0x100208e7, // fsub r3, rb_32_im, r1
+0x02267c00, 0x100208a7, // fsub r2, ra_32_re, r0
+0x019c9e40, 0x10020867, // fadd r1, rb_32_im, r1
+0x01267c00, 0x10020827, // fadd r0, ra_32_re, r0
+0x2066700e, 0x100049c9, // nop;                        fmul rb_32_im, r1, ra_tw_re+TW48
+0x209d900f, 0x100059c9, // nop;                        fmul ra_32_re, r1, rb_tw_im+TW48
+0x209d9007, 0x100049e1, // nop;                        fmul r1,       r0, rb_tw_im+TW48
+0x216493c6, 0x10025320, // fadd rb_64+1, r1, rb_32_im; fmul r0,       r0, ra_tw_re+TW48
+0x2225b19f, 0x100252c9, // fsub rb_64+0, r0, ra_32_re; fmul ra_32_re, r3, rb_tw_im+TW64
+0x206e701e, 0x100049c9, // nop;                        fmul rb_32_im, r3, ra_tw_re+TW64
+0x00000000, 0xf0f549e7, // bra -, ra_save_64
+0x209db017, 0x100049e3, // nop;                        fmul r3,       r2, rb_tw_im+TW64
+0x216c97d6, 0x100253a2, // fadd rb_64+3, r3, rb_32_im; fmul r2,       r2, ra_tw_re+TW64
+0x02267580, 0x10021367, // fsub rb_64+2, r2, ra_32_re
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff7e0, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff790, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x205e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d700f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x205e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22097c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x01267c00, 0x100202e7, // fadd ra_64+0, ra_32_re, r0
+0x019c9e40, 0x10020327, // fadd ra_64+1, rb_32_im, r1
+0x02267c00, 0x10020367, // fsub ra_64+2, ra_32_re, r0
+0x029c9e40, 0x100203a7, // fsub ra_64+3, rb_32_im, r1
+0x8c167d76, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff700, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff6b0, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x205e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d700f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x205e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22097c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x029c9e40, 0x100208e7, // fsub r3, rb_32_im, r1
+0x02267c00, 0x100208a7, // fsub r2, ra_32_re, r0
+0x019c9e40, 0x10020867, // fadd r1, rb_32_im, r1
+0x01267c00, 0x10020827, // fadd r0, ra_32_re, r0
+0x2066700e, 0x100049c9, // nop;                        fmul rb_32_im, r1, ra_tw_re+TW48
+0x209d900f, 0x100059c9, // nop;                        fmul ra_32_re, r1, rb_tw_im+TW48
+0x209d9007, 0x100049e1, // nop;                        fmul r1,       r0, rb_tw_im+TW48
+0x216493c6, 0x10025320, // fadd rb_64+1, r1, rb_32_im; fmul r0,       r0, ra_tw_re+TW48
+0x2225b19f, 0x100252c9, // fsub rb_64+0, r0, ra_32_re; fmul ra_32_re, r3, rb_tw_im+TW64
+0x206e701e, 0x100049c9, // nop;                        fmul rb_32_im, r3, ra_tw_re+TW64
+0x00000000, 0xf0f549e7, // bra -, ra_save_64
+0x209db017, 0x100049e3, // nop;                        fmul r3,       r2, rb_tw_im+TW64
+0x216c97d6, 0x100253a2, // fadd rb_64+3, r3, rb_32_im; fmul r2,       r2, ra_tw_re+TW64
+0x02267580, 0x10021367, // fsub rb_64+2, r2, ra_32_re
+0x8c14cdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff5d0, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff580, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x205e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d700f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x205e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22097c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x00000000, 0xf0f489e7, // bra -, ra_save_32
+0x952c2ff6, 0x100242c2, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x95307ff6, 0x10024307, // mov ra_vpm_hi, rb_vpm_hi; mov rb_vpm_hi, ra_vpm_hi
+0x9538eff6, 0x1002438e, // mov ra_vdw_32, rb_vdw_32; mov rb_vdw_32, ra_vdw_32
+0x159c5fc0, 0x10022827, // mov.setf r0, rb_inst
+0x0d9c11c0, 0xd0020827, // sub r0, r0, 1
+0x119c51c0, 0xd0020827, // shl r0, r0, 5
+0x0c9c6e00, 0x100601a7, // add.ifnz ra_sync, rx_sync_slave, r0
+0x159c4fc0, 0x10060127, // mov.ifnz ra_save_32, rx_save_slave_32
+0x159cafc0, 0x100602a7, // mov.ifnz ra_save_64, rx_save_slave_64
+0x15827d80, 0x100220e7, // mov.setf ra_addr_x, unif
+0x15827d80, 0x100210e7, // mov      rb_addr_y, unif
+0x000016b8, 0xf00809e7, // brr.allz -, r:end
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000003, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020567, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021567, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000002, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100205e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100215e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020667, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021667, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100206e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100216e7, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024596, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024618, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c562, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d563, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c522, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d523, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c4e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d4e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c4a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d4a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c61c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x55555555, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x33333333, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0f0f0f0f, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x00ff00ff, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0000ffff, 0xe00208a7, // mov r2, mask
+0x149e7080, 0x10020867, // and r1, r0, r2
+0x0e9c81c0, 0x10020827, // shr r0, r0, shift
+0x149e7080, 0x10020827, // and r0, r0, r2
+0x119c83c0, 0x10020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c71c0, 0xd0020827, // shr r0, r0, 32-STAGES-3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff2e8, 0xf0f80227, // brr ra_link_1, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x00000200, 0xe0020827, // mov r0, 0x200
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x00000016, 0xe0020867, // mov r1, STAGES
+0x0e1e7c40, 0x100229e7, // shr.setf -, ra_points, r1
+0xfffff2b8, 0xf00809e7, // brr.allz -, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x00000200, 0xe0020827, // mov r0, 0x200
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000003, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020567, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021567, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000002, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100205e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100215e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020667, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021667, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100206e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100216e7, // mov rb_tw_im+dst, r4
+0x00000000, 0xe002469a, // mov ra_tw_re+TW48+1, 0; mov rb_tw_im+TW48+1, 0
+0x00000000, 0xe002471c, // mov ra_tw_re+TW64+1, 0; mov rb_tw_im+TW64+1, 0
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000007, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020427, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021427, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000006, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000004, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020767, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021767, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000005, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100207a7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100217a7, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024596, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024618, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c562, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d563, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c522, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d523, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c4e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d4e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c4a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d4a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c61c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff568, 0xf0f80227, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x00000200, 0xe0020827, // mov r0, 0x200
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x0000ffff, 0xe0020827, // mov r0, 0xFFFF
+0x141e7c00, 0x100229e7, // and.setf -, ra_points, r0
+0xfffff538, 0xf01809e7, // brr.allnz -, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x00000200, 0xe0020827, // mov r0, 0x200
+0x0c1e7c00, 0x100601e7, // add.ifnz ra_points, ra_points, r0
+0x956dbdbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x207a7016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209de017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209de01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x217a709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x026e7c80, 0x10020827, // fsub r0,  a, b
+0x026e7180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x026e7c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x01727380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x1002589b, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x026e7c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10020727, // fadd a+1, r0, r1
+0x029dbec0, 0x10020827, // fsub r0,  a, b
+0x029db1c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029dbe40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019dc3c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x1002489b, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029dbe80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10021727, // fadd a+1, r0, r1
+0x95659dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20767016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209dd017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209dd01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2176709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02667c80, 0x10020827, // fsub r0,  a, b
+0x02667180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02667c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x016a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025899, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02667c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100206a7, // fadd a+1, r0, r1
+0x029d9ec0, 0x10020827, // fsub r0,  a, b
+0x029d91c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d9e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019da3c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024899, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d9e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100216a7, // fadd a+1, r0, r1
+0x955d7dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20467016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209d1017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209d101f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2146709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x025e7c80, 0x10020827, // fsub r0,  a, b
+0x025e7180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x025e7c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x01627380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025897, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x025e7c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10020627, // fadd a+1, r0, r1
+0x029d7ec0, 0x10020827, // fsub r0,  a, b
+0x029d71c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d7e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d83c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024897, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d7e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10021627, // fadd a+1, r0, r1
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20427016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209d0017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209d001f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2142709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02567c80, 0x10020827, // fsub r0,  a, b
+0x02567180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02567c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x015a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025895, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02567c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100205a7, // fadd a+1, r0, r1
+0x029d5ec0, 0x10020827, // fsub r0,  a, b
+0x029d51c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d5e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d63c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024895, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d5e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100215a7, // fadd a+1, r0, r1
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c562, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d563, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c522, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d523, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c4e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d4e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c4a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d4a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x00000016, 0xe0020867, // mov r1, STAGES
+0x0e1e7c40, 0x100229e7, // shr.setf -, ra_points, r1
+0xfffff0a0, 0xf00809e7, // brr.allz -, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x00000200, 0xe0020827, // mov r0, 0x200
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159c0fc0, 0x100202e7, // mov ra_vpm_lo, rb_vpm
+0x159c1fc0, 0x10020327, // mov ra_vpm_hi, rb_vpm_16
+0x80904000, 0xe00203a7, // mov ra_vdw_32, vdw_setup_0(1, 16, dma_h32( 0,0))
+0x80905000, 0xe00213a7, // mov rb_vdw_32, vdw_setup_0(1, 16, dma_h32(32,0))
+0x00000016, 0xe00212e7, // mov rb_STAGES, STAGES
+0x000000f0, 0xe0021327, // mov rb_0xF0, 0xF0
+0x00000040, 0xe0021367, // mov rb_0x40, 0x40
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000003, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020567, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021567, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000002, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100205e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100215e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000009, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020427, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021427, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000008, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024596, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024618, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c562, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d563, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c522, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d523, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c4e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d4e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c4a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d4a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff008, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x000003ff, 0xe0020827, // mov r0, 0x3FF
+0x141e7c00, 0x100229e7, // and.setf -, ra_points, r0
+0xffffefd8, 0xf01809e7, // brr.allnz -, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100601e7, // add.ifnz ra_points, ra_points, r0
+0x955d7dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20467016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209d1017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209d101f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2146709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x025e7c80, 0x10020827, // fsub r0,  a, b
+0x025e7180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x025e7c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x01627380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025897, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x025e7c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10020627, // fadd a+1, r0, r1
+0x029d7ec0, 0x10020827, // fsub r0,  a, b
+0x029d71c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d7e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d83c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024897, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d7e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10021627, // fadd a+1, r0, r1
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20427016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209d0017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209d001f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2142709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02567c80, 0x10020827, // fsub r0,  a, b
+0x02567180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02567c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x015a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025895, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02567c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100205a7, // fadd a+1, r0, r1
+0x029d5ec0, 0x10020827, // fsub r0,  a, b
+0x029d51c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d5e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d63c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024895, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d5e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100215a7, // fadd a+1, r0, r1
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c562, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d563, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c522, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d523, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c4e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d4e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c4a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d4a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1cbdc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0xffffed48, 0xf00809e7, // brr.allz -, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9cfe00, 0x10020e27, // add t0s, ptr, r0
+0x0c9cfe40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020567, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021567, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9cfe00, 0x10020e27, // add t0s, ptr, r0
+0x0c9cfe40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100205e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100215e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x0000000b, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020427, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021427, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x0000000a, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024596, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024618, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c562, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d563, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c522, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d523, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c4e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d4e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c4a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d4a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xffffead8, 0xf0f80227, // brr ra_link_1, r:pass_4
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x955d7dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20467016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209d1017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209d101f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2146709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x025e7c80, 0x10020827, // fsub r0,  a, b
+0x025e7180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x025e7c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x01627380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025897, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x025e7c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10020627, // fadd a+1, r0, r1
+0x029d7ec0, 0x10020827, // fsub r0,  a, b
+0x029d71c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d7e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d83c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024897, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d7e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10021627, // fadd a+1, r0, r1
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20427016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209d0017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209d001f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2142709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02567c80, 0x10020827, // fsub r0,  a, b
+0x02567180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02567c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x015a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025895, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02567c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100205a7, // fadd a+1, r0, r1
+0x029d5ec0, 0x10020827, // fsub r0,  a, b
+0x029d51c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d5e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d63c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024895, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d5e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100215a7, // fadd a+1, r0, r1
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c562, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d563, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c522, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d523, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c4e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d4e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c4a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d4a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1cbdc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0xffffe848, 0xf00809e7, // brr.allz -, r:pass_4
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0xffffe918, 0xf0f809e7, // brr -, r:loop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c3fc0, 0x100209a7, // mov interrupt, flag
+0x009e7000, 0x300009e7, // nop; nop; thrend
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_4k.hex b/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_4k.hex
new file mode 100755 (executable)
index 0000000..c37e50d
--- /dev/null
@@ -0,0 +1,514 @@
+0x00000020, 0xe0021767, // mov rb_0x20,    0x20
+0x00000040, 0xe00217a7, // mov rb_0x40,    0x40
+0x00000080, 0xe00217e7, // mov rb_0x80,    0x80
+0x00005555, 0xe0020727, // mov rx_0x5555,  0x5555
+0x00003333, 0xe0020767, // mov rx_0x3333,  0x3333
+0x00000f0f, 0xe00207a7, // mov rx_0x0F0F,  0x0F0F
+0x000000ff, 0xe00207e7, // mov rx_0x00FF,  0x00FF
+0x88104000, 0xe00206e7, // mov ra_vdw, vdw_setup_0(16, 16, dma_h32( 0,0))
+0x88104800, 0xe00216e7, // mov rb_vdw, vdw_setup_0(16, 16, dma_h32(16,0))
+0x15827d80, 0x10020227, // mov rx_tw_shared, unif
+0x15827d80, 0x10021227, // mov rx_tw_unique, unif
+0x15827d80, 0x10021167, // mov rb_inst, unif
+0x00101200, 0xe0020827, // mov r0, vpm_setup(1, 1, v32( 0,0))
+0x00000010, 0xe0020867, // mov r1, vpm_setup(1, 1, v32(16,0)) - vpm_setup(1, 1, v32(0,0))
+0x00000002, 0xe00208a7, // mov r2, vpm_setup(1, 1, v32( 0,2)) - vpm_setup(1, 1, v32(0,0))
+0x409c5017, 0x100049e2, // nop; mul24 r2, r2, in_inst
+0xcc9e7081, 0x100246a0, // add out_0, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100256a0, // add out_1, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100049e0, // add out_2, r0, r2; v8adds r0, r0, r1
+0x0c9e7080, 0x100009e7, // add out_3, r0, r2
+0x000000b0, 0xf0f80127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x156a7d80, 0x10021c67, // mov vw_setup, arg
+0x159e7000, 0x10020c27, // mov vpm, r0
+0x159e7240, 0x10020c27, // mov vpm, r1
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000000, 0xf0f409e7, // bra -, ra_link_1
+0x156e7d80, 0x10021c67, // mov vw_setup, arg_vdw
+0xc00007c0, 0xe0021c67, // mov vw_setup, vdw_setup_1(0) + PASS16_STRIDE-16*4
+0x8c05edf6, 0x10024072, // add ra_save_ptr, ra_save_ptr, rb_0x40; mov vw_addr, ra_save_ptr
+0x00000038, 0xf0f81127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x156a7d80, 0x10021c67, // mov vw_setup, arg
+0x159e7000, 0x10020c27, // mov vpm, r0
+0x159e7240, 0x10020c27, // mov vpm, r1
+0x00000000, 0xf0f4c9e7, // bra -, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x156a7d80, 0x10020c67, // mov vr_setup, arg_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x00000080, 0xf0f801a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000000, 0xf0f409e7, // bra -, ra_link_1
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x000003e8, 0xf0f811a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f409e7, // bra -, ra_link_1
+0x00000009, 0xe80009e7, // mov -, srel(i+9)
+0x00000011, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f409e7, // bra -, ra_link_1
+0x0000000a, 0xe80009e7, // mov -, srel(i+9)
+0x00000012, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f409e7, // bra -, ra_link_1
+0x0000000b, 0xe80009e7, // mov -, srel(i+9)
+0x00000013, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f409e7, // bra -, ra_link_1
+0x0000000c, 0xe80009e7, // mov -, srel(i+9)
+0x00000014, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f409e7, // bra -, ra_link_1
+0x0000000d, 0xe80009e7, // mov -, srel(i+9)
+0x00000015, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f409e7, // bra -, ra_link_1
+0x0000000e, 0xe80009e7, // mov -, srel(i+9)
+0x00000016, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f409e7, // bra -, ra_link_1
+0x0000000f, 0xe80009e7, // mov -, srel(i+9)
+0x00000017, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x202a7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209ca039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208acb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x202a7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819ff2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f1400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829ff609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f1449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x202e7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209cb039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208bcb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x202e7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fe2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f2400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fe609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f2449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20327030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209cc039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208ccb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20327031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fc2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f4400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fc609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f4449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20367030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209cd039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208dcb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20367031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819f82c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f8400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x00000000, 0xf0f489e7, // bra -, ra_link_0
+0x829f8609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f8449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x8c15fdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14727180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14727180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c11c0, 0xd0020827, // shr r0, r0, 13-STAGES
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x000000cc, 0xe20229e7, // mov.setf  -, [0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
+0x959fa000, 0xd002c8a0, // mov r2, r0; mov.ifnz r0, r0 << 6
+0x959fa249, 0xd002c8e1, // mov r3, r1; mov.ifnz r1, r1 << 6
+0x00003300, 0xe20229e7, // mov.setf  -, [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0]
+0x809f6012, 0xd000c9e0, // nop; mov.ifnz r0, r2 >> 6
+0x809f601b, 0xd000c9e1, // nop; mov.ifnz r1, r3 >> 6
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x000000cc, 0xe20229e7, // mov.setf  -, [0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
+0x959fa000, 0xd002c8a0, // mov r2, r0; mov.ifnz r0, r0 << 6
+0x959fa249, 0xd002c8e1, // mov r3, r1; mov.ifnz r1, r1 << 6
+0x00003300, 0xe20229e7, // mov.setf  -, [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0]
+0x809f6012, 0xd000c9e0, // nop; mov.ifnz r0, r2 >> 6
+0x809f601b, 0xd000c9e1, // nop; mov.ifnz r1, r3 >> 6
+0xfffffd40, 0xf0f809e7, // brr -, r:fft_16
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x8c15fdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffcf8, 0xf0f809e7, // brr -, r:fft_16
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x159c5fc0, 0x10022827, // mov.setf r0, rb_inst
+0x0d9c11c0, 0xd0020827, // sub r0, r0, 1
+0x119c51c0, 0xd0020827, // shl r0, r0, 5
+0x0c9c6e00, 0x100601a7, // add.ifnz ra_sync, rx_sync_slave, r0
+0x159c4fc0, 0x10060127, // mov.ifnz ra_save_16, rx_save_slave_16
+0x15827d80, 0x100220e7, // mov.setf ra_addr_x, unif
+0x15827d80, 0x100210e7, // mov      rb_addr_y, unif
+0x00000928, 0xf00809e7, // brr.allz -, r:end
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c227c00, 0x10020e27, // add t0s, ptr, r0
+0x0c227c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020367, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021367, // mov rb_tw_im+dst, r4
+0x00000000, 0xe002438e, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x9534ddbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c362, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d363, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c322, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d323, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c2e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d2e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c2a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d2a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c41c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15fdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14727180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14727180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c11c0, 0xd0020827, // shr r0, r0, 13-STAGES
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x000000cc, 0xe20229e7, // mov.setf  -, [0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
+0x959fa000, 0xd002c8a0, // mov r2, r0; mov.ifnz r0, r0 << 6
+0x959fa249, 0xd002c8e1, // mov r3, r1; mov.ifnz r1, r1 << 6
+0x00003300, 0xe20229e7, // mov.setf  -, [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0]
+0x809f6012, 0xd000c9e0, // nop; mov.ifnz r0, r2 >> 6
+0x809f601b, 0xd000c9e1, // nop; mov.ifnz r1, r3 >> 6
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffbe0, 0xf0f80027, // brr ra_link_1, r:pass_1
+0x9569aff6, 0x1002469a, // mov ra_vpm, rb_vpm; mov rb_vpm, ra_vpm
+0x956dbff6, 0x100246db, // mov ra_vdw, rb_vdw; mov rb_vdw, ra_vdw
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x0e1ccdc0, 0xd00229e7, // shr.setf -, ra_points, STAGES
+0xfffffbb8, 0xf00809e7, // brr.allz -, r:pass_1
+0x9569aff6, 0x1002469a, // mov ra_vpm, rb_vpm; mov rb_vpm, ra_vpm
+0x956dbff6, 0x100246db, // mov ra_vdw, rb_vdw; mov rb_vdw, ra_vdw
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x00000000, 0xf0f4c027, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c227c00, 0x10020e27, // add t0s, ptr, r0
+0x0c227c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020367, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021367, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c227c00, 0x10020e27, // add t0s, ptr, r0
+0x0c227c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020267, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021267, // mov rb_tw_im+dst, r4
+0x00000000, 0xe002438e, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x9534ddbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c362, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d363, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c322, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d323, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c2e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d2e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c2a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d2a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c41c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15fdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffb78, 0xf0f80027, // brr ra_link_1, r:pass_2
+0x9569aff6, 0x1002469a, // mov ra_vpm, rb_vpm; mov rb_vpm, ra_vpm
+0x956dbff6, 0x100246db, // mov ra_vdw, rb_vdw; mov rb_vdw, ra_vdw
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0xfffffb58, 0xf0f80027, // brr ra_link_1, r:pass_2
+0x9569aff6, 0x1002469a, // mov ra_vpm, rb_vpm; mov rb_vpm, ra_vpm
+0x956dbff6, 0x100246db, // mov ra_vdw, rb_vdw; mov rb_vdw, ra_vdw
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x0d01ddc0, 0x10020027, // sub ra_link_1, ra_link_1, rb_0x20
+0x9534ddbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20267016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209c9017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209c901f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2126709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02367c80, 0x10020827, // fsub r0,  a, b
+0x02367180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02367c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x013a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x1002588d, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02367c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100203a7, // fadd a+1, r0, r1
+0x029cdec0, 0x10020827, // fsub r0,  a, b
+0x029cd1c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029cde40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019ce3c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x1002488d, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029cde80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100213a7, // fadd a+1, r0, r1
+0x9534ddbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c362, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d363, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c322, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d323, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c2e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d2e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c2a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d2a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1ccdc0, 0xd00229e7, // shr.setf -, ra_points, STAGES
+0xfffff9c0, 0xf00809e7, // brr.allz -, r:pass_2
+0x9569aff6, 0x1002469a, // mov ra_vpm, rb_vpm; mov rb_vpm, ra_vpm
+0x956dbff6, 0x100246db, // mov ra_vdw, rb_vdw; mov rb_vdw, ra_vdw
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x00000000, 0xf0f4c027, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9c8e00, 0x10020e27, // add t0s, ptr, r0
+0x0c9c8e40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020367, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021367, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000002, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c227c00, 0x10020e27, // add t0s, ptr, r0
+0x0c227c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020267, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021267, // mov rb_tw_im+dst, r4
+0x00000000, 0xe002438e, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x9534ddbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c362, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d363, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c322, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d323, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c2e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d2e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c2a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d2a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c41c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15fdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff808, 0xf0f80027, // brr ra_link_1, r:pass_3
+0x9569aff6, 0x1002469a, // mov ra_vpm, rb_vpm; mov rb_vpm, ra_vpm
+0x956dbff6, 0x100246db, // mov ra_vdw, rb_vdw; mov rb_vdw, ra_vdw
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x9534ddbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20267016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209c9017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209c901f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2126709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02367c80, 0x10020827, // fsub r0,  a, b
+0x02367180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02367c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x013a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x1002588d, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02367c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100203a7, // fadd a+1, r0, r1
+0x029cdec0, 0x10020827, // fsub r0,  a, b
+0x029cd1c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029cde40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019ce3c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x1002488d, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029cde80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100213a7, // fadd a+1, r0, r1
+0x9534ddbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c362, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d363, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c322, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d323, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c2e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d2e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c2a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d2a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1ccdc0, 0xd00229e7, // shr.setf -, ra_points, STAGES
+0xfffff678, 0xf00809e7, // brr.allz -, r:pass_3
+0x9569aff6, 0x1002469a, // mov ra_vpm, rb_vpm; mov rb_vpm, ra_vpm
+0x956dbff6, 0x100246db, // mov ra_vdw, rb_vdw; mov rb_vdw, ra_vdw
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x00000000, 0xf0f4c027, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0xfffff6a8, 0xf0f809e7, // brr -, r:loop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c3fc0, 0x100209a7, // mov interrupt, flag
+0x009e7000, 0x300009e7, // nop; nop; thrend
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_512.hex b/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_512.hex
new file mode 100755 (executable)
index 0000000..505ab41
--- /dev/null
@@ -0,0 +1,494 @@
+0x00000010, 0xe0021727, // mov rb_0x10,    0x10
+0x00000040, 0xe0021767, // mov rb_0x40,    0x40
+0x00000080, 0xe00217a7, // mov rb_0x80,    0x80
+0x000000f0, 0xe00217e7, // mov rb_0xF0,    0xF0
+0x00005555, 0xe0020727, // mov rx_0x5555,  0x5555
+0x00003333, 0xe0020767, // mov rx_0x3333,  0x3333
+0x00000f0f, 0xe00207a7, // mov rx_0x0F0F,  0x0F0F
+0x000000ff, 0xe00207e7, // mov rx_0x00FF,  0x00FF
+0x88104000, 0xe00206a7, // mov ra_vdw_16, vdw_setup_0(16, 16, dma_h32( 0,0))
+0x88105000, 0xe0021027, // mov rb_vdw_16, vdw_setup_0(16, 16, dma_h32(32,0))
+0x90104000, 0xe00206e7, // mov ra_vdw_32, vdw_setup_0(32, 16, dma_h32( 0,0))
+0x90105000, 0xe0021067, // mov rb_vdw_32, vdw_setup_0(32, 16, dma_h32(32,0))
+0x15827d80, 0x100202e7, // mov rx_tw_shared, unif
+0x15827d80, 0x100212e7, // mov rx_tw_unique, unif
+0x15827d80, 0x10021167, // mov rb_inst, unif
+0x00101200, 0xe0020827, // mov r0, vpm_setup(1, 1, v32( 0,0))
+0x00000010, 0xe0020867, // mov r1, vpm_setup(1, 1, v32(16,0)) - vpm_setup(1, 1, v32(0,0))
+0x00000002, 0xe00208a7, // mov r2, vpm_setup(1, 1, v32( 0,2)) - vpm_setup(1, 1, v32(0,0))
+0x409c5017, 0x100049e2, // nop; mul24 r2, r2, in_inst
+0xcc9e7081, 0x10024620, // add out_0, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x10024660, // add out_1, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100250a0, // add out_2, r0, r2; v8adds r0, r0, r1
+0x0c9e7080, 0x100211e7, // add out_3, r0, r2
+0x000000b0, 0xf0f80127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15627d80, 0x10021c67, // mov vw_setup, arg
+0x159e7000, 0x10020c27, // mov vpm, r0
+0x159e7240, 0x10020c27, // mov vpm, r1
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x156a7d80, 0x10021c67, // mov vw_setup, arg_vdw
+0xc00000c0, 0xe0021c67, // mov vw_setup, vdw_setup_1(0) + PASS16_STRIDE-16*4
+0x8c05ddf6, 0x10024072, // add ra_save_ptr, ra_save_ptr, rb_0x40; mov vw_addr, ra_save_ptr
+0x00000038, 0xf0f81127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15627d80, 0x10021c67, // mov vw_setup, arg
+0x159e7000, 0x10020c27, // mov vpm, r0
+0x159e7240, 0x10020c27, // mov vpm, r1
+0x00000000, 0xf0f4c9e7, // bra -, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x15627d80, 0x10020c67, // mov vr_setup, arg_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x000000c8, 0xf0f802a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15627d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x15667d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x156e7d80, 0x10021c67, // mov vw_setup, ra_vdw_32
+0xc0000040, 0xe0021c67, // mov vw_setup, vdw_setup_1(0) + PASS32_STRIDE-16*4
+0x8c05ddf6, 0x10024072, // add ra_save_ptr, ra_save_ptr, rb_0x40; mov vw_addr, ra_save_ptr
+0x00000050, 0xf0f812a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15627d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x15667d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x00000000, 0xf0f4c9e7, // bra -, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x15627d80, 0x10020c67, // mov vr_setup, ra_vpm_lo
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x00000080, 0xf0f801a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000510, 0xf0f811a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000009, 0xe80009e7, // mov -, srel(i+9)
+0x00000011, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000a, 0xe80009e7, // mov -, srel(i+9)
+0x00000012, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000b, 0xe80009e7, // mov -, srel(i+9)
+0x00000013, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000c, 0xe80009e7, // mov -, srel(i+9)
+0x00000014, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000d, 0xe80009e7, // mov -, srel(i+9)
+0x00000015, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000e, 0xe80009e7, // mov -, srel(i+9)
+0x00000016, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000f, 0xe80009e7, // mov -, srel(i+9)
+0x00000017, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x203a7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209ce039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208ecb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x203a7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819ff2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f1400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829ff609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f1449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x203e7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209cf039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208fcb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x203e7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fe2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f2400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fe609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f2449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20427030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d0039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22090cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20427031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fc2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f4400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fc609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f4449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20467030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d1039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22091cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20467031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819f82c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f8400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x00000000, 0xf0f409e7, // bra -, ra_link_0
+0x829f8609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f8449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x8c15fdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14727180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14727180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c41c0, 0xd0020827, // shr r0, r0, 13-STAGES
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffda0, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c15cdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14727180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14727180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c41c0, 0xd0020827, // shr r0, r0, 13-STAGES
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffc80, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x204e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d300f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x204e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22093c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x00000000, 0xf0f549e7, // bra -, ra_save_32
+0x95602ff6, 0x10024602, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x95647ff6, 0x10024647, // mov ra_vpm_hi, rb_vpm_hi; mov rb_vpm_hi, ra_vpm_hi
+0x956c1ff6, 0x100246c1, // mov ra_vdw_32, rb_vdw_32; mov rb_vdw_32, ra_vdw_32
+0x8c15edf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffbf0, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x00000000, 0xf0f489e7, // bra -, ra_save_16
+0x009e7000, 0x100009e7, // nop
+0x95602ff6, 0x10024602, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x95680ff6, 0x10024680, // mov ra_vdw_16, rb_vdw_16; mov rb_vdw_16, ra_vdw_16
+0x159c5fc0, 0x10022827, // mov.setf r0, rb_inst
+0x0d9c11c0, 0xd0020827, // sub r0, r0, 1
+0x119c51c0, 0xd0020827, // shl r0, r0, 5
+0x0c9c6e00, 0x100601a7, // add.ifnz ra_sync, rx_sync_slave, r0
+0x159c4fc0, 0x10060127, // mov.ifnz ra_save_16, rx_save_slave_16
+0x159cafc0, 0x100602a7, // mov.ifnz ra_save_32, rx_save_slave_32
+0x15827d80, 0x100220e7, // mov.setf ra_addr_x, unif
+0x15827d80, 0x100210e7, // mov      rb_addr_y, unif
+0x000005e8, 0xf00809e7, // brr.allz -, r:end
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100204e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100214e7, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15cdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14727180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14727180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9c41c0, 0xd0020827, // shr r0, r0, 13-STAGES
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffa80, 0xf0f80227, // brr ra_link_1, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0xfffffa60, 0xf0f80227, // brr ra_link_1, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9cbe00, 0x10020e27, // add t0s, ptr, r0
+0x0c9cbe40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000002, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020327, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021327, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c41c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15edf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffb20, 0xf0f80227, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dedc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20327016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cc017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cc01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2132709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02467c80, 0x10020827, // fsub r0,  a, b
+0x02467180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02467c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x014a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02467c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100204a7, // fadd a+1, r0, r1
+0x029d1ec0, 0x10020827, // fsub r0,  a, b
+0x029d11c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d1e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d23c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d1e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100214a7, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1c9dc0, 0xd00229e7, // shr.setf -, ra_points, STAGES
+0xfffff990, 0xf00809e7, // brr.allz -, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dedc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0xfffff9e8, 0xf0f809e7, // brr -, r:loop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c3fc0, 0x100209a7, // mov interrupt, flag
+0x009e7000, 0x300009e7, // nop; nop; thrend
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_512k.hex b/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_512k.hex
new file mode 100755 (executable)
index 0000000..ebc84d8
--- /dev/null
@@ -0,0 +1,983 @@
+0x00000013, 0xe0021227, // mov rb_STAGES,  STAGES
+0x00000010, 0xe00216e7, // mov rb_0x10,    0x10
+0x00000040, 0xe0021727, // mov rb_0x40,    0x40
+0x00000080, 0xe0021767, // mov rb_0x80,    0x80
+0x000000f0, 0xe00217a7, // mov rb_0xF0,    0xF0
+0x00000100, 0xe00217e7, // mov rb_0x100,   0x100
+0x55555555, 0xe0020767, // mov rx_0x55555555, 0x55555555
+0x33333333, 0xe00207a7, // mov rx_0x33333333, 0x33333333
+0x0f0f0f0f, 0xe00207e7, // mov rx_0x0F0F0F0F, 0x0F0F0F0F
+0x00ff00ff, 0xe0021667, // mov rx_0x00FF00FF, 0x00FF00FF
+0x0000ffff, 0xe00216a7, // mov rx_0x0000FFFF, 0x0000FFFF
+0x80904000, 0xe00206e7, // mov ra_vdw_16, vdw_setup_0(1, 16, dma_h32( 0,0))
+0x80905000, 0xe0021027, // mov rb_vdw_16, vdw_setup_0(1, 16, dma_h32(32,0))
+0x80904000, 0xe0020727, // mov ra_vdw_32, vdw_setup_0(1, 16, dma_h32( 0,0))
+0x80905000, 0xe0021067, // mov rb_vdw_32, vdw_setup_0(1, 16, dma_h32(32,0))
+0x15827d80, 0x100202e7, // mov rx_tw_shared, unif
+0x15827d80, 0x100212e7, // mov rx_tw_unique, unif
+0x15827d80, 0x10021167, // mov rb_inst, unif
+0x00101200, 0xe0020827, // mov r0, vpm_setup(1, 1, v32( 0,0))
+0x00000010, 0xe0020867, // mov r1, vpm_setup(1, 1, v32(16,0)) - vpm_setup(1, 1, v32(0,0))
+0x00000002, 0xe00208a7, // mov r2, vpm_setup(1, 1, v32( 0,2)) - vpm_setup(1, 1, v32(0,0))
+0x409c5017, 0x100049e2, // nop; mul24 r2, r2, in_inst
+0xcc9e7081, 0x10024660, // add out_0, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100246a0, // add out_1, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100250a0, // add out_2, r0, r2; v8adds r0, r0, r1
+0x0c9e7080, 0x100211e7, // add out_3, r0, r2
+0x000001d0, 0xf0f80127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10021c67, // mov vw_setup, arg
+0x159e7000, 0x10020c27, // mov vpm, r0
+0x159e7240, 0x10020c27, // mov vpm, r1
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x156e7d80, 0x10020827, // mov r0, arg_vdw
+0x8c05cdf6, 0x10024061, // add ra_save_ptr, ra_save_ptr, rb_0x40; mov r1, ra_save_ptr
+0x00000080, 0xe00208a7, // mov r2, vdw_setup_0(1, 16, dma_h32(1,0)) - vdw_setup_0(1, 16, dma_h32(0,0))
+0x00040000, 0xe00208e7, // mov r3, PASS16_STRIDE
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000038, 0xf0f81127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10021c67, // mov vw_setup, arg
+0x159e7000, 0x10020c27, // mov vpm, r0
+0x159e7240, 0x10020c27, // mov vpm, r1
+0x00000000, 0xf0f4c9e7, // bra -, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10020c67, // mov vr_setup, arg_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x000002e8, 0xf0f802a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x156a7d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x15727d80, 0x10020827, // mov r0, ra_vdw_32
+0x8c05cdf6, 0x10024061, // add ra_save_ptr, ra_save_ptr, rb_0x40; mov r1, ra_save_ptr
+0x00000080, 0xe00208a7, // mov r2, vdw_setup_0(1, 16, dma_h32(1,0)) - vdw_setup_0(1, 16, dma_h32(0,0))
+0x00020000, 0xe00208e7, // mov r3, PASS32_STRIDE
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x8c9e7080, 0x10024831, // add r0, r0, r2; mov vw_setup, r0
+0x8c9e72c9, 0x10024872, // add r1, r1, r3; mov vw_addr,  r1
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000050, 0xf0f812a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x156a7d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x00000000, 0xf0f4c9e7, // bra -, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10020c67, // mov vr_setup, ra_vpm_lo
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x00000080, 0xf0f801a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000640, 0xf0f811a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000009, 0xe80009e7, // mov -, srel(i+9)
+0x00000011, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000a, 0xe80009e7, // mov -, srel(i+9)
+0x00000012, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000b, 0xe80009e7, // mov -, srel(i+9)
+0x00000013, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000c, 0xe80009e7, // mov -, srel(i+9)
+0x00000014, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000d, 0xe80009e7, // mov -, srel(i+9)
+0x00000015, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000e, 0xe80009e7, // mov -, srel(i+9)
+0x00000016, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000f, 0xe80009e7, // mov -, srel(i+9)
+0x00000017, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x203a7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209ce039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208ecb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x203a7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819ff2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f1400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829ff609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f1449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x203e7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209cf039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208fcb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x203e7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fe2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f2400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fe609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f2449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20427030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d0039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22090cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20427031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fc2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f4400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fc609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f4449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20467030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d1039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22091cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20467031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819f82c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f8400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x00000000, 0xf0f409e7, // bra -, ra_link_0
+0x829f8609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f8449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x8c15edf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149d91c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149d91c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149da1c0, 0x10020867, // and r1, r0, mask
+0x0e9db1c0, 0x10020827, // shr r0, r0, shift
+0x149da1c0, 0x10020827, // and r0, r0, mask
+0x119db3c0, 0x10020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9ca1c0, 0xd0020827, // shr r0, r0, 32-STAGES-3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffd78, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149d91c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149d91c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149da1c0, 0x10020867, // and r1, r0, mask
+0x0e9db1c0, 0x10020827, // shr r0, r0, shift
+0x149da1c0, 0x10020827, // and r0, r0, mask
+0x119db3c0, 0x10020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9ca1c0, 0xd0020827, // shr r0, r0, 32-STAGES-3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffc30, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x204e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d300f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x204e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22093c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x00000000, 0xf0f549e7, // bra -, ra_save_32
+0x95642ff6, 0x10024642, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x95687ff6, 0x10024687, // mov ra_vpm_hi, rb_vpm_hi; mov rb_vpm_hi, ra_vpm_hi
+0x95701ff6, 0x10024701, // mov ra_vdw_32, rb_vdw_32; mov rb_vdw_32, ra_vdw_32
+0x8c15ddf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffba0, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x00000000, 0xf0f489e7, // bra -, ra_save_16
+0x009e7000, 0x100009e7, // nop
+0x95642ff6, 0x10024642, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x956c0ff6, 0x100246c0, // mov ra_vdw_16, rb_vdw_16; mov rb_vdw_16, ra_vdw_16
+0x8c15edf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffb38, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffae8, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x204e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d300f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x204e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22093c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x00000000, 0xf0f549e7, // bra -, ra_save_32
+0x95642ff6, 0x10024642, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x95687ff6, 0x10024687, // mov ra_vpm_hi, rb_vpm_hi; mov rb_vpm_hi, ra_vpm_hi
+0x95701ff6, 0x10024701, // mov ra_vdw_32, rb_vdw_32; mov rb_vdw_32, ra_vdw_32
+0x159c5fc0, 0x10022827, // mov.setf r0, rb_inst
+0x0d9c11c0, 0xd0020827, // sub r0, r0, 1
+0x119c51c0, 0xd0020827, // shl r0, r0, 5
+0x0c9c6e00, 0x100601a7, // add.ifnz ra_sync, rx_sync_slave, r0
+0x159c4fc0, 0x10060127, // mov.ifnz ra_save_16, rx_save_slave_16
+0x159cafc0, 0x100602a7, // mov.ifnz ra_save_32, rx_save_slave_32
+0x15827d80, 0x100220e7, // mov.setf ra_addr_x, unif
+0x15827d80, 0x100210e7, // mov      rb_addr_y, unif
+0x000010a8, 0xf00809e7, // brr.allz -, r:end
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100204e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100214e7, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149d91c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149d91c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149da1c0, 0x10020867, // and r1, r0, mask
+0x0e9db1c0, 0x10020827, // shr r0, r0, shift
+0x149da1c0, 0x10020827, // and r0, r0, mask
+0x119db3c0, 0x10020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0e9ca1c0, 0xd0020827, // shr r0, r0, 32-STAGES-3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff928, 0xf0f80227, // brr ra_link_1, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x0e1c8dc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0xfffff900, 0xf00809e7, // brr.allz -, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000002, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020327, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021327, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c41c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15ddf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffa10, 0xf0f80227, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dddc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x00003fff, 0xe0020827, // mov r0, 0x3FFF
+0x141e7c00, 0x100229e7, // and.setf -, ra_points, r0
+0xfffff9e0, 0xf01809e7, // brr.allnz -, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dddc0, 0x100601e7, // add.ifnz ra_points, ra_points, rb_0x80
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20327016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cc017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cc01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2132709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02467c80, 0x10020827, // fsub r0,  a, b
+0x02467180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02467c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x014a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02467c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100204a7, // fadd a+1, r0, r1
+0x029d1ec0, 0x10020827, // fsub r0,  a, b
+0x029d11c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d1e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d23c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d1e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100214a7, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1c8dc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0xfffff850, 0xf00809e7, // brr.allz -, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dddc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100204e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100214e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000004, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020327, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021327, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000003, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020367, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021367, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff648, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0xfffff628, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0xfffff608, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0xfffff5e8, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x954d3dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20367016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cd017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cd01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2136709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x024e7c80, 0x10020827, // fsub r0,  a, b
+0x024e7180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x024e7c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x01527380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025893, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x024e7c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10020527, // fadd a+1, r0, r1
+0x029d3ec0, 0x10020827, // fsub r0,  a, b
+0x029d31c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d3e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d43c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024893, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d3e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10021527, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20327016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cc017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cc01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2132709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02467c80, 0x10020827, // fsub r0,  a, b
+0x02467180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02467c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x014a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02467c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100204a7, // fadd a+1, r0, r1
+0x029d1ec0, 0x10020827, // fsub r0,  a, b
+0x029d11c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d1e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d23c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d1e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100214a7, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1c8dc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0xfffff358, 0xf00809e7, // brr.allz -, r:pass_3
+0x00000060, 0xe0020827, // mov r0, 3*4*8
+0x0d227c00, 0x10020227, // sub ra_link_1, ra_link_1, r0
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9cbe00, 0x10020e27, // add t0s, ptr, r0
+0x0c9cbe40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9cbe00, 0x10020e27, // add t0s, ptr, r0
+0x0c9cbe40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100204e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100214e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000006, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020327, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021327, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000005, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020367, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021367, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff0e8, 0xf0f80227, // brr ra_link_1, r:pass_4
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x954d3dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20367016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cd017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cd01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2136709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x024e7c80, 0x10020827, // fsub r0,  a, b
+0x024e7180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x024e7c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x01527380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025893, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x024e7c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10020527, // fadd a+1, r0, r1
+0x029d3ec0, 0x10020827, // fsub r0,  a, b
+0x029d31c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d3e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d43c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024893, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d3e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10021527, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20327016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cc017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cc01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2132709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02467c80, 0x10020827, // fsub r0,  a, b
+0x02467180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02467c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x014a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02467c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100204a7, // fadd a+1, r0, r1
+0x029d1ec0, 0x10020827, // fsub r0,  a, b
+0x029d11c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d1e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d23c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d1e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100214a7, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1c8dc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0xffffee58, 0xf00809e7, // brr.allz -, r:pass_4
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0xffffef28, 0xf0f809e7, // brr -, r:loop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c3fc0, 0x100209a7, // mov interrupt, flag
+0x009e7000, 0x300009e7, // nop; nop; thrend
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_64k.hex b/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_64k.hex
new file mode 100755 (executable)
index 0000000..5daa0a5
--- /dev/null
@@ -0,0 +1,940 @@
+0x00000010, 0xe0021227, // mov rb_0x10,    0x10
+0x000001d0, 0xe0021967, // mov r5rep,      0x1D0
+0x00005555, 0xe00207a7, // mov rx_0x5555,  0x5555
+0x00003333, 0xe00217a7, // mov rx_0x3333,  0x3333
+0x00000f0f, 0xe00207e7, // mov rx_0x0F0F,  0x0F0F
+0x000000ff, 0xe00217e7, // mov rx_0x00FF,  0x00FF
+0x15827d80, 0x100203e7, // mov rx_tw_shared, unif
+0x15827d80, 0x100213e7, // mov rx_tw_unique, unif
+0x15827d80, 0x10021167, // mov rb_inst, unif
+0x00101200, 0xe0020827, // mov r0, vpm_setup(1, 1, v32( 0,0))
+0x00000010, 0xe0020867, // mov r1, vpm_setup(1, 1, v32(16,0)) - vpm_setup(1, 1, v32(0,0))
+0x00000002, 0xe00208a7, // mov r2, vpm_setup(1, 1, v32( 0,2)) - vpm_setup(1, 1, v32(0,0))
+0x409c5017, 0x100049e2, // nop; mul24 r2, r2, in_inst
+0xcc9e7081, 0x10025020, // add out_0, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x10025060, // add out_1, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100250a0, // add out_2, r0, r2; v8adds r0, r0, r1
+0x0c9e7080, 0x100211e7, // add out_3, r0, r2
+0x000000c8, 0xf0f80127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x152e7d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x15327d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x153a7d80, 0x10021c67, // mov vw_setup, ra_vdw_32
+0xc0003fc0, 0xe0021c67, // mov vw_setup, vdw_setup_1(0) + PASS32_STRIDE-16*4
+0x8c04ddf6, 0x10024072, // add ra_save_ptr, ra_save_ptr, rb_0x40; mov vw_addr, ra_save_ptr
+0x00000050, 0xf0f81127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x152e7d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x15327d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x00000000, 0xf0f4c9e7, // bra -, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x152e7d80, 0x10020c67, // mov vr_setup, ra_vpm_lo
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x00000100, 0xf0f802a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000040, 0xe0020827, // mov r0, 0x40
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x159c0fc0, 0x10021c67, // mov vw_setup, rb_vpm
+0x012cbdc0, 0x10020c27, // fadd vpm, ra_64+0, rb_64+0
+0x0130cdc0, 0x10020c27, // fadd vpm, ra_64+1, rb_64+1
+0x159c1fc0, 0x10021c67, // mov vw_setup, rb_vpm_16
+0x0134ddc0, 0x10020c27, // fadd vpm, ra_64+2, rb_64+2
+0x0138edc0, 0x10020c27, // fadd vpm, ra_64+3, rb_64+3
+0x159c2fc0, 0x10021c67, // mov vw_setup, rb_vpm_32
+0x022cbdc0, 0x10020c27, // fsub vpm, ra_64+0, rb_64+0
+0x0230cdc0, 0x10020c27, // fsub vpm, ra_64+1, rb_64+1
+0x159c7fc0, 0x10021c67, // mov vw_setup, rb_vpm_48
+0x0234ddc0, 0x10020c27, // fsub vpm, ra_64+2, rb_64+2
+0x0238edc0, 0x10020c27, // fsub vpm, ra_64+3, rb_64+3
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0xa0104000, 0xe0021c67, // mov vw_setup, vdw_setup_0(64, 16, dma_h32(0,0))
+0xc0001fc0, 0xe0021c67, // mov vw_setup, vdw_setup_1(PASS64_STRIDE-16*4)
+0x8c067c36, 0x10024072, // add ra_save_ptr, ra_save_ptr, step; mov vw_addr, ra_save_ptr
+0x000002b8, 0xf0f812a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd00200a7, // shl ra_temp, r0, 5
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0fc49e7, // brr -, ra_temp
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x000000e0, 0xf0f809e7, // brr -, r:2f
+0x00000010, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x000000c0, 0xf0f809e7, // brr -, r:2f
+0x00000011, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x000000a0, 0xf0f809e7, // brr -, r:2f
+0x00000012, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000080, 0xf0f809e7, // brr -, r:2f
+0x00000013, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000060, 0xf0f809e7, // brr -, r:2f
+0x00000014, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000040, 0xf0f809e7, // brr -, r:2f
+0x00000015, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000020, 0xf0f809e7, // brr -, r:2f
+0x00000016, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f809e7, // brr -, r:2f
+0x00000017, 0xe80009e7, // mov -, sacq(i)
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c0fc0, 0x10021c67, // mov vw_setup, rb_vpm
+0x012cbdc0, 0x10020c27, // fadd vpm, ra_64+0, rb_64+0
+0x0130cdc0, 0x10020c27, // fadd vpm, ra_64+1, rb_64+1
+0x159c1fc0, 0x10021c67, // mov vw_setup, rb_vpm_16
+0x0134ddc0, 0x10020c27, // fadd vpm, ra_64+2, rb_64+2
+0x0138edc0, 0x10020c27, // fadd vpm, ra_64+3, rb_64+3
+0x159c2fc0, 0x10021c67, // mov vw_setup, rb_vpm_32
+0x022cbdc0, 0x10020c27, // fsub vpm, ra_64+0, rb_64+0
+0x0230cdc0, 0x10020c27, // fsub vpm, ra_64+1, rb_64+1
+0x159c7fc0, 0x10021c67, // mov vw_setup, rb_vpm_48
+0x0234ddc0, 0x10020c27, // fsub vpm, ra_64+2, rb_64+2
+0x0238edc0, 0x10020c27, // fsub vpm, ra_64+3, rb_64+3
+0x00000000, 0xf0fc49e7, // brr -, ra_temp
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x00000008, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x00000009, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000a, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000b, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000c, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000d, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000e, 0xe80009e7, // mov -, srel(i+8)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x159c0fc0, 0x10020c67, // mov vr_setup, rb_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x0000000f, 0xe80009e7, // mov -, srel(i+8)
+0x00000080, 0xf0f801a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000858, 0xf0f811a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000009, 0xe80009e7, // mov -, srel(i+9)
+0x00000011, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000a, 0xe80009e7, // mov -, srel(i+9)
+0x00000012, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000b, 0xe80009e7, // mov -, srel(i+9)
+0x00000013, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000c, 0xe80009e7, // mov -, srel(i+9)
+0x00000014, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000d, 0xe80009e7, // mov -, srel(i+9)
+0x00000015, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000e, 0xe80009e7, // mov -, srel(i+9)
+0x00000016, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000f, 0xe80009e7, // mov -, srel(i+9)
+0x00000017, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x204a7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d2039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22092cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x204a7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819ff2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f1400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829ff609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f1449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x204e7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d3039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22093cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x204e7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fe2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f2400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fe609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f2449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20527030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d4039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22094cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20527031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fc2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f4400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fc609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f4449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20567030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d5039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22095cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20567031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819f82c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f8400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x00000000, 0xf0f409e7, // bra -, ra_link_0
+0x829f8609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f8449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149de1c0, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x149de1c0, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149df1c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149df1c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x119c31c0, 0xd0020827, // shl r0, r0, STAGES-13
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffda0, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149de1c0, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x149de1c0, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149df1c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149df1c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x119c31c0, 0xd0020827, // shl r0, r0, STAGES-13
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffc80, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x205e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d700f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x205e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22097c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x01267c00, 0x100202e7, // fadd ra_64+0, ra_32_re, r0
+0x019c9e40, 0x10020327, // fadd ra_64+1, rb_32_im, r1
+0x02267c00, 0x10020367, // fsub ra_64+2, ra_32_re, r0
+0x029c9e40, 0x100203a7, // fsub ra_64+3, rb_32_im, r1
+0x8c167d76, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149de1c0, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x149de1c0, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149df1c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149df1c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x119c31c0, 0xd0020827, // shl r0, r0, STAGES-13
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffb20, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149de1c0, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x149de1c0, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149df1c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149df1c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x119c31c0, 0xd0020827, // shl r0, r0, STAGES-13
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffa00, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x205e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d700f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x205e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22097c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x029c9e40, 0x100208e7, // fsub r3, rb_32_im, r1
+0x02267c00, 0x100208a7, // fsub r2, ra_32_re, r0
+0x019c9e40, 0x10020867, // fadd r1, rb_32_im, r1
+0x01267c00, 0x10020827, // fadd r0, ra_32_re, r0
+0x2066700e, 0x100049c9, // nop;                        fmul rb_32_im, r1, ra_tw_re+TW48
+0x209d900f, 0x100059c9, // nop;                        fmul ra_32_re, r1, rb_tw_im+TW48
+0x209d9007, 0x100049e1, // nop;                        fmul r1,       r0, rb_tw_im+TW48
+0x216493c6, 0x10025320, // fadd rb_64+1, r1, rb_32_im; fmul r0,       r0, ra_tw_re+TW48
+0x2225a19f, 0x100252c9, // fsub rb_64+0, r0, ra_32_re; fmul ra_32_re, r3, rb_tw_im+TW64
+0x206a701e, 0x100049c9, // nop;                        fmul rb_32_im, r3, ra_tw_re+TW64
+0x00000000, 0xf0f549e7, // bra -, ra_save_64
+0x209da017, 0x100049e3, // nop;                        fmul r3,       r2, rb_tw_im+TW64
+0x216897d6, 0x100253a2, // fadd rb_64+3, r3, rb_32_im; fmul r2,       r2, ra_tw_re+TW64
+0x02267580, 0x10021367, // fsub rb_64+2, r2, ra_32_re
+0x8c14cdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff920, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff8d0, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x205e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d700f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x205e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22097c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x00000000, 0xf0f489e7, // bra -, ra_save_32
+0x952c2ff6, 0x100242c2, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x95307ff6, 0x10024307, // mov ra_vpm_hi, rb_vpm_hi; mov rb_vpm_hi, ra_vpm_hi
+0x9538eff6, 0x1002438e, // mov ra_vdw_32, rb_vdw_32; mov rb_vdw_32, ra_vdw_32
+0x159c5fc0, 0x10022827, // mov.setf r0, rb_inst
+0x0d9c11c0, 0xd0020827, // sub r0, r0, 1
+0x119c51c0, 0xd0020827, // shl r0, r0, 5
+0x0c9c6e00, 0x100601a7, // add.ifnz ra_sync, rx_sync_slave, r0
+0x159c4fc0, 0x10060127, // mov.ifnz ra_save_32, rx_save_slave_32
+0x159cafc0, 0x100602a7, // mov.ifnz ra_save_64, rx_save_slave_64
+0x15827d80, 0x100220e7, // mov.setf ra_addr_x, unif
+0x15827d80, 0x100210e7, // mov      rb_addr_y, unif
+0x00000df0, 0xf00809e7, // brr.allz -, r:end
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000003, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020567, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021567, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000002, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100205e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100215e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020667, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021667, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100206a7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100216a7, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024596, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024618, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c562, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d563, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c522, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d523, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c4e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d4e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c4a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d4a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c61c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149de1c0, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x149de1c0, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149df1c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149df1c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x119c31c0, 0xd0020827, // shl r0, r0, STAGES-13
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff688, 0xf0f80227, // brr ra_link_1, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x00000200, 0xe0020827, // mov r0, 0x200
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x00000010, 0xe0020867, // mov r1, STAGES
+0x0e1e7c40, 0x100229e7, // shr.setf -, ra_points, r1
+0xfffff658, 0xf00809e7, // brr.allz -, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x00000200, 0xe0020827, // mov r0, 0x200
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159c0fc0, 0x100202e7, // mov ra_vpm_lo, rb_vpm
+0x159c1fc0, 0x10020327, // mov ra_vpm_hi, rb_vpm_16
+0x90104000, 0xe00203a7, // mov ra_vdw_32, vdw_setup_0(32, 16, dma_h32( 0,0))
+0x90105000, 0xe00213a7, // mov rb_vdw_32, vdw_setup_0(32, 16, dma_h32(32,0))
+0x00000060, 0xe00212e7, // mov rb_3x4x8, 3*4*8
+0x000000f0, 0xe0021327, // mov rb_0xF0, 0xF0
+0x00000040, 0xe0021367, // mov rb_0x40, 0x40
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000003, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020567, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021567, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000002, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100205e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100215e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000005, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020427, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021427, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000004, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024596, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024618, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c562, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d563, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c522, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d523, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c4e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d4e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c4a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d4a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff900, 0xf0f80227, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0xfffff8e0, 0xf0f80227, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0xfffff8c0, 0xf0f80227, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0xfffff8a0, 0xf0f80227, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x955d7dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20467016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209d1017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209d101f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2146709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x025e7c80, 0x10020827, // fsub r0,  a, b
+0x025e7180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x025e7c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x01627380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025897, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x025e7c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10020627, // fadd a+1, r0, r1
+0x029d7ec0, 0x10020827, // fsub r0,  a, b
+0x029d71c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d7e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d83c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024897, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d7e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10021627, // fadd a+1, r0, r1
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20427016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209d0017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209d001f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2142709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02567c80, 0x10020827, // fsub r0,  a, b
+0x02567180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02567c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x015a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025895, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02567c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100205a7, // fadd a+1, r0, r1
+0x029d5ec0, 0x10020827, // fsub r0,  a, b
+0x029d51c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d5e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d63c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024895, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d5e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100215a7, // fadd a+1, r0, r1
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c562, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d563, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c522, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d523, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c4e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d4e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c4a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d4a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1c8dc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0xfffff610, 0xf00809e7, // brr.allz -, r:pass_2
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x0d20bdc0, 0x10020227, // sub ra_link_1, ra_link_1, rb_3x4x8
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9cfe00, 0x10020e27, // add t0s, ptr, r0
+0x0c9cfe40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020567, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021567, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9cfe00, 0x10020e27, // add t0s, ptr, r0
+0x0c9cfe40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100205e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100215e7, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000007, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020427, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021427, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000006, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c3e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c3e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024596, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024618, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c562, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d563, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c522, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d523, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c4e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d4e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c4a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d4a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c148df6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff3a0, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x955d7dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20467016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209d1017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209d101f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2146709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x025e7c80, 0x10020827, // fsub r0,  a, b
+0x025e7180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x025e7c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x01627380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025897, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x025e7c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10020627, // fadd a+1, r0, r1
+0x029d7ec0, 0x10020827, // fsub r0,  a, b
+0x029d71c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d7e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d83c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024897, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d7e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x10021627, // fadd a+1, r0, r1
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20427016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209d0017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209d001f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2142709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02567c80, 0x10020827, // fsub r0,  a, b
+0x02567180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02567c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x015a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025895, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02567c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100205a7, // fadd a+1, r0, r1
+0x029d5ec0, 0x10020827, // fsub r0,  a, b
+0x029d51c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d5e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d63c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024895, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d5e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100215a7, // fadd a+1, r0, r1
+0x95555dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c562, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d563, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c522, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d523, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c4e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d4e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c4a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d4a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1c8dc0, 0x100229e7, // shr.setf -, ra_points, rb_STAGES
+0xfffff110, 0xf00809e7, // brr.allz -, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x00000100, 0xe0020827, // mov r0, 0x100
+0x0c1e7c00, 0x100201e7, // add ra_points, ra_points, r0
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0xfffff1e0, 0xf0f809e7, // brr -, r:loop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c3fc0, 0x100209a7, // mov interrupt, flag
+0x009e7000, 0x300009e7, // nop; nop; thrend
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_8k.hex b/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_8k.hex
new file mode 100755 (executable)
index 0000000..7e1f112
--- /dev/null
@@ -0,0 +1,603 @@
+0x00000010, 0xe00216e7, // mov rb_0x10,    0x10
+0x00000040, 0xe0021727, // mov rb_0x40,    0x40
+0x00000080, 0xe0021767, // mov rb_0x80,    0x80
+0x000000f0, 0xe00217a7, // mov rb_0xF0,    0xF0
+0x00000100, 0xe00217e7, // mov rb_0x100,   0x100
+0x00005555, 0xe0020767, // mov rx_0x5555,  0x5555
+0x00003333, 0xe00207a7, // mov rx_0x3333,  0x3333
+0x00000f0f, 0xe00207e7, // mov rx_0x0F0F,  0x0F0F
+0x000000ff, 0xe00216a7, // mov rx_0x00FF,  0x00FF
+0x88104000, 0xe00206e7, // mov ra_vdw_16, vdw_setup_0(16, 16, dma_h32( 0,0))
+0x88105000, 0xe0021027, // mov rb_vdw_16, vdw_setup_0(16, 16, dma_h32(32,0))
+0x90104000, 0xe0020727, // mov ra_vdw_32, vdw_setup_0(32, 16, dma_h32( 0,0))
+0x90105000, 0xe0021067, // mov rb_vdw_32, vdw_setup_0(32, 16, dma_h32(32,0))
+0x15827d80, 0x100202e7, // mov rx_tw_shared, unif
+0x15827d80, 0x100212e7, // mov rx_tw_unique, unif
+0x15827d80, 0x10021167, // mov rb_inst, unif
+0x00101200, 0xe0020827, // mov r0, vpm_setup(1, 1, v32( 0,0))
+0x00000010, 0xe0020867, // mov r1, vpm_setup(1, 1, v32(16,0)) - vpm_setup(1, 1, v32(0,0))
+0x00000002, 0xe00208a7, // mov r2, vpm_setup(1, 1, v32( 0,2)) - vpm_setup(1, 1, v32(0,0))
+0x409c5017, 0x100049e2, // nop; mul24 r2, r2, in_inst
+0xcc9e7081, 0x10024660, // add out_0, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100246a0, // add out_1, r0, r2; v8adds r0, r0, r1
+0xcc9e7081, 0x100250a0, // add out_2, r0, r2; v8adds r0, r0, r1
+0x0c9e7080, 0x100211e7, // add out_3, r0, r2
+0x000000b0, 0xf0f80127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10021c67, // mov vw_setup, arg
+0x159e7000, 0x10020c27, // mov vpm, r0
+0x159e7240, 0x10020c27, // mov vpm, r1
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x156e7d80, 0x10021c67, // mov vw_setup, arg_vdw
+0xc0000fc0, 0xe0021c67, // mov vw_setup, vdw_setup_1(0) + PASS16_STRIDE-16*4
+0x8c05cdf6, 0x10024072, // add ra_save_ptr, ra_save_ptr, rb_0x40; mov vw_addr, ra_save_ptr
+0x00000038, 0xf0f81127, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10021c67, // mov vw_setup, arg
+0x159e7000, 0x10020c27, // mov vpm, r0
+0x159e7240, 0x10020c27, // mov vpm, r1
+0x00000000, 0xf0f4c9e7, // bra -, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10020c67, // mov vr_setup, arg_vpm
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x000000c8, 0xf0f802a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x156a7d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x15727d80, 0x10021c67, // mov vw_setup, ra_vdw_32
+0xc00007c0, 0xe0021c67, // mov vw_setup, vdw_setup_1(0) + PASS32_STRIDE-16*4
+0x8c05cdf6, 0x10024072, // add ra_save_ptr, ra_save_ptr, rb_0x40; mov vw_addr, ra_save_ptr
+0x00000050, 0xf0f812a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10021c67, // mov vw_setup, ra_vpm_lo
+0x01267c00, 0x10020c27, // fadd vpm, ra_32_re, r0
+0x019c9e40, 0x10020c27, // fadd vpm, rb_32_im, r1
+0x156a7d80, 0x10021c67, // mov vw_setup, ra_vpm_hi
+0x02267c00, 0x10020c27, // fsub vpm, ra_32_re, r0
+0x029c9e40, 0x10020c27, // fsub vpm, rb_32_im, r1
+0x00000000, 0xf0f4c9e7, // bra -, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x15667d80, 0x10020c67, // mov vr_setup, ra_vpm_lo
+0x15c27d80, 0x100009e7, // mov -, vpm
+0x00000080, 0xf0f801a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x00000019, 0xe80009e7, // mov -, sacq(i+9)
+0x00000001, 0xe80009e7, // mov -, srel(i+1)
+0x0000001a, 0xe80009e7, // mov -, sacq(i+9)
+0x00000002, 0xe80009e7, // mov -, srel(i+1)
+0x0000001b, 0xe80009e7, // mov -, sacq(i+9)
+0x00000003, 0xe80009e7, // mov -, srel(i+1)
+0x0000001c, 0xe80009e7, // mov -, sacq(i+9)
+0x00000004, 0xe80009e7, // mov -, srel(i+1)
+0x0000001d, 0xe80009e7, // mov -, sacq(i+9)
+0x00000005, 0xe80009e7, // mov -, srel(i+1)
+0x0000001e, 0xe80009e7, // mov -, sacq(i+9)
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000006, 0xe80009e7, // mov -, srel(i+1)
+0x0000001f, 0xe80009e7, // mov -, sacq(i+9)
+0x00000007, 0xe80009e7, // mov -, srel(i+1)
+0x00000500, 0xf0f811a7, // brr rx_ptr, label
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x00000009, 0xe80009e7, // mov -, srel(i+9)
+0x00000011, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000a, 0xe80009e7, // mov -, srel(i+9)
+0x00000012, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000b, 0xe80009e7, // mov -, srel(i+9)
+0x00000013, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000c, 0xe80009e7, // mov -, srel(i+9)
+0x00000014, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000d, 0xe80009e7, // mov -, srel(i+9)
+0x00000015, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000e, 0xe80009e7, // mov -, srel(i+9)
+0x00000016, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x00000000, 0xf0f509e7, // bra -, ra_link_1
+0x0000000f, 0xe80009e7, // mov -, srel(i+9)
+0x00000017, 0xe80009e7, // mov -, sacq(i+1)
+0x009e7000, 0x100009e7, // nop
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x203a7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209ce039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208ecb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x203a7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819ff2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f1400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829ff609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f1449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x203e7030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209cf039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x2208fcb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x203e7031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fe2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f2400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fe609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f2449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20427030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d0039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22090cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20427031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819fc2c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f4400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x829fc609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f4449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (1<<i)
+0x20467030, 0x1000d9c2, // nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+0x209d1039, 0x1000c9e2, // nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+0x22091cb8, 0x1006c823, // fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+0x20467031, 0x1000c9e1, // nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+0x819f82c0, 0xd0064862, // fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+0x819f8400, 0xd0044823, // fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+0x00000000, 0xf0f409e7, // bra -, ra_link_0
+0x829f8609, 0xd0064822, // fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+0x819f8449, 0xd0044863, // fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+0x029e7640, 0x10060867, // fsub.ifnz r1, r3, r1
+0x8c15edf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149da1c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149da1c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffda8, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x959e7009, 0x10024249, // mov ra_32_re, r0; mov rb_32_im, r1
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149da1c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149da1c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0xfffffc90, 0xf0f80027, // brr ra_link_0, call
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x204e7006, 0x100059c2, // nop;                  fmul ra_temp, r0, ra_tw_re+TW32
+0x209d300f, 0x100049e2, // nop;                  fmul r2,      r1, rb_tw_im+TW32
+0x204e700e, 0x100049e3, // nop;                  fmul r3,      r1, ra_tw_re+TW32
+0x22093c87, 0x10024821, // fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32
+0x019e72c0, 0x10020867, // fadd r1, r1,      r3
+0x00000000, 0xf0f549e7, // bra -, ra_save_32
+0x95642ff6, 0x10024642, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x95687ff6, 0x10024687, // mov ra_vpm_hi, rb_vpm_hi; mov rb_vpm_hi, ra_vpm_hi
+0x95701ff6, 0x10024701, // mov ra_vdw_32, rb_vdw_32; mov rb_vdw_32, ra_vdw_32
+0x8c15ddf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffc00, 0xf0f80027, // brr ra_link_0, call
+0x009e7000, 0xa00009e7, // nop;        ldtmu0
+0x159e7900, 0xa0020827, // mov r0, r4; ldtmu0
+0x159e7900, 0x10020867, // mov r1, r4
+0x00000000, 0xf0f489e7, // bra -, ra_save_16
+0x009e7000, 0x100009e7, // nop
+0x95642ff6, 0x10024642, // mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+0x956c0ff6, 0x100246c0, // mov ra_vdw_16, rb_vdw_16; mov rb_vdw_16, ra_vdw_16
+0x159c5fc0, 0x10022827, // mov.setf r0, rb_inst
+0x0d9c11c0, 0xd0020827, // sub r0, r0, 1
+0x119c51c0, 0xd0020827, // shl r0, r0, 5
+0x0c9c6e00, 0x100601a7, // add.ifnz ra_sync, rx_sync_slave, r0
+0x159c4fc0, 0x10060127, // mov.ifnz ra_save_16, rx_save_slave_16
+0x159cafc0, 0x100602a7, // mov.ifnz ra_save_32, rx_save_slave_32
+0x15827d80, 0x100220e7, // mov.setf ra_addr_x, unif
+0x15827d80, 0x100210e7, // mov      rb_addr_y, unif
+0x00000958, 0xf00809e7, // brr.allz -, r:end
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100204e7, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x100214e7, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c51c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15bdf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x14767180, 0x10020867, // and r1, r0, mask
+0x0e9c11c0, 0xd0020827, // shr r0, r0, shift
+0x14767180, 0x10020827, // and r0, r0, mask
+0x119c13c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147a7180, 0x10020867, // and r1, r0, mask
+0x0e9c21c0, 0xd0020827, // shr r0, r0, shift
+0x147a7180, 0x10020827, // and r0, r0, mask
+0x119c23c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x147e7180, 0x10020867, // and r1, r0, mask
+0x0e9c41c0, 0xd0020827, // shr r0, r0, shift
+0x147e7180, 0x10020827, // and r0, r0, mask
+0x119c43c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x149da1c0, 0x10020867, // and r1, r0, mask
+0x0e9c81c0, 0xd0020827, // shr r0, r0, shift
+0x149da1c0, 0x10020827, // and r0, r0, mask
+0x119c83c0, 0xd0020867, // shl r1, r1, shift
+0x159e7040, 0x10020827, // or  r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x94981dc0, 0xd00269e2, // and.setf -, elem_num, 1; mov r2, r0
+0x959f1489, 0xd004c820, // mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+0x959ff252, 0xd0068861, // mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffa98, 0xf0f80227, // brr ra_link_1, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x0e1cddc0, 0xd00229e7, // shr.setf -, ra_points, STAGES
+0xfffffa70, 0xf00809e7, // brr.allz -, r:pass_1
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dfdc0, 0x100201e7, // add ra_points, ra_points, rb_0x100
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000001, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000002, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020327, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021327, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c41c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15ddf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffffb20, 0xf0f80227, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dddc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0xfffffb00, 0xf0f80227, // brr ra_link_1, r:pass_2
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dddc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20327016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cc017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cc01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2132709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02467c80, 0x10020827, // fsub r0,  a, b
+0x02467180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02467c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x014a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02467c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100204a7, // fadd a+1, r0, r1
+0x029d1ec0, 0x10020827, // fsub r0,  a, b
+0x029d11c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d1e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d23c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d1e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100214a7, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1cddc0, 0xd00229e7, // shr.setf -, ra_points, STAGES
+0xfffff970, 0xf00809e7, // brr.allz -, r:pass_2
+0x00000020, 0xe0020827, // mov r0, 4*8
+0x0d227c00, 0x10020227, // sub ra_link_1, ra_link_1, r0
+0x0c1dddc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0x950c3dbf, 0x100250c3, // mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000000, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c9cbe00, 0x10020e27, // add t0s, ptr, r0
+0x0c9cbe40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020467, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021467, // mov rb_tw_im+dst, r4
+0x11983dc0, 0xd0020827, // shl r0, elem_num, 3
+0x00000003, 0xe0020867, // mov r1, src
+0x119c73c0, 0xd0020867, // shl r1, r1, 7
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c2e7c00, 0x10020e27, // add t0s, ptr, r0
+0x0c2e7c40, 0x10020e27, // add t0s, ptr, r1
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020327, // mov ra_tw_re+dst, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10021327, // mov rb_tw_im+dst, r4
+0x00000000, 0xe0024492, // mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+0x00000000, 0xe0024514, // mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x159c5fc0, 0x10020827, // mov r0, rb_inst
+0x119c41c0, 0xd0020827, // shl r0, r0, m
+0x0c9a7180, 0x10020167, // add ra_load_idx, r0, elem_num
+0x00000000, 0xe00201e7, // mov ra_points, 0
+0x159c3fc0, 0x10020067, // mov ra_save_ptr, rb_addr_y
+0x8c15ddf6, 0x10024160, // add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+0x119c31c0, 0xd0020827, // shl r0, r0, 3
+0x0c9c41c0, 0xd0020867, // add r1, r0, 4
+0x0c0e7c00, 0x10020e27, // add t0s, ra_addr_x, r0
+0x0c0e7c40, 0x10020e27, // add t0s, ra_addr_x, r1
+0xfffff7b0, 0xf0f80227, // brr ra_link_1, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dddc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+0x20327016, 0x100049e0, // nop;             fmul r0, r2, ra_tw_re+step
+0x209cc017, 0x100049e1, // nop;             fmul r1, r2, rb_tw_im+step
+0x209cc01f, 0x100049e2, // nop;             fmul r2, r3, rb_tw_im+step
+0x2132709e, 0x100248a3, // fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step
+0x029e7640, 0x100208e7, // fsub r3, r3, r1
+0x02467c80, 0x10020827, // fsub r0,  a, b
+0x02467180, 0x10020867, // fsub r1, r0, a
+0x019e7280, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x02467c40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x014a7380, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10025891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x02467c80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100204a7, // fadd a+1, r0, r1
+0x029d1ec0, 0x10020827, // fsub r0,  a, b
+0x029d11c0, 0x10020867, // fsub r1, r0, a
+0x019e72c0, 0x100208a7, // fadd r2, r1, b
+0x029e7040, 0x10020867, // fsub r1, r0, r1
+0x029d1e40, 0x10020867, // fsub r1,  a, r1
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x019d23c0, 0x10020867, // fadd r1, r1, a+1
+0x019e7040, 0x100208a7, // fadd r2, r0, r1
+0x829e7412, 0x10024891, // fsub r2, r2, r0; mov a, r2
+0x029e7280, 0x10020867, // fsub r1, r1, r2
+0x029d1e80, 0x100208a7, // fsub r2,  a, r2
+0x029e7080, 0x10020827, // fsub r0, r0, r2
+0x019e7040, 0x100214a7, // fadd a+1, r0, r1
+0x95451dbf, 0x100248a3, // mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+0x14988dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f8492, 0xd002c462, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f86db, 0xd002d463, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14984dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f4492, 0xd002c422, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f46db, 0xd002d423, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14982dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f2492, 0xd002c3e2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f26db, 0xd002d3e3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x14981dc0, 0xd00229e7, // and.setf -, elem_num, (8>>i)
+0x959f1492, 0xd002c3a2, // mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+0x959f16db, 0xd002d3a3, // mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+0x0e1cddc0, 0xd00229e7, // shr.setf -, ra_points, STAGES
+0xfffff620, 0xf00809e7, // brr.allz -, r:pass_3
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c1dddc0, 0x100201e7, // add ra_points, ra_points, rb_0x80
+0x00000000, 0xf0f4c227, // bra ra_link_1, ra_sync
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0xa00009e7, // ldtmu0
+0x009e7000, 0xa00009e7, // ldtmu0
+0xfffff678, 0xf0f809e7, // brr -, r:loop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x159c3fc0, 0x100209a7, // mov interrupt, flag
+0x009e7000, 0x300009e7, // nop; nop; thrend
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_trans.hex b/host_applications/linux/apps/hello_pi/hello_fft/hex/shader_trans.hex
new file mode 100755 (executable)
index 0000000..93af75e
--- /dev/null
@@ -0,0 +1,126 @@
+0x15827d80, 0x10020e27, // mov t0s, unif
+0x009e7000, 0xa00009e7, // ldtmu0
+0x0c9cc9c0, 0xd0020e27, // add t0s, r4, 3*4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x0c827980, 0x100200a7, // add ra_src_base, r4, unif
+0x15827d80, 0x10020e27, // mov t0s, unif
+0x009e7000, 0xa00009e7, // ldtmu0
+0x0c9cc9c0, 0xd0020e27, // add t0s, r4, 3*4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x0c827980, 0x100200e7, // add ra_dst_base, r4, unif
+0x15827d80, 0x100214a7, // mov rb_Y_STRIDE_SRC, unif
+0x15827d80, 0x100214e7, // mov rb_Y_STRIDE_DST, unif
+0x15827d80, 0x10021527, // mov rb_NX,           unif
+0x15827d80, 0x10021567, // mov rb_NY,           unif
+0x00000008, 0xe0021467, // mov rb_X_STRIDE, 2*4
+0x00000010, 0xe0021427, // mov rb_0x10, 0x10
+0xc0000000, 0xe0020827, // mov r0, vdw_setup_1(0)
+0x0c9d31c0, 0x10020827, // add r0, r0, rb_Y_STRIDE_DST
+0x00000040, 0xe0020867, // mov r1, 16*4
+0x0d9e7040, 0x100201a7, // sub ra_vdw_stride, r0, r1
+0x40991037, 0x100049e0, // nop; mul24 r0, elem_num, rb_X_STRIDE
+0x159e7000, 0x10021027, // mov rb_offsets_re+i, r0
+0x0c9c41c0, 0xd0021227, // add rb_offsets_im+i, r0, 4
+0x0c9d21c0, 0x10020827, // add r0, r0, rb_Y_STRIDE_SRC
+0x159e7000, 0x10021067, // mov rb_offsets_re+i, r0
+0x0c9c41c0, 0xd0021267, // add rb_offsets_im+i, r0, 4
+0x0c9d21c0, 0x10020827, // add r0, r0, rb_Y_STRIDE_SRC
+0x159e7000, 0x100210a7, // mov rb_offsets_re+i, r0
+0x0c9c41c0, 0xd00212a7, // add rb_offsets_im+i, r0, 4
+0x0c9d21c0, 0x10020827, // add r0, r0, rb_Y_STRIDE_SRC
+0x159e7000, 0x100210e7, // mov rb_offsets_re+i, r0
+0x0c9c41c0, 0xd00212e7, // add rb_offsets_im+i, r0, 4
+0x0c9d21c0, 0x10020827, // add r0, r0, rb_Y_STRIDE_SRC
+0x159e7000, 0x10021127, // mov rb_offsets_re+i, r0
+0x0c9c41c0, 0xd0021327, // add rb_offsets_im+i, r0, 4
+0x0c9d21c0, 0x10020827, // add r0, r0, rb_Y_STRIDE_SRC
+0x159e7000, 0x10021167, // mov rb_offsets_re+i, r0
+0x0c9c41c0, 0xd0021367, // add rb_offsets_im+i, r0, 4
+0x0c9d21c0, 0x10020827, // add r0, r0, rb_Y_STRIDE_SRC
+0x159e7000, 0x100211a7, // mov rb_offsets_re+i, r0
+0x0c9c41c0, 0xd00213a7, // add rb_offsets_im+i, r0, 4
+0x0c9d21c0, 0x10020827, // add r0, r0, rb_Y_STRIDE_SRC
+0x159e7000, 0x100211e7, // mov rb_offsets_re+i, r0
+0x0c9c41c0, 0xd00213e7, // add rb_offsets_im+i, r0, 4
+0x0c9d21c0, 0x10020827, // add r0, r0, rb_Y_STRIDE_SRC
+0x00000000, 0xe0020067, // mov ra_y, 0
+0x00000000, 0xe0020027, // mov ra_x, 0
+0x40052037, 0x100049e1, // nop; mul24 r1, ra_y, rb_Y_STRIDE_SRC
+0x40011037, 0x100049e0, // nop; mul24 r0, ra_x, rb_X_STRIDE
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c0a7c00, 0x10020127, // add ra_src_cell, ra_src_base, r0
+0x40013037, 0x100049e1, // nop; mul24 r1, ra_x, rb_Y_STRIDE_DST
+0x40051037, 0x100049e0, // nop; mul24 r0, ra_y, rb_X_STRIDE
+0x0c9e7040, 0x10020827, // add r0, r0, r1
+0x0c0e7c00, 0x10020167, // add ra_dst_cell, ra_dst_base, r0
+0x00001200, 0xe0021c67, // mov vw_setup, vpm_setup(16, 1, v32(0,0))
+0x0c100dc0, 0x10020e27, // add t0s, ra_src_cell, rb_offsets_re
+0x0c108dc0, 0x10020f27, // add t1s, ra_src_cell, rb_offsets_im
+0x0c101dc0, 0x10020e27, // add t0s, ra_src_cell, rb_offsets_re+1+i
+0x0c109dc0, 0x10020f27, // add t1s, ra_src_cell, rb_offsets_im+1+i
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020c27, // mov vpm, r4
+0x009e7000, 0xb00009e7, // ldtmu1
+0x159e7900, 0x10020c27, // mov vpm, r4
+0x0c102dc0, 0x10020e27, // add t0s, ra_src_cell, rb_offsets_re+1+i
+0x0c10adc0, 0x10020f27, // add t1s, ra_src_cell, rb_offsets_im+1+i
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020c27, // mov vpm, r4
+0x009e7000, 0xb00009e7, // ldtmu1
+0x159e7900, 0x10020c27, // mov vpm, r4
+0x0c103dc0, 0x10020e27, // add t0s, ra_src_cell, rb_offsets_re+1+i
+0x0c10bdc0, 0x10020f27, // add t1s, ra_src_cell, rb_offsets_im+1+i
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020c27, // mov vpm, r4
+0x009e7000, 0xb00009e7, // ldtmu1
+0x159e7900, 0x10020c27, // mov vpm, r4
+0x0c104dc0, 0x10020e27, // add t0s, ra_src_cell, rb_offsets_re+1+i
+0x0c10cdc0, 0x10020f27, // add t1s, ra_src_cell, rb_offsets_im+1+i
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020c27, // mov vpm, r4
+0x009e7000, 0xb00009e7, // ldtmu1
+0x159e7900, 0x10020c27, // mov vpm, r4
+0x0c105dc0, 0x10020e27, // add t0s, ra_src_cell, rb_offsets_re+1+i
+0x0c10ddc0, 0x10020f27, // add t1s, ra_src_cell, rb_offsets_im+1+i
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020c27, // mov vpm, r4
+0x009e7000, 0xb00009e7, // ldtmu1
+0x159e7900, 0x10020c27, // mov vpm, r4
+0x0c106dc0, 0x10020e27, // add t0s, ra_src_cell, rb_offsets_re+1+i
+0x0c10edc0, 0x10020f27, // add t1s, ra_src_cell, rb_offsets_im+1+i
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020c27, // mov vpm, r4
+0x009e7000, 0xb00009e7, // ldtmu1
+0x159e7900, 0x10020c27, // mov vpm, r4
+0x0c107dc0, 0x10020e27, // add t0s, ra_src_cell, rb_offsets_re+1+i
+0x0c10fdc0, 0x10020f27, // add t1s, ra_src_cell, rb_offsets_im+1+i
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020c27, // mov vpm, r4
+0x009e7000, 0xb00009e7, // ldtmu1
+0x159e7900, 0x10020c27, // mov vpm, r4
+0x009e7000, 0xa00009e7, // ldtmu0
+0x159e7900, 0x10020c27, // mov vpm, r4
+0x009e7000, 0xb00009e7, // ldtmu1
+0x159e7900, 0x10020c27, // mov vpm, r4
+0x88104000, 0xe0021c67, // mov vw_setup, vdw_setup_0(16, 16, dma_h32(0,0))
+0x151a7d80, 0x10021c67, // mov vw_setup, ra_vdw_stride
+0x15167d80, 0x10021ca7, // mov vw_addr, ra_dst_cell
+0x159f2fc0, 0x100009e7, // mov -, vw_wait
+0x0c010dc0, 0x10020027, // add ra_x, ra_x, rb_0x10
+0x009e7000, 0x100009e7, // nop
+0x0d014dc0, 0x100229e7, // sub.setf -, ra_x, rb_NX
+0xfffffde0, 0xf01809e7, // brr.allnz -, r:inner
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x0c048dc0, 0xd0020067, // add ra_y, ra_y, 8
+0x009e7000, 0x100009e7, // nop
+0x0d055dc0, 0x100229e7, // sub.setf -, ra_y, rb_NY
+0xfffffda0, 0xf01809e7, // brr.allnz -, r:outer
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
+0x00000001, 0xe00209a7, // mov interrupt, 1
+0x009e7000, 0x300009e7, // nop; nop; thrend
+0x009e7000, 0x100009e7, // nop
+0x009e7000, 0x100009e7, // nop
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/mailbox.c b/host_applications/linux/apps/hello_pi/hello_fft/mailbox.c
new file mode 100755 (executable)
index 0000000..de44e81
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <assert.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+#include "mailbox.h"
+
+#define PAGE_SIZE (4*1024)
+
+void *mapmem(unsigned base, unsigned size)
+{
+   int mem_fd;
+   unsigned offset = base % PAGE_SIZE;
+   base = base - offset;
+   size = size + offset;
+   /* open /dev/mem */
+   if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
+      printf("can't open /dev/mem\nThis program should be run as root. Try prefixing command with: sudo\n");
+      exit (-1);
+   }
+   void *mem = mmap(
+      0,
+      size,
+      PROT_READ|PROT_WRITE,
+      MAP_SHARED/*|MAP_FIXED*/,
+      mem_fd,
+      base);
+#ifdef DEBUG
+   printf("base=0x%x, mem=%p\n", base, mem);
+#endif
+   if (mem == MAP_FAILED) {
+      printf("mmap error %d\n", (int)mem);
+      exit (-1);
+   }
+   close(mem_fd);
+   return (char *)mem + offset;
+}
+
+void unmapmem(void *addr, unsigned size)
+{
+   const intptr_t offset = (intptr_t)addr % PAGE_SIZE;
+   addr = (char *)addr - offset;
+   size = size + offset;
+   int s = munmap(addr, size);
+   if (s != 0) {
+      printf("munmap error %d\n", s);
+      exit (-1);
+   }
+}
+
+/*
+ * use ioctl to send mbox property message
+ */
+
+static int mbox_property(int file_desc, void *buf)
+{
+   int ret_val = ioctl(file_desc, IOCTL_MBOX_PROPERTY, buf);
+
+   if (ret_val < 0) {
+      printf("ioctl_set_msg failed:%d\n", ret_val);
+   }
+
+#ifdef DEBUG
+   unsigned *p = buf; int i; unsigned size = *(unsigned *)buf;
+   for (i=0; i<size/4; i++)
+      printf("%04x: 0x%08x\n", i*sizeof *p, p[i]);
+#endif
+   return ret_val;
+}
+
+unsigned mem_alloc(int file_desc, unsigned size, unsigned align, unsigned flags)
+{
+   int i=0;
+   unsigned p[32];
+   p[i++] = 0; // size
+   p[i++] = 0x00000000; // process request
+
+   p[i++] = 0x3000c; // (the tag id)
+   p[i++] = 12; // (size of the buffer)
+   p[i++] = 12; // (size of the data)
+   p[i++] = size; // (num bytes? or pages?)
+   p[i++] = align; // (alignment)
+   p[i++] = flags; // (MEM_FLAG_L1_NONALLOCATING)
+
+   p[i++] = 0x00000000; // end tag
+   p[0] = i*sizeof *p; // actual size
+
+   mbox_property(file_desc, p);
+   return p[5];
+}
+
+unsigned mem_free(int file_desc, unsigned handle)
+{
+   int i=0;
+   unsigned p[32];
+   p[i++] = 0; // size
+   p[i++] = 0x00000000; // process request
+
+   p[i++] = 0x3000f; // (the tag id)
+   p[i++] = 4; // (size of the buffer)
+   p[i++] = 4; // (size of the data)
+   p[i++] = handle;
+
+   p[i++] = 0x00000000; // end tag
+   p[0] = i*sizeof *p; // actual size
+
+   mbox_property(file_desc, p);
+   return p[5];
+}
+
+unsigned mem_lock(int file_desc, unsigned handle)
+{
+   int i=0;
+   unsigned p[32];
+   p[i++] = 0; // size
+   p[i++] = 0x00000000; // process request
+
+   p[i++] = 0x3000d; // (the tag id)
+   p[i++] = 4; // (size of the buffer)
+   p[i++] = 4; // (size of the data)
+   p[i++] = handle;
+
+   p[i++] = 0x00000000; // end tag
+   p[0] = i*sizeof *p; // actual size
+
+   mbox_property(file_desc, p);
+   return p[5];
+}
+
+unsigned mem_unlock(int file_desc, unsigned handle)
+{
+   int i=0;
+   unsigned p[32];
+   p[i++] = 0; // size
+   p[i++] = 0x00000000; // process request
+
+   p[i++] = 0x3000e; // (the tag id)
+   p[i++] = 4; // (size of the buffer)
+   p[i++] = 4; // (size of the data)
+   p[i++] = handle;
+
+   p[i++] = 0x00000000; // end tag
+   p[0] = i*sizeof *p; // actual size
+
+   mbox_property(file_desc, p);
+   return p[5];
+}
+
+unsigned execute_code(int file_desc, unsigned code, unsigned r0, unsigned r1, unsigned r2, unsigned r3, unsigned r4, unsigned r5)
+{
+   int i=0;
+   unsigned p[32];
+   p[i++] = 0; // size
+   p[i++] = 0x00000000; // process request
+
+   p[i++] = 0x30010; // (the tag id)
+   p[i++] = 28; // (size of the buffer)
+   p[i++] = 28; // (size of the data)
+   p[i++] = code;
+   p[i++] = r0;
+   p[i++] = r1;
+   p[i++] = r2;
+   p[i++] = r3;
+   p[i++] = r4;
+   p[i++] = r5;
+
+   p[i++] = 0x00000000; // end tag
+   p[0] = i*sizeof *p; // actual size
+
+   mbox_property(file_desc, p);
+   return p[5];
+}
+
+unsigned qpu_enable(int file_desc, unsigned enable)
+{
+   int i=0;
+   unsigned p[32];
+
+   p[i++] = 0; // size
+   p[i++] = 0x00000000; // process request
+
+   p[i++] = 0x30012; // (the tag id)
+   p[i++] = 4; // (size of the buffer)
+   p[i++] = 4; // (size of the data)
+   p[i++] = enable;
+
+   p[i++] = 0x00000000; // end tag
+   p[0] = i*sizeof *p; // actual size
+
+   mbox_property(file_desc, p);
+   return p[5];
+}
+
+unsigned execute_qpu(int file_desc, unsigned num_qpus, unsigned control, unsigned noflush, unsigned timeout) {
+   int i=0;
+   unsigned p[32];
+
+   p[i++] = 0; // size
+   p[i++] = 0x00000000; // process request
+   p[i++] = 0x30011; // (the tag id)
+   p[i++] = 16; // (size of the buffer)
+   p[i++] = 16; // (size of the data)
+   p[i++] = num_qpus;
+   p[i++] = control;
+   p[i++] = noflush;
+   p[i++] = timeout; // ms
+
+   p[i++] = 0x00000000; // end tag
+   p[0] = i*sizeof *p; // actual size
+
+   mbox_property(file_desc, p);
+   return p[5];
+}
+
+int mbox_open() {
+   int file_desc;
+
+   // open a char device file used for communicating with kernel mbox driver
+   file_desc = open(DEVICE_FILE_NAME, 0);
+   if (file_desc < 0) {
+      printf("Can't open device file: %s\n", DEVICE_FILE_NAME);
+      printf("Try creating a device file with: sudo mknod %s c %d 0\n", DEVICE_FILE_NAME, MAJOR_NUM);
+      exit(-1);
+   }
+   return file_desc;
+}
+
+void mbox_close(int file_desc) {
+  close(file_desc);
+}
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/mailbox.h b/host_applications/linux/apps/hello_pi/hello_fft/mailbox.h
new file mode 100755 (executable)
index 0000000..370d115
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <linux/ioctl.h>
+
+#define MAJOR_NUM 100
+#define IOCTL_MBOX_PROPERTY _IOWR(MAJOR_NUM, 0, char *)
+#define DEVICE_FILE_NAME "/dev/vcio"
+
+int mbox_open();
+void mbox_close(int file_desc);
+
+unsigned get_version(int file_desc);
+unsigned mem_alloc(int file_desc, unsigned size, unsigned align, unsigned flags);
+unsigned mem_free(int file_desc, unsigned handle);
+unsigned mem_lock(int file_desc, unsigned handle);
+unsigned mem_unlock(int file_desc, unsigned handle);
+void *mapmem(unsigned base, unsigned size);
+void unmapmem(void *addr, unsigned size);
+
+unsigned execute_code(int file_desc, unsigned code, unsigned r0, unsigned r1, unsigned r2, unsigned r3, unsigned r4, unsigned r5);
+unsigned execute_qpu(int file_desc, unsigned num_qpus, unsigned control, unsigned noflush, unsigned timeout);
+unsigned qpu_enable(int file_desc, unsigned enable);
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/makefile b/host_applications/linux/apps/hello_pi/hello_fft/makefile
new file mode 100755 (executable)
index 0000000..c31fece
--- /dev/null
@@ -0,0 +1,36 @@
+S = hex/shader_256.hex \
+    hex/shader_512.hex \
+    hex/shader_1k.hex \
+    hex/shader_2k.hex \
+    hex/shader_4k.hex \
+    hex/shader_8k.hex \
+    hex/shader_16k.hex \
+    hex/shader_32k.hex \
+    hex/shader_64k.hex \
+    hex/shader_128k.hex \
+    hex/shader_256k.hex \
+    hex/shader_512k.hex \
+    hex/shader_1024k.hex \
+    hex/shader_2048k.hex \
+    hex/shader_4096k.hex
+
+C = mailbox.c gpu_fft.c gpu_fft_base.c gpu_fft_twiddles.c gpu_fft_shaders.c
+
+C1D = $(C) hello_fft.c
+C2D = $(C) hello_fft_2d.c gpu_fft_trans.c
+
+H1D = gpu_fft.h mailbox.h 
+H2D = gpu_fft.h mailbox.h gpu_fft_trans.h hello_fft_2d_bitmap.h
+
+F = -lrt -lm -ldl
+
+all:   hello_fft.bin hello_fft_2d.bin
+
+hello_fft.bin: $(S) $(C1D) $(H1D)
+       gcc -o hello_fft.bin $(F) $(C1D)
+
+hello_fft_2d.bin:      $(S) hex/shader_trans.hex $(C2D) $(H2D)
+       gcc -o hello_fft_2d.bin $(F) $(C2D)
+
+clean:
+       rm -f *.bin
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft.qinc b/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft.qinc
new file mode 100755 (executable)
index 0000000..1ff96c4
--- /dev/null
@@ -0,0 +1,509 @@
+# BCM2835 "GPU_FFT" release 3.0
+#
+# Copyright (c) 2015, Andrew Holme.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the copyright holder nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+##############################################################################
+# Bit-rotated write
+
+.set PASS16_STRIDE, ((1<<STAGES)/16*8)
+.set PASS32_STRIDE, ((1<<STAGES)/32*8)
+.set PASS64_STRIDE, ((1<<STAGES)/64*8)
+
+##############################################################################
+# Load twiddle factors
+
+.macro load_tw, ptr, dst, src
+    shl r0, elem_num, 3
+    mov r1, src
+    shl r1, r1, 7
+    add r0, r0, r1
+    add r1, r0, 4
+    add t0s, ptr, r0
+    add t0s, ptr, r1
+    ldtmu0
+    mov ra_tw_re+dst, r4
+    ldtmu0
+    mov rb_tw_im+dst, r4
+.endm
+
+##############################################################################
+# VPM pointers
+
+.macro inst_vpm, in_inst, out_0, out_1, out_2, out_3
+    mov r0, vpm_setup(1, 1, v32( 0,0))
+    mov r1, vpm_setup(1, 1, v32(16,0)) - vpm_setup(1, 1, v32(0,0))
+    mov r2, vpm_setup(1, 1, v32( 0,2)) - vpm_setup(1, 1, v32(0,0))
+
+    nop; mul24 r2, r2, in_inst
+
+    add out_0, r0, r2; v8adds r0, r0, r1
+    add out_1, r0, r2; v8adds r0, r0, r1
+    add out_2, r0, r2; v8adds r0, r0, r1
+    add out_3, r0, r2
+.endm
+
+##############################################################################
+
+.macro proc, rx_ptr, label
+    brr rx_ptr, label
+    nop
+    nop
+    nop
+.endm
+
+##############################################################################
+
+.macro write_vpm_16, arg
+    mov vw_setup, arg
+    mov vpm, r0
+    mov vpm, r1
+.endm
+
+.macro write_vpm_32
+    mov vw_setup, ra_vpm_lo
+    fadd vpm, ra_32_re, r0
+    fadd vpm, rb_32_im, r1
+    mov vw_setup, ra_vpm_hi
+    fsub vpm, ra_32_re, r0
+    fsub vpm, rb_32_im, r1
+.endm
+
+.macro write_vpm_64
+    mov vw_setup, rb_vpm
+    fadd vpm, ra_64+0, rb_64+0
+    fadd vpm, ra_64+1, rb_64+1
+    mov vw_setup, rb_vpm_16
+    fadd vpm, ra_64+2, rb_64+2
+    fadd vpm, ra_64+3, rb_64+3
+    mov vw_setup, rb_vpm_32
+    fsub vpm, ra_64+0, rb_64+0
+    fsub vpm, ra_64+1, rb_64+1
+    mov vw_setup, rb_vpm_48
+    fsub vpm, ra_64+2, rb_64+2
+    fsub vpm, ra_64+3, rb_64+3
+.endm
+
+##############################################################################
+
+.macro body_ra_save_16, arg_vpm, arg_vdw
+    write_vpm_16 arg_vpm
+
+    mov -, vw_wait
+
+    .rep i, 7
+        mov -, sacq(i+9) # Master waits for slave
+        mov -, srel(i+1) # Master releases slave
+    .endr
+
+    bra -, ra_link_1
+
+    mov vw_setup, arg_vdw
+    mov vw_setup, vdw_setup_1(0) + PASS16_STRIDE-16*4
+    add ra_save_ptr, ra_save_ptr, rb_0x40; mov vw_addr, ra_save_ptr
+.endm
+
+##############################################################################
+
+.macro body_rx_save_slave_16, arg_vpm
+    write_vpm_16 arg_vpm
+
+    bra -, ra_sync
+
+    nop
+    mov vr_setup, arg_vpm
+    mov -, vpm
+.endm
+
+##############################################################################
+
+.macro body_ra_save_32
+    write_vpm_32
+
+    mov -, vw_wait
+
+    .rep i, 7
+        mov -, sacq(i+9) # Master waits for slave
+        mov -, srel(i+1) # Master releases slave
+    .endr
+
+    bra -, ra_link_1
+
+    mov vw_setup, ra_vdw_32
+    mov vw_setup, vdw_setup_1(0) + PASS32_STRIDE-16*4
+    add ra_save_ptr, ra_save_ptr, rb_0x40; mov vw_addr, ra_save_ptr
+.endm
+
+##############################################################################
+
+.macro body_rx_save_slave_32
+    write_vpm_32
+
+    bra -, ra_sync
+
+    nop
+    mov vr_setup, ra_vpm_lo
+    mov -, vpm
+.endm
+
+##############################################################################
+
+.macro body_ra_save_64, step
+    mov -, vw_wait
+
+    .rep i, 7
+        mov -, srel(i+1) # Master releases slaves
+    .endr
+
+    write_vpm_64
+
+    .rep i, 7
+        mov -, sacq(i+9) # Master waits for slaves
+    .endr
+
+    bra -, ra_link_1
+
+    mov vw_setup, vdw_setup_0(64, 16, dma_h32(0,0))
+    mov vw_setup, vdw_setup_1(PASS64_STRIDE-16*4)
+    add ra_save_ptr, ra_save_ptr, step; mov vw_addr, ra_save_ptr
+.endm
+
+##############################################################################
+
+.macro body_rx_save_slave_64
+    mov r0, rb_inst
+    shl ra_temp, r0, 5
+    nop
+    brr -, ra_temp
+    nop
+    nop
+    nop
+
+    .rep i, 8
+        brr -, r:2f
+        mov -, sacq(i) # Slave waits for master
+        nop
+        nop
+    .endr
+:2
+    write_vpm_64
+
+    brr -, ra_temp
+    nop
+    nop
+    nop
+
+    .rep i, 8
+        bra -, ra_link_1
+        mov vr_setup, rb_vpm
+        mov -, vpm
+        mov -, srel(i+8) # Slave releases master
+    .endr
+.endm
+
+##############################################################################
+
+.macro body_ra_sync
+    mov -, vw_wait
+
+    .rep i, 7
+        mov -, sacq(i+9) # Master waits for slave
+    .if i==5
+        bra -, ra_link_1
+    .endif
+        mov -, srel(i+1) # Master releases slave
+    .endr
+.endm
+
+##############################################################################
+
+.macro body_rx_sync_slave
+    .rep i, 7
+        bra -, ra_link_1
+        mov -, srel(i+9) # Slave releases master
+        mov -, sacq(i+1) # Slave waits for master
+        nop
+    .endr
+.endm
+
+##############################################################################
+
+.macro fft_twiddles_32
+    nop;                  fmul ra_temp, r0, ra_tw_re+TW32 # rr
+    nop;                  fmul r2,      r1, rb_tw_im+TW32 # ii
+    nop;                  fmul r3,      r1, ra_tw_re+TW32 # ir
+    fsub r0, ra_temp, r2; fmul r1,      r0, rb_tw_im+TW32 # ri
+    fadd r1, r1,      r3
+.endm
+
+##############################################################################
+# FFT-16 codelet
+
+.macro body_fft_16
+.rep i, 4
+    and.setf -, elem_num, (1<<i)
+    nop;                       fmul.ifnz ra_temp, ra_tw_re+TW16+i, r0
+    nop;                       fmul.ifnz r2,      rb_tw_im+TW16+i, r1
+    fsub.ifnz r0, ra_temp, r2; fmul.ifnz r3,      rb_tw_im+TW16+i, r0
+    nop;                       fmul.ifnz r1,      ra_tw_re+TW16+i, r1
+    fadd.ifnz r1, r1, r3; mov r2, r0 << (1<<i)
+    fadd.ifz  r0, r2, r0; mov r3, r0 >> (1<<i)
+.if i==3
+    bra -, ra_link_0
+.endif
+    fsub.ifnz r0, r3, r0; mov r2, r1 << (1<<i)
+    fadd.ifz  r1, r2, r1; mov r3, r1 >> (1<<i)
+    fsub.ifnz r1, r3, r1
+.endr
+.endm
+
+##############################################################################
+
+.macro bit_rev, shift, mask
+    and r1, r0, mask
+    shr r0, r0, shift
+    and r0, r0, mask
+    shl r1, r1, shift
+    or  r0, r0, r1
+.endm
+
+##############################################################################
+
+.macro swizzle
+.endm
+
+.macro interleave
+    and.setf -, elem_num, 1; mov r2, r0
+    mov.ifz  r0, r2; mov.ifnz r0, r1 >> 1
+    mov.ifnz r1, r1; mov.ifz  r1, r2 << 1
+.endm
+
+##############################################################################
+
+.macro read_rev, stride
+    add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+
+    bit_rev 1, rx_0x5555    # 16 SIMD
+    bit_rev 2, rx_0x3333
+    bit_rev 4, rx_0x0F0F
+    bit_rev 8, rx_0x00FF    # reversal creates left shift by 16-STAGES
+.if STAGES>13
+    shl r0, r0, STAGES-13
+.endif
+.if STAGES<13
+    shr r0, r0, 13-STAGES
+.endif                      # r0 = re = {idx[0:STAGES-1], 1'b0, 2'b0}
+    add r1, r0, 4           # r1 = im = {idx[0:STAGES-1], 1'b1, 2'b0}
+
+    interleave
+    swizzle
+
+    add t0s, ra_addr_x, r0
+    add t0s, ra_addr_x, r1
+.endm
+
+.macro load_rev, stride, call
+    read_rev stride
+    nop;        ldtmu0
+    mov r0, r4; ldtmu0
+    mov r1, r4
+    brr ra_link_0, call
+    interleave
+.endm
+
+##############################################################################
+
+.macro read_lin, stride
+    add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+
+    shl r0, r0, 3
+    add r1, r0, 4
+
+    add t0s, ra_addr_x, r0
+    add t0s, ra_addr_x, r1
+.endm
+
+.macro load_lin, stride, call
+    read_lin stride
+    brr ra_link_0, call
+    nop;        ldtmu0
+    mov r0, r4; ldtmu0
+    mov r1, r4
+.endm
+
+##############################################################################
+# Unpack twiddles
+
+.macro unpack_twiddles
+    mov r2, ra_tw_re+TW16+3; mov r3, rb_tw_im+TW16+3
+.rep i, 4
+    and.setf -, elem_num, (8>>i)
+    mov ra_tw_re+TW16+3-i, r2; mov.ifnz r2, r2 >> (8>>i)
+    mov rb_tw_im+TW16+3-i, r3; mov.ifnz r3, r3 >> (8>>i)
+.endr
+.endm
+
+##############################################################################
+# float-float enhanced-precision subtract (corrects rounding errors)
+
+.macro df64_sub32, a, b     # df64_sub32(float2 &a, float b)
+    fsub r0,  a, b              # float2 s = twoSub(a.x, b);
+    fsub r1, r0, a
+    fadd r2, r1, b
+    fsub r1, r0, r1
+    fsub r1,  a, r1
+    fsub r1, r1, r2
+
+    fadd r1, r1, a+1            # s.y += a.y;
+
+    fadd r2, r0, r1             # a = twoSum(s.x, s,y);
+    fsub r2, r2, r0; mov a, r2
+    fsub r1, r1, r2
+    fsub r2,  a, r2
+    fsub r0, r0, r2
+    fadd a+1, r0, r1
+.endm
+
+##############################################################################
+# Rotate twiddles using enhanced-precision trig recurrence
+
+.macro rotate, base, step
+    mov r2, ra_tw_re+base; mov r3, rb_tw_im+base
+    nop;             fmul r0, r2, ra_tw_re+step # a.cos
+    nop;             fmul r1, r2, rb_tw_im+step # b.cos
+    nop;             fmul r2, r3, rb_tw_im+step # b.sin
+    fadd r2, r0, r2; fmul r3, r3, ra_tw_re+step # a.sin
+    fsub r3, r3, r1
+    df64_sub32 ra_tw_re+base, r2
+    df64_sub32 rb_tw_im+base, r3
+.endm
+
+.macro next_twiddles_32
+    rotate TW32, TW32_STEP
+.endm
+
+.macro next_twiddles_16
+    rotate TW16+3, TW16_STEP
+    unpack_twiddles
+.endm
+
+##############################################################################
+# Alternate input/output buffers between stages
+
+.macro swap_buffers
+    mov rb_addr_y, ra_addr_x; mov ra_addr_x, rb_addr_y
+.endm
+
+##############################################################################
+# Reset counters and twiddles
+
+.macro init_stage, m
+    mov ra_tw_re+TW16+4, 0; mov rb_tw_im+TW16+4, 0
+.ifset TW32
+    mov ra_tw_re+TW32+1, 0; mov rb_tw_im+TW32+1, 0
+.endif
+    unpack_twiddles
+    mov r0, rb_inst
+    shl r0, r0, m
+    add ra_load_idx, r0, elem_num
+    mov ra_points, 0
+    mov ra_save_ptr, rb_addr_y
+.endm
+
+##############################################################################
+
+.set LOAD_STRAIGHT, 0
+.set LOAD_REVERSED, 1
+
+.macro loader_16, stride, mode
+    .if mode==LOAD_REVERSED
+        load_rev stride, r:fft_16
+    .else
+        load_lin stride, r:fft_16
+    .endif
+.endm
+
+.macro body_pass_16, mode
+    loader_16 rb_0x80, mode
+    bra -, ra_save_16
+    nop
+    mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+    mov ra_vdw_16, rb_vdw_16; mov rb_vdw_16, ra_vdw_16
+.endm
+
+.macro body_pass_32, mode
+    loader_16 rb_0xF0, mode
+    mov ra_32_re, r0; mov rb_32_im, r1
+    loader_16 rb_0x10, mode
+    fft_twiddles_32
+    bra -, ra_save_32
+    mov ra_vpm_lo, rb_vpm_lo; mov rb_vpm_lo, ra_vpm_lo
+    mov ra_vpm_hi, rb_vpm_hi; mov rb_vpm_hi, ra_vpm_hi
+    mov ra_vdw_32, rb_vdw_32; mov rb_vdw_32, ra_vdw_32
+.endm
+
+.macro body_pass_64, mode, step
+    loader_16 rb_0x10, mode
+    mov ra_32_re, r0; mov rb_32_im, r1
+    loader_16 rb_0x10, mode
+    fft_twiddles_32
+
+    fadd ra_64+0, ra_32_re, r0
+    fadd ra_64+1, rb_32_im, r1
+    fsub ra_64+2, ra_32_re, r0
+    fsub ra_64+3, rb_32_im, r1
+
+    loader_16 step, mode
+    mov ra_32_re, r0; mov rb_32_im, r1
+    loader_16 rb_0x10, mode
+    fft_twiddles_32
+
+    fsub r3, rb_32_im, r1
+    fsub r2, ra_32_re, r0
+    fadd r1, rb_32_im, r1
+    fadd r0, ra_32_re, r0
+
+    nop;                        fmul rb_32_im, r1, ra_tw_re+TW48 # ir
+    nop;                        fmul ra_32_re, r1, rb_tw_im+TW48 # ii
+    nop;                        fmul r1,       r0, rb_tw_im+TW48 # ri
+    fadd rb_64+1, r1, rb_32_im; fmul r0,       r0, ra_tw_re+TW48 # rr
+    fsub rb_64+0, r0, ra_32_re; fmul ra_32_re, r3, rb_tw_im+TW64 # ii
+    nop;                        fmul rb_32_im, r3, ra_tw_re+TW64 # ir
+    bra -, ra_save_64
+    nop;                        fmul r3,       r2, rb_tw_im+TW64 # ri
+    fadd rb_64+3, r3, rb_32_im; fmul r2,       r2, ra_tw_re+TW64 # rr
+    fsub rb_64+2, r2, ra_32_re
+.endm
+
+##############################################################################
+
+.macro exit, flag
+    mov interrupt, flag
+    nop; nop; thrend
+    nop
+    nop
+.endm
+
+##############################################################################
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_1024k.qasm b/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_1024k.qasm
new file mode 100755 (executable)
index 0000000..c3c5205
--- /dev/null
@@ -0,0 +1,319 @@
+# BCM2835 "GPU_FFT" release 3.0
+#
+# Copyright (c) 2015, Andrew Holme.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the copyright holder nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+.set STAGES, 20
+
+.include "gpu_fft_ex.qinc"
+
+##############################################################################
+# Twiddles: src
+
+.set TW32_BASE,     0   # rx_tw_shared
+.set TW16_BASE,     1
+.set TW32_P2_STEP,  2
+.set TW16_P2_STEP,  3
+.set TW32_P3_STEP,  4
+.set TW16_P3_STEP,  5
+.set TW32_P4_STEP,  6
+.set TW16_P4_STEP,  7
+
+.set TW32_P4_BASE,  0   # rx_tw_unique
+.set TW16_P4_BASE,  1
+
+##############################################################################
+# Twiddles: dst
+
+.set TW16_STEP, 0  # 1
+.set TW32_STEP, 1  # 1
+.set TW16,      2  # 5
+.set TW32,      7  # 2
+
+##############################################################################
+# Registers
+
+.set ra_link_0,         ra0
+#    rx_0x00FF00FF      rb0
+.set ra_save_ptr,       ra1
+.set rb_vdw_32,         rb1
+.set ra_temp,           ra2
+.set rb_vpm_lo,         rb2
+.set ra_addr_x,         ra3
+.set rb_addr_y,         rb3
+# spare                 ra4
+# spare                 rb4
+.set ra_load_idx,       ra5
+.set rb_inst,           rb5
+.set ra_sync,           ra6
+.set rx_sync_slave,     rb6
+.set ra_points,         ra7
+.set rb_vpm_hi,         rb7
+.set ra_link_1,         ra8
+.set rb_STAGES,         rb8
+.set ra_32_re,          ra9
+.set rb_32_im,          rb9
+.set ra_save_32,        ra10
+.set rx_save_slave_32,  rb10
+
+.set rx_tw_shared,      ra11
+.set rx_tw_unique,      rb11
+
+.set ra_tw_re,          ra12 # 9
+.set rb_tw_im,          rb12 # 9
+
+.set ra_vpm_lo,         ra26
+.set ra_vpm_hi,         ra27
+.set ra_vdw_32,         ra28
+
+.set rx_0x55555555,     ra29
+.set rx_0x33333333,     ra30
+.set rx_0x0F0F0F0F,     ra31
+.set rx_0x00FF00FF,     rb0
+.set rx_0x0000FFFF,     rb26
+
+.set rb_0x10,           rb27
+.set rb_0x40,           rb28
+.set rb_0x80,           rb29
+.set rb_0xF0,           rb30
+.set rb_0x100,          rb31
+
+##############################################################################
+# Constants
+
+mov rb_STAGES,  STAGES
+
+mov rb_0x10,    0x10
+mov rb_0x40,    0x40
+mov rb_0x80,    0x80
+mov rb_0xF0,    0xF0
+mov rb_0x100,   0x100
+
+mov rx_0x55555555, 0x55555555
+mov rx_0x33333333, 0x33333333
+mov rx_0x0F0F0F0F, 0x0F0F0F0F
+mov rx_0x00FF00FF, 0x00FF00FF
+mov rx_0x0000FFFF, 0x0000FFFF
+
+mov ra_vdw_32, vdw_setup_0(1, 16, dma_h32( 0,0))
+mov rb_vdw_32, vdw_setup_0(1, 16, dma_h32(32,0))
+
+##############################################################################
+# Twiddles: ptr
+
+mov rx_tw_shared, unif
+mov rx_tw_unique, unif
+
+##############################################################################
+# Instance
+
+mov rb_inst, unif
+inst_vpm rb_inst, ra_vpm_lo, ra_vpm_hi, rb_vpm_lo, rb_vpm_hi
+
+##############################################################################
+# Master/slave procedures
+
+proc ra_save_32, r:1f
+body_ra_save_32
+:1
+
+proc rx_save_slave_32, r:1f
+body_rx_save_slave_32
+:1
+
+proc ra_sync, r:1f
+body_ra_sync
+:1
+
+proc rx_sync_slave, r:main
+body_rx_sync_slave
+
+##############################################################################
+# Subroutines
+
+:fft_16
+    body_fft_16
+
+:pass_1
+    body_pass_32 LOAD_REVERSED
+
+:pass_2
+:pass_3
+:pass_4
+    body_pass_32 LOAD_STRAIGHT
+
+##############################################################################
+# Top level
+
+:main
+    mov.setf r0, rb_inst
+    sub r0, r0, 1
+    shl r0, r0, 5
+    add.ifnz ra_sync, rx_sync_slave, r0
+    mov.ifnz ra_save_32, rx_save_slave_32
+
+:loop
+    mov.setf ra_addr_x, unif # Ping buffer or null
+    mov      rb_addr_y, unif # Pong buffer or IRQ enable
+
+    brr.allz -, r:end
+
+##############################################################################
+# Pass 1
+
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_BASE
+    init_stage 5
+    read_rev rb_0x10
+
+        brr ra_link_1, r:pass_1
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+        shr.setf -, ra_points, rb_STAGES
+
+        brr.allz -, r:pass_1
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 2
+
+    swap_buffers
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P2_STEP
+    load_tw rx_tw_shared, TW32_STEP, TW32_P2_STEP
+    init_stage 5
+    read_lin rb_0x10
+
+        brr ra_link_1, r:pass_2
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+        mov r0, 0x7FFF
+        and.setf -, ra_points, r0
+
+        brr.allnz -, r:pass_2
+        nop
+        nop
+        add.ifnz ra_points, ra_points, rb_0x100
+
+        next_twiddles_32
+        next_twiddles_16
+
+        shr.setf -, ra_points, rb_STAGES
+
+        brr.allz -, r:pass_2
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 3
+
+    swap_buffers
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P3_STEP
+    load_tw rx_tw_shared, TW32_STEP, TW32_P3_STEP
+    init_stage 5
+    read_lin rb_0x10
+
+    .rep i, 4
+        brr ra_link_1, r:pass_3
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+    .endr
+
+        next_twiddles_32
+        next_twiddles_16
+
+        shr.setf -, ra_points, rb_STAGES
+
+        brr.allz -, r:pass_3
+        mov r0, 3*4*8
+        sub ra_link_1, ra_link_1, r0
+        add ra_points, ra_points, rb_0x100
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 4
+
+    swap_buffers
+    load_tw rx_tw_unique, TW16+3, TW16_P4_BASE
+    load_tw rx_tw_unique, TW32+0, TW32_P4_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P4_STEP
+    load_tw rx_tw_shared, TW32_STEP, TW32_P4_STEP
+    init_stage 5
+    read_lin rb_0x10
+
+        brr ra_link_1, r:pass_4
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+        next_twiddles_32
+        next_twiddles_16
+
+        shr.setf -, ra_points, rb_STAGES
+
+        brr.allz -, r:pass_4
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+
+    brr -, r:loop
+    nop
+    nop
+    nop
+
+:end
+    exit rb_addr_y
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_128k.qasm b/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_128k.qasm
new file mode 100755 (executable)
index 0000000..a1f06ed
--- /dev/null
@@ -0,0 +1,319 @@
+# BCM2835 "GPU_FFT" release 3.0
+#
+# Copyright (c) 2015, Andrew Holme.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the copyright holder nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+.set STAGES, 17
+
+.include "gpu_fft_ex.qinc"
+
+##############################################################################
+# Twiddles: src
+
+.set TW32_BASE,     0   # rx_tw_shared
+.set TW16_BASE,     1
+.set TW16_P2_STEP,  2
+.set TW16_P3_STEP,  3
+.set TW16_P4_STEP,  4
+
+.set TW16_P4_BASE,  0   # rx_tw_unique
+
+##############################################################################
+# Twiddles: dst
+
+.set TW16_STEP, 0  # 1
+.set TW32_STEP, 1  # 1
+.set TW16,      2  # 5
+.set TW32,      7  # 2
+
+##############################################################################
+# Registers
+
+.set ra_link_0,         ra0
+.set rb_vdw_16,         rb0
+.set ra_save_ptr,       ra1
+.set rb_vdw_32,         rb1
+.set ra_temp,           ra2
+.set rb_vpm_lo,         rb2
+.set ra_addr_x,         ra3
+.set rb_addr_y,         rb3
+.set ra_save_16,        ra4
+.set rx_save_slave_16,  rb4
+.set ra_load_idx,       ra5
+.set rb_inst,           rb5
+.set ra_sync,           ra6
+.set rx_sync_slave,     rb6
+.set ra_points,         ra7
+.set rb_vpm_hi,         rb7
+.set ra_link_1,         ra8
+.set rb_STAGES,         rb8
+.set ra_32_re,          ra9
+.set rb_32_im,          rb9
+.set ra_save_32,        ra10
+.set rx_save_slave_32,  rb10
+
+.set rx_tw_shared,      ra11
+.set rx_tw_unique,      rb11
+
+.set ra_tw_re,          ra12 # 9
+.set rb_tw_im,          rb12 # 9
+
+.set ra_vpm_lo,         ra25
+.set ra_vpm_hi,         ra26
+.set ra_vdw_16,         ra27
+.set ra_vdw_32,         ra28
+
+.set rx_0x55555555,     ra29
+.set rx_0x33333333,     ra30
+.set rx_0x0F0F0F0F,     ra31
+.set rx_0x00FF00FF,     rb24
+.set rx_0x0000FFFF,     rb25
+
+.set rb_0x10,           rb26
+.set rb_0x40,           rb27
+.set rb_0x80,           rb28
+.set rb_0xF0,           rb29
+.set rb_0x100,          rb30
+.set rb_0xFFF,          rb31
+
+##############################################################################
+# Constants
+
+mov rb_STAGES,  STAGES
+
+mov rb_0x10,    0x10
+mov rb_0x40,    0x40
+mov rb_0x80,    0x80
+mov rb_0xF0,    0xF0
+mov rb_0x100,   0x100
+mov rb_0xFFF,   0xFFF
+
+mov rx_0x55555555, 0x55555555
+mov rx_0x33333333, 0x33333333
+mov rx_0x0F0F0F0F, 0x0F0F0F0F
+mov rx_0x00FF00FF, 0x00FF00FF
+mov rx_0x0000FFFF, 0x0000FFFF
+
+mov ra_vdw_16, vdw_setup_0(16, 16, dma_h32( 0,0))
+mov rb_vdw_16, vdw_setup_0(16, 16, dma_h32(32,0))
+mov ra_vdw_32, vdw_setup_0(32, 16, dma_h32( 0,0))
+mov rb_vdw_32, vdw_setup_0(32, 16, dma_h32(32,0))
+
+##############################################################################
+# Twiddles: ptr
+
+mov rx_tw_shared, unif
+mov rx_tw_unique, unif
+
+##############################################################################
+# Instance
+
+mov rb_inst, unif
+inst_vpm rb_inst, ra_vpm_lo, ra_vpm_hi, rb_vpm_lo, rb_vpm_hi
+
+##############################################################################
+# Master/slave procedures
+
+proc ra_save_16, r:1f
+body_ra_save_16 ra_vpm_lo, ra_vdw_16
+:1
+
+proc rx_save_slave_16, r:1f
+body_rx_save_slave_16 ra_vpm_lo
+:1
+
+proc ra_save_32, r:1f
+body_ra_save_32
+:1
+
+proc rx_save_slave_32, r:1f
+body_rx_save_slave_32
+:1
+
+proc ra_sync, r:1f
+body_ra_sync
+:1
+
+proc rx_sync_slave, r:main
+body_rx_sync_slave
+
+##############################################################################
+# Subroutines
+
+:fft_16
+    body_fft_16
+
+:pass_1
+    body_pass_32 LOAD_REVERSED
+
+:pass_2
+:pass_3
+:pass_4
+    body_pass_16 LOAD_STRAIGHT
+
+##############################################################################
+# Top level
+
+:main
+    mov.setf r0, rb_inst
+    sub r0, r0, 1
+    shl r0, r0, 5
+    add.ifnz ra_sync, rx_sync_slave, r0
+    mov.ifnz ra_save_16, rx_save_slave_16
+    mov.ifnz ra_save_32, rx_save_slave_32
+
+:loop
+    mov.setf ra_addr_x, unif # Ping buffer or null
+    mov      rb_addr_y, unif # Pong buffer or IRQ enable
+
+    brr.allz -, r:end
+
+##############################################################################
+# Pass 1
+
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_BASE
+    init_stage 5
+    read_rev rb_0x10
+
+        brr ra_link_1, r:pass_1
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+        shr.setf -, ra_points, rb_STAGES
+
+        brr.allz -, r:pass_1
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 2
+
+    swap_buffers
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P2_STEP
+    init_stage 4
+    read_lin rb_0x80
+
+        brr ra_link_1, r:pass_2
+        nop
+        nop
+        add ra_points, ra_points, rb_0x80
+
+        and.setf -, ra_points, rb_0xFFF
+
+        brr.allnz -, r:pass_2
+        nop
+        nop
+        add.ifnz ra_points, ra_points, rb_0x80
+
+        next_twiddles_16
+
+        shr.setf -, ra_points, rb_STAGES
+
+        brr.allz -, r:pass_2
+        nop
+        nop
+        add ra_points, ra_points, rb_0x80
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 3
+
+    swap_buffers
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P3_STEP
+    init_stage 4
+    read_lin rb_0x80
+
+    .rep i, 2
+        brr ra_link_1, r:pass_3
+        nop
+        nop
+        add ra_points, ra_points, rb_0x80
+    .endr
+
+        next_twiddles_16
+
+        shr.setf -, ra_points, rb_STAGES
+
+        brr.allz -, r:pass_3
+        mov r0, 4*8
+        sub ra_link_1, ra_link_1, r0
+        add ra_points, ra_points, rb_0x80
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 4
+
+    swap_buffers
+    load_tw rx_tw_unique, TW16+3, TW16_P4_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P4_STEP
+    init_stage 4
+    read_lin rb_0x80
+
+        brr ra_link_1, r:pass_4
+        nop
+        nop
+        add ra_points, ra_points, rb_0x80
+
+        next_twiddles_16
+
+        shr.setf -, ra_points, rb_STAGES
+
+        brr.allz -, r:pass_4
+        nop
+        nop
+        add ra_points, ra_points, rb_0x80
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+
+    brr -, r:loop
+    nop
+    nop
+    nop
+
+:end
+    exit rb_addr_y
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_16k.qasm b/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_16k.qasm
new file mode 100755 (executable)
index 0000000..177890b
--- /dev/null
@@ -0,0 +1,282 @@
+# BCM2835 "GPU_FFT" release 3.0
+#
+# Copyright (c) 2015, Andrew Holme.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the copyright holder nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+.set STAGES, 14
+
+.include "gpu_fft.qinc"
+
+##############################################################################
+# Twiddles: src
+
+.set TW32_BASE,     0   # rx_tw_shared
+.set TW16_BASE,     1
+.set TW32_P2_STEP,  2
+.set TW16_P2_STEP,  3
+.set TW16_P3_STEP,  4
+
+.set TW16_P3_BASE,  0   # rx_tw_unique
+
+##############################################################################
+# Twiddles: dst
+
+.set TW16_STEP, 0  # 1
+.set TW32_STEP, 1  # 1
+.set TW16,      2  # 5
+.set TW32,      7  # 2
+
+##############################################################################
+# Registers
+
+.set ra_link_0,         ra0
+.set rb_vdw_16,         rb0
+.set ra_save_ptr,       ra1
+.set rb_vdw_32,         rb1
+.set ra_temp,           ra2
+.set rb_vpm_lo,         rb2
+.set ra_addr_x,         ra3
+.set rb_addr_y,         rb3
+.set ra_save_16,        ra4
+.set rx_save_slave_16,  rb4
+.set ra_load_idx,       ra5
+.set rb_inst,           rb5
+.set ra_sync,           ra6
+.set rx_sync_slave,     rb6
+.set ra_points,         ra7
+.set rb_vpm_hi,         rb7
+.set ra_link_1,         ra8
+#                       rb8
+.set ra_32_re,          ra9
+.set rb_32_im,          rb9
+.set ra_save_32,        ra10
+.set rx_save_slave_32,  rb10
+
+.set rx_tw_shared,      ra11
+.set rx_tw_unique,      rb11
+
+.set ra_tw_re,          ra12 # 9
+.set rb_tw_im,          rb12 # 9
+
+.set ra_vpm_lo,         ra25
+.set ra_vpm_hi,         ra26
+.set ra_vdw_16,         ra27
+.set ra_vdw_32,         ra28
+
+.set rx_0x5555,         ra29
+.set rx_0x3333,         ra30
+.set rx_0x0F0F,         ra31
+
+.set rx_0x00FF,         rb26
+.set rb_0x10,           rb27
+.set rb_0x40,           rb28
+.set rb_0x80,           rb29
+.set rb_0xF0,           rb30
+.set rb_0x100,          rb31
+
+##############################################################################
+# Constants
+
+mov rb_0x10,    0x10
+mov rb_0x40,    0x40
+mov rb_0x80,    0x80
+mov rb_0xF0,    0xF0
+mov rb_0x100,   0x100
+
+mov rx_0x5555,  0x5555
+mov rx_0x3333,  0x3333
+mov rx_0x0F0F,  0x0F0F
+mov rx_0x00FF,  0x00FF
+
+mov ra_vdw_16, vdw_setup_0(16, 16, dma_h32( 0,0))
+mov rb_vdw_16, vdw_setup_0(16, 16, dma_h32(32,0))
+mov ra_vdw_32, vdw_setup_0(32, 16, dma_h32( 0,0))
+mov rb_vdw_32, vdw_setup_0(32, 16, dma_h32(32,0))
+
+##############################################################################
+# Twiddles: ptr
+
+mov rx_tw_shared, unif
+mov rx_tw_unique, unif
+
+##############################################################################
+# Instance
+
+mov rb_inst, unif
+inst_vpm rb_inst, ra_vpm_lo, ra_vpm_hi, rb_vpm_lo, rb_vpm_hi
+
+##############################################################################
+# Master/slave procedures
+
+proc ra_save_16, r:1f
+body_ra_save_16 ra_vpm_lo, ra_vdw_16
+:1
+
+proc rx_save_slave_16, r:1f
+body_rx_save_slave_16 ra_vpm_lo
+:1
+
+proc ra_save_32, r:1f
+body_ra_save_32
+:1
+
+proc rx_save_slave_32, r:1f
+body_rx_save_slave_32
+:1
+
+proc ra_sync, r:1f
+body_ra_sync
+:1
+
+proc rx_sync_slave, r:main
+body_rx_sync_slave
+
+##############################################################################
+# Subroutines
+
+:fft_16
+    body_fft_16
+
+:pass_1
+    body_pass_32 LOAD_REVERSED
+
+:pass_2
+    body_pass_32 LOAD_STRAIGHT
+
+:pass_3
+    body_pass_16 LOAD_STRAIGHT
+
+##############################################################################
+# Top level
+
+:main
+    mov.setf r0, rb_inst
+    sub r0, r0, 1
+    shl r0, r0, 5
+    add.ifnz ra_sync, rx_sync_slave, r0
+    mov.ifnz ra_save_16, rx_save_slave_16
+    mov.ifnz ra_save_32, rx_save_slave_32
+
+:loop
+    mov.setf ra_addr_x, unif # Ping buffer or null
+    mov      rb_addr_y, unif # Pong buffer or IRQ enable
+
+    brr.allz -, r:end
+
+##############################################################################
+# Pass 1
+
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_BASE
+    init_stage 5
+    read_rev rb_0x10
+
+        brr ra_link_1, r:pass_1
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+        shr.setf -, ra_points, STAGES
+
+        brr.allz -, r:pass_1
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 2
+
+    swap_buffers
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P2_STEP
+    load_tw rx_tw_shared, TW32_STEP, TW32_P2_STEP
+    init_stage 5
+    read_lin rb_0x10
+
+    .rep i, 2
+        brr ra_link_1, r:pass_2
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+    .endr
+
+        next_twiddles_32
+        next_twiddles_16
+
+        shr.setf -, ra_points, STAGES
+
+        brr.allz -, r:pass_2
+        mov r0, 4*8
+        sub ra_link_1, ra_link_1, r0
+        add ra_points, ra_points, rb_0x100
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 3
+
+    swap_buffers
+    load_tw rx_tw_unique, TW16+3, TW16_P3_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P3_STEP
+    init_stage 4
+    read_lin rb_0x80
+
+        brr ra_link_1, r:pass_3
+        nop
+        nop
+        add ra_points, ra_points, rb_0x80
+
+        next_twiddles_16
+
+        shr.setf -, ra_points, STAGES
+
+        brr.allz -, r:pass_3
+        nop
+        nop
+        add ra_points, ra_points, rb_0x80
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+
+    brr -, r:loop
+    nop
+    nop
+    nop
+
+:end
+    exit rb_addr_y
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_1k.qasm b/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_1k.qasm
new file mode 100755 (executable)
index 0000000..31314ae
--- /dev/null
@@ -0,0 +1,231 @@
+# BCM2835 "GPU_FFT" release 3.0
+#
+# Copyright (c) 2015, Andrew Holme.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the copyright holder nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+.set STAGES, 10
+
+.include "gpu_fft.qinc"
+
+##############################################################################
+# Twiddles: src
+
+.set TW32_P1_BASE,  0   # rx_tw_shared
+.set TW16_P1_BASE,  1
+.set TW32_P2_STEP,  2
+.set TW16_P2_STEP,  3
+
+.set TW32_P2_BASE,  0   # rx_tw_unique
+.set TW16_P2_BASE,  1
+
+##############################################################################
+# Twiddles: dst
+
+.set TW16_STEP, 0  # 1
+.set TW32_STEP, 1  # 1
+.set TW16,      2  # 5
+.set TW32,      7  # 2
+
+##############################################################################
+# Registers
+
+.set ra_link_0,         ra0
+#                       rb0
+.set ra_save_ptr,       ra1
+.set rb_vdw_32,         rb1
+.set ra_temp,           ra2
+.set rb_vpm_lo,         rb2
+.set ra_addr_x,         ra3
+.set rb_addr_y,         rb3
+.set ra_save_32,        ra4
+.set rx_save_slave_32,  rb4
+.set ra_load_idx,       ra5
+.set rb_inst,           rb5
+.set ra_sync,           ra6
+.set rx_sync_slave,     rb6
+.set ra_points,         ra7
+.set rb_vpm_hi,         rb7
+.set ra_link_1,         ra8
+#                       rb8
+.set ra_32_re,          ra9
+.set rb_32_im,          rb9
+
+.set rx_tw_shared,      ra10
+.set rx_tw_unique,      rb10
+
+.set ra_tw_re,          ra11 # 9
+.set rb_tw_im,          rb11 # 9
+
+.set ra_vpm_lo,         ra27
+.set ra_vpm_hi,         ra28
+.set ra_vdw_32,         ra29
+
+.set rb_0x10,           rb27
+.set rb_0x40,           rb28
+.set rb_0xF0,           rb29
+
+.set rx_0x5555,         ra30
+.set rx_0x3333,         rb30
+.set rx_0x0F0F,         ra31
+.set rx_0x00FF,         rb31
+
+##############################################################################
+# Constants
+
+mov rb_0x10,    0x10
+mov rb_0x40,    0x40
+mov rb_0xF0,    0xF0
+
+mov rx_0x5555,  0x5555
+mov rx_0x3333,  0x3333
+mov rx_0x0F0F,  0x0F0F
+mov rx_0x00FF,  0x00FF
+
+mov ra_vdw_32, vdw_setup_0(32, 16, dma_h32( 0,0))
+mov rb_vdw_32, vdw_setup_0(32, 16, dma_h32(32,0))
+
+##############################################################################
+# Twiddles: ptr
+
+mov rx_tw_shared, unif
+mov rx_tw_unique, unif
+
+##############################################################################
+# Instance
+
+mov rb_inst, unif
+inst_vpm rb_inst, ra_vpm_lo, ra_vpm_hi, rb_vpm_lo, rb_vpm_hi
+
+##############################################################################
+# Master/slave procedures
+
+proc ra_save_32, r:1f
+body_ra_save_32
+:1
+
+proc rx_save_slave_32, r:1f
+body_rx_save_slave_32
+:1
+
+proc ra_sync, r:1f
+body_ra_sync
+:1
+
+proc rx_sync_slave, r:main
+body_rx_sync_slave
+
+##############################################################################
+# Subroutines
+
+:fft_16
+    body_fft_16
+
+:pass_1
+    body_pass_32 LOAD_REVERSED
+
+:pass_2
+    body_pass_32 LOAD_STRAIGHT
+
+##############################################################################
+# Top level
+
+:main
+    mov.setf r0, rb_inst
+    sub r0, r0, 1
+    shl r0, r0, 5
+    add.ifnz ra_sync, rx_sync_slave, r0
+    mov.ifnz ra_save_32, rx_save_slave_32
+
+:loop
+    mov.setf ra_addr_x, unif # Ping buffer or null
+    mov      rb_addr_y, unif # Pong buffer or IRQ enable
+
+    brr.allz -, r:end
+
+##############################################################################
+# Pass 1
+
+    load_tw rx_tw_shared, TW16+3, TW16_P1_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_P1_BASE
+    init_stage 5
+    read_rev rb_0x10
+
+        brr ra_link_1, r:pass_1
+        nop
+        mov r0, 0x100
+        add ra_points, ra_points, r0
+
+        shr.setf -, ra_points, STAGES
+
+        brr.allz -, r:pass_1
+        nop
+        mov r0, 0x100
+        add ra_points, ra_points, r0
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 2
+
+    swap_buffers
+    load_tw rx_tw_unique, TW16+3, TW16_P2_BASE
+    load_tw rx_tw_unique, TW32+0, TW32_P2_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P2_STEP
+    load_tw rx_tw_shared, TW32_STEP, TW32_P2_STEP
+    init_stage 5
+    read_lin rb_0x10
+
+        brr ra_link_1, r:pass_2
+        nop
+        mov r0, 0x100
+        add ra_points, ra_points, r0
+
+        next_twiddles_32
+        next_twiddles_16
+
+        shr.setf -, ra_points, STAGES
+
+        brr.allz -, r:pass_2
+        nop
+        mov r0, 0x100
+        add ra_points, ra_points, r0
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+
+    brr -, r:loop
+    nop
+    nop
+    nop
+
+:end
+    exit rb_addr_y
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_2048k.qasm b/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_2048k.qasm
new file mode 100755 (executable)
index 0000000..bc904f2
--- /dev/null
@@ -0,0 +1,336 @@
+# BCM2835 "GPU_FFT" release 3.0
+#
+# Copyright (c) 2015, Andrew Holme.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the copyright holder nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+.set STAGES, 21
+
+.include "gpu_fft_2048k.qinc"
+
+##############################################################################
+# Twiddles: src
+
+.set TW64_BASE0,    0   # rx_tw_shared
+.set TW64_BASE1,    1
+.set TW32_BASE,     2
+.set TW16_BASE,     3
+.set TW32_P2_STEP,  4
+.set TW16_P2_STEP,  5
+.set TW32_P3_STEP,  6
+.set TW16_P3_STEP,  7
+.set TW32_P4_STEP,  8
+.set TW16_P4_STEP,  9
+
+.set TW32_P4_BASE,  0   # rx_tw_unique
+.set TW16_P4_BASE,  1
+
+##############################################################################
+# Twiddles: dst
+
+.set TW16_STEP, 0  # 1
+.set TW32_STEP, 1  # 1
+.set TW16,      2  # 5
+.set TW32,      7  # 2
+.set TW48,      9  # 1
+.set TW64,      10 # 1
+
+##############################################################################
+# Registers
+
+.set ra_link_0,         ra0
+.set rb_vpm,            rb0
+.set ra_save_ptr,       ra1
+.set rb_vpm_16,         rb1
+.set ra_temp,           ra2
+.set rb_vpm_32,         rb2
+.set ra_addr_x,         ra3
+.set rb_addr_y,         rb3
+.set ra_save_32,        ra4
+.set rx_save_slave_32,  rb4
+.set ra_load_idx,       ra5
+.set rb_inst,           rb5
+.set ra_sync,           ra6
+.set rx_sync_slave,     rb6
+.set ra_points,         ra7
+.set rb_vpm_48,         rb7
+.set ra_link_1,         ra8
+.set rb_0x10,           rb8
+.set ra_32_re,          ra9
+.set rb_32_im,          rb9
+.set ra_save_64,        ra10
+.set rx_save_slave_64,  rb10
+
+.set ra_64,             ra11 # 4
+.set rb_64,             rb11 # 4
+
+.set rx_tw_shared,      ra15
+.set rx_tw_unique,      rb15
+
+.set ra_tw_re,          ra16 # 11
+.set rb_tw_im,          rb16 # 11
+
+##############################################################################
+# Dual-use registers
+
+.set rb_STAGES,         rb_64+0
+.set rb_0xF0,           rb_64+1
+.set rb_0x40,           rb_64+2
+
+.set ra_vpm_lo,         ra_64+0
+.set ra_vpm_hi,         ra_64+1
+.set rb_vpm_lo,         rb_vpm_32
+.set rb_vpm_hi,         rb_vpm_48
+.set ra_vdw_32,         ra_64+3
+.set rb_vdw_32,         rb_64+3
+
+##############################################################################
+# Constants
+
+mov rb_0x10,    0x10
+mov r5rep,      0x1D0
+
+##############################################################################
+# Twiddles: ptr
+
+mov rx_tw_shared, unif
+mov rx_tw_unique, unif
+
+##############################################################################
+# Instance
+
+mov rb_inst, unif
+inst_vpm rb_inst, rb_vpm, rb_vpm_16, rb_vpm_32, rb_vpm_48
+
+##############################################################################
+# Master/slave procedures
+
+proc ra_save_32, r:1f
+body_ra_save_32
+:1
+
+proc rx_save_slave_32, r:1f
+body_rx_save_slave_32
+:1
+
+proc ra_save_64, r:1f
+body_ra_save_64
+:1
+
+proc rx_save_slave_64, r:1f
+body_rx_save_slave_64
+:1
+
+proc ra_sync, r:1f
+body_ra_sync
+:1
+
+proc rx_sync_slave, r:main
+body_rx_sync_slave
+
+##############################################################################
+# Subroutines
+
+:fft_16
+    body_fft_16
+
+:pass_1
+    body_pass_64 LOAD_REVERSED, r5
+
+:pass_2
+:pass_3
+:pass_4
+    body_pass_32 LOAD_STRAIGHT
+
+##############################################################################
+# Top level
+
+:main
+    mov.setf r0, rb_inst
+    sub r0, r0, 1
+    shl r0, r0, 5
+    add.ifnz ra_sync, rx_sync_slave, r0
+    mov.ifnz ra_save_32, rx_save_slave_32
+    mov.ifnz ra_save_64, rx_save_slave_64
+
+:loop
+    mov.setf ra_addr_x, unif # Ping buffer or null
+    mov      rb_addr_y, unif # Pong buffer or IRQ enable
+
+    brr.allz -, r:end
+
+##############################################################################
+# Pass 1
+
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_BASE
+    load_tw rx_tw_shared, TW48, TW64_BASE0
+    load_tw rx_tw_shared, TW64, TW64_BASE1
+    init_stage 6
+    read_rev rb_0x10
+
+        brr ra_link_1, r:pass_1
+        nop
+        mov r0, 0x200
+        add ra_points, ra_points, r0
+
+        mov r1, STAGES
+        shr.setf -, ra_points, r1
+
+        brr.allz -, r:pass_1
+        nop
+        mov r0, 0x200
+        add ra_points, ra_points, r0
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Dual-use registers
+
+    mov ra_vpm_lo, rb_vpm
+    mov ra_vpm_hi, rb_vpm_16
+
+    mov ra_vdw_32, vdw_setup_0(1, 16, dma_h32( 0,0))
+    mov rb_vdw_32, vdw_setup_0(1, 16, dma_h32(32,0))
+
+    mov rb_STAGES, STAGES
+    mov rb_0xF0, 0xF0
+    mov rb_0x40, 0x40
+
+##############################################################################
+# Pass 2
+
+    swap_buffers
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P2_STEP
+    load_tw rx_tw_shared, TW32_STEP, TW32_P2_STEP
+    init_stage 5
+    read_lin rb_0x10
+
+        brr ra_link_1, r:pass_2
+        nop
+        mov r0, 0x100
+        add ra_points, ra_points, r0
+
+        mov r0, 0x7FFF
+        and.setf -, ra_points, r0
+
+        brr.allnz -, r:pass_2
+        nop
+        mov r0, 0x100
+        add.ifnz ra_points, ra_points, r0
+
+        next_twiddles_32
+        next_twiddles_16
+
+        shr.setf -, ra_points, rb_STAGES
+
+        brr.allz -, r:pass_2
+        nop
+        mov r0, 0x100
+        add ra_points, ra_points, r0
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 3
+
+    swap_buffers
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P3_STEP
+    load_tw rx_tw_shared, TW32_STEP, TW32_P3_STEP
+    init_stage 5
+    read_lin rb_0x10
+
+    .rep i, 4
+        brr ra_link_1, r:pass_3
+        nop
+        mov r0, 0x100
+        add ra_points, ra_points, r0
+    .endr
+
+        next_twiddles_32
+        next_twiddles_16
+
+        shr.setf -, ra_points, rb_STAGES
+
+        mov r0, 0x100
+        brr.allz -, r:pass_3
+        add ra_points, ra_points, r0
+        mov r0, (4-1)*4*8
+        sub ra_link_1, ra_link_1, r0
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 4
+
+    swap_buffers
+    load_tw rx_tw_unique, TW16+3, TW16_P4_BASE
+    load_tw rx_tw_unique, TW32+0, TW32_P4_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P4_STEP
+    load_tw rx_tw_shared, TW32_STEP, TW32_P4_STEP
+    init_stage 5
+    read_lin rb_0x10
+
+        brr ra_link_1, r:pass_4
+        nop
+        mov r0, 0x100
+        add ra_points, ra_points, r0
+
+        next_twiddles_32
+        next_twiddles_16
+
+        shr.setf -, ra_points, rb_STAGES
+
+        brr.allz -, r:pass_4
+        nop
+        mov r0, 0x100
+        add ra_points, ra_points, r0
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+
+    brr -, r:loop
+    nop
+    nop
+    nop
+
+:end
+    exit rb_addr_y
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_2048k.qinc b/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_2048k.qinc
new file mode 100755 (executable)
index 0000000..680f7c4
--- /dev/null
@@ -0,0 +1,91 @@
+# BCM2835 "GPU_FFT" release 3.0
+#
+# Copyright (c) 2015, Andrew Holme.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the copyright holder nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+##############################################################################
+# Macro baseline
+
+.include "gpu_fft_ex.qinc"
+
+##############################################################################
+# Redefining some macros
+
+.macro body_ra_save_64
+    mov -, vw_wait
+
+    .rep i, 7
+        mov -, srel(i+1) # Master releases slaves
+    .endr
+
+    write_vpm_64
+
+    .rep i, 7
+        mov -, sacq(i+9) # Master waits for slaves
+    .endr
+
+    mov r0, vdw_setup_0(1, 16, dma_h32(0,0))
+    mov r1, 0x40
+    add ra_save_ptr, ra_save_ptr, r1; mov r1, ra_save_ptr
+    mov r2, vdw_setup_0(1, 16, dma_h32(1,0)) - vdw_setup_0(1, 16, dma_h32(0,0))
+    mov r3, PASS64_STRIDE
+
+    .rep i, 64
+        add r0, r0, r2; mov vw_setup, r0
+        add r1, r1, r3; mov vw_addr,  r1
+    .endr
+
+    bra -, ra_link_1
+    nop
+    nop
+    nop
+.endm
+
+.macro bit_rev, shift, mask
+    mov r2, mask
+    and r1, r0, r2
+    shr r0, r0, shift
+    and r0, r0, r2
+    shl r1, r1, shift
+    or  r0, r0, r1
+.endm
+
+.macro read_rev, stride
+    add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+
+    bit_rev 1,       0x55555555  # 16 SIMD
+    bit_rev 2,       0x33333333
+    bit_rev 4,       0x0F0F0F0F
+    bit_rev 8,       0x00FF00FF
+    bit_rev rb_0x10, 0x0000FFFF
+
+    shr r0, r0, 32-STAGES-3 # r0 = re = {idx[0:STAGES-1], 1'b0, 2'b0}
+    add r1, r0, 4           # r1 = im = {idx[0:STAGES-1], 1'b1, 2'b0}
+
+    interleave
+
+    add t0s, ra_addr_x, r0
+    add t0s, ra_addr_x, r1
+.endm
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_256.qasm b/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_256.qasm
new file mode 100755 (executable)
index 0000000..c6328aa
--- /dev/null
@@ -0,0 +1,233 @@
+# BCM2835 "GPU_FFT" release 3.0
+#
+# Copyright (c) 2015, Andrew Holme.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the copyright holder nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+.set STAGES, 8
+
+.include "gpu_fft.qinc"
+
+##############################################################################
+# Twiddles: src
+
+.set TW16_P1_BASE,  0   # rx_tw_shared
+.set TW16_P2_STEP,  1
+
+.set TW16_P2_BASE,  0   # rx_tw_unique
+
+##############################################################################
+# Twiddles: dst
+
+.set TW16_STEP, 0  # 1
+.set TW16,      1  # 5
+
+##############################################################################
+# Registers
+
+.set ra_link_1,         ra0
+#                       rb0
+.set ra_save_ptr,       ra1
+#                       rb1
+.set ra_temp,           ra2
+#                       rb2
+.set ra_addr_x,         ra3
+.set rb_addr_y,         rb3
+.set ra_save_16,        ra4
+.set rx_save_slave_16,  rb4
+.set ra_load_idx,       ra5
+.set rb_inst,           rb5
+.set ra_sync,           ra6
+.set rx_sync_slave,     rb6
+.set ra_points,         ra7
+#                       rb7
+
+.set rx_tw_shared,      ra8
+.set rx_tw_unique,      rb8
+
+.set ra_tw_re,          ra9 # 6
+.set rb_tw_im,          rb9 # 6
+
+.set ra_vpm,            ra27
+.set rb_vpm,            rb27
+.set ra_vdw,            ra28
+.set rb_vdw,            rb28
+
+.set rx_0x5555,         ra29
+.set rx_0x3333,         ra30
+.set rx_0x0F0F,         ra31
+
+.set rb_0x40,           rb30
+.set rb_0x80,           rb31
+
+##############################################################################
+# Register alias
+
+.set ra_link_0, ra_save_16
+
+##############################################################################
+# Constants
+
+mov rb_0x40,    0x40
+mov rb_0x80,    0x80
+
+mov rx_0x5555,  0x5555
+mov rx_0x3333,  0x3333
+mov rx_0x0F0F,  0x0F0F
+
+mov ra_vdw, vdw_setup_0(16, 16, dma_h32( 0,0))
+mov rb_vdw, vdw_setup_0(16, 16, dma_h32(16,0))
+
+##############################################################################
+# Twiddles: ptr
+
+mov rx_tw_shared, unif
+mov rx_tw_unique, unif
+
+##############################################################################
+# Instance
+
+mov rb_inst, unif
+inst_vpm rb_inst, ra_vpm, rb_vpm, -, -
+
+##############################################################################
+# Master/slave procedures
+
+proc ra_save_16, r:1f
+body_ra_save_16 ra_vpm, ra_vdw
+:1
+
+proc rx_save_slave_16, r:1f
+body_rx_save_slave_16 ra_vpm
+:1
+
+proc ra_sync, r:1f
+body_ra_sync
+:1
+
+proc rx_sync_slave, r:main
+body_rx_sync_slave
+
+##############################################################################
+# Redefining this macro
+
+.macro read_rev, stride
+    add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+
+    bit_rev 1, rx_0x5555    # 16 SIMD
+    bit_rev 2, rx_0x3333
+    bit_rev 4, rx_0x0F0F
+
+    shl r0, r0, 3           # {idx[0:7], 1'b0, 2'b0}
+    add r1, r0, 4           # {idx[0:7], 1'b1, 2'b0}
+
+    add t0s, ra_addr_x, r0
+    add t0s, ra_addr_x, r1
+.endm
+
+##############################################################################
+# Subroutines
+
+:fft_16
+    body_fft_16
+
+:pass_1
+:pass_2
+    brr -, r:fft_16
+    nop;        ldtmu0
+    mov r0, r4; ldtmu0
+    mov r1, r4
+
+##############################################################################
+# Top level
+
+:main
+    mov.setf r0, rb_inst
+    sub r0, r0, 1
+    shl r0, r0, 5
+    add.ifnz ra_sync, rx_sync_slave, r0
+    mov.ifnz ra_save_16, rx_save_slave_16
+
+:loop
+    mov.setf ra_addr_x, unif # Ping buffer or null
+    mov      rb_addr_y, unif # Pong buffer or IRQ enable
+
+    brr.allz -, r:end
+
+##############################################################################
+# Pass 1
+
+    load_tw rx_tw_shared, TW16+3, TW16_P1_BASE
+    init_stage 4
+    read_rev rb_0x80
+    read_rev rb_0x80
+
+.rep i, 2
+    brr ra_link_1, r:pass_1
+    nop
+    mov ra_vpm, rb_vpm; mov rb_vpm, ra_vpm
+    mov ra_vdw, rb_vdw; mov rb_vdw, ra_vdw
+.endr
+
+    bra ra_link_1, ra_sync
+    nop
+    nop
+    nop
+
+##############################################################################
+# Pass 2
+
+    swap_buffers
+    load_tw rx_tw_unique, TW16+3, TW16_P2_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P2_STEP
+    init_stage 4
+    read_lin rb_0x80
+    read_lin rb_0x80
+
+    brr ra_link_1, r:pass_2
+    nop
+    mov ra_vpm, rb_vpm; mov rb_vpm, ra_vpm
+    mov ra_vdw, rb_vdw; mov rb_vdw, ra_vdw
+
+    next_twiddles_16
+
+    brr ra_link_1, r:pass_2
+    nop
+    mov ra_vpm, rb_vpm; mov rb_vpm, ra_vpm
+    mov ra_vdw, rb_vdw; mov rb_vdw, ra_vdw
+
+    bra ra_link_1, ra_sync
+    nop
+    nop
+    nop
+
+##############################################################################
+
+    brr -, r:loop
+    nop
+    nop
+    nop
+
+:end
+    exit rb_addr_y
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_256k.qasm b/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_256k.qasm
new file mode 100755 (executable)
index 0000000..759eb69
--- /dev/null
@@ -0,0 +1,326 @@
+# BCM2835 "GPU_FFT" release 3.0
+#
+# Copyright (c) 2015, Andrew Holme.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the copyright holder nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+.set STAGES, 18
+
+.include "gpu_fft_ex.qinc"
+
+##############################################################################
+# Twiddles: src
+
+.set TW32_BASE,     0   # rx_tw_shared
+.set TW16_BASE,     1
+.set TW16_P2_STEP,  2
+.set TW16_P3_STEP,  3
+.set TW32_P4_STEP,  4
+.set TW16_P4_STEP,  5
+
+.set TW32_P4_BASE,  0   # rx_tw_unique
+.set TW16_P4_BASE,  1
+
+##############################################################################
+# Twiddles: dst
+
+.set TW16_STEP, 0  # 1
+.set TW32_STEP, 1  # 1
+.set TW16,      2  # 5
+.set TW32,      7  # 2
+
+##############################################################################
+# Registers
+
+.set ra_link_0,         ra0
+.set rb_vdw_16,         rb0
+.set ra_save_ptr,       ra1
+.set rb_vdw_32,         rb1
+.set ra_temp,           ra2
+.set rb_vpm_lo,         rb2
+.set ra_addr_x,         ra3
+.set rb_addr_y,         rb3
+.set ra_save_16,        ra4
+.set rx_save_slave_16,  rb4
+.set ra_load_idx,       ra5
+.set rb_inst,           rb5
+.set ra_sync,           ra6
+.set rx_sync_slave,     rb6
+.set ra_points,         ra7
+.set rb_vpm_hi,         rb7
+.set ra_link_1,         ra8
+.set rb_STAGES,         rb8
+.set ra_32_re,          ra9
+.set rb_32_im,          rb9
+.set ra_save_32,        ra10
+.set rx_save_slave_32,  rb10
+
+.set rx_tw_shared,      ra11
+.set rx_tw_unique,      rb11
+
+.set ra_tw_re,          ra12 # 9
+.set rb_tw_im,          rb12 # 9
+
+.set ra_vpm_lo,         ra25
+.set ra_vpm_hi,         ra26
+.set ra_vdw_16,         ra27
+.set ra_vdw_32,         ra28
+
+.set rx_0x55555555,     ra29
+.set rx_0x33333333,     ra30
+.set rx_0x0F0F0F0F,     ra31
+.set rx_0x00FF00FF,     rb24
+.set rx_0x0000FFFF,     rb25
+
+.set rb_0x10,           rb26
+.set rb_0x40,           rb27
+.set rb_0x80,           rb28
+.set rb_0xF0,           rb29
+.set rb_0x100,          rb30
+.set rb_0x1FFF,         rb31
+
+##############################################################################
+# Constants
+
+mov rb_STAGES,  STAGES
+
+mov rb_0x10,    0x10
+mov rb_0x40,    0x40
+mov rb_0x80,    0x80
+mov rb_0xF0,    0xF0
+mov rb_0x100,   0x100
+mov rb_0x1FFF,  0x1FFF
+
+mov rx_0x55555555, 0x55555555
+mov rx_0x33333333, 0x33333333
+mov rx_0x0F0F0F0F, 0x0F0F0F0F
+mov rx_0x00FF00FF, 0x00FF00FF
+mov rx_0x0000FFFF, 0x0000FFFF
+
+mov ra_vdw_16, vdw_setup_0( 1, 16, dma_h32( 0,0))
+mov rb_vdw_16, vdw_setup_0( 1, 16, dma_h32(32,0))
+mov ra_vdw_32, vdw_setup_0(32, 16, dma_h32( 0,0))
+mov rb_vdw_32, vdw_setup_0(32, 16, dma_h32(32,0))
+
+##############################################################################
+# Twiddles: ptr
+
+mov rx_tw_shared, unif
+mov rx_tw_unique, unif
+
+##############################################################################
+# Instance
+
+mov rb_inst, unif
+inst_vpm rb_inst, ra_vpm_lo, ra_vpm_hi, rb_vpm_lo, rb_vpm_hi
+
+##############################################################################
+# Master/slave procedures
+
+proc ra_save_16, r:1f
+body_ra_save_16 ra_vpm_lo, ra_vdw_16
+:1
+
+proc rx_save_slave_16, r:1f
+body_rx_save_slave_16 ra_vpm_lo
+:1
+
+proc ra_save_32, r:1f
+body_ra_save_32
+:1
+
+proc rx_save_slave_32, r:1f
+body_rx_save_slave_32
+:1
+
+proc ra_sync, r:1f
+body_ra_sync
+:1
+
+proc rx_sync_slave, r:main
+body_rx_sync_slave
+
+##############################################################################
+# Subroutines
+
+:fft_16
+    body_fft_16
+
+:pass_1
+    body_pass_32 LOAD_REVERSED
+
+:pass_2
+:pass_3
+    body_pass_16 LOAD_STRAIGHT
+
+:pass_4
+    body_pass_32 LOAD_STRAIGHT
+
+##############################################################################
+# Top level
+
+:main
+    mov.setf r0, rb_inst
+    sub r0, r0, 1
+    shl r0, r0, 5
+    add.ifnz ra_sync, rx_sync_slave, r0
+    mov.ifnz ra_save_16, rx_save_slave_16
+    mov.ifnz ra_save_32, rx_save_slave_32
+
+:loop
+    mov.setf ra_addr_x, unif # Ping buffer or null
+    mov      rb_addr_y, unif # Pong buffer or IRQ enable
+
+    brr.allz -, r:end
+
+##############################################################################
+# Pass 1
+
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_BASE
+    init_stage 5
+    read_rev rb_0x10
+
+        brr ra_link_1, r:pass_1
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+        shr.setf -, ra_points, rb_STAGES
+
+        brr.allz -, r:pass_1
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 2
+
+    swap_buffers
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P2_STEP
+    init_stage 4
+    read_lin rb_0x80
+
+        brr ra_link_1, r:pass_2
+        nop
+        nop
+        add ra_points, ra_points, rb_0x80
+
+        and.setf -, ra_points, rb_0x1FFF
+
+        brr.allnz -, r:pass_2
+        nop
+        nop
+        add.ifnz ra_points, ra_points, rb_0x80
+
+        next_twiddles_16
+
+        shr.setf -, ra_points, rb_STAGES
+
+        brr.allz -, r:pass_2
+        nop
+        nop
+        add ra_points, ra_points, rb_0x80
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 3
+
+    swap_buffers
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P3_STEP
+    init_stage 4
+    read_lin rb_0x80
+
+    .rep i, 4
+        brr ra_link_1, r:pass_3
+        nop
+        nop
+        add ra_points, ra_points, rb_0x80
+    .endr
+
+        next_twiddles_16
+
+        shr.setf -, ra_points, rb_STAGES
+
+        brr.allz -, r:pass_3
+        mov r0, 3*4*8
+        sub ra_link_1, ra_link_1, r0
+        add ra_points, ra_points, rb_0x80
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 4
+
+    swap_buffers
+    load_tw rx_tw_unique, TW16+3, TW16_P4_BASE
+    load_tw rx_tw_unique, TW32+0, TW32_P4_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P4_STEP
+    load_tw rx_tw_shared, TW32_STEP, TW32_P4_STEP
+    init_stage 5
+    read_lin rb_0x10
+
+        brr ra_link_1, r:pass_4
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+        next_twiddles_32
+        next_twiddles_16
+
+        shr.setf -, ra_points, rb_STAGES
+
+        brr.allz -, r:pass_4
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+
+    brr -, r:loop
+    nop
+    nop
+    nop
+
+:end
+    exit rb_addr_y
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_2k.qasm b/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_2k.qasm
new file mode 100755 (executable)
index 0000000..304b144
--- /dev/null
@@ -0,0 +1,265 @@
+# BCM2835 "GPU_FFT" release 3.0
+#
+# Copyright (c) 2015, Andrew Holme.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the copyright holder nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+.set STAGES, 11
+
+.include "gpu_fft.qinc"
+
+##############################################################################
+# Twiddles: src
+
+.set TW64_P1_BASE0, 0   # rx_tw_shared
+.set TW64_P1_BASE1, 1
+.set TW32_P1_BASE,  2
+.set TW16_P1_BASE,  3
+.set TW32_P2_STEP,  4
+.set TW16_P2_STEP,  5
+
+.set TW32_P2_BASE,  0   # rx_tw_unique
+.set TW16_P2_BASE,  1
+
+##############################################################################
+# Twiddles: dst
+
+.set TW16_STEP, 0  # 1
+.set TW32_STEP, 1  # 1
+.set TW16,      2  # 5
+.set TW32,      7  # 2
+.set TW48,      9  # 1
+.set TW64,      10 # 1
+
+##############################################################################
+# Registers
+
+.set ra_link_0,         ra0
+.set rb_vpm,            rb0
+.set ra_save_ptr,       ra1
+.set rb_vpm_16,         rb1
+.set ra_temp,           ra2
+.set rb_vpm_32,         rb2
+.set ra_addr_x,         ra3
+.set rb_addr_y,         rb3
+.set ra_save_32,        ra4
+.set rx_save_slave_32,  rb4
+.set ra_load_idx,       ra5
+.set rb_inst,           rb5
+.set ra_sync,           ra6
+.set rx_sync_slave,     rb6
+.set ra_points,         ra7
+.set rb_vpm_48,         rb7
+.set ra_link_1,         ra8
+#                       rb8
+.set ra_32_re,          ra9
+.set rb_32_im,          rb9
+.set ra_save_64,        ra10
+.set rx_save_slave_64,  rb10
+
+.set ra_64,             ra11 # 4
+.set rb_64,             rb11 # 4
+
+.set rx_tw_shared,      ra15
+.set rx_tw_unique,      rb15
+
+.set ra_tw_re,          ra16 # 11
+.set rb_tw_im,          rb16 # 11
+
+.set rx_0x5555,         ra28
+.set rx_0x3333,         ra29
+.set rx_0x0F0F,         ra30
+.set rx_0x00FF,         ra31
+
+.set rb_0x10,           rb28
+.set rb_0x40,           rb29
+.set rb_0xF0,           rb30
+.set rb_0x1D0,          rb31
+
+##############################################################################
+# Dual-use registers
+
+.set ra_vpm_lo,         ra_64+0
+.set ra_vpm_hi,         ra_64+1
+.set rb_vpm_lo,         rb_vpm_32
+.set rb_vpm_hi,         rb_vpm_48
+.set ra_vdw_32,         ra_64+2
+.set rb_vdw_32,         rb_64+2
+
+##############################################################################
+# Constants
+
+mov rb_0x10,    0x10
+mov rb_0x40,    0x40
+mov rb_0xF0,    0xF0
+mov rb_0x1D0,   0x1D0
+
+mov rx_0x5555,  0x5555
+mov rx_0x3333,  0x3333
+mov rx_0x0F0F,  0x0F0F
+mov rx_0x00FF,  0x00FF
+
+##############################################################################
+# Twiddles: ptr
+
+mov rx_tw_shared, unif
+mov rx_tw_unique, unif
+
+##############################################################################
+# Instance
+
+mov rb_inst, unif
+inst_vpm rb_inst, rb_vpm, rb_vpm_16, rb_vpm_32, rb_vpm_48
+
+##############################################################################
+# Master/slave procedures
+
+proc ra_save_32, r:1f
+body_ra_save_32
+:1
+
+proc rx_save_slave_32, r:1f
+body_rx_save_slave_32
+:1
+
+proc ra_save_64, r:1f
+body_ra_save_64 rb_0x40
+:1
+
+proc rx_save_slave_64, r:1f
+body_rx_save_slave_64
+:1
+
+proc ra_sync, r:1f
+body_ra_sync
+:1
+
+proc rx_sync_slave, r:main
+body_rx_sync_slave
+
+##############################################################################
+# Subroutines
+
+:fft_16
+    body_fft_16
+
+:pass_1
+    body_pass_64 LOAD_REVERSED, rb_0x1D0
+
+:pass_2
+    body_pass_32 LOAD_STRAIGHT
+
+##############################################################################
+# Top level
+
+:main
+    mov.setf r0, rb_inst
+    sub r0, r0, 1
+    shl r0, r0, 5
+    add.ifnz ra_sync, rx_sync_slave, r0
+    mov.ifnz ra_save_32, rx_save_slave_32
+    mov.ifnz ra_save_64, rx_save_slave_64
+
+:loop
+    mov.setf ra_addr_x, unif # Ping buffer or null
+    mov      rb_addr_y, unif # Pong buffer or IRQ enable
+
+    brr.allz -, r:end
+
+##############################################################################
+# Pass 1
+
+    load_tw rx_tw_shared, TW16+3, TW16_P1_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_P1_BASE
+    load_tw rx_tw_shared, TW48,   TW64_P1_BASE0
+    load_tw rx_tw_shared, TW64,   TW64_P1_BASE1
+    init_stage 6
+    read_rev rb_0x10
+
+        brr ra_link_1, r:pass_1
+        nop
+        mov r0, 0x200
+        add ra_points, ra_points, r0
+
+        shr.setf -, ra_points, STAGES
+
+        brr.allz -, r:pass_1
+        nop
+        mov r0, 0x200
+        add ra_points, ra_points, r0
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Dual-use registers
+
+    mov ra_vpm_lo, rb_vpm
+    mov ra_vpm_hi, rb_vpm_16
+
+    mov ra_vdw_32, vdw_setup_0(32, 16, dma_h32( 0,0))
+    mov rb_vdw_32, vdw_setup_0(32, 16, dma_h32(32,0))
+
+##############################################################################
+# Pass 2
+
+    swap_buffers
+    load_tw rx_tw_unique, TW16+3, TW16_P2_BASE
+    load_tw rx_tw_unique, TW32+0, TW32_P2_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P2_STEP
+    load_tw rx_tw_shared, TW32_STEP, TW32_P2_STEP
+    init_stage 5
+    read_lin rb_0x10
+
+        brr ra_link_1, r:pass_2
+        nop
+        mov r0, 0x100
+        add ra_points, ra_points, r0
+
+        next_twiddles_32
+        next_twiddles_16
+
+        shr.setf -, ra_points, STAGES
+
+        brr.allz -, r:pass_2
+        nop
+        mov r0, 0x100
+        add ra_points, ra_points, r0
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+
+    brr -, r:loop
+    nop
+    nop
+    nop
+
+:end
+    exit rb_addr_y
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_32k.qasm b/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_32k.qasm
new file mode 100755 (executable)
index 0000000..d0baf9c
--- /dev/null
@@ -0,0 +1,271 @@
+# BCM2835 "GPU_FFT" release 3.0
+#
+# Copyright (c) 2015, Andrew Holme.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the copyright holder nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+.set STAGES, 15
+
+.include "gpu_fft.qinc"
+
+##############################################################################
+# Twiddles: src
+
+.set TW32_BASE,     0   # rx_tw_shared
+.set TW16_BASE,     1
+.set TW32_P2_STEP,  2
+.set TW16_P2_STEP,  3
+.set TW32_P3_STEP,  4
+.set TW16_P3_STEP,  5
+
+.set TW32_P3_BASE,  0   # rx_tw_unique
+.set TW16_P3_BASE,  1
+
+##############################################################################
+# Twiddles: dst
+
+.set TW16_STEP, 0  # 1
+.set TW32_STEP, 1  # 1
+.set TW16,      2  # 5
+.set TW32,      7  # 2
+
+##############################################################################
+# Registers
+
+.set ra_link_0,         ra0
+#                       rb0
+.set ra_save_ptr,       ra1
+.set rb_vdw_32,         rb1
+.set ra_temp,           ra2
+.set rb_vpm_lo,         rb2
+.set ra_addr_x,         ra3
+.set rb_addr_y,         rb3
+.set ra_save_32,        ra4
+.set rx_save_slave_32,  rb4
+.set ra_load_idx,       ra5
+.set rb_inst,           rb5
+.set ra_sync,           ra6
+.set rx_sync_slave,     rb6
+.set ra_points,         ra7
+.set rb_vpm_hi,         rb7
+.set ra_link_1,         ra8
+#                       rb8
+.set ra_32_re,          ra9
+.set rb_32_im,          rb9
+
+.set rx_tw_shared,      ra10
+.set rx_tw_unique,      rb10
+
+.set ra_tw_re,          ra11 # 9
+.set rb_tw_im,          rb11 # 9
+
+.set ra_vpm_lo,         ra26
+.set ra_vpm_hi,         ra27
+.set ra_vdw_32,         ra28
+
+.set rx_0x5555,         ra29
+.set rx_0x3333,         ra30
+.set rx_0x0F0F,         ra31
+
+.set rx_0x00FF,         rb26
+.set rb_0x10,           rb27
+.set rb_0x40,           rb28
+.set rb_0x80,           rb29
+.set rb_0xF0,           rb30
+.set rb_0x100,          rb31
+
+##############################################################################
+# Constants
+
+mov rb_0x10,    0x10
+mov rb_0x40,    0x40
+mov rb_0x80,    0x80
+mov rb_0xF0,    0xF0
+mov rb_0x100,   0x100
+
+mov rx_0x5555,  0x5555
+mov rx_0x3333,  0x3333
+mov rx_0x0F0F,  0x0F0F
+mov rx_0x00FF,  0x00FF
+
+mov ra_vdw_32, vdw_setup_0(32, 16, dma_h32( 0,0))
+mov rb_vdw_32, vdw_setup_0(32, 16, dma_h32(32,0))
+
+##############################################################################
+# Twiddles: ptr
+
+mov rx_tw_shared, unif
+mov rx_tw_unique, unif
+
+##############################################################################
+# Instance
+
+mov rb_inst, unif
+inst_vpm rb_inst, ra_vpm_lo, ra_vpm_hi, rb_vpm_lo, rb_vpm_hi
+
+##############################################################################
+# Master/slave procedures
+
+proc ra_save_32, r:1f
+body_ra_save_32
+:1
+
+proc rx_save_slave_32, r:1f
+body_rx_save_slave_32
+:1
+
+proc ra_sync, r:1f
+body_ra_sync
+:1
+
+proc rx_sync_slave, r:main
+body_rx_sync_slave
+
+##############################################################################
+# Subroutines
+
+:fft_16
+    body_fft_16
+
+:pass_1
+    body_pass_32 LOAD_REVERSED
+
+:pass_2
+:pass_3
+    body_pass_32 LOAD_STRAIGHT
+
+##############################################################################
+# Top level
+
+:main
+    mov.setf r0, rb_inst
+    sub r0, r0, 1
+    shl r0, r0, 5
+    add.ifnz ra_sync, rx_sync_slave, r0
+    mov.ifnz ra_save_32, rx_save_slave_32
+
+:loop
+    mov.setf ra_addr_x, unif # Ping buffer or null
+    mov      rb_addr_y, unif # Pong buffer or IRQ enable
+
+    brr.allz -, r:end
+
+##############################################################################
+# Pass 1
+
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_BASE
+    init_stage 5
+    read_rev rb_0x10
+
+        brr ra_link_1, r:pass_1
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+        shr.setf -, ra_points, STAGES
+
+        brr.allz -, r:pass_1
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 2
+
+    swap_buffers
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P2_STEP
+    load_tw rx_tw_shared, TW32_STEP, TW32_P2_STEP
+    init_stage 5
+    read_lin rb_0x10
+
+    .rep i, 4
+        brr ra_link_1, r:pass_2
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+    .endr
+
+        next_twiddles_32
+        next_twiddles_16
+
+        shr.setf -, ra_points, STAGES
+
+        brr.allz -, r:pass_2
+        mov r0, 3*4*8
+        sub ra_link_1, ra_link_1, r0
+        add ra_points, ra_points, rb_0x100
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 3
+
+    swap_buffers
+    load_tw rx_tw_unique, TW16+3, TW16_P3_BASE
+    load_tw rx_tw_unique, TW32+0, TW32_P3_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P3_STEP
+    load_tw rx_tw_shared, TW32_STEP, TW32_P3_STEP
+    init_stage 5
+    read_lin rb_0x10
+
+        brr ra_link_1, r:pass_3
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+        next_twiddles_32
+        next_twiddles_16
+
+        shr.setf -, ra_points, STAGES
+
+        brr.allz -, r:pass_3
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+
+    brr -, r:loop
+    nop
+    nop
+    nop
+
+:end
+    exit rb_addr_y
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_4096k.qasm b/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_4096k.qasm
new file mode 100755 (executable)
index 0000000..831f5d0
--- /dev/null
@@ -0,0 +1,356 @@
+# BCM2835 "GPU_FFT" release 3.0
+#
+# Copyright (c) 2015, Andrew Holme.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the copyright holder nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+.set STAGES, 22
+
+.include "gpu_fft_2048k.qinc"
+
+##############################################################################
+# Twiddles: src
+
+.set TW64_BASE0,    0   # rx_tw_shared
+.set TW64_BASE1,    1
+.set TW32_BASE,     2
+.set TW16_BASE,     3
+
+.set TW48_P2_STEP,  4
+.set TW64_P2_STEP,  5
+
+.set TW32_P2_STEP,  6
+.set TW16_P2_STEP,  7
+.set TW32_P3_STEP,  8
+.set TW16_P3_STEP,  9
+.set TW32_P4_STEP, 10
+.set TW16_P4_STEP, 11
+
+.set TW32_P4_BASE,  0   # rx_tw_unique
+.set TW16_P4_BASE,  1
+
+##############################################################################
+# Twiddles: dst
+
+.set TW16_STEP, 0  # 1
+.set TW32_STEP, 1  # 1
+.set TW16,      2  # 5
+.set TW32,      7  # 2
+.set TW48,      9  # 2
+.set TW64,      11 # 2
+.set TW48_STEP, 13 # 1
+.set TW64_STEP, 14 # 1
+
+##############################################################################
+# Registers
+
+.set ra_link_0,         ra0
+.set rb_vpm,            rb0
+.set ra_save_ptr,       ra1
+.set rb_vpm_16,         rb1
+.set ra_temp,           ra2
+.set rb_vpm_32,         rb2
+.set ra_addr_x,         ra3
+.set rb_addr_y,         rb3
+.set ra_save_32,        ra4
+.set rx_save_slave_32,  rb4
+.set ra_load_idx,       ra5
+.set rb_inst,           rb5
+.set ra_sync,           ra6
+.set rx_sync_slave,     rb6
+.set ra_points,         ra7
+.set rb_vpm_48,         rb7
+.set ra_link_1,         ra8
+.set rb_0x10,           rb8
+.set ra_32_re,          ra9
+.set rb_32_im,          rb9
+.set ra_save_64,        ra10
+.set rx_save_slave_64,  rb10
+
+.set ra_64,             ra11 # 4
+.set rb_64,             rb11 # 4
+
+.set rx_tw_shared,      ra15
+.set rx_tw_unique,      rb15
+
+.set ra_tw_re,          ra16 # 15
+.set rb_tw_im,          rb16 # 15
+
+##############################################################################
+# Dual-use registers
+
+.set rb_STAGES,         rb_64+0
+.set rb_0xF0,           rb_64+1
+.set rb_0x40,           rb_64+2
+
+.set ra_vpm_lo,         ra_64+0
+.set ra_vpm_hi,         ra_64+1
+.set rb_vpm_lo,         rb_vpm_32
+.set rb_vpm_hi,         rb_vpm_48
+.set ra_vdw_32,         ra_64+3
+.set rb_vdw_32,         rb_64+3
+
+##############################################################################
+# Constants
+
+mov rb_0x10,    0x10
+mov r5rep,      0x1D0
+
+##############################################################################
+# Twiddles: ptr
+
+mov rx_tw_shared, unif
+mov rx_tw_unique, unif
+
+##############################################################################
+# Instance
+
+mov rb_inst, unif
+inst_vpm rb_inst, rb_vpm, rb_vpm_16, rb_vpm_32, rb_vpm_48
+
+##############################################################################
+# Master/slave procedures
+
+proc ra_save_32, r:1f
+body_ra_save_32
+:1
+
+proc rx_save_slave_32, r:1f
+body_rx_save_slave_32
+:1
+
+proc ra_save_64, r:1f
+body_ra_save_64
+:1
+
+proc rx_save_slave_64, r:1f
+body_rx_save_slave_64
+:1
+
+proc ra_sync, r:1f
+body_ra_sync
+:1
+
+proc rx_sync_slave, r:main
+body_rx_sync_slave
+
+##############################################################################
+# Subroutines
+
+:fft_16
+    body_fft_16
+
+:pass_1
+    body_pass_64 LOAD_REVERSED, r5
+:pass_2
+    body_pass_64 LOAD_STRAIGHT, r5
+:pass_3
+:pass_4
+    body_pass_32 LOAD_STRAIGHT
+
+##############################################################################
+# Top level
+
+:main
+    mov.setf r0, rb_inst
+    sub r0, r0, 1
+    shl r0, r0, 5
+    add.ifnz ra_sync, rx_sync_slave, r0
+    mov.ifnz ra_save_32, rx_save_slave_32
+    mov.ifnz ra_save_64, rx_save_slave_64
+
+:loop
+    mov.setf ra_addr_x, unif # Ping buffer or null
+    mov      rb_addr_y, unif # Pong buffer or IRQ enable
+
+    brr.allz -, r:end
+
+##############################################################################
+# Pass 1
+
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_BASE
+    load_tw rx_tw_shared, TW48+0, TW64_BASE0
+    load_tw rx_tw_shared, TW64+0, TW64_BASE1
+    init_stage 6
+    read_rev rb_0x10
+
+        brr ra_link_1, r:pass_1
+        nop
+        mov r0, 0x200
+        add ra_points, ra_points, r0
+
+        mov r1, STAGES
+        shr.setf -, ra_points, r1
+
+        brr.allz -, r:pass_1
+        nop
+        mov r0, 0x200
+        add ra_points, ra_points, r0
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 2
+
+    swap_buffers
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_BASE
+    load_tw rx_tw_shared, TW48+0, TW64_BASE0
+    load_tw rx_tw_shared, TW64+0, TW64_BASE1
+    mov ra_tw_re+TW48+1, 0; mov rb_tw_im+TW48+1, 0
+    mov ra_tw_re+TW64+1, 0; mov rb_tw_im+TW64+1, 0
+    load_tw rx_tw_shared, TW16_STEP, TW16_P2_STEP
+    load_tw rx_tw_shared, TW32_STEP, TW32_P2_STEP
+    load_tw rx_tw_shared, TW48_STEP, TW48_P2_STEP
+    load_tw rx_tw_shared, TW64_STEP, TW64_P2_STEP
+    init_stage 6
+    read_lin rb_0x10
+
+        brr ra_link_1, r:pass_2
+        nop
+        mov r0, 0x200
+        add ra_points, ra_points, r0
+
+        mov r0, 0xFFFF
+        and.setf -, ra_points, r0
+
+        brr.allnz -, r:pass_2
+        nop
+        mov r0, 0x200
+        add.ifnz ra_points, ra_points, r0
+
+        rotate TW64, TW64_STEP
+        rotate TW48, TW48_STEP
+        next_twiddles_32
+        next_twiddles_16
+
+        mov r1, STAGES
+        shr.setf -, ra_points, r1
+
+        brr.allz -, r:pass_2
+        nop
+        mov r0, 0x200
+        add ra_points, ra_points, r0
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Dual-use registers
+
+    mov ra_vpm_lo, rb_vpm
+    mov ra_vpm_hi, rb_vpm_16
+
+    mov ra_vdw_32, vdw_setup_0(1, 16, dma_h32( 0,0))
+    mov rb_vdw_32, vdw_setup_0(1, 16, dma_h32(32,0))
+
+    mov rb_STAGES, STAGES
+    mov rb_0xF0, 0xF0
+    mov rb_0x40, 0x40
+
+##############################################################################
+# Pass 3
+
+    swap_buffers
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P3_STEP
+    load_tw rx_tw_shared, TW32_STEP, TW32_P3_STEP
+    init_stage 5
+    read_lin rb_0x10
+
+        brr ra_link_1, r:pass_3
+        nop
+        mov r0, 0x100
+        add ra_points, ra_points, r0
+
+        mov r0, 0x3FF
+        and.setf -, ra_points, r0
+
+        brr.allnz -, r:pass_3
+        nop
+        mov r0, 0x100
+        add.ifnz ra_points, ra_points, r0
+
+        next_twiddles_32
+        next_twiddles_16
+
+        shr.setf -, ra_points, rb_STAGES
+
+        brr.allz -, r:pass_3
+        nop
+        mov r0, 0x100
+        add ra_points, ra_points, r0
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 4
+
+    swap_buffers
+    load_tw rx_tw_unique, TW16+3, TW16_P4_BASE
+    load_tw rx_tw_unique, TW32+0, TW32_P4_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P4_STEP
+    load_tw rx_tw_shared, TW32_STEP, TW32_P4_STEP
+    init_stage 5
+    read_lin rb_0x10
+
+        brr ra_link_1, r:pass_4
+        nop
+        mov r0, 0x100
+        add ra_points, ra_points, r0
+
+        next_twiddles_32
+        next_twiddles_16
+
+        shr.setf -, ra_points, rb_STAGES
+
+        brr.allz -, r:pass_4
+        nop
+        mov r0, 0x100
+        add ra_points, ra_points, r0
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+
+    brr -, r:loop
+    nop
+    nop
+    nop
+
+:end
+    exit rb_addr_y
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_4k.qasm b/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_4k.qasm
new file mode 100755 (executable)
index 0000000..0b2b558
--- /dev/null
@@ -0,0 +1,276 @@
+# BCM2835 "GPU_FFT" release 3.0
+#
+# Copyright (c) 2015, Andrew Holme.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the copyright holder nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+.set STAGES, 12
+
+.include "gpu_fft.qinc"
+
+##############################################################################
+# Twiddles: src
+
+.set TW16_BASE,     0   # rx_tw_shared
+.set TW16_P2_STEP,  1
+.set TW16_P3_STEP,  2
+
+.set TW16_P3_BASE,  0   # rx_tw_unique
+
+##############################################################################
+# Twiddles: dst
+
+.set TW16_STEP, 0  # 1
+.set TW16,      1  # 5
+
+##############################################################################
+# Registers
+
+.set ra_link_1,         ra0
+#                       rb0
+.set ra_save_ptr,       ra1
+#                       rb1
+.set ra_temp,           ra2
+#                       rb2
+.set ra_addr_x,         ra3
+.set rb_addr_y,         rb3
+.set ra_save_16,        ra4
+.set rx_save_slave_16,  rb4
+.set ra_load_idx,       ra5
+.set rb_inst,           rb5
+.set ra_sync,           ra6
+.set rx_sync_slave,     rb6
+.set ra_points,         ra7
+#                       rb7
+
+.set rx_tw_shared,      ra8
+.set rx_tw_unique,      rb8
+
+.set ra_tw_re,          ra9 # 6
+.set rb_tw_im,          rb9 # 6
+
+.set ra_vpm,            ra26
+.set rb_vpm,            rb26
+.set ra_vdw,            ra27
+.set rb_vdw,            rb27
+
+.set rx_0x5555,         ra28
+.set rx_0x3333,         ra29
+.set rx_0x0F0F,         ra30
+.set rx_0x00FF,         ra31
+
+.set rb_0x20,           rb29
+.set rb_0x40,           rb30
+.set rb_0x80,           rb31
+
+##############################################################################
+# Register alias
+
+.set ra_link_0, ra_save_16
+
+##############################################################################
+# Constants
+
+mov rb_0x20,    0x20
+mov rb_0x40,    0x40
+mov rb_0x80,    0x80
+
+mov rx_0x5555,  0x5555
+mov rx_0x3333,  0x3333
+mov rx_0x0F0F,  0x0F0F
+mov rx_0x00FF,  0x00FF
+
+mov ra_vdw, vdw_setup_0(16, 16, dma_h32( 0,0))
+mov rb_vdw, vdw_setup_0(16, 16, dma_h32(16,0))
+
+##############################################################################
+# Twiddles: ptr
+
+mov rx_tw_shared, unif
+mov rx_tw_unique, unif
+
+##############################################################################
+# Instance
+
+mov rb_inst, unif
+inst_vpm rb_inst, ra_vpm, rb_vpm, -, -
+
+##############################################################################
+# Macros
+
+.macro swap_vpm_vdw
+    mov ra_vpm, rb_vpm; mov rb_vpm, ra_vpm
+    mov ra_vdw, rb_vdw; mov rb_vdw, ra_vdw
+.endm
+
+.macro swizzle
+    mov.setf  -, [0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0]
+    mov r2, r0; mov.ifnz r0, r0 << 6
+    mov r3, r1; mov.ifnz r1, r1 << 6
+    mov.setf  -, [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0]
+    nop; mov.ifnz r0, r2 >> 6
+    nop; mov.ifnz r1, r3 >> 6
+.endm
+
+##############################################################################
+# Master/slave procedures
+
+proc ra_save_16, r:1f
+body_ra_save_16 ra_vpm, ra_vdw
+:1
+
+proc rx_save_slave_16, r:1f
+body_rx_save_slave_16 ra_vpm
+:1
+
+proc ra_sync, r:1f
+body_ra_sync
+:1
+
+proc rx_sync_slave, r:main
+body_rx_sync_slave
+
+##############################################################################
+# Subroutines
+
+:fft_16
+    body_fft_16
+
+:pass_1
+    read_rev rb_0x80
+    nop;        ldtmu0
+    mov r0, r4; ldtmu0
+    mov r1, r4
+    swizzle
+    brr -, r:fft_16
+    interleave
+
+:pass_2
+:pass_3
+    read_lin rb_0x80
+    brr -, r:fft_16
+    nop;        ldtmu0
+    mov r0, r4; ldtmu0
+    mov r1, r4
+
+##############################################################################
+# Top level
+
+:main
+    mov.setf r0, rb_inst
+    sub r0, r0, 1
+    shl r0, r0, 5
+    add.ifnz ra_sync, rx_sync_slave, r0
+    mov.ifnz ra_save_16, rx_save_slave_16
+
+:loop
+    mov.setf ra_addr_x, unif # Ping buffer or null
+    mov      rb_addr_y, unif # Pong buffer or IRQ enable
+
+    brr.allz -, r:end
+
+##############################################################################
+# Pass 1
+
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    init_stage 4
+    read_rev rb_0x80
+
+        brr ra_link_1, r:pass_1
+        swap_vpm_vdw
+        add ra_points, ra_points, rb_0x80
+
+        shr.setf -, ra_points, STAGES
+
+        brr.allz -, r:pass_1
+        swap_vpm_vdw
+        add ra_points, ra_points, rb_0x80
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 2
+
+    swap_buffers
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P2_STEP
+    init_stage 4
+    read_lin rb_0x80
+
+    .rep i, 2
+        brr ra_link_1, r:pass_2
+        swap_vpm_vdw
+        add ra_points, ra_points, rb_0x80
+    .endr
+
+        sub ra_link_1, ra_link_1, rb_0x20
+        next_twiddles_16
+        shr.setf -, ra_points, STAGES
+
+        brr.allz -, r:pass_2
+        swap_vpm_vdw
+        add ra_points, ra_points, rb_0x80
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 3
+
+    swap_buffers
+    load_tw rx_tw_unique, TW16+3, TW16_P3_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P3_STEP
+    init_stage 4
+    read_lin rb_0x80
+
+        brr ra_link_1, r:pass_3
+        swap_vpm_vdw
+        add ra_points, ra_points, rb_0x80
+
+        next_twiddles_16
+        shr.setf -, ra_points, STAGES
+
+        brr.allz -, r:pass_3
+        swap_vpm_vdw
+        add ra_points, ra_points, rb_0x80
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+
+    brr -, r:loop
+    nop
+    nop
+    nop
+
+:end
+    exit rb_addr_y
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_512.qasm b/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_512.qasm
new file mode 100755 (executable)
index 0000000..13e4071
--- /dev/null
@@ -0,0 +1,240 @@
+# BCM2835 "GPU_FFT" release 3.0
+#
+# Copyright (c) 2015, Andrew Holme.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the copyright holder nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+.set STAGES, 9
+
+.include "gpu_fft.qinc"
+
+##############################################################################
+# Twiddles: src
+
+.set TW32_P1_BASE,  0   # rx_tw_shared
+.set TW16_P1_BASE,  1
+.set TW16_P2_STEP,  2
+
+.set TW16_P2_BASE,  0   # rx_tw_unique
+
+##############################################################################
+# Twiddles: dst
+
+.set TW16_STEP, 0  # 1
+.set TW32_STEP, 1  # 1
+.set TW16,      2  # 5
+.set TW32,      7  # 2
+
+##############################################################################
+# Registers
+
+.set ra_link_0,         ra0
+.set rb_vdw_16,         rb0
+.set ra_save_ptr,       ra1
+.set rb_vdw_32,         rb1
+.set ra_temp,           ra2
+.set rb_vpm_lo,         rb2
+.set ra_addr_x,         ra3
+.set rb_addr_y,         rb3
+.set ra_save_16,        ra4
+.set rx_save_slave_16,  rb4
+.set ra_load_idx,       ra5
+.set rb_inst,           rb5
+.set ra_sync,           ra6
+.set rx_sync_slave,     rb6
+.set ra_points,         ra7
+.set rb_vpm_hi,         rb7
+.set ra_link_1,         ra8
+#                       rb8
+.set ra_32_re,          ra9
+.set rb_32_im,          rb9
+.set ra_save_32,        ra10
+.set rx_save_slave_32,  rb10
+
+.set rx_tw_shared,      ra11
+.set rx_tw_unique,      rb11
+
+.set ra_tw_re,          ra12 # 9
+.set rb_tw_im,          rb12 # 9
+
+.set ra_vpm_lo,         ra24
+.set ra_vpm_hi,         ra25
+.set ra_vdw_16,         ra26
+.set ra_vdw_32,         ra27
+
+.set rx_0x5555,         ra28
+.set rx_0x3333,         ra29
+.set rx_0x0F0F,         ra30
+.set rx_0x00FF,         ra31
+
+.set rb_0x10,           rb28
+.set rb_0x40,           rb29
+.set rb_0x80,           rb30
+.set rb_0xF0,           rb31
+
+##############################################################################
+# Constants
+
+mov rb_0x10,    0x10
+mov rb_0x40,    0x40
+mov rb_0x80,    0x80
+mov rb_0xF0,    0xF0
+
+mov rx_0x5555,  0x5555
+mov rx_0x3333,  0x3333
+mov rx_0x0F0F,  0x0F0F
+mov rx_0x00FF,  0x00FF
+
+mov ra_vdw_16, vdw_setup_0(16, 16, dma_h32( 0,0))
+mov rb_vdw_16, vdw_setup_0(16, 16, dma_h32(32,0))
+mov ra_vdw_32, vdw_setup_0(32, 16, dma_h32( 0,0))
+mov rb_vdw_32, vdw_setup_0(32, 16, dma_h32(32,0))
+
+##############################################################################
+# Twiddles: ptr
+
+mov rx_tw_shared, unif
+mov rx_tw_unique, unif
+
+##############################################################################
+# Instance
+
+mov rb_inst, unif
+inst_vpm rb_inst, ra_vpm_lo, ra_vpm_hi, rb_vpm_lo, rb_vpm_hi
+
+##############################################################################
+# Master/slave procedures
+
+proc ra_save_16, r:1f
+body_ra_save_16 ra_vpm_lo, ra_vdw_16
+:1
+
+proc rx_save_slave_16, r:1f
+body_rx_save_slave_16 ra_vpm_lo
+:1
+
+proc ra_save_32, r:1f
+body_ra_save_32
+:1
+
+proc rx_save_slave_32, r:1f
+body_rx_save_slave_32
+:1
+
+proc ra_sync, r:1f
+body_ra_sync
+:1
+
+proc rx_sync_slave, r:main
+body_rx_sync_slave
+
+##############################################################################
+# Subroutines
+
+:fft_16
+    body_fft_16
+
+:pass_1
+    body_pass_32 LOAD_REVERSED
+
+:pass_2
+    body_pass_16 LOAD_STRAIGHT
+
+##############################################################################
+# Top level
+
+:main
+    mov.setf r0, rb_inst
+    sub r0, r0, 1
+    shl r0, r0, 5
+    add.ifnz ra_sync, rx_sync_slave, r0
+    mov.ifnz ra_save_16, rx_save_slave_16
+    mov.ifnz ra_save_32, rx_save_slave_32
+
+:loop
+    mov.setf ra_addr_x, unif # Ping buffer or null
+    mov      rb_addr_y, unif # Pong buffer or IRQ enable
+
+    brr.allz -, r:end
+
+##############################################################################
+# Pass 1
+
+    load_tw rx_tw_shared, TW16+3, TW16_P1_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_P1_BASE
+    init_stage 5
+    read_rev rb_0x10
+
+        brr ra_link_1, r:pass_1
+        nop
+        nop
+        nop
+
+        brr ra_link_1, r:pass_1
+        nop
+        nop
+        nop
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 2
+
+    swap_buffers
+    load_tw rx_tw_unique, TW16+3, TW16_P2_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P2_STEP
+    init_stage 4
+    read_lin rb_0x80
+
+        brr ra_link_1, r:pass_2
+        nop
+        nop
+        add ra_points, ra_points, rb_0x80
+
+        next_twiddles_16
+
+        shr.setf -, ra_points, STAGES
+
+        brr.allz -, r:pass_2
+        nop
+        nop
+        add ra_points, ra_points, rb_0x80
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+
+    brr -, r:loop
+    nop
+    nop
+    nop
+
+:end
+    exit rb_addr_y
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_512k.qasm b/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_512k.qasm
new file mode 100755 (executable)
index 0000000..3722639
--- /dev/null
@@ -0,0 +1,329 @@
+# BCM2835 "GPU_FFT" release 3.0
+#
+# Copyright (c) 2015, Andrew Holme.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the copyright holder nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+.set STAGES, 19
+
+.include "gpu_fft_ex.qinc"
+
+##############################################################################
+# Twiddles: src
+
+.set TW32_BASE,     0   # rx_tw_shared
+.set TW16_BASE,     1
+.set TW16_P2_STEP,  2
+.set TW32_P3_STEP,  3
+.set TW16_P3_STEP,  4
+.set TW32_P4_STEP,  5
+.set TW16_P4_STEP,  6
+
+.set TW32_P4_BASE,  0   # rx_tw_unique
+.set TW16_P4_BASE,  1
+
+##############################################################################
+# Twiddles: dst
+
+.set TW16_STEP, 0  # 1
+.set TW32_STEP, 1  # 1
+.set TW16,      2  # 5
+.set TW32,      7  # 2
+
+##############################################################################
+# Registers
+
+.set ra_link_0,         ra0
+.set rb_vdw_16,         rb0
+.set ra_save_ptr,       ra1
+.set rb_vdw_32,         rb1
+.set ra_temp,           ra2
+.set rb_vpm_lo,         rb2
+.set ra_addr_x,         ra3
+.set rb_addr_y,         rb3
+.set ra_save_16,        ra4
+.set rx_save_slave_16,  rb4
+.set ra_load_idx,       ra5
+.set rb_inst,           rb5
+.set ra_sync,           ra6
+.set rx_sync_slave,     rb6
+.set ra_points,         ra7
+.set rb_vpm_hi,         rb7
+.set ra_link_1,         ra8
+.set rb_STAGES,         rb8
+.set ra_32_re,          ra9
+.set rb_32_im,          rb9
+.set ra_save_32,        ra10
+.set rx_save_slave_32,  rb10
+
+.set rx_tw_shared,      ra11
+.set rx_tw_unique,      rb11
+
+.set ra_tw_re,          ra12 # 9
+.set rb_tw_im,          rb12 # 9
+
+.set ra_vpm_lo,         ra25
+.set ra_vpm_hi,         ra26
+.set ra_vdw_16,         ra27
+.set ra_vdw_32,         ra28
+
+.set rx_0x55555555,     ra29
+.set rx_0x33333333,     ra30
+.set rx_0x0F0F0F0F,     ra31
+.set rx_0x00FF00FF,     rb25
+.set rx_0x0000FFFF,     rb26
+
+.set rb_0x10,           rb27
+.set rb_0x40,           rb28
+.set rb_0x80,           rb29
+.set rb_0xF0,           rb30
+.set rb_0x100,          rb31
+
+##############################################################################
+# Constants
+
+mov rb_STAGES,  STAGES
+
+mov rb_0x10,    0x10
+mov rb_0x40,    0x40
+mov rb_0x80,    0x80
+mov rb_0xF0,    0xF0
+mov rb_0x100,   0x100
+
+mov rx_0x55555555, 0x55555555
+mov rx_0x33333333, 0x33333333
+mov rx_0x0F0F0F0F, 0x0F0F0F0F
+mov rx_0x00FF00FF, 0x00FF00FF
+mov rx_0x0000FFFF, 0x0000FFFF
+
+mov ra_vdw_16, vdw_setup_0(1, 16, dma_h32( 0,0))
+mov rb_vdw_16, vdw_setup_0(1, 16, dma_h32(32,0))
+mov ra_vdw_32, vdw_setup_0(1, 16, dma_h32( 0,0))
+mov rb_vdw_32, vdw_setup_0(1, 16, dma_h32(32,0))
+
+##############################################################################
+# Twiddles: ptr
+
+mov rx_tw_shared, unif
+mov rx_tw_unique, unif
+
+##############################################################################
+# Instance
+
+mov rb_inst, unif
+inst_vpm rb_inst, ra_vpm_lo, ra_vpm_hi, rb_vpm_lo, rb_vpm_hi
+
+##############################################################################
+# Master/slave procedures
+
+proc ra_save_16, r:1f
+body_ra_save_16 ra_vpm_lo, ra_vdw_16
+:1
+
+proc rx_save_slave_16, r:1f
+body_rx_save_slave_16 ra_vpm_lo
+:1
+
+proc ra_save_32, r:1f
+body_ra_save_32
+:1
+
+proc rx_save_slave_32, r:1f
+body_rx_save_slave_32
+:1
+
+proc ra_sync, r:1f
+body_ra_sync
+:1
+
+proc rx_sync_slave, r:main
+body_rx_sync_slave
+
+##############################################################################
+# Subroutines
+
+:fft_16
+    body_fft_16
+
+:pass_1
+    body_pass_32 LOAD_REVERSED
+
+:pass_2
+    body_pass_16 LOAD_STRAIGHT
+
+:pass_3
+:pass_4
+    body_pass_32 LOAD_STRAIGHT
+
+##############################################################################
+# Top level
+
+:main
+    mov.setf r0, rb_inst
+    sub r0, r0, 1
+    shl r0, r0, 5
+    add.ifnz ra_sync, rx_sync_slave, r0
+    mov.ifnz ra_save_16, rx_save_slave_16
+    mov.ifnz ra_save_32, rx_save_slave_32
+
+:loop
+    mov.setf ra_addr_x, unif # Ping buffer or null
+    mov      rb_addr_y, unif # Pong buffer or IRQ enable
+
+    brr.allz -, r:end
+
+##############################################################################
+# Pass 1
+
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_BASE
+    init_stage 5
+    read_rev rb_0x10
+
+        brr ra_link_1, r:pass_1
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+        shr.setf -, ra_points, rb_STAGES
+
+        brr.allz -, r:pass_1
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 2
+
+    swap_buffers
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P2_STEP
+    init_stage 4
+    read_lin rb_0x80
+
+        brr ra_link_1, r:pass_2
+        nop
+        nop
+        add ra_points, ra_points, rb_0x80
+
+        mov r0, 0x3FFF
+        and.setf -, ra_points, r0
+
+        brr.allnz -, r:pass_2
+        nop
+        nop
+        add.ifnz ra_points, ra_points, rb_0x80
+
+        next_twiddles_16
+
+        shr.setf -, ra_points, rb_STAGES
+
+        brr.allz -, r:pass_2
+        nop
+        nop
+        add ra_points, ra_points, rb_0x80
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 3
+
+    swap_buffers
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P3_STEP
+    load_tw rx_tw_shared, TW32_STEP, TW32_P3_STEP
+    init_stage 5
+    read_lin rb_0x10
+
+    .rep i, 4
+        brr ra_link_1, r:pass_3
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+    .endr
+
+        next_twiddles_32
+        next_twiddles_16
+
+        shr.setf -, ra_points, rb_STAGES
+
+        brr.allz -, r:pass_3
+        mov r0, 3*4*8
+        sub ra_link_1, ra_link_1, r0
+        add ra_points, ra_points, rb_0x100
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 4
+
+    swap_buffers
+    load_tw rx_tw_unique, TW16+3, TW16_P4_BASE
+    load_tw rx_tw_unique, TW32+0, TW32_P4_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P4_STEP
+    load_tw rx_tw_shared, TW32_STEP, TW32_P4_STEP
+    init_stage 5
+    read_lin rb_0x10
+
+        brr ra_link_1, r:pass_4
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+        next_twiddles_32
+        next_twiddles_16
+
+        shr.setf -, ra_points, rb_STAGES
+
+        brr.allz -, r:pass_4
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+
+    brr -, r:loop
+    nop
+    nop
+    nop
+
+:end
+    exit rb_addr_y
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_64k.qasm b/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_64k.qasm
new file mode 100755 (executable)
index 0000000..1a94548
--- /dev/null
@@ -0,0 +1,306 @@
+# BCM2835 "GPU_FFT" release 3.0
+#
+# Copyright (c) 2015, Andrew Holme.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the copyright holder nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+.set STAGES, 16
+
+.include "gpu_fft.qinc"
+
+##############################################################################
+# Twiddles: src
+
+.set TW64_BASE0,    0 # rx_tw_shared
+.set TW64_BASE1,    1
+.set TW32_BASE,     2
+.set TW16_BASE,     3
+.set TW32_P2_STEP,  4
+.set TW16_P2_STEP,  5
+.set TW32_P3_STEP,  6
+.set TW16_P3_STEP,  7
+
+.set TW32_P3_BASE,  0 # rx_tw_unique
+.set TW16_P3_BASE,  1
+
+##############################################################################
+# Twiddles: dst
+
+.set TW16_STEP, 0  # 1
+.set TW32_STEP, 1  # 1
+.set TW16,      2  # 5
+.set TW32,      7  # 2
+.set TW48,      9  # 1
+.set TW64,      10 # 1
+
+##############################################################################
+# Registers
+
+.set ra_link_0,         ra0
+.set rb_vpm,            rb0
+.set ra_save_ptr,       ra1
+.set rb_vpm_16,         rb1
+.set ra_temp,           ra2
+.set rb_vpm_32,         rb2
+.set ra_addr_x,         ra3
+.set rb_addr_y,         rb3
+.set ra_save_32,        ra4
+.set rx_save_slave_32,  rb4
+.set ra_load_idx,       ra5
+.set rb_inst,           rb5
+.set ra_sync,           ra6
+.set rx_sync_slave,     rb6
+.set ra_points,         ra7
+.set rb_vpm_48,         rb7
+.set ra_link_1,         ra8
+.set rb_0x10,           rb8
+.set ra_32_re,          ra9
+.set rb_32_im,          rb9
+.set ra_save_64,        ra10
+.set rx_save_slave_64,  rb10
+
+.set ra_64,             ra11 # 4
+.set rb_64,             rb11 # 4
+
+.set rx_tw_shared,      ra15
+.set rx_tw_unique,      rb15
+
+.set ra_tw_re,          ra16 # 11
+.set rb_tw_im,          rb16 # 11
+
+.set rx_0x5555,         ra30
+.set rx_0x3333,         rb30
+.set rx_0x0F0F,         ra31
+.set rx_0x00FF,         rb31
+
+##############################################################################
+# Dual-use registers
+
+.set rb_STAGES,         rb_0x10
+
+.set rb_3x4x8,          rb_64+0
+.set rb_0xF0,           rb_64+1
+.set rb_0x40,           rb_64+2
+
+.set ra_vpm_lo,         ra_64+0
+.set ra_vpm_hi,         ra_64+1
+.set rb_vpm_lo,         rb_vpm_32
+.set rb_vpm_hi,         rb_vpm_48
+.set ra_vdw_32,         ra_64+3
+.set rb_vdw_32,         rb_64+3
+
+##############################################################################
+# Constants
+
+mov rb_0x10,    0x10
+mov r5rep,      0x1D0
+
+mov rx_0x5555,  0x5555
+mov rx_0x3333,  0x3333
+mov rx_0x0F0F,  0x0F0F
+mov rx_0x00FF,  0x00FF
+
+##############################################################################
+# Twiddles: ptr
+
+mov rx_tw_shared, unif
+mov rx_tw_unique, unif
+
+##############################################################################
+# Instance
+
+mov rb_inst, unif
+inst_vpm rb_inst, rb_vpm, rb_vpm_16, rb_vpm_32, rb_vpm_48
+
+##############################################################################
+# Master/slave procedures
+
+proc ra_save_32, r:1f
+body_ra_save_32
+:1
+
+proc rx_save_slave_32, r:1f
+body_rx_save_slave_32
+:1
+
+proc ra_save_64, r:1f
+    mov r0, 0x40
+body_ra_save_64 r0
+:1
+
+proc rx_save_slave_64, r:1f
+body_rx_save_slave_64
+:1
+
+proc ra_sync, r:1f
+body_ra_sync
+:1
+
+proc rx_sync_slave, r:main
+body_rx_sync_slave
+
+##############################################################################
+# Subroutines
+
+:fft_16
+    body_fft_16
+
+:pass_1
+    body_pass_64 LOAD_REVERSED, r5
+
+:pass_2
+:pass_3
+    body_pass_32 LOAD_STRAIGHT
+
+##############################################################################
+# Top level
+
+:main
+    mov.setf r0, rb_inst
+    sub r0, r0, 1
+    shl r0, r0, 5
+    add.ifnz ra_sync, rx_sync_slave, r0
+    mov.ifnz ra_save_32, rx_save_slave_32
+    mov.ifnz ra_save_64, rx_save_slave_64
+
+:loop
+    mov.setf ra_addr_x, unif # Ping buffer or null
+    mov      rb_addr_y, unif # Pong buffer or IRQ enable
+
+    brr.allz -, r:end
+
+##############################################################################
+# Pass 1
+
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_BASE
+    load_tw rx_tw_shared, TW48, TW64_BASE0
+    load_tw rx_tw_shared, TW64, TW64_BASE1
+    init_stage 6
+    read_rev rb_0x10
+
+        brr ra_link_1, r:pass_1
+        nop
+        mov r0, 0x200
+        add ra_points, ra_points, r0
+
+        mov r1, STAGES
+        shr.setf -, ra_points, r1
+
+        brr.allz -, r:pass_1
+        nop
+        mov r0, 0x200
+        add ra_points, ra_points, r0
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Dual-use registers
+
+    mov ra_vpm_lo, rb_vpm
+    mov ra_vpm_hi, rb_vpm_16
+
+    mov ra_vdw_32, vdw_setup_0(32, 16, dma_h32( 0,0))
+    mov rb_vdw_32, vdw_setup_0(32, 16, dma_h32(32,0))
+
+    mov rb_3x4x8, 3*4*8
+    mov rb_0xF0, 0xF0
+    mov rb_0x40, 0x40
+
+##############################################################################
+# Pass 2
+
+    swap_buffers
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P2_STEP
+    load_tw rx_tw_shared, TW32_STEP, TW32_P2_STEP
+    init_stage 5
+    read_lin rb_0x10
+
+    .rep i, 4
+        brr ra_link_1, r:pass_2
+        nop
+        mov r0, 0x100
+        add ra_points, ra_points, r0
+    .endr
+
+        next_twiddles_32
+        next_twiddles_16
+
+        shr.setf -, ra_points, rb_STAGES
+
+        brr.allz -, r:pass_2
+        mov r0, 0x100
+        add ra_points, ra_points, r0
+        sub ra_link_1, ra_link_1, rb_3x4x8
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 3
+
+    swap_buffers
+    load_tw rx_tw_unique, TW16+3, TW16_P3_BASE
+    load_tw rx_tw_unique, TW32+0, TW32_P3_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P3_STEP
+    load_tw rx_tw_shared, TW32_STEP, TW32_P3_STEP
+    init_stage 5
+    read_lin rb_0x10
+
+        brr ra_link_1, r:pass_3
+        nop
+        mov r0, 0x100
+        add ra_points, ra_points, r0
+
+        next_twiddles_32
+        next_twiddles_16
+
+        shr.setf -, ra_points, rb_STAGES
+
+        brr.allz -, r:pass_3
+        nop
+        mov r0, 0x100
+        add ra_points, ra_points, r0
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+
+    brr -, r:loop
+    nop
+    nop
+    nop
+
+:end
+    exit rb_addr_y
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_8k.qasm b/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_8k.qasm
new file mode 100755 (executable)
index 0000000..31acb77
--- /dev/null
@@ -0,0 +1,276 @@
+# BCM2835 "GPU_FFT" release 3.0
+#
+# Copyright (c) 2015, Andrew Holme.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the copyright holder nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+.set STAGES, 13
+
+.include "gpu_fft.qinc"
+
+##############################################################################
+# Twiddles: src
+
+.set TW32_BASE,     0   # rx_tw_shared
+.set TW16_BASE,     1
+.set TW16_P2_STEP,  2
+.set TW16_P3_STEP,  3
+
+.set TW16_P3_BASE,  0   # rx_tw_unique
+
+##############################################################################
+# Twiddles: dst
+
+.set TW16_STEP, 0  # 1
+.set TW32_STEP, 1  # 1
+.set TW16,      2  # 5
+.set TW32,      7  # 2
+
+##############################################################################
+# Registers
+
+.set ra_link_0,         ra0
+.set rb_vdw_16,         rb0
+.set ra_save_ptr,       ra1
+.set rb_vdw_32,         rb1
+.set ra_temp,           ra2
+.set rb_vpm_lo,         rb2
+.set ra_addr_x,         ra3
+.set rb_addr_y,         rb3
+.set ra_save_16,        ra4
+.set rx_save_slave_16,  rb4
+.set ra_load_idx,       ra5
+.set rb_inst,           rb5
+.set ra_sync,           ra6
+.set rx_sync_slave,     rb6
+.set ra_points,         ra7
+.set rb_vpm_hi,         rb7
+.set ra_link_1,         ra8
+#                       rb8
+.set ra_32_re,          ra9
+.set rb_32_im,          rb9
+.set ra_save_32,        ra10
+.set rx_save_slave_32,  rb10
+
+.set rx_tw_shared,      ra11
+.set rx_tw_unique,      rb11
+
+.set ra_tw_re,          ra12 # 9
+.set rb_tw_im,          rb12 # 9
+
+.set ra_vpm_lo,         ra25
+.set ra_vpm_hi,         ra26
+.set ra_vdw_16,         ra27
+.set ra_vdw_32,         ra28
+
+.set rx_0x5555,         ra29
+.set rx_0x3333,         ra30
+.set rx_0x0F0F,         ra31
+
+.set rx_0x00FF,         rb26
+.set rb_0x10,           rb27
+.set rb_0x40,           rb28
+.set rb_0x80,           rb29
+.set rb_0xF0,           rb30
+.set rb_0x100,          rb31
+
+##############################################################################
+# Constants
+
+mov rb_0x10,    0x10
+mov rb_0x40,    0x40
+mov rb_0x80,    0x80
+mov rb_0xF0,    0xF0
+mov rb_0x100,   0x100
+
+mov rx_0x5555,  0x5555
+mov rx_0x3333,  0x3333
+mov rx_0x0F0F,  0x0F0F
+mov rx_0x00FF,  0x00FF
+
+mov ra_vdw_16, vdw_setup_0(16, 16, dma_h32( 0,0))
+mov rb_vdw_16, vdw_setup_0(16, 16, dma_h32(32,0))
+mov ra_vdw_32, vdw_setup_0(32, 16, dma_h32( 0,0))
+mov rb_vdw_32, vdw_setup_0(32, 16, dma_h32(32,0))
+
+##############################################################################
+# Twiddles: ptr
+
+mov rx_tw_shared, unif
+mov rx_tw_unique, unif
+
+##############################################################################
+# Instance
+
+mov rb_inst, unif
+inst_vpm rb_inst, ra_vpm_lo, ra_vpm_hi, rb_vpm_lo, rb_vpm_hi
+
+##############################################################################
+# Master/slave procedures
+
+proc ra_save_16, r:1f
+body_ra_save_16 ra_vpm_lo, ra_vdw_16
+:1
+
+proc rx_save_slave_16, r:1f
+body_rx_save_slave_16 ra_vpm_lo
+:1
+
+proc ra_save_32, r:1f
+body_ra_save_32
+:1
+
+proc rx_save_slave_32, r:1f
+body_rx_save_slave_32
+:1
+
+proc ra_sync, r:1f
+body_ra_sync
+:1
+
+proc rx_sync_slave, r:main
+body_rx_sync_slave
+
+##############################################################################
+# Subroutines
+
+:fft_16
+    body_fft_16
+
+:pass_1
+    body_pass_32 LOAD_REVERSED
+
+:pass_2
+:pass_3
+    body_pass_16 LOAD_STRAIGHT
+
+##############################################################################
+# Top level
+
+:main
+    mov.setf r0, rb_inst
+    sub r0, r0, 1
+    shl r0, r0, 5
+    add.ifnz ra_sync, rx_sync_slave, r0
+    mov.ifnz ra_save_16, rx_save_slave_16
+    mov.ifnz ra_save_32, rx_save_slave_32
+
+:loop
+    mov.setf ra_addr_x, unif # Ping buffer or null
+    mov      rb_addr_y, unif # Pong buffer or IRQ enable
+
+    brr.allz -, r:end
+
+##############################################################################
+# Pass 1
+
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW32+0, TW32_BASE
+    init_stage 5
+    read_rev rb_0x10
+
+        brr ra_link_1, r:pass_1
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+        shr.setf -, ra_points, STAGES
+
+        brr.allz -, r:pass_1
+        nop
+        nop
+        add ra_points, ra_points, rb_0x100
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 2
+
+    swap_buffers
+    load_tw rx_tw_shared, TW16+3, TW16_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P2_STEP
+    init_stage 4
+    read_lin rb_0x80
+
+    .rep i, 2
+        brr ra_link_1, r:pass_2
+        nop
+        nop
+        add ra_points, ra_points, rb_0x80
+    .endr
+
+        next_twiddles_16
+
+        shr.setf -, ra_points, STAGES
+
+        brr.allz -, r:pass_2
+        mov r0, 4*8
+        sub ra_link_1, ra_link_1, r0
+        add ra_points, ra_points, rb_0x80
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+# Pass 3
+
+    swap_buffers
+    load_tw rx_tw_unique, TW16+3, TW16_P3_BASE
+    load_tw rx_tw_shared, TW16_STEP, TW16_P3_STEP
+    init_stage 4
+    read_lin rb_0x80
+
+        brr ra_link_1, r:pass_3
+        nop
+        nop
+        add ra_points, ra_points, rb_0x80
+
+        next_twiddles_16
+
+        shr.setf -, ra_points, STAGES
+
+        brr.allz -, r:pass_3
+        nop
+        nop
+        add ra_points, ra_points, rb_0x80
+
+    bra ra_link_1, ra_sync
+    nop
+    ldtmu0
+    ldtmu0
+
+##############################################################################
+
+    brr -, r:loop
+    nop
+    nop
+    nop
+
+:end
+    exit rb_addr_y
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_ex.qinc b/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_ex.qinc
new file mode 100755 (executable)
index 0000000..12acdb1
--- /dev/null
@@ -0,0 +1,112 @@
+# BCM2835 "GPU_FFT" release 3.0
+#
+# Copyright (c) 2015, Andrew Holme.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the copyright holder nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+##############################################################################
+# Macro baseline
+
+.include "gpu_fft.qinc"
+
+##############################################################################
+# Redefining some macros
+
+.if STAGES>16
+.macro read_rev, stride
+    add ra_load_idx, ra_load_idx, stride; mov r0, ra_load_idx
+
+    bit_rev 1,       rx_0x55555555  # 16 SIMD
+    bit_rev 2,       rx_0x33333333
+    bit_rev 4,       rx_0x0F0F0F0F
+    bit_rev 8,       rx_0x00FF00FF
+    bit_rev rb_0x10, rx_0x0000FFFF
+
+    shr r0, r0, 32-STAGES-3 # r0 = re = {idx[0:STAGES-1], 1'b0, 2'b0}
+    add r1, r0, 4           # r1 = im = {idx[0:STAGES-1], 1'b1, 2'b0}
+
+    interleave
+
+    add t0s, ra_addr_x, r0
+    add t0s, ra_addr_x, r1
+.endm
+.endif
+
+.if STAGES>17
+.macro body_ra_save_16, arg_vpm, arg_vdw
+    write_vpm_16 arg_vpm
+
+    mov -, vw_wait
+
+    .rep i, 7
+        mov -, sacq(i+9) # Master waits for slave
+        mov -, srel(i+1) # Master releases slave
+    .endr
+
+    mov r0, arg_vdw
+    add ra_save_ptr, ra_save_ptr, rb_0x40; mov r1, ra_save_ptr
+
+    mov r2, vdw_setup_0(1, 16, dma_h32(1,0)) - vdw_setup_0(1, 16, dma_h32(0,0))
+    mov r3, PASS16_STRIDE
+
+    .rep i, 16
+        add r0, r0, r2; mov vw_setup, r0
+        add r1, r1, r3; mov vw_addr,  r1
+    .endr
+
+    bra -, ra_link_1
+    nop
+    nop
+    nop
+.endm
+.endif
+
+.if STAGES>18
+.macro body_ra_save_32
+    write_vpm_32
+
+    mov -, vw_wait
+
+    .rep i, 7
+        mov -, sacq(i+9) # Master waits for slave
+        mov -, srel(i+1) # Master releases slave
+    .endr
+
+    mov r0, ra_vdw_32
+    add ra_save_ptr, ra_save_ptr, rb_0x40; mov r1, ra_save_ptr
+
+    mov r2, vdw_setup_0(1, 16, dma_h32(1,0)) - vdw_setup_0(1, 16, dma_h32(0,0))
+    mov r3, PASS32_STRIDE
+
+    .rep i, 32
+        add r0, r0, r2; mov vw_setup, r0
+        add r1, r1, r3; mov vw_addr,  r1
+    .endr
+
+    bra -, ra_link_1
+    nop
+    nop
+    nop
+.endm
+.endif
diff --git a/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_trans.qasm b/host_applications/linux/apps/hello_pi/hello_fft/qasm/gpu_fft_trans.qasm
new file mode 100755 (executable)
index 0000000..fdfa869
--- /dev/null
@@ -0,0 +1,133 @@
+# BCM2835 "GPU_FFT" release 2.0
+#
+# Copyright (c) 2014, Andrew Holme.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above copyright
+#       notice, this list of conditions and the following disclaimer in the
+#       documentation and/or other materials provided with the distribution.
+#     * Neither the name of the copyright holder nor the
+#       names of its contributors may be used to endorse or promote products
+#       derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+.set rb_offsets_re,     rb0 # 8
+.set rb_offsets_im,     rb8 # 8
+.set rb_0x10,           rb16
+.set rb_X_STRIDE,       rb17
+.set rb_Y_STRIDE_SRC,   rb18
+.set rb_Y_STRIDE_DST,   rb19
+.set rb_NX,             rb20
+.set rb_NY,             rb21
+
+.set ra_x,              ra0
+.set ra_y,              ra1
+.set ra_src_base,       ra2
+.set ra_dst_base,       ra3
+.set ra_src_cell,       ra4
+.set ra_dst_cell,       ra5
+.set ra_vdw_stride,     ra6
+
+    mov t0s, unif               # src->vc_msg
+    ldtmu0                      # r4 = vc_unifs
+    add t0s, r4, 3*4            # 3rd unif
+    ldtmu0                      # r4 = src->in
+    add ra_src_base, r4, unif   # optional offset
+
+    mov t0s, unif               # dst->vc_msg
+    ldtmu0                      # r4 = vc_unifs
+    add t0s, r4, 3*4            # 3rd unif
+    ldtmu0                      # r4 = src->in
+    add ra_dst_base, r4, unif   # optional offset
+
+    mov rb_Y_STRIDE_SRC, unif
+    mov rb_Y_STRIDE_DST, unif
+    mov rb_NX,           unif
+    mov rb_NY,           unif
+
+    mov rb_X_STRIDE, 2*4        # sizeof complex
+    mov rb_0x10, 0x10
+
+    mov r0, vdw_setup_1(0)
+    add r0, r0, rb_Y_STRIDE_DST
+    mov r1, 16*4
+    sub ra_vdw_stride, r0, r1
+
+    nop; mul24 r0, elem_num, rb_X_STRIDE
+.rep i, 8
+    mov rb_offsets_re+i, r0
+    add rb_offsets_im+i, r0, 4
+    add r0, r0, rb_Y_STRIDE_SRC
+.endr
+
+    mov ra_y, 0
+:outer
+    mov ra_x, 0
+:inner
+
+    nop; mul24 r1, ra_y, rb_Y_STRIDE_SRC
+    nop; mul24 r0, ra_x, rb_X_STRIDE
+    add r0, r0, r1
+    add ra_src_cell, ra_src_base, r0
+
+    nop; mul24 r1, ra_x, rb_Y_STRIDE_DST
+    nop; mul24 r0, ra_y, rb_X_STRIDE
+    add r0, r0, r1
+    add ra_dst_cell, ra_dst_base, r0
+
+    mov vw_setup, vpm_setup(16, 1, v32(0,0))
+
+        add t0s, ra_src_cell, rb_offsets_re
+        add t1s, ra_src_cell, rb_offsets_im
+    .rep i, 7
+        add t0s, ra_src_cell, rb_offsets_re+1+i
+        add t1s, ra_src_cell, rb_offsets_im+1+i
+        ldtmu0
+        mov vpm, r4
+        ldtmu1
+        mov vpm, r4
+    .endr
+        ldtmu0
+        mov vpm, r4
+        ldtmu1
+        mov vpm, r4
+
+    mov vw_setup, vdw_setup_0(16, 16, dma_h32(0,0))
+    mov vw_setup, ra_vdw_stride
+    mov vw_addr, ra_dst_cell
+    mov -, vw_wait
+
+    add ra_x, ra_x, rb_0x10
+    nop
+    sub.setf -, ra_x, rb_NX
+    brr.allnz -, r:inner
+    nop
+    nop
+    nop
+
+    add ra_y, ra_y, 8
+    nop
+    sub.setf -, ra_y, rb_NY
+    brr.allnz -, r:outer
+    nop
+    nop
+    nop
+
+    mov interrupt, 1
+    nop; nop; thrend
+    nop
+    nop
diff --git a/host_applications/linux/apps/hello_pi/hello_font/CMakeLists.txt b/host_applications/linux/apps/hello_pi/hello_font/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..448d2cf
--- /dev/null
@@ -0,0 +1,9 @@
+set(EXEC hello_font.bin)
+set(SRCS main.c)
+
+add_executable(${EXEC} ${SRCS})
+target_link_libraries(${EXEC} ${HELLO_PI_LIBS})
+target_link_libraries(${EXEC} vgfont freetype z)
+
+install(TARGETS ${EXEC}
+        RUNTIME DESTINATION bin)
diff --git a/host_applications/linux/apps/hello_pi/hello_font/Makefile b/host_applications/linux/apps/hello_pi/hello_font/Makefile
new file mode 100755 (executable)
index 0000000..7ec49f2
--- /dev/null
@@ -0,0 +1,7 @@
+OBJS=main.o
+BIN=hello_font.bin
+
+LDFLAGS+=-lvgfont -lfreetype -lz
+
+include ../Makefile.include
+
diff --git a/host_applications/linux/apps/hello_pi/hello_font/Vera.ttf b/host_applications/linux/apps/hello_pi/hello_font/Vera.ttf
new file mode 100755 (executable)
index 0000000..58cd6b5
Binary files /dev/null and b/host_applications/linux/apps/hello_pi/hello_font/Vera.ttf differ
diff --git a/host_applications/linux/apps/hello_pi/hello_font/main.c b/host_applications/linux/apps/hello_pi/hello_font/main.c
new file mode 100755 (executable)
index 0000000..66bbe83
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Test app for VG font library.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include "bcm_host.h"
+#include "vgfont.h"
+
+static const char *strnchr(const char *str, size_t len, char c)
+{
+   const char *e = str + len;
+   do {
+      if (*str == c) {
+         return str;
+      }
+   } while (++str < e);
+   return NULL;
+}
+
+int32_t render_subtitle(GRAPHICS_RESOURCE_HANDLE img, const char *text, const int skip, const uint32_t text_size, const uint32_t y_offset)
+{
+   uint32_t text_length = strlen(text)-skip;
+   uint32_t width=0, height=0;
+   const char *split = text;
+   int32_t s=0;
+   int len = 0; // length of pre-subtitle
+   uint32_t img_w, img_h;
+
+   graphics_get_resource_size(img, &img_w, &img_h);
+
+   if (text_length==0)
+      return 0;
+   while (split[0]) {
+      s = graphics_resource_text_dimensions_ext(img, split, text_length-(split-text), &width, &height, text_size);
+      if (s != 0) return s;
+      if (width > img_w) {
+         const char *space = strnchr(split, text_length-(split-text), ' ');
+         if (!space) {
+            len = split+1-text;
+            split = split+1;
+         } else {
+            len = space-text;
+            split = space+1;
+         }
+      } else {
+         break;
+      }
+   }
+   // split now points to last line of text. split-text = length of initial text. text_length-(split-text) is length of last line
+   if (width) {
+      s = graphics_resource_render_text_ext(img, (img_w - width)>>1, y_offset-height,
+                                     GRAPHICS_RESOURCE_WIDTH,
+                                     GRAPHICS_RESOURCE_HEIGHT,
+                                     GRAPHICS_RGBA32(0xff,0xff,0xff,0xff), /* fg */
+                                     GRAPHICS_RGBA32(0,0,0,0x80), /* bg */
+                                     split, text_length-(split-text), text_size);
+      if (s!=0) return s;
+   }
+   return render_subtitle(img, text, skip+text_length-len, text_size, y_offset - height);
+}
+
+int main(void)
+{
+   GRAPHICS_RESOURCE_HANDLE img;
+   uint32_t width, height;
+   int LAYER=1;
+   bcm_host_init();
+   int s;
+
+   s = gx_graphics_init(".");
+   assert(s == 0);
+
+   s = graphics_get_display_size(0, &width, &height);
+   assert(s == 0);
+
+   s = gx_create_window(0, width, height, GRAPHICS_RESOURCE_RGBA32, &img);
+   assert(s == 0);
+
+   // transparent before display to avoid screen flash
+   graphics_resource_fill(img, 0, 0, width, height, GRAPHICS_RGBA32(0,0,0,0x00));
+
+   graphics_display_resource(img, 0, LAYER, 0, 0, GRAPHICS_RESOURCE_WIDTH, GRAPHICS_RESOURCE_HEIGHT, VC_DISPMAN_ROT0, 1);
+
+   uint32_t text_size = 10;
+   while (1) {
+      const char *text = "The quick brown fox jumps over the lazy dog";
+      uint32_t y_offset = height-60+text_size/2;
+      graphics_resource_fill(img, 0, 0, width, height, GRAPHICS_RGBA32(0,0,0,0x00));
+      // blue, at the top (y=40)
+      graphics_resource_fill(img, 0, 40, width, 1, GRAPHICS_RGBA32(0,0,0xff,0xff));
+
+      // green, at the bottom (y=height-40)
+      graphics_resource_fill(img, 0, height-40, width, 1, GRAPHICS_RGBA32(0,0xff,0,0xff));
+
+      // draw the subtitle text
+      render_subtitle(img, text, 0, text_size,  y_offset);
+      graphics_update_displayed_resource(img, 0, 0, 0, 0);
+      text_size += 1;
+      if (text_size > 50)
+         text_size = 10;
+   }
+
+   graphics_display_resource(img, 0, LAYER, 0, 0, GRAPHICS_RESOURCE_WIDTH, GRAPHICS_RESOURCE_HEIGHT, VC_DISPMAN_ROT0, 0);
+   graphics_delete_resource(img);
+
+   return 0;
+}
+
diff --git a/host_applications/linux/apps/hello_pi/hello_jpeg/CMakeLists.txt b/host_applications/linux/apps/hello_pi/hello_jpeg/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..a56dda5
--- /dev/null
@@ -0,0 +1,8 @@
+set(EXEC hello_jpeg.bin)
+set(SRCS jpeg.c)
+
+add_executable(${EXEC} ${SRCS})
+target_link_libraries(${EXEC} ${HELLO_PI_LIBS})
+
+install(TARGETS ${EXEC}
+        RUNTIME DESTINATION bin)
diff --git a/host_applications/linux/apps/hello_pi/hello_jpeg/Makefile b/host_applications/linux/apps/hello_pi/hello_jpeg/Makefile
new file mode 100755 (executable)
index 0000000..04fd84f
--- /dev/null
@@ -0,0 +1,6 @@
+OBJS=jpeg.o
+BIN=hello_jpeg.bin
+LDFLAGS+=-lilclient
+
+include ../Makefile.include
+
diff --git a/host_applications/linux/apps/hello_pi/hello_jpeg/jpeg.c b/host_applications/linux/apps/hello_pi/hello_jpeg/jpeg.c
new file mode 100755 (executable)
index 0000000..233b20e
--- /dev/null
@@ -0,0 +1,696 @@
+/*
+Copyright (c) 2012, Matt Ownby
+                    Anthong Sale
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <assert.h>
+#include "jpeg.h"
+
+#define TIMEOUT_MS 2000
+
+typedef struct _COMPONENT_DETAILS {
+    COMPONENT_T    *component;
+    OMX_HANDLETYPE  handle;
+    int             inPort;
+    int             outPort;
+} COMPONENT_DETAILS;
+
+struct _OPENMAX_JPEG_DECODER {
+    ILCLIENT_T     *client;
+    COMPONENT_DETAILS *imageDecoder;
+    COMPONENT_DETAILS *imageResizer;
+    OMX_BUFFERHEADERTYPE **ppInputBufferHeader;
+    int             inputBufferHeaderCount;
+    OMX_BUFFERHEADERTYPE *pOutputBufferHeader;
+};
+
+int             bufferIndex = 0;       // index to buffer array
+
+int
+portSettingsChanged(OPENMAX_JPEG_DECODER * decoder)
+{
+    OMX_PARAM_PORTDEFINITIONTYPE portdef;
+
+    // need to setup the input for the resizer with the output of the
+    // decoder
+    portdef.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
+    portdef.nVersion.nVersion = OMX_VERSION;
+    portdef.nPortIndex = decoder->imageDecoder->outPort;
+    OMX_GetParameter(decoder->imageDecoder->handle,
+                    OMX_IndexParamPortDefinition, &portdef);
+
+    unsigned int    uWidth =
+       (unsigned int) portdef.format.image.nFrameWidth;
+    unsigned int    uHeight =
+       (unsigned int) portdef.format.image.nFrameHeight;
+
+    // tell resizer input what the decoder output will be providing
+    portdef.nPortIndex = decoder->imageResizer->inPort;
+    OMX_SetParameter(decoder->imageResizer->handle,
+                    OMX_IndexParamPortDefinition, &portdef);
+
+    // establish tunnel between decoder output and resizer input
+    OMX_SetupTunnel(decoder->imageDecoder->handle,
+                   decoder->imageDecoder->outPort,
+                   decoder->imageResizer->handle,
+                   decoder->imageResizer->inPort);
+
+    // enable ports
+    OMX_SendCommand(decoder->imageDecoder->handle,
+                   OMX_CommandPortEnable,
+                   decoder->imageDecoder->outPort, NULL);
+    OMX_SendCommand(decoder->imageResizer->handle,
+                   OMX_CommandPortEnable,
+                   decoder->imageResizer->inPort, NULL);
+
+    // put resizer in idle state (this allows the outport of the decoder
+    // to become enabled)
+    OMX_SendCommand(decoder->imageResizer->handle,
+                   OMX_CommandStateSet, OMX_StateIdle, NULL);
+
+    // wait for state change complete
+    ilclient_wait_for_event(decoder->imageResizer->component,
+                           OMX_EventCmdComplete,
+                           OMX_CommandStateSet, 1,
+                           OMX_StateIdle, 1, 0, TIMEOUT_MS);
+
+    // once the state changes, both ports should become enabled and the
+    // resizer
+    // output should generate a settings changed event
+    ilclient_wait_for_event(decoder->imageDecoder->component,
+                           OMX_EventCmdComplete,
+                           OMX_CommandPortEnable, 1,
+                           decoder->imageDecoder->outPort, 1, 0,
+                           TIMEOUT_MS);
+    ilclient_wait_for_event(decoder->imageResizer->component,
+                           OMX_EventCmdComplete, OMX_CommandPortEnable, 1,
+                           decoder->imageResizer->inPort, 1, 0,
+                           TIMEOUT_MS);
+    ilclient_wait_for_event(decoder->imageResizer->component,
+                           OMX_EventPortSettingsChanged,
+                           decoder->imageResizer->outPort, 1, 0, 1, 0,
+                           TIMEOUT_MS);
+
+    ilclient_disable_port(decoder->imageResizer->component,
+                         decoder->imageResizer->outPort);
+
+    // query output buffer requirements for resizer
+    portdef.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
+    portdef.nVersion.nVersion = OMX_VERSION;
+    portdef.nPortIndex = decoder->imageResizer->outPort;
+    OMX_GetParameter(decoder->imageResizer->handle,
+                    OMX_IndexParamPortDefinition, &portdef);
+
+    // change output color format and dimensions to match input
+    portdef.format.image.eCompressionFormat = OMX_IMAGE_CodingUnused;
+    portdef.format.image.eColorFormat = OMX_COLOR_Format32bitABGR8888;
+    portdef.format.image.nFrameWidth = uWidth;
+    portdef.format.image.nFrameHeight = uHeight;
+    portdef.format.image.nStride = 0;
+    portdef.format.image.nSliceHeight = 0;
+    portdef.format.image.bFlagErrorConcealment = OMX_FALSE;
+
+    OMX_SetParameter(decoder->imageResizer->handle,
+                    OMX_IndexParamPortDefinition, &portdef);
+
+    // grab output requirements again to get actual buffer size
+    // requirement (and buffer count requirement!)
+    OMX_GetParameter(decoder->imageResizer->handle,
+                    OMX_IndexParamPortDefinition, &portdef);
+
+    // move resizer into executing state
+    ilclient_change_component_state(decoder->imageResizer->component,
+                                   OMX_StateExecuting);
+
+    // show some logging so user knows it's working
+    printf
+       ("Width: %u Height: %u Output Color Format: 0x%x Buffer Size: %u\n",
+        (unsigned int) portdef.format.image.nFrameWidth,
+        (unsigned int) portdef.format.image.nFrameHeight,
+        (unsigned int) portdef.format.image.eColorFormat,
+        (unsigned int) portdef.nBufferSize);
+    fflush(stdout);
+
+    // enable output port of resizer
+    OMX_SendCommand(decoder->imageResizer->handle,
+                   OMX_CommandPortEnable,
+                   decoder->imageResizer->outPort, NULL);
+
+    // allocate the buffer
+    // void* outputBuffer = 0; 
+    // if (posix_memalign(&outputBuffer, portdef.nBufferAlignment,
+    // portdef.nBufferSize) != 0)
+    // {
+    // perror("Allocating output buffer");
+    // return OMXJPEG_ERROR_MEMORY;
+    // }
+
+    // set the buffer
+    // int ret = OMX_UseBuffer(decoder->imageResizer->handle,
+    // &decoder->pOutputBufferHeader,
+    // decoder->imageResizer->outPort, NULL,
+    // portdef.nBufferSize,
+    // (OMX_U8 *) outputBuffer);
+    int             ret = OMX_AllocateBuffer(decoder->imageResizer->handle,
+                                            &decoder->pOutputBufferHeader,
+                                            decoder->imageResizer->
+                                            outPort,
+                                            NULL,
+                                            portdef.nBufferSize);
+    if (ret != OMX_ErrorNone) {
+       perror("Eror allocating buffer");
+       fprintf(stderr, "OMX_AllocateBuffer returned 0x%x allocating buffer size 0x%x\n", ret, portdef.nBufferSize);
+       return OMXJPEG_ERROR_MEMORY;
+    }
+
+    ilclient_wait_for_event(decoder->imageResizer->component,
+                           OMX_EventCmdComplete,
+                           OMX_CommandPortEnable, 1,
+                           decoder->imageResizer->outPort, 1, 0,
+                           TIMEOUT_MS);
+
+    return OMXJPEG_OK;
+}
+
+int
+portSettingsChangedAgain(OPENMAX_JPEG_DECODER * decoder)
+{
+    ilclient_disable_port(decoder->imageDecoder->component,
+                         decoder->imageDecoder->outPort);
+    ilclient_disable_port(decoder->imageResizer->component,
+                         decoder->imageResizer->inPort);
+
+    OMX_PARAM_PORTDEFINITIONTYPE portdef;
+
+    // need to setup the input for the resizer with the output of the
+    // decoder
+    portdef.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
+    portdef.nVersion.nVersion = OMX_VERSION;
+    portdef.nPortIndex = decoder->imageDecoder->outPort;
+    OMX_GetParameter(decoder->imageDecoder->handle,
+                    OMX_IndexParamPortDefinition, &portdef);
+
+    // tell resizer input what the decoder output will be providing
+    portdef.nPortIndex = decoder->imageResizer->inPort;
+    OMX_SetParameter(decoder->imageResizer->handle,
+                    OMX_IndexParamPortDefinition, &portdef);
+
+    // enable output of decoder and input of resizer (ie enable tunnel)
+    ilclient_enable_port(decoder->imageDecoder->component,
+                        decoder->imageDecoder->outPort);
+    ilclient_enable_port(decoder->imageResizer->component,
+                        decoder->imageResizer->inPort);
+
+    // need to wait for this event
+    ilclient_wait_for_event(decoder->imageResizer->component,
+                           OMX_EventPortSettingsChanged,
+                           decoder->imageResizer->outPort, 1,
+                           0, 0, 0, TIMEOUT_MS);
+
+    return OMXJPEG_OK;
+}
+
+int
+prepareResizer(OPENMAX_JPEG_DECODER * decoder)
+{
+    decoder->imageResizer = malloc(sizeof(COMPONENT_DETAILS));
+    if (decoder->imageResizer == NULL) {
+       perror("malloc image resizer");
+       return OMXJPEG_ERROR_MEMORY;
+    }
+
+    int             ret = ilclient_create_component(decoder->client,
+                                                   &decoder->
+                                                   imageResizer->
+                                                   component,
+                                                   "resize",
+                                                   ILCLIENT_DISABLE_ALL_PORTS
+                                                   |
+                                                   ILCLIENT_ENABLE_INPUT_BUFFERS
+                                                   |
+                                                   ILCLIENT_ENABLE_OUTPUT_BUFFERS);
+    if (ret != 0) {
+       perror("image resizer");
+       return OMXJPEG_ERROR_CREATING_COMP;
+    }
+    // grab the handle for later use
+    decoder->imageResizer->handle =
+       ILC_GET_HANDLE(decoder->imageResizer->component);
+
+    // get and store the ports
+    OMX_PORT_PARAM_TYPE port;
+    port.nSize = sizeof(OMX_PORT_PARAM_TYPE);
+    port.nVersion.nVersion = OMX_VERSION;
+
+    OMX_GetParameter(ILC_GET_HANDLE(decoder->imageResizer->component),
+                    OMX_IndexParamImageInit, &port);
+    if (port.nPorts != 2) {
+       return OMXJPEG_ERROR_WRONG_NO_PORTS;
+    }
+    decoder->imageResizer->inPort = port.nStartPortNumber;
+    decoder->imageResizer->outPort = port.nStartPortNumber + 1;
+
+    decoder->pOutputBufferHeader = NULL;
+
+    return OMXJPEG_OK;
+}
+
+int
+prepareImageDecoder(OPENMAX_JPEG_DECODER * decoder)
+{
+    decoder->imageDecoder = malloc(sizeof(COMPONENT_DETAILS));
+    if (decoder->imageDecoder == NULL) {
+       perror("malloc image decoder");
+       return OMXJPEG_ERROR_MEMORY;
+    }
+
+    int             ret = ilclient_create_component(decoder->client,
+                                                   &decoder->
+                                                   imageDecoder->
+                                                   component,
+                                                   "image_decode",
+                                                   ILCLIENT_DISABLE_ALL_PORTS
+                                                   |
+                                                   ILCLIENT_ENABLE_INPUT_BUFFERS);
+
+    if (ret != 0) {
+       perror("image decode");
+       return OMXJPEG_ERROR_CREATING_COMP;
+    }
+    // grab the handle for later use in OMX calls directly
+    decoder->imageDecoder->handle =
+       ILC_GET_HANDLE(decoder->imageDecoder->component);
+
+    // get and store the ports
+    OMX_PORT_PARAM_TYPE port;
+    port.nSize = sizeof(OMX_PORT_PARAM_TYPE);
+    port.nVersion.nVersion = OMX_VERSION;
+
+    OMX_GetParameter(decoder->imageDecoder->handle,
+                    OMX_IndexParamImageInit, &port);
+    if (port.nPorts != 2) {
+       return OMXJPEG_ERROR_WRONG_NO_PORTS;
+    }
+    decoder->imageDecoder->inPort = port.nStartPortNumber;
+    decoder->imageDecoder->outPort = port.nStartPortNumber + 1;
+
+    return OMXJPEG_OK;
+}
+
+int
+startupImageDecoder(OPENMAX_JPEG_DECODER * decoder)
+{
+    // move to idle
+    ilclient_change_component_state(decoder->imageDecoder->component,
+                                   OMX_StateIdle);
+
+    // set input image format
+    OMX_IMAGE_PARAM_PORTFORMATTYPE imagePortFormat;
+    memset(&imagePortFormat, 0, sizeof(OMX_IMAGE_PARAM_PORTFORMATTYPE));
+    imagePortFormat.nSize = sizeof(OMX_IMAGE_PARAM_PORTFORMATTYPE);
+    imagePortFormat.nVersion.nVersion = OMX_VERSION;
+    imagePortFormat.nPortIndex = decoder->imageDecoder->inPort;
+    imagePortFormat.eCompressionFormat = OMX_IMAGE_CodingJPEG;
+    OMX_SetParameter(decoder->imageDecoder->handle,
+                    OMX_IndexParamImagePortFormat, &imagePortFormat);
+
+    // get buffer requirements
+    OMX_PARAM_PORTDEFINITIONTYPE portdef;
+    portdef.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
+    portdef.nVersion.nVersion = OMX_VERSION;
+    portdef.nPortIndex = decoder->imageDecoder->inPort;
+    OMX_GetParameter(decoder->imageDecoder->handle,
+                    OMX_IndexParamPortDefinition, &portdef);
+
+    // enable the port and setup the buffers
+    OMX_SendCommand(decoder->imageDecoder->handle,
+                   OMX_CommandPortEnable,
+                   decoder->imageDecoder->inPort, NULL);
+    decoder->inputBufferHeaderCount = portdef.nBufferCountActual;
+    // allocate pointer array
+    decoder->ppInputBufferHeader =
+       (OMX_BUFFERHEADERTYPE **) malloc(sizeof(void) *
+                                        decoder->inputBufferHeaderCount);
+    // allocate each buffer
+    int             i;
+    for (i = 0; i < decoder->inputBufferHeaderCount; i++) {
+       if (OMX_AllocateBuffer(decoder->imageDecoder->handle,
+                              &decoder->ppInputBufferHeader[i],
+                              decoder->imageDecoder->inPort,
+                              (void *) i,
+                              portdef.nBufferSize) != OMX_ErrorNone) {
+           perror("Allocate decode buffer");
+           return OMXJPEG_ERROR_MEMORY;
+       }
+    }
+    // wait for port enable to complete - which it should once buffers are 
+    // assigned
+    int             ret =
+       ilclient_wait_for_event(decoder->imageDecoder->component,
+                               OMX_EventCmdComplete,
+                               OMX_CommandPortEnable, 0,
+                               decoder->imageDecoder->inPort, 0,
+                               0, TIMEOUT_MS);
+    if (ret != 0) {
+       fprintf(stderr, "Did not get port enable %d\n", ret);
+       return OMXJPEG_ERROR_EXECUTING;
+    }
+    // start executing the decoder 
+    ret = OMX_SendCommand(decoder->imageDecoder->handle,
+                         OMX_CommandStateSet, OMX_StateExecuting, NULL);
+    if (ret != 0) {
+       fprintf(stderr, "Error starting image decoder %x\n", ret);
+       return OMXJPEG_ERROR_EXECUTING;
+    }
+    ret = ilclient_wait_for_event(decoder->imageDecoder->component,
+                                 OMX_EventCmdComplete,
+                                 OMX_StateExecuting, 0, 0, 1, 0,
+                                 TIMEOUT_MS);
+    if (ret != 0) {
+       fprintf(stderr, "Did not receive executing stat %d\n", ret);
+       // return OMXJPEG_ERROR_EXECUTING;
+    }
+
+    return OMXJPEG_OK;
+}
+
+// this function run the boilerplate to setup the openmax components;
+int
+setupOpenMaxJpegDecoder(OPENMAX_JPEG_DECODER ** pDecoder)
+{
+    *pDecoder = malloc(sizeof(OPENMAX_JPEG_DECODER));
+    if (pDecoder[0] == NULL) {
+       perror("malloc decoder");
+       return OMXJPEG_ERROR_MEMORY;
+    }
+    memset(*pDecoder, 0, sizeof(OPENMAX_JPEG_DECODER));
+
+    if ((pDecoder[0]->client = ilclient_init()) == NULL) {
+       perror("ilclient_init");
+       return OMXJPEG_ERROR_ILCLIENT_INIT;
+    }
+
+    if (OMX_Init() != OMX_ErrorNone) {
+       ilclient_destroy(pDecoder[0]->client);
+       perror("OMX_Init");
+       return OMXJPEG_ERROR_OMX_INIT;
+    }
+    // prepare the image decoder
+    int             ret = prepareImageDecoder(pDecoder[0]);
+    if (ret != OMXJPEG_OK)
+       return ret;
+
+    ret = prepareResizer(pDecoder[0]);
+    if (ret != OMXJPEG_OK)
+       return ret;
+
+    ret = startupImageDecoder(pDecoder[0]);
+    if (ret != OMXJPEG_OK)
+       return ret;
+
+    return OMXJPEG_OK;
+}
+
+// this function passed the jpeg image buffer in, and returns the decoded
+// image
+int
+decodeImage(OPENMAX_JPEG_DECODER * decoder, char *sourceImage,
+           size_t imageSize)
+{
+    char           *sourceOffset = sourceImage;        // we store a separate
+                                               // buffer ot image so we
+                                               // can offset it
+    size_t          toread = 0;        // bytes left to read from buffer
+    toread += imageSize;
+    int             bFilled = 0;       // have we filled our output
+                                       // buffer
+    bufferIndex = 0;
+
+    while (toread > 0) {
+       // get next buffer from array
+       OMX_BUFFERHEADERTYPE *pBufHeader =
+           decoder->ppInputBufferHeader[bufferIndex];
+
+       // step index and reset to 0 if required
+       bufferIndex++;
+       if (bufferIndex >= decoder->inputBufferHeaderCount)
+           bufferIndex = 0;
+
+       // work out the next chunk to load into the decoder
+       if (toread > pBufHeader->nAllocLen)
+           pBufHeader->nFilledLen = pBufHeader->nAllocLen;
+       else
+           pBufHeader->nFilledLen = toread;
+
+       toread = toread - pBufHeader->nFilledLen;
+
+       // pass the bytes to the buffer
+       memcpy(pBufHeader->pBuffer, sourceOffset, pBufHeader->nFilledLen);
+
+       // update the buffer pointer and set the input flags
+
+       sourceOffset = sourceOffset + pBufHeader->nFilledLen;
+       pBufHeader->nOffset = 0;
+       pBufHeader->nFlags = 0;
+       if (toread <= 0) {
+           pBufHeader->nFlags = OMX_BUFFERFLAG_EOS;
+       }
+       // empty the current buffer
+       int             ret =
+           OMX_EmptyThisBuffer(decoder->imageDecoder->handle,
+                               pBufHeader);
+
+       if (ret != OMX_ErrorNone) {
+           perror("Empty input buffer");
+           fprintf(stderr, "return code %x\n", ret);
+           return OMXJPEG_ERROR_MEMORY;
+       }
+       // wait for buffer to empty or port changed event
+       int             done = 0;
+       while ((done == 0) && (decoder->pOutputBufferHeader == NULL)) {
+           if (decoder->pOutputBufferHeader == NULL) {
+               ret =
+                   ilclient_wait_for_event
+                   (decoder->imageDecoder->component,
+                    OMX_EventPortSettingsChanged,
+                    decoder->imageDecoder->outPort, 0, 0, 1, 0, 5);
+
+               if (ret == 0) {
+                   ret = portSettingsChanged(decoder);
+                   if (ret != OMXJPEG_OK)
+                       return ret;
+               }
+           } else {
+               ret =
+                   ilclient_remove_event(decoder->imageDecoder->component,
+                                         OMX_EventPortSettingsChanged,
+                                         decoder->imageDecoder->outPort,
+                                         0, 0, 1);
+               if (ret == 0)
+                   portSettingsChangedAgain(decoder);
+
+           }
+
+           // check to see if buffer is now empty
+           if (pBufHeader->nFilledLen == 0)
+               done = 1;
+
+           if ((done == 0)
+               || (decoder->pOutputBufferHeader == NULL))
+               sleep(1);
+       }
+
+       // fill the buffer if we have created the buffer
+       if ((bFilled == 0) && (decoder->pOutputBufferHeader != NULL)) {
+           ret = OMX_FillThisBuffer(decoder->imageResizer->handle,
+                                    decoder->pOutputBufferHeader);
+           if (ret != OMX_ErrorNone) {
+               perror("Filling output buffer");
+               fprintf(stderr, "Error code %x\n", ret);
+               return OMXJPEG_ERROR_MEMORY;
+           }
+
+           bFilled = 1;
+       }
+    }
+
+    // wait for buffer to fill
+    /*
+     * while(pBufHeader->nFilledLen == 0) { sleep(5); } 
+     */
+
+    // wait for end of stream events
+    int             ret =
+       ilclient_wait_for_event(decoder->imageDecoder->component,
+                               OMX_EventBufferFlag,
+                               decoder->imageDecoder->outPort, 1,
+                               OMX_BUFFERFLAG_EOS, 1,
+                               0, 2);
+    if (ret != 0) {
+       fprintf(stderr, "No EOS event on image decoder %d\n", ret);
+    }
+    ret = ilclient_wait_for_event(decoder->imageResizer->component,
+                                 OMX_EventBufferFlag,
+                                 decoder->imageResizer->outPort, 1,
+                                 OMX_BUFFERFLAG_EOS, 1, 0, 2);
+    if (ret != 0) {
+       fprintf(stderr, "No EOS event on image resizer %d\n", ret);
+    }
+    return OMXJPEG_OK;
+}
+
+// this function cleans up the decoder.
+void
+cleanup(OPENMAX_JPEG_DECODER * decoder)
+{
+    // flush everything through
+    OMX_SendCommand(decoder->imageDecoder->handle,
+                   OMX_CommandFlush, decoder->imageDecoder->outPort,
+                   NULL);
+    ilclient_wait_for_event(decoder->imageDecoder->component,
+                           OMX_EventCmdComplete, OMX_CommandFlush, 0,
+                           decoder->imageDecoder->outPort, 0, 0,
+                           TIMEOUT_MS);
+    OMX_SendCommand(decoder->imageResizer->handle, OMX_CommandFlush,
+                   decoder->imageResizer->inPort, NULL);
+    ilclient_wait_for_event(decoder->imageResizer->component,
+                           OMX_EventCmdComplete, OMX_CommandFlush, 0,
+                           decoder->imageResizer->inPort, 1, 0,
+                           TIMEOUT_MS);
+
+    OMX_SendCommand(decoder->imageDecoder->handle, OMX_CommandPortDisable,
+                   decoder->imageDecoder->inPort, NULL);
+
+    int             i = 0;
+    for (i = 0; i < decoder->inputBufferHeaderCount; i++) {
+       OMX_BUFFERHEADERTYPE *vpBufHeader =
+           decoder->ppInputBufferHeader[i];
+
+       OMX_FreeBuffer(decoder->imageDecoder->handle,
+                      decoder->imageDecoder->inPort, vpBufHeader);
+    }
+
+    ilclient_wait_for_event(decoder->imageDecoder->component,
+                           OMX_EventCmdComplete, OMX_CommandPortDisable,
+                           0, decoder->imageDecoder->inPort, 0, 0,
+                           TIMEOUT_MS);
+
+    OMX_SendCommand(decoder->imageResizer->handle, OMX_CommandPortDisable,
+                   decoder->imageResizer->outPort, NULL);
+
+    OMX_FreeBuffer(decoder->imageResizer->handle,
+                  decoder->imageResizer->outPort,
+                  decoder->pOutputBufferHeader);
+
+    ilclient_wait_for_event(decoder->imageResizer->component,
+                           OMX_EventCmdComplete, OMX_CommandPortDisable,
+                           0, decoder->imageResizer->outPort, 0, 0,
+                           TIMEOUT_MS);
+
+    OMX_SendCommand(decoder->imageDecoder->handle, OMX_CommandPortDisable,
+                   decoder->imageDecoder->outPort, NULL);
+    ilclient_wait_for_event(decoder->imageDecoder->component,
+                           OMX_EventCmdComplete, OMX_CommandPortDisable,
+                           0, decoder->imageDecoder->outPort, 0, 0,
+                           TIMEOUT_MS);
+
+    OMX_SendCommand(decoder->imageResizer->handle, OMX_CommandPortDisable,
+                   decoder->imageResizer->inPort, NULL);
+    ilclient_wait_for_event(decoder->imageResizer->component,
+                           OMX_EventCmdComplete, OMX_CommandPortDisable,
+                           0, decoder->imageResizer->inPort, 0, 0,
+                           TIMEOUT_MS);
+
+    OMX_SetupTunnel(decoder->imageDecoder->handle,
+                   decoder->imageDecoder->outPort, NULL, 0);
+    OMX_SetupTunnel(decoder->imageResizer->handle,
+                   decoder->imageResizer->inPort, NULL, 0);
+
+    ilclient_change_component_state(decoder->imageDecoder->component,
+                                   OMX_StateIdle);
+    ilclient_change_component_state(decoder->imageResizer->component,
+                                   OMX_StateIdle);
+
+    ilclient_wait_for_event(decoder->imageDecoder->component,
+                           OMX_EventCmdComplete, OMX_CommandStateSet, 0,
+                           OMX_StateIdle, 0, 0, TIMEOUT_MS);
+    ilclient_wait_for_event(decoder->imageResizer->component,
+                           OMX_EventCmdComplete, OMX_CommandStateSet, 0,
+                           OMX_StateIdle, 0, 0, TIMEOUT_MS);
+
+    ilclient_change_component_state(decoder->imageDecoder->component,
+                                   OMX_StateLoaded);
+    ilclient_change_component_state(decoder->imageResizer->component,
+                                   OMX_StateLoaded);
+
+    ilclient_wait_for_event(decoder->imageDecoder->component,
+                           OMX_EventCmdComplete, OMX_CommandStateSet, 0,
+                           OMX_StateLoaded, 0, 0, TIMEOUT_MS);
+    ilclient_wait_for_event(decoder->imageResizer->component,
+                           OMX_EventCmdComplete, OMX_CommandStateSet, 0,
+                           OMX_StateLoaded, 0, 0, TIMEOUT_MS);
+
+    OMX_Deinit();
+
+    if (decoder->client != NULL) {
+       ilclient_destroy(decoder->client);
+    }
+}
+
+int
+main(int argc, char *argv[])
+{
+    OPENMAX_JPEG_DECODER *pDecoder;
+    char           *sourceImage;
+    size_t          imageSize;
+    int             s;
+    if (argc < 2) {
+       printf("Usage: %s <filename>\n", argv[0]);
+       return -1;
+    }
+    FILE           *fp = fopen(argv[1], "rb");
+    if (!fp) {
+       printf("File %s not found.\n", argv[1]);
+    }
+    fseek(fp, 0L, SEEK_END);
+    imageSize = ftell(fp);
+    fseek(fp, 0L, SEEK_SET);
+    sourceImage = malloc(imageSize);
+    assert(sourceImage != NULL);
+    s = fread(sourceImage, 1, imageSize, fp);
+    assert(s == imageSize);
+    fclose(fp);
+    bcm_host_init();
+    s = setupOpenMaxJpegDecoder(&pDecoder);
+    assert(s == 0);
+    s = decodeImage(pDecoder, sourceImage, imageSize);
+    assert(s == 0);
+    cleanup(pDecoder);
+    free(sourceImage);
+    return 0;
+}
diff --git a/host_applications/linux/apps/hello_pi/hello_jpeg/jpeg.h b/host_applications/linux/apps/hello_pi/hello_jpeg/jpeg.h
new file mode 100755 (executable)
index 0000000..f525dab
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+Copyright (c) 2012, Matt Ownby
+                    Anthong Sale
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _OPTION_H_
+#define _OPTION_H_
+
+/*
+Defines the methods for interacting with openmax il and ilclient to decode
+jpeg images from the camera
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "bcm_host.h"
+#include "ilclient.h"
+
+#define OMXJPEG_OK                  0
+#define OMXJPEG_ERROR_ILCLIENT_INIT    -1024
+#define OMXJPEG_ERROR_OMX_INIT         -1025
+#define OMXJPEG_ERROR_MEMORY         -1026
+#define OMXJPEG_ERROR_CREATING_COMP    -1027
+#define OMXJPEG_ERROR_WRONG_NO_PORTS   -1028
+#define OMXJPEG_ERROR_EXECUTING         -1029
+#define OMXJPEG_ERROR_NOSETTINGS   -1030
+
+typedef struct _OPENMAX_JPEG_DECODER OPENMAX_JPEG_DECODER;
+
+//this function run the boilerplate to setup the openmax components;
+int setupOpenMaxJpegDecoder(OPENMAX_JPEG_DECODER** decoder);
+
+//this function passed the jpeg image buffer in, and returns the decoded image
+int decodeImage(OPENMAX_JPEG_DECODER* decoder,
+              char* sourceImage, size_t imageSize);
+
+//this function cleans up the decoder.
+void cleanup(OPENMAX_JPEG_DECODER* decoder);
+
+#endif
+
diff --git a/host_applications/linux/apps/hello_pi/hello_mmal_encode/Makefile b/host_applications/linux/apps/hello_pi/hello_mmal_encode/Makefile
new file mode 100755 (executable)
index 0000000..98f83f6
--- /dev/null
@@ -0,0 +1,6 @@
+OBJS=mmal_encode.o
+BIN=hello_mmal_encode.bin
+LDFLAGS+=-lmmal -lmmal_core -lmmal_components -lmmal_util -lmmal_vc_client
+
+include ../Makefile.include
+
diff --git a/host_applications/linux/apps/hello_pi/hello_mmal_encode/mmal_encode.c b/host_applications/linux/apps/hello_pi/hello_mmal_encode/mmal_encode.c
new file mode 100755 (executable)
index 0000000..21ebf92
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+Copyright (C) 2016 RealVNC Limited. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its contributors
+may be used to endorse or promote products derived from this software without
+specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Image encoding example using MMAL
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <bcm_host.h>
+#include <interface/mmal/mmal.h>
+#include <interface/mmal/mmal_format.h>
+#include <interface/mmal/util/mmal_default_components.h>
+#include <interface/mmal/util/mmal_component_wrapper.h>
+#include <interface/mmal/util/mmal_util_params.h>
+
+// Format for test image
+const unsigned int WIDTH = 512;
+const unsigned int HEIGHT = 512;
+const MMAL_FOURCC_T INPUT_ENC = MMAL_ENCODING_RGBA;
+const unsigned int BYTESPP = 4;
+const uint32_t RED = 0xff;
+const uint32_t GREEN = 0xff << 8;
+const uint32_t BLUE = 0xff << 16;
+const uint32_t ALPHA = 0xff << 24;
+
+static MMAL_WRAPPER_T* encoder;
+static VCOS_SEMAPHORE_T sem;
+
+// This callback and the above semaphore is used when waiting for
+// data to be returned.
+static void mmalCallback(MMAL_WRAPPER_T* encoder)
+{
+   vcos_semaphore_post(&sem);
+}
+
+// Create a test input image in the supplied buffer consisting of 8 vertical bars of
+// white | black | red | green | blue | cyan | magenta | yellow
+void create_rgba_test_image(void* buf, unsigned int length, unsigned int stride)
+{
+   uint32_t* pixel = buf;
+   int i;
+   for (i=0; i<length/BYTESPP; ++i) {
+      switch ((i % stride) / (WIDTH / 8)) {
+      case 0: *pixel = RED | GREEN | BLUE; break;
+      case 1: *pixel = 0; break;
+      case 2: *pixel = RED; break;
+      case 3: *pixel = GREEN; break;
+      case 4: *pixel = BLUE; break;
+      case 5: *pixel = GREEN | BLUE; break;
+      case 6: *pixel = RED | BLUE; break;
+      case 7: *pixel = RED | GREEN; break;
+      }
+      *pixel |= ALPHA; // Full alpha
+      ++pixel;
+   }
+}
+
+// mmal_encode_test - Encode a test image and write to file
+void mmal_encode_test(MMAL_FOURCC_T encoding, // Encoding
+                      const char* filename) // File name
+{
+   MMAL_PORT_T* portIn;
+   MMAL_PORT_T* portOut;
+   MMAL_BUFFER_HEADER_T* in;
+   MMAL_BUFFER_HEADER_T* out;
+   MMAL_STATUS_T status;
+   int eos = 0;
+   int sent = 0;
+   int outputWritten = 0;
+   FILE* outFile;
+   int nw;
+  
+   printf("Encoding test image %s\n", filename);
+
+   // Configure input
+
+   portIn = encoder->input[0];
+   encoder->status = MMAL_SUCCESS;
+
+   if (portIn->is_enabled) {
+      if (mmal_wrapper_port_disable(portIn) != MMAL_SUCCESS) {
+         fprintf(stderr, "Failed to disable input port\n");
+         exit(1);
+      }
+   }
+
+   portIn->format->encoding = INPUT_ENC;
+   portIn->format->es->video.width = VCOS_ALIGN_UP(WIDTH, 32);
+   portIn->format->es->video.height = VCOS_ALIGN_UP(HEIGHT, 16);
+   portIn->format->es->video.crop.x = 0;
+   portIn->format->es->video.crop.y = 0;
+   portIn->format->es->video.crop.width = WIDTH;
+   portIn->format->es->video.crop.height = HEIGHT;
+   if (mmal_port_format_commit(portIn) != MMAL_SUCCESS) {
+      fprintf(stderr, "Failed to commit input port format\n");
+      exit(1);
+   }
+
+   portIn->buffer_size = portIn->buffer_size_recommended;
+   portIn->buffer_num = portIn->buffer_num_recommended;
+
+   if (mmal_wrapper_port_enable(portIn, MMAL_WRAPPER_FLAG_PAYLOAD_ALLOCATE)
+       != MMAL_SUCCESS) {
+      fprintf(stderr, "Failed to enable input port\n");
+      exit(1);
+   }
+
+   printf("- input %4.4s %ux%u\n",
+          (char*)&portIn->format->encoding,
+          portIn->format->es->video.width, portIn->format->es->video.height);
+
+   // Configure output
+  
+   portOut = encoder->output[0];
+
+   if (portOut->is_enabled) {
+      if (mmal_wrapper_port_disable(portOut) != MMAL_SUCCESS) {
+         fprintf(stderr, "Failed to disable output port\n");
+         exit(1);
+      }
+   }
+
+   portOut->format->encoding = encoding;
+   if (mmal_port_format_commit(portOut) != MMAL_SUCCESS) {
+      fprintf(stderr, "Failed to commit output port format\n");
+      exit(1);
+   }
+
+   mmal_port_parameter_set_uint32(portOut, MMAL_PARAMETER_JPEG_Q_FACTOR, 100);
+  
+   portOut->buffer_size = portOut->buffer_size_recommended;
+   portOut->buffer_num = portOut->buffer_num_recommended;
+
+   if (mmal_wrapper_port_enable(portOut, MMAL_WRAPPER_FLAG_PAYLOAD_ALLOCATE)
+       != MMAL_SUCCESS) {
+      fprintf(stderr, "Failed to enable output port\n");
+      exit(1);
+   }
+
+   printf("- output %4.4s\n", (char*)&encoding);
+  
+   // Perform the encoding
+
+   outFile = fopen(filename, "w");
+   if (!outFile) {
+      fprintf(stderr, "Failed to open file %s (%s)\n", filename, strerror(errno));
+      exit(1);
+   }
+  
+   while (!eos) {
+    
+      // Send output buffers to be filled with encoded image.
+      while (mmal_wrapper_buffer_get_empty(portOut, &out, 0) == MMAL_SUCCESS) {
+         if (mmal_port_send_buffer(portOut, out) != MMAL_SUCCESS) {
+            fprintf(stderr, "Failed to send buffer\n");
+            break;
+         }
+      }
+
+      // Send image to be encoded.
+      if (!sent && mmal_wrapper_buffer_get_empty(portIn, &in, 0) == MMAL_SUCCESS) {
+         printf("- sending %u bytes to encoder\n", in->alloc_size);
+         create_rgba_test_image(in->data, in->alloc_size, portIn->format->es->video.width);
+         in->length = in->alloc_size;
+         in->flags = MMAL_BUFFER_HEADER_FLAG_EOS;
+         if (mmal_port_send_buffer(portIn, in) != MMAL_SUCCESS) {
+            fprintf(stderr, "Failed to send buffer\n");
+            break;
+         }
+         sent = 1;
+      }
+
+      // Get filled output buffers.
+      status = mmal_wrapper_buffer_get_full(portOut, &out, 0);
+      if (status == MMAL_EAGAIN) {
+         // No buffer available, wait for callback and loop.
+         vcos_semaphore_wait(&sem);
+         continue;
+      } else if (status != MMAL_SUCCESS) {
+         fprintf(stderr, "Failed to get full buffer\n");
+         exit(1);
+      }
+
+      printf("- received %i bytes\n", out->length);
+      eos = out->flags & MMAL_BUFFER_HEADER_FLAG_EOS;
+
+      nw = fwrite(out->data, 1, out->length, outFile);
+      if (nw != out->length) {
+         fprintf(stderr, "Failed to write complete buffer\n");
+         exit(1);
+      }
+      outputWritten += nw;
+    
+      mmal_buffer_header_release(out);
+   }
+
+   mmal_port_flush(portOut);
+
+   fclose(outFile);
+   printf("- written %u bytes to %s\n\n", outputWritten, filename);
+}
+
+
+int main(int argc, const char** argv)
+{
+   bcm_host_init();
+
+   if (vcos_semaphore_create(&sem, "encoder sem", 0) != VCOS_SUCCESS) {
+      fprintf(stderr, "Failed to create semaphore\n");
+      exit(1);
+   }
+
+   if (mmal_wrapper_create(&encoder, MMAL_COMPONENT_DEFAULT_IMAGE_ENCODER)
+       != MMAL_SUCCESS) {
+      fprintf(stderr, "Failed to create mmal component\n");
+      exit(1);
+   }
+   encoder->callback = mmalCallback;
+  
+   // Perform test encodings in various formats
+   mmal_encode_test(MMAL_ENCODING_PNG, "out.png");
+   mmal_encode_test(MMAL_ENCODING_JPEG, "out.jpg");
+   mmal_encode_test(MMAL_ENCODING_GIF, "out.gif");
+   mmal_encode_test(MMAL_ENCODING_BMP, "out.bmp");
+
+   mmal_wrapper_destroy(encoder);
+   vcos_semaphore_delete(&sem);
+
+   return 0;
+}
+
+
diff --git a/host_applications/linux/apps/hello_pi/hello_teapot/CMakeLists.txt b/host_applications/linux/apps/hello_pi/hello_teapot/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..cdb8413
--- /dev/null
@@ -0,0 +1,8 @@
+set(EXEC hello_teapot.bin)
+set(SRCS triangle.c video.c models.c)
+
+add_executable(${EXEC} ${SRCS})
+target_link_libraries(${EXEC} ${HELLO_PI_LIBS})
+
+install(TARGETS ${EXEC}
+        RUNTIME DESTINATION bin)
diff --git a/host_applications/linux/apps/hello_pi/hello_teapot/Makefile b/host_applications/linux/apps/hello_pi/hello_teapot/Makefile
new file mode 100755 (executable)
index 0000000..0ebb234
--- /dev/null
@@ -0,0 +1,7 @@
+OBJS=triangle.o video.o models.o
+BIN=hello_teapot.bin
+LDFLAGS+=-lilclient
+
+include ../Makefile.include
+
+
diff --git a/host_applications/linux/apps/hello_pi/hello_teapot/README.md b/host_applications/linux/apps/hello_pi/hello_teapot/README.md
new file mode 100755 (executable)
index 0000000..36fafcf
--- /dev/null
@@ -0,0 +1,4 @@
+hello_videocube
+===============
+
+Sample for Raspberry Pi that uses egl_render to display video on an animated cube.
\ No newline at end of file
diff --git a/host_applications/linux/apps/hello_pi/hello_teapot/cube_texture_and_coords.h b/host_applications/linux/apps/hello_pi/hello_teapot/cube_texture_and_coords.h
new file mode 100755 (executable)
index 0000000..7dd30a9
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Spatial coordinates for the cube
+
+static const GLbyte quadx[6*4*3] = {
+   /* FRONT */
+   -10, -10,  10,
+   10, -10,  10,
+   -10,  10,  10,
+   10,  10,  10,
+
+   /* BACK */
+   -10, -10, -10,
+   -10,  10, -10,
+   10, -10, -10,
+   10,  10, -10,
+
+   /* LEFT */
+   -10, -10,  10,
+   -10,  10,  10,
+   -10, -10, -10,
+   -10,  10, -10,
+
+   /* RIGHT */
+   10, -10, -10,
+   10,  10, -10,
+   10, -10,  10,
+   10,  10,  10,
+
+   /* TOP */
+   -10,  10,  10,
+   10,  10,  10,
+   -10,  10, -10,
+   10,  10, -10,
+
+   /* BOTTOM */
+   -10, -10,  10,
+   -10, -10, -10,
+   10, -10,  10,
+   10, -10, -10,
+};
+
+/** Texture coordinates for the quad. */
+static const GLfloat texCoords[6 * 4 * 2] = {
+   0.f,  0.f,
+   0.f,  1.f,
+   1.f,  0.f,
+   1.f,  1.f,
+
+   0.f,  0.f,
+   0.f,  1.f,
+   1.f,  0.f,
+   1.f,  1.f,
+
+   0.f,  0.f,
+   0.f,  1.f,
+   1.f,  0.f,
+   1.f,  1.f,
+
+   0.f,  0.f,
+   0.f,  1.f,
+   1.f,  0.f,
+   1.f,  1.f,
+
+   0.f,  0.f,
+   0.f,  1.f,
+   1.f,  0.f,
+   1.f,  1.f,
+
+   0.f,  0.f,
+   0.f,  1.f,
+   1.f,  0.f,
+   1.f,  1.f
+};
+
diff --git a/host_applications/linux/apps/hello_pi/hello_teapot/models.c b/host_applications/linux/apps/hello_pi/hello_teapot/models.c
new file mode 100755 (executable)
index 0000000..a5af141
--- /dev/null
@@ -0,0 +1,515 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <math.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#include "GLES/gl.h"
+#include "EGL/egl.h"
+#include "EGL/eglext.h"
+#include "models.h"
+
+#define VMCS_RESOURCE(a,b) (b)
+
+/******************************************************************************
+Private typedefs, macros and constants
+******************************************************************************/
+
+enum {VBO_VERTEX, VBO_NORMAL, VBO_TEXTURE, VBO_MAX};
+#define MAX_MATERIALS 4
+#define MAX_MATERIAL_NAME 32
+
+typedef struct wavefront_material_s {
+   GLuint vbo[VBO_MAX];
+   int numverts;
+   char name[MAX_MATERIAL_NAME];
+   GLuint texture;
+} WAVEFRONT_MATERIAL_T;
+
+typedef struct wavefront_model_s {
+   WAVEFRONT_MATERIAL_T material[MAX_MATERIALS];
+   int num_materials;
+   GLuint texture;
+} WAVEFRONT_MODEL_T;
+
+
+/******************************************************************************
+Static Data
+******************************************************************************/
+
+/******************************************************************************
+Static Function Declarations
+******************************************************************************/
+
+/******************************************************************************
+Static Function Definitions
+******************************************************************************/
+
+static void create_vbo(GLenum type, GLuint *vbo, int size, void *data)
+{
+   glGenBuffers(1, vbo);
+   vc_assert(*vbo);
+   glBindBuffer(type, *vbo);
+   glBufferData(type, size, data, GL_STATIC_DRAW);
+   glBindBuffer(type, 0);     
+}
+
+
+static void destroy_vbo(GLuint *vbo)
+{
+   glDeleteBuffers(1, vbo);
+   *vbo = 0;
+}
+
+#define MAX_VERTICES 100000
+static void *allocbuffer(int size)
+{
+   return malloc(size);
+}
+
+static void freebuffer(void *p)
+{
+   free (p);
+}
+
+static void centre_and_rescale(float *verts, int numvertices)
+{
+   float cx=0.0f, cy=0.0f, cz=0.0f, scale=0.0f;
+   float minx=0.0f, miny=0.0f, minz=0.0f;
+   float maxx=0.0f, maxy=0.0f, maxz=0.0f;
+   int i;
+   float *v = verts;
+   minx = maxx = verts[0];
+   miny = maxy = verts[1];
+   minz = maxz = verts[2];
+   for (i=0; i<numvertices; i++) {
+      float x = *v++;
+      float y = *v++;
+      float z = *v++;
+      minx = vcos_min(minx, x);
+      miny = vcos_min(miny, y);
+      minz = vcos_min(minz, z);
+      maxx = vcos_max(maxx, x);
+      maxy = vcos_max(maxy, y);
+      maxz = vcos_max(maxz, z);
+      cx += x;
+      cy += y;
+      cz += z;
+   }
+   cx /= (float)numvertices;
+   cy /= (float)numvertices;
+   cz /= (float)numvertices;
+   scale = 3.0f / (maxx-minx + maxy-miny + maxz-minz);
+   v = verts;
+   for (i=0; i<numvertices; i++) {
+      *v = (*v-cx) * scale; v++;
+      *v = (*v-cy) * scale; v++;
+      *v = (*v-cz) * scale; v++;
+   }
+}
+
+static void renormalise(float *verts, int numvertices)
+{
+   int i;
+   float *v = verts;
+   for (i=0;i<numvertices; i++) {
+      float x = v[0];
+      float y = v[1];
+      float z = v[2];
+      float scale = 1.0f/sqrtf(x*x + y*y + z*z);
+      *v++ = x * scale;
+      *v++ = y * scale;
+      *v++ = z * scale;
+   }
+}
+
+static void deindex(float *dst, const float *src, const unsigned short *indexes, GLsizei size, GLsizei count)
+{
+   int i;
+   for (i=0; i<count; i++) {
+      int ind = size * (indexes[0]-1);
+      *dst++ = src[ind + 0];
+      *dst++ = src[ind + 1];
+      // todo: optimise - move out of loop
+      if (size >= 3) *dst++ = src[ind + 2];
+      indexes += 3;
+   }
+}
+
+int draw_wavefront(MODEL_T m, GLuint texture)
+{
+   int i;
+   WAVEFRONT_MODEL_T *model = (WAVEFRONT_MODEL_T *)m;
+
+   for (i=0; i<model->num_materials; i++) {
+      WAVEFRONT_MATERIAL_T *mat = model->material + i;
+      if (mat->texture == -1) continue;
+      glBindTexture(GL_TEXTURE_2D, mat->texture ? mat->texture:texture);
+      if (mat->vbo[VBO_VERTEX]) {
+         glBindBuffer(GL_ARRAY_BUFFER, mat->vbo[VBO_VERTEX]);
+         glVertexPointer(3, GL_FLOAT, 0, NULL);
+      }
+      if (mat->vbo[VBO_NORMAL]) {   
+         glEnableClientState(GL_NORMAL_ARRAY);
+         glBindBuffer(GL_ARRAY_BUFFER, mat->vbo[VBO_NORMAL]);
+         glNormalPointer(GL_FLOAT, 0, NULL);
+      } else {
+         glDisableClientState(GL_NORMAL_ARRAY);
+      }
+      if (mat->vbo[VBO_TEXTURE]) {   
+         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+         glBindBuffer(GL_ARRAY_BUFFER, mat->vbo[VBO_TEXTURE]);
+         glTexCoordPointer(2, GL_FLOAT, 0, NULL);
+      } else {
+         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+      }
+      glDrawArrays(GL_TRIANGLES, 0, mat->numverts);
+   }
+   glBindBuffer(GL_ARRAY_BUFFER, 0);
+   return 0;
+}
+
+struct wavefront_model_loading_s {
+   unsigned short material_index[MAX_MATERIALS];
+   int num_materials;
+   int numv, numt, numn, numf;
+   unsigned int data[0];
+};
+
+static int load_wavefront_obj(const char *modelname, WAVEFRONT_MODEL_T *model, struct wavefront_model_loading_s *m)
+{
+   char line[256+1];
+   unsigned short pp[54+1];
+   FILE *fp;
+   int i, valid;
+   float *qv = (float *)m->data;
+   float *qt = (float *)m->data + 3 * MAX_VERTICES;
+   float *qn = (float *)m->data + (3+2) * MAX_VERTICES;
+   unsigned short *qf = (unsigned short *)((float *)m->data + (3+2+3) * MAX_VERTICES);
+   float *pv = qv, *pt = qt, *pn = qn;
+   unsigned short *pf = qf;
+   fp = fopen(modelname, "r");
+   if (!fp) return -1;
+
+   m->num_materials = 0;
+   m->material_index[0] = 0;
+
+   valid = fread(line, 1, sizeof(line)-1, fp);
+
+   while (valid > 0) {
+      char *s, *end = line;
+      
+      while((end-line < valid) && *end != '\n' && *end != '\r')
+         end++;
+      *end++ = 0;
+
+      if((end-line < valid) && *end != '\n' && *end != '\r')
+         *end++ = 0;
+
+      s = line;
+
+      if (s[strlen(s)-1] == 10) s[strlen(s)-1]=0;
+      switch (s[0]) {
+      case '#': break; // comment
+      case '\r': case '\n': case '\0': break; // blank line
+      case 'm': vc_assert(strncmp(s, "mtllib", sizeof "mtllib"-1)==0); break;
+      case 'o': break;
+      case 'u': 
+         if (sscanf(s, "usemtl %s", /*MAX_MATERIAL_NAME-1, */model->material[m->num_materials].name) == 1) {
+            if (m->num_materials < MAX_MATERIALS) {
+               if (m->num_materials > 0 && ((pf-qf)/3 == m->material_index[m->num_materials-1] || strcmp(model->material[m->num_materials-1].name, model->material[m->num_materials].name)==0)) {
+                  strcpy(model->material[m->num_materials-1].name, model->material[m->num_materials].name);
+                  m->num_materials--;
+               } else
+               m->material_index[m->num_materials] = (pf-qf)/3;
+               m->num_materials++;
+            }
+         } else { printf(s); vc_assert(0); }
+         break;
+      case 'g': vc_assert(strncmp(s, "g ", sizeof "g "-1)==0); break;
+      case 's': vc_assert(strncmp(s, "s ", sizeof "s "-1)==0); break;
+      case 'v': case 'f':
+         if (sscanf(s, "v %f %f %f", pv+0, pv+1, pv+2) == 3) {
+            pv += 3;
+         } else if (sscanf(s, "vt %f %f", pt+0, pt+1) == 2) {
+            pt += 2;
+         } else if (sscanf(s, "vn %f %f %f", pn+0, pn+1, pn+2) == 3) {
+            pn += 3;
+         } else if (i = sscanf(s, "f"" %hu//%hu %hu//%hu %hu//%hu %hu//%hu %hu//%hu %hu//%hu"
+                                     " %hu//%hu %hu//%hu %hu//%hu %hu//%hu %hu//%hu %hu//%hu"
+                                     " %hu//%hu %hu//%hu %hu//%hu %hu//%hu %hu//%hu %hu//%hu %hu",
+               pp+ 0, pp+ 1, pp+ 2, pp+ 3, pp+ 4, pp+ 5, pp+ 6, pp+ 7, pp+ 8, pp+ 9, pp+10, pp+11, 
+               pp+12, pp+13, pp+14, pp+15, pp+16, pp+17, pp+18, pp+19, pp+20, pp+21, pp+22, pp+23, 
+               pp+24, pp+25, pp+26, pp+27, pp+28, pp+29, pp+30, pp+32, pp+32, pp+33, pp+34, pp+35, pp+36), i >= 6) {
+            int poly = i/2;
+            //vc_assert(i < countof(pp)); // may need to increment poly count and pp array
+            for (i=1; i<poly-1; i++) {
+               *pf++ = pp[0]; *pf++ = 0; *pf++ = pp[1];
+               *pf++ = pp[2*i+0]; *pf++ = 0; *pf++ = pp[2*i+1];
+               *pf++ = pp[2*(i+1)+0]; *pf++ = 0; *pf++ = pp[2*(i+1)+1];
+            }
+         } else if (i = sscanf(s, "f"" %hu/%hu %hu/%hu %hu/%hu %hu/%hu %hu/%hu %hu/%hu"
+                                     " %hu/%hu %hu/%hu %hu/%hu %hu/%hu %hu/%hu %hu/%hu"
+                                     " %hu/%hu %hu/%hu %hu/%hu %hu/%hu %hu/%hu %hu/%hu %hu",
+               pp+ 0, pp+ 1, pp+ 2, pp+ 3, pp+ 4, pp+ 5, pp+ 6, pp+ 7, pp+ 8, pp+ 9, pp+10, pp+11, 
+               pp+12, pp+13, pp+14, pp+15, pp+16, pp+17, pp+18, pp+19, pp+20, pp+21, pp+22, pp+23, 
+               pp+24, pp+25, pp+26, pp+27, pp+28, pp+29, pp+30, pp+32, pp+32, pp+33, pp+34, pp+35, pp+36), i >= 6) {
+            int poly = i/2;
+            //vc_assert(i < countof(pp); // may need to increment poly count and pp array
+            for (i=1; i<poly-1; i++) {
+               *pf++ = pp[0]; *pf++ = pp[1]; *pf++ = 0;
+               *pf++ = pp[2*i+0]; *pf++ = pp[2*i+1]; *pf++ = 0;
+               *pf++ = pp[2*(i+1)+0]; *pf++ = pp[2*(i+1)+1]; *pf++ = 0;
+            }
+         } else if (i = sscanf(s, "f"" %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu"
+                                     " %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu"
+                                     " %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu",
+               pp+ 0, pp+ 1, pp+ 2, pp+ 3, pp+ 4, pp+ 5, pp+ 6, pp+ 7, pp+ 8, pp+ 9, pp+10, pp+11, pp+12, pp+13, pp+14, pp+15, pp+16, pp+17, 
+               pp+18, pp+19, pp+20, pp+21, pp+22, pp+23, pp+24, pp+25, pp+26, pp+27, pp+28, pp+29, pp+30, pp+32, pp+32, pp+33, pp+34, pp+35, 
+               pp+36, pp+37, pp+38, pp+39, pp+40, pp+41, pp+42, pp+43, pp+44, pp+45, pp+46, pp+47, pp+48, pp+49, pp+50, pp+51, pp+52, pp+53, pp+54), i >= 9) {
+            int poly = i/3;
+            //vc_assert(i < countof(pp); // may need to increment poly count and pp array
+            for (i=1; i<poly-1; i++) {
+               *pf++ = pp[0]; *pf++ = pp[1]; *pf++ = pp[2];
+               *pf++ = pp[3*i+0]; *pf++ = pp[3*i+1]; *pf++ = pp[3*i+2];
+               *pf++ = pp[3*(i+1)+0]; *pf++ = pp[3*(i+1)+1]; *pf++ = pp[3*(i+1)+2];
+            }
+         } else { printf(s); vc_assert(0); }
+         break;
+      default: 
+         printf("%02x %02x %s", s[0], s[1], s); vc_assert(0); break;
+      }
+
+      // shift down read characters and read some more into the end
+      // if we didn't find a newline, then end is one off the end of our
+      // line, so end-line will be valid+1
+      i = end-line > valid ? valid : end-line;
+      memmove(line, end, valid - i);
+      valid -= i;
+      valid += fread(line+valid, 1, sizeof(line)-1-valid, fp);
+   }
+   fclose(fp);
+
+   if (m->num_materials==0) m->material_index[m->num_materials++] = 0;
+
+   centre_and_rescale(qv, (pv-qv)/3);
+   renormalise(qn, (pn-qn)/3);
+   //centre_and_rescale2(qt, (pt-qt)/2);
+
+   m->numv = pv-qv;
+   m->numt = pt-qt;
+   m->numn = pn-qn;
+   m->numf = pf-qf;
+
+   // compress array
+   //memcpy((float *)m->data, (float *)m->data, m->numv * sizeof *qv); - nop
+   memcpy((float *)m->data + m->numv, (float *)m->data + 3 * MAX_VERTICES, m->numt * sizeof *qt);
+   memcpy((float *)m->data + m->numv + m->numt,(float *) m->data + (3 + 2) * MAX_VERTICES, m->numn * sizeof *qn);
+   memcpy((float *)m->data + m->numv + m->numt + m->numn, (float *)m->data + (3 + 2 + 3) * MAX_VERTICES, m->numf * sizeof *qf);
+
+   return 0;
+}
+
+static int load_wavefront_dat(const char *modelname, WAVEFRONT_MODEL_T *model, struct wavefront_model_loading_s *m)
+{
+   FILE *fp;
+   int s;
+   const int size = sizeof *m + 
+      sizeof(float)*(3+2+3)*MAX_VERTICES +   // 3 vertices + 2 textures + 3 normals
+      sizeof(unsigned short)*3*MAX_VERTICES; //each face has 9 vertices
+
+   fp = fopen(modelname, "r");
+   if (!fp) return -1;
+   s = fread(m, 1, size, fp);
+   if (s < 0) return -1;
+   fclose(fp);
+   return 0;
+}
+
+MODEL_T load_wavefront(const char *modelname, const char *texturename)
+{
+   WAVEFRONT_MODEL_T *model;
+   float *temp, *qv, *qt, *qn;
+   unsigned short *qf;
+   int i;
+   int numverts = 0, offset = 0;
+   struct wavefront_model_loading_s *m;
+   int s=-1;
+   char modelname_obj[128];
+   model = malloc(sizeof *model);
+   if (!model || !modelname) return NULL;
+   memset (model, 0, sizeof *model);
+   model->texture = 0; //load_texture(texturename);
+   m = allocbuffer(sizeof *m + 
+      sizeof(float)*(3+2+3)*MAX_VERTICES +    // 3 vertices + 2 textures + 3 normals
+      sizeof(unsigned short)*3*MAX_VERTICES); //each face has 9 vertices
+   if (!m) return 0;
+
+   if (strlen(modelname) + 5 <= sizeof modelname_obj) {
+      strcpy(modelname_obj, modelname);
+      strcat(modelname_obj, ".dat");
+      s = load_wavefront_dat(modelname_obj, model, m);
+   }
+   if (s==0) {}
+   else if (strncmp(modelname + strlen(modelname) - 4, ".obj", 4) == 0) {
+      #ifdef DUMP_OBJ_DAT
+      int size;
+      FILE *fp;
+      #endif
+      s = load_wavefront_obj(modelname, model, m);
+      #ifdef DUMP_OBJ_DAT
+      strcpy(modelname_obj, modelname);
+      strcat(modelname_obj, ".dat");
+      size = sizeof *m + 
+         sizeof(float)*(3*m->numv+2*m->numt+3*m->numn) +  // 3 vertices + 2 textures + 3 normals
+         sizeof(unsigned short)*3*m->numf;                //each face has 9 vertices
+      fp = host_file_open(modelname_obj, "w");
+      fwrite(m, 1, size, fp);
+      fclose(fp);
+      #endif
+   } else if (strncmp(modelname + strlen(modelname) - 4, ".dat", 4) == 0) {
+      s = load_wavefront_dat(modelname, model, m);
+   }
+   if (s != 0) return 0;
+
+   qv = (float *)(m->data);
+   qt = (float *)(m->data + m->numv);
+   qn = (float *)(m->data + m->numv + m->numt);
+   qf = (unsigned short *)(m->data + m->numv + m->numt + m->numn);
+
+   numverts = m->numf/3;
+   vc_assert(numverts <= MAX_VERTICES);
+
+   temp = allocbuffer(3*numverts*sizeof *temp);
+   for (i=0; i<m->num_materials; i++) {
+      WAVEFRONT_MATERIAL_T *mat = model->material + i;
+      mat->numverts = i < m->num_materials-1 ? m->material_index[i+1]-m->material_index[i] : numverts - m->material_index[i];
+      // vertex, texture, normal
+      deindex(temp, qv, qf+3*offset+0, 3, mat->numverts);
+      create_vbo(GL_ARRAY_BUFFER, mat->vbo+VBO_VERTEX, 3 * mat->numverts * sizeof *qv, temp); // 3
+   
+      deindex(temp, qt, qf+3*offset+1, 2, mat->numverts);
+      create_vbo(GL_ARRAY_BUFFER, mat->vbo+VBO_TEXTURE, 2 * mat->numverts * sizeof *qt, temp); // 2
+   
+      deindex(temp, qn, qf+3*offset+2, 3, mat->numverts);
+      create_vbo(GL_ARRAY_BUFFER, mat->vbo+VBO_NORMAL, 3 * mat->numverts * sizeof *qn, temp); // 3
+      offset += mat->numverts;
+      mat->texture = model->texture;
+   }
+   model->num_materials = m->num_materials;
+   vc_assert(offset == numverts);
+   freebuffer(temp);
+   freebuffer(m);
+   return (MODEL_T)model;
+}
+
+void unload_wavefront(MODEL_T m)
+{
+   WAVEFRONT_MODEL_T *model = (WAVEFRONT_MODEL_T *)m;
+   int i;
+   for (i=0; i<model->num_materials; i++) {
+      WAVEFRONT_MATERIAL_T *mat = model->material + i;
+      if (mat->vbo[VBO_VERTEX])
+         destroy_vbo(mat->vbo+VBO_VERTEX);
+      if (mat->vbo[VBO_TEXTURE])
+         destroy_vbo(mat->vbo+VBO_TEXTURE);
+      if (mat->vbo[VBO_NORMAL])
+         destroy_vbo(mat->vbo+VBO_NORMAL);
+   }
+}
+
+// create a cube model that looks like a wavefront model, 
+MODEL_T cube_wavefront(void)
+{
+   static const float qv[] = {
+    -0.5f, -0.5f,  0.5f,
+    -0.5f, -0.5f, -0.5f,
+     0.5f, -0.5f, -0.5f,
+     0.5f, -0.5f,  0.5f,
+    -0.5f,  0.5f,  0.5f,
+     0.5f,  0.5f,  0.5f,
+     0.5f,  0.5f, -0.5f,
+    -0.5f,  0.5f, -0.5f,
+   };
+   
+   static const float qn[] = {
+     0.0f, -1.0f, -0.0f,
+     0.0f,  1.0f, -0.0f,
+     0.0f,  0.0f,  1.0f,
+     1.0f,  0.0f, -0.0f,
+     0.0f,  0.0f, -1.0f,
+    -1.0f,  0.0f, -0.0f,
+   };
+   
+   static const float qt[] = {
+    1.0f, 0.0f,
+    1.0f, 1.0f,
+    0.0f, 1.0f,
+    0.0f, 0.0f,
+   };
+   
+   static const unsigned short qf[] = {
+    1,1,1, 2,2,1, 3,3,1,
+    3,3,1, 4,4,1, 1,1,1,
+    5,4,2, 6,1,2, 7,2,2,
+    7,2,2, 8,3,2, 5,4,2,
+    1,4,3, 4,1,3, 6,2,3,
+    6,2,3, 5,3,3, 1,4,3,
+    4,4,4, 3,1,4, 7,2,4,
+    7,2,4, 6,3,4, 4,4,4,
+    3,4,5, 2,1,5, 8,2,5,
+    8,2,5, 7,3,5, 3,4,5,
+    2,4,6, 1,1,6, 5,2,6,
+    5,2,6, 8,3,6, 2,4,6,
+   };
+   WAVEFRONT_MODEL_T *model = malloc(sizeof *model);
+   if (model) {
+      WAVEFRONT_MATERIAL_T *mat = model->material;
+      float *temp;
+      const int offset = 0;
+      memset(model, 0, sizeof *model);
+
+      temp = allocbuffer(3*MAX_VERTICES*sizeof *temp);
+      mat->numverts = countof(qf)/3;
+      // vertex, texture, normal
+      deindex(temp, qv, qf+3*offset+0, 3, mat->numverts);
+      create_vbo(GL_ARRAY_BUFFER, mat->vbo+VBO_VERTEX, 3 * mat->numverts * sizeof *qv, temp); // 3
+
+      deindex(temp, qt, qf+3*offset+1, 2, mat->numverts);
+      create_vbo(GL_ARRAY_BUFFER, mat->vbo+VBO_TEXTURE, 2 * mat->numverts * sizeof *qt, temp); // 2
+
+      deindex(temp, qn, qf+3*offset+2, 3, mat->numverts);
+      create_vbo(GL_ARRAY_BUFFER, mat->vbo+VBO_NORMAL, 3 * mat->numverts * sizeof *qn, temp); // 3
+
+      freebuffer(temp);
+      model->num_materials = 1;
+   }
+   return (MODEL_T)model;
+}
+
+
diff --git a/host_applications/linux/apps/hello_pi/hello_teapot/models.h b/host_applications/linux/apps/hello_pi/hello_teapot/models.h
new file mode 100755 (executable)
index 0000000..4a6cbd0
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MODELS_T
+#define MODELS_T
+typedef struct opqaue_model_s * MODEL_T;
+
+MODEL_T load_wavefront(const char *modelname, const char *texturename);
+MODEL_T cube_wavefront(void);
+void unload_wavefront(MODEL_T m);
+int draw_wavefront(MODEL_T m, GLuint texture);
+#endif
diff --git a/host_applications/linux/apps/hello_pi/hello_teapot/teapot.obj.dat b/host_applications/linux/apps/hello_pi/hello_teapot/teapot.obj.dat
new file mode 100755 (executable)
index 0000000..584ab3d
Binary files /dev/null and b/host_applications/linux/apps/hello_pi/hello_teapot/teapot.obj.dat differ
diff --git a/host_applications/linux/apps/hello_pi/hello_teapot/triangle.c b/host_applications/linux/apps/hello_pi/hello_teapot/triangle.c
new file mode 100755 (executable)
index 0000000..8b9c2dd
--- /dev/null
@@ -0,0 +1,468 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+Copyright (c) 2012, OtherCrashOverride
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// A rotating cube rendered with OpenGL|ES. Three images used as textures on the cube faces.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include "bcm_host.h"
+
+#include "GLES/gl.h"
+#include "EGL/egl.h"
+#include "EGL/eglext.h"
+
+#include "cube_texture_and_coords.h"
+#include "models.h"
+#include "triangle.h"
+#include <pthread.h>
+
+
+#define PATH "./"
+
+#define IMAGE_SIZE_WIDTH 1920
+#define IMAGE_SIZE_HEIGHT 1080
+
+#ifndef M_PI
+   #define M_PI 3.141592654
+#endif
+  
+
+typedef struct
+{
+   uint32_t screen_width;
+   uint32_t screen_height;
+// OpenGL|ES objects
+   EGLDisplay display;
+   EGLSurface surface;
+   EGLContext context;
+   GLuint tex;
+// model rotation vector and direction
+   GLfloat rot_angle_x_inc;
+   GLfloat rot_angle_y_inc;
+   GLfloat rot_angle_z_inc;
+// current model rotation angles
+   GLfloat rot_angle_x;
+   GLfloat rot_angle_y;
+   GLfloat rot_angle_z;
+// current distance from camera
+   GLfloat distance;
+   GLfloat distance_inc;
+   MODEL_T model;
+} CUBE_STATE_T;
+
+static void init_ogl(CUBE_STATE_T *state);
+static void init_model_proj(CUBE_STATE_T *state);
+static void reset_model(CUBE_STATE_T *state);
+static GLfloat inc_and_wrap_angle(GLfloat angle, GLfloat angle_inc);
+static GLfloat inc_and_clip_distance(GLfloat distance, GLfloat distance_inc);
+static void redraw_scene(CUBE_STATE_T *state);
+static void update_model(CUBE_STATE_T *state);
+static void init_textures(CUBE_STATE_T *state);
+static void exit_func(void);
+static volatile int terminate;
+static CUBE_STATE_T _state, *state=&_state;
+
+static void* eglImage = 0;
+static pthread_t thread1;
+
+
+/***********************************************************
+ * Name: init_ogl
+ *
+ * Arguments:
+ *       CUBE_STATE_T *state - holds OGLES model info
+ *
+ * Description: Sets the display, OpenGL|ES context and screen stuff
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void init_ogl(CUBE_STATE_T *state)
+{
+   int32_t success = 0;
+   EGLBoolean result;
+   EGLint num_config;
+
+   static EGL_DISPMANX_WINDOW_T nativewindow;
+
+   DISPMANX_ELEMENT_HANDLE_T dispman_element;
+   DISPMANX_DISPLAY_HANDLE_T dispman_display;
+   DISPMANX_UPDATE_HANDLE_T dispman_update;
+   VC_RECT_T dst_rect;
+   VC_RECT_T src_rect;
+
+   static const EGLint attribute_list[] =
+   {
+      EGL_RED_SIZE, 8,
+      EGL_GREEN_SIZE, 8,
+      EGL_BLUE_SIZE, 8,
+      EGL_ALPHA_SIZE, 8,
+      EGL_DEPTH_SIZE, 16,
+      EGL_SAMPLES, 4,
+      EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+      EGL_NONE
+   };
+   
+   EGLConfig config;
+
+   // get an EGL display connection
+   state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+   assert(state->display!=EGL_NO_DISPLAY);
+
+   // initialize the EGL display connection
+   result = eglInitialize(state->display, NULL, NULL);
+   assert(EGL_FALSE != result);
+
+   // get an appropriate EGL frame buffer configuration
+   // this uses a BRCM extension that gets the closest match, rather than standard which returns anything that matches
+   result = eglSaneChooseConfigBRCM(state->display, attribute_list, &config, 1, &num_config);
+   assert(EGL_FALSE != result);
+
+   // create an EGL rendering context
+   state->context = eglCreateContext(state->display, config, EGL_NO_CONTEXT, NULL);
+   assert(state->context!=EGL_NO_CONTEXT);
+
+   // create an EGL window surface
+   success = graphics_get_display_size(0 /* LCD */, &state->screen_width, &state->screen_height);
+   assert( success >= 0 );
+
+   dst_rect.x = 0;
+   dst_rect.y = 0;
+   dst_rect.width = state->screen_width;
+   dst_rect.height = state->screen_height;
+      
+   src_rect.x = 0;
+   src_rect.y = 0;
+   src_rect.width = state->screen_width << 16;
+   src_rect.height = state->screen_height << 16;        
+
+   dispman_display = vc_dispmanx_display_open( 0 /* LCD */);
+   dispman_update = vc_dispmanx_update_start( 0 );
+         
+   dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display,
+      0/*layer*/, &dst_rect, 0/*src*/,
+      &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, 0/*transform*/);
+      
+   nativewindow.element = dispman_element;
+   nativewindow.width = state->screen_width;
+   nativewindow.height = state->screen_height;
+   vc_dispmanx_update_submit_sync( dispman_update );
+      
+   state->surface = eglCreateWindowSurface( state->display, config, &nativewindow, NULL );
+   assert(state->surface != EGL_NO_SURFACE);
+
+   // connect the context to the surface
+   result = eglMakeCurrent(state->display, state->surface, state->surface, state->context);
+   assert(EGL_FALSE != result);
+
+   // Set background color and clear buffers
+   glClearColor((0.3922f+7*0.5f)/8, (0.1176f+7*0.5f)/8, (0.5882f+7*0.5f)/8, 1.0f);
+
+   // Enable back face culling.
+   glEnable(GL_CULL_FACE);
+
+   glEnable(GL_DEPTH_TEST);
+   glClearDepthf(1.0);
+   glDepthFunc(GL_LEQUAL);
+
+   float noAmbient[] = {1.0f, 1.0f, 1.0f, 1.0f};
+   glLightfv(GL_LIGHT0, GL_AMBIENT, noAmbient);
+   glEnable(GL_LIGHT0);
+   glEnable(GL_LIGHTING);
+}
+
+/***********************************************************
+ * Name: init_model_proj
+ *
+ * Arguments:
+ *       CUBE_STATE_T *state - holds OGLES model info
+ *
+ * Description: Sets the OpenGL|ES model to default values
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void init_model_proj(CUBE_STATE_T *state)
+{
+   float nearp = 0.1f;
+   float farp = 500.0f;
+   float hht;
+   float hwd;
+
+   glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
+
+   glViewport(0, 0, (GLsizei)state->screen_width, (GLsizei)state->screen_height);
+      
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+
+   hht = nearp * (float)tan(45.0 / 2.0 / 180.0 * M_PI);
+   hwd = hht * (float)state->screen_width / (float)state->screen_height;
+
+   glFrustumf(-hwd, hwd, -hht, hht, nearp, farp);
+   
+   glEnableClientState( GL_VERTEX_ARRAY );
+
+   reset_model(state);
+}
+
+/***********************************************************
+ * Name: reset_model
+ *
+ * Arguments:
+ *       CUBE_STATE_T *state - holds OGLES model info
+ *
+ * Description: Resets the Model projection and rotation direction
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void reset_model(CUBE_STATE_T *state)
+{
+   // reset model position
+   glMatrixMode(GL_MODELVIEW);
+
+   // reset model rotation
+   state->rot_angle_x = 45.f; state->rot_angle_y = 30.f; state->rot_angle_z = 0.f;
+   state->rot_angle_x_inc = 0.5f; state->rot_angle_y_inc = 0.5f; state->rot_angle_z_inc = 0.f;
+   state->distance = 1.2f*1.5f;
+}
+
+/***********************************************************
+ * Name: update_model
+ *
+ * Arguments:
+ *       CUBE_STATE_T *state - holds OGLES model info
+ *
+ * Description: Updates model projection to current position/rotation
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void update_model(CUBE_STATE_T *state)
+{
+   // update position
+   state->rot_angle_x = inc_and_wrap_angle(state->rot_angle_x, state->rot_angle_x_inc);
+   state->rot_angle_y = inc_and_wrap_angle(state->rot_angle_y, state->rot_angle_y_inc);
+   state->rot_angle_z = inc_and_wrap_angle(state->rot_angle_z, state->rot_angle_z_inc);
+   state->distance    = inc_and_clip_distance(state->distance, state->distance_inc);
+
+   glLoadIdentity();
+   // move camera back to see the cube
+   glTranslatef(0.f, 0.f, -state->distance);
+
+   // Rotate model to new position
+   glRotatef(state->rot_angle_x, 1.f, 0.f, 0.f);
+   glRotatef(state->rot_angle_y, 0.f, 1.f, 0.f);
+   glRotatef(state->rot_angle_z, 0.f, 0.f, 1.f);
+}
+
+/***********************************************************
+ * Name: inc_and_wrap_angle
+ *
+ * Arguments:
+ *       GLfloat angle     current angle
+ *       GLfloat angle_inc angle increment
+ *
+ * Description:   Increments or decrements angle by angle_inc degrees
+ *                Wraps to 0 at 360 deg.
+ *
+ * Returns: new value of angle
+ *
+ ***********************************************************/
+static GLfloat inc_and_wrap_angle(GLfloat angle, GLfloat angle_inc)
+{
+   angle += angle_inc;
+
+   if (angle >= 360.0)
+      angle -= 360.f;
+   else if (angle <=0)
+      angle += 360.f;
+
+   return angle;
+}
+
+/***********************************************************
+ * Name: inc_and_clip_distance
+ *
+ * Arguments:
+ *       GLfloat distance     current distance
+ *       GLfloat distance_inc distance increment
+ *
+ * Description:   Increments or decrements distance by distance_inc units
+ *                Clips to range
+ *
+ * Returns: new value of angle
+ *
+ ***********************************************************/
+static GLfloat inc_and_clip_distance(GLfloat distance, GLfloat distance_inc)
+{
+   distance += distance_inc;
+
+   if (distance >= 10.0f)
+      distance = 10.f;
+   else if (distance <= 1.0f)
+      distance = 1.0f;
+
+   return distance;
+}
+
+/***********************************************************
+ * Name: redraw_scene
+ *
+ * Arguments:
+ *       CUBE_STATE_T *state - holds OGLES model info
+ *
+ * Description:   Draws the model and calls eglSwapBuffers
+ *                to render to screen
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void redraw_scene(CUBE_STATE_T *state)
+{
+   // Start with a clear screen
+   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+   draw_wavefront(state->model, state->tex);
+
+   eglSwapBuffers(state->display, state->surface);
+}
+
+/***********************************************************
+ * Name: init_textures
+ *
+ * Arguments:
+ *       CUBE_STATE_T *state - holds OGLES model info
+ *
+ * Description:   Initialise OGL|ES texture surfaces to use image
+ *                buffers
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void init_textures(CUBE_STATE_T *state)
+{
+   // the texture containing the video
+   glGenTextures(1, &state->tex);
+
+   glBindTexture(GL_TEXTURE_2D, state->tex);
+   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, IMAGE_SIZE_WIDTH, IMAGE_SIZE_HEIGHT, 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+   /* Create EGL Image */
+   eglImage = eglCreateImageKHR(
+                state->display,
+                state->context,
+                EGL_GL_TEXTURE_2D_KHR,
+                (EGLClientBuffer)state->tex,
+                0);
+    
+   if (eglImage == EGL_NO_IMAGE_KHR)
+   {
+      printf("eglCreateImageKHR failed.\n");
+      exit(1);
+   }
+
+   // Start rendering
+   pthread_create(&thread1, NULL, video_decode_test, eglImage);
+
+   // setup overall texture environment
+   glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+   glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+   glEnable(GL_TEXTURE_2D);
+
+   // Bind texture surface to current vertices
+   glBindTexture(GL_TEXTURE_2D, state->tex);
+}
+//------------------------------------------------------------------------------
+
+static void exit_func(void)
+// Function to be passed to atexit().
+{
+   if (eglImage != 0)
+   {
+      if (!eglDestroyImageKHR(state->display, (EGLImageKHR) eglImage))
+         printf("eglDestroyImageKHR failed.");
+   }
+
+   // clear screen
+   glClear( GL_COLOR_BUFFER_BIT );
+   eglSwapBuffers(state->display, state->surface);
+
+   // Release OpenGL resources
+   eglMakeCurrent( state->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
+   eglDestroySurface( state->display, state->surface );
+   eglDestroyContext( state->display, state->context );
+   eglTerminate( state->display );
+
+   printf("\ncube closed\n");
+} // exit_func()
+
+//==============================================================================
+
+int main ()
+{
+   bcm_host_init();
+   printf("Note: ensure you have sufficient gpu_mem configured\n");
+
+   // Clear application state
+   memset( state, 0, sizeof( *state ) );
+      
+   // Start OGLES
+   init_ogl(state);
+
+   // Setup the model world
+   init_model_proj(state);
+
+   // initialise the OGLES texture(s)
+   init_textures(state);
+
+   //state->model = cube_wavefront();
+   state->model = load_wavefront("/opt/vc/src/hello_pi/hello_teapot/teapot.obj.dat", NULL);
+
+   while (!terminate)
+   {
+      update_model(state);
+      redraw_scene(state);
+   }
+   exit_func();
+   return 0;
+}
+
diff --git a/host_applications/linux/apps/hello_pi/hello_teapot/triangle.h b/host_applications/linux/apps/hello_pi/hello_teapot/triangle.h
new file mode 100755 (executable)
index 0000000..0f50e93
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#pragma once
+
+
+void* video_decode_test(void* arg);
diff --git a/host_applications/linux/apps/hello_pi/hello_teapot/video.c b/host_applications/linux/apps/hello_pi/hello_teapot/video.c
new file mode 100755 (executable)
index 0000000..4baae8f
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+Copyright (c) 2012, OtherCrashOverride
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Video decode demo using OpenMAX IL though the ilcient helper library
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bcm_host.h"
+#include "ilclient.h"
+
+static OMX_BUFFERHEADERTYPE* eglBuffer = NULL;
+static COMPONENT_T* egl_render = NULL;
+
+static void* eglImage = 0;
+
+void my_fill_buffer_done(void* data, COMPONENT_T* comp)
+{
+  if (OMX_FillThisBuffer(ilclient_get_handle(egl_render), eglBuffer) != OMX_ErrorNone)
+   {
+      printf("OMX_FillThisBuffer failed in callback\n");
+      exit(1);
+   }
+}
+
+
+// Modified function prototype to work with pthreads
+void *video_decode_test(void* arg)
+{
+   const char* filename = "/opt/vc/src/hello_pi/hello_video/test.h264";
+   eglImage = arg;
+
+   if (eglImage == 0)
+   {
+      printf("eglImage is null.\n");
+      exit(1);
+   }
+
+   OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+   OMX_TIME_CONFIG_CLOCKSTATETYPE cstate;
+   COMPONENT_T *video_decode = NULL, *video_scheduler = NULL, *clock = NULL;
+   COMPONENT_T *list[5];
+   TUNNEL_T tunnel[4];
+   ILCLIENT_T *client;
+   FILE *in;
+   int status = 0;
+   unsigned int data_len = 0;
+
+   memset(list, 0, sizeof(list));
+   memset(tunnel, 0, sizeof(tunnel));
+
+   if((in = fopen(filename, "rb")) == NULL)
+      return (void *)-2;
+
+   if((client = ilclient_init()) == NULL)
+   {
+      fclose(in);
+      return (void *)-3;
+   }
+
+   if(OMX_Init() != OMX_ErrorNone)
+   {
+      ilclient_destroy(client);
+      fclose(in);
+      return (void *)-4;
+   }
+
+   // callback
+   ilclient_set_fill_buffer_done_callback(client, my_fill_buffer_done, 0);
+
+   // create video_decode
+   if(ilclient_create_component(client, &video_decode, "video_decode", ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_INPUT_BUFFERS) != 0)
+      status = -14;
+   list[0] = video_decode;
+
+   // create egl_render
+   if(status == 0 && ilclient_create_component(client, &egl_render, "egl_render", ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_OUTPUT_BUFFERS) != 0)
+      status = -14;
+   list[1] = egl_render;
+
+   // create clock
+   if(status == 0 && ilclient_create_component(client, &clock, "clock", ILCLIENT_DISABLE_ALL_PORTS) != 0)
+      status = -14;
+   list[2] = clock;
+
+   memset(&cstate, 0, sizeof(cstate));
+   cstate.nSize = sizeof(cstate);
+   cstate.nVersion.nVersion = OMX_VERSION;
+   cstate.eState = OMX_TIME_ClockStateWaitingForStartTime;
+   cstate.nWaitMask = 1;
+   if(clock != NULL && OMX_SetParameter(ILC_GET_HANDLE(clock), OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone)
+      status = -13;
+
+   // create video_scheduler
+   if(status == 0 && ilclient_create_component(client, &video_scheduler, "video_scheduler", ILCLIENT_DISABLE_ALL_PORTS) != 0)
+      status = -14;
+   list[3] = video_scheduler;
+
+   set_tunnel(tunnel, video_decode, 131, video_scheduler, 10);
+   set_tunnel(tunnel+1, video_scheduler, 11, egl_render, 220);
+   set_tunnel(tunnel+2, clock, 80, video_scheduler, 12);
+
+   // setup clock tunnel first
+   if(status == 0 && ilclient_setup_tunnel(tunnel+2, 0, 0) != 0)
+      status = -15;
+   else
+      ilclient_change_component_state(clock, OMX_StateExecuting);
+
+   if(status == 0)
+      ilclient_change_component_state(video_decode, OMX_StateIdle);
+
+   memset(&format, 0, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));
+   format.nSize = sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE);
+   format.nVersion.nVersion = OMX_VERSION;
+   format.nPortIndex = 130;
+   format.eCompressionFormat = OMX_VIDEO_CodingAVC;
+
+   if(status == 0 &&
+      OMX_SetParameter(ILC_GET_HANDLE(video_decode), OMX_IndexParamVideoPortFormat, &format) == OMX_ErrorNone &&
+      ilclient_enable_port_buffers(video_decode, 130, NULL, NULL, NULL) == 0)
+   {
+      OMX_BUFFERHEADERTYPE *buf;
+      int port_settings_changed = 0;
+      int first_packet = 1;
+
+      ilclient_change_component_state(video_decode, OMX_StateExecuting);
+
+      while((buf = ilclient_get_input_buffer(video_decode, 130, 1)) != NULL)
+      {
+         // feed data and wait until we get port settings changed
+         unsigned char *dest = buf->pBuffer;
+
+         // loop if at end
+         if (feof(in))
+            rewind(in);
+
+         data_len += fread(dest, 1, buf->nAllocLen-data_len, in);
+
+         if(port_settings_changed == 0 &&
+            ((data_len > 0 && ilclient_remove_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1) == 0) ||
+             (data_len == 0 && ilclient_wait_for_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1,
+                                                       ILCLIENT_EVENT_ERROR | ILCLIENT_PARAMETER_CHANGED, 10000) == 0)))
+         {
+            port_settings_changed = 1;
+
+            if(ilclient_setup_tunnel(tunnel, 0, 0) != 0)
+            {
+               status = -7;
+               break;
+            }
+
+            ilclient_change_component_state(video_scheduler, OMX_StateExecuting);
+
+            // now setup tunnel to egl_render
+            if(ilclient_setup_tunnel(tunnel+1, 0, 1000) != 0)
+            {
+               status = -12;
+               break;
+            }
+
+            // Set egl_render to idle
+            ilclient_change_component_state(egl_render, OMX_StateIdle);
+
+            // Enable the output port and tell egl_render to use the texture as a buffer
+            //ilclient_enable_port(egl_render, 221); THIS BLOCKS SO CAN'T BE USED
+            if (OMX_SendCommand(ILC_GET_HANDLE(egl_render), OMX_CommandPortEnable, 221, NULL) != OMX_ErrorNone)
+            {
+               printf("OMX_CommandPortEnable failed.\n");
+               exit(1);
+            }
+
+            if (OMX_UseEGLImage(ILC_GET_HANDLE(egl_render), &eglBuffer, 221, NULL, eglImage) != OMX_ErrorNone)
+            {
+               printf("OMX_UseEGLImage failed.\n");
+               exit(1);
+            }
+
+            // Set egl_render to executing
+            ilclient_change_component_state(egl_render, OMX_StateExecuting);
+
+
+            // Request egl_render to write data to the texture buffer
+            if(OMX_FillThisBuffer(ILC_GET_HANDLE(egl_render), eglBuffer) != OMX_ErrorNone)
+            {
+               printf("OMX_FillThisBuffer failed.\n");
+               exit(1);
+            }
+         }
+         if(!data_len)
+            break;
+
+         buf->nFilledLen = data_len;
+         data_len = 0;
+
+         buf->nOffset = 0;
+         if(first_packet)
+         {
+            buf->nFlags = OMX_BUFFERFLAG_STARTTIME;
+            first_packet = 0;
+         }
+         else
+            buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN;
+
+         if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf) != OMX_ErrorNone)
+         {
+            status = -6;
+            break;
+         }
+      }
+
+      buf->nFilledLen = 0;
+      buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN | OMX_BUFFERFLAG_EOS;
+
+      if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf) != OMX_ErrorNone)
+         status = -20;
+
+      // need to flush the renderer to allow video_decode to disable its input port
+      ilclient_flush_tunnels(tunnel, 0);
+
+      ilclient_disable_port_buffers(video_decode, 130, NULL, NULL, NULL);
+   }
+
+   fclose(in);
+
+   ilclient_disable_tunnel(tunnel);
+   ilclient_disable_tunnel(tunnel+1);
+   ilclient_disable_tunnel(tunnel+2);
+   ilclient_teardown_tunnels(tunnel);
+
+   ilclient_state_transition(list, OMX_StateIdle);
+   ilclient_state_transition(list, OMX_StateLoaded);
+
+   ilclient_cleanup_components(list);
+
+   OMX_Deinit();
+
+   ilclient_destroy(client);
+   return (void *)status;
+}
+
diff --git a/host_applications/linux/apps/hello_pi/hello_tiger/CMakeLists.txt b/host_applications/linux/apps/hello_pi/hello_tiger/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..b253f3f
--- /dev/null
@@ -0,0 +1,9 @@
+set(EXEC hello_tiger.bin)
+set(SRCS main.c tiger.c)
+add_definitions(-D__RASPBERRYPI__)
+
+add_executable(${EXEC} ${SRCS})
+target_link_libraries(${EXEC} ${HELLO_PI_LIBS})
+
+install(TARGETS ${EXEC}
+        RUNTIME DESTINATION bin)
diff --git a/host_applications/linux/apps/hello_pi/hello_tiger/Makefile b/host_applications/linux/apps/hello_pi/hello_tiger/Makefile
new file mode 100755 (executable)
index 0000000..f95e244
--- /dev/null
@@ -0,0 +1,8 @@
+OBJS=main.o tiger.o
+BIN=hello_tiger.bin
+
+#LDFLAGS+=
+CFLAGS+=-D__RASPBERRYPI__
+
+include ../Makefile.include
+
diff --git a/host_applications/linux/apps/hello_pi/hello_tiger/license.txt b/host_applications/linux/apps/hello_pi/hello_tiger/license.txt
new file mode 100755 (executable)
index 0000000..07599fc
--- /dev/null
@@ -0,0 +1,53 @@
+OpenVG 1.1 Reference Implementation
+-----------------------------------
+
+Copyright (c) 2007 The Khronos Group Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and /or associated documentation files
+(the "Materials "), to deal in the Materials without restriction,
+including without limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of the Materials,
+and to permit persons to whom the Materials are furnished to do so,
+subject to the following conditions: 
+
+The above copyright notice and this permission notice shall be included 
+in all copies or substantial portions of the Materials. 
+
+THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR
+THE USE OR OTHER DEALINGS IN THE MATERIALS.
+
+
+Path data for the Tiger sample program has been extracted from Ghostscript's
+tiger.eps example file distributed under GNU General Public License.
+
+Ghostscript's License document:
+" The files in the src, lib, toolbin, examples, doc and man
+  directories (folders) and any subdirectories (sub-folders)
+  thereof are part of GPL Ghostscript.
+
+  The files in the Resource directory and any subdirectories thereof
+  are also part of GPL Ghostscript, with the explicit exception of
+  the files in the CMap subdirectory. The CMap files are copyright
+  Adobe Systems Incorporated and covered by a separate license
+  which permits only verbatim distribution.
+
+  GPL Ghostscript is free software; you can redistribute it and/or
+  modify it under the terms of version 2 of the GNU General Public
+  License as published by the Free Software Foundation.
+
+  GPL Ghostscript is distributed in the hope that it will be
+  useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+  of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+  General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program so you can know your rights and responsibilities.
+  It should be in a file named doc/COPYING. If not, write to the
+  Free Software Foundation, Inc., 59 Temple Place Suite 330, Boston, MA
+  02111-1307, USA."
diff --git a/host_applications/linux/apps/hello_pi/hello_tiger/main.c b/host_applications/linux/apps/hello_pi/hello_tiger/main.c
new file mode 100755 (executable)
index 0000000..a15dda6
--- /dev/null
@@ -0,0 +1,533 @@
+/*------------------------------------------------------------------------
+ *
+ * OpenVG 1.0.1 Reference Implementation sample code
+ * -------------------------------------------------
+ *
+ * Copyright (c) 2007 The Khronos Group Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and /or associated documentation files
+ * (the "Materials "), to deal in the Materials without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Materials,
+ * and to permit persons to whom the Materials are furnished to do so,
+ * subject to the following conditions: 
+ *
+ * The above copyright notice and this permission notice shall be included 
+ * in all copies or substantial portions of the Materials. 
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR
+ * THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//**
+ * \file
+ * \brief      Tiger sample application. Resizing the application window
+ *                     rerenders the tiger in the new resolution. Pressing 1,2,3
+ *                     or 4 sets pixel zoom factor, mouse moves inside the zoomed
+ *                     image (mouse move works on OpenGL >= 1.2).
+ * \note       
+ *//*-------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#define UNREF(X) ((void)(X))
+
+#ifdef HG_FLAT_INCLUDES
+#      include "openvg.h"
+#      include "vgu.h"
+#      include "egl.h"
+#else
+#      include "VG/openvg.h"
+#      include "VG/vgu.h"
+#      include "EGL/egl.h"
+#endif
+
+#include "tiger.h"
+
+/*--------------------------------------------------------------*/
+
+#ifdef __RASPBERRYPI__
+static float rotateN = 0.0f;
+#endif
+const float                    aspectRatio = 612.0f / 792.0f;
+int                                    renderWidth = 0;
+int                                    renderHeight = 0;
+EGLDisplay                     egldisplay;
+EGLConfig                      eglconfig;
+EGLSurface                     eglsurface;
+EGLContext                     eglcontext;
+
+/*--------------------------------------------------------------*/
+
+typedef struct
+{
+       VGFillRule              m_fillRule;
+       VGPaintMode             m_paintMode;
+       VGCapStyle              m_capStyle;
+       VGJoinStyle             m_joinStyle;
+       float                   m_miterLimit;
+       float                   m_strokeWidth;
+       VGPaint                 m_fillPaint;
+       VGPaint                 m_strokePaint;
+       VGPath                  m_path;
+} PathData;
+
+typedef struct
+{
+       PathData*                       m_paths;
+       int                                     m_numPaths;
+} PS;
+
+PS* PS_construct(const char* commands, int commandCount, const float* points, int pointCount)
+{
+       PS* ps = (PS*)malloc(sizeof(PS));
+       int p = 0;
+       int c = 0;
+       int i = 0;
+       int paths = 0;
+       int maxElements = 0;
+       unsigned char* cmd;
+       UNREF(pointCount);
+
+       while(c < commandCount)
+       {
+               int elements, e;
+               c += 4;
+               p += 8;
+               elements = (int)points[p++];
+               assert(elements > 0);
+               if(elements > maxElements)
+                       maxElements = elements;
+               for(e=0;e<elements;e++)
+               {
+                       switch(commands[c])
+                       {
+                       case 'M': p += 2; break;
+                       case 'L': p += 2; break;
+                       case 'C': p += 6; break;
+                       case 'E': break;
+                       default:
+                               assert(0);              //unknown command
+                       }
+                       c++;
+               }
+               paths++;
+       }
+
+       ps->m_numPaths = paths;
+       ps->m_paths = (PathData*)malloc(paths * sizeof(PathData));
+       cmd = (unsigned char*)malloc(maxElements);
+
+       i = 0;
+       p = 0;
+       c = 0;
+       while(c < commandCount)
+       {
+               int elements, startp, e;
+               float color[4];
+
+               //fill type
+               int paintMode = 0;
+               ps->m_paths[i].m_fillRule = VG_NON_ZERO;
+               switch( commands[c] )
+               {
+               case 'N':
+                       break;
+               case 'F':
+                       ps->m_paths[i].m_fillRule = VG_NON_ZERO;
+                       paintMode |= VG_FILL_PATH;
+                       break;
+               case 'E':
+                       ps->m_paths[i].m_fillRule = VG_EVEN_ODD;
+                       paintMode |= VG_FILL_PATH;
+                       break;
+               default:
+                       assert(0);              //unknown command
+               }
+               c++;
+
+               //stroke
+               switch( commands[c] )
+               {
+               case 'N':
+                       break;
+               case 'S':
+                       paintMode |= VG_STROKE_PATH;
+                       break;
+               default:
+                       assert(0);              //unknown command
+               }
+               ps->m_paths[i].m_paintMode = (VGPaintMode)paintMode;
+               c++;
+
+               //line cap
+               switch( commands[c] )
+               {
+               case 'B':
+                       ps->m_paths[i].m_capStyle = VG_CAP_BUTT;
+                       break;
+               case 'R':
+                       ps->m_paths[i].m_capStyle = VG_CAP_ROUND;
+                       break;
+               case 'S':
+                       ps->m_paths[i].m_capStyle = VG_CAP_SQUARE;
+                       break;
+               default:
+                       assert(0);              //unknown command
+               }
+               c++;
+
+               //line join
+               switch( commands[c] )
+               {
+               case 'M':
+                       ps->m_paths[i].m_joinStyle = VG_JOIN_MITER;
+                       break;
+               case 'R':
+                       ps->m_paths[i].m_joinStyle = VG_JOIN_ROUND;
+                       break;
+               case 'B':
+                       ps->m_paths[i].m_joinStyle = VG_JOIN_BEVEL;
+                       break;
+               default:
+                       assert(0);              //unknown command
+               }
+               c++;
+
+               //the rest of stroke attributes
+               ps->m_paths[i].m_miterLimit = points[p++];
+               ps->m_paths[i].m_strokeWidth = points[p++];
+
+               //paints
+               color[0] = points[p++];
+               color[1] = points[p++];
+               color[2] = points[p++];
+               color[3] = 1.0f;
+               ps->m_paths[i].m_strokePaint = vgCreatePaint();
+               vgSetParameteri(ps->m_paths[i].m_strokePaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+               vgSetParameterfv(ps->m_paths[i].m_strokePaint, VG_PAINT_COLOR, 4, color);
+
+               color[0] = points[p++];
+               color[1] = points[p++];
+               color[2] = points[p++];
+               color[3] = 1.0f;
+               ps->m_paths[i].m_fillPaint = vgCreatePaint();
+               vgSetParameteri(ps->m_paths[i].m_fillPaint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+               vgSetParameterfv(ps->m_paths[i].m_fillPaint, VG_PAINT_COLOR, 4, color);
+
+               //read number of elements
+
+               elements = (int)points[p++];
+               assert(elements > 0);
+               startp = p;
+               for(e=0;e<elements;e++)
+               {
+                       switch( commands[c] )
+                       {
+                       case 'M':
+                               cmd[e] = VG_MOVE_TO | VG_ABSOLUTE;
+                               p += 2;
+                               break;
+                       case 'L':
+                               cmd[e] = VG_LINE_TO | VG_ABSOLUTE;
+                               p += 2;
+                               break;
+                       case 'C':
+                               cmd[e] = VG_CUBIC_TO | VG_ABSOLUTE;
+                               p += 6;
+                               break;
+                       case 'E':
+                               cmd[e] = VG_CLOSE_PATH;
+                               break;
+                       default:
+                               assert(0);              //unknown command
+                       }
+                       c++;
+               }
+
+               ps->m_paths[i].m_path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 0, 0, (unsigned int)VG_PATH_CAPABILITY_ALL);
+               vgAppendPathData(ps->m_paths[i].m_path, elements, cmd, points + startp);
+               i++;
+       }
+       free(cmd);
+       return ps;
+}
+
+void PS_destruct(PS* ps)
+{
+       int i;
+       assert(ps);
+       for(i=0;i<ps->m_numPaths;i++)
+       {
+               vgDestroyPaint(ps->m_paths[i].m_fillPaint);
+               vgDestroyPaint(ps->m_paths[i].m_strokePaint);
+               vgDestroyPath(ps->m_paths[i].m_path);
+       }
+       free(ps->m_paths);
+       free(ps);
+}
+
+void PS_render(PS* ps)
+{
+       int i;
+       assert(ps);
+       vgSeti(VG_BLEND_MODE, VG_BLEND_SRC_OVER);
+
+       for(i=0;i<ps->m_numPaths;i++)
+       {
+               vgSeti(VG_FILL_RULE, ps->m_paths[i].m_fillRule);
+               vgSetPaint(ps->m_paths[i].m_fillPaint, VG_FILL_PATH);
+
+               if(ps->m_paths[i].m_paintMode & VG_STROKE_PATH)
+               {
+                       vgSetf(VG_STROKE_LINE_WIDTH, ps->m_paths[i].m_strokeWidth);
+                       vgSeti(VG_STROKE_CAP_STYLE, ps->m_paths[i].m_capStyle);
+                       vgSeti(VG_STROKE_JOIN_STYLE, ps->m_paths[i].m_joinStyle);
+                       vgSetf(VG_STROKE_MITER_LIMIT, ps->m_paths[i].m_miterLimit);
+                       vgSetPaint(ps->m_paths[i].m_strokePaint, VG_STROKE_PATH);
+               }
+
+               vgDrawPath(ps->m_paths[i].m_path, ps->m_paths[i].m_paintMode);
+       }
+       assert(vgGetError() == VG_NO_ERROR);
+}
+
+PS* tiger = NULL;
+
+/*--------------------------------------------------------------*/
+
+void render(int w, int h)
+{
+#ifndef __RASPBERRYPI__
+       if(renderWidth != w || renderHeight != h)
+#endif
+       {
+               float clearColor[4] = {1,1,1,1};
+               float scale = w / (tigerMaxX - tigerMinX);
+
+               eglSwapBuffers(egldisplay, eglsurface); //force EGL to recognize resize
+
+               vgSetfv(VG_CLEAR_COLOR, 4, clearColor);
+               vgClear(0, 0, w, h);
+
+               vgLoadIdentity();
+#ifdef __RASPBERRYPI__
+                vgTranslate(w * 0.5f, h * 0.5f);
+                vgRotate(rotateN);
+                vgTranslate(-w * 0.5f, -h * 0.5f);
+#endif
+               vgScale(scale, scale);
+               vgTranslate(-tigerMinX, -tigerMinY + 0.5f * (h / scale - (tigerMaxY - tigerMinY)));
+
+               PS_render(tiger);
+               assert(vgGetError() == VG_NO_ERROR);
+
+               renderWidth = w;
+               renderHeight = h;
+       }
+#ifndef __RASPBERRYPI__
+       eglSwapBuffers(egldisplay, eglsurface);
+       assert(eglGetError() == EGL_SUCCESS);
+#endif
+}
+
+/*--------------------------------------------------------------*/
+
+void init(NativeWindowType window)
+{
+       static const EGLint s_configAttribs[] =
+       {
+               EGL_RED_SIZE,           8,
+               EGL_GREEN_SIZE,         8,
+               EGL_BLUE_SIZE,          8,
+               EGL_ALPHA_SIZE,         8,
+               EGL_LUMINANCE_SIZE, EGL_DONT_CARE,                      //EGL_DONT_CARE
+               EGL_SURFACE_TYPE,       EGL_WINDOW_BIT,
+               EGL_SAMPLES,            1,
+               EGL_NONE
+       };
+       EGLint numconfigs;
+
+       egldisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+       eglInitialize(egldisplay, NULL, NULL);
+       assert(eglGetError() == EGL_SUCCESS);
+       eglBindAPI(EGL_OPENVG_API);
+
+       eglChooseConfig(egldisplay, s_configAttribs, &eglconfig, 1, &numconfigs);
+       assert(eglGetError() == EGL_SUCCESS);
+       assert(numconfigs == 1);
+
+       eglsurface = eglCreateWindowSurface(egldisplay, eglconfig, window, NULL);
+       assert(eglGetError() == EGL_SUCCESS);
+       eglcontext = eglCreateContext(egldisplay, eglconfig, NULL, NULL);
+       assert(eglGetError() == EGL_SUCCESS);
+       eglMakeCurrent(egldisplay, eglsurface, eglsurface, eglcontext);
+       assert(eglGetError() == EGL_SUCCESS);
+
+       tiger = PS_construct(tigerCommands, tigerCommandCount, tigerPoints, tigerPointCount);
+}
+
+/*--------------------------------------------------------------*/
+
+void deinit(void)
+{
+       PS_destruct(tiger);
+       eglMakeCurrent(egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+       assert(eglGetError() == EGL_SUCCESS);
+       eglTerminate(egldisplay);
+       assert(eglGetError() == EGL_SUCCESS);
+       eglReleaseThread();
+}
+
+/*--------------------------------------------------------------*/
+
+#ifdef WIN32
+#pragma warning(disable:4115)  /* named type definition in parentheses (this comes from a visual studio include file) */
+#include <windows.h>
+
+static LONG WINAPI windowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+       switch (uMsg)
+       {
+       case WM_CLOSE:
+       case WM_DESTROY:
+               PostQuitMessage(0);
+               return 0;
+       case WM_PAINT:
+               {
+                       RECT rect;
+                       InvalidateRect(hWnd, NULL, 0);
+                       GetClientRect(hWnd, &rect);
+                       render(rect.right - rect.left, rect.bottom - rect.top);
+                       return 0;
+               }
+       default:
+               break;
+       }
+       return DefWindowProc(hWnd, uMsg, wParam, lParam);
+}
+
+/*--------------------------------------------------------------*/
+
+int main(void)
+{
+       HWND window;
+       {
+               WNDCLASS wndclass;
+               wndclass.style             = 0;
+               wndclass.lpfnWndProc   = windowProc;
+               wndclass.cbClsExtra    = 0;
+               wndclass.cbWndExtra    = 0;
+               wndclass.hInstance         = (HINSTANCE)GetModuleHandle(NULL);
+               wndclass.hIcon             = LoadIcon(wndclass.hInstance, MAKEINTRESOURCE(101));
+               wndclass.hCursor           = LoadCursor(NULL, IDC_ARROW);
+               wndclass.hbrBackground = CreateSolidBrush(RGB(0, 0, 0));
+               wndclass.lpszMenuName  = NULL;
+               wndclass.lpszClassName = "MainWndClass";
+               if (!wndclass.hIcon)
+                       wndclass.hIcon = LoadIcon(NULL, IDI_EXCLAMATION);
+               RegisterClass(&wndclass);
+       }
+
+       window = CreateWindow(
+               "MainWndClass",
+               "OpenVG Tiger sample (rendering, please wait)",
+               WS_OVERLAPPEDWINDOW,
+               200, 200, 400, (int)(400.0f / aspectRatio),
+               NULL,
+               NULL,
+               (HINSTANCE)GetModuleHandle(NULL),
+               NULL);
+       if (!window)
+               return -1;
+
+       init((NativeWindowType)window);
+
+       {
+               MSG msg;
+               ShowWindow(window, SW_SHOW);
+               while (GetMessage(&msg, NULL, 0, 0))
+               {
+                       DispatchMessage(&msg);
+                       if (msg.message == WM_QUIT)
+                               break;
+               }
+       }
+
+       deinit();
+
+       DestroyWindow(window);
+       return 0;
+}
+
+/*--------------------------------------------------------------*/
+
+#elif defined __APPLE__
+
+/*--------------------------------------------------------------*/
+
+#include <OpenGL/gl.h>
+
+//TODO
+
+#elif defined __RASPBERRYPI__
+#include "bcm_host.h"
+int main(void)
+{
+   uint32_t width, height;
+   bcm_host_init();
+   int s;
+
+   static EGL_DISPMANX_WINDOW_T nativewindow;
+
+   DISPMANX_ELEMENT_HANDLE_T dispman_element;
+   DISPMANX_DISPLAY_HANDLE_T dispman_display;
+   DISPMANX_UPDATE_HANDLE_T dispman_update;
+   VC_RECT_T dst_rect;
+   VC_RECT_T src_rect;
+
+   s = graphics_get_display_size(0 /* LCD */, &width, &height);
+   assert( s >= 0 );
+
+   dst_rect.x = 0;
+   dst_rect.y = 0;
+   dst_rect.width = width;
+   dst_rect.height = height;
+      
+   src_rect.x = 0;
+   src_rect.y = 0;
+   src_rect.width = width << 16;
+   src_rect.height = height << 16;        
+
+   dispman_display = vc_dispmanx_display_open( 0 /* LCD */);
+   dispman_update = vc_dispmanx_update_start( 0 );
+         
+   dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display,
+      1/*layer*/, &dst_rect, 0/*src*/,
+      &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, 0/*transform*/);
+      
+   nativewindow.element = dispman_element;
+   nativewindow.width = width;
+   nativewindow.height = height;
+   vc_dispmanx_update_submit_sync( dispman_update );
+
+   init(&nativewindow);
+
+   while (1) {
+      render(width, height);
+      rotateN += 1.0f;
+   }
+   deinit();
+
+   return 0;
+}
+#endif
+
diff --git a/host_applications/linux/apps/hello_pi/hello_tiger/readme.txt b/host_applications/linux/apps/hello_pi/hello_tiger/readme.txt
new file mode 100755 (executable)
index 0000000..6845e24
--- /dev/null
@@ -0,0 +1,263 @@
+OpenVG 1.1 Reference Implementation
+-----------------------------------
+
+Copyright (c) 2007 The Khronos Group Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and /or associated documentation files
+(the "Materials "), to deal in the Materials without restriction,
+including without limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of the Materials,
+and to permit persons to whom the Materials are furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Materials.
+
+THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR
+THE USE OR OTHER DEALINGS IN THE MATERIALS.
+
+
+Version
+-------
+Official RI for OpenVG 1.1
+Released: May 13, 2008
+
+
+Release Notes
+-------------
+
+This release is based on OpenVG 1.1 and EGL 1.3 specifications.
+This release is Windows-only, although the source code
+compiles at least on Mac OS X 10.5 and Cygwin. Project files are
+provided for MSVC 6.
+
+This archive contains sources for OpenVG RI, VGU and EGL. There's
+also a precompiled libOpenVG.dll that contains OpenVG and EGL implementations.
+
+
+Package Structure
+-----------------
+
+bin
+  win32
+    libOpenVG.dll         OpenVG Windows .dll
+    tiger.exe             Windows executable of the Tiger sample
+lib
+  libOpenVG.lib           MSVC 6 dll import library
+ri
+  openvg_ri.dsp           MSVC 6 project file for libOpenVG.dll
+  src                     .cpp and .h -files of the reference implementation
+    win32                 Windows backend for EGL
+    macosx                Mac OS X backend for EGL
+    null                  null backend for EGL
+  include                 Public OpenVG and EGL headers
+    EGL
+      egl.h
+    VG
+      openvg.h
+      vgu.h
+samples
+  samples.dsw             MSVC 6 workspace file for tiger sample and libOpenVG.dll
+  samples.dsp             MSVC 6 project file for tiger.exe
+  tiger
+    main.c
+    tiger.c
+    tiger.h
+readme.txt
+license.txt
+
+
+Samples
+-------
+
+Tiger
+
+The release contains a sample application that renders an image of a
+tiger. Note that the sample doesn't start immediately, since it takes
+a few seconds to render the image. Resizing the window rerenders the
+image in the new resolution.
+
+
+Known Issues
+------------
+
+-EGL functionality is incomplete (some functions lack proper error checking, some
+ attribs may not be processed, etc.)
+-When opening samples.dsw, MSVC may complain about missing Perforce connection. Just
+ ignore that.
+
+
+Changes
+-------
+
+Nov 25, 2008
+-Clamp color transform scale to [-127, 127] and bias to [-1, 1]
+
+May 13, 2008
+- Changed 8 sample MSAA configs into 32 sample configs
+- Changed max gaussian std deviation to 16 (was 128)
+- VG_DRAW_IMAGE_MULTIPLY converts luminance to RGB if either paint or image color is RGB
+- Fixes A40102 by storing input floats as is
+
+February 12, 2008
+- fixed arc transformation.
+- fixed point along path corner cases.
+- partially fixed A40102 by not filtering invalid float input.
+
+December 12, 2007
+- fixed an overflow bug in vgFillMaskLayer error handling.
+- increased accuracy for Gaussian blur. The new code avoids an infinite loop with a very small std dev.
+- fixed a bug in Font::find that caused deleted fonts to be returned.
+
+November 20, 2007
+- reimplemented 1,2 & 4 bits per pixel images
+- fixed vgGetParameter for paint
+- fixed https://cvs.khronos.org/bugzilla/show_bug.cgi?id=1095 RI handling of child images with shared storage
+  -vgGetParent: return closest valid ancestor, or image itself if no ancestor was found.
+- EGL refactoring & clean up
+- divided OS native parts of EGL into separate files that should be included in that platform's build
+- added a generic OS backend for EGL (not thread safe, no window rendering)
+- fixed https://cvs.khronos.org/bugzilla/show_bug.cgi?id=1943 RI does not handle channel mask correctly for lL/sL/BW1
+- removed EGL_IMAGE_IN_USE_ERROR from vgDrawGlyph(s)
+- added configs without an alpha mask to facilitate CTS reference image creation
+- implemented more accurate stroking by rendering each stroke part into a coverage buffer and compositing from there
+  -fixes https://cvs.khronos.org/bugzilla/show_bug.cgi?id=2221 RI errors at end of curved strokes.
+- bugfix: joins used path midpoints, interpolateStroke and caps didn't => seams (visible in some G60101 cases)
+- vgCreateMaskLayer returns VG_INVALID_HANDLE if the current surface doesn't have a mask layer
+- vgRenderToMask bugfix: temp buffer is now cleared between fill and stroke
+- bugfix: vgCreateImage returns an error if allowedQuality is zero
+- bugfix: vgSetPaint returns an error if paintModes is zero
+- bugfix: vgCreateFont doesn't return an error if capacityHint is zero
+- bugfix: writeFilteredPixel writes also into luminance formats
+
+October 12, 2007
+-Upgrade to OpenVG 1.1, including
+  -Implemented MSAA, added 4 and 8 sample EGLConfigs
+  -Implemented VG_A_4 and VG_A_1 image formats and EGLConfigs
+  -Implemented Glyph API
+  -Implemented new masking functions
+  -Implemented color transform
+-Implemented native EGL backends for Windows & Mac OS X => Fix for bugzilla 1376 RI uses non-standard EGL implementation
+  *RI now works with CTS generation's native_w32.c (native_ri.c can be removed).
+  *dependency on GLUT has been removed. GLUT code is still included and can be compiled in instead of native by defining RI_USE_GLUT.
+-16 bit EGLConfigs now expose 4 mask bits, 8 bit configs 8, 4 bit configs 4, and 1 bit configs 1. MSAA configs expose one bit per sample.
+-EGL now works with any display, not just EGL_DEFAULT_DISPLAY
+-Simplification: removed code to handle less than 8 bits per pixel. Smaller bit depths always allocate 8 bits per pixel.
+-Changed rasterizer data types to RScalar and RVector2 so that it's possible to alter RIfloat precision without affecting rasterization.
+-Accuracy: increased circularLerp precision
+-Bugfix: matrix inversion now checks if the input matrix is affine and forces the inverted matrix to be affine as well
+-Bugfix: fixed eglCopyBuffers (copied from dst to dst)
+-Bugfix: fixed eglCreatePixmapSurface (allowed only VG_sRGBA_8888, didn't give an error if config had more than one sample per pixel)
+-Bugfix: bugzilla 2465: RI asserts when setting maximum amount of gradient stops
+
+February 27, 2007
+-changed to MIT open source license.
+-bugfix, bugzilla 820: RGB and luminance are now treated as different color spaces.
+-bugfix, bugzilla 1094/1095: vgGetParent now returns the input image in case its parent is already destroyed.
+
+December 1, 2006
+-bugfix, bugzilla 649: allowed image quality is now taken into account when deciding resampling filter.
+-bugfix, bugzilla 650, bad stroking accuracy reported by TK Chan and Mika Tuomi: curve tessellation is now increased from 64 to 256. RI_MAX_EDGES has been increased from 100000 to 262144 to facilitate the increased number of edges.
+-bugfix, reported by Chris Wynn, affects I30206: degenerate gradients in repeat mode now render the first stop color instead of the last one.
+-changed float to RIfloat, added an option to compile RIfloat into a class to test reduced precision float ops
+
+September 6, 2006
+-bugfix, bugzilla 591: CLOSE_PATH followed by a MOVE_TO doesn't produce an extra end cap anymore
+-abs values of arc axis lengths are taken only just before rendering
+-undefined bits of bitfields are now ignored in the API
+
+September 1, 2006
+-changed colorToInt to use mathematical round-to-nearest as recommended by new language in section 3.4.4.
+-implemented VG_PAINT_COLOR_RAMP_PREMULTIPLIED
+-implemented VG_STROKE_DASH_PHASE_RESET
+-implemented new language for filter channelMasks (section 11.2)
+-tangents returned by vgPointAlongPath are now normalized
+-implemented VG_MAX_GAUSSIAN_STD_DEVIATION, rewrote Gaussian blur code
+-vgGetString: if no context, return NULL. VG_VERSION returns the spec version (1.0).
+-bugfix, bugzilla 542: vgSeparableConvolve now convolves the edge color with the horizontal kernel and uses that as the edge color for the vertical pass
+-ellipse rh and rv are replaced by their absolute values whenever read for processing, the absolute values are not written into the path data
+
+August 18, 2006
+-bugfix, M30301: the arguments for vguComputeWarpQuadToQuad were the wrong way around, destination should come before source.
+-bugfix, M10102: check for degeneracy in vguComputeWarpSquareToQuad is done before the affinity check so that degenerate affine matrices also produce the bad warp error
+-bugfix, bugzilla 491: Chris Wynn's vgComputeWarpSquareToQuad -case. There was a wrong mapping between vertices, (1,1) was mapped to (dx2,dy2)
+-bugfix, bugzilla 519: vguPolygon wrong error check. vguPolygon didn't have an error check for the count argument
+-bugfix, bugzilla 518: vgGetParameterfv/iv wrong errors. vgGetParametrtfv/iv error checking was for count < 0 instead of count <= 0.
+-bugfix, bugzilla 517: wrong cap flag checked in vgPathTransformedBounds
+-bugfix, bugzilla 494: egl.h has wrong values for OPENVG_BIT and OPENGL_ES_BIT. Copied the enumerations from the 1.3 egl.h on the Khronos site (OpenKode/egl/egl.h)
+-bugfix, bugzilla 492: gradient filter window was biased
+-bugfix: when appending paths, there was a loop over coordinates to replace arc axis lengths by their absolute values. However, if the path wasn't empty, the loop accessed wrong coordinates. Fixes: Qingping Zhang's cases 2&3.
+-bugfix: image filter write mask was ignored when writing to VG_A_8 images. Fixes: Qingping Zhang's case 13.
+-bugfix: if image filter processing format is premultiplied, color channels are clamped to alpha before conversion to destination format
+-bugfix: in eglReleaseThread the EGL instance was freed when its reference count reached zero, but the pointer wasn't made NULL, causing the use of uninitialized instance.
+-bugfix: vgClearImage didn't clamp the clear color to [0,1] range
+-bugfix: a zero-length dash at a path vertex produces a join
+-bugfix: vgSetParameter now checks paramType for all object types
+-bugfix: convolution filters incorrectly restricted the area read from the source image to the intersection of source and destination image sizes
+-bugfix: EGL surface creation now defaults correctly to EGL_COLOR_SPACE_sRGB
+-antialiasing is done in the linear color space as the spec recommends.
+-image filters clamp the result to [0,1] range.
+-Color::pack and Color::convert assert that their input is in [0,1] range
+-in case a projective transform is used, VGImageMode is always VG_DRAW_IMAGE_NORMAL
+-the default value for VG_FILTER_FORMAT_LINEAR is now VG_FALSE
+-added Matrix::isAffine for easy affinity check
+-Color::clamp clamps color channels to alpha for premultiplied colors
+-VG_BLEND_LIGHTEN: color channels cannot exceed alpha anymore
+-RI now supports flexible pixel formats. Any bit depth for RGBA is now supported.
+-eglGetProcAddress is now properly implemented, it returns a function pointer for eglSetConfigPreferenceHG extension
+-eglQueryString now returns "eglSetConfigPreferenceHG" for EGL_EXTENSIONS
+-location of egl.h in RI. use EGL/egl.h, VG/openvg.h, VG/vgu.h
+-OpenVG 1.0.1 spec changes
+ +use the latest openvg.h
+ +2.8: AA happens in linear space
+ +3.4: alpha channel depth of zero results in alpha=1 when read
+ +4.1: return VG_NO_CONTEXT_ERROR from vgGetError in case no context is current
+ +5.1: VG_SCREEN_LAYOUT (default = screen layout of the display)
+ +5.2, 5.3: vgSet, vgGet, vgSetParameter, vgGetParameter: handling of invalid values of count
+ +5.2.1: new default for VG_FILTER_FORMAT_LINEAR is VG_FALSE
+ +8.5.3: get rid of VG_PATH_DATATYPE_INVALID and VG_IMAGE_FORMAT_INVALID enums
+ +10.2: get rid of old extension image formats, add the official ones
+ +10.5: when reading/writing pixels, clamp color channels to [0, alpha]
+ +10.8: when a projective transform is used, always use VG_DRAW_IMAGE_NORMAL mode
+ +10.8: VG_DRAW_IMAGE_MULTIPLY: if color spaces of paint and image don't match, no conversion takes place, result is in image color space
+ +12.4: clamp the result of additive blend to [0,1]
+
+October 20, 2005
+-Gradients are filtered to avoid aliasing
+-Subpaths that ended with a close path segment were capped and joined incorrectly. Fixed.
+-Alpha mask was allocated per context, not per EGL surface. Fixed.
+
+August 22, 2005
+-Updated to spec amendment
+-Fixed bugs
+-Implemented eglChooseConfig and eglReleaseThread
+
+July 22, 2005
+-Updated to 18th July 2005 version of the OpenVG 1.0 spec.
+-Updated to 20th July 2005 version of the EGL 1.2 spec.
+-Fixed bugs.
+-openvg.h, vgu.h and egl.h are now contained in include/vg directory.
+
+May 4, 2005
+-Updated to April 26th 2005 version of the OpenVG 1.0 spec.
+-Can share images, paths, and paint between contexts.
+-Fixed path tangent computation.
+-Implemented image filters.
+-Fixed bugs.
+-Changed directory structure a bit.
+
+March 29, 2005
+-Updated to March 28th 2005 version of the OpenVG 1.0 spec.
+-Changed rasterizer to use 32 samples per pixel in the high quality
+ mode (renders faster at the expense of some aliasing).
+-EGL allocates sRGB rendering surfaces.
+-Includes GLUT dll against which tiger.exe was linked.
+
+March 24, 2005
+-Initial release.
diff --git a/host_applications/linux/apps/hello_pi/hello_tiger/tiger.c b/host_applications/linux/apps/hello_pi/hello_tiger/tiger.c
new file mode 100755 (executable)
index 0000000..ae2eff9
--- /dev/null
@@ -0,0 +1,1952 @@
+/*------------------------------------------------------------------------
+ *
+ * OpenVG 1.0.1 Reference Implementation sample code
+ * -------------------------------------------------
+ *
+ * Copyright (c) 2007 The Khronos Group Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and /or associated documentation files
+ * (the "Materials "), to deal in the Materials without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Materials,
+ * and to permit persons to whom the Materials are furnished to do so,
+ * subject to the following conditions: 
+ *
+ * The above copyright notice and this permission notice shall be included 
+ * in all copies or substantial portions of the Materials. 
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR
+ * THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//**
+ * \file
+ * \brief      Path and paint data for Tiger image.
+ * \note       
+ *//*-------------------------------------------------------------------*/
+
+const int tigerCommandCount = 4151;
+const char tigerCommands[4151] = {
+'F', 'N', 'B', 'M', 'M', 'L', 'L', 'L', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 
+'B', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 'M', 
+'M', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 'M', 'M', 'C', 
+'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 'M', 'M', 'C', 'C', 'C', 
+'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 
+'N', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 
+'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 
+'C', 'C', 'C', 'E', 'N', 'S', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 
+'C', 'E', 'N', 'S', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 
+'N', 'S', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 
+'B', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 'M', 
+'M', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'C', 
+'L', 'C', 'L', 'C', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'L', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 
+'L', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'N', 'S', 'B', 
+'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'C', 'L', 'C', 'L', 'C', 'C', 'C', 'C', 'C', 
+'L', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'L', 'L', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 
+'L', 'C', 'L', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 
+'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'C', 'L', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'L', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 
+'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'E', 'F', 
+'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 
+'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 
+'L', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'C', 
+'C', 'C', 'C', 'L', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'L', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 
+'M', 'M', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'F', 
+'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 
+'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'L', 'C', 'L', 'C', 'C', 'C', 'C', 'L', 'C', 'L', 'C', 'C', 
+'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 
+'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 
+'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'L', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 
+'C', 'C', 'L', 'L', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 
+'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 
+'L', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 'M', 'M', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 
+'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 'M', 'M', 
+'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'N', 
+'S', 'B', 'M', 'M', 'C', 'C', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 'M', 'M', 
+'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 'M', 'M', 'C', 'C', 
+'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 
+'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 
+'B', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 
+'M', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 'M', 'M', 'C', 
+'C', 'C', 'N', 'S', 'B', 'M', 'M', 'C', 'C', 'C', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 
+'E', 'N', 'S', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 'M', 'M', 'C', 'N', 'S', 
+'B', 'M', 'M', 'C', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 
+'C', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 
+'M', 'C', 'C', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 
+'B', 'M', 'M', 'C', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 
+'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 
+'C', 'E', 'N', 'S', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 
+'E', 'N', 'S', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 
+'S', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 
+'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'B', 'M', 'M', 
+'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'L', 'C', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 
+'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 
+'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'E', 'F', 
+'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 
+'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 
+'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 
+'C', 'C', 'L', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 
+'C', 'L', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'C', 'C', 
+'C', 'C', 'L', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'C', 'C', 'C', 
+'C', 'L', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 
+'L', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 
+'C', 'C', 'L', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 
+'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 'C', 'L', 'F', 'N', 'B', 
+'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 
+'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 
+'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 
+'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'L', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'F', 'N', 'R', 
+'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'L', 'L', 'C', 'E', 'F', 'N', 'R', 
+'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 
+'M', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'L', 'L', 'L', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'L', 'L', 'C', 'L', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 
+'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 
+'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'L', 'L', 'C', 'C', 'C', 'C', 'C', 
+'C', 'L', 'L', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'L', 'L', 'L', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 
+'N', 'S', 'R', 'M', 'M', 'C', 'C', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 'C', 'N', 'S', 'R', 'M', 'M', 
+'C', 'C', 'C', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'L', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 
+'M', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 
+'M', 'M', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 
+'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'E', 'F', 'N', 
+'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 
+'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'F', 'N', 'B', 
+'M', 'M', 'C', 'C', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 'L', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 
+'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 
+'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 
+'L', 'C', 'C', 'C', 'C', 'L', 'L', 'C', 'C', 'C', 'C', 'C', 'C', 'L', 'C', 'F', 'N', 'B', 'M', 'M', 
+'C', 'L', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 
+'M', 'C', 'C', 'C', 'L', 'C', 'C', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 
+'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 
+'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'F', 'N', 'B', 
+'M', 'M', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 
+'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'F', 'N', 'B', 
+'M', 'M', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 
+'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'F', 'N', 'B', 
+'M', 'M', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 
+'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'F', 'N', 'B', 
+'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 
+'L', 'L', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 
+'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 
+'E', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 
+'S', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 
+'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 
+'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 
+'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 
+'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 
+'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 
+'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 
+'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'F', 'N', 
+'B', 'M', 'M', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 
+'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'F', 'N', 
+'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'B', 'M', 
+'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 
+'S', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 
+'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 
+'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 
+'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 
+'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 
+'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 
+'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 
+'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 
+'E', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 
+'S', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 
+'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 
+'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 
+'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 
+'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 
+'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 
+'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 
+'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 
+'E', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 
+'S', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 
+'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 
+'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 
+'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'N', 'S', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 
+'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 
+'M', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 
+'F', 'N', 'B', 'M', 'M', 'C', 'C', 'L', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 
+'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 
+'R', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'C', 'C', 'C', 
+'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 
+'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 
+'M', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 
+'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 
+'C', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 
+'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 
+'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 
+'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 'N', 'R', 'M', 'M', 'C', 'C', 'C', 'E', 'F', 
+'N', 'R', 'M', 'M', 'L', 'C', 'L', 'N', 'S', 'R', 'M', 'M', 'L', 'N', 'S', 'R', 'M', 'M', 'C', 'N', 
+'S', 'R', 'M', 'M', 'C', 'N', 'S', 'R', 'M', 'M', 'C'};
+
+const float tigerMinX = 0.0f;
+const float tigerMaxX = 612.0f;
+const float tigerMinY = 0.0f;
+const float tigerMaxY = 792.0f;
+
+const int tigerPointCount = 17005;
+const float tigerPoints[17005] = {
+10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 5, 0, 
+792, 0, 0, 612, 0, 612, 792, 10, 0, 1, 
+1, 1, 1, 1, 1, 5, 85.25f, 487.75f, 85.25f, 487.75f, 
+85.5742f, 485.199f, 84.25f, 484.746f, 83.7617f, 485.242f, 65.6641f, 538.125f, 43.2461f, 535.746f, 
+43.2422f, 535.746f, 62.6445f, 543.746f, 85.25f, 487.75f, 10, 0.1892f, 0, 0, 
+0, 0, 0, 0, 5, 85.25f, 487.75f, 85.25f, 487.75f, 85.5742f, 
+485.199f, 84.25f, 484.746f, 83.7617f, 485.242f, 65.6641f, 538.125f, 43.2461f, 535.746f, 43.2422f, 
+535.746f, 62.6445f, 543.746f, 85.25f, 487.75f, 10, 0, 1, 1, 1, 
+1, 1, 1, 5, 89.2461f, 490.75f, 89.2461f, 490.75f, 88.7422f, 488.613f, 
+88.2461f, 488.746f, 87.0508f, 489.27f, 88.0234f, 545.156f, 66.2461f, 550.746f, 66.2461f, 550.742f, 
+87.0977f, 551.469f, 89.2461f, 490.75f, 10, 0.1892f, 0, 0, 0, 0, 
+0, 0, 5, 89.2461f, 490.75f, 89.2461f, 490.75f, 88.7422f, 488.613f, 88.2461f, 
+488.746f, 87.0508f, 489.27f, 88.0234f, 545.156f, 66.2461f, 550.746f, 66.2461f, 550.742f, 87.0977f, 
+551.469f, 89.2461f, 490.75f, 10, 0, 1, 1, 1, 1, 1, 
+1, 5, 119.25f, 443.75f, 119.25f, 443.75f, 121.387f, 442.992f, 121.246f, 442.746f, 
+120.352f, 441.504f, 66.2578f, 455.586f, 56.25f, 435.75f, 56.25f, 435.75f, 59.9062f, 456.168f, 
+119.25f, 443.75f, 10, 0.1892f, 0, 0, 0, 0, 0, 0, 
+5, 119.25f, 443.75f, 119.25f, 443.75f, 121.387f, 442.992f, 121.246f, 442.746f, 120.352f, 
+441.504f, 66.2578f, 455.586f, 56.25f, 435.75f, 56.25f, 435.75f, 59.9062f, 456.168f, 119.25f, 
+443.75f, 10, 0, 1, 1, 1, 1, 1, 1, 5, 
+116.246f, 432.75f, 116.246f, 432.75f, 118.539f, 432.383f, 118.25f, 431.746f, 118.023f, 430.641f, 
+62.25f, 426.965f, 58.25f, 404.75f, 58.25f, 404.75f, 56.0391f, 425.516f, 116.246f, 432.75f, 
+10, 0.1892f, 0, 0, 0, 0, 0, 0, 5, 116.246f, 
+432.75f, 116.246f, 432.75f, 118.539f, 432.383f, 118.25f, 431.746f, 118.023f, 430.641f, 62.25f, 
+426.965f, 58.25f, 404.75f, 58.25f, 404.75f, 56.0391f, 425.516f, 116.246f, 432.75f, 10, 
+0, 1, 1, 1, 1, 1, 1, 5, 112.25f, 438.746f, 
+112.25f, 438.742f, 113.82f, 438.164f, 113.25f, 437.75f, 113.059f, 436.52f, 57.3437f, 441.016f, 
+50.2461f, 419.75f, 50.2461f, 419.75f, 50.9883f, 440.492f, 112.25f, 438.746f, 10, 0.1892f, 
+0, 0, 0, 0, 0, 0, 5, 112.25f, 438.746f, 112.25f, 
+438.742f, 113.82f, 438.164f, 113.25f, 437.75f, 113.059f, 436.52f, 57.3437f, 441.016f, 50.2461f, 
+419.75f, 50.2461f, 419.75f, 50.9883f, 440.492f, 112.25f, 438.746f, 10, 0, 1, 
+1, 1, 1, 1, 1, 5, 100.246f, 458.746f, 100.246f, 458.746f, 
+101.527f, 457.406f, 101.25f, 456.746f, 100.121f, 456.262f, 52.0039f, 484.699f, 36.25f, 467.746f, 
+36.25f, 467.746f, 46.0586f, 487.012f, 100.246f, 458.746f, 10, 0.1892f, 0, 0, 
+0, 0, 0, 0, 5, 100.246f, 458.746f, 100.246f, 458.746f, 101.527f, 
+457.406f, 101.25f, 456.746f, 100.121f, 456.262f, 52.0039f, 484.699f, 36.25f, 467.746f, 36.25f, 
+467.746f, 46.0586f, 487.012f, 100.246f, 458.746f, 10, 0, 1, 1, 1, 
+1, 1, 1, 5, 92.2461f, 454.75f, 92.2422f, 454.75f, 93.3906f, 452.969f, 
+93.2461f, 452.75f, 92.125f, 451.672f, 41.0976f, 474.484f, 27.25f, 456.746f, 27.25f, 456.746f, 
+34.9258f, 476.105f, 92.2461f, 454.75f, 10, 0.1892f, 0, 0, 0, 0, 
+0, 0, 5, 92.2461f, 454.75f, 92.2422f, 454.75f, 93.3906f, 452.969f, 93.2461f, 
+452.75f, 92.125f, 451.672f, 41.0976f, 474.484f, 27.25f, 456.746f, 27.25f, 456.746f, 34.9258f, 
+476.105f, 92.2461f, 454.75f, 10, 0, 1, 1, 1, 1, 1, 
+1, 5, 89.2461f, 449.746f, 89.2461f, 449.742f, 90.6992f, 448.723f, 90.25f, 447.746f, 
+89.6211f, 447.262f, 35.9609f, 462.906f, 25.25f, 442.746f, 25.25f, 442.742f, 29.625f, 463.676f, 
+89.2461f, 449.746f, 10, 0.1892f, 0, 0, 0, 0, 0, 0, 
+5, 89.2461f, 449.746f, 89.2461f, 449.742f, 90.6992f, 448.723f, 90.25f, 447.746f, 89.6211f, 
+447.262f, 35.9609f, 462.906f, 25.25f, 442.746f, 25.25f, 442.742f, 29.625f, 463.676f, 89.2461f, 
+449.746f, 10, 0, 1, 1, 1, 1, 1, 1, 5, 
+100.246f, 448.75f, 100.246f, 448.75f, 101.969f, 447.469f, 101.25f, 446.75f, 100.43f, 446.512f, 
+56.3516f, 480.887f, 39.2461f, 466.746f, 39.2461f, 466.742f, 50.75f, 483.941f, 100.246f, 448.75f, 
+10, 0.1892f, 0, 0, 0, 0, 0, 0, 5, 100.246f, 
+448.75f, 100.246f, 448.75f, 101.969f, 447.469f, 101.25f, 446.75f, 100.43f, 446.512f, 56.3516f, 
+480.887f, 39.2461f, 466.746f, 39.2461f, 466.742f, 50.75f, 483.941f, 100.246f, 448.75f, 10, 
+0, 1, 1, 1, 1, 1, 1, 5, 79.25f, 480.746f, 
+79.25f, 480.746f, 79.6367f, 479.02f, 79.25f, 478.746f, 77.8789f, 478.578f, 46.418f, 524.777f, 
+25.25f, 516.75f, 25.25f, 516.75f, 42.0195f, 529.398f, 79.25f, 480.746f, 10, 0.1892f, 
+0, 0, 0, 0, 0, 0, 5, 79.25f, 480.746f, 79.25f, 
+480.746f, 79.6367f, 479.02f, 79.25f, 478.746f, 77.8789f, 478.578f, 46.418f, 524.777f, 25.25f, 
+516.75f, 25.25f, 516.75f, 42.0195f, 529.398f, 79.25f, 480.746f, 10, 0, 1, 
+1, 1, 1, 1, 1, 5, 79.25f, 473.746f, 79.25f, 473.742f, 
+80.8164f, 471.527f, 80.25f, 470.75f, 79.1914f, 470.723f, 38.5078f, 509.051f, 19.25f, 496.75f, 
+19.25f, 496.75f, 33.2148f, 512.609f, 79.25f, 473.746f, 10, 0.1892f, 0, 0, 
+0, 0, 0, 0, 5, 79.25f, 473.746f, 79.25f, 473.742f, 80.8164f, 
+471.527f, 80.25f, 470.75f, 79.1914f, 470.723f, 38.5078f, 509.051f, 19.25f, 496.75f, 19.25f, 
+496.75f, 33.2148f, 512.609f, 79.25f, 473.746f, 10, 0, 1, 1, 1, 
+1, 1, 1, 5, 79.25f, 468.75f, 79.25f, 468.75f, 80.8516f, 466.828f, 
+80.25f, 466.746f, 79.3086f, 465.875f, 35.2305f, 500.246f, 17.25f, 485.75f, 17.25f, 485.75f, 
+29.6289f, 503.301f, 79.25f, 468.75f, 10, 0.1892f, 0, 0, 0, 0, 
+0, 0, 5, 79.25f, 468.75f, 79.25f, 468.75f, 80.8516f, 466.828f, 80.25f, 
+466.746f, 79.3086f, 465.875f, 35.2305f, 500.246f, 17.25f, 485.75f, 17.25f, 485.75f, 29.6289f, 
+503.301f, 79.25f, 468.75f, 10, 0, 1, 1, 1, 1, 1, 
+1, 88, 77.2461f, 466.746f, 77.7383f, 459.973f, 78.8242f, 452.746f, 80.25f, 449.746f, 
+80.25f, 449.742f, 76.7773f, 435.676f, 86.25f, 420.746f, 86.25f, 420.742f, 86.0195f, 413.238f, 
+88.2461f, 409.746f, 88.2461f, 409.742f, 92.1797f, 400.477f, 97.25f, 399.75f, 101.73f, 398.887f, 
+111.324f, 395.508f, 122.246f, 393.75f, 122.246f, 393.75f, 141.02f, 378.477f, 137.246f, 364.75f, 
+137.242f, 364.75f, 137.059f, 346.355f, 133.246f, 344.75f, 133.246f, 344.75f, 145.859f, 356.918f, 
+135.25f, 338.75f, 130.25f, 317.746f, 130.25f, 317.742f, 158.617f, 341.516f, 141.25f, 321.746f, 
+130.25f, 292.75f, 130.25f, 292.75f, 152.02f, 312.918f, 144.246f, 303.75f, 140.25f, 293.746f, 
+140.25f, 293.746f, 188.098f, 323.918f, 154.246f, 291.746f, 154.242f, 291.746f, 163.02f, 295.316f, 
+168.25f, 291.746f, 168.25f, 291.746f, 175.34f, 293.559f, 174.25f, 291.746f, 174.25f, 291.746f, 
+151.578f, 280.355f, 147.25f, 259.746f, 147.25f, 259.746f, 156.859f, 271.117f, 153.246f, 258.746f, 
+154.246f, 246.746f, 154.242f, 246.746f, 158.18f, 270.238f, 157.25f, 228.746f, 157.25f, 228.742f, 
+178.859f, 248.676f, 166.246f, 225.746f, 166.246f, 207.75f, 166.246f, 207.75f, 182.816f, 225.355f, 
+176.246f, 211.75f, 176.246f, 211.75f, 186.777f, 220.957f, 182.25f, 203.746f, 182.25f, 203.746f, 
+181.5f, 192.797f, 186.25f, 204.746f, 186.25f, 204.746f, 203.938f, 238.777f, 197.25f, 209.75f, 
+197.25f, 209.75f, 196.457f, 188.836f, 201.246f, 204.746f, 201.246f, 204.746f, 202.18f, 193.676f, 
+212.246f, 185.75f, 212.246f, 185.75f, 210.977f, 241.637f, 225.25f, 201.746f, 229.25f, 183.746f, 
+229.25f, 183.742f, 232.539f, 194.117f, 232.246f, 199.75f, 232.246f, 199.75f, 248.379f, 217.879f, 
+241.25f, 190.746f, 241.25f, 190.746f, 257.617f, 216.117f, 254.246f, 201.746f, 254.246f, 201.746f, 
+245.738f, 183.996f, 247.246f, 178.75f, 247.242f, 178.75f, 265.977f, 216.996f, 267.246f, 218.75f, 
+267.246f, 218.75f, 265.098f, 172.117f, 277.246f, 211.75f, 277.246f, 211.75f, 283.137f, 198.516f, 
+280.246f, 193.746f, 280.242f, 193.746f, 288.859f, 202.477f, 288.246f, 205.746f, 288.246f, 205.742f, 
+293.039f, 215.016f, 296.25f, 199.75f, 296.25f, 199.75f, 298.098f, 189.719f, 300.246f, 192.746f, 
+300.246f, 192.746f, 304.258f, 166.836f, 305.25f, 191.746f, 305.25f, 191.746f, 307.34f, 206.879f, 
+299.246f, 219.75f, 299.246f, 219.75f, 300.297f, 223.156f, 297.246f, 227.746f, 297.246f, 227.742f, 
+312.18f, 203.797f, 304.25f, 235.746f, 304.25f, 235.746f, 316.578f, 226.676f, 318.25f, 226.746f, 
+318.25f, 226.746f, 302.937f, 252.195f, 312.246f, 246.746f, 312.242f, 246.746f, 306.898f, 258.355f, 
+326.25f, 244.75f, 326.25f, 244.75f, 309.098f, 262.758f, 328.25f, 251.75f, 328.25f, 251.75f, 
+337.258f, 245.156f, 329.25f, 255.75f, 329.25f, 255.75f, 313.059f, 273.758f, 337.25f, 253.75f, 
+337.25f, 253.75f, 350.02f, 235.918f, 351.25f, 232.75f, 351.25f, 232.75f, 339.898f, 264.957f, 
+335.246f, 267.75f, 335.242f, 267.75f, 344.301f, 308.078f, 389.246f, 290.75f, 389.246f, 290.75f, 
+397.098f, 271.996f, 402.246f, 291.746f, 402.242f, 291.746f, 416.02f, 299.277f, 428.25f, 268.75f, 
+428.25f, 268.75f, 432.738f, 283.879f, 432.246f, 286.746f, 432.246f, 286.742f, 439.34f, 285.637f, 
+438.25f, 286.746f, 438.25f, 286.742f, 452.98f, 282.117f, 454.246f, 282.746f, 454.246f, 282.746f, 
+461.777f, 275.516f, 462.246f, 279.75f, 462.242f, 279.75f, 472.34f, 276.398f, 470.25f, 280.746f, 
+470.25f, 280.746f, 479.82f, 263.195f, 480.246f, 258.746f, 483.25f, 274.75f, 485.25f, 271.746f, 
+485.25f, 271.746f, 486.859f, 279.918f, 486.25f, 280.746f, 485.098f, 282.559f, 507.98f, 273.758f, 
+513.246f, 250.746f, 515.246f, 241.75f, 515.242f, 241.75f, 522.059f, 257.918f, 520.246f, 262.75f, 
+520.246f, 262.75f, 526.02f, 261.438f, 526.246f, 256.746f, 526.242f, 256.746f, 530.859f, 282.117f, 
+525.25f, 288.746f, 525.25f, 288.742f, 530.418f, 289.598f, 531.246f, 285.75f, 531.246f, 293.746f, 
+531.246f, 293.746f, 539.66f, 292.676f, 539.246f, 295.746f, 539.242f, 295.742f, 544.5f, 299.719f, 
+546.246f, 294.75f, 546.242f, 294.75f, 533.059f, 333.156f, 553.246f, 311.75f, 553.246f, 311.75f, 
+561.219f, 300.156f, 557.246f, 320.75f, 553.301f, 341.516f, 548.898f, 343.277f, 554.25f, 343.746f, 
+554.25f, 343.742f, 555.059f, 347.676f, 553.246f, 349.75f, 550.66f, 351.195f, 554.25f, 349.75f, 
+554.25f, 349.75f, 554.25f, 349.75f, 559.461f, 345.035f, 553.246f, 368.746f, 553.246f, 368.746f, 
+560.777f, 367.477f, 547.25f, 399.75f, 547.25f, 399.75f, 550.66f, 402.238f, 546.246f, 411.746f, 
+546.242f, 411.742f, 555.059f, 406.637f, 558.25f, 408.75f, 558.25f, 408.75f, 557.699f, 410.156f, 
+554.25f, 414.746f, 554.25f, 414.746f, 530.418f, 474.84f, 553.246f, 450.75f, 553.246f, 450.75f, 
+565.895f, 435.73f, 559.246f, 460.746f, 559.242f, 460.742f, 548.832f, 487.223f, 549.25f, 491.746f, 
+77.2461f, 466.746f, 10, 1.1f, 0, 0, 0, 0, 0, 0, 
+88, 77.2461f, 466.746f, 77.7383f, 459.973f, 78.8242f, 452.746f, 80.25f, 449.746f, 80.25f, 
+449.742f, 76.7773f, 435.676f, 86.25f, 420.746f, 86.25f, 420.742f, 86.0195f, 413.238f, 88.2461f, 
+409.746f, 88.2461f, 409.742f, 92.1797f, 400.477f, 97.25f, 399.75f, 101.73f, 398.887f, 111.324f, 
+395.508f, 122.246f, 393.75f, 122.246f, 393.75f, 141.02f, 378.477f, 137.246f, 364.75f, 137.242f, 
+364.75f, 137.059f, 346.355f, 133.246f, 344.75f, 133.246f, 344.75f, 145.859f, 356.918f, 135.25f, 
+338.75f, 130.25f, 317.746f, 130.25f, 317.742f, 158.617f, 341.516f, 141.25f, 321.746f, 130.25f, 
+292.75f, 130.25f, 292.75f, 152.02f, 312.918f, 144.246f, 303.75f, 140.25f, 293.746f, 140.25f, 
+293.746f, 188.098f, 323.918f, 154.246f, 291.746f, 154.242f, 291.746f, 163.02f, 295.316f, 168.25f, 
+291.746f, 168.25f, 291.746f, 175.34f, 293.559f, 174.25f, 291.746f, 174.25f, 291.746f, 151.578f, 
+280.355f, 147.25f, 259.746f, 147.25f, 259.746f, 156.859f, 271.117f, 153.246f, 258.746f, 154.246f, 
+246.746f, 154.242f, 246.746f, 158.18f, 270.238f, 157.25f, 228.746f, 157.25f, 228.742f, 178.859f, 
+248.676f, 166.246f, 225.746f, 166.246f, 207.75f, 166.246f, 207.75f, 182.816f, 225.355f, 176.246f, 
+211.75f, 176.246f, 211.75f, 186.777f, 220.957f, 182.25f, 203.746f, 182.25f, 203.746f, 181.5f, 
+192.797f, 186.25f, 204.746f, 186.25f, 204.746f, 203.938f, 238.777f, 197.25f, 209.75f, 197.25f, 
+209.75f, 196.457f, 188.836f, 201.246f, 204.746f, 201.246f, 204.746f, 202.18f, 193.676f, 212.246f, 
+185.75f, 212.246f, 185.75f, 210.977f, 241.637f, 225.25f, 201.746f, 229.25f, 183.746f, 229.25f, 
+183.742f, 232.539f, 194.117f, 232.246f, 199.75f, 232.246f, 199.75f, 248.379f, 217.879f, 241.25f, 
+190.746f, 241.25f, 190.746f, 257.617f, 216.117f, 254.246f, 201.746f, 254.246f, 201.746f, 245.738f, 
+183.996f, 247.246f, 178.75f, 247.242f, 178.75f, 265.977f, 216.996f, 267.246f, 218.75f, 267.246f, 
+218.75f, 265.098f, 172.117f, 277.246f, 211.75f, 277.246f, 211.75f, 283.137f, 198.516f, 280.246f, 
+193.746f, 280.242f, 193.746f, 288.859f, 202.477f, 288.246f, 205.746f, 288.246f, 205.742f, 293.039f, 
+215.016f, 296.25f, 199.75f, 296.25f, 199.75f, 298.098f, 189.719f, 300.246f, 192.746f, 300.246f, 
+192.746f, 304.258f, 166.836f, 305.25f, 191.746f, 305.25f, 191.746f, 307.34f, 206.879f, 299.246f, 
+219.75f, 299.246f, 219.75f, 300.297f, 223.156f, 297.246f, 227.746f, 297.246f, 227.742f, 312.18f, 
+203.797f, 304.25f, 235.746f, 304.25f, 235.746f, 316.578f, 226.676f, 318.25f, 226.746f, 318.25f, 
+226.746f, 302.937f, 252.195f, 312.246f, 246.746f, 312.242f, 246.746f, 306.898f, 258.355f, 326.25f, 
+244.75f, 326.25f, 244.75f, 309.098f, 262.758f, 328.25f, 251.75f, 328.25f, 251.75f, 337.258f, 
+245.156f, 329.25f, 255.75f, 329.25f, 255.75f, 313.059f, 273.758f, 337.25f, 253.75f, 337.25f, 
+253.75f, 350.02f, 235.918f, 351.25f, 232.75f, 351.25f, 232.75f, 339.898f, 264.957f, 335.246f, 
+267.75f, 335.242f, 267.75f, 344.301f, 308.078f, 389.246f, 290.75f, 389.246f, 290.75f, 397.098f, 
+271.996f, 402.246f, 291.746f, 402.242f, 291.746f, 416.02f, 299.277f, 428.25f, 268.75f, 428.25f, 
+268.75f, 432.738f, 283.879f, 432.246f, 286.746f, 432.246f, 286.742f, 439.34f, 285.637f, 438.25f, 
+286.746f, 438.25f, 286.742f, 452.98f, 282.117f, 454.246f, 282.746f, 454.246f, 282.746f, 461.777f, 
+275.516f, 462.246f, 279.75f, 462.242f, 279.75f, 472.34f, 276.398f, 470.25f, 280.746f, 470.25f, 
+280.746f, 479.82f, 263.195f, 480.246f, 258.746f, 483.25f, 274.75f, 485.25f, 271.746f, 485.25f, 
+271.746f, 486.859f, 279.918f, 486.25f, 280.746f, 485.098f, 282.559f, 507.98f, 273.758f, 513.246f, 
+250.746f, 515.246f, 241.75f, 515.242f, 241.75f, 522.059f, 257.918f, 520.246f, 262.75f, 520.246f, 
+262.75f, 526.02f, 261.438f, 526.246f, 256.746f, 526.242f, 256.746f, 530.859f, 282.117f, 525.25f, 
+288.746f, 525.25f, 288.742f, 530.418f, 289.598f, 531.246f, 285.75f, 531.246f, 293.746f, 531.246f, 
+293.746f, 539.66f, 292.676f, 539.246f, 295.746f, 539.242f, 295.742f, 544.5f, 299.719f, 546.246f, 
+294.75f, 546.242f, 294.75f, 533.059f, 333.156f, 553.246f, 311.75f, 553.246f, 311.75f, 561.219f, 
+300.156f, 557.246f, 320.75f, 553.301f, 341.516f, 548.898f, 343.277f, 554.25f, 343.746f, 554.25f, 
+343.742f, 555.059f, 347.676f, 553.246f, 349.75f, 550.66f, 351.195f, 554.25f, 349.75f, 554.25f, 
+349.75f, 554.25f, 349.75f, 559.461f, 345.035f, 553.246f, 368.746f, 553.246f, 368.746f, 560.777f, 
+367.477f, 547.25f, 399.75f, 547.25f, 399.75f, 550.66f, 402.238f, 546.246f, 411.746f, 546.242f, 
+411.742f, 555.059f, 406.637f, 558.25f, 408.75f, 558.25f, 408.75f, 557.699f, 410.156f, 554.25f, 
+414.746f, 554.25f, 414.746f, 530.418f, 474.84f, 553.246f, 450.75f, 553.246f, 450.75f, 565.895f, 
+435.73f, 559.246f, 460.746f, 559.242f, 460.742f, 548.832f, 487.223f, 549.25f, 491.746f, 77.2461f, 
+466.746f, 10, 0, 0.8f, 0.45f, 0.15f, 0.8f, 0.45f, 0.15f, 44, 
+549.25f, 491.746f, 550.379f, 491.531f, 552.805f, 490.293f, 554.25f, 488.746f, 554.25f, 488.742f, 
+561.66f, 476.598f, 556.25f, 496.75f, 556.25f, 496.75f, 545.82f, 528.52f, 555.246f, 515.746f, 
+555.246f, 515.742f, 562.098f, 508.277f, 558.25f, 522.746f, 554.328f, 541.309f, 551.25f, 548.746f, 
+551.25f, 548.746f, 551.25f, 548.746f, 564.301f, 543.039f, 535.246f, 586.75f, 544.246f, 582.75f, 
+544.246f, 582.75f, 522.938f, 626.199f, 499.25f, 631.746f, 490.25f, 638.746f, 490.25f, 638.742f, 
+532.621f, 680.316f, 518.25f, 720.75f, 518.25f, 720.75f, 511.059f, 726.52f, 500.246f, 716.75f, 
+500.246f, 716.75f, 493.461f, 711.117f, 487.246f, 712.75f, 487.246f, 712.75f, 452.98f, 711.559f, 
+451.25f, 711.746f, 448.578f, 711.559f, 410.301f, 752.477f, 338.25f, 732.746f, 338.25f, 732.742f, 
+332.418f, 730.918f, 327.25f, 731.75f, 327.25f, 731.75f, 307.34f, 749.84f, 253.246f, 724.746f, 
+253.246f, 724.746f, 242.656f, 722.559f, 241.25f, 722.746f, 239.137f, 722.559f, 236.059f, 722.559f, 
+227.25f, 715.746f, 218.457f, 708.477f, 218.02f, 707.598f, 216.25f, 705.75f, 216.25f, 705.75f, 
+197.777f, 693.52f, 192.25f, 692.75f, 192.25f, 692.75f, 179.738f, 685.598f, 175.25f, 674.75f, 
+171.246f, 673.746f, 171.246f, 673.742f, 169.18f, 665.359f, 168.25f, 663.75f, 168.25f, 663.75f, 
+163.457f, 660.078f, 162.25f, 653.746f, 162.25f, 653.742f, 152.898f, 647.316f, 153.246f, 642.746f, 
+153.242f, 642.742f, 151.578f, 636.758f, 150.246f, 631.746f, 150.246f, 631.742f, 142.777f, 626.199f, 
+143.246f, 622.75f, 143.242f, 622.75f, 135.297f, 607.719f, 136.25f, 599.75f, 136.25f, 599.75f, 
+129.578f, 600.68f, 126.246f, 597.75f, 126.242f, 597.75f, 125.617f, 592.758f, 124.25f, 592.746f, 
+124.25f, 592.746f, 120.777f, 591, 123.25f, 586.75f, 123.25f, 586.75f, 121.656f, 583.52f, 
+121.246f, 581.746f, 121.246f, 581.746f, 122.098f, 578.68f, 117.25f, 572.746f, 117.25f, 572.742f, 
+110.219f, 551.84f, 112.25f, 545.75f, 112.25f, 545.75f, 112.859f, 540.84f, 110.246f, 538.75f, 
+110.246f, 538.75f, 105.816f, 539.52f, 115.246f, 526.746f, 115.242f, 526.742f, 115.938f, 525, 
+112.25f, 522.746f, 112.25f, 522.746f, 93.5f, 518.398f, 91.25f, 500.746f, 91.25f, 500.746f, 
+75.8984f, 484.078f, 76.2461f, 478.746f, 75.8984f, 475.824f, 76.1953f, 472.359f, 77.2461f, 467.746f, 
+77.2461f, 467.746f, 76.3398f, 458.117f, 106.25f, 456.746f, 137.059f, 456.355f, 549.25f, 491.746f, 
+549.25f, 491.746f, 10, 1.1f, 0, 0, 0, 0, 0, 0, 
+44, 549.25f, 491.746f, 550.379f, 491.531f, 552.805f, 490.293f, 554.25f, 488.746f, 554.25f, 
+488.742f, 561.66f, 476.598f, 556.25f, 496.75f, 556.25f, 496.75f, 545.82f, 528.52f, 555.246f, 
+515.746f, 555.246f, 515.742f, 562.098f, 508.277f, 558.25f, 522.746f, 554.328f, 541.309f, 551.25f, 
+548.746f, 551.25f, 548.746f, 551.25f, 548.746f, 564.301f, 543.039f, 535.246f, 586.75f, 544.246f, 
+582.75f, 544.246f, 582.75f, 522.938f, 626.199f, 499.25f, 631.746f, 490.25f, 638.746f, 490.25f, 
+638.742f, 532.621f, 680.316f, 518.25f, 720.75f, 518.25f, 720.75f, 511.059f, 726.52f, 500.246f, 
+716.75f, 500.246f, 716.75f, 493.461f, 711.117f, 487.246f, 712.75f, 487.246f, 712.75f, 452.98f, 
+711.559f, 451.25f, 711.746f, 448.578f, 711.559f, 410.301f, 752.477f, 338.25f, 732.746f, 338.25f, 
+732.742f, 332.418f, 730.918f, 327.25f, 731.75f, 327.25f, 731.75f, 307.34f, 749.84f, 253.246f, 
+724.746f, 253.246f, 724.746f, 242.656f, 722.559f, 241.25f, 722.746f, 239.137f, 722.559f, 236.059f, 
+722.559f, 227.25f, 715.746f, 218.457f, 708.477f, 218.02f, 707.598f, 216.25f, 705.75f, 216.25f, 
+705.75f, 197.777f, 693.52f, 192.25f, 692.75f, 192.25f, 692.75f, 179.738f, 685.598f, 175.25f, 
+674.75f, 171.246f, 673.746f, 171.246f, 673.742f, 169.18f, 665.359f, 168.25f, 663.75f, 168.25f, 
+663.75f, 163.457f, 660.078f, 162.25f, 653.746f, 162.25f, 653.742f, 152.898f, 647.316f, 153.246f, 
+642.746f, 153.242f, 642.742f, 151.578f, 636.758f, 150.246f, 631.746f, 150.246f, 631.742f, 142.777f, 
+626.199f, 143.246f, 622.75f, 143.242f, 622.75f, 135.297f, 607.719f, 136.25f, 599.75f, 136.25f, 
+599.75f, 129.578f, 600.68f, 126.246f, 597.75f, 126.242f, 597.75f, 125.617f, 592.758f, 124.25f, 
+592.746f, 124.25f, 592.746f, 120.777f, 591, 123.25f, 586.75f, 123.25f, 586.75f, 121.656f, 
+583.52f, 121.246f, 581.746f, 121.246f, 581.746f, 122.098f, 578.68f, 117.25f, 572.746f, 117.25f, 
+572.742f, 110.219f, 551.84f, 112.25f, 545.75f, 112.25f, 545.75f, 112.859f, 540.84f, 110.246f, 
+538.75f, 110.246f, 538.75f, 105.816f, 539.52f, 115.246f, 526.746f, 115.242f, 526.742f, 115.938f, 
+525, 112.25f, 522.746f, 112.25f, 522.746f, 93.5f, 518.398f, 91.25f, 500.746f, 91.25f, 
+500.746f, 75.8984f, 484.078f, 76.2461f, 478.746f, 75.8984f, 475.824f, 76.1953f, 472.359f, 77.2461f, 
+467.746f, 77.2461f, 467.746f, 76.3398f, 458.117f, 106.25f, 456.746f, 137.059f, 456.355f, 549.25f, 
+491.746f, 549.25f, 491.746f, 10, 0, 0.8f, 0.45f, 0.15f, 0.8f, 0.45f, 
+0.15f, 18, 93.2461f, 466.746f, 65.3398f, 510.477f, 81.2461f, 448.75f, 81.2461f, 448.75f, 
+90.8594f, 410.598f, 233.246f, 451.746f, 233.246f, 451.746f, 233.246f, 451.742f, 419.098f, 485.398f, 
+431.246f, 489.746f, 443.738f, 494.199f, 548.246f, 486.746f, 548.246f, 486.746f, 542.246f, 505.75f, 
+471.02f, 556.68f, 449.898f, 531.156f, 435.246f, 535.746f, 419.98f, 539.957f, 422.621f, 529.398f, 
+419.246f, 528.746f, 415.578f, 527.637f, 372.461f, 554.918f, 365.246f, 553.75f, 358.379f, 553.156f, 
+330.504f, 579.285f, 347.25f, 544.746f, 364.539f, 506.957f, 282.699f, 501.238f, 264.246f, 513.746f, 
+245.738f, 525.879f, 272.25f, 493.746f, 272.25f, 493.746f, 292.379f, 471.316f, 254.246f, 489.746f, 
+254.246f, 489.746f, 216.699f, 503.879f, 190.297f, 475.719f, 187.246f, 474.75f, 183.258f, 473.957f, 
+177.977f, 470.438f, 177.246f, 477.746f, 176.219f, 484.52f, 167.957f, 502.891f, 133.246f, 473.746f, 
+111.098f, 455.695f, 96.25f, 479.75f, 96.25f, 479.75f, 93.2461f, 466.746f, 10, 0, 
+0.91f, 0.5f, 0.228f, 0.91f, 0.5f, 0.228f, 19, 367.246f, 551.75f, 359.82f, 
+551.238f, 331.914f, 577.352f, 348.25f, 542.75f, 366.641f, 503.719f, 284.141f, 499.316f, 265.246f, 
+511.746f, 247.18f, 523.957f, 273.25f, 491.746f, 273.25f, 491.746f, 293.82f, 469.398f, 256.246f, 
+487.75f, 256.246f, 487.75f, 218.137f, 501.957f, 191.738f, 473.797f, 188.246f, 472.75f, 184.699f, 
+472.039f, 179.418f, 468.516f, 178.246f, 475.746f, 177.656f, 482.598f, 169.543f, 500.785f, 134.25f, 
+471.746f, 111.18f, 452.957f, 96.25f, 476.75f, 96.25f, 476.75f, 93.2461f, 465.75f, 65.3164f, 
+509.219f, 82.2461f, 444.746f, 82.2461f, 444.746f, 91.5781f, 407.238f, 235.246f, 449.746f, 235.246f, 
+449.746f, 235.242f, 449.742f, 420.539f, 483.477f, 433.246f, 487.75f, 445.18f, 492.277f, 549.25f, 
+485.75f, 549.25f, 485.75f, 543.25f, 504.746f, 471.578f, 555.398f, 451.34f, 529.238f, 436.25f, 
+533.746f, 421.418f, 538.039f, 424.059f, 527.477f, 420.246f, 526.746f, 417.02f, 525.719f, 373.898f, 
+552.996f, 367.246f, 551.75f, 10, 0, 0.919f, 0.55f, 0.305f, 0.919f, 0.55f, 
+0.305f, 19, 368.246f, 549.75f, 361.258f, 549.316f, 334.051f, 575.75f, 350.25f, 540.75f, 
+367.641f, 500.695f, 285.578f, 497.398f, 267.246f, 509.75f, 248.617f, 522.035f, 275.246f, 489.746f, 
+275.246f, 489.746f, 295.258f, 467.477f, 257.246f, 485.75f, 257.246f, 485.75f, 219.578f, 500.035f, 
+193.18f, 471.875f, 189.246f, 470.75f, 186.137f, 470.117f, 180.859f, 466.598f, 180.246f, 473.746f, 
+179.098f, 480.676f, 171.125f, 498.68f, 136.25f, 469.746f, 111.258f, 450.215f, 97.25f, 472.75f, 
+97.25f, 472.75f, 93.2461f, 463.75f, 66.6172f, 506.637f, 82.2461f, 441.75f, 82.2461f, 441.75f, 
+92.2969f, 403.879f, 236.25f, 447.746f, 236.25f, 447.746f, 236.25f, 447.746f, 421.98f, 481.559f, 
+434.246f, 485.75f, 446.617f, 490.355f, 549.25f, 483.75f, 549.25f, 483.75f, 543.25f, 502.746f, 
+472.141f, 554.117f, 452.777f, 527.316f, 438.25f, 531.75f, 422.859f, 536.117f, 425.5f, 525.559f, 
+422.246f, 524.746f, 418.457f, 523.797f, 375.34f, 551.078f, 368.246f, 549.75f, 10, 0, 
+0.928f, 0.6f, 0.382f, 0.928f, 0.6f, 0.382f, 19, 369.25f, 548.746f, 362.699f, 
+547.398f, 335.496f, 573.832f, 351.25f, 538.75f, 369.738f, 497.285f, 286.43f, 495.867f, 268.246f, 
+507.75f, 250.059f, 520.117f, 276.246f, 487.75f, 276.246f, 487.75f, 296.699f, 465.559f, 259.25f, 
+483.75f, 259.25f, 483.75f, 221.02f, 498.117f, 194.617f, 469.957f, 191.246f, 468.75f, 187.578f, 
+468.199f, 182.301f, 464.676f, 181.25f, 471.746f, 180.539f, 478.758f, 172.711f, 496.574f, 137.246f, 
+467.746f, 111.336f, 447.477f, 97.25f, 469.746f, 97.25f, 469.746f, 93.2461f, 461.75f, 68.7969f, 
+502.516f, 83.2461f, 438.746f, 83.2461f, 438.746f, 93.0195f, 400.516f, 237.25f, 445.746f, 237.25f, 
+445.746f, 237.25f, 445.746f, 423.418f, 479.637f, 435.246f, 483.75f, 448.059f, 488.438f, 550.246f, 
+481.75f, 550.246f, 481.75f, 544.246f, 501.75f, 472.699f, 552.84f, 454.219f, 525.398f, 439.25f, 
+529.75f, 424.301f, 534.199f, 426.938f, 523.637f, 423.246f, 522.746f, 419.898f, 521.879f, 376.777f, 
+549.156f, 369.25f, 548.746f, 10, 0, 0.937f, 0.65f, 0.46f, 0.937f, 0.65f, 
+0.46f, 19, 371.25f, 546.746f, 364.141f, 545.477f, 337.492f, 572.156f, 352.25f, 536.75f, 
+371.18f, 493.559f, 288.457f, 493.559f, 270.25f, 505.75f, 251.5f, 518.195f, 278.246f, 485.75f, 
+278.246f, 485.75f, 298.141f, 463.637f, 260.25f, 481.75f, 260.25f, 481.75f, 222.457f, 496.195f, 
+196.059f, 468.035f, 192.25f, 466.746f, 189.02f, 466.277f, 183.738f, 462.758f, 183.25f, 469.746f, 
+181.98f, 476.836f, 174.297f, 494.473f, 139.246f, 466.746f, 111.418f, 444.738f, 97.25f, 466.746f, 
+97.25f, 466.746f, 93.2461f, 460.746f, 70.9766f, 498.617f, 84.25f, 434.746f, 84.25f, 434.746f, 
+93.7383f, 397.156f, 239.25f, 444.746f, 239.25f, 444.746f, 239.25f, 444.742f, 424.859f, 477.715f, 
+437.25f, 481.75f, 449.5f, 486.516f, 550.246f, 479.75f, 550.246f, 479.75f, 544.246f, 500.746f, 
+473.262f, 551.559f, 455.66f, 523.477f, 440.25f, 527.75f, 425.738f, 532.277f, 428.379f, 521.715f, 
+425.25f, 520.75f, 421.34f, 519.957f, 378.219f, 547.238f, 371.25f, 546.746f, 10, 0, 
+0.946f, 0.7f, 0.537f, 0.946f, 0.7f, 0.537f, 19, 372.25f, 544.746f, 365.578f, 
+543.559f, 337.02f, 569.352f, 354.246f, 534.75f, 375.258f, 492.078f, 289.898f, 491.637f, 271.25f, 
+503.75f, 252.938f, 516.277f, 279.246f, 483.75f, 279.246f, 483.75f, 299.578f, 461.719f, 261.25f, 
+479.75f, 261.25f, 479.75f, 223.898f, 494.277f, 197.5f, 466.117f, 194.25f, 464.746f, 190.457f, 
+464.355f, 185.18f, 460.836f, 184.25f, 467.746f, 183.418f, 474.918f, 175.879f, 492.367f, 140.25f, 
+464.746f, 111.5f, 441.996f, 98.2461f, 462.746f, 98.2461f, 462.746f, 92.2461f, 458.746f, 72.9375f, 
+495.156f, 85.25f, 431.746f, 85.25f, 431.746f, 94.457f, 393.797f, 240.25f, 442.746f, 240.25f, 
+442.746f, 240.25f, 442.742f, 426.301f, 475.797f, 438.25f, 479.75f, 450.941f, 484.598f, 551.25f, 
+477.746f, 551.25f, 477.746f, 545.25f, 498.75f, 473.82f, 550.277f, 457.102f, 521.559f, 442.246f, 
+525.75f, 427.18f, 530.355f, 429.82f, 519.797f, 426.25f, 518.75f, 422.781f, 518.039f, 379.66f, 
+545.316f, 372.25f, 544.746f, 10, 0, 0.955f, 0.75f, 0.614f, 0.955f, 0.75f, 
+0.614f, 19, 374.25f, 542.75f, 367.02f, 541.637f, 338.043f, 567.223f, 355.246f, 532.746f, 
+378.02f, 488.836f, 291.34f, 489.715f, 273.25f, 501.75f, 254.379f, 514.355f, 281.25f, 481.75f, 
+281.25f, 481.75f, 301.02f, 459.797f, 263.25f, 478.746f, 263.25f, 478.746f, 225.34f, 492.355f, 
+198.938f, 464.195f, 195.25f, 463.75f, 191.898f, 462.438f, 186.617f, 458.918f, 185.25f, 465.75f, 
+184.859f, 472.996f, 177.465f, 490.262f, 141.25f, 462.746f, 111.578f, 439.258f, 98.2461f, 459.75f, 
+98.2461f, 459.75f, 92.2461f, 456.746f, 75.1172f, 490.156f, 85.25f, 428.75f, 85.25f, 428.75f, 
+95.1797f, 390.438f, 242.246f, 440.746f, 242.246f, 440.746f, 242.246f, 440.742f, 427.738f, 473.875f, 
+440.25f, 478.746f, 452.379f, 482.676f, 551.25f, 475.746f, 551.25f, 475.746f, 545.25f, 497.746f, 
+474.379f, 548.996f, 458.539f, 519.637f, 443.246f, 523.75f, 428.621f, 528.438f, 431.258f, 517.875f, 
+427.25f, 516.75f, 424.219f, 516.117f, 381.102f, 543.398f, 374.25f, 542.75f, 10, 0, 
+0.964f, 0.8f, 0.691f, 0.964f, 0.8f, 0.691f, 19, 375.246f, 540.75f, 368.461f, 
+539.719f, 338.273f, 564.66f, 357.246f, 530.746f, 381.219f, 487.355f, 292.777f, 487.797f, 274.25f, 
+499.746f, 255.82f, 512.438f, 282.25f, 479.75f, 282.25f, 479.75f, 302.457f, 457.879f, 264.246f, 
+476.75f, 264.246f, 476.75f, 226.777f, 490.438f, 200.379f, 462.277f, 197.25f, 461.75f, 193.34f, 
+460.516f, 188.059f, 456.996f, 187.246f, 463.75f, 186.297f, 471.078f, 179.047f, 488.156f, 143.246f, 
+460.746f, 111.656f, 436.516f, 99.2461f, 456.746f, 99.2461f, 456.746f, 92.2461f, 454.75f, 76.8555f, 
+486.477f, 86.25f, 424.75f, 86.25f, 424.75f, 95.8984f, 387.074f, 243.246f, 438.746f, 243.246f, 
+438.746f, 243.246f, 438.742f, 429.18f, 471.957f, 441.246f, 476.75f, 453.82f, 480.758f, 552.25f, 
+474.75f, 552.25f, 474.75f, 546.246f, 496.75f, 474.941f, 547.719f, 459.98f, 517.719f, 445.246f, 
+521.746f, 430.059f, 526.516f, 432.699f, 515.957f, 429.25f, 514.75f, 425.66f, 514.195f, 382.539f, 
+541.477f, 375.246f, 540.75f, 10, 0, 0.973f, 0.85f, 0.769f, 0.973f, 0.85f, 
+0.769f, 19, 377.246f, 538.75f, 369.898f, 537.797f, 339.715f, 562.738f, 358.25f, 528.746f, 
+382.66f, 485.437f, 294.219f, 485.875f, 275.246f, 497.746f, 257.258f, 510.516f, 283.25f, 477.746f, 
+283.25f, 477.746f, 303.898f, 455.957f, 266.246f, 474.75f, 266.246f, 474.75f, 228.219f, 488.516f, 
+201.816f, 460.355f, 198.246f, 459.75f, 194.777f, 458.598f, 189.5f, 455.078f, 188.246f, 461.75f, 
+187.738f, 469.156f, 180.633f, 486.051f, 144.246f, 458.746f, 111.738f, 433.777f, 99.2461f, 452.75f, 
+99.2461f, 452.75f, 92.2461f, 453.746f, 77.7188f, 482.578f, 87.2461f, 421.75f, 87.2461f, 421.75f, 
+96.6172f, 383.715f, 245.246f, 436.746f, 245.246f, 436.746f, 245.246f, 436.746f, 430.621f, 470.035f, 
+443.246f, 474.75f, 455.258f, 478.836f, 552.25f, 472.75f, 552.25f, 472.75f, 547.25f, 495.746f, 
+475.5f, 546.438f, 461.418f, 515.797f, 446.246f, 519.746f, 431.5f, 524.598f, 434.141f, 514.035f, 
+430.246f, 512.75f, 427.098f, 512.277f, 383.98f, 539.555f, 377.246f, 538.75f, 10, 0, 
+0.982f, 0.9f, 0.846f, 0.982f, 0.9f, 0.846f, 19, 378.246f, 536.75f, 371.34f, 
+535.879f, 341.578f, 561.055f, 360.25f, 526.746f, 384.098f, 482.195f, 295.66f, 483.957f, 277.246f, 
+496.75f, 258.699f, 508.598f, 285.25f, 475.746f, 285.25f, 475.746f, 305.34f, 454.035f, 267.246f, 
+472.75f, 267.246f, 472.75f, 229.66f, 486.598f, 203.258f, 458.438f, 199.246f, 457.75f, 196.219f, 
+456.676f, 190.937f, 453.156f, 190.246f, 459.75f, 189.18f, 467.238f, 182.219f, 483.949f, 146.25f, 
+456.746f, 111.82f, 431.035f, 99.2461f, 449.746f, 99.2461f, 449.746f, 92.2461f, 451.746f, 78.3594f, 
+478.238f, 87.2461f, 417.75f, 87.2461f, 417.75f, 97.3399f, 380.355f, 246.246f, 434.746f, 246.246f, 
+434.746f, 246.242f, 434.746f, 432.059f, 468.117f, 444.246f, 472.75f, 456.699f, 476.918f, 553.246f, 
+470.75f, 553.246f, 470.75f, 547.25f, 493.746f, 476.059f, 545.156f, 462.859f, 513.879f, 448.25f, 
+518.75f, 432.938f, 522.676f, 435.578f, 512.117f, 432.246f, 510.746f, 428.539f, 510.355f, 385.418f, 
+537.637f, 378.246f, 536.75f, 10, 0, 0.991f, 0.95f, 0.923f, 0.991f, 0.95f, 
+0.923f, 19, 380.25f, 534.75f, 372.777f, 533.957f, 344.207f, 559.746f, 361.25f, 524.746f, 
+384.66f, 478.078f, 297.098f, 482.035f, 278.246f, 494.75f, 260.141f, 506.676f, 286.246f, 473.746f, 
+286.246f, 473.746f, 306.777f, 452.117f, 269.246f, 470.75f, 269.246f, 470.75f, 231.098f, 484.676f, 
+204.699f, 456.516f, 201.246f, 455.746f, 197.66f, 454.758f, 192.379f, 451.238f, 191.246f, 458.746f, 
+190.621f, 465.316f, 183.801f, 481.844f, 147.25f, 454.75f, 111.898f, 428.297f, 100.246f, 446.75f, 
+100.246f, 446.75f, 92.2461f, 449.746f, 78.5586f, 475.656f, 88.2461f, 414.746f, 88.2461f, 414.746f, 
+98.0586f, 376.996f, 248.25f, 432.75f, 248.25f, 432.75f, 248.25f, 432.75f, 433.5f, 466.195f, 
+446.246f, 470.75f, 458.141f, 474.996f, 553.246f, 468.75f, 553.246f, 468.75f, 548.246f, 492.75f, 
+476.621f, 543.879f, 464.301f, 511.957f, 449.25f, 516.75f, 434.379f, 520.758f, 437.02f, 510.195f, 
+433.246f, 509.75f, 429.98f, 508.438f, 386.859f, 535.719f, 380.25f, 534.75f, 10, 0, 
+1, 1, 1, 1, 1, 1, 18, 92.2461f, 448.75f, 78.5391f, 
+472.637f, 89.2461f, 411.746f, 89.2461f, 411.746f, 98.7773f, 373.637f, 249.25f, 430.75f, 249.25f, 
+430.75f, 249.25f, 430.75f, 434.938f, 464.277f, 447.25f, 468.75f, 459.578f, 473.078f, 553.246f, 
+466.746f, 553.246f, 466.746f, 548.246f, 491.746f, 477.18f, 542.598f, 465.738f, 510.039f, 451.25f, 
+514.75f, 435.82f, 518.84f, 438.461f, 508.277f, 435.246f, 507.75f, 431.418f, 506.52f, 388.301f, 
+533.797f, 381.25f, 532.746f, 374.219f, 532.039f, 346.477f, 558.227f, 363.25f, 522.746f, 387.23f, 
+470.762f, 295.941f, 481.848f, 280.246f, 492.75f, 261.578f, 504.758f, 288.246f, 471.746f, 288.246f, 
+471.746f, 308.219f, 450.195f, 270.25f, 468.75f, 270.25f, 468.75f, 232.539f, 482.758f, 206.137f, 
+454.598f, 202.246f, 453.746f, 199.098f, 452.836f, 193.816f, 449.316f, 193.25f, 456.746f, 192.059f, 
+463.398f, 185.387f, 479.738f, 149.246f, 452.75f, 111.977f, 425.559f, 100.246f, 442.746f, 100.246f, 
+442.746f, 92.2461f, 448.75f, 10, 0, 0, 0, 0, 0, 0, 
+0, 7, 138.246f, 415.75f, 138.246f, 415.75f, 130.457f, 402.676f, 153.246f, 387.746f, 
+153.242f, 387.742f, 154.879f, 386.617f, 135.25f, 390.746f, 135.25f, 390.746f, 128.258f, 393.438f, 
+126.246f, 404.75f, 126.242f, 404.75f, 121.219f, 409.719f, 116.246f, 415.75f, 110.656f, 422.035f, 
+138.246f, 415.75f, 138.246f, 415.75f, 10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 
+0.8f, 0.8f, 8, 292.25f, 467.746f, 292.25f, 467.746f, 311.848f, 438.297f, 311.246f, 
+432.75f, 309.758f, 421.598f, 309.539f, 411.035f, 313.246f, 406.75f, 316.578f, 402.238f, 326.25f, 
+365.746f, 326.25f, 365.746f, 326.25f, 365.742f, 325.82f, 364.398f, 339.25f, 405.746f, 339.25f, 
+405.742f, 352.219f, 423.797f, 330.25f, 443.75f, 330.25f, 443.75f, 291.5f, 475.719f, 292.25f, 
+467.746f, 10, 0, 0, 0, 0, 0, 0, 0, 15, 
+160.246f, 385.746f, 160.246f, 385.742f, 172.699f, 378.035f, 157.25f, 343.746f, 164.246f, 346.746f, 
+164.242f, 346.746f, 163.02f, 334.035f, 159.246f, 331.75f, 167.25f, 334.75f, 167.25f, 334.75f, 
+172.699f, 326.117f, 168.25f, 320.75f, 168.25f, 320.75f, 186.777f, 312.035f, 186.25f, 304.746f, 
+186.25f, 304.746f, 192.938f, 313.797f, 188.246f, 320.75f, 184.137f, 327.879f, 176.219f, 323.477f, 
+177.246f, 343.746f, 167.25f, 339.746f, 167.25f, 339.742f, 173.578f, 349.879f, 173.25f, 356.75f, 
+165.246f, 354.746f, 165.242f, 354.742f, 181.793f, 383.512f, 170.246f, 384.75f, 163.457f, 385.957f, 
+160.246f, 385.746f, 160.246f, 385.746f, 10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 
+0.8f, 0.8f, 5, 196.25f, 367.75f, 196.25f, 367.75f, 199.098f, 372.316f, 196.25f, 
+371.75f, 192.938f, 370.559f, 158.617f, 354.277f, 152.25f, 343.746f, 152.25f, 343.742f, 189.859f, 
+370.559f, 196.25f, 367.75f, 10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 
+0.8f, 5, 207.25f, 358.75f, 207.25f, 358.75f, 210.539f, 363.516f, 207.25f, 362.75f, 
+204.379f, 361.758f, 170.059f, 345.477f, 163.25f, 334.75f, 163.25f, 334.75f, 201.297f, 361.758f, 
+207.25f, 358.75f, 10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 
+5, 222.246f, 375.75f, 222.246f, 375.75f, 225.059f, 380.238f, 222.246f, 379.746f, 218.898f, 
+378.477f, 184.578f, 362.195f, 178.246f, 351.75f, 178.246f, 351.75f, 215.816f, 378.477f, 222.246f, 
+375.75f, 10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 5, 
+196.25f, 327.75f, 196.25f, 327.75f, 196.457f, 334.035f, 193.25f, 332.746f, 190.297f, 332.277f, 
+150.699f, 312.918f, 144.246f, 302.746f, 144.246f, 302.746f, 190.297f, 330.516f, 196.25f, 327.75f, 
+10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 5, 198.246f, 
+339.746f, 198.246f, 339.742f, 199.098f, 344.598f, 196.25f, 343.746f, 193.816f, 343.719f, 164.777f, 
+330.957f, 158.25f, 320.75f, 158.25f, 320.75f, 190.738f, 344.156f, 198.246f, 339.746f, 10, 
+0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 24, 182.25f, 286.746f, 
+171.246f, 278.75f, 171.246f, 278.75f, 182.379f, 286.957f, 186.25f, 285.75f, 186.25f, 285.75f, 
+178.859f, 273.316f, 178.246f, 267.75f, 178.246f, 267.75f, 189.418f, 281.676f, 195.25f, 280.746f, 
+195.25f, 280.746f, 203.938f, 280.797f, 204.25f, 268.75f, 204.25f, 268.75f, 210.098f, 280.355f, 
+213.246f, 279.75f, 213.242f, 279.75f, 214.938f, 272.879f, 213.246f, 265.75f, 213.242f, 265.75f, 
+218.02f, 273.758f, 222.246f, 271.746f, 222.246f, 271.746f, 229.457f, 274.195f, 228.25f, 261.746f, 
+228.25f, 261.742f, 228.578f, 249.996f, 227.25f, 246.746f, 227.25f, 246.746f, 233.859f, 275.957f, 
+236.25f, 276.75f, 236.25f, 276.75f, 245.297f, 277.719f, 250.25f, 267.75f, 250.25f, 267.75f, 
+246.18f, 276.398f, 251.25f, 273.746f, 251.25f, 273.742f, 263.34f, 272.438f, 267.246f, 264.746f, 
+267.246f, 264.742f, 259.379f, 278.156f, 265.246f, 274.75f, 265.246f, 274.75f, 273.02f, 274.637f, 
+274.25f, 267.75f, 274.25f, 267.75f, 283.578f, 244.277f, 286.246f, 242.75f, 286.246f, 242.75f, 
+277.418f, 266.277f, 279.246f, 266.746f, 279.242f, 266.742f, 276.977f, 279.477f, 282.25f, 262.75f, 
+282.25f, 262.75f, 279.18f, 278.598f, 285.25f, 277.746f, 291.5f, 276.836f, 296.34f, 265.836f, 
+305.25f, 268.75f, 305.25f, 268.75f, 316.141f, 262.316f, 318.25f, 338.75f, 182.25f, 286.746f, 
+10, 0, 0, 0, 0, 0, 0, 0, 15, 187.246f, 
+388.75f, 187.246f, 388.75f, 203.5f, 395.637f, 247.246f, 388.75f, 247.242f, 388.75f, 255.418f, 
+388.598f, 263.25f, 398.746f, 270.379f, 407.957f, 299.859f, 415.879f, 307.25f, 413.75f, 317.25f, 
+406.75f, 318.25f, 405.746f, 318.25f, 405.742f, 331.98f, 393.879f, 332.246f, 385.746f, 332.859f, 
+377.156f, 316.578f, 324.355f, 306.25f, 306.746f, 295.457f, 289.156f, 284.898f, 275.516f, 264.246f, 
+277.746f, 264.246f, 277.742f, 240.898f, 282.559f, 212.246f, 277.746f, 212.246f, 277.742f, 180.617f, 
+279.918f, 177.246f, 288.746f, 174.457f, 297.516f, 190.246f, 313.746f, 190.246f, 313.746f, 190.246f, 
+313.746f, 194.699f, 323.477f, 193.25f, 339.746f, 192.059f, 355.156f, 192.5f, 385.957f, 187.246f, 
+388.75f, 10, 0, 0.9f, 0.4f, 0.55f, 0.9f, 0.4f, 0.55f, 8, 
+211.246f, 386.75f, 220.656f, 366.598f, 188.246f, 294.75f, 188.246f, 294.75f, 185.898f, 293.117f, 
+202.023f, 286.469f, 213.246f, 288.746f, 225.219f, 292.059f, 269.246f, 287.75f, 269.246f, 287.75f, 
+295.457f, 304.559f, 309.246f, 353.75f, 309.246f, 353.75f, 309.246f, 353.75f, 320.98f, 379.797f, 
+301.246f, 383.746f, 282.258f, 386.836f, 211.246f, 386.75f, 211.246f, 386.75f, 10, 0, 
+0.7f, 0.2f, 0.35f, 0.7f, 0.2f, 0.35f, 6, 209.246f, 352.746f, 212.844f, 
+366.922f, 214.586f, 379.902f, 211.246f, 386.75f, 211.246f, 386.75f, 280.059f, 379.797f, 292.25f, 
+402.75f, 297.043f, 411.34f, 313.277f, 377.598f, 313.246f, 366.75f, 313.242f, 366.75f, 243.539f, 
+351.195f, 227.25f, 363.746f, 209.246f, 352.746f, 10, 0, 0.65f, 0.15f, 0.3f, 
+0.65f, 0.15f, 0.3f, 13, 214.25f, 334.75f, 214.25f, 334.75f, 216.258f, 326.996f, 
+213.246f, 322.75f, 213.242f, 322.75f, 211.859f, 321.719f, 210.246f, 321.746f, 210.246f, 321.742f, 
+211.859f, 317.316f, 218.25f, 315.746f, 218.25f, 315.746f, 220.656f, 310.719f, 223.246f, 310.746f, 
+225.938f, 309.836f, 231.219f, 303.676f, 235.246f, 304.746f, 240.02f, 306.316f, 252.25f, 310.746f, 
+252.25f, 310.746f, 252.25f, 310.742f, 258.5f, 314.238f, 268.246f, 310.746f, 268.242f, 310.742f, 
+270.789f, 311.16f, 271.25f, 315.746f, 271.809f, 320.727f, 275.219f, 324.797f, 277.246f, 326.746f, 
+279.617f, 329.195f, 290.18f, 343.277f, 289.246f, 343.746f, 287.539f, 344.156f, 214.25f, 334.75f, 
+214.25f, 334.75f, 10, 0, 1, 0.45f, 0.5f, 1, 0.45f, 0.5f, 
+12, 209.246f, 387.746f, 209.246f, 387.742f, 206.137f, 363.516f, 209.246f, 354.746f, 213.18f, 
+345.035f, 212.297f, 342.836f, 211.246f, 338.75f, 210.539f, 334.035f, 215.379f, 323.035f, 221.246f, 
+316.75f, 234.246f, 314.75f, 234.246f, 314.75f, 251.457f, 318.637f, 261.25f, 315.746f, 261.25f, 
+315.746f, 271.473f, 314.078f, 275.246f, 330.746f, 275.246f, 330.742f, 280.5f, 337.559f, 288.246f, 
+340.75f, 296.34f, 343.719f, 304.258f, 389.477f, 300.246f, 398.746f, 295.457f, 407.078f, 279.617f, 
+411.918f, 262.25f, 394.746f, 244.418f, 377.598f, 242.219f, 396.078f, 209.246f, 387.746f, 10, 
+1.1f, 0, 0, 0, 0, 0, 0, 12, 209.246f, 387.746f, 
+209.246f, 387.742f, 206.137f, 363.516f, 209.246f, 354.746f, 213.18f, 345.035f, 212.297f, 342.836f, 
+211.246f, 338.75f, 210.539f, 334.035f, 215.379f, 323.035f, 221.246f, 316.75f, 234.246f, 314.75f, 
+234.246f, 314.75f, 251.457f, 318.637f, 261.25f, 315.746f, 261.25f, 315.746f, 271.473f, 314.078f, 
+275.246f, 330.746f, 275.246f, 330.742f, 280.5f, 337.559f, 288.246f, 340.75f, 296.34f, 343.719f, 
+304.258f, 389.477f, 300.246f, 398.746f, 295.457f, 407.078f, 279.617f, 411.918f, 262.25f, 394.746f, 
+244.418f, 377.598f, 242.219f, 396.078f, 209.246f, 387.746f, 10, 0, 1, 1, 
+0.8f, 1, 1, 0.8f, 7, 211.246f, 305.75f, 211.246f, 305.75f, 210.098f, 
+308.078f, 205.25f, 308.746f, 205.25f, 308.742f, 180.617f, 312.477f, 171.246f, 325.75f, 171.246f, 
+325.75f, 163.898f, 332.277f, 168.25f, 319.746f, 168.25f, 319.742f, 180.18f, 297.078f, 187.246f, 
+293.746f, 187.246f, 293.746f, 205.699f, 289.598f, 211.246f, 305.75f, 10, 0.55f, 0, 
+0, 0, 0, 0, 0, 7, 211.246f, 305.75f, 211.246f, 305.75f, 
+210.098f, 308.078f, 205.25f, 308.746f, 205.25f, 308.742f, 180.617f, 312.477f, 171.246f, 325.75f, 
+171.246f, 325.75f, 163.898f, 332.277f, 168.25f, 319.746f, 168.25f, 319.742f, 180.18f, 297.078f, 
+187.246f, 293.746f, 187.246f, 293.746f, 205.699f, 289.598f, 211.246f, 305.75f, 10, 0, 
+0.8f, 0.25f, 0.3f, 0.8f, 0.25f, 0.3f, 9, 299.246f, 375.75f, 299.641f, 
+384.941f, 301.789f, 394.418f, 300.246f, 398.746f, 292.766f, 412.461f, 274.098f, 406.535f, 262.25f, 
+394.746f, 244.418f, 377.598f, 242.219f, 396.078f, 209.246f, 387.746f, 209.246f, 387.742f, 207.297f, 
+372.797f, 208.25f, 361.746f, 208.25f, 361.742f, 249.258f, 374.516f, 250.25f, 368.746f, 250.25f, 
+368.746f, 251.898f, 371.879f, 262.25f, 371.75f, 272.137f, 371.879f, 297.152f, 373.168f, 299.246f, 
+375.75f, 10, 2.2f, 0.65f, 0.1f, 0.15f, 0.65f, 0.1f, 0.15f, 3, 
+251.25f, 387.746f, 251.25f, 387.742f, 256.738f, 381.996f, 253.246f, 371.75f, 253.246f, 371.75f, 
+236.938f, 353.836f, 239.25f, 338.75f, 10, 0, 1, 1, 0.8f, 1, 
+1, 0.8f, 5, 198.246f, 293.746f, 198.246f, 293.746f, 193.816f, 308.078f, 203.25f, 
+300.75f, 203.25f, 300.75f, 208.777f, 298.398f, 207.25f, 296.75f, 206.137f, 294.879f, 199.977f, 
+290.477f, 198.246f, 293.746f, 10, 0.55f, 0, 0, 0, 0, 0, 
+0, 5, 198.246f, 293.746f, 198.246f, 293.746f, 193.816f, 308.078f, 203.25f, 300.75f, 
+203.25f, 300.75f, 208.777f, 298.398f, 207.25f, 296.75f, 206.137f, 294.879f, 199.977f, 290.477f, 
+198.246f, 293.746f, 10, 0, 1, 1, 0.8f, 1, 1, 0.8f, 
+5, 204.25f, 292.75f, 204.25f, 292.75f, 200.328f, 303.941f, 208.25f, 297.746f, 208.25f, 
+297.742f, 212.937f, 295.266f, 211.246f, 294.75f, 206.227f, 293.383f, 211.242f, 290.566f, 204.25f, 
+292.75f, 10, 0.55f, 0, 0, 0, 0, 0, 0, 5, 
+204.25f, 292.75f, 204.25f, 292.75f, 200.328f, 303.941f, 208.25f, 297.746f, 208.25f, 297.742f, 
+212.937f, 295.266f, 211.246f, 294.75f, 206.227f, 293.383f, 211.242f, 290.566f, 204.25f, 292.75f, 
+10, 0, 1, 1, 0.8f, 1, 1, 0.8f, 5, 209.246f, 
+292.75f, 209.246f, 292.75f, 205.609f, 303.941f, 213.246f, 297.746f, 213.242f, 297.742f, 218.168f, 
+295.414f, 216.25f, 294.75f, 212.824f, 293.383f, 216.523f, 290.566f, 209.246f, 292.75f, 10, 
+0.55f, 0, 0, 0, 0, 0, 0, 5, 209.246f, 292.75f, 
+209.246f, 292.75f, 205.609f, 303.941f, 213.246f, 297.746f, 213.242f, 297.742f, 218.168f, 295.414f, 
+216.25f, 294.75f, 212.824f, 293.383f, 216.523f, 290.566f, 209.246f, 292.75f, 10, 0, 
+1, 1, 0.8f, 1, 1, 0.8f, 5, 216.25f, 292.75f, 216.25f, 
+292.75f, 212.871f, 303.723f, 220.246f, 297.746f, 220.246f, 297.742f, 225.434f, 295.172f, 224.246f, 
+294.75f, 220.527f, 293.383f, 223.781f, 290.344f, 216.25f, 292.75f, 10, 0.55f, 0, 
+0, 0, 0, 0, 0, 5, 216.25f, 292.75f, 216.25f, 292.75f, 
+212.871f, 303.723f, 220.246f, 297.746f, 220.246f, 297.742f, 225.434f, 295.172f, 224.246f, 294.75f, 
+220.527f, 293.383f, 223.781f, 290.344f, 216.25f, 292.75f, 10, 0, 1, 1, 
+0.8f, 1, 1, 0.8f, 5, 224.246f, 292.75f, 224.242f, 292.75f, 220, 
+303.809f, 227.25f, 297.746f, 227.25f, 297.742f, 231.969f, 296.066f, 231.246f, 294.75f, 229.855f, 
+293.25f, 230.91f, 290.434f, 224.246f, 292.75f, 10, 0.55f, 0, 0, 0, 
+0, 0, 0, 5, 224.246f, 292.75f, 224.242f, 292.75f, 220, 303.809f, 
+227.25f, 297.746f, 227.25f, 297.742f, 231.969f, 296.066f, 231.246f, 294.75f, 229.855f, 293.25f, 
+230.91f, 290.434f, 224.246f, 292.75f, 10, 0, 1, 1, 0.8f, 1, 
+1, 0.8f, 5, 231.246f, 291.746f, 231.246f, 291.746f, 225.938f, 305.438f, 236.25f, 
+298.75f, 236.25f, 298.75f, 241.34f, 296.195f, 240.25f, 294.75f, 238.699f, 292.676f, 240.02f, 
+289.156f, 231.246f, 291.746f, 10, 0.55f, 0, 0, 0, 0, 0, 
+0, 5, 231.246f, 291.746f, 231.246f, 291.746f, 225.938f, 305.438f, 236.25f, 298.75f, 
+236.25f, 298.75f, 241.34f, 296.195f, 240.25f, 294.75f, 238.699f, 292.676f, 240.02f, 289.156f, 
+231.246f, 291.746f, 10, 2.2f, 0.65f, 0.15f, 0.3f, 0.65f, 0.15f, 0.3f, 
+4, 200.246f, 310.746f, 200.246f, 310.742f, 214.5f, 313.797f, 221.246f, 310.746f, 221.246f, 
+310.742f, 227.699f, 308.957f, 229.25f, 309.75f, 230.34f, 309.836f, 234.246f, 310.746f, 234.246f, 
+310.746f, 10, 2.2f, 0.65f, 0.15f, 0.3f, 0.65f, 0.15f, 0.3f, 4, 
+237.25f, 300.75f, 237.25f, 300.75f, 250.578f, 315.996f, 264.246f, 310.746f, 271.496f, 308.328f, 
+270.379f, 312.035f, 271.25f, 314.75f, 272.137f, 318.195f, 272.359f, 322.816f, 278.246f, 325.75f, 
+10, 0, 1, 1, 0.8f, 1, 1, 0.8f, 7, 256.246f, 
+318.75f, 256.246f, 318.75f, 251.898f, 330.516f, 249.25f, 316.75f, 245.738f, 302.355f, 242.219f, 
+298.398f, 240.25f, 295.746f, 240.25f, 295.742f, 240.457f, 289.598f, 249.25f, 289.75f, 249.25f, 
+289.75f, 261.578f, 290.477f, 262.25f, 293.746f, 262.457f, 296.637f, 260.699f, 309.398f, 256.246f, 
+318.75f, 10, 0.55f, 0, 0, 0, 0, 0, 0, 7, 
+256.246f, 318.75f, 256.246f, 318.75f, 251.898f, 330.516f, 249.25f, 316.75f, 245.738f, 302.355f, 
+242.219f, 298.398f, 240.25f, 295.746f, 240.25f, 295.742f, 240.457f, 289.598f, 249.25f, 289.75f, 
+249.25f, 289.75f, 261.578f, 290.477f, 262.25f, 293.746f, 262.457f, 296.637f, 260.699f, 309.398f, 
+256.246f, 318.75f, 10, 2.2f, 0.65f, 0.15f, 0.3f, 0.65f, 0.15f, 0.3f, 
+2, 271.25f, 310.746f, 271.25f, 310.742f, 275.656f, 313.355f, 278.246f, 311.75f, 10, 
+2.2f, 0.65f, 0.15f, 0.3f, 0.65f, 0.15f, 0.3f, 2, 279.246f, 328.746f, 
+279.242f, 328.742f, 282.039f, 334.148f, 287.246f, 334.75f, 10, 0, 0.7f, 0.7f, 
+0.7f, 0.7f, 0.7f, 0.7f, 6, 191.246f, 288.746f, 191.242f, 288.742f, 211.418f, 
+284.758f, 216.25f, 286.746f, 216.25f, 286.742f, 225.938f, 286.516f, 216.25f, 284.746f, 216.25f, 
+284.742f, 202.617f, 284.316f, 194.25f, 285.75f, 194.25f, 285.75f, 181.059f, 291.797f, 191.246f, 
+288.746f, 10, 0, 1, 1, 0.8f, 1, 1, 0.8f, 7, 
+207.25f, 390.746f, 207.25f, 390.746f, 226.379f, 390.797f, 228.25f, 389.75f, 228.25f, 389.75f, 
+236.5f, 356.035f, 232.246f, 347.75f, 232.246f, 347.75f, 231.219f, 344.598f, 228.25f, 350.746f, 
+228.25f, 350.742f, 207.898f, 386.836f, 204.25f, 388.75f, 200.859f, 391.238f, 205.699f, 390.797f, 
+207.25f, 390.746f, 10, 0.55f, 0, 0, 0, 0, 0, 0, 
+7, 207.25f, 390.746f, 207.25f, 390.746f, 226.379f, 390.797f, 228.25f, 389.75f, 228.25f, 
+389.75f, 236.5f, 356.035f, 232.246f, 347.75f, 232.246f, 347.75f, 231.219f, 344.598f, 228.25f, 
+350.746f, 228.25f, 350.742f, 207.898f, 386.836f, 204.25f, 388.75f, 200.859f, 391.238f, 205.699f, 
+390.797f, 207.25f, 390.746f, 10, 0, 1, 1, 0.8f, 1, 1, 
+0.8f, 7, 122.246f, 393.75f, 122.246f, 393.75f, 132, 391.898f, 146.25f, 388.75f, 
+146.25f, 388.75f, 151.137f, 364.398f, 154.246f, 358.75f, 158.18f, 353.836f, 154.219f, 353.836f, 
+150.246f, 356.75f, 146.297f, 359.996f, 130.02f, 375.398f, 128.25f, 379.746f, 125.617f, 385.078f, 
+122.246f, 393.75f, 122.246f, 393.75f, 10, 0.55f, 0, 0, 0, 0, 
+0, 0, 7, 122.246f, 393.75f, 122.246f, 393.75f, 132, 391.898f, 146.25f, 
+388.75f, 146.25f, 388.75f, 151.137f, 364.398f, 154.246f, 358.75f, 158.18f, 353.836f, 154.219f, 
+353.836f, 150.246f, 356.75f, 146.297f, 359.996f, 130.02f, 375.398f, 128.25f, 379.746f, 125.617f, 
+385.078f, 122.246f, 393.75f, 122.246f, 393.75f, 10, 0, 1, 1, 0.8f, 
+1, 1, 0.8f, 6, 146.25f, 388.75f, 146.25f, 388.75f, 152.637f, 387.094f, 
+153.246f, 384.75f, 154.855f, 382.223f, 152.25f, 378.75f, 152.25f, 378.75f, 152.25f, 378.75f, 
+151.324f, 374.961f, 150.246f, 377.75f, 148.68f, 379.719f, 145.52f, 388.145f, 146.25f, 388.75f, 
+10, 0.55f, 0, 0, 0, 0, 0, 0, 6, 146.25f, 
+388.75f, 146.25f, 388.75f, 152.637f, 387.094f, 153.246f, 384.75f, 154.855f, 382.223f, 152.25f, 
+378.75f, 152.25f, 378.75f, 152.25f, 378.75f, 151.324f, 374.961f, 150.246f, 377.75f, 148.68f, 
+379.719f, 145.52f, 388.145f, 146.25f, 388.75f, 10, 0, 0, 0, 0, 
+0, 0, 0, 10, 146.25f, 388.75f, 146.25f, 388.75f, 150.258f, 383.316f, 
+154.246f, 383.746f, 158.18f, 383.316f, 158.598f, 383.77f, 161.246f, 382.75f, 166.758f, 381.996f, 
+166.316f, 384.195f, 173.25f, 382.75f, 176.48f, 382.348f, 179.297f, 383.316f, 182.25f, 381.746f, 
+185.457f, 380.676f, 188.977f, 381.559f, 190.246f, 383.746f, 191.617f, 385.957f, 197.25f, 390.746f, 
+197.25f, 390.746f, 197.25f, 390.746f, 182.816f, 388.598f, 179.246f, 387.746f, 179.246f, 387.742f, 
+155.098f, 386.398f, 146.25f, 388.75f, 10, 0, 1, 1, 0.8f, 1, 
+1, 0.8f, 6, 195.25f, 388.75f, 195.25f, 388.75f, 188.262f, 384.969f, 188.246f, 
+382.75f, 187.383f, 379.688f, 193.25f, 375.75f, 193.25f, 375.75f, 193.25f, 375.75f, 196.625f, 
+370.559f, 197.25f, 372.746f, 197.941f, 375.836f, 196.238f, 388.379f, 195.25f, 388.75f, 10, 
+0.55f, 0, 0, 0, 0, 0, 0, 6, 195.25f, 388.75f, 
+195.25f, 388.75f, 188.262f, 384.969f, 188.246f, 382.75f, 187.383f, 379.688f, 193.25f, 375.75f, 
+193.25f, 375.75f, 193.25f, 375.75f, 196.625f, 370.559f, 197.25f, 372.746f, 197.941f, 375.836f, 
+196.238f, 388.379f, 195.25f, 388.75f, 10, 0, 1, 1, 0.8f, 1, 
+1, 0.8f, 5, 154.246f, 382.75f, 154.242f, 382.75f, 161.832f, 370.5f, 162.25f, 
+382.75f, 162.25f, 382.75f, 162.684f, 384.215f, 160.246f, 383.746f, 154.066f, 384.324f, 155.738f, 
+388.836f, 154.246f, 382.75f, 10, 0.55f, 0, 0, 0, 0, 0, 
+0, 5, 154.246f, 382.75f, 154.242f, 382.75f, 161.832f, 370.5f, 162.25f, 382.75f, 
+162.25f, 382.75f, 162.684f, 384.215f, 160.246f, 383.746f, 154.066f, 384.324f, 155.738f, 388.836f, 
+154.246f, 382.75f, 10, 0, 1, 1, 0.8f, 1, 1, 0.8f, 
+5, 162.25f, 382.75f, 162.25f, 382.75f, 170.734f, 370.227f, 170.246f, 382.75f, 170.242f, 
+382.75f, 170.043f, 383, 168.25f, 382.75f, 162.891f, 383.625f, 163.27f, 388.594f, 162.25f, 
+382.75f, 10, 0.55f, 0, 0, 0, 0, 0, 0, 5, 
+162.25f, 382.75f, 162.25f, 382.75f, 170.734f, 370.227f, 170.246f, 382.75f, 170.242f, 382.75f, 
+170.043f, 383, 168.25f, 382.75f, 162.891f, 383.625f, 163.27f, 388.594f, 162.25f, 382.75f, 
+10, 0, 1, 1, 0.8f, 1, 1, 0.8f, 5, 170.246f, 
+382.75f, 170.242f, 382.75f, 178.711f, 370.832f, 178.246f, 381.746f, 178.246f, 381.746f, 178.105f, 
+382.82f, 176.246f, 382.75f, 172.004f, 383.93f, 171.773f, 387.504f, 170.246f, 382.75f, 10, 
+0.55f, 0, 0, 0, 0, 0, 0, 5, 170.246f, 382.75f, 
+170.242f, 382.75f, 178.711f, 370.832f, 178.246f, 381.746f, 178.246f, 381.746f, 178.105f, 382.82f, 
+176.246f, 382.75f, 172.004f, 383.93f, 171.773f, 387.504f, 170.246f, 382.75f, 10, 0, 
+1, 1, 0.8f, 1, 1, 0.8f, 5, 177.246f, 382.75f, 177.246f, 
+382.75f, 186.207f, 369.719f, 186.25f, 380.75f, 186.25f, 380.75f, 188.398f, 381.992f, 186.25f, 
+381.746f, 180.078f, 383.051f, 180.957f, 387.953f, 177.246f, 382.75f, 10, 0.55f, 0, 
+0, 0, 0, 0, 0, 5, 177.246f, 382.75f, 177.246f, 382.75f, 
+186.207f, 369.719f, 186.25f, 380.75f, 186.25f, 380.75f, 188.398f, 381.992f, 186.25f, 381.746f, 
+180.078f, 383.051f, 180.957f, 387.953f, 177.246f, 382.75f, 10, 0, 0.9f, 0.9f, 
+0.7f, 0.9f, 0.9f, 0.7f, 6, 137.246f, 378.75f, 129.25f, 379.746f, 126.441f, 
+385.738f, 124.25f, 392.746f, 124.25f, 392.746f, 124.25f, 392.746f, 131.117f, 391.402f, 145.25f, 
+388.75f, 145.25f, 388.75f, 145.832f, 384.672f, 147.25f, 378.75f, 137.246f, 378.75f, 10, 
+0, 0.9f, 0.9f, 0.7f, 0.9f, 0.9f, 0.7f, 7, 209.246f, 383.746f, 
+207.469f, 386.437f, 206.02f, 388.371f, 205.25f, 388.75f, 201.992f, 390.891f, 206.547f, 390.477f, 
+208.25f, 390.746f, 208.25f, 390.746f, 226.02f, 390.477f, 228.25f, 389.75f, 228.25f, 389.75f, 
+228.668f, 387.18f, 229.25f, 383.746f, 229.25f, 383.742f, 218.32f, 385.66f, 209.246f, 383.746f, 
+10, 0, 0.8f, 0.45f, 0.15f, 0.8f, 0.45f, 0.15f, 10, 268.246f, 
+535.746f, 298.758f, 531.289f, 326.832f, 570.492f, 329.25f, 580.75f, 330.703f, 591.789f, 319.25f, 
+604.75f, 319.25f, 604.75f, 321.023f, 608.246f, 315.699f, 623.734f, 310.246f, 633.75f, 304.082f, 
+644.063f, 286.594f, 642.992f, 267.246f, 643.75f, 249.875f, 645.031f, 229.547f, 619.379f, 228.25f, 
+617.75f, 226.641f, 615.508f, 233.418f, 573.398f, 235.246f, 566.75f, 236.32f, 560.813f, 233.246f, 
+531.75f, 233.246f, 531.75f, 271.082f, 541.781f, 237.773f, 540, 268.246f, 535.746f, 10, 
+0, 0.92f, 0.56f, 0.32f, 0.92f, 0.56f, 0.32f, 10, 229.25f, 616.746f, 
+227.469f, 614.828f, 234.121f, 573.484f, 235.246f, 567.75f, 236.973f, 561.129f, 234.246f, 532.746f, 
+234.246f, 532.746f, 270.063f, 542.387f, 238.398f, 540.695f, 268.246f, 536.75f, 298.273f, 532.141f, 
+325.836f, 570.633f, 327.25f, 580.75f, 329.637f, 591.543f, 318.25f, 604.75f, 318.25f, 604.75f, 
+320.133f, 607.699f, 314.906f, 622.906f, 309.246f, 632.75f, 303.504f, 642.867f, 286.332f, 641.813f, 
+267.246f, 642.746f, 250.277f, 643.816f, 230.32f, 618.629f, 229.25f, 616.746f, 10, 0, 
+0.94f, 0.67f, 0.49f, 0.94f, 0.67f, 0.49f, 10, 229.25f, 615.75f, 228.297f, 
+614.152f, 234.824f, 573.574f, 236.25f, 567.75f, 237.625f, 561.445f, 235.246f, 533.746f, 235.246f, 
+533.746f, 269.371f, 543.539f, 239.023f, 541.391f, 268.246f, 536.75f, 297.793f, 532.996f, 324.844f, 
+570.773f, 326.25f, 580.75f, 328.574f, 591.297f, 318.25f, 603.746f, 318.25f, 603.746f, 319.246f, 
+607.156f, 314.113f, 622.078f, 308.246f, 631.746f, 302.922f, 641.668f, 286.066f, 640.637f, 267.246f, 
+641.75f, 250.684f, 642.602f, 231.094f, 617.883f, 229.25f, 615.75f, 10, 0, 0.96f, 
+0.78f, 0.66f, 0.96f, 0.78f, 0.66f, 10, 230.25f, 615.75f, 229.125f, 613.473f, 
+235.531f, 573.66f, 237.25f, 567.75f, 238.277f, 561.762f, 235.246f, 534.75f, 235.246f, 534.75f, 
+267.91f, 544.25f, 239.648f, 542.086f, 268.246f, 537.746f, 297.309f, 533.852f, 323.848f, 570.914f, 
+325.25f, 580.75f, 327.508f, 591.051f, 317.25f, 603.746f, 317.25f, 603.746f, 318.355f, 606.609f, 
+313.324f, 621.254f, 308.246f, 630.75f, 302.34f, 640.473f, 285.805f, 639.457f, 267.246f, 640.746f, 
+251.09f, 641.387f, 231.871f, 617.133f, 230.25f, 615.75f, 10, 0, 0.98f, 0.89f, 
+0.83f, 0.98f, 0.89f, 0.83f, 10, 231.246f, 614.746f, 229.949f, 612.797f, 236.234f, 
+573.75f, 237.25f, 567.75f, 238.926f, 562.082f, 236.25f, 534.75f, 236.25f, 534.75f, 266.891f, 
+544.965f, 240.273f, 542.781f, 268.246f, 538.75f, 296.824f, 534.703f, 322.855f, 571.055f, 324.246f, 
+580.75f, 326.445f, 590.805f, 316.25f, 602.75f, 316.25f, 602.75f, 317.469f, 606.063f, 312.531f, 
+620.426f, 307.25f, 629.746f, 301.762f, 639.273f, 285.543f, 638.281f, 267.246f, 639.75f, 251.492f, 
+640.172f, 232.645f, 616.387f, 231.246f, 614.746f, 10, 0, 1, 1, 1, 
+1, 1, 1, 10, 268.246f, 539.746f, 296.34f, 535.559f, 321.859f, 571.199f, 
+323.246f, 580.75f, 325.379f, 590.559f, 315.25f, 602.75f, 315.25f, 602.75f, 316.578f, 605.52f, 
+311.738f, 619.598f, 306.25f, 628.75f, 301.18f, 638.078f, 285.277f, 637.102f, 267.246f, 637.75f, 
+251.898f, 638.957f, 233.418f, 615.637f, 232.246f, 613.75f, 230.777f, 612.117f, 236.938f, 573.84f, 
+238.25f, 567.75f, 239.578f, 562.398f, 237.25f, 535.746f, 237.25f, 535.746f, 264.988f, 545.457f, 
+240.898f, 543.477f, 268.246f, 539.746f, 10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 
+0.8f, 0.8f, 6, 319.25f, 576.746f, 319.25f, 576.742f, 289.078f, 568.559f, 276.246f, 
+570.746f, 276.246f, 570.746f, 258.937f, 577.578f, 249.25f, 553.75f, 249.25f, 553.75f, 245.297f, 
+545.68f, 243.246f, 543.746f, 240.898f, 541.277f, 319.25f, 576.746f, 319.25f, 576.746f, 10, 
+0, 0, 0, 0, 0, 0, 0, 11, 324.246f, 579.746f, 
+324.242f, 579.746f, 291.937f, 565.918f, 281.25f, 566.75f, 281.25f, 566.75f, 262.898f, 571.418f, 
+253.246f, 555.75f, 253.246f, 555.75f, 244.418f, 545.238f, 241.25f, 543.746f, 241.25f, 543.742f, 
+240.457f, 541.719f, 247.246f, 545.75f, 259.25f, 540.75f, 259.25f, 540.75f, 275.219f, 529.84f, 
+286.246f, 547.75f, 286.246f, 547.75f, 290.18f, 559.758f, 290.246f, 561.746f, 290.18f, 564.156f, 
+313.5f, 570.316f, 315.25f, 570.746f, 317.02f, 571.199f, 324.277f, 575.816f, 324.246f, 579.746f, 
+10, 0, 0.6f, 0.8f, 0.2f, 0.6f, 0.8f, 0.2f, 6, 271.25f, 
+539.746f, 264.141f, 539.832f, 254.93f, 544.086f, 255.246f, 550.746f, 254.93f, 557.832f, 264.141f, 
+564.723f, 271.25f, 564.75f, 279.258f, 564.723f, 285.387f, 559.152f, 285.25f, 552.746f, 285.387f, 
+545.402f, 279.258f, 539.832f, 271.25f, 539.746f, 10, 0, 0.4f, 0.6f, 0, 
+0.4f, 0.6f, 0, 6, 267.246f, 557.746f, 262.383f, 557.391f, 256.785f, 555.738f, 
+257.246f, 555.75f, 258.559f, 561.055f, 265.555f, 564.723f, 271.25f, 564.75f, 276.422f, 564.723f, 
+280.59f, 562.547f, 283.25f, 558.75f, 283.25f, 558.75f, 277.203f, 559.598f, 267.246f, 557.746f, 
+10, 0, 1, 1, 1, 1, 1, 1, 4, 281.25f, 
+558.75f, 281.25f, 558.75f, 276.098f, 561.957f, 276.246f, 559.746f, 276.246f, 559.746f, 280.059f, 
+554.699f, 281.25f, 558.75f, 10, 0, 0, 0, 0, 0, 0, 
+0, 6, 270.25f, 549.75f, 267.187f, 549.5f, 264.961f, 551.727f, 265.246f, 554.746f, 
+264.961f, 557.227f, 267.187f, 559.457f, 270.25f, 559.746f, 272.687f, 559.457f, 274.918f, 557.227f, 
+275.246f, 554.746f, 274.918f, 551.727f, 272.687f, 549.5f, 270.25f, 549.75f, 10, 0, 
+0.8f, 0.45f, 0.15f, 0.8f, 0.45f, 0.15f, 15, 155.246f, 563.746f, 155.246f, 
+563.742f, 152.02f, 587.477f, 154.246f, 592.746f, 154.242f, 592.746f, 166.539f, 603.316f, 166.246f, 
+607.746f, 166.246f, 607.742f, 165.656f, 627.078f, 164.246f, 627.746f, 163.02f, 628.84f, 154.656f, 
+635.438f, 148.246f, 628.75f, 148.242f, 628.75f, 136.617f, 608.598f, 137.246f, 601.746f, 137.246f, 
+599.75f, 137.242f, 599.75f, 129.137f, 599.797f, 127.246f, 597.75f, 127.246f, 597.75f, 126.059f, 
+591.879f, 124.25f, 591.75f, 124.25f, 591.75f, 121.656f, 588.797f, 124.25f, 585.746f, 124.25f, 
+585.742f, 121.656f, 583.078f, 122.246f, 578.75f, 130.25f, 574.746f, 130.25f, 574.742f, 132.656f, 
+558.438f, 144.246f, 552.746f, 149.859f, 550.156f, 153.34f, 557.559f, 155.246f, 563.746f, 10, 
+0, 1, 1, 1, 1, 1, 1, 15, 154.246f, 565.746f, 
+154.242f, 565.742f, 151.27f, 587.172f, 153.246f, 591.75f, 153.242f, 591.75f, 164.34f, 601.426f, 
+164.246f, 604.75f, 164.242f, 604.75f, 163.547f, 622.809f, 162.25f, 623.746f, 161.172f, 624.395f, 
+153.645f, 630.336f, 147.25f, 623.746f, 147.25f, 623.746f, 137.41f, 606.18f, 138.246f, 599.75f, 
+138.246f, 597.75f, 138.246f, 597.75f, 130.68f, 598.258f, 129.25f, 596.746f, 129.25f, 596.742f, 
+127.906f, 591.129f, 126.246f, 590.746f, 126.242f, 590.746f, 123.945f, 588.359f, 126.246f, 585.746f, 
+126.242f, 585.742f, 123.945f, 583.211f, 124.25f, 579.746f, 132.246f, 575.75f, 132.246f, 575.75f, 
+133.848f, 561.035f, 144.246f, 555.75f, 149.324f, 553.582f, 152.457f, 560.242f, 154.246f, 565.746f, 
+10, 0, 0.925f, 0.588f, 0.363f, 0.925f, 0.588f, 0.363f, 15, 164.246f, 
+626.75f, 162.645f, 627.816f, 154.406f, 634.16f, 148.246f, 627.746f, 148.242f, 627.742f, 136.816f, 
+607.992f, 137.246f, 600.75f, 137.246f, 598.746f, 137.242f, 598.742f, 129.523f, 599.414f, 128.25f, 
+597.75f, 128.25f, 597.75f, 126.52f, 591.691f, 125.25f, 591.75f, 125.25f, 591.75f, 122.23f, 
+588.688f, 124.25f, 585.746f, 124.25f, 585.742f, 122.23f, 583.109f, 122.246f, 578.75f, 131.246f, 
+574.746f, 131.242f, 574.742f, 132.953f, 559.086f, 144.246f, 553.75f, 149.723f, 551.012f, 153.117f, 
+558.23f, 155.246f, 564.75f, 155.246f, 564.75f, 151.832f, 587.402f, 154.246f, 591.75f, 154.242f, 
+591.75f, 165.988f, 602.844f, 165.246f, 606.75f, 165.242f, 606.75f, 165.129f, 626.012f, 164.246f, 
+626.75f, 10, 0, 0.95f, 0.725f, 0.575f, 0.95f, 0.725f, 0.575f, 15, 
+163.25f, 625.746f, 162.27f, 626.793f, 154.152f, 632.887f, 148.246f, 625.746f, 148.242f, 625.746f, 
+137.016f, 607.387f, 138.246f, 600.75f, 138.246f, 598.746f, 138.246f, 598.742f, 129.906f, 599.027f, 
+128.25f, 596.746f, 128.25f, 596.742f, 126.98f, 591.504f, 125.25f, 590.746f, 125.25f, 590.746f, 
+122.801f, 588.578f, 125.25f, 585.746f, 125.25f, 585.742f, 122.801f, 583.145f, 123.25f, 578.75f, 
+131.246f, 574.746f, 131.242f, 574.742f, 133.254f, 559.734f, 144.246f, 554.746f, 149.59f, 551.867f, 
+152.898f, 558.898f, 155.246f, 564.75f, 155.246f, 564.75f, 151.645f, 587.324f, 154.246f, 591.75f, 
+154.242f, 591.75f, 165.438f, 602.371f, 165.246f, 605.746f, 165.242f, 605.742f, 164.602f, 624.945f, 
+163.25f, 625.746f, 10, 0, 0.975f, 0.863f, 0.788f, 0.975f, 0.863f, 0.788f, 
+15, 163.25f, 624.75f, 161.895f, 625.77f, 153.898f, 631.609f, 148.246f, 624.75f, 148.242f, 
+624.75f, 137.211f, 606.781f, 138.246f, 600.75f, 138.246f, 597.75f, 138.246f, 597.75f, 130.293f, 
+598.645f, 128.25f, 596.746f, 128.25f, 596.742f, 127.445f, 591.316f, 126.246f, 590.746f, 126.242f, 
+590.746f, 123.375f, 588.469f, 125.25f, 585.746f, 125.25f, 585.742f, 123.375f, 583.176f, 124.25f, 
+578.75f, 131.246f, 574.746f, 131.242f, 574.742f, 133.551f, 560.387f, 144.246f, 554.746f, 149.457f, 
+552.727f, 152.68f, 559.57f, 154.246f, 565.746f, 154.242f, 565.742f, 151.457f, 587.246f, 154.246f, 
+591.75f, 154.242f, 591.75f, 164.887f, 601.898f, 164.246f, 605.746f, 164.242f, 605.742f, 164.074f, 
+623.879f, 163.25f, 624.75f, 10, 0, 1, 1, 1, 1, 1, 
+1, 15, 154.246f, 566.75f, 154.242f, 566.75f, 151.27f, 587.172f, 153.246f, 591.75f, 
+153.242f, 591.75f, 164.34f, 601.426f, 164.246f, 604.75f, 164.242f, 604.75f, 163.547f, 622.809f, 
+162.25f, 623.746f, 161.523f, 624.746f, 153.645f, 630.336f, 147.25f, 623.746f, 147.25f, 623.746f, 
+137.41f, 606.18f, 138.246f, 599.75f, 138.246f, 597.75f, 138.246f, 597.75f, 130.68f, 598.258f, 
+129.25f, 596.746f, 129.25f, 596.742f, 127.906f, 591.129f, 126.246f, 590.746f, 126.242f, 590.746f, 
+123.945f, 588.359f, 126.246f, 585.746f, 126.242f, 585.742f, 123.945f, 583.211f, 124.25f, 579.746f, 
+132.246f, 575.75f, 132.246f, 575.75f, 133.848f, 561.035f, 144.246f, 555.75f, 149.324f, 553.582f, 
+152.457f, 560.352f, 154.246f, 566.75f, 10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 
+0.8f, 0.8f, 5, 151.25f, 572.746f, 151.25f, 572.742f, 127.27f, 584.398f, 126.246f, 
+585.746f, 126.242f, 585.742f, 136.289f, 576.258f, 137.246f, 576.746f, 138.047f, 576.258f, 151.25f, 
+572.746f, 151.25f, 572.746f, 10, 0, 0, 0, 0, 0, 0, 
+0, 5, 132.246f, 579.746f, 132.246f, 579.746f, 152.457f, 576.039f, 152.25f, 570.746f, 
+152.457f, 567.996f, 152.191f, 553.234f, 146.25f, 554.746f, 137.059f, 557.559f, 141.02f, 573.398f, 
+132.246f, 579.746f, 10, 0, 0.6f, 0.8f, 0.2f, 0.6f, 0.8f, 0.2f, 
+5, 141.25f, 575.75f, 141.25f, 575.75f, 151.332f, 574.195f, 152.25f, 570.746f, 153.117f, 
+569.438f, 153.848f, 560.301f, 148.246f, 558.75f, 142.832f, 558.098f, 140.379f, 569.34f, 141.25f, 
+575.75f, 10, 0, 0, 0, 0, 0, 0, 0, 44, 
+236.25f, 528.746f, 235.504f, 530.93f, 236.949f, 530.785f, 239.25f, 531.75f, 241.117f, 532.039f, 
+254.539f, 536.219f, 255.246f, 538.75f, 256.297f, 541.938f, 271.25f, 536.75f, 271.25f, 536.75f, 
+272.797f, 536.219f, 277.246f, 533.746f, 277.246f, 533.746f, 282.918f, 532.039f, 290.246f, 531.75f, 
+290.246f, 531.75f, 292.816f, 530.5f, 296.25f, 527.75f, 296.25f, 527.75f, 312.617f, 516.199f, 
+326.25f, 523.75f, 326.25f, 523.75f, 348.258f, 531.379f, 341.25f, 550.746f, 341.25f, 550.746f, 
+338.359f, 560.199f, 342.246f, 563.746f, 342.246f, 563.746f, 342.098f, 568.117f, 350.25f, 560.75f, 
+350.25f, 560.75f, 352.879f, 556.457f, 354.246f, 550.746f, 354.246f, 550.746f, 362.559f, 538.637f, 
+359.25f, 557.746f, 359.25f, 557.746f, 359.039f, 559.316f, 355.961f, 563.277f, 356.246f, 564.75f, 
+355.961f, 565.918f, 354.246f, 569.75f, 354.246f, 569.75f, 350.68f, 573.398f, 353.246f, 580.75f, 
+353.246f, 580.75f, 355.301f, 596.277f, 353.246f, 594.746f, 353.246f, 594.746f, 351.559f, 596.277f, 
+341.25f, 585.746f, 341.25f, 585.746f, 339.02f, 581.539f, 332.246f, 579.746f, 332.246f, 579.746f, 
+329.34f, 577.797f, 325.25f, 579.746f, 325.25f, 579.746f, 322.738f, 579.777f, 316.25f, 571.75f, 
+316.25f, 571.75f, 319.66f, 572.297f, 322.301f, 567.457f, 325.25f, 566.75f, 327.578f, 567.02f, 
+329.559f, 569.879f, 331.246f, 570.746f, 333.078f, 571.199f, 336.25f, 564.75f, 336.25f, 564.75f, 
+336.598f, 561.957f, 330.25f, 556.75f, 330.25f, 556.75f, 330, 551.617f, 328.25f, 553.75f, 
+328.25f, 553.75f, 324.938f, 554.039f, 323.621f, 549.859f, 322.246f, 544.746f, 321.418f, 539.738f, 
+317.25f, 539.746f, 317.25f, 539.746f, 315.039f, 531.156f, 313.246f, 534.75f, 313.246f, 534.75f, 
+313.5f, 540.617f, 307.25f, 533.746f, 307.25f, 533.746f, 305.578f, 532.039f, 300.246f, 534.75f, 
+300.246f, 534.75f, 293.039f, 536.656f, 295.25f, 538.75f, 295.25f, 538.75f, 297.656f, 541.277f, 
+310.246f, 538.75f, 310.246f, 538.75f, 312.398f, 540.617f, 303.25f, 544.746f, 303.25f, 544.746f, 
+302.937f, 547, 304.25f, 551.75f, 304.25f, 551.75f, 305.359f, 555.359f, 313.246f, 561.746f, 
+313.246f, 561.746f, 323.18f, 562.84f, 320.246f, 564.75f, 320.246f, 564.75f, 313.277f, 570.316f, 
+307.25f, 561.746f, 307.25f, 561.746f, 304.477f, 555.137f, 285.25f, 538.75f, 285.25f, 538.75f, 
+280.059f, 534.898f, 282.918f, 542.379f, 278.246f, 538.75f, 274.117f, 534.898f, 251.25f, 544.746f, 
+251.25f, 544.746f, 238.738f, 546.109f, 235.734f, 528.793f, 232.246f, 531.75f, 232.246f, 531.75f, 
+237.813f, 522.855f, 236.25f, 528.746f, 10, 0, 0, 0, 0, 0, 
+0, 0, 12, 450.25f, 711.746f, 450.25f, 711.746f, 422.18f, 703.199f, 419.246f, 
+682.746f, 419.246f, 682.742f, 416.461f, 657.438f, 439.25f, 637.75f, 439.25f, 637.75f, 439.34f, 
+631.039f, 441.246f, 627.746f, 441.246f, 627.742f, 439.777f, 622.238f, 460.246f, 630.75f, 490.25f, 
+639.75f, 490.25f, 639.75f, 497.418f, 642.477f, 503.25f, 651.746f, 508.859f, 661.84f, 525.578f, 
+682.52f, 521.25f, 709.75f, 521.25f, 709.75f, 522.938f, 722.559f, 516.25f, 722.746f, 516.25f, 
+722.746f, 507.098f, 724.758f, 499.25f, 716.75f, 499.25f, 716.75f, 491.699f, 712.879f, 489.246f, 
+713.746f, 450.25f, 711.746f, 10, 0, 0, 0, 0, 0, 0, 
+0, 8, 510.25f, 712.75f, 510.25f, 712.75f, 512.73f, 722.91f, 507.25f, 717.746f, 
+507.25f, 717.742f, 499.664f, 711.293f, 491.246f, 711.746f, 491.242f, 711.746f, 475.465f, 708.875f, 
+470.25f, 694.75f, 470.25f, 694.75f, 466.266f, 664.828f, 475.25f, 658.746f, 475.25f, 658.746f, 
+480.305f, 650.309f, 488.25f, 657.75f, 495.793f, 664.828f, 512.844f, 698.082f, 510.25f, 712.75f, 
+10, 0, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 8, 510.25f, 
+712.75f, 510.25f, 712.75f, 512.309f, 722.313f, 507.25f, 716.75f, 507.25f, 716.75f, 499.48f, 
+710.906f, 491.246f, 710.746f, 491.242f, 710.742f, 475.719f, 708.531f, 471.246f, 694.75f, 471.242f, 
+694.75f, 466.691f, 665.289f, 475.25f, 658.746f, 475.25f, 658.746f, 480.469f, 651.031f, 488.25f, 
+657.75f, 495.68f, 665.289f, 512.387f, 697.961f, 510.25f, 712.75f, 10, 0, 0.4f, 
+0.4f, 0.4f, 0.4f, 0.4f, 0.4f, 8, 509.246f, 712.75f, 509.246f, 712.75f, 
+511.887f, 721.715f, 507.25f, 716.75f, 507.25f, 716.75f, 499.293f, 710.52f, 491.246f, 710.746f, 
+491.242f, 710.742f, 475.973f, 708.188f, 471.246f, 693.746f, 471.242f, 693.742f, 467.113f, 665.746f, 
+475.25f, 659.75f, 475.25f, 659.75f, 480.637f, 651.754f, 488.25f, 658.746f, 495.563f, 665.746f, 
+511.93f, 697.84f, 509.246f, 712.75f, 10, 0, 0.6f, 0.6f, 0.6f, 0.6f, 
+0.6f, 0.6f, 8, 509.246f, 711.746f, 509.246f, 711.746f, 511.465f, 721.113f, 506.246f, 
+715.746f, 506.242f, 715.742f, 499.109f, 710.133f, 491.246f, 709.75f, 491.242f, 709.75f, 476.23f, 
+707.844f, 471.246f, 693.746f, 471.242f, 693.742f, 467.535f, 666.203f, 476.246f, 660.746f, 476.246f, 
+660.742f, 480.805f, 652.477f, 488.25f, 659.75f, 495.449f, 666.203f, 511.477f, 697.719f, 509.246f, 
+711.746f, 10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 8, 
+509.246f, 711.746f, 509.246f, 711.746f, 511.043f, 720.516f, 506.246f, 715.746f, 506.242f, 715.742f, 
+498.926f, 709.746f, 491.246f, 709.75f, 491.242f, 709.75f, 476.484f, 707.5f, 472.25f, 693.746f, 
+472.25f, 693.742f, 467.957f, 666.66f, 476.246f, 660.746f, 476.246f, 660.742f, 480.973f, 653.195f, 
+488.25f, 659.75f, 495.332f, 666.66f, 511.02f, 697.598f, 509.246f, 711.746f, 10, 0, 
+1, 1, 1, 1, 1, 1, 8, 508.25f, 710.746f, 508.25f, 
+710.742f, 510.621f, 719.918f, 506.246f, 714.75f, 506.242f, 714.75f, 498.738f, 709.359f, 491.246f, 
+709.75f, 491.242f, 709.75f, 476.738f, 707.156f, 472.25f, 693.746f, 472.25f, 693.742f, 468.379f, 
+667.117f, 476.246f, 661.75f, 476.246f, 661.75f, 481.141f, 653.918f, 488.25f, 660.746f, 495.219f, 
+667.117f, 510.563f, 697.477f, 508.25f, 710.746f, 10, 0, 0.6f, 0.15f, 0, 
+0.6f, 0.15f, 0, 24, 275.246f, 487.75f, 275.246f, 487.75f, 253.219f, 508.719f, 
+244.246f, 509.75f, 244.246f, 509.75f, 206.578f, 514, 190.246f, 493.746f, 190.246f, 493.742f, 
+209.656f, 516.637f, 240.25f, 510.746f, 240.25f, 510.742f, 216.258f, 515.316f, 202.246f, 511.746f, 
+202.242f, 511.746f, 184.137f, 511.797f, 173.25f, 496.75f, 170.246f, 490.75f, 170.242f, 490.75f, 
+174.898f, 507.398f, 195.25f, 513.746f, 195.25f, 513.746f, 220.219f, 519.277f, 232.246f, 513.746f, 
+232.246f, 513.746f, 208.34f, 521.477f, 197.25f, 519.746f, 197.25f, 519.742f, 163.898f, 521.918f, 
+150.246f, 492.75f, 150.246f, 492.75f, 154.219f, 508.719f, 170.246f, 516.75f, 170.242f, 516.75f, 
+185.457f, 526.316f, 208.25f, 522.746f, 208.25f, 522.746f, 223.738f, 519.719f, 229.25f, 516.75f, 
+235.18f, 514.438f, 233.859f, 517.52f, 224.246f, 522.746f, 224.242f, 522.746f, 218.457f, 533.797f, 
+203.25f, 533.746f, 203.25f, 533.746f, 155.977f, 529.398f, 144.246f, 515.746f, 144.246f, 515.742f, 
+159.5f, 528.52f, 171.246f, 531.75f, 171.246f, 531.75f, 195.578f, 540.398f, 205.25f, 539.746f, 
+205.25f, 539.742f, 232.098f, 538.418f, 240.25f, 542.75f, 240.25f, 542.75f, 228.137f, 537.316f, 
+231.246f, 533.746f, 235.18f, 530.277f, 242.656f, 521.918f, 242.246f, 520.75f, 242.656f, 519.277f, 
+269.277f, 494.969f, 273.25f, 489.746f, 275.246f, 487.75f, 10, 0, 0.8f, 0.8f, 
+0.8f, 0.8f, 0.8f, 0.8f, 5, 428.25f, 273.746f, 428.25f, 273.742f, 410.848f, 
+314.348f, 397.246f, 324.746f, 397.246f, 324.746f, 425.699f, 307.199f, 429.25f, 287.75f, 429.25f, 
+287.75f, 429.547f, 276.398f, 428.25f, 273.746f, 10, 0, 0.8f, 0.8f, 0.8f, 
+0.8f, 0.8f, 0.8f, 7, 479.25f, 265.75f, 479.25f, 265.75f, 450.449f, 326.449f, 
+430.246f, 352.746f, 430.246f, 352.742f, 477.949f, 311.598f, 483.25f, 282.746f, 484.246f, 276.75f, 
+480.246f, 278.75f, 480.242f, 278.75f, 480.148f, 269.25f, 479.25f, 265.75f, 10, 0, 
+0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 5, 542.246f, 319.746f, 542.246f, 
+319.742f, 473, 384.75f, 471.246f, 387.746f, 471.242f, 387.742f, 537.898f, 314.898f, 541.25f, 
+306.746f, 541.25f, 306.742f, 539, 316.547f, 542.246f, 319.746f, 10, 0, 0.8f, 
+0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 6, 334.246f, 271.746f, 334.246f, 271.746f, 
+355.848f, 328.648f, 377.246f, 303.75f, 377.246f, 303.75f, 393.25f, 292.898f, 392.25f, 289.75f, 
+392.25f, 289.75f, 388.297f, 296.75f, 368.246f, 295.746f, 368.242f, 295.742f, 347.598f, 299.5f, 
+334.246f, 271.746f, 10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 
+5, 544.246f, 411.746f, 544.246f, 411.742f, 494.449f, 443.047f, 486.25f, 444.746f, 473.211f, 
+447.297f, 540.648f, 412.797f, 546.246f, 400.75f, 546.242f, 400.75f, 548.348f, 404, 544.246f, 
+411.746f, 10, 0, 0, 0, 0, 0, 0, 0, 63, 
+378.246f, 294.75f, 378.246f, 294.75f, 400.621f, 296.637f, 408.246f, 303.75f, 413.246f, 299.746f, 
+432.246f, 342.75f, 436.25f, 336.75f, 436.25f, 336.75f, 452.098f, 352.957f, 451.25f, 361.746f, 
+450.34f, 370.559f, 465.246f, 354.746f, 465.246f, 354.746f, 465.246f, 354.742f, 464.418f, 367.918f, 
+472.25f, 360.75f, 472.25f, 360.75f, 469.699f, 377.598f, 479.25f, 368.746f, 479.25f, 368.746f, 
+467.348f, 401.969f, 492.25f, 373.75f, 498.301f, 366.598f, 493.246f, 373.75f, 493.246f, 373.75f, 
+493.242f, 373.75f, 464.859f, 426.879f, 488.25f, 410.75f, 488.25f, 410.75f, 490.82f, 436.117f, 
+489.246f, 440.746f, 488.18f, 445.797f, 485.98f, 470.438f, 480.246f, 475.746f, 475.418f, 481.879f, 
+481.141f, 483.637f, 487.246f, 477.746f, 487.246f, 477.742f, 474.98f, 504.316f, 489.246f, 490.75f, 
+489.246f, 490.75f, 485.539f, 507.84f, 480.246f, 510.746f, 480.242f, 510.742f, 474.539f, 529.84f, 
+491.246f, 517.746f, 491.242f, 517.742f, 486.418f, 531.598f, 483.25f, 534.75f, 483.25f, 534.75f, 
+470.141f, 565.477f, 478.246f, 559.746f, 483.25f, 555.75f, 483.25f, 555.75f, 475.418f, 571.637f, 
+482.246f, 566.75f, 489.5f, 561.957f, 489.246f, 562.75f, 489.246f, 562.75f, 489.246f, 562.75f, 
+466.18f, 598.918f, 488.25f, 579.746f, 488.25f, 579.746f, 479.645f, 594.867f, 476.246f, 602.75f, 
+476.246f, 602.75f, 455.18f, 624.879f, 471.246f, 617.75f, 476.246f, 615.75f, 476.246f, 615.75f, 
+466.621f, 627.078f, 458.246f, 628.75f, 449.02f, 630.598f, 460.461f, 637.637f, 467.246f, 635.75f, 
+474.539f, 633.238f, 491.246f, 624.75f, 491.246f, 624.75f, 491.242f, 624.75f, 505.777f, 604.199f, 
+510.25f, 603.746f, 510.25f, 603.746f, 488.18f, 612.117f, 495.246f, 603.746f, 495.242f, 603.746f, 
+510.621f, 587.918f, 502.246f, 588.75f, 502.242f, 588.75f, 496.098f, 580.438f, 501.25f, 570.746f, 
+501.25f, 570.746f, 481.074f, 590.988f, 497.25f, 562.75f, 505.25f, 544.746f, 505.25f, 544.746f, 
+478.059f, 572.078f, 490.25f, 547.75f, 490.25f, 547.75f, 509.301f, 521.918f, 511.246f, 521.746f, 
+513.699f, 521.039f, 518.25f, 511.746f, 518.25f, 511.746f, 513.246f, 513.746f, 519.25f, 503.75f, 
+519.25f, 503.75f, 507.098f, 517.078f, 513.246f, 502.746f, 520.246f, 486.746f, 520.246f, 486.742f, 
+497.418f, 510.918f, 512.25f, 478.746f, 512.25f, 478.746f, 494.34f, 484.078f, 504.246f, 464.746f, 
+504.242f, 464.742f, 502.258f, 447.559f, 502.246f, 441.75f, 503.141f, 436.117f, 504.461f, 404.879f, 
+499.25f, 395.75f, 494.777f, 387.277f, 506.219f, 366.156f, 508.25f, 361.746f, 510.621f, 357.355f, 
+514.578f, 345.477f, 505.25f, 355.75f, 495.219f, 365.719f, 500.059f, 359.559f, 502.246f, 349.75f, 
+504.461f, 340.195f, 511.059f, 323.035f, 510.25f, 316.75f, 510.25f, 316.75f, 508.859f, 315.559f, 
+505.25f, 319.746f, 505.25f, 319.742f, 489.059f, 344.598f, 491.246f, 328.746f, 491.242f, 328.742f, 
+489.5f, 319.957f, 486.25f, 310.746f, 486.25f, 310.742f, 482.461f, 298.398f, 482.246f, 307.75f, 
+482.242f, 307.75f, 478.938f, 326.559f, 476.246f, 317.746f, 472.777f, 309.836f, 468.82f, 303.238f, 
+465.246f, 300.75f, 462.66f, 297.957f, 456.938f, 323.035f, 455.25f, 311.75f, 455.25f, 311.75f, 
+442.418f, 325.238f, 437.25f, 306.746f, 424.246f, 288.746f, 424.242f, 288.742f, 423.938f, 302.797f, 
+422.246f, 295.746f, 422.246f, 295.742f, 389.621f, 289.598f, 378.246f, 294.75f, 10, 0, 
+0, 0, 0, 0, 0, 0, 34, 340.25f, 686.746f, 340.25f, 
+686.742f, 327.578f, 695.719f, 323.246f, 695.746f, 318.777f, 694.84f, 353.539f, 704.957f, 399.246f, 
+674.75f, 399.246f, 674.75f, 404.141f, 671.52f, 408.246f, 671.746f, 408.246f, 671.742f, 411.621f, 
+669.316f, 408.246f, 665.75f, 408.246f, 665.75f, 398.859f, 654.797f, 411.246f, 642.746f, 411.246f, 
+642.742f, 431.418f, 635, 425.25f, 644.75f, 425.25f, 644.75f, 437.141f, 640.277f, 440.25f, 
+635.75f, 442.418f, 631.477f, 441.246f, 635.75f, 441.246f, 635.75f, 441.246f, 635.75f, 434.059f, 
+643.797f, 427.25f, 649.746f, 427.25f, 649.742f, 421.738f, 651.719f, 418.25f, 660.746f, 415.578f, 
+670.199f, 412.938f, 681.199f, 418.25f, 684.746f, 418.25f, 684.742f, 413.379f, 679.879f, 414.25f, 
+684.746f, 415.141f, 688.68f, 419.098f, 692.637f, 421.246f, 692.75f, 422.621f, 693.52f, 440.66f, 
+710.898f, 448.25f, 711.746f, 448.25f, 711.746f, 438.02f, 709.797f, 434.246f, 710.746f, 431.418f, 
+712, 402.16f, 724.539f, 395.25f, 725.75f, 395.25f, 725.75f, 377.078f, 733.117f, 390.246f, 
+730.746f, 390.242f, 730.742f, 429.66f, 726.738f, 449.25f, 711.746f, 449.25f, 711.746f, 441.758f, 
+721.457f, 421.246f, 728.746f, 421.246f, 728.742f, 397.098f, 743.02f, 358.25f, 737.746f, 358.25f, 
+737.742f, 338.801f, 734, 330.25f, 731.75f, 330.25f, 731.75f, 327.359f, 732.68f, 326.25f, 
+732.746f, 326.039f, 733.559f, 313.059f, 743.457f, 282.25f, 735.746f, 282.25f, 735.746f, 264, 
+730.699f, 254.246f, 725.75f, 254.246f, 725.75f, 237.816f, 724.098f, 234.246f, 720.75f, 234.246f, 
+720.75f, 213.398f, 704.52f, 211.246f, 703.75f, 209, 702.758f, 196.457f, 694.398f, 195.25f, 
+693.746f, 195.25f, 693.742f, 222.637f, 701.219f, 225.25f, 703.75f, 227.918f, 706.5f, 247.059f, 
+709.359f, 249.25f, 707.75f, 252.34f, 706.277f, 261.578f, 706.938f, 251.25f, 706.746f, 251.25f, 
+706.742f, 334.18f, 690, 335.246f, 687.75f, 335.938f, 685.598f, 340.25f, 686.746f, 340.25f, 
+686.746f, 10, 0, 0.8f, 0.45f, 0.15f, 0.8f, 0.45f, 0.15f, 13, 
+419.246f, 696.75f, 419.246f, 696.75f, 407.66f, 705.18f, 405.25f, 704.746f, 403.258f, 705.18f, 
+389.621f, 716.398f, 385.25f, 715.746f, 380.379f, 715.52f, 366.961f, 726.52f, 337.25f, 717.746f, 
+337.25f, 717.742f, 336.16f, 719.699f, 340.25f, 720.75f, 340.25f, 720.75f, 347.16f, 723, 
+347.25f, 723.75f, 347.25f, 723.75f, 369.82f, 728.277f, 377.246f, 724.746f, 377.246f, 724.746f, 
+387.859f, 721.457f, 394.25f, 714.75f, 394.25f, 714.75f, 407, 711.117f, 410.246f, 711.746f, 
+410.246f, 711.746f, 420.199f, 709.797f, 420.246f, 707.75f, 420.246f, 707.75f, 427.02f, 704.52f, 
+425.25f, 701.75f, 425.25f, 701.75f, 425.48f, 699.898f, 419.246f, 696.75f, 10, 0, 
+0.8f, 0.45f, 0.15f, 0.8f, 0.45f, 0.15f, 38, 405.25f, 699.746f, 406.047f, 
+698.664f, 407.168f, 698.555f, 408.246f, 697.746f, 408.094f, 697.32f, 407.773f, 696.961f, 407.25f, 
+696.75f, 406.281f, 696.504f, 405.121f, 697.133f, 404.25f, 696.75f, 403.422f, 696.258f, 402.715f, 
+696.457f, 402.246f, 696.75f, 400.313f, 697.105f, 398.301f, 697.137f, 396.25f, 696.75f, 394.254f, 
+697.621f, 391.66f, 696.977f, 389.246f, 697.746f, 389.309f, 698.109f, 389.063f, 697.727f, 389.246f, 
+697.746f, 385.629f, 699.016f, 381.512f, 698.707f, 379.246f, 700.746f, 376.168f, 701.672f, 373.574f, 
+702.18f, 371.25f, 702.746f, 368.906f, 703.488f, 367.355f, 704.574f, 365.246f, 705.75f, 364.059f, 
+706.27f, 362.457f, 706.844f, 361.25f, 707.75f, 358.719f, 707.75f, 356.703f, 707.625f, 354.246f, 
+707.75f, 354.52f, 708.227f, 354.309f, 707.848f, 354.246f, 707.75f, 353.863f, 707.996f, 353.543f, 
+708.637f, 353.246f, 708.746f, 351.508f, 708.004f, 349.871f, 709.074f, 348.25f, 708.746f, 346.742f, 
+710.043f, 344.844f, 709.773f, 343.246f, 710.746f, 339.883f, 711.195f, 336.414f, 709.797f, 333.246f, 
+710.746f, 337.602f, 712.926f, 342.758f, 711.57f, 347.25f, 713.746f, 349.789f, 715.148f, 352.715f, 
+713.938f, 355.246f, 714.75f, 356.078f, 714.934f, 356.84f, 715.152f, 357.246f, 714.75f, 357.426f, 
+714.566f, 357.625f, 714.828f, 357.246f, 714.75f, 360.387f, 713.527f, 362.934f, 712.125f, 365.246f, 
+710.746f, 366.039f, 710.793f, 366.621f, 711.047f, 367.246f, 710.746f, 368.57f, 709.488f, 370.711f, 
+709.602f, 372.25f, 708.746f, 374.105f, 708.809f, 376.078f, 708.391f, 378.246f, 708.746f, 378.066f, 
+709.109f, 378.324f, 708.734f, 378.246f, 708.746f, 379.602f, 709.582f, 380.875f, 709.281f, 382.25f, 
+708.746f, 382.227f, 708.82f, 382.957f, 708.551f, 383.25f, 708.746f, 384.531f, 708.164f, 385.473f, 
+707.637f, 387.246f, 707.75f, 386.895f, 707.414f, 387.098f, 707.789f, 387.246f, 707.75f, 388.41f, 
+707.277f, 389.559f, 707.34f, 390.246f, 705.75f, 390.426f, 706.207f, 390.609f, 706.469f, 390.246f, 
+706.746f, 391.828f, 706.066f, 392.543f, 705.238f, 394.25f, 704.746f, 394.289f, 704.855f, 394.961f, 
+704.168f, 395.25f, 703.75f, 398.227f, 703.168f, 400.254f, 701.488f, 402.246f, 700.746f, 403.5f, 
+700.16f, 404.465f, 699.902f, 405.25f, 699.746f, 10, 0, 0.8f, 0.45f, 0.15f, 
+0.8f, 0.45f, 0.15f, 23, 321.246f, 714.75f, 318.094f, 716.91f, 315.488f, 718.125f, 
+313.246f, 719.746f, 312.605f, 720.234f, 312.207f, 720.051f, 312.246f, 719.746f, 310.879f, 720.852f, 
+309.902f, 721.492f, 309.246f, 722.746f, 308.227f, 722.68f, 307.324f, 722.664f, 307.25f, 722.746f, 
+303.969f, 724.371f, 301.074f, 724.984f, 298.246f, 726.746f, 299.066f, 727, 300.301f, 726.73f, 
+301.246f, 727.75f, 301.172f, 727.309f, 301.434f, 726.996f, 302.246f, 726.746f, 303.668f, 728.203f, 
+305.703f, 728.371f, 307.25f, 728.746f, 309.422f, 728.172f, 311.313f, 727.836f, 313.246f, 727.75f, 
+313.605f, 727.484f, 313.824f, 726.91f, 314.25f, 726.746f, 316.629f, 726.074f, 319.258f, 726.648f, 
+321.246f, 725.75f, 323.336f, 725.035f, 325.066f, 724.133f, 326.25f, 722.746f, 326.703f, 722.441f, 
+326.348f, 722.113f, 326.25f, 721.746f, 326.465f, 722.02f, 326.766f, 721.793f, 327.25f, 721.746f, 
+326.98f, 721.184f, 326.98f, 720.852f, 327.25f, 720.75f, 326.766f, 720.246f, 326.457f, 720.133f, 
+326.25f, 719.746f, 324.5f, 719.871f, 326.449f, 721.387f, 325.25f, 720.75f, 324.277f, 720, 
+325.098f, 718.453f, 324.246f, 716.75f, 323.973f, 717.27f, 323.719f, 717.512f, 324.246f, 717.746f, 
+324.098f, 717.363f, 323.434f, 717.043f, 323.246f, 716.75f, 322.824f, 715.898f, 321.836f, 714.344f, 
+321.246f, 714.75f, 10, 0, 0.8f, 0.45f, 0.15f, 0.8f, 0.45f, 0.15f, 
+25, 285.25f, 706.746f, 281.645f, 707.801f, 278.293f, 707.676f, 275.246f, 708.746f, 274.898f, 
+709.109f, 274.656f, 708.727f, 274.25f, 708.746f, 273.082f, 709.41f, 272.07f, 710.473f, 271.25f, 
+711.746f, 269.883f, 712.602f, 268.059f, 712.176f, 266.246f, 712.75f, 266.301f, 712.848f, 266.078f, 
+713.41f, 266.246f, 713.746f, 264.406f, 713.625f, 263.387f, 714.672f, 262.25f, 715.746f, 264.809f, 
+716.172f, 267.461f, 716.137f, 270.25f, 716.75f, 270.293f, 716.582f, 270.453f, 716.227f, 270.25f, 
+715.746f, 270.746f, 716.227f, 270.891f, 716.469f, 271.25f, 716.75f, 271.254f, 716.309f, 271.586f, 
+715.953f, 272.25f, 715.746f, 272.469f, 716.824f, 273.082f, 716.617f, 273.25f, 716.75f, 273.836f, 
+716.563f, 273.973f, 716.227f, 274.25f, 715.746f, 274.27f, 716.227f, 274.41f, 716.57f, 274.25f, 
+716.75f, 274.707f, 716.57f, 274.852f, 716.227f, 275.246f, 715.746f, 275.148f, 716.227f, 275.289f, 
+716.469f, 275.246f, 716.75f, 276.199f, 715.758f, 277.172f, 716.367f, 278.246f, 715.746f, 279.219f, 
+715.922f, 279.512f, 714.656f, 280.246f, 714.75f, 285.879f, 712.895f, 290.43f, 710.535f, 295.25f, 
+707.75f, 295.566f, 708.078f, 295.801f, 707.805f, 295.25f, 707.75f, 295.973f, 707.379f, 296.316f, 
+707.477f, 296.25f, 707.75f, 297.688f, 706.523f, 298.832f, 705.922f, 299.246f, 704.746f, 299.84f, 
+704.34f, 299.477f, 703.895f, 299.246f, 703.75f, 294.348f, 705.047f, 289.941f, 705.715f, 285.25f, 
+706.746f, 10, 0, 0.8f, 0.45f, 0.15f, 0.8f, 0.45f, 0.15f, 10, 
+270.25f, 658.746f, 268.117f, 659.637f, 267.477f, 661.871f, 266.246f, 663.75f, 266, 664.215f, 
+266.301f, 664.563f, 266.246f, 664.746f, 267.266f, 664.832f, 267.863f, 664.309f, 268.246f, 663.75f, 
+270.234f, 663.137f, 271.922f, 661.77f, 274.25f, 661.75f, 276.309f, 659.16f, 280.992f, 658.738f, 
+281.25f, 654.75f, 281, 654.074f, 279.43f, 655.082f, 279.246f, 653.746f, 276.262f, 655.242f, 
+273.633f, 655.129f, 271.25f, 656.746f, 270.336f, 657.16f, 270.699f, 657.66f, 270.25f, 658.746f, 
+10, 0, 0.8f, 0.45f, 0.15f, 0.8f, 0.45f, 0.15f, 6, 239.25f, 
+715.746f, 239.727f, 716.129f, 247.461f, 715.871f, 247.246f, 715.746f, 247.391f, 715.406f, 238.891f, 
+714.254f, 238.25f, 714.75f, 238.309f, 714.523f, 230.047f, 711.852f, 230.25f, 711.746f, 230.191f, 
+712.148f, 239.285f, 716.129f, 239.25f, 715.746f, 10, 0, 0, 0, 0, 
+0, 0, 0, 80, 256.246f, 705.75f, 256.246f, 705.75f, 240.238f, 703.418f, 
+235.246f, 701.75f, 230.559f, 700.777f, 210.098f, 692.418f, 207.25f, 689.746f, 207.25f, 689.746f, 
+192.059f, 684.277f, 173.25f, 662.746f, 173.25f, 662.742f, 181.719f, 666.02f, 184.25f, 668.75f, 
+184.25f, 668.75f, 199.098f, 682.957f, 199.246f, 679.75f, 199.246f, 679.75f, 212.297f, 689.559f, 
+211.246f, 686.746f, 211.246f, 686.742f, 238.477f, 699.457f, 236.25f, 695.746f, 236.25f, 695.742f, 
+260.039f, 701, 259.25f, 698.75f, 259.25f, 698.75f, 279.617f, 693.957f, 276.246f, 693.746f, 
+276.246f, 693.742f, 270.156f, 692.418f, 277.246f, 688.746f, 277.246f, 688.742f, 273.457f, 683.617f, 
+267.246f, 687.75f, 261.578f, 692.418f, 264.879f, 690, 259.25f, 688.746f, 259.25f, 688.742f, 
+256.52f, 688.02f, 251.25f, 692.75f, 251.25f, 692.75f, 245.297f, 697.477f, 235.246f, 693.746f, 
+235.242f, 693.742f, 201.957f, 679.656f, 200.246f, 678.746f, 200.246f, 678.746f, 195.797f, 675.918f, 
+193.25f, 671.746f, 193.25f, 671.742f, 186.777f, 667.117f, 183.25f, 665.75f, 183.25f, 665.75f, 
+169.398f, 652.816f, 168.25f, 651.746f, 168.25f, 651.742f, 164.34f, 645.559f, 163.25f, 644.75f, 
+163.25f, 644.75f, 170.5f, 649.297f, 172.25f, 651.746f, 172.25f, 651.742f, 188.098f, 662.5f, 
+194.25f, 663.75f, 194.25f, 663.75f, 198.879f, 666.68f, 200.246f, 667.746f, 200.246f, 667.746f, 
+215.598f, 678.34f, 220.246f, 678.746f, 220.246f, 678.746f, 230.34f, 672.617f, 233.246f, 680.746f, 
+233.246f, 680.746f, 239.359f, 682.297f, 245.246f, 680.746f, 245.246f, 680.746f, 249.039f, 683.84f, 
+248.25f, 686.746f, 248.25f, 686.742f, 249.918f, 688.238f, 251.25f, 683.75f, 251.25f, 683.75f, 
+254.758f, 680.098f, 260.25f, 682.746f, 260.25f, 682.742f, 264.437f, 682.52f, 262.25f, 679.75f, 
+262.25f, 679.75f, 257.398f, 675.699f, 244.246f, 675.746f, 244.246f, 675.742f, 230.777f, 674.816f, 
+212.246f, 666.75f, 212.246f, 666.75f, 179.957f, 655.02f, 170.246f, 643.75f, 170.242f, 643.75f, 
+162.797f, 633.898f, 157.25f, 632.75f, 157.25f, 632.75f, 150.477f, 631.699f, 144.246f, 623.746f, 
+144.246f, 623.746f, 154.656f, 629.938f, 164.246f, 629.746f, 164.242f, 629.742f, 168.957f, 632.578f, 
+165.246f, 628.75f, 165.242f, 628.75f, 160.816f, 620.258f, 162.25f, 614.746f, 162.25f, 614.746f, 
+161.918f, 608.598f, 161.246f, 606.75f, 161.246f, 606.75f, 152.457f, 592.758f, 152.25f, 589.75f, 
+152.457f, 587.477f, 153.777f, 576.699f, 154.246f, 575.75f, 154.656f, 575.379f, 153.117f, 577.797f, 
+157.25f, 574.746f, 161.477f, 572.52f, 164.559f, 570.758f, 165.246f, 567.75f, 166.316f, 564.598f, 
+163.238f, 573.617f, 163.25f, 575.75f, 162.797f, 577.578f, 158.18f, 585.5f, 159.246f, 587.746f, 
+159.242f, 587.742f, 160.156f, 587.039f, 161.246f, 585.746f, 161.246f, 585.742f, 160.379f, 586.156f, 
+161.246f, 589.75f, 161.246f, 589.75f, 161.918f, 595.84f, 163.25f, 599.75f, 165, 602.879f, 
+167.199f, 607.059f, 167.25f, 607.746f, 168.078f, 608.816f, 168.078f, 615.199f, 169.25f, 612.746f, 
+173.25f, 609.746f, 173.25f, 609.742f, 170.277f, 612.34f, 172.25f, 614.746f, 172.25f, 614.746f, 
+171.598f, 620.918f, 173.25f, 623.746f, 173.25f, 623.746f, 181.277f, 633.02f, 183.25f, 633.75f, 
+184.797f, 635.219f, 183.25f, 634.746f, 183.25f, 634.746f, 183.25f, 634.746f, 189.859f, 639.398f, 
+183.25f, 637.75f, 183.25f, 637.75f, 179.078f, 635.879f, 176.246f, 635.75f, 176.246f, 635.75f, 
+167.418f, 633.68f, 172.25f, 638.746f, 176.219f, 642.918f, 187.219f, 648.859f, 191.246f, 648.75f, 
+192.25f, 646.75f, 204.25f, 649.746f, 203.25f, 648.75f, 203.25f, 648.75f, 203.059f, 648.859f, 
+207.25f, 649.746f, 212.297f, 649.738f, 218.68f, 648.199f, 220.246f, 649.746f, 221.758f, 652.156f, 
+225.5f, 653.258f, 225.25f, 651.746f, 224.617f, 650.18f, 224.246f, 647.746f, 224.246f, 647.746f, 
+224.242f, 647.746f, 229.898f, 654.359f, 229.25f, 651.746f, 228.578f, 649.52f, 219.559f, 643.797f, 
+218.25f, 636.746f, 229.25f, 645.746f, 233.246f, 649.746f, 233.246f, 649.742f, 237.379f, 646.879f, 
+237.25f, 648.75f, 237.816f, 650.398f, 242.879f, 656.777f, 244.246f, 656.746f, 245.52f, 656.34f, 
+247.719f, 659.418f, 247.246f, 656.746f, 247.277f, 653.699f, 255.246f, 647.746f, 255.246f, 647.746f, 
+255.246f, 647.746f, 259.156f, 649.738f, 260.25f, 647.746f, 262.238f, 646.656f, 267.246f, 669.746f, 
+267.246f, 669.746f, 294.25f, 681.75f, 342.246f, 685.75f, 323.246f, 692.75f, 256.246f, 705.75f, 
+10, 2.2f, 0.3f, 0, 0, 0.3f, 0, 0, 3, 276.246f, 
+486.746f, 276.246f, 486.742f, 260.039f, 504.977f, 251.25f, 507.75f, 251.25f, 507.75f, 236.059f, 
+515.316f, 209.246f, 506.746f, 10, 2.2f, 0.3f, 0, 0, 0.3f, 0, 
+0, 3, 247.246f, 509.75f, 247.242f, 509.75f, 219.559f, 518.18f, 202.246f, 513.746f, 
+202.242f, 513.746f, 182.379f, 511.359f, 173.25f, 495.746f, 10, 2.2f, 0.3f, 0, 
+0, 0.3f, 0, 0, 4, 243.246f, 510.746f, 243.246f, 510.742f, 224.617f, 
+518.617f, 208.25f, 520.75f, 208.25f, 520.75f, 190.078f, 523.898f, 172.25f, 515.746f, 172.25f, 
+515.742f, 158.398f, 509.379f, 152.25f, 497.746f, 10, 2.2f, 0.3f, 0, 0, 
+0.3f, 0, 0, 4, 244.246f, 510.746f, 244.246f, 510.742f, 227.477f, 522.359f, 
+226.25f, 523.75f, 226.25f, 523.75f, 218.68f, 536, 204.25f, 536.75f, 204.25f, 536.75f, 
+180.84f, 535.559f, 162.25f, 526.746f, 10, 0, 0, 0, 0, 0, 
+0, 0, 169, 243.246f, 519.746f, 244.68f, 518.543f, 274.25f, 486.746f, 274.25f, 
+486.746f, 313.059f, 446.457f, 282.25f, 483.75f, 282.25f, 483.75f, 273.898f, 489.359f, 264.246f, 
+509.75f, 264.246f, 509.75f, 262.457f, 513.117f, 279.246f, 501.75f, 279.246f, 501.75f, 283.578f, 
+501.238f, 298.246f, 479.75f, 298.246f, 479.75f, 291.059f, 482.758f, 296.25f, 474.75f, 296.25f, 
+474.75f, 299.418f, 472.637f, 322.246f, 455.746f, 322.246f, 455.746f, 325.82f, 451.078f, 330.25f, 
+449.746f, 330.25f, 449.746f, 345.621f, 455.035f, 338.25f, 440.746f, 338.25f, 440.746f, 341.219f, 
+433.035f, 347.25f, 445.746f, 347.25f, 445.746f, 359.699f, 464.277f, 341.25f, 461.75f, 341.25f, 
+461.75f, 308.656f, 458.559f, 301.246f, 475.746f, 301.246f, 475.746f, 298.539f, 478.797f, 308.246f, 
+475.746f, 308.246f, 475.746f, 317.461f, 473.957f, 300.246f, 489.746f, 300.246f, 489.746f, 302.937f, 
+489.797f, 313.246f, 482.746f, 313.246f, 482.746f, 324.5f, 472.199f, 326.25f, 474.75f, 326.25f, 
+474.75f, 346.5f, 484.078f, 358.25f, 475.746f, 358.25f, 475.746f, 360.141f, 473.957f, 353.98f, 
+466.477f, 355.246f, 460.746f, 357.5f, 455.035f, 363.25f, 441.75f, 363.25f, 441.75f, 360.141f, 
+439.637f, 360.25f, 427.746f, 360.25f, 427.746f, 379.059f, 402.238f, 368.246f, 404.75f, 368.246f, 
+404.75f, 351.34f, 404.879f, 367.246f, 396.746f, 367.246f, 396.746f, 371.141f, 394.316f, 381.25f, 
+386.75f, 381.25f, 386.75f, 377.738f, 387.719f, 376.246f, 381.746f, 376.246f, 381.746f, 381.258f, 
+377.598f, 378.246f, 372.746f, 378.246f, 372.746f, 371.578f, 370.996f, 370.25f, 366.75f, 370.25f, 
+366.75f, 377.738f, 357.797f, 366.246f, 357.746f, 366.246f, 357.746f, 370.699f, 352.516f, 365.246f, 
+339.746f, 365.246f, 339.746f, 360.141f, 339.316f, 353.246f, 332.746f, 353.246f, 332.746f, 355.738f, 
+327.879f, 344.246f, 321.746f, 344.246f, 321.746f, 335.059f, 319.957f, 338.25f, 312.75f, 338.25f, 
+312.75f, 329.34f, 305.879f, 326.25f, 288.746f, 326.25f, 288.746f, 325.82f, 276.836f, 323.18f, 
+273.316f, 329.25f, 275.746f, 334.621f, 277.719f, 333.246f, 291.746f, 333.246f, 291.746f, 328.461f, 
+308.516f, 375.246f, 325.75f, 375.246f, 325.75f, 379.938f, 327.879f, 381.25f, 333.75f, 381.25f, 
+333.75f, 383.02f, 333.156f, 392.25f, 324.746f, 392.25f, 324.746f, 401.059f, 312.477f, 401.246f, 
+322.75f, 401.246f, 322.75f, 402.82f, 326.559f, 401.246f, 332.746f, 401.246f, 332.746f, 407.66f, 
+356.918f, 392.25f, 363.746f, 392.25f, 363.746f, 381.258f, 400.918f, 396.25f, 391.75f, 396.25f, 
+391.75f, 399.738f, 385.516f, 411.246f, 379.746f, 411.246f, 379.746f, 415.25f, 382.75f, 413.82f, 
+387.719f, 423.246f, 394.746f, 423.246f, 394.746f, 426.141f, 387.277f, 432.246f, 395.75f, 432.246f, 
+395.75f, 436.699f, 422.918f, 450.25f, 406.75f, 450.25f, 406.75f, 454.738f, 405.758f, 456.246f, 
+412.746f, 456.246f, 412.746f, 460.02f, 424.676f, 456.246f, 439.75f, 456.246f, 439.75f, 460.02f, 
+440.078f, 470.25f, 433.746f, 470.25f, 433.746f, 473.66f, 437.438f, 463.539f, 455.918f, 468.25f, 
+453.746f, 472.34f, 450.637f, 477.25f, 448.75f, 477.25f, 448.75f, 478.059f, 451.078f, 467.246f, 
+464.746f, 467.246f, 464.746f, 462.219f, 467.797f, 456.246f, 489.746f, 456.246f, 489.746f, 464.418f, 
+486.277f, 453.25f, 502.746f, 453.25f, 502.746f, 453.418f, 506.52f, 460.246f, 518.75f, 460.246f, 
+518.75f, 459.141f, 526.316f, 460.246f, 525.75f, 460.246f, 525.75f, 463.098f, 524.559f, 471.898f, 
+522.797f, 464.25f, 529.75f, 456.938f, 536.879f, 465.246f, 541.746f, 465.246f, 541.746f, 470.141f, 
+545.238f, 455.25f, 544.746f, 455.25f, 544.746f, 449.461f, 549.637f, 450.25f, 553.75f, 450.25f, 
+553.75f, 458.699f, 551.84f, 442.859f, 567.68f, 440.25f, 571.75f, 437.578f, 575.598f, 448.25f, 
+581.746f, 448.25f, 581.746f, 462.66f, 585.277f, 450.25f, 588.75f, 450.25f, 588.75f, 428.34f, 
+588.359f, 440.25f, 599.75f, 440.25f, 599.75f, 446.82f, 599.797f, 445.246f, 602.75f, 445.246f, 
+602.75f, 439.34f, 603.758f, 429.25f, 610.75f, 429.25f, 610.75f, 424.379f, 614.758f, 428.25f, 
+613.75f, 428.25f, 613.75f, 446.82f, 612.559f, 415.25f, 624.75f, 415.25f, 624.75f, 423.938f, 
+624.879f, 404.25f, 636.746f, 404.25f, 636.746f, 401.938f, 638.078f, 398.246f, 646.75f, 398.246f, 
+646.75f, 391.82f, 652.156f, 386.246f, 659.75f, 386.246f, 659.75f, 386.098f, 664.477f, 381.25f, 
+669.746f, 381.25f, 669.746f, 368.059f, 684.719f, 362.25f, 684.746f, 362.25f, 684.746f, 345.621f, 
+688.238f, 340.25f, 687.75f, 340.25f, 687.75f, 282.25f, 682.746f, 252.777f, 668.438f, 261.25f, 
+645.746f, 261.25f, 645.746f, 268.398f, 636.098f, 278.246f, 640.746f, 278.246f, 640.746f, 283.578f, 
+647.098f, 296.25f, 644.75f, 296.25f, 644.75f, 318.777f, 641.156f, 316.25f, 644.75f, 316.25f, 
+644.75f, 313.277f, 650.18f, 295.457f, 657, 295.25f, 657.75f, 295.02f, 658.316f, 285.25f, 
+661.75f, 285.25f, 661.75f, 282.039f, 663.379f, 277.246f, 673.746f, 277.246f, 673.746f, 273.68f, 
+677.238f, 291.246f, 670.75f, 291.246f, 670.75f, 289.738f, 669.758f, 298.246f, 665.75f, 298.246f, 
+665.75f, 317.02f, 666.457f, 328.25f, 654.75f, 328.25f, 654.75f, 340.559f, 636.316f, 341.25f, 
+645.746f, 341.25f, 645.746f, 343.859f, 655.68f, 331.246f, 678.746f, 331.246f, 678.746f, 331.32f, 
+681.199f, 340.25f, 673.746f, 340.25f, 673.746f, 341.879f, 676.137f, 343.246f, 669.746f, 343.246f, 
+669.746f, 342.98f, 667.117f, 347.25f, 658.746f, 347.25f, 658.746f, 350.238f, 644.02f, 354.246f, 
+651.746f, 354.246f, 651.746f, 359.25f, 641.75f, 360.801f, 638.957f, 354.246f, 630.75f, 354.246f, 
+630.75f, 353.98f, 627.52f, 354.859f, 627.738f, 348.25f, 619.75f, 342.539f, 611.02f, 346.246f, 
+605.746f, 346.246f, 605.746f, 344.738f, 598.918f, 354.246f, 599.75f, 354.246f, 599.75f, 357.277f, 
+596.938f, 361.25f, 596.746f, 361.25f, 596.746f, 363, 594.738f, 365.246f, 595.75f, 365.246f, 
+595.75f, 367.398f, 599.578f, 374.25f, 597.75f, 374.25f, 597.75f, 375.758f, 600.02f, 385.25f, 
+600.75f, 385.25f, 600.75f, 385.879f, 603.316f, 386.32f, 605.078f, 390.246f, 605.746f, 393.801f, 
+606.398f, 366.246f, 653.746f, 366.246f, 653.746f, 373.777f, 654.578f, 365.246f, 667.746f, 365.246f, 
+667.746f, 362.34f, 675.477f, 374.879f, 659.418f, 377.246f, 657.75f, 379.719f, 656.34f, 380.82f, 
+653.918f, 379.246f, 653.746f, 377.301f, 654.359f, 375.32f, 651.938f, 377.246f, 651.746f, 378.398f, 
+651.5f, 392.699f, 635, 396.25f, 623.746f, 400.18f, 612.559f, 406.777f, 608.156f, 413.246f, 
+601.746f, 420.418f, 594.957f, 419.246f, 568.746f, 419.246f, 568.746f, 419.098f, 558.656f, 425.25f, 
+546.746f, 425.25f, 546.746f, 427.898f, 542.816f, 423.246f, 522.746f, 423.246f, 522.746f, 421.078f, 
+520.379f, 422.246f, 519.746f, 422.246f, 519.746f, 423.719f, 518.18f, 431.246f, 503.75f, 431.246f, 
+503.75f, 429.219f, 503.879f, 433.246f, 499.746f, 433.246f, 499.746f, 438.898f, 493.316f, 432.246f, 
+496.75f, 432.246f, 496.75f, 425.258f, 498.379f, 433.246f, 487.75f, 433.246f, 487.75f, 434.277f, 
+485.617f, 424.246f, 490.75f, 424.246f, 490.75f, 414.258f, 491.34f, 427.25f, 483.75f, 427.25f, 
+483.75f, 436.48f, 475.5f, 424.246f, 480.746f, 424.246f, 480.746f, 418.879f, 482.316f, 422.246f, 
+474.75f, 422.246f, 474.75f, 425.918f, 473.078f, 445.246f, 465.75f, 445.246f, 465.75f, 445.277f, 
+461.195f, 442.246f, 455.746f, 442.246f, 455.746f, 442.418f, 451.297f, 440.25f, 447.746f, 440.25f, 
+447.746f, 438.68f, 438.535f, 438.25f, 437.75f, 438.25f, 437.75f, 433.398f, 437.438f, 425.25f, 
+422.746f, 425.25f, 422.746f, 423.277f, 419.398f, 412.246f, 405.746f, 412.246f, 405.746f, 409.859f, 
+398.496f, 390.246f, 406.75f, 390.246f, 406.75f, 382.801f, 402.676f, 385.25f, 406.75f, 385.25f, 
+406.75f, 384.559f, 408.836f, 390.246f, 415.75f, 390.246f, 415.75f, 397.539f, 418.297f, 394.25f, 
+429.746f, 394.25f, 429.746f, 399.078f, 431.719f, 386.758f, 434.797f, 387.246f, 435.75f, 387.199f, 
+437.438f, 393.25f, 438.746f, 393.25f, 438.746f, 402.379f, 441.176f, 397.246f, 443.75f, 397.246f, 
+443.75f, 396.879f, 448.219f, 400.246f, 454.75f, 400.246f, 454.75f, 412.938f, 455.258f, 400.246f, 
+472.75f, 400.246f, 472.75f, 388.301f, 481.438f, 387.246f, 487.75f, 387.246f, 487.75f, 401.059f, 
+496.84f, 392.039f, 510.477f, 392.25f, 514.75f, 392.48f, 518.398f, 394.25f, 541.746f, 394.25f, 
+541.746f, 391.598f, 548.977f, 388.246f, 563.746f, 388.246f, 563.746f, 390.719f, 569.656f, 399.246f, 
+583.746f, 399.246f, 583.746f, 401.938f, 588.137f, 411.621f, 593.418f, 409.246f, 596.746f, 406.777f, 
+600.02f, 398.246f, 597.75f, 398.246f, 597.75f, 389.621f, 599.578f, 390.246f, 593.75f, 390.246f, 
+593.75f, 388.52f, 592.758f, 387.246f, 587.746f, 387.246f, 587.746f, 386.848f, 578.531f, 377.246f, 
+571.75f, 377.246f, 571.75f, 364.758f, 564.816f, 375.246f, 560.75f, 375.246f, 560.75f, 381.48f, 
+553.156f, 370.25f, 552.746f, 370.25f, 552.746f, 358.598f, 554.918f, 367.246f, 543.746f, 367.246f, 
+543.746f, 379.5f, 529.617f, 376.246f, 526.746f, 376.246f, 526.746f, 364.98f, 525.438f, 379.246f, 
+515.746f, 379.246f, 515.746f, 379.242f, 515.742f, 377.961f, 517.52f, 378.246f, 515.746f, 378.398f, 
+513.559f, 381.699f, 508.938f, 382.25f, 506.746f, 383.461f, 504.539f, 379.246f, 504.746f, 379.246f, 
+504.746f, 379.719f, 493.758f, 363.25f, 498.75f, 363.25f, 498.75f, 363.25f, 498.75f, 362.777f, 
+498.379f, 361.25f, 497.746f, 359.258f, 497.938f, 346.938f, 498.816f, 340.25f, 500.746f, 334.18f, 
+503.656f, 326.25f, 503.75f, 326.25f, 503.75f, 326.25f, 503.75f, 322.301f, 501.68f, 314.25f, 
+501.75f, 305.578f, 502.117f, 297.246f, 498.75f, 297.246f, 498.75f, 291.937f, 499.477f, 301.398f, 
+504.316f, 301.246f, 503.75f, 301.84f, 503.879f, 308, 510.039f, 299.246f, 509.75f, 275.223f, 
+507.578f, 263.25f, 518.75f, 263.25f, 518.75f, 261.137f, 520.379f, 258.246f, 523.75f, 258.246f, 
+523.75f, 247.277f, 525.656f, 260.25f, 509.75f, 260.25f, 509.75f, 261.137f, 508.277f, 259.25f, 
+506.746f, 259.25f, 506.746f, 258.719f, 508.938f, 250.25f, 514.75f, 250.25f, 514.75f, 247.047f, 
+515.949f, 245.547f, 517.414f, 243.246f, 519.746f, 10, 0, 0.3f, 0, 0, 
+0.3f, 0, 0, 7, 216.25f, 532.746f, 216.25f, 532.742f, 229.457f, 526.758f, 
+232.246f, 523.75f, 235.18f, 520.598f, 250.25f, 507.75f, 250.25f, 507.75f, 250.25f, 507.75f, 
+244.637f, 510.258f, 242.246f, 511.746f, 238.918f, 514.219f, 227.25f, 522.746f, 227.25f, 522.746f, 
+227.25f, 522.746f, 222.859f, 529.84f, 216.25f, 532.746f, 10, 0, 0.6f, 0.8f, 
+0.2f, 0.6f, 0.8f, 0.2f, 6, 153.246f, 566.75f, 153.258f, 567.398f, 152.684f, 
+570.379f, 152.25f, 570.746f, 151.332f, 573.977f, 141.25f, 575.75f, 141.25f, 575.75f, 141.207f, 
+574.098f, 141.148f, 572.34f, 141.25f, 570.746f, 141.25f, 570.746f, 146.621f, 564.469f, 153.246f, 
+566.75f, 10, 0, 0.4f, 0.6f, 0, 0.4f, 0.6f, 0, 6, 
+153.246f, 567.75f, 152.395f, 567.281f, 152.871f, 570.461f, 152.25f, 570.746f, 151.555f, 573.977f, 
+141.25f, 575.75f, 141.25f, 575.75f, 141.207f, 574.207f, 141.148f, 572.449f, 141.25f, 570.746f, 
+141.25f, 570.746f, 145.961f, 565.02f, 153.246f, 567.75f, 10, 0, 0, 0, 
+0, 0, 0, 0, 6, 148.246f, 567.75f, 147.371f, 567.297f, 146.812f, 
+568.551f, 147.25f, 569.75f, 146.812f, 571.645f, 147.371f, 572.898f, 148.246f, 572.746f, 148.746f, 
+572.898f, 149.305f, 571.645f, 149.246f, 569.75f, 149.305f, 568.551f, 148.746f, 567.297f, 148.246f, 
+567.75f, 10, 0, 0, 0, 0, 0, 0, 0, 17, 
+98.2461f, 459.75f, 98.2422f, 459.75f, 91.7383f, 448.438f, 119.25f, 454.75f, 119.25f, 454.75f, 
+134.418f, 456.355f, 137.246f, 458.746f, 138.379f, 458.117f, 147.582f, 454.891f, 150.246f, 453.746f, 
+158.18f, 452.398f, 167.25f, 463.75f, 167.25f, 463.75f, 167.25f, 463.75f, 172.477f, 474.949f, 
+175.25f, 474.75f, 178.637f, 474.949f, 175.25f, 472.75f, 175.25f, 472.75f, 175.25f, 472.75f, 
+167.859f, 462.078f, 168.25f, 460.746f, 168.25f, 460.742f, 162.578f, 438.316f, 145.25f, 437.75f, 
+145.25f, 437.75f, 127.215f, 436.391f, 128.25f, 429.746f, 128.25f, 429.742f, 138.379f, 432.598f, 
+141.25f, 429.746f, 141.25f, 429.742f, 152.898f, 430.398f, 144.246f, 423.746f, 136.25f, 410.75f, 
+136.25f, 410.75f, 136.773f, 406.289f, 125.25f, 409.746f, 114.84f, 413.898f, 103.25f, 427.746f, 
+103.25f, 427.746f, 103.25f, 427.742f, 85.9648f, 444.094f, 98.2461f, 459.75f, 10, 0, 
+0.9f, 0.6f, 0.6f, 0.9f, 0.6f, 0.6f, 14, 96.25f, 454.75f, 96.25f, 
+454.75f, 94.3789f, 444.477f, 135.25f, 455.746f, 135.25f, 455.742f, 139.699f, 455.918f, 142.246f, 
+454.75f, 144.977f, 454.156f, 158.18f, 451.078f, 160.246f, 452.75f, 160.246f, 452.75f, 152.457f, 
+437.438f, 139.246f, 438.746f, 139.246f, 438.742f, 125.18f, 437.438f, 125.25f, 431.746f, 125.25f, 
+431.742f, 130.02f, 424.238f, 135.25f, 421.75f, 135.25f, 421.75f, 138.379f, 418.957f, 138.246f, 
+415.75f, 137.5f, 411.918f, 134.418f, 410.156f, 132.246f, 409.746f, 130.02f, 408.398f, 126.5f, 
+411.918f, 124.25f, 411.746f, 122.977f, 411.918f, 113.738f, 418.957f, 109.246f, 423.746f, 104.059f, 
+429.516f, 94.8164f, 442.719f, 95.25f, 445.746f, 95.6992f, 448.879f, 96.25f, 454.75f, 96.25f, 
+454.75f, 10, 0, 0.7f, 0.4f, 0.4f, 0.7f, 0.4f, 0.4f, 13, 
+100.246f, 435.75f, 102.957f, 431.496f, 106.477f, 426.879f, 109.246f, 423.746f, 113.738f, 418.957f, 
+122.977f, 411.918f, 124.25f, 411.746f, 126.5f, 411.918f, 130.02f, 408.398f, 132.246f, 409.746f, 
+134.418f, 410.156f, 137.5f, 411.918f, 138.246f, 415.75f, 138.379f, 418.957f, 135.25f, 421.75f, 
+135.25f, 421.75f, 131.926f, 423.285f, 128.91f, 427.125f, 127.246f, 429.746f, 127.246f, 429.742f, 
+127.379f, 426.879f, 121.246f, 427.746f, 115.938f, 428.637f, 110.219f, 431.719f, 108.25f, 434.746f, 
+106.699f, 438.758f, 104.059f, 441.398f, 106.25f, 437.75f, 107.578f, 433.477f, 110.219f, 429.516f, 
+112.25f, 428.75f, 113.738f, 428.637f, 113.297f, 427.316f, 110.246f, 427.746f, 108.02f, 428.195f, 
+104.938f, 428.637f, 100.246f, 434.746f, 10, 0, 0.6f, 0.15f, 0, 0.6f, 
+0.15f, 0, 20, 97.25f, 458.746f, 97.25f, 458.746f, 99.2187f, 473.957f, 100.246f, 
+478.746f, 100.246f, 478.746f, 99.6563f, 485.84f, 102.25f, 490.75f, 104.938f, 495.078f, 107.137f, 
+501.898f, 110.246f, 507.75f, 113.738f, 513.777f, 113.957f, 518.18f, 118.25f, 519.746f, 122.758f, 
+521.699f, 129.359f, 531.156f, 132.246f, 532.746f, 135.52f, 533.359f, 135.25f, 532.746f, 135.25f, 
+532.746f, 135.25f, 532.742f, 142.777f, 548.758f, 157.25f, 544.746f, 157.25f, 544.746f, 139.918f, 
+547.438f, 157.25f, 557.746f, 157.25f, 557.746f, 152.02f, 556.566f, 155.246f, 564.75f, 158.07f, 
+569.402f, 157.52f, 561.957f, 145.25f, 548.746f, 145.25f, 548.746f, 139.918f, 539.52f, 134.25f, 
+535.746f, 128.477f, 532.918f, 115.277f, 525.219f, 114.25f, 520.75f, 112.637f, 516.859f, 109.117f, 
+510.477f, 107.25f, 508.746f, 104.719f, 506.957f, 101.637f, 502.34f, 101.25f, 498.75f, 101.25f, 
+498.75f, 99.8789f, 494.199f, 98.2461f, 492.75f, 96.7969f, 491.559f, 96.5781f, 488.039f, 96.25f, 
+485.75f, 96.5781f, 483.637f, 94.3789f, 480.559f, 94.2461f, 477.746f, 94.2461f, 477.742f, 95.4766f, 
+457.016f, 95.25f, 454.75f, 97.25f, 458.746f, 10, 0, 1, 1, 1, 
+1, 1, 1, 6, 88.2461f, 453.746f, 88.2461f, 453.742f, 85.5781f, 455.477f, 
+80.25f, 448.75f, 80.25f, 448.75f, 88.7695f, 412.578f, 89.2461f, 410.75f, 89.2461f, 410.75f, 
+89.9766f, 413.348f, 88.2461f, 421.75f, 87.1172f, 429.188f, 86.25f, 442.746f, 86.25f, 442.746f, 
+88.2461f, 453.746f, 10, 0, 0.6f, 0.15f, 0, 0.6f, 0.15f, 0, 
+13, 111.246f, 520.75f, 111.246f, 520.75f, 92.1797f, 517.078f, 92.2461f, 484.746f, 91.25f, 
+457.75f, 91.25f, 457.75f, 90.418f, 485.84f, 89.2461f, 487.75f, 87.7773f, 489.359f, 92.1797f, 
+501.68f, 88.2461f, 494.75f, 88.2461f, 494.75f, 73.2578f, 479.68f, 82.2461f, 456.746f, 82.2422f, 
+456.746f, 83.707f, 452.727f, 80.25f, 457.75f, 80.25f, 457.75f, 75.3477f, 471.648f, 76.2461f, 
+478.746f, 76.2422f, 478.746f, 76.7773f, 481.109f, 79.25f, 483.75f, 79.25f, 483.75f, 88.3281f, 
+497.059f, 91.25f, 499.746f, 91.25f, 499.742f, 93.2773f, 515.43f, 110.246f, 520.75f, 110.246f, 
+520.75f, 116.488f, 523.68f, 111.246f, 520.75f, 10, 0, 0, 0, 0, 
+0, 0, 0, 28, 265.246f, 593.75f, 265.605f, 593.809f, 265.594f, 594.875f, 
+266.246f, 594.746f, 267.496f, 595.441f, 267.676f, 596.617f, 268.246f, 597.75f, 269.207f, 598.93f, 
+269.418f, 600.617f, 270.25f, 602.75f, 270.359f, 603.027f, 270.387f, 604.078f, 270.25f, 604.75f, 
+268.754f, 607.531f, 267.98f, 610.227f, 266.246f, 612.746f, 266.098f, 613.391f, 265.812f, 614.262f, 
+265.246f, 614.746f, 265.082f, 616.441f, 263.699f, 617.535f, 263.25f, 618.746f, 262.434f, 619.469f, 
+263.012f, 620.488f, 262.25f, 620.746f, 261.238f, 620.695f, 259.645f, 621.332f, 259.25f, 619.75f, 
+258.742f, 617.359f, 259.852f, 614.586f, 261.25f, 611.75f, 260.059f, 611.137f, 260.426f, 610.125f, 
+260.25f, 609.746f, 261.375f, 605.313f, 260.055f, 601.625f, 259.25f, 597.75f, 259.191f, 597.691f, 
+259.57f, 597.473f, 259.25f, 597.75f, 258.195f, 594.449f, 256.598f, 591.762f, 254.246f, 588.75f, 
+253.762f, 588.051f, 252.805f, 587.043f, 252.25f, 585.746f, 251.852f, 585.008f, 251.402f, 583.945f, 
+251.25f, 582.75f, 247.898f, 579.801f, 245.426f, 575.57f, 242.246f, 571.75f, 242.043f, 570.594f, 
+242.363f, 569.262f, 243.246f, 568.746f, 243.863f, 568.527f, 244.918f, 569.656f, 245.246f, 570.746f, 
+245.859f, 571.352f, 246.25f, 572.066f, 247.246f, 572.746f, 246.937f, 572.969f, 246.738f, 573.43f, 
+247.246f, 573.75f, 249.785f, 576.145f, 251.621f, 579.375f, 254.246f, 581.746f, 256.465f, 582.34f, 
+258.152f, 583.438f, 260.25f, 584.75f, 260.414f, 584.75f, 260.992f, 584.477f, 261.25f, 584.75f, 
+263.238f, 585.984f, 263.238f, 588.223f, 263.25f, 590.746f, 263.41f, 591.297f, 263.625f, 592.746f, 
+265.246f, 593.75f, 10, 0, 0, 0, 0, 0, 0, 0, 
+19, 255.246f, 598.746f, 255.289f, 598.414f, 255.117f, 598.879f, 255.246f, 598.746f, 255.418f, 
+599.477f, 255.859f, 599.68f, 256.246f, 599.75f, 256.16f, 600.277f, 255.98f, 600.695f, 256.246f, 
+600.75f, 258.695f, 603.543f, 258.977f, 606.867f, 258.246f, 609.746f, 258.965f, 610.82f, 259.031f, 
+612.207f, 258.246f, 612.746f, 257.625f, 615.012f, 257.414f, 617.129f, 256.246f, 618.746f, 255.457f, 
+620.223f, 253.723f, 621.59f, 252.25f, 619.75f, 251.75f, 619.719f, 251.398f, 618.852f, 251.25f, 
+617.75f, 251.773f, 617.887f, 252.09f, 617.727f, 252.25f, 617.75f, 251.941f, 617.281f, 251.34f, 
+617.035f, 251.25f, 616.746f, 251.301f, 615.09f, 250.25f, 613.43f, 251.25f, 611.75f, 251.793f, 
+610.176f, 252.695f, 608.133f, 253.246f, 605.746f, 252.082f, 603.852f, 253.219f, 601.156f, 251.25f, 
+598.746f, 251.141f, 598.93f, 251.148f, 598.508f, 251.25f, 598.746f, 251.605f, 597.75f, 252.051f, 
+597.305f, 252.25f, 596.746f, 252.809f, 596.848f, 253.191f, 596.848f, 253.246f, 596.746f, 254.047f, 
+597.383f, 254.484f, 597.918f, 255.246f, 598.746f, 10, 0, 0, 0, 0, 
+0, 0, 0, 21, 324.246f, 609.746f, 325.773f, 607.703f, 326.094f, 604.629f, 
+324.246f, 602.75f, 324.445f, 599.457f, 328.129f, 601.637f, 330.25f, 601.746f, 330.32f, 602.645f, 
+330.57f, 603.023f, 331.246f, 602.75f, 332.043f, 603.047f, 332.789f, 604.18f, 334.246f, 603.746f, 
+334.438f, 605.691f, 336.238f, 606.465f, 337.25f, 607.746f, 338.844f, 612.047f, 338.195f, 616.746f, 
+335.246f, 620.746f, 335.129f, 620.598f, 335.371f, 621.164f, 335.246f, 621.75f, 334.402f, 623.996f, 
+332.125f, 624.34f, 330.25f, 624.75f, 328.703f, 629.359f, 327.977f, 633.793f, 326.25f, 637.75f, 
+324.266f, 638.133f, 323.496f, 640.047f, 322.246f, 640.746f, 320.559f, 641.629f, 319.934f, 639.891f, 
+320.246f, 638.746f, 319.988f, 638.516f, 320.484f, 638.27f, 320.246f, 637.75f, 320.215f, 637.688f, 
+319.926f, 637.566f, 320.246f, 637.75f, 319.93f, 637.27f, 320.172f, 637.125f, 320.246f, 636.746f, 
+319.309f, 636.074f, 317.742f, 635.551f, 317.25f, 634.746f, 316.371f, 630.211f, 319.199f, 626.773f, 
+321.246f, 623.746f, 321.684f, 622.004f, 320.875f, 620.605f, 320.246f, 619.75f, 319.559f, 618.512f, 
+319.676f, 617.273f, 320.246f, 616.746f, 320.809f, 613.766f, 322.559f, 611.855f, 324.246f, 609.746f, 
+10, 0, 0, 0, 0, 0, 0, 0, 73, 283.25f, 
+589.75f, 281.734f, 587.41f, 277.98f, 584.586f, 281.25f, 582.75f, 281.402f, 582.324f, 281.809f, 
+582.32f, 282.25f, 582.75f, 284.223f, 584.188f, 286.426f, 585.18f, 289.246f, 585.746f, 289.242f, 
+585.852f, 289.543f, 585.34f, 290.246f, 585.746f, 291.727f, 586.289f, 293.938f, 586.227f, 295.25f, 
+587.746f, 299.383f, 587.453f, 303.305f, 588.68f, 307.25f, 589.75f, 308.309f, 590.609f, 309.707f, 
+591.227f, 311.246f, 591.75f, 312.543f, 592.41f, 313.867f, 593.434f, 315.25f, 594.746f, 315.234f, 
+594.836f, 315.625f, 594.738f, 316.25f, 594.746f, 315.875f, 595.688f, 316.934f, 595.828f, 317.25f, 
+596.746f, 317.305f, 596.766f, 317.141f, 597.203f, 317.25f, 597.75f, 319.641f, 599.105f, 320.652f, 
+601.328f, 319.25f, 603.746f, 319.051f, 604.578f, 318.777f, 605.258f, 318.25f, 605.746f, 316.961f, 
+606.781f, 315.75f, 605.844f, 314.25f, 605.746f, 314.422f, 605.488f, 313.621f, 605.676f, 313.246f, 
+605.746f, 312.25f, 604.977f, 310.785f, 605.621f, 310.246f, 604.75f, 308.344f, 604.371f, 306.977f, 
+604.188f, 305.25f, 603.746f, 305.07f, 603.684f, 304.215f, 603.789f, 304.25f, 602.75f, 303.891f, 
+603.246f, 303.727f, 603.504f, 303.25f, 603.746f, 301.512f, 603.043f, 300.125f, 602.809f, 298.246f, 
+600.75f, 298.582f, 600.801f, 298.098f, 600.996f, 298.246f, 600.75f, 296.867f, 599.961f, 296.422f, 
+598.602f, 295.25f, 597.75f, 294.992f, 597.727f, 294.602f, 597.914f, 294.25f, 597.75f, 293.68f, 
+597.297f, 293.277f, 596.59f, 292.25f, 595.75f, 292.207f, 595.848f, 291.766f, 596.207f, 292.25f, 
+596.746f, 292.07f, 598.629f, 292.789f, 600.594f, 292.25f, 602.75f, 294.441f, 605.43f, 297.211f, 
+607.574f, 299.246f, 610.75f, 299.215f, 612.961f, 299.977f, 615.32f, 300.246f, 617.75f, 299.84f, 
+617.816f, 299.523f, 618.625f, 299.246f, 618.746f, 299.043f, 619.945f, 300.039f, 621.117f, 299.246f, 
+621.75f, 297.566f, 623.238f, 296.145f, 622.273f, 295.25f, 620.746f, 293.215f, 620.27f, 290.945f, 
+619.508f, 289.246f, 620.746f, 288.102f, 621.73f, 287.465f, 622.727f, 286.246f, 623.746f, 285.504f, 
+625.32f, 285.871f, 626.898f, 286.246f, 628.75f, 285.953f, 628.762f, 285.609f, 628.91f, 285.25f, 
+628.75f, 285.609f, 629.207f, 285.852f, 629.352f, 286.246f, 629.746f, 285.223f, 630.188f, 284.918f, 
+631.352f, 284.25f, 631.746f, 284.133f, 632.898f, 283.391f, 633.871f, 282.25f, 633.75f, 280.238f, 
+634.965f, 278.395f, 632.859f, 276.246f, 632.75f, 275.746f, 632.758f, 275.23f, 633.902f, 274.25f, 
+634.746f, 274.043f, 634.496f, 273.27f, 634.531f, 273.25f, 633.75f, 272.113f, 633.688f, 271.465f, 
+633.559f, 270.25f, 633.75f, 268.852f, 632.855f, 267.449f, 631.652f, 266.246f, 630.75f, 264.188f, 
+629.77f, 263.137f, 628.188f, 262.25f, 626.75f, 260.914f, 625.469f, 260.762f, 622.813f, 262.25f, 
+622.75f, 264.352f, 621.547f, 265.785f, 624.523f, 268.246f, 623.746f, 268.293f, 624.105f, 268.52f, 
+623.766f, 268.246f, 623.746f, 268.824f, 623.219f, 269.066f, 623.469f, 269.246f, 623.746f, 270.223f, 
+622.656f, 271.504f, 622.285f, 272.25f, 621.75f, 273.602f, 620.332f, 275.523f, 620.793f, 276.246f, 
+619.75f, 278.32f, 618.043f, 277.707f, 615.094f, 280.246f, 613.75f, 279.195f, 612.215f, 278.527f, 
+610.809f, 278.246f, 608.75f, 277.848f, 607.914f, 278.941f, 606.598f, 280.246f, 606.75f, 281.656f, 
+606.801f, 281.945f, 607.633f, 282.25f, 608.75f, 282.773f, 608.523f, 283.289f, 608.199f, 283.25f, 
+607.746f, 282.738f, 605.336f, 281.609f, 603.141f, 281.25f, 600.75f, 281.043f, 600.121f, 280.707f, 
+599.898f, 280.246f, 599.75f, 279.762f, 595.453f, 275.305f, 592.82f, 272.25f, 589.75f, 272.063f, 
+588.785f, 272.059f, 587.414f, 272.25f, 586.75f, 274.051f, 585.445f, 276.207f, 587.145f, 278.246f, 
+587.746f, 278.313f, 589.023f, 279.258f, 590.063f, 280.246f, 589.75f, 281.004f, 589.988f, 281.262f, 
+590.586f, 281.25f, 590.746f, 282, 590.879f, 282.555f, 590.633f, 283.25f, 590.746f, 284.77f, 
+592.164f, 286.32f, 593.383f, 288.246f, 594.746f, 288.441f, 594.832f, 288.82f, 594.66f, 289.246f, 
+594.746f, 289.414f, 594.957f, 289.621f, 595.383f, 290.246f, 595.75f, 290.359f, 595.805f, 290.625f, 
+595.484f, 291.246f, 594.746f, 290.129f, 594.793f, 290.125f, 593.742f, 289.246f, 593.75f, 288.629f, 
+593.223f, 288.012f, 592.66f, 287.246f, 591.75f, 286.949f, 591.957f, 286.227f, 592.23f, 286.246f, 
+591.75f, 285.453f, 590.902f, 284.152f, 590.418f, 283.25f, 589.75f, 10, 0, 0, 
+0, 0, 0, 0, 0, 30, 222.246f, 643.75f, 222.246f, 643.75f, 
+212.258f, 646.957f, 200.246f, 618.746f, 200.246f, 618.742f, 197.34f, 613, 194.25f, 610.75f, 
+192.059f, 608.598f, 179.738f, 604.637f, 177.246f, 599.75f, 166.246f, 582.75f, 166.246f, 582.75f, 
+182.379f, 600.238f, 186.25f, 602.75f, 186.25f, 602.75f, 194.699f, 612.117f, 191.246f, 604.75f, 
+191.242f, 604.75f, 175.777f, 592.758f, 177.246f, 582.75f, 177.246f, 582.75f, 170.938f, 566.797f, 
+170.246f, 564.75f, 170.242f, 564.75f, 187.656f, 599.797f, 190.246f, 600.75f, 192.938f, 602.438f, 
+194.258f, 602.438f, 193.25f, 598.746f, 191.617f, 594.52f, 191.18f, 576.477f, 188.246f, 574.746f, 
+188.246f, 574.742f, 196.898f, 596.719f, 196.25f, 599.75f, 196.25f, 599.75f, 199.539f, 604.199f, 
+202.246f, 598.746f, 201.246f, 580.75f, 205.25f, 567.75f, 205.25f, 567.75f, 203.059f, 580, 
+205.25f, 596.746f, 205.25f, 596.742f, 202.617f, 608.598f, 207.25f, 602.75f, 211.418f, 596.277f, 
+221.977f, 589.68f, 222.246f, 584.75f, 222.246f, 584.75f, 216.258f, 603.758f, 206.25f, 608.75f, 
+201.246f, 602.75f, 200.246f, 604.75f, 200.246f, 604.75f, 196.457f, 605.52f, 201.246f, 612.746f, 
+206.137f, 620.477f, 205.25f, 621.75f, 205.25f, 621.75f, 205.25f, 621.75f, 212.738f, 613.438f, 
+214.25f, 613.75f, 214.25f, 613.75f, 229.02f, 621.797f, 230.25f, 594.746f, 230.25f, 594.742f, 
+237.816f, 610.797f, 227.25f, 618.746f, 227.25f, 618.742f, 211.418f, 620.477f, 212.246f, 625.746f, 
+220.246f, 639.75f, 224.617f, 645.559f, 223.246f, 642.746f, 223.246f, 642.746f, 10, 0, 
+0, 0, 0, 0, 0, 0, 6, 200.246f, 625.746f, 200.246f, 
+625.746f, 186.34f, 625.758f, 183.25f, 619.75f, 175.25f, 609.746f, 175.25f, 609.742f, 193.816f, 
+620.477f, 198.246f, 621.75f, 202.617f, 623.117f, 200.246f, 625.746f, 200.246f, 625.746f, 10, 
+0, 0, 0, 0, 0, 0, 0, 7, 156.25f, 618.746f, 
+156.25f, 618.742f, 154.219f, 617.398f, 154.246f, 614.746f, 153.34f, 611.238f, 150.699f, 610.797f, 
+151.25f, 607.746f, 152.457f, 604.637f, 154.656f, 602, 154.246f, 606.75f, 154.656f, 610.797f, 
+156.418f, 613, 157.25f, 614.746f, 158.18f, 615.637f, 159.938f, 620.477f, 156.25f, 618.746f, 
+10, 0, 0, 0, 0, 0, 0, 0, 10, 146.25f, 
+551.75f, 146.25f, 551.75f, 137.5f, 555.797f, 134.25f, 559.746f, 130.457f, 563.719f, 130.957f, 
+558.035f, 125.25f, 558.75f, 119.187f, 558.922f, 120.246f, 576.746f, 120.246f, 576.746f, 116.246f, 
+567.75f, 116.246f, 567.75f, 114.617f, 552.277f, 123.25f, 554.746f, 127.715f, 556.207f, 129.137f, 
+554.477f, 127.246f, 553.75f, 125.617f, 552.719f, 133.539f, 552.277f, 130.25f, 550.746f, 127.379f, 
+548.758f, 143.219f, 554.477f, 140.25f, 542.75f, 146.25f, 551.75f, 10, 0, 0, 
+0, 0, 0, 0, 0, 8, 133.246f, 535.746f, 133.246f, 535.746f, 
+115.938f, 530.719f, 112.25f, 541.746f, 112.25f, 541.742f, 106.699f, 538.637f, 109.246f, 535.746f, 
+111.539f, 532.039f, 113.25f, 531.75f, 113.25f, 531.75f, 113.25f, 531.75f, 118.797f, 530.277f, 
+118.25f, 529.75f, 117.477f, 528.52f, 115.246f, 524.746f, 115.246f, 524.746f, 115.242f, 524.746f, 
+126.059f, 531.379f, 133.246f, 535.746f, 10, 0, 1, 1, 1, 1, 
+1, 1, 24, 384.25f, 449.746f, 383.648f, 447.191f, 381.813f, 446.309f, 379.246f, 
+445.746f, 377.609f, 446.629f, 374.754f, 450.047f, 372.25f, 447.746f, 372.156f, 448.305f, 371.301f, 
+448.371f, 371.25f, 448.75f, 370.41f, 450.086f, 370.711f, 451.238f, 370.25f, 451.746f, 369.734f, 
+453.516f, 368.953f, 455.016f, 369.25f, 456.746f, 371.145f, 457.359f, 371.801f, 459.457f, 371.25f, 
+461.75f, 371.203f, 461.68f, 370.73f, 461.895f, 371.25f, 462.746f, 371.156f, 462.633f, 371.504f, 
+462.883f, 372.25f, 462.746f, 371.652f, 463.031f, 371.492f, 462.773f, 371.25f, 462.746f, 370.699f, 
+462.91f, 370.836f, 463.613f, 371.25f, 463.75f, 371.621f, 465.957f, 373.836f, 466.25f, 375.246f, 
+464.746f, 375.602f, 465.559f, 376.16f, 465.348f, 376.246f, 465.75f, 376.586f, 466.016f, 377.031f, 
+466.594f, 377.246f, 466.746f, 377.82f, 468.266f, 379.613f, 467.047f, 380.25f, 467.746f, 381.672f, 
+468.629f, 382.844f, 469.398f, 384.25f, 468.75f, 386.02f, 467.621f, 387.898f, 466.285f, 389.246f, 
+464.746f, 389.848f, 463.453f, 390.113f, 462.047f, 390.246f, 460.746f, 390.008f, 460.281f, 388.488f, 
+460.668f, 388.246f, 459.75f, 387.402f, 457.723f, 389.414f, 457.152f, 390.246f, 455.746f, 390.465f, 
+455.297f, 390.176f, 454.961f, 390.246f, 454.75f, 389.375f, 454.711f, 388.516f, 454.922f, 388.246f, 
+454.75f, 389.734f, 450.91f, 386.703f, 450.164f, 384.25f, 449.746f, 10, 0, 1, 
+1, 1, 1, 1, 1, 11, 373.25f, 427.746f, 373.551f, 429.891f, 
+371.789f, 431.82f, 373.25f, 433.746f, 373.27f, 433.551f, 373.41f, 433.305f, 373.25f, 433.746f, 
+373.707f, 433.305f, 373.852f, 433.551f, 374.25f, 433.746f, 375.645f, 431.258f, 379.66f, 430.238f, 
+379.246f, 426.75f, 379.48f, 426.617f, 378.285f, 425.605f, 379.246f, 424.75f, 377.285f, 423.414f, 
+377.223f, 420.809f, 376.246f, 418.746f, 374.836f, 419.051f, 373.504f, 419.449f, 372.25f, 419.75f, 
+372.625f, 421.691f, 372.496f, 423.543f, 373.25f, 424.75f, 373.879f, 425.766f, 373.563f, 426.949f, 
+373.25f, 427.746f, 10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 
+15, 190.246f, 437.75f, 190.246f, 437.75f, 172.195f, 426.727f, 187.246f, 443.75f, 197.34f, 
+454.156f, 208.25f, 460.746f, 208.25f, 460.746f, 208.25f, 460.742f, 219.777f, 465.156f, 223.246f, 
+466.746f, 227.699f, 467.797f, 244.418f, 473.52f, 248.25f, 473.746f, 251.457f, 474.398f, 262.02f, 
+478.797f, 269.246f, 474.75f, 276.977f, 470, 286.246f, 464.746f, 286.246f, 464.746f, 286.246f, 
+464.742f, 267.738f, 474.398f, 264.246f, 471.746f, 259.816f, 469.117f, 251.898f, 469.559f, 245.246f, 
+465.75f, 245.246f, 465.75f, 229.02f, 461.195f, 225.25f, 458.746f, 221.977f, 456.797f, 210.539f, 
+444.035f, 209.246f, 444.746f, 207.02f, 445.797f, 209.219f, 446.238f, 210.246f, 449.746f, 211.859f, 
+452.398f, 209.656f, 454.156f, 201.246f, 446.75f, 192.059f, 440.078f, 190.246f, 437.75f, 190.246f, 
+437.75f, 10, 0, 0, 0, 0, 0, 0, 0, 11, 
+199.246f, 444.746f, 199.246f, 444.742f, 200.434f, 458.785f, 210.246f, 456.746f, 210.246f, 456.746f, 
+218.809f, 461.539f, 222.246f, 463.75f, 222.246f, 463.75f, 230.758f, 465.578f, 232.246f, 466.746f, 
+252.523f, 475.824f, 268.715f, 470.855f, 269.246f, 471.746f, 269.918f, 473.316f, 291.504f, 465.488f, 
+295.25f, 460.746f, 295.906f, 460.508f, 284.219f, 467.152f, 273.25f, 468.75f, 264.453f, 471.008f, 
+240.691f, 468.961f, 228.25f, 462.746f, 225.422f, 461.211f, 215.582f, 454.848f, 213.246f, 454.75f, 
+210.016f, 455.094f, 199.246f, 444.746f, 199.246f, 444.746f, 10, 0, 0.8f, 0.8f, 
+0.8f, 0.8f, 0.8f, 0.8f, 11, 194.25f, 416.746f, 194.25f, 416.742f, 177.977f, 
+418.957f, 196.25f, 420.746f, 196.25f, 420.742f, 216.258f, 422.918f, 220.246f, 428.75f, 220.246f, 
+428.75f, 235.617f, 438.758f, 238.25f, 438.746f, 241.777f, 439.637f, 274.777f, 447.559f, 275.246f, 
+449.746f, 275.656f, 452.836f, 281.816f, 452.836f, 283.25f, 451.746f, 285.34f, 451.078f, 284.457f, 
+449.758f, 281.25f, 448.75f, 278.297f, 447.996f, 243.977f, 429.957f, 237.25f, 428.75f, 229.898f, 
+427.316f, 217.137f, 418.957f, 212.246f, 417.75f, 206.578f, 416.316f, 194.25f, 416.746f, 194.25f, 
+416.746f, 10, 0, 0, 0, 0, 0, 0, 0, 11, 
+216.25f, 424.75f, 216.25f, 424.75f, 206.73f, 425.367f, 216.25f, 426.75f, 216.25f, 426.75f, 
+225.887f, 430.035f, 228.25f, 432.75f, 228.25f, 432.75f, 235.801f, 438.145f, 237.25f, 438.746f, 
+238.957f, 438.594f, 254.313f, 442.652f, 254.246f, 443.75f, 254.762f, 445.355f, 292.234f, 459.191f, 
+297.246f, 455.746f, 300.301f, 453.371f, 289.406f, 455.219f, 279.246f, 450.75f, 277.32f, 449.684f, 
+240.082f, 433.637f, 236.25f, 432.75f, 232.871f, 432.285f, 226.34f, 428.008f, 223.246f, 427.746f, 
+220.934f, 426.656f, 216.25f, 424.75f, 216.25f, 424.75f, 10, 0, 0, 0, 
+0, 0, 0, 0, 4, 207.25f, 421.75f, 207.25f, 421.75f, 213.18f, 
+422.477f, 212.246f, 420.746f, 210.539f, 418.957f, 208.25f, 419.75f, 208.25f, 419.75f, 207.25f, 
+421.75f, 10, 0, 0, 0, 0, 0, 0, 0, 4, 
+199.246f, 420.746f, 199.246f, 420.742f, 205.258f, 420.719f, 204.25f, 418.746f, 202.617f, 417.195f, 
+200.246f, 417.75f, 200.246f, 417.75f, 199.246f, 420.746f, 10, 0, 0, 0, 
+0, 0, 0, 0, 4, 188.246f, 418.746f, 188.246f, 418.742f, 193.816f, 
+418.957f, 192.25f, 416.746f, 191.18f, 415.438f, 188.246f, 416.746f, 188.246f, 416.746f, 188.246f, 
+418.746f, 10, 0, 0, 0, 0, 0, 0, 0, 4, 
+179.246f, 417.75f, 179.246f, 417.75f, 185.457f, 418.078f, 184.25f, 416.746f, 182.816f, 414.559f, 
+180.246f, 415.75f, 180.246f, 415.75f, 179.246f, 417.75f, 10, 0, 0, 0, 
+0, 0, 0, 0, 4, 222.246f, 460.746f, 222.246f, 460.742f, 226.816f, 
+461.195f, 225.25f, 459.75f, 224.18f, 457.676f, 220.246f, 457.75f, 220.246f, 457.75f, 222.246f, 
+460.746f, 10, 0, 0, 0, 0, 0, 0, 0, 4, 
+211.246f, 454.75f, 211.246f, 454.75f, 218.133f, 457.391f, 215.25f, 453.746f, 214.059f, 451.957f, 
+211.246f, 452.75f, 211.246f, 452.75f, 211.246f, 454.75f, 10, 0, 0, 0, 
+0, 0, 0, 0, 4, 198.246f, 449.746f, 198.246f, 449.742f, 204.379f, 
+450.195f, 203.25f, 448.75f, 201.738f, 446.676f, 199.246f, 447.746f, 199.246f, 447.746f, 198.246f, 
+449.746f, 10, 0, 0, 0, 0, 0, 0, 0, 4, 
+190.246f, 442.746f, 190.246f, 442.742f, 196.02f, 443.598f, 194.25f, 441.75f, 193.379f, 440.078f, 
+190.246f, 440.746f, 190.246f, 440.746f, 190.246f, 442.746f, 10, 0, 0, 0, 
+0, 0, 0, 0, 4, 183.25f, 437.75f, 183.25f, 437.75f, 188.539f, 
+438.316f, 187.246f, 436.746f, 185.898f, 434.797f, 183.25f, 435.75f, 183.25f, 435.75f, 183.25f, 
+437.75f, 10, 0, 0, 0, 0, 0, 0, 0, 4, 
+226.25f, 430.75f, 226.25f, 430.75f, 233.422f, 431.426f, 231.246f, 428.75f, 229.906f, 426.742f, 
+226.25f, 427.746f, 226.25f, 427.746f, 226.25f, 430.75f, 10, 0, 0, 0, 
+0, 0, 0, 0, 4, 237.25f, 435.75f, 237.25f, 435.75f, 244.863f, 
+436.707f, 243.246f, 434.746f, 241.348f, 432.02f, 238.25f, 432.75f, 238.25f, 432.75f, 237.25f, 
+435.75f, 10, 0, 0, 0, 0, 0, 0, 0, 4, 
+249.25f, 440.746f, 249.25f, 440.742f, 256.742f, 441.547f, 255.246f, 438.746f, 253.227f, 436.859f, 
+249.25f, 437.75f, 249.25f, 437.75f, 249.25f, 440.746f, 10, 0, 0, 0, 
+0, 0, 0, 0, 4, 260.25f, 445.746f, 260.25f, 445.746f, 268.18f, 
+446.824f, 266.246f, 444.746f, 264.668f, 442.141f, 261.25f, 443.75f, 261.25f, 443.75f, 260.25f, 
+445.746f, 10, 0, 0, 0, 0, 0, 0, 0, 4, 
+230.25f, 465.75f, 230.25f, 465.75f, 237.82f, 466.625f, 236.25f, 464.746f, 234.309f, 461.941f, 
+230.25f, 461.75f, 230.25f, 461.75f, 230.25f, 465.75f, 10, 0, 0, 0, 
+0, 0, 0, 0, 4, 241.25f, 469.746f, 241.25f, 469.746f, 248.82f, 
+470.145f, 247.246f, 467.746f, 245.309f, 465.461f, 240.25f, 465.75f, 240.25f, 465.75f, 241.25f, 
+469.746f, 10, 0, 0, 0, 0, 0, 0, 0, 4, 
+216.25f, 425.746f, 216.25f, 425.746f, 221.977f, 425.996f, 220.246f, 423.746f, 219.34f, 422.477f, 
+216.25f, 423.746f, 216.25f, 423.746f, 216.25f, 425.746f, 10, 0, 0.6f, 0.15f, 
+0, 0.6f, 0.15f, 0, 5, 135.25f, 534.75f, 135.25f, 534.75f, 130.898f, 
+525, 130.25f, 521.746f, 130.25f, 521.742f, 131.34f, 531.156f, 132.246f, 533.746f, 133.977f, 
+535.559f, 135.25f, 534.75f, 135.25f, 534.75f, 10, 0, 0.6f, 0.15f, 0, 
+0.6f, 0.15f, 0, 5, 115.246f, 519.746f, 115.242f, 519.742f, 111.977f, 503.438f, 
+112.25f, 500.746f, 112.25f, 500.746f, 111.098f, 513.117f, 111.246f, 514.75f, 111.977f, 515.758f, 
+115.246f, 519.746f, 115.246f, 519.746f, 10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 
+0.8f, 0.8f, 6, 138.246f, 601.746f, 138.246f, 597.75f, 135.25f, 597.75f, 135.25f, 
+597.75f, 151.359f, 583.738f, 152.25f, 575.75f, 152.25f, 575.75f, 152.898f, 584.398f, 138.246f, 
+601.746f, 10, 0, 0, 0, 0, 0, 0, 0, 28, 
+143.246f, 599.75f, 142.285f, 600.402f, 142.527f, 601.223f, 142.246f, 601.746f, 141.188f, 602.078f, 
+143.508f, 602.141f, 143.246f, 602.75f, 142.836f, 604.254f, 143.039f, 604.277f, 143.246f, 605.746f, 
+142.844f, 606.34f, 143.488f, 608.031f, 144.246f, 608.75f, 145.504f, 610.332f, 144.047f, 613.559f, 
+146.25f, 615.75f, 146.188f, 615.582f, 146.598f, 616.191f, 147.25f, 616.746f, 147.637f, 617.711f, 
+148.941f, 618.246f, 150.246f, 618.746f, 150.336f, 619.461f, 150.113f, 620.371f, 150.246f, 620.746f, 
+151.523f, 620.141f, 152.891f, 620.285f, 153.246f, 619.75f, 152.715f, 617.027f, 151.254f, 615.137f, 
+150.246f, 613.75f, 150.344f, 612.527f, 149.84f, 611.828f, 149.246f, 610.75f, 148.059f, 608.336f, 
+148.266f, 605.207f, 148.246f, 601.746f, 148.07f, 601.992f, 147.73f, 601.906f, 147.25f, 601.746f, 
+148.129f, 599.277f, 148.77f, 596.859f, 149.246f, 594.746f, 150.141f, 593.387f, 150.66f, 592.402f, 
+151.25f, 591.75f, 150.945f, 590.625f, 151.059f, 589.711f, 150.246f, 588.75f, 152.848f, 585.754f, 
+151.41f, 582.84f, 152.25f, 578.75f, 152.922f, 578.27f, 154.785f, 576.164f, 154.246f, 576.746f, 
+151.512f, 577.297f, 151.387f, 577.734f, 151.25f, 578.75f, 151.031f, 579.25f, 150.668f, 580.762f, 
+150.246f, 581.746f, 150.336f, 581.605f, 150.148f, 583.68f, 150.246f, 583.746f, 148.398f, 586.434f, 
+149.895f, 586.238f, 148.246f, 588.75f, 146.816f, 589.582f, 145.754f, 590.797f, 144.246f, 591.75f, 
+144.301f, 592.297f, 145.559f, 593.094f, 145.25f, 593.75f, 144.156f, 594.746f, 142.887f, 595.59f, 
+143.246f, 596.746f, 143.43f, 597.992f, 143.578f, 599.156f, 143.246f, 599.75f, 10, 0, 
+0, 0, 0, 0, 0, 0, 11, 139.246f, 597.75f, 139.246f, 
+597.75f, 139.258f, 590.559f, 142.246f, 588.75f, 144.539f, 587.039f, 143.219f, 587.918f, 139.246f, 
+588.75f, 136.18f, 590.559f, 137.246f, 591.75f, 137.246f, 591.75f, 137.242f, 591.75f, 134.418f, 
+591, 137.246f, 588.75f, 139.699f, 586.598f, 143.656f, 583.957f, 142.246f, 583.746f, 140.137f, 
+583.957f, 131.777f, 588.359f, 132.246f, 591.75f, 131.777f, 594.52f, 130.25f, 598.746f, 130.25f, 
+598.746f, 130.25f, 598.742f, 131.887f, 599.906f, 137.246f, 599.75f, 137.242f, 599.75f, 138.707f, 
+599.027f, 139.246f, 597.75f, 10, 0, 1, 1, 1, 1, 1, 
+1, 5, 138.246f, 577.75f, 138.246f, 577.75f, 128.566f, 580.648f, 108.25f, 576.746f, 
+108.25f, 576.742f, 118.172f, 579.203f, 139.246f, 576.746f, 150.148f, 575.324f, 138.246f, 577.75f, 
+138.246f, 577.75f, 10, 0.11f, 0, 0, 0, 0, 0, 0, 
+5, 138.246f, 577.75f, 138.246f, 577.75f, 128.566f, 580.648f, 108.25f, 576.746f, 108.25f, 
+576.742f, 118.172f, 579.203f, 139.246f, 576.746f, 150.148f, 575.324f, 138.246f, 577.75f, 138.246f, 
+577.75f, 10, 0, 1, 1, 1, 1, 1, 1, 5, 
+140.25f, 577.75f, 140.25f, 577.75f, 131.176f, 581.527f, 110.246f, 579.746f, 110.246f, 579.746f, 
+120.695f, 580.984f, 141.25f, 576.746f, 152.215f, 574.355f, 140.25f, 577.75f, 140.25f, 577.75f, 
+10, 0.11f, 0, 0, 0, 0, 0, 0, 5, 140.25f, 
+577.75f, 140.25f, 577.75f, 131.176f, 581.527f, 110.246f, 579.746f, 110.246f, 579.746f, 120.695f, 
+580.984f, 141.25f, 576.746f, 152.215f, 574.355f, 140.25f, 577.75f, 140.25f, 577.75f, 10, 
+0, 1, 1, 1, 1, 1, 1, 5, 142.246f, 577.75f, 
+142.242f, 577.75f, 133.453f, 582.086f, 113.25f, 581.746f, 113.25f, 581.746f, 122.965f, 582.328f, 
+143.246f, 576.746f, 153.902f, 573.371f, 142.246f, 577.75f, 142.246f, 577.75f, 10, 0.11f, 
+0, 0, 0, 0, 0, 0, 5, 142.246f, 577.75f, 142.242f, 
+577.75f, 133.453f, 582.086f, 113.25f, 581.746f, 113.25f, 581.746f, 122.965f, 582.328f, 143.246f, 
+576.746f, 153.902f, 573.371f, 142.246f, 577.75f, 142.246f, 577.75f, 10, 0, 1, 
+1, 1, 1, 1, 1, 5, 143.246f, 577.75f, 143.242f, 577.75f, 
+136.102f, 582.047f, 117.25f, 583.746f, 117.25f, 583.742f, 126.715f, 583.066f, 144.246f, 576.746f, 
+153.77f, 572.66f, 143.246f, 577.75f, 143.246f, 577.75f, 10, 0.11f, 0, 0, 
+0, 0, 0, 0, 5, 143.246f, 577.75f, 143.242f, 577.75f, 136.102f, 
+582.047f, 117.25f, 583.746f, 117.25f, 583.742f, 126.715f, 583.066f, 144.246f, 576.746f, 153.77f, 
+572.66f, 143.246f, 577.75f, 143.246f, 577.75f, 10, 0, 1, 1, 1, 
+1, 1, 1, 5, 270.25f, 565.746f, 270.25f, 565.742f, 269.398f, 565.031f, 
+269.246f, 566.75f, 269.871f, 567.629f, 300.898f, 582.117f, 305.25f, 581.746f, 305.25f, 581.746f, 
+271.602f, 567.316f, 270.25f, 565.746f, 10, 0.11f, 0, 0, 0, 0, 
+0, 0, 5, 270.25f, 565.746f, 270.25f, 565.742f, 269.398f, 565.031f, 269.246f, 
+566.75f, 269.871f, 567.629f, 300.898f, 582.117f, 305.25f, 581.746f, 305.25f, 581.746f, 271.602f, 
+567.316f, 270.25f, 565.746f, 10, 0, 1, 1, 1, 1, 1, 
+1, 5, 266.246f, 564.75f, 266.246f, 564.75f, 265.727f, 564.25f, 266.246f, 565.746f, 
+265.992f, 566.879f, 295.785f, 583.758f, 300.246f, 583.746f, 300.246f, 583.742f, 267.742f, 566.699f, 
+266.246f, 564.75f, 10, 0.11f, 0, 0, 0, 0, 0, 0, 
+5, 266.246f, 564.75f, 266.246f, 564.75f, 265.727f, 564.25f, 266.246f, 565.746f, 265.992f, 
+566.879f, 295.785f, 583.758f, 300.246f, 583.746f, 300.246f, 583.742f, 267.742f, 566.699f, 266.246f, 
+564.75f, 10, 0, 1, 1, 1, 1, 1, 1, 5, 
+263.25f, 563.746f, 263.25f, 563.742f, 262.164f, 562.676f, 262.25f, 563.746f, 262.254f, 565.316f, 
+284.055f, 582.363f, 295.25f, 584.75f, 295.25f, 584.75f, 275.016f, 575.484f, 263.25f, 563.746f, 
+10, 0.11f, 0, 0, 0, 0, 0, 0, 5, 263.25f, 
+563.746f, 263.25f, 563.742f, 262.164f, 562.676f, 262.25f, 563.746f, 262.254f, 565.316f, 284.055f, 
+582.363f, 295.25f, 584.75f, 295.25f, 584.75f, 275.016f, 575.484f, 263.25f, 563.746f, 10, 
+0, 1, 1, 1, 1, 1, 1, 5, 260.25f, 561.746f, 
+260.25f, 561.742f, 259.09f, 560.711f, 259.25f, 561.746f, 259.176f, 563.086f, 278.793f, 578.43f, 
+288.246f, 580.75f, 288.246f, 580.75f, 270.656f, 572.238f, 260.25f, 561.746f, 10, 0.11f, 
+0, 0, 0, 0, 0, 0, 5, 260.25f, 561.746f, 260.25f, 
+561.742f, 259.09f, 560.711f, 259.25f, 561.746f, 259.176f, 563.086f, 278.793f, 578.43f, 288.246f, 
+580.75f, 288.246f, 580.75f, 270.656f, 572.238f, 260.25f, 561.746f, 10, 0, 0.8f, 
+0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 11, 225.25f, 398.746f, 225.25f, 398.742f, 
+208.34f, 401.355f, 227.25f, 402.75f, 227.25f, 402.75f, 246.617f, 405.316f, 251.25f, 410.75f, 
+251.25f, 410.75f, 265.977f, 421.156f, 269.246f, 421.75f, 272.137f, 422.035f, 290.18f, 425.996f, 
+290.246f, 428.75f, 291.059f, 431.277f, 297.656f, 433.918f, 299.246f, 432.75f, 301.18f, 432.156f, 
+301.18f, 422.035f, 298.246f, 420.746f, 295.02f, 420.277f, 274.34f, 412.355f, 267.246f, 410.75f, 
+260.258f, 409.719f, 247.5f, 401.355f, 242.246f, 399.75f, 236.938f, 398.719f, 225.25f, 398.746f, 
+225.25f, 398.746f, 10, 0, 0, 0, 0, 0, 0, 0, 
+11, 305.25f, 439.75f, 305.25f, 439.75f, 302.059f, 438.098f, 300.246f, 434.746f, 300.246f, 
+434.746f, 293.699f, 423.578f, 278.246f, 419.75f, 278.246f, 419.75f, 252.777f, 410.156f, 244.246f, 
+407.746f, 244.246f, 407.742f, 229.457f, 402.457f, 221.246f, 403.746f, 221.246f, 403.746f, 213.617f, 
+403.117f, 220.246f, 401.746f, 220.246f, 401.746f, 242.656f, 403.559f, 246.246f, 405.746f, 246.242f, 
+405.742f, 263.559f, 411.258f, 267.246f, 413.75f, 270.156f, 416.977f, 290.18f, 422.477f, 292.25f, 
+424.75f, 295.02f, 426.879f, 305.797f, 436.117f, 305.25f, 439.75f, 10, 0, 0, 
+0, 0, 0, 0, 0, 4, 241.25f, 404.75f, 241.25f, 404.75f, 
+246.52f, 405.445f, 245.246f, 403.746f, 243.984f, 402.035f, 241.25f, 402.75f, 241.25f, 402.75f, 
+241.25f, 404.75f, 10, 0, 0, 0, 0, 0, 0, 0, 
+4, 233.246f, 403.746f, 233.246f, 403.746f, 238.598f, 403.957f, 237.25f, 402.75f, 236.063f, 
+400.547f, 233.246f, 401.746f, 233.246f, 401.746f, 233.246f, 403.746f, 10, 0, 0, 
+0, 0, 0, 0, 0, 4, 221.246f, 402.75f, 221.246f, 402.75f, 
+227.125f, 402.586f, 226.25f, 400.75f, 224.59f, 399.176f, 222.246f, 399.75f, 222.246f, 399.75f, 
+221.246f, 402.75f, 10, 0, 0, 0, 0, 0, 0, 0, 
+4, 213.246f, 401.746f, 213.242f, 401.746f, 218.73f, 401.984f, 217.25f, 400.75f, 216.191f, 
+398.578f, 213.246f, 399.75f, 213.246f, 399.75f, 213.246f, 401.746f, 10, 0, 0, 
+0, 0, 0, 0, 0, 4, 259.25f, 413.75f, 259.25f, 413.75f, 
+266.609f, 413.664f, 265.246f, 411.746f, 263.234f, 409.129f, 259.25f, 410.75f, 259.25f, 410.75f, 
+259.25f, 413.75f, 10, 0, 0, 0, 0, 0, 0, 0, 
+4, 270.25f, 417.75f, 270.25f, 417.75f, 276.855f, 421.832f, 276.246f, 416.746f, 275.973f, 
+413.453f, 271.25f, 415.75f, 271.25f, 415.75f, 270.25f, 417.75f, 10, 0, 0, 
+0, 0, 0, 0, 0, 4, 280.246f, 421.75f, 280.242f, 421.75f, 
+288.223f, 425.367f, 286.246f, 419.75f, 285.457f, 416.664f, 281.25f, 418.746f, 281.25f, 418.746f, 
+280.246f, 421.75f, 10, 0, 0, 0, 0, 0, 0, 0, 
+4, 291.246f, 426.75f, 291.242f, 426.75f, 295.605f, 431.996f, 297.246f, 424.75f, 297.227f, 
+421.875f, 291.246f, 423.746f, 291.246f, 423.746f, 291.246f, 426.75f, 10, 0, 0, 
+0, 0, 0, 0, 0, 4, 249.25f, 408.75f, 249.25f, 408.75f, 
+255.266f, 408.652f, 254.246f, 406.75f, 252.73f, 405.242f, 250.25f, 405.746f, 250.25f, 405.746f, 
+249.25f, 408.75f, 10, 0, 1, 1, 1, 1, 1, 1, 
+5, 288.246f, 541.746f, 288.246f, 541.742f, 287.875f, 541.203f, 288.246f, 542.75f, 287.875f, 
+543.559f, 307.109f, 558.148f, 317.25f, 559.746f, 317.25f, 559.746f, 299.125f, 552.27f, 288.246f, 
+541.746f, 10, 0.11f, 0, 0, 0, 0, 0, 0, 5, 
+288.246f, 541.746f, 288.246f, 541.742f, 287.875f, 541.203f, 288.246f, 542.75f, 287.875f, 543.559f, 
+307.109f, 558.148f, 317.25f, 559.746f, 317.25f, 559.746f, 299.125f, 552.27f, 288.246f, 541.746f, 
+10, 0, 0, 0, 0, 0, 0, 0, 10, 292.25f, 
+471.746f, 292.25f, 471.742f, 316.141f, 447.117f, 326.25f, 442.746f, 326.25f, 442.742f, 336.379f, 
+430.836f, 332.246f, 401.746f, 332.246f, 401.746f, 328.461f, 393.879f, 325.25f, 416.746f, 325.25f, 
+416.742f, 328.461f, 444.477f, 316.25f, 426.75f, 316.25f, 426.75f, 306.898f, 437.766f, 314.25f, 
+437.75f, 314.25f, 437.75f, 317.461f, 435.238f, 318.25f, 436.746f, 318.34f, 438.758f, 309.539f, 
+453.719f, 290.246f, 469.746f, 271.699f, 485.398f, 292.25f, 471.746f, 292.25f, 471.746f, 10, 
+0, 1, 1, 1, 1, 1, 1, 5, 227.25f, 428.75f, 
+227.25f, 428.75f, 227.477f, 431.059f, 229.25f, 429.746f, 231.438f, 429.297f, 335.059f, 422.477f, 
+370.25f, 395.75f, 370.25f, 395.75f, 320.098f, 421.598f, 227.25f, 428.75f, 10, 0.11f, 
+0, 0, 0, 0, 0, 0, 5, 227.25f, 428.75f, 227.25f, 
+428.75f, 227.477f, 431.059f, 229.25f, 429.746f, 231.438f, 429.297f, 335.059f, 422.477f, 370.25f, 
+395.75f, 370.25f, 395.75f, 320.098f, 421.598f, 227.25f, 428.75f, 10, 0, 1, 
+1, 1, 1, 1, 1, 5, 239.25f, 433.746f, 239.25f, 433.742f, 
+238.918f, 435.898f, 241.25f, 434.746f, 242.879f, 434.137f, 393.141f, 435.238f, 419.246f, 399.75f, 
+419.246f, 399.75f, 394.898f, 427.316f, 239.25f, 433.746f, 10, 0.11f, 0, 0, 
+0, 0, 0, 0, 5, 239.25f, 433.746f, 239.25f, 433.742f, 238.918f, 
+435.898f, 241.25f, 434.746f, 242.879f, 434.137f, 393.141f, 435.238f, 419.246f, 399.75f, 419.246f, 
+399.75f, 394.898f, 427.316f, 239.25f, 433.746f, 10, 0, 1, 1, 1, 
+1, 1, 1, 5, 252.25f, 438.746f, 252.25f, 438.742f, 251.68f, 440.297f, 
+253.246f, 439.75f, 255.637f, 438.535f, 446.379f, 452.836f, 472.25f, 416.746f, 472.25f, 416.742f, 
+461.777f, 445.355f, 252.25f, 438.746f, 10, 0.11f, 0, 0, 0, 0, 
+0, 0, 5, 252.25f, 438.746f, 252.25f, 438.742f, 251.68f, 440.297f, 253.246f, 
+439.75f, 255.637f, 438.535f, 446.379f, 452.836f, 472.25f, 416.746f, 472.25f, 416.742f, 461.777f, 
+445.355f, 252.25f, 438.746f, 10, 0, 1, 1, 1, 1, 1, 
+1, 5, 263.25f, 443.75f, 263.25f, 443.75f, 262.68f, 445.578f, 264.246f, 444.746f, 
+266.637f, 443.816f, 401.059f, 486.277f, 427.25f, 450.75f, 427.25f, 450.75f, 412.277f, 477.699f, 
+263.25f, 443.75f, 10, 0.11f, 0, 0, 0, 0, 0, 0, 
+5, 263.25f, 443.75f, 263.25f, 443.75f, 262.68f, 445.578f, 264.246f, 444.746f, 266.637f, 
+443.816f, 401.059f, 486.277f, 427.25f, 450.75f, 427.25f, 450.75f, 412.277f, 477.699f, 263.25f, 
+443.75f, 10, 0, 1, 1, 1, 1, 1, 1, 5, 
+199.246f, 418.746f, 199.246f, 418.742f, 198.879f, 420.496f, 201.246f, 419.75f, 202.84f, 418.738f, 
+222.418f, 416.316f, 224.246f, 373.75f, 224.242f, 373.75f, 216.699f, 419.836f, 199.246f, 418.746f, 
+10, 0.11f, 0, 0, 0, 0, 0, 0, 5, 199.246f, 
+418.746f, 199.246f, 418.742f, 198.879f, 420.496f, 201.246f, 419.75f, 202.84f, 418.738f, 222.418f, 
+416.316f, 224.246f, 373.75f, 224.242f, 373.75f, 216.699f, 419.836f, 199.246f, 418.746f, 10, 
+0, 1, 1, 1, 1, 1, 1, 5, 189.246f, 416.746f, 
+189.246f, 416.742f, 189.199f, 418.738f, 191.246f, 417.75f, 193.156f, 416.977f, 208.777f, 422.035f, 
+205.25f, 379.746f, 205.25f, 379.746f, 207.02f, 418.078f, 189.246f, 416.746f, 10, 0.11f, 
+0, 0, 0, 0, 0, 0, 5, 189.246f, 416.746f, 189.246f, 
+416.742f, 189.199f, 418.738f, 191.246f, 417.75f, 193.156f, 416.977f, 208.777f, 422.035f, 205.25f, 
+379.746f, 205.25f, 379.746f, 207.02f, 418.078f, 189.246f, 416.746f, 10, 0, 1, 
+1, 1, 1, 1, 1, 5, 180.246f, 416.746f, 180.242f, 416.742f, 
+180.398f, 418.297f, 182.25f, 417.75f, 184.359f, 416.535f, 201.297f, 415.879f, 187.246f, 390.746f, 
+187.246f, 390.746f, 198.219f, 417.637f, 180.246f, 416.746f, 10, 0.11f, 0, 0, 
+0, 0, 0, 0, 5, 180.246f, 416.746f, 180.242f, 416.742f, 180.398f, 
+418.297f, 182.25f, 417.75f, 184.359f, 416.535f, 201.297f, 415.879f, 187.246f, 390.746f, 187.246f, 
+390.746f, 198.219f, 417.637f, 180.246f, 416.746f, 10, 0, 1, 1, 1, 
+1, 1, 1, 5, 232.246f, 464.746f, 232.246f, 464.742f, 232.187f, 462.887f, 
+234.246f, 463.75f, 251.566f, 478.113f, 287.254f, 542.906f, 348.25f, 548.746f, 348.25f, 548.746f, 
+306.367f, 562.426f, 232.246f, 464.746f, 10, 0.11f, 0, 0, 0, 0, 
+0, 0, 5, 232.246f, 464.746f, 232.246f, 464.742f, 232.187f, 462.887f, 234.246f, 
+463.75f, 251.566f, 478.113f, 287.254f, 542.906f, 348.25f, 548.746f, 348.25f, 548.746f, 306.367f, 
+562.426f, 232.246f, 464.746f, 10, 0, 1, 1, 1, 1, 1, 
+1, 5, 245.246f, 466.746f, 245.246f, 466.742f, 243.496f, 468.379f, 245.246f, 468.75f, 
+247.605f, 469.754f, 371.293f, 549.508f, 414.25f, 540.75f, 414.25f, 540.75f, 384.688f, 549.004f, 
+245.246f, 466.746f, 10, 0.11f, 0, 0, 0, 0, 0, 0, 
+5, 245.246f, 466.746f, 245.246f, 466.742f, 243.496f, 468.379f, 245.246f, 468.75f, 247.605f, 
+469.754f, 371.293f, 549.508f, 414.25f, 540.75f, 414.25f, 540.75f, 384.688f, 549.004f, 245.246f, 
+466.746f, 10, 0, 1, 1, 1, 1, 1, 1, 5, 
+222.246f, 460.746f, 222.246f, 460.742f, 221.512f, 458.594f, 223.246f, 459.75f, 233.266f, 465.301f, 
+237.242f, 528.234f, 285.25f, 529.75f, 285.25f, 529.75f, 249.523f, 545.801f, 222.246f, 460.746f, 
+10, 0.11f, 0, 0, 0, 0, 0, 0, 5, 222.246f, 
+460.746f, 222.246f, 460.742f, 221.512f, 458.594f, 223.246f, 459.75f, 233.266f, 465.301f, 237.242f, 
+528.234f, 285.25f, 529.75f, 285.25f, 529.75f, 249.523f, 545.801f, 222.246f, 460.746f, 10, 
+0, 1, 1, 1, 1, 1, 1, 5, 200.246f, 447.746f, 
+200.246f, 447.746f, 198.973f, 446.812f, 201.246f, 446.75f, 212.391f, 448.555f, 235.937f, 493.953f, 
+285.25f, 488.746f, 285.25f, 488.742f, 249.656f, 504.148f, 200.246f, 447.746f, 10, 0.11f, 
+0, 0, 0, 0, 0, 0, 5, 200.246f, 447.746f, 200.246f, 
+447.746f, 198.973f, 446.812f, 201.246f, 446.75f, 212.391f, 448.555f, 235.937f, 493.953f, 285.25f, 
+488.746f, 285.25f, 488.742f, 249.656f, 504.148f, 200.246f, 447.746f, 10, 0, 1, 
+1, 1, 1, 1, 1, 5, 212.246f, 454.75f, 212.246f, 454.75f, 
+211.625f, 453.348f, 213.246f, 453.746f, 224.461f, 457.637f, 238.852f, 506.711f, 288.246f, 510.746f, 
+288.246f, 510.742f, 250.363f, 519.348f, 212.246f, 454.75f, 10, 0.11f, 0, 0, 
+0, 0, 0, 0, 5, 212.246f, 454.75f, 212.246f, 454.75f, 211.625f, 
+453.348f, 213.246f, 453.746f, 224.461f, 457.637f, 238.852f, 506.711f, 288.246f, 510.746f, 288.246f, 
+510.742f, 250.363f, 519.348f, 212.246f, 454.75f, 10, 0, 1, 1, 1, 
+1, 1, 1, 5, 192.25f, 442.746f, 192.25f, 442.742f, 191.453f, 441.449f, 
+193.25f, 441.75f, 202.32f, 442.863f, 221.395f, 479.633f, 261.25f, 474.75f, 261.25f, 474.75f, 
+232.508f, 487.891f, 192.25f, 442.746f, 10, 0.11f, 0, 0, 0, 0, 
+0, 0, 5, 192.25f, 442.746f, 192.25f, 442.742f, 191.453f, 441.449f, 193.25f, 
+441.75f, 202.32f, 442.863f, 221.395f, 479.633f, 261.25f, 474.75f, 261.25f, 474.75f, 232.508f, 
+487.891f, 192.25f, 442.746f, 10, 0, 1, 1, 1, 1, 1, 
+1, 5, 184.25f, 435.75f, 184.25f, 435.75f, 182.949f, 434.945f, 184.25f, 434.746f, 
+189.281f, 435.414f, 222.984f, 471.801f, 243.246f, 454.75f, 243.246f, 454.75f, 230.082f, 475.344f, 
+184.25f, 435.75f, 10, 0.11f, 0, 0, 0, 0, 0, 0, 
+5, 184.25f, 435.75f, 184.25f, 435.75f, 182.949f, 434.945f, 184.25f, 434.746f, 189.281f, 
+435.414f, 222.984f, 471.801f, 243.246f, 454.75f, 243.246f, 454.75f, 230.082f, 475.344f, 184.25f, 
+435.75f, 10, 0, 1, 1, 1, 1, 1, 1, 5, 
+260.25f, 470.75f, 260.25f, 470.75f, 259.219f, 472.699f, 261.25f, 472.75f, 263.469f, 473.547f, 
+396.242f, 537.031f, 438.25f, 522.746f, 438.25f, 522.746f, 409.465f, 534.84f, 260.25f, 470.75f, 
+10, 0.11f, 0, 0, 0, 0, 0, 0, 5, 260.25f, 
+470.75f, 260.25f, 470.75f, 259.219f, 472.699f, 261.25f, 472.75f, 263.469f, 473.547f, 396.242f, 
+537.031f, 438.25f, 522.746f, 438.25f, 522.746f, 409.465f, 534.84f, 260.25f, 470.75f, 10, 
+0, 1, 1, 1, 1, 1, 1, 5, 223.246f, 400.75f, 
+223.246f, 400.75f, 223.52f, 402.457f, 225.25f, 401.746f, 227.477f, 400.695f, 244.418f, 400.035f, 
+231.246f, 375.75f, 231.246f, 375.75f, 241.34f, 401.797f, 223.246f, 400.75f, 10, 0.11f, 
+0, 0, 0, 0, 0, 0, 5, 223.246f, 400.75f, 223.246f, 
+400.75f, 223.52f, 402.457f, 225.25f, 401.746f, 227.477f, 400.695f, 244.418f, 400.035f, 231.246f, 
+375.75f, 231.246f, 375.75f, 241.34f, 401.797f, 223.246f, 400.75f, 10, 0, 1, 
+1, 1, 1, 1, 1, 5, 235.246f, 401.746f, 235.242f, 401.746f, 
+234.957f, 404.219f, 237.25f, 403.746f, 238.918f, 402.457f, 258.5f, 400.035f, 260.25f, 357.746f, 
+260.25f, 357.746f, 252.777f, 403.559f, 235.246f, 401.746f, 10, 0.11f, 0, 0, 
+0, 0, 0, 0, 5, 235.246f, 401.746f, 235.242f, 401.746f, 234.957f, 
+404.219f, 237.25f, 403.746f, 238.918f, 402.457f, 258.5f, 400.035f, 260.25f, 357.746f, 260.25f, 
+357.746f, 252.777f, 403.559f, 235.246f, 401.746f, 10, 0, 1, 1, 1, 
+1, 1, 1, 5, 242.246f, 403.746f, 242.246f, 403.746f, 242.437f, 405.977f, 
+244.246f, 404.75f, 246.398f, 404.219f, 273.457f, 400.477f, 299.246f, 364.75f, 299.246f, 364.75f, 
+260.258f, 405.316f, 242.246f, 403.746f, 10, 0.11f, 0, 0, 0, 0, 
+0, 0, 5, 242.246f, 403.746f, 242.246f, 403.746f, 242.437f, 405.977f, 244.246f, 
+404.75f, 246.398f, 404.219f, 273.457f, 400.477f, 299.246f, 364.75f, 299.246f, 364.75f, 260.258f, 
+405.316f, 242.246f, 403.746f, 10, 0, 1, 1, 1, 1, 1, 
+1, 5, 251.25f, 405.746f, 251.25f, 405.742f, 250.566f, 408.164f, 252.25f, 407.746f, 
+254.723f, 406.945f, 277.199f, 409.031f, 319.25f, 371.75f, 319.25f, 371.75f, 268.316f, 409.875f, 
+251.25f, 405.746f, 10, 0.11f, 0, 0, 0, 0, 0, 0, 
+5, 251.25f, 405.746f, 251.25f, 405.742f, 250.566f, 408.164f, 252.25f, 407.746f, 254.723f, 
+406.945f, 277.199f, 409.031f, 319.25f, 371.75f, 319.25f, 371.75f, 268.316f, 409.875f, 251.25f, 
+405.746f, 10, 0, 1, 1, 1, 1, 1, 1, 5, 
+262.25f, 410.75f, 262.25f, 410.75f, 262.004f, 413.004f, 264.246f, 412.746f, 266.164f, 411.785f, 
+304.48f, 406.832f, 361.25f, 368.746f, 361.25f, 368.746f, 279.754f, 414.715f, 262.25f, 410.75f, 
+10, 0.11f, 0, 0, 0, 0, 0, 0, 5, 262.25f, 
+410.75f, 262.25f, 410.75f, 262.004f, 413.004f, 264.246f, 412.746f, 266.164f, 411.785f, 304.48f, 
+406.832f, 361.25f, 368.746f, 361.25f, 368.746f, 279.754f, 414.715f, 262.25f, 410.75f, 10, 
+0, 1, 1, 1, 1, 1, 1, 5, 218.25f, 423.746f, 
+218.25f, 423.746f, 217.797f, 425.777f, 220.246f, 424.75f, 221.758f, 424.016f, 280.5f, 421.156f, 
+314.25f, 391.75f, 314.25f, 391.75f, 275.547f, 418.93f, 218.25f, 423.746f, 10, 0.11f, 
+0, 0, 0, 0, 0, 0, 5, 218.25f, 423.746f, 218.25f, 
+423.746f, 217.797f, 425.777f, 220.246f, 424.75f, 221.758f, 424.016f, 280.5f, 421.156f, 314.25f, 
+391.75f, 314.25f, 391.75f, 275.547f, 418.93f, 218.25f, 423.746f, 10, 0, 1, 
+1, 1, 1, 1, 1, 5, 207.25f, 419.75f, 207.25f, 419.75f, 
+206.797f, 421.379f, 209.246f, 420.746f, 210.758f, 419.617f, 237.816f, 415.879f, 264.246f, 379.746f, 
+264.246f, 379.746f, 224.617f, 420.719f, 207.25f, 419.75f, 10, 0.11f, 0, 0, 
+0, 0, 0, 0, 5, 207.25f, 419.75f, 207.25f, 419.75f, 206.797f, 
+421.379f, 209.246f, 420.746f, 210.758f, 419.617f, 237.816f, 415.879f, 264.246f, 379.746f, 264.246f, 
+379.746f, 224.617f, 420.719f, 207.25f, 419.75f, 10, 0, 1, 1, 1, 
+1, 1, 1, 5, 274.25f, 415.75f, 274.25f, 415.75f, 273.828f, 418.031f, 
+276.246f, 417.75f, 278.066f, 417.125f, 316.645f, 414.992f, 376.246f, 380.75f, 376.246f, 380.75f, 
+290.746f, 418.625f, 274.25f, 415.75f, 10, 0.11f, 0, 0, 0, 0, 
+0, 0, 5, 274.25f, 415.75f, 274.25f, 415.75f, 273.828f, 418.031f, 276.246f, 
+417.75f, 278.066f, 417.125f, 316.645f, 414.992f, 376.246f, 380.75f, 376.246f, 380.75f, 290.746f, 
+418.625f, 274.25f, 415.75f, 10, 0, 1, 1, 1, 1, 1, 
+1, 5, 283.25f, 418.746f, 283.25f, 418.742f, 283.07f, 420.672f, 285.25f, 419.75f, 
+287.309f, 419.762f, 325.883f, 417.633f, 385.25f, 383.746f, 385.25f, 383.742f, 300.648f, 421.703f, 
+283.25f, 418.746f, 10, 0.11f, 0, 0, 0, 0, 0, 0, 
+5, 283.25f, 418.746f, 283.25f, 418.742f, 283.07f, 420.672f, 285.25f, 419.75f, 287.309f, 
+419.762f, 325.883f, 417.633f, 385.25f, 383.746f, 385.25f, 383.742f, 300.648f, 421.703f, 283.25f, 
+418.746f, 10, 0, 1, 1, 1, 1, 1, 1, 5, 
+294.25f, 424.75f, 294.25f, 424.75f, 293.629f, 426.172f, 296.25f, 425.746f, 297.867f, 425.262f, 
+345.242f, 420.492f, 444.246f, 382.75f, 444.246f, 382.75f, 311.207f, 427.203f, 294.25f, 424.75f, 
+10, 0.11f, 0, 0, 0, 0, 0, 0, 5, 294.25f, 
+424.75f, 294.25f, 424.75f, 293.629f, 426.172f, 296.25f, 425.746f, 297.867f, 425.262f, 345.242f, 
+420.492f, 444.246f, 382.75f, 444.246f, 382.75f, 311.207f, 427.203f, 294.25f, 424.75f, 10, 
+0, 0, 0, 0, 0, 0, 0, 4, 172.25f, 416.746f, 
+172.25f, 416.742f, 177.539f, 417.195f, 176.246f, 415.75f, 174.898f, 413.676f, 172.25f, 414.746f, 
+172.25f, 414.746f, 172.25f, 416.746f, 10, 0, 0, 0, 0, 0, 
+0, 0, 4, 205.25f, 401.746f, 205.25f, 401.746f, 211.418f, 401.797f, 210.246f, 
+399.75f, 208.777f, 398.277f, 206.25f, 398.746f, 206.25f, 398.746f, 205.25f, 401.746f, 10, 
+0, 0, 0, 0, 0, 0, 0, 4, 196.25f, 401.746f, 
+196.25f, 401.746f, 201.738f, 402.238f, 200.246f, 400.75f, 199.098f, 398.719f, 196.25f, 399.75f, 
+196.25f, 399.75f, 196.25f, 401.746f, 10, 0, 0, 0, 0, 0, 
+0, 0, 4, 91.25f, 414.746f, 91.25f, 414.746f, 96.6602f, 413.344f, 95.25f, 
+411.746f, 93.0156f, 410.879f, 91.25f, 412.746f, 91.25f, 412.746f, 91.25f, 414.746f, 10, 
+0, 0, 0, 0, 0, 0, 0, 4, 93.2461f, 425.746f, 
+93.2422f, 425.746f, 98.8633f, 423.902f, 97.25f, 422.746f, 95.2148f, 421.441f, 93.2461f, 422.746f, 
+93.2461f, 422.746f, 93.2461f, 425.746f, 10, 0, 0, 0, 0, 0, 
+0, 0, 4, 85.25f, 429.746f, 85.25f, 429.742f, 90.9414f, 428.742f, 89.2461f, 
+427.746f, 87.2969f, 426.281f, 85.25f, 427.746f, 85.25f, 427.746f, 85.25f, 429.746f, 10, 
+0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 5, 173.25f, 347.75f, 
+173.25f, 347.75f, 171.379f, 347.676f, 167.25f, 345.75f, 164.777f, 345.477f, 152.457f, 341.516f, 
+146.25f, 330.746f, 146.25f, 330.742f, 159.938f, 341.078f, 173.25f, 347.75f, 10, 0, 
+0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 9, 269.246f, 245.746f, 269.781f, 
+245.484f, 269.84f, 245.02f, 270.25f, 244.75f, 270.887f, 244.957f, 272.242f, 244.625f, 272.25f, 
+245.746f, 271.172f, 250.063f, 270.211f, 255.492f, 265.246f, 257.746f, 264.961f, 257.789f, 263.375f, 
+257.332f, 263.25f, 256.746f, 263.156f, 254.684f, 263.027f, 253.203f, 263.25f, 251.75f, 263.695f, 
+250.027f, 266.07f, 250.016f, 267.246f, 251.75f, 268.109f, 249.699f, 268.582f, 247.672f, 269.246f, 
+245.746f, 10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 9, 
+257.246f, 240.75f, 258.262f, 239.004f, 258.121f, 236.961f, 259.25f, 236.746f, 260.492f, 236.016f, 
+262.527f, 237.09f, 262.25f, 238.746f, 261.188f, 240.539f, 260.758f, 243, 259.25f, 244.75f, 
+259.012f, 245.281f, 259.277f, 245.867f, 259.25f, 245.746f, 258.445f, 247.57f, 257.188f, 248.379f, 
+255.246f, 247.746f, 254.41f, 245.594f, 255.676f, 243.25f, 257.246f, 241.75f, 257.5f, 241.203f, 
+257.316f, 240.793f, 257.246f, 240.75f, 10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 
+0.8f, 0.8f, 11, 214.25f, 246.746f, 213.758f, 246.684f, 213.719f, 247.191f, 214.25f, 
+247.746f, 214.484f, 248.68f, 215.355f, 249.914f, 215.25f, 250.746f, 214.602f, 252.203f, 213.375f, 
+252, 212.246f, 251.75f, 211.41f, 250.281f, 211.355f, 248.273f, 210.246f, 246.746f, 210.379f, 
+246.355f, 210.438f, 245.723f, 210.246f, 245.746f, 209.43f, 244.832f, 208.945f, 243.152f, 209.246f, 
+242.75f, 209.109f, 242.18f, 208.91f, 231.281f, 209.246f, 231.75f, 209.836f, 232.379f, 213.188f, 
+243.086f, 213.246f, 243.75f, 213.328f, 244.871f, 214.133f, 245.383f, 214.25f, 246.746f, 10, 
+0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 7, 185.25f, 253.75f, 
+188.574f, 256.488f, 191.641f, 259.746f, 191.246f, 263.75f, 191.027f, 264.902f, 189.074f, 264.32f, 
+189.246f, 263.75f, 187.988f, 259.402f, 185.746f, 256.477f, 183.25f, 253.75f, 180.504f, 251.594f, 
+178.457f, 244.617f, 178.246f, 243.75f, 182.266f, 249.84f, 184.746f, 252.859f, 185.25f, 253.75f, 
+10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 10, 170.246f, 
+260.746f, 171.32f, 260.707f, 170.988f, 261.246f, 171.246f, 261.746f, 172.273f, 263.215f, 173.707f, 
+264.586f, 173.25f, 266.746f, 173.73f, 266.805f, 173.313f, 267.145f, 173.25f, 266.746f, 172.641f, 
+266.695f, 172.262f, 266.551f, 172.25f, 266.746f, 169.91f, 263.715f, 168.371f, 260.777f, 167.25f, 
+257.746f, 166.582f, 257.289f, 165.324f, 252.352f, 165.246f, 251.75f, 165.934f, 252.133f, 167.824f, 
+256.734f, 168.25f, 256.746f, 169.445f, 257.613f, 169.457f, 259.391f, 170.246f, 260.746f, 10, 
+0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 6, 189.246f, 238.746f, 
+189.641f, 239.758f, 191.371f, 241.078f, 191.246f, 241.75f, 191.117f, 243.078f, 191.633f, 244.664f, 
+190.246f, 243.75f, 189.246f, 242.867f, 185.453f, 241.383f, 185.25f, 234.746f, 185.129f, 234.363f, 
+188.398f, 237.328f, 189.246f, 238.746f, 10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 
+0.8f, 0.8f, 19, 205.25f, 257.746f, 205.477f, 258.434f, 206.258f, 257.91f, 207.25f, 
+257.746f, 207.473f, 258.609f, 208.148f, 259.223f, 208.25f, 259.746f, 209.535f, 262.301f, 211.48f, 
+264.305f, 211.246f, 266.746f, 209.996f, 268.484f, 209.25f, 266.238f, 208.25f, 264.746f, 207.102f, 
+266.988f, 206.004f, 264.926f, 204.25f, 264.746f, 204.496f, 264.324f, 204.262f, 264.707f, 204.25f, 
+264.746f, 202.887f, 264.195f, 202.137f, 263.004f, 201.246f, 261.746f, 200.852f, 261.996f, 200.406f, 
+262.195f, 200.246f, 261.746f, 199.527f, 261.383f, 198.457f, 261.027f, 198.246f, 260.746f, 196.93f, 
+257.297f, 193.473f, 254.992f, 191.246f, 246.746f, 191.816f, 245.695f, 196.359f, 254.004f, 197.25f, 
+254.75f, 197.816f, 256.086f, 197.945f, 252.945f, 199.246f, 253.75f, 199.406f, 253.707f, 199.609f, 
+253.445f, 200.246f, 253.75f, 199.973f, 253.605f, 200.211f, 253.855f, 200.246f, 253.75f, 200.637f, 
+254.176f, 200.492f, 254.789f, 200.246f, 254.75f, 202.074f, 256.039f, 201.98f, 257.215f, 203.25f, 
+258.746f, 203.344f, 257.711f, 204.508f, 258.5f, 205.25f, 257.746f, 10, 0, 0.8f, 
+0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 6, 271.25f, 197.75f, 271.25f, 197.75f, 
+278.957f, 220.297f, 274.25f, 232.75f, 274.25f, 232.75f, 286.656f, 208.855f, 281.25f, 196.75f, 
+281.25f, 196.75f, 281.156f, 207.977f, 277.246f, 213.746f, 277.246f, 213.746f, 272.359f, 199.398f, 
+271.25f, 197.75f, 10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 
+5, 254.246f, 200.75f, 254.246f, 200.75f, 260.477f, 210.398f, 251.25f, 230.75f, 251.25f, 
+230.75f, 250.797f, 208.195f, 243.246f, 195.746f, 243.246f, 195.742f, 258.937f, 218.316f, 254.246f, 
+200.75f, 10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 5, 
+243.246f, 202.746f, 243.246f, 202.746f, 243.316f, 224.918f, 244.246f, 227.746f, 244.246f, 227.742f, 
+239.578f, 209.957f, 228.25f, 199.75f, 228.25f, 199.75f, 244.199f, 212.598f, 243.246f, 202.746f, 
+10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 5, 233.246f, 
+237.746f, 233.246f, 237.746f, 239.578f, 223.156f, 228.25f, 202.746f, 228.25f, 202.746f, 235.617f, 
+216.336f, 230.25f, 223.746f, 230.25f, 223.746f, 233.199f, 227.777f, 233.246f, 237.746f, 10, 
+0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 8, 212.246f, 203.746f, 
+212.246f, 203.746f, 210.758f, 220.516f, 212.246f, 222.75f, 212.246f, 222.75f, 212.957f, 229.977f, 
+212.246f, 230.75f, 212.246f, 230.75f, 216.918f, 237.898f, 217.25f, 229.75f, 217.25f, 229.75f, 
+218.68f, 221.176f, 222.246f, 215.746f, 222.246f, 215.746f, 225.719f, 210.176f, 225.25f, 202.746f, 
+225.25f, 202.746f, 214.5f, 236.355f, 212.246f, 203.746f, 10, 0, 0.8f, 0.8f, 
+0.8f, 0.8f, 0.8f, 0.8f, 5, 208.25f, 233.75f, 208.25f, 233.75f, 200.637f, 
+221.836f, 198.246f, 200.75f, 198.246f, 200.75f, 197.117f, 207.758f, 201.246f, 223.746f, 201.246f, 
+223.746f, 205.918f, 240.535f, 208.25f, 233.75f, 10, 0, 0.8f, 0.8f, 0.8f, 
+0.8f, 0.8f, 0.8f, 6, 184.25f, 211.75f, 184.25f, 211.75f, 189.418f, 217.879f, 
+191.246f, 223.746f, 191.242f, 223.746f, 194.918f, 240.758f, 188.246f, 231.75f, 188.246f, 231.75f, 
+188.098f, 222.496f, 179.246f, 214.746f, 179.246f, 214.746f, 184.359f, 216.996f, 184.25f, 211.75f, 
+10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 6, 177.246f, 
+217.746f, 177.246f, 217.742f, 181.277f, 236.578f, 182.25f, 237.746f, 182.25f, 237.746f, 184.137f, 
+241.195f, 181.25f, 237.746f, 181.25f, 237.746f, 171.379f, 216.559f, 167.25f, 209.75f, 167.25f, 
+209.75f, 175.777f, 219.418f, 177.246f, 217.746f, 10, 0, 0.8f, 0.8f, 0.8f, 
+0.8f, 0.8f, 0.8f, 4, 171.246f, 235.746f, 171.246f, 235.746f, 183.918f, 260.336f, 
+160.246f, 231.75f, 160.246f, 231.75f, 172.039f, 242.738f, 171.246f, 235.746f, 10, 0, 
+0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 6, 154.246f, 251.75f, 154.242f, 
+251.75f, 159.5f, 272.438f, 162.25f, 271.746f, 162.25f, 271.746f, 171.379f, 282.117f, 164.246f, 
+270.75f, 164.242f, 270.75f, 157.52f, 259.898f, 158.25f, 248.746f, 158.25f, 248.746f, 157.52f, 
+259.676f, 154.246f, 251.75f, 10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 
+0.8f, 5, 517.246f, 264.746f, 517.242f, 264.742f, 504.348f, 275.297f, 501.25f, 278.75f, 
+501.25f, 278.75f, 516.449f, 258.797f, 516.25f, 250.746f, 516.25f, 250.742f, 519.199f, 259.348f, 
+517.246f, 264.746f, 10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 
+5, 523.25f, 288.746f, 523.25f, 288.742f, 500.5f, 305, 496.25f, 312.75f, 496.25f, 
+312.75f, 525.797f, 280.797f, 526.246f, 275.746f, 526.242f, 275.742f, 526.348f, 285.75f, 523.25f, 
+288.746f, 10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 5, 
+542.246f, 457.75f, 542.246f, 457.75f, 529.098f, 466.699f, 527.25f, 464.746f, 527.25f, 464.742f, 
+539, 457.348f, 542.246f, 447.746f, 542.246f, 447.746f, 540.098f, 457.898f, 542.246f, 457.75f, 
+10, 0, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 0.8f, 4, 551.25f, 
+369.75f, 532.25f, 382.75f, 532.25f, 382.75f, 553.297f, 363.848f, 554.25f, 359.746f, 551.25f, 
+369.75f, 10, 1.1f, 0, 0, 0, 0, 0, 0, 2, 
+122.246f, 393.75f, 146.25f, 388.75f, 10, 1.1f, 0, 0, 0, 0, 
+0, 0, 2, 177.246f, 215.746f, 177.246f, 215.746f, 176.547f, 219.75f, 166.246f, 
+207.75f, 10, 1.1f, 0, 0, 0, 0, 0, 0, 2, 
+183.25f, 210.75f, 183.25f, 210.75f, 185.348f, 217.547f, 178.246f, 212.746f, 10, 1.1f, 
+0, 0, 0, 0, 0, 0, 2, 242.246f, 200.75f, 242.246f, 
+200.75f, 244.199f, 213.148f, 231.246f, 198.75f};
+
diff --git a/host_applications/linux/apps/hello_pi/hello_tiger/tiger.h b/host_applications/linux/apps/hello_pi/hello_tiger/tiger.h
new file mode 100755 (executable)
index 0000000..c83d3f1
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef __TIGER_H
+#define __TIGER_H
+
+/*------------------------------------------------------------------------
+ *
+ * OpenVG 1.0.1 Reference Implementation sample code
+ * -------------------------------------------------
+ *
+ * Copyright (c) 2007 The Khronos Group Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and /or associated documentation files
+ * (the "Materials "), to deal in the Materials without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Materials,
+ * and to permit persons to whom the Materials are furnished to do so,
+ * subject to the following conditions: 
+ *
+ * The above copyright notice and this permission notice shall be included 
+ * in all copies or substantial portions of the Materials. 
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR
+ * THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//**
+ * \file
+ * \brief      Header for including the Tiger image data.
+ * \note       
+ *//*-------------------------------------------------------------------*/
+
+extern const int tigerCommandCount;
+extern const char tigerCommands[];
+extern const float tigerMinX;
+extern const float tigerMaxX;
+extern const float tigerMinY;
+extern const float tigerMaxY;
+extern const int tigerPointCount;
+extern const float tigerPoints[];
+
+#endif /* __TIGER_H */
diff --git a/host_applications/linux/apps/hello_pi/hello_triangle/CMakeLists.txt b/host_applications/linux/apps/hello_pi/hello_triangle/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..4e8128e
--- /dev/null
@@ -0,0 +1,8 @@
+set(EXEC hello_triangle.bin)
+set(SRCS triangle.c)
+
+add_executable(${EXEC} ${SRCS})
+target_link_libraries(${EXEC} ${HELLO_PI_LIBS})
+
+install(TARGETS ${EXEC}
+        RUNTIME DESTINATION bin)
diff --git a/host_applications/linux/apps/hello_pi/hello_triangle/Makefile b/host_applications/linux/apps/hello_pi/hello_triangle/Makefile
new file mode 100755 (executable)
index 0000000..45dcc0d
--- /dev/null
@@ -0,0 +1,5 @@
+OBJS=triangle.o
+BIN=hello_triangle.bin
+
+include ../Makefile.include
+
diff --git a/host_applications/linux/apps/hello_pi/hello_triangle/cube_texture_and_coords.h b/host_applications/linux/apps/hello_pi/hello_triangle/cube_texture_and_coords.h
new file mode 100755 (executable)
index 0000000..7dd30a9
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Spatial coordinates for the cube
+
+static const GLbyte quadx[6*4*3] = {
+   /* FRONT */
+   -10, -10,  10,
+   10, -10,  10,
+   -10,  10,  10,
+   10,  10,  10,
+
+   /* BACK */
+   -10, -10, -10,
+   -10,  10, -10,
+   10, -10, -10,
+   10,  10, -10,
+
+   /* LEFT */
+   -10, -10,  10,
+   -10,  10,  10,
+   -10, -10, -10,
+   -10,  10, -10,
+
+   /* RIGHT */
+   10, -10, -10,
+   10,  10, -10,
+   10, -10,  10,
+   10,  10,  10,
+
+   /* TOP */
+   -10,  10,  10,
+   10,  10,  10,
+   -10,  10, -10,
+   10,  10, -10,
+
+   /* BOTTOM */
+   -10, -10,  10,
+   -10, -10, -10,
+   10, -10,  10,
+   10, -10, -10,
+};
+
+/** Texture coordinates for the quad. */
+static const GLfloat texCoords[6 * 4 * 2] = {
+   0.f,  0.f,
+   0.f,  1.f,
+   1.f,  0.f,
+   1.f,  1.f,
+
+   0.f,  0.f,
+   0.f,  1.f,
+   1.f,  0.f,
+   1.f,  1.f,
+
+   0.f,  0.f,
+   0.f,  1.f,
+   1.f,  0.f,
+   1.f,  1.f,
+
+   0.f,  0.f,
+   0.f,  1.f,
+   1.f,  0.f,
+   1.f,  1.f,
+
+   0.f,  0.f,
+   0.f,  1.f,
+   1.f,  0.f,
+   1.f,  1.f,
+
+   0.f,  0.f,
+   0.f,  1.f,
+   1.f,  0.f,
+   1.f,  1.f
+};
+
diff --git a/host_applications/linux/apps/hello_pi/hello_triangle/triangle.c b/host_applications/linux/apps/hello_pi/hello_triangle/triangle.c
new file mode 100755 (executable)
index 0000000..0956c97
--- /dev/null
@@ -0,0 +1,551 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// A rotating cube rendered with OpenGL|ES. Three images used as textures on the cube faces.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include "bcm_host.h"
+
+#include "GLES/gl.h"
+#include "EGL/egl.h"
+#include "EGL/eglext.h"
+
+#include "cube_texture_and_coords.h"
+
+#define PATH "./"
+
+#define IMAGE_SIZE 128
+
+#ifndef M_PI
+   #define M_PI 3.141592654
+#endif
+       
+
+typedef struct
+{
+   uint32_t screen_width;
+   uint32_t screen_height;
+// OpenGL|ES objects
+   DISPMANX_DISPLAY_HANDLE_T dispman_display;
+   DISPMANX_ELEMENT_HANDLE_T dispman_element;
+   EGLDisplay display;
+   EGLSurface surface;
+   EGLContext context;
+   GLuint tex[6];
+// model rotation vector and direction
+   GLfloat rot_angle_x_inc;
+   GLfloat rot_angle_y_inc;
+   GLfloat rot_angle_z_inc;
+// current model rotation angles
+   GLfloat rot_angle_x;
+   GLfloat rot_angle_y;
+   GLfloat rot_angle_z;
+// current distance from camera
+   GLfloat distance;
+   GLfloat distance_inc;
+// pointers to texture buffers
+   char *tex_buf1;
+   char *tex_buf2;
+   char *tex_buf3;
+} CUBE_STATE_T;
+
+static void init_ogl(CUBE_STATE_T *state);
+static void init_model_proj(CUBE_STATE_T *state);
+static void reset_model(CUBE_STATE_T *state);
+static GLfloat inc_and_wrap_angle(GLfloat angle, GLfloat angle_inc);
+static GLfloat inc_and_clip_distance(GLfloat distance, GLfloat distance_inc);
+static void redraw_scene(CUBE_STATE_T *state);
+static void update_model(CUBE_STATE_T *state);
+static void init_textures(CUBE_STATE_T *state);
+static void load_tex_images(CUBE_STATE_T *state);
+static void exit_func(void);
+static volatile int terminate;
+static CUBE_STATE_T _state, *state=&_state;
+
+
+/***********************************************************
+ * Name: init_ogl
+ *
+ * Arguments:
+ *       CUBE_STATE_T *state - holds OGLES model info
+ *
+ * Description: Sets the display, OpenGL|ES context and screen stuff
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void init_ogl(CUBE_STATE_T *state)
+{
+   int32_t success = 0;
+   EGLBoolean result;
+   EGLint num_config;
+
+   static EGL_DISPMANX_WINDOW_T nativewindow;
+
+   DISPMANX_UPDATE_HANDLE_T dispman_update;
+   VC_RECT_T dst_rect;
+   VC_RECT_T src_rect;
+
+   static const EGLint attribute_list[] =
+   {
+      EGL_RED_SIZE, 8,
+      EGL_GREEN_SIZE, 8,
+      EGL_BLUE_SIZE, 8,
+      EGL_ALPHA_SIZE, 8,
+      EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+      EGL_NONE
+   };
+   
+   EGLConfig config;
+
+   // get an EGL display connection
+   state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+   assert(state->display!=EGL_NO_DISPLAY);
+
+   // initialize the EGL display connection
+   result = eglInitialize(state->display, NULL, NULL);
+   assert(EGL_FALSE != result);
+
+   // get an appropriate EGL frame buffer configuration
+   result = eglChooseConfig(state->display, attribute_list, &config, 1, &num_config);
+   assert(EGL_FALSE != result);
+
+   // create an EGL rendering context
+   state->context = eglCreateContext(state->display, config, EGL_NO_CONTEXT, NULL);
+   assert(state->context!=EGL_NO_CONTEXT);
+
+   // create an EGL window surface
+   success = graphics_get_display_size(0 /* LCD */, &state->screen_width, &state->screen_height);
+   assert( success >= 0 );
+
+   dst_rect.x = 0;
+   dst_rect.y = 0;
+   dst_rect.width = state->screen_width;
+   dst_rect.height = state->screen_height;
+      
+   src_rect.x = 0;
+   src_rect.y = 0;
+   src_rect.width = state->screen_width << 16;
+   src_rect.height = state->screen_height << 16;        
+
+   state->dispman_display = vc_dispmanx_display_open( 0 /* LCD */);
+   dispman_update = vc_dispmanx_update_start( 0 );
+         
+   state->dispman_element = vc_dispmanx_element_add ( dispman_update, state->dispman_display,
+      0/*layer*/, &dst_rect, 0/*src*/,
+      &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, 0/*transform*/);
+      
+   nativewindow.element = state->dispman_element;
+   nativewindow.width = state->screen_width;
+   nativewindow.height = state->screen_height;
+   vc_dispmanx_update_submit_sync( dispman_update );
+      
+   state->surface = eglCreateWindowSurface( state->display, config, &nativewindow, NULL );
+   assert(state->surface != EGL_NO_SURFACE);
+
+   // connect the context to the surface
+   result = eglMakeCurrent(state->display, state->surface, state->surface, state->context);
+   assert(EGL_FALSE != result);
+
+   // Set background color and clear buffers
+   glClearColor(0.15f, 0.25f, 0.35f, 1.0f);
+
+   // Enable back face culling.
+   glEnable(GL_CULL_FACE);
+
+   glMatrixMode(GL_MODELVIEW);
+}
+
+/***********************************************************
+ * Name: init_model_proj
+ *
+ * Arguments:
+ *       CUBE_STATE_T *state - holds OGLES model info
+ *
+ * Description: Sets the OpenGL|ES model to default values
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void init_model_proj(CUBE_STATE_T *state)
+{
+   float nearp = 1.0f;
+   float farp = 500.0f;
+   float hht;
+   float hwd;
+
+   glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
+
+   glViewport(0, 0, (GLsizei)state->screen_width, (GLsizei)state->screen_height);
+      
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+
+   hht = nearp * (float)tan(45.0 / 2.0 / 180.0 * M_PI);
+   hwd = hht * (float)state->screen_width / (float)state->screen_height;
+
+   glFrustumf(-hwd, hwd, -hht, hht, nearp, farp);
+   
+   glEnableClientState( GL_VERTEX_ARRAY );
+   glVertexPointer( 3, GL_BYTE, 0, quadx );
+
+   reset_model(state);
+}
+
+/***********************************************************
+ * Name: reset_model
+ *
+ * Arguments:
+ *       CUBE_STATE_T *state - holds OGLES model info
+ *
+ * Description: Resets the Model projection and rotation direction
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void reset_model(CUBE_STATE_T *state)
+{
+   // reset model position
+   glMatrixMode(GL_MODELVIEW);
+   glLoadIdentity();
+   glTranslatef(0.f, 0.f, -50.f);
+
+   // reset model rotation
+   state->rot_angle_x = 45.f; state->rot_angle_y = 30.f; state->rot_angle_z = 0.f;
+   state->rot_angle_x_inc = 0.5f; state->rot_angle_y_inc = 0.5f; state->rot_angle_z_inc = 0.f;
+   state->distance = 40.f;
+}
+
+/***********************************************************
+ * Name: update_model
+ *
+ * Arguments:
+ *       CUBE_STATE_T *state - holds OGLES model info
+ *
+ * Description: Updates model projection to current position/rotation
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void update_model(CUBE_STATE_T *state)
+{
+   // update position
+   state->rot_angle_x = inc_and_wrap_angle(state->rot_angle_x, state->rot_angle_x_inc);
+   state->rot_angle_y = inc_and_wrap_angle(state->rot_angle_y, state->rot_angle_y_inc);
+   state->rot_angle_z = inc_and_wrap_angle(state->rot_angle_z, state->rot_angle_z_inc);
+   state->distance    = inc_and_clip_distance(state->distance, state->distance_inc);
+
+   glLoadIdentity();
+   // move camera back to see the cube
+   glTranslatef(0.f, 0.f, -state->distance);
+
+   // Rotate model to new position
+   glRotatef(state->rot_angle_x, 1.f, 0.f, 0.f);
+   glRotatef(state->rot_angle_y, 0.f, 1.f, 0.f);
+   glRotatef(state->rot_angle_z, 0.f, 0.f, 1.f);
+}
+
+/***********************************************************
+ * Name: inc_and_wrap_angle
+ *
+ * Arguments:
+ *       GLfloat angle     current angle
+ *       GLfloat angle_inc angle increment
+ *
+ * Description:   Increments or decrements angle by angle_inc degrees
+ *                Wraps to 0 at 360 deg.
+ *
+ * Returns: new value of angle
+ *
+ ***********************************************************/
+static GLfloat inc_and_wrap_angle(GLfloat angle, GLfloat angle_inc)
+{
+   angle += angle_inc;
+
+   if (angle >= 360.0)
+      angle -= 360.f;
+   else if (angle <=0)
+      angle += 360.f;
+
+   return angle;
+}
+
+/***********************************************************
+ * Name: inc_and_clip_distance
+ *
+ * Arguments:
+ *       GLfloat distance     current distance
+ *       GLfloat distance_inc distance increment
+ *
+ * Description:   Increments or decrements distance by distance_inc units
+ *                Clips to range
+ *
+ * Returns: new value of angle
+ *
+ ***********************************************************/
+static GLfloat inc_and_clip_distance(GLfloat distance, GLfloat distance_inc)
+{
+   distance += distance_inc;
+
+   if (distance >= 120.0f)
+      distance = 120.f;
+   else if (distance <= 40.0f)
+      distance = 40.0f;
+
+   return distance;
+}
+
+/***********************************************************
+ * Name: redraw_scene
+ *
+ * Arguments:
+ *       CUBE_STATE_T *state - holds OGLES model info
+ *
+ * Description:   Draws the model and calls eglSwapBuffers
+ *                to render to screen
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void redraw_scene(CUBE_STATE_T *state)
+{
+   // Start with a clear screen
+   glClear( GL_COLOR_BUFFER_BIT );
+
+   // Draw first (front) face:
+   // Bind texture surface to current vertices
+   glBindTexture(GL_TEXTURE_2D, state->tex[0]);
+
+   // Need to rotate textures - do this by rotating each cube face
+   glRotatef(270.f, 0.f, 0.f, 1.f ); // front face normal along z axis
+
+   // draw first 4 vertices
+   glDrawArrays( GL_TRIANGLE_STRIP, 0, 4);
+
+   // same pattern for other 5 faces - rotation chosen to make image orientation 'nice'
+   glBindTexture(GL_TEXTURE_2D, state->tex[1]);
+   glRotatef(90.f, 0.f, 0.f, 1.f ); // back face normal along z axis
+   glDrawArrays( GL_TRIANGLE_STRIP, 4, 4);
+
+   glBindTexture(GL_TEXTURE_2D, state->tex[2]);
+   glRotatef(90.f, 1.f, 0.f, 0.f ); // left face normal along x axis
+   glDrawArrays( GL_TRIANGLE_STRIP, 8, 4);
+
+   glBindTexture(GL_TEXTURE_2D, state->tex[3]);
+   glRotatef(90.f, 1.f, 0.f, 0.f ); // right face normal along x axis
+   glDrawArrays( GL_TRIANGLE_STRIP, 12, 4);
+
+   glBindTexture(GL_TEXTURE_2D, state->tex[4]);
+   glRotatef(270.f, 0.f, 1.f, 0.f ); // top face normal along y axis
+   glDrawArrays( GL_TRIANGLE_STRIP, 16, 4);
+
+   glBindTexture(GL_TEXTURE_2D, state->tex[5]);
+   glRotatef(90.f, 0.f, 1.f, 0.f ); // bottom face normal along y axis
+   glDrawArrays( GL_TRIANGLE_STRIP, 20, 4);
+
+   eglSwapBuffers(state->display, state->surface);
+}
+
+/***********************************************************
+ * Name: init_textures
+ *
+ * Arguments:
+ *       CUBE_STATE_T *state - holds OGLES model info
+ *
+ * Description:   Initialise OGL|ES texture surfaces to use image
+ *                buffers
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void init_textures(CUBE_STATE_T *state)
+{
+   // load three texture buffers but use them on six OGL|ES texture surfaces
+   load_tex_images(state);
+   glGenTextures(6, &state->tex[0]);
+
+   // setup first texture
+   glBindTexture(GL_TEXTURE_2D, state->tex[0]);
+   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, IMAGE_SIZE, IMAGE_SIZE, 0,
+                GL_RGB, GL_UNSIGNED_BYTE, state->tex_buf1);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLfloat)GL_NEAREST);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLfloat)GL_NEAREST);
+
+   // setup second texture - reuse first image
+   glBindTexture(GL_TEXTURE_2D, state->tex[1]);
+   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, IMAGE_SIZE, IMAGE_SIZE, 0,
+                GL_RGB, GL_UNSIGNED_BYTE, state->tex_buf1);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLfloat)GL_NEAREST);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLfloat)GL_NEAREST);
+
+   // third texture
+   glBindTexture(GL_TEXTURE_2D, state->tex[2]);
+   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, IMAGE_SIZE, IMAGE_SIZE, 0,
+                GL_RGB, GL_UNSIGNED_BYTE, state->tex_buf2);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLfloat)GL_NEAREST);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLfloat)GL_NEAREST);
+
+   // fourth texture  - reuse second image
+   glBindTexture(GL_TEXTURE_2D, state->tex[3]);
+   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, IMAGE_SIZE, IMAGE_SIZE, 0,
+                GL_RGB, GL_UNSIGNED_BYTE, state->tex_buf2);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLfloat)GL_NEAREST);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLfloat)GL_NEAREST);
+
+   //fifth texture
+   glBindTexture(GL_TEXTURE_2D, state->tex[4]);
+   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, IMAGE_SIZE, IMAGE_SIZE, 0,
+                GL_RGB, GL_UNSIGNED_BYTE, state->tex_buf3);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLfloat)GL_NEAREST);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLfloat)GL_NEAREST);
+
+   // sixth texture  - reuse third image
+   glBindTexture(GL_TEXTURE_2D, state->tex[5]);
+   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, IMAGE_SIZE, IMAGE_SIZE, 0,
+                GL_RGB, GL_UNSIGNED_BYTE, state->tex_buf3);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLfloat)GL_NEAREST);
+   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLfloat)GL_NEAREST);
+
+   // setup overall texture environment
+   glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+   glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+   
+   glEnable(GL_TEXTURE_2D);
+}
+
+/***********************************************************
+ * Name: load_tex_images
+ *
+ * Arguments:
+ *       void
+ *
+ * Description: Loads three raw images to use as textures on faces
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void load_tex_images(CUBE_STATE_T *state)
+{
+   FILE *tex_file1 = NULL, *tex_file2=NULL, *tex_file3 = NULL;
+   int bytes_read, image_sz = IMAGE_SIZE*IMAGE_SIZE*3;
+
+   state->tex_buf1 = malloc(image_sz);
+   state->tex_buf2 = malloc(image_sz);
+   state->tex_buf3 = malloc(image_sz);
+
+   tex_file1 = fopen(PATH "Lucca_128_128.raw", "rb");
+   if (tex_file1 && state->tex_buf1)
+   {
+      bytes_read=fread(state->tex_buf1, 1, image_sz, tex_file1);
+      assert(bytes_read == image_sz);  // some problem with file?
+      fclose(tex_file1);
+   }
+
+   tex_file2 = fopen(PATH "Djenne_128_128.raw", "rb");
+   if (tex_file2 && state->tex_buf2)
+   {
+      bytes_read=fread(state->tex_buf2, 1, image_sz, tex_file2);
+      assert(bytes_read == image_sz);  // some problem with file?
+      fclose(tex_file2);      
+   }
+
+   tex_file3 = fopen(PATH "Gaudi_128_128.raw", "rb");
+   if (tex_file3 && state->tex_buf3)
+   {
+      bytes_read=fread(state->tex_buf3, 1, image_sz, tex_file3);
+      assert(bytes_read == image_sz);  // some problem with file?
+      fclose(tex_file3);
+   }   
+}
+
+//------------------------------------------------------------------------------
+
+static void exit_func(void)
+// Function to be passed to atexit().
+{
+   DISPMANX_UPDATE_HANDLE_T dispman_update;
+   int s;
+   // clear screen
+   glClear( GL_COLOR_BUFFER_BIT );
+   eglSwapBuffers(state->display, state->surface);
+
+   glDeleteTextures(6, state->tex);
+   eglDestroySurface( state->display, state->surface );
+
+   dispman_update = vc_dispmanx_update_start( 0 );
+   s = vc_dispmanx_element_remove(dispman_update, state->dispman_element);
+   assert(s == 0);
+   vc_dispmanx_update_submit_sync( dispman_update );
+   s = vc_dispmanx_display_close(state->dispman_display);
+   assert (s == 0);
+
+   // Release OpenGL resources
+   eglMakeCurrent( state->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
+   eglDestroyContext( state->display, state->context );
+   eglTerminate( state->display );
+
+   // release texture buffers
+   free(state->tex_buf1);
+   free(state->tex_buf2);
+   free(state->tex_buf3);
+
+   printf("\ncube closed\n");
+} // exit_func()
+
+//==============================================================================
+
+int main ()
+{
+   bcm_host_init();
+
+   // Clear application state
+   memset( state, 0, sizeof( *state ) );
+      
+   // Start OGLES
+   init_ogl(state);
+
+   // Setup the model world
+   init_model_proj(state);
+
+   // initialise the OGLES texture(s)
+   init_textures(state);
+
+   while (!terminate)
+   {
+      update_model(state);
+      redraw_scene(state);
+   }
+   exit_func();
+   return 0;
+}
+
diff --git a/host_applications/linux/apps/hello_pi/hello_triangle2/CMakeLists.txt b/host_applications/linux/apps/hello_pi/hello_triangle2/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..390980a
--- /dev/null
@@ -0,0 +1,8 @@
+set(EXEC hello_triangle2.bin)
+set(SRCS triangle2.c)
+
+add_executable(${EXEC} ${SRCS})
+target_link_libraries(${EXEC} ${HELLO_PI_LIBS})
+
+install(TARGETS ${EXEC}
+        RUNTIME DESTINATION bin)
diff --git a/host_applications/linux/apps/hello_pi/hello_triangle2/Makefile b/host_applications/linux/apps/hello_pi/hello_triangle2/Makefile
new file mode 100755 (executable)
index 0000000..13b1b39
--- /dev/null
@@ -0,0 +1,5 @@
+OBJS=triangle2.o
+BIN=hello_triangle2.bin
+
+include ../Makefile.include
+
diff --git a/host_applications/linux/apps/hello_pi/hello_triangle2/triangle2.c b/host_applications/linux/apps/hello_pi/hello_triangle2/triangle2.c
new file mode 100755 (executable)
index 0000000..bc68c51
--- /dev/null
@@ -0,0 +1,509 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// OpenGL|ES 2 demo using shader to compute mandelbrot/julia sets
+// Thanks to Peter de Rivas for original Python code
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include "bcm_host.h"
+
+#include "GLES2/gl2.h"
+#include "EGL/egl.h"
+#include "EGL/eglext.h"
+
+typedef struct
+{
+   uint32_t screen_width;
+   uint32_t screen_height;
+// OpenGL|ES objects
+   EGLDisplay display;
+   EGLSurface surface;
+   EGLContext context;
+
+   GLuint verbose;
+   GLuint vshader;
+   GLuint fshader;
+   GLuint mshader;
+   GLuint program;
+   GLuint program2;
+   GLuint tex_fb;
+   GLuint tex;
+   GLuint buf;
+// julia attribs
+   GLuint unif_color, attr_vertex, unif_scale, unif_offset, unif_tex, unif_centre; 
+// mandelbrot attribs
+   GLuint attr_vertex2, unif_scale2, unif_offset2, unif_centre2;
+} CUBE_STATE_T;
+
+static CUBE_STATE_T _state, *state=&_state;
+
+#define check() assert(glGetError() == 0)
+
+static void showlog(GLint shader)
+{
+   // Prints the compile log for a shader
+   char log[1024];
+   glGetShaderInfoLog(shader,sizeof log,NULL,log);
+   printf("%d:shader:\n%s\n", shader, log);
+}
+
+static void showprogramlog(GLint shader)
+{
+   // Prints the information log for a program object
+   char log[1024];
+   glGetProgramInfoLog(shader,sizeof log,NULL,log);
+   printf("%d:program:\n%s\n", shader, log);
+}
+    
+/***********************************************************
+ * Name: init_ogl
+ *
+ * Arguments:
+ *       CUBE_STATE_T *state - holds OGLES model info
+ *
+ * Description: Sets the display, OpenGL|ES context and screen stuff
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void init_ogl(CUBE_STATE_T *state)
+{
+   int32_t success = 0;
+   EGLBoolean result;
+   EGLint num_config;
+
+   static EGL_DISPMANX_WINDOW_T nativewindow;
+
+   DISPMANX_ELEMENT_HANDLE_T dispman_element;
+   DISPMANX_DISPLAY_HANDLE_T dispman_display;
+   DISPMANX_UPDATE_HANDLE_T dispman_update;
+   VC_RECT_T dst_rect;
+   VC_RECT_T src_rect;
+
+   static const EGLint attribute_list[] =
+   {
+      EGL_RED_SIZE, 8,
+      EGL_GREEN_SIZE, 8,
+      EGL_BLUE_SIZE, 8,
+      EGL_ALPHA_SIZE, 8,
+      EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+      EGL_NONE
+   };
+   
+   static const EGLint context_attributes[] = 
+   {
+      EGL_CONTEXT_CLIENT_VERSION, 2,
+      EGL_NONE
+   };
+   EGLConfig config;
+
+   // get an EGL display connection
+   state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+   assert(state->display!=EGL_NO_DISPLAY);
+   check();
+
+   // initialize the EGL display connection
+   result = eglInitialize(state->display, NULL, NULL);
+   assert(EGL_FALSE != result);
+   check();
+
+   // get an appropriate EGL frame buffer configuration
+   result = eglChooseConfig(state->display, attribute_list, &config, 1, &num_config);
+   assert(EGL_FALSE != result);
+   check();
+
+   // get an appropriate EGL frame buffer configuration
+   result = eglBindAPI(EGL_OPENGL_ES_API);
+   assert(EGL_FALSE != result);
+   check();
+
+   // create an EGL rendering context
+   state->context = eglCreateContext(state->display, config, EGL_NO_CONTEXT, context_attributes);
+   assert(state->context!=EGL_NO_CONTEXT);
+   check();
+
+   // create an EGL window surface
+   success = graphics_get_display_size(0 /* LCD */, &state->screen_width, &state->screen_height);
+   assert( success >= 0 );
+
+   dst_rect.x = 0;
+   dst_rect.y = 0;
+   dst_rect.width = state->screen_width;
+   dst_rect.height = state->screen_height;
+      
+   src_rect.x = 0;
+   src_rect.y = 0;
+   src_rect.width = state->screen_width << 16;
+   src_rect.height = state->screen_height << 16;        
+
+   dispman_display = vc_dispmanx_display_open( 0 /* LCD */);
+   dispman_update = vc_dispmanx_update_start( 0 );
+         
+   dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display,
+      0/*layer*/, &dst_rect, 0/*src*/,
+      &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, 0/*transform*/);
+      
+   nativewindow.element = dispman_element;
+   nativewindow.width = state->screen_width;
+   nativewindow.height = state->screen_height;
+   vc_dispmanx_update_submit_sync( dispman_update );
+      
+   check();
+
+   state->surface = eglCreateWindowSurface( state->display, config, &nativewindow, NULL );
+   assert(state->surface != EGL_NO_SURFACE);
+   check();
+
+   // connect the context to the surface
+   result = eglMakeCurrent(state->display, state->surface, state->surface, state->context);
+   assert(EGL_FALSE != result);
+   check();
+
+   // Set background color and clear buffers
+   glClearColor(0.15f, 0.25f, 0.35f, 1.0f);
+   glClear( GL_COLOR_BUFFER_BIT );
+
+   check();
+}
+
+
+static void init_shaders(CUBE_STATE_T *state)
+{
+   static const GLfloat vertex_data[] = {
+        -1.0,-1.0,1.0,1.0,
+        1.0,-1.0,1.0,1.0,
+        1.0,1.0,1.0,1.0,
+        -1.0,1.0,1.0,1.0
+   };
+   const GLchar *vshader_source =
+              "attribute vec4 vertex;"
+              "varying vec2 tcoord;"
+              "void main(void) {"
+              " vec4 pos = vertex;"
+              " gl_Position = pos;"
+              " tcoord = vertex.xy*0.5+0.5;"
+              "}";
+      
+   //Mandelbrot
+   const GLchar *mandelbrot_fshader_source =
+"uniform vec4 color;"
+"uniform vec2 scale;"
+"uniform vec2 centre;"
+"varying vec2 tcoord;"
+"void main(void) {"
+"  float intensity;"
+"  vec4 color2;"
+"  float cr=(gl_FragCoord.x-centre.x)*scale.x;"
+"  float ci=(gl_FragCoord.y-centre.y)*scale.y;"
+"  float ar=cr;"
+"  float ai=ci;"
+"  float tr,ti;"
+"  float col=0.0;"
+"  float p=0.0;"
+"  int i=0;"
+"  for(int i2=1;i2<16;i2++)"
+"  {"
+"    tr=ar*ar-ai*ai+cr;"
+"    ti=2.0*ar*ai+ci;"
+"    p=tr*tr+ti*ti;"
+"    ar=tr;"
+"    ai=ti;"
+"    if (p>16.0)"
+"    {"
+"      i=i2;"
+"      break;"
+"    }"
+"  }"
+"  color2 = vec4(float(i)*0.0625,0,0,1);"
+"  gl_FragColor = color2;"
+"}";
+
+   // Julia
+   const GLchar *julia_fshader_source =
+"uniform vec4 color;"
+"uniform vec2 scale;"
+"uniform vec2 centre;"
+"uniform vec2 offset;"
+"varying vec2 tcoord;"
+"uniform sampler2D tex;"
+"void main(void) {"
+"  float intensity;"
+"  vec4 color2;"
+"  float ar=(gl_FragCoord.x-centre.x)*scale.x;"
+"  float ai=(gl_FragCoord.y-centre.y)*scale.y;"
+"  float cr=(offset.x-centre.x)*scale.x;"
+"  float ci=(offset.y-centre.y)*scale.y;"
+"  float tr,ti;"
+"  float col=0.0;"
+"  float p=0.0;"
+"  int i=0;"
+"  vec2 t2;"
+"  t2.x=tcoord.x+(offset.x-centre.x)*(0.5/centre.y);"
+"  t2.y=tcoord.y+(offset.y-centre.y)*(0.5/centre.x);"
+"  for(int i2=1;i2<16;i2++)"
+"  {"
+"    tr=ar*ar-ai*ai+cr;"
+"    ti=2.0*ar*ai+ci;"
+"    p=tr*tr+ti*ti;"
+"    ar=tr;"
+"    ai=ti;"
+"    if (p>16.0)"
+"    {"
+"      i=i2;"
+"      break;"
+"    }"
+"  }"
+"  color2 = vec4(0,float(i)*0.0625,0,1);"
+"  color2 = color2+texture2D(tex,t2);"
+"  gl_FragColor = color2;"
+"}";
+
+        state->vshader = glCreateShader(GL_VERTEX_SHADER);
+        glShaderSource(state->vshader, 1, &vshader_source, 0);
+        glCompileShader(state->vshader);
+        check();
+
+        if (state->verbose)
+            showlog(state->vshader);
+            
+        state->fshader = glCreateShader(GL_FRAGMENT_SHADER);
+        glShaderSource(state->fshader, 1, &julia_fshader_source, 0);
+        glCompileShader(state->fshader);
+        check();
+
+        if (state->verbose)
+            showlog(state->fshader);
+
+        state->mshader = glCreateShader(GL_FRAGMENT_SHADER);
+        glShaderSource(state->mshader, 1, &mandelbrot_fshader_source, 0);
+        glCompileShader(state->mshader);
+        check();
+
+        if (state->verbose)
+            showlog(state->mshader);
+
+        // julia 
+        state->program = glCreateProgram();
+        glAttachShader(state->program, state->vshader);
+        glAttachShader(state->program, state->fshader);
+        glLinkProgram(state->program);
+        check();
+
+        if (state->verbose)
+            showprogramlog(state->program);
+            
+        state->attr_vertex = glGetAttribLocation(state->program, "vertex");
+        state->unif_color  = glGetUniformLocation(state->program, "color");
+        state->unif_scale  = glGetUniformLocation(state->program, "scale");
+        state->unif_offset = glGetUniformLocation(state->program, "offset");
+        state->unif_tex    = glGetUniformLocation(state->program, "tex");       
+        state->unif_centre = glGetUniformLocation(state->program, "centre");
+
+        // mandelbrot
+        state->program2 = glCreateProgram();
+        glAttachShader(state->program2, state->vshader);
+        glAttachShader(state->program2, state->mshader);
+        glLinkProgram(state->program2);
+        check();
+
+        if (state->verbose)
+            showprogramlog(state->program2);
+            
+        state->attr_vertex2 = glGetAttribLocation(state->program2, "vertex");
+        state->unif_scale2  = glGetUniformLocation(state->program2, "scale");
+        state->unif_offset2 = glGetUniformLocation(state->program2, "offset");
+        state->unif_centre2 = glGetUniformLocation(state->program2, "centre");
+        check();
+   
+        glClearColor ( 0.0, 1.0, 1.0, 1.0 );
+        
+        glGenBuffers(1, &state->buf);
+
+        check();
+
+        // Prepare a texture image
+        glGenTextures(1, &state->tex);
+        check();
+        glBindTexture(GL_TEXTURE_2D,state->tex);
+        check();
+        // glActiveTexture(0)
+        glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,state->screen_width,state->screen_height,0,GL_RGB,GL_UNSIGNED_SHORT_5_6_5,0);
+        check();
+        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+        check();
+        // Prepare a framebuffer for rendering
+        glGenFramebuffers(1,&state->tex_fb);
+        check();
+        glBindFramebuffer(GL_FRAMEBUFFER,state->tex_fb);
+        check();
+        glFramebufferTexture2D(GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,state->tex,0);
+        check();
+        glBindFramebuffer(GL_FRAMEBUFFER,0);
+        check();
+        // Prepare viewport
+        glViewport ( 0, 0, state->screen_width, state->screen_height );
+        check();
+        
+        // Upload vertex data to a buffer
+        glBindBuffer(GL_ARRAY_BUFFER, state->buf);
+        glBufferData(GL_ARRAY_BUFFER, sizeof(vertex_data),
+                             vertex_data, GL_STATIC_DRAW);
+        glVertexAttribPointer(state->attr_vertex, 4, GL_FLOAT, 0, 16, 0);
+        glEnableVertexAttribArray(state->attr_vertex);
+        check();
+}
+
+
+static void draw_mandelbrot_to_texture(CUBE_STATE_T *state, GLfloat cx, GLfloat cy, GLfloat scale)
+{
+        // Draw the mandelbrot to a texture
+        glBindFramebuffer(GL_FRAMEBUFFER,state->tex_fb);
+        check();
+        glBindBuffer(GL_ARRAY_BUFFER, state->buf);
+        
+        glUseProgram ( state->program2 );
+        check();
+
+        glUniform2f(state->unif_scale2, scale, scale);
+        glUniform2f(state->unif_centre2, cx, cy);
+        check();
+        glDrawArrays ( GL_TRIANGLE_FAN, 0, 4 );
+        check();
+               
+        glFlush();
+        glFinish();
+        check();
+}
+        
+static void draw_triangles(CUBE_STATE_T *state, GLfloat cx, GLfloat cy, GLfloat scale, GLfloat x, GLfloat y)
+{
+        // Now render to the main frame buffer
+        glBindFramebuffer(GL_FRAMEBUFFER,0);
+        // Clear the background (not really necessary I suppose)
+        glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+        check();
+        
+        glBindBuffer(GL_ARRAY_BUFFER, state->buf);
+        check();
+        glUseProgram ( state->program );
+        check();
+        glBindTexture(GL_TEXTURE_2D,state->tex);
+        check();
+        glUniform4f(state->unif_color, 0.5, 0.5, 0.8, 1.0);
+        glUniform2f(state->unif_scale, scale, scale);
+        glUniform2f(state->unif_offset, x, y);
+        glUniform2f(state->unif_centre, cx, cy);
+        glUniform1i(state->unif_tex, 0); // I don't really understand this part, perhaps it relates to active texture?
+        check();
+        
+        glDrawArrays ( GL_TRIANGLE_FAN, 0, 4 );
+        check();
+
+        glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+        glFlush();
+        glFinish();
+        check();
+        
+        eglSwapBuffers(state->display, state->surface);
+        check();
+}
+
+static int get_mouse(CUBE_STATE_T *state, int *outx, int *outy)
+{
+    static int fd = -1;
+    const int width=state->screen_width, height=state->screen_height;
+    static int x=800, y=400;
+    const int XSIGN = 1<<4, YSIGN = 1<<5;
+    if (fd<0) {
+       fd = open("/dev/input/mouse0",O_RDONLY|O_NONBLOCK);
+    }
+    if (fd>=0) {
+        struct {char buttons, dx, dy; } m;
+        while (1) {
+           int bytes = read(fd, &m, sizeof m);
+           if (bytes < (int)sizeof m) goto _exit;
+           if (m.buttons&8) {
+              break; // This bit should always be set
+           }
+           read(fd, &m, 1); // Try to sync up again
+        }
+        if (m.buttons&3)
+           return m.buttons&3;
+        x+=m.dx;
+        y+=m.dy;
+        if (m.buttons&XSIGN)
+           x-=256;
+        if (m.buttons&YSIGN)
+           y-=256;
+        if (x<0) x=0;
+        if (y<0) y=0;
+        if (x>width) x=width;
+        if (y>height) y=height;
+   }
+_exit:
+   if (outx) *outx = x;
+   if (outy) *outy = y;
+   return 0;
+}       
+//==============================================================================
+
+int main ()
+{
+   int terminate = 0;
+   GLfloat cx, cy;
+   bcm_host_init();
+
+   // Clear application state
+   memset( state, 0, sizeof( *state ) );
+      
+   // Start OGLES
+   init_ogl(state);
+   init_shaders(state);
+   cx = state->screen_width/2;
+   cy = state->screen_height/2;
+
+   draw_mandelbrot_to_texture(state, cx, cy, 0.003);
+   while (!terminate)
+   {
+      int x, y, b;
+      b = get_mouse(state, &x, &y);
+      if (b) break;
+      draw_triangles(state, cx, cy, 0.003, x, y);
+   }
+   return 0;
+}
+
diff --git a/host_applications/linux/apps/hello_pi/hello_video/CMakeLists.txt b/host_applications/linux/apps/hello_pi/hello_video/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..fdc1182
--- /dev/null
@@ -0,0 +1,10 @@
+set(EXEC hello_video.bin)
+set(SRCS tsemaphore.c queue.c video.c)
+#SET(pc_dependents "libtbm")
+
+add_executable(${EXEC} ${SRCS})
+#add_dependencies(${EXEC} ${pc_dependents})
+target_link_libraries(${EXEC} ${HELLO_PI_LIBS} -ltbm)
+
+install(TARGETS ${EXEC}
+        RUNTIME DESTINATION bin)
diff --git a/host_applications/linux/apps/hello_pi/hello_video/Makefile b/host_applications/linux/apps/hello_pi/hello_video/Makefile
new file mode 100755 (executable)
index 0000000..c86256a
--- /dev/null
@@ -0,0 +1,6 @@
+OBJS=tsemaphore.o queue.o video.o
+BIN=hello_video.bin
+LDFLAGS+=-lilclient
+
+include ../Makefile.include
+
diff --git a/host_applications/linux/apps/hello_pi/hello_video/README b/host_applications/linux/apps/hello_pi/hello_video/README
new file mode 100755 (executable)
index 0000000..c4922d9
--- /dev/null
@@ -0,0 +1 @@
+The video clip test.h264 is (c) copyright 2008, Blender Foundation / www.bigbuckbunny.org
diff --git a/host_applications/linux/apps/hello_pi/hello_video/omx_comp_debug_levels.h b/host_applications/linux/apps/hello_pi/hello_video/omx_comp_debug_levels.h
new file mode 100755 (executable)
index 0000000..3ba1d1a
--- /dev/null
@@ -0,0 +1,77 @@
+/**
+  @file src/omx_comp_debug_levels.h
+
+  Define the level of debug prints on standard err. The different levels can 
+  be composed with binary OR.
+  The debug levels defined here belong to OpenMAX components and IL core
+
+  Copyright (C) 2007-2008 STMicroelectronics
+  Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies).
+
+  This library is free software; you can redistribute it and/or modify it under
+  the terms of the GNU Lesser General Public License as published by the Free
+  Software Foundation; either version 2.1 of the License, or (at your option)
+  any later version.
+
+  This library is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+  FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+  details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with this library; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St, Fifth Floor, Boston, MA
+  02110-1301  USA
+
+  $Date: 2008-07-16 09:39:31 +0200 (Wed, 16 Jul 2008) $
+  Revision $Rev: 577 $
+  Author $Author: gsent $
+
+*/
+
+#ifndef __OMX_COMP_DEBUG_LEVELS_H__
+#define __OMX_COMP_DEBUG_LEVELS_H__
+
+#include <stdio.h>
+
+/** Remove all debug output lines
+ */
+#define DEB_LEV_NO_OUTPUT  0
+
+/** Messages explaing the reason of critical errors 
+ */
+#define DEB_LEV_ERR        1
+/** Messages showing values related to the test and the component/s used
+ */
+#define DEB_LEV_PARAMS     2
+
+/** Messages representing steps in the execution. These are the simple messages, because 
+ * they avoid iterations 
+ */
+#define DEB_LEV_SIMPLE_SEQ 4
+
+/** Messages representing steps in the execution. All the steps are described, 
+ * also with iterations. With this level of output the performances are 
+ * seriously compromised
+ */
+#define DEB_LEV_FULL_SEQ   8
+
+/** Messages that indicates the beginning and the end of a function.
+ * It can be used to trace the execution
+ */
+#define DEB_LEV_FUNCTION_NAME 16
+
+/** All the messages - max value
+ */
+#define DEB_ALL_MESS   255
+
+/** \def DEBUG_LEVEL is the current level do debug output on standard err */
+#define DEBUG_LEVEL (DEB_LEV_ERR)
+#if DEBUG_LEVEL > 0
+#define DEBUG(n, fmt, args...) do { if (DEBUG_LEVEL & (n)){fprintf(stderr, "OMX-" fmt, ##args);} } while (0)
+#else
+#define DEBUG(n, fmt, args...) 
+#endif
+
+#endif
diff --git a/host_applications/linux/apps/hello_pi/hello_video/queue.c b/host_applications/linux/apps/hello_pi/hello_video/queue.c
new file mode 100755 (executable)
index 0000000..e6ee4b7
--- /dev/null
@@ -0,0 +1,134 @@
+/**
+  @file src/queue.c
+
+  Implements a simple LIFO structure used for queueing OMX buffers.
+
+  Copyright (C) 2007-2008 STMicroelectronics
+  Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies).
+
+  This library is free software; you can redistribute it and/or modify it under
+  the terms of the GNU Lesser General Public License as published by the Free
+  Software Foundation; either version 2.1 of the License, or (at your option)
+  any later version.
+
+  This library is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+  FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+  details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with this library; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St, Fifth Floor, Boston, MA
+  02110-1301  USA
+
+  $Date: 2008-06-27 12:00:23 +0200 (Fri, 27 Jun 2008) $
+  Revision $Rev: 554 $
+  Author $Author: pankaj_sen $
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "queue.h"
+#include "omx_comp_debug_levels.h"
+
+/** Initialize a queue descriptor
+ * 
+ * @param queue The queue descriptor to initialize. 
+ * The user needs to allocate the queue
+ */
+void queue_init(queue_t* queue) {
+  int i;
+  qelem_t* newelem;
+  qelem_t* current;
+  queue->first = malloc(sizeof(qelem_t));
+  memset(queue->first, 0, sizeof(qelem_t));
+  current = queue->last = queue->first;
+  queue->nelem = 0;
+  for (i = 0; i<MAX_QUEUE_ELEMENTS - 2; i++) {
+    newelem = malloc(sizeof(qelem_t));
+    memset(newelem, 0, sizeof(qelem_t));
+    current->q_forw = newelem;
+    current = newelem;
+  }
+  current->q_forw = queue->first;
+  
+  pthread_mutex_init(&queue->mutex, NULL);
+}
+
+/** Deinitialize a queue descriptor
+ * flushing all of its internal data
+ * 
+ * @param queue the queue descriptor to dump
+ */
+void queue_deinit(queue_t* queue) {
+  int i;
+  qelem_t* current;
+  current = queue->first;
+  for (i = 0; i<MAX_QUEUE_ELEMENTS - 2; i++) {
+    if (current != NULL) {
+      current = current->q_forw;
+      free(queue->first);
+      queue->first = current;
+    }
+  }
+  if(queue->first) {
+    free(queue->first);
+    queue->first = NULL;
+  }
+  pthread_mutex_destroy(&queue->mutex);
+}
+
+/** Enqueue an element to the given queue descriptor
+ * 
+ * @param queue the queue descritpor where to queue data
+ * 
+ * @param data the data to be enqueued
+ */
+void queue(queue_t* queue, void* data) {
+  if (queue->last->data != NULL) {
+    return;
+  }
+  pthread_mutex_lock(&queue->mutex);
+  queue->last->data = data;
+  queue->last = queue->last->q_forw;
+  queue->nelem++;
+  pthread_mutex_unlock(&queue->mutex);
+}
+
+/** Dequeue an element from the given queue descriptor
+ * 
+ * @param queue the queue descriptor from which to dequeue the element
+ * 
+ * @return the element that has bee dequeued. If the queue is empty
+ *  a NULL value is returned
+ */
+void* dequeue(queue_t* queue) {
+  void* data;
+  if (queue->first->data == NULL) {
+    return NULL;
+  }
+  pthread_mutex_lock(&queue->mutex);
+  data = queue->first->data;
+  queue->first->data = NULL;
+  queue->first = queue->first->q_forw;
+  queue->nelem--;
+  pthread_mutex_unlock(&queue->mutex);
+
+  return data;
+}
+
+/** Returns the number of elements hold in the queue
+ * 
+ * @param queue the requested queue
+ * 
+ * @return the number of elements in the queue
+ */
+int getquenelem(queue_t* queue) {
+  int qelem;
+  pthread_mutex_lock(&queue->mutex);
+  qelem = queue->nelem;
+  pthread_mutex_unlock(&queue->mutex);
+  return qelem;
+}
diff --git a/host_applications/linux/apps/hello_pi/hello_video/queue.h b/host_applications/linux/apps/hello_pi/hello_video/queue.h
new file mode 100755 (executable)
index 0000000..745ca70
--- /dev/null
@@ -0,0 +1,92 @@
+/**
+  @file src/queue.h
+
+  Implements a simple LIFO structure used for queueing OMX buffers.
+
+  Copyright (C) 2007-2008 STMicroelectronics
+  Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies).
+
+  This library is free software; you can redistribute it and/or modify it under
+  the terms of the GNU Lesser General Public License as published by the Free
+  Software Foundation; either version 2.1 of the License, or (at your option)
+  any later version.
+
+  This library is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+  FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+  details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with this library; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St, Fifth Floor, Boston, MA
+  02110-1301  USA
+
+  $Date: 2008-06-27 12:00:23 +0200 (Fri, 27 Jun 2008) $
+  Revision $Rev: 554 $
+  Author $Author: pankaj_sen $
+*/
+
+#ifndef __TQUEUE_H__
+#define __TQUEUE_H__
+
+#include <pthread.h>
+/** Maximum number of elements in a queue 
+ */
+#define MAX_QUEUE_ELEMENTS 10
+/** Output port queue element. Contains an OMX buffer header type
+ */
+typedef struct qelem_t qelem_t;
+struct qelem_t{
+  qelem_t* q_forw;
+  void* data;
+};
+
+/** This structure contains the queue
+ */
+typedef struct queue_t{
+  qelem_t* first; /**< Output buffer queue head */
+  qelem_t* last; /**< Output buffer queue tail */
+  int nelem; /**< Number of elements in the queue */
+  pthread_mutex_t mutex;
+} queue_t;
+
+/** Initialize a queue descriptor
+ * 
+ * @param queue The queue descriptor to initialize. 
+ * The user needs to allocate the queue
+ */
+void queue_init(queue_t* queue);
+
+/** Deinitialize a queue descriptor
+ * flushing all of its internal data
+ * 
+ * @param queue the queue descriptor to dump
+ */
+void queue_deinit(queue_t* queue);
+
+/** Enqueue an element to the given queue descriptor
+ * 
+ * @param queue the queue descritpor where to queue data
+ * 
+ * @param data the data to be enqueued
+ */
+void queue(queue_t* queue, void* data);
+
+/** Dequeue an element from the given queue descriptor
+ * 
+ * @param queue the queue descriptor from which to dequeue the element
+ * 
+ * @return the element that has bee dequeued. If the queue is empty
+ *  a NULL value is returned
+ */
+void* dequeue(queue_t* queue);
+
+/** Returns the number of elements hold in the queue
+ * 
+ * @param queue the requested queue
+ * 
+ * @return the number of elements in the queue
+ */
+int getquenelem(queue_t* queue);
+
+#endif
diff --git a/host_applications/linux/apps/hello_pi/hello_video/tags b/host_applications/linux/apps/hello_pi/hello_video/tags
new file mode 100755 (executable)
index 0000000..eb7bd70
--- /dev/null
@@ -0,0 +1,10 @@
+!_TAG_FILE_FORMAT      2       /extended format; --format=1 will not append ;" to lines/
+!_TAG_FILE_SORTED      1       /0=unsorted, 1=sorted, 2=foldcase/
+!_TAG_PROGRAM_AUTHOR   Darren Hiebert  /dhiebert@users.sourceforge.net/
+!_TAG_PROGRAM_NAME     Exuberant Ctags //
+!_TAG_PROGRAM_URL      http://ctags.sourceforge.net    /official site/
+!_TAG_PROGRAM_VERSION  5.9~svn20110310 //
+BIN    Makefile        /^BIN=hello_video.bin$/;"       m
+OBJS   Makefile        /^OBJS=video.o$/;"      m
+main   video.c /^int main (int argc, char **argv)$/;"  f       signature:(int argc, char **argv)
+video_decode_test      video.c /^static int video_decode_test(char *filename)$/;"      f       file:   signature:(char *filename)
diff --git a/host_applications/linux/apps/hello_pi/hello_video/tsemaphore.c b/host_applications/linux/apps/hello_pi/hello_video/tsemaphore.c
new file mode 100755 (executable)
index 0000000..6f2b6ad
--- /dev/null
@@ -0,0 +1,111 @@
+/**
+  @file src/tsemaphore.c
+
+  Implements a simple inter-thread semaphore so not to have to deal with IPC
+  creation and the like.
+
+  Copyright (C) 2007-2008 STMicroelectronics
+  Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies).
+
+  This library is free software; you can redistribute it and/or modify it under
+  the terms of the GNU Lesser General Public License as published by the Free
+  Software Foundation; either version 2.1 of the License, or (at your option)
+  any later version.
+
+  This library is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+  FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+  details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with this library; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St, Fifth Floor, Boston, MA
+  02110-1301  USA
+
+  $Date: 2008-06-27 12:00:23 +0200 (Fri, 27 Jun 2008) $
+  Revision $Rev: 554 $
+  Author $Author: pankaj_sen $
+*/
+
+#include <pthread.h>
+#include <sys/time.h>
+#include <errno.h>
+#include "tsemaphore.h"
+#include "omx_comp_debug_levels.h"
+
+/** Initializes the semaphore at a given value
+ * 
+ * @param tsem the semaphore to initialize
+ * @param val the initial value of the semaphore
+ * 
+ */
+void tsem_init(tsem_t* tsem, unsigned int val) {
+  pthread_cond_init(&tsem->condition, NULL);
+  pthread_mutex_init(&tsem->mutex, NULL);
+  tsem->semval = val;
+}
+
+/** Destroy the semaphore
+ *  
+ * @param tsem the semaphore to destroy
+ */
+void tsem_deinit(tsem_t* tsem) {
+  pthread_cond_destroy(&tsem->condition);
+  pthread_mutex_destroy(&tsem->mutex);
+}
+
+/** Decreases the value of the semaphore. Blocks if the semaphore
+ * value is zero.
+ * 
+ * @param tsem the semaphore to decrease
+ */
+void tsem_down(tsem_t* tsem) {
+  pthread_mutex_lock(&tsem->mutex);
+  while (tsem->semval == 0) {
+    pthread_cond_wait(&tsem->condition, &tsem->mutex);
+  }
+  tsem->semval--;
+  pthread_mutex_unlock(&tsem->mutex);
+}
+
+/** Increases the value of the semaphore
+ * 
+ * @param tsem the semaphore to increase
+ */
+void tsem_up(tsem_t* tsem) {
+  pthread_mutex_lock(&tsem->mutex);
+  tsem->semval++;
+  pthread_cond_signal(&tsem->condition);
+  pthread_mutex_unlock(&tsem->mutex);
+}
+
+/** Reset the value of the semaphore
+ * 
+ * @param tsem the semaphore to reset
+ */
+void tsem_reset(tsem_t* tsem) {
+  pthread_mutex_lock(&tsem->mutex);
+  tsem->semval=0;
+  pthread_mutex_unlock(&tsem->mutex);
+}
+
+/** Wait on the condition.
+ * 
+ * @param tsem the semaphore to wait
+ */
+void tsem_wait(tsem_t* tsem) {
+  pthread_mutex_lock(&tsem->mutex);
+  pthread_cond_wait(&tsem->condition, &tsem->mutex);
+  pthread_mutex_unlock(&tsem->mutex);
+}
+
+/** Signal the condition,if waiting
+ * 
+ * @param tsem the semaphore to signal
+ */
+void tsem_signal(tsem_t* tsem) {
+  pthread_mutex_lock(&tsem->mutex);
+  pthread_cond_signal(&tsem->condition);
+  pthread_mutex_unlock(&tsem->mutex);
+}
+
diff --git a/host_applications/linux/apps/hello_pi/hello_video/tsemaphore.h b/host_applications/linux/apps/hello_pi/hello_video/tsemaphore.h
new file mode 100755 (executable)
index 0000000..4bc1ab2
--- /dev/null
@@ -0,0 +1,87 @@
+/**
+  @file src/tsemaphore.h
+
+  Implements a simple inter-thread semaphore so not to have to deal with IPC
+  creation and the like.
+
+  Copyright (C) 2007-2008 STMicroelectronics
+  Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies).
+
+  This library is free software; you can redistribute it and/or modify it under
+  the terms of the GNU Lesser General Public License as published by the Free
+  Software Foundation; either version 2.1 of the License, or (at your option)
+  any later version.
+
+  This library is distributed in the hope that it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+  FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+  details.
+
+  You should have received a copy of the GNU Lesser General Public License
+  along with this library; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St, Fifth Floor, Boston, MA
+  02110-1301  USA
+
+  $Date: 2008-06-27 12:00:23 +0200 (Fri, 27 Jun 2008) $
+  Revision $Rev: 554 $
+  Author $Author: pankaj_sen $
+
+*/
+
+#ifndef __TSEMAPHORE_H__
+#define __TSEMAPHORE_H__
+
+/** The structure contains the semaphore value, mutex and green light flag
+ */ 
+typedef struct tsem_t{
+  pthread_cond_t condition;
+  pthread_mutex_t mutex;
+  unsigned int semval;
+}tsem_t;
+
+/** Initializes the semaphore at a given value
+ * 
+ * @param tsem the semaphore to initialize
+ * 
+ * @param val the initial value of the semaphore
+ */
+void tsem_init(tsem_t* tsem, unsigned int val);
+
+/** Destroy the semaphore
+ *  
+ * @param tsem the semaphore to destroy
+ */
+void tsem_deinit(tsem_t* tsem);
+
+/** Decreases the value of the semaphore. Blocks if the semaphore
+ * value is zero.
+ * 
+ * @param tsem the semaphore to decrease
+ */
+void tsem_down(tsem_t* tsem);
+
+/** Increases the value of the semaphore
+ * 
+ * @param tsem the semaphore to increase
+ */
+void tsem_up(tsem_t* tsem);
+
+/** Reset the value of the semaphore
+ * 
+ * @param tsem the semaphore to reset
+ */
+void tsem_reset(tsem_t* tsem);
+
+/** Wait on the condition.
+ * 
+ * @param tsem the semaphore to wait
+ */
+void tsem_wait(tsem_t* tsem);
+
+/** Signal the condition,if waiting
+ * 
+ * @param tsem the semaphore to signal
+ */
+void tsem_signal(tsem_t* tsem);
+
+#endif
diff --git a/host_applications/linux/apps/hello_pi/hello_video/user_debug_levels.h b/host_applications/linux/apps/hello_pi/hello_video/user_debug_levels.h
new file mode 100755 (executable)
index 0000000..b28b07f
--- /dev/null
@@ -0,0 +1,73 @@
+/**
+       @file test/components/common/user_debug_levels.h
+       
+       Define the level of debug prints on standard err. The different levels can 
+       be composed with binary OR.
+       The debug levels defined here belong to the test applications
+       
+       Copyright (C) 2007-2008 STMicroelectronics
+       Copyright (C) 2007-2008 Nokia Corporation and/or its subsidiary(-ies).
+
+       This library is free software; you can redistribute it and/or modify it under
+       the terms of the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 2.1 of the License, or (at your option)
+       any later version.
+
+       This library is distributed in the hope that it will be useful, but WITHOUT
+       ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+       FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+       details.
+
+       You should have received a copy of the GNU Lesser General Public License
+       along with this library; if not, write to the Free Software Foundation, Inc.,
+       51 Franklin St, Fifth Floor, Boston, MA
+       02110-1301  USA
+       
+       $Date: 2008-07-16 09:39:31 +0200 (Wed, 16 Jul 2008) $
+       Revision $Rev: 577 $
+       Author $Author: gsent $
+
+*/
+
+
+/** Remove all debug output lines
+ */
+#define DEB_LEV_NO_OUTPUT  0
+/** Messages explaing the reason of critical errors 
+ */
+#define DEB_LEV_ERR        1 
+/** Messages showing values related to the test and the component/s used
+ */
+#define DEB_LEV_PARAMS     2
+/** Messages representing steps in the execution. These are the simple messages, because 
+ * they avoid iterations 
+ */
+#define DEB_LEV_SIMPLE_SEQ 4
+/** Messages representing steps in the execution. All the steps are described, 
+ * also with iterations. With this level of output the performance is 
+ * seriously compromised
+ */
+#define DEB_LEV_FULL_SEQ   8
+/** Messages that indicate the beginning and the end of a function.
+ * It can be used to trace the execution
+ */
+#define DEB_LEV_FUNCTION_NAME 16
+
+/** Messages that are the default test application output. These message should be 
+       * shown every time
+       */
+#define DEFAULT_MESSAGES 32
+
+/** All the messages - max value
+ */
+#define DEB_ALL_MESS   255
+
+
+/** \def DEBUG_LEVEL is the current level do debug output on standard err */
+#define DEBUG_LEVEL (DEB_LEV_ERR | DEFAULT_MESSAGES)
+#if DEBUG_LEVEL > 0
+#define DEBUG(n, args...) do { if (DEBUG_LEVEL & (n)){fprintf(stderr, args);} } while (0)
+#else
+#define DEBUG(n, args...)
+#endif
+
diff --git a/host_applications/linux/apps/hello_pi/hello_video/video.c b/host_applications/linux/apps/hello_pi/hello_video/video.c
new file mode 100755 (executable)
index 0000000..3275d57
--- /dev/null
@@ -0,0 +1,1055 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Video deocode demo using OpenMAX IL though the ilcient helper library
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "video.h"
+/*
+#define VERSIONMAJOR    1
+#define VERSIONMINOR    1
+#define VERSIONREVISION 0
+#define VERSIONSTEP     0
+
+#define OMX_VERSION ((VERSIONSTEP<<24) | (VERSIONREVISION<<16) | (VERSIONMINOR<<8) | VERSIONMAJOR)
+
+#define OMX_INIT_STRUCTURE(a) \
+memset(&(a), 0, sizeof(a)); \
+(a).nSize = sizeof(a); \
+(a).nVersion.nVersion = OMX_VERSION; \
+(a).nVersion.s.nVersionMajor = VERSIONMAJOR; \
+(a).nVersion.s.nVersionMinor = VERSIONMINOR; \
+(a).nVersion.s.nRevision = VERSIONREVISION; \
+(a).nVersion.s.nStep = VERSIONSTEP
+
+static void setHeader(OMX_PTR header, OMX_U32 size) {
+  OMX_VERSIONTYPE* ver = (OMX_VERSIONTYPE*)(header + sizeof(OMX_U32));
+  *((OMX_U32*)header) = size;
+
+  ver->s.nVersionMajor = VERSIONMAJOR;
+  ver->s.nVersionMinor = VERSIONMINOR;
+  ver->s.nRevision = VERSIONREVISION;
+  ver->s.nStep = VERSIONSTEP;
+}
+*/
+
+/*
+void allocateBuffer(int index, int actualBuffer, int width, int height)
+{
+  int i, err;
+  tbm_bo_handle handle_bo;
+  int y_size, uv_size;
+
+  y_size = ALIGN(width, 16) * ALIGN(height, 16);
+  uv_size = y_size /2;
+
+  for (i = 0; i < actualBuffer; i++) {
+
+    unsigned char *tmp;
+
+    //tmp = (MMVideoBuffer*) malloc(sizeof(MMVideoBuffer));
+    //tmp->handle.bo[0] = tbm_bo_alloc(hBufmgr, y_size, TBM_BO_WC);
+    handle_bo = tbm_bo_get_handle(tmp->handle.bo[0], TBM_DEVICE_CPU);
+    tmp = handle_bo.ptr;
+       //handle_bo = tbm_bo_get_handle(tmp->handle.bo[0], TBM_DEVICE_MM);
+       //tmp->handle.dmabuf_fd[0] = handle_bo.u32;
+       //tmp->size[0] = y_size;
+
+
+       if (index == 1) {
+         tmp->handle.bo[1] = tbm_bo_alloc(hBufmgr, uv_size, TBM_BO_WC);
+         handle_bo = tbm_bo_get_handle(tmp->handle.bo[1], TBM_DEVICE_CPU);
+         tmp->data[1] = handle_bo.ptr;
+         handle_bo = tbm_bo_get_handle(tmp->handle.bo[1], TBM_DEVICE_MM);
+         tmp->handle.dmabuf_fd[1] = handle_bo.u32;
+         tmp->size[1] = uv_size;
+       }
+
+       if (index == 0) {
+      err = OMX_UseBuffer(appPriv->videodechandle, &pInBuffer[i], 0, NULL, y_size, tmp);
+      printf( "index : %d -> OMX_UseBuffer :%x\n", index, err);
+      queue(pInBufQueue, pInBuffer[i]);
+      //queue(pInBufQueue, tmp);
+       } else if (index == 1) {
+      err = OMX_UseBuffer(appPriv->videodechandle, &pOutBuffer[i], 1, NULL, y_size + uv_size, tmp);
+      printf( "index : %d -> OMX_UseBuffer :%i\n", index, err);
+      queue(pOutBufQueue, pOutBuffer[i]);
+       }
+
+  }
+
+}
+*/
+
+#define COMPONENT_NAME_BASE "OMX.broadcom.video_decode"
+#define BASE_ROLE "video_decoder.avc"
+
+OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+OMX_TIME_CONFIG_CLOCKSTATETYPE cstate;
+COMPONENT_T *video_decode = NULL;
+COMPONENT_T *list[5];
+TUNNEL_T tunnel[4];
+ILCLIENT_T *client;
+FILE *in;
+int status = 0;
+unsigned int data_len = 0;
+int err;
+int actualInBufferCount;
+int actualOutBufferCount;
+int nInBufferSize, nOutBufferSize;
+int nInBufferAlignment, nOutBufferAlignment;
+OMX_BUFFERHEADERTYPE *pInBuffer[20], *pOutBuffer[16];
+OMX_STRING full_component_name;
+appPrivateType* appPriv;
+tbm_bufmgr hBufmgr;
+int drm_fd;
+queue_t* pInBufQueue;
+queue_t* pOutBufQueue;
+
+OMX_CALLBACKTYPE videodeccallbacks = {
+    .EventHandler = videodecEventHandler,
+    .EmptyBufferDone = videodecEmptyBufferDone,
+    .FillBufferDone = videodecFillBufferDone
+  };
+/*
+static void setHeader(OMX_PTR header, OMX_U32 size) {
+  OMX_VERSIONTYPE* ver = (OMX_VERSIONTYPE*)(header + sizeof(OMX_U32));
+  *((OMX_U32*)header) = size;
+
+  ver->s.nVersionMajor = VERSIONMAJOR;
+  ver->s.nVersionMinor = VERSIONMINOR;
+  ver->s.nRevision = VERSIONREVISION;
+  ver->s.nStep = VERSIONSTEP;
+}
+*/
+OMX_ERRORTYPE test_OMX_ComponentNameEnum() {
+  char * name;
+  int index;
+
+  OMX_ERRORTYPE err = OMX_ErrorNone;
+
+  printf("GENERAL TEST %s\n", __func__);
+
+  name = malloc(OMX_MAX_STRINGNAME_SIZE);
+  index = 0;
+  while(1) {
+    err = OMX_ComponentNameEnum (name, OMX_MAX_STRINGNAME_SIZE, index);
+    if ((name != NULL) && (err == OMX_ErrorNone)) {
+      printf("component %i is %s\n", index, name);
+    } else break;
+    if (err != OMX_ErrorNone) break;
+    index++;
+  }
+  free(name);
+  name = NULL;
+  printf("GENERAL TEST %s result %i\n", __func__, err);
+  return err;
+}
+
+OMX_ERRORTYPE test_OMX_RoleEnum(OMX_STRING component_name) {
+  OMX_U32 no_of_roles;
+  OMX_U8 **string_of_roles;
+  OMX_ERRORTYPE err = OMX_ErrorNone;
+  int index;
+
+  printf("GENERAL TEST %s\n", __func__);
+  printf("Getting roles of %s. Passing Null first...\n", component_name);
+  err = OMX_GetRolesOfComponent(component_name, &no_of_roles, NULL);
+  if (err != OMX_ErrorNone) {
+    printf("Not able to retrieve the number of roles of the given component\n");
+    printf("GENERAL TEST %s result %i\n", __func__, err);
+    return err;
+  }
+  printf("The number of roles for the component %s is: %i\n", component_name, (int)no_of_roles);
+
+  if(no_of_roles == 0) {
+    printf("The Number or roles is 0.\nThe component selected is not correct for the purpose of this test.\nExiting...\n");
+    err = OMX_ErrorInvalidComponentName;
+  } else {
+    string_of_roles = malloc(no_of_roles * sizeof(OMX_STRING));
+    for (index = 0; index < no_of_roles; index++) {
+      *(string_of_roles + index) = malloc(no_of_roles * OMX_MAX_STRINGNAME_SIZE);
+    }
+    printf("...then buffers\n");
+
+    err = OMX_GetRolesOfComponent(component_name, &no_of_roles, string_of_roles);
+    if (err != OMX_ErrorNone) {
+      printf("Not able to retrieve the roles of the given component\n");
+    } else if(string_of_roles != NULL) {
+      for (index = 0; index < no_of_roles; index++) {
+        printf("The role %i for the component:  %s \n", (index + 1), *(string_of_roles+index));
+      }
+    } else {
+      printf("role string is NULL!!! Exiting...\n");
+      err = OMX_ErrorInvalidComponentName;
+    }
+  }
+  printf("GENERAL TEST %s result %i\n", __func__, err);
+  return err;
+}
+
+OMX_ERRORTYPE test_OMX_ComponentEnumByRole(OMX_STRING role_name) {
+  OMX_U32 no_of_comp_per_role;
+  OMX_U8 **string_of_comp_per_role;
+  OMX_ERRORTYPE err;
+  int index;
+
+  printf("GENERAL TEST %s\n", __func__);
+  string_of_comp_per_role = malloc (10 * sizeof(OMX_STRING));
+  for (index = 0; index < 10; index++) {
+    string_of_comp_per_role[index] = malloc(OMX_MAX_STRINGNAME_SIZE);
+  }
+
+  printf("Getting number of components per role for %s\n", role_name);
+
+  err = OMX_GetComponentsOfRole(role_name, &no_of_comp_per_role, NULL);
+  if (err != OMX_ErrorNone) {
+    printf("Not able to retrieve the number of components of a given role\n");
+    printf( "GENERAL TEST %s result %i\n", __func__, err);
+    return err;
+  }
+  printf("Number of components per role for %s is %i\n", role_name, (int)no_of_comp_per_role);
+
+  err = OMX_GetComponentsOfRole(role_name, &no_of_comp_per_role, string_of_comp_per_role);
+  if (err != OMX_ErrorNone) {
+    printf("Not able to retrieve the components of a given role\n");
+    printf( "GENERAL TEST %s result %i\n",__func__, err);
+    return err;
+  }
+
+  printf(" The components are:\n");
+  for (index = 0; index < no_of_comp_per_role; index++) {
+    printf("%s\n", string_of_comp_per_role[index]);
+  }
+  for (index = 0; index<10; index++) {
+    if(string_of_comp_per_role[index]) {
+      free(string_of_comp_per_role[index]);
+      string_of_comp_per_role[index] = NULL;
+    }
+  }
+
+  if(string_of_comp_per_role)  {
+    free(string_of_comp_per_role);
+    string_of_comp_per_role = NULL;
+  }
+  printf("GENERAL TEST %s result OMX_ErrorNone\n", __func__);
+  return OMX_ErrorNone;
+}
+
+OMX_ERRORTYPE test_OpenClose(OMX_STRING component_name) {
+  OMX_ERRORTYPE err = OMX_ErrorNone;
+
+  printf("GENERAL TEST %s\n",__func__);
+  err = OMX_GetHandle(&appPriv->videodechandle, component_name, NULL /*appPriv */, &videodeccallbacks);
+  if(err != OMX_ErrorNone) {
+    printf("No component found\n");
+  } else {
+    err = OMX_FreeHandle(appPriv->videodechandle);
+  }
+  printf("GENERAL TEST %s result %i\n", __func__, err);
+  return err;
+}
+
+void allocateBuffer(int index, int actualBuffer, int width, int height, int aligned_size)
+{
+  int i, err;
+  tbm_bo_handle handle_bo;
+  int y_size, uv_size;
+  int size;
+
+  y_size = ALIGN(width + 128, 16) * ALIGN(height + 128, 16);
+  uv_size = y_size /2;
+  size = y_size + uv_size;
+
+  for (i = 0; i < actualBuffer; i++) {
+
+    void *tmp;
+       unsigned char *buf;
+
+
+
+       if (index == 130) {
+               buf = (unsigned char*) malloc (sizeof(unsigned char) * aligned_size);
+        err = OMX_UseBuffer(appPriv->videodechandle, &pInBuffer[i], 130, NULL, ALIGN(aligned_size, 16), buf);
+           printf("index : %d -> OMX_UseBuffer : %p, %x\n", index, pInBuffer[i], err);
+               //queue(pInBufQueue, pInBuffer[i]);
+       } else if (index == 131) {
+        tmp = tbm_bo_alloc(hBufmgr, ALIGN(aligned_size, 16), TBM_BO_WC);
+        handle_bo = tbm_bo_get_handle(tmp, TBM_DEVICE_CPU);
+           buf = handle_bo.ptr;
+
+        err = OMX_UseBuffer(appPriv->videodechandle, &pOutBuffer[i], 131, NULL, ALIGN(aligned_size, 16), buf);
+           printf("index : %d -> OMX_UseBuffer : %p, %x\n", index, pOutBuffer[i], err);
+               //queue(pOutBufQueue, pOutBuffer[i]);
+       } else
+               printf("invalid port\n");
+/*
+
+       if (index == 1) {
+         tmp->handle.bo[1] = tbm_bo_alloc(hBufmgr, uv_size, TBM_BO_WC);
+         handle_bo = tbm_bo_get_handle(tmp->handle.bo[1], TBM_DEVICE_CPU);
+         tmp->data[1] = handle_bo.ptr;
+         handle_bo = tbm_bo_get_handle(tmp->handle.bo[1], TBM_DEVICE_MM);
+         tmp->handle.dmabuf_fd[1] = handle_bo.u32;
+         tmp->size[1] = uv_size;
+       }
+
+       if (index == 0) {
+      err = OMX_UseBuffer(appPriv->videodechandle, &pInBuffer[i], 0, NULL, y_size, tmp);
+      DEBUG(DEFAULT_MESSAGES, "index : %d -> OMX_UseBuffer :%x\n", index, err);
+      queue(pInBufQueue, pInBuffer[i]);
+      //queue(pInBufQueue, tmp);
+       } else if (index == 1) {
+      err = OMX_UseBuffer(appPriv->videodechandle, &pOutBuffer[i], 1, NULL, y_size + uv_size, tmp);
+      DEBUG(DEFAULT_MESSAGES, "index : %d -> OMX_UseBuffer :%i\n", index, err);
+      queue(pOutBufQueue, pOutBuffer[i]);
+       }
+*/
+  }
+
+}
+/*
+void deallocateBuffer(int index, int actualBuffer)
+{
+  int i, err;
+  MMVideoBuffer *pTmp;
+
+  for (i = 0; i < actualBuffer; i++) {
+    if (index == 0) {
+               //pTmp = (MMVideoBuffer*)dequeue(pInBufQueue);
+               pTmp = pInBuffer[i];
+       } else if (index == 1) {
+               //pTmp = (MMVideoBuffer*)dequeue(pOutBufQueue);
+               pTmp = pOutBuffer[i];
+       }
+
+       tbm_bo_unref(pTmp->handle.bo[0]);
+       if (index == 1)
+               tbm_bo_unref(pTmp->handle.bo[1]);
+
+       err = OMX_FreeBuffer (appPriv->videodechandle, index, pTmp);
+    DEBUG(DEFAULT_MESSAGES, "%d port %d buffer free : %d\n", index, i, err);
+  }
+}
+*/
+const char * omx_state_to_string(OMX_STATETYPE state)
+{
+       switch (state)
+       {
+               case OMX_StateInvalid: return "Invalid"; break;
+               case OMX_StateLoaded: return "Loaded"; break;
+               case OMX_StateIdle: return "Idle"; break;
+               case OMX_StateExecuting: return "Executing"; break;
+               case OMX_StatePause: return "Pause"; break;
+               case OMX_StateWaitForResources:  return "Wait for resources"; break;
+               default: return "Bad state"; break;
+       }
+}
+
+void wait_for(appPrivateType *app, OMX_STATETYPE state)
+{
+       while (app->state != state)
+       {
+               printf("wait for %s \n", omx_state_to_string(state));
+               tsem_down(app->stateSem);
+               if (app->state != state) {
+                       printf("we got an event, but still waiting for %s \n", omx_state_to_string(state));
+               }
+
+       }
+}
+
+unsigned int FromByteStream2NalUnit(FILE *ByteStream, unsigned char *Nal)
+{
+       unsigned int NalLeng=0;
+
+       unsigned char Val, ZeroCount, i;
+       ZeroCount = 0;
+       if(feof(ByteStream))
+               return 0;
+       Val = fgetc(ByteStream);
+       while(!Val)
+       {
+               if(ZeroCount == 3)
+                       break;
+               ZeroCount++;
+               Val = fgetc(ByteStream);
+       }
+
+       if( (ZeroCount != 3) || (Val != 1) )
+       {
+               for(i=0;i<ZeroCount;i++)
+                       Nal[NalLeng++] = 0;
+               Nal[NalLeng++] = Val;
+       }
+
+       ZeroCount = 0;
+       while(1) {
+               Val = fgetc(ByteStream);
+               if(feof(ByteStream))
+                       break;
+               if(!Val)
+                       ZeroCount++;
+               else {
+                       if( (ZeroCount == 3) && (Val == 1) )
+                               break;
+                       else {
+                               for(i=0;i<ZeroCount;i++)
+                                       Nal[NalLeng++] = 0;
+                               Nal[NalLeng++] = Val;
+                               ZeroCount = 0;
+                       }
+               }
+       }
+
+       return NalLeng;
+}
+
+void hex_dump(char *desc, void *addr, int len)
+{
+       int i;
+       unsigned char buff[17];
+       unsigned char *pc = (unsigned char *)addr;
+
+       if (desc != NULL)
+               printf("%s:\n", desc);
+
+       for (i = 0; i < len; i++) {
+
+               if ((i % 16) == 0) {
+                       if (i != 0)
+                               printf("  %s\n", buff);
+
+                       printf("  %04x ", i);
+               }
+
+               printf(" %02x", pc[i]);
+
+               if ((pc[i] < 0x20) || (pc[i] > 0x7e))
+                       buff[i % 16] = '.';
+               else
+                       buff[i % 16] = pc[i];
+               buff[(i % 16) + 1] = '\0';
+       }
+
+       while ((i % 16) != 0) {
+               printf("   ");
+               i++;
+       }
+       printf("  %s\n", buff);
+}
+
+static int video_decode_test(char *filename)
+{
+   int i;
+   int offset;
+   int data_read;
+   int fd;
+
+   memset(list, 0, sizeof(list));
+
+   if((in = fopen(filename, "rb")) == NULL)
+      return -2;
+   if ((fd = open(filename, O_RDONLY)) == -1)
+          return -2;
+/*
+   if((client = ilclient_init()) == NULL)
+   {
+      fclose(in);
+      return -3;
+   }
+*/
+   /* Initialize application private data */
+   appPriv = malloc(sizeof(appPrivateType));
+   appPriv->decoderEventSem = malloc(sizeof(tsem_t));
+   appPriv->stateSem =  malloc(sizeof(tsem_t));
+   appPriv->state = OMX_StateInvalid;
+
+   appPriv->eofSem = malloc(sizeof(tsem_t));
+   tsem_init(appPriv->decoderEventSem, 0);
+   tsem_init(appPriv->stateSem, 0);
+   tsem_init(appPriv->eofSem, 0);
+
+   printf("Init the OMX Core\n");
+
+   if(OMX_Init() != OMX_ErrorNone)
+   {
+      ilclient_destroy(client);
+      fclose(in);
+      return -4;
+   }
+   printf("Omx core is initialized \n");
+
+/*
+   // create video_decode
+   if (ilclient_create_component(client, &video_decode, "video_decode", ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_INPUT_BUFFERS | ILCLIENT_ENABLE_OUTPUT_BUFFERS) != 0)
+      status = -14;
+   list[0] = video_decode;
+*/
+
+   printf("------------------------------------\n");
+   test_OMX_ComponentNameEnum();
+   printf("------------------------------------\n");
+   test_OMX_RoleEnum(COMPONENT_NAME_BASE);
+   printf("------------------------------------\n");
+   test_OMX_ComponentEnumByRole(BASE_ROLE);
+   printf("------------------------------------\n");
+   test_OpenClose(COMPONENT_NAME_BASE);
+   printf("------------------------------------\n");
+
+   full_component_name = malloc(sizeof(char*) * OMX_MAX_STRINGNAME_SIZE);
+   strcpy(full_component_name, COMPONENT_NAME_BASE);
+   printf("The component selected for decoding is %s\n", full_component_name);
+
+   err = OMX_GetHandle(&appPriv->videodechandle, full_component_name, NULL, &videodeccallbacks);
+   if(err != OMX_ErrorNone){
+    printf("No video decoder component found. Exiting...\n");
+    exit(1);
+  } else {
+    printf("Found The component for decoding is %s\n", full_component_name);
+  }
+
+   /** sending command to video decoder component to go to idle state */
+   //pInBuffer1 = pInBuffer2 = NULL;
+   err = OMX_SendCommand(appPriv->videodechandle, OMX_CommandStateSet, OMX_StateIdle, NULL);
+
+   //wait_for(appPriv, OMX_StateIdle);
+   printf("state changed to Idle :%i\n", err);
+
+   hBufmgr = tbm_bufmgr_init(drm_fd);
+   if(hBufmgr == NULL){
+        printf("TBM initialization failed\n");
+   }
+
+
+   OMX_PARAM_PORTDEFINITIONTYPE port_def;
+   memset(&port_def, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+   port_def.nVersion.nVersion = OMX_VERSION;
+   port_def.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
+   port_def.nPortIndex = 130;
+
+   err = OMX_GetParameter (appPriv->videodechandle, OMX_IndexParamPortDefinition, &port_def);
+   printf( "OMX_GetParameter :%x, input buffer count : %d, nBufferSize : %d, nBufferAlignment : %d\n", err, port_def.nBufferCountActual, port_def.nBufferSize, port_def.nBufferAlignment);
+   actualInBufferCount = port_def.nBufferCountActual;
+   nInBufferSize = port_def.nBufferSize;
+   nInBufferAlignment = port_def.nBufferAlignment;
+
+   port_def.nPortIndex = 131;
+   err = OMX_GetParameter (appPriv->videodechandle, OMX_IndexParamPortDefinition, &port_def);
+   printf( "OMX_GetParameter :%x, output buffer count : %d, nBufferSize : %d, nBufferAlignment : %d\n", err, port_def.nBufferCountActual,  port_def.nBufferSize, port_def.nBufferAlignment);
+   actualOutBufferCount = port_def.nBufferCountActual;
+   nOutBufferSize = port_def.nBufferSize;
+   nOutBufferAlignment = port_def.nBufferAlignment;
+
+
+   err = OMX_SendCommand(appPriv->videodechandle, OMX_CommandPortDisable, 130, NULL);
+   printf( "Input port OMX_CommandPortDisable : %x\n", err);
+
+   err = OMX_SendCommand(appPriv->videodechandle, OMX_CommandPortDisable, 131, NULL);
+   printf( "Output port OMX_CommandPortDisable : %x\n", err);
+
+   memset(&format, 0, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));
+   format.nSize = sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE);
+   format.nVersion.nVersion = OMX_VERSION;
+   format.nPortIndex = 130;
+   format.eCompressionFormat = OMX_VIDEO_CodingAVC;
+
+   err = OMX_SetParameter(appPriv->videodechandle, OMX_IndexParamVideoPortFormat, &format);
+   printf("Input OMX_IndexParamVideoPortFormat: %x\n", err);
+
+   memset(&format, 0, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));
+   format.nSize = sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE);
+   format.nVersion.nVersion = OMX_VERSION;
+   format.nPortIndex = 131;
+   err = OMX_SetParameter(appPriv->videodechandle, OMX_IndexParamVideoPortFormat, &format);
+   printf("Output OMX_IndexParamVideoPortFormat: %x\n", err);
+
+
+   pInBufQueue = calloc(1,sizeof(queue_t));
+   pOutBufQueue = calloc(1,sizeof(queue_t));
+
+   queue_init(pInBufQueue);
+   queue_init(pOutBufQueue);
+
+   //err = ilclient_change_component_state(video_decode, OMX_StateExecuting);
+   //printf("ilclient_change_component_state -> OMX_StateExecuting : err : %d\n", err);
+
+   err = OMX_SendCommand(appPriv->videodechandle, OMX_CommandPortEnable, 130, NULL);
+   printf( "Input port OMX_CommandPortEnable : %x\n", err);
+   err = OMX_SendCommand(appPriv->videodechandle, OMX_CommandPortEnable, 131, NULL);
+   printf( "Output port OMX_CommandPortEnable : %x\n", err);
+
+   allocateBuffer(130, actualInBufferCount, 1280, 720, nInBufferSize);
+   allocateBuffer(131, actualOutBufferCount, 1280, 720, nOutBufferSize);
+
+  wait_for(appPriv, OMX_StateIdle);
+
+  /** sending command to video decoder component to go to executing state */
+  err = OMX_SendCommand(appPriv->videodechandle, OMX_CommandStateSet, OMX_StateExecuting, NULL);
+  printf("send Excuting :%d\n", err);
+
+  wait_for(appPriv, OMX_StateExecuting);
+  printf("Excuting state\n");
+
+  for (i = 0; i < actualOutBufferCount; i++) {
+    err = OMX_FillThisBuffer(appPriv->videodechandle, pOutBuffer[i]);
+    printf( "FillThisBuffer : %p, %x\n",pOutBuffer[i], err);
+  }
+
+  for (i = 0; i < actualInBufferCount; i++) {
+    //pthread_mutex_lock(&mutex);
+       unsigned char *pTmp;
+       offset = 0;
+
+       pTmp = pInBuffer[i]->pBuffer;
+       pTmp[offset++] = 0;
+       pTmp[offset++] = 0;
+       pTmp[offset++] = 0;
+       pTmp[offset++] = 1;
+
+       data_read = FromByteStream2NalUnit(in, pTmp + offset);
+
+    pInBuffer[i]->nFilledLen = data_read + offset;
+    pInBuffer[i]->nOffset = 0;
+    hex_dump("src0", pInBuffer[i]->pBuffer, 16);
+
+       //pthread_mutex_unlock(&mutex);
+
+    err = OMX_EmptyThisBuffer(appPriv->videodechandle, pInBuffer[i]);
+    printf("EmptyThisBuffer %x, %d\n", pInBuffer[i]->pBuffer, data_read + offset);
+       usleep(100000);
+  }
+
+  tsem_down(appPriv->decoderEventSem);
+  printf("port setting changed\n");
+
+  err = OMX_SendCommand(appPriv->videodechandle, OMX_CommandPortDisable, 131, NULL);
+  printf("Sending Port Disable Command : %d\n", err);
+#if 0
+   if(status == 0 &&
+      OMX_SetParameter(ILC_GET_HANDLE(video_decode), OMX_IndexParamVideoPortFormat, &format) == OMX_ErrorNone &&
+      ilclient_enable_port_buffers(video_decode, 130, NULL, NULL, NULL) == 0 &&
+         ilclient_enable_port_buffers(video_decode, 131, NULL, NULL, NULL) == 0)
+   {
+      OMX_BUFFERHEADERTYPE *buf, *outbuf;
+      int port_settings_changed = 0;
+      int first_packet = 1;
+
+
+     while ((outbuf = ilclient_get_output_buffer(video_decode, 131, 1)) != NULL)
+        {
+                unsigned char *tmp = outbuf->pBuffer;
+
+               err = OMX_FillThisBuffer(ILC_GET_HANDLE(video_decode), outbuf);
+               if (err != OMX_ErrorNone)
+               {
+                   printf("Failed to call OMX_FillThisBuffer\n");
+                       status = -6;
+                       break;
+               }
+               printf("call OMX_FillThisBuffer : %d\n", err);
+        }
+
+      while((buf = ilclient_get_input_buffer(video_decode, 130, 1)) != NULL)
+      {
+         // feed data and wait until we get port settings changed
+         unsigned char *dest = buf->pBuffer;
+
+         data_len += fread(dest, 1, buf->nAllocLen-data_len, in);
+         printf( "data_len :%i\n", data_len);
+
+         if(port_settings_changed == 0 &&
+            ((data_len > 0 && ilclient_remove_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1) == 0) ||
+             (data_len == 0 && ilclient_wait_for_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1,
+                                                       ILCLIENT_EVENT_ERROR | ILCLIENT_PARAMETER_CHANGED, 10000) == 0)))
+         {
+            port_settings_changed = 1;
+
+            //err = ilclient_change_component_state(video_decode, OMX_StateExecuting);
+                       //printf("ilclient_change_component_state -> OMX_StateExecuting : err : %d\n", err);
+                       printf("port setting changed \n");
+            port_def.nPortIndex = 131;
+            err = OMX_GetParameter (ILC_GET_HANDLE(video_decode), OMX_IndexParamPortDefinition, &port_def);
+            printf( "OMX_GetParameter :%i\n", err);
+            actualOutBufferCount = port_def.nBufferCountActual;
+            printf("outbuf count :%d\n", actualOutBufferCount);
+                }
+
+                       if(!data_len)
+                               break;
+
+                       buf->nFilledLen = data_len;
+                       data_len = 0;
+
+                       buf->nOffset = 0;
+                       if(first_packet)
+                       {
+                               buf->nFlags = OMX_BUFFERFLAG_STARTTIME;
+                               first_packet = 0;
+                       }
+                       else
+                               buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN;
+
+                       if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf) != OMX_ErrorNone)
+                       {
+                           printf("Failed to call OMX_EmptyThisBuffer\n");
+                               status = -6;
+                               break;
+                       }
+         }
+/*
+      while((buf = ilclient_get_input_buffer(video_decode, 130, 1)) != NULL)
+      {
+         // feed data and wait until we get port settings changed
+         unsigned char *dest = buf->pBuffer;
+
+         data_len += fread(dest, 1, buf->nAllocLen-data_len, in);
+
+         if(port_settings_changed == 0 &&
+            ((data_len > 0 && ilclient_remove_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1) == 0) ||
+             (data_len == 0 && ilclient_wait_for_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1,
+                                                       ILCLIENT_EVENT_ERROR | ILCLIENT_PARAMETER_CHANGED, 10000) == 0)))
+         {
+            port_settings_changed = 1;
+
+            if(ilclient_setup_tunnel(tunnel, 0, 0) != 0)
+            {
+               status = -7;
+               break;
+            }
+
+            ilclient_change_component_state(video_scheduler, OMX_StateExecuting);
+
+            // now setup tunnel to video_render
+            if(ilclient_setup_tunnel(tunnel+1, 0, 1000) != 0)
+            {
+               status = -12;
+               break;
+            }
+
+            ilclient_change_component_state(video_render, OMX_StateExecuting);
+         }
+         if(!data_len)
+            break;
+
+         buf->nFilledLen = data_len;
+         data_len = 0;
+
+         buf->nOffset = 0;
+         if(first_packet)
+         {
+            buf->nFlags = OMX_BUFFERFLAG_STARTTIME;
+            first_packet = 0;
+         }
+         else
+            buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN;
+
+         if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf) != OMX_ErrorNone)
+         {
+            status = -6;
+            break;
+         }
+      }
+
+      buf->nFilledLen = 0;
+      buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN | OMX_BUFFERFLAG_EOS;
+
+      if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf) != OMX_ErrorNone)
+         status = -20;
+
+      // wait for EOS from render
+      ilclient_wait_for_event(video_render, OMX_EventBufferFlag, 90, 0, OMX_BUFFERFLAG_EOS, 0,
+                              ILCLIENT_BUFFER_FLAG_EOS, -1);
+
+      // need to flush the renderer to allow video_decode to disable its input port
+      ilclient_flush_tunnels(tunnel, 0);
+*/
+   }
+#endif
+   fclose(in);
+
+   //ilclient_disable_tunnel(tunnel);
+   //ilclient_disable_tunnel(tunnel+1);
+   //ilclient_disable_tunnel(tunnel+2);
+   //ilclient_disable_port_buffers(video_decode, 130, NULL, NULL, NULL);
+   //ilclient_teardown_tunnels(tunnel);
+
+   //ilclient_state_transition(list, OMX_StateIdle);
+   //ilclient_state_transition(list, OMX_StateLoaded);
+
+   //ilclient_cleanup_components(list);
+
+   OMX_Deinit();
+
+   //ilclient_destroy(client);
+   return status;
+}
+
+int main (int argc, char **argv)
+{
+   if (argc < 2) {
+      printf("Usage: %s <filename>\n", argv[0]);
+      exit(1);
+   }
+   bcm_host_init();
+   return video_decode_test(argv[1]);
+}
+
+
+OMX_ERRORTYPE videodecEventHandler(
+  OMX_OUT OMX_HANDLETYPE hComponent,
+  OMX_OUT OMX_PTR pAppData,
+  OMX_OUT OMX_EVENTTYPE eEvent,
+  OMX_OUT OMX_U32 Data1,
+  OMX_OUT OMX_U32 Data2,
+  OMX_OUT OMX_PTR pEventData) {
+
+  OMX_ERRORTYPE err = OMX_ErrorNone;
+
+  printf("Hi there, I am in the %s callback\n", __func__);
+  if(eEvent == OMX_EventCmdComplete) {
+    if (Data1 == OMX_CommandStateSet) {
+      appPriv->state = (int)Data2;
+      printf( "State changed in ");
+      switch ((int)Data2) {
+        case OMX_StateInvalid:
+          printf( "OMX_StateInvalid\n");
+          break;
+        case OMX_StateLoaded:
+          printf( "OMX_StateLoaded\n");
+          break;
+        case OMX_StateIdle:
+          printf( "OMX_StateIdle\n");
+          break;
+        case OMX_StateExecuting:
+          printf( "OMX_StateExecuting\n");
+          break;
+        case OMX_StatePause:
+          printf( "OMX_StatePause\n");
+          break;
+        case OMX_StateWaitForResources:
+          printf( "OMX_StateWaitForResources\n");
+          break;
+               default:
+          printf( "default\n");
+                 break;
+
+      }
+      //tsem_up(appPriv->decoderEventSem);
+         tsem_up(appPriv->stateSem);
+      printf( "tsem up decoderEventSem\n");
+    } else if (OMX_CommandPortEnable || OMX_CommandPortDisable) {
+      printf( "In %s Received Port Enable/Disable Event\n",__func__);
+      tsem_up(appPriv->decoderEventSem);
+      printf( "tsem up decoderEventSem\n");
+    }
+  } else if(eEvent == OMX_EventPortSettingsChanged) {
+    printf( "\n port settings change event handler in %s %i\n", __func__, Data2);
+    if(Data2 == 0) {
+
+/*
+      if(!flagSetupTunnel) {
+        err = setPortParameters();
+        printf("set port param %i\n",err);
+        printf("tsem_up\n");
+        tsem_up(appPriv->decoderEventSem);
+        if(flagIsColorConvRequested == 1) {
+          pOutBufferColorConv1 = pOutBufferColorConv2 = NULL;
+          err = OMX_SendCommand(appPriv->colorconv_handle, OMX_CommandStateSet, OMX_StateIdle, NULL);
+#if 1
+          err = OMX_UseBuffer(appPriv->colorconv_handle, &pInBufferColorConv1, 0, NULL, buffer_out_size, pOutBuffer1->pBuffer);
+          if(err != OMX_ErrorNone) {
+            printf(DEB_LEV_ERR, "Unable to use the video dec comp allocate buffer\n");
+            exit(1);
+          }
+          err = OMX_UseBuffer(appPriv->colorconv_handle, &pInBufferColorConv2, 0, NULL, buffer_out_size, pOutBuffer2->pBuffer);
+          if(err != OMX_ErrorNone) {
+            printf(DEB_LEV_ERR, "Unable to use the video dec comp allocate buffer\n");
+            exit(1);
+          }
+#else
+          err = OMX_UseBuffer(appPriv->colorconv_handle, &pInBufferColorConv1, 0, NULL, buffer_out_size, pOutBuffer1->data[0]);
+          if(err != OMX_ErrorNone) {
+            printf(DEB_LEV_ERR, "Unable to use the video dec comp allocate buffer\n");
+            exit(1);
+          }
+          err = OMX_UseBuffer(appPriv->colorconv_handle, &pInBufferColorConv2, 0, NULL, buffer_out_size, pOutBuffer2->data[0]);
+          if(err != OMX_ErrorNone) {
+            printf(DEB_LEV_ERR, "Unable to use the video dec comp allocate buffer\n");
+            exit(1);
+          }
+#endif
+          omx_colorconvPortDefinition.nPortIndex = 1;
+          setHeader(&omx_colorconvPortDefinition, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+          err = OMX_GetParameter(appPriv->colorconv_handle, OMX_IndexParamPortDefinition, &omx_colorconvPortDefinition);
+          outbuf_colorconv_size = omx_colorconvPortDefinition.nBufferSize;
+          printf( " outbuf_colorconv_size : %d \n", (int)outbuf_colorconv_size);
+
+          err = OMX_AllocateBuffer(appPriv->colorconv_handle, &pOutBufferColorConv1, 1, NULL, outbuf_colorconv_size);
+          if(err != OMX_ErrorNone) {
+            printf(DEB_LEV_ERR, "Unable to allocate buffer in color conv\n");
+            exit(1);
+          }
+          err = OMX_AllocateBuffer(appPriv->colorconv_handle, &pOutBufferColorConv2, 1, NULL, outbuf_colorconv_size);
+          if(err != OMX_ErrorNone) {
+            printf(DEB_LEV_ERR, "Unable to allocate buffer in colro conv\n");
+            exit(1);
+          }
+
+          printf( "Before locking on idle wait semaphore\n");
+          tsem_down(appPriv->colorconvEventSem);
+          printf( "color conv Sem free\n");
+
+        }
+      }
+         */
+    }
+  } else if(eEvent == OMX_EventBufferFlag) {
+    printf( "In %s OMX_BUFFERFLAG_EOS\n", __func__);
+    if((int)Data2 == OMX_BUFFERFLAG_EOS) {
+      tsem_up(appPriv->eofSem);
+    }
+  } else {
+    printf( "Param1 is %x\n", (int)Data1);
+    printf( "Param2 is %x\n", (int)Data2);
+  }
+
+  return err;
+}
+
+OMX_ERRORTYPE videodecEmptyBufferDone(
+  OMX_OUT OMX_HANDLETYPE hComponent,
+  OMX_OUT OMX_PTR pAppData,
+  OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer) {
+
+  OMX_ERRORTYPE err;
+/*
+  int data_read;
+  static int iBufferDropped=0;
+  unsigned char *pTmp;
+  int offset = 0;
+
+  printf( "Hi there, I am in the %s callback.\n", __func__);
+
+  pthread_mutex_lock(&mutex);
+
+  pTmp = pBuffer->pBuffer;
+  pTmp[offset++] = 0;
+  pTmp[offset++] = 0;
+  pTmp[offset++] = 0;
+  pTmp[offset++] = 1;
+
+  data_read = FromByteStream2NalUnit(fd, pTmp+offset);
+  usleep(3000);
+  pBuffer->nFilledLen = data_read+offset;
+  pBuffer->nOffset = 0;
+  pthread_mutex_unlock(&mutex);
+
+  if (data_read <= 0) {
+         printf( "In the %s no more input data available\n", __func__);
+         iBufferDropped++;
+         if(iBufferDropped>=2) {
+                 bEOS=OMX_TRUE;
+                 return OMX_ErrorNone;
+         }
+         pBuffer->nFilledLen=0;
+         pBuffer->nFlags = OMX_BUFFERFLAG_EOS;
+         memset(pBuffer->pBuffer, 0x0, 640*480);
+         err = OMX_EmptyThisBuffer(hComponent, pBuffer);
+         printf( "EmptyThisBuffer for EOS %d\n", err);
+         hex_dump("src2", pBuffer->pBuffer, 16);
+         return OMX_ErrorNone;
+  }
+
+  if(!bEOS) {
+    printf( "EmptyThisBuffer %x, %d\n", (int)pBuffer, offset);
+    err = OMX_EmptyThisBuffer(hComponent, pBuffer);
+    hex_dump("src1", pBuffer->pBuffer, 16);
+  } else {
+    printf( "In %s Dropping Empty This buffer to Audio Dec\n", __func__);
+  }
+*/
+  return OMX_ErrorNone;
+}
+
+
+OMX_ERRORTYPE videodecFillBufferDone(
+  OMX_OUT OMX_HANDLETYPE hComponent,
+  OMX_OUT OMX_PTR pAppData,
+  OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer) {
+
+  OMX_ERRORTYPE err;
+/*
+  OMX_STATETYPE eState;
+
+  printf( "Hi there, I am in the %s callback.\n", __func__);
+  if(pBuffer != NULL) {
+    if(!bEOS) {
+      if(flagIsColorConvRequested && (!flagSetupTunnel)) {
+        OMX_GetState(appPriv->colorconv_handle,&eState);
+        if(eState == OMX_StateExecuting || eState == OMX_StatePause) {
+          if(pInBufferColorConv1->pBuffer == pBuffer->pBuffer) {
+            pInBufferColorConv1->nFilledLen = pBuffer->nFilledLen;
+            err = OMX_EmptyThisBuffer(appPriv->colorconv_handle, pInBufferColorConv1);
+          } else {
+            pInBufferColorConv2->nFilledLen = pBuffer->nFilledLen;
+            err = OMX_EmptyThisBuffer(appPriv->colorconv_handle, pInBufferColorConv2);
+          }
+          if(err != OMX_ErrorNone) {
+            printf( "In %s Error %08x Calling FillThisBuffer\n", __func__,err);
+          }
+        } else {
+          err = OMX_FillThisBuffer(hComponent, pBuffer);
+        }
+      } else if((pBuffer->nFilledLen > 0) && (!flagSetupTunnel)) {
+          printf( "nFilledLen :%d \n", pBuffer->nFilledLen);
+          //fwrite(pBuffer->pBuffer, 1,  pBuffer->nFilledLen, outfile);
+                 decoder_output_dump(pBuffer->pBuffer);
+          pBuffer->nFilledLen = 0;
+      } else {
+          printf( "In %s Empty buffer in Else\n", __func__);
+          printf( "nFilledLen :%d \n", pBuffer->nFilledLen);
+      }
+      if(pBuffer->nFlags == OMX_BUFFERFLAG_EOS) {
+        printf( "In %s: eos=%x Calling Empty This Buffer\n", __func__, (int)pBuffer->nFlags);
+        bEOS = OMX_TRUE;
+      }
+      if(!bEOS && !flagIsColorConvRequested && (!flagSetupTunnel)) {
+        err = OMX_FillThisBuffer(hComponent, pBuffer);
+        printf( "FillThisBuffer :%d \n", err);
+      }
+    } else {
+      printf( "In %s: eos=%x Dropping Empty This Buffer\n", __func__,(int)pBuffer->nFlags);
+    }
+  } else {
+    printf( "Ouch! In %s: had NULL buffer to output...\n", __func__);
+  }
+*/
+  return OMX_ErrorNone;
+}
diff --git a/host_applications/linux/apps/hello_pi/hello_video/video.h b/host_applications/linux/apps/hello_pi/hello_video/video.h
new file mode 100755 (executable)
index 0000000..056db03
--- /dev/null
@@ -0,0 +1,40 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "queue.h"
+#include "bcm_host.h"
+#include "ilclient.h"
+#include <tbm_type.h>
+#include <tbm_surface.h>
+#include <tbm_bufmgr.h>
+#include "tsemaphore.h"
+
+#define ALIGN(x, a)       (((x) + (a) - 1) & ~((a) - 1))
+
+typedef struct appPrivateType{
+  tsem_t* stateSem;
+  tsem_t* decoderEventSem;
+  tsem_t* eofSem;
+  OMX_HANDLETYPE videodechandle;
+  OMX_STATETYPE state;
+} appPrivateType;
+
+/* Callback prototypes for video decoder */
+OMX_ERRORTYPE videodecEventHandler(
+  OMX_OUT OMX_HANDLETYPE hComponent,
+  OMX_OUT OMX_PTR pAppData,
+  OMX_OUT OMX_EVENTTYPE eEvent,
+  OMX_OUT OMX_U32 Data1,
+  OMX_OUT OMX_U32 Data2,
+  OMX_OUT OMX_PTR pEventData);
+
+OMX_ERRORTYPE videodecEmptyBufferDone(
+  OMX_OUT OMX_HANDLETYPE hComponent,
+  OMX_OUT OMX_PTR pAppData,
+  OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer);
+
+OMX_ERRORTYPE videodecFillBufferDone(
+  OMX_OUT OMX_HANDLETYPE hComponent,
+  OMX_OUT OMX_PTR pAppData,
+  OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer);
diff --git a/host_applications/linux/apps/hello_pi/hello_videocube/CMakeLists.txt b/host_applications/linux/apps/hello_pi/hello_videocube/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..d7fb059
--- /dev/null
@@ -0,0 +1,8 @@
+set(EXEC hello_videocube.bin)
+set(SRCS triangle.c video.c)
+
+add_executable(${EXEC} ${SRCS})
+target_link_libraries(${EXEC} ${HELLO_PI_LIBS})
+
+install(TARGETS ${EXEC}
+        RUNTIME DESTINATION bin)
diff --git a/host_applications/linux/apps/hello_pi/hello_videocube/Makefile b/host_applications/linux/apps/hello_pi/hello_videocube/Makefile
new file mode 100755 (executable)
index 0000000..60d4b0a
--- /dev/null
@@ -0,0 +1,7 @@
+OBJS=triangle.o video.o
+BIN=hello_videocube.bin
+LDFLAGS+=-lilclient
+
+include ../Makefile.include
+
+
diff --git a/host_applications/linux/apps/hello_pi/hello_videocube/README.md b/host_applications/linux/apps/hello_pi/hello_videocube/README.md
new file mode 100755 (executable)
index 0000000..36fafcf
--- /dev/null
@@ -0,0 +1,4 @@
+hello_videocube
+===============
+
+Sample for Raspberry Pi that uses egl_render to display video on an animated cube.
\ No newline at end of file
diff --git a/host_applications/linux/apps/hello_pi/hello_videocube/cube_texture_and_coords.h b/host_applications/linux/apps/hello_pi/hello_videocube/cube_texture_and_coords.h
new file mode 100755 (executable)
index 0000000..7dd30a9
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Spatial coordinates for the cube
+
+static const GLbyte quadx[6*4*3] = {
+   /* FRONT */
+   -10, -10,  10,
+   10, -10,  10,
+   -10,  10,  10,
+   10,  10,  10,
+
+   /* BACK */
+   -10, -10, -10,
+   -10,  10, -10,
+   10, -10, -10,
+   10,  10, -10,
+
+   /* LEFT */
+   -10, -10,  10,
+   -10,  10,  10,
+   -10, -10, -10,
+   -10,  10, -10,
+
+   /* RIGHT */
+   10, -10, -10,
+   10,  10, -10,
+   10, -10,  10,
+   10,  10,  10,
+
+   /* TOP */
+   -10,  10,  10,
+   10,  10,  10,
+   -10,  10, -10,
+   10,  10, -10,
+
+   /* BOTTOM */
+   -10, -10,  10,
+   -10, -10, -10,
+   10, -10,  10,
+   10, -10, -10,
+};
+
+/** Texture coordinates for the quad. */
+static const GLfloat texCoords[6 * 4 * 2] = {
+   0.f,  0.f,
+   0.f,  1.f,
+   1.f,  0.f,
+   1.f,  1.f,
+
+   0.f,  0.f,
+   0.f,  1.f,
+   1.f,  0.f,
+   1.f,  1.f,
+
+   0.f,  0.f,
+   0.f,  1.f,
+   1.f,  0.f,
+   1.f,  1.f,
+
+   0.f,  0.f,
+   0.f,  1.f,
+   1.f,  0.f,
+   1.f,  1.f,
+
+   0.f,  0.f,
+   0.f,  1.f,
+   1.f,  0.f,
+   1.f,  1.f,
+
+   0.f,  0.f,
+   0.f,  1.f,
+   1.f,  0.f,
+   1.f,  1.f
+};
+
diff --git a/host_applications/linux/apps/hello_pi/hello_videocube/triangle.c b/host_applications/linux/apps/hello_pi/hello_videocube/triangle.c
new file mode 100755 (executable)
index 0000000..42a78a4
--- /dev/null
@@ -0,0 +1,481 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+Copyright (c) 2012, OtherCrashOverride
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// A rotating cube rendered with OpenGL|ES. Three images used as textures on the cube faces.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include "bcm_host.h"
+
+#include "GLES/gl.h"
+#include "EGL/egl.h"
+#include "EGL/eglext.h"
+
+#include "cube_texture_and_coords.h"
+
+#include "triangle.h"
+#include <pthread.h>
+
+
+#define PATH "./"
+
+#define IMAGE_SIZE_WIDTH 1920
+#define IMAGE_SIZE_HEIGHT 1080
+
+#ifndef M_PI
+   #define M_PI 3.141592654
+#endif
+  
+
+typedef struct
+{
+   uint32_t screen_width;
+   uint32_t screen_height;
+// OpenGL|ES objects
+   EGLDisplay display;
+   EGLSurface surface;
+   EGLContext context;
+   GLuint tex;
+// model rotation vector and direction
+   GLfloat rot_angle_x_inc;
+   GLfloat rot_angle_y_inc;
+   GLfloat rot_angle_z_inc;
+// current model rotation angles
+   GLfloat rot_angle_x;
+   GLfloat rot_angle_y;
+   GLfloat rot_angle_z;
+// current distance from camera
+   GLfloat distance;
+   GLfloat distance_inc;
+} CUBE_STATE_T;
+
+static void init_ogl(CUBE_STATE_T *state);
+static void init_model_proj(CUBE_STATE_T *state);
+static void reset_model(CUBE_STATE_T *state);
+static GLfloat inc_and_wrap_angle(GLfloat angle, GLfloat angle_inc);
+static GLfloat inc_and_clip_distance(GLfloat distance, GLfloat distance_inc);
+static void redraw_scene(CUBE_STATE_T *state);
+static void update_model(CUBE_STATE_T *state);
+static void init_textures(CUBE_STATE_T *state);
+static void exit_func(void);
+static volatile int terminate;
+static CUBE_STATE_T _state, *state=&_state;
+
+static void* eglImage = 0;
+static pthread_t thread1;
+
+
+/***********************************************************
+ * Name: init_ogl
+ *
+ * Arguments:
+ *       CUBE_STATE_T *state - holds OGLES model info
+ *
+ * Description: Sets the display, OpenGL|ES context and screen stuff
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void init_ogl(CUBE_STATE_T *state)
+{
+   int32_t success = 0;
+   EGLBoolean result;
+   EGLint num_config;
+
+   static EGL_DISPMANX_WINDOW_T nativewindow;
+
+   DISPMANX_ELEMENT_HANDLE_T dispman_element;
+   DISPMANX_DISPLAY_HANDLE_T dispman_display;
+   DISPMANX_UPDATE_HANDLE_T dispman_update;
+   VC_RECT_T dst_rect;
+   VC_RECT_T src_rect;
+
+   static const EGLint attribute_list[] =
+   {
+      EGL_RED_SIZE, 8,
+      EGL_GREEN_SIZE, 8,
+      EGL_BLUE_SIZE, 8,
+      EGL_ALPHA_SIZE, 8,
+      EGL_DEPTH_SIZE, 16,
+      //EGL_SAMPLES, 4,
+      EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+      EGL_NONE
+   };
+   
+   EGLConfig config;
+
+   // get an EGL display connection
+   state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+   assert(state->display!=EGL_NO_DISPLAY);
+
+   // initialize the EGL display connection
+   result = eglInitialize(state->display, NULL, NULL);
+   assert(EGL_FALSE != result);
+
+   // get an appropriate EGL frame buffer configuration
+   // this uses a BRCM extension that gets the closest match, rather than standard which returns anything that matches
+   result = eglSaneChooseConfigBRCM(state->display, attribute_list, &config, 1, &num_config);
+   assert(EGL_FALSE != result);
+
+   // create an EGL rendering context
+   state->context = eglCreateContext(state->display, config, EGL_NO_CONTEXT, NULL);
+   assert(state->context!=EGL_NO_CONTEXT);
+
+   // create an EGL window surface
+   success = graphics_get_display_size(0 /* LCD */, &state->screen_width, &state->screen_height);
+   assert( success >= 0 );
+
+   dst_rect.x = 0;
+   dst_rect.y = 0;
+   dst_rect.width = state->screen_width;
+   dst_rect.height = state->screen_height;
+      
+   src_rect.x = 0;
+   src_rect.y = 0;
+   src_rect.width = state->screen_width << 16;
+   src_rect.height = state->screen_height << 16;        
+
+   dispman_display = vc_dispmanx_display_open( 0 /* LCD */);
+   dispman_update = vc_dispmanx_update_start( 0 );
+         
+   dispman_element = vc_dispmanx_element_add ( dispman_update, dispman_display,
+      0/*layer*/, &dst_rect, 0/*src*/,
+      &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, 0/*transform*/);
+      
+   nativewindow.element = dispman_element;
+   nativewindow.width = state->screen_width;
+   nativewindow.height = state->screen_height;
+   vc_dispmanx_update_submit_sync( dispman_update );
+      
+   state->surface = eglCreateWindowSurface( state->display, config, &nativewindow, NULL );
+   assert(state->surface != EGL_NO_SURFACE);
+
+   // connect the context to the surface
+   result = eglMakeCurrent(state->display, state->surface, state->surface, state->context);
+   assert(EGL_FALSE != result);
+
+   // Set background color and clear buffers
+   glClearColor(0.15f, 0.25f, 0.35f, 1.0f);
+
+   // Enable back face culling.
+   glEnable(GL_CULL_FACE);
+
+   glMatrixMode(GL_MODELVIEW);
+}
+
+/***********************************************************
+ * Name: init_model_proj
+ *
+ * Arguments:
+ *       CUBE_STATE_T *state - holds OGLES model info
+ *
+ * Description: Sets the OpenGL|ES model to default values
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void init_model_proj(CUBE_STATE_T *state)
+{
+   float nearp = 1.0f;
+   float farp = 500.0f;
+   float hht;
+   float hwd;
+
+   glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
+
+   glViewport(0, 0, (GLsizei)state->screen_width, (GLsizei)state->screen_height);
+      
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+
+   hht = nearp * (float)tan(45.0 / 2.0 / 180.0 * M_PI);
+   hwd = hht * (float)state->screen_width / (float)state->screen_height;
+
+   glFrustumf(-hwd, hwd, -hht, hht, nearp, farp);
+   
+   glEnableClientState( GL_VERTEX_ARRAY );
+   glVertexPointer( 3, GL_BYTE, 0, quadx );
+
+   reset_model(state);
+}
+
+/***********************************************************
+ * Name: reset_model
+ *
+ * Arguments:
+ *       CUBE_STATE_T *state - holds OGLES model info
+ *
+ * Description: Resets the Model projection and rotation direction
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void reset_model(CUBE_STATE_T *state)
+{
+   // reset model position
+   glMatrixMode(GL_MODELVIEW);
+   glLoadIdentity();
+   glTranslatef(0.f, 0.f, -50.f);
+
+   // reset model rotation
+   state->rot_angle_x = 45.f; state->rot_angle_y = 30.f; state->rot_angle_z = 0.f;
+   state->rot_angle_x_inc = 0.5f; state->rot_angle_y_inc = 0.5f; state->rot_angle_z_inc = 0.f;
+   state->distance = 40.f;
+}
+
+/***********************************************************
+ * Name: update_model
+ *
+ * Arguments:
+ *       CUBE_STATE_T *state - holds OGLES model info
+ *
+ * Description: Updates model projection to current position/rotation
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void update_model(CUBE_STATE_T *state)
+{
+   // update position
+   state->rot_angle_x = inc_and_wrap_angle(state->rot_angle_x, state->rot_angle_x_inc);
+   state->rot_angle_y = inc_and_wrap_angle(state->rot_angle_y, state->rot_angle_y_inc);
+   state->rot_angle_z = inc_and_wrap_angle(state->rot_angle_z, state->rot_angle_z_inc);
+   state->distance    = inc_and_clip_distance(state->distance, state->distance_inc);
+
+   glLoadIdentity();
+   // move camera back to see the cube
+   glTranslatef(0.f, 0.f, -state->distance);
+
+   // Rotate model to new position
+   glRotatef(state->rot_angle_x, 1.f, 0.f, 0.f);
+   glRotatef(state->rot_angle_y, 0.f, 1.f, 0.f);
+   glRotatef(state->rot_angle_z, 0.f, 0.f, 1.f);
+}
+
+/***********************************************************
+ * Name: inc_and_wrap_angle
+ *
+ * Arguments:
+ *       GLfloat angle     current angle
+ *       GLfloat angle_inc angle increment
+ *
+ * Description:   Increments or decrements angle by angle_inc degrees
+ *                Wraps to 0 at 360 deg.
+ *
+ * Returns: new value of angle
+ *
+ ***********************************************************/
+static GLfloat inc_and_wrap_angle(GLfloat angle, GLfloat angle_inc)
+{
+   angle += angle_inc;
+
+   if (angle >= 360.0)
+      angle -= 360.f;
+   else if (angle <=0)
+      angle += 360.f;
+
+   return angle;
+}
+
+/***********************************************************
+ * Name: inc_and_clip_distance
+ *
+ * Arguments:
+ *       GLfloat distance     current distance
+ *       GLfloat distance_inc distance increment
+ *
+ * Description:   Increments or decrements distance by distance_inc units
+ *                Clips to range
+ *
+ * Returns: new value of angle
+ *
+ ***********************************************************/
+static GLfloat inc_and_clip_distance(GLfloat distance, GLfloat distance_inc)
+{
+   distance += distance_inc;
+
+   if (distance >= 120.0f)
+      distance = 120.f;
+   else if (distance <= 40.0f)
+      distance = 40.0f;
+
+   return distance;
+}
+
+/***********************************************************
+ * Name: redraw_scene
+ *
+ * Arguments:
+ *       CUBE_STATE_T *state - holds OGLES model info
+ *
+ * Description:   Draws the model and calls eglSwapBuffers
+ *                to render to screen
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void redraw_scene(CUBE_STATE_T *state)
+{
+   // Start with a clear screen
+   glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+   // Need to rotate textures - do this by rotating each cube face
+   glRotatef(270.f, 0.f, 0.f, 1.f ); // front face normal along z axis
+
+   // draw first 4 vertices
+   glDrawArrays( GL_TRIANGLE_STRIP, 0, 4);
+
+   // same pattern for other 5 faces - rotation chosen to make image orientation 'nice'
+   glRotatef(90.f, 0.f, 0.f, 1.f ); // back face normal along z axis
+   glDrawArrays( GL_TRIANGLE_STRIP, 4, 4);
+
+   glRotatef(90.f, 1.f, 0.f, 0.f ); // left face normal along x axis
+   glDrawArrays( GL_TRIANGLE_STRIP, 8, 4);
+
+   glRotatef(90.f, 1.f, 0.f, 0.f ); // right face normal along x axis
+   glDrawArrays( GL_TRIANGLE_STRIP, 12, 4);
+
+   glRotatef(270.f, 0.f, 1.f, 0.f ); // top face normal along y axis
+   glDrawArrays( GL_TRIANGLE_STRIP, 16, 4);
+
+   glRotatef(90.f, 0.f, 1.f, 0.f ); // bottom face normal along y axis
+   glDrawArrays( GL_TRIANGLE_STRIP, 20, 4);
+
+   eglSwapBuffers(state->display, state->surface);
+}
+
+/***********************************************************
+ * Name: init_textures
+ *
+ * Arguments:
+ *       CUBE_STATE_T *state - holds OGLES model info
+ *
+ * Description:   Initialise OGL|ES texture surfaces to use image
+ *                buffers
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void init_textures(CUBE_STATE_T *state)
+{
+   //// load three texture buffers but use them on six OGL|ES texture surfaces
+   glGenTextures(1, &state->tex);
+
+   glBindTexture(GL_TEXTURE_2D, state->tex);
+   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, IMAGE_SIZE_WIDTH, IMAGE_SIZE_HEIGHT, 0,
+                GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+
+   /* Create EGL Image */
+   eglImage = eglCreateImageKHR(
+                state->display,
+                state->context,
+                EGL_GL_TEXTURE_2D_KHR,
+                (EGLClientBuffer)state->tex,
+                0);
+    
+   if (eglImage == EGL_NO_IMAGE_KHR)
+   {
+      printf("eglCreateImageKHR failed.\n");
+      exit(1);
+   }
+
+   // Start rendering
+   pthread_create(&thread1, NULL, video_decode_test, eglImage);
+
+   // setup overall texture environment
+   glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
+   glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+
+   glEnable(GL_TEXTURE_2D);
+
+   // Bind texture surface to current vertices
+   glBindTexture(GL_TEXTURE_2D, state->tex);
+}
+//------------------------------------------------------------------------------
+
+static void exit_func(void)
+// Function to be passed to atexit().
+{
+   if (eglImage != 0)
+   {
+      if (!eglDestroyImageKHR(state->display, (EGLImageKHR) eglImage))
+         printf("eglDestroyImageKHR failed.");
+   }
+
+   // clear screen
+   glClear( GL_COLOR_BUFFER_BIT );
+   eglSwapBuffers(state->display, state->surface);
+
+   // Release OpenGL resources
+   eglMakeCurrent( state->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
+   eglDestroySurface( state->display, state->surface );
+   eglDestroyContext( state->display, state->context );
+   eglTerminate( state->display );
+
+   printf("\ncube closed\n");
+} // exit_func()
+
+//==============================================================================
+
+int main ()
+{
+   bcm_host_init();
+   printf("Note: ensure you have sufficient gpu_mem configured\n");
+
+   // Clear application state
+   memset( state, 0, sizeof( *state ) );
+      
+   // Start OGLES
+   init_ogl(state);
+
+   // Setup the model world
+   init_model_proj(state);
+
+   // initialise the OGLES texture(s)
+   init_textures(state);
+
+   while (!terminate)
+   {
+      update_model(state);
+      redraw_scene(state);
+   }
+   exit_func();
+   return 0;
+}
+
diff --git a/host_applications/linux/apps/hello_pi/hello_videocube/triangle.h b/host_applications/linux/apps/hello_pi/hello_videocube/triangle.h
new file mode 100755 (executable)
index 0000000..0f50e93
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#pragma once
+
+
+void* video_decode_test(void* arg);
diff --git a/host_applications/linux/apps/hello_pi/hello_videocube/video.c b/host_applications/linux/apps/hello_pi/hello_videocube/video.c
new file mode 100755 (executable)
index 0000000..4baae8f
--- /dev/null
@@ -0,0 +1,266 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+Copyright (c) 2012, OtherCrashOverride
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Video decode demo using OpenMAX IL though the ilcient helper library
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "bcm_host.h"
+#include "ilclient.h"
+
+static OMX_BUFFERHEADERTYPE* eglBuffer = NULL;
+static COMPONENT_T* egl_render = NULL;
+
+static void* eglImage = 0;
+
+void my_fill_buffer_done(void* data, COMPONENT_T* comp)
+{
+  if (OMX_FillThisBuffer(ilclient_get_handle(egl_render), eglBuffer) != OMX_ErrorNone)
+   {
+      printf("OMX_FillThisBuffer failed in callback\n");
+      exit(1);
+   }
+}
+
+
+// Modified function prototype to work with pthreads
+void *video_decode_test(void* arg)
+{
+   const char* filename = "/opt/vc/src/hello_pi/hello_video/test.h264";
+   eglImage = arg;
+
+   if (eglImage == 0)
+   {
+      printf("eglImage is null.\n");
+      exit(1);
+   }
+
+   OMX_VIDEO_PARAM_PORTFORMATTYPE format;
+   OMX_TIME_CONFIG_CLOCKSTATETYPE cstate;
+   COMPONENT_T *video_decode = NULL, *video_scheduler = NULL, *clock = NULL;
+   COMPONENT_T *list[5];
+   TUNNEL_T tunnel[4];
+   ILCLIENT_T *client;
+   FILE *in;
+   int status = 0;
+   unsigned int data_len = 0;
+
+   memset(list, 0, sizeof(list));
+   memset(tunnel, 0, sizeof(tunnel));
+
+   if((in = fopen(filename, "rb")) == NULL)
+      return (void *)-2;
+
+   if((client = ilclient_init()) == NULL)
+   {
+      fclose(in);
+      return (void *)-3;
+   }
+
+   if(OMX_Init() != OMX_ErrorNone)
+   {
+      ilclient_destroy(client);
+      fclose(in);
+      return (void *)-4;
+   }
+
+   // callback
+   ilclient_set_fill_buffer_done_callback(client, my_fill_buffer_done, 0);
+
+   // create video_decode
+   if(ilclient_create_component(client, &video_decode, "video_decode", ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_INPUT_BUFFERS) != 0)
+      status = -14;
+   list[0] = video_decode;
+
+   // create egl_render
+   if(status == 0 && ilclient_create_component(client, &egl_render, "egl_render", ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_ENABLE_OUTPUT_BUFFERS) != 0)
+      status = -14;
+   list[1] = egl_render;
+
+   // create clock
+   if(status == 0 && ilclient_create_component(client, &clock, "clock", ILCLIENT_DISABLE_ALL_PORTS) != 0)
+      status = -14;
+   list[2] = clock;
+
+   memset(&cstate, 0, sizeof(cstate));
+   cstate.nSize = sizeof(cstate);
+   cstate.nVersion.nVersion = OMX_VERSION;
+   cstate.eState = OMX_TIME_ClockStateWaitingForStartTime;
+   cstate.nWaitMask = 1;
+   if(clock != NULL && OMX_SetParameter(ILC_GET_HANDLE(clock), OMX_IndexConfigTimeClockState, &cstate) != OMX_ErrorNone)
+      status = -13;
+
+   // create video_scheduler
+   if(status == 0 && ilclient_create_component(client, &video_scheduler, "video_scheduler", ILCLIENT_DISABLE_ALL_PORTS) != 0)
+      status = -14;
+   list[3] = video_scheduler;
+
+   set_tunnel(tunnel, video_decode, 131, video_scheduler, 10);
+   set_tunnel(tunnel+1, video_scheduler, 11, egl_render, 220);
+   set_tunnel(tunnel+2, clock, 80, video_scheduler, 12);
+
+   // setup clock tunnel first
+   if(status == 0 && ilclient_setup_tunnel(tunnel+2, 0, 0) != 0)
+      status = -15;
+   else
+      ilclient_change_component_state(clock, OMX_StateExecuting);
+
+   if(status == 0)
+      ilclient_change_component_state(video_decode, OMX_StateIdle);
+
+   memset(&format, 0, sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE));
+   format.nSize = sizeof(OMX_VIDEO_PARAM_PORTFORMATTYPE);
+   format.nVersion.nVersion = OMX_VERSION;
+   format.nPortIndex = 130;
+   format.eCompressionFormat = OMX_VIDEO_CodingAVC;
+
+   if(status == 0 &&
+      OMX_SetParameter(ILC_GET_HANDLE(video_decode), OMX_IndexParamVideoPortFormat, &format) == OMX_ErrorNone &&
+      ilclient_enable_port_buffers(video_decode, 130, NULL, NULL, NULL) == 0)
+   {
+      OMX_BUFFERHEADERTYPE *buf;
+      int port_settings_changed = 0;
+      int first_packet = 1;
+
+      ilclient_change_component_state(video_decode, OMX_StateExecuting);
+
+      while((buf = ilclient_get_input_buffer(video_decode, 130, 1)) != NULL)
+      {
+         // feed data and wait until we get port settings changed
+         unsigned char *dest = buf->pBuffer;
+
+         // loop if at end
+         if (feof(in))
+            rewind(in);
+
+         data_len += fread(dest, 1, buf->nAllocLen-data_len, in);
+
+         if(port_settings_changed == 0 &&
+            ((data_len > 0 && ilclient_remove_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1) == 0) ||
+             (data_len == 0 && ilclient_wait_for_event(video_decode, OMX_EventPortSettingsChanged, 131, 0, 0, 1,
+                                                       ILCLIENT_EVENT_ERROR | ILCLIENT_PARAMETER_CHANGED, 10000) == 0)))
+         {
+            port_settings_changed = 1;
+
+            if(ilclient_setup_tunnel(tunnel, 0, 0) != 0)
+            {
+               status = -7;
+               break;
+            }
+
+            ilclient_change_component_state(video_scheduler, OMX_StateExecuting);
+
+            // now setup tunnel to egl_render
+            if(ilclient_setup_tunnel(tunnel+1, 0, 1000) != 0)
+            {
+               status = -12;
+               break;
+            }
+
+            // Set egl_render to idle
+            ilclient_change_component_state(egl_render, OMX_StateIdle);
+
+            // Enable the output port and tell egl_render to use the texture as a buffer
+            //ilclient_enable_port(egl_render, 221); THIS BLOCKS SO CAN'T BE USED
+            if (OMX_SendCommand(ILC_GET_HANDLE(egl_render), OMX_CommandPortEnable, 221, NULL) != OMX_ErrorNone)
+            {
+               printf("OMX_CommandPortEnable failed.\n");
+               exit(1);
+            }
+
+            if (OMX_UseEGLImage(ILC_GET_HANDLE(egl_render), &eglBuffer, 221, NULL, eglImage) != OMX_ErrorNone)
+            {
+               printf("OMX_UseEGLImage failed.\n");
+               exit(1);
+            }
+
+            // Set egl_render to executing
+            ilclient_change_component_state(egl_render, OMX_StateExecuting);
+
+
+            // Request egl_render to write data to the texture buffer
+            if(OMX_FillThisBuffer(ILC_GET_HANDLE(egl_render), eglBuffer) != OMX_ErrorNone)
+            {
+               printf("OMX_FillThisBuffer failed.\n");
+               exit(1);
+            }
+         }
+         if(!data_len)
+            break;
+
+         buf->nFilledLen = data_len;
+         data_len = 0;
+
+         buf->nOffset = 0;
+         if(first_packet)
+         {
+            buf->nFlags = OMX_BUFFERFLAG_STARTTIME;
+            first_packet = 0;
+         }
+         else
+            buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN;
+
+         if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf) != OMX_ErrorNone)
+         {
+            status = -6;
+            break;
+         }
+      }
+
+      buf->nFilledLen = 0;
+      buf->nFlags = OMX_BUFFERFLAG_TIME_UNKNOWN | OMX_BUFFERFLAG_EOS;
+
+      if(OMX_EmptyThisBuffer(ILC_GET_HANDLE(video_decode), buf) != OMX_ErrorNone)
+         status = -20;
+
+      // need to flush the renderer to allow video_decode to disable its input port
+      ilclient_flush_tunnels(tunnel, 0);
+
+      ilclient_disable_port_buffers(video_decode, 130, NULL, NULL, NULL);
+   }
+
+   fclose(in);
+
+   ilclient_disable_tunnel(tunnel);
+   ilclient_disable_tunnel(tunnel+1);
+   ilclient_disable_tunnel(tunnel+2);
+   ilclient_teardown_tunnels(tunnel);
+
+   ilclient_state_transition(list, OMX_StateIdle);
+   ilclient_state_transition(list, OMX_StateLoaded);
+
+   ilclient_cleanup_components(list);
+
+   OMX_Deinit();
+
+   ilclient_destroy(client);
+   return (void *)status;
+}
+
diff --git a/host_applications/linux/apps/hello_pi/hello_world/CMakeLists.txt b/host_applications/linux/apps/hello_pi/hello_world/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..b0120fe
--- /dev/null
@@ -0,0 +1,8 @@
+set(EXEC hello_world.bin)
+set(SRCS world.c)
+
+add_executable(${EXEC} ${SRCS})
+target_link_libraries(${EXEC} ${HELLO_PI_LIBS})
+
+install(TARGETS ${EXEC}
+        RUNTIME DESTINATION bin)
diff --git a/host_applications/linux/apps/hello_pi/hello_world/Makefile b/host_applications/linux/apps/hello_pi/hello_world/Makefile
new file mode 100755 (executable)
index 0000000..7bf2402
--- /dev/null
@@ -0,0 +1,5 @@
+OBJS=world.o
+BIN=hello_world.bin
+
+include ../Makefile.include
+
diff --git a/host_applications/linux/apps/hello_pi/hello_world/world.c b/host_applications/linux/apps/hello_pi/hello_world/world.c
new file mode 100755 (executable)
index 0000000..0a9c4aa
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Classic Hello World
+
+#include <stdio.h>
+
+int main(void)
+{
+   printf("Hello world!\n");
+   return 0;
+}
diff --git a/host_applications/linux/apps/hello_pi/libs/ilclient/Makefile b/host_applications/linux/apps/hello_pi/libs/ilclient/Makefile
new file mode 100755 (executable)
index 0000000..82979e3
--- /dev/null
@@ -0,0 +1,5 @@
+OBJS=ilclient.o ilcore.o
+LIB=libilclient.a
+
+include ../../Makefile.include
+
diff --git a/host_applications/linux/apps/hello_pi/libs/ilclient/ilclient.c b/host_applications/linux/apps/hello_pi/libs/ilclient/ilclient.c
new file mode 100755 (executable)
index 0000000..da08ad0
--- /dev/null
@@ -0,0 +1,1836 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * \file
+ *
+ * \brief This API defines helper functions for writing IL clients.
+ *
+ * This file defines an IL client side library.  This is useful when
+ * writing IL clients, since there tends to be much repeated and
+ * common code across both single and multiple clients.  This library
+ * seeks to remove that common code and abstract some of the
+ * interactions with components.  There is a wrapper around a
+ * component and tunnel, and some operations can be done on lists of
+ * these.  The callbacks from components are handled, and specific
+ * events can be checked or waited for.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "interface/vcos/vcos.h"
+#include "interface/vcos/vcos_logging.h"
+#include "interface/vmcs_host/vchost.h"
+
+#include "IL/OMX_Broadcom.h"
+#include "ilclient.h"
+
+#define VCOS_LOG_CATEGORY (&ilclient_log_category)
+
+#ifndef ILCLIENT_THREAD_DEFAULT_STACK_SIZE
+#define ILCLIENT_THREAD_DEFAULT_STACK_SIZE   (6<<10)
+#endif
+
+static VCOS_LOG_CAT_T ilclient_log_category;
+
+/******************************************************************************
+Static data and types used only in this file.
+******************************************************************************/
+
+struct _ILEVENT_T {
+   OMX_EVENTTYPE eEvent;
+   OMX_U32 nData1;
+   OMX_U32 nData2;
+   OMX_PTR pEventData;
+   struct _ILEVENT_T *next;
+};
+
+#define NUM_EVENTS 100
+struct _ILCLIENT_T {
+   ILEVENT_T *event_list;
+   VCOS_SEMAPHORE_T event_sema;
+   ILEVENT_T event_rep[NUM_EVENTS];
+
+   ILCLIENT_CALLBACK_T port_settings_callback;
+   void *port_settings_callback_data;
+   ILCLIENT_CALLBACK_T eos_callback;
+   void *eos_callback_data;
+   ILCLIENT_CALLBACK_T error_callback;
+   void *error_callback_data;
+   ILCLIENT_BUFFER_CALLBACK_T fill_buffer_done_callback;
+   void *fill_buffer_done_callback_data;
+   ILCLIENT_BUFFER_CALLBACK_T empty_buffer_done_callback;
+   void *empty_buffer_done_callback_data;
+   ILCLIENT_CALLBACK_T configchanged_callback;
+   void *configchanged_callback_data;
+};
+
+struct _COMPONENT_T {
+   OMX_HANDLETYPE comp;
+   ILCLIENT_CREATE_FLAGS_T flags;
+   VCOS_SEMAPHORE_T sema;
+   VCOS_EVENT_FLAGS_T event;
+   struct _COMPONENT_T *related;
+   OMX_BUFFERHEADERTYPE *out_list;
+   OMX_BUFFERHEADERTYPE *in_list;
+   char name[32];
+   char bufname[32];
+   unsigned int error_mask;
+   unsigned int private;
+   ILEVENT_T *list;
+   ILCLIENT_T *client;
+};
+
+#define random_wait()
+static char *states[] = {"Invalid", "Loaded", "Idle", "Executing", "Pause", "WaitingForResources"};
+
+typedef enum {
+   ILCLIENT_ERROR_UNPOPULATED  = 0x1,
+   ILCLIENT_ERROR_SAMESTATE    = 0x2,
+   ILCLIENT_ERROR_BADPARAMETER = 0x4
+} ILERROR_MASK_T;
+
+/******************************************************************************
+Static functions.
+******************************************************************************/
+
+static OMX_ERRORTYPE ilclient_empty_buffer_done(OMX_IN OMX_HANDLETYPE hComponent,
+      OMX_IN OMX_PTR pAppData,
+      OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+static OMX_ERRORTYPE ilclient_empty_buffer_done_error(OMX_IN OMX_HANDLETYPE hComponent,
+      OMX_IN OMX_PTR pAppData,
+      OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+static OMX_ERRORTYPE ilclient_fill_buffer_done(OMX_OUT OMX_HANDLETYPE hComponent,
+      OMX_OUT OMX_PTR pAppData,
+      OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer);
+static OMX_ERRORTYPE ilclient_fill_buffer_done_error(OMX_OUT OMX_HANDLETYPE hComponent,
+      OMX_OUT OMX_PTR pAppData,
+      OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer);
+static OMX_ERRORTYPE ilclient_event_handler(OMX_IN OMX_HANDLETYPE hComponent,
+      OMX_IN OMX_PTR pAppData,
+      OMX_IN OMX_EVENTTYPE eEvent,
+      OMX_IN OMX_U32 nData1,
+      OMX_IN OMX_U32 nData2,
+      OMX_IN OMX_PTR pEventData);
+static void ilclient_lock_events(ILCLIENT_T *st);
+static void ilclient_unlock_events(ILCLIENT_T *st);
+
+/******************************************************************************
+Global functions
+******************************************************************************/
+
+/***********************************************************
+ * Name: ilclient_init
+ *
+ * Description: Creates ilclient pointer
+ *
+ * Returns: pointer to client structure
+ ***********************************************************/
+ILCLIENT_T *ilclient_init()
+{
+   ILCLIENT_T *st = vcos_malloc(sizeof(ILCLIENT_T), "ilclient");
+   int i;
+   
+   if (!st)
+      return NULL;
+   
+   vcos_log_set_level(VCOS_LOG_CATEGORY, VCOS_LOG_WARN);
+   vcos_log_register("ilclient", VCOS_LOG_CATEGORY);
+
+   memset(st, 0, sizeof(ILCLIENT_T));
+
+   i = vcos_semaphore_create(&st->event_sema, "il:event", 1);
+   vc_assert(i == VCOS_SUCCESS);
+
+   ilclient_lock_events(st);
+   st->event_list = NULL;
+   for (i=0; i<NUM_EVENTS; i++)
+   {
+      st->event_rep[i].eEvent = -1; // mark as unused
+      st->event_rep[i].next = st->event_list;
+      st->event_list = st->event_rep+i;
+   }
+   ilclient_unlock_events(st);
+   return st;
+}
+
+/***********************************************************
+ * Name: ilclient_destroy
+ *
+ * Description: frees client state
+ *
+ * Returns: void
+ ***********************************************************/
+void ilclient_destroy(ILCLIENT_T *st)
+{
+   vcos_semaphore_delete(&st->event_sema);
+   vcos_free(st);
+   vcos_log_unregister(VCOS_LOG_CATEGORY);
+}
+
+/***********************************************************
+ * Name: ilclient_set_port_settings_callback
+ *
+ * Description: sets the callback used when receiving port settings
+ * changed messages.  The data field in the callback function will be
+ * the port index reporting the message.
+ *
+ * Returns: void
+ ***********************************************************/
+void ilclient_set_port_settings_callback(ILCLIENT_T *st, ILCLIENT_CALLBACK_T func, void *userdata)
+{
+   st->port_settings_callback = func;
+   st->port_settings_callback_data = userdata;
+}
+
+/***********************************************************
+ * Name: ilclient_set_eos_callback
+ *
+ * Description: sets the callback used when receiving eos flags.  The
+ * data parameter in the callback function will be the port index
+ * reporting an eos flag.
+ *
+ * Returns: void
+ ***********************************************************/
+void ilclient_set_eos_callback(ILCLIENT_T *st, ILCLIENT_CALLBACK_T func, void *userdata)
+{
+   st->eos_callback = func;
+   st->eos_callback_data = userdata;
+}
+
+/***********************************************************
+ * Name: ilclient_set_error_callback
+ *
+ * Description: sets the callback used when receiving error events.
+ * The data parameter in the callback function will be the error code
+ * being reported.
+ *
+ * Returns: void
+ ***********************************************************/
+void ilclient_set_error_callback(ILCLIENT_T *st, ILCLIENT_CALLBACK_T func, void *userdata)
+{
+   st->error_callback = func;
+   st->error_callback_data = userdata;
+}
+
+/***********************************************************
+ * Name: ilclient_set_fill_buffer_done_callback
+ *
+ * Description: sets the callback used when receiving
+ * fill_buffer_done event
+ *
+ * Returns: void
+ ***********************************************************/
+void ilclient_set_fill_buffer_done_callback(ILCLIENT_T *st, ILCLIENT_BUFFER_CALLBACK_T func, void *userdata)
+{
+   st->fill_buffer_done_callback = func;
+   st->fill_buffer_done_callback_data = userdata;
+}
+
+/***********************************************************
+ * Name: ilclient_set_empty_buffer_done_callback
+ *
+ * Description: sets the callback used when receiving
+ * empty_buffer_done event
+ *
+ * Returns: void
+ ***********************************************************/
+void ilclient_set_empty_buffer_done_callback(ILCLIENT_T *st, ILCLIENT_BUFFER_CALLBACK_T func, void *userdata)
+{
+   st->empty_buffer_done_callback = func;
+   st->empty_buffer_done_callback_data = userdata;
+}
+
+/***********************************************************
+ * Name: ilclient_set_configchanged_callback
+ *
+ * Description: sets the callback used when a config changed
+ * event is received
+ *
+ * Returns: void
+ ***********************************************************/
+void ilclient_set_configchanged_callback(ILCLIENT_T *st, ILCLIENT_CALLBACK_T func, void *userdata)
+{
+   st->configchanged_callback = func;
+   st->configchanged_callback_data = userdata;
+}
+
+/***********************************************************
+ * Name: ilclient_create_component
+ *
+ * Description: initialises a component state structure and creates
+ * the IL component.
+ *
+ * Returns: 0 on success, -1 on failure
+ ***********************************************************/
+int ilclient_create_component(ILCLIENT_T *client, COMPONENT_T **comp, char *name,
+                              ILCLIENT_CREATE_FLAGS_T flags)
+{
+   OMX_CALLBACKTYPE callbacks;
+   OMX_ERRORTYPE error;
+   char component_name[128];
+   int32_t status;
+
+   *comp = vcos_malloc(sizeof(COMPONENT_T), "il:comp");
+   if(!*comp)
+      return -1;
+
+   memset(*comp, 0, sizeof(COMPONENT_T));
+
+#define COMP_PREFIX "OMX.broadcom."
+
+   status = vcos_event_flags_create(&(*comp)->event,"il:comp");
+   vc_assert(status == VCOS_SUCCESS);
+   status = vcos_semaphore_create(&(*comp)->sema, "il:comp", 1);
+   vc_assert(status == VCOS_SUCCESS);
+   (*comp)->client = client;
+
+   vcos_snprintf((*comp)->name, sizeof((*comp)->name), "cl:%s", name);
+   vcos_snprintf((*comp)->bufname, sizeof((*comp)->bufname), "cl:%s buffer", name);
+   vcos_snprintf(component_name, sizeof(component_name), "%s%s", COMP_PREFIX, name);
+
+   (*comp)->flags = flags;
+
+   callbacks.EventHandler = ilclient_event_handler;
+   callbacks.EmptyBufferDone = flags & ILCLIENT_ENABLE_INPUT_BUFFERS ? ilclient_empty_buffer_done : ilclient_empty_buffer_done_error;
+   callbacks.FillBufferDone = flags & ILCLIENT_ENABLE_OUTPUT_BUFFERS ? ilclient_fill_buffer_done : ilclient_fill_buffer_done_error;
+
+   error = OMX_GetHandle(&(*comp)->comp, component_name, *comp, &callbacks);
+
+   if (error == OMX_ErrorNone)
+   {
+      OMX_UUIDTYPE uid;
+      char name[128];
+      OMX_VERSIONTYPE compVersion, specVersion;
+
+      if(OMX_GetComponentVersion((*comp)->comp, name, &compVersion, &specVersion, &uid) == OMX_ErrorNone)
+      {
+         char *p = (char *) uid + strlen(COMP_PREFIX);
+
+         vcos_snprintf((*comp)->name, sizeof((*comp)->name), "cl:%s", p);
+         (*comp)->name[sizeof((*comp)->name)-1] = 0;
+         vcos_snprintf((*comp)->bufname, sizeof((*comp)->bufname), "cl:%s buffer", p);
+         (*comp)->bufname[sizeof((*comp)->bufname)-1] = 0;
+      }
+
+      if(flags & (ILCLIENT_DISABLE_ALL_PORTS | ILCLIENT_OUTPUT_ZERO_BUFFERS))
+      {
+         OMX_PORT_PARAM_TYPE ports;
+         OMX_INDEXTYPE types[] = {OMX_IndexParamAudioInit, OMX_IndexParamVideoInit, OMX_IndexParamImageInit, OMX_IndexParamOtherInit};
+         int i;
+
+         ports.nSize = sizeof(OMX_PORT_PARAM_TYPE);
+         ports.nVersion.nVersion = OMX_VERSION;
+
+         for(i=0; i<4; i++)
+         {
+            OMX_ERRORTYPE error = OMX_GetParameter((*comp)->comp, types[i], &ports);
+            if(error == OMX_ErrorNone)
+            {
+               uint32_t j;
+               for(j=0; j<ports.nPorts; j++)
+               {
+                  if(flags & ILCLIENT_DISABLE_ALL_PORTS)
+                     ilclient_disable_port(*comp, ports.nStartPortNumber+j);
+                  
+                  if(flags & ILCLIENT_OUTPUT_ZERO_BUFFERS)
+                  {
+                     OMX_PARAM_PORTDEFINITIONTYPE portdef;
+                     portdef.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
+                     portdef.nVersion.nVersion = OMX_VERSION;
+                     portdef.nPortIndex = ports.nStartPortNumber+j;
+                     if(OMX_GetParameter((*comp)->comp, OMX_IndexParamPortDefinition, &portdef) == OMX_ErrorNone)
+                     {
+                        if(portdef.eDir == OMX_DirOutput && portdef.nBufferCountActual > 0)
+                        {
+                           portdef.nBufferCountActual = 0;
+                           OMX_SetParameter((*comp)->comp, OMX_IndexParamPortDefinition, &portdef);
+                        }
+                     }
+                  }
+               }
+            }
+         }
+      }
+      return 0;
+   }
+   else
+   {
+      vcos_event_flags_delete(&(*comp)->event);
+      vcos_semaphore_delete(&(*comp)->sema);
+      vcos_free(*comp);
+      *comp = NULL;
+      return -1;
+   }
+}
+
+/***********************************************************
+ * Name: ilclient_remove_event
+ *
+ * Description: Removes an event from a component event list.  ignore1
+ * and ignore2 are flags indicating whether to not match on nData1 and
+ * nData2 respectively.
+ *
+ * Returns: 0 if the event was removed.  -1 if no matching event was
+ * found.
+ ***********************************************************/
+int ilclient_remove_event(COMPONENT_T *st, OMX_EVENTTYPE eEvent,
+                          OMX_U32 nData1, int ignore1, OMX_IN OMX_U32 nData2, int ignore2)
+{
+   ILEVENT_T *cur, *prev;
+   uint32_t set;
+   ilclient_lock_events(st->client);
+
+   cur = st->list;
+   prev = NULL;
+
+   while (cur && !(cur->eEvent == eEvent && (ignore1 || cur->nData1 == nData1) && (ignore2 || cur->nData2 == nData2)))
+   {
+      prev = cur;
+      cur = cur->next;
+   }
+
+   if (cur == NULL)
+   {
+      ilclient_unlock_events(st->client);
+      return -1;
+   }
+
+   if (prev == NULL)
+      st->list = cur->next;
+   else
+      prev->next = cur->next;
+
+   // add back into spare list
+   cur->next = st->client->event_list;
+   st->client->event_list = cur;
+   cur->eEvent = -1; // mark as unused
+
+   // if we're removing an OMX_EventError or OMX_EventParamOrConfigChanged event, then clear the error bit from the eventgroup,
+   // since the user might have been notified through the error callback, and then 
+   // can't clear the event bit - this will then cause problems the next time they
+   // wait for an error.
+   if(eEvent == OMX_EventError)
+      vcos_event_flags_get(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR_CONSUME, 0, &set);
+   else if(eEvent == OMX_EventParamOrConfigChanged)
+      vcos_event_flags_get(&st->event, ILCLIENT_CONFIG_CHANGED, VCOS_OR_CONSUME, 0, &set);
+
+   ilclient_unlock_events(st->client);
+   return 0;
+}
+
+/***********************************************************
+ * Name: ilclient_state_transition
+ *
+ * Description: Transitions a null terminated list of IL components to
+ * a given state.  All components are told to transition in a random
+ * order before any are checked for transition completion.
+ *
+ * Returns: void
+ ***********************************************************/
+void ilclient_state_transition(COMPONENT_T *list[], OMX_STATETYPE state)
+{
+   OMX_ERRORTYPE error;
+   int i, num;
+   uint32_t set;
+
+   num=0;
+   while (list[num])
+      num++;
+
+   // if we transition the supplier port first, it will call freebuffer on the non
+   // supplier, which will correctly signal a port unpopulated error.  We want to
+   // ignore these errors.
+   if (state == OMX_StateLoaded)
+      for (i=0; i<num; i++)
+         list[i]->error_mask |= ILCLIENT_ERROR_UNPOPULATED;
+   for (i=0; i<num; i++)
+      list[i]->private = ((rand() >> 13) & 0xff)+1;
+
+   for (i=0; i<num; i++)
+   {
+      // transition the components in a random order
+      int j, min = -1;
+      for (j=0; j<num; j++)
+         if (list[j]->private && (min == -1 || list[min]->private > list[j]->private))
+            min = j;
+
+      list[min]->private = 0;
+
+      random_wait();
+      //Clear error event for this component
+      vcos_event_flags_get(&list[min]->event, ILCLIENT_EVENT_ERROR, VCOS_OR_CONSUME, 0, &set);
+
+      error = OMX_SendCommand(list[min]->comp, OMX_CommandStateSet, state, NULL);
+      vc_assert(error == OMX_ErrorNone);
+   }
+
+   random_wait();
+
+   for (i=0; i<num; i++)
+      if(ilclient_wait_for_command_complete(list[i], OMX_CommandStateSet, state) < 0)
+         vc_assert(0);
+
+   if (state == OMX_StateLoaded)
+      for (i=0; i<num; i++)
+         list[i]->error_mask &= ~ILCLIENT_ERROR_UNPOPULATED;
+}
+
+/***********************************************************
+ * Name: ilclient_teardown_tunnels
+ *
+ * Description: tears down a null terminated list of tunnels.
+ *
+ * Returns: void
+ ***********************************************************/
+void ilclient_teardown_tunnels(TUNNEL_T *tunnel)
+{
+   int i;
+   OMX_ERRORTYPE error;
+
+   i=0;;
+   while (tunnel[i].source)
+   {
+      error = OMX_SetupTunnel(tunnel[i].source->comp, tunnel[i].source_port, NULL, 0);
+      vc_assert(error == OMX_ErrorNone);
+
+      error = OMX_SetupTunnel(tunnel[i].sink->comp, tunnel[i].sink_port, NULL, 0);
+      vc_assert(error == OMX_ErrorNone);
+      i++;
+   }
+}
+
+/***********************************************************
+ * Name: ilclient_disable_tunnel
+ *
+ * Description: disables a tunnel by disabling the ports.  Allows
+ * ports to signal same state error if they were already disabled.
+ *
+ * Returns: void
+ ***********************************************************/
+void ilclient_disable_tunnel(TUNNEL_T *tunnel)
+{
+   OMX_ERRORTYPE error;
+   
+   if(tunnel->source == 0 || tunnel->sink == 0)
+      return;
+
+   tunnel->source->error_mask |= ILCLIENT_ERROR_UNPOPULATED;
+   tunnel->sink->error_mask |= ILCLIENT_ERROR_UNPOPULATED;
+
+   error = OMX_SendCommand(tunnel->source->comp, OMX_CommandPortDisable, tunnel->source_port, NULL);
+   vc_assert(error == OMX_ErrorNone);
+
+   error = OMX_SendCommand(tunnel->sink->comp, OMX_CommandPortDisable, tunnel->sink_port, NULL);
+   vc_assert(error == OMX_ErrorNone);
+
+   if(ilclient_wait_for_command_complete(tunnel->source, OMX_CommandPortDisable, tunnel->source_port) < 0)
+      vc_assert(0);
+
+   if(ilclient_wait_for_command_complete(tunnel->sink, OMX_CommandPortDisable, tunnel->sink_port) < 0)
+      vc_assert(0);
+
+   tunnel->source->error_mask &= ~ILCLIENT_ERROR_UNPOPULATED;
+   tunnel->sink->error_mask &= ~ILCLIENT_ERROR_UNPOPULATED;
+}
+
+/***********************************************************
+ * Name: ilclient_enable_tunnel
+ *
+ * Description: enables a tunnel by enabling the ports
+ *
+ * Returns: 0 on success, -1 on failure
+ ***********************************************************/
+int ilclient_enable_tunnel(TUNNEL_T *tunnel)
+{
+   OMX_STATETYPE state;
+   OMX_ERRORTYPE error;
+
+   ilclient_debug_output("ilclient: enable tunnel from %x/%d to %x/%d",
+                         tunnel->source, tunnel->source_port,
+                         tunnel->sink, tunnel->sink_port);
+
+   error = OMX_SendCommand(tunnel->source->comp, OMX_CommandPortEnable, tunnel->source_port, NULL);
+   vc_assert(error == OMX_ErrorNone);
+
+   error = OMX_SendCommand(tunnel->sink->comp, OMX_CommandPortEnable, tunnel->sink_port, NULL);
+   vc_assert(error == OMX_ErrorNone);
+
+   // to complete, the sink component can't be in loaded state
+   error = OMX_GetState(tunnel->sink->comp, &state);
+   vc_assert(error == OMX_ErrorNone);
+   if (state == OMX_StateLoaded)
+   {
+      int ret = 0;
+
+      if(ilclient_wait_for_command_complete(tunnel->sink, OMX_CommandPortEnable, tunnel->sink_port) != 0 ||
+         OMX_SendCommand(tunnel->sink->comp, OMX_CommandStateSet, OMX_StateIdle, NULL) != OMX_ErrorNone ||
+         (ret = ilclient_wait_for_command_complete_dual(tunnel->sink, OMX_CommandStateSet, OMX_StateIdle, tunnel->source)) < 0)
+      {
+         if(ret == -2)
+         {
+            // the error was reported fom the source component: clear this error and disable the sink component
+            ilclient_wait_for_command_complete(tunnel->source, OMX_CommandPortEnable, tunnel->source_port);
+            ilclient_disable_port(tunnel->sink, tunnel->sink_port);
+         }
+
+         ilclient_debug_output("ilclient: could not change component state to IDLE");
+         ilclient_disable_port(tunnel->source, tunnel->source_port);
+         return -1;
+      }
+   }
+   else
+   {
+      if (ilclient_wait_for_command_complete(tunnel->sink, OMX_CommandPortEnable, tunnel->sink_port) != 0)
+      {
+         ilclient_debug_output("ilclient: could not change sink port %d to enabled", tunnel->sink_port);
+
+         //Oops failed to enable the sink port
+         ilclient_disable_port(tunnel->source, tunnel->source_port);
+         //Clean up the port enable event from the source port.
+         ilclient_wait_for_event(tunnel->source, OMX_EventCmdComplete,
+                                 OMX_CommandPortEnable, 0, tunnel->source_port, 0,
+                                 ILCLIENT_PORT_ENABLED | ILCLIENT_EVENT_ERROR, VCOS_EVENT_FLAGS_SUSPEND);
+         return -1;
+      }
+   }
+
+   if(ilclient_wait_for_command_complete(tunnel->source, OMX_CommandPortEnable, tunnel->source_port) != 0)
+   {
+      ilclient_debug_output("ilclient: could not change source port %d to enabled", tunnel->source_port);
+
+      //Failed to enable the source port
+      ilclient_disable_port(tunnel->sink, tunnel->sink_port);
+      return -1;
+   }
+
+   return 0;
+}
+
+
+/***********************************************************
+ * Name: ilclient_flush_tunnels
+ *
+ * Description: flushes all ports used in a null terminated list of
+ * tunnels.  max specifies the maximum number of tunnels to flush from
+ * the list, where max=0 means all tunnels.
+ *
+ * Returns: void
+ ***********************************************************/
+void ilclient_flush_tunnels(TUNNEL_T *tunnel, int max)
+{
+   OMX_ERRORTYPE error;
+   int i;
+
+   i=0;
+   while (tunnel[i].source && (max == 0 || i < max))
+   {
+      error = OMX_SendCommand(tunnel[i].source->comp, OMX_CommandFlush, tunnel[i].source_port, NULL);
+      vc_assert(error == OMX_ErrorNone);
+
+      error = OMX_SendCommand(tunnel[i].sink->comp, OMX_CommandFlush, tunnel[i].sink_port, NULL);
+      vc_assert(error == OMX_ErrorNone);
+
+      ilclient_wait_for_event(tunnel[i].source, OMX_EventCmdComplete,
+                              OMX_CommandFlush, 0, tunnel[i].source_port, 0,
+                              ILCLIENT_PORT_FLUSH, VCOS_EVENT_FLAGS_SUSPEND);
+      ilclient_wait_for_event(tunnel[i].sink, OMX_EventCmdComplete,
+                              OMX_CommandFlush, 0, tunnel[i].sink_port, 0,
+                              ILCLIENT_PORT_FLUSH, VCOS_EVENT_FLAGS_SUSPEND);
+      i++;
+   }
+}
+
+
+/***********************************************************
+ * Name: ilclient_return_events
+ *
+ * Description: Returns all events from a component event list to the
+ * list of unused event structures.
+ *
+ * Returns: void
+ ***********************************************************/
+void ilclient_return_events(COMPONENT_T *comp)
+{
+   ilclient_lock_events(comp->client);
+   while (comp->list)
+   {
+      ILEVENT_T *next = comp->list->next;
+      comp->list->next = comp->client->event_list;
+      comp->client->event_list = comp->list;
+      comp->list = next;
+   }
+   ilclient_unlock_events(comp->client);
+}
+
+/***********************************************************
+ * Name: ilclient_cleanup_components
+ *
+ * Description: frees all components from a null terminated list and
+ * deletes resources used in component state structure.
+ *
+ * Returns: void
+ ***********************************************************/
+void ilclient_cleanup_components(COMPONENT_T *list[])
+{
+   int i;
+   OMX_ERRORTYPE error;
+
+   i=0;
+   while (list[i])
+   {
+      ilclient_return_events(list[i]);
+      if (list[i]->comp)
+      {
+         error = OMX_FreeHandle(list[i]->comp);
+
+         vc_assert(error == OMX_ErrorNone);
+      }
+      i++;
+   }
+
+   i=0;
+   while (list[i])
+   {
+      vcos_event_flags_delete(&list[i]->event);
+      vcos_semaphore_delete(&list[i]->sema);
+      vcos_free(list[i]);
+      list[i] = NULL;
+      i++;
+   }
+}
+
+/***********************************************************
+ * Name: ilclient_change_component_state
+ *
+ * Description: changes the state of a single component.  Note: this
+ * may not be suitable if the component is tunnelled and requires
+ * connected components to also change state.
+ *
+ * Returns: 0 on success, -1 on failure (note - trying to change to
+ * the same state which causes a OMX_ErrorSameState is treated as
+ * success)
+ ***********************************************************/
+int ilclient_change_component_state(COMPONENT_T *comp, OMX_STATETYPE state)
+{
+   OMX_ERRORTYPE error;
+   error = OMX_SendCommand(comp->comp, OMX_CommandStateSet, state, NULL);
+   vc_assert(error == OMX_ErrorNone);
+   if(ilclient_wait_for_command_complete(comp, OMX_CommandStateSet, state) < 0)
+   {
+      ilclient_debug_output("ilclient: could not change component state to %d", state);
+      ilclient_remove_event(comp, OMX_EventError, 0, 1, 0, 1);
+      return -1;
+   }
+   return 0;
+}
+
+/***********************************************************
+ * Name: ilclient_disable_port
+ *
+ * Description: disables a port on a given component.
+ *
+ * Returns: void
+ ***********************************************************/
+void ilclient_disable_port(COMPONENT_T *comp, int portIndex)
+{
+   OMX_ERRORTYPE error;
+   error = OMX_SendCommand(comp->comp, OMX_CommandPortDisable, portIndex, NULL);
+   vc_assert(error == OMX_ErrorNone);
+   if(ilclient_wait_for_command_complete(comp, OMX_CommandPortDisable, portIndex) < 0)
+      vc_assert(0);
+}
+
+/***********************************************************
+ * Name: ilclient_enabled_port
+ *
+ * Description: enables a port on a given component.
+ *
+ * Returns: void
+ ***********************************************************/
+void ilclient_enable_port(COMPONENT_T *comp, int portIndex)
+{
+   OMX_ERRORTYPE error;
+   error = OMX_SendCommand(comp->comp, OMX_CommandPortEnable, portIndex, NULL);
+   vc_assert(error == OMX_ErrorNone);
+   if(ilclient_wait_for_command_complete(comp, OMX_CommandPortEnable, portIndex) < 0)
+      vc_assert(0);
+}
+
+
+/***********************************************************
+ * Name: ilclient_enable_port_buffers
+ *
+ * Description: enables a port on a given component which requires
+ * buffers to be supplied by the client.
+ *
+ * Returns: void
+ ***********************************************************/
+int ilclient_enable_port_buffers(COMPONENT_T *comp, int portIndex,
+                                 ILCLIENT_MALLOC_T ilclient_malloc,
+                                 ILCLIENT_FREE_T ilclient_free,
+                                 void *private)
+{
+   OMX_ERRORTYPE error;
+   OMX_PARAM_PORTDEFINITIONTYPE portdef;
+   OMX_BUFFERHEADERTYPE *list = NULL, **end = &list;
+   OMX_STATETYPE state;
+   int i;
+
+   memset(&portdef, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+   portdef.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
+   portdef.nVersion.nVersion = OMX_VERSION;
+   portdef.nPortIndex = portIndex;
+   
+   // work out buffer requirements, check port is in the right state
+   error = OMX_GetParameter(comp->comp, OMX_IndexParamPortDefinition, &portdef);
+   if(error != OMX_ErrorNone || portdef.bEnabled != OMX_FALSE || portdef.nBufferCountActual == 0 || portdef.nBufferSize == 0)
+      return -1;
+
+   // check component is in the right state to accept buffers
+   error = OMX_GetState(comp->comp, &state);
+   if (error != OMX_ErrorNone || !(state == OMX_StateIdle || state == OMX_StateExecuting || state == OMX_StatePause))
+      return -1;
+
+   // send the command
+   error = OMX_SendCommand(comp->comp, OMX_CommandPortEnable, portIndex, NULL);
+   vc_assert(error == OMX_ErrorNone);
+
+   for (i=0; i != portdef.nBufferCountActual; i++)
+   {
+      unsigned char *buf;
+      if(ilclient_malloc)
+         buf = ilclient_malloc(private, portdef.nBufferSize, portdef.nBufferAlignment, comp->bufname);
+      else
+         buf = vcos_malloc_aligned(portdef.nBufferSize, portdef.nBufferAlignment, comp->bufname);
+
+      if(!buf)
+         break;
+
+      error = OMX_UseBuffer(comp->comp, end, portIndex, NULL, portdef.nBufferSize, buf);
+      if(error != OMX_ErrorNone)
+      {
+         if(ilclient_free)
+            ilclient_free(private, buf);
+         else
+            vcos_free(buf);
+
+         break;
+      }
+      end = (OMX_BUFFERHEADERTYPE **) &((*end)->pAppPrivate);
+   }
+
+   // queue these buffers
+   vcos_semaphore_wait(&comp->sema);
+
+   if(portdef.eDir == OMX_DirInput)
+   {
+      *end = comp->in_list;
+      comp->in_list = list;
+   }
+   else
+   {
+      *end = comp->out_list;
+      comp->out_list = list;
+   }
+
+   vcos_semaphore_post(&comp->sema);
+
+   if(i != portdef.nBufferCountActual ||
+      ilclient_wait_for_command_complete(comp, OMX_CommandPortEnable, portIndex) < 0)
+   {
+      ilclient_disable_port_buffers(comp, portIndex, NULL, ilclient_free, private);
+
+      // at this point the first command might have terminated with an error, which means that
+      // the port is disabled before the disable_port_buffers function is called, so we're left
+      // with the error bit set and an error event in the queue.  Clear these now if they exist.
+      ilclient_remove_event(comp, OMX_EventError, 0, 1, 1, 0);
+
+      return -1;
+   }
+
+   // success
+   return 0;
+}
+
+
+/***********************************************************
+ * Name: ilclient_disable_port_buffers
+ *
+ * Description: disables a port on a given component which has
+ * buffers supplied by the client.
+ *
+ * Returns: void
+ ***********************************************************/
+void ilclient_disable_port_buffers(COMPONENT_T *comp, int portIndex,
+                                   OMX_BUFFERHEADERTYPE *bufferList,
+                                   ILCLIENT_FREE_T ilclient_free,
+                                   void *private)
+{
+   OMX_ERRORTYPE error;
+   OMX_BUFFERHEADERTYPE *list = bufferList;
+   OMX_BUFFERHEADERTYPE **head, *clist, *prev;
+   OMX_PARAM_PORTDEFINITIONTYPE portdef;
+   int num;
+
+   // get the buffers off the relevant queue
+   memset(&portdef, 0, sizeof(OMX_PARAM_PORTDEFINITIONTYPE));
+   portdef.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
+   portdef.nVersion.nVersion = OMX_VERSION;
+   portdef.nPortIndex = portIndex;
+   
+   // work out buffer requirements, check port is in the right state
+   error = OMX_GetParameter(comp->comp, OMX_IndexParamPortDefinition, &portdef);
+   if(error != OMX_ErrorNone || portdef.bEnabled != OMX_TRUE || portdef.nBufferCountActual == 0 || portdef.nBufferSize == 0)
+      return;
+   
+   num = portdef.nBufferCountActual;
+   
+   error = OMX_SendCommand(comp->comp, OMX_CommandPortDisable, portIndex, NULL);
+   vc_assert(error == OMX_ErrorNone);
+      
+   while(num > 0)
+   {
+      VCOS_UNSIGNED set;
+
+      if(list == NULL)
+      {
+         vcos_semaphore_wait(&comp->sema);
+         
+         // take buffers for this port off the relevant queue
+         head = portdef.eDir == OMX_DirInput ? &comp->in_list : &comp->out_list;
+         clist = *head;
+         prev = NULL;
+         
+         while(clist)
+         {
+            if((portdef.eDir == OMX_DirInput ? clist->nInputPortIndex : clist->nOutputPortIndex) == portIndex)
+            {
+               OMX_BUFFERHEADERTYPE *pBuffer = clist;
+               
+               if(!prev)
+                  clist = *head = (OMX_BUFFERHEADERTYPE *) pBuffer->pAppPrivate;
+               else
+                  clist = prev->pAppPrivate = (OMX_BUFFERHEADERTYPE *) pBuffer->pAppPrivate;
+               
+               pBuffer->pAppPrivate = list;
+               list = pBuffer;
+            }
+            else
+            {
+               prev = clist;
+               clist = (OMX_BUFFERHEADERTYPE *) &(clist->pAppPrivate);
+            }
+         }
+         
+         vcos_semaphore_post(&comp->sema);
+      }
+
+      while(list)
+      {
+         void *buf = list->pBuffer;
+         OMX_BUFFERHEADERTYPE *next = list->pAppPrivate;
+         
+         error = OMX_FreeBuffer(comp->comp, portIndex, list);
+         vc_assert(error == OMX_ErrorNone);
+         
+         if(ilclient_free)
+            ilclient_free(private, buf);
+         else
+            vcos_free(buf);
+         
+         num--;
+         list = next;
+      }
+
+      if(num)
+      {
+         OMX_U32 mask = ILCLIENT_PORT_DISABLED | ILCLIENT_EVENT_ERROR;
+         mask |= (portdef.eDir == OMX_DirInput ? ILCLIENT_EMPTY_BUFFER_DONE : ILCLIENT_FILL_BUFFER_DONE);
+
+         // also wait for command complete/error in case we didn't have all the buffers allocated
+         vcos_event_flags_get(&comp->event, mask, VCOS_OR_CONSUME, -1, &set);
+
+         if((set & ILCLIENT_EVENT_ERROR) && ilclient_remove_event(comp, OMX_EventError, 0, 1, 1, 0) >= 0)
+            return;
+
+         if((set & ILCLIENT_PORT_DISABLED) && ilclient_remove_event(comp, OMX_EventCmdComplete, OMX_CommandPortDisable, 0, portIndex, 0) >= 0)
+            return;
+      }            
+   }
+  
+   if(ilclient_wait_for_command_complete(comp, OMX_CommandPortDisable, portIndex) < 0)
+      vc_assert(0);
+}
+
+
+/***********************************************************
+ * Name: ilclient_setup_tunnel
+ *
+ * Description: creates a tunnel between components that require that
+ * ports be inititially disabled, then enabled after tunnel setup.  If
+ * timeout is non-zero, it will initially wait until a port settings
+ * changes message has been received by the output port.  If port
+ * streams are supported by the output port, the requested port stream
+ * will be selected.
+ *
+ * Returns: 0 indicates success, negative indicates failure.
+ * -1: a timeout waiting for the parameter changed
+ * -2: an error was returned instead of parameter changed
+ * -3: no streams are available from this port
+ * -4: requested stream is not available from this port
+ * -5: the data format was not acceptable to the sink
+ ***********************************************************/
+int ilclient_setup_tunnel(TUNNEL_T *tunnel, unsigned int portStream, int timeout)
+{
+   OMX_ERRORTYPE error;
+   OMX_PARAM_U32TYPE param;
+   OMX_STATETYPE state;
+   int32_t status;
+   int enable_error;
+
+   // source component must at least be idle, not loaded
+   error = OMX_GetState(tunnel->source->comp, &state);
+   vc_assert(error == OMX_ErrorNone);
+   if (state == OMX_StateLoaded && ilclient_change_component_state(tunnel->source, OMX_StateIdle) < 0)
+      return -2;
+
+   // wait for the port parameter changed from the source port
+   if(timeout)
+   {
+      status = ilclient_wait_for_event(tunnel->source, OMX_EventPortSettingsChanged,
+                                       tunnel->source_port, 0, -1, 1,
+                                       ILCLIENT_PARAMETER_CHANGED | ILCLIENT_EVENT_ERROR, timeout);
+      
+      if (status < 0)
+      {
+         ilclient_debug_output(
+            "ilclient: timed out waiting for port settings changed on port %d", tunnel->source_port);
+         return status;
+      }
+   }
+
+   // disable ports
+   ilclient_disable_tunnel(tunnel);
+
+   // if this source port uses port streams, we need to select one of them before proceeding
+   // if getparameter causes an error that's fine, nothing needs selecting
+   param.nSize = sizeof(OMX_PARAM_U32TYPE);
+   param.nVersion.nVersion = OMX_VERSION;
+   param.nPortIndex = tunnel->source_port;
+   if (OMX_GetParameter(tunnel->source->comp, OMX_IndexParamNumAvailableStreams, &param) == OMX_ErrorNone)
+   {
+      if (param.nU32 == 0)
+      {
+         // no streams available
+         // leave the source port disabled, and return a failure
+         return -3;
+      }
+      if (param.nU32 <= portStream)
+      {
+         // requested stream not available
+         // no streams available
+         // leave the source port disabled, and return a failure
+         return -4;
+      }
+
+      param.nU32 = portStream;
+      error = OMX_SetParameter(tunnel->source->comp, OMX_IndexParamActiveStream, &param);
+      vc_assert(error == OMX_ErrorNone);
+   }
+
+   // now create the tunnel
+   error = OMX_SetupTunnel(tunnel->source->comp, tunnel->source_port, tunnel->sink->comp, tunnel->sink_port);
+
+   enable_error = 0;
+
+   if (error != OMX_ErrorNone || (enable_error=ilclient_enable_tunnel(tunnel)) < 0)
+   {
+      // probably format not compatible
+      error = OMX_SetupTunnel(tunnel->source->comp, tunnel->source_port, NULL, 0);
+      vc_assert(error == OMX_ErrorNone);
+      error = OMX_SetupTunnel(tunnel->sink->comp, tunnel->sink_port, NULL, 0);
+      vc_assert(error == OMX_ErrorNone);
+      
+      if(enable_error)
+      {
+         //Clean up the errors. This does risk removing an error that was nothing to do with this tunnel :-/
+         ilclient_remove_event(tunnel->sink, OMX_EventError, 0, 1, 0, 1);
+         ilclient_remove_event(tunnel->source, OMX_EventError, 0, 1, 0, 1);
+      }
+
+      ilclient_debug_output("ilclient: could not setup/enable tunnel (setup=0x%x,enable=%d)",
+                             error, enable_error);
+      return -5;
+   }
+
+   return 0;
+}
+
+/***********************************************************
+ * Name: ilclient_wait_for_event
+ *
+ * Description: waits for a given event to appear on a component event
+ * list.  If not immediately present, will wait on that components
+ * event group for the given event flag.
+ *
+ * Returns: 0 indicates success, negative indicates failure.
+ * -1: a timeout was received.
+ * -2: an error event was received.
+ * -3: a config change event was received.
+ ***********************************************************/
+int ilclient_wait_for_event(COMPONENT_T *comp, OMX_EVENTTYPE event,
+                            OMX_U32 nData1, int ignore1, OMX_IN OMX_U32 nData2, int ignore2,
+                            int event_flag, int suspend)
+{
+   int32_t status;
+   uint32_t set;
+
+   while (ilclient_remove_event(comp, event, nData1, ignore1, nData2, ignore2) < 0)
+   {
+      // if we want to be notified of errors, check the list for an error now
+      // before blocking, the event flag may have been cleared already.
+      if(event_flag & ILCLIENT_EVENT_ERROR)
+      {
+         ILEVENT_T *cur;
+         ilclient_lock_events(comp->client);
+         cur = comp->list;
+         while(cur && cur->eEvent != OMX_EventError)            
+            cur = cur->next;
+         
+         if(cur)
+         {
+            // clear error flag
+            vcos_event_flags_get(&comp->event, ILCLIENT_EVENT_ERROR, VCOS_OR_CONSUME, 0, &set);
+            ilclient_unlock_events(comp->client);
+            return -2;
+         }
+
+         ilclient_unlock_events(comp->client);
+      }
+      // check for config change event if we are asked to be notified of that
+      if(event_flag & ILCLIENT_CONFIG_CHANGED)
+      {
+         ILEVENT_T *cur;
+         ilclient_lock_events(comp->client);
+         cur = comp->list;
+         while(cur && cur->eEvent != OMX_EventParamOrConfigChanged)
+            cur = cur->next;
+         
+         ilclient_unlock_events(comp->client);
+
+         if(cur)
+            return ilclient_remove_event(comp, event, nData1, ignore1, nData2, ignore2) == 0 ? 0 : -3;
+      }
+
+      status = vcos_event_flags_get(&comp->event, event_flag, VCOS_OR_CONSUME, 
+                                    suspend, &set);
+      if (status != 0)
+         return -1;
+      if (set & ILCLIENT_EVENT_ERROR)
+         return -2;
+      if (set & ILCLIENT_CONFIG_CHANGED)
+         return ilclient_remove_event(comp, event, nData1, ignore1, nData2, ignore2) == 0 ? 0 : -3;
+   }
+
+   return 0;
+}
+
+
+
+/***********************************************************
+ * Name: ilclient_wait_for_command_complete_dual
+ *
+ * Description: Waits for an event signalling command completion.  In
+ * this version we may also return failure if there is an error event
+ * that has terminated a command on a second component.
+ *
+ * Returns: 0 on success, -1 on failure of comp, -2 on failure of other
+ ***********************************************************/
+int ilclient_wait_for_command_complete_dual(COMPONENT_T *comp, OMX_COMMANDTYPE command, OMX_U32 nData2, COMPONENT_T *other)
+{
+   OMX_U32 mask = ILCLIENT_EVENT_ERROR;
+   int ret = 0;
+
+   switch(command) {
+   case OMX_CommandStateSet:    mask |= ILCLIENT_STATE_CHANGED; break;
+   case OMX_CommandPortDisable: mask |= ILCLIENT_PORT_DISABLED; break;
+   case OMX_CommandPortEnable:  mask |= ILCLIENT_PORT_ENABLED;  break;
+   default: return -1;
+   }
+
+   if(other)
+      other->related = comp;
+
+   while(1)
+   {
+      ILEVENT_T *cur, *prev = NULL;
+      VCOS_UNSIGNED set;
+
+      ilclient_lock_events(comp->client);
+
+      cur = comp->list;
+      while(cur &&
+            !(cur->eEvent == OMX_EventCmdComplete && cur->nData1 == command && cur->nData2 == nData2) &&
+            !(cur->eEvent == OMX_EventError && cur->nData2 == 1))
+      {
+         prev = cur;
+         cur = cur->next;
+      }
+
+      if(cur)
+      {
+         if(prev == NULL)
+            comp->list = cur->next;
+         else
+            prev->next = cur->next;
+
+         // work out whether this was a success or a fail event
+         ret = cur->eEvent == OMX_EventCmdComplete || cur->nData1 == OMX_ErrorSameState ? 0 : -1;
+
+         if(cur->eEvent == OMX_EventError)
+            vcos_event_flags_get(&comp->event, ILCLIENT_EVENT_ERROR, VCOS_OR_CONSUME, 0, &set);
+
+         // add back into spare list
+         cur->next = comp->client->event_list;
+         comp->client->event_list = cur;
+         cur->eEvent = -1; // mark as unused
+         
+         ilclient_unlock_events(comp->client);
+         break;
+      }
+      else if(other != NULL)
+      {
+         // check the other component for an error event that terminates a command
+         cur = other->list;
+         while(cur && !(cur->eEvent == OMX_EventError && cur->nData2 == 1))
+            cur = cur->next;
+
+         if(cur)
+         {
+            // we don't remove the event in this case, since the user
+            // can confirm that this event errored by calling wait_for_command on the
+            // other component
+
+            ret = -2;
+            ilclient_unlock_events(comp->client);
+            break;
+         }
+      }
+
+      ilclient_unlock_events(comp->client);
+
+      vcos_event_flags_get(&comp->event, mask, VCOS_OR_CONSUME, VCOS_SUSPEND, &set);
+   }
+
+   if(other)
+      other->related = NULL;
+
+   return ret;
+}
+
+
+/***********************************************************
+ * Name: ilclient_wait_for_command_complete
+ *
+ * Description: Waits for an event signalling command completion.
+ *
+ * Returns: 0 on success, -1 on failure.
+ ***********************************************************/
+int ilclient_wait_for_command_complete(COMPONENT_T *comp, OMX_COMMANDTYPE command, OMX_U32 nData2)
+{
+   return ilclient_wait_for_command_complete_dual(comp, command, nData2, NULL);
+}
+
+/***********************************************************
+ * Name: ilclient_get_output_buffer
+ *
+ * Description: Returns an output buffer returned from a component
+ * using the OMX_FillBufferDone callback from the output list for the
+ * given component and port index.
+ *
+ * Returns: pointer to buffer if available, otherwise NULL
+ ***********************************************************/
+OMX_BUFFERHEADERTYPE *ilclient_get_output_buffer(COMPONENT_T *comp, int portIndex, int block)
+{
+   OMX_BUFFERHEADERTYPE *ret = NULL, *prev = NULL;
+   VCOS_UNSIGNED set;
+
+   do {
+      vcos_semaphore_wait(&comp->sema);
+      ret = comp->out_list;
+      while(ret != NULL && ret->nOutputPortIndex != portIndex)
+      {
+         prev = ret;
+         ret = ret->pAppPrivate;
+      }
+      
+      if(ret)
+      {
+         if(prev == NULL)
+            comp->out_list = ret->pAppPrivate;
+         else
+            prev->pAppPrivate = ret->pAppPrivate;
+         
+         ret->pAppPrivate = NULL;
+      }
+      vcos_semaphore_post(&comp->sema);
+
+      if(block && !ret)
+         vcos_event_flags_get(&comp->event, ILCLIENT_FILL_BUFFER_DONE, VCOS_OR_CONSUME, -1, &set);
+
+   } while(block && !ret);
+
+   return ret;
+}
+
+/***********************************************************
+ * Name: ilclient_get_input_buffer
+ *
+ * Description: Returns an input buffer return from a component using
+ * the OMX_EmptyBufferDone callback from the output list for the given
+ * component and port index.
+ *
+ * Returns: pointer to buffer if available, otherwise NULL
+ ***********************************************************/
+OMX_BUFFERHEADERTYPE *ilclient_get_input_buffer(COMPONENT_T *comp, int portIndex, int block)
+{
+   OMX_BUFFERHEADERTYPE *ret = NULL, *prev = NULL;
+
+   do {
+      VCOS_UNSIGNED set;
+
+      vcos_semaphore_wait(&comp->sema);
+      ret = comp->in_list;
+      while(ret != NULL && ret->nInputPortIndex != portIndex)
+      {
+         prev = ret;
+         ret = ret->pAppPrivate;
+      }
+      
+      if(ret)
+      {
+         if(prev == NULL)
+            comp->in_list = ret->pAppPrivate;
+         else
+            prev->pAppPrivate = ret->pAppPrivate;
+         
+         ret->pAppPrivate = NULL;
+      }
+      vcos_semaphore_post(&comp->sema);
+
+      if(block && !ret)
+         vcos_event_flags_get(&comp->event, ILCLIENT_EMPTY_BUFFER_DONE, VCOS_OR_CONSUME, -1, &set);
+
+   } while(block && !ret);
+
+   return ret;
+}
+
+/***********************************************************
+ * Name: ilclient_debug_output
+ *
+ * Description: prints a varg message to the log or the debug screen
+ * under win32
+ *
+ * Returns: void
+ ***********************************************************/
+void ilclient_debug_output(char *format, ...)
+{
+   va_list args;
+
+   va_start(args, format);
+   vcos_vlog_info(format, args);
+   va_end(args);
+}
+
+/******************************************************************************
+Static functions
+******************************************************************************/
+
+/***********************************************************
+ * Name: ilclient_lock_events
+ *
+ * Description: locks the client event structure
+ *
+ * Returns: void
+ ***********************************************************/
+static void ilclient_lock_events(ILCLIENT_T *st)
+{
+   vcos_semaphore_wait(&st->event_sema);
+}
+
+/***********************************************************
+ * Name: ilclient_unlock_events
+ *
+ * Description: unlocks the client event structure
+ *
+ * Returns: void
+ ***********************************************************/
+static void ilclient_unlock_events(ILCLIENT_T *st)
+{
+   vcos_semaphore_post(&st->event_sema);
+}
+
+/***********************************************************
+ * Name: ilclient_event_handler
+ *
+ * Description: event handler passed to core to use as component
+ * callback
+ *
+ * Returns: success
+ ***********************************************************/
+static OMX_ERRORTYPE ilclient_event_handler(OMX_IN OMX_HANDLETYPE hComponent,
+                                            OMX_IN OMX_PTR pAppData,
+                                            OMX_IN OMX_EVENTTYPE eEvent,
+                                            OMX_IN OMX_U32 nData1,
+                                            OMX_IN OMX_U32 nData2,
+                                            OMX_IN OMX_PTR pEventData)
+{
+   COMPONENT_T *st = (COMPONENT_T *) pAppData;
+   ILEVENT_T *event;
+   OMX_ERRORTYPE error = OMX_ErrorNone;
+
+   ilclient_lock_events(st->client);
+
+   // go through the events on this component and remove any duplicates in the
+   // existing list, since the client probably doesn't need them.  it's better
+   // than asserting when we run out.
+   event = st->list;
+   while(event != NULL)
+   {
+      ILEVENT_T **list = &(event->next);
+      while(*list != NULL)
+      {
+         if((*list)->eEvent == event->eEvent &&
+            (*list)->nData1 == event->nData1 &&
+            (*list)->nData2 == event->nData2)
+         {
+            // remove this duplicate
+            ILEVENT_T *rem = *list;
+            ilclient_debug_output("%s: removing %d/%d/%d", st->name, event->eEvent, event->nData1, event->nData2);            
+            *list = rem->next;
+            rem->eEvent = -1;
+            rem->next = st->client->event_list;
+            st->client->event_list = rem;
+         }
+         else
+            list = &((*list)->next);
+      }
+
+      event = event->next;
+   }
+
+   vc_assert(st->client->event_list);
+   event = st->client->event_list;
+
+   switch (eEvent) {
+   case OMX_EventCmdComplete:
+      switch (nData1) {
+      case OMX_CommandStateSet:
+         ilclient_debug_output("%s: callback state changed (%s)", st->name, states[nData2]);
+         vcos_event_flags_set(&st->event, ILCLIENT_STATE_CHANGED, VCOS_OR);
+         break;
+      case OMX_CommandPortDisable:
+         ilclient_debug_output("%s: callback port disable %d", st->name, nData2);
+         vcos_event_flags_set(&st->event, ILCLIENT_PORT_DISABLED, VCOS_OR);
+         break;
+      case OMX_CommandPortEnable:
+         ilclient_debug_output("%s: callback port enable %d", st->name, nData2);
+         vcos_event_flags_set(&st->event, ILCLIENT_PORT_ENABLED, VCOS_OR);
+         break;
+      case OMX_CommandFlush:
+         ilclient_debug_output("%s: callback port flush %d", st->name, nData2);
+         vcos_event_flags_set(&st->event, ILCLIENT_PORT_FLUSH, VCOS_OR);
+         break;
+      case OMX_CommandMarkBuffer:
+         ilclient_debug_output("%s: callback mark buffer %d", st->name, nData2);
+         vcos_event_flags_set(&st->event, ILCLIENT_MARKED_BUFFER, VCOS_OR);
+         break;
+      default:
+         vc_assert(0);
+      }
+      break;
+   case OMX_EventError:
+      {
+         // check if this component failed a command, and we have to notify another command
+         // of this failure
+         if(nData2 == 1 && st->related != NULL)
+            vcos_event_flags_set(&st->related->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
+
+         error = nData1;
+         switch (error) {
+         case OMX_ErrorPortUnpopulated:
+            if (st->error_mask & ILCLIENT_ERROR_UNPOPULATED)
+            {
+               ilclient_debug_output("%s: ignore error: port unpopulated (%d)", st->name, nData2);
+               event = NULL;
+               break;
+            }
+            ilclient_debug_output("%s: port unpopulated %x (%d)", st->name, error, nData2);
+            vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
+            break;
+         case OMX_ErrorSameState:
+            if (st->error_mask & ILCLIENT_ERROR_SAMESTATE)
+            {
+               ilclient_debug_output("%s: ignore error: same state (%d)", st->name, nData2);
+               event = NULL;
+               break;
+            }
+            ilclient_debug_output("%s: same state %x (%d)", st->name, error, nData2);
+            vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
+            break;
+         case OMX_ErrorBadParameter:
+            if (st->error_mask & ILCLIENT_ERROR_BADPARAMETER)
+            {
+               ilclient_debug_output("%s: ignore error: bad parameter (%d)", st->name, nData2);
+               event = NULL;
+               break;
+            }
+            ilclient_debug_output("%s: bad parameter %x (%d)", st->name, error, nData2);
+            vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
+            break;
+         case OMX_ErrorIncorrectStateTransition:
+            ilclient_debug_output("%s: incorrect state transition %x (%d)", st->name, error, nData2);
+            vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
+            break;
+         case OMX_ErrorBadPortIndex:
+            ilclient_debug_output("%s: bad port index %x (%d)", st->name, error, nData2);
+            vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
+            break;
+         case OMX_ErrorStreamCorrupt:
+            ilclient_debug_output("%s: stream corrupt %x (%d)", st->name, error, nData2);
+            vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
+            break;
+         case OMX_ErrorInsufficientResources:
+            ilclient_debug_output("%s: insufficient resources %x (%d)", st->name, error, nData2);
+            vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
+            break;
+         case OMX_ErrorUnsupportedSetting:
+            ilclient_debug_output("%s: unsupported setting %x (%d)", st->name, error, nData2);
+            vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
+            break;
+         case OMX_ErrorOverflow:
+            ilclient_debug_output("%s: overflow %x (%d)", st->name, error, nData2);
+            vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
+            break;
+         case OMX_ErrorDiskFull:
+            ilclient_debug_output("%s: disk full %x (%d)", st->name, error, nData2);
+            //we do not set the error
+            break;
+         case OMX_ErrorMaxFileSize:
+            ilclient_debug_output("%s: max file size %x (%d)", st->name, error, nData2);
+            //we do not set the error
+            break;
+         case OMX_ErrorDrmUnauthorised:
+            ilclient_debug_output("%s: drm file is unauthorised %x (%d)", st->name, error, nData2);
+            vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
+            break;
+         case OMX_ErrorDrmExpired:
+            ilclient_debug_output("%s: drm file has expired %x (%d)", st->name, error, nData2);
+            vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
+            break;
+         case OMX_ErrorDrmGeneral:
+            ilclient_debug_output("%s: drm library error %x (%d)", st->name, error, nData2);
+            vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
+            break;
+         default:
+            vc_assert(0);
+            ilclient_debug_output("%s: unexpected error %x (%d)", st->name, error, nData2);
+            vcos_event_flags_set(&st->event, ILCLIENT_EVENT_ERROR, VCOS_OR);
+            break;
+         }
+      }
+      break;
+   case OMX_EventBufferFlag:
+      ilclient_debug_output("%s: buffer flag %d/%x", st->name, nData1, nData2);
+      if (nData2 & OMX_BUFFERFLAG_EOS)
+      {
+         vcos_event_flags_set(&st->event, ILCLIENT_BUFFER_FLAG_EOS, VCOS_OR);
+         nData2 = OMX_BUFFERFLAG_EOS;
+      }
+      else
+         vc_assert(0);
+      break;
+   case OMX_EventPortSettingsChanged:
+      ilclient_debug_output("%s: port settings changed %d", st->name, nData1);
+      vcos_event_flags_set(&st->event, ILCLIENT_PARAMETER_CHANGED, VCOS_OR);
+      break;
+   case OMX_EventMark:
+      ilclient_debug_output("%s: buffer mark %p", st->name, pEventData);
+      vcos_event_flags_set(&st->event, ILCLIENT_BUFFER_MARK, VCOS_OR);
+      break;
+   case OMX_EventParamOrConfigChanged:
+      ilclient_debug_output("%s: param/config 0x%X on port %d changed", st->name, nData2, nData1);
+      vcos_event_flags_set(&st->event, ILCLIENT_CONFIG_CHANGED, VCOS_OR);
+      break;
+   default:
+      vc_assert(0);
+      break;
+   }
+
+   if (event)
+   {
+      // fill in details
+      event->eEvent = eEvent;
+      event->nData1 = nData1;
+      event->nData2 = nData2;
+      event->pEventData = pEventData;
+
+      // remove from top of spare list
+      st->client->event_list = st->client->event_list->next;
+
+      // put at head of component event queue
+      event->next = st->list;
+      st->list = event;
+   }
+   ilclient_unlock_events(st->client);
+
+   // now call any callbacks without the event lock so the client can 
+   // remove the event in context
+   switch(eEvent) {
+   case OMX_EventError:
+      if(event && st->client->error_callback)
+         st->client->error_callback(st->client->error_callback_data, st, error);
+      break;
+   case OMX_EventBufferFlag:
+      if ((nData2 & OMX_BUFFERFLAG_EOS) && st->client->eos_callback)
+         st->client->eos_callback(st->client->eos_callback_data, st, nData1);
+      break;
+   case OMX_EventPortSettingsChanged:
+      if (st->client->port_settings_callback)
+         st->client->port_settings_callback(st->client->port_settings_callback_data, st, nData1);
+      break;
+   case OMX_EventParamOrConfigChanged:
+      if (st->client->configchanged_callback)
+         st->client->configchanged_callback(st->client->configchanged_callback_data, st, nData2);
+      break;
+   default:
+      // ignore
+      break;
+   }
+
+   return OMX_ErrorNone;
+}
+
+/***********************************************************
+ * Name: ilclient_empty_buffer_done
+ *
+ * Description: passed to core to use as component callback, puts
+ * buffer on list
+ *
+ * Returns:
+ ***********************************************************/
+static OMX_ERRORTYPE ilclient_empty_buffer_done(OMX_IN OMX_HANDLETYPE hComponent,
+      OMX_IN OMX_PTR pAppData,
+      OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
+{
+   COMPONENT_T *st = (COMPONENT_T *) pAppData;
+   OMX_BUFFERHEADERTYPE *list;
+
+   ilclient_debug_output("%s: empty buffer done %p", st->name, pBuffer);
+
+   vcos_semaphore_wait(&st->sema);
+   // insert at end of the list, so we process buffers in
+   // the same order
+   list = st->in_list;
+   while(list && list->pAppPrivate)
+      list = list->pAppPrivate;
+
+   if(!list)
+      st->in_list = pBuffer;
+   else
+      list->pAppPrivate = pBuffer;
+
+   pBuffer->pAppPrivate = NULL;
+   vcos_semaphore_post(&st->sema);
+
+   vcos_event_flags_set(&st->event, ILCLIENT_EMPTY_BUFFER_DONE, VCOS_OR);
+
+   if (st->client->empty_buffer_done_callback)
+      st->client->empty_buffer_done_callback(st->client->empty_buffer_done_callback_data, st);
+
+   return OMX_ErrorNone;
+}
+
+/***********************************************************
+ * Name: ilclient_empty_buffer_done_error
+ *
+ * Description: passed to core to use as component callback, asserts
+ * on use as client not expecting component to use this callback.
+ *
+ * Returns:
+ ***********************************************************/
+static OMX_ERRORTYPE ilclient_empty_buffer_done_error(OMX_IN OMX_HANDLETYPE hComponent,
+      OMX_IN OMX_PTR pAppData,
+      OMX_IN OMX_BUFFERHEADERTYPE* pBuffer)
+{
+   vc_assert(0);
+   return OMX_ErrorNone;
+}
+
+/***********************************************************
+ * Name: ilclient_fill_buffer_done
+ *
+ * Description: passed to core to use as component callback, puts
+ * buffer on list
+ *
+ * Returns:
+ ***********************************************************/
+static OMX_ERRORTYPE ilclient_fill_buffer_done(OMX_OUT OMX_HANDLETYPE hComponent,
+      OMX_OUT OMX_PTR pAppData,
+      OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer)
+{
+   COMPONENT_T *st = (COMPONENT_T *) pAppData;
+   OMX_BUFFERHEADERTYPE *list;
+
+   ilclient_debug_output("%s: fill buffer done %p", st->name, pBuffer);
+
+   vcos_semaphore_wait(&st->sema);
+   // insert at end of the list, so we process buffers in
+   // the correct order
+   list = st->out_list;
+   while(list && list->pAppPrivate)
+      list = list->pAppPrivate;
+
+   if(!list)
+      st->out_list = pBuffer;
+   else
+      list->pAppPrivate = pBuffer;
+      
+   pBuffer->pAppPrivate = NULL;
+   vcos_semaphore_post(&st->sema);
+
+   vcos_event_flags_set(&st->event, ILCLIENT_FILL_BUFFER_DONE, VCOS_OR);
+
+   if (st->client->fill_buffer_done_callback)
+      st->client->fill_buffer_done_callback(st->client->fill_buffer_done_callback_data, st);
+
+   return OMX_ErrorNone;
+}
+
+/***********************************************************
+ * Name: ilclient_fill_buffer_done_error
+ *
+ * Description: passed to core to use as component callback, asserts
+ * on use as client not expecting component to use this callback.
+ *
+ * Returns:
+ ***********************************************************/
+static OMX_ERRORTYPE ilclient_fill_buffer_done_error(OMX_OUT OMX_HANDLETYPE hComponent,
+      OMX_OUT OMX_PTR pAppData,
+      OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer)
+{
+   vc_assert(0);
+   return OMX_ErrorNone;
+}
+
+
+
+OMX_HANDLETYPE ilclient_get_handle(COMPONENT_T *comp)
+{
+   vcos_assert(comp);
+   return comp->comp;
+}
+
+
+static struct {
+   OMX_PORTDOMAINTYPE dom;
+   int param;
+} port_types[] = {
+   { OMX_PortDomainVideo, OMX_IndexParamVideoInit },
+   { OMX_PortDomainAudio, OMX_IndexParamAudioInit },
+   { OMX_PortDomainImage, OMX_IndexParamImageInit },
+   { OMX_PortDomainOther, OMX_IndexParamOtherInit },
+};
+
+int ilclient_get_port_index(COMPONENT_T *comp, OMX_DIRTYPE dir, OMX_PORTDOMAINTYPE type, int index)
+{
+   uint32_t i;
+   // for each possible port type...
+   for (i=0; i<sizeof(port_types)/sizeof(port_types[0]); i++)
+   {
+      if ((port_types[i].dom == type) || (type == (OMX_PORTDOMAINTYPE) -1))
+      {
+         OMX_PORT_PARAM_TYPE param;
+         OMX_ERRORTYPE error;
+         uint32_t j;
+
+         param.nSize = sizeof(param);
+         param.nVersion.nVersion = OMX_VERSION;
+         error = OMX_GetParameter(ILC_GET_HANDLE(comp), port_types[i].param, &param);
+         assert(error == OMX_ErrorNone);
+
+         // for each port of this type...
+         for (j=0; j<param.nPorts; j++)
+         {
+            int port = param.nStartPortNumber+j;
+
+            OMX_PARAM_PORTDEFINITIONTYPE portdef;
+            portdef.nSize = sizeof(portdef);
+            portdef.nVersion.nVersion = OMX_VERSION;
+            portdef.nPortIndex = port;
+
+            error = OMX_GetParameter(ILC_GET_HANDLE(comp), OMX_IndexParamPortDefinition, &portdef);
+            assert(error == OMX_ErrorNone);
+
+            if (portdef.eDir == dir)
+            {
+               if (index-- == 0)
+                  return port;
+            }
+         }
+      }
+   }
+   return -1;
+}
+
+int ilclient_suggest_bufsize(COMPONENT_T *comp, OMX_U32 nBufSizeHint)
+{
+   OMX_PARAM_BRCMOUTPUTBUFFERSIZETYPE param;
+   OMX_ERRORTYPE error;
+
+   param.nSize = sizeof(param);
+   param.nVersion.nVersion = OMX_VERSION;
+   param.nBufferSize = nBufSizeHint;
+   error = OMX_SetParameter(ILC_GET_HANDLE(comp), OMX_IndexParamBrcmOutputBufferSize,
+                            &param);
+   assert(error == OMX_ErrorNone);
+
+   return (error == OMX_ErrorNone) ? 0 : -1;
+}
+
+unsigned int ilclient_stack_size(void)
+{
+   return ILCLIENT_THREAD_DEFAULT_STACK_SIZE;
+}
+
diff --git a/host_applications/linux/apps/hello_pi/libs/ilclient/ilclient.h b/host_applications/linux/apps/hello_pi/libs/ilclient/ilclient.h
new file mode 100755 (executable)
index 0000000..5e1b10d
--- /dev/null
@@ -0,0 +1,1039 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * \file
+ *
+ * \brief This API defines helper functions for writing IL clients.
+ *
+ * This file defines an IL client side library.  This is useful when
+ * writing IL clients, since there tends to be much repeated and
+ * common code across both single and multiple clients.  This library
+ * seeks to remove that common code and abstract some of the
+ * interactions with components.  There is a wrapper around a
+ * component and tunnel, and some operations can be done on lists of
+ * these.  The callbacks from components are handled, and specific
+ * events can be checked or waited for.
+ */
+
+#ifndef _IL_CLIENT_H
+#define _IL_CLIENT_H
+
+#include "IL/OMX_Broadcom.h"
+#include "interface/vcos/vcos.h"
+
+/**
+ * The <DFN>ILCLIENT_T</DFN> structure encapsulates the state needed for the IL
+ * Client API.  It contains a set of callback functions used to
+ * communicate with the user.  It also includes a linked list of free
+ * event structures.
+ ***********************************************************/
+typedef struct _ILCLIENT_T ILCLIENT_T;
+
+
+/**
+ * Each <DFN>ILEVENT_T</DFN> structure stores the result of an <DFN>EventHandler</DFN>
+ * callback from a component, storing the event message type and any
+ * parameters returned.
+ ***********************************************************/
+typedef struct _ILEVENT_T ILEVENT_T;
+
+
+
+struct _COMPONENT_T;
+
+/**
+ * The <DFN>COMPONENT_T</DFN> structure represents an IL component,
+ * together with the necessary extra information required by the IL
+ * Client API.  This structure stores the handle to the OMX component,
+ * as well as the event list containing all events sent by this
+ * component.  The component state structure also holds a pair of
+ * buffer queues, for input and output buffers returned to the client
+ * by the <DFN>FillBufferDone</DFN> and <DFN>EmptyBufferDone</DFN>
+ * callbacks.  As some operations result in error callbacks that can
+ * be ignored, an error mask is maintained to allow some errors to be
+ * ignored.  A pointer to the client state structure is also added.
+ ***********************************************************/
+typedef struct _COMPONENT_T COMPONENT_T;
+
+
+/**
+ * The generic callback function is used for communicating events from
+ * a particular component to the user.
+ *
+ * @param userdata The data returned from when the callback was registered.
+ *
+ * @param comp The component structure representing the component that
+ * originated this event.
+ *
+ * @param data The relevant data field from the event.
+ *
+ * @return Void.
+ ***********************************************************/
+typedef void (*ILCLIENT_CALLBACK_T)(void *userdata, COMPONENT_T *comp, OMX_U32 data);
+
+
+/**
+ * The buffer callback function is used for indicating that a
+ * component has returned a buffer on a port using client buffer
+ * communication.
+ *
+ * @param data The data returned from when the callback was registered.
+ *
+ * @param comp The component from which the buffer originated.
+ *
+ * @return Void.
+ ***********************************************************/
+typedef void (*ILCLIENT_BUFFER_CALLBACK_T)(void *data, COMPONENT_T *comp);
+
+
+/**
+ * The malloc function is passed into
+ * <DFN>ilclient_enable_port_buffers()</DFN> and used for allocating the
+ * buffer payload.
+ *
+ * @param userdata Private pointer passed into
+ * <DFN>ilclient_enable_port_buffers()</DFN> call.
+ *
+ * @param size Size in bytes of the requested memory region.
+ *
+ * @param align Alignment requirement in bytes for the base memory address.
+ *
+ * @param description Text description of the memory being allocated.
+ *
+ * @return The memory address on success, <DFN>NULL</DFN> on failure.
+ ***********************************************************/
+typedef void *(*ILCLIENT_MALLOC_T)(void *userdata, VCOS_UNSIGNED size, VCOS_UNSIGNED align, const char *description);
+
+
+/**
+ * The free function is passed into
+ * <DFN>ilclient_enable_port_buffers()</DFN> and
+ * <DFN>ilclient_disable_port_buffers()</DFN> and used for freeing the
+ * buffer payload.
+ *
+ * @param userdata Private pointer passed into
+ * <DFN>ilclient_enable_port_buffers()</DFN> and
+ * <DFN>ilclient_disable_port_buffers()</DFN>.
+ *
+ * @param pointer Memory address to free, that was previously returned
+ * from <DFN>ILCLIENT_MALLOC_T</DFN> function.
+ *
+ * @return Void.
+ ***********************************************************/
+typedef void (*ILCLIENT_FREE_T)(void *userdata, void *pointer);
+
+
+/**
+ * The event mask enumeration describes the possible events that the
+ * user can ask to wait for when waiting for a particular event.
+ ***********************************************************/
+typedef enum {
+   ILCLIENT_EMPTY_BUFFER_DONE  = 0x1,   /**< Set when a buffer is
+                                           returned from an input
+                                           port */
+
+   ILCLIENT_FILL_BUFFER_DONE   = 0x2,   /**< Set when a buffer is
+                                           returned from an output
+                                           port */
+
+   ILCLIENT_PORT_DISABLED      = 0x4,   /**< Set when a port indicates
+                                           it has completed a disable
+                                           command. */
+
+   ILCLIENT_PORT_ENABLED       = 0x8,   /**< Set when a port indicates
+                                           is has completed an enable
+                                           command. */
+
+   ILCLIENT_STATE_CHANGED      = 0x10,  /**< Set when a component
+                                           indicates it has completed
+                                           a state change command. */
+
+   ILCLIENT_BUFFER_FLAG_EOS    = 0x20,  /**< Set when a port signals
+                                           an EOS event. */
+
+   ILCLIENT_PARAMETER_CHANGED  = 0x40,  /**< Set when a port signals a
+                                           port settings changed
+                                           event. */
+
+   ILCLIENT_EVENT_ERROR        = 0x80,  /**< Set when a component
+                                           indicates an error. */
+
+   ILCLIENT_PORT_FLUSH         = 0x100, /**< Set when a port indicates
+                                           is has completed a flush
+                                           command. */
+
+   ILCLIENT_MARKED_BUFFER      = 0x200, /**< Set when a port indicates
+                                           it has marked a buffer. */
+
+   ILCLIENT_BUFFER_MARK        = 0x400, /**< Set when a port indicates
+                                           it has received a buffer
+                                           mark. */
+
+   ILCLIENT_CONFIG_CHANGED     = 0x800  /**< Set when a config parameter
+                                           changed. */
+} ILEVENT_MASK_T;
+
+
+/**
+ * On component creation the user can set flags to control the 
+ * creation of that component.
+ ***********************************************************/
+typedef enum {
+   ILCLIENT_FLAGS_NONE            = 0x0, /**< Used if no flags are
+                                            set. */
+
+   ILCLIENT_ENABLE_INPUT_BUFFERS  = 0x1, /**< If set we allow the
+                                            client to communicate with
+                                            input ports via buffer
+                                            communication, rather than
+                                            tunneling with another
+                                            component. */
+
+   ILCLIENT_ENABLE_OUTPUT_BUFFERS = 0x2, /**< If set we allow the
+                                            client to communicate with
+                                            output ports via buffer
+                                            communication, rather than
+                                            tunneling with another
+                                            component. */
+
+   ILCLIENT_DISABLE_ALL_PORTS     = 0x4, /**< If set we disable all
+                                            ports on creation. */
+
+   ILCLIENT_HOST_COMPONENT        = 0x8, /**< Create a host component.
+                                            The default host ilcore
+                                            only can create host components
+                                            by being locally hosted
+                                            so should only be used for testing
+                                            purposes. */
+
+   ILCLIENT_OUTPUT_ZERO_BUFFERS   = 0x10 /**< All output ports will have
+                                            nBufferCountActual set to zero,
+                                            if supported by the component. */                                            
+} ILCLIENT_CREATE_FLAGS_T;
+  
+
+/**
+ * \brief This structure represents a tunnel in the OpenMAX IL API.
+ *
+ * Some operations in this API act on a tunnel, so the tunnel state
+ * structure (<DFN>TUNNEL_T</DFN>) is a convenient store of the source and sink
+ * of the tunnel.  For each, a pointer to the relevant component state
+ * structure and the port index is stored.
+ ***********************************************************/
+typedef struct {
+   COMPONENT_T *source;  /**< The source component */
+   int source_port;      /**< The output port index on the source component */
+   COMPONENT_T *sink;    /**< The sink component */
+   int sink_port;        /**< The input port index on the sink component */
+} TUNNEL_T;
+
+
+/**
+ * The <DFN>set_tunnel</DFN> macro is a useful function that initialises a
+ * <DFN>TUNNEL_T</DFN> structure.
+ ***********************************************************/
+#define set_tunnel(t,a,b,c,d)  do {TUNNEL_T *_ilct = (t); \
+  _ilct->source = (a); _ilct->source_port = (b); \
+  _ilct->sink = (c); _ilct->sink_port = (d);} while(0)
+
+/**
+ * For calling OpenMAX IL methods directory, we need to access the
+ * <DFN>OMX_HANDLETYPE</DFN> corresponding to the <DFN>COMPONENT_T</DFN> structure.  This
+ * macro enables this while keeping the <DFN>COMPONENT_T</DFN> structure opaque.
+ * The parameter <DFN>x</DFN> should be of the type <DFN>*COMPONENT_T</DFN>.
+ ***********************************************************/
+#define ILC_GET_HANDLE(x) ilclient_get_handle(x)
+
+/**
+ * An IL Client structure is created by the <DFN>ilclient_init()</DFN>
+ * method.  This structure is used when creating components, but
+ * otherwise is not needed in other API functions as a pointer to this
+ * structure is maintained in the <DFN>COMPONENT_T</DFN> structure.
+ *
+ * @return pointer to client structure
+ ***********************************************************/
+VCHPRE_ ILCLIENT_T VCHPOST_ *ilclient_init(void);
+
+/**
+ * When all components have been deleted, the IL Client structure can
+ * be destroyed by calling the <DFN>ilclient_destroy()</DFN> function.
+ *
+ * @param handle The client handle.  After calling this function, this
+ * handle should not be used.
+ *
+ * @return void
+ ***********************************************************/
+VCHPRE_ void VCHPOST_ ilclient_destroy(ILCLIENT_T *handle);
+
+/**
+ * The <DFN>ilclient_set_port_settings_callback()</DFN> function registers a
+ * callback to be used when the <DFN>OMX_EventPortSettingsChanged</DFN> event is
+ * received.  When the event is received, a pointer to the component
+ * structure and port index is returned by the callback.
+ *
+ * @param handle The client handle
+ *
+ * @param func The callback function to use.  Calling this function
+ * with a <DFN>NULL</DFN> function pointer will deregister any existing
+ * registered callback.
+ *
+ * @param userdata Data to be passed back when calling the callback
+ * function.
+ *
+ * @return void
+ ***********************************************************/
+VCHPRE_ void VCHPOST_ ilclient_set_port_settings_callback(ILCLIENT_T *handle,
+                                                          ILCLIENT_CALLBACK_T func,
+                                                          void *userdata);
+
+/**
+ * The <DFN>ilclient_set_eos_callback()</DFN> function registers a callback to be
+ * used when the <DFN>OMX_EventBufferFlag</DFN> is received with the
+ * <DFN>OMX_BUFFERFLAG_EOS</DFN> flag set. When the event is received, a pointer
+ * to the component structure and port index is returned by the
+ * callback.
+ *
+ * @param handle The client handle
+ *
+ * @param func The callback function to use.  Calling this function
+ * with a <DFN>NULL</DFN> function pointer will deregister any existing
+ * registered callback.
+ *
+ * @param userdata Data to be passed back when calling the callback
+ * function.
+ *
+ * @return void
+ ***********************************************************/
+VCHPRE_ void VCHPOST_ ilclient_set_eos_callback(ILCLIENT_T *handle,
+                                                ILCLIENT_CALLBACK_T func,
+                                                void *userdata);
+
+/**
+ * The <DFN>ilclient_set_error_callback()</DFN> function registers a callback to be
+ * used when the <DFN>OMX_EventError</DFN> is received from a component.  When
+ * the event is received, a pointer to the component structure and the
+ * error code are reported by the callback.
+ *
+ * @param handle The client handle
+ *
+ * @param func The callback function to use.  Calling this function
+ * with a <DFN>NULL</DFN> function pointer will deregister any existing
+ * registered callback.
+ *
+ * @param userdata Data to be passed back when calling the callback
+ * function.
+ *
+ * @return void
+ ***********************************************************/
+VCHPRE_ void VCHPOST_ ilclient_set_error_callback(ILCLIENT_T *handle,
+                                                  ILCLIENT_CALLBACK_T func,
+                                                  void *userdata);
+
+/**
+ * The <DFN>ilclient_set_configchanged_callback()</DFN> function
+ * registers a callback to be used when an
+ * <DFN>OMX_EventParamOrConfigChanged</DFN> event occurs.  When the
+ * event is received, a pointer to the component structure and the
+ * index value that has changed are reported by the callback.  The
+ * user may then use an <DFN>OMX_GetConfig</DFN> call with the index
+ * as specified to retrieve the updated information.
+ *
+ * @param handle The client handle
+ *
+ * @param func The callback function to use.  Calling this function
+ * with a <DFN>NULL</DFN> function pointer will deregister any existing
+ * registered callback.
+ *
+ * @param userdata Data to be passed back when calling the callback
+ * function.
+ *
+ * @return void
+ ***********************************************************/
+VCHPRE_ void VCHPOST_ ilclient_set_configchanged_callback(ILCLIENT_T *handle, 
+                                                          ILCLIENT_CALLBACK_T func, 
+                                                          void *userdata);
+
+
+/**
+ * The <DFN>ilclient_set_fill_buffer_done_callback()</DFN> function registers a
+ * callback to be used when a buffer passed to an output port using the
+ * <DFN>OMX_FillBuffer</DFN> call is returned with the <DFN>OMX_FillBufferDone</DFN>
+ * callback.  When the event is received, a pointer to the component
+ * structure is returned by the callback.  The user may then use the
+ * <DFN>ilclient_get_output_buffer()</DFN> function to retrieve the buffer.
+ *
+ * @param handle The client handle
+ *
+ * @param func The callback function to use.  Calling this function
+ * with a <DFN>NULL</DFN> function pointer will deregister any existing
+ * registered callback.
+ *
+ * @param userdata Data to be passed back when calling the callback
+ * function.
+ *
+ * @return void
+ ***********************************************************/
+VCHPRE_ void VCHPOST_ ilclient_set_fill_buffer_done_callback(ILCLIENT_T *handle,
+                                                             ILCLIENT_BUFFER_CALLBACK_T func,
+                                                             void *userdata);
+
+/**
+ * The <DFN>ilclient_set_empty_buffer_done_callback()</DFN> function registers a
+ * callback to be used when a buffer passed to an input port using the
+ * <DFN>OMX_EmptyBuffer</DFN> call is returned with the <DFN>OMX_EmptyBufferDone</DFN>
+ * callback.  When the event is received, a pointer to the component
+ * structure is returned by the callback.  The user may then use the
+ * <DFN>ilclient_get_input_buffer()</DFN> function to retrieve the buffer.
+ *
+ * @param handle The client handle
+ *
+ * @param func The callback function to use.  Calling this function
+ * with a <DFN>NULL</DFN> function pointer will deregister any existing
+ * registered callback.
+ *
+ * @param userdata Data to be passed back when calling the callback
+ * function.
+ *
+ * @return void
+ ***********************************************************/
+VCHPRE_ void VCHPOST_ ilclient_set_empty_buffer_done_callback(ILCLIENT_T *handle,
+                                                              ILCLIENT_BUFFER_CALLBACK_T func,
+                                                              void *userdata);
+
+
+/**
+ * Components are created using the <DFN>ilclient_create_component()</DFN>
+ * function.  
+ *
+ * @param handle The client handle
+ *
+ * @param comp On successful creation, the component structure pointer
+ * will be written back into <DFN>comp</DFN>.
+ *
+ * @param name The name of the component to be created.  Component
+ * names as provided are automatically prefixed with
+ * <DFN>"OMX.broadcom."</DFN> before passing to the IL core.  The name
+ * provided will also be used in debugging messages added about this
+ * component.
+ *
+ * @param flags The client can specify some creation behaviour by using
+ * the <DFN>flags</DFN> field.  The meaning of each flag is defined 
+ * by the <DFN>ILCLIENT_CREATE_FLAGS_T</DFN> type.
+ *
+ * @return 0 on success, -1 on failure
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ ilclient_create_component(ILCLIENT_T *handle,
+                                               COMPONENT_T **comp,
+                                               char *name,
+                                               ILCLIENT_CREATE_FLAGS_T flags);
+
+/**
+ * The <DFN>ilclient_cleanup_components()</DFN> function deallocates all
+ * state associated with components and frees the OpenMAX component
+ * handles. All tunnels connecting components should have been torn
+ * down explicitly, and all components must be in loaded state.
+ *
+ * @param list A null-terminated list of component pointers to be
+ * deallocated.
+ * 
+ * @return void
+ ***********************************************************/
+VCHPRE_ void VCHPOST_ ilclient_cleanup_components(COMPONENT_T *list[]);
+
+
+/**
+ * The <DFN>ilclient_change_component_state()</DFN> function changes the
+ * state of an individual component.  This will trigger the state
+ * change, and also wait for that state change to be completed.  It
+ * should not be called if this state change has dependencies on other
+ * components also changing states.  Trying to change a component to
+ * its current state is treated as success.
+ *
+ * @param comp The component to change.
+ *
+ * @param state The new state to transition to.
+ *
+ * @return 0 on success, -1 on failure.
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ ilclient_change_component_state(COMPONENT_T *comp,
+                                                     OMX_STATETYPE state);
+
+
+/**
+ * The <DFN>ilclient_state_transition()</DFN> function transitions a set of
+ * components that need to perform a simultaneous state transition; 
+ * for example, when two components are tunnelled and the buffer
+ * supplier port needs to allocate and pass buffers to a non-supplier
+ * port.  All components are sent a command to change state, then the
+ * function will wait for all components to signal that they have
+ * changed state.
+ *
+ * @param list A null-terminated list of component pointers.
+ *
+ * @param state The new state to which to transition all components.
+ *
+ * @return void
+ ***********************************************************/
+VCHPRE_ void VCHPOST_  ilclient_state_transition(COMPONENT_T *list[],
+                                                 OMX_STATETYPE state);
+
+
+/**
+ * The <DFN>ilclient_disable_port()</DFN> function disables a port on a
+ * given component.  This function sends the disable port message to
+ * the component and waits for the component to signal that this has
+ * taken place.  If the port is already disabled, this is treated as a
+ * success.
+ *
+ * @param comp The component containing the port to disable.
+ *
+ * @param portIndex The port index of the port to disable.  This must
+ * be a named port index, rather than a <DFN>OMX_ALL</DFN> value.
+ *
+ * @return void
+ ***********************************************************/
+VCHPRE_ void VCHPOST_ ilclient_disable_port(COMPONENT_T *comp,
+                                            int portIndex);
+
+
+/**
+ * The <DFN>ilclient_enable_port()</DFN> function enables a port on a
+ * given component.  This function sends the enable port message to
+ * the component and waits for the component to signal that this has
+ * taken place.  If the port is already disabled, this is treated as a
+ * success.
+ *
+ * @param comp The component containing the port to enable.
+ *
+ * @param portIndex The port index of the port to enable.  This must
+ * be a named port index, rather than a <DFN>OMX_ALL</DFN> value.
+ *
+ * @return void
+ ***********************************************************/
+VCHPRE_ void VCHPOST_ ilclient_enable_port(COMPONENT_T *comp,
+                                           int portIndex);
+
+
+
+/**
+ * The <DFN>ilclient_enable_port_buffers()</DFN> function enables a port
+ * in base profile mode on a given component.  The port is not
+ * tunneled, so requires buffers to be allocated.
+ *
+ * @param comp The component containing the port to enable.
+ *
+ * @param portIndex The port index of the port to enable.  This must
+ * be a named port index, rather than a <DFN>OMX_ALL</DFN> value.
+ *
+ * @param ilclient_malloc This function will be used to allocate
+ * buffer payloads.  If <DFN>NULL</DFN> then
+ * <DFN>vcos_malloc_aligned</DFN> will be used.
+ *
+ * @param ilclient_free If an error occurs, this function is used to
+ * free previously allocated payloads.  If <DFN>NULL</DFN> then
+ * <DFN>vcos_free</DFN> will be used.
+ *
+ * @param userdata The first argument to calls to
+ * <DFN>ilclient_malloc</DFN> and <DFN>ilclient_free</DFN>, if these
+ * arguments are not <DFN>NULL</DFN>.
+ *
+ * @return 0 indicates success. -1 indicates failure.
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ ilclient_enable_port_buffers(COMPONENT_T *comp,
+                                                  int portIndex,
+                                                  ILCLIENT_MALLOC_T ilclient_malloc,
+                                                  ILCLIENT_FREE_T ilclient_free,
+                                                  void *userdata);
+
+
+/**
+ * The <DFN>ilclient_disable_port_buffers()</DFN> function disables a
+ * port in base profile mode on a given component.  The port is not
+ * tunneled, and has been supplied with buffers by the client.
+ *
+ * @param comp The component containing the port to disable.
+ *
+ * @param portIndex The port index of the port to disable.  This must
+ * be a named port index, rather than a <DFN>OMX_ALL</DFN> value.
+ *
+ * @param bufferList A list of buffers, using <DFN>pAppPrivate</DFN>
+ * as the next pointer that were allocated on this port, and currently
+ * held by the application.  If buffers on this port are held by IL
+ * client or the component then these are automatically freed.
+ *
+ * @param ilclient_free This function is used to free the buffer payloads.
+ * If <DFN>NULL</DFN> then <DFN>vcos_free</DFN> will be used.
+ *
+ * @param userdata The first argument to calls to
+ * <DFN>ilclient_free</DFN>.
+ *
+ * @return void
+ */
+VCHPRE_ void VCHPOST_ ilclient_disable_port_buffers(COMPONENT_T *comp,
+                                                    int portIndex,
+                                                    OMX_BUFFERHEADERTYPE *bufferList,
+                                                    ILCLIENT_FREE_T ilclient_free,
+                                                    void *userdata);
+
+
+/**
+ * With a populated tunnel structure, the
+ * <DFN>ilclient_setup_tunnel()</DFN> function connects the tunnel.  It
+ * first transitions the source component to idle if currently in
+ * loaded state, and then optionally checks the source event list for
+ * a port settings changed event from the source port.  If this event
+ * is not in the event queue then this function optionally waits for
+ * it to arrive.  To disable this check for the port settings changed
+ * event, set <DFN>timeout</DFN> to zero.
+ *
+ * Both ports are then disabled, and the source port is inspected for
+ * a port streams parameter.  If this is supported, then the
+ * <DFN>portStream</DFN> argument is used to select which port stream
+ * to use.  The two ports are then tunnelled using the
+ * <DFN>OMX_SetupTunnel</DFN> function.  If this is successful, then
+ * both ports are enabled.  Note that for disabling and enabling the
+ * tunnelled ports, the functions <DFN>ilclient_disable_tunnel()</DFN>
+ * and <DFN>ilclient_enable_tunnel()</DFN> are used, so the relevant
+ * documentation for those functions applies here.
+ *
+ * @param tunnel The tunnel structure representing the tunnel to
+ * set up.
+ *
+ * @param portStream If port streams are supported on the output port
+ * of the tunnel, then this parameter indicates the port stream to
+ * select on this port.
+ *
+ * @param timeout The time duration in milliseconds to wait for the
+ * output port to signal a port settings changed event before
+ * returning a timeout failure.  If this is 0, then we do not check
+ * for a port settings changed before setting up the tunnel.
+ *
+ * @return 0 indicates success, negative indicates failure:
+ *  - -1: a timeout waiting for the parameter changed
+ *  - -2: an error was returned instead of parameter changed
+ *  - -3: no streams are available from this port
+ *  - -4: requested stream is not available from this port
+ *  - -5: the data format was not acceptable to the sink
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ ilclient_setup_tunnel(TUNNEL_T *tunnel,
+                                           unsigned int portStream,
+                                           int timeout);
+
+
+/**
+ * The <DFN>ilclient_disable_tunnel()</DFN> function disables both ports listed in
+ * the tunnel structure.  It will send a port disable command to each
+ * port, then waits for both to indicate they have completed the
+ * transition.  The errors <DFN>OMX_ErrorPortUnpopulated</DFN> and
+ * <DFN>OMX_ErrorSameState</DFN> are both ignored by this function; the former
+ * since the first port to disable may deallocate buffers before the
+ * second port has been disabled, leading to the second port reporting
+ * the unpopulated error.
+ *
+ * @param tunnel The tunnel to disable.
+ *
+ * @return void
+ ***********************************************************/
+VCHPRE_ void VCHPOST_ ilclient_disable_tunnel(TUNNEL_T *tunnel);
+
+
+/**
+ * The <DFN>ilclient_enable_tunnel()</DFN> function enables both ports listed in
+ * the tunnel structure.  It will first send a port enable command to
+ * each port.  It then checks whether the sink component is not in
+ * loaded state - if so, the function waits for both ports to complete
+ * the requested port enable.  If the sink component was in loaded
+ * state, then this component is transitioned to idle to allow the
+ * ports to exchange buffers and enable the ports.  This is since
+ * typically this function is used when creating a tunnel between two
+ * components, where the source component is processing data to enable
+ * it to report the port settings changed event, and the sink port has
+ * yet to be used.  Before transitioning the sink component to idle,
+ * this function waits for the sink port to be enabled - since the
+ * component is in loaded state, this will happen quickly.  If the
+ * transition to idle fails, the sink component is transitioned back
+ * to loaded and the source port disabled.  If the transition
+ * succeeds, the function then waits for the source port to complete
+ * the requested port enable.
+ *
+ * @param tunnel The tunnel to enable.
+ *
+ * @return 0 on success, -1 on failure.
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ ilclient_enable_tunnel(TUNNEL_T *tunnel);
+
+
+/**
+ * The <DFN>ilclient_flush_tunnels()</DFN> function will flush a number of tunnels
+ * from the list of tunnels presented.  For each tunnel that is to be
+ * flushed, both source and sink ports are sent a flush command.  The
+ * function then waits for both ports to report they have completed
+ * the flush operation.
+ *
+ * @param tunnel List of tunnels.  The list must be terminated with a
+ * tunnel structure with <DFN>NULL</DFN> component entries.
+ *
+ * @param max The maximum number of tunnels to flush from the list.
+ * A value of 0 indicates that all tunnels in the list are flushed.
+ *
+ * @return void
+ ***********************************************************/
+VCHPRE_ void VCHPOST_ ilclient_flush_tunnels(TUNNEL_T *tunnel,
+                                             int max);
+
+
+/**
+ * The <DFN>ilclient_teardown_tunnels()</DFN> function tears down all tunnels in
+ * the list of tunnels presented.  For each tunnel in the list, the
+ * <DFN>OMX_SetupTunnel</DFN> is called on the source port and on the sink port,
+ * where for both calls the destination component is <DFN>NULL</DFN> and the
+ * destination port is zero.  The VMCSX IL implementation requires
+ * that all tunnels are torn down in this manner before components are
+ * freed. 
+ *
+ * @param tunnels List of tunnels to teardown.  The list must be
+ * terminated with a tunnel structure with <DFN>NULL</DFN> component entries.
+ *
+ * @return void
+ ***********************************************************/
+VCHPRE_ void VCHPOST_ ilclient_teardown_tunnels(TUNNEL_T *tunnels);
+
+
+/**
+ * The <DFN>ilclient_get_output_buffer()</DFN> function returns a buffer
+ * that was sent to an output port and that has been returned from a
+ * component using the <DFN>OMX_FillBufferDone</DFN> callback.
+ *
+ * @param comp The component that returned the buffer.
+ *
+ * @param portIndex The port index on the component that the buffer
+ * was returned from.
+ *
+ * @param block If non-zero, the function will block until a buffer is available.
+ *
+ * @return Pointer to buffer if available, otherwise <DFN>NULL</DFN>.
+ ***********************************************************/
+VCHPRE_ OMX_BUFFERHEADERTYPE* VCHPOST_ ilclient_get_output_buffer(COMPONENT_T *comp,
+                                                                  int portIndex,
+                                                                  int block);
+
+
+/**
+ * The <DFN>ilclient_get_input_buffer()</DFN> function returns a buffer
+ * that was sent to an input port and that has been returned from a
+ * component using the <DFN>OMX_EmptyBufferDone</DFN> callback.
+ *
+ * @param comp The component that returned the buffer.
+ *
+ * @param portIndex The port index on the component from which the buffer
+ * was returned.
+ *
+ * @param block If non-zero, the function will block until a buffer is available.
+ *
+ * @return pointer to buffer if available, otherwise <DFN>NULL</DFN>
+ ***********************************************************/
+VCHPRE_ OMX_BUFFERHEADERTYPE* VCHPOST_ ilclient_get_input_buffer(COMPONENT_T *comp,
+                                                                 int portIndex,
+                                                                 int block);
+
+
+/**
+ * The <DFN>ilclient_remove_event()</DFN> function queries the event list for the
+ * given component, matching against the given criteria.  If a matching
+ * event is found, it is removed and added to the free event list.
+ *
+ * @param comp The component that returned the matching event.
+ *
+ * @param event The event type of the matching event.
+ *
+ * @param nData1 The <DFN>nData1</DFN> field of the matching event.
+ *
+ * @param ignore1 Whether to ignore the <DFN>nData1</DFN> field when finding a
+ * matching event.  A value of 0 indicates that <DFN>nData1</DFN> must match, a
+ * value of 1 indicates that <DFN>nData1</DFN> does not have to match.
+ *
+ * @param nData2 The <DFN>nData2</DFN> field of the matching event.
+ *
+ * @param ignore2 Whether to ignore the <DFN>nData2</DFN> field when finding a
+ * matching event.  A value of 0 indicates that <DFN>nData2</DFN> must match, a
+ * value of 1 indicates that <DFN>nData2</DFN> does not have to match.
+ *
+ * @return 0 if the event was removed.  -1 if no matching event was
+ * found.
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ ilclient_remove_event(COMPONENT_T *comp,
+                                           OMX_EVENTTYPE event,
+                                           OMX_U32 nData1,
+                                           int ignore1,
+                                           OMX_U32 nData2,
+                                           int ignore2);
+
+
+/**
+ * The <DFN>ilclient_return_events()</DFN> function removes all events
+ * from a component event list and adds them to the IL client free
+ * event list.  This function is automatically called when components
+ * are freed.
+ *
+ * @param comp The component from which all events should be moved to
+ * the free list.
+ *
+ * @return void
+ ***********************************************************/
+VCHPRE_ void VCHPOST_ ilclient_return_events(COMPONENT_T *comp);
+
+
+/**
+ * The <DFN>ilclient_wait_for_event()</DFN> function is similar to
+ * <DFN>ilclient_remove_event()</DFN>, but allows the caller to block until that
+ * event arrives.
+ *
+ * @param comp The component that returned the matching event.
+ *
+ * @param event The event type of the matching event.
+ *
+ * @param nData1 The <DFN>nData1</DFN> field of the matching event.
+ *
+ * @param ignore1 Whether to ignore the <DFN>nData1</DFN> field when finding a
+ * matching event.  A value of 0 indicates that <DFN>nData1</DFN> must match, a
+ * value of 1 indicates that <DFN>nData1</DFN> does not have to match.
+ *
+ * @param nData2 The <DFN>nData2</DFN> field of the matching event.
+ *
+ * @param ignore2 Whether to ignore the <DFN>nData2</DFN> field when finding a
+ * matching event.  A value of 0 indicates that <DFN>nData2</DFN> must match, a
+ * value of 1 indicates that <DFN>nData2</DFN> does not have to match.
+ *
+ * @param event_flag Specifies a bitfield of IL client events to wait
+ * for, given in <DFN>ILEVENT_MASK_T</DFN>.  If any of these events
+ * are signalled by the component, the event list is then re-checked
+ * for a matching event.  If the <DFN>ILCLIENT_EVENT_ERROR</DFN> bit
+ * is included, and an error is signalled by the component, then the
+ * function will return an error code.  If the
+ * <DFN>ILCLIENT_CONFIG_CHANGED</DFN> bit is included, and this bit is
+ * signalled by the component, then the function will return an error
+ * code.
+ *
+ * @param timeout Specifies how long to block for in milliseconds
+ * before returning a failure.
+ *
+ * @return 0 indicates success, a matching event has been removed from
+ * the component's event queue.  A negative return indicates failure,
+ * in this case no events have been removed from the component's event
+ * queue.
+ *  - -1: a timeout was received.
+ *  - -2: an error event was received.
+ *  - -3: a config changed event was received.
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ ilclient_wait_for_event(COMPONENT_T *comp,
+                                             OMX_EVENTTYPE event,
+                                             OMX_U32 nData1,
+                                             int ignore1,
+                                             OMX_U32 nData2,
+                                             int ignore2,
+                                             int event_flag,
+                                             int timeout);
+
+
+/**
+ * The <DFN>ilclient_wait_for_command_complete()</DFN> function waits
+ * for a message from a component that indicates that the command
+ * has completed.  This is either a command success message, or an 
+ * error message that signals the completion of an event.
+ * 
+ * @param comp The component currently processing a command.
+ *
+ * @param command The command being processed.  This must be either
+ * <DFN>OMX_CommandStateSet</DFN>, <DFN>OMX_CommandPortDisable</DFN>
+ * or <DFN>OMX_CommandPortEnable</DFN>.
+ *
+ * @param nData2 The expected value of <DFN>nData2</DFN> in the
+ * command complete message.
+ *
+ * @return 0 indicates success, either the command successfully completed
+ * or the <DFN>OMX_ErrorSameState</DFN> was returned.  -1 indicates
+ * that the command terminated with a different error message.
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ ilclient_wait_for_command_complete(COMPONENT_T *comp,
+                                                        OMX_COMMANDTYPE command,
+                                                        OMX_U32 nData2);
+
+
+/**
+ * The <DFN>ilclient_wait_for_command_complete_dual()</DFN> function
+ * is similar to <DFN>ilclient_wait_for_command_complete()</DFN>.  The
+ * difference is that while waiting for the component to complete the
+ * event or raise an error, we can also report if another reports an
+ * error that terminates a command.  This is useful if the two
+ * components are tunneled, and we need to wait for one component to
+ * enable a port, or change state to <DFN>OMX_StateIdle</DFN>.  If the
+ * other component is the buffer supplier and reports an error, then
+ * it will not allocate buffers, so our first component may stall.
+ * 
+ * @param comp The component currently processing a command.
+ *
+ * @param command The command being processed.  This must be either
+ * <DFN>OMX_CommandStateSet</DFN>, <DFN>OMX_CommandPortDisable</DFN>
+ * or <DFN>OMX_CommandPortEnable</DFN>.
+ *
+ * @param nData2 The expected value of <DFN>nData2</DFN> in the
+ * command complete message.
+ *
+ * @param related Another component, where we will return if this
+ * component raises an error that terminates a command.
+ *
+ * @return 0 indicates success, either the command successfully
+ * completed or the <DFN>OMX_ErrorSameState</DFN> was returned.  -1
+ * indicates that the command terminated with a different error
+ * message. -2 indicates that the related component raised an error.
+ * In this case, the error is not cleared from the related
+ * component's event list.
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ ilclient_wait_for_command_complete_dual(COMPONENT_T *comp,
+                                                             OMX_COMMANDTYPE command,
+                                                             OMX_U32 nData2,
+                                                             COMPONENT_T *related);
+                                                             
+
+/**
+ * The <DFN>ilclient_debug_output()</DFN> function adds a message to a 
+ * host-specific debug display.  For a local VideoCore host the message is
+ * added to the internal message log.  For a Win32 host the message is
+ * printed to the debug display.  This function should be customised
+ * when IL client is ported to another platform.
+ * 
+ * @param format A message to add, together with the variable
+ * argument list similar to <DFN>printf</DFN> and other standard C functions.
+ *
+ * @return void
+ ***********************************************************/
+VCHPRE_ void VCHPOST_ ilclient_debug_output(char *format, ...);
+
+/**
+ * The <DFN>ilclient_get_handle()</DFN> function returns the
+ * underlying OMX component held by an IL component handle.  This is
+ * needed when calling methods such as <DFN>OMX_SetParameter</DFN> on
+ * a component created using the IL client library.
+ *
+ * @param comp  IL component handle
+ *
+ * @return The <DFN>OMX_HANDLETYPE</DFN> value for the component.
+ ***********************************************************/
+VCHPRE_ OMX_HANDLETYPE VCHPOST_ ilclient_get_handle(COMPONENT_T *comp);
+
+
+#ifndef OMX_SKIP64BIT
+
+/**
+ * Macro to return <DFN>OMX_TICKS</DFN> from a signed 64 bit value.
+ * This is the version where <DFN>OMX_TICKS</DFN> is a signed 64 bit
+ * value, an alternative definition is used when <DFN>OMX_TICKS</DFN>
+ * is a structure.
+ */
+#define ilclient_ticks_from_s64(s) (s)
+
+/**
+ * Macro to return signed 64 bit value from <DFN>OMX_TICKS</DFN>.
+ * This is the version where <DFN>OMX_TICKS</DFN> is a signed 64 bit
+ * value, an alternative definition is used when <DFN>OMX_TICKS</DFN>
+ * is a structure.
+ */
+#define ilclient_ticks_to_s64(t)   (t)
+
+#else
+
+/**
+ * Inline function to return <DFN>OMX_TICKS</DFN> from a signed 64 bit
+ * value.  This is the version where <DFN>OMX_TICKS</DFN> is a
+ * structure, an alternative definition is used when
+ * <DFN>OMX_TICKS</DFN> is a signed 64 bit value.
+ */
+static inline OMX_TICKS ilclient_ticks_from_s64(int64_t s) {
+   OMX_TICKS ret;
+   ret.nLowPart = s;
+   ret.nHighPart = s>>32;
+   return ret;
+}
+
+/**
+ * Inline function to return signed 64 bit value from
+ * <DFN>OMX_TICKS</DFN>.  This is the version where
+ * <DFN>OMX_TICKS</DFN> is a structure, an alternative definition is
+ * used when <DFN>OMX_TICKS</DFN> is a signed 64 bit value.
+ */
+static inline int64_t ilclient_ticks_to_s64(OMX_TICKS t) {
+   uint64_t u = t.nLowPart | ((uint64_t)t.nHighPart << 32);
+   return u;
+}
+
+
+#endif /* OMX_SKIP64BIT */
+
+/**
+ * The <DFN>ilclient_get_port_index()</DFN> function returns the n'th
+ * port index of the specified type and direction for the given
+ * component.
+ *
+ * @param comp    The component of interest
+ * @param dir     The direction
+ * @param type    The type, or -1 for any type.
+ * @param index   Which port (counting from 0).
+ *
+ * @return        The port index, or -1 if not found.
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ ilclient_get_port_index(COMPONENT_T *comp,
+                                             OMX_DIRTYPE dir,
+                                             OMX_PORTDOMAINTYPE type,
+                                             int index);
+
+
+/**
+ * The <DFN>ilclient_suggest_bufsize()</DFN> function gives a
+ * component a hint about the size of buffer it should use.  This size
+ * is set on the component by setting the
+ * <DFN>OMX_IndexParamBrcmOutputBufferSize</DFN> index on the given
+ * component.
+ *
+ * @param comp         IL component handle
+ * @param nBufSizeHint Size of buffer in bytes
+ *
+ * @return             0 indicates success, -1 indicates failure.
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ ilclient_suggest_bufsize(COMPONENT_T *comp,
+                                              OMX_U32 nBufSizeHint);
+
+
+/**
+ * The <DFN>ilclient_stack_size()</DFN> function suggests a minimum
+ * stack size that tasks calling into with API will require.
+ *
+ * @return    Suggested stack size in bytes.
+ ***********************************************************/
+VCHPRE_ unsigned int VCHPOST_ ilclient_stack_size(void);
+
+#endif /* ILCLIENT_H */
diff --git a/host_applications/linux/apps/hello_pi/libs/ilclient/ilcore.c b/host_applications/linux/apps/hello_pi/libs/ilclient/ilcore.c
new file mode 100755 (executable)
index 0000000..356733d
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * \file
+ *
+ * \brief Host core implementation.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+//includes
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "IL/OMX_Component.h"
+#include "interface/vcos/vcos.h"
+
+#include "interface/vmcs_host/vcilcs.h"
+#include "interface/vmcs_host/vchost.h"
+#include "interface/vmcs_host/vcilcs_common.h"
+
+static int coreInit = 0;
+static int nActiveHandles = 0;
+static ILCS_SERVICE_T *ilcs_service = NULL;
+static VCOS_MUTEX_T lock;
+static VCOS_ONCE_T once = VCOS_ONCE_INIT;
+
+/* Atomic creation of lock protecting shared state */
+static void initOnce(void)
+{
+   VCOS_STATUS_T status;
+   status = vcos_mutex_create(&lock, VCOS_FUNCTION);
+   vcos_demand(status == VCOS_SUCCESS);
+}
+
+/* OMX_Init */
+OMX_ERRORTYPE OMX_APIENTRY OMX_Init(void)
+{
+   VCOS_STATUS_T status;
+   OMX_ERRORTYPE err = OMX_ErrorNone;
+
+   status = vcos_once(&once, initOnce);
+   vcos_demand(status == VCOS_SUCCESS);
+
+   vcos_mutex_lock(&lock);
+   
+   if(coreInit == 0)
+   {
+      // we need to connect via an ILCS connection to VideoCore
+      VCHI_INSTANCE_T initialise_instance;
+      VCHI_CONNECTION_T *connection;
+      ILCS_CONFIG_T config;
+
+      vc_host_get_vchi_state(&initialise_instance, &connection);
+
+      vcilcs_config(&config);
+
+      ilcs_service = ilcs_init((VCHIQ_INSTANCE_T) initialise_instance, (void **) &connection, &config, 0);
+
+      if(ilcs_service == NULL)
+      {
+         err = OMX_ErrorHardware;
+         goto end;
+      }
+
+      coreInit = 1;
+   }
+   else
+      coreInit++;
+
+end:
+   vcos_mutex_unlock(&lock);
+   return err;
+}
+
+/* OMX_Deinit */
+OMX_ERRORTYPE OMX_APIENTRY OMX_Deinit(void)
+{
+   if(coreInit == 0) // || (coreInit == 1 && nActiveHandles > 0))
+      return OMX_ErrorNotReady;
+
+   vcos_mutex_lock(&lock);
+
+   coreInit--;
+
+   if(coreInit == 0)
+   {
+      // we need to teardown the ILCS connection to VideoCore
+      ilcs_deinit(ilcs_service);
+      ilcs_service = NULL;
+   }
+
+   vcos_mutex_unlock(&lock);
+   
+   return OMX_ErrorNone;
+}
+
+
+/* OMX_ComponentNameEnum */
+OMX_ERRORTYPE OMX_APIENTRY OMX_ComponentNameEnum(
+   OMX_OUT OMX_STRING cComponentName,
+   OMX_IN  OMX_U32 nNameLength,
+   OMX_IN  OMX_U32 nIndex)
+{
+   if(ilcs_service == NULL)
+      return OMX_ErrorBadParameter;
+
+   return vcil_out_component_name_enum(ilcs_get_common(ilcs_service), cComponentName, nNameLength, nIndex);
+}
+
+
+/* OMX_GetHandle */
+OMX_ERRORTYPE OMX_APIENTRY OMX_GetHandle(
+   OMX_OUT OMX_HANDLETYPE* pHandle,
+   OMX_IN  OMX_STRING cComponentName,
+   OMX_IN  OMX_PTR pAppData,
+   OMX_IN  OMX_CALLBACKTYPE* pCallBacks)
+{
+   OMX_ERRORTYPE eError;
+   OMX_COMPONENTTYPE *pComp;
+   OMX_HANDLETYPE hHandle = 0;
+
+   if (pHandle == NULL || cComponentName == NULL || pCallBacks == NULL || ilcs_service == NULL)
+   {
+      if(pHandle)
+         *pHandle = NULL;
+      return OMX_ErrorBadParameter;
+   }
+
+   {
+      pComp = (OMX_COMPONENTTYPE *)malloc(sizeof(OMX_COMPONENTTYPE));
+      if (!pComp)
+      {
+         vcos_assert(0);
+         return OMX_ErrorInsufficientResources;
+      }
+      memset(pComp, 0, sizeof(OMX_COMPONENTTYPE));
+      hHandle = (OMX_HANDLETYPE)pComp;
+      pComp->nSize = sizeof(OMX_COMPONENTTYPE);
+      pComp->nVersion.nVersion = OMX_VERSION;
+      eError = vcil_out_create_component(ilcs_get_common(ilcs_service), hHandle, cComponentName);
+
+      if (eError == OMX_ErrorNone) {
+         // Check that all function pointers have been filled in.
+         // All fields should be non-zero.
+         int i;
+         uint32_t *p = (uint32_t *) pComp;
+         for(i=0; i<sizeof(OMX_COMPONENTTYPE)>>2; i++)
+            if(*p++ == 0)
+               eError = OMX_ErrorInvalidComponent;
+
+         if(eError != OMX_ErrorNone && pComp->ComponentDeInit)
+            pComp->ComponentDeInit(hHandle);
+      }      
+
+      if (eError == OMX_ErrorNone) {
+         eError = pComp->SetCallbacks(hHandle,pCallBacks,pAppData);
+         if (eError != OMX_ErrorNone)
+            pComp->ComponentDeInit(hHandle);
+      }
+      if (eError == OMX_ErrorNone) {
+         *pHandle = hHandle;
+      }
+      else {
+         *pHandle = NULL;
+         free(pComp);
+      }
+   } 
+
+   if (eError == OMX_ErrorNone) {
+      vcos_mutex_lock(&lock);
+      nActiveHandles++;
+      vcos_mutex_unlock(&lock);
+   }
+
+   return eError;
+}
+
+/* OMX_FreeHandle */
+OMX_ERRORTYPE OMX_APIENTRY OMX_FreeHandle(
+   OMX_IN  OMX_HANDLETYPE hComponent)
+{
+   OMX_ERRORTYPE eError = OMX_ErrorNone;
+   OMX_COMPONENTTYPE *pComp;
+
+   if (hComponent == NULL || ilcs_service == NULL)
+      return OMX_ErrorBadParameter;
+
+   pComp = (OMX_COMPONENTTYPE*)hComponent;
+
+   if (ilcs_service == NULL)
+      return OMX_ErrorBadParameter;
+
+   eError = (pComp->ComponentDeInit)(hComponent);
+   if (eError == OMX_ErrorNone) {
+      vcos_mutex_lock(&lock);
+      --nActiveHandles;
+      vcos_mutex_unlock(&lock);
+      free(pComp);
+   }
+
+   vcos_assert(nActiveHandles >= 0);
+
+   return eError;
+}
+
+/* OMX_SetupTunnel */
+OMX_ERRORTYPE OMX_APIENTRY OMX_SetupTunnel(
+   OMX_IN  OMX_HANDLETYPE hOutput,
+   OMX_IN  OMX_U32 nPortOutput,
+   OMX_IN  OMX_HANDLETYPE hInput,
+   OMX_IN  OMX_U32 nPortInput)
+{
+   OMX_ERRORTYPE eError = OMX_ErrorNone;
+   OMX_COMPONENTTYPE *pCompIn, *pCompOut;
+   OMX_TUNNELSETUPTYPE oTunnelSetup;
+
+   if ((hOutput == NULL && hInput == NULL) || ilcs_service == NULL)
+      return OMX_ErrorBadParameter;
+
+   oTunnelSetup.nTunnelFlags = 0;
+   oTunnelSetup.eSupplier = OMX_BufferSupplyUnspecified;
+
+   pCompOut = (OMX_COMPONENTTYPE*)hOutput;
+
+   if (hOutput){
+      eError = pCompOut->ComponentTunnelRequest(hOutput, nPortOutput, hInput, nPortInput, &oTunnelSetup);
+   }
+
+   if (eError == OMX_ErrorNone && hInput) {
+      pCompIn = (OMX_COMPONENTTYPE*)hInput;
+      eError = pCompIn->ComponentTunnelRequest(hInput, nPortInput, hOutput, nPortOutput, &oTunnelSetup);
+
+      if (eError != OMX_ErrorNone && hOutput) {
+         /* cancel tunnel request on output port since input port failed */
+         pCompOut->ComponentTunnelRequest(hOutput, nPortOutput, NULL, 0, NULL);
+      }
+   }
+   return eError;
+}
+
+/* OMX_GetComponentsOfRole */
+OMX_ERRORTYPE OMX_GetComponentsOfRole (
+   OMX_IN      OMX_STRING role,
+   OMX_INOUT   OMX_U32 *pNumComps,
+   OMX_INOUT   OMX_U8  **compNames)
+{
+   OMX_ERRORTYPE eError = OMX_ErrorNone;
+
+   *pNumComps = 0;
+   return eError;
+}
+
+/* OMX_GetRolesOfComponent */
+OMX_ERRORTYPE OMX_GetRolesOfComponent (
+   OMX_IN      OMX_STRING compName,
+   OMX_INOUT   OMX_U32 *pNumRoles,
+   OMX_OUT     OMX_U8 **roles)
+{
+   OMX_ERRORTYPE eError = OMX_ErrorNone;
+
+   *pNumRoles = 0;
+   return eError;
+}
+
+/* OMX_GetDebugInformation */
+OMX_ERRORTYPE OMX_GetDebugInformation (
+   OMX_OUT    OMX_STRING debugInfo,
+   OMX_INOUT  OMX_S32 *pLen)
+{
+   if(ilcs_service == NULL)
+      return OMX_ErrorBadParameter;
+
+   return vcil_out_get_debug_information(ilcs_get_common(ilcs_service), debugInfo, pLen);
+}
+
+
+
+/* File EOF */
+
diff --git a/host_applications/linux/apps/hello_pi/libs/vgfont/Makefile b/host_applications/linux/apps/hello_pi/libs/vgfont/Makefile
new file mode 100755 (executable)
index 0000000..1e2a22b
--- /dev/null
@@ -0,0 +1,7 @@
+OBJS=font.o vgft.o graphics.o
+LIB=libvgfont.a
+
+INCLUDES+=-I$(SDKSTAGE)/usr/include/freetype2 -I$(SDKSTAGE)/usr/include -I$(SDKSTAGE)/usr/include/arm-linux-gnueabi
+
+include ../../Makefile.include
+
diff --git a/host_applications/linux/apps/hello_pi/libs/vgfont/font.c b/host_applications/linux/apps/hello_pi/libs/vgfont/font.c
new file mode 100755 (executable)
index 0000000..7da2a4e
--- /dev/null
@@ -0,0 +1,355 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Font handling for graphicsx
+
+/** @file font.c
+  *
+  * Fairly primitive font handling, just enough to emulate the old API.
+  *
+  * Hinting and Font Size
+  *
+  * The old API does not create fonts explicitly, it just renders them
+  * as needed. That works fine for unhinted fonts, but for hinted fonts we
+  * care about font size.
+  *
+  * Since we now *can* do hinted fonts, we should do. Regenerating the
+  * fonts each time becomes quite slow, so we maintain a cache of fonts.
+  *
+  * For the typical applications which use graphics_x this is fine, but
+  * won't work well if lots of fonts sizes are used.
+  *
+  * Unicode
+  *
+  * This API doesn't support unicode at all at present, nor UTF-8.
+  */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "graphics_x_private.h"
+#include "vgft.h"
+
+#define VMCS_INSTALL_PREFIX ""
+
+/** The one and only (default) font we support for now.
+  */
+static struct
+{
+   const char *file;
+   void *mem;
+   size_t len;
+} default_font = { "Vera.ttf" };
+
+/** An entry in our list of fonts
+  */
+typedef struct gx_font_cache_entry_t
+{
+   struct gx_font_cache_entry_t *next;
+   VGFT_FONT_T font;
+   uint32_t ptsize;                    /** size in points, 26.6 */
+} gx_font_cache_entry_t;
+
+static char fname[128];
+static int inited;
+static gx_font_cache_entry_t *fonts;
+
+static VGFT_FONT_T *find_font(const char *text, uint32_t text_size);
+
+VCOS_STATUS_T gx_priv_font_init(const char *font_dir)
+{
+   VCOS_STATUS_T ret;
+   size_t len;
+   int rc;
+   if (vgft_init())
+   {
+      ret = VCOS_ENOMEM;
+      goto fail_init;
+   }
+
+   int fd = -1;
+   // search for the font
+   sprintf(fname, "%s/%s", font_dir, default_font.file);
+   fd = open(fname, O_RDONLY);
+
+   if (fd < 0)
+   {
+      GX_ERROR("Could not open font file '%s'", default_font.file);
+      ret = VCOS_ENOENT;
+      goto fail_open;
+   }
+
+   len = lseek(fd, 0, SEEK_END);
+   lseek(fd, 0, SEEK_SET);
+
+   default_font.mem = vcos_malloc(len, default_font.file);
+   if (!default_font.mem)
+   {
+      GX_ERROR("No memory for font %s", fname);
+      ret = VCOS_ENOMEM;
+      goto fail_mem;
+   }
+
+   rc = read(fd, default_font.mem, len);
+   if (rc != len)
+   {
+      GX_ERROR("Could not read font %s", fname);
+      ret = VCOS_EINVAL;
+      goto fail_rd;
+   }
+   default_font.len = len;
+   close(fd);
+
+   GX_TRACE("Opened font file '%s'", fname);
+
+   inited = 1;
+   return VCOS_SUCCESS;
+
+fail_rd:
+   vcos_free(default_font.mem);
+fail_mem:
+   if (fd >= 0) close(fd);
+fail_open:
+   vgft_term();
+fail_init:
+   return ret;
+}
+
+void gx_priv_font_term(void)
+{
+   gx_font_cache_flush();
+   vgft_term();
+   vcos_free(default_font.mem);
+}
+
+/** Render text.
+  *
+  * FIXME: Not at all optimal - re-renders each time.
+  * FIXME: Not UTF-8 aware
+  * FIXME: better caching
+  */
+VCOS_STATUS_T gx_priv_render_text( GX_DISPLAY_T *disp,
+                                   GRAPHICS_RESOURCE_HANDLE res,
+                                   int32_t x,
+                                   int32_t y,
+                                   uint32_t width,
+                                   uint32_t height,
+                                   uint32_t fg_colour,
+                                   uint32_t bg_colour,
+                                   const char *text,
+                                   uint32_t text_length,
+                                   uint32_t text_size )
+{
+   VGfloat vg_colour[4];
+   VGFT_FONT_T *font;
+   VGPaint fg;
+   GX_CLIENT_STATE_T save;
+   VCOS_STATUS_T status = VCOS_SUCCESS;
+   int clip = 1;
+
+   vcos_demand(inited); // has gx_font_init() been called?
+
+   gx_priv_save(&save, res);
+
+   if (width == GRAPHICS_RESOURCE_WIDTH &&
+       height == GRAPHICS_RESOURCE_HEIGHT)
+   {
+      clip = 0;
+   }
+
+   width = (width == GRAPHICS_RESOURCE_WIDTH) ? res->width : width;
+   height = (height == GRAPHICS_RESOURCE_HEIGHT) ? res->height : height;
+   font = find_font(text, text_size);
+   if (!font)
+   {
+      status = VCOS_ENOMEM;
+      goto finish;
+   }
+
+   // setup the clipping rectangle
+   if (clip)
+   {
+      VGint coords[] = {x,y,width,height};
+      vgSeti(VG_SCISSORING, VG_TRUE);
+      vgSetiv(VG_SCISSOR_RECTS, 4, coords);
+   }
+
+   // setup the background colour if needed
+   if (bg_colour != GRAPHICS_TRANSPARENT_COLOUR)
+   {
+      int err;
+      VGfloat rendered_w, rendered_h;
+      VGfloat vg_bg_colour[4];
+
+      // setup the background colour...
+      gx_priv_colour_to_paint(bg_colour, vg_bg_colour);
+      vgSetfv(VG_CLEAR_COLOR, 4, vg_bg_colour);
+
+      // fill in a rectangle...
+      vgft_get_text_extents(font, text, text_length, (VGfloat)x, (VGfloat)y, &rendered_w, &rendered_h);
+
+      if ( ( 0 < (VGint)rendered_w ) && ( 0 < (VGint)rendered_h ) )
+      {
+         // Have to compensate for the messed up y position of multiline text.
+         VGfloat offset = vgft_first_line_y_offset(font);
+         int32_t bottom = y + offset - rendered_h;
+
+         vgClear(x, bottom, (VGint)rendered_w, (VGint)rendered_h);
+         err = vgGetError();
+         if (err)
+         {
+            GX_LOG("Error %d clearing bg text %d %d %g %g",
+                   err, x, y, rendered_w, rendered_h);
+            vcos_assert(0);
+         } // if
+      } // if
+   } // if
+   // setup the foreground colour
+   fg = vgCreatePaint();
+   if (!fg)
+   {
+      status = VCOS_ENOMEM;
+      goto finish;
+   }
+
+   // draw the foreground text
+   vgSetParameteri(fg, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR);
+   gx_priv_colour_to_paint(fg_colour, vg_colour);
+   vgSetParameterfv(fg, VG_PAINT_COLOR, 4, vg_colour);
+   vgSetPaint(fg, VG_FILL_PATH);
+
+   vgft_font_draw(font, (VGfloat)x, (VGfloat)y, text, text_length, VG_FILL_PATH);
+
+   vgDestroyPaint(fg);
+
+   vcos_assert(vgGetError() == 0);
+   vgSeti(VG_SCISSORING, VG_FALSE);
+
+finish:
+   gx_priv_restore(&save);
+
+   return status;
+}
+
+
+/** Find a font in our cache, or create a new entry in the cache.
+  *
+  * Very primitive at present.
+  */
+static VGFT_FONT_T *find_font(const char *text, uint32_t text_size)
+{
+   int ptsize, dpi_x = 0, dpi_y = 0;
+   VCOS_STATUS_T status;
+   gx_font_cache_entry_t *font;
+
+   ptsize = text_size << 6; // freetype takes size in points, in 26.6 format.
+
+   for (font = fonts; font; font = font->next)
+   {
+      if (font->ptsize == ptsize)
+         return &font->font;
+   }
+
+   font = vcos_malloc(sizeof(*font), "font");
+   if (!font)
+      return NULL;
+
+   font->ptsize = ptsize;
+
+   status = vgft_font_init(&font->font);
+   if (status != VCOS_SUCCESS)
+   {
+      vcos_free(font);
+      return NULL;
+   }
+
+   // load the font
+   status = vgft_font_load_mem(&font->font, default_font.mem, default_font.len);
+   if (status != VCOS_SUCCESS)
+   {
+      GX_LOG("Could not load font from memory: %d", status);
+      vgft_font_term(&font->font);
+      vcos_free(font);
+      return NULL;
+   }
+
+   status = vgft_font_convert_glyphs(&font->font, ptsize, dpi_x, dpi_y);
+   if (status != VCOS_SUCCESS)
+   {
+      GX_LOG("Could not convert font '%s' at size %d", fname, ptsize);
+      vgft_font_term(&font->font);
+      vcos_free(font);
+      return NULL;
+   }
+
+   font->next = fonts;
+   fonts = font;
+
+   return &font->font;
+}
+
+void gx_font_cache_flush(void)
+{
+   while (fonts != NULL)
+   {
+      struct gx_font_cache_entry_t *next = fonts->next;
+      vgft_font_term(&fonts->font);
+      vcos_free(fonts);
+      fonts = next;
+   }
+}
+
+int32_t graphics_resource_text_dimensions_ext(GRAPHICS_RESOURCE_HANDLE res,
+                                              const char *text,
+                                              const uint32_t text_length,
+                                              uint32_t *width,
+                                              uint32_t *height,
+                                              const uint32_t text_size )
+{
+   GX_CLIENT_STATE_T save;
+   VGfloat w, h;
+   int ret = -1;
+
+   gx_priv_save(&save, res);
+
+   VGFT_FONT_T *font = find_font(text, text_size);
+   if (!font)
+      goto finish;
+
+
+   vgft_get_text_extents(font, text, text_length, 0.0, 0.0, &w, &h);
+   *width = w;
+   *height = h;
+   ret = 0;
+
+finish:
+   gx_priv_restore(&save);
+   return ret;
+}
+
diff --git a/host_applications/linux/apps/hello_pi/libs/vgfont/graphics.c b/host_applications/linux/apps/hello_pi/libs/vgfont/graphics.c
new file mode 100755 (executable)
index 0000000..20e1d5a
--- /dev/null
@@ -0,0 +1,1609 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Graphics library for VG
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include "vgfont.h"
+#include "graphics_x_private.h"
+
+/******************************************************************************
+Defines.
+******************************************************************************/
+#define ATEXT_FONT_SIZE 12 /*< Default font size (font size can be set with *_ext functions). */
+
+/******************************************************************************
+Local data
+******************************************************************************/
+static GX_DISPLAY_T display; /*< Our one and only EGL display. */
+
+/**
+ * We create one eglContext for each of the possible graphics_x resource types 
+ * that are supported.
+ ***********************************************************/
+static EGLContext gx_contexts[GRAPHICS_RESOURCE_HANDLE_TYPE_MAX]; 
+
+/** Note: we have to share all our contexts, because otherwise it seems
+ * to be not valid to blit from one image to another if the images
+ * have different contexts.
+ *
+ * That means we have to use a single global lock to serialise all accesses
+ * to any contexts.
+ ***********************************************************/
+static VCOS_MUTEX_T lock;
+
+static EGLConfig gx_configs[GRAPHICS_RESOURCE_HANDLE_TYPE_MAX];
+
+static int inited;
+
+/******************************************************************************
+Local Functions
+******************************************************************************/
+
+/** Convert graphics_x colour formats into EGL format. */
+static int gx_egl_attrib_colours(EGLint *attribs, GRAPHICS_RESOURCE_TYPE_T res_type)
+{
+   int i, n;
+   static EGLint rgba[] = {EGL_RED_SIZE, EGL_GREEN_SIZE, EGL_BLUE_SIZE, EGL_ALPHA_SIZE};
+   static uint8_t rgb565[] = {5,6,5,0};
+   static uint8_t rgb888[] = {8,8,8,0};
+   static uint8_t rgb32a[] = {8,8,8,8};
+
+   uint8_t *sizes = NULL;
+
+   switch (res_type)
+   {
+      case GRAPHICS_RESOURCE_RGB565:
+         sizes = rgb565;
+         break;
+      case GRAPHICS_RESOURCE_RGB888:
+         sizes = rgb888;
+         break;
+      case GRAPHICS_RESOURCE_RGBA32:
+         sizes = rgb32a;
+         break;
+      default:
+         vcos_assert(0);
+         return -1;
+   }
+   for (n=0, i=0; i<countof(rgba); i++)
+   {
+      attribs[n++] = rgba[i];
+      attribs[n++] = sizes[i];
+   }
+   return n;
+}
+
+/* Create an EGLContext for a given GRAPHICS_RESOURCE_TYPE */
+static VCOS_STATUS_T create_context(EGLDisplay disp, 
+                                    GRAPHICS_RESOURCE_TYPE_T image_type,
+                                    EGLContext *shared_with)
+{
+   int n;
+   EGLConfig configs[1];
+   EGLint nconfigs, attribs[32];
+   n = gx_egl_attrib_colours(attribs, image_type);
+
+   // we want to be able to do OpenVG on this surface...
+   attribs[n++] = EGL_RENDERABLE_TYPE; attribs[n++] = EGL_OPENVG_BIT;
+   attribs[n++] = EGL_SURFACE_TYPE;    attribs[n++] = EGL_WINDOW_BIT;
+
+   attribs[n] = EGL_NONE;
+
+   EGLBoolean egl_ret = eglChooseConfig(disp,
+                                        attribs, configs,
+                                        countof(configs), &nconfigs);
+
+   if (!egl_ret || !nconfigs)
+   {
+      GX_LOG("%s: no suitable configurations for res type %d",
+             __FUNCTION__, image_type);
+      return VCOS_EINVAL;
+   }
+
+   EGLContext cxt = eglCreateContext(disp, configs[0], *shared_with, 0);
+   if (!cxt)
+   {
+      GX_LOG("Could not create context for image type %d: 0x%x",
+             image_type, eglGetError());
+      return VCOS_ENOSPC;
+   }
+   
+   gx_contexts[image_type] = cxt;
+   gx_configs[image_type] = configs[0];
+   *shared_with = cxt;
+
+   return VCOS_SUCCESS;
+}
+
+/******************************************************************************
+Functions private to code inside GraphicsX
+******************************************************************************/
+
+static VCOS_STATUS_T gx_priv_initialise( void )
+{
+   int i;
+   EGLDisplay disp;
+   EGLint egl_maj, egl_min;
+   int32_t ret = VCOS_EINVAL;
+   EGLBoolean result;
+
+   vcos_demand(inited == 0);
+
+   vcos_log_set_level(&gx_log_cat, VCOS_LOG_WARN);
+   vcos_log_register("graphics", &gx_log_cat);
+
+   memset(&display,0,sizeof(display));
+
+   gx_priv_init();
+
+   disp = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+
+   if (disp == EGL_NO_DISPLAY)
+   {
+      GX_LOG("Could not open display: 0x%x", eglGetError());
+      vcos_assert(0);
+      goto fail_disp;
+   }
+
+   result = eglInitialize(disp, &egl_maj, &egl_min);
+   if (!result)
+   {
+      GX_LOG("Could not init display :0x%x", eglGetError());
+      vcos_assert(0); // really can't continue
+      goto fail_egl_init;
+   }
+
+   result = eglBindAPI(EGL_OPENVG_API);
+   vcos_assert(result); // really should succeed
+
+   display.disp = disp;
+
+   GX_TRACE("Supported client APIS: %s", eglQueryString(disp, EGL_CLIENT_APIS));
+
+   // create the available contexts
+   EGLContext shared_context = EGL_NO_CONTEXT;
+   ret =  create_context(disp,GRAPHICS_RESOURCE_RGB565, &shared_context);
+   ret |= create_context(disp,GRAPHICS_RESOURCE_RGB888, &shared_context);
+   ret |= create_context(disp,GRAPHICS_RESOURCE_RGBA32, &shared_context);
+
+   if (ret != VCOS_SUCCESS)
+      goto fail_cxt;
+
+   eglSwapInterval(disp, 1);
+
+   inited = 1;
+
+   return ret;
+
+fail_cxt:
+   for (i=0; i<GRAPHICS_RESOURCE_HANDLE_TYPE_MAX; i++)
+   {
+      if (gx_contexts[i])
+      {
+         eglDestroyContext(display.disp,gx_contexts[i]);
+         vcos_mutex_delete(&lock);
+      }
+   }
+   eglTerminate(display.disp);
+fail_egl_init:
+fail_disp:
+   return ret;
+}
+
+/*****************************************************************************/
+void gx_priv_save(GX_CLIENT_STATE_T *state, GRAPHICS_RESOURCE_HANDLE res)
+{
+   EGLBoolean egl_result;
+   vcos_assert(res == NULL || (res->magic == RES_MAGIC));
+   vcos_assert(res == NULL || !res->context_bound);
+
+   state->context      = eglGetCurrentContext();
+   state->api          = eglQueryAPI();
+   state->read_surface = eglGetCurrentSurface(EGL_READ);
+   state->draw_surface = eglGetCurrentSurface(EGL_DRAW);
+   state->res = res;
+
+   vcos_assert(state->api); // should never be anything other than VG or GL
+   
+   vcos_mutex_lock(&lock);
+
+   egl_result = eglBindAPI(EGL_OPENVG_API);
+   vcos_assert(egl_result);
+   
+   if (res)
+   {
+      GX_TRACE("gx_priv_save: eglMakeCurrent: %s, res %x surface %x, cxt %x", vcos_thread_get_name(vcos_thread_current()), 
+         (uint32_t)res, (uint32_t)res->surface, (uint32_t)res->context);
+
+      egl_result = eglMakeCurrent(display.disp, res->surface, 
+                                  res->surface, res->context);
+      vcos_assert(egl_result);
+      
+      res->context_bound = 1;
+   }
+}
+
+/*****************************************************************************/
+void gx_priv_restore(GX_CLIENT_STATE_T *state)
+{
+   EGLBoolean egl_result;
+
+   GX_TRACE("gx_priv_restore: eglMakeCurrent: %s, res %x draw_surface %x, surface %x, cxt %x", vcos_thread_get_name(vcos_thread_current()),
+      (uint32_t)state->res, (uint32_t)state->draw_surface, (uint32_t)state->read_surface, (uint32_t)state->context);
+
+   // disconnect our thread from this context, so we other threads can use it via
+   // this API
+   egl_result = eglMakeCurrent(display.disp, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+   vcos_assert(egl_result);
+
+   // now return to the client's API binding
+   egl_result = eglBindAPI(state->api);
+   vcos_assert(egl_result);
+
+   egl_result = eglMakeCurrent(display.disp, state->draw_surface, state->read_surface, state->context);
+   vcos_assert(egl_result);
+
+   if (state->res) state->res->context_bound = 0;
+   
+   vcos_mutex_unlock(&lock);
+}
+
+/******************************************************************************
+Functions and data exported as part of the public GraphicsX API
+******************************************************************************/
+
+VCOS_LOG_CAT_T gx_log_cat; /*< Logging category for GraphicsX. */
+
+int32_t graphics_initialise( void )
+{
+   // dummy initialisation function. This is typically called
+   // early in the day before VLLs are available, and so cannot
+   // do anything useful.
+   return 0;
+}
+
+/*****************************************************************************/
+int32_t graphics_uninitialise( void )
+{
+   int i;
+   vcos_assert(inited);
+
+   gx_priv_font_term();
+
+   for (i=0; i<GRAPHICS_RESOURCE_HANDLE_TYPE_MAX; i++)
+      if (gx_contexts[i])
+         eglDestroyContext(display.disp,gx_contexts[i]);
+
+   eglTerminate(display.disp);
+   gx_priv_destroy();
+   vcos_log_unregister(&gx_log_cat);
+   inited = 0;
+   return 0;
+}
+
+/*****************************************************************************/
+VCOS_STATUS_T gx_create_window( uint32_t screen_id,
+                                uint32_t width,
+                                uint32_t height,
+                                GRAPHICS_RESOURCE_TYPE_T image_type,
+                                GRAPHICS_RESOURCE_HANDLE *resource_handle )
+{
+   int rc;
+   VCOS_STATUS_T status = VCOS_SUCCESS;
+   GRAPHICS_RESOURCE_HANDLE h;
+   EGLBoolean egl_result;
+   void *cookie;
+   GX_CLIENT_STATE_T save;
+
+   if (!gx_contexts[image_type])
+   {
+      GX_LOG("Invalid image type %d", image_type);
+      return VCOS_EINVAL;
+   }
+
+   h = vcos_calloc(1,sizeof(*h), "graphics_x_resource");
+   if (!h)
+   {
+      GX_LOG("%s: no memory for resource", __FUNCTION__);
+      return VCOS_ENOMEM;
+   }
+
+   // now need to get the native window
+   rc = gx_priv_create_native_window(screen_id, 
+                                     width, height, image_type,
+                                     &h->u.native_window,
+                                     &cookie);
+   if (rc < 0)
+   {
+      GX_LOG("%s: could not create native window", __FUNCTION__);
+      status = VCOS_ENOMEM;
+      goto fail_create_native_win;
+   }
+
+   h->magic = RES_MAGIC;
+   h->type  = GX_WINDOW;
+   h->alpha = 1.0;
+
+   h->surface = eglCreateWindowSurface(display.disp, gx_configs[image_type], &h->u.native_window.egl_win, NULL);
+   if (!h->surface)
+   {
+      GX_LOG("Could not create window surface: 0x%x", eglGetError());
+      status = VCOS_ENOMEM;
+      goto fail_win;
+   }
+
+   egl_result = eglSurfaceAttrib(display.disp, h->surface,
+      EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
+   vcos_assert(egl_result);
+
+   h->context   = gx_contexts[image_type];
+   h->screen_id = screen_id;
+   h->width     = width;
+   h->height    = height;
+   h->restype   = image_type;
+
+   gx_priv_save(&save, h);
+
+   // fill it with black
+   status = gx_priv_resource_fill(h, 0, 0, width, height, GRAPHICS_RGBA32(0,0,0,0xff));
+   vcos_assert(status == VCOS_SUCCESS);
+
+   gx_priv_finish_native_window(h, cookie);
+   gx_priv_flush(h);
+
+   *resource_handle = h;
+   gx_priv_restore(&save);
+   return status;
+
+fail_win:
+   gx_priv_destroy_native_window(h);
+fail_create_native_win:
+   vcos_free(h);
+   gx_priv_restore(&save);
+   return status;
+}
+
+/*****************************************************************************/
+int32_t graphics_delete_resource( GRAPHICS_RESOURCE_HANDLE res )
+{
+   EGLBoolean result;
+
+   if (!res)
+   {
+      // let it slide - mimics old behaviour
+      return 0;
+   }
+   GX_TRACE("delete resource @%p", res);
+
+   vcos_assert(res->magic == RES_MAGIC);
+
+   if (res->type == GX_PBUFFER)
+   {
+      GX_CLIENT_STATE_T save;
+      gx_priv_save(&save, res);
+      vgDestroyImage(res->u.pixmap);
+      vcos_assert(vgGetError() == 0);
+      gx_priv_restore(&save);
+   }
+
+   GX_TRACE("graphics_delete_resource: calling eglDestroySurface...");
+   result = eglDestroySurface(display.disp, res->surface);
+   vcos_assert(result);
+
+   GX_TRACE("graphics_delete_resource: calling eglWaitClient...");
+   eglWaitClient(); // wait for EGL to finish sorting out its surfaces
+
+   if (res->type == GX_WINDOW)
+   {
+      GX_TRACE("graphics_delete_resource: calling gx_priv_destroy_native_window...");
+      gx_priv_destroy_native_window(res);
+   }
+
+   res->magic = ~RES_MAGIC;
+   vcos_free(res);
+   GX_TRACE("graphics_delete_resource: done");
+
+   return 0;
+}
+
+/*****************************************************************************/
+int32_t graphics_update_displayed_resource(GRAPHICS_RESOURCE_HANDLE res,
+                                           const uint32_t x_offset,
+                                           const uint32_t y_offset,
+                                           const uint32_t width,
+                                           const uint32_t height )
+{
+   GX_CLIENT_STATE_T save;
+   gx_priv_save(&save, res);
+      
+   gx_priv_flush(res);
+
+   gx_priv_restore(&save);
+
+   return 0;
+}
+
+/*****************************************************************************/
+int32_t graphics_resource_fill(GRAPHICS_RESOURCE_HANDLE res,
+                               uint32_t x,
+                               uint32_t y,
+                               uint32_t width,
+                               uint32_t height,
+                               uint32_t fill_colour )
+{
+   GX_CLIENT_STATE_T save;
+   gx_priv_save(&save, res);
+   
+   VCOS_STATUS_T st = gx_priv_resource_fill(
+      res, 
+      x, res->height-y-height, 
+      width, height, 
+      fill_colour);
+
+   gx_priv_restore(&save);
+      
+   return st == VCOS_SUCCESS ? 0 : -1;
+}
+
+/*****************************************************************************/
+int32_t graphics_resource_render_text_ext( GRAPHICS_RESOURCE_HANDLE res,
+                                           const int32_t x,
+                                           const int32_t y,
+                                           const uint32_t width,
+                                           const uint32_t height,
+                                           const uint32_t fg_colour,
+                                           const uint32_t bg_colour,
+                                           const char *text,
+                                           const uint32_t text_length,
+                                           const uint32_t text_size )
+{
+
+   /*
+   * FIXME: Not at all optimal - re-renders each time.
+   * FIXME: Not UTF-8 safe
+   * FIXME: much better caching (or any caching)
+   */
+   VCOS_STATUS_T rc = gx_priv_render_text(
+      &display, res, 
+      x, res->height-y-text_size, width, height, fg_colour, bg_colour,
+      text, text_length, text_size);
+
+   return (rc == VCOS_SUCCESS) ? 0 : -1;
+}
+
+/*****************************************************************************/
+int32_t graphics_resource_render_text(  GRAPHICS_RESOURCE_HANDLE res,
+                                        const int32_t x,
+                                        const int32_t y,
+                                        const uint32_t width, /* this can be GRAPHICS_RESOURCE_WIDTH for no clipping */
+                                        const uint32_t height, /* this can be GRAPHICS_RESOURCE_HEIGHT for no clipping */
+                                        const uint32_t fg_colour,
+                                        const uint32_t bg_colour,
+                                        const char *text,
+                                        const uint32_t text_length)
+{
+   return graphics_resource_render_text_ext(res, x, y, width, height,
+                                            fg_colour, bg_colour,
+                                            text, text_length,
+                                            ATEXT_FONT_SIZE);
+}
+
+/*****************************************************************************/
+int32_t graphics_get_resource_size(
+   const GRAPHICS_RESOURCE_HANDLE res,
+   uint32_t *w,
+   uint32_t *h)
+{
+   if (w) *w = res->width;
+   if (h) *h = res->height;
+   return 0;
+}
+
+/*****************************************************************************/
+int32_t graphics_get_resource_type(const GRAPHICS_RESOURCE_HANDLE res, GRAPHICS_RESOURCE_TYPE_T *type)
+{
+   if (type) *type = res->restype;
+   return 0;
+}
+
+/*****************************************************************************/
+int32_t graphics_bitblt( const GRAPHICS_RESOURCE_HANDLE src,
+                         const uint32_t x, // offset within source
+                         const uint32_t y, // offset within source
+                         const uint32_t width,
+                         const uint32_t height,
+                         GRAPHICS_RESOURCE_HANDLE dest,
+                         const uint32_t x_pos,
+                         const uint32_t y_pos )
+{
+   int rc = -1;
+   VGfloat old[9];
+   uint32_t w, h;
+   VGPaint paint = VG_INVALID_HANDLE;
+   GX_CLIENT_STATE_T save;
+   int is_child = 0;
+   VGImage img = VG_INVALID_HANDLE;
+
+   gx_priv_save(&save, dest);
+
+   if (src->type != GX_PBUFFER)
+   {
+      vcos_assert(0);
+      goto finish;
+   }
+
+   // create a child image that contains just the part wanted
+   w = width == GRAPHICS_RESOURCE_WIDTH ? src->width : width;
+   h = height == GRAPHICS_RESOURCE_HEIGHT ? src->height : height;
+
+   if (x==0 && y==0 && 
+       w == src->width &&
+       h == src->height)
+   {
+      img = src->u.pixmap;
+   }
+   else
+   {
+      is_child = 1;
+      img = vgChildImage(src->u.pixmap, x, y, w, h);
+      if (img == VG_INVALID_HANDLE)
+      {
+         vcos_assert(0);
+         goto finish;
+      }
+   }
+
+   vcos_assert(vgGetError()==0);
+
+   vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+   vgGetMatrix(old);
+   vgLoadIdentity();
+   vgTranslate((VGfloat)x_pos, (VGfloat)(dest->height-y_pos));
+   vgScale(1.0, -1.0);
+
+   // Do we have a translucency going on?
+   if (src->alpha != 1.0)
+   {
+      VGfloat colour[4] = {1.0,1.0,1.0,src->alpha};
+      paint = vgCreatePaint();
+
+      vgSetParameterfv(paint, VG_PAINT_COLOR, 4, colour);
+      vgSeti(VG_IMAGE_MODE, VG_DRAW_IMAGE_MULTIPLY);
+      vgSetPaint(paint, VG_STROKE_PATH | VG_FILL_PATH);
+   }
+   vcos_assert(vgGetError()==0);
+
+   vgDrawImage(img);
+   vcos_assert(vgGetError()==0);
+   vgLoadMatrix(old);
+
+   int err = vgGetError();
+
+   if (err)
+   {
+      GX_LOG("vg error %x blitting area", err);
+      vcos_assert(0);
+      rc = -1;
+   }
+   else
+   {
+      rc = 0;
+   }
+finish:
+   if (paint != VG_INVALID_HANDLE)
+      vgDestroyPaint(paint);
+
+   if (is_child)
+      vgDestroyImage(img);
+
+   gx_priv_restore(&save);
+   return rc;
+}
+
+void gx_priv_flush(GRAPHICS_RESOURCE_HANDLE res)
+{
+   EGLBoolean result;
+   result = eglSwapBuffers(display.disp, res->surface);
+   vcos_assert(result);
+}
+
+
+/** Map a colour, which the client will have supplied in RGB888.
+ */
+
+void gx_priv_colour_to_paint(uint32_t col, VGfloat *rgba)
+{
+   // with OpenVG we use RGB order.
+   rgba[0] = ((VGfloat)((col & R_888_MASK) >> 16 )) / 0xff;
+   rgba[1] = ((VGfloat)((col & G_888_MASK) >> 8 )) / 0xff;
+   rgba[2] = ((VGfloat)((col & B_888_MASK) >> 0 )) / 0xff;
+   rgba[3] = ((VGfloat)((col & ALPHA_888_MASK) >> 24)) / 0xff;
+}
+
+/** Fill an area of a surface with a fixed colour.
+  */
+VCOS_STATUS_T gx_priv_resource_fill(GRAPHICS_RESOURCE_HANDLE res,
+                               uint32_t x,
+                               uint32_t y,
+                               uint32_t width,
+                               uint32_t height,
+                               uint32_t fill_colour )
+{
+   VGfloat vg_clear_colour[4];
+
+   gx_priv_colour_to_paint(fill_colour, vg_clear_colour);
+   vgSeti(VG_SCISSORING, VG_FALSE);
+
+   vgSetfv(VG_CLEAR_COLOR, 4, vg_clear_colour);
+   vgClear(x, y, width, height);
+
+   int err = vgGetError();
+   if (err)
+   {
+      GX_LOG("vg error %x filling area", err);
+      vcos_assert(0);
+   }
+
+   return VCOS_SUCCESS;
+}
+
+VCOS_STATUS_T gx_priv_get_pixels(const GRAPHICS_RESOURCE_HANDLE res, void **p_pixels, GX_RASTER_ORDER_T raster_order)
+{
+   VCOS_STATUS_T status = VCOS_SUCCESS;
+   void *pixels, *dest;
+   uint32_t width, height;
+   int data_size, pitch;
+   VGImageFormat image_format;
+   if (!p_pixels)
+   {
+      status = VCOS_EINVAL;
+      goto finish;
+   }
+
+   GX_TRACE("%s: res %p", __FUNCTION__, res);
+
+   graphics_get_resource_size(res, &width, &height);
+
+   /* FIXME: implement e.g. gx_get_pitch */
+   switch (res->restype)
+   {
+      case GRAPHICS_RESOURCE_RGB565:
+         pitch = ((width + 31)&(~31)) << 1;
+         break;
+      case GRAPHICS_RESOURCE_RGB888:
+      case GRAPHICS_RESOURCE_RGBA32:
+         pitch = ((width + 31)&(~31)) << 2;
+         break;
+      default:
+      {
+         GX_LOG("Unsupported pixel format");
+         status = VCOS_EINVAL;
+         goto finish;
+      }
+   }
+   
+   data_size = pitch * height;
+
+   /* NB: vgReadPixels requires that the data pointer is aligned, but does not 
+      require the stride to be aligned. Most implementations probably will 
+      require that as well though... */
+   pixels = vcos_malloc(data_size, "gx_get_pixels data");
+   if (!pixels)
+   {
+      GX_LOG("Could not allocate %d bytes for vgReadPixels", data_size);
+      status = VCOS_ENOMEM;
+      goto finish;
+   }
+   /* FIXME: introduce e.g. GX_COLOR_FORMAT and mapping to VGImageFormat... */
+
+   /* Hand out image data formatted to match OpenGL RGBA format.
+    */
+   switch (res->restype)
+   {
+      case GRAPHICS_RESOURCE_RGB565:
+         image_format = VG_sBGR_565;
+         break;
+      case GRAPHICS_RESOURCE_RGB888:
+         image_format = VG_sXBGR_8888;
+         break;
+      case GRAPHICS_RESOURCE_RGBA32:
+         image_format = VG_sABGR_8888;
+         break;
+      default:
+      {
+         GX_LOG("Unsupported pixel format");
+         status = VCOS_EINVAL;
+         goto finish;
+      }
+   }   
+
+   /* VG raster order is bottom-to-top */
+   if (raster_order == GX_TOP_BOTTOM)
+   {
+      dest = ((uint8_t*)pixels)+(pitch*(height-1));
+      pitch = -pitch;
+   }
+   else
+   {
+      dest = pixels;
+   }
+
+   vgReadPixels(dest, pitch, image_format, 0, 0, width, height);
+
+   vcos_assert(vgGetError() == 0);
+   
+   *p_pixels = pixels;
+
+finish:
+   return status;
+}
+
+static VCOS_STATUS_T convert_image_type(GRAPHICS_RESOURCE_TYPE_T image_type,
+                                        VGImageFormat *vg_image_type,
+                                        int *pbytes_per_pixel)
+{
+   int bytes_per_pixel;
+
+   switch (image_type)
+   {
+   case GRAPHICS_RESOURCE_RGB565:
+      *vg_image_type = VG_sRGB_565;
+      bytes_per_pixel = 2;
+      break;
+   case GRAPHICS_RESOURCE_RGB888:
+      *vg_image_type = VG_sRGBX_8888;
+      bytes_per_pixel = 3; // 24 bpp
+      break;
+   case GRAPHICS_RESOURCE_RGBA32:
+      *vg_image_type = VG_sARGB_8888;
+      bytes_per_pixel = 4;
+      break;
+   default:
+      vcos_assert(0);
+      *vg_image_type = 0;
+      return VCOS_EINVAL;
+   }
+   if (pbytes_per_pixel)
+      *pbytes_per_pixel = bytes_per_pixel;
+
+   return VCOS_SUCCESS;
+}
+
+
+/*****************************************************************************/
+VCOS_STATUS_T gx_create_pbuffer( uint32_t width,
+                                uint32_t height,
+                                GRAPHICS_RESOURCE_TYPE_T image_type,
+                                GRAPHICS_RESOURCE_HANDLE *resource_handle )
+{
+   VCOS_STATUS_T status = VCOS_SUCCESS;
+   GRAPHICS_RESOURCE_HANDLE h;
+   VGImage image;
+   VGImageFormat vg_image_type;
+   GX_CLIENT_STATE_T save;
+
+   h = vcos_calloc(1,sizeof(*h), "graphics_x_resource");
+   if (!h)
+   {
+      GX_LOG("%s: no memory for resource", __FUNCTION__);
+      return VCOS_ENOMEM;
+   }
+
+   status = convert_image_type(image_type, &vg_image_type, NULL);
+   if (status != VCOS_SUCCESS)
+   {
+      vcos_free(h);
+      return status;
+   }
+
+   h->magic     = RES_MAGIC;
+   h->context   = gx_contexts[image_type];
+   h->config    = gx_configs[image_type];
+   h->alpha     = 1.0;
+   h->type      = GX_PBUFFER;
+   h->width     = width;
+   h->height    = height;
+   h->restype   = image_type;
+
+   GX_TRACE("Creating pbuffer surface");
+
+   EGLint attribs[] = {EGL_WIDTH, width, EGL_HEIGHT, height, EGL_NONE};
+   h->surface = eglCreatePbufferSurface(display.disp, h->config, 
+                                        attribs);
+   if (!h->surface)
+   {
+      GX_LOG("Could not create EGL pbuffer surface: 0x%x", eglGetError());
+      vcos_free(h);
+      return VCOS_EINVAL;
+   }
+
+   gx_priv_save(&save, h);
+
+   image = vgCreateImage(vg_image_type, width, height, VG_IMAGE_QUALITY_BETTER);
+   if (image == VG_INVALID_HANDLE)
+   {
+      GX_LOG("Could not create vg image type %d: vg error 0x%x",
+             vg_image_type, vgGetError());
+      eglDestroySurface(display.disp, h->surface);
+      vcos_free(h);
+      status = VCOS_ENOMEM;
+      goto finish;
+   }
+   h->u.pixmap  = image;
+   // fill it with black
+   status = gx_priv_resource_fill(h, 0, 0, width, height, GRAPHICS_RGBA32(0,0,0,0xff));
+   vcos_assert(status == VCOS_SUCCESS);
+
+   *resource_handle = h;
+finish:
+   gx_priv_restore(&save);
+   return status;
+}
+
+/*****************************************************************************/
+GX_PAINT_T *gx_create_gradient(GRAPHICS_RESOURCE_HANDLE res,
+                               uint32_t start_colour,
+                               uint32_t end_colour)
+{
+   // holds  the two colour stops (offset,r,g,b,a).
+   VGfloat fill_stops[10];
+   GX_CLIENT_STATE_T save;
+   VGPaint paint = VG_INVALID_HANDLE;
+
+   gx_priv_save(&save, res);
+
+   paint = vgCreatePaint();
+   if (!paint)
+   {
+      gx_priv_restore(&save);
+      vcos_log("Could not create paint: vg %d\n", vgGetError());
+      vcos_assert(0);
+      goto finish;
+   }
+
+   fill_stops[0] = 0.0;
+   gx_priv_colour_to_paint(start_colour, fill_stops+1);
+
+   fill_stops[5] = 1.0;
+   gx_priv_colour_to_paint(end_colour, fill_stops+6);
+
+   vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_LINEAR_GRADIENT);
+   vgSetParameterfv(paint, VG_PAINT_COLOR_RAMP_STOPS, 5*2, fill_stops);
+
+finish:
+   gx_priv_restore(&save);
+   return (GX_PAINT_T*)paint;
+}
+
+/*****************************************************************************/
+void gx_destroy_paint(GRAPHICS_RESOURCE_HANDLE res, GX_PAINT_T *p)
+{
+   GX_CLIENT_STATE_T save;
+   VGPaint paint = (VGPaint)p;
+   gx_priv_save(&save, res);
+   vgDestroyPaint(paint);
+   gx_priv_restore(&save);
+}
+
+/*****************************************************************************/
+VCOS_STATUS_T gx_fill_gradient(GRAPHICS_RESOURCE_HANDLE dest,
+                               uint32_t x, uint32_t y,
+                               uint32_t width, uint32_t height,
+                               uint32_t radius,
+                               GX_PAINT_T *p)
+{
+   /* Define start and end points of gradient, see OpenVG specification, 
+      section 9.3.3. */
+   VGfloat gradient[4] = {0.0, 0.0, 0.0, 0.0};
+   VGPaint paint = (VGPaint)p;
+   VGPath path;
+   GX_CLIENT_STATE_T save;
+   VCOS_STATUS_T status = VCOS_SUCCESS;
+
+   if (!paint)
+      return VCOS_EINVAL;
+
+   gx_priv_save(&save, dest);
+
+   if (width == GRAPHICS_RESOURCE_WIDTH)
+      width = dest->width;
+
+   if (height == GRAPHICS_RESOURCE_HEIGHT)
+      height = dest->height;
+
+   gradient[2] = width;
+
+   vgSetParameterfv(paint, VG_PAINT_LINEAR_GRADIENT, 4, gradient);
+   vgSetPaint(paint, VG_FILL_PATH);
+
+   path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_S_32,
+                       1.0, 0.0, 8, 8, VG_PATH_CAPABILITY_ALL);
+   if (!path)
+   {
+      status = VCOS_ENOMEM;
+      goto finish;
+   }
+
+   vguRoundRect(path, (VGfloat)x, (VGfloat)y, (VGfloat)width, (VGfloat)height,
+                (VGfloat)radius, (VGfloat)radius);
+   vgDrawPath(path, VG_FILL_PATH);
+   vgDestroyPath(path);
+
+   vcos_assert(vgGetError() == 0);
+   
+finish:
+   gx_priv_restore(&save);
+
+   return status;
+}
+
+/*****************************************************************************/
+VCOS_STATUS_T gx_graphics_init(const char *font_dir)
+{
+   GX_CLIENT_STATE_T save;
+   VCOS_STATUS_T rc;
+   
+   gx_priv_save(&save, NULL);
+   
+   rc = gx_priv_initialise();
+   if (rc == VCOS_SUCCESS)
+      rc = gx_priv_font_init(font_dir);
+
+   gx_priv_restore(&save);
+   
+   return rc;
+}
+
+/*****************************************************************************/
+int gx_is_double_buffered(void)
+{
+   return 1;
+}
+
+/*****************************************************************************/
+int32_t graphics_userblt(GRAPHICS_RESOURCE_TYPE_T src_type,
+                         const void *src_data,
+                         const uint32_t src_x,
+                         const uint32_t src_y,
+                         const uint32_t width,
+                         const uint32_t height,
+                         const uint32_t pitch,
+                         GRAPHICS_RESOURCE_HANDLE dest,
+                         const uint32_t x_pos,
+                         const uint32_t y_pos )
+{
+   VCOS_STATUS_T status;
+   VGImageFormat vg_src_type;
+   int bytes_per_pixel;
+   GX_CLIENT_STATE_T save;
+   
+   status = convert_image_type(src_type, &vg_src_type, &bytes_per_pixel);
+   if (status != VCOS_SUCCESS)
+      return status;
+
+   gx_priv_save(&save, dest);
+
+   if (dest->type == GX_PBUFFER)
+   {
+      vgImageSubData(dest->u.pixmap,
+                     src_data,
+                     pitch,
+                     vg_src_type,
+                     x_pos, y_pos, width, height);
+   }
+   else if (dest->type == GX_WINDOW)
+   {
+      // need to invert this as VG thinks zero is at the bottom
+      // while graphics_x thinks it is at the top.
+      vgWritePixels((uint8_t*)src_data + pitch*(height-1),
+                    -pitch,
+                    vg_src_type,
+                    x_pos, dest->height-y_pos-height, width, height);
+   }
+   else
+   {
+      vcos_assert(0);
+   }
+
+   if (vgGetError() == 0)
+      status = VCOS_SUCCESS;
+   else
+   {
+      vcos_assert(0);
+      status = VCOS_EINVAL;
+   }
+
+   gx_priv_restore(&save);
+   return status;
+}
+
+/*****************************************************************************/
+int32_t graphics_resource_text_dimensions( GRAPHICS_RESOURCE_HANDLE resource_handle,
+                                           const char *text,
+                                           const uint32_t text_length,
+                                           uint32_t *width,
+                                           uint32_t *height )
+{
+   return graphics_resource_text_dimensions_ext(resource_handle, text, text_length, width, height, ATEXT_FONT_SIZE);
+}
+
+/*****************************************************************************/
+VCOS_STATUS_T gx_render_arrowhead(GRAPHICS_RESOURCE_HANDLE res,
+                                  uint32_t tip_x, uint32_t tip_y, 
+                                  int32_t w, int32_t h,
+                                  GX_PAINT_T *p)
+{
+   VGfloat gradient[4];
+   VGPaint paint = (VGPaint)p;
+   VGPath path;
+   VCOS_STATUS_T status = VCOS_SUCCESS;
+
+   GX_CLIENT_STATE_T save;
+   gx_priv_save(&save, res);
+
+   if (!paint)
+   {
+      vcos_assert(0);
+      status = VCOS_EINVAL;
+      goto finish;
+   }
+
+   gradient[0] = 0.0; gradient[1] = 0.0;
+   gradient[2] = w; gradient[2] = 0.0;
+
+   vgSetParameterfv(paint, VG_PAINT_LINEAR_GRADIENT, 4, gradient);
+   vgSetPaint(paint, VG_FILL_PATH);
+
+   path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_S_32,
+                       1.0, 0.0, 8, 8, VG_PATH_CAPABILITY_ALL);
+   if (!path)
+   {
+      status = VCOS_ENOMEM;
+      goto finish;
+   }
+   VGfloat points[] = {
+      (VGfloat)tip_x, (VGfloat)tip_y,
+      (VGfloat)tip_x + w, (VGfloat)tip_y + h/2,
+      (VGfloat)tip_x + w, (VGfloat)tip_y - h/2,
+   };
+
+   vguPolygon(path, points, 3, 1);
+
+   vgDrawPath(path, VG_FILL_PATH);
+   vgDestroyPath(path);
+
+   vcos_assert(vgGetError()==0);
+
+finish:
+   gx_priv_restore(&save);
+   return status;
+}
+
+/*****************************************************************************/
+int32_t gx_apply_alpha( GRAPHICS_RESOURCE_HANDLE resource_handle,
+                        const uint8_t alpha )
+{
+   vcos_assert(resource_handle);
+   if (resource_handle->type != GX_PBUFFER)
+   {
+      vcos_assert(0);
+      return -1;
+   }
+   resource_handle->alpha = 1.0*alpha/255;
+   return 0;
+}
+
+/*****************************************************************************/
+int32_t graphics_resource_set_alpha_per_colour( GRAPHICS_RESOURCE_HANDLE res,
+                                                const uint32_t colour,
+                                                const uint8_t alpha )
+{
+   GX_ERROR("Not implemented yet!");
+   return 0;
+}
+
+/*****************************************************************************/
+VCOS_STATUS_T gx_get_pixels(const GRAPHICS_RESOURCE_HANDLE res, void **pixels)
+{
+   VCOS_STATUS_T status = VCOS_SUCCESS;
+   GX_CLIENT_STATE_T save;
+   gx_priv_save(&save, res);
+   
+   /* Default to top-top-bottom raster scan order */
+   status = gx_priv_get_pixels(res, pixels, GX_TOP_BOTTOM);
+   
+   gx_priv_restore(&save);
+   return status;
+}
+
+/*****************************************************************************/
+VCOS_STATUS_T gx_get_pixels_in_raster_order(const GRAPHICS_RESOURCE_HANDLE res, 
+                                            void **pixels, 
+                                            GX_RASTER_ORDER_T raster_order)
+{
+   VCOS_STATUS_T status = VCOS_SUCCESS;
+   GX_CLIENT_STATE_T save;
+   gx_priv_save(&save, res);
+   
+   status = gx_priv_get_pixels(res, pixels, raster_order);
+   
+   gx_priv_restore(&save);
+   return status;
+}
+
+/*****************************************************************************/
+void gx_free_pixels(const GRAPHICS_RESOURCE_HANDLE res, void *pixels)
+{
+   vcos_free(pixels);
+}
+
+VCOS_STATUS_T gx_bind_vg( GX_CLIENT_STATE_T *save, GRAPHICS_RESOURCE_HANDLE res )
+{
+   gx_priv_save(save, res);
+   vcos_assert(vgGetError()==0);
+   return VCOS_SUCCESS;
+}
+
+/** Unbind VG */
+void gx_unbind_vg(GX_CLIENT_STATE_T *restore)
+{
+   gx_priv_restore(restore);
+}
+
+
+GX_CLIENT_STATE_T *gx_alloc_context(void)
+{
+   GX_CLIENT_STATE_T *ret = vcos_calloc(1,sizeof(*ret), "gx_client_state");
+   return ret;
+}
+
+void gx_free_context(GX_CLIENT_STATE_T *state)
+{
+   vcos_free(state);
+}
+
+void gx_convert_colour(uint32_t colour, float *dest)
+{
+   gx_priv_colour_to_paint(colour, dest);
+}
+
+
+#define MAX_DISPLAY_HANDLES  4
+
+#define CHANGE_LAYER    (1<<0)
+#define CHANGE_OPACITY  (1<<1)
+#define CHANGE_DEST     (1<<2)
+#define CHANGE_SRC      (1<<3)
+#define CHANGE_MASK     (1<<4)
+#define CHANGE_XFORM    (1<<5)
+
+typedef struct
+{
+   /** Keep a display handle going for each connected screen (LCD, HDMI). */
+   DISPMANX_DISPLAY_HANDLE_T screens[MAX_DISPLAY_HANDLES];
+   int refcounts[MAX_DISPLAY_HANDLES];
+
+   //a flag to count the number of dispman starts that have been invoked
+
+   uint32_t dispman_start_count;
+   // maintain the single global handle to the update in progress
+   DISPMANX_UPDATE_HANDLE_T current_update;
+
+   VCOS_MUTEX_T lock;
+} gx_priv_state_t;
+
+static gx_priv_state_t gx;
+
+void gx_priv_init(void)
+{
+   vcos_mutex_create(&gx.lock,NULL);
+}
+
+void gx_priv_destroy(void)
+{
+   vcos_mutex_delete(&gx.lock);
+}
+
+
+static
+int32_t gx_priv_open_screen(uint32_t index, DISPMANX_DISPLAY_HANDLE_T *pscreen)
+{
+   int ret = -1;
+   vcos_mutex_lock(&gx.lock);
+
+   if (gx.refcounts[index] != 0)
+   {
+      *pscreen = gx.screens[index];
+      gx.refcounts[index]++;
+      ret = 0;
+   }
+   else
+   {
+      DISPMANX_DISPLAY_HANDLE_T h = vc_dispmanx_display_open(index);
+      if (h == DISPMANX_NO_HANDLE)
+      {
+         GX_LOG("Could not open dispmanx display %d", index);
+         ret = -1;
+         goto finish;
+      }
+      gx.screens[index] = h;
+      gx.refcounts[index] = 1;
+      *pscreen = h;
+      ret = 0;
+   }
+finish:
+   vcos_mutex_unlock(&gx.lock);
+   return ret;
+}
+
+static
+int32_t gx_priv_release_screen(uint32_t index)
+{
+   vcos_mutex_lock(&gx.lock);
+   gx.refcounts[index]--;
+   if (gx.refcounts[index] == 0)
+   {
+      vc_dispmanx_display_close(gx.screens[index]);
+      gx.screens[index] = DISPMANX_NO_HANDLE;
+   }
+   vcos_mutex_unlock(&gx.lock);
+   return 0;
+}
+
+
+
+
+int gx_priv_create_native_window(uint32_t screen_id,
+                                 uint32_t w, uint32_t h,
+                                 GRAPHICS_RESOURCE_TYPE_T type,
+                                 GX_NATIVE_WINDOW_T *win,
+                                 void **cookie)
+{
+   int rc;
+   DISPMANX_DISPLAY_HANDLE_T dispmanx_display;
+   VC_RECT_T dst_rect;
+   VC_RECT_T src_rect;
+   DISPMANX_UPDATE_HANDLE_T current_update;
+   *cookie = NULL;
+
+   rc = gx_priv_open_screen(screen_id, &dispmanx_display);
+   if (rc < 0)
+   {
+      GX_LOG("Could not open display %d", screen_id);
+      goto fail_screen;
+   }
+
+   current_update = vc_dispmanx_update_start(0);
+   if (!current_update)
+   {
+      GX_LOG("Could not start update on screen %d", screen_id);
+      goto fail_update;
+   }
+   
+   src_rect.x = src_rect.y = 0;
+   src_rect.width = w << 16;
+   src_rect.height = h << 16;
+
+   dst_rect.x = dst_rect.y = 0;
+   dst_rect.width = dst_rect.height = 1;
+   
+   win->egl_win.width = w;
+   win->egl_win.height = h;
+   VC_DISPMANX_ALPHA_T alpha;
+   memset(&alpha, 0x0, sizeof(VC_DISPMANX_ALPHA_T));
+   alpha.flags = DISPMANX_FLAGS_ALPHA_FROM_SOURCE;
+
+   DISPMANX_CLAMP_T clamp;
+   memset(&clamp, 0x0, sizeof(DISPMANX_CLAMP_T));
+
+   win->egl_win.element = vc_dispmanx_element_add(current_update, dispmanx_display,
+      0 /* layer */, &dst_rect, 
+      0 /* src */, &src_rect, 
+      DISPMANX_PROTECTION_NONE,
+      &alpha /* alpha */,
+      &clamp /* clamp */,
+      0 /* transform */);
+
+   if ( !win->egl_win.element )
+   {
+      GX_LOG("Could not add element %dx%d",w,h);
+      vc_dispmanx_update_submit_sync(current_update);
+      rc = -1;
+   }
+
+   // have to pass back the update so it can be completed *After* the
+   // window has been initialised (filled with background colour).
+   *cookie = (void*)current_update;
+
+   return 0;
+
+fail_update:
+   gx_priv_release_screen(screen_id);
+fail_screen:
+   return rc;
+}
+
+void gx_priv_finish_native_window(GRAPHICS_RESOURCE_HANDLE_TABLE_T *res,
+                                  void *current_update)
+{
+   vc_dispmanx_update_submit_sync((DISPMANX_UPDATE_HANDLE_T)current_update);
+}
+
+void
+gx_priv_destroy_native_window(GRAPHICS_RESOURCE_HANDLE_TABLE_T *res)
+{
+   DISPMANX_UPDATE_HANDLE_T current_update;
+
+   if((current_update = vc_dispmanx_update_start(0)) != 0)
+   {
+      int ret = vc_dispmanx_element_remove(current_update, res->u.native_window.egl_win.element);
+      vcos_assert(ret == 0);
+      ret = vc_dispmanx_update_submit_sync(current_update);
+      vcos_assert(ret == 0);
+   }
+
+   gx_priv_release_screen(res->screen_id);
+}
+
+
+/***********************************************************
+ * Name: graphics_get_display_size
+ *
+ * Arguments:
+ *       void
+ *
+ * Description: Return size of display
+ *
+ * Returns: int32_t:
+ *               >=0 if it succeeded
+ *
+ ***********************************************************/
+int32_t graphics_get_display_size( const uint16_t display_number,
+                                   uint32_t *width,
+                                   uint32_t *height)
+{
+   DISPMANX_MODEINFO_T mode_info;
+   int32_t success = -1;
+   DISPMANX_DISPLAY_HANDLE_T disp;
+   vcos_assert(width && height);
+   *width = *height = 0;
+
+   if(vcos_verify(display_number < MAX_DISPLAY_HANDLES))
+   {
+      // TODO Shouldn't this close the display if it wasn't previously open?
+      if (gx_priv_open_screen(display_number, &disp) < 0)
+      {
+         vcos_assert(0);
+         return -1;
+      }
+      success = vc_dispmanx_display_get_info(disp, &mode_info);
+
+      if( success >= 0 )
+      {
+         *width = mode_info.width;
+         *height = mode_info.height;
+         vcos_assert(*height > 64);
+      }
+      else
+      {
+         vcos_assert(0);
+      }
+   }
+
+   return success;
+}
+
+static inline uint16_t auto_size(uint16_t arg, uint16_t actual_size)
+{
+   return arg == GRAPHICS_RESOURCE_WIDTH ? actual_size : arg;
+}
+
+int32_t graphics_display_resource( GRAPHICS_RESOURCE_HANDLE res,
+                                   const uint16_t screen_number,
+                                   const int16_t z_order,
+                                   const uint16_t offset_x,
+                                   const uint16_t offset_y,
+                                   const uint16_t dest_width,
+                                   const uint16_t dest_height,
+                                   const VC_DISPMAN_TRANSFORM_T transform,
+                                   const uint8_t display )
+{
+   DISPMANX_UPDATE_HANDLE_T update;
+   int32_t rc;
+   int xform_changed;
+
+   if (!res)
+   {
+      // mimics old behaviour.
+      (void)vcos_verify(0);
+      return 0;
+   }
+   vcos_assert(res->magic == RES_MAGIC);
+
+   xform_changed = transform != res->transform;
+   res->transform = transform;
+
+   rc = graphics_update_start();
+   update = gx.current_update;
+   vcos_assert(rc == 0);
+
+   if (display)
+   {
+      VC_RECT_T src_rect, dest_rect;
+
+      int32_t src_width = res->width;
+      int32_t src_height = res->height;
+
+      uint32_t change_flags = CHANGE_LAYER;
+
+      // has the destination position changed?
+      uint32_t w = auto_size(dest_width, res->width);
+      uint32_t h = auto_size(dest_height, res->height);
+
+      vcos_assert(screen_number == res->screen_id);
+
+      if (gx.screens[screen_number] == 0)
+      {
+         vcos_assert(0);
+         DISPMANX_DISPLAY_HANDLE_T display_handle;
+         gx_priv_open_screen(screen_number, &display_handle);
+      }
+
+      if ((offset_x != res->dest.x) ||
+          (offset_y != res->dest.y) ||
+          (h != res->dest.height) ||
+          (w != res->dest.width))
+      {
+         change_flags |= CHANGE_DEST;
+         res->dest.x      = offset_x;
+         res->dest.y      = offset_y;
+         res->dest.height = h;
+         res->dest.width  = w;
+      }
+
+      if (xform_changed)
+         change_flags |= CHANGE_XFORM;
+
+      vc_dispmanx_rect_set( &src_rect, 0, 0, ((uint32_t)src_width)<<16, ((uint32_t)src_height)<<16 );
+      vc_dispmanx_rect_set( &dest_rect, offset_x, offset_y, w, h);
+
+      rc = vc_dispmanx_element_change_attributes(update,
+         res->u.native_window.egl_win.element,
+         change_flags,
+         z_order, /* layer */
+         0xff, /* opacity */
+         &dest_rect,
+         &src_rect,
+         0, transform);
+
+      vcos_assert(rc==0);
+      gx_priv_flush(res);
+
+   }
+   else
+   {
+      vgFinish();
+      eglWaitClient();
+      rc = vc_dispmanx_element_change_source(update, res->u.native_window.egl_win.element, 0);
+      vcos_assert(rc==0);
+   }
+
+   rc = graphics_update_end();
+   vcos_assert(rc==0);
+
+   return rc;
+}
+
+/***********************************************************
+ * Name: graphics_update_start
+ *
+ * Arguments:
+ *       void
+ *
+ * Description: Starts an update UNLESS and update is already in progress
+ *
+ * Returns: int32_t:
+ *               >=0 if it succeeded
+ *
+ ***********************************************************/
+int32_t graphics_update_start(void)
+{
+   int32_t success = 0;
+
+   //check we are not already in an update
+   if ( 0 == gx.dispman_start_count )
+   {
+      gx.current_update = vc_dispmanx_update_start( 10 );
+      if( gx.current_update == DISPMANX_NO_HANDLE )
+      {
+         //error
+         success = -1;
+         vc_assert( 0 );
+      }
+   }
+
+   if( success == 0 )
+   {
+      //inc the counter
+      gx.dispman_start_count++;
+   }
+
+   return success;
+}
+
+
+/***********************************************************
+ * Name: graphics_update_end
+ *
+ * Arguments:
+ *       void
+ *
+ * Description: Ends an update UNLESS more than one update is in progress
+ *
+ * Returns: int32_t:
+ *               >=0 if it succeeded
+ *
+ ***********************************************************/
+int32_t graphics_update_end( void )
+{
+   int32_t success = -1;
+
+   // make sure you are checking the return value of graphics_update_start
+   if(vcos_verify(gx.current_update != DISPMANX_NO_HANDLE))
+   {
+      //check we are in an update
+      if(vcos_verify(gx.dispman_start_count > 0))
+      {
+         //dec the counter
+         gx.dispman_start_count--;
+
+         success = 0;
+
+         //is the counter now 0?
+         if( 0 == gx.dispman_start_count )
+         {
+            eglWaitClient();
+            if( vc_dispmanx_update_submit_sync( gx.current_update ) != 0 )
+            {
+               //error
+               success = -1;
+               vc_assert( 0 );
+            }
+         }
+      }
+   }
+
+   return success;
+}
+
diff --git a/host_applications/linux/apps/hello_pi/libs/vgfont/graphics_x_private.h b/host_applications/linux/apps/hello_pi/libs/vgfont/graphics_x_private.h
new file mode 100755 (executable)
index 0000000..05d94b7
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Graphics library for VG
+
+#ifndef GRAPHICS_X_PRIVATE_H
+#define GRAPHICS_X_PRIVATE_H
+
+#define VCOS_LOG_CATEGORY (&gx_log_cat)
+
+#include "EGL/egl.h"
+#include "EGL/eglext.h"
+#include "VG/openvg.h"
+#include "VG/vgu.h"
+
+#include "vgfont.h"
+#include "bcm_host.h"
+
+extern VCOS_LOG_CAT_T gx_log_cat;
+
+#define LOG_ERR( fmt, arg... )   vcos_log_error( "%s:%d " fmt, __func__, __LINE__, ##arg)
+
+#define GX_ERROR(format, arg...) if (1) {} else printf( format "\n", ##arg)
+#define GX_LOG(format, arg...) if (1) {} else printf( format "\n", ##arg)
+#define GX_TRACE(format, arg...) if (1) {} else printf( format "\n", ##arg)
+
+typedef struct
+{
+   EGL_DISPMANX_WINDOW_T egl_win;
+} GX_NATIVE_WINDOW_T;
+
+typedef enum
+{
+   GX_TOP_BOTTOM,
+   GX_BOTTOM_TOP,
+} GX_RASTER_ORDER_T;
+
+typedef struct {} GX_PAINT_T;
+
+typedef struct GX_CLIENT_STATE_T GX_CLIENT_STATE_T;
+typedef struct {
+   EGLDisplay disp;
+} GX_DISPLAY_T;
+
+struct GX_DISPLAY_T
+{
+   EGLDisplay disp;
+};
+
+typedef enum
+{
+   GX_WINDOW, GX_PIXMAP, GX_PBUFFER
+} GX_RES_TYPE;
+
+#define RES_MAGIC ('G'<<24|'X'<<16|'R'<<8|'S'<<0)
+#define GX_PRIV_FLAG_FLIP (1<<0)
+
+/**
+ * Structure encapsulating the per-surface state.
+ ***********************************************************/
+typedef struct GRAPHICS_RESOURCE_HANDLE_TABLE_T
+{
+   union
+   {
+      GX_NATIVE_WINDOW_T native_window;
+      VGImage pixmap;
+   } u;
+   GX_RES_TYPE type;
+
+   uint32_t magic;         /** To work around broken create interface */
+   int context_bound;
+   const char *last_caller;
+   EGLSurface surface;
+   EGLContext context;
+   EGLConfig config;
+   uint32_t screen_id;     /** 0-LCD, etc */
+   uint16_t width;
+   uint16_t height;
+   GRAPHICS_RESOURCE_TYPE_T restype;
+   VC_DISPMAN_TRANSFORM_T transform;
+
+   VC_RECT_T dest;         /** destination rectangle in use, for book-keeping */
+
+   VGfloat alpha;
+} GRAPHICS_RESOURCE_HANDLE_TABLE_T;
+
+/**
+ * Structure used to store an EGL client state. 
+ ***********************************************************/
+struct GX_CLIENT_STATE_T
+{
+   EGLSurface read_surface;
+   EGLSurface draw_surface;
+   EGLContext context;
+   EGLenum api;
+   GRAPHICS_RESOURCE_HANDLE res;
+};
+
+/**
+ * \fixme add documentation
+ *
+ ***********************************************************/ 
+void gx_priv_init(void);
+
+/**
+ * \fixme add documentation
+ *
+ ***********************************************************/ 
+void gx_priv_destroy(void);
+
+/**
+ * \fixme add documentation
+ *
+ * @param col colour
+ *
+ * @param rgba OpenVG paint colour
+ *
+ ***********************************************************/ 
+void gx_priv_colour_to_paint(uint32_t col, VGfloat *rgba);
+
+/** 
+ * Save current EGL client state.
+ *
+ * @param state upon return, holds the saved EGL client state.
+ *
+ * @param res handle to the surface the EGL client state belongs to (may be <code>NULL</code>).
+ * 
+ */
+void gx_priv_save(GX_CLIENT_STATE_T *state, GRAPHICS_RESOURCE_HANDLE res);
+
+/** 
+ * Restore current EGL client state.
+ *
+ * @param state the EGL client state to restore.
+ * 
+ */
+void gx_priv_restore(GX_CLIENT_STATE_T *state);
+
+/** 
+ * Create a native window for a surface.
+ *
+ * @param screen_id \fixme
+ * 
+ * @param w width of the window
+ *
+ * @param h height of the window
+ *
+ * @param type color/raster format of the resource
+ *
+ * @param win upon successful return, holds a handle to the native window
+ *
+ * @param cookie \fixme
+ *
+ * @return VCOS_SUCCESS on success, or error code.
+ */
+int gx_priv_create_native_window(uint32_t screen_id,
+                                 uint32_t w, uint32_t h,
+                                 GRAPHICS_RESOURCE_TYPE_T type,
+                                 GX_NATIVE_WINDOW_T *win,
+                                 void **cookie);
+
+/** 
+ * Destroy native window bound to surface.
+ *
+ * @param res Handle to surface.
+ * 
+ */
+void gx_priv_destroy_native_window(GRAPHICS_RESOURCE_HANDLE_TABLE_T *res);
+
+/** 
+ * Initialise font from the given directory.
+ *
+ * @param font_dir path to font
+ * 
+ * \fixme only supports Vera.tff at the moment?
+ *
+ * @return VCOS_SUCCESS on success, or error code.
+ */
+VCOS_STATUS_T gx_priv_font_init(const char *font_dir);
+
+/**
+ * \fixme add documentation
+ *
+ ***********************************************************/ 
+void gx_priv_font_term(void);
+
+/**
+ * Fill an area of a surface with a single colour.
+ *
+ * @param res Handle to surface.
+ *
+ * @param x x-offset of area to fill
+ * 
+ * @param y y-offset of area to fill
+ *
+ * @param width width of area to fill
+ *
+ * @param height height of area to fill
+ *
+ * @param fill_colour fill colour
+ *
+ ***********************************************************/
+VCOS_STATUS_T gx_priv_resource_fill(GRAPHICS_RESOURCE_HANDLE res,
+                               uint32_t x,
+                               uint32_t y,
+                               uint32_t width,
+                               uint32_t height,
+                               uint32_t fill_colour );
+
+/**
+ * Render text into a surface
+ *
+ * @param disp Handle to display.
+ *
+ * @param res Handle to surface.
+ *
+ * @param x x-offset
+ *
+ * @param y y-offset
+ *
+ * @param width bounding rectangle width
+ *
+ * @param height bounding rectangle height
+ *
+ * @param fg_colour foreground color
+ *
+ * @param bg_colour background color
+ *
+ * @param text text to render
+ *
+ * @param text_length length of text
+ *
+ * @param text_size size of text
+ *
+ ***********************************************************/
+VCOS_STATUS_T gx_priv_render_text( GX_DISPLAY_T *disp,
+                                   GRAPHICS_RESOURCE_HANDLE res,
+                                   int32_t x,
+                                   int32_t y,
+                                   uint32_t width,
+                                   uint32_t height,
+                                   uint32_t fg_colour,
+                                   uint32_t bg_colour,
+                                   const char *text,
+                                   uint32_t text_length,
+                                   uint32_t text_size );
+
+/**
+ * Flush a surface.
+ *
+ * @param res Handle to surface.
+ *
+ ***********************************************************/ 
+void gx_priv_flush(GRAPHICS_RESOURCE_HANDLE res);
+
+/**
+ * Called after the EGL/VG initialisation of a window has completed
+ * following its creation.
+ *
+ * @param res ???
+ *
+ * @param cookie ???
+ *
+ ***********************************************************/ 
+void gx_priv_finish_native_window(GRAPHICS_RESOURCE_HANDLE_TABLE_T *res,
+                                  void *cookie);
+
+/**
+ * Flush font cache.
+ *
+ ***********************************************************/ 
+void gx_font_cache_flush(void);
+
+/**
+ * Read a bitmap (.BMP) image from the given file. 
+ *  
+ * @param filename filename (must not be <code>NULL</code>).
+ *
+ * @param width holds the width of the image upon return.
+ *
+ * @param height holds the height of the image upon return.
+ *
+ * @param pitch_bytes holds the pitch of the image data (in bytes) upon return.
+ *
+ * @param restype holds the type of the image upon return.
+ *
+ * @param vg_format holds the OpenVG image format upon return.
+ *
+ * @param flags holds flags describing image properties upon return.
+ *
+ * @param image_data_size holds size of the image data upon return.
+ * 
+ * @param pimage_data holds the image data buffer upon return (must not be <code>NULL</code>),
+ *                    the caller is responsible for releasing the buffer afterwards.
+ *
+ * @return 0 if success, non-zero otherwise (in which case the output parameters
+ *           may be invalid).
+ *
+ ***********************************************************/ 
+int gx_priv_read_bmp(const char *file_name, 
+                     uint32_t *width, uint32_t *height, uint32_t *pitch_bytes,
+                     GRAPHICS_RESOURCE_TYPE_T *restype,
+                     VGImageFormat *vg_format,
+                     uint32_t *flags,
+                     uint32_t *image_data_size,
+                     void **pimage_data);
+
+/**
+ * Read a Targa (.TGA) image from the given file. 
+ *  
+ * @param filename filename (must not be <code>NULL</code>).
+ *
+ * @param width holds the width of the image upon return.
+ *
+ * @param height holds the height of the image upon return.
+ *
+ * @param pitch_bytes holds the pitch of the image data (in bytes) upon return.
+ *
+ * @param restype holds the type of the image upon return.
+ *
+ * @param vg_format holds the OpenVG image format upon return.
+ *
+ * @param flags holds flags describing image properties upon return.
+ *
+ * @param image_data_size holds size of the image data upon return.
+ * 
+ * @param pimage_data holds the image data buffer upon return (must not be <code>NULL</code>),
+ *                    the caller is responsible for releasing the memory afterwards.
+ *
+ * @return 0 if success, non-zero otherwise (in which case the output parameters.
+ *           may be invalid).
+ *
+ ***********************************************************/ 
+int gx_priv_read_tga(const char *file_name, 
+                     uint32_t *width, uint32_t *height, uint32_t *pitch_bytes,
+                     GRAPHICS_RESOURCE_TYPE_T *restype,
+                     VGImageFormat *vg_format,
+                     uint32_t *flags,
+                     uint32_t *image_data_size,
+                     void **pimage_data);
+
+#endif
diff --git a/host_applications/linux/apps/hello_pi/libs/vgfont/vgfont.h b/host_applications/linux/apps/hello_pi/libs/vgfont/vgfont.h
new file mode 100755 (executable)
index 0000000..b20bb55
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Font handling for graphicsx
+
+#ifndef VCFTLIB_H
+#define VCFTLIB_H
+
+#include <stdint.h>
+#include "interface/vmcs_host/vc_dispservice_x_defs.h"
+#include "interface/vctypes/vc_image_types.h"
+#include "interface/vcos/vcos.h"
+
+//Definitions which in certain functions can be used to mean the actual width and height of a resource, without
+//having to know the data implicitly.
+#define GRAPHICS_RESOURCE_WIDTH  0xFFFF
+#define GRAPHICS_RESOURCE_HEIGHT 0xFFFF
+
+#define R_888_MASK      (0x00FF0000)
+#define G_888_MASK      (0x0000FF00)
+#define B_888_MASK      (0x000000FF)
+#define ALPHA_888_MASK  (0xFF000000)
+#define GRAPHICS_RGBA32( r, g, b, a ) GRAPHICS_RGBA888( r, g, b, a )
+#define GRAPHICS_RGBA888( r, g, b, a ) ( (((a) << (8+8+8)) & ALPHA_888_MASK) | (((b) << (8+8)) & R_888_MASK) | (((g) << 8) & G_888_MASK) | ((r) & B_888_MASK) )
+#define GRAPHICS_TRANSPARENT_COLOUR 0x00000001UL
+
+//resource defs
+
+typedef enum
+{
+   GRAPHICS_RESOURCE_HANDLE_TYPE_MIN,
+
+   GRAPHICS_RESOURCE_RGB565,
+   GRAPHICS_RESOURCE_RGB888, /*  888 format is ONLY used when loading bitmaps
+                                 - you can't create or delete bitmaps with this format */
+   GRAPHICS_RESOURCE_RGBA32,
+   GRAPHICS_RESOURCE_TF_RGB32A,
+   GRAPHICS_RESOURCE_TF_RGB565,
+   GRAPHICS_RESOURCE_YUV420,
+
+   GRAPHICS_RESOURCE_HANDLE_TYPE_MAX
+
+} GRAPHICS_RESOURCE_TYPE_T;
+
+
+typedef struct GRAPHICS_RESOURCE_HANDLE_TABLE_T *GRAPHICS_RESOURCE_HANDLE;
+
+VCOS_STATUS_T gx_graphics_init(const char *font_dir);
+int32_t graphics_delete_resource( GRAPHICS_RESOURCE_HANDLE res );
+VCOS_STATUS_T gx_create_window( uint32_t screen_id,
+                                uint32_t width,
+                                uint32_t height,
+                                GRAPHICS_RESOURCE_TYPE_T image_type,
+                                GRAPHICS_RESOURCE_HANDLE *resource_handle );
+
+int32_t graphics_display_resource( GRAPHICS_RESOURCE_HANDLE res,
+                                   const uint16_t screen_number,
+                                   const int16_t z_order,
+                                   const uint16_t offset_x,
+                                   const uint16_t offset_y,
+                                   const uint16_t dest_width,
+                                   const uint16_t dest_height,
+                                   const VC_DISPMAN_TRANSFORM_T transform,
+                                   const uint8_t display );
+
+int32_t graphics_resource_fill(GRAPHICS_RESOURCE_HANDLE res,
+                               uint32_t x,
+                               uint32_t y,
+                               uint32_t width,
+                               uint32_t height,
+                               uint32_t fill_colour );
+
+int32_t graphics_update_displayed_resource(GRAPHICS_RESOURCE_HANDLE res,
+                                           const uint32_t x_offset,
+                                           const uint32_t y_offset,
+                                           const uint32_t width,
+                                           const uint32_t height );
+
+int32_t graphics_resource_render_text_ext( GRAPHICS_RESOURCE_HANDLE res,
+                                           const int32_t x,
+                                           const int32_t y,
+                                           const uint32_t width,
+                                           const uint32_t height,
+                                           const uint32_t fg_colour,
+                                           const uint32_t bg_colour,
+                                           const char *text,
+                                           const uint32_t text_length,
+                                           const uint32_t text_size );
+
+int32_t graphics_resource_text_dimensions_ext(GRAPHICS_RESOURCE_HANDLE res,
+                                              const char *text,
+                                              const uint32_t text_length,
+                                              uint32_t *width,
+                                              uint32_t *height,
+                                              const uint32_t text_size );
+
+int32_t graphics_get_resource_size(
+   const GRAPHICS_RESOURCE_HANDLE res,
+   uint32_t *w,
+   uint32_t *h);
+
+int32_t graphics_update_start(void);
+
+int32_t graphics_update_end( void );
+
+int32_t graphics_resource_text_dimensions( GRAPHICS_RESOURCE_HANDLE resource_handle,
+                                           const char *text,
+                                           const uint32_t text_length,
+                                           uint32_t *width,
+                                           uint32_t *height );
+
+#endif
diff --git a/host_applications/linux/apps/hello_pi/libs/vgfont/vgft.c b/host_applications/linux/apps/hello_pi/libs/vgfont/vgft.c
new file mode 100755 (executable)
index 0000000..53104c3
--- /dev/null
@@ -0,0 +1,424 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Font handling for graphicsx
+
+#include <assert.h>
+#include <stdlib.h>
+
+#include "graphics_x_private.h"
+#include "vgft.h"
+
+static FT_Library lib;
+
+int vgft_init(void)
+{
+   if (FT_Init_FreeType(&lib) == 0)
+      return 0;
+   else
+   {
+      return -1;
+   }
+}
+
+void vgft_term(void)
+{
+   FT_Done_FreeType(lib);
+}
+
+#define SEGMENTS_COUNT_MAX 256
+#define COORDS_COUNT_MAX 1024
+
+static VGuint segments_count;
+static VGubyte segments[SEGMENTS_COUNT_MAX];
+static VGuint coords_count;
+static VGfloat coords[COORDS_COUNT_MAX];
+
+static VGfloat float_from_26_6(FT_Pos x)
+{
+   return (VGfloat)x / 64.0f;
+}
+
+static void convert_contour(const FT_Vector *points, const char *tags, short points_count)
+{
+   int first_coords = coords_count;
+
+   int first = 1;
+   char last_tag = 0;
+   int c = 0;
+
+   for (; points_count != 0; ++points, ++tags, --points_count) {
+      ++c;
+
+      char tag = *tags;
+      if (first) {
+         assert(tag & 0x1);
+         assert(c==1); c=0;
+         segments[segments_count++] = VG_MOVE_TO;
+         first = 0;
+      } else if (tag & 0x1) {
+         /* on curve */
+
+         if (last_tag & 0x1) {
+            /* last point was also on -- line */
+            assert(c==1); c=0;
+            segments[segments_count++] = VG_LINE_TO;
+         } else {
+            /* last point was off -- quad or cubic */
+            if (last_tag & 0x2) {
+               /* cubic */
+               assert(c==3); c=0;
+               segments[segments_count++] = VG_CUBIC_TO;
+            } else {
+               /* quad */
+               assert(c==2); c=0;
+               segments[segments_count++] = VG_QUAD_TO;
+            }
+         }
+      } else {
+         /* off curve */
+
+         if (tag & 0x2) {
+            /* cubic */
+
+            assert((last_tag & 0x1) || (last_tag & 0x2)); /* last either on or off and cubic */
+         } else {
+            /* quad */
+
+            if (!(last_tag & 0x1)) {
+               /* last was also off curve */
+
+               assert(!(last_tag & 0x2)); /* must be quad */
+
+               /* add on point half-way between */
+               assert(c==2); c=1;
+               segments[segments_count++] = VG_QUAD_TO;
+               VGfloat x = (coords[coords_count - 2] + float_from_26_6(points->x)) * 0.5f;
+               VGfloat y = (coords[coords_count - 1] + float_from_26_6(points->y)) * 0.5f;
+               coords[coords_count++] = x;
+               coords[coords_count++] = y;
+            }
+         }
+      }
+      last_tag = tag;
+
+      coords[coords_count++] = float_from_26_6(points->x);
+      coords[coords_count++] = float_from_26_6(points->y);
+   }
+
+   if (last_tag & 0x1) {
+      /* last point was also on -- line (implicit with close path) */
+      assert(c==0);
+   } else {
+      ++c;
+
+      /* last point was off -- quad or cubic */
+      if (last_tag & 0x2) {
+         /* cubic */
+         assert(c==3); c=0;
+         segments[segments_count++] = VG_CUBIC_TO;
+      } else {
+         /* quad */
+         assert(c==2); c=0;
+         segments[segments_count++] = VG_QUAD_TO;
+      }
+
+      coords[coords_count++] = coords[first_coords + 0];
+      coords[coords_count++] = coords[first_coords + 1];
+   }
+
+   segments[segments_count++] = VG_CLOSE_PATH;
+}
+
+static void convert_outline(const FT_Vector *points, const char *tags, const short *contours, short contours_count, short points_count)
+{
+   segments_count = 0;
+   coords_count = 0;
+
+   short last_contour = 0;
+   for (; contours_count != 0; ++contours, --contours_count) {
+      short contour = *contours + 1;
+      convert_contour(points + last_contour, tags + last_contour, contour - last_contour);
+      last_contour = contour;
+   }
+   assert(last_contour == points_count);
+
+   assert(segments_count <= SEGMENTS_COUNT_MAX); /* oops... we overwrote some memory */
+   assert(coords_count <= COORDS_COUNT_MAX);
+}
+
+VCOS_STATUS_T vgft_font_init(VGFT_FONT_T *font)
+{
+   font->ft_face = NULL;
+   font->vg_font = vgCreateFont(0);
+   if (font->vg_font == VG_INVALID_HANDLE)
+   {
+      return VCOS_ENOMEM;
+   }
+   return VCOS_SUCCESS;
+}
+
+VCOS_STATUS_T vgft_font_load_mem(VGFT_FONT_T *font, void *mem, size_t len)
+{
+   if (FT_New_Memory_Face(lib, mem, len, 0, &font->ft_face))
+   {
+      return VCOS_EINVAL;
+   }
+   return VCOS_SUCCESS;
+}
+
+VCOS_STATUS_T vgft_font_load_file(VGFT_FONT_T *font, const char *file)
+{
+   if (FT_New_Face(lib, file, 0, &font->ft_face)) {
+      return VCOS_EINVAL;
+   }
+   return VCOS_SUCCESS;
+}
+
+VCOS_STATUS_T vgft_font_convert_glyphs(VGFT_FONT_T *font, unsigned int char_height, unsigned int dpi_x, unsigned int dpi_y)
+{
+   FT_UInt glyph_index;
+   FT_ULong ch;
+
+   if (FT_Set_Char_Size(font->ft_face, 0, char_height, dpi_x, dpi_y))
+   {
+      FT_Done_Face(font->ft_face);
+      vgDestroyFont(font->vg_font);
+      return VCOS_EINVAL;
+   }
+
+   ch = FT_Get_First_Char(font->ft_face, &glyph_index);
+
+   while (ch != 0)
+   {
+      if (FT_Load_Glyph(font->ft_face, glyph_index, FT_LOAD_DEFAULT)) {
+         FT_Done_Face(font->ft_face);
+         vgDestroyFont(font->vg_font);
+         return VCOS_ENOMEM;
+      }
+
+      VGPath vg_path;
+      FT_Outline *outline = &font->ft_face->glyph->outline;
+      if (outline->n_contours != 0) {
+         vg_path = vgCreatePath(VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1.0f, 0.0f, 0, 0, VG_PATH_CAPABILITY_ALL);
+         assert(vg_path != VG_INVALID_HANDLE);
+
+         convert_outline(outline->points, outline->tags, outline->contours, outline->n_contours, outline->n_points);
+         vgAppendPathData(vg_path, segments_count, segments, coords);
+      } else {
+         vg_path = VG_INVALID_HANDLE;
+      }
+
+      VGfloat origin[] = { 0.0f, 0.0f };
+      VGfloat escapement[] = { float_from_26_6(font->ft_face->glyph->advance.x), float_from_26_6(font->ft_face->glyph->advance.y) };
+      vgSetGlyphToPath(font->vg_font, glyph_index, vg_path, VG_FALSE, origin, escapement);
+
+      if (vg_path != VG_INVALID_HANDLE) {
+         vgDestroyPath(vg_path);
+      }
+      ch = FT_Get_Next_Char(font->ft_face, ch, &glyph_index);
+   }
+
+   return VCOS_SUCCESS;
+}
+
+void vgft_font_term(VGFT_FONT_T *font)
+{
+   if (font->ft_face)
+      FT_Done_Face(font->ft_face);
+   if (font->vg_font)
+      vgDestroyFont(font->vg_font);
+   memset(font, 0, sizeof(*font));
+}
+
+
+#define CHAR_COUNT_MAX 200
+static VGuint glyph_indices[CHAR_COUNT_MAX];
+static VGfloat adjustments_x[CHAR_COUNT_MAX];
+static VGfloat adjustments_y[CHAR_COUNT_MAX];
+
+// Draws the first char_count characters from text, with adjustments, starting 
+// from the current origin.  The peek argument indicates whether to peek ahead 
+// and get a final adjustment based on the next character past char_count, or 
+// else just assume that this is the end of the text and add no final 
+// adjustment.
+//
+// Returns silently in some error cases.  Assert fails in some error cases.
+
+static void draw_chars(VGFT_FONT_T *font, const char *text, int char_count, VGbitfield paint_modes, int peek) {
+   // Put in first character
+   glyph_indices[0] = FT_Get_Char_Index(font->ft_face, text[0]);
+   int prev_glyph_index = glyph_indices[0];
+
+   // Calculate glyph_indices and adjustments
+   int i;
+   FT_Vector kern;
+   for (i = 1; i != char_count; ++i) {
+      int glyph_index = FT_Get_Char_Index(font->ft_face, text[i]);
+      if (!glyph_index) { return; }
+      glyph_indices[i] = glyph_index;
+
+      if (FT_Get_Kerning(font->ft_face, prev_glyph_index, glyph_index, FT_KERNING_DEFAULT, &kern)) assert(0);
+      adjustments_x[i - 1] = float_from_26_6(kern.x);
+      adjustments_y[i - 1] = float_from_26_6(kern.y);
+
+      prev_glyph_index = glyph_index;
+   }
+
+   // Get the last adjustment?
+   if (peek) {
+      int peek_glyph_index = FT_Get_Char_Index(font->ft_face, text[i]);
+      if (!peek_glyph_index) { return; }
+      if (FT_Get_Kerning(font->ft_face, prev_glyph_index, peek_glyph_index, FT_KERNING_DEFAULT, &kern)) assert(0);
+      adjustments_x[char_count - 1] = float_from_26_6(kern.x);
+      adjustments_y[char_count - 1] = float_from_26_6(kern.y);
+   } else {
+      adjustments_x[char_count - 1] = 0.0f;
+      adjustments_y[char_count - 1] = 0.0f;
+   }
+
+   vgDrawGlyphs(font->vg_font, char_count, glyph_indices, adjustments_x, adjustments_y, paint_modes, VG_FALSE);
+}
+
+// Goes to the x,y position and draws arbitrary number of characters, draws 
+// iteratively if the char_count exceeds the max buffer size given above.
+
+static void draw_line(VGFT_FONT_T *font, VGfloat x, VGfloat y, const char *text, int char_count, VGbitfield paint_modes) {
+   if (char_count == 0) return;
+
+   // Set origin to requested x,y
+   VGfloat glor[] = { x, y };
+   vgSetfv(VG_GLYPH_ORIGIN, 2, glor);
+
+   // Draw the characters in blocks to reuse buffer memory
+   const char *curr_text = text;
+   int chars_left = char_count;
+   while (chars_left > CHAR_COUNT_MAX) {
+      draw_chars(font, curr_text, CHAR_COUNT_MAX, paint_modes, 1);
+      chars_left -= CHAR_COUNT_MAX;
+      curr_text += CHAR_COUNT_MAX;
+   }
+
+   // Draw the last block
+   draw_chars(font, curr_text, chars_left, paint_modes, 0);
+}
+
+// Draw multiple lines of text, starting from the given x and y.  The x and y
+// correspond to the lower left corner of the first line of text, without
+// descenders.  Unfortunately, for multiline text, this ends up in the middle of
+// the y-extent of the block.
+
+void vgft_font_draw(VGFT_FONT_T *font, VGfloat x, VGfloat y, const char *text, unsigned text_length, VGbitfield paint_modes)
+{
+   VGfloat descent = float_from_26_6(font->ft_face->size->metrics.descender);
+   int last_draw = 0;
+   int i = 0;
+   y -= descent;
+   for (;;) {
+      int last = !text[i] || (text_length && i==text_length);
+
+      if ((text[i] == '\n') || last)
+      {
+         draw_line(font, x, y, text + last_draw, i - last_draw, paint_modes);
+         last_draw = i+1;
+         y -= float_from_26_6(font->ft_face->size->metrics.height);
+      }
+      if (last)
+      {
+         break;
+      }
+      ++i;
+   }
+}
+
+// Get text extents for a single line.  Returns silently in some error cases.
+// Assert fails in some error cases.
+
+static void line_extents(VGFT_FONT_T *font, VGfloat *x, VGfloat *y, const char *text, int chars_count)
+{
+   int i;
+   int prev_glyph_index = 0;
+   if (chars_count == 0) return;
+
+   for (i=0; i < chars_count; i++)
+   {
+      int glyph_index = FT_Get_Char_Index(font->ft_face, text[i]);
+      if (!glyph_index) return;
+
+      if (i != 0)
+      {
+         FT_Vector kern;
+         if (FT_Get_Kerning(font->ft_face, prev_glyph_index, glyph_index,
+                            FT_KERNING_DEFAULT, &kern))
+         {
+            assert(0);
+         }
+         *x += float_from_26_6(kern.x);
+         *y += float_from_26_6(kern.y);
+      }
+      FT_Load_Glyph(font->ft_face, glyph_index, FT_LOAD_DEFAULT);
+      *x += float_from_26_6(font->ft_face->glyph->advance.x);
+
+      prev_glyph_index = glyph_index;
+   }
+}
+
+// Text extents for some ASCII text.
+//
+// Use text_length if non-zero, otherwise look for trailing '\0'.
+
+void vgft_get_text_extents(VGFT_FONT_T *font,
+                           const char *text,
+                           unsigned text_length,
+                           VGfloat unused0, VGfloat unused1,
+                           VGfloat *w, VGfloat *h) {
+   int last_draw = 0;
+   VGfloat max_x = 0;
+   VGfloat y = 0;
+
+   int i, last;
+   for (i = 0, last = 0; !last; ++i) {
+      last = !text[i] || (text_length && i==text_length);
+      if ((text[i] == '\n') || last) {
+         VGfloat x = 0;
+         line_extents(font, &x, &y, text + last_draw, i - last_draw);
+         last_draw = i + 1;
+         y -= float_from_26_6(font->ft_face->size->metrics.height);
+         if (x > max_x) max_x = x;
+      }
+   }
+   *w = max_x;
+   *h = -y;
+}
+
+// Get y offset for first line; mitigates issue of start y being middle of block
+// for multiline renders by vgft_font_draw.  Currently simple, may be worth
+// adding y kerning?
+
+VGfloat vgft_first_line_y_offset(VGFT_FONT_T *font) {
+   return float_from_26_6(font->ft_face->size->metrics.height);
+}
diff --git a/host_applications/linux/apps/hello_pi/libs/vgfont/vgft.h b/host_applications/linux/apps/hello_pi/libs/vgfont/vgft.h
new file mode 100755 (executable)
index 0000000..4fe548d
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Font handling for graphicsx
+
+#ifndef VGFT_H
+#define VGFT_H
+
+#include "interface/vcos/vcos.h"
+#include <VG/openvg.h>
+#include <ft2build.h>
+
+typedef int VGFT_BOOL;
+#define VGFT_FALSE 0
+#define VGFT_TRUE (!VGFT_FALSE)
+
+#include FT_FREETYPE_H
+
+/* Returns 0 on success */
+extern int vgft_init(void);
+extern void vgft_term(void);
+
+typedef struct {
+   VGFont vg_font;
+   FT_Face ft_face;
+} VGFT_FONT_T;
+
+/** Initialise a FT->VG font */
+VCOS_STATUS_T vgft_font_init(VGFT_FONT_T *font);
+
+/** Load a font file from memory */
+VCOS_STATUS_T vgft_font_load_mem(VGFT_FONT_T *font, void *mem, size_t len);
+
+/** Convert a font into VG glyphs */
+VCOS_STATUS_T vgft_font_convert_glyphs(VGFT_FONT_T *font, unsigned int char_height, unsigned int dpi_x, unsigned int dpi_y);
+
+/** Release a font. */
+void vgft_font_term(VGFT_FONT_T *font);
+
+void vgft_font_draw(VGFT_FONT_T *font, VGfloat x, VGfloat y, const char *text, unsigned text_length, VGbitfield paint_modes);
+
+void vgft_get_text_extents(VGFT_FONT_T *font, const char *text, unsigned text_length, VGfloat start_x, VGfloat start_y, VGfloat *w, VGfloat *h);
+
+VGfloat vgft_first_line_y_offset(VGFT_FONT_T *font);
+
+#endif
diff --git a/host_applications/linux/apps/hello_pi/rebuild.sh b/host_applications/linux/apps/hello_pi/rebuild.sh
new file mode 100755 (executable)
index 0000000..8225dd5
--- /dev/null
@@ -0,0 +1,34 @@
+make -C libs/ilclient clean
+make -C libs/vgfont clean
+make -C hello_world clean
+make -C hello_triangle clean
+make -C hello_triangle2 clean
+make -C hello_video clean
+make -C hello_audio clean
+make -C hello_font clean
+make -C hello_dispmanx clean
+make -C hello_tiger clean
+make -C hello_encode clean
+make -C hello_jpeg clean
+make -C hello_videocube clean
+make -C hello_teapot clean
+make -C hello_fft clean
+make -C hello_mmal_encode clean
+
+make -C libs/ilclient
+make -C libs/vgfont
+make -C hello_world
+make -C hello_triangle
+make -C hello_triangle2
+make -C hello_video
+make -C hello_audio
+make -C hello_font
+make -C hello_dispmanx
+make -C hello_tiger
+make -C hello_encode
+make -C hello_jpeg
+make -C hello_videocube
+make -C hello_teapot
+make -C hello_fft
+make -C hello_mmal_encode
+
diff --git a/host_applications/linux/apps/raspicam/CMakeLists.txt b/host_applications/linux/apps/raspicam/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..e6aa6b8
--- /dev/null
@@ -0,0 +1,36 @@
+
+# raspistill/raspivid/raspiyuv
+
+SET(COMPILE_DEFINITIONS -Werror)
+
+include_directories(${PROJECT_SOURCE_DIR}/host_applications/linux/libs/bcm_host/include)
+include_directories(${PROJECT_SOURCE_DIR}/host_applications/linux/apps/raspicam/)
+include_directories(${PROJECT_SOURCE_DIR}/host_applications/linux/libs/sm)
+
+set (GL_SCENE_SOURCES
+   gl_scenes/models.c
+   gl_scenes/mirror.c
+   gl_scenes/yuv.c
+   gl_scenes/sobel.c
+   gl_scenes/square.c
+   gl_scenes/teapot.c
+   gl_scenes/vcsm_square.c)
+
+set (COMMON_SOURCES
+   RaspiCamControl.c
+   RaspiCLI.c
+   RaspiPreview.c)
+
+add_executable(raspistill ${COMMON_SOURCES} RaspiStill.c  RaspiTex.c RaspiTexUtil.c tga.c ${GL_SCENE_SOURCES})
+add_executable(raspiyuv   ${COMMON_SOURCES} RaspiStillYUV.c)
+add_executable(raspivid   ${COMMON_SOURCES} RaspiVid.c)
+add_executable(raspividyuv  ${COMMON_SOURCES} RaspiVidYUV.c)
+
+set (MMAL_LIBS mmal_core mmal_util mmal_vc_client)
+
+target_link_libraries(raspistill ${MMAL_LIBS} vcos bcm_host brcmGLESv2 brcmEGL m)
+target_link_libraries(raspiyuv   ${MMAL_LIBS} vcos bcm_host)
+target_link_libraries(raspivid   ${MMAL_LIBS} vcos bcm_host)
+target_link_libraries(raspividyuv   ${MMAL_LIBS} vcos bcm_host)
+
+install(TARGETS raspistill raspiyuv raspivid raspividyuv RUNTIME DESTINATION bin)
diff --git a/host_applications/linux/apps/raspicam/Doxyfile b/host_applications/linux/apps/raspicam/Doxyfile
new file mode 100755 (executable)
index 0000000..94285b9
--- /dev/null
@@ -0,0 +1,1869 @@
+# Doxyfile 1.8.3.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a hash (#) is considered a comment and will be ignored.
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or sequence of words) that should
+# identify the project. Note that if you do not use Doxywizard you need
+# to put quotes around the project name if it contains spaces.
+
+PROJECT_NAME           = "RaspiCam"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = 1
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer
+# a quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF          =  Raspberry Pi Camera support applications
+
+# With the PROJECT_LOGO tag one can specify an logo or icon that is
+# included in the documentation. The maximum height of the logo should not
+# exceed 55 pixels and the maximum width should not exceed 200 pixels.
+# Doxygen will copy the logo to the output directory.
+
+PROJECT_LOGO           =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = docs
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip. Note that you specify absolute paths here, but also
+# relative paths, which will be relative from the directory where doxygen is
+# started.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful if your file system
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 4
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding
+# "class=itcl::class" will allow you to use the command class in the
+# itcl::class meaning.
+
+TCL_SUBST              =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension,
+# and language is one of the parsers supported by doxygen: IDL, Java,
+# Javascript, CSharp, C, C++, D, PHP, Objective-C, Python, Fortran, VHDL, C,
+# C++. For instance to make doxygen treat .inc files as Fortran files (default
+# is PHP), and .f files as C (default is Fortran), use: inc=Fortran f=C. Note
+# that for custom extensions you also need to set FILE_PATTERNS otherwise the
+# files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
+# comments according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you
+# can mix doxygen, HTML, and XML commands with Markdown formatting.
+# Disable only in case of backward compatibilities issues.
+
+MARKDOWN_SUPPORT       = YES
+
+# When enabled doxygen tries to link words that correspond to documented classes,
+# or namespaces to their corresponding documentation. Such a link can be
+# prevented in individual cases by by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+
+AUTOLINK_SUPPORT       = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also makes the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES (the
+# default) will make doxygen replace the get and set methods by a property in
+# the documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
+# unions are shown inside the group in which they are included (e.g. using
+# @ingroup) instead of on a separate page (for HTML and Man pages) or
+# section (for LaTeX and RTF).
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
+# unions with only public data fields will be shown inline in the documentation
+# of the scope in which they are defined (i.e. file, namespace, or group
+# documentation), provided this scope is documented. If set to NO (the default),
+# structs, classes, and unions are shown on a separate page (for HTML and Man
+# pages) or section (for LaTeX and RTF).
+
+INLINE_SIMPLE_STRUCTS  = NO
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penalty.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+SYMBOL_CACHE_SIZE      = 0
+
+# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
+# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
+# their name and scope. Since this can be an expensive process and often the
+# same symbol appear multiple times in the code, doxygen keeps a cache of
+# pre-resolved symbols. If the cache is too small doxygen will become slower.
+# If the cache is too large, memory is wasted. The cache size is given by this
+# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols.
+
+LOOKUP_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+
+EXTRACT_PACKAGE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespaces are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
+# will list include files with double quotes in the documentation
+# rather than with sharp brackets.
+
+FORCE_LOCAL_INCLUDES   = NO
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
+# do proper type resolution of all parameters of a function it will reject a
+# match between the prototype and the implementation of a member function even
+# if there is only one candidate or it is obvious which candidate to choose
+# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
+# will still accept a match between prototype and implementation in such cases.
+
+STRICT_PROTO_MATCHING  = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if section-label ... \endif
+# and \cond section-label ... \endcond blocks.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or macro consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and macros in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option.
+# You can optionally specify a file name after the option, if omitted
+# DoxygenLayout.xml will be used as the name of the layout file.
+
+LAYOUT_FILE            =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files
+# containing the references data. This must be a list of .bib files. The
+# .bib extension is automatically appended if omitted. Using this command
+# requires the bibtex tool to be installed. See also
+# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
+# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
+# feature you need bibtex and perl available in the search path. Do not use
+# file names with spaces, bibtex cannot handle them.
+
+CITE_BIB_FILES         =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# The WARN_NO_PARAMDOC option can be enabled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  =
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
+# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
+# *.f90 *.f *.for *.vhd *.vhdl
+
+FILE_PATTERNS          =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER           =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty or if
+# non of the patterns match the file name, INPUT_FILTER is applied.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
+# and it is also possible to disable source filtering for a specific pattern
+# using *.ext= (so without naming a filter). This option only has effect when
+# FILTER_SOURCE_FILES is enabled.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MD_FILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page (index.html).
+# This can be useful if you have a project on for instance GitHub and want reuse
+# the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C, C++ and Fortran comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header. Note that when using a custom header you are responsible
+#  for the proper inclusion of any scripts and style sheets that doxygen
+# needs, which is dependent on the configuration options used.
+# It is advised to generate a default header using "doxygen -w html
+# header.html footer.html stylesheet.css YourConfigFile" and then modify
+# that header. Note that the header is subject to change so you typically
+# have to redo this when upgrading to a newer version of doxygen or when
+# changing the value of configuration settings such as GENERATE_TREEVIEW!
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If left blank doxygen will
+# generate a default style sheet. Note that it is recommended to use
+# HTML_EXTRA_STYLESHEET instead of this one, as it is more robust and this
+# tag will in the future become obsolete.
+
+HTML_STYLESHEET        =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional
+# user-defined cascading style sheet that is included after the standard
+# style sheets created by doxygen. Using this option one can overrule
+# certain style aspects. This is preferred over using HTML_STYLESHEET
+# since it does not replace the standard style sheet and is therefor more
+# robust against future updates. Doxygen will copy the style sheet file to
+# the output directory.
+
+HTML_EXTRA_STYLESHEET  =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that
+# the files will be copied as-is; there are no commands or markers available.
+
+HTML_EXTRA_FILES       =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
+# Doxygen will adjust the colors in the style sheet and background images
+# according to this color. Hue is specified as an angle on a colorwheel,
+# see http://en.wikipedia.org/wiki/Hue for more information.
+# For instance the value 0 represents red, 60 is yellow, 120 is green,
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
+# The allowed range is 0 to 359.
+
+HTML_COLORSTYLE_HUE    = 220
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
+# the colors in the HTML output. For a value of 0 the output will use
+# grayscales only. A value of 255 will produce the most vivid colors.
+
+HTML_COLORSTYLE_SAT    = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
+# the luminance component of the colors in the HTML output. Values below
+# 100 gradually make the output lighter, whereas values above 100 make
+# the output darker. The value divided by 100 is the actual gamma applied,
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
+# and 100 does not change the gamma.
+
+HTML_COLORSTYLE_GAMMA  = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting
+# this to NO can help when comparing the output of multiple runs.
+
+HTML_TIMESTAMP         = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
+# entries shown in the various tree structured indices initially; the user
+# can expand and collapse entries dynamically later on. Doxygen will expand
+# the tree to such a level that at most the specified number of entries are
+# visible (unless a fully collapsed tree already exceeds this amount).
+# So setting the number of entries 1 will produce a full collapsed tree by
+# default. 0 is a special value representing an infinite number of entries
+# and will result in a full expanded tree by default.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely
+# identify the documentation publisher. This should be a reverse domain-name
+# style string, e.g. com.mycompany.MyDocSet.documentation.
+
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher
+
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+
+DOCSET_PUBLISHER_NAME  = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
+# that can be used as input for Qt's qhelpgenerator to generate a
+# Qt Compressed Help (.qch) of the generated HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
+# add. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
+# Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
+# Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
+#  will be generated, which together with the HTML files, form an Eclipse help
+# plugin. To install this plugin and make it available under the help contents
+# menu in Eclipse, the contents of the directory containing the HTML and XML
+# files needs to be copied into the plugins directory of eclipse. The name of
+# the directory within the plugins directory should be the same as
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
+# the help appears.
+
+GENERATE_ECLIPSEHELP   = NO
+
+# A unique identifier for the eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have
+# this name.
+
+ECLIPSE_DOC_ID         = org.doxygen.Project
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
+# at top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it. Since the tabs have the same information as the
+# navigation tree you can set this option to NO if you already set
+# GENERATE_TREEVIEW to YES.
+
+DISABLE_INDEX          = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+# Since the tree basically has the same information as the tab index you
+# could consider to set DISABLE_INDEX to NO when enabling this option.
+
+GENERATE_TREEVIEW      = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
+# (range [0,1..20]) that doxygen will group on one line in the generated HTML
+# documentation. Note that a value of 0 will completely suppress the enum
+# values from appearing in the overview section.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
+# links to external symbols imported via tag files in a separate window.
+
+EXT_LINKS_IN_WINDOW    = NO
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are
+# not supported properly for IE 6.0, but are supported on all modern browsers.
+# Note that when changing this option you need to delete any form_*.png files
+# in the HTML output before the changes have effect.
+
+FORMULA_TRANSPARENT    = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
+# (see http://www.mathjax.org) which uses client side Javascript for the
+# rendering instead of using prerendered bitmaps. Use this if you do not
+# have LaTeX installed or if you want to formulas look prettier in the HTML
+# output. When enabled you may also need to install MathJax separately and
+# configure the path to it using the MATHJAX_RELPATH option.
+
+USE_MATHJAX            = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# thA MathJax output. Supported types are HTML-CSS, NativeMML (i.e. MathML) and
+# SVG. The default value is HTML-CSS, which is slower, but has the best
+# compatibility.
+
+MATHJAX_FORMAT         = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the
+# HTML output directory using the MATHJAX_RELPATH option. The destination
+# directory should contain the MathJax.js script. For instance, if the mathjax
+# directory is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to
+# the MathJax Content Delivery Network so you can quickly see the result without
+# installing MathJax.
+# However, it is strongly recommended to install a local
+# copy of MathJax from http://www.mathjax.org before deployment.
+
+MATHJAX_RELPATH        = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
+# names that should be enabled during MathJax rendering.
+
+MATHJAX_EXTENSIONS     =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
+# (GENERATE_DOCSET) there is already a search function so this one should
+# typically be disabled. For large projects the javascript based search engine
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+
+SEARCHENGINE           = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript.
+# There are two flavours of web server based search depending on the
+# EXTERNAL_SEARCH setting. When disabled, doxygen will generate a PHP script for
+# searching and an index file used by the script. When EXTERNAL_SEARCH is
+# enabled the indexing and searching needs to be provided by external tools.
+# See the manual for details.
+
+SERVER_BASED_SEARCH    = NO
+
+# When EXTERNAL_SEARCH is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain
+# the search results. Doxygen ships with an example indexer (doxyindexer) and
+# search engine (doxysearch.cgi) which are based on the open source search engine
+# library Xapian. See the manual for configuration details.
+
+EXTERNAL_SEARCH        = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will returned the search results when EXTERNAL_SEARCH is enabled.
+# Doxygen ships with an example search engine (doxysearch) which is based on
+# the open source search engine library Xapian. See the manual for configuration
+# details.
+
+SEARCHENGINE_URL       =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+
+SEARCHDATA_FILE        = searchdata.xml
+
+# When SERVER_BASED_SEARCH AND EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+
+EXTERNAL_SEARCH_ID     =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id
+# of to a relative location where the documentation can be found.
+# The format is: EXTRA_SEARCH_MAPPINGS = id1=loc1 id2=loc2 ...
+
+EXTRA_SEARCH_MAPPINGS  =
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+# Note that when enabling USE_PDFLATEX this option is only used for
+# generating bitmaps for formulas in the HTML output, but not in the
+# Makefile that is written to the output directory.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
+# the generated latex document. The footer should contain everything after
+# the last chapter. If it is left blank doxygen will generate a
+# standard footer. Notice: only use this tag if you know what you are doing!
+
+LATEX_FOOTER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
+# http://en.wikipedia.org/wiki/BibTeX for more info.
+
+LATEX_BIB_STYLE        = plain
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load style sheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# pointed to by INCLUDE_PATH will be searched when a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition that
+# overrules the definition found in the source code.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all references to function-like macros
+# that are alone on a line, have an all uppercase name, and do not end with a
+# semicolon, because these will confuse the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles. For each
+# tag file the location of the external documentation should be added. The
+# format of a tag file without this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths
+# or URLs. Note that each tag file must have a unique name (where the name does
+# NOT include the path). If a tag file is not located in the directory in which
+# doxygen is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option also works with HAVE_DOT disabled, but it is recommended to
+# install and use dot, since it yields more powerful graphs.
+
+CLASS_DIAGRAMS         = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = NO
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
+# allowed to run in parallel. When set to 0 (the default) doxygen will
+# base this on the number of processors available in the system. You can set it
+# explicitly to a value larger than 0 to get control over the balance
+# between CPU load and processing speed.
+
+DOT_NUM_THREADS        = 0
+
+# By default doxygen will use the Helvetica font for all dot files that
+# doxygen generates. When you want a differently looking font you can specify
+# the font name using DOT_FONTNAME. You need to make sure dot is able to find
+# the font, which can be done by putting it in a standard location or by setting
+# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
+# directory containing the font.
+
+DOT_FONTNAME           = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the Helvetica font.
+# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
+# set the path where dot can find it.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside
+# the class node. If there are many fields or methods and many nodes the
+# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
+# threshold limits the number of items for each type to make the size more
+# manageable. Set this to 0 for no limit. Note that the threshold may be
+# exceeded by 50% before the limit is enforced.
+
+UML_LIMIT_NUM_FIELDS   = 10
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will generate a graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = YES
+
+# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are svg, png, jpg, or gif.
+# If left blank png will be used. If you choose svg you need to set
+# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible in IE 9+ (other browsers do not have this requirement).
+
+DOT_IMAGE_FORMAT       = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+# Note that this requires a modern browser other than Internet Explorer.
+# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
+# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
+# visible. Older versions of IE do not have SVG support.
+
+INTERACTIVE_SVG        = NO
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the
+# \mscfile command).
+
+MSCFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/host_applications/linux/apps/raspicam/Makefile b/host_applications/linux/apps/raspicam/Makefile
new file mode 100755 (executable)
index 0000000..ca1853c
--- /dev/null
@@ -0,0 +1,6 @@
+OBJS=RaspiCamControl.o RaspiCLI.o RaspiPreview.o RaspiStill.o
+BIN=raspicam.bin
+LDFLAGS+=-lmmal -lmmal_core -lmmal_util
+
+include ../Makefile.include
+
diff --git a/host_applications/linux/apps/raspicam/README.md b/host_applications/linux/apps/raspicam/README.md
new file mode 100755 (executable)
index 0000000..6232cab
--- /dev/null
@@ -0,0 +1,477 @@
+RaspiCam Documentation
+
+This document describes the use of the three Raspberry Pi camera applications as of October 11th 2013.
+
+There are three applications provided, raspistill, raspivid and raspistillyuv. raspistill and raspistillyuv are very similar and are intended for capturing images, raspivid is for capturing video.
+
+All the applications are command line driven, written to take advantage of the mmal API which runs over OpenMAX. The mmal API provides an easier to use system than that presented by OpenMAX. Note that mmal is a Broadcom specific API used only on Videocore 4 systems.
+
+The applications use up to four OpenMAX(mmal) components - camera, preview,  encoder and null_sink. All applications use the camera component, raspistill uses the Image Encode component, raspivid uses the Video Encode component and raspistillyuv does not use an encoder, and sends its YUV or RGB output direct from camera component to file.
+
+The preview display is optional, but can be used full screen or directed to a specific rectangular area on the display. If preview is disabled, the null_sink component is used to 'absorb' the preview frames. It is necessary for the camera to produce preview frames even if not required for display, as they are used for calculating exposure and white balance settings.
+
+In addition it is possible to omit the filename option, in which case the preview is displayed but no file is written, or to redirect all output to stdout.
+     
+Command line help is available by typing just the application name in on the command line.
+
+
+Setting up the Camera hardware
+
+
+Warning. Cameras are static sensitive. Earth yourself prior to handling the PCB, a sink tap/faucet or similar should suffice if you don't have an earthing strap.
+The camera board attaches to the Raspberry Pi via a 15 way ribbon cable. There are only two connections to make, the ribbon cable need to be attached to the camera PCB and the Raspberry Pi itself. You need to get it the right way round or the camera will not work. On the camera PCB, the blue backing on the cable should be away from the PCB, and on the Raspberry Pi it should be towards the Ethernet connection (or where the Ethernet connector would be if you are using a model A).
+
+Although the connectors on the PCB and the Pi are different, they work in a similar way. On the Raspberry Pi, pull up the tabs on each end of the connector. It should slide up easily, and be able to pivot around slightly. Fully insert the ribbon cable into the slot, ensuring it is straight, then gently press down the tabs to clip it into place. The camera PCB itself also requires you to pull the tabs away from the board, gently insert the cable, then push the tabs back. The PCB connector is a little more awkward than the one on the Pi itself. 
+
+Setting up the Camera software
+
+Execute the following instructions on the command line to download and install the latest kernel,  GPU firmware and applications. You will need a internet connection for this to work correctly.
+
+sudo apt-get update
+sudo apt-get upgrade
+
+Now you need to enable camera support using the raspi-config program you will have used when you first set up your Raspberry Pi.
+
+sudo raspi-config
+
+Use the cursor keys to move to the camera option and select enable. On exiting raspi-config it will ask to reboot. The enable option will ensure that on reboot the correct GPU firmware will be running (with the camera driver and tuning), and the GPU memory split is sufficient to allow the camera to acquire enough memory to run correctly. 
+
+To test that the system is installed and working, try the following command : 
+
+raspistill -v -o test.jpg
+
+The display should show a 5 second preview from the camera and then take a picture, saved to the file test.jpg, whilst display various informational messages.
+
+Troubleshooting
+
+If the camera is not working correctly, there are number of things to try. 
+Are the ribbon connectors all firmly seated and the right way round? They must be straight in their sockets.
+Is the camera module connector firmly attached to the camera PCB? This is the connection from the smaller black camera module itself to the camera PCB. Sometimes this connection can come loose. Using a fingernail, flip up the connector on the PCB, then reseat it with gentle pressure, it engages with a very slight click.
+Have sudo apt-get update, sudo apt-get upgrade been run?
+Has raspi-config been run and the camera enabled?
+Is your power supply sufficient? The camera adds about 200-250mA to the power requirements of the Raspberry Pi.
+
+So, if things are still not working, try the following:
+
+Error : raspistill/raspivid not found. This probably means your update/upgrade failed in some way. Try it again.
+
+Error : ENOMEM displayed. Camera is not starting up. Check all connections again. 
+
+Error : ENOSPC displayed. Camera is probably running out of GPU memory. Check config.txt in the /boot/ folder. The gpu_mem option should be at least 128.
+
+If after all the above, the camera is still not working, it may be defective. Try posting on the Raspberry Pi forum (Camera section) to see if there is any more help available there.
+
+Common Command line Options
+Preview Window
+
+
+       --preview,      -p      Preview window settings <'x,y,w,h'>
+
+Allows the user to define the size and location on the screen that the preview window will be placed. Note this will be superimposed over the top of any other windows/graphics.
+
+       --fullscreen,   -f      Fullscreen preview mode
+
+Forces the preview window to use the whole screen. Note that the aspect ratio of the incoming image will be retained, so there may be bars on some edges.
+
+       --nopreview,    -n,     Do not display a preview window
+
+Disables the preview window completely. Note that even though the preview is disabled, the camera will still be producing frames, so will be using power.
+
+       --opacity,      -op     Set preview window opacity
+
+Sets the opacity of the preview windows. 0 = invisible, 255 = fully opaque.
+
+Camera Control Options
+
+
+       --sharpness,    -sh     Set image sharpness (-100 to 100)
+
+Set the sharpness of the image, 0 is the default.
+
+       --contrast,     -co     Set image contrast (-100 to 100)
+
+Set the contrast of the image, 0 is the default
+
+       --brightness,   -br     Set image brightness (0 to 100)
+
+Set the brightness of the image, 50 is the default. 0 is black, 100 is white.
+
+       --saturation,   -sa     Set image saturation (-100 to 100)
+
+set the colour saturation of the image. 0 is the default.
+
+       --ISO,          -ISO    Set capture ISO
+
+Sets the ISO to be used for captures. Range is 100 to 800.
+       --vstab,        -vs     Turn on video stabilisation
+
+In video mode only, turn on video stabilisation.
+
+       --ev,           -ev     Set EV compensation
+
+Set the EV compensation of the image. Range is -10 to +10, default is 0.
+
+       --exposure,     -ex     Set exposure mode 
+
+Possible options are: 
+
+auto           Use automatic exposure mode
+night          Select setting for night shooting
+nightpreview
+backlight      Select setting for back lit subject
+spotlight              
+sports         Select setting for sports (fast shutter etc)
+snow           Select setting optimised for snowy scenery
+beach          Select setting optimised for beach
+verylong       Select setting for long exposures
+fixedfps,      Constrain fps to a fixed value
+antishake      Antishake mode
+fireworks      Select settings
+
+Note that not all of these settings may be implemented, depending on camera tuning.
+
+       --awb,          -awb    Set Automatic White Balance (AWB) mode
+
+off                    Turn off white balance calculation
+auto           Automatic mode (default)
+sun            Sunny mode
+cloud          Cloudy mode
+shade          Shaded mode
+tungsten       Tungsten lighting mode
+fluorescent    Fluorescent     lighting mode   
+incandescent           Incandescent lighting mode
+flash                  Flash mode
+horizon                Horizon mode
+
+       --imxfx,        -ifx    Set image effect
+
+Set an effect to be applied to the image
+
+none           NO effect (default)
+negative       Negate the image        
+solarise       Solarise the image
+posterize      Posterise the image
+whiteboard     Whiteboard effect
+blackboard     Blackboard effect
+sketch         Sketch style effect
+denoise        Denoise the image
+emboss Emboss the image
+oilpaint               Apply an oil paint style effect
+hatch          Hatch sketch style
+gpen   
+pastel         A pastel style effect
+watercolour    A watercolour style effect
+film           Film grain style effect
+blur           Blur the image
+saturation     Colour saturate the image
+colourswap     Not fully implemented
+washedout      Not fully implemented
+posterise      Not fully implemented
+colourpoint    Not fully implemented
+colourbalance  Not fully implemented
+cartoon                Not fully implemented
+
+       --colfx,         -cfx   Set colour effect <U:V>
+
+The supplied U and V parameters (range 0 to 255) are applied to the U and Y channels of the image. For example, --colfx 128:128 should result in a monochrome image.
+
+       --metering,     -mm     Set metering mode
+
+Specify the metering mode used for the preview and capture
+
+average        Average the whole frame for metering.
+spot           Spot metering
+backlit                Assume a backlit image
+matrix         Matrix metering
+
+       --rotation,      -rot  Set image rotation (0-359)
+
+Sets the rotation of the image in viewfinder and resulting image. This can take any value from 0 upwards, but due to hardware constraints only 0, 90, 180 and 270 degree rotations are supported.
+
+
+       --hflip,                -hf     Set horizontal flip
+
+Flips the preview and saved image horizontally.
+
+       --vflip,        -vf     Set vertical flip
+
+Flips the preview and saved image vertically.
+
+       --roi,          -roi    Set sensor region of interest 
+
+Allows the specification of the area of the sensor to be used as the source for the preview and capture. This is defined as x,y for the top left corner, and a width and height, all values in normalised coordinates (0.0-1.0). So to set a ROI at half way across and down the sensor, and an width and height of a quarter of the sensor use :
+
+               -roi 0.5,0.5,0.25,0.25
+
+       --shutter,      -ss     Set shutter speed
+
+Set the shutter speed to the specified value (in microseconds). There is currently an upper limit of approximately 330000us (330ms, 0.33s) past which operation is undefined. This is being investigated.
+
+       --camselect,    -cs     Select <camera number>
+
+Select camera number. Default 0
+
+Application specific settings
+
+raspistill
+
+--width,               -w              Set image width <size>
+--height,      -h              Set image height <size>
+--quality,     -q              Set jpeg quality <0 to 100>
+
+Quality 100 is almost completely uncompressed. 75 is a good all round value
+
+       --raw,          -r              Add raw bayer data to jpeg metadata
+
+This option inserts the raw Bayer data from the camera in to the JPEG metadata
+
+       --output        -o              Output filename <filename>.
+
+Specify the output filename. If not specified, no file is saved. If the filename is '-', then all output is sent to stdout.
+
+       --latest                -l              Link latest frame to filename <filename>
+
+Make a file system link under this name to the latest frame.
+
+       --verbose,      -v              Output verbose information during run
+
+Outputs debugging/information messages during the program run.
+
+       --timeout,      -t              Time before takes picture and shuts down.
+
+The program will run for this length of time, then take the capture (if output is specified). If not specified, this is set to 5 seconds. 
+
+       --timelapse,    -tl             Timelapse mode.
+
+The specific value is the time between shots in milliseconds. Note you should specify %04d at the point in the filename where you want a frame count number to appear. e.g.
+
+               -t 30000 -tl 2000 -o image%04d.jpg
+
+You can also name the files with timestamp (-ts) or datetime(-dt)
+
+               -t 30000 -tl 2000 -ts -o image%d.jpg
+               -t 30000 -tl 2000 -dt -o image2015%10d.jpg
+
+will produce a capture every 2 seconds, over a total period of 30s, named image1.jpg, image0002.jpg..image0015.jpg. Note that the %04d indicates a 4 digit number with leading zero's added to pad to the required number of digits. So, for example,  %08d would result in an 8 digit number.
+
+If a timelapse value of 0 is entered, the application will take pictures as fast as possible. Note there is an minimum enforced pause of 30ms between captures to ensure that exposure calculations can be made. 
+
+       --thumb,        -th             Set thumbnail parameters (x:y:quality)
+
+Allows specification of the thumbnail image inserted in to the JPEG file. If not specified, defaults are a size of 64x48 at quality 35.
+
+       --demo,         -d              Run a demo mode <milliseconds>
+
+This options cycles through range of camera options, no capture is done, the demo will end at the end of the timeout period, irrespective of whether all the options have been cycled. The time between cycles should be specified as a millisecond value.
+
+       --encoding,     -e              Encoding to use for output file
+
+Valid options are jpg, bmp, gif and png. Note that unaccelerated image types (gif, png, bmp) will take much longer to save than JPG which is hardware accelerated. Also note that the filename suffix is completely ignored when deciding the encoding of a file.
+
+       --exif,         -x              EXIF tag to apply to captures (format as 'key=value')
+
+Allows the insertion of specific exif tags in to the JPEG image. You can have up to 32 exif tge entries. This is useful for things like adding GPS metadata. For example, to set the Longitude
+
+               --exif GPS.GPSLongitude=5/1,10/1,15/100
+
+would set the Longitude to 5degs, 10 minutes, 15 seconds. See exif documentation for more details on the range of tags available; the supported tags are as follows.
+
+IFD0.<   or 
+IFD1.<
+ImageWidth, ImageLength, BitsPerSample, Compression, PhotometricInterpretation, ImageDescription, Make, Model, StripOffsets, Orientation, SamplesPerPixel, RowsPerString, StripByteCounts, Xresolution, Yresolution, PlanarConfiguration, ResolutionUnit, TransferFunction, Software, DateTime, Artist, WhitePoint, PrimaryChromaticities, JPEGInterchangeFormat, JPEGInterchangeFormatLength, YcbCrCoefficients, YcbCrSubSampling, YcbCrPositioning, ReferenceBlackWhite, Copyright>
+
+EXIF.<
+ExposureTime, FNumber, ExposureProgram, SpectralSensitivity,          a
+ISOSpeedRatings, OECF, ExifVersion, DateTimeOriginal, DateTimeDigitized, ComponentsConfiguration, CompressedBitsPerPixel, ShutterSpeedValue, ApertureValue, BrightnessValue, ExposureBiasValue, MaxApertureValue, SubjectDistance, MeteringMode, LightSource, Flash, FocalLength, SubjectArea, MakerNote, UserComment, SubSecTime, SubSecTimeOriginal, SubSecTimeDigitized, FlashpixVersion, ColorSpace, PixelXDimension, PixelYDimension, RelatedSoundFile, FlashEnergy, SpacialFrequencyResponse, FocalPlaneXResolution, FocalPlaneYResolution, FocalPlaneResolutionUnit, SubjectLocation, ExposureIndex, SensingMethod, FileSource, SceneType, CFAPattern, CustomRendered, ExposureMode,                 
+WhiteBalance, DigitalZoomRatio, FocalLengthIn35mmFilm, SceneCaptureType, GainControl, Contrast, Saturation, Sharpness, DeviceSettingDescription, SubjectDistanceRange, ImageUniqueID>
+
+GPS.<
+GPSVersionID, GPSLatitudeRef, GPSLatitude, GPSLongitudeRef, GPSLongitude, GPSAltitudeRef, GPSAltitude, GPSTimeStamp, GPSSatellites, GPSStatus, GPSMeasureMode, GPSDOP, GPSSpeedRef, GPSSpeed, GPSTrackRef, GPSTrack, GPSImgDirectionRef, GPSImgDirection, GPSMapDatum, GPSDestLatitudeRef, GPSDestLatitude, GPSDestLongitudeRef, GPSDestLongitude, GPSDestBearingRef, GPSDestBearing, GPSDestDistanceRef, GPSDestDistance, GPSProcessingMethod, GPSAreaInformation, GPSDateStamp, GPSDifferential>
+
+EINT.<
+InteroperabilityIndex, InteroperabilityVersion, RelatedImageFileFormat, RelatedImageWidth, RelatedImageLength>
+
+Note that a small subset of these tags will be set automatically by the camera system, but will be overridden by any exif options on the command line.
+
+       --fullpreview,          -fp     Full Preview mode
+
+This runs the preview windows using the full resolution capture mode. Maximum frames per second in this mode is 15fps and the preview will have the same field of view as the capture. Captures should happen more quickly as no mode change should be required. This feature is currently under development.
+
+       --keypress              -k      Keypress mode
+
+The camera is run for the requested time (-t), and a captures can be initiated throughout that by pressing the Enter key.  Press X then Enter will exit the application before the timeout is reached. If the timeout is set to 0, the camera will run indefinitely until X then Enter is typed.
+Additional supported keys: 'i', 'o' and 'r'. Press 'i' then Enter will zoom in by 10%. Press 'o' then Enter will zoom out by 10%.  Press 'r' then Enter will reset zoom.
+Using the verbose option (-v) will display a prompt asking for user input, otherwise no prompt is displayed.
+
+       --signal                        -s      Signal mode
+
+The camera is run for the requested time (-t), and a captures can be initiated throughout that time by sending a USR1 signal to the camera process. If USR2 signal is received the application makes a capture and exits. This can be done using the kill command. You can find the camera process ID using the 'ps ax' command or using pidof command.
+
+               kill -USR1 <process id of raspistill>
+               kill -USR2 <process id of raspistill>
+
+raspistillyuv
+
+
+Many of the options for raspistillyuv are the same as those for raspistill. This section shows the differences.
+
+Unsupported Options:
+       --exif, --encoding, --thumb, --raw, --quality
+
+Extra Options :
+
+       --rgb,          -rgb    Save uncompressed data as RGB888
+
+This option forces the image to be saved as RGB data with 8 bits per channel, rather than YUV420. 
+
+Note that the image buffers saved in raspistillyuv are padded to a horizontal size divisible by 16 (so there may be unused bytes at the end of each line to made the width divisible by 16). Buffers are also padded vertically to be divisible by 16, and in the YUV mode, each plane of Y,U,V is padded in this way.
+
+
+raspivid
+
+
+       --width,                -w      Set image width <size>
+
+Width of resulting video. This should be between 64 and 1920.
+
+       --height,       -h      Set image height <size>
+
+Height of resulting video. This should be between 64 and 1080.
+
+       --bitrate,      -b      Set bitrate. 
+
+Use bits per second, so 10MBits/s would be -b 10000000. For H264, 1080p a high quality bitrate would be 15Mbits/s or more.
+
+       --output        -o      Output filename <filename>.
+
+Specify the output filename. If not specified, no file is saved. If the filename is '-', then all output is sent to stdout.
+
+       --verbose,      -v      Output verbose information during run
+
+Outputs debugging/information messages during the program run.
+
+       --timeout,      -t      Time before takes picture and shuts down.
+
+The program will run for this length of time, then take the capture (if output is specified). If not specified, this is set to 5seconds. Setting 0 will mean the application will run continuously until stopped with Ctrl-C.
+
+       --demo,         -d      Run a demo mode <milliseconds>
+
+This options cycles through range of camera options, no capture is done, the demo will end at the end of the timeout period, irrespective of whether all the options have been cycled. The time between cycles should be specified as a millisecond value.
+
+       --framerate,    -fps    Specify the frames per second to record
+
+At present, the minimum frame rate allowed is 2fps, the maximum is 30fps. This is likely to change in the future.
+
+       --penc,         -e      Display preview image *after* encoding
+
+Switch on an option to display the preview after compression. This will show any compression artefacts in the preview window. In normal operation, the preview will show the camera output prior to being compressed. This option is not guaranteed to work in future releases.
+
+       --intra,        -g      Specify the intra refresh period (key frame rate/GoP)
+
+Sets the intra refresh period (GoP) rate for the recorded video. H264 video uses a complete frame (I-frame) every intra refresh period from which subsequent frames are based. This options specifies the numbers of frames between each I-frame. Larger numbers here will reduce the size of the resulting video, smaller numbers make the stream more robust to error. Setting 0 will produce an initial I-frame and then just P-frames.
+
+       --profile,      -pf     Specify H264 profile to use for encoding
+
+Sets the H264 profile to be used for the encoding. Options are :  baseline, main, high.
+
+Examples
+
+Still captures
+
+By default, captures are done at the highest resolution supported by the sensor.  This can be changed using the -w and -h command line options.
+
+Taking a default capture after 2s (note times are specified in milliseconds) on viewfinder, saving in image.jpg
+
+       raspistill -t 2000 -o image.jpg
+
+Take a capture at a different resolution.
+
+       raspistill -t 2000 -o image.jpg -w 640 -h 480
+
+Now reduce the quality considerably to reduce file size
+
+       raspistill -t 2000 -o image.jpg -q 5
+
+Force the preview to appear at coordinate 100,100, with width 300 and height 200 pixels.
+
+       raspistill -t 2000 -o image.jpg -p 100,100,300,200
+
+Disable preview entirely
+
+       raspistill -t 2000 -o image.jpg -n
+
+Save the image as a png file (lossless compression, but slower than JPEG). Note that the filename suffix is ignored when choosing the image encoding. 
+
+       raspistill -t 2000 -o image.png -e png 
+
+Add some EXIF information to the JPEG. This sets the Artist tag name to Boris, and the GPS altitude to 123.5m. Note that if setting GPS tags you should set as a minimum GPSLatitude, GPSLatitudeRef, GPSLongitude, GPSLongitudeRef, GPSAltitude and GPSAltitudeRef.
+
+       raspistill -t 2000 -o image.jpg -x IFDO.Artist=Boris -x GPS.GPSAltitude=1235/10
+
+Set an emboss style image effect
+
+       raspistill -t 2000 -o image.jpg -ifx emboss
+
+Set the U and V channels of the YUV image to specific values (128:128 produces a greyscale image)
+
+       raspistill -t 2000 -o image.jpg -cfx 128:128
+
+Run preview ONLY for 2s, no saved image.
+
+       raspistill -t 2000 
+
+Take timelapse picture, one every 10 seconds for 10 minutes (10 minutes = 600000ms), named image_num_001_today.jpg, image_num_002_today.jpg onwards, with the latest picture also available under the name latest.jpg.
+
+       raspistill -t 600000 -tl 10000 -o image_num_%03d_today.jpg -l latest.jpg
+
+Take a picture and send image data to stdout
+
+       raspistill -t 2000 -o - 
+
+Take a picture and send image data to file
+
+       raspistill -t 2000 -o - > my_file.jpg
+
+Run camera forever, taking a picture when Enter is pressed
+
+       raspistill -t 0 -k -o my_pics%02d.jpg 
+Video Captures
+
+Image size and preview settings are the same as for stills capture. Default size for video recording is 1080p (1920x1080)
+
+Record a 5s clip with default settings (1080p30)
+
+       raspivid -t 5000 -o video.h264
+
+Record a 5s clip at a specified bitrate (3.5MBits/s)
+
+       raspivid -t 5000 -o video.h264 -b 3500000
+
+Record a 5s clip at a specified framerate (5fps)
+
+       raspivid -t 5000 -o video.h264 -f 5
+
+Encode a 5s camera stream and send image data to stdout
+
+       raspivid -t 5000 -o - 
+
+Encode a 5s camera stream and send image data to file
+
+       raspivid -t 5000 -o - > my_file.h264
+
+
+
+Shell Error Codes
+
+The applications described here will return a standard error code to the shell on completion. Possible error codes are : 
+
+ER_OK                  0       Application ran successfully.
+EX_USAGE               64      Bad command line parameter
+ER_SOFTWARE            70      Software or camera error
+                       130     Application terminated by ctrl-C.
+
+
+
+
+
+
diff --git a/host_applications/linux/apps/raspicam/RaspiCLI.c b/host_applications/linux/apps/raspicam/RaspiCLI.c
new file mode 100755 (executable)
index 0000000..9f858f4
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, James Hughes
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * \file RaspiCLI.c
+ * Code for handling command line parameters
+ *
+ * \date 4th March 2013
+ * \Author: James Hughes
+ *
+ * Description
+ *
+ * Some functions/structures for command line parameter parsing
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+
+#include "interface/vcos/vcos.h"
+
+#include "RaspiCLI.h"
+
+
+/**
+ * Convert a string from command line to a comand_id from the list
+ *
+ * @param commands Array of command to check
+ * @param num_command Number of commands in the array
+ * @param arg String to search for in the list
+ * @param num_parameters Returns the number of parameters used by the command
+ *
+ * @return command ID if found, -1 if not found
+ *
+ */
+int raspicli_get_command_id(const COMMAND_LIST *commands, const int num_commands, const char *arg, int *num_parameters)
+{
+   int command_id = -1;
+   int j;
+
+   vcos_assert(commands);
+   vcos_assert(num_parameters);
+   vcos_assert(arg);
+
+   if (!commands || !num_parameters || !arg)
+      return -1;
+
+   for (j = 0; j < num_commands; j++)
+   {
+      if (!strcmp(arg, commands[j].command) ||
+          !strcmp(arg, commands[j].abbrev))
+      {
+         // match
+         command_id = commands[j].id;
+         *num_parameters = commands[j].num_parameters;
+         break;
+      }
+   }
+
+   return command_id;
+}
+
+
+/**
+ * Display the list of commands in help format
+ *
+ * @param commands Array of command to check
+ * @param num_command Number of commands in the arry
+ *
+ *
+ */
+void raspicli_display_help(const COMMAND_LIST *commands, const int num_commands)
+{
+   int i;
+
+   vcos_assert(commands);
+
+   if (!commands)
+      return;
+
+   for (i = 0; i < num_commands; i++)
+   {
+      fprintf(stdout, "-%s, -%s\t: %s\n", commands[i].abbrev,
+         commands[i].command, commands[i].help);
+   }
+}
+
+
+/**
+ * Function to take a string, a mapping, and return the int equivalent
+ * @param str Incoming string to match
+ * @param map Mapping data
+ * @param num_refs The number of items in the mapping data
+ * @return The integer match for the string, or -1 if no match
+ */
+int raspicli_map_xref(const char *str, const XREF_T *map, int num_refs)
+{
+   int i;
+
+   for (i=0;i<num_refs;i++)
+   {
+      if (!strcasecmp(str, map[i].mode))
+      {
+         return map[i].mmal_mode;
+      }
+   }
+   return -1;
+}
+
+/**
+ * Function to take a mmal enum (as int) and return the string equivalent
+ * @param en Incoming int to match
+ * @param map Mapping data
+ * @param num_refs The number of items in the mapping data
+ * @return const pointer to string, or NULL if no match
+ */
+const char *raspicli_unmap_xref(const int en, XREF_T *map, int num_refs)
+{
+   int i;
+
+   for (i=0;i<num_refs;i++)
+   {
+      if (en == map[i].mmal_mode)
+      {
+         return map[i].mode;
+      }
+   }
+   return NULL;
+}
diff --git a/host_applications/linux/apps/raspicam/RaspiCLI.h b/host_applications/linux/apps/raspicam/RaspiCLI.h
new file mode 100755 (executable)
index 0000000..26b1ce3
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, James Hughes
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef RASPICLI_H_
+#define RASPICLI_H_
+
+typedef struct
+{
+   int id;
+   char *command;
+   char *abbrev;
+   char *help;
+   int num_parameters;
+} COMMAND_LIST;
+
+/// Cross reference structure, mode string against mode id
+typedef struct xref_t
+{
+   char *mode;
+   int mmal_mode;
+} XREF_T;
+
+
+void raspicli_display_help(const COMMAND_LIST *commands, const int num_commands);
+int raspicli_get_command_id(const COMMAND_LIST *commands, const int num_commands, const char *arg, int *num_parameters);
+
+int raspicli_map_xref(const char *str, const XREF_T *map, int num_refs);
+const char *raspicli_unmap_xref(const int en, XREF_T *map, int num_refs);
+
+
+#endif
diff --git a/host_applications/linux/apps/raspicam/RaspiCamControl.c b/host_applications/linux/apps/raspicam/RaspiCamControl.c
new file mode 100755 (executable)
index 0000000..a700010
--- /dev/null
@@ -0,0 +1,1773 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, James Hughes
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <memory.h>
+#include <ctype.h>
+
+#include "interface/vcos/vcos.h"
+
+#include "interface/vmcs_host/vc_vchi_gencmd.h"
+#include "interface/mmal/mmal.h"
+#include "interface/mmal/mmal_logging.h"
+#include "interface/mmal/util/mmal_util.h"
+#include "interface/mmal/util/mmal_util_params.h"
+#include "interface/mmal/util/mmal_default_components.h"
+#include "RaspiCamControl.h"
+#include "RaspiCLI.h"
+
+/// Structure to cross reference exposure strings against the MMAL parameter equivalent
+static XREF_T  exposure_map[] =
+{
+   {"off",           MMAL_PARAM_EXPOSUREMODE_OFF},
+   {"auto",          MMAL_PARAM_EXPOSUREMODE_AUTO},
+   {"night",         MMAL_PARAM_EXPOSUREMODE_NIGHT},
+   {"nightpreview",  MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW},
+   {"backlight",     MMAL_PARAM_EXPOSUREMODE_BACKLIGHT},
+   {"spotlight",     MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT},
+   {"sports",        MMAL_PARAM_EXPOSUREMODE_SPORTS},
+   {"snow",          MMAL_PARAM_EXPOSUREMODE_SNOW},
+   {"beach",         MMAL_PARAM_EXPOSUREMODE_BEACH},
+   {"verylong",      MMAL_PARAM_EXPOSUREMODE_VERYLONG},
+   {"fixedfps",      MMAL_PARAM_EXPOSUREMODE_FIXEDFPS},
+   {"antishake",     MMAL_PARAM_EXPOSUREMODE_ANTISHAKE},
+   {"fireworks",     MMAL_PARAM_EXPOSUREMODE_FIREWORKS}
+};
+
+static const int exposure_map_size = sizeof(exposure_map) / sizeof(exposure_map[0]);
+
+/// Structure to cross reference flicker avoid strings against the MMAL parameter equivalent
+
+static XREF_T  flicker_avoid_map[] =
+{
+   {"off",           MMAL_PARAM_FLICKERAVOID_OFF},
+   {"auto",          MMAL_PARAM_FLICKERAVOID_AUTO},
+   {"50hz",          MMAL_PARAM_FLICKERAVOID_50HZ},
+   {"60hz",          MMAL_PARAM_FLICKERAVOID_60HZ}
+};
+
+static const int flicker_avoid_map_size = sizeof(flicker_avoid_map) / sizeof(flicker_avoid_map[0]);
+
+/// Structure to cross reference awb strings against the MMAL parameter equivalent
+static XREF_T awb_map[] =
+{
+   {"off",           MMAL_PARAM_AWBMODE_OFF},
+   {"auto",          MMAL_PARAM_AWBMODE_AUTO},
+   {"sun",           MMAL_PARAM_AWBMODE_SUNLIGHT},
+   {"cloud",         MMAL_PARAM_AWBMODE_CLOUDY},
+   {"shade",         MMAL_PARAM_AWBMODE_SHADE},
+   {"tungsten",      MMAL_PARAM_AWBMODE_TUNGSTEN},
+   {"fluorescent",   MMAL_PARAM_AWBMODE_FLUORESCENT},
+   {"incandescent",  MMAL_PARAM_AWBMODE_INCANDESCENT},
+   {"flash",         MMAL_PARAM_AWBMODE_FLASH},
+   {"horizon",       MMAL_PARAM_AWBMODE_HORIZON}
+};
+
+static const int awb_map_size = sizeof(awb_map) / sizeof(awb_map[0]);
+
+/// Structure to cross reference image effect against the MMAL parameter equivalent
+static XREF_T imagefx_map[] =
+{
+   {"none",          MMAL_PARAM_IMAGEFX_NONE},
+   {"negative",      MMAL_PARAM_IMAGEFX_NEGATIVE},
+   {"solarise",      MMAL_PARAM_IMAGEFX_SOLARIZE},
+   {"sketch",        MMAL_PARAM_IMAGEFX_SKETCH},
+   {"denoise",       MMAL_PARAM_IMAGEFX_DENOISE},
+   {"emboss",        MMAL_PARAM_IMAGEFX_EMBOSS},
+   {"oilpaint",      MMAL_PARAM_IMAGEFX_OILPAINT},
+   {"hatch",         MMAL_PARAM_IMAGEFX_HATCH},
+   {"gpen",          MMAL_PARAM_IMAGEFX_GPEN},
+   {"pastel",        MMAL_PARAM_IMAGEFX_PASTEL},
+   {"watercolour",   MMAL_PARAM_IMAGEFX_WATERCOLOUR},
+   {"film",          MMAL_PARAM_IMAGEFX_FILM},
+   {"blur",          MMAL_PARAM_IMAGEFX_BLUR},
+   {"saturation",    MMAL_PARAM_IMAGEFX_SATURATION},
+   {"colourswap",    MMAL_PARAM_IMAGEFX_COLOURSWAP},
+   {"washedout",     MMAL_PARAM_IMAGEFX_WASHEDOUT},
+   {"posterise",     MMAL_PARAM_IMAGEFX_POSTERISE},
+   {"colourpoint",   MMAL_PARAM_IMAGEFX_COLOURPOINT},
+   {"colourbalance", MMAL_PARAM_IMAGEFX_COLOURBALANCE},
+   {"cartoon",       MMAL_PARAM_IMAGEFX_CARTOON}
+ };
+
+static const int imagefx_map_size = sizeof(imagefx_map) / sizeof(imagefx_map[0]);
+
+static XREF_T metering_mode_map[] =
+{
+   {"average",       MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE},
+   {"spot",          MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT},
+   {"backlit",       MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT},
+   {"matrix",        MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX}
+};
+
+static const int metering_mode_map_size = sizeof(metering_mode_map)/sizeof(metering_mode_map[0]);
+
+static XREF_T drc_mode_map[] =
+{
+   {"off",           MMAL_PARAMETER_DRC_STRENGTH_OFF},
+   {"low",           MMAL_PARAMETER_DRC_STRENGTH_LOW},
+   {"med",           MMAL_PARAMETER_DRC_STRENGTH_MEDIUM},
+   {"high",          MMAL_PARAMETER_DRC_STRENGTH_HIGH}
+};
+
+static const int drc_mode_map_size = sizeof(drc_mode_map)/sizeof(drc_mode_map[0]);
+
+static XREF_T stereo_mode_map[] =
+{
+   {"off",           MMAL_STEREOSCOPIC_MODE_NONE},
+   {"sbs",           MMAL_STEREOSCOPIC_MODE_SIDE_BY_SIDE},
+   {"tb",            MMAL_STEREOSCOPIC_MODE_TOP_BOTTOM},
+};
+
+static const int stereo_mode_map_size = sizeof(stereo_mode_map)/sizeof(stereo_mode_map[0]);
+
+
+#define CommandSharpness   0
+#define CommandContrast    1
+#define CommandBrightness  2
+#define CommandSaturation  3
+#define CommandISO         4
+#define CommandVideoStab   5
+#define CommandEVComp      6
+#define CommandExposure    7
+#define CommandAWB         8
+#define CommandImageFX     9
+#define CommandColourFX    10
+#define CommandMeterMode   11
+#define CommandRotation    12
+#define CommandHFlip       13
+#define CommandVFlip       14
+#define CommandROI         15
+#define CommandShutterSpeed 16
+#define CommandAwbGains    17
+#define CommandDRCLevel    18
+#define CommandStatsPass   19
+#define CommandAnnotate    20
+#define CommandStereoMode  21
+#define CommandStereoDecimate 22
+#define CommandStereoSwap  23
+#define CommandAnnotateExtras 24
+#define CommandFlicker     25
+#define CommandAnalogGain  26
+#define CommandDigitalGain 27
+
+static COMMAND_LIST  cmdline_commands[] =
+{
+   {CommandSharpness,   "-sharpness", "sh", "Set image sharpness (-100 to 100)",  1},
+   {CommandContrast,    "-contrast",  "co", "Set image contrast (-100 to 100)",  1},
+   {CommandBrightness,  "-brightness","br", "Set image brightness (0 to 100)",  1},
+   {CommandSaturation,  "-saturation","sa", "Set image saturation (-100 to 100)", 1},
+   {CommandISO,         "-ISO",       "ISO","Set capture ISO",  1},
+   {CommandVideoStab,   "-vstab",     "vs", "Turn on video stabilisation", 0},
+   {CommandEVComp,      "-ev",        "ev", "Set EV compensation - steps of 1/6 stop",  1},
+   {CommandExposure,    "-exposure",  "ex", "Set exposure mode (see Notes)", 1},
+   {CommandFlicker,     "-flicker",   "fli","Set flicker avoid mode (see Notes)", 1},
+   {CommandAWB,         "-awb",       "awb","Set AWB mode (see Notes)", 1},
+   {CommandImageFX,     "-imxfx",     "ifx","Set image effect (see Notes)", 1},
+   {CommandColourFX,    "-colfx",     "cfx","Set colour effect (U:V)",  1},
+   {CommandMeterMode,   "-metering",  "mm", "Set metering mode (see Notes)", 1},
+   {CommandRotation,    "-rotation",  "rot","Set image rotation (0-359)", 1},
+   {CommandHFlip,       "-hflip",     "hf", "Set horizontal flip", 0},
+   {CommandVFlip,       "-vflip",     "vf", "Set vertical flip", 0},
+   {CommandROI,         "-roi",       "roi","Set region of interest (x,y,w,d as normalised coordinates [0.0-1.0])", 1},
+   {CommandShutterSpeed,"-shutter",   "ss", "Set shutter speed in microseconds", 1},
+   {CommandAwbGains,    "-awbgains",  "awbg", "Set AWB gains - AWB mode must be off", 1},
+   {CommandDRCLevel,    "-drc",       "drc", "Set DRC Level (see Notes)", 1},
+   {CommandStatsPass,   "-stats",     "st", "Force recomputation of statistics on stills capture pass"},
+   {CommandAnnotate,    "-annotate",  "a",  "Enable/Set annotate flags or text", 1},
+   {CommandStereoMode,  "-stereo",    "3d", "Select stereoscopic mode", 1},
+   {CommandStereoDecimate,"-decimate","dec", "Half width/height of stereo image"},
+   {CommandStereoSwap,  "-3dswap",    "3dswap", "Swap camera order for stereoscopic"},
+   {CommandAnnotateExtras,"-annotateex","ae",  "Set extra annotation parameters (text size, text colour(hex YUV), bg colour(hex YUV))", 2},
+   {CommandAnalogGain,  "-analoggain", "ag", "Set the analog gain (floating point)", 1},
+   {CommandDigitalGain, "-digitalgain", "dg", "Set the digtial gain (floating point)", 1},
+};
+
+static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]);
+
+
+#define parameter_reset -99999
+
+#define zoom_full_16P16 ((unsigned int)(65536 * 0.15))
+#define zoom_increment_16P16 (65536UL / 10)
+
+/**
+ * Update the passed in parameter according to the rest of the parameters
+ * passed in.
+ *
+ *
+ * @return 0 if reached end of cycle for this parameter, !0 otherwise
+ */
+static int update_cycle_parameter(int *option, int min, int max, int increment)
+{
+   vcos_assert(option);
+   if (!option)
+      return 0;
+
+   if (*option == parameter_reset)
+      *option = min - increment;
+
+   *option += increment;
+
+   if (*option > max)
+   {
+      *option = parameter_reset;
+      return 0;
+   }
+   else
+      return 1;
+}
+
+
+/**
+ * Test/Demo code to cycle through a bunch of camera settings
+ * This code is pretty hacky so please don't complain!!
+ * It only does stuff that should have a visual impact (hence demo!)
+ * This will override any user supplied parameters
+ *
+ * Each call of this function will move on to the next setting
+ *
+ * @param camera Pointer to the camera to change settings on.
+ * @return 0 if reached end of complete sequence, !0 otherwise
+ */
+
+int raspicamcontrol_cycle_test(MMAL_COMPONENT_T *camera)
+{
+   static int parameter = 0;
+   static int parameter_option = parameter_reset; // which value the parameter currently has
+
+   vcos_assert(camera);
+
+   // We are going to cycle through all the relevant entries in the parameter block
+   // and send options to the camera.
+   if (parameter == 0)
+   {
+      // sharpness
+      if (update_cycle_parameter(&parameter_option, -100, 100, 10))
+         raspicamcontrol_set_sharpness(camera, parameter_option);
+      else
+      {
+         raspicamcontrol_set_sharpness(camera, 0);
+         parameter++;
+      }
+   }
+   else
+   if (parameter == 1)
+   {
+      // contrast
+      if (update_cycle_parameter(&parameter_option, -100, 100, 10))
+         raspicamcontrol_set_contrast(camera, parameter_option);
+      else
+      {
+         raspicamcontrol_set_contrast(camera, 0);
+         parameter++;
+      }
+   }
+   else
+   if (parameter == 2)
+   {
+      // brightness
+      if (update_cycle_parameter(&parameter_option, 0, 100, 10))
+         raspicamcontrol_set_brightness(camera, parameter_option);
+      else
+      {
+         raspicamcontrol_set_brightness(camera, 50);
+         parameter++;
+      }
+   }
+   else
+   if (parameter == 3)
+   {
+      // contrast
+      if (update_cycle_parameter(&parameter_option, -100, 100, 10))
+         raspicamcontrol_set_saturation(camera, parameter_option);
+      else
+      {
+         parameter++;
+         raspicamcontrol_set_saturation(camera, 0);
+      }
+   }
+   else
+   if (parameter == 4)
+   {
+      // EV
+      if (update_cycle_parameter(&parameter_option, -10, 10, 4))
+         raspicamcontrol_set_exposure_compensation(camera, parameter_option);
+      else
+      {
+         raspicamcontrol_set_exposure_compensation(camera, 0);
+         parameter++;
+      }
+   }
+   else
+   if (parameter == 5)
+   {
+      // MMAL_PARAM_EXPOSUREMODE_T
+      if (update_cycle_parameter(&parameter_option, 0, exposure_map_size, 1))
+         raspicamcontrol_set_exposure_mode(camera, exposure_map[parameter_option].mmal_mode);
+      else
+      {
+         raspicamcontrol_set_exposure_mode(camera, MMAL_PARAM_EXPOSUREMODE_AUTO);
+         parameter++;
+      }
+   }
+   else
+   if (parameter == 6)
+   {
+      // MMAL_PARAM_AWB_T
+      if (update_cycle_parameter(&parameter_option, 0, awb_map_size, 1))
+         raspicamcontrol_set_awb_mode(camera, awb_map[parameter_option].mmal_mode);
+      else
+      {
+         raspicamcontrol_set_awb_mode(camera, MMAL_PARAM_AWBMODE_AUTO);
+         parameter++;
+      }
+   }
+   if (parameter == 7)
+   {
+      // MMAL_PARAM_IMAGEFX_T
+      if (update_cycle_parameter(&parameter_option, 0, imagefx_map_size, 1))
+         raspicamcontrol_set_imageFX(camera, imagefx_map[parameter_option].mmal_mode);
+      else
+      {
+         raspicamcontrol_set_imageFX(camera, MMAL_PARAM_IMAGEFX_NONE);
+         parameter++;
+      }
+   }
+   if (parameter == 8)
+   {
+      MMAL_PARAM_COLOURFX_T colfx = {0,0,0};
+      switch (parameter_option)
+      {
+         case parameter_reset :
+            parameter_option = 1;
+            colfx.u = 128;
+            colfx.v = 128;
+            break;
+         case 1 :
+            parameter_option = 2;
+            colfx.u = 100;
+            colfx.v = 200;
+            break;
+         case 2 :
+            parameter_option = parameter_reset;
+            colfx.enable = 0;
+            parameter++;
+            break;
+      }
+      raspicamcontrol_set_colourFX(camera, &colfx);
+   }
+
+   // Orientation
+   if (parameter == 9)
+   {
+      switch (parameter_option)
+      {
+      case parameter_reset:
+         raspicamcontrol_set_rotation(camera, 90);
+         parameter_option = 1;
+         break;
+
+      case 1 :
+         raspicamcontrol_set_rotation(camera, 180);
+         parameter_option = 2;
+         break;
+
+      case 2 :
+         raspicamcontrol_set_rotation(camera, 270);
+         parameter_option = 3;
+         break;
+
+      case 3 :
+      {
+         raspicamcontrol_set_rotation(camera, 0);
+         raspicamcontrol_set_flips(camera, 1,0);
+         parameter_option = 4;
+         break;
+      }
+      case 4 :
+      {
+         raspicamcontrol_set_flips(camera, 0,1);
+         parameter_option = 5;
+         break;
+      }
+      case 5 :
+      {
+         raspicamcontrol_set_flips(camera, 1, 1);
+         parameter_option = 6;
+         break;
+      }
+      case 6 :
+      {
+         raspicamcontrol_set_flips(camera, 0, 0);
+         parameter_option = parameter_reset;
+         parameter++;
+         break;
+      }
+      }
+   }
+
+   if (parameter == 10)
+   {
+      parameter = 1;
+      return 0;
+   }
+
+   return 1;
+}
+
+
+
+/**
+ * Convert string to the MMAL parameter for exposure mode
+ * @param str Incoming string to match
+ * @return MMAL parameter matching the string, or the AUTO option if no match found
+ */
+static MMAL_PARAM_EXPOSUREMODE_T exposure_mode_from_string(const char *str)
+{
+   int i = raspicli_map_xref(str, exposure_map, exposure_map_size);
+
+   if( i != -1)
+      return (MMAL_PARAM_EXPOSUREMODE_T)i;
+
+   vcos_log_error("Unknown exposure mode: %s", str);
+   return MMAL_PARAM_EXPOSUREMODE_AUTO;
+}
+
+/**
+ * Convert string to the MMAL parameter for flicker avoid mode
+ * @param str Incoming string to match
+ * @return MMAL parameter matching the string, or the AUTO option if no match found
+ */
+static MMAL_PARAM_FLICKERAVOID_T flicker_avoid_mode_from_string(const char *str)
+{
+   int i = raspicli_map_xref(str, flicker_avoid_map, flicker_avoid_map_size);
+
+   if( i != -1)
+      return (MMAL_PARAM_FLICKERAVOID_T)i;
+
+   vcos_log_error("Unknown flicker avoid mode: %s", str);
+   return MMAL_PARAM_FLICKERAVOID_OFF;
+}
+
+/**
+ * Convert string to the MMAL parameter for AWB mode
+ * @param str Incoming string to match
+ * @return MMAL parameter matching the string, or the AUTO option if no match found
+ */
+static MMAL_PARAM_AWBMODE_T awb_mode_from_string(const char *str)
+{
+   int i = raspicli_map_xref(str, awb_map, awb_map_size);
+
+   if( i != -1)
+      return (MMAL_PARAM_AWBMODE_T)i;
+
+   vcos_log_error("Unknown awb mode: %s", str);
+   return MMAL_PARAM_AWBMODE_AUTO;
+}
+
+/**
+ * Convert string to the MMAL parameter for image effects mode
+ * @param str Incoming string to match
+ * @return MMAL parameter matching the strong, or the AUTO option if no match found
+ */
+MMAL_PARAM_IMAGEFX_T imagefx_mode_from_string(const char *str)
+{
+   int i = raspicli_map_xref(str, imagefx_map, imagefx_map_size);
+
+   if( i != -1)
+     return (MMAL_PARAM_IMAGEFX_T)i;
+
+   vcos_log_error("Unknown image fx: %s", str);
+   return MMAL_PARAM_IMAGEFX_NONE;
+}
+
+/**
+ * Convert string to the MMAL parameter for exposure metering mode
+ * @param str Incoming string to match
+ * @return MMAL parameter matching the string, or the AUTO option if no match found
+ */
+static MMAL_PARAM_EXPOSUREMETERINGMODE_T metering_mode_from_string(const char *str)
+{
+   int i = raspicli_map_xref(str, metering_mode_map, metering_mode_map_size);
+
+   if( i != -1)
+      return (MMAL_PARAM_EXPOSUREMETERINGMODE_T)i;
+
+   vcos_log_error("Unknown metering mode: %s", str);
+   return MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE;
+}
+
+/**
+ * Convert string to the MMAL parameter for DRC level
+ * @param str Incoming string to match
+ * @return MMAL parameter matching the string, or the AUTO option if no match found
+ */
+static MMAL_PARAMETER_DRC_STRENGTH_T drc_mode_from_string(const char *str)
+{
+   int i = raspicli_map_xref(str, drc_mode_map, drc_mode_map_size);
+
+   if( i != -1)
+      return (MMAL_PARAMETER_DRC_STRENGTH_T)i;
+
+   vcos_log_error("Unknown DRC level: %s", str);
+   return MMAL_PARAMETER_DRC_STRENGTH_OFF;
+}
+
+/**
+ * Convert string to the MMAL parameter for exposure metering mode
+ * @param str Incoming string to match
+ * @return MMAL parameter matching the string, or the AUTO option if no match found
+ */
+static MMAL_STEREOSCOPIC_MODE_T stereo_mode_from_string(const char *str)
+{
+   int i = raspicli_map_xref(str, stereo_mode_map, stereo_mode_map_size);
+
+   if( i != -1)
+      return (MMAL_STEREOSCOPIC_MODE_T)i;
+
+   vcos_log_error("Unknown metering mode: %s", str);
+   return MMAL_STEREOSCOPIC_MODE_NONE;
+}
+
+/**
+ * Parse a possible command pair - command and parameter
+ * @param arg1 Command
+ * @param arg2 Parameter (could be NULL)
+ * @return How many parameters were used, 0,1,2
+ */
+int raspicamcontrol_parse_cmdline(RASPICAM_CAMERA_PARAMETERS *params, const char *arg1, const char *arg2)
+{
+   int command_id, used = 0, num_parameters;
+
+   if (!arg1)
+       return 0;
+
+   command_id = raspicli_get_command_id(cmdline_commands, cmdline_commands_size, arg1, &num_parameters);
+
+   // If invalid command, or we are missing a parameter, drop out
+   if (command_id==-1 || (command_id != -1 && num_parameters > 0 && arg2 == NULL))
+      return 0;
+
+   switch (command_id)
+   {
+   case CommandSharpness : // sharpness - needs single number parameter
+      sscanf(arg2, "%d", &params->sharpness);
+      used = 2;
+      break;
+
+   case CommandContrast : // contrast - needs single number parameter
+      sscanf(arg2, "%d", &params->contrast);
+      used = 2;
+      break;
+
+   case CommandBrightness : // brightness - needs single number parameter
+      sscanf(arg2, "%d", &params->brightness);
+      used = 2;
+      break;
+
+   case CommandSaturation : // saturation - needs single number parameter
+      sscanf(arg2, "%d", &params->saturation);
+      used = 2;
+      break;
+
+   case CommandISO : // ISO - needs single number parameter
+      sscanf(arg2, "%d", &params->ISO);
+      used = 2;
+      break;
+
+   case CommandVideoStab : // video stabilisation - if here, its on
+      params->videoStabilisation = 1;
+      used = 1;
+      break;
+
+   case CommandEVComp : // EV - needs single number parameter
+      sscanf(arg2, "%d", &params->exposureCompensation);
+      used = 2;
+      break;
+
+   case CommandExposure : // exposure mode - needs string
+      params->exposureMode = exposure_mode_from_string(arg2);
+      used = 2;
+      break;
+      
+   case CommandFlicker : // flicker avoid mode - needs string
+      params->flickerAvoidMode = flicker_avoid_mode_from_string(arg2);
+      used = 2;
+      break;
+
+   case CommandAWB : // AWB mode - needs single number parameter
+      params->awbMode = awb_mode_from_string(arg2);
+      used = 2;
+      break;
+
+   case CommandImageFX : // Image FX - needs string
+      params->imageEffect = imagefx_mode_from_string(arg2);
+      used = 2;
+      break;
+
+   case CommandColourFX : // Colour FX - needs string "u:v"
+      sscanf(arg2, "%d:%d", &params->colourEffects.u, &params->colourEffects.v);
+      params->colourEffects.enable = 1;
+      used = 2;
+      break;
+
+   case CommandMeterMode:
+      params->exposureMeterMode = metering_mode_from_string(arg2);
+      used = 2;
+      break;
+
+   case CommandRotation : // Rotation - degree
+      sscanf(arg2, "%d", &params->rotation);
+      used = 2;
+      break;
+
+   case CommandHFlip :
+      params->hflip  = 1;
+      used = 1;
+      break;
+
+   case CommandVFlip :
+      params->vflip = 1;
+      used = 1;
+      break;
+
+   case CommandROI :
+   {
+      double x,y,w,h;
+      int args;
+
+      args = sscanf(arg2, "%lf,%lf,%lf,%lf", &x,&y,&w,&h);
+
+      if (args != 4 || x > 1.0 || y > 1.0 || w > 1.0 || h > 1.0)
+      {
+         return 0;
+      }
+
+      // Make sure we stay within bounds
+      if (x + w > 1.0)
+         w = 1 - x;
+
+      if (y + h > 1.0)
+         h = 1 - y;
+
+      params->roi.x = x;
+      params->roi.y = y;
+      params->roi.w = w;
+      params->roi.h = h;
+
+      used = 2;
+      break;
+   }
+
+   case CommandShutterSpeed : // Shutter speed needs single number parameter
+   {
+      sscanf(arg2, "%d", &params->shutter_speed);
+      used = 2;
+      break;
+   }
+
+   case CommandAwbGains :
+      {
+      double r,b;
+      int args;
+
+      args = sscanf(arg2, "%lf,%lf", &r,&b);
+
+      if (args != 2 || r > 8.0 || b > 8.0)
+      {
+         return 0;
+      }
+
+      params->awb_gains_r = r;
+      params->awb_gains_b = b;
+
+      used = 2;
+      break;
+      }
+
+   case CommandDRCLevel:
+   {
+      params->drc_level = drc_mode_from_string(arg2);
+      used = 2;
+      break;
+   }
+
+   case CommandStatsPass:
+   {
+      params->stats_pass = MMAL_TRUE;
+      used = 1;
+      break;
+   }
+
+   case CommandAnnotate:
+   {
+      char dummy;
+      unsigned int bitmask;
+      // If parameter is a number, assume its a bitmask, otherwise a string
+      if (sscanf(arg2, "%u%c", &bitmask, &dummy) == 1)
+      {
+         params->enable_annotate |= bitmask;
+      }
+      else
+      {
+         params->enable_annotate |= ANNOTATE_USER_TEXT;
+         //copy string char by char and replace "\n" with newline character
+         unsigned char c;
+         char const *s = arg2;
+         char *t = &params->annotate_string[0];
+         int n=0;
+         while ((c = *s++) && n < MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3-1)
+         {
+            if (c == '\\' && *s)
+            {
+               switch (c = *s++)
+               {
+                  case 'n':
+                  c = '\n';
+                  break;
+
+                  default:
+                  c = '\\';
+                  s--;
+                  break;
+               }
+            }
+            *(t++) = c;
+            n++;
+         }
+         *t='\0';
+
+         //params->annotate_string[MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3-1] = '\0';
+      }
+      used=2;
+      break;
+   }
+
+   case CommandAnnotateExtras:
+   {
+      // 3 parameters - text size (6-80), text colour (Hex VVUUYY) and background colour (Hex VVUUYY)
+      sscanf(arg2, "%u,%X,%X", &params->annotate_text_size,
+                               &params->annotate_text_colour,
+                               &params->annotate_bg_colour);
+      used=2;
+      break;
+   }
+
+   case CommandStereoMode:
+   {
+      params->stereo_mode.mode = stereo_mode_from_string(arg2);
+      used = 2;
+      break;
+   }
+
+   case CommandStereoDecimate:
+   {
+      params->stereo_mode.decimate = MMAL_TRUE;
+      used = 1;
+      break;
+   }
+
+   case CommandStereoSwap:
+   {
+      params->stereo_mode.swap_eyes = MMAL_TRUE;
+      used = 1;
+      break;
+   }
+
+   case CommandAnalogGain:
+   {
+      double gain;
+      int args;
+
+      args = sscanf(arg2, "%lf", &gain);
+
+      if (args != 1 || gain > 16.0)
+      {
+         return 0;
+      }
+
+      params->analog_gain = gain;
+
+      used = 2;
+      break;
+   }
+   case CommandDigitalGain:
+   {
+      double gain;
+      int args;
+
+      args = sscanf(arg2, "%lf", &gain);
+
+      if (args != 1 || gain > 64.0)
+      {
+         return 0;
+      }
+
+      params->digital_gain = gain;
+
+      used = 2;
+      break;
+   }
+
+
+   }
+
+   return used;
+}
+
+/**
+ * Display help for command line options
+ */
+void raspicamcontrol_display_help()
+{
+   int i;
+
+   fprintf(stdout, "\nImage parameter commands\n\n");
+
+   raspicli_display_help(cmdline_commands, cmdline_commands_size);
+
+   fprintf(stdout, "\n\nNotes\n\nExposure mode options :\n%s", exposure_map[0].mode );
+
+   for (i=1;i<exposure_map_size;i++)
+   {
+      fprintf(stdout, ",%s", exposure_map[i].mode);
+   }
+   
+   fprintf(stdout, "\n\nFlicker avoid mode options :\n%s", flicker_avoid_map[0].mode );
+
+   for (i=1;i<flicker_avoid_map_size;i++)
+   {
+      fprintf(stdout, ",%s", flicker_avoid_map[i].mode);
+   }
+
+   fprintf(stdout, "\n\nAWB mode options :\n%s", awb_map[0].mode );
+
+   for (i=1;i<awb_map_size;i++)
+   {
+      fprintf(stdout, ",%s", awb_map[i].mode);
+   }
+
+   fprintf(stdout, "\n\nImage Effect mode options :\n%s", imagefx_map[0].mode );
+
+   for (i=1;i<imagefx_map_size;i++)
+   {
+      fprintf(stdout, ",%s", imagefx_map[i].mode);
+   }
+
+   fprintf(stdout, "\n\nMetering Mode options :\n%s", metering_mode_map[0].mode );
+
+   for (i=1;i<metering_mode_map_size;i++)
+   {
+      fprintf(stdout, ",%s", metering_mode_map[i].mode);
+   }
+
+   fprintf(stdout, "\n\nDynamic Range Compression (DRC) options :\n%s", drc_mode_map[0].mode );
+
+   for (i=1;i<drc_mode_map_size;i++)
+   {
+      fprintf(stdout, ",%s", drc_mode_map[i].mode);
+   }
+
+   fprintf(stdout, "\n");
+}
+
+
+/**
+ * Dump contents of camera parameter structure to stderr for debugging/verbose logging
+ *
+ * @param params Const pointer to parameters structure to dump
+ */
+void raspicamcontrol_dump_parameters(const RASPICAM_CAMERA_PARAMETERS *params)
+{
+   const char *exp_mode = raspicli_unmap_xref(params->exposureMode, exposure_map, exposure_map_size);
+   const char *fl_mode = raspicli_unmap_xref(params->flickerAvoidMode, flicker_avoid_map, flicker_avoid_map_size);
+   const char *awb_mode = raspicli_unmap_xref(params->awbMode, awb_map, awb_map_size);
+   const char *image_effect = raspicli_unmap_xref(params->imageEffect, imagefx_map, imagefx_map_size);
+   const char *metering_mode = raspicli_unmap_xref(params->exposureMeterMode, metering_mode_map, metering_mode_map_size);
+
+   fprintf(stderr, "Sharpness %d, Contrast %d, Brightness %d\n", params->sharpness, params->contrast, params->brightness);
+   fprintf(stderr, "Saturation %d, ISO %d, Video Stabilisation %s, Exposure compensation %d\n", params->saturation, params->ISO, params->videoStabilisation ? "Yes": "No", params->exposureCompensation);
+   fprintf(stderr, "Exposure Mode '%s', AWB Mode '%s', Image Effect '%s'\n", exp_mode, awb_mode, image_effect);
+   fprintf(stderr, "Flicker Avoid Mode '%s'\n", fl_mode);
+   fprintf(stderr, "Metering Mode '%s', Colour Effect Enabled %s with U = %d, V = %d\n", metering_mode, params->colourEffects.enable ? "Yes":"No", params->colourEffects.u, params->colourEffects.v);
+   fprintf(stderr, "Rotation %d, hflip %s, vflip %s\n", params->rotation, params->hflip ? "Yes":"No",params->vflip ? "Yes":"No");
+   fprintf(stderr, "ROI x %lf, y %f, w %f h %f\n", params->roi.x, params->roi.y, params->roi.w, params->roi.h);
+}
+
+/**
+ * Convert a MMAL status return value to a simple boolean of success
+ * ALso displays a fault if code is not success
+ *
+ * @param status The error code to convert
+ * @return 0 if status is success, 1 otherwise
+ */
+int mmal_status_to_int(MMAL_STATUS_T status)
+{
+   if (status == MMAL_SUCCESS)
+      return 0;
+   else
+   {
+      switch (status)
+      {
+      case MMAL_ENOMEM :   vcos_log_error("Out of memory"); break;
+      case MMAL_ENOSPC :   vcos_log_error("Out of resources (other than memory)"); break;
+      case MMAL_EINVAL:    vcos_log_error("Argument is invalid"); break;
+      case MMAL_ENOSYS :   vcos_log_error("Function not implemented"); break;
+      case MMAL_ENOENT :   vcos_log_error("No such file or directory"); break;
+      case MMAL_ENXIO :    vcos_log_error("No such device or address"); break;
+      case MMAL_EIO :      vcos_log_error("I/O error"); break;
+      case MMAL_ESPIPE :   vcos_log_error("Illegal seek"); break;
+      case MMAL_ECORRUPT : vcos_log_error("Data is corrupt \attention FIXME: not POSIX"); break;
+      case MMAL_ENOTREADY :vcos_log_error("Component is not ready \attention FIXME: not POSIX"); break;
+      case MMAL_ECONFIG :  vcos_log_error("Component is not configured \attention FIXME: not POSIX"); break;
+      case MMAL_EISCONN :  vcos_log_error("Port is already connected "); break;
+      case MMAL_ENOTCONN : vcos_log_error("Port is disconnected"); break;
+      case MMAL_EAGAIN :   vcos_log_error("Resource temporarily unavailable. Try again later"); break;
+      case MMAL_EFAULT :   vcos_log_error("Bad address"); break;
+      default :            vcos_log_error("Unknown status error"); break;
+      }
+
+      return 1;
+   }
+}
+
+/**
+ * Give the supplied parameter block a set of default values
+ * @params Pointer to parameter block
+ */
+void raspicamcontrol_set_defaults(RASPICAM_CAMERA_PARAMETERS *params)
+{
+   vcos_assert(params);
+
+   params->sharpness = 0;
+   params->contrast = 0;
+   params->brightness = 50;
+   params->saturation = 0;
+   params->ISO = 0;                    // 0 = auto
+   params->videoStabilisation = 0;
+   params->exposureCompensation = 0;
+   params->exposureMode = MMAL_PARAM_EXPOSUREMODE_AUTO;
+   params->flickerAvoidMode = MMAL_PARAM_FLICKERAVOID_OFF;
+   params->exposureMeterMode = MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE;
+   params->awbMode = MMAL_PARAM_AWBMODE_AUTO;
+   params->imageEffect = MMAL_PARAM_IMAGEFX_NONE;
+   params->colourEffects.enable = 0;
+   params->colourEffects.u = 128;
+   params->colourEffects.v = 128;
+   params->rotation = 0;
+   params->hflip = params->vflip = 0;
+   params->roi.x = params->roi.y = 0.0;
+   params->roi.w = params->roi.h = 1.0;
+   params->shutter_speed = 0;          // 0 = auto
+   params->awb_gains_r = 0;      // Only have any function if AWB OFF is used.
+   params->awb_gains_b = 0;
+   params->drc_level = MMAL_PARAMETER_DRC_STRENGTH_OFF;
+   params->stats_pass = MMAL_FALSE;
+   params->enable_annotate = 0;
+   params->annotate_string[0] = '\0';
+   params->annotate_text_size = 0;     //Use firmware default
+   params->annotate_text_colour = -1;   //Use firmware default
+   params->annotate_bg_colour = -1;     //Use firmware default
+   params->stereo_mode.mode = MMAL_STEREOSCOPIC_MODE_NONE;
+   params->stereo_mode.decimate = MMAL_FALSE;
+   params->stereo_mode.swap_eyes = MMAL_FALSE;
+}
+
+/**
+ * Get all the current camera parameters from specified camera component
+ * @param camera Pointer to camera component
+ * @param params Pointer to parameter block to accept settings
+ * @return 0 if successful, non-zero if unsuccessful
+ */
+int raspicamcontrol_get_all_parameters(MMAL_COMPONENT_T *camera, RASPICAM_CAMERA_PARAMETERS *params)
+{
+   vcos_assert(camera);
+   vcos_assert(params);
+
+   if (!camera || !params)
+      return 1;
+
+/* TODO : Write these get functions
+   params->sharpness = raspicamcontrol_get_sharpness(camera);
+   params->contrast = raspicamcontrol_get_contrast(camera);
+   params->brightness = raspicamcontrol_get_brightness(camera);
+   params->saturation = raspicamcontrol_get_saturation(camera);
+   params->ISO = raspicamcontrol_get_ISO(camera);
+   params->videoStabilisation = raspicamcontrol_get_video_stabilisation(camera);
+   params->exposureCompensation = raspicamcontrol_get_exposure_compensation(camera);
+   params->exposureMode = raspicamcontrol_get_exposure_mode(camera);
+   params->flickerAvoidMode = raspicamcontrol_get_flicker_avoid_mode(camera);
+   params->awbMode = raspicamcontrol_get_awb_mode(camera);
+   params->imageEffect = raspicamcontrol_get_image_effect(camera);
+   params->colourEffects = raspicamcontrol_get_colour_effect(camera);
+   params->thumbnailConfig = raspicamcontrol_get_thumbnail_config(camera);
+*/
+   return 0;
+}
+
+/**
+ * Set the specified camera to all the specified settings
+ * @param camera Pointer to camera component
+ * @param params Pointer to parameter block containing parameters
+ * @return 0 if successful, none-zero if unsuccessful.
+ */
+int raspicamcontrol_set_all_parameters(MMAL_COMPONENT_T *camera, const RASPICAM_CAMERA_PARAMETERS *params)
+{
+   int result;
+
+   result  = raspicamcontrol_set_saturation(camera, params->saturation);
+   result += raspicamcontrol_set_sharpness(camera, params->sharpness);
+   result += raspicamcontrol_set_contrast(camera, params->contrast);
+   result += raspicamcontrol_set_brightness(camera, params->brightness);
+   result += raspicamcontrol_set_ISO(camera, params->ISO);
+   result += raspicamcontrol_set_video_stabilisation(camera, params->videoStabilisation);
+   result += raspicamcontrol_set_exposure_compensation(camera, params->exposureCompensation);
+   result += raspicamcontrol_set_exposure_mode(camera, params->exposureMode);
+   result += raspicamcontrol_set_flicker_avoid_mode(camera, params->flickerAvoidMode);
+   result += raspicamcontrol_set_metering_mode(camera, params->exposureMeterMode);
+   result += raspicamcontrol_set_awb_mode(camera, params->awbMode);
+   result += raspicamcontrol_set_awb_gains(camera, params->awb_gains_r, params->awb_gains_b);
+   result += raspicamcontrol_set_imageFX(camera, params->imageEffect);
+   result += raspicamcontrol_set_colourFX(camera, &params->colourEffects);
+   //result += raspicamcontrol_set_thumbnail_parameters(camera, &params->thumbnailConfig);  TODO Not working for some reason
+   result += raspicamcontrol_set_rotation(camera, params->rotation);
+   result += raspicamcontrol_set_flips(camera, params->hflip, params->vflip);
+   result += raspicamcontrol_set_ROI(camera, params->roi);
+   result += raspicamcontrol_set_shutter_speed(camera, params->shutter_speed);
+   result += raspicamcontrol_set_DRC(camera, params->drc_level);
+   result += raspicamcontrol_set_stats_pass(camera, params->stats_pass);
+   result += raspicamcontrol_set_annotate(camera, params->enable_annotate, params->annotate_string,
+                       params->annotate_text_size,
+                       params->annotate_text_colour,
+                       params->annotate_bg_colour);
+   result += raspicamcontrol_set_gains(camera, params->analog_gain, params->digital_gain);
+
+   return result;
+}
+
+/**
+ * Adjust the saturation level for images
+ * @param camera Pointer to camera component
+ * @param saturation Value to adjust, -100 to 100
+ * @return 0 if successful, non-zero if any parameters out of range
+ */
+int raspicamcontrol_set_saturation(MMAL_COMPONENT_T *camera, int saturation)
+{
+   int ret = 0;
+
+   if (!camera)
+      return 1;
+
+   if (saturation >= -100 && saturation <= 100)
+   {
+      MMAL_RATIONAL_T value = {saturation, 100};
+      ret = mmal_status_to_int(mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_SATURATION, value));
+   }
+   else
+   {
+      vcos_log_error("Invalid saturation value");
+      ret = 1;
+   }
+
+   return ret;
+}
+
+/**
+ * Set the sharpness of the image
+ * @param camera Pointer to camera component
+ * @param sharpness Sharpness adjustment -100 to 100
+ */
+int raspicamcontrol_set_sharpness(MMAL_COMPONENT_T *camera, int sharpness)
+{
+   int ret = 0;
+
+   if (!camera)
+      return 1;
+
+   if (sharpness >= -100 && sharpness <= 100)
+   {
+      MMAL_RATIONAL_T value = {sharpness, 100};
+      ret = mmal_status_to_int(mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_SHARPNESS, value));
+   }
+   else
+   {
+      vcos_log_error("Invalid sharpness value");
+      ret = 1;
+   }
+
+   return ret;
+}
+
+/**
+ * Set the contrast adjustment for the image
+ * @param camera Pointer to camera component
+ * @param contrast Contrast adjustment -100 to  100
+ * @return
+ */
+int raspicamcontrol_set_contrast(MMAL_COMPONENT_T *camera, int contrast)
+{
+   int ret = 0;
+
+   if (!camera)
+      return 1;
+
+   if (contrast >= -100 && contrast <= 100)
+   {
+      MMAL_RATIONAL_T value = {contrast, 100};
+      ret = mmal_status_to_int(mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_CONTRAST, value));
+   }
+   else
+   {
+      vcos_log_error("Invalid contrast value");
+      ret = 1;
+   }
+
+   return ret;
+}
+
+/**
+ * Adjust the brightness level for images
+ * @param camera Pointer to camera component
+ * @param brightness Value to adjust, 0 to 100
+ * @return 0 if successful, non-zero if any parameters out of range
+ */
+int raspicamcontrol_set_brightness(MMAL_COMPONENT_T *camera, int brightness)
+{
+   int ret = 0;
+
+   if (!camera)
+      return 1;
+
+   if (brightness >= 0 && brightness <= 100)
+   {
+      MMAL_RATIONAL_T value = {brightness, 100};
+      ret = mmal_status_to_int(mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_BRIGHTNESS, value));
+   }
+   else
+   {
+      vcos_log_error("Invalid brightness value");
+      ret = 1;
+   }
+
+   return ret;
+}
+
+/**
+ * Adjust the ISO used for images
+ * @param camera Pointer to camera component
+ * @param ISO Value to set TODO :
+ * @return 0 if successful, non-zero if any parameters out of range
+ */
+int raspicamcontrol_set_ISO(MMAL_COMPONENT_T *camera, int ISO)
+{
+   if (!camera)
+      return 1;
+
+   return mmal_status_to_int(mmal_port_parameter_set_uint32(camera->control, MMAL_PARAMETER_ISO, ISO));
+}
+
+/**
+ * Adjust the metering mode for images
+ * @param camera Pointer to camera component
+ * @param saturation Value from following
+ *   - MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE,
+ *   - MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT,
+ *   - MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT,
+ *   - MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX
+ * @return 0 if successful, non-zero if any parameters out of range
+ */
+int raspicamcontrol_set_metering_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_EXPOSUREMETERINGMODE_T m_mode )
+{
+   MMAL_PARAMETER_EXPOSUREMETERINGMODE_T meter_mode = {{MMAL_PARAMETER_EXP_METERING_MODE,sizeof(meter_mode)},
+                                                      m_mode};
+   if (!camera)
+      return 1;
+
+   return mmal_status_to_int(mmal_port_parameter_set(camera->control, &meter_mode.hdr));
+}
+
+
+/**
+ * Set the video stabilisation flag. Only used in video mode
+ * @param camera Pointer to camera component
+ * @param saturation Flag 0 off 1 on
+ * @return 0 if successful, non-zero if any parameters out of range
+ */
+int raspicamcontrol_set_video_stabilisation(MMAL_COMPONENT_T *camera, int vstabilisation)
+{
+   if (!camera)
+      return 1;
+
+   return mmal_status_to_int(mmal_port_parameter_set_boolean(camera->control, MMAL_PARAMETER_VIDEO_STABILISATION, vstabilisation));
+}
+
+/**
+ * Adjust the exposure compensation for images (EV)
+ * @param camera Pointer to camera component
+ * @param exp_comp Value to adjust, -10 to +10
+ * @return 0 if successful, non-zero if any parameters out of range
+ */
+int raspicamcontrol_set_exposure_compensation(MMAL_COMPONENT_T *camera, int exp_comp)
+{
+   if (!camera)
+      return 1;
+
+   return mmal_status_to_int(mmal_port_parameter_set_int32(camera->control, MMAL_PARAMETER_EXPOSURE_COMP , exp_comp));
+}
+
+
+/**
+ * Set exposure mode for images
+ * @param camera Pointer to camera component
+ * @param mode Exposure mode to set from
+ *   - MMAL_PARAM_EXPOSUREMODE_OFF,
+ *   - MMAL_PARAM_EXPOSUREMODE_AUTO,
+ *   - MMAL_PARAM_EXPOSUREMODE_NIGHT,
+ *   - MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW,
+ *   - MMAL_PARAM_EXPOSUREMODE_BACKLIGHT,
+ *   - MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT,
+ *   - MMAL_PARAM_EXPOSUREMODE_SPORTS,
+ *   - MMAL_PARAM_EXPOSUREMODE_SNOW,
+ *   - MMAL_PARAM_EXPOSUREMODE_BEACH,
+ *   - MMAL_PARAM_EXPOSUREMODE_VERYLONG,
+ *   - MMAL_PARAM_EXPOSUREMODE_FIXEDFPS,
+ *   - MMAL_PARAM_EXPOSUREMODE_ANTISHAKE,
+ *   - MMAL_PARAM_EXPOSUREMODE_FIREWORKS,
+ *
+ * @return 0 if successful, non-zero if any parameters out of range
+ */
+int raspicamcontrol_set_exposure_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_EXPOSUREMODE_T mode)
+{
+   MMAL_PARAMETER_EXPOSUREMODE_T exp_mode = {{MMAL_PARAMETER_EXPOSURE_MODE,sizeof(exp_mode)}, mode};
+
+   if (!camera)
+      return 1;
+
+   return mmal_status_to_int(mmal_port_parameter_set(camera->control, &exp_mode.hdr));
+}
+
+
+/**
+ * Set flicker avoid mode for images
+ * @param camera Pointer to camera component
+ * @param mode Exposure mode to set from
+ *   - MMAL_PARAM_FLICKERAVOID_OFF,
+ *   - MMAL_PARAM_FLICKERAVOID_AUTO,
+ *   - MMAL_PARAM_FLICKERAVOID_50HZ,
+ *   - MMAL_PARAM_FLICKERAVOID_60HZ,
+ *
+ * @return 0 if successful, non-zero if any parameters out of range
+ */
+int raspicamcontrol_set_flicker_avoid_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_FLICKERAVOID_T mode)
+{
+   MMAL_PARAMETER_FLICKERAVOID_T fl_mode = {{MMAL_PARAMETER_FLICKER_AVOID,sizeof(fl_mode)}, mode};
+
+   if (!camera)
+      return 1;
+
+   return mmal_status_to_int(mmal_port_parameter_set(camera->control, &fl_mode.hdr));
+}
+
+
+/**
+ * Set the aWB (auto white balance) mode for images
+ * @param camera Pointer to camera component
+ * @param awb_mode Value to set from
+ *   - MMAL_PARAM_AWBMODE_OFF,
+ *   - MMAL_PARAM_AWBMODE_AUTO,
+ *   - MMAL_PARAM_AWBMODE_SUNLIGHT,
+ *   - MMAL_PARAM_AWBMODE_CLOUDY,
+ *   - MMAL_PARAM_AWBMODE_SHADE,
+ *   - MMAL_PARAM_AWBMODE_TUNGSTEN,
+ *   - MMAL_PARAM_AWBMODE_FLUORESCENT,
+ *   - MMAL_PARAM_AWBMODE_INCANDESCENT,
+ *   - MMAL_PARAM_AWBMODE_FLASH,
+ *   - MMAL_PARAM_AWBMODE_HORIZON,
+ * @return 0 if successful, non-zero if any parameters out of range
+ */
+int raspicamcontrol_set_awb_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_AWBMODE_T awb_mode)
+{
+   MMAL_PARAMETER_AWBMODE_T param = {{MMAL_PARAMETER_AWB_MODE,sizeof(param)}, awb_mode};
+
+   if (!camera)
+      return 1;
+
+   return mmal_status_to_int(mmal_port_parameter_set(camera->control, &param.hdr));
+}
+
+int raspicamcontrol_set_awb_gains(MMAL_COMPONENT_T *camera, float r_gain, float b_gain)
+{
+   MMAL_PARAMETER_AWB_GAINS_T param = {{MMAL_PARAMETER_CUSTOM_AWB_GAINS,sizeof(param)}, {0,0}, {0,0}};
+
+   if (!camera)
+      return 1;
+
+   if (!r_gain || !b_gain)
+      return 0;
+
+   param.r_gain.num = (unsigned int)(r_gain * 65536);
+   param.b_gain.num = (unsigned int)(b_gain * 65536);
+   param.r_gain.den = param.b_gain.den = 65536;
+   return mmal_status_to_int(mmal_port_parameter_set(camera->control, &param.hdr));
+}
+
+/**
+ * Set the image effect for the images
+ * @param camera Pointer to camera component
+ * @param imageFX Value from
+ *   - MMAL_PARAM_IMAGEFX_NONE,
+ *   - MMAL_PARAM_IMAGEFX_NEGATIVE,
+ *   - MMAL_PARAM_IMAGEFX_SOLARIZE,
+ *   - MMAL_PARAM_IMAGEFX_POSTERIZE,
+ *   - MMAL_PARAM_IMAGEFX_WHITEBOARD,
+ *   - MMAL_PARAM_IMAGEFX_BLACKBOARD,
+ *   - MMAL_PARAM_IMAGEFX_SKETCH,
+ *   - MMAL_PARAM_IMAGEFX_DENOISE,
+ *   - MMAL_PARAM_IMAGEFX_EMBOSS,
+ *   - MMAL_PARAM_IMAGEFX_OILPAINT,
+ *   - MMAL_PARAM_IMAGEFX_HATCH,
+ *   - MMAL_PARAM_IMAGEFX_GPEN,
+ *   - MMAL_PARAM_IMAGEFX_PASTEL,
+ *   - MMAL_PARAM_IMAGEFX_WATERCOLOUR,
+ *   - MMAL_PARAM_IMAGEFX_FILM,
+ *   - MMAL_PARAM_IMAGEFX_BLUR,
+ *   - MMAL_PARAM_IMAGEFX_SATURATION,
+ *   - MMAL_PARAM_IMAGEFX_COLOURSWAP,
+ *   - MMAL_PARAM_IMAGEFX_WASHEDOUT,
+ *   - MMAL_PARAM_IMAGEFX_POSTERISE,
+ *   - MMAL_PARAM_IMAGEFX_COLOURPOINT,
+ *   - MMAL_PARAM_IMAGEFX_COLOURBALANCE,
+ *   - MMAL_PARAM_IMAGEFX_CARTOON,
+ * @return 0 if successful, non-zero if any parameters out of range
+ */
+int raspicamcontrol_set_imageFX(MMAL_COMPONENT_T *camera, MMAL_PARAM_IMAGEFX_T imageFX)
+{
+   MMAL_PARAMETER_IMAGEFX_T imgFX = {{MMAL_PARAMETER_IMAGE_EFFECT,sizeof(imgFX)}, imageFX};
+
+   if (!camera)
+      return 1;
+
+   return mmal_status_to_int(mmal_port_parameter_set(camera->control, &imgFX.hdr));
+}
+
+/* TODO :what to do with the image effects parameters?
+   MMAL_PARAMETER_IMAGEFX_PARAMETERS_T imfx_param = {{MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,sizeof(imfx_param)},
+                              imageFX, 0, {0}};
+mmal_port_parameter_set(camera->control, &imfx_param.hdr);
+                             */
+
+/**
+ * Set the colour effect  for images (Set UV component)
+ * @param camera Pointer to camera component
+ * @param colourFX  Contains enable state and U and V numbers to set (e.g. 128,128 = Black and white)
+ * @return 0 if successful, non-zero if any parameters out of range
+ */
+int raspicamcontrol_set_colourFX(MMAL_COMPONENT_T *camera, const MMAL_PARAM_COLOURFX_T *colourFX)
+{
+   MMAL_PARAMETER_COLOURFX_T colfx = {{MMAL_PARAMETER_COLOUR_EFFECT,sizeof(colfx)}, 0, 0, 0};
+
+   if (!camera)
+      return 1;
+
+   colfx.enable = colourFX->enable;
+   colfx.u = colourFX->u;
+   colfx.v = colourFX->v;
+
+   return mmal_status_to_int(mmal_port_parameter_set(camera->control, &colfx.hdr));
+
+}
+
+
+/**
+ * Set the rotation of the image
+ * @param camera Pointer to camera component
+ * @param rotation Degree of rotation (any number, but will be converted to 0,90,180 or 270 only)
+ * @return 0 if successful, non-zero if any parameters out of range
+ */
+int raspicamcontrol_set_rotation(MMAL_COMPONENT_T *camera, int rotation)
+{
+   int ret;
+   int my_rotation = ((rotation % 360 ) / 90) * 90;
+
+   ret = mmal_port_parameter_set_int32(camera->output[0], MMAL_PARAMETER_ROTATION, my_rotation);
+   mmal_port_parameter_set_int32(camera->output[1], MMAL_PARAMETER_ROTATION, my_rotation);
+   mmal_port_parameter_set_int32(camera->output[2], MMAL_PARAMETER_ROTATION, my_rotation);
+
+   return ret;
+}
+
+/**
+ * Set the flips state of the image
+ * @param camera Pointer to camera component
+ * @param hflip If true, horizontally flip the image
+ * @param vflip If true, vertically flip the image
+ *
+ * @return 0 if successful, non-zero if any parameters out of range
+ */
+int raspicamcontrol_set_flips(MMAL_COMPONENT_T *camera, int hflip, int vflip)
+{
+   MMAL_PARAMETER_MIRROR_T mirror = {{MMAL_PARAMETER_MIRROR, sizeof(MMAL_PARAMETER_MIRROR_T)}, MMAL_PARAM_MIRROR_NONE};
+
+   if (hflip && vflip)
+      mirror.value = MMAL_PARAM_MIRROR_BOTH;
+   else
+   if (hflip)
+      mirror.value = MMAL_PARAM_MIRROR_HORIZONTAL;
+   else
+   if (vflip)
+      mirror.value = MMAL_PARAM_MIRROR_VERTICAL;
+
+   mmal_port_parameter_set(camera->output[0], &mirror.hdr);
+   mmal_port_parameter_set(camera->output[1], &mirror.hdr);
+   return mmal_port_parameter_set(camera->output[2], &mirror.hdr);
+}
+
+/**
+ * Set the ROI of the sensor to use for captures/preview
+ * @param camera Pointer to camera component
+ * @param rect   Normalised coordinates of ROI rectangle
+ *
+ * @return 0 if successful, non-zero if any parameters out of range
+ */
+int raspicamcontrol_set_ROI(MMAL_COMPONENT_T *camera, PARAM_FLOAT_RECT_T rect)
+{
+   MMAL_PARAMETER_INPUT_CROP_T crop = {{MMAL_PARAMETER_INPUT_CROP, sizeof(MMAL_PARAMETER_INPUT_CROP_T)}};
+
+   crop.rect.x = (65536 * rect.x);
+   crop.rect.y = (65536 * rect.y);
+   crop.rect.width = (65536 * rect.w);
+   crop.rect.height = (65536 * rect.h);
+
+   return mmal_port_parameter_set(camera->control, &crop.hdr);
+}
+
+/**
+ * Zoom in and Zoom out by changing ROI
+ * @param camera Pointer to camera component
+ * @param zoom_command zoom command enum
+ * @return 0 if successful, non-zero otherwise
+ */
+int raspicamcontrol_zoom_in_zoom_out(MMAL_COMPONENT_T *camera, ZOOM_COMMAND_T zoom_command, PARAM_FLOAT_RECT_T *roi) {
+    MMAL_PARAMETER_INPUT_CROP_T crop;
+    crop.hdr.id = MMAL_PARAMETER_INPUT_CROP;
+    crop.hdr.size = sizeof(crop);
+
+    if (mmal_port_parameter_get(camera->control, &crop.hdr) != MMAL_SUCCESS)
+    {
+        vcos_log_error("mmal_port_parameter_get(camera->control, &crop.hdr) failed, skip it");
+        return 0;
+    }
+
+    if (zoom_command == ZOOM_IN)
+    {
+        if (crop.rect.width <= (zoom_full_16P16 + zoom_increment_16P16))
+        {
+            crop.rect.width = zoom_full_16P16;
+            crop.rect.height = zoom_full_16P16;
+        }
+        else
+        {
+            crop.rect.width -= zoom_increment_16P16;
+            crop.rect.height -= zoom_increment_16P16;
+        }
+    }
+    else if (zoom_command == ZOOM_OUT)
+    {
+        unsigned int increased_size = crop.rect.width + zoom_increment_16P16;
+        if (increased_size < crop.rect.width) //overflow
+        {
+            crop.rect.width = 65536;
+            crop.rect.height = 65536;
+        }
+        else
+        {
+            crop.rect.width = increased_size;
+            crop.rect.height = increased_size;
+        }
+    }
+
+    if (zoom_command == ZOOM_RESET)
+    {
+        crop.rect.x = 0;
+        crop.rect.y = 0;
+        crop.rect.width = 65536;
+        crop.rect.height = 65536;
+    }
+    else
+    {
+        unsigned int centered_top_coordinate = (65536 - crop.rect.width) / 2;
+        crop.rect.x = centered_top_coordinate;
+        crop.rect.y = centered_top_coordinate;
+    }
+
+    int ret = mmal_status_to_int(mmal_port_parameter_set(camera->control, &crop.hdr));
+
+    if (ret == 0) {
+       roi->x = roi->y = (double)crop.rect.x/65536;
+       roi->w = roi->h = (double)crop.rect.width/65536;
+    }
+    else
+    {
+        vcos_log_error("Failed to set crop values, x/y: %u, w/h: %u", crop.rect.x, crop.rect.width);
+        ret = 1;
+    }
+
+    return ret;
+}
+
+/**
+ * Adjust the exposure time used for images
+ * @param camera Pointer to camera component
+ * @param shutter speed in microseconds
+ * @return 0 if successful, non-zero if any parameters out of range
+ */
+int raspicamcontrol_set_shutter_speed(MMAL_COMPONENT_T *camera, int speed)
+{
+   if (!camera)
+      return 1;
+
+   return mmal_status_to_int(mmal_port_parameter_set_uint32(camera->control, MMAL_PARAMETER_SHUTTER_SPEED, speed));
+}
+
+/**
+ * Adjust the Dynamic range compression level
+ * @param camera Pointer to camera component
+ * @param strength Strength of DRC to apply
+ *        MMAL_PARAMETER_DRC_STRENGTH_OFF
+ *        MMAL_PARAMETER_DRC_STRENGTH_LOW
+ *        MMAL_PARAMETER_DRC_STRENGTH_MEDIUM
+ *        MMAL_PARAMETER_DRC_STRENGTH_HIGH
+ *
+ * @return 0 if successful, non-zero if any parameters out of range
+ */
+int raspicamcontrol_set_DRC(MMAL_COMPONENT_T *camera, MMAL_PARAMETER_DRC_STRENGTH_T strength)
+{
+   MMAL_PARAMETER_DRC_T drc = {{MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION, sizeof(MMAL_PARAMETER_DRC_T)}, strength};
+
+   if (!camera)
+      return 1;
+
+   return mmal_status_to_int(mmal_port_parameter_set(camera->control, &drc.hdr));
+}
+
+int raspicamcontrol_set_stats_pass(MMAL_COMPONENT_T *camera, int stats_pass)
+{
+   if (!camera)
+      return 1;
+
+   return mmal_status_to_int(mmal_port_parameter_set_boolean(camera->control, MMAL_PARAMETER_CAPTURE_STATS_PASS, stats_pass));
+}
+
+
+/**
+ * Set the annotate data
+ * @param camera Pointer to camera component
+ * @param Bitmask of required annotation data. 0 for off.
+ * @param If set, a pointer to text string to use instead of bitmask, max length 32 characters
+ *
+ * @return 0 if successful, non-zero if any parameters out of range
+ */
+int raspicamcontrol_set_annotate(MMAL_COMPONENT_T *camera, const int settings, const char *string,
+                const int text_size, const int text_colour, const int bg_colour)
+{
+   MMAL_PARAMETER_CAMERA_ANNOTATE_V3_T annotate =
+      {{MMAL_PARAMETER_ANNOTATE, sizeof(MMAL_PARAMETER_CAMERA_ANNOTATE_V3_T)}};
+
+   if (settings)
+   {
+      time_t t = time(NULL);
+      struct tm tm = *localtime(&t);
+      char tmp[MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3];
+      int process_datetime = 1;
+
+      annotate.enable = 1;
+
+      if (settings & (ANNOTATE_APP_TEXT | ANNOTATE_USER_TEXT))
+      {
+         if ((settings & (ANNOTATE_TIME_TEXT | ANNOTATE_DATE_TEXT)) && strchr(string,'%') != NULL)
+         {  //string contains strftime parameter?
+            strftime(annotate.text, MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3, string, &tm );
+            process_datetime = 0;
+         }else{
+            strncpy(annotate.text, string, MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3);
+         }
+         annotate.text[MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3-1] = '\0';
+      }
+
+      if (process_datetime && (settings & ANNOTATE_TIME_TEXT))
+      {
+         if(strlen(annotate.text)){
+            strftime(tmp, 32, " %X", &tm );
+         }else{
+            strftime(tmp, 32, "%X", &tm );
+         }
+         strncat(annotate.text, tmp, MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3 - strlen(annotate.text) - 1);
+      }
+
+      if (process_datetime && (settings & ANNOTATE_DATE_TEXT))
+      {
+         if(strlen(annotate.text)){
+            strftime(tmp, 32, " %x", &tm );
+         }else{
+            strftime(tmp, 32, "%x", &tm );
+         }
+         strncat(annotate.text, tmp, MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3 - strlen(annotate.text) - 1);
+      }
+
+      if (settings & ANNOTATE_SHUTTER_SETTINGS)
+         annotate.show_shutter = MMAL_TRUE;
+
+      if (settings & ANNOTATE_GAIN_SETTINGS)
+         annotate.show_analog_gain = MMAL_TRUE;
+
+      if (settings & ANNOTATE_LENS_SETTINGS)
+         annotate.show_lens = MMAL_TRUE;
+
+      if (settings & ANNOTATE_CAF_SETTINGS)
+         annotate.show_caf = MMAL_TRUE;
+
+      if (settings & ANNOTATE_MOTION_SETTINGS)
+         annotate.show_motion = MMAL_TRUE;
+
+      if (settings & ANNOTATE_FRAME_NUMBER)
+         annotate.show_frame_num = MMAL_TRUE;
+
+      if (settings & ANNOTATE_BLACK_BACKGROUND)
+         annotate.enable_text_background = MMAL_TRUE;
+
+      annotate.text_size = text_size;
+
+      if (text_colour != -1)
+      {
+         annotate.custom_text_colour = MMAL_TRUE;
+         annotate.custom_text_Y = text_colour&0xff;
+         annotate.custom_text_U = (text_colour>>8)&0xff;
+         annotate.custom_text_V = (text_colour>>16)&0xff;
+      }
+      else
+         annotate.custom_text_colour = MMAL_FALSE;
+
+      if (bg_colour != -1)
+      {
+         annotate.custom_background_colour = MMAL_TRUE;
+         annotate.custom_background_Y = bg_colour&0xff;
+         annotate.custom_background_U = (bg_colour>>8)&0xff;
+         annotate.custom_background_V = (bg_colour>>16)&0xff;
+      }
+      else
+         annotate.custom_background_colour = MMAL_FALSE;
+    }
+    else
+       annotate.enable = 0;
+
+   return mmal_status_to_int(mmal_port_parameter_set(camera->control, &annotate.hdr));
+}
+
+int raspicamcontrol_set_stereo_mode(MMAL_PORT_T *port, MMAL_PARAMETER_STEREOSCOPIC_MODE_T *stereo_mode)
+{
+   MMAL_PARAMETER_STEREOSCOPIC_MODE_T stereo = { {MMAL_PARAMETER_STEREOSCOPIC_MODE, sizeof(stereo)},
+                               MMAL_STEREOSCOPIC_MODE_NONE, MMAL_FALSE, MMAL_FALSE };
+   if (stereo_mode->mode != MMAL_STEREOSCOPIC_MODE_NONE)
+   {
+      stereo.mode = stereo_mode->mode;
+      stereo.decimate = stereo_mode->decimate;
+      stereo.swap_eyes = stereo_mode->swap_eyes;
+   }
+   return mmal_status_to_int(mmal_port_parameter_set(port, &stereo.hdr));
+}
+
+int raspicamcontrol_set_gains(MMAL_COMPONENT_T *camera, float analog, float digital)
+{
+   MMAL_RATIONAL_T rational = {0,65536};
+   MMAL_STATUS_T status;
+
+   if (!camera)
+      return 1;
+
+   rational.num = (unsigned int)(analog * 65536);
+   status = mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_ANALOG_GAIN, rational);
+   if (status != MMAL_SUCCESS)
+      return mmal_status_to_int(status);
+
+   rational.num = (unsigned int)(digital * 65536);
+   status = mmal_port_parameter_set_rational(camera->control, MMAL_PARAMETER_DIGITAL_GAIN, rational);
+   return mmal_status_to_int(status);
+}
+
+/**
+ * Asked GPU how much memory it has allocated
+ *
+ * @return amount of memory in MB
+ */
+static int raspicamcontrol_get_mem_gpu(void)
+{
+   char response[80] = "";
+   int gpu_mem = 0;
+   if (vc_gencmd(response, sizeof response, "get_mem gpu") == 0)
+      vc_gencmd_number_property(response, "gpu", &gpu_mem);
+   return gpu_mem;
+}
+
+/**
+ * Ask GPU about its camera abilities
+ * @param supported None-zero if software supports the camera 
+ * @param detected  None-zero if a camera has been detected
+ */
+static void raspicamcontrol_get_camera(int *supported, int *detected)
+{
+   char response[80] = "";
+   if (vc_gencmd(response, sizeof response, "get_camera") == 0)
+   {
+      if (supported)
+         vc_gencmd_number_property(response, "supported", supported);
+      if (detected)
+         vc_gencmd_number_property(response, "detected", detected);
+   }
+}
+
+/**
+ * Check to see if camera is supported, and we have allocated enough meooryAsk GPU about its camera abilities
+ * @param supported None-zero if software supports the camera 
+ * @param detected  None-zero if a camera has been detected
+ */
+void raspicamcontrol_check_configuration(int min_gpu_mem)
+{
+   int gpu_mem = raspicamcontrol_get_mem_gpu();
+   int supported = 0, detected = 0;
+   raspicamcontrol_get_camera(&supported, &detected);
+   if (!supported)
+      vcos_log_error("Camera is not enabled in this build. Try running \"sudo raspi-config\" and ensure that \"camera\" has been enabled\n");
+   else if (gpu_mem < min_gpu_mem)
+      vcos_log_error("Only %dM of gpu_mem is configured. Try running \"sudo raspi-config\" and ensure that \"memory_split\" has a value of %d or greater\n", gpu_mem, min_gpu_mem);
+   else if (!detected)
+      vcos_log_error("Camera is not detected. Please check carefully the camera module is installed correctly\n");
+   else
+      vcos_log_error("Failed to run camera app. Please check for firmware updates\n");
+}
+
diff --git a/host_applications/linux/apps/raspicam/RaspiCamControl.h b/host_applications/linux/apps/raspicam/RaspiCamControl.h
new file mode 100755 (executable)
index 0000000..0286d9f
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, James Hughes
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef RASPICAMCONTROL_H_
+#define RASPICAMCONTROL_H_
+
+/* Various parameters
+ *
+ * Exposure Mode
+ *          MMAL_PARAM_EXPOSUREMODE_OFF,
+            MMAL_PARAM_EXPOSUREMODE_AUTO,
+            MMAL_PARAM_EXPOSUREMODE_NIGHT,
+            MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW,
+            MMAL_PARAM_EXPOSUREMODE_BACKLIGHT,
+            MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT,
+            MMAL_PARAM_EXPOSUREMODE_SPORTS,
+            MMAL_PARAM_EXPOSUREMODE_SNOW,
+            MMAL_PARAM_EXPOSUREMODE_BEACH,
+            MMAL_PARAM_EXPOSUREMODE_VERYLONG,
+            MMAL_PARAM_EXPOSUREMODE_FIXEDFPS,
+            MMAL_PARAM_EXPOSUREMODE_ANTISHAKE,
+            MMAL_PARAM_EXPOSUREMODE_FIREWORKS,
+ *
+ * Flicker Avoid Mode
+ *          MMAL_PARAM_FLICKERAVOID_OFF,
+            MMAL_PARAM_FLICKERAVOID_AUTO,
+            MMAL_PARAM_FLICKERAVOID_50HZ,
+            MMAL_PARAM_FLICKERAVOID_60HZ,
+ *
+ * AWB Mode
+ *          MMAL_PARAM_AWBMODE_OFF,
+            MMAL_PARAM_AWBMODE_AUTO,
+            MMAL_PARAM_AWBMODE_SUNLIGHT,
+            MMAL_PARAM_AWBMODE_CLOUDY,
+            MMAL_PARAM_AWBMODE_SHADE,
+            MMAL_PARAM_AWBMODE_TUNGSTEN,
+            MMAL_PARAM_AWBMODE_FLUORESCENT,
+            MMAL_PARAM_AWBMODE_INCANDESCENT,
+            MMAL_PARAM_AWBMODE_FLASH,
+            MMAL_PARAM_AWBMODE_HORIZON,
+ *
+ * Image FX
+            MMAL_PARAM_IMAGEFX_NONE,
+            MMAL_PARAM_IMAGEFX_NEGATIVE,
+            MMAL_PARAM_IMAGEFX_SOLARIZE,
+            MMAL_PARAM_IMAGEFX_POSTERIZE,
+            MMAL_PARAM_IMAGEFX_WHITEBOARD,
+            MMAL_PARAM_IMAGEFX_BLACKBOARD,
+            MMAL_PARAM_IMAGEFX_SKETCH,
+            MMAL_PARAM_IMAGEFX_DENOISE,
+            MMAL_PARAM_IMAGEFX_EMBOSS,
+            MMAL_PARAM_IMAGEFX_OILPAINT,
+            MMAL_PARAM_IMAGEFX_HATCH,
+            MMAL_PARAM_IMAGEFX_GPEN,
+            MMAL_PARAM_IMAGEFX_PASTEL,
+            MMAL_PARAM_IMAGEFX_WATERCOLOUR,
+            MMAL_PARAM_IMAGEFX_FILM,
+            MMAL_PARAM_IMAGEFX_BLUR,
+            MMAL_PARAM_IMAGEFX_SATURATION,
+            MMAL_PARAM_IMAGEFX_COLOURSWAP,
+            MMAL_PARAM_IMAGEFX_WASHEDOUT,
+            MMAL_PARAM_IMAGEFX_POSTERISE,
+            MMAL_PARAM_IMAGEFX_COLOURPOINT,
+            MMAL_PARAM_IMAGEFX_COLOURBALANCE,
+            MMAL_PARAM_IMAGEFX_CARTOON,
+
+ */
+
+/// Annotate bitmask options
+/// Supplied by user on command line
+#define ANNOTATE_USER_TEXT          1
+/// Supplied by app using this module
+#define ANNOTATE_APP_TEXT           2
+/// Insert current date
+#define ANNOTATE_DATE_TEXT          4
+// Insert current time
+#define ANNOTATE_TIME_TEXT          8
+
+#define ANNOTATE_SHUTTER_SETTINGS   16
+#define ANNOTATE_CAF_SETTINGS       32
+#define ANNOTATE_GAIN_SETTINGS      64
+#define ANNOTATE_LENS_SETTINGS      128
+#define ANNOTATE_MOTION_SETTINGS    256
+#define ANNOTATE_FRAME_NUMBER       512
+#define ANNOTATE_BLACK_BACKGROUND   1024
+
+
+// There isn't actually a MMAL structure for the following, so make one
+typedef struct mmal_param_colourfx_s
+{
+   int enable;       /// Turn colourFX on or off
+   int u,v;          /// U and V to use
+} MMAL_PARAM_COLOURFX_T;
+
+typedef struct mmal_param_thumbnail_config_s
+{
+   int enable;
+   int width,height;
+   int quality;
+} MMAL_PARAM_THUMBNAIL_CONFIG_T;
+
+typedef struct param_float_rect_s
+{
+   double x;
+   double y;
+   double w;
+   double h;
+} PARAM_FLOAT_RECT_T;
+
+/// struct contain camera settings
+typedef struct raspicam_camera_parameters_s
+{
+   int sharpness;             /// -100 to 100
+   int contrast;              /// -100 to 100
+   int brightness;            ///  0 to 100
+   int saturation;            ///  -100 to 100
+   int ISO;                   ///  TODO : what range?
+   int videoStabilisation;    /// 0 or 1 (false or true)
+   int exposureCompensation;  /// -10 to +10 ?
+   MMAL_PARAM_EXPOSUREMODE_T exposureMode;
+   MMAL_PARAM_EXPOSUREMETERINGMODE_T exposureMeterMode;
+   MMAL_PARAM_AWBMODE_T awbMode;
+   MMAL_PARAM_IMAGEFX_T imageEffect;
+   MMAL_PARAMETER_IMAGEFX_PARAMETERS_T imageEffectsParameters;
+   MMAL_PARAM_COLOURFX_T colourEffects;
+   MMAL_PARAM_FLICKERAVOID_T flickerAvoidMode;
+   int rotation;              /// 0-359
+   int hflip;                 /// 0 or 1
+   int vflip;                 /// 0 or 1
+   PARAM_FLOAT_RECT_T  roi;   /// region of interest to use on the sensor. Normalised [0,1] values in the rect
+   int shutter_speed;         /// 0 = auto, otherwise the shutter speed in ms
+   float awb_gains_r;         /// AWB red gain
+   float awb_gains_b;         /// AWB blue gain
+   MMAL_PARAMETER_DRC_STRENGTH_T drc_level;  // Strength of Dynamic Range compression to apply
+   MMAL_BOOL_T stats_pass;    /// Stills capture statistics pass on/off
+   int enable_annotate;       /// Flag to enable the annotate, 0 = disabled, otherwise a bitmask of what needs to be displayed
+   char annotate_string[MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V2]; /// String to use for annotate - overrides certain bitmask settings
+   int annotate_text_size;    // Text size for annotation
+   int annotate_text_colour;  // Text colour for annotation
+   int annotate_bg_colour;    // Background colour for annotation
+   MMAL_PARAMETER_STEREOSCOPIC_MODE_T stereo_mode;
+   float analog_gain;         // Analog gain
+   float digital_gain;        // Digital gain
+} RASPICAM_CAMERA_PARAMETERS;
+
+typedef enum {
+    ZOOM_IN, ZOOM_OUT, ZOOM_RESET
+} ZOOM_COMMAND_T;
+
+
+void raspicamcontrol_check_configuration(int min_gpu_mem);
+
+int raspicamcontrol_parse_cmdline(RASPICAM_CAMERA_PARAMETERS *params, const char *arg1, const char *arg2);
+void raspicamcontrol_display_help();
+int raspicamcontrol_cycle_test(MMAL_COMPONENT_T *camera);
+
+int raspicamcontrol_set_all_parameters(MMAL_COMPONENT_T *camera, const RASPICAM_CAMERA_PARAMETERS *params);
+int raspicamcontrol_get_all_parameters(MMAL_COMPONENT_T *camera, RASPICAM_CAMERA_PARAMETERS *params);
+void raspicamcontrol_dump_parameters(const RASPICAM_CAMERA_PARAMETERS *params);
+
+void raspicamcontrol_set_defaults(RASPICAM_CAMERA_PARAMETERS *params);
+
+void raspicamcontrol_check_configuration(int min_gpu_mem);
+
+// Individual setting functions
+int raspicamcontrol_set_saturation(MMAL_COMPONENT_T *camera, int saturation);
+int raspicamcontrol_set_sharpness(MMAL_COMPONENT_T *camera, int sharpness);
+int raspicamcontrol_set_contrast(MMAL_COMPONENT_T *camera, int contrast);
+int raspicamcontrol_set_brightness(MMAL_COMPONENT_T *camera, int brightness);
+int raspicamcontrol_set_ISO(MMAL_COMPONENT_T *camera, int ISO);
+int raspicamcontrol_set_metering_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_EXPOSUREMETERINGMODE_T mode);
+int raspicamcontrol_set_video_stabilisation(MMAL_COMPONENT_T *camera, int vstabilisation);
+int raspicamcontrol_set_exposure_compensation(MMAL_COMPONENT_T *camera, int exp_comp);
+int raspicamcontrol_set_exposure_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_EXPOSUREMODE_T mode);
+int raspicamcontrol_set_flicker_avoid_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_FLICKERAVOID_T mode);
+int raspicamcontrol_set_awb_mode(MMAL_COMPONENT_T *camera, MMAL_PARAM_AWBMODE_T awb_mode);
+int raspicamcontrol_set_awb_gains(MMAL_COMPONENT_T *camera, float r_gain, float b_gain);
+int raspicamcontrol_set_imageFX(MMAL_COMPONENT_T *camera, MMAL_PARAM_IMAGEFX_T imageFX);
+int raspicamcontrol_set_colourFX(MMAL_COMPONENT_T *camera, const MMAL_PARAM_COLOURFX_T *colourFX);
+int raspicamcontrol_set_rotation(MMAL_COMPONENT_T *camera, int rotation);
+int raspicamcontrol_set_flips(MMAL_COMPONENT_T *camera, int hflip, int vflip);
+int raspicamcontrol_set_ROI(MMAL_COMPONENT_T *camera, PARAM_FLOAT_RECT_T rect);
+int raspicamcontrol_zoom_in_zoom_out(MMAL_COMPONENT_T *camera, ZOOM_COMMAND_T zoom_command, PARAM_FLOAT_RECT_T *roi);
+int raspicamcontrol_set_shutter_speed(MMAL_COMPONENT_T *camera, int speed_ms);
+int raspicamcontrol_set_DRC(MMAL_COMPONENT_T *camera, MMAL_PARAMETER_DRC_STRENGTH_T strength);
+int raspicamcontrol_set_stats_pass(MMAL_COMPONENT_T *camera, int stats_pass);
+int raspicamcontrol_set_annotate(MMAL_COMPONENT_T *camera, const int bitmask, const char *string,
+                                 const int text_size, const int text_colour, const int bg_colour);
+int raspicamcontrol_set_stereo_mode(MMAL_PORT_T *port, MMAL_PARAMETER_STEREOSCOPIC_MODE_T *stereo_mode);
+int raspicamcontrol_set_gains(MMAL_COMPONENT_T *camera, float analog, float digital);
+
+//Individual getting functions
+int raspicamcontrol_get_saturation(MMAL_COMPONENT_T *camera);
+int raspicamcontrol_get_sharpness(MMAL_COMPONENT_T *camera);
+int raspicamcontrol_get_contrast(MMAL_COMPONENT_T *camera);
+int raspicamcontrol_get_brightness(MMAL_COMPONENT_T *camera);
+int raspicamcontrol_get_ISO(MMAL_COMPONENT_T *camera);
+MMAL_PARAM_EXPOSUREMETERINGMODE_T raspicamcontrol_get_metering_mode(MMAL_COMPONENT_T *camera);
+int raspicamcontrol_get_video_stabilisation(MMAL_COMPONENT_T *camera);
+int raspicamcontrol_get_exposure_compensation(MMAL_COMPONENT_T *camera);
+MMAL_PARAM_THUMBNAIL_CONFIG_T raspicamcontrol_get_thumbnail_parameters(MMAL_COMPONENT_T *camera);
+MMAL_PARAM_EXPOSUREMODE_T raspicamcontrol_get_exposure_mode(MMAL_COMPONENT_T *camera);
+MMAL_PARAM_FLICKERAVOID_T raspicamcontrol_get_flicker_avoid_mode(MMAL_COMPONENT_T *camera);
+MMAL_PARAM_AWBMODE_T raspicamcontrol_get_awb_mode(MMAL_COMPONENT_T *camera);
+MMAL_PARAM_IMAGEFX_T raspicamcontrol_get_imageFX(MMAL_COMPONENT_T *camera);
+MMAL_PARAM_COLOURFX_T raspicamcontrol_get_colourFX(MMAL_COMPONENT_T *camera);
+
+
+
+
+#endif /* RASPICAMCONTROL_H_ */
diff --git a/host_applications/linux/apps/raspicam/RaspiPreview.c b/host_applications/linux/apps/raspicam/RaspiPreview.c
new file mode 100755 (executable)
index 0000000..7656c87
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, James Hughes
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+
+#include "interface/vcos/vcos.h"
+
+#include "interface/mmal/mmal.h"
+#include "interface/mmal/mmal_logging.h"
+#include "interface/mmal/mmal_buffer.h"
+#include "interface/mmal/util/mmal_util.h"
+#include "interface/mmal/util/mmal_util_params.h"
+#include "interface/mmal/util/mmal_default_components.h"
+#include "interface/mmal/util/mmal_connection.h"
+
+#include "RaspiPreview.h"
+#include "RaspiCLI.h"
+
+#define CommandPreview        1
+#define CommandFullScreen     2
+#define CommandOpacity        3
+#define CommandDisablePreview 4
+
+static COMMAND_LIST cmdline_commands[] =
+{
+   { CommandPreview,       "-preview",    "p",  "Preview window settings <'x,y,w,h'>", 1 },
+   { CommandFullScreen,    "-fullscreen", "f",  "Fullscreen preview mode", 0 },
+   { CommandOpacity,       "-opacity",    "op", "Preview window opacity (0-255)", 1},
+   { CommandDisablePreview,"-nopreview",  "n",  "Do not display a preview window", 0},
+};
+
+static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]);
+
+/**
+ * Create the preview component, set up its ports
+ *
+ * @param state Pointer to state control struct
+ *
+ * @return MMAL_SUCCESS if all OK, something else otherwise
+ *
+ */
+MMAL_STATUS_T raspipreview_create(RASPIPREVIEW_PARAMETERS *state)
+{
+   MMAL_COMPONENT_T *preview = 0;
+   MMAL_PORT_T *preview_port = NULL;
+   MMAL_STATUS_T status;
+
+   if (!state->wantPreview)
+   {
+      // No preview required, so create a null sink component to take its place
+      status = mmal_component_create("vc.null_sink", &preview);
+
+      if (status != MMAL_SUCCESS)
+      {
+         vcos_log_error("Unable to create null sink component");
+         goto error;
+      }
+   }
+   else
+   {
+      status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER,
+            &preview);
+
+      if (status != MMAL_SUCCESS)
+      {
+         vcos_log_error("Unable to create preview component");
+         goto error;
+      }
+
+      if (!preview->input_num)
+      {
+         status = MMAL_ENOSYS;
+         vcos_log_error("No input ports found on component");
+         goto error;
+      }
+
+      preview_port = preview->input[0];
+
+      MMAL_DISPLAYREGION_T param;
+      param.hdr.id = MMAL_PARAMETER_DISPLAYREGION;
+      param.hdr.size = sizeof(MMAL_DISPLAYREGION_T);
+
+      param.set = MMAL_DISPLAY_SET_LAYER;
+      param.layer = PREVIEW_LAYER;
+
+      param.set |= MMAL_DISPLAY_SET_ALPHA;
+      param.alpha = state->opacity;
+
+      if (state->wantFullScreenPreview)
+      {
+         param.set |= MMAL_DISPLAY_SET_FULLSCREEN;
+         param.fullscreen = 1;
+      }
+      else
+      {
+         param.set |= (MMAL_DISPLAY_SET_DEST_RECT | MMAL_DISPLAY_SET_FULLSCREEN);
+         param.fullscreen = 0;
+         param.dest_rect = state->previewWindow;
+      }
+
+      status = mmal_port_parameter_set(preview_port, &param.hdr);
+
+      if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
+      {
+         vcos_log_error("unable to set preview port parameters (%u)", status);
+         goto error;
+      }
+   }
+
+   /* Enable component */
+   status = mmal_component_enable(preview);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Unable to enable preview/null sink component (%u)", status);
+      goto error;
+   }
+
+   state->preview_component = preview;
+
+   return status;
+
+error:
+
+   if (preview)
+      mmal_component_destroy(preview);
+
+   return status;
+}
+
+
+/**
+ * Destroy the preview component
+ *
+ * @param state Pointer to state control struct
+ *
+ */
+void raspipreview_destroy(RASPIPREVIEW_PARAMETERS *state)
+{
+   if (state->preview_component)
+   {
+      mmal_component_destroy(state->preview_component);
+      state->preview_component = NULL;
+   }
+}
+
+/**
+ * Assign set of default parameters to the passed in parameter block
+ *
+ * @param state Pointer to parameter block
+ *
+ */
+void raspipreview_set_defaults(RASPIPREVIEW_PARAMETERS *state)
+{
+   state->wantPreview = 1;
+   state->wantFullScreenPreview = 1;
+   state->opacity = 255;
+   state->previewWindow.x = 0;
+   state->previewWindow.y = 0;
+   state->previewWindow.width = 1024;
+   state->previewWindow.height = 768;
+   state->preview_component = NULL;
+}
+
+/**
+ * Dump parameters as human readable to stdout
+ *
+ * @param state Pointer to parameter block
+ *
+ */
+void raspipreview_dump_parameters(RASPIPREVIEW_PARAMETERS *state)
+{
+   fprintf(stderr, "Preview %s, Full screen %s\n", state->wantPreview ? "Yes" : "No",
+      state->wantFullScreenPreview ? "Yes" : "No");
+
+   fprintf(stderr, "Preview window %d,%d,%d,%d\nOpacity %d\n", state->previewWindow.x,
+      state->previewWindow.y, state->previewWindow.width,
+      state->previewWindow.height, state->opacity);
+};
+
+/**
+ * Parse a possible command pair - command and parameter
+ * @param arg1 Command
+ * @param arg2 Parameter (could be NULL)
+ * @return How many parameters were used, 0,1,2
+ */
+int raspipreview_parse_cmdline(RASPIPREVIEW_PARAMETERS *params, const char *arg1, const char *arg2)
+{
+   int command_id, used = 0, num_parameters;
+
+   if (!arg1)
+       return 0;
+
+   command_id = raspicli_get_command_id(cmdline_commands, cmdline_commands_size, arg1, &num_parameters);
+
+   // If invalid command, or we are missing a parameter, drop out
+   if (command_id==-1 || (command_id != -1 && num_parameters > 0 && arg2 == NULL))
+      return 0;
+
+   switch (command_id)
+   {
+      case CommandPreview: // Preview window
+      {
+         int tmp;
+
+         params->wantPreview = 1;
+
+         tmp = sscanf(arg2, "%d,%d,%d,%d",
+               &params->previewWindow.x, &params->previewWindow.y,
+               &params->previewWindow.width, &params->previewWindow.height);
+
+         // Failed to get any window parameters, so revert to full screen
+         if (tmp == 0)
+            params->wantFullScreenPreview = 1;
+         else
+            params->wantFullScreenPreview = 0;
+
+         used = 2;
+
+         break;
+      }
+
+      case CommandFullScreen: // Want full screen preview mode (overrides display rect)
+         params->wantPreview = 1;
+         params->wantFullScreenPreview = 1;
+
+         used = 1;
+         break;
+
+      case CommandOpacity: // Define preview window opacity
+         if (sscanf(arg2, "%u", &params->opacity) != 1)
+            params->opacity = 255;
+         else
+            used = 2;
+         break;
+
+      case CommandDisablePreview: // Turn off preview output
+         params->wantPreview = 0;
+         used = 1;
+         break;
+   }
+
+   return used;
+}
+
+/**
+ * Display help for command line options
+ */
+void raspipreview_display_help()
+{
+   fprintf(stdout, "\nPreview parameter commands\n\n");
+   raspicli_display_help(cmdline_commands, cmdline_commands_size);
+}
diff --git a/host_applications/linux/apps/raspicam/RaspiPreview.h b/host_applications/linux/apps/raspicam/RaspiPreview.h
new file mode 100755 (executable)
index 0000000..409dbff
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, James Hughes
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef RASPIPREVIEW_H_
+#define RASPIPREVIEW_H_
+
+/// Layer that preview window should be displayed on
+#define PREVIEW_LAYER      2
+
+// Frames rates of 0 implies variable, but denominator needs to be 1 to prevent div by 0
+#define PREVIEW_FRAME_RATE_NUM 0
+#define PREVIEW_FRAME_RATE_DEN 1
+
+#define FULL_RES_PREVIEW_FRAME_RATE_NUM 0
+#define FULL_RES_PREVIEW_FRAME_RATE_DEN 1
+
+#define FULL_FOV_PREVIEW_16x9_X 1280
+#define FULL_FOV_PREVIEW_16x9_Y 720
+
+#define FULL_FOV_PREVIEW_4x3_X 1296
+#define FULL_FOV_PREVIEW_4x3_Y 972
+
+#define FULL_FOV_PREVIEW_FRAME_RATE_NUM 0
+#define FULL_FOV_PREVIEW_FRAME_RATE_DEN 1
+
+typedef struct
+{
+   int wantPreview;                       /// Display a preview
+   int wantFullScreenPreview;             /// 0 is use previewRect, non-zero to use full screen
+   int opacity;                           /// Opacity of window - 0 = transparent, 255 = opaque
+   MMAL_RECT_T previewWindow;             /// Destination rectangle for the preview window.
+   MMAL_COMPONENT_T *preview_component;   /// Pointer to the created preview display component
+} RASPIPREVIEW_PARAMETERS;
+
+MMAL_STATUS_T raspipreview_create(RASPIPREVIEW_PARAMETERS *state);
+void raspipreview_destroy(RASPIPREVIEW_PARAMETERS *state);
+void raspipreview_set_defaults(RASPIPREVIEW_PARAMETERS *state);
+void raspipreview_dump_parameters(RASPIPREVIEW_PARAMETERS *state);
+int raspipreview_parse_cmdline(RASPIPREVIEW_PARAMETERS *params, const char *arg1, const char *arg2);
+void raspipreview_display_help();
+
+#endif /* RASPIPREVIEW_H_ */
diff --git a/host_applications/linux/apps/raspicam/RaspiStill.c b/host_applications/linux/apps/raspicam/RaspiStill.c
new file mode 100755 (executable)
index 0000000..0c3cf3f
--- /dev/null
@@ -0,0 +1,2169 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, James Hughes
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * \file RaspiStill.c
+ * Command line program to capture a still frame and encode it to file.
+ * Also optionally display a preview/viewfinder of current camera input.
+ *
+ * \date 31 Jan 2013
+ * \Author: James Hughes
+ *
+ * Description
+ *
+ * 3 components are created; camera, preview and JPG encoder.
+ * Camera component has three ports, preview, video and stills.
+ * This program connects preview and stills to the preview and jpg
+ * encoder. Using mmal we don't need to worry about buffers between these
+ * components, but we do need to handle buffers from the encoder, which
+ * are simply written straight to the file in the requisite buffer callback.
+ *
+ * We use the RaspiCamControl code to handle the specific camera settings.
+ */
+
+// We use some GNU extensions (asprintf, basename)
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <memory.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sysexits.h>
+
+#define VERSION_STRING "v1.3.11"
+
+#include "bcm_host.h"
+#include "interface/vcos/vcos.h"
+
+#include "interface/mmal/mmal.h"
+#include "interface/mmal/mmal_logging.h"
+#include "interface/mmal/mmal_buffer.h"
+#include "interface/mmal/util/mmal_util.h"
+#include "interface/mmal/util/mmal_util_params.h"
+#include "interface/mmal/util/mmal_default_components.h"
+#include "interface/mmal/util/mmal_connection.h"
+#include "interface/mmal/mmal_parameters_camera.h"
+
+
+#include "RaspiCamControl.h"
+#include "RaspiPreview.h"
+#include "RaspiCLI.h"
+#include "RaspiTex.h"
+
+#include <semaphore.h>
+
+// Standard port setting for the camera component
+#define MMAL_CAMERA_PREVIEW_PORT 0
+#define MMAL_CAMERA_VIDEO_PORT 1
+#define MMAL_CAMERA_CAPTURE_PORT 2
+
+
+// Stills format information
+// 0 implies variable
+#define STILLS_FRAME_RATE_NUM 0
+#define STILLS_FRAME_RATE_DEN 1
+
+/// Video render needs at least 2 buffers.
+#define VIDEO_OUTPUT_BUFFERS_NUM 3
+
+#define MAX_USER_EXIF_TAGS      32
+#define MAX_EXIF_PAYLOAD_LENGTH 128
+
+/// Frame advance method
+#define FRAME_NEXT_SINGLE        0
+#define FRAME_NEXT_TIMELAPSE     1
+#define FRAME_NEXT_KEYPRESS      2
+#define FRAME_NEXT_FOREVER       3
+#define FRAME_NEXT_GPIO          4
+#define FRAME_NEXT_SIGNAL        5
+#define FRAME_NEXT_IMMEDIATELY   6
+
+
+int mmal_status_to_int(MMAL_STATUS_T status);
+static void signal_handler(int signal_number);
+
+
+/** Structure containing all state information for the current run
+ */
+typedef struct
+{
+   int timeout;                        /// Time taken before frame is grabbed and app then shuts down. Units are milliseconds
+   int width;                          /// Requested width of image
+   int height;                         /// requested height of image
+   char camera_name[MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN]; // Name of the camera sensor
+   int quality;                        /// JPEG quality setting (1-100)
+   int wantRAW;                        /// Flag for whether the JPEG metadata also contains the RAW bayer image
+   char *filename;                     /// filename of output file
+   char *linkname;                     /// filename of output file
+   int frameStart;                     /// First number of frame output counter
+   MMAL_PARAM_THUMBNAIL_CONFIG_T thumbnailConfig;
+   int verbose;                        /// !0 if want detailed run information
+   int demoMode;                       /// Run app in demo mode
+   int demoInterval;                   /// Interval between camera settings changes
+   MMAL_FOURCC_T encoding;             /// Encoding to use for the output file.
+   const char *exifTags[MAX_USER_EXIF_TAGS]; /// Array of pointers to tags supplied from the command line
+   int numExifTags;                    /// Number of supplied tags
+   int enableExifTags;                 /// Enable/Disable EXIF tags in output
+   int timelapse;                      /// Delay between each picture in timelapse mode. If 0, disable timelapse
+   int fullResPreview;                 /// If set, the camera preview port runs at capture resolution. Reduces fps.
+   int frameNextMethod;                /// Which method to use to advance to next frame
+   int useGL;                          /// Render preview using OpenGL
+   int glCapture;                      /// Save the GL frame-buffer instead of camera output
+   int settings;                       /// Request settings from the camera
+   int cameraNum;                      /// Camera number
+   int burstCaptureMode;               /// Enable burst mode
+   int sensor_mode;                     /// Sensor mode. 0=auto. Check docs/forum for modes selected by other values.
+   int datetime;                       /// Use DateTime instead of frame#
+   int timestamp;                      /// Use timestamp instead of frame#
+   int restart_interval;               /// JPEG restart interval. 0 for none.
+
+   RASPIPREVIEW_PARAMETERS preview_parameters;    /// Preview setup parameters
+   RASPICAM_CAMERA_PARAMETERS camera_parameters; /// Camera setup parameters
+
+   MMAL_COMPONENT_T *camera_component;    /// Pointer to the camera component
+   MMAL_COMPONENT_T *encoder_component;   /// Pointer to the encoder component
+   MMAL_COMPONENT_T *null_sink_component; /// Pointer to the null sink component
+   MMAL_CONNECTION_T *preview_connection; /// Pointer to the connection from camera to preview
+   MMAL_CONNECTION_T *encoder_connection; /// Pointer to the connection from camera to encoder
+
+   MMAL_POOL_T *encoder_pool; /// Pointer to the pool of buffers used by encoder output port
+
+   RASPITEX_STATE raspitex_state; /// GL renderer state and parameters
+
+} RASPISTILL_STATE;
+
+/** Struct used to pass information in encoder port userdata to callback
+ */
+typedef struct
+{
+   FILE *file_handle;                   /// File handle to write buffer data to.
+   VCOS_SEMAPHORE_T complete_semaphore; /// semaphore which is posted when we reach end of frame (indicates end of capture or fault)
+   RASPISTILL_STATE *pstate;            /// pointer to our state in case required in callback
+} PORT_USERDATA;
+
+static void display_valid_parameters(char *app_name);
+static void store_exif_tag(RASPISTILL_STATE *state, const char *exif_tag);
+
+/// Comamnd ID's and Structure defining our command line options
+#define CommandHelp         0
+#define CommandWidth        1
+#define CommandHeight       2
+#define CommandQuality      3
+#define CommandRaw          4
+#define CommandOutput       5
+#define CommandVerbose      6
+#define CommandTimeout      7
+#define CommandThumbnail    8
+#define CommandDemoMode     9
+#define CommandEncoding     10
+#define CommandExifTag      11
+#define CommandTimelapse    12
+#define CommandFullResPreview 13
+#define CommandLink         14
+#define CommandKeypress     15
+#define CommandSignal       16
+#define CommandGL           17
+#define CommandGLCapture    18
+#define CommandSettings     19
+#define CommandCamSelect    20
+#define CommandBurstMode    21
+#define CommandSensorMode   22
+#define CommandDateTime     23
+#define CommandTimeStamp    24
+#define CommandFrameStart   25
+#define CommandRestartInterval 26
+
+static COMMAND_LIST cmdline_commands[] =
+{
+   { CommandHelp,    "-help",       "?",  "This help information", 0 },
+   { CommandWidth,   "-width",      "w",  "Set image width <size>", 1 },
+   { CommandHeight,  "-height",     "h",  "Set image height <size>", 1 },
+   { CommandQuality, "-quality",    "q",  "Set jpeg quality <0 to 100>", 1 },
+   { CommandRaw,     "-raw",        "r",  "Add raw bayer data to jpeg metadata", 0 },
+   { CommandOutput,  "-output",     "o",  "Output filename <filename> (to write to stdout, use '-o -'). If not specified, no file is saved", 1 },
+   { CommandLink,    "-latest",     "l",  "Link latest complete image to filename <filename>", 1},
+   { CommandVerbose, "-verbose",    "v",  "Output verbose information during run", 0 },
+   { CommandTimeout, "-timeout",    "t",  "Time (in ms) before takes picture and shuts down (if not specified, set to 5s)", 1 },
+   { CommandThumbnail,"-thumb",     "th", "Set thumbnail parameters (x:y:quality) or none", 1},
+   { CommandDemoMode,"-demo",       "d",  "Run a demo mode (cycle through range of camera options, no capture)", 0},
+   { CommandEncoding,"-encoding",   "e",  "Encoding to use for output file (jpg, bmp, gif, png)", 1},
+   { CommandExifTag, "-exif",       "x",  "EXIF tag to apply to captures (format as 'key=value') or none", 1},
+   { CommandTimelapse,"-timelapse", "tl", "Timelapse mode. Takes a picture every <t>ms. %d == frame number (Try: -o img_%04d.jpg)", 1},
+   { CommandFullResPreview,"-fullpreview","fp", "Run the preview using the still capture resolution (may reduce preview fps)", 0},
+   { CommandKeypress,"-keypress",   "k",  "Wait between captures for a ENTER, X then ENTER to exit", 0},
+   { CommandSignal,  "-signal",     "s",  "Wait between captures for a SIGUSR1 or SIGUSR2 from another process", 0},
+   { CommandGL,      "-gl",         "g",  "Draw preview to texture instead of using video render component", 0},
+   { CommandGLCapture, "-glcapture","gc", "Capture the GL frame-buffer instead of the camera image", 0},
+   { CommandSettings, "-settings",  "set","Retrieve camera settings and write to stdout", 0},
+   { CommandCamSelect, "-camselect","cs", "Select camera <number>. Default 0", 1 },
+   { CommandBurstMode, "-burst",    "bm", "Enable 'burst capture mode'", 0},
+   { CommandSensorMode,"-mode",     "md", "Force sensor mode. 0=auto. See docs for other modes available", 1},
+   { CommandDateTime,  "-datetime",  "dt", "Replace output pattern (%d) with DateTime (MonthDayHourMinSec)", 0},
+   { CommandTimeStamp, "-timestamp", "ts", "Replace output pattern (%d) with unix timestamp (seconds since 1970)", 0},
+   { CommandFrameStart,"-framestart","fs",  "Starting frame number in output pattern(%d)", 1},
+   { CommandRestartInterval, "-restart","rs","JPEG Restart interval (default of 0 for none)", 1},
+};
+
+static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]);
+
+static struct
+{
+   char *format;
+   MMAL_FOURCC_T encoding;
+} encoding_xref[] =
+{
+   {"jpg", MMAL_ENCODING_JPEG},
+   {"bmp", MMAL_ENCODING_BMP},
+   {"gif", MMAL_ENCODING_GIF},
+   {"png", MMAL_ENCODING_PNG}
+};
+
+static int encoding_xref_size = sizeof(encoding_xref) / sizeof(encoding_xref[0]);
+
+
+static struct
+{
+   char *description;
+   int nextFrameMethod;
+} next_frame_description[] =
+{
+      {"Single capture",         FRAME_NEXT_SINGLE},
+      {"Capture on timelapse",   FRAME_NEXT_TIMELAPSE},
+      {"Capture on keypress",    FRAME_NEXT_KEYPRESS},
+      {"Run forever",            FRAME_NEXT_FOREVER},
+      {"Capture on GPIO",        FRAME_NEXT_GPIO},
+      {"Capture on signal",      FRAME_NEXT_SIGNAL},
+};
+
+static int next_frame_description_size = sizeof(next_frame_description) / sizeof(next_frame_description[0]);
+
+static void set_sensor_defaults(RASPISTILL_STATE *state)
+{
+   MMAL_COMPONENT_T *camera_info;
+   MMAL_STATUS_T status;
+
+   // Default to the OV5647 setup
+   strncpy(state->camera_name, "OV5647", MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN);
+
+   // Try to get the camera name and maximum supported resolution
+   status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA_INFO, &camera_info);
+   if (status == MMAL_SUCCESS)
+   {
+      MMAL_PARAMETER_CAMERA_INFO_T param;
+      param.hdr.id = MMAL_PARAMETER_CAMERA_INFO;
+      param.hdr.size = sizeof(param)-4;  // Deliberately undersize to check firmware veresion
+      status = mmal_port_parameter_get(camera_info->control, &param.hdr);
+
+      if (status != MMAL_SUCCESS)
+      {
+         // Running on newer firmware
+         param.hdr.size = sizeof(param);
+         status = mmal_port_parameter_get(camera_info->control, &param.hdr);
+         if (status == MMAL_SUCCESS && param.num_cameras > state->cameraNum)
+         {
+            // Take the parameters from the first camera listed.
+            if (state->width == 0)
+               state->width = param.cameras[state->cameraNum].max_width;
+            if (state->height == 0)
+               state->height = param.cameras[state->cameraNum].max_height;
+            strncpy(state->camera_name,  param.cameras[state->cameraNum].camera_name, MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN);
+            state->camera_name[MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN-1] = 0;
+         }
+         else
+            vcos_log_error("Cannot read camera info, keeping the defaults for OV5647");
+      }
+      else
+      {
+         // Older firmware
+         // Nothing to do here, keep the defaults for OV5647
+      }
+
+      mmal_component_destroy(camera_info);
+   }
+   else
+   {
+      vcos_log_error("Failed to create camera_info component");
+   }
+   //Command line hasn't specified a resolution, and we failed to
+   //get a default resolution from camera_info. Assume OV5647 full res
+   if (state->width == 0)
+      state->width = 2592;
+   if (state->height == 0)
+      state->height = 1944;
+}
+
+/**
+ * Assign a default set of parameters to the state passed in
+ *
+ * @param state Pointer to state structure to assign defaults to
+ */
+static void default_status(RASPISTILL_STATE *state)
+{
+   if (!state)
+   {
+      vcos_assert(0);
+      return;
+   }
+
+   state->timeout = 5000; // 5s delay before take image
+   state->quality = 85;
+   state->wantRAW = 0;
+   state->filename = NULL;
+   state->linkname = NULL;
+   state->frameStart = 0;
+   state->verbose = 0;
+   state->thumbnailConfig.enable = 1;
+   state->thumbnailConfig.width = 64;
+   state->thumbnailConfig.height = 48;
+   state->thumbnailConfig.quality = 35;
+   state->demoMode = 0;
+   state->demoInterval = 250; // ms
+   state->camera_component = NULL;
+   state->encoder_component = NULL;
+   state->preview_connection = NULL;
+   state->encoder_connection = NULL;
+   state->encoder_pool = NULL;
+   state->encoding = MMAL_ENCODING_JPEG;
+   state->numExifTags = 0;
+   state->enableExifTags = 1;
+   state->timelapse = 0;
+   state->fullResPreview = 0;
+   state->frameNextMethod = FRAME_NEXT_SINGLE;
+   state->useGL = 0;
+   state->glCapture = 0;
+   state->settings = 0;
+   state->cameraNum = 0;
+   state->burstCaptureMode=0;
+   state->sensor_mode = 0;
+   state->datetime = 0;
+   state->timestamp = 0;
+   state->restart_interval = 0;
+
+   // Setup preview window defaults
+   raspipreview_set_defaults(&state->preview_parameters);
+
+   // Set up the camera_parameters to default
+   raspicamcontrol_set_defaults(&state->camera_parameters);
+
+   // Set initial GL preview state
+   raspitex_set_defaults(&state->raspitex_state);
+}
+
+/**
+ * Dump image state parameters to stderr. Used for debugging
+ *
+ * @param state Pointer to state structure to assign defaults to
+ */
+static void dump_status(RASPISTILL_STATE *state)
+{
+   int i;
+
+   if (!state)
+   {
+      vcos_assert(0);
+      return;
+   }
+
+   fprintf(stderr, "Width %d, Height %d, quality %d, filename %s\n", state->width,
+         state->height, state->quality, state->filename);
+   fprintf(stderr, "Time delay %d, Raw %s\n", state->timeout,
+         state->wantRAW ? "yes" : "no");
+   fprintf(stderr, "Thumbnail enabled %s, width %d, height %d, quality %d\n",
+         state->thumbnailConfig.enable ? "Yes":"No", state->thumbnailConfig.width,
+         state->thumbnailConfig.height, state->thumbnailConfig.quality);
+   fprintf(stderr, "Link to latest frame enabled ");
+   if (state->linkname)
+   {
+      fprintf(stderr, " yes, -> %s\n", state->linkname);
+   }
+   else
+   {
+      fprintf(stderr, " no\n");
+   }
+   fprintf(stderr, "Full resolution preview %s\n", state->fullResPreview ? "Yes": "No");
+
+   fprintf(stderr, "Capture method : ");
+   for (i=0;i<next_frame_description_size;i++)
+   {
+      if (state->frameNextMethod == next_frame_description[i].nextFrameMethod)
+         fprintf(stderr, "%s", next_frame_description[i].description);
+   }
+   fprintf(stderr, "\n\n");
+
+   if (state->enableExifTags)
+   {
+          if (state->numExifTags)
+          {
+                 fprintf(stderr, "User supplied EXIF tags :\n");
+
+                 for (i=0;i<state->numExifTags;i++)
+                 {
+                        fprintf(stderr, "%s", state->exifTags[i]);
+                        if (i != state->numExifTags-1)
+                               fprintf(stderr, ",");
+                 }
+                 fprintf(stderr, "\n\n");
+          }
+   }
+   else
+      fprintf(stderr, "EXIF tags disabled\n");
+
+   raspipreview_dump_parameters(&state->preview_parameters);
+   raspicamcontrol_dump_parameters(&state->camera_parameters);
+}
+
+/**
+ * Parse the incoming command line and put resulting parameters in to the state
+ *
+ * @param argc Number of arguments in command line
+ * @param argv Array of pointers to strings from command line
+ * @param state Pointer to state structure to assign any discovered parameters to
+ * @return non-0 if failed for some reason, 0 otherwise
+ */
+static int parse_cmdline(int argc, const char **argv, RASPISTILL_STATE *state)
+{
+   // Parse the command line arguments.
+   // We are looking for --<something> or -<abbreviation of something>
+
+   int valid = 1;
+   int i;
+
+   for (i = 1; i < argc && valid; i++)
+   {
+      int command_id, num_parameters;
+
+      if (!argv[i])
+         continue;
+
+      if (argv[i][0] != '-')
+      {
+         valid = 0;
+         continue;
+      }
+
+      // Assume parameter is valid until proven otherwise
+      valid = 1;
+
+      command_id = raspicli_get_command_id(cmdline_commands, cmdline_commands_size, &argv[i][1], &num_parameters);
+
+      // If we found a command but are missing a parameter, continue (and we will drop out of the loop)
+      if (command_id != -1 && num_parameters > 0 && (i + 1 >= argc) )
+         continue;
+
+      //  We are now dealing with a command line option
+      switch (command_id)
+      {
+      case CommandHelp:
+         display_valid_parameters(basename(argv[0]));
+         // exit straight away if help requested
+         return -1;
+
+      case CommandWidth: // Width > 0
+         if (sscanf(argv[i + 1], "%u", &state->width) != 1)
+            valid = 0;
+         else
+            i++;
+         break;
+
+      case CommandHeight: // Height > 0
+         if (sscanf(argv[i + 1], "%u", &state->height) != 1)
+            valid = 0;
+         else
+            i++;
+         break;
+
+      case CommandQuality: // Quality = 1-100
+         if (sscanf(argv[i + 1], "%u", &state->quality) == 1)
+         {
+            if (state->quality > 100)
+            {
+               fprintf(stderr, "Setting max quality = 100\n");
+               state->quality = 100;
+            }
+            i++;
+         }
+         else
+            valid = 0;
+
+         break;
+
+      case CommandRaw: // Add raw bayer data in metadata
+         state->wantRAW = 1;
+         break;
+
+      case CommandOutput:  // output filename
+      {
+         int len = strlen(argv[i + 1]);
+         if (len)
+         {
+            //We use sprintf to append the frame number for timelapse mode
+            //Ensure that any %<char> is either %% or %d.
+            const char *percent = argv[i+1];
+            while(valid && *percent && (percent=strchr(percent, '%')) != NULL)
+            {
+               int digits=0;
+               percent++;
+               while(isdigit(*percent))
+               {
+                 percent++;
+                 digits++;
+               }
+               if(!((*percent == '%' && !digits) || *percent == 'd'))
+               {
+                  valid = 0;
+                  fprintf(stderr, "Filename contains %% characters, but not %%d or %%%% - sorry, will fail\n");
+               }
+               percent++;
+            }
+            state->filename = malloc(len + 10); // leave enough space for any timelapse generated changes to filename
+            vcos_assert(state->filename);
+            if (state->filename)
+               strncpy(state->filename, argv[i + 1], len+1);
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandLink :
+      {
+         int len = strlen(argv[i+1]);
+         if (len)
+         {
+            state->linkname = malloc(len + 10);
+            vcos_assert(state->linkname);
+            if (state->linkname)
+               strncpy(state->linkname, argv[i + 1], len+1);
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+
+      }
+
+      case CommandFrameStart:  // use a staring value != 0
+      {
+         if (sscanf(argv[i + 1], "%d", &state->frameStart) == 1)
+         {
+           i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandVerbose: // display lots of data during run
+         state->verbose = 1;
+         break;
+      case CommandDateTime: // use datetime
+         state->datetime = 1;
+         break;
+      case CommandTimeStamp: // use timestamp
+         state->timestamp = 1;
+         break;
+
+      case CommandTimeout: // Time to run viewfinder for before taking picture, in seconds
+      {
+         if (sscanf(argv[i + 1], "%u", &state->timeout) == 1)
+         {
+            // Ensure that if previously selected CommandKeypress we don't overwrite it
+            if (state->timeout == 0 && state->frameNextMethod == FRAME_NEXT_SINGLE)
+               state->frameNextMethod = FRAME_NEXT_FOREVER;
+
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+      case CommandThumbnail : // thumbnail parameters - needs string "x:y:quality"
+         if ( strcmp( argv[ i + 1 ], "none" ) == 0 )
+         {
+            state->thumbnailConfig.enable = 0;
+         }
+         else
+         {
+            sscanf(argv[i + 1], "%d:%d:%d",
+                   &state->thumbnailConfig.width,
+                   &state->thumbnailConfig.height,
+                   &state->thumbnailConfig.quality);
+         }
+         i++;
+         break;
+
+      case CommandDemoMode: // Run in demo mode - no capture
+      {
+         // Demo mode might have a timing parameter
+         // so check if a) we have another parameter, b) its not the start of the next option
+         if (i + 1 < argc  && argv[i+1][0] != '-')
+         {
+            if (sscanf(argv[i + 1], "%u", &state->demoInterval) == 1)
+            {
+               // TODO : What limits do we need for timeout?
+               state->demoMode = 1;
+               i++;
+            }
+            else
+               valid = 0;
+         }
+         else
+         {
+            state->demoMode = 1;
+         }
+
+         break;
+      }
+
+      case CommandEncoding :
+      {
+         int len = strlen(argv[i + 1]);
+         valid = 0;
+
+         if (len)
+         {
+            int j;
+            for (j=0;j<encoding_xref_size;j++)
+            {
+               if (strcmp(encoding_xref[j].format, argv[i+1]) == 0)
+               {
+                  state->encoding = encoding_xref[j].encoding;
+                  valid = 1;
+                  i++;
+                  break;
+               }
+            }
+         }
+         break;
+      }
+
+      case CommandExifTag:
+         if ( strcmp( argv[ i + 1 ], "none" ) == 0 )
+         {
+            state->enableExifTags = 0;
+         }
+         else
+         {
+            store_exif_tag(state, argv[i+1]);
+         }
+         i++;
+         break;
+
+      case CommandTimelapse:
+         if (sscanf(argv[i + 1], "%u", &state->timelapse) != 1)
+            valid = 0;
+         else
+         {
+            if (state->timelapse)
+               state->frameNextMethod = FRAME_NEXT_TIMELAPSE;
+            else
+               state->frameNextMethod = FRAME_NEXT_IMMEDIATELY;
+
+
+            i++;
+         }
+         break;
+
+      case CommandFullResPreview:
+         state->fullResPreview = 1;
+         break;
+
+      case CommandKeypress: // Set keypress between capture mode
+         state->frameNextMethod = FRAME_NEXT_KEYPRESS;
+         break;
+
+      case CommandSignal:   // Set SIGUSR1 & SIGUSR2 between capture mode
+         state->frameNextMethod = FRAME_NEXT_SIGNAL;
+         // Reenable the signal
+         signal(SIGUSR1, signal_handler);
+         signal(SIGUSR2, signal_handler);
+         break;
+
+      case CommandGL:
+         state->useGL = 1;
+         break;
+
+      case CommandGLCapture:
+         state->glCapture = 1;
+         break;
+
+      case CommandSettings:
+         state->settings = 1;
+         break;
+
+
+      case CommandCamSelect:  //Select camera input port
+      {
+         if (sscanf(argv[i + 1], "%u", &state->cameraNum) == 1)
+         {
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandBurstMode:
+         state->burstCaptureMode=1;
+         break;
+
+      case CommandSensorMode:
+      {
+         if (sscanf(argv[i + 1], "%u", &state->sensor_mode) == 1)
+         {
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandRestartInterval:
+      {
+         if (sscanf(argv[i + 1], "%u", &state->restart_interval) == 1)
+         {
+           i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+
+      default:
+      {
+         // Try parsing for any image specific parameters
+         // result indicates how many parameters were used up, 0,1,2
+         // but we adjust by -1 as we have used one already
+         const char *second_arg = (i + 1 < argc) ? argv[i + 1] : NULL;
+         int parms_used = raspicamcontrol_parse_cmdline(&state->camera_parameters, &argv[i][1], second_arg);
+
+         // Still unused, try preview options
+         if (!parms_used)
+            parms_used = raspipreview_parse_cmdline(&state->preview_parameters, &argv[i][1], second_arg);
+
+         // Still unused, try GL preview options
+         if (!parms_used)
+            parms_used = raspitex_parse_cmdline(&state->raspitex_state, &argv[i][1], second_arg);
+
+         // If no parms were used, this must be a bad parameters
+         if (!parms_used)
+            valid = 0;
+         else
+            i += parms_used - 1;
+
+         break;
+      }
+      }
+   }
+
+   /* GL preview parameters use preview parameters as defaults unless overriden */
+   if (! state->raspitex_state.gl_win_defined)
+   {
+      state->raspitex_state.x       = state->preview_parameters.previewWindow.x;
+      state->raspitex_state.y       = state->preview_parameters.previewWindow.y;
+      state->raspitex_state.width   = state->preview_parameters.previewWindow.width;
+      state->raspitex_state.height  = state->preview_parameters.previewWindow.height;
+   }
+   /* Also pass the preview information through so GL renderer can determine
+    * the real resolution of the multi-media image */
+   state->raspitex_state.preview_x       = state->preview_parameters.previewWindow.x;
+   state->raspitex_state.preview_y       = state->preview_parameters.previewWindow.y;
+   state->raspitex_state.preview_width   = state->preview_parameters.previewWindow.width;
+   state->raspitex_state.preview_height  = state->preview_parameters.previewWindow.height;
+   state->raspitex_state.opacity         = state->preview_parameters.opacity;
+   state->raspitex_state.verbose         = state->verbose;
+
+   if (!valid)
+   {
+      fprintf(stderr, "Invalid command line option (%s)\n", argv[i-1]);
+      return 1;
+   }
+
+   return 0;
+}
+
+/**
+ * Display usage information for the application to stdout
+ *
+ * @param app_name String to display as the application name
+ */
+static void display_valid_parameters(char *app_name)
+{
+   fprintf(stdout, "Runs camera for specific time, and take JPG capture at end if requested\n\n");
+   fprintf(stdout, "usage: %s [options]\n\n", app_name);
+
+   fprintf(stdout, "Image parameter commands\n\n");
+
+   raspicli_display_help(cmdline_commands, cmdline_commands_size);
+
+   // Help for preview options
+   raspipreview_display_help();
+
+   // Now display any help information from the camcontrol code
+   raspicamcontrol_display_help();
+
+   // Now display GL preview help
+   raspitex_display_help();
+
+   fprintf(stdout, "\n");
+
+   return;
+}
+
+/**
+ *  buffer header callback function for camera control
+ *
+ *  No actions taken in current version
+ *
+ * @param port Pointer to port from which callback originated
+ * @param buffer mmal buffer header pointer
+ */
+static void camera_control_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   if (buffer->cmd == MMAL_EVENT_PARAMETER_CHANGED)
+   {
+      MMAL_EVENT_PARAMETER_CHANGED_T *param = (MMAL_EVENT_PARAMETER_CHANGED_T *)buffer->data;
+      switch (param->hdr.id) {
+         case MMAL_PARAMETER_CAMERA_SETTINGS:
+         {
+            MMAL_PARAMETER_CAMERA_SETTINGS_T *settings = (MMAL_PARAMETER_CAMERA_SETTINGS_T*)param;
+            vcos_log_error("Exposure now %u, analog gain %u/%u, digital gain %u/%u",
+                       settings->exposure,
+                        settings->analog_gain.num, settings->analog_gain.den,
+                        settings->digital_gain.num, settings->digital_gain.den);
+            vcos_log_error("AWB R=%u/%u, B=%u/%u",
+                        settings->awb_red_gain.num, settings->awb_red_gain.den,
+                        settings->awb_blue_gain.num, settings->awb_blue_gain.den
+                        );
+         }
+         break;
+      }
+   }
+   else if (buffer->cmd == MMAL_EVENT_ERROR)
+   {
+      vcos_log_error("No data received from sensor. Check all connections, including the Sunny one on the camera board");
+   }
+   else
+      vcos_log_error("Received unexpected camera control callback event, 0x%08x", buffer->cmd);
+
+   mmal_buffer_header_release(buffer);
+}
+
+/**
+ *  buffer header callback function for encoder
+ *
+ *  Callback will dump buffer data to the specific file
+ *
+ * @param port Pointer to port from which callback originated
+ * @param buffer mmal buffer header pointer
+ */
+static void encoder_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   int complete = 0;
+
+   // We pass our file handle and other stuff in via the userdata field.
+
+   PORT_USERDATA *pData = (PORT_USERDATA *)port->userdata;
+
+   if (pData)
+   {
+      int bytes_written = buffer->length;
+
+      if (buffer->length && pData->file_handle)
+      {
+         mmal_buffer_header_mem_lock(buffer);
+
+         bytes_written = fwrite(buffer->data, 1, buffer->length, pData->file_handle);
+
+         mmal_buffer_header_mem_unlock(buffer);
+      }
+
+      // We need to check we wrote what we wanted - it's possible we have run out of storage.
+      if (bytes_written != buffer->length)
+      {
+         vcos_log_error("Unable to write buffer to file - aborting");
+         complete = 1;
+      }
+
+      // Now flag if we have completed
+      if (buffer->flags & (MMAL_BUFFER_HEADER_FLAG_FRAME_END | MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED))
+         complete = 1;
+   }
+   else
+   {
+      vcos_log_error("Received a encoder buffer callback with no state");
+   }
+
+   // release buffer back to the pool
+   mmal_buffer_header_release(buffer);
+
+   // and send one back to the port (if still open)
+   if (port->is_enabled)
+   {
+      MMAL_STATUS_T status = MMAL_SUCCESS;
+      MMAL_BUFFER_HEADER_T *new_buffer;
+
+      new_buffer = mmal_queue_get(pData->pstate->encoder_pool->queue);
+
+      if (new_buffer)
+      {
+         status = mmal_port_send_buffer(port, new_buffer);
+      }
+      if (!new_buffer || status != MMAL_SUCCESS)
+         vcos_log_error("Unable to return a buffer to the encoder port");
+   }
+
+   if (complete)
+      vcos_semaphore_post(&(pData->complete_semaphore));
+}
+
+/**
+ * Create the camera component, set up its ports
+ *
+ * @param state Pointer to state control struct. camera_component member set to the created camera_component if successful.
+ *
+ * @return MMAL_SUCCESS if all OK, something else otherwise
+ *
+ */
+static MMAL_STATUS_T create_camera_component(RASPISTILL_STATE *state)
+{
+   MMAL_COMPONENT_T *camera = 0;
+   MMAL_ES_FORMAT_T *format;
+   MMAL_PORT_T *preview_port = NULL, *video_port = NULL, *still_port = NULL;
+   MMAL_STATUS_T status;
+
+   /* Create the component */
+   status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Failed to create camera component");
+      goto error;
+   }
+
+   status = raspicamcontrol_set_stereo_mode(camera->output[0], &state->camera_parameters.stereo_mode);
+   status += raspicamcontrol_set_stereo_mode(camera->output[1], &state->camera_parameters.stereo_mode);
+   status += raspicamcontrol_set_stereo_mode(camera->output[2], &state->camera_parameters.stereo_mode);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Could not set stereo mode : error %d", status);
+      goto error;
+   }
+
+   MMAL_PARAMETER_INT32_T camera_num =
+      {{MMAL_PARAMETER_CAMERA_NUM, sizeof(camera_num)}, state->cameraNum};
+
+   status = mmal_port_parameter_set(camera->control, &camera_num.hdr);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Could not select camera : error %d", status);
+      goto error;
+   }
+
+   if (!camera->output_num)
+   {
+      status = MMAL_ENOSYS;
+      vcos_log_error("Camera doesn't have output ports");
+      goto error;
+   }
+
+   status = mmal_port_parameter_set_uint32(camera->control, MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG, state->sensor_mode);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Could not set sensor mode : error %d", status);
+      goto error;
+   }
+
+   preview_port = camera->output[MMAL_CAMERA_PREVIEW_PORT];
+   video_port = camera->output[MMAL_CAMERA_VIDEO_PORT];
+   still_port = camera->output[MMAL_CAMERA_CAPTURE_PORT];
+
+   if (state->settings)
+   {
+      MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T change_event_request =
+         {{MMAL_PARAMETER_CHANGE_EVENT_REQUEST, sizeof(MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T)},
+          MMAL_PARAMETER_CAMERA_SETTINGS, 1};
+
+      status = mmal_port_parameter_set(camera->control, &change_event_request.hdr);
+      if ( status != MMAL_SUCCESS )
+      {
+         vcos_log_error("No camera settings events");
+      }
+   }
+
+   // Enable the camera, and tell it its control callback function
+   status = mmal_port_enable(camera->control, camera_control_callback);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Unable to enable control port : error %d", status);
+      goto error;
+   }
+
+   //  set up the camera configuration
+   {
+      MMAL_PARAMETER_CAMERA_CONFIG_T cam_config =
+      {
+         { MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) },
+         .max_stills_w = state->width,
+         .max_stills_h = state->height,
+         .stills_yuv422 = 0,
+         .one_shot_stills = 1,
+         .max_preview_video_w = state->preview_parameters.previewWindow.width,
+         .max_preview_video_h = state->preview_parameters.previewWindow.height,
+         .num_preview_video_frames = 3,
+         .stills_capture_circular_buffer_height = 0,
+         .fast_preview_resume = 0,
+         .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RESET_STC
+      };
+
+      if (state->fullResPreview)
+      {
+         cam_config.max_preview_video_w = state->width;
+         cam_config.max_preview_video_h = state->height;
+      }
+
+      mmal_port_parameter_set(camera->control, &cam_config.hdr);
+   }
+
+   raspicamcontrol_set_all_parameters(camera, &state->camera_parameters);
+
+   // Now set up the port formats
+
+   format = preview_port->format;
+   format->encoding = MMAL_ENCODING_OPAQUE;
+   format->encoding_variant = MMAL_ENCODING_I420;
+
+   if(state->camera_parameters.shutter_speed > 6000000)
+   {
+        MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
+                                                     { 50, 1000 }, {166, 1000}};
+        mmal_port_parameter_set(preview_port, &fps_range.hdr);
+   }
+   else if(state->camera_parameters.shutter_speed > 1000000)
+   {
+        MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
+                                                     { 166, 1000 }, {999, 1000}};
+        mmal_port_parameter_set(preview_port, &fps_range.hdr);
+   }
+   if (state->fullResPreview)
+   {
+      // In this mode we are forcing the preview to be generated from the full capture resolution.
+      // This runs at a max of 15fps with the OV5647 sensor.
+      format->es->video.width = VCOS_ALIGN_UP(state->width, 32);
+      format->es->video.height = VCOS_ALIGN_UP(state->height, 16);
+      format->es->video.crop.x = 0;
+      format->es->video.crop.y = 0;
+      format->es->video.crop.width = state->width;
+      format->es->video.crop.height = state->height;
+      format->es->video.frame_rate.num = FULL_RES_PREVIEW_FRAME_RATE_NUM;
+      format->es->video.frame_rate.den = FULL_RES_PREVIEW_FRAME_RATE_DEN;
+   }
+   else
+   {
+      // Use a full FOV 4:3 mode
+      format->es->video.width = VCOS_ALIGN_UP(state->preview_parameters.previewWindow.width, 32);
+      format->es->video.height = VCOS_ALIGN_UP(state->preview_parameters.previewWindow.height, 16);
+      format->es->video.crop.x = 0;
+      format->es->video.crop.y = 0;
+      format->es->video.crop.width = state->preview_parameters.previewWindow.width;
+      format->es->video.crop.height = state->preview_parameters.previewWindow.height;
+      format->es->video.frame_rate.num = PREVIEW_FRAME_RATE_NUM;
+      format->es->video.frame_rate.den = PREVIEW_FRAME_RATE_DEN;
+   }
+
+   status = mmal_port_format_commit(preview_port);
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("camera viewfinder format couldn't be set");
+      goto error;
+   }
+
+   // Set the same format on the video  port (which we don't use here)
+   mmal_format_full_copy(video_port->format, format);
+   status = mmal_port_format_commit(video_port);
+
+   if (status  != MMAL_SUCCESS)
+   {
+      vcos_log_error("camera video format couldn't be set");
+      goto error;
+   }
+
+   // Ensure there are enough buffers to avoid dropping frames
+   if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
+      video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
+
+   format = still_port->format;
+
+   if(state->camera_parameters.shutter_speed > 6000000)
+   {
+        MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
+                                                     { 50, 1000 }, {166, 1000}};
+        mmal_port_parameter_set(still_port, &fps_range.hdr);
+   }
+   else if(state->camera_parameters.shutter_speed > 1000000)
+   {
+        MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
+                                                     { 167, 1000 }, {999, 1000}};
+        mmal_port_parameter_set(still_port, &fps_range.hdr);
+   }
+   // Set our stills format on the stills (for encoder) port
+   format->encoding = MMAL_ENCODING_OPAQUE;
+   format->es->video.width = VCOS_ALIGN_UP(state->width, 32);
+   format->es->video.height = VCOS_ALIGN_UP(state->height, 16);
+   format->es->video.crop.x = 0;
+   format->es->video.crop.y = 0;
+   format->es->video.crop.width = state->width;
+   format->es->video.crop.height = state->height;
+   format->es->video.frame_rate.num = STILLS_FRAME_RATE_NUM;
+   format->es->video.frame_rate.den = STILLS_FRAME_RATE_DEN;
+
+
+   status = mmal_port_format_commit(still_port);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("camera still format couldn't be set");
+      goto error;
+   }
+
+   /* Ensure there are enough buffers to avoid dropping frames */
+   if (still_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
+      still_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
+
+   /* Enable component */
+   status = mmal_component_enable(camera);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("camera component couldn't be enabled");
+      goto error;
+   }
+
+   if (state->useGL)
+   {
+      status = raspitex_configure_preview_port(&state->raspitex_state, preview_port);
+      if (status != MMAL_SUCCESS)
+      {
+         fprintf(stderr, "Failed to configure preview port for GL rendering");
+         goto error;
+      }
+   }
+
+   state->camera_component = camera;
+
+   if (state->verbose)
+      fprintf(stderr, "Camera component done\n");
+
+   return status;
+
+error:
+
+   if (camera)
+      mmal_component_destroy(camera);
+
+   return status;
+}
+
+/**
+ * Destroy the camera component
+ *
+ * @param state Pointer to state control struct
+ *
+ */
+static void destroy_camera_component(RASPISTILL_STATE *state)
+{
+   if (state->camera_component)
+   {
+      mmal_component_destroy(state->camera_component);
+      state->camera_component = NULL;
+   }
+}
+
+/**
+ * Create the encoder component, set up its ports
+ *
+ * @param state Pointer to state control struct. encoder_component member set to the created camera_component if successful.
+ *
+ * @return a MMAL_STATUS, MMAL_SUCCESS if all OK, something else otherwise
+ */
+static MMAL_STATUS_T create_encoder_component(RASPISTILL_STATE *state)
+{
+   MMAL_COMPONENT_T *encoder = 0;
+   MMAL_PORT_T *encoder_input = NULL, *encoder_output = NULL;
+   MMAL_STATUS_T status;
+   MMAL_POOL_T *pool;
+
+   status = mmal_component_create(MMAL_COMPONENT_DEFAULT_IMAGE_ENCODER, &encoder);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Unable to create JPEG encoder component");
+      goto error;
+   }
+
+   if (!encoder->input_num || !encoder->output_num)
+   {
+      status = MMAL_ENOSYS;
+      vcos_log_error("JPEG encoder doesn't have input/output ports");
+      goto error;
+   }
+
+   encoder_input = encoder->input[0];
+   encoder_output = encoder->output[0];
+
+   // We want same format on input and output
+   mmal_format_copy(encoder_output->format, encoder_input->format);
+
+   // Specify out output format
+   encoder_output->format->encoding = state->encoding;
+
+   encoder_output->buffer_size = encoder_output->buffer_size_recommended;
+
+   if (encoder_output->buffer_size < encoder_output->buffer_size_min)
+      encoder_output->buffer_size = encoder_output->buffer_size_min;
+
+   encoder_output->buffer_num = encoder_output->buffer_num_recommended;
+
+   if (encoder_output->buffer_num < encoder_output->buffer_num_min)
+      encoder_output->buffer_num = encoder_output->buffer_num_min;
+
+   // Commit the port changes to the output port
+   status = mmal_port_format_commit(encoder_output);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Unable to set format on video encoder output port");
+      goto error;
+   }
+
+   // Set the JPEG quality level
+   status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_JPEG_Q_FACTOR, state->quality);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Unable to set JPEG quality");
+      goto error;
+   }
+
+   // Set the JPEG restart interval
+   status = mmal_port_parameter_set_uint32(encoder_output, MMAL_PARAMETER_JPEG_RESTART_INTERVAL, state->restart_interval);
+
+   if (state->restart_interval && status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Unable to set JPEG restart interval");
+      goto error;
+   }
+
+   // Set up any required thumbnail
+   {
+      MMAL_PARAMETER_THUMBNAIL_CONFIG_T param_thumb = {{MMAL_PARAMETER_THUMBNAIL_CONFIGURATION, sizeof(MMAL_PARAMETER_THUMBNAIL_CONFIG_T)}, 0, 0, 0, 0};
+
+      if ( state->thumbnailConfig.enable &&
+           state->thumbnailConfig.width > 0 && state->thumbnailConfig.height > 0 )
+      {
+         // Have a valid thumbnail defined
+         param_thumb.enable = 1;
+         param_thumb.width = state->thumbnailConfig.width;
+         param_thumb.height = state->thumbnailConfig.height;
+         param_thumb.quality = state->thumbnailConfig.quality;
+      }
+      status = mmal_port_parameter_set(encoder->control, &param_thumb.hdr);
+   }
+
+   //  Enable component
+   status = mmal_component_enable(encoder);
+
+   if (status  != MMAL_SUCCESS)
+   {
+      vcos_log_error("Unable to enable video encoder component");
+      goto error;
+   }
+
+   /* Create pool of buffer headers for the output port to consume */
+   pool = mmal_port_pool_create(encoder_output, encoder_output->buffer_num, encoder_output->buffer_size);
+
+   if (!pool)
+   {
+      vcos_log_error("Failed to create buffer header pool for encoder output port %s", encoder_output->name);
+   }
+
+   state->encoder_pool = pool;
+   state->encoder_component = encoder;
+
+   if (state->verbose)
+      fprintf(stderr, "Encoder component done\n");
+
+   return status;
+
+   error:
+
+   if (encoder)
+      mmal_component_destroy(encoder);
+
+   return status;
+}
+
+/**
+ * Destroy the encoder component
+ *
+ * @param state Pointer to state control struct
+ *
+ */
+static void destroy_encoder_component(RASPISTILL_STATE *state)
+{
+   // Get rid of any port buffers first
+   if (state->encoder_pool)
+   {
+      mmal_port_pool_destroy(state->encoder_component->output[0], state->encoder_pool);
+   }
+
+   if (state->encoder_component)
+   {
+      mmal_component_destroy(state->encoder_component);
+      state->encoder_component = NULL;
+   }
+}
+
+
+/**
+ * Add an exif tag to the capture
+ *
+ * @param state Pointer to state control struct
+ * @param exif_tag String containing a "key=value" pair.
+ * @return  Returns a MMAL_STATUS_T giving result of operation
+ */
+static MMAL_STATUS_T add_exif_tag(RASPISTILL_STATE *state, const char *exif_tag)
+{
+   MMAL_STATUS_T status;
+   MMAL_PARAMETER_EXIF_T *exif_param = (MMAL_PARAMETER_EXIF_T*)calloc(sizeof(MMAL_PARAMETER_EXIF_T) + MAX_EXIF_PAYLOAD_LENGTH, 1);
+
+   vcos_assert(state);
+   vcos_assert(state->encoder_component);
+
+   // Check to see if the tag is present or is indeed a key=value pair.
+   if (!exif_tag || strchr(exif_tag, '=') == NULL || strlen(exif_tag) > MAX_EXIF_PAYLOAD_LENGTH-1)
+      return MMAL_EINVAL;
+
+   exif_param->hdr.id = MMAL_PARAMETER_EXIF;
+
+   strncpy((char*)exif_param->data, exif_tag, MAX_EXIF_PAYLOAD_LENGTH-1);
+
+   exif_param->hdr.size = sizeof(MMAL_PARAMETER_EXIF_T) + strlen((char*)exif_param->data);
+
+   status = mmal_port_parameter_set(state->encoder_component->output[0], &exif_param->hdr);
+
+   free(exif_param);
+
+   return status;
+}
+
+/**
+ * Add a basic set of EXIF tags to the capture
+ * Make, Time etc
+ *
+ * @param state Pointer to state control struct
+ *
+ */
+static void add_exif_tags(RASPISTILL_STATE *state)
+{
+   time_t rawtime;
+   struct tm *timeinfo;
+   char model_buf[32];
+   char time_buf[32];
+   char exif_buf[128];
+   int i;
+
+
+   snprintf(model_buf, 32, "IFD0.Model=RP_%s", state->camera_name);
+   add_exif_tag(state, model_buf);
+   add_exif_tag(state, "IFD0.Make=RaspberryPi");
+
+   time(&rawtime);
+   timeinfo = localtime(&rawtime);
+
+   snprintf(time_buf, sizeof(time_buf),
+            "%04d:%02d:%02d %02d:%02d:%02d",
+            timeinfo->tm_year+1900,
+            timeinfo->tm_mon+1,
+            timeinfo->tm_mday,
+            timeinfo->tm_hour,
+            timeinfo->tm_min,
+            timeinfo->tm_sec);
+
+   snprintf(exif_buf, sizeof(exif_buf), "EXIF.DateTimeDigitized=%s", time_buf);
+   add_exif_tag(state, exif_buf);
+
+   snprintf(exif_buf, sizeof(exif_buf), "EXIF.DateTimeOriginal=%s", time_buf);
+   add_exif_tag(state, exif_buf);
+
+   snprintf(exif_buf, sizeof(exif_buf), "IFD0.DateTime=%s", time_buf);
+   add_exif_tag(state, exif_buf);
+
+   // Now send any user supplied tags
+
+   for (i=0;i<state->numExifTags && i < MAX_USER_EXIF_TAGS;i++)
+   {
+      if (state->exifTags[i])
+      {
+         add_exif_tag(state, state->exifTags[i]);
+      }
+   }
+}
+
+/**
+ * Stores an EXIF tag in the state, incrementing various pointers as necessary.
+ * Any tags stored in this way will be added to the image file when add_exif_tags
+ * is called
+ *
+ * Will not store if run out of storage space
+ *
+ * @param state Pointer to state control struct
+ * @param exif_tag EXIF tag string
+ *
+ */
+static void store_exif_tag(RASPISTILL_STATE *state, const char *exif_tag)
+{
+   if (state->numExifTags < MAX_USER_EXIF_TAGS)
+   {
+      state->exifTags[state->numExifTags] = exif_tag;
+      state->numExifTags++;
+   }
+}
+
+/**
+ * Connect two specific ports together
+ *
+ * @param output_port Pointer the output port
+ * @param input_port Pointer the input port
+ * @param Pointer to a mmal connection pointer, reassigned if function successful
+ * @return Returns a MMAL_STATUS_T giving result of operation
+ *
+ */
+static MMAL_STATUS_T connect_ports(MMAL_PORT_T *output_port, MMAL_PORT_T *input_port, MMAL_CONNECTION_T **connection)
+{
+   MMAL_STATUS_T status;
+
+   status =  mmal_connection_create(connection, output_port, input_port, MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT);
+
+   if (status == MMAL_SUCCESS)
+   {
+      status =  mmal_connection_enable(*connection);
+      if (status != MMAL_SUCCESS)
+         mmal_connection_destroy(*connection);
+   }
+
+   return status;
+}
+
+
+/**
+ * Allocates and generates a filename based on the
+ * user-supplied pattern and the frame number.
+ * On successful return, finalName and tempName point to malloc()ed strings
+ * which must be freed externally.  (On failure, returns nulls that
+ * don't need free()ing.)
+ *
+ * @param finalName pointer receives an
+ * @param pattern sprintf pattern with %d to be replaced by frame
+ * @param frame for timelapse, the frame number
+ * @return Returns a MMAL_STATUS_T giving result of operation
+*/
+
+MMAL_STATUS_T create_filenames(char** finalName, char** tempName, char * pattern, int frame)
+{
+   *finalName = NULL;
+   *tempName = NULL;
+   if (0 > asprintf(finalName, pattern, frame) ||
+       0 > asprintf(tempName, "%s~", *finalName))
+   {
+      if (*finalName != NULL)
+      {
+         free(*finalName);
+      }
+      return MMAL_ENOMEM;    // It may be some other error, but it is not worth getting it right
+   }
+   return MMAL_SUCCESS;
+}
+
+/**
+ * Checks if specified port is valid and enabled, then disables it
+ *
+ * @param port  Pointer the port
+ *
+ */
+static void check_disable_port(MMAL_PORT_T *port)
+{
+   if (port && port->is_enabled)
+      mmal_port_disable(port);
+}
+
+/**
+ * Handler for sigint signals
+ *
+ * @param signal_number ID of incoming signal.
+ *
+ */
+static void signal_handler(int signal_number)
+{
+   if (signal_number == SIGUSR1 || signal_number == SIGUSR2)
+   {
+      // Handle but ignore - prevents us dropping out if started in none-signal mode
+      // and someone sends us the USR1 or USR2 signal anyway
+   }
+   else
+   {
+      // Going to abort on all other signals
+      vcos_log_error("Aborting program\n");
+      exit(130);
+   }
+}
+
+
+/**
+ * Function to wait in various ways (depending on settings) for the next frame
+ *
+ * @param state Pointer to the state data
+ * @param [in][out] frame The last frame number, adjusted to next frame number on output
+ * @return !0 if to continue, 0 if reached end of run
+ */
+static int wait_for_next_frame(RASPISTILL_STATE *state, int *frame)
+{
+   static int64_t complete_time = -1;
+   int keep_running = 1;
+
+   int64_t current_time =  vcos_getmicrosecs64()/1000;
+
+   if (complete_time == -1)
+      complete_time =  current_time + state->timeout;
+
+   // if we have run out of time, flag we need to exit
+   // If timeout = 0 then always continue
+   if (current_time >= complete_time && state->timeout != 0)
+      keep_running = 0;
+
+   switch (state->frameNextMethod)
+   {
+   case FRAME_NEXT_SINGLE :
+      // simple timeout for a single capture
+      vcos_sleep(state->timeout);
+      return 0;
+
+   case FRAME_NEXT_FOREVER :
+   {
+      *frame+=1;
+
+      // Have a sleep so we don't hog the CPU.
+      vcos_sleep(10000);
+
+      // Run forever so never indicate end of loop
+      return 1;
+   }
+
+   case FRAME_NEXT_TIMELAPSE :
+   {
+      static int64_t next_frame_ms = -1;
+
+      // Always need to increment by at least one, may add a skip later
+      *frame += 1;
+
+      if (next_frame_ms == -1)
+      {
+         vcos_sleep(state->timelapse);
+
+         // Update our current time after the sleep
+         current_time =  vcos_getmicrosecs64()/1000;
+
+         // Set our initial 'next frame time'
+         next_frame_ms = current_time + state->timelapse;
+      }
+      else
+      {
+         int64_t this_delay_ms = next_frame_ms - current_time;
+
+         if (this_delay_ms < 0)
+         {
+            // We are already past the next exposure time
+            if (-this_delay_ms < state->timelapse/2)
+            {
+               // Less than a half frame late, take a frame and hope to catch up next time
+               next_frame_ms += state->timelapse;
+               vcos_log_error("Frame %d is %d ms late", *frame, (int)(-this_delay_ms));
+            }
+            else
+            {
+               int nskip = 1 + (-this_delay_ms)/state->timelapse;
+               vcos_log_error("Skipping frame %d to restart at frame %d", *frame, *frame+nskip);
+               *frame += nskip;
+               this_delay_ms += nskip * state->timelapse;
+               vcos_sleep(this_delay_ms);
+               next_frame_ms += (nskip + 1) * state->timelapse;
+            }
+         }
+         else
+         {
+            vcos_sleep(this_delay_ms);
+            next_frame_ms += state->timelapse;
+         }
+      }
+
+      return keep_running;
+   }
+
+   case FRAME_NEXT_KEYPRESS :
+   {
+       int ch;
+
+       if (state->verbose)
+         fprintf(stderr, "Press Enter to capture, X then ENTER to exit\n");
+
+       ch = getchar();
+       *frame+=1;
+       if (ch == 'x' || ch == 'X')
+          return 0;
+       else
+       {
+             return keep_running;
+       }
+   }
+
+   case FRAME_NEXT_IMMEDIATELY :
+   {
+      // Not waiting, just go to next frame.
+      // Actually, we do need a slight delay here otherwise exposure goes
+      // badly wrong since we never allow it frames to work it out
+      // This could probably be tuned down.
+      // First frame has a much longer delay to ensure we get exposure to a steady state
+      if (*frame == 0)
+         vcos_sleep(1000);
+      else
+         vcos_sleep(30);
+
+      *frame+=1;
+
+      return keep_running;
+   }
+
+   case FRAME_NEXT_GPIO :
+   {
+       // Intended for GPIO firing of a capture
+      return 0;
+   }
+
+   case FRAME_NEXT_SIGNAL :
+   {
+      // Need to wait for a SIGUSR1 or SIGUSR2 signal
+      sigset_t waitset;
+      int sig;
+      int result = 0;
+
+      sigemptyset( &waitset );
+      sigaddset( &waitset, SIGUSR1 );
+      sigaddset( &waitset, SIGUSR2 );
+
+      // We are multi threaded because we use mmal, so need to use the pthread
+      // variant of procmask to block until a SIGUSR1 or SIGUSR2 signal appears
+      pthread_sigmask( SIG_BLOCK, &waitset, NULL );
+
+      if (state->verbose)
+      {
+         fprintf(stderr, "Waiting for SIGUSR1 to initiate capture and continue or SIGUSR2 to capture and exit\n");
+      }
+
+      result = sigwait( &waitset, &sig );
+
+      if (result == 0)
+      {
+         if (sig == SIGUSR1)
+         {
+            if (state->verbose)
+               fprintf(stderr, "Received SIGUSR1\n");
+         }
+         else if (sig == SIGUSR2)
+         {
+            if (state->verbose)
+               fprintf(stderr, "Received SIGUSR2\n");
+            keep_running = 0;
+         }
+      }
+      else
+      {
+         if (state->verbose)
+            fprintf(stderr, "Bad signal received - error %d\n", errno);
+      }
+
+      *frame+=1;
+
+      return keep_running;
+   }
+   } // end of switch
+
+   // Should have returned by now, but default to timeout
+   return keep_running;
+}
+
+static void rename_file(RASPISTILL_STATE *state, FILE *output_file,
+      const char *final_filename, const char *use_filename, int frame)
+{
+   MMAL_STATUS_T status;
+
+   fclose(output_file);
+   vcos_assert(use_filename != NULL && final_filename != NULL);
+   if (0 != rename(use_filename, final_filename))
+   {
+      vcos_log_error("Could not rename temp file to: %s; %s",
+            final_filename,strerror(errno));
+   }
+   if (state->linkname)
+   {
+      char *use_link;
+      char *final_link;
+      status = create_filenames(&final_link, &use_link, state->linkname, frame);
+
+      // Create hard link if possible, symlink otherwise
+      if (status != MMAL_SUCCESS
+            || (0 != link(final_filename, use_link)
+               &&  0 != symlink(final_filename, use_link))
+            || 0 != rename(use_link, final_link))
+      {
+         vcos_log_error("Could not link as filename: %s; %s",
+               state->linkname,strerror(errno));
+      }
+      if (use_link) free(use_link);
+      if (final_link) free(final_link);
+   }
+}
+
+/**
+ * main
+ */
+int main(int argc, const char **argv)
+{
+   // Our main data storage vessel..
+   RASPISTILL_STATE state = {0};
+   int exit_code = EX_OK;
+
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   MMAL_PORT_T *camera_preview_port = NULL;
+   MMAL_PORT_T *camera_video_port = NULL;
+   MMAL_PORT_T *camera_still_port = NULL;
+   MMAL_PORT_T *preview_input_port = NULL;
+   MMAL_PORT_T *encoder_input_port = NULL;
+   MMAL_PORT_T *encoder_output_port = NULL;
+
+   bcm_host_init();
+
+   // Register our application with the logging system
+   vcos_log_register("RaspiStill", VCOS_LOG_CATEGORY);
+
+   signal(SIGINT, signal_handler);
+
+   // Disable USR1 and USR2 for the moment - may be reenabled if go in to signal capture mode
+   signal(SIGUSR1, SIG_IGN);
+   signal(SIGUSR2, SIG_IGN);
+
+   default_status(&state);
+
+   // Do we have any parameters
+   if (argc == 1)
+   {
+      fprintf(stdout, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING);
+
+      display_valid_parameters(basename(argv[0]));
+      exit(EX_USAGE);
+   }
+
+   // Parse the command line and put options in to our status structure
+   if (parse_cmdline(argc, argv, &state))
+   {
+      exit(EX_USAGE);
+   }
+
+   // Setup for sensor specific parameters
+   set_sensor_defaults(&state);
+
+   if (state.verbose)
+   {
+      fprintf(stderr, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING);
+
+      dump_status(&state);
+   }
+
+   if (state.useGL)
+      raspitex_init(&state.raspitex_state);
+
+   // OK, we have a nice set of parameters. Now set up our components
+   // We have three components. Camera, Preview and encoder.
+   // Camera and encoder are different in stills/video, but preview
+   // is the same so handed off to a separate module
+
+   if ((status = create_camera_component(&state)) != MMAL_SUCCESS)
+   {
+      vcos_log_error("%s: Failed to create camera component", __func__);
+      exit_code = EX_SOFTWARE;
+   }
+   else if ((!state.useGL) && (status = raspipreview_create(&state.preview_parameters)) != MMAL_SUCCESS)
+   {
+      vcos_log_error("%s: Failed to create preview component", __func__);
+      destroy_camera_component(&state);
+      exit_code = EX_SOFTWARE;
+   }
+   else if ((status = create_encoder_component(&state)) != MMAL_SUCCESS)
+   {
+      vcos_log_error("%s: Failed to create encode component", __func__);
+      raspipreview_destroy(&state.preview_parameters);
+      destroy_camera_component(&state);
+      exit_code = EX_SOFTWARE;
+   }
+   else
+   {
+      PORT_USERDATA callback_data;
+
+      if (state.verbose)
+         fprintf(stderr, "Starting component connection stage\n");
+
+      camera_preview_port = state.camera_component->output[MMAL_CAMERA_PREVIEW_PORT];
+      camera_video_port   = state.camera_component->output[MMAL_CAMERA_VIDEO_PORT];
+      camera_still_port   = state.camera_component->output[MMAL_CAMERA_CAPTURE_PORT];
+      encoder_input_port  = state.encoder_component->input[0];
+      encoder_output_port = state.encoder_component->output[0];
+
+      if (! state.useGL)
+      {
+         if (state.verbose)
+            fprintf(stderr, "Connecting camera preview port to video render.\n");
+
+         // Note we are lucky that the preview and null sink components use the same input port
+         // so we can simple do this without conditionals
+         preview_input_port  = state.preview_parameters.preview_component->input[0];
+
+         // Connect camera to preview (which might be a null_sink if no preview required)
+         status = connect_ports(camera_preview_port, preview_input_port, &state.preview_connection);
+      }
+
+      if (status == MMAL_SUCCESS)
+      {
+         VCOS_STATUS_T vcos_status;
+
+         if (state.verbose)
+            fprintf(stderr, "Connecting camera stills port to encoder input port\n");
+
+         // Now connect the camera to the encoder
+         status = connect_ports(camera_still_port, encoder_input_port, &state.encoder_connection);
+
+         if (status != MMAL_SUCCESS)
+         {
+            vcos_log_error("%s: Failed to connect camera video port to encoder input", __func__);
+            goto error;
+         }
+
+         // Set up our userdata - this is passed though to the callback where we need the information.
+         // Null until we open our filename
+         callback_data.file_handle = NULL;
+         callback_data.pstate = &state;
+         vcos_status = vcos_semaphore_create(&callback_data.complete_semaphore, "RaspiStill-sem", 0);
+
+         vcos_assert(vcos_status == VCOS_SUCCESS);
+
+         /* If GL preview is requested then start the GL threads */
+         if (state.useGL && (raspitex_start(&state.raspitex_state) != 0))
+            goto error;
+
+         if (status != MMAL_SUCCESS)
+         {
+            vcos_log_error("Failed to setup encoder output");
+            goto error;
+         }
+
+         if (state.demoMode)
+         {
+            // Run for the user specific time..
+            int num_iterations = state.timeout / state.demoInterval;
+            int i;
+            for (i=0;i<num_iterations;i++)
+            {
+               raspicamcontrol_cycle_test(state.camera_component);
+               vcos_sleep(state.demoInterval);
+            }
+         }
+         else
+         {
+            int frame, keep_looping = 1;
+            FILE *output_file = NULL;
+            char *use_filename = NULL;      // Temporary filename while image being written
+            char *final_filename = NULL;    // Name that file gets once writing complete
+
+            frame = state.frameStart - 1;
+
+            while (keep_looping)
+            {
+               keep_looping = wait_for_next_frame(&state, &frame);
+
+                if (state.datetime)
+                {
+                   time_t rawtime;
+                   struct tm *timeinfo;
+
+                   time(&rawtime);
+                   timeinfo = localtime(&rawtime);
+
+                   frame = timeinfo->tm_mon+1;
+                   frame *= 100;
+                   frame += timeinfo->tm_mday;
+                   frame *= 100;
+                   frame += timeinfo->tm_hour;
+                   frame *= 100;
+                   frame += timeinfo->tm_min;
+                   frame *= 100;
+                   frame += timeinfo->tm_sec;
+                }
+                if (state.timestamp)
+                {
+                   frame = (int)time(NULL);
+                }
+
+               // Open the file
+               if (state.filename)
+               {
+                  if (state.filename[0] == '-')
+                  {
+                     output_file = stdout;
+
+                     // Ensure we don't upset the output stream with diagnostics/info
+                     state.verbose = 0;
+                  }
+                  else
+                  {
+                     vcos_assert(use_filename == NULL && final_filename == NULL);
+                     status = create_filenames(&final_filename, &use_filename, state.filename, frame);
+                     if (status  != MMAL_SUCCESS)
+                     {
+                        vcos_log_error("Unable to create filenames");
+                        goto error;
+                     }
+
+                     if (state.verbose)
+                        fprintf(stderr, "Opening output file %s\n", final_filename);
+                        // Technically it is opening the temp~ filename which will be ranamed to the final filename
+
+                     output_file = fopen(use_filename, "wb");
+
+                     if (!output_file)
+                     {
+                        // Notify user, carry on but discarding encoded output buffers
+                        vcos_log_error("%s: Error opening output file: %s\nNo output file will be generated\n", __func__, use_filename);
+                     }
+                  }
+
+                  callback_data.file_handle = output_file;
+               }
+
+               // We only capture if a filename was specified and it opened
+               if (state.useGL && state.glCapture && output_file)
+               {
+                  /* Save the next GL framebuffer as the next camera still */
+                  int rc = raspitex_capture(&state.raspitex_state, output_file);
+                  if (rc != 0)
+                     vcos_log_error("Failed to capture GL preview");
+                  rename_file(&state, output_file, final_filename, use_filename, frame);
+               }
+               else if (output_file)
+               {
+                  int num, q;
+
+                  // Must do this before the encoder output port is enabled since
+                  // once enabled no further exif data is accepted
+                  if ( state.enableExifTags )
+                  {
+                     add_exif_tags(&state);
+                  }
+                  else
+                  {
+                     mmal_port_parameter_set_boolean(
+                        state.encoder_component->output[0], MMAL_PARAMETER_EXIF_DISABLE, 1);
+                  }
+
+                  // Same with raw, apparently need to set it for each capture, whilst port
+                  // is not enabled
+                  if (state.wantRAW)
+                  {
+                     if (mmal_port_parameter_set_boolean(camera_still_port, MMAL_PARAMETER_ENABLE_RAW_CAPTURE, 1) != MMAL_SUCCESS)
+                     {
+                        vcos_log_error("RAW was requested, but failed to enable");
+                     }
+                  }
+
+                  // There is a possibility that shutter needs to be set each loop.
+                  if (mmal_status_to_int(mmal_port_parameter_set_uint32(state.camera_component->control, MMAL_PARAMETER_SHUTTER_SPEED, state.camera_parameters.shutter_speed)) != MMAL_SUCCESS)
+                     vcos_log_error("Unable to set shutter speed");
+
+
+                  // Enable the encoder output port
+                  encoder_output_port->userdata = (struct MMAL_PORT_USERDATA_T *)&callback_data;
+
+                  if (state.verbose)
+                     fprintf(stderr, "Enabling encoder output port\n");
+
+                  // Enable the encoder output port and tell it its callback function
+                  status = mmal_port_enable(encoder_output_port, encoder_buffer_callback);
+
+                  // Send all the buffers to the encoder output port
+                  num = mmal_queue_length(state.encoder_pool->queue);
+
+                  for (q=0;q<num;q++)
+                  {
+                     MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state.encoder_pool->queue);
+
+                     if (!buffer)
+                        vcos_log_error("Unable to get a required buffer %d from pool queue", q);
+
+                     if (mmal_port_send_buffer(encoder_output_port, buffer)!= MMAL_SUCCESS)
+                        vcos_log_error("Unable to send a buffer to encoder output port (%d)", q);
+                  }
+
+                  if (state.burstCaptureMode && frame==1)
+                  {
+                     mmal_port_parameter_set_boolean(state.camera_component->control,  MMAL_PARAMETER_CAMERA_BURST_CAPTURE, 1);
+                  }
+
+                  if(state.camera_parameters.enable_annotate)
+                     raspicamcontrol_set_annotate(state.camera_component, state.camera_parameters.enable_annotate, 
+                                      state.camera_parameters.annotate_string,
+                                      state.camera_parameters.annotate_text_size,
+                                      state.camera_parameters.annotate_text_colour,
+                                      state.camera_parameters.annotate_bg_colour);
+
+                  if (state.verbose)
+                     fprintf(stderr, "Starting capture %d\n", frame);
+
+                  if (mmal_port_parameter_set_boolean(camera_still_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS)
+                  {
+                     vcos_log_error("%s: Failed to start capture", __func__);
+                  }
+                  else
+                  {
+                     // Wait for capture to complete
+                     // For some reason using vcos_semaphore_wait_timeout sometimes returns immediately with bad parameter error
+                     // even though it appears to be all correct, so reverting to untimed one until figure out why its erratic
+                     vcos_semaphore_wait(&callback_data.complete_semaphore);
+                     if (state.verbose)
+                        fprintf(stderr, "Finished capture %d\n", frame);
+                  }
+
+                  // Ensure we don't die if get callback with no open file
+                  callback_data.file_handle = NULL;
+
+                  if (output_file != stdout)
+                  {
+                     rename_file(&state, output_file, final_filename, use_filename, frame);
+                  }
+                  else
+                  {
+                     fflush(output_file);
+                  }
+                  // Disable encoder output port
+                  status = mmal_port_disable(encoder_output_port);
+               }
+
+               if (use_filename)
+               {
+                  free(use_filename);
+                  use_filename = NULL;
+               }
+               if (final_filename)
+               {
+                  free(final_filename);
+                  final_filename = NULL;
+               }
+            } // end for (frame)
+
+            vcos_semaphore_delete(&callback_data.complete_semaphore);
+         }
+      }
+      else
+      {
+         mmal_status_to_int(status);
+         vcos_log_error("%s: Failed to connect camera to preview", __func__);
+      }
+
+error:
+
+      mmal_status_to_int(status);
+
+      if (state.verbose)
+         fprintf(stderr, "Closing down\n");
+
+      if (state.useGL)
+      {
+         raspitex_stop(&state.raspitex_state);
+         raspitex_destroy(&state.raspitex_state);
+      }
+
+      // Disable all our ports that are not handled by connections
+      check_disable_port(camera_video_port);
+      check_disable_port(encoder_output_port);
+
+      if (state.preview_connection)
+         mmal_connection_destroy(state.preview_connection);
+
+      if (state.encoder_connection)
+         mmal_connection_destroy(state.encoder_connection);
+
+
+      /* Disable components */
+      if (state.encoder_component)
+         mmal_component_disable(state.encoder_component);
+
+      if (state.preview_parameters.preview_component)
+         mmal_component_disable(state.preview_parameters.preview_component);
+
+      if (state.camera_component)
+         mmal_component_disable(state.camera_component);
+
+      destroy_encoder_component(&state);
+      raspipreview_destroy(&state.preview_parameters);
+      destroy_camera_component(&state);
+
+      if (state.verbose)
+         fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n");
+   }
+
+   if (status != MMAL_SUCCESS)
+      raspicamcontrol_check_configuration(128);
+
+   return exit_code;
+}
+
+
diff --git a/host_applications/linux/apps/raspicam/RaspiStillYUV.c b/host_applications/linux/apps/raspicam/RaspiStillYUV.c
new file mode 100755 (executable)
index 0000000..ac178a3
--- /dev/null
@@ -0,0 +1,1472 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, James Hughes
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * \file RaspiStillYUV.c
+ * Command line program to capture a still frame and dump uncompressed it to file.
+ * Also optionally display a preview/viewfinder of current camera input.
+ *
+ * \date 4th March 2013
+ * \Author: James Hughes
+ *
+ * Description
+ *
+ * 2 components are created; camera and preview.
+ * Camera component has three ports, preview, video and stills.
+ * Preview is connected using standard mmal connections, the stills output
+ * is written straight to the file in YUV 420 format via the requisite buffer
+ * callback. video port is not used
+ *
+ * We use the RaspiCamControl code to handle the specific camera settings.
+ * We use the RaspiPreview code to handle the generic preview
+ */
+
+// We use some GNU extensions (basename)
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <sysexits.h>
+#include <unistd.h>
+#include <errno.h>
+
+#define VERSION_STRING "v1.3.7"
+
+#include "bcm_host.h"
+#include "interface/vcos/vcos.h"
+
+#include "interface/mmal/mmal.h"
+#include "interface/mmal/mmal_logging.h"
+#include "interface/mmal/mmal_buffer.h"
+#include "interface/mmal/util/mmal_util.h"
+#include "interface/mmal/util/mmal_util_params.h"
+#include "interface/mmal/util/mmal_default_components.h"
+#include "interface/mmal/util/mmal_connection.h"
+
+
+#include "RaspiCamControl.h"
+#include "RaspiPreview.h"
+#include "RaspiCLI.h"
+
+#include <semaphore.h>
+
+// Standard port setting for the camera component
+#define MMAL_CAMERA_PREVIEW_PORT 0
+#define MMAL_CAMERA_VIDEO_PORT 1
+#define MMAL_CAMERA_CAPTURE_PORT 2
+
+
+// Stills format information
+// 0 implies variable
+#define STILLS_FRAME_RATE_NUM 0
+#define STILLS_FRAME_RATE_DEN 1
+
+/// Video render needs at least 2 buffers.
+#define VIDEO_OUTPUT_BUFFERS_NUM 3
+
+/// Frame advance method
+#define FRAME_NEXT_SINGLE        0
+#define FRAME_NEXT_TIMELAPSE     1
+#define FRAME_NEXT_KEYPRESS      2
+#define FRAME_NEXT_FOREVER       3
+#define FRAME_NEXT_GPIO          4
+#define FRAME_NEXT_SIGNAL        5
+#define FRAME_NEXT_IMMEDIATELY   6
+
+int mmal_status_to_int(MMAL_STATUS_T status);
+static void signal_handler(int signal_number);
+
+/** Structure containing all state information for the current run
+ */
+typedef struct
+{
+   int timeout;                        /// Time taken before frame is grabbed and app then shuts down. Units are milliseconds
+   int width;                          /// Requested width of image
+   int height;                         /// requested height of image
+   char *filename;                     /// filename of output file
+   char *linkname;                     /// filename of output file
+   int verbose;                        /// !0 if want detailed run information
+   int timelapse;                      /// Delay between each picture in timelapse mode. If 0, disable timelapse
+   int useRGB;                         /// Output RGB data rather than YUV
+   int fullResPreview;                 /// If set, the camera preview port runs at capture resolution. Reduces fps.
+   int frameNextMethod;                /// Which method to use to advance to next frame
+   int settings;                       /// Request settings from the camera
+   int cameraNum;                      /// Camera number
+   int burstCaptureMode;               /// Enable burst mode
+   int onlyLuma;                       /// Only output the luma / Y plane of the YUV data
+
+   RASPIPREVIEW_PARAMETERS preview_parameters;    /// Preview setup parameters
+   RASPICAM_CAMERA_PARAMETERS camera_parameters; /// Camera setup parameters
+
+   MMAL_COMPONENT_T *camera_component;    /// Pointer to the camera component
+   MMAL_COMPONENT_T *null_sink_component;    /// Pointer to the camera component
+   MMAL_CONNECTION_T *preview_connection; /// Pointer to the connection from camera to preview
+   MMAL_POOL_T *camera_pool;              /// Pointer to the pool of buffers used by camera stills port
+} RASPISTILLYUV_STATE;
+
+
+/** Struct used to pass information in camera still port userdata to callback
+ */
+typedef struct
+{
+   FILE *file_handle;                   /// File handle to write buffer data to.
+   VCOS_SEMAPHORE_T complete_semaphore; /// semaphore which is posted when we reach end of frame (indicates end of capture or fault)
+   RASPISTILLYUV_STATE *pstate;            /// pointer to our state in case required in callback
+} PORT_USERDATA;
+
+static void display_valid_parameters(char *app_name);
+
+/// Comamnd ID's and Structure defining our command line options
+#define CommandHelp         0
+#define CommandWidth        1
+#define CommandHeight       2
+#define CommandOutput       3
+#define CommandVerbose      4
+#define CommandTimeout      5
+#define CommandTimelapse    6
+#define CommandUseRGB       7
+#define CommandCamSelect    8
+#define CommandFullResPreview 9
+#define CommandLink         10
+#define CommandKeypress     11
+#define CommandSignal       12
+#define CommandSettings     13
+#define CommandBurstMode    14
+#define CommandOnlyLuma     15
+
+static COMMAND_LIST cmdline_commands[] =
+{
+   { CommandHelp,    "-help",       "?",  "This help information", 0 },
+   { CommandWidth,   "-width",      "w",  "Set image width <size>", 1 },
+   { CommandHeight,  "-height",     "h",  "Set image height <size>", 1 },
+   { CommandOutput,  "-output",     "o",  "Output filename <filename>. If not specifed, no image is saved", 1 },
+   { CommandVerbose, "-verbose",    "v",  "Output verbose information during run", 0 },
+   { CommandTimeout, "-timeout",    "t",  "Time (in ms) before takes picture and shuts down. If not specified set to 5s", 1 },
+   { CommandTimelapse,"-timelapse", "tl", "Timelapse mode. Takes a picture every <t>ms", 1},
+   { CommandUseRGB,  "-rgb",        "rgb","Save as RGB data rather than YUV", 0},
+   { CommandCamSelect,"-camselect", "cs", "Select camera <number>. Default 0", 1 },
+   { CommandFullResPreview,"-fullpreview","fp", "Run the preview using the still capture resolution (may reduce preview fps)", 0},
+   { CommandLink,    "-latest",     "l",  "Link latest complete image to filename <filename>", 1},
+   { CommandKeypress,"-keypress",   "k",  "Wait between captures for a ENTER, X then ENTER to exit", 0},
+   { CommandSignal,  "-signal",     "s",  "Wait between captures for a SIGUSR1 from another process", 0},
+   { CommandSettings, "-settings",  "set","Retrieve camera settings and write to stdout", 0},
+   { CommandBurstMode, "-burst",    "bm", "Enable 'burst capture mode'", 0},
+   { CommandOnlyLuma,  "-luma",     "y",  "Only output the luma / Y of the YUV data'", 0},
+};
+
+static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]);
+
+static struct
+{
+   char *description;
+   int nextFrameMethod;
+} next_frame_description[] =
+{
+      {"Single capture",         FRAME_NEXT_SINGLE},
+      {"Capture on timelapse",   FRAME_NEXT_TIMELAPSE},
+      {"Capture on keypress",    FRAME_NEXT_KEYPRESS},
+      {"Run forever",            FRAME_NEXT_FOREVER},
+      {"Capture on GPIO",        FRAME_NEXT_GPIO},
+      {"Capture on signal",      FRAME_NEXT_SIGNAL},
+};
+
+static int next_frame_description_size = sizeof(next_frame_description) / sizeof(next_frame_description[0]);
+
+/**
+ * Assign a default set of parameters to the state passed in
+ *
+ * @param state Pointer to state structure to assign defaults to
+ */
+static void default_status(RASPISTILLYUV_STATE *state)
+{
+   if (!state)
+   {
+      vcos_assert(0);
+      return;
+   }
+
+   // Default everything to zero
+   memset(state, 0, sizeof(RASPISTILLYUV_STATE));
+
+   // Now set anything non-zero
+   state->timeout = 5000; // 5s delay before take image
+   state->width = 2592;
+   state->height = 1944;
+   state->timelapse = 0;
+   state->filename = NULL;
+   state->linkname = NULL;
+   state->verbose = 0;
+   state->fullResPreview = 0;
+   state->frameNextMethod = FRAME_NEXT_SINGLE;
+   state->settings = 0;
+   state->burstCaptureMode=0;
+   state->onlyLuma = 0;
+
+   // Setup preview window defaults
+   raspipreview_set_defaults(&state->preview_parameters);
+
+   // Set up the camera_parameters to default
+   raspicamcontrol_set_defaults(&state->camera_parameters);
+
+   // Set default camera
+   state->cameraNum = 0;
+}
+
+/**
+ * Dump image state parameters to stderr. Used for debugging
+ *
+ * @param state Pointer to state structure to assign defaults to
+ */
+static void dump_status(RASPISTILLYUV_STATE *state)
+{
+   int i;
+   if (!state)
+   {
+      vcos_assert(0);
+      return;
+   }
+
+   fprintf(stderr, "Width %d, Height %d, filename %s\n", state->width,
+         state->height, state->filename);
+   fprintf(stderr, "Time delay %d, Timelapse %d\n", state->timeout, state->timelapse);
+   fprintf(stderr, "Link to latest frame enabled ");
+   if (state->linkname)
+   {
+      fprintf(stderr, " yes, -> %s\n", state->linkname);
+   }
+   else
+   {
+      fprintf(stderr, " no\n");
+   }
+   fprintf(stderr, "Full resolution preview %s\n", state->fullResPreview ? "Yes": "No");
+
+   fprintf(stderr, "Capture method : ");
+   for (i=0;i<next_frame_description_size;i++)
+   {
+      if (state->frameNextMethod == next_frame_description[i].nextFrameMethod)
+         fprintf(stderr, "%s", next_frame_description[i].description);
+   }
+   fprintf(stderr, "\n\n");
+
+   raspipreview_dump_parameters(&state->preview_parameters);
+   raspicamcontrol_dump_parameters(&state->camera_parameters);
+}
+
+/**
+ * Parse the incoming command line and put resulting parameters in to the state
+ *
+ * @param argc Number of arguments in command line
+ * @param argv Array of pointers to strings from command line
+ * @param state Pointer to state structure to assign any discovered parameters to
+ * @return non-0 if failed for some reason, 0 otherwise
+ */
+static int parse_cmdline(int argc, const char **argv, RASPISTILLYUV_STATE *state)
+{
+   // Parse the command line arguments.
+   // We are looking for --<something> or -<abbreviation of something>
+
+   int valid = 1; // set 0 if we have a bad parameter
+   int i;
+
+   for (i = 1; i < argc && valid; i++)
+   {
+      int command_id, num_parameters;
+
+      if (!argv[i])
+         continue;
+
+      if (argv[i][0] != '-')
+      {
+         valid = 0;
+         continue;
+      }
+
+      // Assume parameter is valid until proven otherwise
+      valid = 1;
+
+      command_id = raspicli_get_command_id(cmdline_commands, cmdline_commands_size, &argv[i][1], &num_parameters);
+
+      // If we found a command but are missing a parameter, continue (and we will drop out of the loop)
+      if (command_id != -1 && num_parameters > 0 && (i + 1 >= argc) )
+         continue;
+
+      //  We are now dealing with a command line option
+      switch (command_id)
+      {
+      case CommandHelp:
+         display_valid_parameters(basename(argv[0]));
+         return -1;
+
+      case CommandWidth: // Width > 0
+         if (sscanf(argv[i + 1], "%u", &state->width) != 1)
+            valid = 0;
+         else
+            i++;
+         break;
+
+      case CommandHeight: // Height > 0
+         if (sscanf(argv[i + 1], "%u", &state->height) != 1)
+            valid = 0;
+         else
+            i++;
+         break;
+
+      case CommandOutput:  // output filename
+      {
+         int len = strlen(argv[i + 1]);
+         if (len)
+         {
+            state->filename = malloc(len + 10); // leave enough space for any timelapse generated changes to filename
+            vcos_assert(state->filename);
+            if (state->filename)
+               strncpy(state->filename, argv[i + 1], len+1);
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandLink :
+      {
+         int len = strlen(argv[i+1]);
+         if (len)
+         {
+            state->linkname = malloc(len + 10);
+            vcos_assert(state->linkname);
+            if (state->linkname)
+               strncpy(state->linkname, argv[i + 1], len+1);
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+
+      }
+
+      case CommandVerbose: // display lots of data during run
+         state->verbose = 1;
+         break;
+
+      case CommandTimeout: // Time to run viewfinder for before taking picture, in seconds
+      {
+         if (sscanf(argv[i + 1], "%u", &state->timeout) == 1)
+         {
+            // Ensure that if previously selected CommandKeypress we don't overwrite it
+            if (state->timeout == 0 && state->frameNextMethod == FRAME_NEXT_SINGLE)
+               state->frameNextMethod = FRAME_NEXT_FOREVER;
+
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandTimelapse:
+         if (sscanf(argv[i + 1], "%u", &state->timelapse) != 1)
+            valid = 0;
+         else
+         {
+            if (state->timelapse)
+               state->frameNextMethod = FRAME_NEXT_TIMELAPSE;
+            else
+               state->frameNextMethod = FRAME_NEXT_IMMEDIATELY;
+
+
+            i++;
+         }
+         break;
+
+      case CommandUseRGB: // display lots of data during run
+         if (state->onlyLuma)
+         {
+            fprintf(stderr, "--luma and --rgb are mutually exclusive\n");
+            valid = 0;
+         }
+         state->useRGB = 1;
+         break;
+
+      case CommandCamSelect:  //Select camera input port
+      {
+         if (sscanf(argv[i + 1], "%u", &state->cameraNum) == 1)
+         {
+            i++;
+         }
+         else
+            valid = 0;
+        break;
+      }
+
+      case CommandFullResPreview:
+         state->fullResPreview = 1;
+         break;
+
+      case CommandKeypress: // Set keypress between capture mode
+         state->frameNextMethod = FRAME_NEXT_KEYPRESS;
+         break;
+
+      case CommandSignal:   // Set SIGUSR1 between capture mode
+         state->frameNextMethod = FRAME_NEXT_SIGNAL;
+         // Reenable the signal
+         signal(SIGUSR1, signal_handler);
+         break;
+
+      case CommandSettings:
+         state->settings = 1;
+         break;
+
+      case CommandBurstMode:
+         state->burstCaptureMode=1;
+         break;
+
+      case CommandOnlyLuma:
+         if (state->useRGB)
+         {
+            fprintf(stderr, "--luma and --rgb are mutually exclusive\n");
+            valid = 0;
+         }
+         state->onlyLuma = 1;
+         break;
+
+      default:
+      {
+         // Try parsing for any image specific parameters
+         // result indicates how many parameters were used up, 0,1,2
+         // but we adjust by -1 as we have used one already
+         const char *second_arg = (i + 1 < argc) ? argv[i + 1] : NULL;
+
+         int parms_used = (raspicamcontrol_parse_cmdline(&state->camera_parameters, &argv[i][1], second_arg));
+
+         // Still unused, try preview options
+         if (!parms_used)
+            parms_used = raspipreview_parse_cmdline(&state->preview_parameters, &argv[i][1], second_arg);
+
+
+         // If no parms were used, this must be a bad parameters
+         if (!parms_used)
+            valid = 0;
+         else
+            i += parms_used - 1;
+
+         break;
+      }
+      }
+   }
+
+   if (!valid)
+   {
+      fprintf(stderr, "Invalid command line option (%s)\n", argv[i-1]);
+      return 1;
+   }
+
+   return 0;
+}
+
+/**
+ * Display usage information for the application to stdout
+ *
+ * @param app_name String to display as the application name
+ *
+ */
+static void display_valid_parameters(char *app_name)
+{
+   fprintf(stdout, "Runs camera for specific time, and take uncompressed YUV capture at end if requested\n\n");
+   fprintf(stdout, "usage: %s [options]\n\n", app_name);
+
+   fprintf(stdout, "Image parameter commands\n\n");
+
+   raspicli_display_help(cmdline_commands, cmdline_commands_size);
+
+   // Help for preview options
+   raspipreview_display_help();
+
+   // Now display any help information from the camcontrol code
+   raspicamcontrol_display_help();
+
+   fprintf(stdout, "\n");
+
+   return;
+}
+
+/**
+ *  buffer header callback function for camera control
+ *
+ * @param port Pointer to port from which callback originated
+ * @param buffer mmal buffer header pointer
+ */
+static void camera_control_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   fprintf(stderr, "Camera control callback  cmd=0x%08x", buffer->cmd);
+
+   if (buffer->cmd == MMAL_EVENT_PARAMETER_CHANGED)
+   {
+      MMAL_EVENT_PARAMETER_CHANGED_T *param = (MMAL_EVENT_PARAMETER_CHANGED_T *)buffer->data;
+      switch (param->hdr.id) {
+         case MMAL_PARAMETER_CAMERA_SETTINGS:
+         {
+            MMAL_PARAMETER_CAMERA_SETTINGS_T *settings = (MMAL_PARAMETER_CAMERA_SETTINGS_T*)param;
+            vcos_log_error("Exposure now %u, analog gain %u/%u, digital gain %u/%u",
+                       settings->exposure,
+                        settings->analog_gain.num, settings->analog_gain.den,
+                        settings->digital_gain.num, settings->digital_gain.den);
+            vcos_log_error("AWB R=%u/%u, B=%u/%u",
+                        settings->awb_red_gain.num, settings->awb_red_gain.den,
+                        settings->awb_blue_gain.num, settings->awb_blue_gain.den
+                        );
+         }
+         break;
+      }
+   }
+   else if (buffer->cmd == MMAL_EVENT_ERROR)
+   {
+      vcos_log_error("No data received from sensor. Check all connections, including the Sunny one on the camera board");
+   }
+   else
+   {
+      vcos_log_error("Received unexpected camera control callback event, 0x%08x", buffer->cmd);
+   }
+
+   mmal_buffer_header_release(buffer);
+}
+
+/**
+ *  buffer header callback function for camera output port
+ *
+ *  Callback will dump buffer data to the specific file
+ *
+ * @param port Pointer to port from which callback originated
+ * @param buffer mmal buffer header pointer
+ */
+static void camera_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   int complete = 0;
+   // We pass our file handle and other stuff in via the userdata field.
+
+
+   PORT_USERDATA *pData = (PORT_USERDATA *)port->userdata;
+
+   if (pData)
+   {
+      int bytes_written = 0;
+      int bytes_to_write = buffer->length;
+
+      if (pData->pstate->onlyLuma)
+         bytes_to_write = vcos_min(buffer->length, port->format->es->video.width * port->format->es->video.height);
+
+      if (bytes_to_write && pData->file_handle)
+      {
+         mmal_buffer_header_mem_lock(buffer);
+
+         bytes_written = fwrite(buffer->data, 1, bytes_to_write, pData->file_handle);
+
+         mmal_buffer_header_mem_unlock(buffer);
+      }
+
+      // We need to check we wrote what we wanted - it's possible we have run out of storage.
+      if (buffer->length && bytes_written != bytes_to_write)
+      {
+         vcos_log_error("Unable to write buffer to file - aborting %d vs %d", bytes_written, bytes_to_write);
+         complete = 1;
+      }
+
+      // Check end of frame or error
+      if (buffer->flags & (MMAL_BUFFER_HEADER_FLAG_FRAME_END | MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED))
+         complete = 1;
+   }
+   else
+   {
+      vcos_log_error("Received a camera still buffer callback with no state");
+   }
+
+   // release buffer back to the pool
+   mmal_buffer_header_release(buffer);
+
+   // and send one back to the port (if still open)
+   if (port->is_enabled)
+   {
+      MMAL_STATUS_T status;
+      MMAL_BUFFER_HEADER_T *new_buffer = mmal_queue_get(pData->pstate->camera_pool->queue);
+
+      // and back to the port from there.
+      if (new_buffer)
+      {
+         status = mmal_port_send_buffer(port, new_buffer);
+      }
+
+      if (!new_buffer || status != MMAL_SUCCESS)
+         vcos_log_error("Unable to return the buffer to the camera still port");
+   }
+
+   if (complete)
+   {
+      vcos_semaphore_post(&(pData->complete_semaphore));
+   }
+}
+
+
+/**
+ * Create the camera component, set up its ports
+ *
+ * @param state Pointer to state control struct
+ *
+ * @return 0 if failed, pointer to component if successful
+ *
+ */
+static MMAL_STATUS_T create_camera_component(RASPISTILLYUV_STATE *state)
+{
+   MMAL_COMPONENT_T *camera = 0;
+   MMAL_ES_FORMAT_T *format;
+   MMAL_PORT_T *preview_port = NULL, *video_port = NULL, *still_port = NULL;
+   MMAL_STATUS_T status;
+   MMAL_POOL_T *pool;
+
+   /* Create the component */
+   status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Failed to create camera component");
+      goto error;
+   }
+
+   MMAL_PARAMETER_INT32_T camera_num =
+      {{MMAL_PARAMETER_CAMERA_NUM, sizeof(camera_num)}, state->cameraNum};
+
+   status = mmal_port_parameter_set(camera->control, &camera_num.hdr);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Could not select camera : error %d", status);
+      goto error;
+   }
+
+   if (!camera->output_num)
+   {
+      status = MMAL_ENOSYS;
+      vcos_log_error("Camera doesn't have output ports");
+      goto error;
+   }
+
+   preview_port = camera->output[MMAL_CAMERA_PREVIEW_PORT];
+   video_port = camera->output[MMAL_CAMERA_VIDEO_PORT];
+   still_port = camera->output[MMAL_CAMERA_CAPTURE_PORT];
+
+   if (state->settings)
+   {
+      MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T change_event_request =
+         {{MMAL_PARAMETER_CHANGE_EVENT_REQUEST, sizeof(MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T)},
+          MMAL_PARAMETER_CAMERA_SETTINGS, 1};
+
+      status = mmal_port_parameter_set(camera->control, &change_event_request.hdr);
+      if ( status != MMAL_SUCCESS )
+      {
+         vcos_log_error("No camera settings events");
+      }
+   }
+
+   // Enable the camera, and tell it its control callback function
+   status = mmal_port_enable(camera->control, camera_control_callback);
+
+   if (status != MMAL_SUCCESS )
+   {
+      vcos_log_error("Unable to enable control port : error %d", status);
+      goto error;
+   }
+
+   //  set up the camera configuration
+   {
+      MMAL_PARAMETER_CAMERA_CONFIG_T cam_config =
+      {
+         { MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) },
+         .max_stills_w = state->width,
+         .max_stills_h = state->height,
+         .stills_yuv422 = 0,
+         .one_shot_stills = 1,
+         .max_preview_video_w = state->preview_parameters.previewWindow.width,
+         .max_preview_video_h = state->preview_parameters.previewWindow.height,
+         .num_preview_video_frames = 3,
+         .stills_capture_circular_buffer_height = 0,
+         .fast_preview_resume = 0,
+         .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RESET_STC
+      };
+
+      if (state->fullResPreview)
+      {
+         cam_config.max_preview_video_w = state->width;
+         cam_config.max_preview_video_h = state->height;
+      }
+
+      mmal_port_parameter_set(camera->control, &cam_config.hdr);
+   }
+
+   raspicamcontrol_set_all_parameters(camera, &state->camera_parameters);
+
+   // Now set up the port formats
+
+   format = preview_port->format;
+
+   format->encoding = MMAL_ENCODING_OPAQUE;
+   format->encoding_variant = MMAL_ENCODING_I420;
+
+   if(state->camera_parameters.shutter_speed > 6000000)
+   {
+        MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
+                                                     { 50, 1000 }, {166, 1000}};
+        mmal_port_parameter_set(preview_port, &fps_range.hdr);
+   }
+   else if(state->camera_parameters.shutter_speed > 1000000)
+   {
+        MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
+                                                     { 166, 1000 }, {999, 1000}};
+        mmal_port_parameter_set(preview_port, &fps_range.hdr);
+   }
+   if (state->fullResPreview)
+   {
+      // In this mode we are forcing the preview to be generated from the full capture resolution.
+      // This runs at a max of 15fps with the OV5647 sensor.
+      format->es->video.width = VCOS_ALIGN_UP(state->width, 32);
+      format->es->video.height = VCOS_ALIGN_UP(state->height, 16);
+      format->es->video.crop.x = 0;
+      format->es->video.crop.y = 0;
+      format->es->video.crop.width = state->width;
+      format->es->video.crop.height = state->height;
+      format->es->video.frame_rate.num = FULL_RES_PREVIEW_FRAME_RATE_NUM;
+      format->es->video.frame_rate.den = FULL_RES_PREVIEW_FRAME_RATE_DEN;
+   }
+   else
+   {
+      // Use a full FOV 4:3 mode
+      format->es->video.width = VCOS_ALIGN_UP(state->preview_parameters.previewWindow.width, 32);
+      format->es->video.height = VCOS_ALIGN_UP(state->preview_parameters.previewWindow.height, 16);
+      format->es->video.crop.x = 0;
+      format->es->video.crop.y = 0;
+      format->es->video.crop.width = state->preview_parameters.previewWindow.width;
+      format->es->video.crop.height = state->preview_parameters.previewWindow.height;
+      format->es->video.frame_rate.num = PREVIEW_FRAME_RATE_NUM;
+      format->es->video.frame_rate.den = PREVIEW_FRAME_RATE_DEN;
+   }
+
+   status = mmal_port_format_commit(preview_port);
+
+   if (status != MMAL_SUCCESS )
+   {
+      vcos_log_error("camera viewfinder format couldn't be set");
+      goto error;
+   }
+
+   // Set the same format on the video  port (which we don't use here)
+   mmal_format_full_copy(video_port->format, format);
+   status = mmal_port_format_commit(video_port);
+
+   if (status != MMAL_SUCCESS )
+   {
+      vcos_log_error("camera video format couldn't be set");
+      goto error;
+   }
+
+   // Ensure there are enough buffers to avoid dropping frames
+   if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
+      video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
+
+   format = still_port->format;
+
+   if(state->camera_parameters.shutter_speed > 6000000)
+   {
+        MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
+                                                     { 50, 1000 }, {166, 1000}};
+        mmal_port_parameter_set(still_port, &fps_range.hdr);
+   }
+   else if(state->camera_parameters.shutter_speed > 1000000)
+   {
+        MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
+                                                     { 167, 1000 }, {999, 1000}};
+        mmal_port_parameter_set(still_port, &fps_range.hdr);
+   }
+   // Set our stills format on the stills  port
+   if (state->useRGB)
+   {
+      format->encoding = mmal_util_rgb_order_fixed(still_port) ? MMAL_ENCODING_RGB24 : MMAL_ENCODING_BGR24;
+      format->encoding_variant = 0;  //Irrelevant when not in opaque mode
+   }
+   else
+   {
+      format->encoding = MMAL_ENCODING_I420;
+      format->encoding_variant = MMAL_ENCODING_I420;
+   }
+   format->es->video.width = VCOS_ALIGN_UP(state->width, 32);
+   format->es->video.height = VCOS_ALIGN_UP(state->height, 16);
+   format->es->video.crop.x = 0;
+   format->es->video.crop.y = 0;
+   format->es->video.crop.width = state->width;
+   format->es->video.crop.height = state->height;
+   format->es->video.frame_rate.num = STILLS_FRAME_RATE_NUM;
+   format->es->video.frame_rate.den = STILLS_FRAME_RATE_DEN;
+
+   if (still_port->buffer_size < still_port->buffer_size_min)
+      still_port->buffer_size = still_port->buffer_size_min;
+
+   still_port->buffer_num = still_port->buffer_num_recommended;
+
+   status = mmal_port_parameter_set_boolean(video_port, MMAL_PARAMETER_ZERO_COPY, MMAL_TRUE);
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Failed to select zero copy");
+      goto error;
+   }
+
+   status = mmal_port_format_commit(still_port);
+
+   if (status != MMAL_SUCCESS )
+   {
+      vcos_log_error("camera still format couldn't be set");
+      goto error;
+   }
+
+   /* Enable component */
+   status = mmal_component_enable(camera);
+
+   if (status != MMAL_SUCCESS )
+   {
+      vcos_log_error("camera component couldn't be enabled");
+      goto error;
+   }
+
+   /* Create pool of buffer headers for the output port to consume */
+   pool = mmal_port_pool_create(still_port, still_port->buffer_num, still_port->buffer_size);
+
+   if (!pool)
+   {
+      vcos_log_error("Failed to create buffer header pool for camera still port %s", still_port->name);
+   }
+
+   state->camera_pool = pool;
+   state->camera_component = camera;
+
+   if (state->verbose)
+      fprintf(stderr, "Camera component done\n");
+
+   return status;
+
+error:
+
+   if (camera)
+      mmal_component_destroy(camera);
+
+   return status;
+}
+
+/**
+ * Destroy the camera component
+ *
+ * @param state Pointer to state control struct
+ *
+ */
+static void destroy_camera_component(RASPISTILLYUV_STATE *state)
+{
+   if (state->camera_component)
+   {
+      mmal_component_destroy(state->camera_component);
+      state->camera_component = NULL;
+   }
+}
+
+/**
+ * Connect two specific ports together
+ *
+ * @param output_port Pointer the output port
+ * @param input_port Pointer the input port
+ * @param Pointer to a mmal connection pointer, reassigned if function successful
+ * @return Returns a MMAL_STATUS_T giving result of operation
+ *
+ */
+static MMAL_STATUS_T connect_ports(MMAL_PORT_T *output_port, MMAL_PORT_T *input_port, MMAL_CONNECTION_T **connection)
+{
+   MMAL_STATUS_T status;
+
+   status =  mmal_connection_create(connection, output_port, input_port, MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT);
+
+   if (status == MMAL_SUCCESS)
+   {
+      status =  mmal_connection_enable(*connection);
+      if (status != MMAL_SUCCESS)
+         mmal_connection_destroy(*connection);
+   }
+
+   return status;
+}
+
+/**
+ * Allocates and generates a filename based on the
+ * user-supplied pattern and the frame number.
+ * On successful return, finalName and tempName point to malloc()ed strings
+ * which must be freed externally.  (On failure, returns nulls that
+ * don't need free()ing.)
+ *
+ * @param finalName pointer receives an
+ * @param pattern sprintf pattern with %d to be replaced by frame
+ * @param frame for timelapse, the frame number
+ * @return Returns a MMAL_STATUS_T giving result of operation
+*/
+
+MMAL_STATUS_T create_filenames(char** finalName, char** tempName, char * pattern, int frame)
+{
+   *finalName = NULL;
+   *tempName = NULL;
+   if (0 > asprintf(finalName, pattern, frame) ||
+       0 > asprintf(tempName, "%s~", *finalName))
+   {
+      if (*finalName != NULL)
+      {
+         free(*finalName);
+      }
+      return MMAL_ENOMEM;    // It may be some other error, but it is not worth getting it right
+   }
+   return MMAL_SUCCESS;
+}
+
+/**
+ * Checks if specified port is valid and enabled, then disables it
+ *
+ * @param port  Pointer the port
+ *
+ */
+static void check_disable_port(MMAL_PORT_T *port)
+{
+   if (port && port->is_enabled)
+      mmal_port_disable(port);
+}
+
+/**
+ * Handler for sigint signals
+ *
+ * @param signal_number ID of incoming signal.
+ *
+ */
+static void signal_handler(int signal_number)
+{
+   if (signal_number == SIGUSR1)
+   {
+      // Handle but ignore - prevents us dropping out if started in none-signal mode
+      // and someone sends us the USR1 signal anyway
+   }
+   else
+   {
+      // Going to abort on all other signals
+      vcos_log_error("Aborting program\n");
+      exit(130);
+   }
+}
+
+/**
+ * Function to wait in various ways (depending on settings) for the next frame
+ *
+ * @param state Pointer to the state data
+ * @param [in][out] frame The last frame number, adjusted to next frame number on output
+ * @return !0 if to continue, 0 if reached end of run
+ */
+static int wait_for_next_frame(RASPISTILLYUV_STATE *state, int *frame)
+{
+   static int64_t complete_time = -1;
+   int keep_running = 1;
+
+   int64_t current_time =  vcos_getmicrosecs64()/1000;
+
+   if (complete_time == -1)
+      complete_time =  current_time + state->timeout;
+
+   // if we have run out of time, flag we need to exit
+   // If timeout = 0 then always continue
+   if (current_time >= complete_time && state->timeout != 0)
+      keep_running = 0;
+
+   switch (state->frameNextMethod)
+   {
+   case FRAME_NEXT_SINGLE :
+      // simple timeout for a single capture
+      vcos_sleep(state->timeout);
+      return 0;
+
+   case FRAME_NEXT_FOREVER :
+   {
+      *frame+=1;
+
+      // Have a sleep so we don't hog the CPU.
+      vcos_sleep(10000);
+
+      // Run forever so never indicate end of loop
+      return 1;
+   }
+
+   case FRAME_NEXT_TIMELAPSE :
+   {
+      static int64_t next_frame_ms = -1;
+
+      // Always need to increment by at least one, may add a skip later
+      *frame += 1;
+
+      if (next_frame_ms == -1)
+      {
+         vcos_sleep(state->timelapse);
+
+         // Update our current time after the sleep
+         current_time =  vcos_getmicrosecs64()/1000;
+
+         // Set our initial 'next frame time'
+         next_frame_ms = current_time + state->timelapse;
+      }
+      else
+      {
+         int64_t this_delay_ms = next_frame_ms - current_time;
+
+         if (this_delay_ms < 0)
+         {
+            // We are already past the next exposure time
+            if (-this_delay_ms < -state->timelapse/2)
+            {
+               // Less than a half frame late, take a frame and hope to catch up next time
+               next_frame_ms += state->timelapse;
+               vcos_log_error("Frame %d is %d ms late", *frame, (int)(-this_delay_ms));
+            }
+            else
+            {
+               int nskip = 1 + (-this_delay_ms)/state->timelapse;
+               vcos_log_error("Skipping frame %d to restart at frame %d", *frame, *frame+nskip);
+               *frame += nskip;
+               this_delay_ms += nskip * state->timelapse;
+               vcos_sleep(this_delay_ms);
+               next_frame_ms += (nskip + 1) * state->timelapse;
+            }
+         }
+         else
+         {
+            vcos_sleep(this_delay_ms);
+            next_frame_ms += state->timelapse;
+         }
+      }
+
+      return keep_running;
+   }
+
+   case FRAME_NEXT_KEYPRESS :
+   {
+       int ch;
+
+       if (state->verbose)
+         fprintf(stderr, "Press Enter to capture, X then ENTER to exit\n");
+
+       ch = getchar();
+       *frame+=1;
+       if (ch == 'x' || ch == 'X')
+          return 0;
+       else
+       {
+             return keep_running;
+       }
+   }
+
+   case FRAME_NEXT_IMMEDIATELY :
+   {
+      // Not waiting, just go to next frame.
+      // Actually, we do need a slight delay here otherwise exposure goes
+      // badly wrong since we never allow it frames to work it out
+      // This could probably be tuned down.
+      // First frame has a much longer delay to ensure we get exposure to a steady state
+      if (*frame == 0)
+         vcos_sleep(1000);
+      else
+         vcos_sleep(30);
+
+      *frame+=1;
+
+      return keep_running;
+   }
+
+   case FRAME_NEXT_GPIO :
+   {
+       // Intended for GPIO firing of a capture
+      return 0;
+   }
+
+   case FRAME_NEXT_SIGNAL :
+   {
+      // Need to wait for a SIGUSR1 signal
+      sigset_t waitset;
+      int sig;
+      int result = 0;
+
+      sigemptyset( &waitset );
+      sigaddset( &waitset, SIGUSR1 );
+
+      // We are multi threaded because we use mmal, so need to use the pthread
+      // variant of procmask to block SIGUSR1 so we can wait on it.
+      pthread_sigmask( SIG_BLOCK, &waitset, NULL );
+
+      if (state->verbose)
+      {
+         fprintf(stderr, "Waiting for SIGUSR1 to initiate capture\n");
+      }
+
+      result = sigwait( &waitset, &sig );
+
+      if (state->verbose)
+      {
+         if( result == 0)
+         {
+            fprintf(stderr, "Received SIGUSR1\n");
+         }
+         else
+         {
+            fprintf(stderr, "Bad signal received - error %d\n", errno);
+         }
+      }
+
+      *frame+=1;
+
+      return keep_running;
+   }
+   } // end of switch
+
+   // Should have returned by now, but default to timeout
+   return keep_running;
+}
+
+static void rename_file(RASPISTILLYUV_STATE *state, FILE *output_file,
+      const char *final_filename, const char *use_filename, int frame)
+{
+   MMAL_STATUS_T status;
+
+   fclose(output_file);
+   vcos_assert(use_filename != NULL && final_filename != NULL);
+   if (0 != rename(use_filename, final_filename))
+   {
+      vcos_log_error("Could not rename temp file to: %s; %s",
+            final_filename,strerror(errno));
+   }
+   if (state->linkname)
+   {
+      char *use_link;
+      char *final_link;
+      status = create_filenames(&final_link, &use_link, state->linkname, frame);
+
+      // Create hard link if possible, symlink otherwise
+      if (status != MMAL_SUCCESS
+            || (0 != link(final_filename, use_link)
+               &&  0 != symlink(final_filename, use_link))
+            || 0 != rename(use_link, final_link))
+      {
+         vcos_log_error("Could not link as filename: %s; %s",
+               state->linkname,strerror(errno));
+      }
+      if (use_link) free(use_link);
+      if (final_link) free(final_link);
+   }
+}
+
+/**
+ * main
+ */
+int main(int argc, const char **argv)
+{
+   // Our main data storage vessel..
+   RASPISTILLYUV_STATE state;
+   int exit_code = EX_OK;
+
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   MMAL_PORT_T *camera_preview_port = NULL;
+   MMAL_PORT_T *camera_video_port = NULL;
+   MMAL_PORT_T *camera_still_port = NULL;
+   MMAL_PORT_T *preview_input_port = NULL;
+   FILE *output_file = NULL;
+
+   bcm_host_init();
+
+   // Register our application with the logging system
+   vcos_log_register("RaspiStill", VCOS_LOG_CATEGORY);
+
+   signal(SIGINT, signal_handler);
+
+   // Disable USR1 for the moment - may be reenabled if go in to signal capture mode
+   signal(SIGUSR1, SIG_IGN);
+
+   default_status(&state);
+
+   // Do we have any parameters
+   if (argc == 1)
+   {
+      fprintf(stdout, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING);
+
+      display_valid_parameters(basename(argv[0]));
+      exit(EX_USAGE);
+   }
+
+   default_status(&state);
+
+   // Parse the command line and put options in to our status structure
+   if (parse_cmdline(argc, argv, &state))
+   {
+      status = -1;
+      exit(EX_USAGE);
+   }
+
+   if (state.verbose)
+   {
+      fprintf(stderr, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING);
+      dump_status(&state);
+   }
+
+   // OK, we have a nice set of parameters. Now set up our components
+   // We have two components. Camera and Preview
+   // Camera is different in stills/video, but preview
+   // is the same so handed off to a separate module
+
+   if ((status = create_camera_component(&state)) != MMAL_SUCCESS)
+   {
+      vcos_log_error("%s: Failed to create camera component", __func__);
+      exit_code = EX_SOFTWARE;
+   }
+   else if ((status = raspipreview_create(&state.preview_parameters)) != MMAL_SUCCESS)
+   {
+      vcos_log_error("%s: Failed to create preview component", __func__);
+      destroy_camera_component(&state);
+      exit_code = EX_SOFTWARE;
+   }
+   else
+   {
+      PORT_USERDATA callback_data;
+
+      if (state.verbose)
+         fprintf(stderr, "Starting component connection stage\n");
+
+      camera_preview_port = state.camera_component->output[MMAL_CAMERA_PREVIEW_PORT];
+      camera_video_port   = state.camera_component->output[MMAL_CAMERA_VIDEO_PORT];
+      camera_still_port   = state.camera_component->output[MMAL_CAMERA_CAPTURE_PORT];
+
+      // Note we are lucky that the preview and null sink components use the same input port
+      // so we can simple do this without conditionals
+      preview_input_port  = state.preview_parameters.preview_component->input[0];
+
+      // Connect camera to preview (which might be a null_sink if no preview required)
+      status = connect_ports(camera_preview_port, preview_input_port, &state.preview_connection);
+
+      if (status == MMAL_SUCCESS)
+      {
+         VCOS_STATUS_T vcos_status;
+
+         // Set up our userdata - this is passed though to the callback where we need the information.
+         // Null until we open our filename
+         callback_data.file_handle = NULL;
+         callback_data.pstate = &state;
+
+         vcos_status = vcos_semaphore_create(&callback_data.complete_semaphore, "RaspiStill-sem", 0);
+         vcos_assert(vcos_status == VCOS_SUCCESS);
+
+         camera_still_port->userdata = (struct MMAL_PORT_USERDATA_T *)&callback_data;
+
+         if (state.verbose)
+            fprintf(stderr, "Enabling camera still output port\n");
+
+         // Enable the camera still output port and tell it its callback function
+         status = mmal_port_enable(camera_still_port, camera_buffer_callback);
+
+         if (status != MMAL_SUCCESS)
+         {
+            vcos_log_error("Failed to setup camera output");
+            goto error;
+         }
+
+         if (state.verbose)
+            fprintf(stderr, "Starting video preview\n");
+
+
+         int frame, keep_looping = 1;
+         FILE *output_file = NULL;
+         char *use_filename = NULL;      // Temporary filename while image being written
+         char *final_filename = NULL;    // Name that file gets once writing complete
+
+         frame = 0;
+
+         while (keep_looping)
+         {
+             keep_looping = wait_for_next_frame(&state, &frame);
+
+            // Open the file
+            if (state.filename)
+            {
+               if (state.filename[0] == '-')
+               {
+                  output_file = stdout;
+
+                  // Ensure we don't upset the output stream with diagnostics/info
+                  state.verbose = 0;
+               }
+               else
+               {
+                  vcos_assert(use_filename == NULL && final_filename == NULL);
+                  status = create_filenames(&final_filename, &use_filename, state.filename, frame);
+                  if (status  != MMAL_SUCCESS)
+                  {
+                     vcos_log_error("Unable to create filenames");
+                     goto error;
+                  }
+
+                  if (state.verbose)
+                     fprintf(stderr, "Opening output file %s\n", final_filename);
+                     // Technically it is opening the temp~ filename which will be ranamed to the final filename
+
+                  output_file = fopen(use_filename, "wb");
+
+                  if (!output_file)
+                  {
+                     // Notify user, carry on but discarding encoded output buffers
+                     vcos_log_error("%s: Error opening output file: %s\nNo output file will be generated\n", __func__, use_filename);
+                  }
+               }
+
+               callback_data.file_handle = output_file;
+            }
+
+            if (output_file)
+            {
+               int num, q;
+
+               // There is a possibility that shutter needs to be set each loop.
+               if (mmal_status_to_int(mmal_port_parameter_set_uint32(state.camera_component->control, MMAL_PARAMETER_SHUTTER_SPEED, state.camera_parameters.shutter_speed) != MMAL_SUCCESS))
+                  vcos_log_error("Unable to set shutter speed");
+
+
+               // Send all the buffers to the camera output port
+               num = mmal_queue_length(state.camera_pool->queue);
+
+               for (q=0;q<num;q++)
+               {
+                  MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state.camera_pool->queue);
+
+                  if (!buffer)
+                     vcos_log_error("Unable to get a required buffer %d from pool queue", q);
+
+                  if (mmal_port_send_buffer(camera_still_port, buffer)!= MMAL_SUCCESS)
+                     vcos_log_error("Unable to send a buffer to camera output port (%d)", q);
+               }
+
+               if (state.burstCaptureMode && frame==1)
+               {
+                  mmal_port_parameter_set_boolean(state.camera_component->control,  MMAL_PARAMETER_CAMERA_BURST_CAPTURE, 1);
+               }
+
+               if (state.verbose)
+                  fprintf(stderr, "Starting capture %d\n", frame);
+
+               if (mmal_port_parameter_set_boolean(camera_still_port, MMAL_PARAMETER_CAPTURE, 1) != MMAL_SUCCESS)
+               {
+                  vcos_log_error("%s: Failed to start capture", __func__);
+               }
+               else
+               {
+                  // Wait for capture to complete
+                  // For some reason using vcos_semaphore_wait_timeout sometimes returns immediately with bad parameter error
+                  // even though it appears to be all correct, so reverting to untimed one until figure out why its erratic
+                  vcos_semaphore_wait(&callback_data.complete_semaphore);
+                  if (state.verbose)
+                     fprintf(stderr, "Finished capture %d\n", frame);
+               }
+
+               // Ensure we don't die if get callback with no open file
+               callback_data.file_handle = NULL;
+
+               if (output_file != stdout)
+               {
+                  rename_file(&state, output_file, final_filename, use_filename, frame);
+               }
+               else
+               {
+                  fflush(output_file);
+               }
+            }
+
+            if (use_filename)
+            {
+               free(use_filename);
+               use_filename = NULL;
+            }
+            if (final_filename)
+            {
+               free(final_filename);
+               final_filename = NULL;
+            }
+         } // end for (frame)
+
+         vcos_semaphore_delete(&callback_data.complete_semaphore);
+      }
+      else
+      {
+         mmal_status_to_int(status);
+         vcos_log_error("%s: Failed to connect camera to preview", __func__);
+      }
+
+error:
+
+      mmal_status_to_int(status);
+
+      if (state.verbose)
+         fprintf(stderr, "Closing down\n");
+
+      if (output_file)
+         fclose(output_file);
+
+      // Disable all our ports that are not handled by connections
+      check_disable_port(camera_video_port);
+
+      if (state.preview_connection)
+         mmal_connection_destroy(state.preview_connection);
+
+      /* Disable components */
+      if (state.preview_parameters.preview_component)
+         mmal_component_disable(state.preview_parameters.preview_component);
+
+      if (state.camera_component)
+         mmal_component_disable(state.camera_component);
+
+      raspipreview_destroy(&state.preview_parameters);
+      destroy_camera_component(&state);
+
+      if (state.verbose)
+         fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n");
+   }
+
+   if (status != MMAL_SUCCESS)
+      raspicamcontrol_check_configuration(128);
+
+   return exit_code;
+}
+
+
+
+
diff --git a/host_applications/linux/apps/raspicam/RaspiTex.c b/host_applications/linux/apps/raspicam/RaspiTex.c
new file mode 100755 (executable)
index 0000000..f7cc08f
--- /dev/null
@@ -0,0 +1,754 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, Tim Gover
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "RaspiTex.h"
+#include "RaspiCLI.h"
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include "RaspiTexUtil.h"
+#include "interface/vcos/vcos.h"
+#include "interface/mmal/mmal_buffer.h"
+#include "interface/mmal/util/mmal_util.h"
+#include "interface/mmal/util/mmal_util_params.h"
+#include "tga.h"
+
+#include "gl_scenes/mirror.h"
+#include "gl_scenes/sobel.h"
+#include "gl_scenes/square.h"
+#include "gl_scenes/teapot.h"
+#include "gl_scenes/vcsm_square.h"
+#include "gl_scenes/yuv.h"
+
+/**
+ * \file RaspiTex.c
+ *
+ * A simple framework for extending a MMAL application to render buffers via
+ * OpenGL.
+ *
+ * MMAL buffers are often in YUV colour space and in either a planar or
+ * tile format which is not supported directly by V3D. Instead of copying
+ * the buffer from the GPU and doing a colour space / pixel format conversion
+ * the GL_OES_EGL_image_external is used. This allows an EGL image to be
+ * created from GPU buffer handle (MMAL opaque buffer handle). The EGL image
+ * may then be used to create a texture (glEGLImageTargetTexture2DOES) and
+ * drawn by either OpenGL ES 1.0 or 2.0 contexts.
+ *
+ * Notes:
+ * 1) GL_OES_EGL_image_external textures always return pixels in RGBA format.
+ *    This is also the case when used from a fragment shader.
+ *
+ * 2) The driver implementation creates a new RGB_565 buffer and does the color
+ *    space conversion from YUV. This happens in GPU memory using the vector
+ *    processor.
+ *
+ * 3) Each EGL external image in use will consume GPU memory for the RGB 565
+ *    buffer. In addition, the GL pipeline might require more than one EGL image
+ *    to be retained in GPU memory until the drawing commands are flushed.
+ *
+ *    Typically 128 MB of GPU memory is sufficient for 720p viewfinder and 720p
+ *    GL surface. If both the viewfinder and the GL surface are 1080p then
+ *    256MB of GPU memory is recommended, otherwise, for non-trivial scenes
+ *    the system can run out of GPU memory whilst the camera is running.
+ *
+ * 4) It is important to make sure that the MMAL opaque buffer is not returned
+ *    to MMAL before the GL driver has completed the asynchronous call to
+ *    glEGLImageTargetTexture2DOES. Deferring destruction of the EGL image and
+ *    the buffer return to MMAL until after eglSwapBuffers is the recommended.
+ *
+ * See also: http://www.khronos.org/registry/gles/extensions/OES/OES_EGL_image_external.txt
+ */
+
+#define DEFAULT_WIDTH   640
+#define DEFAULT_HEIGHT  480
+
+#define CommandGLScene   1
+#define CommandGLWin     2
+
+static COMMAND_LIST cmdline_commands[] =
+{
+   { CommandGLScene, "-glscene",  "gs",  "GL scene square,teapot,mirror,yuv,sobel,vcsm_square", 1 },
+   { CommandGLWin,   "-glwin",    "gw",  "GL window settings <'x,y,w,h'>", 1 },
+};
+
+static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]);
+
+/**
+ * Parse a possible command pair - command and parameter
+ * @param arg1 Command
+ * @param arg2 Parameter (could be NULL)
+ * @return How many parameters were used, 0,1,2
+ */
+int raspitex_parse_cmdline(RASPITEX_STATE *state,
+      const char *arg1, const char *arg2)
+{
+   int command_id, used = 0, num_parameters;
+
+   if (!arg1)
+       return 0;
+
+   command_id = raspicli_get_command_id(cmdline_commands,
+         cmdline_commands_size, arg1, &num_parameters);
+
+   // If invalid command, or we are missing a parameter, drop out
+   if (command_id==-1 || (command_id != -1 && num_parameters > 0 && arg2 == NULL))
+      return 0;
+
+   switch (command_id)
+   {
+      case CommandGLWin: // Allows a GL window to be different to preview-res
+      {
+         int tmp;
+         tmp = sscanf(arg2, "%d,%d,%d,%d",
+               &state->x, &state->y, &state->width, &state->height);
+         if (tmp != 4)
+         {
+            // Default to safe size on parse error
+            state->x = state->y = 0;
+            state->width = DEFAULT_WIDTH;
+            state->height = DEFAULT_HEIGHT;
+         }
+         else
+         {
+            state->gl_win_defined = 1;
+         }
+
+         used = 2;
+         break;
+      }
+
+      case CommandGLScene: // Selects the GL scene
+      {
+         if (strcmp(arg2, "square") == 0)
+            state->scene_id = RASPITEX_SCENE_SQUARE;
+         else if (strcmp(arg2, "teapot") == 0)
+            state->scene_id = RASPITEX_SCENE_TEAPOT;
+         else if (strcmp(arg2, "mirror") == 0)
+            state->scene_id = RASPITEX_SCENE_MIRROR;
+         else if (strcmp(arg2, "yuv") == 0)
+            state->scene_id = RASPITEX_SCENE_YUV;
+         else if (strcmp(arg2, "sobel") == 0)
+            state->scene_id = RASPITEX_SCENE_SOBEL;
+         else if (strcmp(arg2, "vcsm_square") == 0)
+            state->scene_id = RASPITEX_SCENE_VCSM_SQUARE;
+         else
+            vcos_log_error("Unknown scene %s", arg2);
+
+         used = 2;
+         break;
+      }
+   }
+   return used;
+}
+
+/**
+ * Display help for command line options
+ */
+void raspitex_display_help()
+{
+   fprintf(stdout, "\nPreview parameter commands\n\n");
+   raspicli_display_help(cmdline_commands, cmdline_commands_size);
+}
+
+static void update_fps()
+{
+   static int frame_count = 0;
+   static long long time_start = 0;
+   long long time_now;
+   struct timeval te;
+   float fps;
+
+   frame_count++;
+
+   gettimeofday(&te, NULL);
+   time_now = te.tv_sec * 1000LL + te.tv_usec / 1000;
+
+   if (time_start == 0)
+   {
+      time_start = time_now;
+   }
+   else if (time_now - time_start > 5000)
+   {
+      fps = (float) frame_count / ((time_now - time_start) / 1000.0);
+      frame_count = 0;
+      time_start = time_now;
+      vcos_log_error("%3.2f FPS", fps);
+   }
+}
+
+/**
+ * Captures the frame-buffer if requested.
+ * @param state RASPITEX STATE
+ * @return Zero if successful.
+ */
+static void raspitex_do_capture(RASPITEX_STATE *state)
+{
+   uint8_t *buffer = NULL;
+   size_t size = 0;
+
+   if (state->capture.request)
+   {
+      if (state->ops.capture(state, &buffer, &size) == 0)
+      {
+         /* Pass ownership of buffer to main thread via capture state */
+         state->capture.buffer = buffer;
+         state->capture.size = size;
+      }
+      else
+      {
+         state->capture.buffer = NULL; // Null indicates an error
+         state->capture.size = 0;
+      }
+
+      state->capture.request = 0; // Always clear request and post sem
+      vcos_semaphore_post(&state->capture.completed_sem);
+   }
+}
+
+/**
+ * Checks if there is at least one valid EGL image.
+ * @param state RASPITEX STATE
+ * @return Zero if successful.
+ */
+static int check_egl_image(RASPITEX_STATE *state)
+{
+   if (state->egl_image == EGL_NO_IMAGE_KHR &&
+         state->y_egl_image == EGL_NO_IMAGE_KHR &&
+         state->u_egl_image == EGL_NO_IMAGE_KHR &&
+         state->v_egl_image == EGL_NO_IMAGE_KHR)
+      return -1;
+   else
+      return 0;
+}
+
+/**
+ * Draws the next preview frame. If a new preview buffer is available then the
+ * preview texture is updated first.
+ *
+ * @param state RASPITEX STATE
+ * @param video_frame MMAL buffer header containing the opaque buffer handle.
+ * @return Zero if successful.
+ */
+static int raspitex_draw(RASPITEX_STATE *state, MMAL_BUFFER_HEADER_T *buf)
+{
+   int rc = 0;
+
+   /* If buf is non-NULL then there is a new viewfinder frame available
+    * from the camera so the texture should be updated.
+    *
+    * Although it's possible to have multiple textures mapped to different
+    * viewfinder frames this can consume a lot of GPU memory for high-resolution
+    * viewfinders.
+    */
+   if (buf)
+   {
+      /* Update the texture to the new viewfinder image which should */
+      if (state->ops.update_texture)
+      {
+         rc = state->ops.update_texture(state, (EGLClientBuffer) buf->data);
+         if (rc != 0)
+         {
+            vcos_log_error("%s: Failed to update RGBX texture %d",
+                  VCOS_FUNCTION, rc);
+            goto end;
+         }
+      }
+
+      if (state->ops.update_y_texture)
+      {
+         rc = state->ops.update_y_texture(state, (EGLClientBuffer) buf->data);
+         if (rc != 0)
+         {
+            vcos_log_error("%s: Failed to update Y' plane texture %d", VCOS_FUNCTION, rc);
+            goto end;
+         }
+      }
+
+      if (state->ops.update_u_texture)
+      {
+         rc = state->ops.update_u_texture(state, (EGLClientBuffer) buf->data);
+         if (rc != 0)
+         {
+            vcos_log_error("%s: Failed to update U plane texture %d", VCOS_FUNCTION, rc);
+            goto end;
+         }
+      }
+
+      if (state->ops.update_v_texture)
+      {
+         rc = state->ops.update_v_texture(state, (EGLClientBuffer) buf->data);
+         if (rc != 0)
+         {
+            vcos_log_error("%s: Failed to update V texture %d", VCOS_FUNCTION, rc);
+            goto end;
+         }
+      }
+
+      /* Now return the PREVIOUS MMAL buffer header back to the camera preview. */
+      if (state->preview_buf)
+         mmal_buffer_header_release(state->preview_buf);
+
+      state->preview_buf = buf;
+   }
+
+   /*  Do the drawing */
+   if (check_egl_image(state) == 0)
+   {
+      rc = state->ops.update_model(state);
+      if (rc != 0)
+         goto end;
+
+      rc = state->ops.redraw(state);
+      if (rc != 0)
+         goto end;
+
+      raspitex_do_capture(state);
+
+      eglSwapBuffers(state->display, state->surface);
+      update_fps();
+   }
+   else
+   {
+      // vcos_log_trace("%s: No preview image", VCOS_FUNCTION);
+   }
+
+end:
+   return rc;
+}
+
+/**
+ * Process preview buffers.
+ *
+ * Dequeue each available preview buffer in order and call current redraw
+ * function. If no new buffers are available then the render function is
+ * invoked anyway.
+ * @param   state The GL preview window state.
+ * @return Zero if successful.
+ */
+static int preview_process_returned_bufs(RASPITEX_STATE* state)
+{
+   MMAL_BUFFER_HEADER_T *buf;
+   int new_frame = 0;
+   int rc = 0;
+
+   while ((buf = mmal_queue_get(state->preview_queue)) != NULL)
+   {
+      if (state->preview_stop == 0)
+      {
+         new_frame = 1;
+         rc = raspitex_draw(state, buf);
+         if (rc != 0)
+         {
+            vcos_log_error("%s: Error drawing frame. Stopping.", VCOS_FUNCTION);
+            state->preview_stop = 1;
+            return rc;
+         }
+      }
+   }
+
+   /* If there were no new frames then redraw the scene again with the previous
+    * texture. Otherwise, go round the loop again to see if any new buffers
+    * are returned.
+    */
+   if (! new_frame)
+      rc = raspitex_draw(state, NULL);
+   return rc;
+}
+
+/** Preview worker thread.
+ * Ensures camera preview is supplied with buffers and sends preview frames to GL.
+ * @param arg  Pointer to state.
+ * @return NULL always.
+ */
+static void *preview_worker(void *arg)
+{
+   RASPITEX_STATE* state = arg;
+   MMAL_PORT_T *preview_port = state->preview_port;
+   MMAL_BUFFER_HEADER_T *buf;
+   MMAL_STATUS_T st;
+   int rc;
+
+   vcos_log_trace("%s: port %p", VCOS_FUNCTION, preview_port);
+
+   rc = state->ops.create_native_window(state);
+   if (rc != 0)
+      goto end;
+
+   rc = state->ops.gl_init(state);
+   if (rc != 0)
+      goto end;
+
+   while (state->preview_stop == 0)
+   {
+      /* Send empty buffers to camera preview port */
+      while ((buf = mmal_queue_get(state->preview_pool->queue)) != NULL)
+      {
+         st = mmal_port_send_buffer(preview_port, buf);
+         if (st != MMAL_SUCCESS)
+         {
+            vcos_log_error("Failed to send buffer to %s", preview_port->name);
+         }
+      }
+      /* Process returned buffers */
+      if (preview_process_returned_bufs(state) != 0)
+      {
+         vcos_log_error("Preview error. Exiting.");
+         state->preview_stop = 1;
+      }
+   }
+
+end:
+   /* Make sure all buffers are returned on exit */
+   while ((buf = mmal_queue_get(state->preview_queue)) != NULL)
+      mmal_buffer_header_release(buf);
+
+   /* Tear down GL */
+   state->ops.gl_term(state);
+   vcos_log_trace("Exiting preview worker");
+   return NULL;
+}
+
+/**
+ * MMAL Callback from camera preview output port.
+ * @param port The camera preview port.
+ * @param buf The new preview buffer.
+ **/
+static void preview_output_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buf)
+{
+   RASPITEX_STATE *state = (RASPITEX_STATE*) port->userdata;
+
+   if (buf->length == 0)
+   {
+      vcos_log_trace("%s: zero-length buffer => EOS", port->name);
+      state->preview_stop = 1;
+      mmal_buffer_header_release(buf);
+   }
+   else if (buf->data == NULL)
+   {
+      vcos_log_trace("%s: zero buffer handle", port->name);
+      mmal_buffer_header_release(buf);
+   }
+   else
+   {
+      /* Enqueue the preview frame for rendering and return to
+       * avoid blocking MMAL core.
+       */
+      mmal_queue_put(state->preview_queue, buf);
+   }
+}
+
+/* Registers a callback on the camera preview port to receive
+ * notifications of new frames.
+ * This must be called before rapitex_start and may not be called again
+ * without calling raspitex_destroy first.
+ *
+ * @param state Pointer to the GL preview state.
+ * @param port  Pointer to the camera preview port
+ * @return Zero if successful.
+ */
+int raspitex_configure_preview_port(RASPITEX_STATE *state,
+      MMAL_PORT_T *preview_port)
+{
+   MMAL_STATUS_T status;
+   vcos_log_trace("%s port %p", VCOS_FUNCTION, preview_port);
+
+   /* Enable ZERO_COPY mode on the preview port which instructs MMAL to only
+    * pass the 4-byte opaque buffer handle instead of the contents of the opaque
+    * buffer.
+    * The opaque handle is resolved on VideoCore by the GL driver when the EGL
+    * image is created.
+    */
+   status = mmal_port_parameter_set_boolean(preview_port,
+         MMAL_PARAMETER_ZERO_COPY, MMAL_TRUE);
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Failed to enable zero copy on camera preview port");
+      goto end;
+   }
+
+   status = mmal_port_format_commit(preview_port);
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("camera viewfinder format couldn't be set");
+      goto end;
+   }
+
+   /* For GL a pool of opaque buffer handles must be allocated in the client.
+    * These buffers are used to create the EGL images.
+    */
+   state->preview_port = preview_port;
+   preview_port->buffer_num = preview_port->buffer_num_recommended;
+   preview_port->buffer_size = preview_port->buffer_size_recommended;
+
+   vcos_log_trace("Creating buffer pool for GL renderer num %d size %d",
+         preview_port->buffer_num, preview_port->buffer_size);
+
+   /* Pool + queue to hold preview frames */
+   state->preview_pool = mmal_port_pool_create(preview_port,
+         preview_port->buffer_num, preview_port->buffer_size);
+
+   if (! state->preview_pool)
+   {
+      vcos_log_error("Error allocating pool");
+      status = MMAL_ENOMEM;
+      goto end;
+   }
+
+   /* Place filled buffers from the preview port in a queue to render */
+   state->preview_queue = mmal_queue_create();
+   if (! state->preview_queue)
+   {
+      vcos_log_error("Error allocating queue");
+      status = MMAL_ENOMEM;
+      goto end;
+   }
+
+   /* Enable preview port callback */
+   preview_port->userdata = (struct MMAL_PORT_USERDATA_T*) state;
+   status = mmal_port_enable(preview_port, preview_output_cb);
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Failed to camera preview port");
+      goto end;
+   }
+end:
+   return (status == MMAL_SUCCESS ? 0 : -1);
+}
+
+/* Initialises GL preview state and creates the dispmanx native window.
+ * @param state Pointer to the GL preview state.
+ * @return Zero if successful.
+ */
+int raspitex_init(RASPITEX_STATE *state)
+{
+   VCOS_STATUS_T status;
+   int rc;
+   vcos_init();
+
+   vcos_log_register("RaspiTex", VCOS_LOG_CATEGORY);
+   vcos_log_set_level(VCOS_LOG_CATEGORY,
+         state->verbose ? VCOS_LOG_INFO : VCOS_LOG_WARN);
+   vcos_log_trace("%s", VCOS_FUNCTION);
+
+   status = vcos_semaphore_create(&state->capture.start_sem,
+         "glcap_start_sem", 1);
+   if (status != VCOS_SUCCESS)
+      goto error;
+
+   status = vcos_semaphore_create(&state->capture.completed_sem,
+         "glcap_completed_sem", 0);
+   if (status != VCOS_SUCCESS)
+      goto error;
+
+   switch (state->scene_id)
+   {
+      case RASPITEX_SCENE_SQUARE:
+         rc = square_open(state);
+         break;
+      case RASPITEX_SCENE_MIRROR:
+         rc = mirror_open(state);
+         break;
+      case RASPITEX_SCENE_TEAPOT:
+         rc = teapot_open(state);
+         break;
+      case RASPITEX_SCENE_YUV:
+         rc = yuv_open(state);
+         break;
+      case RASPITEX_SCENE_SOBEL:
+         rc = sobel_open(state);
+         break;
+      case RASPITEX_SCENE_VCSM_SQUARE:
+         rc = vcsm_square_open(state);
+         break;
+      default:
+         rc = -1;
+         break;
+   }
+   if (rc != 0)
+      goto error;
+
+   return 0;
+
+error:
+   vcos_log_error("%s: failed", VCOS_FUNCTION);
+   return -1;
+}
+
+/* Destroys the pools of buffers used by the GL renderer.
+ * @param  state Pointer to the GL preview state.
+ */
+void raspitex_destroy(RASPITEX_STATE *state)
+{
+   vcos_log_trace("%s", VCOS_FUNCTION);
+   if (state->preview_pool)
+   {
+      mmal_pool_destroy(state->preview_pool);
+      state->preview_pool = NULL;
+   }
+
+   if (state->preview_queue)
+   {
+      mmal_queue_destroy(state->preview_queue);
+      state->preview_queue = NULL;
+   }
+
+   if (state->ops.destroy_native_window)
+      state->ops.destroy_native_window(state);
+
+   if (state->ops.close)
+      state->ops.close(state);
+
+   vcos_semaphore_delete(&state->capture.start_sem);
+   vcos_semaphore_delete(&state->capture.completed_sem);
+}
+
+/* Initialise the GL / window state to sensible defaults.
+ * Also initialise any rendering parameters e.g. the scene
+ *
+ * @param state Pointer to the GL preview state.
+ * @return Zero if successful.
+ */
+void raspitex_set_defaults(RASPITEX_STATE *state)
+{
+   memset(state, 0, sizeof(*state));
+   state->version_major = RASPITEX_VERSION_MAJOR;
+   state->version_minor = RASPITEX_VERSION_MINOR;
+   state->display = EGL_NO_DISPLAY;
+   state->surface = EGL_NO_SURFACE;
+   state->context = EGL_NO_CONTEXT;
+   state->egl_image = EGL_NO_IMAGE_KHR;
+   state->y_egl_image = EGL_NO_IMAGE_KHR;
+   state->u_egl_image = EGL_NO_IMAGE_KHR;
+   state->v_egl_image = EGL_NO_IMAGE_KHR;
+   state->opacity = 255;
+   state->width = DEFAULT_WIDTH;
+   state->height = DEFAULT_HEIGHT;
+   state->scene_id = RASPITEX_SCENE_SQUARE;
+
+   state->ops.create_native_window = raspitexutil_create_native_window;
+   state->ops.gl_init = raspitexutil_gl_init_1_0;
+   state->ops.update_model = raspitexutil_update_model;
+   state->ops.redraw = raspitexutil_redraw;
+   state->ops.capture = raspitexutil_capture_bgra;
+   state->ops.gl_term = raspitexutil_gl_term;
+   state->ops.destroy_native_window = raspitexutil_destroy_native_window;
+   state->ops.close = raspitexutil_close;
+}
+
+/* Stops the rendering loop and destroys MMAL resources
+ * @param state  Pointer to the GL preview state.
+ */
+void raspitex_stop(RASPITEX_STATE *state)
+{
+   if (! state->preview_stop)
+   {
+      vcos_log_trace("Stopping GL preview");
+      state->preview_stop = 1;
+      vcos_thread_join(&state->preview_thread, NULL);
+   }
+}
+
+/**
+ * Starts the worker / GL renderer thread.
+ * @pre raspitex_init was successful
+ * @pre raspitex_configure_preview_port was successful
+ * @param state Pointer to the GL preview state.
+ * @return Zero on success, otherwise, -1 is returned
+ * */
+int raspitex_start(RASPITEX_STATE *state)
+{
+   VCOS_STATUS_T status;
+
+   vcos_log_trace("%s", VCOS_FUNCTION);
+   status = vcos_thread_create(&state->preview_thread, "preview-worker",
+         NULL, preview_worker, state);
+
+   if (status != VCOS_SUCCESS)
+      vcos_log_error("%s: Failed to start worker thread %d",
+            VCOS_FUNCTION, status);
+
+   return (status == VCOS_SUCCESS ? 0 : -1);
+}
+
+/**
+ * Writes the next GL frame-buffer to a RAW .ppm formatted file
+ * using the specified file-handle.
+ * @param state Pointer to the GL preview state.
+ * @param outpt_file Output file handle for the ppm image.
+ * @return Zero on success.
+ */
+int raspitex_capture(RASPITEX_STATE *state, FILE *output_file)
+{
+   int rc = 0;
+   uint8_t *buffer = NULL;
+   size_t size = 0;
+
+   vcos_log_trace("%s: state %p file %p", VCOS_FUNCTION,
+         state, output_file);
+
+   if (state && output_file)
+   {
+      /* Only request one capture at a time */
+      vcos_semaphore_wait(&state->capture.start_sem);
+      state->capture.request = 1;
+
+      /* Wait for capture to start */
+      vcos_semaphore_wait(&state->capture.completed_sem);
+
+      /* Take ownership of the captured buffer */
+      buffer = state->capture.buffer;
+      size = state->capture.size;
+
+      state->capture.request = 0;
+      state->capture.buffer = 0;
+      state->capture.size = 0;
+
+      /* Allow another capture to be requested */
+      vcos_semaphore_post(&state->capture.start_sem);
+   }
+   if (size == 0 || ! buffer)
+   {
+      vcos_log_error("%s: capture failed", VCOS_FUNCTION);
+      rc = -1;
+      goto end;
+   }
+
+   raspitexutil_brga_to_rgba(buffer, size);
+   rc = write_tga(output_file, state->width, state->height, buffer, size);
+   fflush(output_file);
+
+end:
+   free(buffer);
+   return rc;
+}
diff --git a/host_applications/linux/apps/raspicam/RaspiTex.h b/host_applications/linux/apps/raspicam/RaspiTex.h
new file mode 100755 (executable)
index 0000000..712a5ba
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, Tim Gover
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef RASPITEX_H_
+#define RASPITEX_H_
+
+#include <stdio.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include "interface/khronos/include/EGL/eglext_brcm.h"
+#include "interface/mmal/mmal.h"
+
+#define RASPITEX_VERSION_MAJOR 1
+#define RASPITEX_VERSION_MINOR 0
+
+typedef enum {
+   RASPITEX_SCENE_SQUARE = 0,
+   RASPITEX_SCENE_MIRROR,
+   RASPITEX_SCENE_TEAPOT,
+   RASPITEX_SCENE_YUV,
+   RASPITEX_SCENE_SOBEL,
+   RASPITEX_SCENE_VCSM_SQUARE,
+
+} RASPITEX_SCENE_T;
+
+struct RASPITEX_STATE;
+
+typedef struct RASPITEX_SCENE_OPS
+{
+   /// Creates a native window that will be used by egl_init
+   /// to create a window surface.
+   int (*create_native_window)(struct RASPITEX_STATE *state);
+
+   /// Creates EGL surface for native window
+   int (*gl_init)(struct RASPITEX_STATE *state);
+
+   /// Updates the RGBX texture from the next MMAL buffer
+   /// Set to null if this texture type is not required
+   int (*update_texture)(struct RASPITEX_STATE *state, EGLClientBuffer mm_buf);
+
+   /// Updates the Y' plane texture from the next MMAL buffer
+   /// Set to null if this texture type is not required
+   int (*update_y_texture)(struct RASPITEX_STATE *state, EGLClientBuffer mm_buf);
+
+   /// Updates the U plane texture from the next MMAL buffer
+   /// Set to null if this texture type is not required
+   int (*update_u_texture)(struct RASPITEX_STATE *state, EGLClientBuffer mm_buf);
+
+   /// Updates the V plane texture from the next MMAL buffer
+   /// Set to null if this texture type is not required
+   int (*update_v_texture)(struct RASPITEX_STATE *state, EGLClientBuffer mm_buf);
+
+   /// Advance to the next animation step
+   int (*update_model)(struct RASPITEX_STATE *state);
+
+   /// Draw the scene - called after update_model
+   int (*redraw)(struct RASPITEX_STATE *state);
+
+   /// Allocates a buffer and copies the pixels from the current
+   /// frame-buffer into it.
+   int (*capture)(struct RASPITEX_STATE *state,
+         uint8_t **buffer, size_t *buffer_size);
+
+   /// Creates EGL surface for native window
+   void (*gl_term)(struct RASPITEX_STATE *state);
+
+   /// Destroys the native window
+   void (*destroy_native_window)(struct RASPITEX_STATE *state);
+
+   /// Called when the scene is unloaded
+   void (*close)(struct RASPITEX_STATE *state);
+} RASPITEX_SCENE_OPS;
+
+typedef struct RASPITEX_CAPTURE
+{
+   /// Wait for previous capture to complete
+   VCOS_SEMAPHORE_T start_sem;
+
+   /// Posted once the capture is complete
+   VCOS_SEMAPHORE_T completed_sem;
+
+   /// The RGB capture buffer
+   uint8_t *buffer;
+
+   /// Size of the captured buffer in bytes
+   size_t size;
+
+   /// Frame-buffer capture has been requested. Could use
+   /// a queue instead here to allow multiple capture requests.
+   int request;
+} RASPITEX_CAPTURE;
+
+/**
+ * Contains the internal state and configuration for the GL rendered
+ * preview window.
+ */
+typedef struct RASPITEX_STATE
+{
+   int version_major;                  /// For binary compatibility
+   int version_minor;                  /// Incremented for new features
+   MMAL_PORT_T *preview_port;          /// Source port for preview opaque buffers
+   MMAL_POOL_T *preview_pool;          /// Pool for storing opaque buffer handles
+   MMAL_QUEUE_T *preview_queue;        /// Queue preview buffers to display in order
+   VCOS_THREAD_T preview_thread;       /// Preview worker / GL rendering thread
+   uint32_t preview_stop;              /// If zero the worker can continue
+
+   /* Copy of preview window params */
+   int32_t preview_x;                  /// x-offset of preview window
+   int32_t preview_y;                  /// y-offset of preview window
+   int32_t preview_width;              /// preview y-plane width in pixels
+   int32_t preview_height;             /// preview y-plane height in pixels
+
+   /* Display rectangle for the native window */
+   int32_t x;                          /// x-offset in pixels
+   int32_t y;                          /// y-offset in pixels
+   int32_t width;                      /// width in pixels
+   int32_t height;                     /// height in pixels
+   int opacity;                        /// Alpha value for display element
+   int gl_win_defined;                 /// Use rect from --glwin instead of preview
+
+   /* DispmanX info. This might be unused if a custom create_native_window
+    * does something else. */
+   DISPMANX_DISPLAY_HANDLE_T disp;     /// Dispmanx display for GL preview
+   EGL_DISPMANX_WINDOW_T win;          /// Dispmanx handle for preview surface
+
+   EGLNativeWindowType* native_window; /// Native window used for EGL surface
+   EGLDisplay display;                 /// The current EGL display
+   EGLSurface surface;                 /// The current EGL surface
+   EGLContext context;                 /// The current EGL context
+   const EGLint *egl_config_attribs;   /// GL scenes preferred EGL configuration
+
+   GLuint texture;                     /// Name for the preview texture
+   EGLImageKHR egl_image;              /// The current preview EGL image
+
+   GLuint y_texture;                   /// The Y plane texture
+   EGLImageKHR y_egl_image;            /// EGL image for Y plane texture
+   GLuint u_texture;                   /// The U plane texture
+   EGLImageKHR u_egl_image;            /// EGL image for U plane texture
+   GLuint v_texture;                   /// The V plane texture
+   EGLImageKHR v_egl_image;            /// EGL image for V plane texture
+
+   MMAL_BUFFER_HEADER_T *preview_buf;  /// MMAL buffer currently bound to texture(s)
+
+   RASPITEX_SCENE_T scene_id;          /// Id of the scene to load
+   RASPITEX_SCENE_OPS ops;             /// The interface for the current scene
+   void *scene_state;                  /// Pointer to scene specific data
+   int verbose;                        /// Log FPS
+
+   RASPITEX_CAPTURE capture;           /// Frame-buffer capture state
+
+} RASPITEX_STATE;
+
+int raspitex_init(RASPITEX_STATE *state);
+void raspitex_destroy(RASPITEX_STATE *state);
+int raspitex_start(RASPITEX_STATE *state);
+void raspitex_stop(RASPITEX_STATE *state);
+void raspitex_set_defaults(RASPITEX_STATE *state);
+int raspitex_configure_preview_port(RASPITEX_STATE *state,
+      MMAL_PORT_T *preview_port);
+void raspitex_display_help();
+int raspitex_parse_cmdline(RASPITEX_STATE *state,
+      const char *arg1, const char *arg2);
+int raspitex_capture(RASPITEX_STATE *state, FILE* output_file);
+
+#endif /* RASPITEX_H_ */
diff --git a/host_applications/linux/apps/raspicam/RaspiTexUtil.c b/host_applications/linux/apps/raspicam/RaspiTexUtil.c
new file mode 100755 (executable)
index 0000000..d5b5954
--- /dev/null
@@ -0,0 +1,597 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, Tim Gover
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "RaspiTexUtil.h"
+#include "RaspiTex.h"
+#include <bcm_host.h>
+#include <GLES2/gl2.h>
+
+VCOS_LOG_CAT_T raspitex_log_category;
+
+/**
+ * \file RaspiTexUtil.c
+ *
+ * Provides default implementations for the raspitex_scene_ops functions
+ * and general utility functions.
+ */
+
+/**
+ * Deletes textures and EGL surfaces and context.
+ * @param   raspitex_state  Pointer to the Raspi
+ */
+void raspitexutil_gl_term(RASPITEX_STATE *raspitex_state)
+{
+   vcos_log_trace("%s", VCOS_FUNCTION);
+
+   /* Delete OES textures */
+   glDeleteTextures(1, &raspitex_state->texture);
+   eglDestroyImageKHR(raspitex_state->display, raspitex_state->egl_image);
+   raspitex_state->egl_image = EGL_NO_IMAGE_KHR;
+
+   glDeleteTextures(1, &raspitex_state->y_texture);
+   eglDestroyImageKHR(raspitex_state->display, raspitex_state->y_egl_image);
+   raspitex_state->y_egl_image = EGL_NO_IMAGE_KHR;
+
+   glDeleteTextures(1, &raspitex_state->u_texture);
+   eglDestroyImageKHR(raspitex_state->display, raspitex_state->u_egl_image);
+   raspitex_state->u_egl_image = EGL_NO_IMAGE_KHR;
+
+   glDeleteTextures(1, &raspitex_state->v_texture);
+   eglDestroyImageKHR(raspitex_state->display, raspitex_state->v_egl_image);
+   raspitex_state->v_egl_image = EGL_NO_IMAGE_KHR;
+
+   /* Terminate EGL */
+   eglMakeCurrent(raspitex_state->display, EGL_NO_SURFACE,
+         EGL_NO_SURFACE, EGL_NO_CONTEXT);
+   eglDestroyContext(raspitex_state->display, raspitex_state->context);
+   eglDestroySurface(raspitex_state->display, raspitex_state->surface);
+   eglTerminate(raspitex_state->display);
+}
+
+/** Creates a native window for the GL surface using dispmanx
+ * @param raspitex_state A pointer to the GL preview state.
+ * @return Zero if successful, otherwise, -1 is returned.
+ */
+int raspitexutil_create_native_window(RASPITEX_STATE *raspitex_state)
+{
+   VC_DISPMANX_ALPHA_T alpha = {DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS, 255, 0};
+   VC_RECT_T src_rect = {0};
+   VC_RECT_T dest_rect = {0};
+   uint32_t disp_num = 0; // Primary
+   uint32_t layer_num = 0;
+   DISPMANX_ELEMENT_HANDLE_T elem;
+   DISPMANX_UPDATE_HANDLE_T update;
+
+   alpha.opacity = raspitex_state->opacity;
+   dest_rect.x = raspitex_state->x;
+   dest_rect.y = raspitex_state->y;
+   dest_rect.width = raspitex_state->width;
+   dest_rect.height = raspitex_state->height;
+
+   vcos_log_trace("%s: %d,%d,%d,%d %d,%d,0x%x,0x%x", VCOS_FUNCTION,
+         src_rect.x, src_rect.y, src_rect.width, src_rect.height,
+         dest_rect.x, dest_rect.y, dest_rect.width, dest_rect.height);
+
+   src_rect.width = dest_rect.width << 16;
+   src_rect.height = dest_rect.height << 16;
+
+   raspitex_state->disp = vc_dispmanx_display_open(disp_num);
+   if (raspitex_state->disp == DISPMANX_NO_HANDLE)
+   {
+      vcos_log_error("Failed to open display handle");
+      goto error;
+   }
+
+   update = vc_dispmanx_update_start(0);
+   if (update == DISPMANX_NO_HANDLE)
+   {
+      vcos_log_error("Failed to open update handle");
+      goto error;
+   }
+
+   elem = vc_dispmanx_element_add(update, raspitex_state->disp, layer_num,
+         &dest_rect, 0, &src_rect, DISPMANX_PROTECTION_NONE, &alpha, NULL,
+         DISPMANX_NO_ROTATE);
+   if (elem == DISPMANX_NO_HANDLE)
+   {
+      vcos_log_error("Failed to create element handle");
+      goto error;
+   }
+
+   raspitex_state->win.element = elem;
+   raspitex_state->win.width = raspitex_state->width;
+   raspitex_state->win.height = raspitex_state->height;
+   vc_dispmanx_update_submit_sync(update);
+
+   raspitex_state->native_window = (EGLNativeWindowType*) &raspitex_state->win;
+
+   return 0;
+error:
+   return -1;
+}
+
+/** Destroys the pools of buffers used by the GL renderer.
+ * @param raspitex_state A pointer to the GL preview state.
+ */
+void raspitexutil_destroy_native_window(RASPITEX_STATE *raspitex_state)
+{
+   vcos_log_trace("%s", VCOS_FUNCTION);
+   if (raspitex_state->disp != DISPMANX_NO_HANDLE)
+   {
+      vc_dispmanx_display_close(raspitex_state->disp);
+      raspitex_state->disp = DISPMANX_NO_HANDLE;
+   }
+}
+
+/** Creates the EGL context and window surface for the native window
+ * using specified arguments.
+ * @param raspitex_state  A pointer to the GL preview state. This contains
+ *                        the native_window pointer.
+ * @param attribs         The config attributes.
+ * @param context_attribs The context attributes.
+ * @return Zero if successful.
+ */
+static int raspitexutil_gl_common(RASPITEX_STATE *raspitex_state,
+      const EGLint attribs[], const EGLint context_attribs[])
+{
+   EGLConfig config;
+   EGLint num_configs;
+
+   vcos_log_trace("%s", VCOS_FUNCTION);
+
+   if (raspitex_state->native_window == NULL)
+   {
+      vcos_log_error("%s: No native window", VCOS_FUNCTION);
+      goto error;
+   }
+
+   raspitex_state->display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+   if (raspitex_state->display == EGL_NO_DISPLAY)
+   {
+      vcos_log_error("%s: Failed to get EGL display", VCOS_FUNCTION);
+      goto error;
+   }
+
+   if (! eglInitialize(raspitex_state->display, 0, 0))
+   {
+      vcos_log_error("%s: eglInitialize failed", VCOS_FUNCTION);
+      goto error;
+   }
+
+   if (! eglChooseConfig(raspitex_state->display, attribs, &config,
+            1, &num_configs))
+   {
+      vcos_log_error("%s: eglChooseConfig failed", VCOS_FUNCTION);
+      goto error;
+   }
+
+   raspitex_state->surface = eglCreateWindowSurface(raspitex_state->display,
+         config, raspitex_state->native_window, NULL);
+   if (raspitex_state->surface == EGL_NO_SURFACE)
+   {
+      vcos_log_error("%s: eglCreateWindowSurface failed", VCOS_FUNCTION);
+      goto error;
+   }
+
+   raspitex_state->context = eglCreateContext(raspitex_state->display,
+         config, EGL_NO_CONTEXT, context_attribs);
+   if (raspitex_state->context == EGL_NO_CONTEXT)
+   {
+      vcos_log_error("%s: eglCreateContext failed", VCOS_FUNCTION);
+      goto error;
+   }
+
+   if (!eglMakeCurrent(raspitex_state->display, raspitex_state->surface,
+            raspitex_state->surface, raspitex_state->context))
+   {
+      vcos_log_error("%s: Failed to activate EGL context", VCOS_FUNCTION);
+      goto error;
+   }
+
+   return 0;
+
+error:
+   vcos_log_error("%s: EGL error 0x%08x", VCOS_FUNCTION, eglGetError());
+   raspitex_state->ops.gl_term(raspitex_state);
+   return -1;
+}
+
+/* Creates the RGBA and luma textures with some default parameters
+ * @param raspitex_state A pointer to the GL preview state.
+ * @return Zero if successful.
+ */
+int raspitexutil_create_textures(RASPITEX_STATE *raspitex_state)
+{
+   GLCHK(glGenTextures(1, &raspitex_state->texture));
+   GLCHK(glGenTextures(1, &raspitex_state->y_texture));
+   GLCHK(glGenTextures(1, &raspitex_state->u_texture));
+   GLCHK(glGenTextures(1, &raspitex_state->v_texture));
+   return 0;
+}
+
+/**
+ * Creates an OpenGL ES 1.X context.
+ * @param raspitex_state A pointer to the GL preview state.
+ * @return Zero if successful.
+ */
+int raspitexutil_gl_init_1_0(RASPITEX_STATE *raspitex_state)
+{
+   int rc;
+   const EGLint* attribs = raspitex_state->egl_config_attribs;
+
+   const EGLint default_attribs[] =
+   {
+      EGL_RED_SIZE,   8,
+      EGL_GREEN_SIZE, 8,
+      EGL_BLUE_SIZE,  8,
+      EGL_ALPHA_SIZE, 8,
+      EGL_DEPTH_SIZE, 16,
+      EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
+      EGL_NONE
+   };
+
+   const EGLint context_attribs[] =
+   {
+      EGL_CONTEXT_CLIENT_VERSION, 1,
+      EGL_NONE
+   };
+
+   if (! attribs)
+      attribs = default_attribs;
+
+   rc = raspitexutil_gl_common(raspitex_state, attribs, context_attribs);
+   if (rc != 0)
+      goto end;
+
+   GLCHK(glEnable(GL_TEXTURE_EXTERNAL_OES));
+   rc = raspitexutil_create_textures(raspitex_state);
+
+end:
+   return rc;
+}
+
+/**
+ * Creates an OpenGL ES 2.X context.
+ * @param raspitex_state A pointer to the GL preview state.
+ * @return Zero if successful.
+ */
+int raspitexutil_gl_init_2_0(RASPITEX_STATE *raspitex_state)
+{
+   int rc;
+   const EGLint* attribs = raspitex_state->egl_config_attribs;;
+
+   const EGLint default_attribs[] =
+   {
+      EGL_RED_SIZE,   8,
+      EGL_GREEN_SIZE, 8,
+      EGL_BLUE_SIZE,  8,
+      EGL_ALPHA_SIZE, 8,
+      EGL_DEPTH_SIZE, 16,
+      EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+      EGL_NONE
+   };
+
+   const EGLint context_attribs[] =
+   {
+      EGL_CONTEXT_CLIENT_VERSION, 2,
+      EGL_NONE
+   };
+
+   if (! attribs)
+      attribs = default_attribs;
+
+   vcos_log_trace("%s", VCOS_FUNCTION);
+   rc = raspitexutil_gl_common(raspitex_state, attribs, context_attribs);
+   if (rc != 0)
+      goto end;
+
+   rc = raspitexutil_create_textures(raspitex_state);
+end:
+   return rc;
+}
+
+/**
+ * Advances the texture and EGL image to the next MMAL buffer.
+ *
+ * @param display The EGL display.
+ * @param target The EGL image target e.g. EGL_IMAGE_BRCM_MULTIMEDIA
+ * @param mm_buf The EGL client buffer (mmal opaque buffer) that is used to
+ * create the EGL Image for the preview texture.
+ * @param egl_image Pointer to the EGL image to update with mm_buf.
+ * @param texture Pointer to the texture to update from EGL image.
+ * @return Zero if successful.
+ */
+int raspitexutil_do_update_texture(EGLDisplay display, EGLenum target,
+      EGLClientBuffer mm_buf, GLuint *texture, EGLImageKHR *egl_image)
+{
+   vcos_log_trace("%s: mm_buf %u", VCOS_FUNCTION, (unsigned) mm_buf);
+   GLCHK(glBindTexture(GL_TEXTURE_EXTERNAL_OES, *texture));
+   if (*egl_image != EGL_NO_IMAGE_KHR)
+   {
+      /* Discard the EGL image for the preview frame */
+      eglDestroyImageKHR(display, *egl_image);
+      *egl_image = EGL_NO_IMAGE_KHR;
+   }
+
+   *egl_image = eglCreateImageKHR(display, EGL_NO_CONTEXT, target, mm_buf, NULL);
+   GLCHK(glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, *egl_image));
+
+   return 0;
+}
+
+/**
+ * Updates the RGBX texture to the specified MMAL buffer.
+ * @param raspitex_state A pointer to the GL preview state.
+ * @param mm_buf The MMAL buffer.
+ * @return Zero if successful.
+ */
+int raspitexutil_update_texture(RASPITEX_STATE *raspitex_state,
+      EGLClientBuffer mm_buf)
+{
+   return raspitexutil_do_update_texture(raspitex_state->display,
+         EGL_IMAGE_BRCM_MULTIMEDIA, mm_buf,
+         &raspitex_state->texture, &raspitex_state->egl_image);
+}
+
+/**
+ * Updates the Y plane texture to the specified MMAL buffer.
+ * @param raspitex_state A pointer to the GL preview state.
+ * @param mm_buf The MMAL buffer.
+ * @return Zero if successful.
+ */
+int raspitexutil_update_y_texture(RASPITEX_STATE *raspitex_state,
+      EGLClientBuffer mm_buf)
+{
+   return raspitexutil_do_update_texture(raspitex_state->display,
+         EGL_IMAGE_BRCM_MULTIMEDIA_Y, mm_buf,
+         &raspitex_state->y_texture, &raspitex_state->y_egl_image);
+}
+
+/**
+ * Updates the U plane texture to the specified MMAL buffer.
+ * @param raspitex_state A pointer to the GL preview state.
+ * @param mm_buf The MMAL buffer.
+ * @return Zero if successful.
+ */
+int raspitexutil_update_u_texture(RASPITEX_STATE *raspitex_state,
+      EGLClientBuffer mm_buf)
+{
+   return raspitexutil_do_update_texture(raspitex_state->display,
+         EGL_IMAGE_BRCM_MULTIMEDIA_U, mm_buf,
+         &raspitex_state->u_texture, &raspitex_state->u_egl_image);
+}
+
+/**
+ * Updates the V plane texture to the specified MMAL buffer.
+ * @param raspitex_state A pointer to the GL preview state.
+ * @param mm_buf The MMAL buffer.
+ * @return Zero if successful.
+ */
+int raspitexutil_update_v_texture(RASPITEX_STATE *raspitex_state,
+      EGLClientBuffer mm_buf)
+{
+   return raspitexutil_do_update_texture(raspitex_state->display,
+         EGL_IMAGE_BRCM_MULTIMEDIA_V, mm_buf,
+         &raspitex_state->v_texture, &raspitex_state->v_egl_image);
+}
+
+/**
+ * Default is a no-op
+ * @param raspitex_state A pointer to the GL preview state.
+ * @return Zero.
+ */
+int raspitexutil_update_model(RASPITEX_STATE* raspitex_state)
+{
+   (void) raspitex_state;
+   return 0;
+}
+
+/**
+ * Default is a no-op
+ * @param raspitex_state A pointer to the GL preview state.
+ * @return Zero.
+ */
+int raspitexutil_redraw(RASPITEX_STATE* raspitex_state)
+{
+   (void) raspitex_state;
+   return 0;
+}
+
+/**
+ * Default is a no-op
+ * @param raspitex_state A pointer to the GL preview state.
+ */
+void raspitexutil_close(RASPITEX_STATE* raspitex_state)
+{
+   (void) raspitex_state;
+}
+
+/**
+ * Performs an in-place byte swap from BGRA to RGBA.
+ * @param buffer The buffer to modify.
+ * @param size Size of the buffer in bytes.
+ */
+void raspitexutil_brga_to_rgba(uint8_t *buffer, size_t size)
+{
+   uint8_t* out = buffer;
+   uint8_t* end = buffer + size;
+
+   while (out < end)
+   {
+      uint8_t tmp = out[0];
+      out[0] = out[2];
+      out[2] = tmp;
+      out += 4;
+   }
+}
+
+/**
+ * Uses glReadPixels to grab the current frame-buffer contents
+ * and returns the result in a newly allocate buffer along with
+ * the its size.
+ * Data is returned in BGRA format for TGA output. PPM output doesn't
+ * require the channel order swap but would require a vflip. The TGA
+ * format also supports alpha. The byte swap is not done in this function
+ * to avoid blocking the GL rendering thread.
+ * @param state Pointer to the GL preview state.
+ * @param buffer Address of pointer to set to pointer to new buffer.
+ * @param buffer_size The size of the new buffer in bytes (out param)
+ * @return Zero if successful.
+ */
+int raspitexutil_capture_bgra(RASPITEX_STATE *state,
+      uint8_t **buffer, size_t *buffer_size)
+{
+   const int bytes_per_pixel = 4;
+
+   vcos_log_trace("%s: %dx%d %d", VCOS_FUNCTION,
+         state->width, state->height, bytes_per_pixel);
+
+   *buffer_size = state->width * state->height * bytes_per_pixel;
+   *buffer = calloc(*buffer_size, 1);
+   if (! *buffer)
+      goto error;
+
+   glReadPixels(0, 0, state->width, state->height, GL_RGBA,
+         GL_UNSIGNED_BYTE, *buffer);
+   if (glGetError() != GL_NO_ERROR)
+      goto error;
+
+   return 0;
+
+error:
+   *buffer_size = 0;
+   if (*buffer)
+      free(*buffer);
+   *buffer = NULL;
+   return -1;
+}
+
+
+/**
+ * Takes a description of shader program, compiles it and gets the locations
+ * of uniforms and attributes.
+ *
+ * @param p The shader program state.
+ * @return Zero if successful.
+ */
+int raspitexutil_build_shader_program(RASPITEXUTIL_SHADER_PROGRAM_T *p)
+{
+    GLint status;
+    int i = 0;
+    char log[1024];
+    int logLen = 0;
+    vcos_assert(p);
+    vcos_assert(p->vertex_source);
+    vcos_assert(p->fragment_source);
+
+    if (! (p && p->vertex_source && p->fragment_source))
+        goto fail;
+
+    p->vs = p->fs = 0;
+
+    p->vs = glCreateShader(GL_VERTEX_SHADER);
+    glShaderSource(p->vs, 1, &p->vertex_source, NULL);
+    glCompileShader(p->vs);
+    glGetShaderiv(p->vs, GL_COMPILE_STATUS, &status);
+    if (! status) {
+        glGetShaderInfoLog(p->vs, sizeof(log), &logLen, log);
+        vcos_log_error("Program info log %s", log);
+        goto fail;
+    }
+
+    p->fs = glCreateShader(GL_FRAGMENT_SHADER);
+    glShaderSource(p->fs, 1, &p->fragment_source, NULL);
+    glCompileShader(p->fs);
+
+    glGetShaderiv(p->fs, GL_COMPILE_STATUS, &status);
+    if (! status) {
+        glGetShaderInfoLog(p->fs, sizeof(log), &logLen, log);
+        vcos_log_error("Program info log %s", log);
+        goto fail;
+    }
+
+    p->program = glCreateProgram();
+    glAttachShader(p->program, p->vs);
+    glAttachShader(p->program, p->fs);
+    glLinkProgram(p->program);
+    glGetProgramiv(p->program, GL_LINK_STATUS, &status);
+    if (! status)
+    {
+        vcos_log_error("Failed to link shader program");
+        glGetProgramInfoLog(p->program, sizeof(log), &logLen, log);
+        vcos_log_error("Program info log %s", log);
+        goto fail;
+    }
+
+    for (i = 0; i < SHADER_MAX_ATTRIBUTES; ++i)
+    {
+        if (! p->attribute_names[i])
+            break;
+        p->attribute_locations[i] = glGetAttribLocation(p->program, p->attribute_names[i]);
+        if (p->attribute_locations[i] == -1)
+        {
+            vcos_log_error("Failed to get location for attribute %s",
+                  p->attribute_names[i]);
+            goto fail;
+        }
+        else {
+            vcos_log_trace("Attribute for %s is %d",
+                  p->attribute_names[i], p->attribute_locations[i]);
+        }
+    }
+
+    for (i = 0; i < SHADER_MAX_UNIFORMS; ++i)
+    {
+        if (! p->uniform_names[i])
+            break;
+        p->uniform_locations[i] = glGetUniformLocation(p->program, p->uniform_names[i]);
+        if (p->uniform_locations[i] == -1)
+        {
+            vcos_log_error("Failed to get location for uniform %s",
+                  p->uniform_names[i]);
+            goto fail;
+        }
+        else {
+            vcos_log_trace("Uniform for %s is %d",
+                  p->uniform_names[i], p->uniform_locations[i]);
+        }
+    }
+
+    return 0;
+
+fail:
+    vcos_log_error("%s: Failed to build shader program", VCOS_FUNCTION);
+    if (p)
+    {
+        glDeleteProgram(p->program);
+        glDeleteShader(p->fs);
+        glDeleteShader(p->vs);
+    }
+    return -1;
+}
+
diff --git a/host_applications/linux/apps/raspicam/RaspiTexUtil.h b/host_applications/linux/apps/raspicam/RaspiTexUtil.h
new file mode 100755 (executable)
index 0000000..cf5dfb3
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, Tim Gover
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef RASPITEX_UTIL_H_
+#define RASPITEX_UTIL_H_
+
+#define VCOS_LOG_CATEGORY (&raspitex_log_category)
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include "RaspiTex.h"
+#include "interface/vcos/vcos.h"
+
+extern VCOS_LOG_CAT_T raspitex_log_category;
+
+#define SHADER_MAX_ATTRIBUTES 16
+#define SHADER_MAX_UNIFORMS   16
+/**
+ * Container for a simple shader program. The uniform and attribute locations
+ * are automatically setup by raspitex_build_shader_program.
+ */
+typedef struct RASPITEXUTIL_SHADER_PROGRAM_T
+{
+   const char *vertex_source;       /// Pointer to vertex shader source
+   const char *fragment_source;     /// Pointer to fragment shader source
+
+   /// Array of uniform names for raspitex_build_shader_program to process
+   const char *uniform_names[SHADER_MAX_UNIFORMS];
+   /// Array of attribute names for raspitex_build_shader_program to process
+   const char *attribute_names[SHADER_MAX_ATTRIBUTES];
+
+   GLint vs;                        /// Vertex shader handle
+   GLint fs;                        /// Fragment shader handle
+   GLint program;                   /// Shader program handle
+
+   /// The locations for uniforms defined in uniform_names
+   GLint uniform_locations[SHADER_MAX_UNIFORMS];
+
+   /// The locations for attributes defined in attribute_names
+   GLint attribute_locations[SHADER_MAX_ATTRIBUTES];
+} RASPITEXUTIL_SHADER_PROGRAM_T;
+
+
+/* Uncomment to enable extra GL error checking */
+//#define CHECK_GL_ERRORS
+#if defined(CHECK_GL_ERRORS)
+#define GLCHK(X) \
+do { \
+    GLenum err = GL_NO_ERROR; \
+    X; \
+   while ((err = glGetError())) \
+   { \
+      vcos_log_error("GL error 0x%x in " #X "file %s line %d", err, __FILE__,__LINE__); \
+      vcos_assert(err == GL_NO_ERROR); \
+      exit(err); \
+   } \
+} \
+while(0)
+#else
+#define GLCHK(X) X
+#endif /* CHECK_GL_ERRORS */
+
+/* Default GL scene ops functions */
+int raspitexutil_create_native_window(RASPITEX_STATE *raspitex_state);
+int raspitexutil_gl_init_1_0(RASPITEX_STATE *raspitex_state);
+int raspitexutil_gl_init_2_0(RASPITEX_STATE *raspitex_state);
+int raspitexutil_update_model(RASPITEX_STATE* raspitex_state);
+int raspitexutil_redraw(RASPITEX_STATE* raspitex_state);
+void raspitexutil_gl_term(RASPITEX_STATE *raspitex_state);
+void raspitexutil_destroy_native_window(RASPITEX_STATE *raspitex_state);
+int raspitexutil_create_textures(RASPITEX_STATE *raspitex_state);
+int raspitexutil_update_texture(RASPITEX_STATE *raspitex_state,
+      EGLClientBuffer mm_buf);
+int raspitexutil_update_y_texture(RASPITEX_STATE *raspitex_state,
+      EGLClientBuffer mm_buf);
+int raspitexutil_update_u_texture(RASPITEX_STATE *raspitex_state,
+      EGLClientBuffer mm_buf);
+int raspitexutil_update_v_texture(RASPITEX_STATE *raspitex_state,
+      EGLClientBuffer mm_buf);
+int raspitexutil_capture_bgra(struct RASPITEX_STATE *state,
+      uint8_t **buffer, size_t *buffer_size);
+void raspitexutil_close(RASPITEX_STATE* raspitex_state);
+
+/* Utility functions */
+int raspitexutil_build_shader_program(RASPITEXUTIL_SHADER_PROGRAM_T *p);
+void raspitexutil_brga_to_rgba(uint8_t *buffer, size_t size);
+
+#endif /* RASPITEX_UTIL_H_ */
diff --git a/host_applications/linux/apps/raspicam/RaspiVid.c b/host_applications/linux/apps/raspicam/RaspiVid.c
new file mode 100755 (executable)
index 0000000..20b0ad5
--- /dev/null
@@ -0,0 +1,3018 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, James Hughes
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * \file RaspiVid.c
+ * Command line program to capture a camera video stream and encode it to file.
+ * Also optionally display a preview/viewfinder of current camera input.
+ *
+ * \date 28th Feb 2013
+ * \Author: James Hughes
+ *
+ * Description
+ *
+ * 3 components are created; camera, preview and video encoder.
+ * Camera component has three ports, preview, video and stills.
+ * This program connects preview and video to the preview and video
+ * encoder. Using mmal we don't need to worry about buffers between these
+ * components, but we do need to handle buffers from the encoder, which
+ * are simply written straight to the file in the requisite buffer callback.
+ *
+ * If raw option is selected, a video splitter component is connected between
+ * camera and preview. This allows us to set up callback for raw camera data
+ * (in YUV420 or RGB format) which might be useful for further image processing.
+ *
+ * We use the RaspiCamControl code to handle the specific camera settings.
+ * We use the RaspiPreview code to handle the (generic) preview window
+ */
+
+// We use some GNU extensions (basename)
+#ifndef _GNU_SOURCE
+   #define _GNU_SOURCE
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <sysexits.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#define VERSION_STRING "v1.3.12"
+
+#include "bcm_host.h"
+#include "interface/vcos/vcos.h"
+
+#include "interface/mmal/mmal.h"
+#include "interface/mmal/mmal_logging.h"
+#include "interface/mmal/mmal_buffer.h"
+#include "interface/mmal/util/mmal_util.h"
+#include "interface/mmal/util/mmal_util_params.h"
+#include "interface/mmal/util/mmal_default_components.h"
+#include "interface/mmal/util/mmal_connection.h"
+#include "interface/mmal/mmal_parameters_camera.h"
+
+#include "RaspiCamControl.h"
+#include "RaspiPreview.h"
+#include "RaspiCLI.h"
+
+#include <semaphore.h>
+
+#include <stdbool.h>
+
+// Standard port setting for the camera component
+#define MMAL_CAMERA_PREVIEW_PORT 0
+#define MMAL_CAMERA_VIDEO_PORT 1
+#define MMAL_CAMERA_CAPTURE_PORT 2
+
+// Port configuration for the splitter component
+#define SPLITTER_OUTPUT_PORT 0
+#define SPLITTER_PREVIEW_PORT 1
+
+// Video format information
+// 0 implies variable
+#define VIDEO_FRAME_RATE_NUM 30
+#define VIDEO_FRAME_RATE_DEN 1
+
+/// Video render needs at least 2 buffers.
+#define VIDEO_OUTPUT_BUFFERS_NUM 3
+
+// Max bitrate we allow for recording
+const int MAX_BITRATE_MJPEG = 25000000; // 25Mbits/s
+const int MAX_BITRATE_LEVEL4 = 25000000; // 25Mbits/s
+const int MAX_BITRATE_LEVEL42 = 62500000; // 62.5Mbits/s
+
+/// Interval at which we check for an failure abort during capture
+const int ABORT_INTERVAL = 100; // ms
+
+
+/// Capture/Pause switch method
+/// Simply capture for time specified
+#define WAIT_METHOD_NONE           0
+/// Cycle between capture and pause for times specified
+#define WAIT_METHOD_TIMED          1
+/// Switch between capture and pause on keypress
+#define WAIT_METHOD_KEYPRESS       2
+/// Switch between capture and pause on signal
+#define WAIT_METHOD_SIGNAL         3
+/// Run/record forever
+#define WAIT_METHOD_FOREVER        4
+
+
+
+int mmal_status_to_int(MMAL_STATUS_T status);
+static void signal_handler(int signal_number);
+
+// Forward
+typedef struct RASPIVID_STATE_S RASPIVID_STATE;
+
+/** Struct used to pass information in encoder port userdata to callback
+ */
+typedef struct
+{
+   FILE *file_handle;                   /// File handle to write buffer data to.
+   RASPIVID_STATE *pstate;              /// pointer to our state in case required in callback
+   int abort;                           /// Set to 1 in callback if an error occurs to attempt to abort the capture
+   char *cb_buff;                       /// Circular buffer
+   int   cb_len;                        /// Length of buffer
+   int   cb_wptr;                       /// Current write pointer
+   int   cb_wrap;                       /// Has buffer wrapped at least once?
+   int   cb_data;                       /// Valid bytes in buffer
+#define IFRAME_BUFSIZE (60*1000)
+   int   iframe_buff[IFRAME_BUFSIZE];          /// buffer of iframe pointers
+   int   iframe_buff_wpos;
+   int   iframe_buff_rpos;
+   char  header_bytes[29];
+   int  header_wptr;
+   FILE *imv_file_handle;               /// File handle to write inline motion vectors to.
+   FILE *raw_file_handle;               /// File handle to write raw data to.
+   int  flush_buffers;
+   FILE *pts_file_handle;               /// File timestamps
+} PORT_USERDATA;
+
+/** Possible raw output formats
+ */
+typedef enum {
+   RAW_OUTPUT_FMT_YUV = 1,
+   RAW_OUTPUT_FMT_RGB,
+   RAW_OUTPUT_FMT_GRAY,
+} RAW_OUTPUT_FMT;
+
+/** Structure containing all state information for the current run
+ */
+struct RASPIVID_STATE_S
+{
+   int timeout;                        /// Time taken before frame is grabbed and app then shuts down. Units are milliseconds
+   int width;                          /// Requested width of image
+   int height;                         /// requested height of image
+   MMAL_FOURCC_T encoding;             /// Requested codec video encoding (MJPEG or H264)
+   int bitrate;                        /// Requested bitrate
+   int framerate;                      /// Requested frame rate (fps)
+   int intraperiod;                    /// Intra-refresh period (key frame rate)
+   int quantisationParameter;          /// Quantisation parameter - quality. Set bitrate 0 and set this for variable bitrate
+   int bInlineHeaders;                  /// Insert inline headers to stream (SPS, PPS)
+   char *filename;                     /// filename of output file
+   int verbose;                        /// !0 if want detailed run information
+   int demoMode;                       /// Run app in demo mode
+   int demoInterval;                   /// Interval between camera settings changes
+   int immutableInput;                 /// Flag to specify whether encoder works in place or creates a new buffer. Result is preview can display either
+                                       /// the camera output or the encoder output (with compression artifacts)
+   int profile;                        /// H264 profile to use for encoding
+   int level;                          /// H264 level to use for encoding
+   int waitMethod;                     /// Method for switching between pause and capture
+
+   int onTime;                         /// In timed cycle mode, the amount of time the capture is on per cycle
+   int offTime;                        /// In timed cycle mode, the amount of time the capture is off per cycle
+
+   int segmentSize;                    /// Segment mode In timed cycle mode, the amount of time the capture is off per cycle
+   int segmentWrap;                    /// Point at which to wrap segment counter
+   int segmentNumber;                  /// Current segment counter
+   int splitNow;                       /// Split at next possible i-frame if set to 1.
+   int splitWait;                      /// Switch if user wants splited files
+
+   RASPIPREVIEW_PARAMETERS preview_parameters;   /// Preview setup parameters
+   RASPICAM_CAMERA_PARAMETERS camera_parameters; /// Camera setup parameters
+
+   MMAL_COMPONENT_T *camera_component;    /// Pointer to the camera component
+   MMAL_COMPONENT_T *splitter_component;  /// Pointer to the splitter component
+   MMAL_COMPONENT_T *encoder_component;   /// Pointer to the encoder component
+   MMAL_CONNECTION_T *preview_connection; /// Pointer to the connection from camera or splitter to preview
+   MMAL_CONNECTION_T *splitter_connection;/// Pointer to the connection from camera to splitter
+   MMAL_CONNECTION_T *encoder_connection; /// Pointer to the connection from camera to encoder
+
+   MMAL_POOL_T *splitter_pool; /// Pointer to the pool of buffers used by splitter output port 0
+   MMAL_POOL_T *encoder_pool; /// Pointer to the pool of buffers used by encoder output port
+
+   PORT_USERDATA callback_data;        /// Used to move data to the encoder callback
+
+   int bCapturing;                     /// State of capture/pause
+   int bCircularBuffer;                /// Whether we are writing to a circular buffer
+
+   int inlineMotionVectors;             /// Encoder outputs inline Motion Vectors
+   char *imv_filename;                  /// filename of inline Motion Vectors output
+   int raw_output;                      /// Output raw video from camera as well
+   RAW_OUTPUT_FMT raw_output_fmt;       /// The raw video format
+   char *raw_filename;                  /// Filename for raw video output
+   int cameraNum;                       /// Camera number
+   int settings;                        /// Request settings from the camera
+   int sensor_mode;                                /// Sensor mode. 0=auto. Check docs/forum for modes selected by other values.
+   int intra_refresh_type;              /// What intra refresh type to use. -1 to not set.
+   int frame;
+   char *pts_filename;
+   int save_pts;
+   int64_t starttime;
+   int64_t lasttime;
+
+   bool netListen;
+};
+
+
+/// Structure to cross reference H264 profile strings against the MMAL parameter equivalent
+static XREF_T  profile_map[] =
+{
+   {"baseline",     MMAL_VIDEO_PROFILE_H264_BASELINE},
+   {"main",         MMAL_VIDEO_PROFILE_H264_MAIN},
+   {"high",         MMAL_VIDEO_PROFILE_H264_HIGH},
+//   {"constrained",  MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE} // Does anyone need this?
+};
+
+static int profile_map_size = sizeof(profile_map) / sizeof(profile_map[0]);
+
+/// Structure to cross reference H264 level strings against the MMAL parameter equivalent
+static XREF_T  level_map[] =
+{
+   {"4",           MMAL_VIDEO_LEVEL_H264_4},
+   {"4.1",         MMAL_VIDEO_LEVEL_H264_41},
+   {"4.2",         MMAL_VIDEO_LEVEL_H264_42},
+};
+
+static int level_map_size = sizeof(level_map) / sizeof(level_map[0]);
+
+static XREF_T  initial_map[] =
+{
+   {"record",     0},
+   {"pause",      1},
+};
+
+static int initial_map_size = sizeof(initial_map) / sizeof(initial_map[0]);
+
+static XREF_T  intra_refresh_map[] =
+{
+   {"cyclic",       MMAL_VIDEO_INTRA_REFRESH_CYCLIC},
+   {"adaptive",     MMAL_VIDEO_INTRA_REFRESH_ADAPTIVE},
+   {"both",         MMAL_VIDEO_INTRA_REFRESH_BOTH},
+   {"cyclicrows",   MMAL_VIDEO_INTRA_REFRESH_CYCLIC_MROWS},
+//   {"random",       MMAL_VIDEO_INTRA_REFRESH_PSEUDO_RAND} Cannot use random, crashes the encoder. No idea why.
+};
+
+static int intra_refresh_map_size = sizeof(intra_refresh_map) / sizeof(intra_refresh_map[0]);
+
+static XREF_T  raw_output_fmt_map[] =
+{
+   {"yuv",  RAW_OUTPUT_FMT_YUV},
+   {"rgb",  RAW_OUTPUT_FMT_RGB},
+   {"gray", RAW_OUTPUT_FMT_GRAY},
+};
+
+static int raw_output_fmt_map_size = sizeof(raw_output_fmt_map) / sizeof(raw_output_fmt_map[0]);
+
+static void display_valid_parameters(char *app_name);
+
+/// Command ID's and Structure defining our command line options
+#define CommandHelp         0
+#define CommandWidth        1
+#define CommandHeight       2
+#define CommandBitrate      3
+#define CommandOutput       4
+#define CommandVerbose      5
+#define CommandTimeout      6
+#define CommandDemoMode     7
+#define CommandFramerate    8
+#define CommandPreviewEnc   9
+#define CommandIntraPeriod  10
+#define CommandProfile      11
+#define CommandTimed        12
+#define CommandSignal       13
+#define CommandKeypress     14
+#define CommandInitialState 15
+#define CommandQP           16
+#define CommandInlineHeaders 17
+#define CommandSegmentFile  18
+#define CommandSegmentWrap  19
+#define CommandSegmentStart 20
+#define CommandSplitWait    21
+#define CommandCircular     22
+#define CommandIMV          23
+#define CommandCamSelect    24
+#define CommandSettings     25
+#define CommandSensorMode   26
+#define CommandIntraRefreshType 27
+#define CommandFlush        28
+#define CommandSavePTS      29
+#define CommandCodec        30
+#define CommandLevel        31
+#define CommandRaw          32
+#define CommandRawFormat    33
+#define CommandNetListen    34
+
+static COMMAND_LIST cmdline_commands[] =
+{
+   { CommandHelp,          "-help",       "?",  "This help information", 0 },
+   { CommandWidth,         "-width",      "w",  "Set image width <size>. Default 1920", 1 },
+   { CommandHeight,        "-height",     "h",  "Set image height <size>. Default 1080", 1 },
+   { CommandBitrate,       "-bitrate",    "b",  "Set bitrate. Use bits per second (e.g. 10MBits/s would be -b 10000000)", 1 },
+   { CommandOutput,        "-output",     "o",  "Output filename <filename> (to write to stdout, use '-o -').\n"
+         "\t\t  Connect to a remote IPv4 host (e.g. tcp://192.168.1.2:1234, udp://192.168.1.2:1234)\n"
+         "\t\t  To listen on a TCP port (IPv4) and wait for an incoming connection use -l\n"
+         "\t\t  (e.g. raspivid -l -o tcp://0.0.0.0:3333 -> bind to all network interfaces, raspivid -l -o tcp://192.168.1.1:3333 -> bind to a certain local IPv4)", 1 },
+   { CommandVerbose,       "-verbose",    "v",  "Output verbose information during run", 0 },
+   { CommandTimeout,       "-timeout",    "t",  "Time (in ms) to capture for. If not specified, set to 5s. Zero to disable", 1 },
+   { CommandDemoMode,      "-demo",       "d",  "Run a demo mode (cycle through range of camera options, no capture)", 1},
+   { CommandFramerate,     "-framerate",  "fps","Specify the frames per second to record", 1},
+   { CommandPreviewEnc,    "-penc",       "e",  "Display preview image *after* encoding (shows compression artifacts)", 0},
+   { CommandIntraPeriod,   "-intra",      "g",  "Specify the intra refresh period (key frame rate/GoP size). Zero to produce an initial I-frame and then just P-frames.", 1},
+   { CommandProfile,       "-profile",    "pf", "Specify H264 profile to use for encoding", 1},
+   { CommandTimed,         "-timed",      "td", "Cycle between capture and pause. -cycle on,off where on is record time and off is pause time in ms", 0},
+   { CommandSignal,        "-signal",     "s",  "Cycle between capture and pause on Signal", 0},
+   { CommandKeypress,      "-keypress",   "k",  "Cycle between capture and pause on ENTER", 0},
+   { CommandInitialState,  "-initial",    "i",  "Initial state. Use 'record' or 'pause'. Default 'record'", 1},
+   { CommandQP,            "-qp",         "qp", "Quantisation parameter. Use approximately 10-40. Default 0 (off)", 1},
+   { CommandInlineHeaders, "-inline",     "ih", "Insert inline headers (SPS, PPS) to stream", 0},
+   { CommandSegmentFile,   "-segment",    "sg", "Segment output file in to multiple files at specified interval <ms>", 1},
+   { CommandSegmentWrap,   "-wrap",       "wr", "In segment mode, wrap any numbered filename back to 1 when reach number", 1},
+   { CommandSegmentStart,  "-start",      "sn", "In segment mode, start with specified segment number", 1},
+   { CommandSplitWait,     "-split",      "sp", "In wait mode, create new output file for each start event", 0},
+   { CommandCircular,      "-circular",   "c",  "Run encoded data through circular buffer until triggered then save", 0},
+   { CommandIMV,           "-vectors",    "x",  "Output filename <filename> for inline motion vectors", 1 },
+   { CommandCamSelect,     "-camselect",  "cs", "Select camera <number>. Default 0", 1 },
+   { CommandSettings,      "-settings",   "set","Retrieve camera settings and write to stdout", 0},
+   { CommandSensorMode,    "-mode",       "md", "Force sensor mode. 0=auto. See docs for other modes available", 1},
+   { CommandIntraRefreshType,"-irefresh", "if", "Set intra refresh type", 1},
+   { CommandFlush,         "-flush",      "fl",  "Flush buffers in order to decrease latency", 0 },
+   { CommandSavePTS,       "-save-pts",   "pts","Save Timestamps to file for mkvmerge", 1 },
+   { CommandCodec,         "-codec",      "cd", "Specify the codec to use - H264 (default) or MJPEG", 1 },
+   { CommandLevel,         "-level",      "lev","Specify H264 level to use for encoding", 1},
+   { CommandRaw,           "-raw",        "r",  "Output filename <filename> for raw video", 1 },
+   { CommandRawFormat,     "-raw-format", "rf", "Specify output format for raw video. Default is yuv", 1},
+   { CommandNetListen,     "-listen",     "l", "Listen on a TCP socket", 0},
+};
+
+static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]);
+
+
+static struct
+{
+   char *description;
+   int nextWaitMethod;
+} wait_method_description[] =
+{
+      {"Simple capture",         WAIT_METHOD_NONE},
+      {"Capture forever",        WAIT_METHOD_FOREVER},
+      {"Cycle on time",          WAIT_METHOD_TIMED},
+      {"Cycle on keypress",      WAIT_METHOD_KEYPRESS},
+      {"Cycle on signal",        WAIT_METHOD_SIGNAL},
+};
+
+static int wait_method_description_size = sizeof(wait_method_description) / sizeof(wait_method_description[0]);
+
+
+
+/**
+ * Assign a default set of parameters to the state passed in
+ *
+ * @param state Pointer to state structure to assign defaults to
+ */
+static void default_status(RASPIVID_STATE *state)
+{
+   if (!state)
+   {
+      vcos_assert(0);
+      return;
+   }
+
+   // Default everything to zero
+   memset(state, 0, sizeof(RASPIVID_STATE));
+
+   // Now set anything non-zero
+   state->timeout = 5000;     // 5s delay before take image
+   state->width = 1920;       // Default to 1080p
+   state->height = 1080;
+   state->encoding = MMAL_ENCODING_H264;
+   state->bitrate = 17000000; // This is a decent default bitrate for 1080p
+   state->framerate = VIDEO_FRAME_RATE_NUM;
+   state->intraperiod = -1;    // Not set
+   state->quantisationParameter = 0;
+   state->demoMode = 0;
+   state->demoInterval = 250; // ms
+   state->immutableInput = 1;
+   state->profile = MMAL_VIDEO_PROFILE_H264_HIGH;
+   state->level = MMAL_VIDEO_LEVEL_H264_4;
+   state->waitMethod = WAIT_METHOD_NONE;
+   state->onTime = 5000;
+   state->offTime = 5000;
+
+   state->bCapturing = 0;
+   state->bInlineHeaders = 0;
+
+   state->segmentSize = 0;  // 0 = not segmenting the file.
+   state->segmentNumber = 1;
+   state->segmentWrap = 0; // Point at which to wrap segment number back to 1. 0 = no wrap
+   state->splitNow = 0;
+   state->splitWait = 0;
+
+   state->inlineMotionVectors = 0;
+   state->cameraNum = 0;
+   state->settings = 0;
+   state->sensor_mode = 0;
+
+   state->intra_refresh_type = -1;
+
+   state->frame = 0;
+   state->save_pts = 0;
+
+   state->netListen = false;
+
+
+   // Setup preview window defaults
+   raspipreview_set_defaults(&state->preview_parameters);
+
+   // Set up the camera_parameters to default
+   raspicamcontrol_set_defaults(&state->camera_parameters);
+}
+
+
+/**
+ * Dump image state parameters to stderr.
+ *
+ * @param state Pointer to state structure to assign defaults to
+ */
+static void dump_status(RASPIVID_STATE *state)
+{
+   int i;
+
+   if (!state)
+   {
+      vcos_assert(0);
+      return;
+   }
+
+   fprintf(stderr, "Width %d, Height %d, filename %s\n", state->width, state->height, state->filename);
+   fprintf(stderr, "bitrate %d, framerate %d, time delay %d\n", state->bitrate, state->framerate, state->timeout);
+   fprintf(stderr, "H264 Profile %s\n", raspicli_unmap_xref(state->profile, profile_map, profile_map_size));
+   fprintf(stderr, "H264 Level %s\n", raspicli_unmap_xref(state->level, level_map, level_map_size));
+   fprintf(stderr, "H264 Quantisation level %d, Inline headers %s\n", state->quantisationParameter, state->bInlineHeaders ? "Yes" : "No");
+   fprintf(stderr, "H264 Intra refresh type %s, period %d\n", raspicli_unmap_xref(state->intra_refresh_type, intra_refresh_map, intra_refresh_map_size), state->intraperiod);
+
+   // Not going to display segment data unless asked for it.
+   if (state->segmentSize)
+      fprintf(stderr, "Segment size %d, segment wrap value %d, initial segment number %d\n", state->segmentSize, state->segmentWrap, state->segmentNumber);
+
+   if (state->raw_output)
+      fprintf(stderr, "Raw output enabled, format %s\n", raspicli_unmap_xref(state->raw_output_fmt, raw_output_fmt_map, raw_output_fmt_map_size));
+
+   fprintf(stderr, "Wait method : ");
+   for (i=0;i<wait_method_description_size;i++)
+   {
+      if (state->waitMethod == wait_method_description[i].nextWaitMethod)
+         fprintf(stderr, "%s", wait_method_description[i].description);
+   }
+   fprintf(stderr, "\nInitial state '%s'\n", raspicli_unmap_xref(state->bCapturing, initial_map, initial_map_size));
+   fprintf(stderr, "\n\n");
+
+   raspipreview_dump_parameters(&state->preview_parameters);
+   raspicamcontrol_dump_parameters(&state->camera_parameters);
+}
+
+/**
+ * Parse the incoming command line and put resulting parameters in to the state
+ *
+ * @param argc Number of arguments in command line
+ * @param argv Array of pointers to strings from command line
+ * @param state Pointer to state structure to assign any discovered parameters to
+ * @return Non-0 if failed for some reason, 0 otherwise
+ */
+static int parse_cmdline(int argc, const char **argv, RASPIVID_STATE *state)
+{
+   // Parse the command line arguments.
+   // We are looking for --<something> or -<abbreviation of something>
+
+   int valid = 1;
+   int i;
+
+   for (i = 1; i < argc && valid; i++)
+   {
+      int command_id, num_parameters;
+
+      if (!argv[i])
+         continue;
+
+      if (argv[i][0] != '-')
+      {
+         valid = 0;
+         continue;
+      }
+
+      // Assume parameter is valid until proven otherwise
+      valid = 1;
+
+      command_id = raspicli_get_command_id(cmdline_commands, cmdline_commands_size, &argv[i][1], &num_parameters);
+
+      // If we found a command but are missing a parameter, continue (and we will drop out of the loop)
+      if (command_id != -1 && num_parameters > 0 && (i + 1 >= argc) )
+         continue;
+
+      //  We are now dealing with a command line option
+      switch (command_id)
+      {
+      case CommandHelp:
+         display_valid_parameters(basename(argv[0]));
+         return -1;
+
+      case CommandWidth: // Width > 0
+         if (sscanf(argv[i + 1], "%u", &state->width) != 1)
+            valid = 0;
+         else
+            i++;
+         break;
+
+      case CommandHeight: // Height > 0
+         if (sscanf(argv[i + 1], "%u", &state->height) != 1)
+            valid = 0;
+         else
+            i++;
+         break;
+
+      case CommandBitrate: // 1-100
+         if (sscanf(argv[i + 1], "%u", &state->bitrate) == 1)
+         {
+            i++;
+         }
+         else
+            valid = 0;
+
+         break;
+
+      case CommandOutput:  // output filename
+      {
+         int len = strlen(argv[i + 1]);
+         if (len)
+         {
+            state->filename = malloc(len + 1);
+            vcos_assert(state->filename);
+            if (state->filename)
+               strncpy(state->filename, argv[i + 1], len+1);
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandVerbose: // display lots of data during run
+         state->verbose = 1;
+         break;
+
+      case CommandTimeout: // Time to run viewfinder/capture
+      {
+         if (sscanf(argv[i + 1], "%u", &state->timeout) == 1)
+         {
+            // Ensure that if previously selected a waitMethod we don't overwrite it
+            if (state->timeout == 0 && state->waitMethod == WAIT_METHOD_NONE)
+               state->waitMethod = WAIT_METHOD_FOREVER;
+
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandDemoMode: // Run in demo mode - no capture
+      {
+         // Demo mode might have a timing parameter
+         // so check if a) we have another parameter, b) its not the start of the next option
+         if (i + 1 < argc  && argv[i+1][0] != '-')
+         {
+            if (sscanf(argv[i + 1], "%u", &state->demoInterval) == 1)
+            {
+               // TODO : What limits do we need for timeout?
+               if (state->demoInterval == 0)
+                  state->demoInterval = 250; // ms
+
+               state->demoMode = 1;
+               i++;
+            }
+            else
+               valid = 0;
+         }
+         else
+         {
+            state->demoMode = 1;
+         }
+
+         break;
+      }
+
+      case CommandFramerate: // fps to record
+      {
+         if (sscanf(argv[i + 1], "%u", &state->framerate) == 1)
+         {
+            // TODO : What limits do we need for fps 1 - 30 - 120??
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+      
+      case CommandPreviewEnc:
+         state->immutableInput = 0;
+         break;
+
+      case CommandIntraPeriod: // key frame rate
+      {
+         if (sscanf(argv[i + 1], "%u", &state->intraperiod) == 1)
+            i++;
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandQP: // quantisation parameter
+      {
+         if (sscanf(argv[i + 1], "%u", &state->quantisationParameter) == 1)
+            i++;
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandProfile: // H264 profile
+      {
+         state->profile = raspicli_map_xref(argv[i + 1], profile_map, profile_map_size);
+
+         if( state->profile == -1)
+            state->profile = MMAL_VIDEO_PROFILE_H264_HIGH;
+
+         i++;
+         break;
+      }
+
+      case CommandInlineHeaders: // H264 inline headers
+      {
+         state->bInlineHeaders = 1;
+         break;
+      }
+
+      case CommandTimed:
+      {
+         if (sscanf(argv[i + 1], "%u,%u", &state->onTime, &state->offTime) == 2)
+         {
+            i++;
+
+            if (state->onTime < 1000)
+               state->onTime = 1000;
+
+            if (state->offTime < 1000)
+               state->offTime = 1000;
+
+            state->waitMethod = WAIT_METHOD_TIMED;
+         }
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandKeypress:
+         state->waitMethod = WAIT_METHOD_KEYPRESS;
+         break;
+
+      case CommandSignal:
+         state->waitMethod = WAIT_METHOD_SIGNAL;
+         // Reenable the signal
+         signal(SIGUSR1, signal_handler);
+         break;
+
+      case CommandInitialState:
+      {
+         state->bCapturing = raspicli_map_xref(argv[i + 1], initial_map, initial_map_size);
+
+         if( state->bCapturing == -1)
+            state->bCapturing = 0;
+
+         i++;
+         break;
+      }
+
+      case CommandSegmentFile: // Segment file in to chunks of specified time
+      {
+         if (sscanf(argv[i + 1], "%u", &state->segmentSize) == 1)
+         {
+            // Must enable inline headers for this to work
+            state->bInlineHeaders = 1;
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandSegmentWrap: // segment wrap value
+      {
+         if (sscanf(argv[i + 1], "%u", &state->segmentWrap) == 1)
+            i++;
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandSegmentStart: // initial segment number
+      {
+         if((sscanf(argv[i + 1], "%u", &state->segmentNumber) == 1) && (!state->segmentWrap || (state->segmentNumber <= state->segmentWrap)))
+            i++;
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandSplitWait: // split files on restart
+      {
+         // Must enable inline headers for this to work
+         state->bInlineHeaders = 1;
+         state->splitWait = 1;
+         break;
+      }
+
+      case CommandCircular:
+      {
+         state->bCircularBuffer = 1;
+         break;
+      }
+
+      case CommandIMV:  // output filename
+      {
+         state->inlineMotionVectors = 1;
+         int len = strlen(argv[i + 1]);
+         if (len)
+         {
+            state->imv_filename = malloc(len + 1);
+            vcos_assert(state->imv_filename);
+            if (state->imv_filename)
+               strncpy(state->imv_filename, argv[i + 1], len+1);
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+      case CommandCamSelect:  //Select camera input port
+      {
+         if (sscanf(argv[i + 1], "%u", &state->cameraNum) == 1)
+         {
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandSettings:
+         state->settings = 1;
+         break;
+
+      case CommandSensorMode:
+      {
+         if (sscanf(argv[i + 1], "%u", &state->sensor_mode) == 1)
+         {
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandIntraRefreshType:
+      {
+         state->intra_refresh_type = raspicli_map_xref(argv[i + 1], intra_refresh_map, intra_refresh_map_size);
+         i++;
+         break;
+      }
+
+      case CommandFlush:
+      {
+         state->callback_data.flush_buffers = 1;
+         break;
+      }
+      case CommandSavePTS:  // output filename
+      {
+         state->save_pts = 1;
+         int len = strlen(argv[i + 1]);
+         if (len)
+         {
+            state->pts_filename = malloc(len + 1);
+            vcos_assert(state->pts_filename);
+            if (state->pts_filename)
+               strncpy(state->pts_filename, argv[i + 1], len+1);
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+      case CommandCodec:  // codec type
+      {
+         int len = strlen(argv[i + 1]);
+         if (len)
+         {
+            if (len==4 && !strncmp("H264", argv[i+1], 4))
+               state->encoding = MMAL_ENCODING_H264;
+            else  if (len==5 && !strncmp("MJPEG", argv[i+1], 5))
+               state->encoding = MMAL_ENCODING_MJPEG;
+            else
+               valid = 0;
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandLevel: // H264 level
+      {
+         state->level = raspicli_map_xref(argv[i + 1], level_map, level_map_size);
+
+         if( state->level == -1)
+            state->level = MMAL_VIDEO_LEVEL_H264_4;
+
+         i++;
+         break;
+      }
+
+      case CommandRaw:  // output filename
+      {
+         state->raw_output = 1;
+         state->raw_output_fmt = RAW_OUTPUT_FMT_YUV;
+         int len = strlen(argv[i + 1]);
+         if (len)
+         {
+            state->raw_filename = malloc(len + 1);
+            vcos_assert(state->raw_filename);
+            if (state->raw_filename)
+               strncpy(state->raw_filename, argv[i + 1], len+1);
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandRawFormat:
+      {
+         state->raw_output_fmt = raspicli_map_xref(argv[i + 1], raw_output_fmt_map, raw_output_fmt_map_size);
+
+         if (state->raw_output_fmt == -1)
+            valid = 0;
+
+         i++;
+         break;
+      }
+
+      case CommandNetListen:
+      {
+         state->netListen = true;
+
+         break;
+      }
+
+      default:
+      {
+         // Try parsing for any image specific parameters
+         // result indicates how many parameters were used up, 0,1,2
+         // but we adjust by -1 as we have used one already
+         const char *second_arg = (i + 1 < argc) ? argv[i + 1] : NULL;
+         int parms_used = (raspicamcontrol_parse_cmdline(&state->camera_parameters, &argv[i][1], second_arg));
+
+         // Still unused, try preview options
+         if (!parms_used)
+            parms_used = raspipreview_parse_cmdline(&state->preview_parameters, &argv[i][1], second_arg);
+
+
+         // If no parms were used, this must be a bad parameters
+         if (!parms_used)
+            valid = 0;
+         else
+            i += parms_used - 1;
+
+         break;
+      }
+      }
+   }
+
+   if (!valid)
+   {
+      fprintf(stderr, "Invalid command line option (%s)\n", argv[i-1]);
+      return 1;
+   }
+
+   // Always disable verbose if output going to stdout
+   if (state->filename && state->filename[0] == '-')
+   {
+      state->verbose = 0;
+   }
+
+   return 0;
+}
+
+/**
+ * Display usage information for the application to stdout
+ *
+ * @param app_name String to display as the application name
+ */
+static void display_valid_parameters(char *app_name)
+{
+   int i;
+
+   fprintf(stdout, "Display camera output to display, and optionally saves an H264 capture at requested bitrate\n\n");
+   fprintf(stdout, "\nusage: %s [options]\n\n", app_name);
+
+   fprintf(stdout, "Image parameter commands\n\n");
+
+   raspicli_display_help(cmdline_commands, cmdline_commands_size);
+
+   // Profile options
+   fprintf(stdout, "\n\nH264 Profile options :\n%s", profile_map[0].mode );
+
+   for (i=1;i<profile_map_size;i++)
+   {
+      fprintf(stdout, ",%s", profile_map[i].mode);
+   }
+
+   // Level options
+   fprintf(stdout, "\n\nH264 Level options :\n%s", level_map[0].mode );
+
+   for (i=1;i<level_map_size;i++)
+   {
+      fprintf(stdout, ",%s", level_map[i].mode);
+   }
+
+   // Intra refresh options
+   fprintf(stdout, "\n\nH264 Intra refresh options :\n%s", intra_refresh_map[0].mode );
+
+   for (i=1;i<intra_refresh_map_size;i++)
+   {
+      fprintf(stdout, ",%s", intra_refresh_map[i].mode);
+   }
+
+   // Raw output format options
+   fprintf(stdout, "\n\nRaw output format options :\n%s", raw_output_fmt_map[0].mode );
+
+   for (i=1;i<raw_output_fmt_map_size;i++)
+   {
+      fprintf(stdout, ",%s", raw_output_fmt_map[i].mode);
+   }
+
+   fprintf(stdout, "\n");
+
+   // Help for preview options
+   raspipreview_display_help();
+
+   // Now display any help information from the camcontrol code
+   raspicamcontrol_display_help();
+
+   fprintf(stdout, "\n");
+
+   return;
+}
+
+/**
+ *  buffer header callback function for camera control
+ *
+ *  Callback will dump buffer data to the specific file
+ *
+ * @param port Pointer to port from which callback originated
+ * @param buffer mmal buffer header pointer
+ */
+static void camera_control_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   if (buffer->cmd == MMAL_EVENT_PARAMETER_CHANGED)
+   {
+      MMAL_EVENT_PARAMETER_CHANGED_T *param = (MMAL_EVENT_PARAMETER_CHANGED_T *)buffer->data;
+      switch (param->hdr.id) {
+         case MMAL_PARAMETER_CAMERA_SETTINGS:
+         {
+            MMAL_PARAMETER_CAMERA_SETTINGS_T *settings = (MMAL_PARAMETER_CAMERA_SETTINGS_T*)param;
+            vcos_log_error("Exposure now %u, analog gain %u/%u, digital gain %u/%u",
+                       settings->exposure,
+                        settings->analog_gain.num, settings->analog_gain.den,
+                        settings->digital_gain.num, settings->digital_gain.den);
+            vcos_log_error("AWB R=%u/%u, B=%u/%u",
+                        settings->awb_red_gain.num, settings->awb_red_gain.den,
+                        settings->awb_blue_gain.num, settings->awb_blue_gain.den
+                        );
+         }
+         break;
+      }
+   }
+   else if (buffer->cmd == MMAL_EVENT_ERROR)
+   {
+      vcos_log_error("No data received from sensor. Check all connections, including the Sunny one on the camera board");
+   }
+   else
+   {
+      vcos_log_error("Received unexpected camera control callback event, 0x%08x", buffer->cmd);
+   }
+
+   mmal_buffer_header_release(buffer);
+}
+
+
+/**
+ * Open a file based on the settings in state
+ *
+ * @param state Pointer to state
+ */
+static FILE *open_filename(RASPIVID_STATE *pState, char *filename)
+{
+   FILE *new_handle = NULL;
+   char *tempname = NULL;
+
+   if (pState->segmentSize || pState->splitWait)
+   {
+      // Create a new filename string
+      asprintf(&tempname, filename, pState->segmentNumber);
+      filename = tempname;
+   }
+
+   if (filename)
+   {
+      bool bNetwork = false;
+      int sfd = -1, socktype;
+
+      if(!strncmp("tcp://", filename, 6))
+      {
+         bNetwork = true;
+         socktype = SOCK_STREAM;
+      }
+      else if(!strncmp("udp://", filename, 6))
+      {
+         if (pState->netListen)
+         {
+            fprintf(stderr, "No support for listening in UDP mode\n");
+            exit(131);
+         }
+         bNetwork = true;
+         socktype = SOCK_DGRAM;
+      }
+
+      if(bNetwork)
+      {
+         unsigned short port;
+         filename += 6;
+         char *colon;
+         if(NULL == (colon = strchr(filename, ':')))
+         {
+            fprintf(stderr, "%s is not a valid IPv4:port, use something like tcp://1.2.3.4:1234 or udp://1.2.3.4:1234\n",
+                    filename);
+            exit(132);
+         }
+         if(1 != sscanf(colon + 1, "%hu", &port))
+         {
+            fprintf(stderr,
+                    "Port parse failed. %s is not a valid network file name, use something like tcp://1.2.3.4:1234 or udp://1.2.3.4:1234\n",
+                    filename);
+            exit(133);
+         }
+         char chTmp = *colon;
+         *colon = 0;
+
+         struct sockaddr_in saddr={};
+         saddr.sin_family = AF_INET;
+         saddr.sin_port = htons(port);
+         if(0 == inet_aton(filename, &saddr.sin_addr))
+         {
+            fprintf(stderr, "inet_aton failed. %s is not a valid IPv4 address\n",
+                    filename);
+            exit(134);
+         }
+         *colon = chTmp;
+
+         if (pState->netListen)
+         {
+            int sockListen = socket(AF_INET, SOCK_STREAM, 0);
+            if (sockListen >= 0)
+            {
+               int iTmp = 1;
+               setsockopt(sockListen, SOL_SOCKET, SO_REUSEADDR, &iTmp, sizeof(int));//no error handling, just go on
+               if (bind(sockListen, (struct sockaddr *) &saddr, sizeof(saddr)) >= 0)
+               {
+                  while ((-1 == (iTmp = listen(sockListen, 0))) && (EINTR == errno))
+                     ;
+                  if (-1 != iTmp)
+                  {
+                     fprintf(stderr, "Waiting for a TCP connection on %s:%"SCNu16"...",
+                             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+                     struct sockaddr_in cli_addr;
+                     socklen_t clilen = sizeof(cli_addr);
+                     while ((-1 == (sfd = accept(sockListen, (struct sockaddr *) &cli_addr, &clilen))) && (EINTR == errno))
+                        ;
+                     if (sfd >= 0)
+                        fprintf(stderr, "Client connected from %s:%"SCNu16"\n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
+                     else
+                        fprintf(stderr, "Error on accept: %s\n", strerror(errno));
+                  }
+                  else//if (-1 != iTmp)
+                  {
+                     fprintf(stderr, "Error trying to listen on a socket: %s\n", strerror(errno));
+                  }
+               }
+               else//if (bind(sockListen, (struct sockaddr *) &saddr, sizeof(saddr)) >= 0)
+               {
+                  fprintf(stderr, "Error on binding socket: %s\n", strerror(errno));
+               }
+            }
+            else//if (sockListen >= 0)
+            {
+               fprintf(stderr, "Error creating socket: %s\n", strerror(errno));
+            }
+
+            if (sockListen >= 0)//regardless success or error
+               close(sockListen);//do not listen on a given port anymore
+         }
+         else//if (pState->netListen)
+         {
+            if(0 <= (sfd = socket(AF_INET, socktype, 0)))
+            {
+               fprintf(stderr, "Connecting to %s:%hu...", inet_ntoa(saddr.sin_addr), port);
+
+               int iTmp = 1;
+               while ((-1 == (iTmp = connect(sfd, (struct sockaddr *) &saddr, sizeof(struct sockaddr_in)))) && (EINTR == errno))
+                  ;
+               if (iTmp < 0)
+                  fprintf(stderr, "error: %s\n", strerror(errno));
+               else
+                  fprintf(stderr, "connected, sending video...\n");
+            }
+            else
+               fprintf(stderr, "Error creating socket: %s\n", strerror(errno));
+         }
+
+         if (sfd >= 0)
+            new_handle = fdopen(sfd, "w");
+      }
+      else
+      {
+         new_handle = fopen(filename, "wb");
+      }
+   }
+
+   if (pState->verbose)
+   {
+      if (new_handle)
+         fprintf(stderr, "Opening output file \"%s\"\n", filename);
+      else
+         fprintf(stderr, "Failed to open new file \"%s\"\n", filename);
+   }
+
+   if (tempname)
+      free(tempname);
+
+   return new_handle;
+}
+
+/**
+ * Update any annotation data specific to the video.
+ * This simply passes on the setting from cli, or
+ * if application defined annotate requested, updates
+ * with the H264 parameters
+ *
+ * @param state Pointer to state control struct
+ *
+ */
+static void update_annotation_data(RASPIVID_STATE *state)
+{
+   // So, if we have asked for a application supplied string, set it to the H264 parameters
+   if (state->camera_parameters.enable_annotate & ANNOTATE_APP_TEXT)
+   {
+      char *text;
+      const char *refresh = raspicli_unmap_xref(state->intra_refresh_type, intra_refresh_map, intra_refresh_map_size);
+
+      asprintf(&text,  "%dk,%df,%s,%d,%s,%s",
+            state->bitrate / 1000,  state->framerate,
+            refresh ? refresh : "(none)",
+            state->intraperiod,
+            raspicli_unmap_xref(state->profile, profile_map, profile_map_size),
+            raspicli_unmap_xref(state->level, level_map, level_map_size));
+
+      raspicamcontrol_set_annotate(state->camera_component, state->camera_parameters.enable_annotate, text,
+                       state->camera_parameters.annotate_text_size,
+                       state->camera_parameters.annotate_text_colour,
+                       state->camera_parameters.annotate_bg_colour);
+
+      free(text);
+   }
+   else
+   {
+      raspicamcontrol_set_annotate(state->camera_component, state->camera_parameters.enable_annotate, state->camera_parameters.annotate_string,
+                       state->camera_parameters.annotate_text_size,
+                       state->camera_parameters.annotate_text_colour,
+                       state->camera_parameters.annotate_bg_colour);
+   }
+}
+
+
+
+/**
+ *  buffer header callback function for encoder
+ *
+ *  Callback will dump buffer data to the specific file
+ *
+ * @param port Pointer to port from which callback originated
+ * @param buffer mmal buffer header pointer
+ */
+static void encoder_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_BUFFER_HEADER_T *new_buffer;
+   static int64_t base_time =  -1;
+   static int64_t last_second = -1;
+
+   // All our segment times based on the receipt of the first encoder callback
+   if (base_time == -1)
+      base_time = vcos_getmicrosecs64()/1000;
+
+   // We pass our file handle and other stuff in via the userdata field.
+
+   PORT_USERDATA *pData = (PORT_USERDATA *)port->userdata;
+
+   if (pData)
+   {
+      int bytes_written = buffer->length;
+      int64_t current_time = vcos_getmicrosecs64()/1000;
+
+      vcos_assert(pData->file_handle);
+      if(pData->pstate->inlineMotionVectors) vcos_assert(pData->imv_file_handle);
+
+      if (pData->cb_buff)
+      {
+         int space_in_buff = pData->cb_len - pData->cb_wptr;
+         int copy_to_end = space_in_buff > buffer->length ? buffer->length : space_in_buff;
+         int copy_to_start = buffer->length - copy_to_end;
+
+         if(buffer->flags & MMAL_BUFFER_HEADER_FLAG_CONFIG)
+         {
+            if(pData->header_wptr + buffer->length > sizeof(pData->header_bytes))
+            {
+               vcos_log_error("Error in header bytes\n");
+            }
+            else
+            {
+               // These are the header bytes, save them for final output
+               mmal_buffer_header_mem_lock(buffer);
+               memcpy(pData->header_bytes + pData->header_wptr, buffer->data, buffer->length);
+               mmal_buffer_header_mem_unlock(buffer);
+               pData->header_wptr += buffer->length;
+            }
+         }
+         else if((buffer->flags & MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO))
+         {
+            // Do something with the inline motion vectors...
+         }
+         else
+         {
+            static int frame_start = -1;
+            int i;
+
+            if(frame_start == -1)
+               frame_start = pData->cb_wptr;
+
+            if(buffer->flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
+            {
+               pData->iframe_buff[pData->iframe_buff_wpos] = frame_start;
+               pData->iframe_buff_wpos = (pData->iframe_buff_wpos + 1) % IFRAME_BUFSIZE;
+            }
+
+            if(buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END)
+               frame_start = -1;
+
+            // If we overtake the iframe rptr then move the rptr along
+            if((pData->iframe_buff_rpos + 1) % IFRAME_BUFSIZE != pData->iframe_buff_wpos)
+            {
+               while(
+                  (
+                     pData->cb_wptr <= pData->iframe_buff[pData->iframe_buff_rpos] &&
+                    (pData->cb_wptr + buffer->length) > pData->iframe_buff[pData->iframe_buff_rpos]
+                  ) ||
+                  (
+                    (pData->cb_wptr > pData->iframe_buff[pData->iframe_buff_rpos]) &&
+                    (pData->cb_wptr + buffer->length) > (pData->iframe_buff[pData->iframe_buff_rpos] + pData->cb_len)
+                  )
+               )
+                  pData->iframe_buff_rpos = (pData->iframe_buff_rpos + 1) % IFRAME_BUFSIZE;
+            }
+
+            mmal_buffer_header_mem_lock(buffer);
+            // We are pushing data into a circular buffer
+            memcpy(pData->cb_buff + pData->cb_wptr, buffer->data, copy_to_end);
+            memcpy(pData->cb_buff, buffer->data + copy_to_end, copy_to_start);
+            mmal_buffer_header_mem_unlock(buffer);
+
+            if((pData->cb_wptr + buffer->length) > pData->cb_len)
+               pData->cb_wrap = 1;
+
+            pData->cb_wptr = (pData->cb_wptr + buffer->length) % pData->cb_len;
+
+            for(i = pData->iframe_buff_rpos; i != pData->iframe_buff_wpos; i = (i + 1) % IFRAME_BUFSIZE)
+            {
+               int p = pData->iframe_buff[i];
+               if(pData->cb_buff[p] != 0 || pData->cb_buff[p+1] != 0 || pData->cb_buff[p+2] != 0 || pData->cb_buff[p+3] != 1)
+               {
+                  vcos_log_error("Error in iframe list\n");
+               }
+            }
+         }
+      }
+      else
+      {
+         // For segmented record mode, we need to see if we have exceeded our time/size,
+         // but also since we have inline headers turned on we need to break when we get one to
+         // ensure that the new stream has the header in it. If we break on an I-frame, the
+         // SPS/PPS header is actually in the previous chunk.
+         if ((buffer->flags & MMAL_BUFFER_HEADER_FLAG_CONFIG) &&
+             ((pData->pstate->segmentSize && current_time > base_time + pData->pstate->segmentSize) ||
+              (pData->pstate->splitWait && pData->pstate->splitNow)))
+         {
+            FILE *new_handle;
+
+            base_time = current_time;
+
+            pData->pstate->splitNow = 0;
+            pData->pstate->segmentNumber++;
+
+            // Only wrap if we have a wrap point set
+            if (pData->pstate->segmentWrap && pData->pstate->segmentNumber > pData->pstate->segmentWrap)
+               pData->pstate->segmentNumber = 1;
+
+            if (pData->pstate->filename && pData->pstate->filename[0] != '-')
+            {
+               new_handle = open_filename(pData->pstate, pData->pstate->filename);
+
+               if (new_handle)
+               {
+                  fclose(pData->file_handle);
+                  pData->file_handle = new_handle;
+               }
+            }
+
+            if (pData->pstate->imv_filename && pData->pstate->imv_filename[0] != '-')
+            {
+               new_handle = open_filename(pData->pstate, pData->pstate->imv_filename);
+
+               if (new_handle)
+               {
+                  fclose(pData->imv_file_handle);
+                  pData->imv_file_handle = new_handle;
+               }
+            }
+
+            if (pData->pstate->pts_filename && pData->pstate->pts_filename[0] != '-')
+            {
+               new_handle = open_filename(pData->pstate, pData->pstate->pts_filename);
+
+               if (new_handle)
+               {
+                  fclose(pData->pts_file_handle);
+                  pData->pts_file_handle = new_handle;
+               }
+            }
+         }
+         if (buffer->length)
+         {
+            mmal_buffer_header_mem_lock(buffer);
+            if(buffer->flags & MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO)
+            {
+               if(pData->pstate->inlineMotionVectors)
+               {
+                  bytes_written = fwrite(buffer->data, 1, buffer->length, pData->imv_file_handle);
+                  if(pData->flush_buffers) fflush(pData->imv_file_handle);
+               }
+               else
+               {
+                  //We do not want to save inlineMotionVectors...
+                  bytes_written = buffer->length;
+               }
+            }
+            else
+            {
+               bytes_written = fwrite(buffer->data, 1, buffer->length, pData->file_handle);
+               if(pData->flush_buffers) fflush(pData->file_handle);
+
+               if(pData->pstate->save_pts &&
+                  (buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END ||
+                   buffer->flags == 0 ||
+                   buffer->flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME) &&
+                  !(buffer->flags & MMAL_BUFFER_HEADER_FLAG_CONFIG))
+               {
+                  if(buffer->pts != MMAL_TIME_UNKNOWN && buffer->pts != pData->pstate->lasttime)
+                  {
+                    int64_t pts;
+                    if(pData->pstate->frame==0)pData->pstate->starttime=buffer->pts;
+                    pData->pstate->lasttime=buffer->pts;
+                    pts = buffer->pts - pData->pstate->starttime;
+                    fprintf(pData->pts_file_handle,"%lld.%03lld\n", pts/1000, pts%1000);
+                    pData->pstate->frame++;
+                  }
+               }
+            }
+
+            mmal_buffer_header_mem_unlock(buffer);
+
+            if (bytes_written != buffer->length)
+            {
+               vcos_log_error("Failed to write buffer data (%d from %d)- aborting", bytes_written, buffer->length);
+               pData->abort = 1;
+            }
+         }
+      }
+
+      // See if the second count has changed and we need to update any annotation
+      if (current_time/1000 != last_second)
+      {
+         update_annotation_data(pData->pstate);
+         last_second = current_time/1000;
+      }
+   }
+   else
+   {
+      vcos_log_error("Received a encoder buffer callback with no state");
+   }
+
+   // release buffer back to the pool
+   mmal_buffer_header_release(buffer);
+
+   // and send one back to the port (if still open)
+   if (port->is_enabled)
+   {
+      MMAL_STATUS_T status;
+
+      new_buffer = mmal_queue_get(pData->pstate->encoder_pool->queue);
+
+      if (new_buffer)
+         status = mmal_port_send_buffer(port, new_buffer);
+
+      if (!new_buffer || status != MMAL_SUCCESS)
+         vcos_log_error("Unable to return a buffer to the encoder port");
+   }
+}
+
+/**
+ *  buffer header callback function for splitter
+ *
+ *  Callback will dump buffer data to the specific file
+ *
+ * @param port Pointer to port from which callback originated
+ * @param buffer mmal buffer header pointer
+ */
+static void splitter_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_BUFFER_HEADER_T *new_buffer;
+   PORT_USERDATA *pData = (PORT_USERDATA *)port->userdata;
+
+   if (pData)
+   {
+      int bytes_written = 0;
+      int bytes_to_write = buffer->length;
+
+      /* Write only luma component to get grayscale image: */
+      if (buffer->length && pData->pstate->raw_output_fmt == RAW_OUTPUT_FMT_GRAY)
+         bytes_to_write = port->format->es->video.width * port->format->es->video.height;
+
+      vcos_assert(pData->raw_file_handle);
+
+      if (bytes_to_write)
+      {
+         mmal_buffer_header_mem_lock(buffer);
+         bytes_written = fwrite(buffer->data, 1, bytes_to_write, pData->raw_file_handle);
+         mmal_buffer_header_mem_unlock(buffer);
+
+         if (bytes_written != bytes_to_write)
+         {
+            vcos_log_error("Failed to write raw buffer data (%d from %d)- aborting", bytes_written, bytes_to_write);
+            pData->abort = 1;
+         }
+      }
+   }
+   else
+   {
+      vcos_log_error("Received a camera buffer callback with no state");
+   }
+
+   // release buffer back to the pool
+   mmal_buffer_header_release(buffer);
+
+   // and send one back to the port (if still open)
+   if (port->is_enabled)
+   {
+      MMAL_STATUS_T status;
+
+      new_buffer = mmal_queue_get(pData->pstate->splitter_pool->queue);
+
+      if (new_buffer)
+         status = mmal_port_send_buffer(port, new_buffer);
+
+      if (!new_buffer || status != MMAL_SUCCESS)
+         vcos_log_error("Unable to return a buffer to the splitter port");
+   }
+}
+
+/**
+ * Create the camera component, set up its ports
+ *
+ * @param state Pointer to state control struct
+ *
+ * @return MMAL_SUCCESS if all OK, something else otherwise
+ *
+ */
+static MMAL_STATUS_T create_camera_component(RASPIVID_STATE *state)
+{
+   MMAL_COMPONENT_T *camera = 0;
+   MMAL_ES_FORMAT_T *format;
+   MMAL_PORT_T *preview_port = NULL, *video_port = NULL, *still_port = NULL;
+   MMAL_STATUS_T status;
+
+   /* Create the component */
+   status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Failed to create camera component");
+      goto error;
+   }
+
+   status = raspicamcontrol_set_stereo_mode(camera->output[0], &state->camera_parameters.stereo_mode);
+   status += raspicamcontrol_set_stereo_mode(camera->output[1], &state->camera_parameters.stereo_mode);
+   status += raspicamcontrol_set_stereo_mode(camera->output[2], &state->camera_parameters.stereo_mode);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Could not set stereo mode : error %d", status);
+      goto error;
+   }
+
+   MMAL_PARAMETER_INT32_T camera_num =
+      {{MMAL_PARAMETER_CAMERA_NUM, sizeof(camera_num)}, state->cameraNum};
+
+   status = mmal_port_parameter_set(camera->control, &camera_num.hdr);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Could not select camera : error %d", status);
+      goto error;
+   }
+
+   if (!camera->output_num)
+   {
+      status = MMAL_ENOSYS;
+      vcos_log_error("Camera doesn't have output ports");
+      goto error;
+   }
+
+   status = mmal_port_parameter_set_uint32(camera->control, MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG, state->sensor_mode);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Could not set sensor mode : error %d", status);
+      goto error;
+   }
+
+   preview_port = camera->output[MMAL_CAMERA_PREVIEW_PORT];
+   video_port = camera->output[MMAL_CAMERA_VIDEO_PORT];
+   still_port = camera->output[MMAL_CAMERA_CAPTURE_PORT];
+
+   if (state->settings)
+   {
+      MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T change_event_request =
+         {{MMAL_PARAMETER_CHANGE_EVENT_REQUEST, sizeof(MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T)},
+          MMAL_PARAMETER_CAMERA_SETTINGS, 1};
+
+      status = mmal_port_parameter_set(camera->control, &change_event_request.hdr);
+      if ( status != MMAL_SUCCESS )
+      {
+         vcos_log_error("No camera settings events");
+      }
+   }
+
+   // Enable the camera, and tell it its control callback function
+   status = mmal_port_enable(camera->control, camera_control_callback);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Unable to enable control port : error %d", status);
+      goto error;
+   }
+
+   //  set up the camera configuration
+   {
+      MMAL_PARAMETER_CAMERA_CONFIG_T cam_config =
+      {
+         { MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) },
+         .max_stills_w = state->width,
+         .max_stills_h = state->height,
+         .stills_yuv422 = 0,
+         .one_shot_stills = 0,
+         .max_preview_video_w = state->width,
+         .max_preview_video_h = state->height,
+         .num_preview_video_frames = 3 + vcos_max(0, (state->framerate-30)/10),
+         .stills_capture_circular_buffer_height = 0,
+         .fast_preview_resume = 0,
+         .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RAW_STC
+      };
+      mmal_port_parameter_set(camera->control, &cam_config.hdr);
+   }
+
+   // Now set up the port formats
+
+   // Set the encode format on the Preview port
+   // HW limitations mean we need the preview to be the same size as the required recorded output
+
+   format = preview_port->format;
+
+   format->encoding = MMAL_ENCODING_OPAQUE;
+   format->encoding_variant = MMAL_ENCODING_I420;
+
+   if(state->camera_parameters.shutter_speed > 6000000)
+   {
+        MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
+                                                     { 50, 1000 }, {166, 1000}};
+        mmal_port_parameter_set(preview_port, &fps_range.hdr);
+   }
+   else if(state->camera_parameters.shutter_speed > 1000000)
+   {
+        MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
+                                                     { 166, 1000 }, {999, 1000}};
+        mmal_port_parameter_set(preview_port, &fps_range.hdr);
+   }
+
+   //enable dynamic framerate if necessary
+   if (state->camera_parameters.shutter_speed)
+   {
+      if (state->framerate > 1000000./state->camera_parameters.shutter_speed)
+      {
+         state->framerate=0;
+         if (state->verbose)
+            fprintf(stderr, "Enable dynamic frame rate to fulfil shutter speed requirement\n");
+      }
+   }
+
+   format->encoding = MMAL_ENCODING_OPAQUE;
+   format->es->video.width = VCOS_ALIGN_UP(state->width, 32);
+   format->es->video.height = VCOS_ALIGN_UP(state->height, 16);
+   format->es->video.crop.x = 0;
+   format->es->video.crop.y = 0;
+   format->es->video.crop.width = state->width;
+   format->es->video.crop.height = state->height;
+   format->es->video.frame_rate.num = PREVIEW_FRAME_RATE_NUM;
+   format->es->video.frame_rate.den = PREVIEW_FRAME_RATE_DEN;
+
+   status = mmal_port_format_commit(preview_port);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("camera viewfinder format couldn't be set");
+      goto error;
+   }
+
+   // Set the encode format on the video  port
+
+   format = video_port->format;
+   format->encoding_variant = MMAL_ENCODING_I420;
+
+   if(state->camera_parameters.shutter_speed > 6000000)
+   {
+        MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
+                                                     { 50, 1000 }, {166, 1000}};
+        mmal_port_parameter_set(video_port, &fps_range.hdr);
+   }
+   else if(state->camera_parameters.shutter_speed > 1000000)
+   {
+        MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
+                                                     { 167, 1000 }, {999, 1000}};
+        mmal_port_parameter_set(video_port, &fps_range.hdr);
+   }
+
+   format->encoding = MMAL_ENCODING_OPAQUE;
+   format->es->video.width = VCOS_ALIGN_UP(state->width, 32);
+   format->es->video.height = VCOS_ALIGN_UP(state->height, 16);
+   format->es->video.crop.x = 0;
+   format->es->video.crop.y = 0;
+   format->es->video.crop.width = state->width;
+   format->es->video.crop.height = state->height;
+   format->es->video.frame_rate.num = state->framerate;
+   format->es->video.frame_rate.den = VIDEO_FRAME_RATE_DEN;
+
+   status = mmal_port_format_commit(video_port);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("camera video format couldn't be set");
+      goto error;
+   }
+
+   // Ensure there are enough buffers to avoid dropping frames
+   if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
+      video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
+
+
+   // Set the encode format on the still  port
+
+   format = still_port->format;
+
+   format->encoding = MMAL_ENCODING_OPAQUE;
+   format->encoding_variant = MMAL_ENCODING_I420;
+
+   format->es->video.width = VCOS_ALIGN_UP(state->width, 32);
+   format->es->video.height = VCOS_ALIGN_UP(state->height, 16);
+   format->es->video.crop.x = 0;
+   format->es->video.crop.y = 0;
+   format->es->video.crop.width = state->width;
+   format->es->video.crop.height = state->height;
+   format->es->video.frame_rate.num = 0;
+   format->es->video.frame_rate.den = 1;
+
+   status = mmal_port_format_commit(still_port);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("camera still format couldn't be set");
+      goto error;
+   }
+
+   /* Ensure there are enough buffers to avoid dropping frames */
+   if (still_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
+      still_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
+
+   /* Enable component */
+   status = mmal_component_enable(camera);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("camera component couldn't be enabled");
+      goto error;
+   }
+
+   // Note: this sets lots of parameters that were not individually addressed before.
+   raspicamcontrol_set_all_parameters(camera, &state->camera_parameters);
+
+   state->camera_component = camera;
+
+   update_annotation_data(state);
+
+   if (state->verbose)
+      fprintf(stderr, "Camera component done\n");
+
+   return status;
+
+error:
+
+   if (camera)
+      mmal_component_destroy(camera);
+
+   return status;
+}
+
+/**
+ * Destroy the camera component
+ *
+ * @param state Pointer to state control struct
+ *
+ */
+static void destroy_camera_component(RASPIVID_STATE *state)
+{
+   if (state->camera_component)
+   {
+      mmal_component_destroy(state->camera_component);
+      state->camera_component = NULL;
+   }
+}
+
+/**
+ * Create the splitter component, set up its ports
+ *
+ * @param state Pointer to state control struct
+ *
+ * @return MMAL_SUCCESS if all OK, something else otherwise
+ *
+ */
+static MMAL_STATUS_T create_splitter_component(RASPIVID_STATE *state)
+{
+   MMAL_COMPONENT_T *splitter = 0;
+   MMAL_PORT_T *splitter_output = NULL;
+   MMAL_ES_FORMAT_T *format;
+   MMAL_STATUS_T status;
+   MMAL_POOL_T *pool;
+   int i;
+
+   if (state->camera_component == NULL)
+   {
+      status = MMAL_ENOSYS;
+      vcos_log_error("Camera component must be created before splitter");
+      goto error;
+   }
+
+   /* Create the component */
+   status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_SPLITTER, &splitter);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Failed to create splitter component");
+      goto error;
+   }
+
+   if (!splitter->input_num)
+   {
+      status = MMAL_ENOSYS;
+      vcos_log_error("Splitter doesn't have any input port");
+      goto error;
+   }
+
+   if (splitter->output_num < 2)
+   {
+      status = MMAL_ENOSYS;
+      vcos_log_error("Splitter doesn't have enough output ports");
+      goto error;
+   }
+
+   /* Ensure there are enough buffers to avoid dropping frames: */
+   mmal_format_copy(splitter->input[0]->format, state->camera_component->output[MMAL_CAMERA_PREVIEW_PORT]->format);
+
+   if (splitter->input[0]->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
+      splitter->input[0]->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
+
+   status = mmal_port_format_commit(splitter->input[0]);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Unable to set format on splitter input port");
+      goto error;
+   }
+
+   /* Splitter can do format conversions, configure format for its output port: */
+   for (i = 0; i < splitter->output_num; i++)
+   {
+      mmal_format_copy(splitter->output[i]->format, splitter->input[0]->format);
+
+      if (i == SPLITTER_OUTPUT_PORT)
+      {
+         format = splitter->output[i]->format;
+
+         switch (state->raw_output_fmt)
+         {
+         case RAW_OUTPUT_FMT_YUV:
+         case RAW_OUTPUT_FMT_GRAY: /* Grayscale image contains only luma (Y) component */
+            format->encoding = MMAL_ENCODING_I420;
+            format->encoding_variant = MMAL_ENCODING_I420;
+            break;
+         case RAW_OUTPUT_FMT_RGB:
+            if (mmal_util_rgb_order_fixed(state->camera_component->output[MMAL_CAMERA_CAPTURE_PORT]))
+               format->encoding = MMAL_ENCODING_RGB24;
+            else
+               format->encoding = MMAL_ENCODING_BGR24;
+            format->encoding_variant = 0;  /* Irrelevant when not in opaque mode */
+            break;
+         default:
+            status = MMAL_EINVAL;
+            vcos_log_error("unknown raw output format");
+            goto error;
+         }
+      }
+
+      status = mmal_port_format_commit(splitter->output[i]);
+
+      if (status != MMAL_SUCCESS)
+      {
+         vcos_log_error("Unable to set format on splitter output port %d", i);
+         goto error;
+      }
+   }
+
+   /* Enable component */
+   status = mmal_component_enable(splitter);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("splitter component couldn't be enabled");
+      goto error;
+   }
+
+   /* Create pool of buffer headers for the output port to consume */
+   splitter_output = splitter->output[SPLITTER_OUTPUT_PORT];
+   pool = mmal_port_pool_create(splitter_output, splitter_output->buffer_num, splitter_output->buffer_size);
+
+   if (!pool)
+   {
+      vcos_log_error("Failed to create buffer header pool for splitter output port %s", splitter_output->name);
+   }
+
+   state->splitter_pool = pool;
+   state->splitter_component = splitter;
+
+   if (state->verbose)
+      fprintf(stderr, "Splitter component done\n");
+
+   return status;
+
+error:
+
+   if (splitter)
+      mmal_component_destroy(splitter);
+
+   return status;
+}
+
+/**
+ * Destroy the splitter component
+ *
+ * @param state Pointer to state control struct
+ *
+ */
+static void destroy_splitter_component(RASPIVID_STATE *state)
+{
+   // Get rid of any port buffers first
+   if (state->splitter_pool)
+   {
+      mmal_port_pool_destroy(state->splitter_component->output[SPLITTER_OUTPUT_PORT], state->splitter_pool);
+   }
+
+   if (state->splitter_component)
+   {
+      mmal_component_destroy(state->splitter_component);
+      state->splitter_component = NULL;
+   }
+}
+
+/**
+ * Create the encoder component, set up its ports
+ *
+ * @param state Pointer to state control struct
+ *
+ * @return MMAL_SUCCESS if all OK, something else otherwise
+ *
+ */
+static MMAL_STATUS_T create_encoder_component(RASPIVID_STATE *state)
+{
+   MMAL_COMPONENT_T *encoder = 0;
+   MMAL_PORT_T *encoder_input = NULL, *encoder_output = NULL;
+   MMAL_STATUS_T status;
+   MMAL_POOL_T *pool;
+
+   status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_ENCODER, &encoder);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Unable to create video encoder component");
+      goto error;
+   }
+
+   if (!encoder->input_num || !encoder->output_num)
+   {
+      status = MMAL_ENOSYS;
+      vcos_log_error("Video encoder doesn't have input/output ports");
+      goto error;
+   }
+
+   encoder_input = encoder->input[0];
+   encoder_output = encoder->output[0];
+
+   // We want same format on input and output
+   mmal_format_copy(encoder_output->format, encoder_input->format);
+
+   // Only supporting H264 at the moment
+   encoder_output->format->encoding = state->encoding;
+
+   if(state->encoding == MMAL_ENCODING_H264)
+   {
+      if(state->level == MMAL_VIDEO_LEVEL_H264_4)
+      {
+         if(state->bitrate > MAX_BITRATE_LEVEL4)
+         {
+            fprintf(stderr, "Bitrate too high: Reducing to 25MBit/s\n");
+            state->bitrate = MAX_BITRATE_LEVEL4;
+         }
+      }
+      else
+      {
+         if(state->bitrate > MAX_BITRATE_LEVEL42)
+         {
+            fprintf(stderr, "Bitrate too high: Reducing to 62.5MBit/s\n");
+            state->bitrate = MAX_BITRATE_LEVEL42;
+         }
+      }
+   }
+   else if(state->encoding == MMAL_ENCODING_MJPEG)
+   {
+      if(state->bitrate > MAX_BITRATE_MJPEG)
+      {
+         fprintf(stderr, "Bitrate too high: Reducing to 25MBit/s\n");
+         state->bitrate = MAX_BITRATE_MJPEG;
+      }
+   }
+   
+   encoder_output->format->bitrate = state->bitrate;
+
+   if (state->encoding == MMAL_ENCODING_H264)
+      encoder_output->buffer_size = encoder_output->buffer_size_recommended;
+   else
+      encoder_output->buffer_size = 256<<10;
+
+
+   if (encoder_output->buffer_size < encoder_output->buffer_size_min)
+      encoder_output->buffer_size = encoder_output->buffer_size_min;
+
+   encoder_output->buffer_num = encoder_output->buffer_num_recommended;
+
+   if (encoder_output->buffer_num < encoder_output->buffer_num_min)
+      encoder_output->buffer_num = encoder_output->buffer_num_min;
+
+   // We need to set the frame rate on output to 0, to ensure it gets
+   // updated correctly from the input framerate when port connected
+   encoder_output->format->es->video.frame_rate.num = 0;
+   encoder_output->format->es->video.frame_rate.den = 1;
+
+   // Commit the port changes to the output port
+   status = mmal_port_format_commit(encoder_output);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Unable to set format on video encoder output port");
+      goto error;
+   }
+
+   // Set the rate control parameter
+   if (0)
+   {
+      MMAL_PARAMETER_VIDEO_RATECONTROL_T param = {{ MMAL_PARAMETER_RATECONTROL, sizeof(param)}, MMAL_VIDEO_RATECONTROL_DEFAULT};
+      status = mmal_port_parameter_set(encoder_output, &param.hdr);
+      if (status != MMAL_SUCCESS)
+      {
+         vcos_log_error("Unable to set ratecontrol");
+         goto error;
+      }
+
+   }
+
+   if (state->encoding == MMAL_ENCODING_H264 &&
+       state->intraperiod != -1)
+   {
+      MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_INTRAPERIOD, sizeof(param)}, state->intraperiod};
+      status = mmal_port_parameter_set(encoder_output, &param.hdr);
+      if (status != MMAL_SUCCESS)
+      {
+         vcos_log_error("Unable to set intraperiod");
+         goto error;
+      }
+   }
+
+   if (state->encoding == MMAL_ENCODING_H264 &&
+       state->quantisationParameter)
+   {
+      MMAL_PARAMETER_UINT32_T param = {{ MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT, sizeof(param)}, state->quantisationParameter};
+      status = mmal_port_parameter_set(encoder_output, &param.hdr);
+      if (status != MMAL_SUCCESS)
+      {
+         vcos_log_error("Unable to set initial QP");
+         goto error;
+      }
+
+      MMAL_PARAMETER_UINT32_T param2 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT, sizeof(param)}, state->quantisationParameter};
+      status = mmal_port_parameter_set(encoder_output, &param2.hdr);
+      if (status != MMAL_SUCCESS)
+      {
+         vcos_log_error("Unable to set min QP");
+         goto error;
+      }
+
+      MMAL_PARAMETER_UINT32_T param3 = {{ MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT, sizeof(param)}, state->quantisationParameter};
+      status = mmal_port_parameter_set(encoder_output, &param3.hdr);
+      if (status != MMAL_SUCCESS)
+      {
+         vcos_log_error("Unable to set max QP");
+         goto error;
+      }
+
+   }
+
+   if (state->encoding == MMAL_ENCODING_H264)
+   {
+      MMAL_PARAMETER_VIDEO_PROFILE_T  param;
+      param.hdr.id = MMAL_PARAMETER_PROFILE;
+      param.hdr.size = sizeof(param);
+
+      param.profile[0].profile = state->profile;
+
+      if((VCOS_ALIGN_UP(state->width,16) >> 4) * (VCOS_ALIGN_UP(state->height,16) >> 4) * state->framerate > 245760)
+      {
+         if((VCOS_ALIGN_UP(state->width,16) >> 4) * (VCOS_ALIGN_UP(state->height,16) >> 4) * state->framerate <= 522240)
+         {
+            fprintf(stderr, "Too many macroblocks/s: Increasing H264 Level to 4.2\n");
+            state->level=MMAL_VIDEO_LEVEL_H264_42;
+         }
+         else
+         {
+            vcos_log_error("Too many macroblocks/s requested");
+            goto error;
+         }
+      }
+      
+      param.profile[0].level = state->level;
+
+      status = mmal_port_parameter_set(encoder_output, &param.hdr);
+      if (status != MMAL_SUCCESS)
+      {
+         vcos_log_error("Unable to set H264 profile");
+         goto error;
+      }
+   }
+
+   if (mmal_port_parameter_set_boolean(encoder_input, MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT, state->immutableInput) != MMAL_SUCCESS)
+   {
+      vcos_log_error("Unable to set immutable input flag");
+      // Continue rather than abort..
+   }
+
+   //set INLINE HEADER flag to generate SPS and PPS for every IDR if requested
+   if (mmal_port_parameter_set_boolean(encoder_output, MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER, state->bInlineHeaders) != MMAL_SUCCESS)
+   {
+      vcos_log_error("failed to set INLINE HEADER FLAG parameters");
+      // Continue rather than abort..
+   }
+
+   //set INLINE VECTORS flag to request motion vector estimates
+   if (state->encoding == MMAL_ENCODING_H264 &&
+       mmal_port_parameter_set_boolean(encoder_output, MMAL_PARAMETER_VIDEO_ENCODE_INLINE_VECTORS, state->inlineMotionVectors) != MMAL_SUCCESS)
+   {
+      vcos_log_error("failed to set INLINE VECTORS parameters");
+      // Continue rather than abort..
+   }
+
+   // Adaptive intra refresh settings
+   if (state->encoding == MMAL_ENCODING_H264 &&
+       state->intra_refresh_type != -1)
+   {
+      MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T  param;
+      param.hdr.id = MMAL_PARAMETER_VIDEO_INTRA_REFRESH;
+      param.hdr.size = sizeof(param);
+
+      // Get first so we don't overwrite anything unexpectedly
+      status = mmal_port_parameter_get(encoder_output, &param.hdr);
+      if (status != MMAL_SUCCESS)
+      {
+         vcos_log_warn("Unable to get existing H264 intra-refresh values. Please update your firmware");
+         // Set some defaults, don't just pass random stack data
+         param.air_mbs = param.air_ref = param.cir_mbs = param.pir_mbs = 0;
+      }
+
+      param.refresh_mode = state->intra_refresh_type;
+
+      //if (state->intra_refresh_type == MMAL_VIDEO_INTRA_REFRESH_CYCLIC_MROWS)
+      //   param.cir_mbs = 10;
+
+      status = mmal_port_parameter_set(encoder_output, &param.hdr);
+      if (status != MMAL_SUCCESS)
+      {
+         vcos_log_error("Unable to set H264 intra-refresh values");
+         goto error;
+      }
+   }
+
+   //  Enable component
+   status = mmal_component_enable(encoder);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Unable to enable video encoder component");
+      goto error;
+   }
+
+   /* Create pool of buffer headers for the output port to consume */
+   pool = mmal_port_pool_create(encoder_output, encoder_output->buffer_num, encoder_output->buffer_size);
+
+   if (!pool)
+   {
+      vcos_log_error("Failed to create buffer header pool for encoder output port %s", encoder_output->name);
+   }
+
+   state->encoder_pool = pool;
+   state->encoder_component = encoder;
+
+   if (state->verbose)
+      fprintf(stderr, "Encoder component done\n");
+
+   return status;
+
+   error:
+   if (encoder)
+      mmal_component_destroy(encoder);
+
+   state->encoder_component = NULL;
+
+   return status;
+}
+
+/**
+ * Destroy the encoder component
+ *
+ * @param state Pointer to state control struct
+ *
+ */
+static void destroy_encoder_component(RASPIVID_STATE *state)
+{
+   // Get rid of any port buffers first
+   if (state->encoder_pool)
+   {
+      mmal_port_pool_destroy(state->encoder_component->output[0], state->encoder_pool);
+   }
+
+   if (state->encoder_component)
+   {
+      mmal_component_destroy(state->encoder_component);
+      state->encoder_component = NULL;
+   }
+}
+
+/**
+ * Connect two specific ports together
+ *
+ * @param output_port Pointer the output port
+ * @param input_port Pointer the input port
+ * @param Pointer to a mmal connection pointer, reassigned if function successful
+ * @return Returns a MMAL_STATUS_T giving result of operation
+ *
+ */
+static MMAL_STATUS_T connect_ports(MMAL_PORT_T *output_port, MMAL_PORT_T *input_port, MMAL_CONNECTION_T **connection)
+{
+   MMAL_STATUS_T status;
+
+   status =  mmal_connection_create(connection, output_port, input_port, MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT);
+
+   if (status == MMAL_SUCCESS)
+   {
+      status =  mmal_connection_enable(*connection);
+      if (status != MMAL_SUCCESS)
+         mmal_connection_destroy(*connection);
+   }
+
+   return status;
+}
+
+/**
+ * Checks if specified port is valid and enabled, then disables it
+ *
+ * @param port  Pointer the port
+ *
+ */
+static void check_disable_port(MMAL_PORT_T *port)
+{
+   if (port && port->is_enabled)
+      mmal_port_disable(port);
+}
+
+/**
+ * Handler for sigint signals
+ *
+ * @param signal_number ID of incoming signal.
+ *
+ */
+static void signal_handler(int signal_number)
+{
+   if (signal_number == SIGUSR1)
+   {
+      // Handle but ignore - prevents us dropping out if started in none-signal mode
+      // and someone sends us the USR1 signal anyway
+   }
+   else
+   {
+      // Going to abort on all other signals
+      vcos_log_error("Aborting program\n");
+      exit(130);
+   }
+
+}
+
+/**
+ * Pause for specified time, but return early if detect an abort request
+ *
+ * @param state Pointer to state control struct
+ * @param pause Time in ms to pause
+ * @param callback Struct contain an abort flag tested for early termination
+ *
+ */
+static int pause_and_test_abort(RASPIVID_STATE *state, int pause)
+{
+   int wait;
+
+   if (!pause)
+      return 0;
+
+   // Going to check every ABORT_INTERVAL milliseconds
+   for (wait = 0; wait < pause; wait+= ABORT_INTERVAL)
+   {
+      vcos_sleep(ABORT_INTERVAL);
+      if (state->callback_data.abort)
+         return 1;
+   }
+
+   return 0;
+}
+
+
+/**
+ * Function to wait in various ways (depending on settings)
+ *
+ * @param state Pointer to the state data
+ *
+ * @return !0 if to continue, 0 if reached end of run
+ */
+static int wait_for_next_change(RASPIVID_STATE *state)
+{
+   int keep_running = 1;
+   static int64_t complete_time = -1;
+
+   // Have we actually exceeded our timeout?
+   int64_t current_time =  vcos_getmicrosecs64()/1000;
+
+   if (complete_time == -1)
+      complete_time =  current_time + state->timeout;
+
+   // if we have run out of time, flag we need to exit
+   if (current_time >= complete_time && state->timeout != 0)
+      keep_running = 0;
+
+   switch (state->waitMethod)
+   {
+   case WAIT_METHOD_NONE:
+      (void)pause_and_test_abort(state, state->timeout);
+      return 0;
+
+   case WAIT_METHOD_FOREVER:
+   {
+      // We never return from this. Expect a ctrl-c to exit.
+      while (1)
+         // Have a sleep so we don't hog the CPU.
+         vcos_sleep(10000);
+
+      return 0;
+   }
+
+   case WAIT_METHOD_TIMED:
+   {
+      int abort;
+
+      if (state->bCapturing)
+         abort = pause_and_test_abort(state, state->onTime);
+      else
+         abort = pause_and_test_abort(state, state->offTime);
+
+      if (abort)
+         return 0;
+      else
+         return keep_running;
+   }
+
+   case WAIT_METHOD_KEYPRESS:
+   {
+      char ch;
+
+      if (state->verbose)
+         fprintf(stderr, "Press Enter to %s, X then ENTER to exit, [i,o,r] then ENTER to change zoom\n", state->bCapturing ? "pause" : "capture");
+
+      ch = getchar();
+      if (ch == 'x' || ch == 'X')
+         return 0;
+      else if (ch == 'i' || ch == 'I')
+      {
+         if (state->verbose)
+            fprintf(stderr, "Starting zoom in\n");
+
+         raspicamcontrol_zoom_in_zoom_out(state->camera_component, ZOOM_IN, &(state->camera_parameters).roi);
+
+         if (state->verbose)
+            dump_status(state);
+      }
+      else if (ch == 'o' || ch == 'O')
+      {
+         if (state->verbose)
+            fprintf(stderr, "Starting zoom out\n");
+
+         raspicamcontrol_zoom_in_zoom_out(state->camera_component, ZOOM_OUT, &(state->camera_parameters).roi);
+
+         if (state->verbose)
+            dump_status(state);
+      }
+      else if (ch == 'r' || ch == 'R')
+      {
+         if (state->verbose)
+            fprintf(stderr, "starting reset zoom\n");
+
+         raspicamcontrol_zoom_in_zoom_out(state->camera_component, ZOOM_RESET, &(state->camera_parameters).roi);
+
+         if (state->verbose)
+            dump_status(state);
+      }
+
+      return keep_running;
+   }
+
+
+   case WAIT_METHOD_SIGNAL:
+   {
+      // Need to wait for a SIGUSR1 signal
+      sigset_t waitset;
+      int sig;
+      int result = 0;
+
+      sigemptyset( &waitset );
+      sigaddset( &waitset, SIGUSR1 );
+
+      // We are multi threaded because we use mmal, so need to use the pthread
+      // variant of procmask to block SIGUSR1 so we can wait on it.
+      pthread_sigmask( SIG_BLOCK, &waitset, NULL );
+
+      if (state->verbose)
+      {
+         fprintf(stderr, "Waiting for SIGUSR1 to %s\n", state->bCapturing ? "pause" : "capture");
+      }
+
+      result = sigwait( &waitset, &sig );
+
+      if (state->verbose && result != 0)
+         fprintf(stderr, "Bad signal received - error %d\n", errno);
+
+      return keep_running;
+   }
+
+   } // switch
+
+   return keep_running;
+}
+
+/**
+ * main
+ */
+int main(int argc, const char **argv)
+{
+   // Our main data storage vessel..
+   RASPIVID_STATE state;
+   int exit_code = EX_OK;
+
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   MMAL_PORT_T *camera_preview_port = NULL;
+   MMAL_PORT_T *camera_video_port = NULL;
+   MMAL_PORT_T *camera_still_port = NULL;
+   MMAL_PORT_T *preview_input_port = NULL;
+   MMAL_PORT_T *encoder_input_port = NULL;
+   MMAL_PORT_T *encoder_output_port = NULL;
+   MMAL_PORT_T *splitter_input_port = NULL;
+   MMAL_PORT_T *splitter_output_port = NULL;
+   MMAL_PORT_T *splitter_preview_port = NULL;
+
+   bcm_host_init();
+
+   // Register our application with the logging system
+   vcos_log_register("RaspiVid", VCOS_LOG_CATEGORY);
+
+   signal(SIGINT, signal_handler);
+
+   // Disable USR1 for the moment - may be reenabled if go in to signal capture mode
+   signal(SIGUSR1, SIG_IGN);
+
+   default_status(&state);
+
+   // Do we have any parameters
+   if (argc == 1)
+   {
+      fprintf(stdout, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING);
+
+      display_valid_parameters(basename(argv[0]));
+      exit(EX_USAGE);
+   }
+
+   // Parse the command line and put options in to our status structure
+   if (parse_cmdline(argc, argv, &state))
+   {
+      status = -1;
+      exit(EX_USAGE);
+   }
+
+   if (state.verbose)
+   {
+      fprintf(stderr, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING);
+      dump_status(&state);
+   }
+
+   // OK, we have a nice set of parameters. Now set up our components
+   // We have three components. Camera, Preview and encoder.
+
+   if ((status = create_camera_component(&state)) != MMAL_SUCCESS)
+   {
+      vcos_log_error("%s: Failed to create camera component", __func__);
+      exit_code = EX_SOFTWARE;
+   }
+   else if ((status = raspipreview_create(&state.preview_parameters)) != MMAL_SUCCESS)
+   {
+      vcos_log_error("%s: Failed to create preview component", __func__);
+      destroy_camera_component(&state);
+      exit_code = EX_SOFTWARE;
+   }
+   else if ((status = create_encoder_component(&state)) != MMAL_SUCCESS)
+   {
+      vcos_log_error("%s: Failed to create encode component", __func__);
+      raspipreview_destroy(&state.preview_parameters);
+      destroy_camera_component(&state);
+      exit_code = EX_SOFTWARE;
+   }
+   else if (state.raw_output && (status = create_splitter_component(&state)) != MMAL_SUCCESS)
+   {
+      vcos_log_error("%s: Failed to create splitter component", __func__);
+      raspipreview_destroy(&state.preview_parameters);
+      destroy_camera_component(&state);
+      destroy_encoder_component(&state);
+      exit_code = EX_SOFTWARE;
+   }
+   else
+   {
+      if (state.verbose)
+         fprintf(stderr, "Starting component connection stage\n");
+
+      camera_preview_port = state.camera_component->output[MMAL_CAMERA_PREVIEW_PORT];
+      camera_video_port   = state.camera_component->output[MMAL_CAMERA_VIDEO_PORT];
+      camera_still_port   = state.camera_component->output[MMAL_CAMERA_CAPTURE_PORT];
+      preview_input_port  = state.preview_parameters.preview_component->input[0];
+      encoder_input_port  = state.encoder_component->input[0];
+      encoder_output_port = state.encoder_component->output[0];
+
+      if (state.raw_output)
+      {
+         splitter_input_port = state.splitter_component->input[0];
+         splitter_output_port = state.splitter_component->output[SPLITTER_OUTPUT_PORT];
+         splitter_preview_port = state.splitter_component->output[SPLITTER_PREVIEW_PORT];
+      }
+
+      if (state.preview_parameters.wantPreview )
+      {
+         if (state.raw_output)
+         {
+            if (state.verbose)
+               fprintf(stderr, "Connecting camera preview port to splitter input port\n");
+
+            // Connect camera to splitter
+            status = connect_ports(camera_preview_port, splitter_input_port, &state.splitter_connection);
+
+            if (status != MMAL_SUCCESS)
+            {
+               state.splitter_connection = NULL;
+               vcos_log_error("%s: Failed to connect camera preview port to splitter input", __func__);
+               goto error;
+            }
+
+            if (state.verbose)
+            {
+               fprintf(stderr, "Connecting splitter preview port to preview input port\n");
+               fprintf(stderr, "Starting video preview\n");
+            }
+
+            // Connect splitter to preview
+            status = connect_ports(splitter_preview_port, preview_input_port, &state.preview_connection);
+         }
+         else
+         {
+            if (state.verbose)
+            {
+               fprintf(stderr, "Connecting camera preview port to preview input port\n");
+               fprintf(stderr, "Starting video preview\n");
+            }
+
+            // Connect camera to preview
+            status = connect_ports(camera_preview_port, preview_input_port, &state.preview_connection);
+         }
+
+         if (status != MMAL_SUCCESS)
+            state.preview_connection = NULL;
+      }
+      else
+      {
+         if (state.raw_output)
+         {
+            if (state.verbose)
+               fprintf(stderr, "Connecting camera preview port to splitter input port\n");
+
+            // Connect camera to splitter
+            status = connect_ports(camera_preview_port, splitter_input_port, &state.splitter_connection);
+
+            if (status != MMAL_SUCCESS)
+            {
+               state.splitter_connection = NULL;
+               vcos_log_error("%s: Failed to connect camera preview port to splitter input", __func__);
+               goto error;
+            }
+         }
+         else
+         {
+            status = MMAL_SUCCESS;
+         }
+      }
+
+      if (status == MMAL_SUCCESS)
+      {
+         if (state.verbose)
+            fprintf(stderr, "Connecting camera video port to encoder input port\n");
+
+         // Now connect the camera to the encoder
+         status = connect_ports(camera_video_port, encoder_input_port, &state.encoder_connection);
+
+         if (status != MMAL_SUCCESS)
+         {
+            state.encoder_connection = NULL;
+            vcos_log_error("%s: Failed to connect camera video port to encoder input", __func__);
+            goto error;
+         }
+      }
+
+      if (status == MMAL_SUCCESS)
+      {
+         // Set up our userdata - this is passed though to the callback where we need the information.
+         state.callback_data.pstate = &state;
+         state.callback_data.abort = 0;
+
+         if (state.raw_output)
+         {
+            splitter_output_port->userdata = (struct MMAL_PORT_USERDATA_T *)&state.callback_data;
+
+            if (state.verbose)
+               fprintf(stderr, "Enabling splitter output port\n");
+
+            // Enable the splitter output port and tell it its callback function
+            status = mmal_port_enable(splitter_output_port, splitter_buffer_callback);
+
+            if (status != MMAL_SUCCESS)
+            {
+               vcos_log_error("%s: Failed to setup splitter output port", __func__);
+               goto error;
+            }
+         }
+
+         state.callback_data.file_handle = NULL;
+
+         if (state.filename)
+         {
+            if (state.filename[0] == '-')
+            {
+               state.callback_data.file_handle = stdout;
+
+               // Ensure we don't upset the output stream with diagnostics/info
+               state.verbose = 0;
+            }
+            else
+            {
+               state.callback_data.file_handle = open_filename(&state, state.filename);
+            }
+
+            if (!state.callback_data.file_handle)
+            {
+               // Notify user, carry on but discarding encoded output buffers
+               vcos_log_error("%s: Error opening output file: %s\nNo output file will be generated\n", __func__, state.filename);
+            }
+         }
+
+         state.callback_data.imv_file_handle = NULL;
+
+         if (state.imv_filename)
+         {
+            if (state.imv_filename[0] == '-')
+            {
+               state.callback_data.imv_file_handle = stdout;
+            }
+            else
+            {
+               state.callback_data.imv_file_handle = open_filename(&state, state.imv_filename);
+            }
+
+            if (!state.callback_data.imv_file_handle)
+            {
+               // Notify user, carry on but discarding encoded output buffers
+               fprintf(stderr, "Error opening output file: %s\nNo output file will be generated\n",state.imv_filename);
+               state.inlineMotionVectors=0;
+            }
+         }
+
+         state.callback_data.pts_file_handle = NULL;
+
+         if (state.pts_filename)
+         {
+            if (state.pts_filename[0] == '-')
+            {
+               state.callback_data.pts_file_handle = stdout;
+            }
+            else
+            {
+               state.callback_data.pts_file_handle = open_filename(&state, state.pts_filename);
+               if (state.callback_data.pts_file_handle) /* save header for mkvmerge */
+                  fprintf(state.callback_data.pts_file_handle, "# timecode format v2\n");
+            }
+
+            if (!state.callback_data.pts_file_handle)
+            {
+               // Notify user, carry on but discarding encoded output buffers
+               fprintf(stderr, "Error opening output file: %s\nNo output file will be generated\n",state.pts_filename);
+               state.save_pts=0;
+            }
+         }
+
+         state.callback_data.raw_file_handle = NULL;
+
+         if (state.raw_filename)
+         {
+            if (state.raw_filename[0] == '-')
+            {
+               state.callback_data.raw_file_handle = stdout;
+            }
+            else
+            {
+               state.callback_data.raw_file_handle = open_filename(&state, state.raw_filename);
+            }
+
+            if (!state.callback_data.raw_file_handle)
+            {
+               // Notify user, carry on but discarding encoded output buffers
+               fprintf(stderr, "Error opening output file: %s\nNo output file will be generated\n", state.raw_filename);
+               state.raw_output = 0;
+            }
+         }
+
+         if(state.bCircularBuffer)
+         {
+            if(state.bitrate == 0)
+            {
+               vcos_log_error("%s: Error circular buffer requires constant bitrate and small intra period\n", __func__);
+               goto error;
+            }
+            else if(state.timeout == 0)
+            {
+               vcos_log_error("%s: Error, circular buffer size is based on timeout must be greater than zero\n", __func__);
+               goto error;
+            }
+            else if(state.waitMethod != WAIT_METHOD_KEYPRESS && state.waitMethod != WAIT_METHOD_SIGNAL)
+            {
+               vcos_log_error("%s: Error, Circular buffer mode requires either keypress (-k) or signal (-s) triggering\n", __func__);
+               goto error;
+            }
+            else if(!state.callback_data.file_handle)
+            {
+               vcos_log_error("%s: Error require output file (or stdout) for Circular buffer mode\n", __func__);
+               goto error;
+            }
+            else
+            {
+               int count = state.bitrate * (state.timeout / 1000) / 8;
+
+               state.callback_data.cb_buff = (char *) malloc(count);
+               if(state.callback_data.cb_buff == NULL)
+               {
+                  vcos_log_error("%s: Unable to allocate circular buffer for %d seconds at %.1f Mbits\n", __func__, state.timeout / 1000, (double)state.bitrate/1000000.0);
+                  goto error;
+               }
+               else
+               {
+                  state.callback_data.cb_len = count;
+                  state.callback_data.cb_wptr = 0;
+                  state.callback_data.cb_wrap = 0;
+                  state.callback_data.cb_data = 0;
+                  state.callback_data.iframe_buff_wpos = 0;
+                  state.callback_data.iframe_buff_rpos = 0;
+                  state.callback_data.header_wptr = 0;
+               }
+            }
+         }
+
+         // Set up our userdata - this is passed though to the callback where we need the information.
+         encoder_output_port->userdata = (struct MMAL_PORT_USERDATA_T *)&state.callback_data;
+
+         if (state.verbose)
+            fprintf(stderr, "Enabling encoder output port\n");
+
+         // Enable the encoder output port and tell it its callback function
+         status = mmal_port_enable(encoder_output_port, encoder_buffer_callback);
+
+         if (status != MMAL_SUCCESS)
+         {
+            vcos_log_error("Failed to setup encoder output");
+            goto error;
+         }
+
+         if (state.demoMode)
+         {
+            // Run for the user specific time..
+            int num_iterations = state.timeout / state.demoInterval;
+            int i;
+
+            if (state.verbose)
+               fprintf(stderr, "Running in demo mode\n");
+
+            for (i=0;state.timeout == 0 || i<num_iterations;i++)
+            {
+               raspicamcontrol_cycle_test(state.camera_component);
+               vcos_sleep(state.demoInterval);
+            }
+         }
+         else
+         {
+            // Only encode stuff if we have a filename and it opened
+            // Note we use the copy in the callback, as the call back MIGHT change the file handle
+            if (state.callback_data.file_handle)
+            {
+               int running = 1;
+
+               // Send all the buffers to the encoder output port
+               {
+                  int num = mmal_queue_length(state.encoder_pool->queue);
+                  int q;
+                  for (q=0;q<num;q++)
+                  {
+                     MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state.encoder_pool->queue);
+
+                     if (!buffer)
+                        vcos_log_error("Unable to get a required buffer %d from pool queue", q);
+
+                     if (mmal_port_send_buffer(encoder_output_port, buffer)!= MMAL_SUCCESS)
+                        vcos_log_error("Unable to send a buffer to encoder output port (%d)", q);
+                  }
+               }
+
+               // Send all the buffers to the splitter output port
+               if (state.raw_output) {
+                  int num = mmal_queue_length(state.splitter_pool->queue);
+                  int q;
+                  for (q = 0; q < num; q++)
+                  {
+                     MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state.splitter_pool->queue);
+
+                     if (!buffer)
+                        vcos_log_error("Unable to get a required buffer %d from pool queue", q);
+
+                     if (mmal_port_send_buffer(splitter_output_port, buffer)!= MMAL_SUCCESS)
+                        vcos_log_error("Unable to send a buffer to splitter output port (%d)", q);
+                  }
+               }
+
+               int initialCapturing=state.bCapturing;
+               while (running)
+               {
+                  // Change state
+
+                  state.bCapturing = !state.bCapturing;
+
+                  if (mmal_port_parameter_set_boolean(camera_video_port, MMAL_PARAMETER_CAPTURE, state.bCapturing) != MMAL_SUCCESS)
+                  {
+                     // How to handle?
+                  }
+
+                  // In circular buffer mode, exit and save the buffer (make sure we do this after having paused the capture
+                  if(state.bCircularBuffer && !state.bCapturing)
+                  {
+                     break;
+                  }
+
+                  if (state.verbose)
+                  {
+                     if (state.bCapturing)
+                        fprintf(stderr, "Starting video capture\n");
+                     else
+                        fprintf(stderr, "Pausing video capture\n");
+                  }
+
+                  if(state.splitWait)
+                  {
+                     if(state.bCapturing)
+                     {
+                        if (mmal_port_parameter_set_boolean(encoder_output_port, MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME, 1) != MMAL_SUCCESS)
+                        {
+                           vcos_log_error("failed to request I-FRAME");
+                        }
+                     }
+                     else
+                     {
+                        if(!initialCapturing)
+                           state.splitNow=1;
+                     }
+                     initialCapturing=0;
+                  }
+                  running = wait_for_next_change(&state);
+               }
+
+               if (state.verbose)
+                  fprintf(stderr, "Finished capture\n");
+            }
+            else
+            {
+               if (state.timeout)
+                  vcos_sleep(state.timeout);
+               else
+               {
+                  // timeout = 0 so run forever
+                  while(1)
+                     vcos_sleep(ABORT_INTERVAL);
+               }
+            }
+         }
+      }
+      else
+      {
+         mmal_status_to_int(status);
+         vcos_log_error("%s: Failed to connect camera to preview", __func__);
+      }
+
+      if(state.bCircularBuffer)
+      {
+         int copy_from_end, copy_from_start;
+
+         copy_from_end = state.callback_data.cb_len - state.callback_data.iframe_buff[state.callback_data.iframe_buff_rpos];
+         copy_from_start = state.callback_data.cb_len - copy_from_end;
+         copy_from_start = state.callback_data.cb_wptr < copy_from_start ? state.callback_data.cb_wptr : copy_from_start;
+         if(!state.callback_data.cb_wrap)
+         {
+            copy_from_start = state.callback_data.cb_wptr;
+            copy_from_end = 0;
+         }
+
+         fwrite(state.callback_data.header_bytes, 1, state.callback_data.header_wptr, state.callback_data.file_handle);
+         // Save circular buffer
+         fwrite(state.callback_data.cb_buff + state.callback_data.iframe_buff[state.callback_data.iframe_buff_rpos], 1, copy_from_end, state.callback_data.file_handle);
+         fwrite(state.callback_data.cb_buff, 1, copy_from_start, state.callback_data.file_handle);
+         if(state.callback_data.flush_buffers) fflush(state.callback_data.file_handle);
+      }
+
+error:
+
+      mmal_status_to_int(status);
+
+      if (state.verbose)
+         fprintf(stderr, "Closing down\n");
+
+      // Disable all our ports that are not handled by connections
+      check_disable_port(camera_still_port);
+      check_disable_port(encoder_output_port);
+      check_disable_port(splitter_output_port);
+
+      if (state.preview_parameters.wantPreview && state.preview_connection)
+         mmal_connection_destroy(state.preview_connection);
+
+      if (state.encoder_connection)
+         mmal_connection_destroy(state.encoder_connection);
+
+      if (state.splitter_connection)
+         mmal_connection_destroy(state.splitter_connection);
+
+      // Can now close our file. Note disabling ports may flush buffers which causes
+      // problems if we have already closed the file!
+      if (state.callback_data.file_handle && state.callback_data.file_handle != stdout)
+         fclose(state.callback_data.file_handle);
+      if (state.callback_data.imv_file_handle && state.callback_data.imv_file_handle != stdout)
+         fclose(state.callback_data.imv_file_handle);
+      if (state.callback_data.pts_file_handle && state.callback_data.pts_file_handle != stdout)
+         fclose(state.callback_data.pts_file_handle);
+      if (state.callback_data.raw_file_handle && state.callback_data.raw_file_handle != stdout)
+         fclose(state.callback_data.raw_file_handle);
+
+      /* Disable components */
+      if (state.encoder_component)
+         mmal_component_disable(state.encoder_component);
+
+      if (state.preview_parameters.preview_component)
+         mmal_component_disable(state.preview_parameters.preview_component);
+
+      if (state.splitter_component)
+         mmal_component_disable(state.splitter_component);
+
+      if (state.camera_component)
+         mmal_component_disable(state.camera_component);
+
+      destroy_encoder_component(&state);
+      raspipreview_destroy(&state.preview_parameters);
+      destroy_splitter_component(&state);
+      destroy_camera_component(&state);
+
+      if (state.verbose)
+         fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n");
+   }
+
+   if (status != MMAL_SUCCESS)
+      raspicamcontrol_check_configuration(128);
+
+   return exit_code;
+}
diff --git a/host_applications/linux/apps/raspicam/RaspiVidYUV.c b/host_applications/linux/apps/raspicam/RaspiVidYUV.c
new file mode 100755 (executable)
index 0000000..7034b40
--- /dev/null
@@ -0,0 +1,1651 @@
+/*
+Copyright (c) 2014, DSP Group Ltd
+Copyright (c) 2014, James Hughes
+Copyright (c) 2013, Broadcom Europe Ltd
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * \file RaspiVidYUV.c
+ * Command line program to capture a camera video stream and save file
+ * as uncompressed YUV420 data
+ * Also optionally display a preview/viewfinder of current camera input.
+ *
+ * \date 7th Jan 2014
+ * \Author: James Hughes
+ *
+ * Description
+ *
+  * 2 components are created; camera and preview.
+ * Camera component has three ports, preview, video and stills.
+ * Preview is connected using standard mmal connections, the video output
+ * is written straight to the file in YUV 420 format via the requisite buffer
+ * callback. Still port is not used
+ *
+ * We use the RaspiCamControl code to handle the specific camera settings.
+ * We use the RaspiPreview code to handle the generic preview
+*/
+
+// We use some GNU extensions (basename)
+#define _GNU_SOURCE
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <memory.h>
+#include <sysexits.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#define VERSION_STRING "v1.3.15"
+
+#include "bcm_host.h"
+#include "interface/vcos/vcos.h"
+
+#include "interface/mmal/mmal.h"
+#include "interface/mmal/mmal_logging.h"
+#include "interface/mmal/mmal_buffer.h"
+#include "interface/mmal/util/mmal_util.h"
+#include "interface/mmal/util/mmal_util_params.h"
+#include "interface/mmal/util/mmal_default_components.h"
+#include "interface/mmal/util/mmal_connection.h"
+
+#include "RaspiCamControl.h"
+#include "RaspiPreview.h"
+#include "RaspiCLI.h"
+
+#include <semaphore.h>
+
+// Standard port setting for the camera component
+#define MMAL_CAMERA_PREVIEW_PORT 0
+#define MMAL_CAMERA_VIDEO_PORT 1
+#define MMAL_CAMERA_CAPTURE_PORT 2
+
+// Video format information
+// 0 implies variable
+#define VIDEO_FRAME_RATE_NUM 30
+#define VIDEO_FRAME_RATE_DEN 1
+
+/// Video render needs at least 2 buffers.
+#define VIDEO_OUTPUT_BUFFERS_NUM 3
+
+/// Interval at which we check for an failure abort during capture
+const int ABORT_INTERVAL = 100; // ms
+
+
+/// Capture/Pause switch method
+/// Simply capture for time specified
+#define WAIT_METHOD_NONE           0
+/// Cycle between capture and pause for times specified
+#define WAIT_METHOD_TIMED          1
+/// Switch between capture and pause on keypress
+#define WAIT_METHOD_KEYPRESS       2
+/// Switch between capture and pause on signal
+#define WAIT_METHOD_SIGNAL         3
+/// Run/record forever
+#define WAIT_METHOD_FOREVER        4
+
+int mmal_status_to_int(MMAL_STATUS_T status);
+static void signal_handler(int signal_number);
+
+// Forward
+typedef struct RASPIVIDYUV_STATE_S RASPIVIDYUV_STATE;
+
+/** Struct used to pass information in camera video port userdata to callback
+ */
+typedef struct
+{
+   FILE *file_handle;                   /// File handle to write buffer data to.
+   RASPIVIDYUV_STATE *pstate;           /// pointer to our state in case required in callback
+   int abort;                           /// Set to 1 in callback if an error occurs to attempt to abort the capture
+   FILE *pts_file_handle;               /// File timestamps
+} PORT_USERDATA;
+
+/** Structure containing all state information for the current run
+ */
+struct RASPIVIDYUV_STATE_S
+{
+   int timeout;                        /// Time taken before frame is grabbed and app then shuts down. Units are milliseconds
+   int width;                          /// Requested width of image
+   int height;                         /// requested height of image
+   int framerate;                      /// Requested frame rate (fps)
+   char *filename;                     /// filename of output file
+   int verbose;                        /// !0 if want detailed run information
+   int demoMode;                       /// Run app in demo mode
+   int demoInterval;                   /// Interval between camera settings changes
+   int waitMethod;                     /// Method for switching between pause and capture
+
+   int onTime;                         /// In timed cycle mode, the amount of time the capture is on per cycle
+   int offTime;                        /// In timed cycle mode, the amount of time the capture is off per cycle
+
+   int onlyLuma;                       /// Only output the luma / Y plane of the YUV data
+   int useRGB;                         /// Output RGB data rather than YUV
+
+   RASPIPREVIEW_PARAMETERS preview_parameters;   /// Preview setup parameters
+   RASPICAM_CAMERA_PARAMETERS camera_parameters; /// Camera setup parameters
+
+   MMAL_COMPONENT_T *camera_component;    /// Pointer to the camera component
+   MMAL_CONNECTION_T *preview_connection; /// Pointer to the connection from camera to preview
+
+   MMAL_POOL_T *camera_pool;            /// Pointer to the pool of buffers used by camera video port
+
+   PORT_USERDATA callback_data;         /// Used to move data to the camera callback
+
+   int bCapturing;                      /// State of capture/pause
+
+   int cameraNum;                       /// Camera number
+   int settings;                        /// Request settings from the camera
+   int sensor_mode;                     /// Sensor mode. 0=auto. Check docs/forum for modes selected by other values.
+
+   int frame;
+   char *pts_filename;
+   int save_pts;
+   int64_t starttime;
+   int64_t lasttime;
+
+   bool netListen;
+};
+
+static XREF_T  initial_map[] =
+{
+   {"record",     0},
+   {"pause",      1},
+};
+
+static int initial_map_size = sizeof(initial_map) / sizeof(initial_map[0]);
+
+
+static void display_valid_parameters(char *app_name);
+
+/// Command ID's and Structure defining our command line options
+#define CommandHelp         0
+#define CommandWidth        1
+#define CommandHeight       2
+#define CommandOutput       3
+#define CommandVerbose      4
+#define CommandTimeout      5
+#define CommandDemoMode     6
+#define CommandFramerate    7
+#define CommandTimed        8
+#define CommandSignal       9
+#define CommandKeypress     10
+#define CommandInitialState 11
+#define CommandCamSelect    12
+#define CommandSettings     13
+#define CommandSensorMode   14
+#define CommandOnlyLuma     15
+#define CommandUseRGB       16
+#define CommandSavePTS      17
+#define CommandNetListen    18
+
+static COMMAND_LIST cmdline_commands[] =
+{
+   { CommandHelp,          "-help",       "?",  "This help information", 0 },
+   { CommandWidth,         "-width",      "w",  "Set image width <size>. Default 1920", 1 },
+   { CommandHeight,        "-height",     "h",  "Set image height <size>. Default 1080", 1 },
+   { CommandOutput,        "-output",     "o",  "Output filename <filename> (to write to stdout, use '-o -')", 1 },
+   { CommandVerbose,       "-verbose",    "v",  "Output verbose information during run", 0 },
+   { CommandTimeout,       "-timeout",    "t",  "Time (in ms) to capture for. If not specified, set to 5s. Zero to disable", 1 },
+   { CommandDemoMode,      "-demo",       "d",  "Run a demo mode (cycle through range of camera options, no capture)", 1},
+   { CommandFramerate,     "-framerate",  "fps","Specify the frames per second to record", 1},
+   { CommandTimed,         "-timed",      "td", "Cycle between capture and pause. -cycle on,off where on is record time and off is pause time in ms", 0},
+   { CommandSignal,        "-signal",     "s",  "Cycle between capture and pause on Signal", 0},
+   { CommandKeypress,      "-keypress",   "k",  "Cycle between capture and pause on ENTER", 0},
+   { CommandInitialState,  "-initial",    "i",  "Initial state. Use 'record' or 'pause'. Default 'record'", 1},
+   { CommandCamSelect,     "-camselect",  "cs", "Select camera <number>. Default 0", 1 },
+   { CommandSettings,      "-settings",   "set","Retrieve camera settings and write to stdout", 0},
+   { CommandSensorMode,    "-mode",       "md", "Force sensor mode. 0=auto. See docs for other modes available", 1},
+   { CommandOnlyLuma,      "-luma",       "y",  "Only output the luma / Y of the YUV data'", 0},
+   { CommandUseRGB,        "-rgb",        "rgb","Save as RGB data rather than YUV", 0},
+   { CommandSavePTS,       "-save-pts",   "pts","Save Timestamps to file", 1 },
+   { CommandNetListen,     "-listen",     "l", "Listen on a TCP socket", 0},
+};
+
+static int cmdline_commands_size = sizeof(cmdline_commands) / sizeof(cmdline_commands[0]);
+
+
+static struct
+{
+   char *description;
+   int nextWaitMethod;
+} wait_method_description[] =
+{
+      {"Simple capture",         WAIT_METHOD_NONE},
+      {"Capture forever",        WAIT_METHOD_FOREVER},
+      {"Cycle on time",          WAIT_METHOD_TIMED},
+      {"Cycle on keypress",      WAIT_METHOD_KEYPRESS},
+      {"Cycle on signal",        WAIT_METHOD_SIGNAL},
+};
+
+static int wait_method_description_size = sizeof(wait_method_description) / sizeof(wait_method_description[0]);
+
+
+
+/**
+ * Assign a default set of parameters to the state passed in
+ *
+ * @param state Pointer to state structure to assign defaults to
+ */
+static void default_status(RASPIVIDYUV_STATE *state)
+{
+   if (!state)
+   {
+      vcos_assert(0);
+      return;
+   }
+
+   // Default everything to zero
+   memset(state, 0, sizeof(RASPIVIDYUV_STATE));
+
+   // Now set anything non-zero
+   state->timeout = 5000;     // 5s delay before take image
+   state->width = 1920;       // Default to 1080p
+   state->height = 1080;
+   state->framerate = VIDEO_FRAME_RATE_NUM;
+   state->demoMode = 0;
+   state->demoInterval = 250; // ms
+   state->waitMethod = WAIT_METHOD_NONE;
+   state->onTime = 5000;
+   state->offTime = 5000;
+
+   state->bCapturing = 0;
+
+   state->cameraNum = 0;
+   state->settings = 0;
+   state->sensor_mode = 0;
+   state->onlyLuma = 0;
+
+   // Setup preview window defaults
+   raspipreview_set_defaults(&state->preview_parameters);
+
+   // Set up the camera_parameters to default
+   raspicamcontrol_set_defaults(&state->camera_parameters);
+}
+
+
+/**
+ * Dump image state parameters to stderr.
+ *
+ * @param state Pointer to state structure to assign defaults to
+ */
+static void dump_status(RASPIVIDYUV_STATE *state)
+{
+   int i, size, ystride, yheight;
+
+   if (!state)
+   {
+      vcos_assert(0);
+      return;
+   }
+
+   fprintf(stderr, "Width %d, Height %d, filename %s\n", state->width, state->height, state->filename);
+   fprintf(stderr, "framerate %d, time delay %d\n", state->framerate, state->timeout);
+
+   // Calculate the individual image size
+   // Y stride rounded to multiple of 32. U&V stride is Y stride/2 (ie multiple of 16).
+   // Y height is padded to a 16. U/V height is Y height/2 (ie multiple of 8).
+
+   // Y plane
+   ystride = ((state->width + 31) & ~31);
+   yheight = ((state->height + 15) & ~15);
+
+   size = ystride * yheight;
+
+   // U and V plane
+   size += 2 * ystride/2 * yheight/2;
+
+   fprintf(stderr, "Sub-image size %d bytes in total.\n  Y pitch %d, Y height %d, UV pitch %d, UV Height %d\n", size, ystride, yheight, ystride/2,yheight/2);
+
+   fprintf(stderr, "Wait method : ");
+   for (i=0;i<wait_method_description_size;i++)
+   {
+      if (state->waitMethod == wait_method_description[i].nextWaitMethod)
+         fprintf(stderr, "%s", wait_method_description[i].description);
+   }
+   fprintf(stderr, "\nInitial state '%s'\n", raspicli_unmap_xref(state->bCapturing, initial_map, initial_map_size));
+   fprintf(stderr, "\n\n");
+
+   raspipreview_dump_parameters(&state->preview_parameters);
+   raspicamcontrol_dump_parameters(&state->camera_parameters);
+}
+
+/**
+ * Parse the incoming command line and put resulting parameters in to the state
+ *
+ * @param argc Number of arguments in command line
+ * @param argv Array of pointers to strings from command line
+ * @param state Pointer to state structure to assign any discovered parameters to
+ * @return Non-0 if failed for some reason, 0 otherwise
+ */
+static int parse_cmdline(int argc, const char **argv, RASPIVIDYUV_STATE *state)
+{
+   // Parse the command line arguments.
+   // We are looking for --<something> or -<abbreviation of something>
+
+   int valid = 1;
+   int i;
+
+   for (i = 1; i < argc && valid; i++)
+   {
+      int command_id, num_parameters;
+
+      if (!argv[i])
+         continue;
+
+      if (argv[i][0] != '-')
+      {
+         valid = 0;
+         continue;
+      }
+
+      // Assume parameter is valid until proven otherwise
+      valid = 1;
+
+      command_id = raspicli_get_command_id(cmdline_commands, cmdline_commands_size, &argv[i][1], &num_parameters);
+
+      // If we found a command but are missing a parameter, continue (and we will drop out of the loop)
+      if (command_id != -1 && num_parameters > 0 && (i + 1 >= argc) )
+         continue;
+
+      //  We are now dealing with a command line option
+      switch (command_id)
+      {
+      case CommandHelp:
+         display_valid_parameters(basename(argv[0]));
+         return -1;
+
+      case CommandWidth: // Width > 0
+         if (sscanf(argv[i + 1], "%u", &state->width) != 1)
+            valid = 0;
+         else
+            i++;
+         break;
+
+      case CommandHeight: // Height > 0
+         if (sscanf(argv[i + 1], "%u", &state->height) != 1)
+            valid = 0;
+         else
+            i++;
+         break;
+
+      case CommandOutput:  // output filename
+      {
+         int len = strlen(argv[i + 1]);
+         if (len)
+         {
+            state->filename = malloc(len + 1);
+            vcos_assert(state->filename);
+            if (state->filename)
+               strncpy(state->filename, argv[i + 1], len+1);
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandVerbose: // display lots of data during run
+         state->verbose = 1;
+         break;
+
+      case CommandTimeout: // Time to run viewfinder/capture
+      {
+         if (sscanf(argv[i + 1], "%u", &state->timeout) == 1)
+         {
+            // Ensure that if previously selected a waitMethod we don't overwrite it
+            if (state->timeout == 0 && state->waitMethod == WAIT_METHOD_NONE)
+               state->waitMethod = WAIT_METHOD_FOREVER;
+
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandDemoMode: // Run in demo mode - no capture
+      {
+         // Demo mode might have a timing parameter
+         // so check if a) we have another parameter, b) its not the start of the next option
+         if (i + 1 < argc  && argv[i+1][0] != '-')
+         {
+            if (sscanf(argv[i + 1], "%u", &state->demoInterval) == 1)
+            {
+               // TODO : What limits do we need for timeout?
+               if (state->demoInterval == 0)
+                  state->demoInterval = 250; // ms
+
+               state->demoMode = 1;
+               i++;
+            }
+            else
+               valid = 0;
+         }
+         else
+         {
+            state->demoMode = 1;
+         }
+
+         break;
+      }
+
+      case CommandFramerate: // fps to record
+      {
+         if (sscanf(argv[i + 1], "%u", &state->framerate) == 1)
+         {
+            // TODO : What limits do we need for fps 1 - 30 - 120??
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandTimed:
+      {
+         if (sscanf(argv[i + 1], "%u,%u", &state->onTime, &state->offTime) == 2)
+         {
+            i++;
+
+            if (state->onTime < 1000)
+               state->onTime = 1000;
+
+            if (state->offTime < 1000)
+               state->offTime = 1000;
+
+            state->waitMethod = WAIT_METHOD_TIMED;
+         }
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandKeypress:
+         state->waitMethod = WAIT_METHOD_KEYPRESS;
+         break;
+
+      case CommandSignal:
+         state->waitMethod = WAIT_METHOD_SIGNAL;
+         // Reenable the signal
+         signal(SIGUSR1, signal_handler);
+         break;
+
+      case CommandInitialState:
+      {
+         state->bCapturing = raspicli_map_xref(argv[i + 1], initial_map, initial_map_size);
+
+         if( state->bCapturing == -1)
+            state->bCapturing = 0;
+
+         i++;
+         break;
+      }
+
+      case CommandCamSelect:  //Select camera input port
+      {
+         if (sscanf(argv[i + 1], "%u", &state->cameraNum) == 1)
+         {
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandSettings:
+         state->settings = 1;
+         break;
+
+      case CommandSensorMode:
+      {
+         if (sscanf(argv[i + 1], "%u", &state->sensor_mode) == 1)
+         {
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandOnlyLuma:
+         if (state->useRGB)
+         {
+            fprintf(stderr, "--luma and --rgb are mutually exclusive\n");
+            valid = 0;
+         }
+         state->onlyLuma = 1;
+         break;
+
+      case CommandUseRGB: // display lots of data during run
+         if (state->onlyLuma)
+         {
+            fprintf(stderr, "--luma and --rgb are mutually exclusive\n");
+            valid = 0;
+         }
+         state->useRGB = 1;
+         break;
+
+      case CommandSavePTS:  // output filename
+      {
+         state->save_pts = 1;
+         int len = strlen(argv[i + 1]);
+         if (len)
+         {
+            state->pts_filename = malloc(len + 1);
+            vcos_assert(state->pts_filename);
+            if (state->pts_filename)
+               strncpy(state->pts_filename, argv[i + 1], len+1);
+            i++;
+         }
+         else
+            valid = 0;
+         break;
+      }
+
+      case CommandNetListen:
+      {
+         state->netListen = true;
+
+         break;
+      }
+
+      default:
+      {
+         // Try parsing for any image specific parameters
+         // result indicates how many parameters were used up, 0,1,2
+         // but we adjust by -1 as we have used one already
+         const char *second_arg = (i + 1 < argc) ? argv[i + 1] : NULL;
+         int parms_used = (raspicamcontrol_parse_cmdline(&state->camera_parameters, &argv[i][1], second_arg));
+
+         // Still unused, try preview options
+         if (!parms_used)
+            parms_used = raspipreview_parse_cmdline(&state->preview_parameters, &argv[i][1], second_arg);
+
+
+         // If no parms were used, this must be a bad parameters
+         if (!parms_used)
+            valid = 0;
+         else
+            i += parms_used - 1;
+
+         break;
+      }
+      }
+   }
+
+   if (!valid)
+   {
+      fprintf(stderr, "Invalid command line option (%s)\n", argv[i-1]);
+      return 1;
+   }
+
+   // Always disable verbose if output going to stdout
+   if (state->filename && state->filename[0] == '-')
+   {
+      state->verbose = 0;
+   }
+
+   return 0;
+}
+
+/**
+ * Display usage information for the application to stdout
+ *
+ * @param app_name String to display as the application name
+ */
+static void display_valid_parameters(char *app_name)
+{
+   fprintf(stdout, "Display camera output to display, and optionally saves an uncompressed YUV420 file \n\n");
+   fprintf(stdout, "NOTE: High resolutions and/or frame rates may exceed the bandwidth of the system due\n");
+   fprintf(stdout, "to the large amounts of data being moved to the SD card. This will result in undefined\n");
+   fprintf(stdout, "results in the subsequent file.\n");
+   fprintf(stdout, "The raw file produced contains all the files. Each image in the files will be of size\n");
+   fprintf(stdout, "width*height*1.5, unless width and/or height are not divisible by 16. Use the image size\n");
+   fprintf(stdout, "displayed during the run (in verbose mode) for an accurate value\n");
+
+   fprintf(stdout, "The Linux split command can be used to split up the file to individual frames\n");
+
+   fprintf(stdout, "\nusage: %s [options]\n\n", app_name);
+
+   fprintf(stdout, "Image parameter commands\n\n");
+
+   raspicli_display_help(cmdline_commands, cmdline_commands_size);
+
+   fprintf(stdout, "\n");
+
+   // Help for preview options
+   raspipreview_display_help();
+
+   // Now display any help information from the camcontrol code
+   raspicamcontrol_display_help();
+
+   fprintf(stdout, "\n");
+
+   return;
+}
+
+/**
+ *  buffer header callback function for camera control
+ *
+ *  Callback will dump buffer data to the specific file
+ *
+ * @param port Pointer to port from which callback originated
+ * @param buffer mmal buffer header pointer
+ */
+static void camera_control_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   if (buffer->cmd == MMAL_EVENT_PARAMETER_CHANGED)
+   {
+      MMAL_EVENT_PARAMETER_CHANGED_T *param = (MMAL_EVENT_PARAMETER_CHANGED_T *)buffer->data;
+      switch (param->hdr.id) {
+         case MMAL_PARAMETER_CAMERA_SETTINGS:
+         {
+            MMAL_PARAMETER_CAMERA_SETTINGS_T *settings = (MMAL_PARAMETER_CAMERA_SETTINGS_T*)param;
+            vcos_log_error("Exposure now %u, analog gain %u/%u, digital gain %u/%u",
+                       settings->exposure,
+                        settings->analog_gain.num, settings->analog_gain.den,
+                        settings->digital_gain.num, settings->digital_gain.den);
+            vcos_log_error("AWB R=%u/%u, B=%u/%u",
+                        settings->awb_red_gain.num, settings->awb_red_gain.den,
+                        settings->awb_blue_gain.num, settings->awb_blue_gain.den
+                        );
+         }
+         break;
+      }
+   }
+   else if (buffer->cmd == MMAL_EVENT_ERROR)
+   {
+      vcos_log_error("No data received from sensor. Check all connections, including the Sunny one on the camera board");
+   }
+   else
+   {
+      vcos_log_error("Received unexpected camera control callback event, 0x%08x", buffer->cmd);
+   }
+
+   mmal_buffer_header_release(buffer);
+}
+
+
+/**
+ * Open a file based on the settings in state
+ *
+ * @param state Pointer to state
+ */
+static FILE *open_filename(RASPIVIDYUV_STATE *pState, char *filename)
+{
+   FILE *new_handle = NULL;
+
+   if (filename)
+   {
+      bool bNetwork = false;
+      int sfd = -1, socktype;
+
+      if(!strncmp("tcp://", filename, 6))
+      {
+         bNetwork = true;
+         socktype = SOCK_STREAM;
+      }
+      else if(!strncmp("udp://", filename, 6))
+      {
+         if (pState->netListen)
+         {
+            fprintf(stderr, "No support for listening in UDP mode\n");
+            exit(131);
+         }
+         bNetwork = true;
+         socktype = SOCK_DGRAM;
+      }
+
+      if(bNetwork)
+      {
+         unsigned short port;
+         filename += 6;
+         char *colon;
+         if(NULL == (colon = strchr(filename, ':')))
+         {
+            fprintf(stderr, "%s is not a valid IPv4:port, use something like tcp://1.2.3.4:1234 or udp://1.2.3.4:1234\n",
+                    filename);
+            exit(132);
+         }
+         if(1 != sscanf(colon + 1, "%hu", &port))
+         {
+            fprintf(stderr,
+                    "Port parse failed. %s is not a valid network file name, use something like tcp://1.2.3.4:1234 or udp://1.2.3.4:1234\n",
+                    filename);
+            exit(133);
+         }
+         char chTmp = *colon;
+         *colon = 0;
+
+         struct sockaddr_in saddr={};
+         saddr.sin_family = AF_INET;
+         saddr.sin_port = htons(port);
+         if(0 == inet_aton(filename, &saddr.sin_addr))
+         {
+            fprintf(stderr, "inet_aton failed. %s is not a valid IPv4 address\n",
+                    filename);
+            exit(134);
+         }
+         *colon = chTmp;
+
+         if (pState->netListen)
+         {
+            int sockListen = socket(AF_INET, SOCK_STREAM, 0);
+            if (sockListen >= 0)
+            {
+               int iTmp = 1;
+               setsockopt(sockListen, SOL_SOCKET, SO_REUSEADDR, &iTmp, sizeof(int));//no error handling, just go on
+               if (bind(sockListen, (struct sockaddr *) &saddr, sizeof(saddr)) >= 0)
+               {
+                  while ((-1 == (iTmp = listen(sockListen, 0))) && (EINTR == errno))
+                     ;
+                  if (-1 != iTmp)
+                  {
+                     fprintf(stderr, "Waiting for a TCP connection on %s:%"SCNu16"...",
+                             inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
+                     struct sockaddr_in cli_addr;
+                     socklen_t clilen = sizeof(cli_addr);
+                     while ((-1 == (sfd = accept(sockListen, (struct sockaddr *) &cli_addr, &clilen))) && (EINTR == errno))
+                        ;
+                     if (sfd >= 0)
+                        fprintf(stderr, "Client connected from %s:%"SCNu16"\n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
+                     else
+                        fprintf(stderr, "Error on accept: %s\n", strerror(errno));
+                  }
+                  else//if (-1 != iTmp)
+                  {
+                     fprintf(stderr, "Error trying to listen on a socket: %s\n", strerror(errno));
+                  }
+               }
+               else//if (bind(sockListen, (struct sockaddr *) &saddr, sizeof(saddr)) >= 0)
+               {
+                  fprintf(stderr, "Error on binding socket: %s\n", strerror(errno));
+               }
+            }
+            else//if (sockListen >= 0)
+            {
+               fprintf(stderr, "Error creating socket: %s\n", strerror(errno));
+            }
+
+            if (sockListen >= 0)//regardless success or error
+               close(sockListen);//do not listen on a given port anymore
+         }
+         else//if (pState->netListen)
+         {
+            if(0 <= (sfd = socket(AF_INET, socktype, 0)))
+            {
+               fprintf(stderr, "Connecting to %s:%hu...", inet_ntoa(saddr.sin_addr), port);
+
+               int iTmp = 1;
+               while ((-1 == (iTmp = connect(sfd, (struct sockaddr *) &saddr, sizeof(struct sockaddr_in)))) && (EINTR == errno))
+                  ;
+               if (iTmp < 0)
+                  fprintf(stderr, "error: %s\n", strerror(errno));
+               else
+                  fprintf(stderr, "connected, sending video...\n");
+            }
+            else
+               fprintf(stderr, "Error creating socket: %s\n", strerror(errno));
+         }
+
+         if (sfd >= 0)
+            new_handle = fdopen(sfd, "w");
+      }
+      else
+      {
+         new_handle = fopen(filename, "wb");
+      }
+   }
+
+   if (pState->verbose)
+   {
+      if (new_handle)
+         fprintf(stderr, "Opening output file \"%s\"\n", filename);
+      else
+         fprintf(stderr, "Failed to open new file \"%s\"\n", filename);
+   }
+
+   return new_handle;
+}
+
+/**
+ *  buffer header callback function for camera
+ *
+ *  Callback will dump buffer data to internal buffer
+ *
+ * @param port Pointer to port from which callback originated
+ * @param buffer mmal buffer header pointer
+ */
+static void camera_buffer_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_BUFFER_HEADER_T *new_buffer;
+   static int64_t base_time =  -1;
+
+   // All our times based on the receipt of the first callback
+   if (base_time == -1)
+      base_time = vcos_getmicrosecs64()/1000;
+
+   // We pass our file handle and other stuff in via the userdata field.
+
+   PORT_USERDATA *pData = (PORT_USERDATA *)port->userdata;
+
+   if (pData)
+   {
+      int bytes_written = 0;
+      int bytes_to_write = buffer->length;
+
+      if (pData->pstate->onlyLuma)
+         bytes_to_write = vcos_min(buffer->length, port->format->es->video.width * port->format->es->video.height);
+
+      vcos_assert(pData->file_handle);
+
+      if (bytes_to_write)
+      {
+         mmal_buffer_header_mem_lock(buffer);
+         bytes_written = fwrite(buffer->data, 1, bytes_to_write, pData->file_handle);
+         mmal_buffer_header_mem_unlock(buffer);
+
+         if (bytes_written != bytes_to_write)
+         {
+            vcos_log_error("Failed to write buffer data (%d from %d)- aborting", bytes_written, bytes_to_write);
+            pData->abort = 1;
+         }
+      }
+   }
+   else
+   {
+      vcos_log_error("Received a camera buffer callback with no state");
+   }
+
+   // release buffer back to the pool
+   mmal_buffer_header_release(buffer);
+
+   // and send one back to the port (if still open)
+   if (port->is_enabled)
+   {
+      MMAL_STATUS_T status;
+
+      new_buffer = mmal_queue_get(pData->pstate->camera_pool->queue);
+
+      if (new_buffer)
+         status = mmal_port_send_buffer(port, new_buffer);
+
+      if (!new_buffer || status != MMAL_SUCCESS)
+         vcos_log_error("Unable to return a buffer to the camera port");
+   }
+}
+
+
+/**
+ * Create the camera component, set up its ports
+ *
+ * @param state Pointer to state control struct
+ *
+ * @return MMAL_SUCCESS if all OK, something else otherwise
+ *
+ */
+static MMAL_STATUS_T create_camera_component(RASPIVIDYUV_STATE *state)
+{
+   MMAL_COMPONENT_T *camera = 0;
+   MMAL_ES_FORMAT_T *format;
+   MMAL_PORT_T *preview_port = NULL, *video_port = NULL, *still_port = NULL;
+   MMAL_STATUS_T status;
+   MMAL_POOL_T *pool;
+
+   /* Create the component */
+   status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Failed to create camera component");
+      goto error;
+   }
+
+   MMAL_PARAMETER_INT32_T camera_num =
+      {{MMAL_PARAMETER_CAMERA_NUM, sizeof(camera_num)}, state->cameraNum};
+
+   status = mmal_port_parameter_set(camera->control, &camera_num.hdr);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Could not select camera : error %d", status);
+      goto error;
+   }
+
+   if (!camera->output_num)
+   {
+      status = MMAL_ENOSYS;
+      vcos_log_error("Camera doesn't have output ports");
+      goto error;
+   }
+
+   status = mmal_port_parameter_set_uint32(camera->control, MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG, state->sensor_mode);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Could not set sensor mode : error %d", status);
+      goto error;
+   }
+
+   preview_port = camera->output[MMAL_CAMERA_PREVIEW_PORT];
+   video_port = camera->output[MMAL_CAMERA_VIDEO_PORT];
+   still_port = camera->output[MMAL_CAMERA_CAPTURE_PORT];
+
+   if (state->settings)
+   {
+      MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T change_event_request =
+         {{MMAL_PARAMETER_CHANGE_EVENT_REQUEST, sizeof(MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T)},
+          MMAL_PARAMETER_CAMERA_SETTINGS, 1};
+
+      status = mmal_port_parameter_set(camera->control, &change_event_request.hdr);
+      if ( status != MMAL_SUCCESS )
+      {
+         vcos_log_error("No camera settings events");
+      }
+   }
+
+   // Enable the camera, and tell it its control callback function
+   status = mmal_port_enable(camera->control, camera_control_callback);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Unable to enable control port : error %d", status);
+      goto error;
+   }
+
+   //  set up the camera configuration
+   {
+      MMAL_PARAMETER_CAMERA_CONFIG_T cam_config =
+      {
+         { MMAL_PARAMETER_CAMERA_CONFIG, sizeof(cam_config) },
+         .max_stills_w = state->width,
+         .max_stills_h = state->height,
+         .stills_yuv422 = 0,
+         .one_shot_stills = 0,
+         .max_preview_video_w = state->width,
+         .max_preview_video_h = state->height,
+         .num_preview_video_frames = 3,
+         .stills_capture_circular_buffer_height = 0,
+         .fast_preview_resume = 0,
+         .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RESET_STC
+      };
+      mmal_port_parameter_set(camera->control, &cam_config.hdr);
+   }
+
+   // Now set up the port formats
+
+   // Set the encode format on the Preview port
+   // HW limitations mean we need the preview to be the same size as the required recorded output
+
+   format = preview_port->format;
+
+   if(state->camera_parameters.shutter_speed > 6000000)
+   {
+        MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
+                                                     { 50, 1000 }, {166, 1000}};
+        mmal_port_parameter_set(preview_port, &fps_range.hdr);
+   }
+   else if(state->camera_parameters.shutter_speed > 1000000)
+   {
+        MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
+                                                     { 166, 1000 }, {999, 1000}};
+        mmal_port_parameter_set(preview_port, &fps_range.hdr);
+   }
+
+   //enable dynamic framerate if necessary
+   if (state->camera_parameters.shutter_speed)
+   {
+      if (state->framerate > 1000000./state->camera_parameters.shutter_speed)
+      {
+         state->framerate=0;
+         if (state->verbose)
+            fprintf(stderr, "Enable dynamic frame rate to fulfil shutter speed requirement\n");
+      }
+   }
+
+   format->encoding = MMAL_ENCODING_OPAQUE;
+   format->es->video.width = VCOS_ALIGN_UP(state->width, 32);
+   format->es->video.height = VCOS_ALIGN_UP(state->height, 16);
+   format->es->video.crop.x = 0;
+   format->es->video.crop.y = 0;
+   format->es->video.crop.width = state->width;
+   format->es->video.crop.height = state->height;
+   format->es->video.frame_rate.num = PREVIEW_FRAME_RATE_NUM;
+   format->es->video.frame_rate.den = PREVIEW_FRAME_RATE_DEN;
+
+   status = mmal_port_format_commit(preview_port);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("camera viewfinder format couldn't be set");
+      goto error;
+   }
+
+   // Set the encode format on the video  port
+
+   format = video_port->format;
+
+   if(state->camera_parameters.shutter_speed > 6000000)
+   {
+        MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
+                                                     { 50, 1000 }, {166, 1000}};
+        mmal_port_parameter_set(video_port, &fps_range.hdr);
+   }
+   else if(state->camera_parameters.shutter_speed > 1000000)
+   {
+        MMAL_PARAMETER_FPS_RANGE_T fps_range = {{MMAL_PARAMETER_FPS_RANGE, sizeof(fps_range)},
+                                                     { 167, 1000 }, {999, 1000}};
+        mmal_port_parameter_set(video_port, &fps_range.hdr);
+   }
+
+   if (state->useRGB)
+   {
+      format->encoding = mmal_util_rgb_order_fixed(still_port) ? MMAL_ENCODING_RGB24 : MMAL_ENCODING_BGR24;
+      format->encoding_variant = 0;  //Irrelevant when not in opaque mode
+   }
+   else
+   {
+      format->encoding = MMAL_ENCODING_I420;
+      format->encoding_variant = MMAL_ENCODING_I420;
+   }
+
+   format->es->video.width = VCOS_ALIGN_UP(state->width, 32);
+   format->es->video.height = VCOS_ALIGN_UP(state->height, 16);
+   format->es->video.crop.x = 0;
+   format->es->video.crop.y = 0;
+   format->es->video.crop.width = state->width;
+   format->es->video.crop.height = state->height;
+   format->es->video.frame_rate.num = state->framerate;
+   format->es->video.frame_rate.den = VIDEO_FRAME_RATE_DEN;
+
+   status = mmal_port_format_commit(video_port);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("camera video format couldn't be set");
+      goto error;
+   }
+
+   // Ensure there are enough buffers to avoid dropping frames
+   if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
+      video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
+
+   status = mmal_port_parameter_set_boolean(video_port, MMAL_PARAMETER_ZERO_COPY, MMAL_TRUE);
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("Failed to select zero copy");
+      goto error;
+   }
+
+   // Set the encode format on the still  port
+
+   format = still_port->format;
+
+   format->encoding = MMAL_ENCODING_OPAQUE;
+   format->encoding_variant = MMAL_ENCODING_I420;
+
+   format->es->video.width = VCOS_ALIGN_UP(state->width, 32);
+   format->es->video.height = VCOS_ALIGN_UP(state->height, 16);
+   format->es->video.crop.x = 0;
+   format->es->video.crop.y = 0;
+   format->es->video.crop.width = state->width;
+   format->es->video.crop.height = state->height;
+   format->es->video.frame_rate.num = 0;
+   format->es->video.frame_rate.den = 1;
+
+   status = mmal_port_format_commit(still_port);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("camera still format couldn't be set");
+      goto error;
+   }
+
+   /* Ensure there are enough buffers to avoid dropping frames */
+   if (still_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
+      still_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
+
+   /* Enable component */
+   status = mmal_component_enable(camera);
+
+   if (status != MMAL_SUCCESS)
+   {
+      vcos_log_error("camera component couldn't be enabled");
+      goto error;
+   }
+
+   raspicamcontrol_set_all_parameters(camera, &state->camera_parameters);
+
+   /* Create pool of buffer headers for the output port to consume */
+   pool = mmal_port_pool_create(video_port, video_port->buffer_num, video_port->buffer_size);
+
+   if (!pool)
+   {
+      vcos_log_error("Failed to create buffer header pool for camera still port %s", still_port->name);
+   }
+
+   state->camera_pool = pool;
+   state->camera_component = camera;
+
+   if (state->verbose)
+      fprintf(stderr, "Camera component done\n");
+
+   return status;
+
+error:
+
+   if (camera)
+      mmal_component_destroy(camera);
+
+   return status;
+}
+
+/**
+ * Destroy the camera component
+ *
+ * @param state Pointer to state control struct
+ *
+ */
+static void destroy_camera_component(RASPIVIDYUV_STATE *state)
+{
+   if (state->camera_component)
+   {
+      mmal_component_destroy(state->camera_component);
+      state->camera_component = NULL;
+   }
+}
+
+
+/**
+ * Connect two specific ports together
+ *
+ * @param output_port Pointer the output port
+ * @param input_port Pointer the input port
+ * @param Pointer to a mmal connection pointer, reassigned if function successful
+ * @return Returns a MMAL_STATUS_T giving result of operation
+ *
+ */
+static MMAL_STATUS_T connect_ports(MMAL_PORT_T *output_port, MMAL_PORT_T *input_port, MMAL_CONNECTION_T **connection)
+{
+   MMAL_STATUS_T status;
+
+   status =  mmal_connection_create(connection, output_port, input_port, MMAL_CONNECTION_FLAG_TUNNELLING | MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT);
+
+   if (status == MMAL_SUCCESS)
+   {
+      status =  mmal_connection_enable(*connection);
+      if (status != MMAL_SUCCESS)
+         mmal_connection_destroy(*connection);
+   }
+
+   return status;
+}
+
+/**
+ * Checks if specified port is valid and enabled, then disables it
+ *
+ * @param port  Pointer the port
+ *
+ */
+static void check_disable_port(MMAL_PORT_T *port)
+{
+   if (port && port->is_enabled)
+      mmal_port_disable(port);
+}
+
+/**
+ * Handler for sigint signals
+ *
+ * @param signal_number ID of incoming signal.
+ *
+ */
+static void signal_handler(int signal_number)
+{
+   if (signal_number == SIGUSR1)
+   {
+      // Handle but ignore - prevents us dropping out if started in none-signal mode
+      // and someone sends us the USR1 signal anyway
+   }
+   else
+   {
+      // Going to abort on all other signals
+      vcos_log_error("Aborting program\n");
+      exit(130);
+   }
+
+}
+
+/**
+ * Pause for specified time, but return early if detect an abort request
+ *
+ * @param state Pointer to state control struct
+ * @param pause Time in ms to pause
+ * @param callback Struct contain an abort flag tested for early termination
+ *
+ */
+static int pause_and_test_abort(RASPIVIDYUV_STATE *state, int pause)
+{
+   int wait;
+
+   if (!pause)
+      return 0;
+
+   // Going to check every ABORT_INTERVAL milliseconds
+   for (wait = 0; wait < pause; wait+= ABORT_INTERVAL)
+   {
+      vcos_sleep(ABORT_INTERVAL);
+      if (state->callback_data.abort)
+         return 1;
+   }
+
+   return 0;
+}
+
+
+/**
+ * Function to wait in various ways (depending on settings)
+ *
+ * @param state Pointer to the state data
+ *
+ * @return !0 if to continue, 0 if reached end of run
+ */
+static int wait_for_next_change(RASPIVIDYUV_STATE *state)
+{
+   int keep_running = 1;
+   static int64_t complete_time = -1;
+
+   // Have we actually exceeded our timeout?
+   int64_t current_time =  vcos_getmicrosecs64()/1000;
+
+   if (complete_time == -1)
+      complete_time =  current_time + state->timeout;
+
+   // if we have run out of time, flag we need to exit
+   if (current_time >= complete_time && state->timeout != 0)
+      keep_running = 0;
+
+   switch (state->waitMethod)
+   {
+   case WAIT_METHOD_NONE:
+      (void)pause_and_test_abort(state, state->timeout);
+      return 0;
+
+   case WAIT_METHOD_FOREVER:
+   {
+      // We never return from this. Expect a ctrl-c to exit.
+      while (1)
+         // Have a sleep so we don't hog the CPU.
+         vcos_sleep(10000);
+
+      return 0;
+   }
+
+   case WAIT_METHOD_TIMED:
+   {
+      int abort;
+
+      if (state->bCapturing)
+         abort = pause_and_test_abort(state, state->onTime);
+      else
+         abort = pause_and_test_abort(state, state->offTime);
+
+      if (abort)
+         return 0;
+      else
+         return keep_running;
+   }
+
+   case WAIT_METHOD_KEYPRESS:
+   {
+      char ch;
+
+      if (state->verbose)
+         fprintf(stderr, "Press Enter to %s, X then ENTER to exit\n", state->bCapturing ? "pause" : "capture");
+
+      ch = getchar();
+      if (ch == 'x' || ch == 'X')
+         return 0;
+      else
+         return keep_running;
+   }
+
+   case WAIT_METHOD_SIGNAL:
+   {
+      // Need to wait for a SIGUSR1 signal
+      sigset_t waitset;
+      int sig;
+      int result = 0;
+
+      sigemptyset( &waitset );
+      sigaddset( &waitset, SIGUSR1 );
+
+      // We are multi threaded because we use mmal, so need to use the pthread
+      // variant of procmask to block SIGUSR1 so we can wait on it.
+      pthread_sigmask( SIG_BLOCK, &waitset, NULL );
+
+      if (state->verbose)
+      {
+         fprintf(stderr, "Waiting for SIGUSR1 to %s\n", state->bCapturing ? "pause" : "capture");
+      }
+
+      result = sigwait( &waitset, &sig );
+
+      if (state->verbose && result != 0)
+         fprintf(stderr, "Bad signal received - error %d\n", errno);
+
+      return keep_running;
+   }
+
+   } // switch
+
+   return keep_running;
+}
+
+/**
+ * main
+ */
+int main(int argc, const char **argv)
+{
+   // Our main data storage vessel..
+   RASPIVIDYUV_STATE state = {0};
+   int exit_code = EX_OK;
+
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   MMAL_PORT_T *camera_preview_port = NULL;
+   MMAL_PORT_T *camera_video_port = NULL;
+   MMAL_PORT_T *camera_still_port = NULL;
+   MMAL_PORT_T *preview_input_port = NULL;
+
+   bcm_host_init();
+
+   // Register our application with the logging system
+   vcos_log_register("RaspiVid", VCOS_LOG_CATEGORY);
+
+   signal(SIGINT, signal_handler);
+
+   // Disable USR1 for the moment - may be reenabled if go in to signal capture mode
+   signal(SIGUSR1, SIG_IGN);
+
+   default_status(&state);
+
+   // Do we have any parameters
+   if (argc == 1)
+   {
+      fprintf(stdout, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING);
+
+      display_valid_parameters(basename(argv[0]));
+      exit(EX_USAGE);
+   }
+
+   // Parse the command line and put options in to our status structure
+   if (parse_cmdline(argc, argv, &state))
+   {
+      status = -1;
+      exit(EX_USAGE);
+   }
+
+   if (state.verbose)
+   {
+      fprintf(stderr, "\n%s Camera App %s\n\n", basename(argv[0]), VERSION_STRING);
+      dump_status(&state);
+   }
+
+   // OK, we have a nice set of parameters. Now set up our components
+   // We have two components. Camera, Preview
+
+   if ((status = create_camera_component(&state)) != MMAL_SUCCESS)
+   {
+      vcos_log_error("%s: Failed to create camera component", __func__);
+      exit_code = EX_SOFTWARE;
+   }
+   else if ((status = raspipreview_create(&state.preview_parameters)) != MMAL_SUCCESS)
+   {
+      vcos_log_error("%s: Failed to create preview component", __func__);
+      destroy_camera_component(&state);
+      exit_code = EX_SOFTWARE;
+   }
+   else
+   {
+      if (state.verbose)
+         fprintf(stderr, "Starting component connection stage\n");
+
+      camera_preview_port = state.camera_component->output[MMAL_CAMERA_PREVIEW_PORT];
+      camera_video_port   = state.camera_component->output[MMAL_CAMERA_VIDEO_PORT];
+      camera_still_port   = state.camera_component->output[MMAL_CAMERA_CAPTURE_PORT];
+      preview_input_port  = state.preview_parameters.preview_component->input[0];
+
+      if (state.preview_parameters.wantPreview )
+      {
+         if (state.verbose)
+         {
+            fprintf(stderr, "Connecting camera preview port to preview input port\n");
+            fprintf(stderr, "Starting video preview\n");
+         }
+
+         // Connect camera to preview
+         status = connect_ports(camera_preview_port, preview_input_port, &state.preview_connection);
+
+         if (status != MMAL_SUCCESS)
+            state.preview_connection = NULL;
+      }
+      else
+      {
+         status = MMAL_SUCCESS;
+      }
+
+      if (status == MMAL_SUCCESS)
+      {
+         state.callback_data.file_handle = NULL;
+
+         if (state.filename)
+         {
+            if (state.filename[0] == '-')
+            {
+               state.callback_data.file_handle = stdout;
+
+               // Ensure we don't upset the output stream with diagnostics/info
+               state.verbose = 0;
+            }
+            else
+            {
+               state.callback_data.file_handle = open_filename(&state, state.filename);
+            }
+
+            if (!state.callback_data.file_handle)
+            {
+               // Notify user, carry on but discarding output buffers
+               vcos_log_error("%s: Error opening output file: %s\nNo output file will be generated\n", __func__, state.filename);
+            }
+         }
+
+         state.callback_data.pts_file_handle = NULL;
+
+         if (state.pts_filename)
+         {
+            if (state.pts_filename[0] == '-')
+            {
+               state.callback_data.pts_file_handle = stdout;
+            }
+            else
+            {
+               state.callback_data.pts_file_handle = open_filename(&state, state.pts_filename);
+               if (state.callback_data.pts_file_handle) /* save header for mkvmerge */
+                  fprintf(state.callback_data.pts_file_handle, "# timecode format v2\n");
+            }
+
+            if (!state.callback_data.pts_file_handle)
+            {
+               // Notify user, carry on but discarding encoded output buffers
+               fprintf(stderr, "Error opening output file: %s\nNo output file will be generated\n",state.pts_filename);
+               state.save_pts=0;
+            }
+         }
+
+         // Set up our userdata - this is passed though to the callback where we need the information.
+         state.callback_data.pstate = &state;
+         state.callback_data.abort = 0;
+
+         camera_video_port->userdata = (struct MMAL_PORT_USERDATA_T *)&state.callback_data;
+
+         if (state.verbose)
+            fprintf(stderr, "Enabling camera video port\n");
+
+         // Enable the camera video port and tell it its callback function
+         status = mmal_port_enable(camera_video_port, camera_buffer_callback);
+
+         if (status != MMAL_SUCCESS)
+         {
+            vcos_log_error("Failed to setup camera output");
+            goto error;
+         }
+
+         if (state.demoMode)
+         {
+            // Run for the user specific time..
+            int num_iterations = state.timeout / state.demoInterval;
+            int i;
+
+            if (state.verbose)
+               fprintf(stderr, "Running in demo mode\n");
+
+            for (i=0;state.timeout == 0 || i<num_iterations;i++)
+            {
+               raspicamcontrol_cycle_test(state.camera_component);
+               vcos_sleep(state.demoInterval);
+            }
+         }
+         else
+         {
+            // Only save stuff if we have a filename and it opened
+            // Note we use the file handle copy in the callback, as the call back MIGHT change the file handle
+            if (state.callback_data.file_handle)
+            {
+               int running = 1;
+
+               // Send all the buffers to the camera video port
+               {
+                  int num = mmal_queue_length(state.camera_pool->queue);
+                  int q;
+                  for (q=0;q<num;q++)
+                  {
+                     MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(state.camera_pool->queue);
+
+                     if (!buffer)
+                        vcos_log_error("Unable to get a required buffer %d from pool queue", q);
+
+                     if (mmal_port_send_buffer(camera_video_port, buffer)!= MMAL_SUCCESS)
+                        vcos_log_error("Unable to send a buffer to camera video port (%d)", q);
+                  }
+               }
+
+               while (running)
+               {
+                  // Change state
+
+                  state.bCapturing = !state.bCapturing;
+
+                  if (mmal_port_parameter_set_boolean(camera_video_port, MMAL_PARAMETER_CAPTURE, state.bCapturing) != MMAL_SUCCESS)
+                  {
+                     // How to handle?
+                  }
+
+                  if (state.verbose)
+                  {
+                     if (state.bCapturing)
+                        fprintf(stderr, "Starting video capture\n");
+                     else
+                        fprintf(stderr, "Pausing video capture\n");
+                  }
+
+                  running = wait_for_next_change(&state);
+               }
+
+               if (state.verbose)
+                  fprintf(stderr, "Finished capture\n");
+            }
+            else
+            {
+               if (state.timeout)
+                  vcos_sleep(state.timeout);
+               else
+               {
+                  // timeout = 0 so run forever
+                  while(1)
+                     vcos_sleep(ABORT_INTERVAL);
+               }
+            }
+         }
+      }
+      else
+      {
+         mmal_status_to_int(status);
+         vcos_log_error("%s: Failed to connect camera to preview", __func__);
+      }
+
+error:
+
+      mmal_status_to_int(status);
+
+      if (state.verbose)
+         fprintf(stderr, "Closing down\n");
+
+      // Disable all our ports that are not handled by connections
+      check_disable_port(camera_still_port);
+
+      if (state.preview_parameters.wantPreview && state.preview_connection)
+         mmal_connection_destroy(state.preview_connection);
+
+      if (state.preview_parameters.preview_component)
+         mmal_component_disable(state.preview_parameters.preview_component);
+
+      if (state.camera_component)
+         mmal_component_disable(state.camera_component);
+
+      // Can now close our file. Note disabling ports may flush buffers which causes
+      // problems if we have already closed the file!
+      if (state.callback_data.file_handle && state.callback_data.file_handle != stdout)
+         fclose(state.callback_data.file_handle);
+      if (state.callback_data.pts_file_handle && state.callback_data.pts_file_handle != stdout)
+         fclose(state.callback_data.pts_file_handle);
+
+      raspipreview_destroy(&state.preview_parameters);
+      destroy_camera_component(&state);
+
+      if (state.verbose)
+         fprintf(stderr, "Close down completed, all components disconnected, disabled and destroyed\n\n");
+   }
+
+   if (status != MMAL_SUCCESS)
+      raspicamcontrol_check_configuration(128);
+
+   return exit_code;
+}
+
+
diff --git a/host_applications/linux/apps/raspicam/gl_scenes/cube_texture_and_coords.h b/host_applications/linux/apps/raspicam/gl_scenes/cube_texture_and_coords.h
new file mode 100755 (executable)
index 0000000..663e23b
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Spatial coordinates for the cube
+
+static const GLbyte quadx[6*4*3] = {
+   /* FRONT */
+   -10, -10,  10,
+   10, -10,  10,
+   -10,  10,  10,
+   10,  10,  10,
+
+   /* BACK */
+   -10, -10, -10,
+   -10,  10, -10,
+   10, -10, -10,
+   10,  10, -10,
+
+   /* LEFT */
+   -10, -10,  10,
+   -10,  10,  10,
+   -10, -10, -10,
+   -10,  10, -10,
+
+   /* RIGHT */
+   10, -10, -10,
+   10,  10, -10,
+   10, -10,  10,
+   10,  10,  10,
+
+   /* TOP */
+   -10,  10,  10,
+   10,  10,  10,
+   -10,  10, -10,
+   10,  10, -10,
+
+   /* BOTTOM */
+   -10, -10,  10,
+   -10, -10, -10,
+   10, -10,  10,
+   10, -10, -10,
+};
+
+/** Texture coordinates for the quad. */
+static const GLfloat texCoords[6 * 4 * 2] = {
+   0.f,  0.f,
+   1.f,  0.f,
+   0.f,  1.f,
+   1.f,  1.f,
+
+   0.f,  0.f,
+   1.f,  0.f,
+   0.f,  1.f,
+   1.f,  1.f,
+
+   0.f,  0.f,
+   1.f,  0.f,
+   0.f,  1.f,
+   1.f,  1.f,
+
+   0.f,  0.f,
+   1.f,  0.f,
+   0.f,  1.f,
+   1.f,  1.f,
+
+   0.f,  0.f,
+   1.f,  0.f,
+   0.f,  1.f,
+   1.f,  1.f,
+
+   0.f,  0.f,
+   1.f,  0.f,
+   0.f,  1.f,
+   1.f,  1.f,
+};
+
diff --git a/host_applications/linux/apps/raspicam/gl_scenes/mirror.c b/host_applications/linux/apps/raspicam/gl_scenes/mirror.c
new file mode 100755 (executable)
index 0000000..fe14096
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, Tim Gover
+All rights reserved.
+
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mirror.h"
+#include "RaspiTex.h"
+#include "RaspiTexUtil.h"
+#include <GLES2/gl2.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+/**
+ * Draws an external EGL image and applies a sine wave distortion to create
+ * a hall of mirrors effect.
+ */
+static RASPITEXUTIL_SHADER_PROGRAM_T mirror_shader = {
+    .vertex_source =
+    "attribute vec2 vertex;\n"
+    "varying vec2 texcoord;"
+    "void main(void) {\n"
+    "   texcoord = 0.5 * (vertex + 1.0);\n"
+    "   gl_Position = vec4(vertex, 0.0, 1.0);\n"
+    "}\n",
+
+    .fragment_source =
+    "#extension GL_OES_EGL_image_external : require\n"
+    "uniform samplerExternalOES tex;\n"
+    "uniform float offset;\n"
+    "const float waves = 2.0;\n"
+    "varying vec2 texcoord;\n"
+    "void main(void) {\n"
+    "    float x = texcoord.x + 0.05 * sin(offset + (texcoord.y * waves * 2.0 * 3.141592));\n"
+    "    float y = texcoord.y + 0.05 * sin(offset + (texcoord.x * waves * 2.0 * 3.141592));\n"
+    "    if (y < 1.0 && y > 0.0 && x < 1.0 && x > 0.0) {\n"
+    "       vec2 pos = vec2(x, y);\n"
+    "       gl_FragColor = texture2D(tex, pos);\n"
+    "    }\n"
+    "    else {\n"
+    "       gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);\n"
+    "    }\n"
+    "}\n",
+    .uniform_names = {"tex", "offset"},
+    .attribute_names = {"vertex"},
+};
+
+/**
+ * Creates the OpenGL ES 2.X context and builds the shaders.
+ * @param raspitex_state A pointer to the GL preview state.
+ * @return Zero if successful.
+ */
+static int mirror_init(RASPITEX_STATE *state)
+{
+    int rc = raspitexutil_gl_init_2_0(state);
+    if (rc != 0)
+       goto end;
+
+    rc = raspitexutil_build_shader_program(&mirror_shader);
+end:
+    return rc;
+}
+
+static int mirror_redraw(RASPITEX_STATE *raspitex_state) {
+    static float offset = 0.0;
+
+    // Start with a clear screen
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    // Bind the OES texture which is used to render the camera preview
+    glBindTexture(GL_TEXTURE_EXTERNAL_OES, raspitex_state->texture);
+
+    offset += 0.05;
+    GLCHK(glUseProgram(mirror_shader.program));
+    GLCHK(glEnableVertexAttribArray(mirror_shader.attribute_locations[0]));
+    GLfloat varray[] = {
+        -1.0f, -1.0f,
+        1.0f,  1.0f,
+        1.0f, -1.0f,
+
+        -1.0f,  1.0f,
+        1.0f,  1.0f,
+        -1.0f, -1.0f,
+    };
+    GLCHK(glVertexAttribPointer(mirror_shader.attribute_locations[0], 2, GL_FLOAT, GL_FALSE, 0, varray));
+    GLCHK(glUniform1f(mirror_shader.uniform_locations[1], offset));
+    GLCHK(glDrawArrays(GL_TRIANGLES, 0, 6));
+
+    GLCHK(glDisableVertexAttribArray(mirror_shader.attribute_locations[0]));
+    GLCHK(glUseProgram(0));
+    return 0;
+}
+
+int mirror_open(RASPITEX_STATE *state)
+{
+   state->ops.gl_init = mirror_init;
+   state->ops.redraw = mirror_redraw;
+   state->ops.update_texture = raspitexutil_update_texture;
+   return 0;
+}
diff --git a/host_applications/linux/apps/raspicam/gl_scenes/mirror.h b/host_applications/linux/apps/raspicam/gl_scenes/mirror.h
new file mode 100755 (executable)
index 0000000..8437728
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, Tim Gover
+All rights reserved.
+
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MIRROR_H
+#define MIRROR_H
+
+#include "RaspiTex.h"
+
+int mirror_open(RASPITEX_STATE *state);
+
+#endif /* MIRROR_H */
diff --git a/host_applications/linux/apps/raspicam/gl_scenes/models.c b/host_applications/linux/apps/raspicam/gl_scenes/models.c
new file mode 100755 (executable)
index 0000000..bbb5a30
--- /dev/null
@@ -0,0 +1,521 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <math.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#include "GLES/gl.h"
+#include <GLES/glext.h>
+#include "EGL/egl.h"
+#include "EGL/eglext.h"
+#include "models.h"
+
+#define VMCS_RESOURCE(a,b) (b)
+
+/******************************************************************************
+Private typedefs, macros and constants
+******************************************************************************/
+
+enum {VBO_VERTEX, VBO_NORMAL, VBO_TEXTURE, VBO_MAX};
+#define MAX_MATERIALS 4
+#define MAX_MATERIAL_NAME 32
+
+typedef struct wavefront_material_s {
+   GLuint vbo[VBO_MAX];
+   int numverts;
+   char name[MAX_MATERIAL_NAME];
+   GLuint texture;
+} WAVEFRONT_MATERIAL_T;
+
+typedef struct wavefront_model_s {
+   WAVEFRONT_MATERIAL_T material[MAX_MATERIALS];
+   int num_materials;
+   GLuint texture;
+} WAVEFRONT_MODEL_T;
+
+
+/******************************************************************************
+Static Data
+******************************************************************************/
+
+/******************************************************************************
+Static Function Declarations
+******************************************************************************/
+
+/******************************************************************************
+Static Function Definitions
+******************************************************************************/
+
+static void create_vbo(GLenum type, GLuint *vbo, int size, void *data)
+{
+   glGenBuffers(1, vbo);
+   vc_assert(*vbo);
+   glBindBuffer(type, *vbo);
+   glBufferData(type, size, data, GL_STATIC_DRAW);
+   glBindBuffer(type, 0);     
+}
+
+
+static void destroy_vbo(GLuint *vbo)
+{
+   glDeleteBuffers(1, vbo);
+   *vbo = 0;
+}
+
+#define MAX_VERTICES 100000
+static void *allocbuffer(int size)
+{
+   return malloc(size);
+}
+
+static void freebuffer(void *p)
+{
+   free (p);
+}
+
+static void centre_and_rescale(float *verts, int numvertices)
+{
+   float cx=0.0f, cy=0.0f, cz=0.0f, scale=0.0f;
+   float minx=0.0f, miny=0.0f, minz=0.0f;
+   float maxx=0.0f, maxy=0.0f, maxz=0.0f;
+   int i;
+   float *v = verts;
+   minx = maxx = verts[0];
+   miny = maxy = verts[1];
+   minz = maxz = verts[2];
+   for (i=0; i<numvertices; i++) {
+      float x = *v++;
+      float y = *v++;
+      float z = *v++;
+      minx = vcos_min(minx, x);
+      miny = vcos_min(miny, y);
+      minz = vcos_min(minz, z);
+      maxx = vcos_max(maxx, x);
+      maxy = vcos_max(maxy, y);
+      maxz = vcos_max(maxz, z);
+      cx += x;
+      cy += y;
+      cz += z;
+   }
+   cx /= (float)numvertices;
+   cy /= (float)numvertices;
+   cz /= (float)numvertices;
+   scale = 3.0f / (maxx-minx + maxy-miny + maxz-minz);
+   v = verts;
+   for (i=0; i<numvertices; i++) {
+      *v = (*v-cx) * scale; v++;
+      *v = (*v-cy) * scale; v++;
+      *v = (*v-cz) * scale; v++;
+   }
+}
+
+static void renormalise(float *verts, int numvertices)
+{
+   int i;
+   float *v = verts;
+   for (i=0;i<numvertices; i++) {
+      float x = v[0];
+      float y = v[1];
+      float z = v[2];
+      float scale = 1.0f/sqrtf(x*x + y*y + z*z);
+      *v++ = x * scale;
+      *v++ = y * scale;
+      *v++ = z * scale;
+   }
+}
+
+static void deindex(float *dst, const float *src, const unsigned short *indexes, GLsizei size, GLsizei count)
+{
+   int i;
+   for (i=0; i<count; i++) {
+      int ind = size * (indexes[0]-1);
+      *dst++ = src[ind + 0];
+      *dst++ = src[ind + 1];
+      // todo: optimise - move out of loop
+      if (size >= 3) *dst++ = src[ind + 2];
+      indexes += 3;
+   }
+}
+
+int draw_wavefront(MODEL_T m, GLuint texture)
+{
+   int i;
+   WAVEFRONT_MODEL_T *model = (WAVEFRONT_MODEL_T *)m;
+
+   for (i=0; i<model->num_materials; i++) {
+      WAVEFRONT_MATERIAL_T *mat = model->material + i;
+      if (mat->texture == -1) continue;
+
+      if (mat->texture)
+         glBindTexture(GL_TEXTURE_2D, mat->texture);
+      else
+         glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture);
+
+      if (mat->vbo[VBO_VERTEX]) {
+         glBindBuffer(GL_ARRAY_BUFFER, mat->vbo[VBO_VERTEX]);
+         glVertexPointer(3, GL_FLOAT, 0, NULL);
+      }
+      if (mat->vbo[VBO_NORMAL]) {   
+         glEnableClientState(GL_NORMAL_ARRAY);
+         glBindBuffer(GL_ARRAY_BUFFER, mat->vbo[VBO_NORMAL]);
+         glNormalPointer(GL_FLOAT, 0, NULL);
+      } else {
+         glDisableClientState(GL_NORMAL_ARRAY);
+      }
+      if (mat->vbo[VBO_TEXTURE]) {   
+         glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+         glBindBuffer(GL_ARRAY_BUFFER, mat->vbo[VBO_TEXTURE]);
+         glTexCoordPointer(2, GL_FLOAT, 0, NULL);
+      } else {
+         glDisableClientState(GL_TEXTURE_COORD_ARRAY);
+      }
+      glDrawArrays(GL_TRIANGLES, 0, mat->numverts);
+   }
+   glBindBuffer(GL_ARRAY_BUFFER, 0);
+   return 0;
+}
+
+struct wavefront_model_loading_s {
+   unsigned short material_index[MAX_MATERIALS];
+   int num_materials;
+   int numv, numt, numn, numf;
+   unsigned int data[0];
+};
+
+static int load_wavefront_obj(const char *modelname, WAVEFRONT_MODEL_T *model, struct wavefront_model_loading_s *m)
+{
+   char line[256+1];
+   unsigned short pp[54+1];
+   FILE *fp;
+   int i, valid;
+   float *qv = (float *)m->data;
+   float *qt = (float *)m->data + 3 * MAX_VERTICES;
+   float *qn = (float *)m->data + (3+2) * MAX_VERTICES;
+   unsigned short *qf = (unsigned short *)((float *)m->data + (3+2+3) * MAX_VERTICES);
+   float *pv = qv, *pt = qt, *pn = qn;
+   unsigned short *pf = qf;
+   fp = fopen(modelname, "r");
+   if (!fp) return -1;
+
+   m->num_materials = 0;
+   m->material_index[0] = 0;
+
+   valid = fread(line, 1, sizeof(line)-1, fp);
+
+   while (valid > 0) {
+      char *s, *end = line;
+      
+      while((end-line < valid) && *end != '\n' && *end != '\r')
+         end++;
+      *end++ = 0;
+
+      if((end-line < valid) && *end != '\n' && *end != '\r')
+         *end++ = 0;
+
+      s = line;
+
+      if (s[strlen(s)-1] == 10) s[strlen(s)-1]=0;
+      switch (s[0]) {
+      case '#': break; // comment
+      case '\r': case '\n': case '\0': break; // blank line
+      case 'm': vc_assert(strncmp(s, "mtllib", sizeof "mtllib"-1)==0); break;
+      case 'o': break;
+      case 'u': 
+         if (sscanf(s, "usemtl %s", /*MAX_MATERIAL_NAME-1, */model->material[m->num_materials].name) == 1) {
+            if (m->num_materials < MAX_MATERIALS) {
+               if (m->num_materials > 0 && ((pf-qf)/3 == m->material_index[m->num_materials-1] || strcmp(model->material[m->num_materials-1].name, model->material[m->num_materials].name)==0)) {
+                  strcpy(model->material[m->num_materials-1].name, model->material[m->num_materials].name);
+                  m->num_materials--;
+               } else
+               m->material_index[m->num_materials] = (pf-qf)/3;
+               m->num_materials++;
+            }
+         } else { printf("%s", s); vc_assert(0); }
+         break;
+      case 'g': vc_assert(strncmp(s, "g ", sizeof "g "-1)==0); break;
+      case 's': vc_assert(strncmp(s, "s ", sizeof "s "-1)==0); break;
+      case 'v': case 'f':
+         if (sscanf(s, "v %f %f %f", pv+0, pv+1, pv+2) == 3) {
+            pv += 3;
+         } else if (sscanf(s, "vt %f %f", pt+0, pt+1) == 2) {
+            pt += 2;
+         } else if (sscanf(s, "vn %f %f %f", pn+0, pn+1, pn+2) == 3) {
+            pn += 3;
+         } else if (i = sscanf(s, "f"" %hu//%hu %hu//%hu %hu//%hu %hu//%hu %hu//%hu %hu//%hu"
+                                     " %hu//%hu %hu//%hu %hu//%hu %hu//%hu %hu//%hu %hu//%hu"
+                                     " %hu//%hu %hu//%hu %hu//%hu %hu//%hu %hu//%hu %hu//%hu %hu",
+               pp+ 0, pp+ 1, pp+ 2, pp+ 3, pp+ 4, pp+ 5, pp+ 6, pp+ 7, pp+ 8, pp+ 9, pp+10, pp+11, 
+               pp+12, pp+13, pp+14, pp+15, pp+16, pp+17, pp+18, pp+19, pp+20, pp+21, pp+22, pp+23, 
+               pp+24, pp+25, pp+26, pp+27, pp+28, pp+29, pp+30, pp+32, pp+32, pp+33, pp+34, pp+35, pp+36), i >= 6) {
+            int poly = i/2;
+            //vc_assert(i < countof(pp)); // may need to increment poly count and pp array
+            for (i=1; i<poly-1; i++) {
+               *pf++ = pp[0]; *pf++ = 0; *pf++ = pp[1];
+               *pf++ = pp[2*i+0]; *pf++ = 0; *pf++ = pp[2*i+1];
+               *pf++ = pp[2*(i+1)+0]; *pf++ = 0; *pf++ = pp[2*(i+1)+1];
+            }
+         } else if (i = sscanf(s, "f"" %hu/%hu %hu/%hu %hu/%hu %hu/%hu %hu/%hu %hu/%hu"
+                                     " %hu/%hu %hu/%hu %hu/%hu %hu/%hu %hu/%hu %hu/%hu"
+                                     " %hu/%hu %hu/%hu %hu/%hu %hu/%hu %hu/%hu %hu/%hu %hu",
+               pp+ 0, pp+ 1, pp+ 2, pp+ 3, pp+ 4, pp+ 5, pp+ 6, pp+ 7, pp+ 8, pp+ 9, pp+10, pp+11, 
+               pp+12, pp+13, pp+14, pp+15, pp+16, pp+17, pp+18, pp+19, pp+20, pp+21, pp+22, pp+23, 
+               pp+24, pp+25, pp+26, pp+27, pp+28, pp+29, pp+30, pp+32, pp+32, pp+33, pp+34, pp+35, pp+36), i >= 6) {
+            int poly = i/2;
+            //vc_assert(i < countof(pp); // may need to increment poly count and pp array
+            for (i=1; i<poly-1; i++) {
+               *pf++ = pp[0]; *pf++ = pp[1]; *pf++ = 0;
+               *pf++ = pp[2*i+0]; *pf++ = pp[2*i+1]; *pf++ = 0;
+               *pf++ = pp[2*(i+1)+0]; *pf++ = pp[2*(i+1)+1]; *pf++ = 0;
+            }
+         } else if (i = sscanf(s, "f"" %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu"
+                                     " %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu"
+                                     " %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu/%hu/%hu %hu",
+               pp+ 0, pp+ 1, pp+ 2, pp+ 3, pp+ 4, pp+ 5, pp+ 6, pp+ 7, pp+ 8, pp+ 9, pp+10, pp+11, pp+12, pp+13, pp+14, pp+15, pp+16, pp+17, 
+               pp+18, pp+19, pp+20, pp+21, pp+22, pp+23, pp+24, pp+25, pp+26, pp+27, pp+28, pp+29, pp+30, pp+32, pp+32, pp+33, pp+34, pp+35, 
+               pp+36, pp+37, pp+38, pp+39, pp+40, pp+41, pp+42, pp+43, pp+44, pp+45, pp+46, pp+47, pp+48, pp+49, pp+50, pp+51, pp+52, pp+53, pp+54), i >= 9) {
+            int poly = i/3;
+            //vc_assert(i < countof(pp); // may need to increment poly count and pp array
+            for (i=1; i<poly-1; i++) {
+               *pf++ = pp[0]; *pf++ = pp[1]; *pf++ = pp[2];
+               *pf++ = pp[3*i+0]; *pf++ = pp[3*i+1]; *pf++ = pp[3*i+2];
+               *pf++ = pp[3*(i+1)+0]; *pf++ = pp[3*(i+1)+1]; *pf++ = pp[3*(i+1)+2];
+            }
+         } else { printf("%s", s); vc_assert(0); }
+         break;
+      default: 
+         printf("%02x %02x %s", s[0], s[1], s); vc_assert(0); break;
+      }
+
+      // shift down read characters and read some more into the end
+      // if we didn't find a newline, then end is one off the end of our
+      // line, so end-line will be valid+1
+      i = end-line > valid ? valid : end-line;
+      memmove(line, end, valid - i);
+      valid -= i;
+      valid += fread(line+valid, 1, sizeof(line)-1-valid, fp);
+   }
+   fclose(fp);
+
+   if (m->num_materials==0) m->material_index[m->num_materials++] = 0;
+
+   centre_and_rescale(qv, (pv-qv)/3);
+   renormalise(qn, (pn-qn)/3);
+   //centre_and_rescale2(qt, (pt-qt)/2);
+
+   m->numv = pv-qv;
+   m->numt = pt-qt;
+   m->numn = pn-qn;
+   m->numf = pf-qf;
+
+   // compress array
+   //memcpy((float *)m->data, (float *)m->data, m->numv * sizeof *qv); - nop
+   memcpy((float *)m->data + m->numv, (float *)m->data + 3 * MAX_VERTICES, m->numt * sizeof *qt);
+   memcpy((float *)m->data + m->numv + m->numt,(float *) m->data + (3 + 2) * MAX_VERTICES, m->numn * sizeof *qn);
+   memcpy((float *)m->data + m->numv + m->numt + m->numn, (float *)m->data + (3 + 2 + 3) * MAX_VERTICES, m->numf * sizeof *qf);
+
+   return 0;
+}
+
+static int load_wavefront_dat(const char *modelname, WAVEFRONT_MODEL_T *model, struct wavefront_model_loading_s *m)
+{
+   FILE *fp;
+   int s;
+   const int size = sizeof *m + 
+      sizeof(float)*(3+2+3)*MAX_VERTICES +   // 3 vertices + 2 textures + 3 normals
+      sizeof(unsigned short)*3*MAX_VERTICES; //each face has 9 vertices
+
+   fp = fopen(modelname, "r");
+   if (!fp) return -1;
+   s = fread(m, 1, size, fp);
+   if (s < 0) return -1;
+   fclose(fp);
+   return 0;
+}
+
+MODEL_T load_wavefront(const char *modelname, const char *texturename)
+{
+   WAVEFRONT_MODEL_T *model;
+   float *temp, *qv, *qt, *qn;
+   unsigned short *qf;
+   int i;
+   int numverts = 0, offset = 0;
+   struct wavefront_model_loading_s *m;
+   int s=-1;
+   char modelname_obj[128];
+   model = malloc(sizeof *model);
+   if (!model || !modelname) return NULL;
+   memset (model, 0, sizeof *model);
+   model->texture = 0; //load_texture(texturename);
+   m = allocbuffer(sizeof *m + 
+      sizeof(float)*(3+2+3)*MAX_VERTICES +    // 3 vertices + 2 textures + 3 normals
+      sizeof(unsigned short)*3*MAX_VERTICES); //each face has 9 vertices
+   if (!m) return 0;
+
+   if (strlen(modelname) + 5 <= sizeof modelname_obj) {
+      strcpy(modelname_obj, modelname);
+      strcat(modelname_obj, ".dat");
+      s = load_wavefront_dat(modelname_obj, model, m);
+   }
+   if (s==0) {}
+   else if (strncmp(modelname + strlen(modelname) - 4, ".obj", 4) == 0) {
+      #ifdef DUMP_OBJ_DAT
+      int size;
+      FILE *fp;
+      #endif
+      s = load_wavefront_obj(modelname, model, m);
+      #ifdef DUMP_OBJ_DAT
+      strcpy(modelname_obj, modelname);
+      strcat(modelname_obj, ".dat");
+      size = sizeof *m + 
+         sizeof(float)*(3*m->numv+2*m->numt+3*m->numn) +  // 3 vertices + 2 textures + 3 normals
+         sizeof(unsigned short)*3*m->numf;                //each face has 9 vertices
+      fp = host_file_open(modelname_obj, "w");
+      fwrite(m, 1, size, fp);
+      fclose(fp);
+      #endif
+   } else if (strncmp(modelname + strlen(modelname) - 4, ".dat", 4) == 0) {
+      s = load_wavefront_dat(modelname, model, m);
+   }
+   if (s != 0) return 0;
+
+   qv = (float *)(m->data);
+   qt = (float *)(m->data + m->numv);
+   qn = (float *)(m->data + m->numv + m->numt);
+   qf = (unsigned short *)(m->data + m->numv + m->numt + m->numn);
+
+   numverts = m->numf/3;
+   vc_assert(numverts <= MAX_VERTICES);
+
+   temp = allocbuffer(3*numverts*sizeof *temp);
+   for (i=0; i<m->num_materials; i++) {
+      WAVEFRONT_MATERIAL_T *mat = model->material + i;
+      mat->numverts = i < m->num_materials-1 ? m->material_index[i+1]-m->material_index[i] : numverts - m->material_index[i];
+      // vertex, texture, normal
+      deindex(temp, qv, qf+3*offset+0, 3, mat->numverts);
+      create_vbo(GL_ARRAY_BUFFER, mat->vbo+VBO_VERTEX, 3 * mat->numverts * sizeof *qv, temp); // 3
+   
+      deindex(temp, qt, qf+3*offset+1, 2, mat->numverts);
+      create_vbo(GL_ARRAY_BUFFER, mat->vbo+VBO_TEXTURE, 2 * mat->numverts * sizeof *qt, temp); // 2
+   
+      deindex(temp, qn, qf+3*offset+2, 3, mat->numverts);
+      create_vbo(GL_ARRAY_BUFFER, mat->vbo+VBO_NORMAL, 3 * mat->numverts * sizeof *qn, temp); // 3
+      offset += mat->numverts;
+      mat->texture = model->texture;
+   }
+   model->num_materials = m->num_materials;
+   vc_assert(offset == numverts);
+   freebuffer(temp);
+   freebuffer(m);
+   return (MODEL_T)model;
+}
+
+void unload_wavefront(MODEL_T m)
+{
+   WAVEFRONT_MODEL_T *model = (WAVEFRONT_MODEL_T *)m;
+   int i;
+   for (i=0; i<model->num_materials; i++) {
+      WAVEFRONT_MATERIAL_T *mat = model->material + i;
+      if (mat->vbo[VBO_VERTEX])
+         destroy_vbo(mat->vbo+VBO_VERTEX);
+      if (mat->vbo[VBO_TEXTURE])
+         destroy_vbo(mat->vbo+VBO_TEXTURE);
+      if (mat->vbo[VBO_NORMAL])
+         destroy_vbo(mat->vbo+VBO_NORMAL);
+   }
+}
+
+// create a cube model that looks like a wavefront model, 
+MODEL_T cube_wavefront(void)
+{
+   static const float qv[] = {
+    -0.5f, -0.5f,  0.5f,
+    -0.5f, -0.5f, -0.5f,
+     0.5f, -0.5f, -0.5f,
+     0.5f, -0.5f,  0.5f,
+    -0.5f,  0.5f,  0.5f,
+     0.5f,  0.5f,  0.5f,
+     0.5f,  0.5f, -0.5f,
+    -0.5f,  0.5f, -0.5f,
+   };
+   
+   static const float qn[] = {
+     0.0f, -1.0f, -0.0f,
+     0.0f,  1.0f, -0.0f,
+     0.0f,  0.0f,  1.0f,
+     1.0f,  0.0f, -0.0f,
+     0.0f,  0.0f, -1.0f,
+    -1.0f,  0.0f, -0.0f,
+   };
+   
+   static const float qt[] = {
+    1.0f, 0.0f,
+    1.0f, 1.0f,
+    0.0f, 1.0f,
+    0.0f, 0.0f,
+   };
+   
+   static const unsigned short qf[] = {
+    1,1,1, 2,2,1, 3,3,1,
+    3,3,1, 4,4,1, 1,1,1,
+    5,4,2, 6,1,2, 7,2,2,
+    7,2,2, 8,3,2, 5,4,2,
+    1,4,3, 4,1,3, 6,2,3,
+    6,2,3, 5,3,3, 1,4,3,
+    4,4,4, 3,1,4, 7,2,4,
+    7,2,4, 6,3,4, 4,4,4,
+    3,4,5, 2,1,5, 8,2,5,
+    8,2,5, 7,3,5, 3,4,5,
+    2,4,6, 1,1,6, 5,2,6,
+    5,2,6, 8,3,6, 2,4,6,
+   };
+   WAVEFRONT_MODEL_T *model = malloc(sizeof *model);
+   if (model) {
+      WAVEFRONT_MATERIAL_T *mat = model->material;
+      float *temp;
+      const int offset = 0;
+      memset(model, 0, sizeof *model);
+
+      temp = allocbuffer(3*MAX_VERTICES*sizeof *temp);
+      mat->numverts = countof(qf)/3;
+      // vertex, texture, normal
+      deindex(temp, qv, qf+3*offset+0, 3, mat->numverts);
+      create_vbo(GL_ARRAY_BUFFER, mat->vbo+VBO_VERTEX, 3 * mat->numverts * sizeof *qv, temp); // 3
+
+      deindex(temp, qt, qf+3*offset+1, 2, mat->numverts);
+      create_vbo(GL_ARRAY_BUFFER, mat->vbo+VBO_TEXTURE, 2 * mat->numverts * sizeof *qt, temp); // 2
+
+      deindex(temp, qn, qf+3*offset+2, 3, mat->numverts);
+      create_vbo(GL_ARRAY_BUFFER, mat->vbo+VBO_NORMAL, 3 * mat->numverts * sizeof *qn, temp); // 3
+
+      freebuffer(temp);
+      model->num_materials = 1;
+   }
+   return (MODEL_T)model;
+}
+
+
diff --git a/host_applications/linux/apps/raspicam/gl_scenes/models.h b/host_applications/linux/apps/raspicam/gl_scenes/models.h
new file mode 100755 (executable)
index 0000000..4a6cbd0
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MODELS_T
+#define MODELS_T
+typedef struct opqaue_model_s * MODEL_T;
+
+MODEL_T load_wavefront(const char *modelname, const char *texturename);
+MODEL_T cube_wavefront(void);
+void unload_wavefront(MODEL_T m);
+int draw_wavefront(MODEL_T m, GLuint texture);
+#endif
diff --git a/host_applications/linux/apps/raspicam/gl_scenes/sobel.c b/host_applications/linux/apps/raspicam/gl_scenes/sobel.c
new file mode 100755 (executable)
index 0000000..ad2c8d9
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, Tim Gover
+All rights reserved.
+
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "sobel.h"
+#include "RaspiTex.h"
+#include "RaspiTexUtil.h"
+#include <GLES2/gl2.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+/* \file sobel.c
+ * Example code for implementing Sobel filter as GLSL shaders.
+ * The input image is a greyscale texture from the MMAL buffer Y plane.
+ */
+
+#define SOBEL_VSHADER_SOURCE \
+    "attribute vec2 vertex;\n" \
+    "varying vec2 texcoord;\n" \
+    "void main(void) {\n" \
+    "   texcoord = 0.5 * (vertex + 1.0);\n" \
+    "   gl_Position = vec4(vertex, 0.0, 1.0);\n" \
+    "}\n"
+
+/* Example Sobel edge detct shader. The texture format for
+ * EGL_IMAGE_BRCM_MULTIMEDIA_Y is a one byte per pixel greyscale GL_LUMINANCE.
+ * If the output is to be fed into another image processing shader then it may
+ * be worth changing this code to take 4 input Y pixels and pack the result
+ * into a 32bpp RGBA pixel.
+ */
+#define SOBEL_FSHADER_SOURCE \
+    "#extension GL_OES_EGL_image_external : require\n" \
+    "uniform samplerExternalOES tex;\n" \
+    "varying vec2 texcoord;\n" \
+    "uniform vec2 tex_unit;\n" \
+    "void main(void) {\n" \
+    "    float x = texcoord.x;\n" \
+    "    float y = texcoord.y;\n" \
+    "    float x1 = x - tex_unit.x;\n" \
+    "    float y1 = y - tex_unit.y;\n" \
+    "    float x2 = x + tex_unit.x;\n" \
+    "    float y2 = y + tex_unit.y;\n" \
+    "    vec4 p0 = texture2D(tex, vec2(x1, y1));\n" \
+    "    vec4 p1 = texture2D(tex, vec2(x, y1));\n" \
+    "    vec4 p2 = texture2D(tex, vec2(x2, y1));\n" \
+    "    vec4 p3 = texture2D(tex, vec2(x1, y));\n" \
+    "    /* vec4 p4 = texture2D(tex, vec2(x, y)); */\n" \
+    "    vec4 p5 = texture2D(tex, vec2(x2, y));\n" \
+    "    vec4 p6 = texture2D(tex, vec2(x1, y2));\n" \
+    "    vec4 p7 = texture2D(tex, vec2(x, y2));\n" \
+    "    vec4 p8 = texture2D(tex, vec2(x2, y2));\n" \
+    "\n" \
+    "    vec4 v =  p0 + (2.0 * p1) + p3 -p6 + (-2.0 * p7) + -p8;\n" \
+    "    vec4 h =  p0 + (2.0 * p3) + p7 -p2 + (-2.0 * p5) + -p8;\n" \
+    "    gl_FragColor = sqrt(h*h + v*v);\n" \
+    "    gl_FragColor.a = 1.0;\n" \
+    "}\n"
+
+static GLfloat quad_varray[] = {
+   -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f,
+   -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f,
+};
+
+static GLuint quad_vbo;
+
+static RASPITEXUTIL_SHADER_PROGRAM_T sobel_shader =
+{
+    .vertex_source = SOBEL_VSHADER_SOURCE,
+    .fragment_source = SOBEL_FSHADER_SOURCE,
+    .uniform_names = {"tex", "tex_unit"},
+    .attribute_names = {"vertex"},
+};
+
+static const EGLint sobel_egl_config_attribs[] =
+{
+   EGL_RED_SIZE,   8,
+   EGL_GREEN_SIZE, 8,
+   EGL_BLUE_SIZE,  8,
+   EGL_ALPHA_SIZE, 8,
+   EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+   EGL_NONE
+};
+
+
+/**
+ * Initialisation of shader uniforms.
+ *
+ * @param width Width of the EGL image.
+ * @param width Height of the EGL image.
+ */
+static int shader_set_uniforms(RASPITEXUTIL_SHADER_PROGRAM_T *shader,
+      int width, int height)
+{
+   GLCHK(glUseProgram(shader->program));
+   GLCHK(glUniform1i(shader->uniform_locations[0], 0)); // Texture unit
+
+   /* Dimensions of a single pixel in texture co-ordinates */
+   GLCHK(glUniform2f(shader->uniform_locations[1],
+            1.0 / (float) width, 1.0 / (float) height));
+
+   /* Enable attrib 0 as vertex array */
+   GLCHK(glEnableVertexAttribArray(shader->attribute_locations[0]));
+   return 0;
+}
+
+/**
+ * Creates the OpenGL ES 2.X context and builds the shaders.
+ * @param raspitex_state A pointer to the GL preview state.
+ * @return Zero if successful.
+ */
+static int sobel_init(RASPITEX_STATE *raspitex_state)
+{
+    int rc = 0;
+    int width = raspitex_state->width;
+    int height = raspitex_state->height;
+
+    vcos_log_trace("%s", VCOS_FUNCTION);
+    raspitex_state->egl_config_attribs = sobel_egl_config_attribs;
+    rc = raspitexutil_gl_init_2_0(raspitex_state);
+    if (rc != 0)
+       goto end;
+
+    rc = raspitexutil_build_shader_program(&sobel_shader);
+    if (rc != 0)
+       goto end;
+
+    rc = shader_set_uniforms(&sobel_shader, width, height);
+    if (rc != 0)
+       goto end;
+
+   GLCHK(glGenBuffers(1, &quad_vbo));
+   GLCHK(glBindBuffer(GL_ARRAY_BUFFER, quad_vbo));
+   GLCHK(glBufferData(GL_ARRAY_BUFFER, sizeof(quad_varray), quad_varray, GL_STATIC_DRAW));
+   GLCHK(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
+
+end:
+    return rc;
+}
+
+/* Redraws the scene with the latest luma buffer.
+ *
+ * @param raspitex_state A pointer to the GL preview state.
+ * @return Zero if successful.
+ */
+static int sobel_redraw(RASPITEX_STATE* state)
+{
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+   GLCHK(glUseProgram(sobel_shader.program));
+
+   /* Bind the Y plane texture */
+   GLCHK(glActiveTexture(GL_TEXTURE0));
+   GLCHK(glBindTexture(GL_TEXTURE_EXTERNAL_OES, state->y_texture));
+   GLCHK(glBindBuffer(GL_ARRAY_BUFFER, quad_vbo));
+   GLCHK(glEnableVertexAttribArray(sobel_shader.attribute_locations[0]));
+   GLCHK(glVertexAttribPointer(sobel_shader.attribute_locations[0], 2, GL_FLOAT, GL_FALSE, 0, 0));
+   GLCHK(glDrawArrays(GL_TRIANGLES, 0, 6));
+
+   return 0;
+}
+
+int sobel_open(RASPITEX_STATE *state)
+{
+   state->ops.gl_init = sobel_init;
+   state->ops.redraw = sobel_redraw;
+   state->ops.update_y_texture = raspitexutil_update_y_texture;
+   return 0;
+}
diff --git a/host_applications/linux/apps/raspicam/gl_scenes/sobel.h b/host_applications/linux/apps/raspicam/gl_scenes/sobel.h
new file mode 100755 (executable)
index 0000000..14ab13a
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, Tim Gover
+All rights reserved.
+
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef SOBEL_H
+#define SOBEL_H
+
+#include "RaspiTex.h"
+
+int sobel_open(RASPITEX_STATE *state);
+
+#endif /* SOBEL_H */
diff --git a/host_applications/linux/apps/raspicam/gl_scenes/square.c b/host_applications/linux/apps/raspicam/gl_scenes/square.c
new file mode 100755 (executable)
index 0000000..a1028a1
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, Tim Gover
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <GLES/gl.h>
+#include <GLES/glext.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include "RaspiTexUtil.h"
+
+/* Vertex co-ordinates:
+ *
+ * v0----v1
+ * |     |
+ * |     |
+ * |     |
+ * v3----v2
+ */
+
+static const GLfloat vertices[] =
+{
+#define V0  -0.8,  0.8,  0.8,
+#define V1   0.8,  0.8,  0.8,
+#define V2   0.8, -0.8,  0.8,
+#define V3  -0.8, -0.8,  0.8,
+   V0 V3 V2 V2 V1 V0
+};
+
+/* Texture co-ordinates:
+ *
+ * (0,0) b--c
+ *       |  |
+ *       a--d
+ *
+ * b,a,d d,c,b
+ */
+static const GLfloat tex_coords[] =
+{
+   0, 0, 0, 1, 1, 1,
+   1, 1, 1, 0, 0, 0
+};
+
+static GLfloat angle;
+static uint32_t anim_step;
+
+static int square_init(RASPITEX_STATE *state)
+{
+   int rc = raspitexutil_gl_init_1_0(state);
+
+   if (rc != 0)
+      goto end;
+
+   angle = 0.0f;
+   anim_step = 0;
+
+   glClearColor(0, 0, 0, 0);
+   glClearDepthf(1);
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+   glLoadIdentity();
+
+end:
+   return rc;
+}
+
+static int square_update_model(RASPITEX_STATE *state)
+{
+   int frames_per_rev = 30 * 15;
+   (void) state;
+   angle = (anim_step * 360) / (GLfloat) frames_per_rev;
+   anim_step = (anim_step + 1) % frames_per_rev;
+
+   return 0;
+}
+
+static int square_redraw(RASPITEX_STATE *state)
+{
+   /* Bind the OES texture which is used to render the camera preview */
+   GLCHK(glBindTexture(GL_TEXTURE_EXTERNAL_OES, state->texture));
+   glLoadIdentity();
+   glRotatef(angle, 0.0, 0.0, 1.0);
+   glEnableClientState(GL_VERTEX_ARRAY);
+   glVertexPointer(3, GL_FLOAT, 0, vertices);
+   glDisableClientState(GL_COLOR_ARRAY);
+   glEnableClientState(GL_TEXTURE_COORD_ARRAY);
+   glTexCoordPointer(2, GL_FLOAT, 0, tex_coords);
+   GLCHK(glDrawArrays(GL_TRIANGLES, 0, vcos_countof(tex_coords) / 2));
+   return 0;
+}
+
+int square_open(RASPITEX_STATE *state)
+{
+   state->ops.gl_init = square_init;
+   state->ops.update_model = square_update_model;
+   state->ops.redraw = square_redraw;
+   state->ops.update_texture = raspitexutil_update_texture;
+   return 0;
+}
diff --git a/host_applications/linux/apps/raspicam/gl_scenes/square.h b/host_applications/linux/apps/raspicam/gl_scenes/square.h
new file mode 100755 (executable)
index 0000000..ef4741a
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, Tim Gover
+All rights reserved.
+
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef SQUARE_H
+#define SQUARE_H
+
+#include "RaspiTex.h"
+
+int square_open(RASPITEX_STATE *state);
+
+#endif /* SQUARE_H */
diff --git a/host_applications/linux/apps/raspicam/gl_scenes/teapot.c b/host_applications/linux/apps/raspicam/gl_scenes/teapot.c
new file mode 100755 (executable)
index 0000000..eac4bcb
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+Copyright (c) 2012, OtherCrashOverride
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// A rotating cube rendered with OpenGL|ES. Three images used as textures on the cube faces.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <unistd.h>
+
+#include <GLES/gl.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#include "cube_texture_and_coords.h"
+#include "models.h"
+#include "teapot.h"
+
+#include "RaspiTex.h"
+#include "RaspiTexUtil.h"
+
+#define PATH "./"
+
+#ifndef M_PI
+   #define M_PI 3.141592654
+#endif
+
+typedef struct
+{
+   uint32_t screen_width;
+   uint32_t screen_height;
+   GLuint tex;
+// model rotation vector and direction
+   GLfloat rot_angle_x_inc;
+   GLfloat rot_angle_y_inc;
+   GLfloat rot_angle_z_inc;
+// current model rotation angles
+   GLfloat rot_angle_x;
+   GLfloat rot_angle_y;
+   GLfloat rot_angle_z;
+// current distance from camera
+   GLfloat distance;
+   GLfloat distance_inc;
+   MODEL_T model;
+} TEAPOT_STATE_T;
+
+static void init_ogl(TEAPOT_STATE_T *state);
+static void init_model_proj(TEAPOT_STATE_T *state);
+static void reset_model(TEAPOT_STATE_T *state);
+static GLfloat inc_and_wrap_angle(GLfloat angle, GLfloat angle_inc);
+static GLfloat inc_and_clip_distance(GLfloat distance, GLfloat distance_inc);
+
+/***********************************************************
+ * Name: init_ogl
+ *
+ * Arguments:
+ *       TEAPOT_STATE_T *state - holds OGLES model info
+ *
+ * Description: Sets the display, OpenGL|ES context and screen stuff
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void init_ogl(TEAPOT_STATE_T *state)
+{
+   // Set background color and clear buffers
+   glClearColor((0.3922f+7*0.5f)/8, (0.1176f+7*0.5f)/8, (0.5882f+7*0.5f)/8, 1.0f);
+
+   // Enable back face culling.
+   glEnable(GL_CULL_FACE);
+
+   glEnable(GL_DEPTH_TEST);
+   glClearDepthf(1.0);
+   glDepthFunc(GL_LEQUAL);
+
+   float noAmbient[] = {1.0f, 1.0f, 1.0f, 1.0f};
+   glLightfv(GL_LIGHT0, GL_AMBIENT, noAmbient);
+   glEnable(GL_LIGHT0);
+   glEnable(GL_LIGHTING);
+}
+
+/***********************************************************
+ * Name: init_model_proj
+ *
+ * Arguments:
+ *       TEAPOT_STATE_T *state - holds OGLES model info
+ *
+ * Description: Sets the OpenGL|ES model to default values
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void init_model_proj(TEAPOT_STATE_T *state)
+{
+   float nearp = 0.1f;
+   float farp = 500.0f;
+   float hht;
+   float hwd;
+
+   glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
+
+   glViewport(0, 0, (GLsizei)state->screen_width, (GLsizei)state->screen_height);
+
+   glMatrixMode(GL_PROJECTION);
+   glLoadIdentity();
+
+   hht = nearp * (float)tan(45.0 / 2.0 / 180.0 * M_PI);
+   hwd = hht * (float)state->screen_width / (float)state->screen_height;
+
+   glFrustumf(-hwd, hwd, -hht, hht, nearp, farp);
+
+   glEnableClientState( GL_VERTEX_ARRAY );
+
+   reset_model(state);
+}
+
+/***********************************************************
+ * Name: reset_model
+ *
+ * Arguments:
+ *       TEAPOT_STATE_T *state - holds OGLES model info
+ *
+ * Description: Resets the Model projection and rotation direction
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static void reset_model(TEAPOT_STATE_T *state)
+{
+   // reset model position
+   glMatrixMode(GL_MODELVIEW);
+
+   // reset model rotation
+   state->rot_angle_x = 45.f; state->rot_angle_y = 30.f; state->rot_angle_z = 0.f;
+   state->rot_angle_x_inc = 0.5f; state->rot_angle_y_inc = 0.5f; state->rot_angle_z_inc = 0.f;
+   state->distance = 0.8f*1.5f;
+}
+
+/***********************************************************
+ * Name: teapot_update_model
+ *
+ * Arguments:
+ *       TEAPOT_STATE_T *state - holds OGLES model info
+ *
+ * Description: Updates model projection to current position/rotation
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static int teapot_update_model(RASPITEX_STATE *raspitex_state)
+{
+   TEAPOT_STATE_T *state = (TEAPOT_STATE_T *) raspitex_state->scene_state;
+
+   // update position
+   state->rot_angle_x = inc_and_wrap_angle(state->rot_angle_x, state->rot_angle_x_inc);
+   state->rot_angle_y = inc_and_wrap_angle(state->rot_angle_y, state->rot_angle_y_inc);
+   state->rot_angle_z = inc_and_wrap_angle(state->rot_angle_z, state->rot_angle_z_inc);
+   state->distance    = inc_and_clip_distance(state->distance, state->distance_inc);
+
+   glLoadIdentity();
+   // move camera back to see the cube
+   glTranslatef(0.f, 0.f, -state->distance);
+
+   // Rotate model to new position
+   glRotatef(state->rot_angle_x, 1.f, 0.f, 0.f);
+   glRotatef(state->rot_angle_y, 0.f, 1.f, 0.f);
+   glRotatef(state->rot_angle_z, 0.f, 0.f, 1.f);
+
+   return 0;
+}
+
+/***********************************************************
+ * Name: inc_and_wrap_angle
+ *
+ * Arguments:
+ *       GLfloat angle     current angle
+ *       GLfloat angle_inc angle increment
+ *
+ * Description:   Increments or decrements angle by angle_inc degrees
+ *                Wraps to 0 at 360 deg.
+ *
+ * Returns: new value of angle
+ *
+ ***********************************************************/
+static GLfloat inc_and_wrap_angle(GLfloat angle, GLfloat angle_inc)
+{
+   angle += angle_inc;
+
+   if (angle >= 360.0)
+      angle -= 360.f;
+   else if (angle <=0)
+      angle += 360.f;
+
+   return angle;
+}
+
+/***********************************************************
+ * Name: inc_and_clip_distance
+ *
+ * Arguments:
+ *       GLfloat distance     current distance
+ *       GLfloat distance_inc distance increment
+ *
+ * Description:   Increments or decrements distance by distance_inc units
+ *                Clips to range
+ *
+ * Returns: new value of angle
+ *
+ ***********************************************************/
+static GLfloat inc_and_clip_distance(GLfloat distance, GLfloat distance_inc)
+{
+   distance += distance_inc;
+
+   if (distance >= 10.0f)
+      distance = 10.f;
+   else if (distance <= 1.0f)
+      distance = 1.0f;
+
+   return distance;
+}
+
+/***********************************************************
+ * Name: teapot_redraw
+ *
+ * Arguments:
+ *       RASPITEX_STATE_T *state - holds OGLES model info
+ *
+ * Description:   Draws the model
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+static int teapot_redraw(RASPITEX_STATE *raspitex_state)
+{
+   TEAPOT_STATE_T *state = (TEAPOT_STATE_T *) raspitex_state->scene_state;
+
+   // Start with a clear screen
+   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+   /* Bind the OES texture which is used to render the camera preview */
+   glBindTexture(GL_TEXTURE_EXTERNAL_OES, raspitex_state->texture);
+   draw_wavefront(state->model, raspitex_state->texture);
+   return 0;
+}
+
+//==============================================================================
+
+static int teapot_gl_init(RASPITEX_STATE *raspitex_state)
+{
+   const char *model_path = "/opt/vc/src/hello_pi/hello_teapot/teapot.obj.dat";
+   TEAPOT_STATE_T *state = NULL;
+   int rc = 0;
+
+   // Clear scene state
+   state = calloc(1, sizeof(TEAPOT_STATE_T));
+   raspitex_state->scene_state = state;
+   state->screen_width = raspitex_state->width;
+   state->screen_height = raspitex_state->height;
+
+   rc = raspitexutil_gl_init_1_0(raspitex_state);
+   if (rc != 0)
+      goto end;
+
+   // Start OGLES
+   init_ogl(state);
+
+   // Setup the model world
+   init_model_proj(state);
+   state->model = load_wavefront(model_path, NULL);
+
+   if (! state->model)
+   {
+      vcos_log_error("Failed to load model from %s\n", model_path);
+      rc = -1;
+   }
+
+end:
+   return rc;
+}
+
+static void teapot_gl_term(RASPITEX_STATE *raspitex_state)
+{
+   vcos_log_trace("%s:", VCOS_FUNCTION);
+
+   TEAPOT_STATE_T *state = raspitex_state->scene_state;
+   if (state)
+   {
+      if (state->model)
+         unload_wavefront(state->model);
+      raspitexutil_gl_term(raspitex_state);
+      free(raspitex_state->scene_state);
+      raspitex_state->scene_state = NULL;
+   }
+}
+
+int teapot_open(RASPITEX_STATE *raspitex_state)
+{
+   raspitex_state->ops.gl_init = teapot_gl_init;
+   raspitex_state->ops.update_model = teapot_update_model;
+   raspitex_state->ops.redraw = teapot_redraw;
+   raspitex_state->ops.gl_term = teapot_gl_term;
+   raspitex_state->ops.update_texture = raspitexutil_update_texture;
+   return 0;
+}
+
diff --git a/host_applications/linux/apps/raspicam/gl_scenes/teapot.h b/host_applications/linux/apps/raspicam/gl_scenes/teapot.h
new file mode 100755 (executable)
index 0000000..c8d5162
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+Copyright (c) 2012-2013, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef TEAPOT_H
+#define TEAPOT_H
+
+#include "RaspiTex.h"
+
+int teapot_open(RASPITEX_STATE *raspitex_state);
+
+#endif /* TEAPOT_H */
diff --git a/host_applications/linux/apps/raspicam/gl_scenes/vcsm_square.c b/host_applications/linux/apps/raspicam/gl_scenes/vcsm_square.c
new file mode 100755 (executable)
index 0000000..f47b83e
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2016, Tim Gover
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/* Make the render output CPU accessible by defining a framebuffer texture
+ * stored in a VCSM (VideoCore shared memory) EGL image.
+ *
+ * This example just demonstrates how to use use the APIs by using the CPU.
+ * to blit an animated rectangle into frame-buffer texture in shared memory.
+ *
+ * A more realistic example would be to do a blur, edge-detect in GLSL then pass
+ * the buffer to OpenCV. There may be some benefit in using multiple GL contexts
+ * to reduce the impact of serializing operations with a glFlush.
+ *
+ * N.B VCSM textures are raster scan order textures. This makes it very
+ * convenient to read and modify VCSM frame-buffer textures from the CPU.
+ * However, if the output of the CPU stage is drawn again as a texture that
+ * is rotated or scaled then it can sometimes be better to use glTexImage2D
+ * to allow the driver to convert this back into the native texture format.
+ *
+ * Example usage
+ * raspistill -p 0,0,1024,1024 -gw 0,0,1024,1024 -t 10000 --gl -gs vcsm_square
+ */
+/* Uncomment the next line to compare with the glReadPixels implementation. VCSM
+ * should run at about 40fps with a 1024x1024 texture compared to about 20fps
+ * using glReadPixels.
+ */
+//#define USE_READPIXELS
+
+#include "vcsm_square.h"
+#include <GLES2/gl2.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include "RaspiTex.h"
+#include "RaspiTexUtil.h"
+#include "user-vcsm.h"
+
+/* Draw a scaled quad showing the entire texture with the
+ * origin defined as an attribute */
+static RASPITEXUTIL_SHADER_PROGRAM_T vcsm_square_oes_shader =
+{
+    .vertex_source =
+    "attribute vec2 vertex;\n"
+    "varying vec2 texcoord;\n"
+    "void main(void) {\n"
+    "   texcoord = 0.5 * (vertex + 1.0);\n" \
+    "   gl_Position = vec4(vertex, 0.0, 1.0);\n"
+    "}\n",
+
+    .fragment_source =
+    "#extension GL_OES_EGL_image_external : require\n"
+    "uniform samplerExternalOES tex;\n"
+    "varying vec2 texcoord;\n"
+    "void main(void) {\n"
+    "    gl_FragColor = texture2D(tex, texcoord);\n"
+    "}\n",
+    .uniform_names = {"tex"},
+    .attribute_names = {"vertex"},
+};
+static RASPITEXUTIL_SHADER_PROGRAM_T vcsm_square_shader =
+{
+    .vertex_source =
+    "attribute vec2 vertex;\n"
+    "varying vec2 texcoord;\n"
+    "void main(void) {\n"
+    "   texcoord = 0.5 * (vertex + 1.0);\n" \
+    "   gl_Position = vec4(vertex, 0.0, 1.0);\n"
+    "}\n",
+
+    .fragment_source =
+    "uniform sampler2D tex;\n"
+    "varying vec2 texcoord;\n"
+    "void main(void) {\n"
+    "    gl_FragColor = texture2D(tex, texcoord);\n"
+    "}\n",
+    .uniform_names = {"tex"},
+    .attribute_names = {"vertex"},
+};
+
+static GLfloat quad_varray[] = {
+   -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, -1.0f,
+   -1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f,
+};
+
+static GLuint quad_vbo;
+
+#ifdef USE_READPIXELS
+unsigned char *pixel_buffer;
+#else
+static struct egl_image_brcm_vcsm_info vcsm_info;
+static EGLImageKHR eglFbImage;
+#endif
+static GLuint fb_tex_name;
+static GLuint fb_name;
+
+
+// VCSM buffer dimensions must be a power of two. Use glViewPort to draw NPOT
+// rectangles within the VCSM buffer.
+static int fb_width = 1024;
+static int fb_height = 1024;
+
+static const EGLint vcsm_square_egl_config_attribs[] =
+{
+    EGL_RED_SIZE,   8,
+    EGL_GREEN_SIZE, 8,
+    EGL_BLUE_SIZE,  8,
+    EGL_ALPHA_SIZE, 8,
+    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+    EGL_NONE
+};
+
+static int vcsm_square_init(RASPITEX_STATE *raspitex_state)
+{
+    int rc = vcsm_init();
+    vcos_log_trace("%s: vcsm_init %d", VCOS_FUNCTION, rc);
+
+    raspitex_state->egl_config_attribs = vcsm_square_egl_config_attribs;
+    rc = raspitexutil_gl_init_2_0(raspitex_state);
+
+    if (rc != 0)
+        goto end;
+
+    // Shader for drawing the YUV OES texture
+    rc = raspitexutil_build_shader_program(&vcsm_square_oes_shader);
+    GLCHK(glUseProgram(vcsm_square_oes_shader.program));
+    GLCHK(glUniform1i(vcsm_square_oes_shader.uniform_locations[0], 0)); // tex unit
+
+    // Shader for drawing VCSM sampler2D texture
+    rc = raspitexutil_build_shader_program(&vcsm_square_shader);
+    GLCHK(glUseProgram(vcsm_square_shader.program));
+    GLCHK(glUniform1i(vcsm_square_shader.uniform_locations[0], 0)); // tex unit
+
+    GLCHK(glGenFramebuffers(1, &fb_name));
+    GLCHK(glBindFramebuffer(GL_FRAMEBUFFER, fb_name));
+
+    GLCHK(glGenTextures(1, &fb_tex_name));
+    GLCHK(glBindTexture(GL_TEXTURE_2D, fb_tex_name));
+    GLCHK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
+    GLCHK(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
+
+#ifdef USE_READPIXELS
+    printf("Using glReadPixels\n");
+    GLCHK(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fb_width, fb_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL));
+    pixel_buffer = malloc(fb_width * fb_height * 4);
+    if (! pixel_buffer) {
+        rc = -1;
+        goto end;
+    }
+#else /* USE_READPIXELS */
+    printf("Using VCSM\n");
+    vcsm_info.width = fb_width;
+    vcsm_info.height = fb_height;
+    eglFbImage = eglCreateImageKHR(raspitex_state->display, EGL_NO_CONTEXT,
+            EGL_IMAGE_BRCM_VCSM, &vcsm_info, NULL);
+    if (eglFbImage == EGL_NO_IMAGE_KHR || vcsm_info.vcsm_handle == 0) {
+        vcos_log_error("%s: Failed to create EGL VCSM image\n", VCOS_FUNCTION);
+        rc = -1;
+        goto end;
+    }
+
+    GLCHK(glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglFbImage));
+#endif /* USE_READPIXELS */
+
+    GLCHK(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb_tex_name, 0));
+    if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
+        vcos_log_error("GL_FRAMEBUFFER is not complete\n");
+        rc = -1;
+        goto end;
+    }
+    GLCHK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
+    GLCHK(glGenBuffers(1, &quad_vbo));
+    GLCHK(glBindBuffer(GL_ARRAY_BUFFER, quad_vbo));
+    GLCHK(glBufferData(GL_ARRAY_BUFFER, sizeof(quad_varray), quad_varray, GL_STATIC_DRAW));
+
+    GLCHK(glClearColor(0, 0, 0, 0));
+end:
+    return rc;
+}
+
+// Write the shared memory texture writing something to each line. This is
+// just to show that the buffer really is CPU modifiable.
+static void vcsm_square_draw_pattern(unsigned char *buffer)
+{
+    static unsigned x_offset;
+
+    unsigned char *line_start = (unsigned char *) buffer;
+    unsigned width = fb_width > 32 ? 32 : fb_width;
+    int i = 0;
+    size_t stride = fb_width  << 2;
+
+    x_offset = (x_offset + 1) % (fb_width - width);
+    for (i = 0; i < fb_height; i++) {
+        memset(line_start + (x_offset << 2), ~0, width << 2);
+        line_start += stride;
+    }
+}
+
+#ifdef USE_READPIXELS
+static int vcsm_square_redraw_readpixels(RASPITEX_STATE *raspitex_state)
+{
+    vcos_log_trace("%s", VCOS_FUNCTION);
+
+    GLCHK(glBindFramebuffer(GL_FRAMEBUFFER, fb_name));
+    GLCHK(glViewport(0,0,fb_width,fb_height));
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    // Fill the viewport with the camFill the viewport with the camera image
+    GLCHK(glUseProgram(vcsm_square_oes_shader.program));
+    GLCHK(glActiveTexture(GL_TEXTURE0));
+    GLCHK(glBindTexture(GL_TEXTURE_EXTERNAL_OES, raspitex_state->y_texture));
+    GLCHK(glBindBuffer(GL_ARRAY_BUFFER, quad_vbo));
+    GLCHK(glEnableVertexAttribArray(vcsm_square_oes_shader.attribute_locations[0]));
+    GLCHK(glVertexAttribPointer(vcsm_square_oes_shader.attribute_locations[0], 2, GL_FLOAT, GL_FALSE, 0, 0));
+    GLCHK(glDrawArrays(GL_TRIANGLES, 0, 6));
+
+    GLCHK(glReadPixels(0, 0, fb_width, fb_height, GL_RGBA, GL_UNSIGNED_BYTE, pixel_buffer));
+
+    vcsm_square_draw_pattern(pixel_buffer);
+
+    // Enable default window surface
+    GLCHK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
+
+    // Draw the modified texture buffer to the screen
+    GLCHK(glViewport(raspitex_state->x, raspitex_state->y, raspitex_state->width, raspitex_state->height));
+    GLCHK(glUseProgram(vcsm_square_shader.program));
+    GLCHK(glActiveTexture(GL_TEXTURE0));
+    GLCHK(glBindTexture(GL_TEXTURE_2D, fb_tex_name));
+    GLCHK(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fb_width, fb_height, GL_RGBA, GL_UNSIGNED_BYTE, pixel_buffer));
+    GLCHK(glEnableVertexAttribArray(vcsm_square_shader.attribute_locations[0]));
+    GLCHK(glVertexAttribPointer(vcsm_square_shader.attribute_locations[0], 2, GL_FLOAT, GL_FALSE, 0, 0));
+    GLCHK(glDrawArrays(GL_TRIANGLES, 0, 6));
+
+    GLCHK(glDisableVertexAttribArray(vcsm_square_shader.attribute_locations[0]));
+    GLCHK(glUseProgram(0));
+
+    return 0;
+}
+#else /* USE_READPIXELS */
+static int vcsm_square_redraw(RASPITEX_STATE *raspitex_state)
+{
+    unsigned char *vcsm_buffer = NULL;
+    VCSM_CACHE_TYPE_T cache_type;
+
+    vcos_log_trace("%s", VCOS_FUNCTION);
+
+    glClearColor(255, 0, 0, 255);
+
+    GLCHK(glBindFramebuffer(GL_FRAMEBUFFER, fb_name));
+    GLCHK(glViewport(0, 0, fb_width, fb_height));
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    // Fill the viewport with the camFill the viewport with the camera image
+    GLCHK(glUseProgram(vcsm_square_oes_shader.program));
+    GLCHK(glActiveTexture(GL_TEXTURE0));
+    GLCHK(glBindTexture(GL_TEXTURE_EXTERNAL_OES, raspitex_state->y_texture));
+    GLCHK(glBindBuffer(GL_ARRAY_BUFFER, quad_vbo));
+    GLCHK(glEnableVertexAttribArray(vcsm_square_oes_shader.attribute_locations[0]));
+    GLCHK(glVertexAttribPointer(vcsm_square_oes_shader.attribute_locations[0], 2, GL_FLOAT, GL_FALSE, 0, 0));
+    GLCHK(glDrawArrays(GL_TRIANGLES, 0, 6));
+
+    GLCHK(glFinish());
+
+    // Make the buffer CPU addressable with host cache enabled
+    vcsm_buffer = (unsigned char *) vcsm_lock_cache(vcsm_info.vcsm_handle, VCSM_CACHE_TYPE_HOST, &cache_type);
+    if (! vcsm_buffer) {
+        vcos_log_error("Failed to lock VCSM buffer for handle %d\n", vcsm_info.vcsm_handle);
+        return -1;
+    }
+    vcos_log_trace("Locked vcsm handle %d at %p\n", vcsm_info.vcsm_handle, vcsm_buffer);
+
+    vcsm_square_draw_pattern(vcsm_buffer);
+
+    // Release the locked texture memory to flush the CPU cache and allow GPU
+    // to read it
+    vcsm_unlock_ptr(vcsm_buffer);
+
+    // Enable default window surface
+    GLCHK(glBindFramebuffer(GL_FRAMEBUFFER, 0));
+
+    // Draw the modified texture buffer to the screen
+    GLCHK(glViewport(raspitex_state->x, raspitex_state->y, raspitex_state->width, raspitex_state->height));
+    GLCHK(glUseProgram(vcsm_square_shader.program));
+    GLCHK(glActiveTexture(GL_TEXTURE0));
+    GLCHK(glBindTexture(GL_TEXTURE_2D, fb_tex_name));
+    GLCHK(glEnableVertexAttribArray(vcsm_square_shader.attribute_locations[0]));
+    GLCHK(glVertexAttribPointer(vcsm_square_shader.attribute_locations[0], 2, GL_FLOAT, GL_FALSE, 0, 0));
+    GLCHK(glDrawArrays(GL_TRIANGLES, 0, 6));
+
+    GLCHK(glDisableVertexAttribArray(vcsm_square_shader.attribute_locations[0]));
+    GLCHK(glUseProgram(0));
+
+    return 0;
+}
+#endif /* USE_READPIXELS */
+
+int vcsm_square_open(RASPITEX_STATE *raspitex_state)
+{
+    vcos_log_trace("%s", VCOS_FUNCTION);
+
+    raspitex_state->ops.gl_init = vcsm_square_init;
+#ifdef USE_READPIXELS
+    raspitex_state->ops.redraw = vcsm_square_redraw_readpixels;
+#else
+    raspitex_state->ops.redraw = vcsm_square_redraw;
+#endif /* USE_READPIXELS */
+    raspitex_state->ops.update_y_texture = raspitexutil_update_y_texture;
+    return 0;
+}
diff --git a/host_applications/linux/apps/raspicam/gl_scenes/vcsm_square.h b/host_applications/linux/apps/raspicam/gl_scenes/vcsm_square.h
new file mode 100755 (executable)
index 0000000..632d640
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2016, Tim Gover
+All rights reserved.
+
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VCSM_SQUARE_H
+#define VCSM_SQUARE_H
+
+#include "RaspiTex.h"
+
+int vcsm_square_open(RASPITEX_STATE *state);
+
+#endif /* VCSM_SQUARE_H */
diff --git a/host_applications/linux/apps/raspicam/gl_scenes/yuv.c b/host_applications/linux/apps/raspicam/gl_scenes/yuv.c
new file mode 100755 (executable)
index 0000000..89fd6ab
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, Tim Gover
+All rights reserved.
+
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "yuv.h"
+#include "RaspiTex.h"
+#include "RaspiTexUtil.h"
+#include <GLES2/gl2.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+/* Draw a scaled quad showing the the entire texture with the
+ * origin defined as an attribute */
+static RASPITEXUTIL_SHADER_PROGRAM_T yuv_shader =
+{
+    .vertex_source =
+    "attribute vec2 vertex;\n"
+    "attribute vec2 top_left;\n"
+    "varying vec2 texcoord;\n"
+    "void main(void) {\n"
+    "   texcoord = vertex + vec2(0.0, 1.0);\n"
+    "   gl_Position = vec4(top_left + vertex, 0.0, 1.0);\n"
+    "}\n",
+
+    .fragment_source =
+    "#extension GL_OES_EGL_image_external : require\n"
+    "uniform samplerExternalOES tex;\n"
+    "varying vec2 texcoord;\n"
+    "void main(void) {\n"
+    "    gl_FragColor = texture2D(tex, texcoord);\n"
+    "}\n",
+    .uniform_names = {"tex"},
+    .attribute_names = {"vertex", "top_left"},
+};
+
+static GLfloat varray[] =
+{
+   0.0f, 0.0f, 0.0f, -1.0f, 1.0f, -1.0f,
+   1.0f, -1.0f, 1.0f, 0.0f, 0.0f, 0.0f,
+};
+
+static const EGLint yuv_egl_config_attribs[] =
+{
+   EGL_RED_SIZE,   8,
+   EGL_GREEN_SIZE, 8,
+   EGL_BLUE_SIZE,  8,
+   EGL_ALPHA_SIZE, 8,
+   EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+   EGL_NONE
+};
+
+/**
+ * Creates the OpenGL ES 2.X context and builds the shaders.
+ * @param raspitex_state A pointer to the GL preview state.
+ * @return Zero if successful.
+ */
+static int yuv_init(RASPITEX_STATE *state)
+{
+    int rc;
+    state->egl_config_attribs = yuv_egl_config_attribs;
+    rc = raspitexutil_gl_init_2_0(state);
+    if (rc != 0)
+       goto end;
+
+    rc = raspitexutil_build_shader_program(&yuv_shader);
+    GLCHK(glUseProgram(yuv_shader.program));
+    GLCHK(glUniform1i(yuv_shader.uniform_locations[0], 0)); // tex unit
+end:
+    return rc;
+}
+
+/**
+ * Draws a 2x2 grid with each shell showing the entire MMAL buffer from a
+ * different EGL image target.
+ */
+static int yuv_redraw(RASPITEX_STATE *raspitex_state)
+{
+    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+    GLCHK(glUseProgram(yuv_shader.program));
+    GLCHK(glActiveTexture(GL_TEXTURE0));
+    GLCHK(glEnableVertexAttribArray(yuv_shader.attribute_locations[0]));
+    GLCHK(glVertexAttribPointer(yuv_shader.attribute_locations[0],
+             2, GL_FLOAT, GL_FALSE, 0, varray));
+
+    // Y plane
+    GLCHK(glBindTexture(GL_TEXTURE_EXTERNAL_OES, raspitex_state->y_texture));
+    GLCHK(glVertexAttrib2f(yuv_shader.attribute_locations[1], -1.0f, 1.0f));
+    GLCHK(glDrawArrays(GL_TRIANGLES, 0, 6));
+
+    // U plane
+    GLCHK(glBindTexture(GL_TEXTURE_EXTERNAL_OES, raspitex_state->u_texture));
+    GLCHK(glVertexAttrib2f(yuv_shader.attribute_locations[1], 0.0f, 1.0f));
+    GLCHK(glDrawArrays(GL_TRIANGLES, 0, 6));
+
+    // V plane
+    GLCHK(glBindTexture(GL_TEXTURE_EXTERNAL_OES, raspitex_state->v_texture));
+    GLCHK(glVertexAttrib2f(yuv_shader.attribute_locations[1], 0.0f, 0.0f));
+    GLCHK(glDrawArrays(GL_TRIANGLES, 0, 6));
+
+    // RGB plane
+    GLCHK(glBindTexture(GL_TEXTURE_EXTERNAL_OES, raspitex_state->texture));
+    GLCHK(glVertexAttrib2f(yuv_shader.attribute_locations[1], -1.0f, 0.0f));
+    GLCHK(glDrawArrays(GL_TRIANGLES, 0, 6));
+
+    GLCHK(glDisableVertexAttribArray(yuv_shader.attribute_locations[0]));
+    GLCHK(glUseProgram(0));
+    return 0;
+}
+
+int yuv_open(RASPITEX_STATE *state)
+{
+   state->ops.gl_init = yuv_init;
+   state->ops.redraw = yuv_redraw;
+   state->ops.update_texture = raspitexutil_update_texture;
+   state->ops.update_y_texture = raspitexutil_update_y_texture;
+   state->ops.update_u_texture = raspitexutil_update_u_texture;
+   state->ops.update_v_texture = raspitexutil_update_v_texture;
+   return 0;
+}
diff --git a/host_applications/linux/apps/raspicam/gl_scenes/yuv.h b/host_applications/linux/apps/raspicam/gl_scenes/yuv.h
new file mode 100755 (executable)
index 0000000..b0e3a91
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, Tim Gover
+All rights reserved.
+
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef YUV_H
+#define YUV_H
+
+#include "RaspiTex.h"
+
+int yuv_open(RASPITEX_STATE *state);
+
+#endif /* YUV_H */
diff --git a/host_applications/linux/apps/raspicam/imv_examples/README.md b/host_applications/linux/apps/raspicam/imv_examples/README.md
new file mode 100755 (executable)
index 0000000..d85f343
--- /dev/null
@@ -0,0 +1,39 @@
+Post-processing example programs to play with the imv buffer:
+=============================================================
+
+Compile:
+--------
+gcc imv2pgm.c -o imv2pgm -lm
+
+gcc imv2txt.c -o imv2txt
+
+Record and split buffer:
+------------------------
+raspivid -x test.imv -o test.h264
+
+We need to split the buffer first using split:
+
+split -a 4 -d -b $(((120+1)\*68\*4)) test.imv frame-
+
+Play:
+-----
+Now we can transform the velocity magnitues to a pgm image
+
+./imv2pgm frame-0001 120 68 frame-0001.pgm
+
+Or loop over all frames and create a movie
+
+for i in frame-????; do ./imv2pgm $i 120 68 $i.pgm;convert $i.pgm $i.png; rm $i.pgm; done
+
+avconv -i frame-%04d.png motion.avi
+
+And we can create a text file for easy plotting
+
+./imv2txt frame-0001 120 68 frame-0001.dat
+
+This textfile has in each line the center position x y of the macro block and
+the velocities u and v and the sum of differences sad.
+
+These can be plot with xmgrace
+
+xmgrace -autoscale none -settype xyvmap frame-0001.dat -param plot.par
diff --git a/host_applications/linux/apps/raspicam/imv_examples/imv2pgm.c b/host_applications/linux/apps/raspicam/imv_examples/imv2pgm.c
new file mode 100755 (executable)
index 0000000..fd32227
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+Copyright (c) 2014, Christian Kroener
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h> 
+
+typedef struct
+{
+   signed char x_vector;
+   signed char y_vector;
+   short sad;
+} INLINE_MOTION_VECTOR; 
+
+int main(int argc, const char **argv)
+{
+   if(argc!=5)
+   {
+      printf("usage: %s data.imv mbx mby out.pgm\n",argv[0]);
+      return 0;
+   }
+   int mbx=atoi(argv[2]);
+   int mby=atoi(argv[3]);
+   ///////////////////////////////
+   //  Read raw file to buffer  //
+   ///////////////////////////////
+   FILE *f = fopen(argv[1], "rb");
+   fseek(f, 0, SEEK_END);
+   long fsize = ftell(f);
+   fseek(f, 0, SEEK_SET);
+   char *buffer = malloc(fsize + 1);
+   fread(buffer, fsize, 1, f);
+   fclose(f); 
+   buffer[fsize] = 0;
+   
+   ///////////////////
+   //  Fill struct  //
+   ///////////////////
+   if(fsize<(mbx+1)*mby*4)
+   {
+      printf("File to short!\n");
+      return 0;
+   }
+   INLINE_MOTION_VECTOR *imv; 
+   imv = malloc((mbx+1)*mby*sizeof(INLINE_MOTION_VECTOR));
+   memcpy ( &imv[0], &buffer[0], (mbx+1)*mby*sizeof(INLINE_MOTION_VECTOR) );
+
+   /////////////////////
+   //  Export to PGM  //
+   /////////////////////    
+   FILE *out = fopen(argv[4], "w");
+   fprintf(out,"P5\n%d %d\n255\n",mbx,mby);  
+   int i,j;
+   for(j=0;j<mby; j++)
+      for(i=0;i<mbx; i++)
+   {
+         unsigned char magU=floor(sqrt(imv[i+(mbx+1)*j].x_vector*imv[i+(mbx+1)*j].x_vector+imv[i+(mbx+1)*j].y_vector*imv[i+(mbx+1)*j].y_vector));
+         fputc(magU,out);
+   }
+   fclose(out);
+ return 0;
+}
diff --git a/host_applications/linux/apps/raspicam/imv_examples/imv2txt.c b/host_applications/linux/apps/raspicam/imv_examples/imv2txt.c
new file mode 100755 (executable)
index 0000000..26ca7e1
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+Copyright (c) 2014, Christian Kroener
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+typedef struct
+{
+   signed char x_vector;
+   signed char y_vector;
+   short sad;
+} INLINE_MOTION_VECTOR; 
+
+int main(int argc, const char **argv)
+{
+   if(argc!=5)
+   {
+      printf("usage: %s data.imv mbx mby out.dat\n",argv[0]);
+      return 0;
+   }
+   int mbx=atoi(argv[2]);
+   int mby=atoi(argv[3]);
+   ///////////////////////////////
+   //  Read raw file to buffer  //
+   ///////////////////////////////
+   FILE *f = fopen(argv[1], "rb");
+   fseek(f, 0, SEEK_END);
+   long fsize = ftell(f);
+   fseek(f, 0, SEEK_SET);
+   char *buffer = malloc(fsize + 1);
+   fread(buffer, fsize, 1, f);
+   fclose(f); 
+   buffer[fsize] = 0;
+   
+   ///////////////////
+   //  Fill struct  //
+   ///////////////////
+   if(fsize<(mbx+1)*mby*4)
+   {
+      printf("File to short!\n");
+      return 0;
+   }
+   INLINE_MOTION_VECTOR *imv; 
+   imv = malloc((mbx+1)*mby*sizeof(INLINE_MOTION_VECTOR));
+   memcpy ( &imv[0], &buffer[0], (mbx+1)*mby*sizeof(INLINE_MOTION_VECTOR) );
+
+   //////////////////////////
+   //  Export to txt data  //
+   //////////////////////////    
+   FILE *out = fopen(argv[4], "w");
+   fprintf(out,"#x y u v sad\n");  
+   int i,j;
+   for(j=0;j<mby; j++)
+      for(i=0;i<mbx; i++)
+   {
+      fprintf(out,"%g %g %d %d %d\n",(i+0.5)*16.,(mby-j-0.5)*16.,-imv[i+(mbx+1)*j].x_vector,imv[i+(mbx+1)*j].y_vector,imv[i+(mbx+1)*j].sad);
+   }
+   fclose(out);
+ return 0;
+}
diff --git a/host_applications/linux/apps/raspicam/imv_examples/plot.par b/host_applications/linux/apps/raspicam/imv_examples/plot.par
new file mode 100755 (executable)
index 0000000..f2411ec
--- /dev/null
@@ -0,0 +1,353 @@
+# Grace project file
+#
+version 50122
+page size 792, 612
+page scroll 5%
+page inout 5%
+link page off
+map font 8 to "Courier", "Courier"
+map font 10 to "Courier-Bold", "Courier-Bold"
+map font 11 to "Courier-BoldOblique", "Courier-BoldOblique"
+map font 9 to "Courier-Oblique", "Courier-Oblique"
+map font 14 to "Courier-Regular", "Courier-Regular"
+map font 15 to "Dingbats-Regular", "Dingbats-Regular"
+map font 4 to "Helvetica", "Helvetica"
+map font 6 to "Helvetica-Bold", "Helvetica-Bold"
+map font 7 to "Helvetica-BoldOblique", "Helvetica-BoldOblique"
+map font 5 to "Helvetica-Oblique", "Helvetica-Oblique"
+map font 20 to "Hershey-Gothic-English-Regular", "Hershey-Gothic-English-Regular"
+map font 21 to "Hershey-Gothic-German-Regular", "Hershey-Gothic-German-Regular"
+map font 22 to "Hershey-Gothic-Italian-Regular", "Hershey-Gothic-Italian-Regular"
+map font 23 to "Hershey-Plain-Duplex-Italic-Regular", "Hershey-Plain-Duplex-Italic-Regular"
+map font 24 to "Hershey-Plain-Duplex-Regular", "Hershey-Plain-Duplex-Regular"
+map font 25 to "Hershey-Plain-Triplex-Italic-Regular", "Hershey-Plain-Triplex-Italic-Regular"
+map font 26 to "Hershey-Plain-Triplex-Regular", "Hershey-Plain-Triplex-Regular"
+map font 27 to "Hershey-Script-Complex-Regular", "Hershey-Script-Complex-Regular"
+map font 28 to "Hershey-Script-Simplex-Regular", "Hershey-Script-Simplex-Regular"
+map font 29 to "LuxiMono-Bold", "LuxiMono-Bold"
+map font 30 to "LuxiMono-BoldOblique", "LuxiMono-BoldOblique"
+map font 31 to "LuxiMono-Oblique", "LuxiMono-Oblique"
+map font 32 to "LuxiMono-Regular", "LuxiMono-Regular"
+map font 33 to "LuxiSans-Bold", "LuxiSans-Bold"
+map font 34 to "LuxiSans-BoldOblique", "LuxiSans-BoldOblique"
+map font 35 to "LuxiSans-Oblique", "LuxiSans-Oblique"
+map font 36 to "LuxiSans-Regular", "LuxiSans-Regular"
+map font 37 to "LuxiSerif-Bold", "LuxiSerif-Bold"
+map font 38 to "LuxiSerif-BoldOblique", "LuxiSerif-BoldOblique"
+map font 39 to "LuxiSerif-Oblique", "LuxiSerif-Oblique"
+map font 40 to "LuxiSerif-Regular", "LuxiSerif-Regular"
+map font 41 to "NimbusMonoL-Bold", "NimbusMonoL-Bold"
+map font 42 to "NimbusMonoL-BoldOblique", "NimbusMonoL-BoldOblique"
+map font 43 to "NimbusMonoL-Regular", "NimbusMonoL-Regular"
+map font 44 to "NimbusMonoL-RegularOblique", "NimbusMonoL-RegularOblique"
+map font 45 to "NimbusRomanNo9L-Medium", "NimbusRomanNo9L-Medium"
+map font 46 to "NimbusRomanNo9L-MediumItalic", "NimbusRomanNo9L-MediumItalic"
+map font 47 to "NimbusRomanNo9L-Regular", "NimbusRomanNo9L-Regular"
+map font 48 to "NimbusRomanNo9L-RegularItalic", "NimbusRomanNo9L-RegularItalic"
+map font 49 to "NimbusSansL-Bold", "NimbusSansL-Bold"
+map font 50 to "NimbusSansL-BoldCondensed", "NimbusSansL-BoldCondensed"
+map font 51 to "NimbusSansL-BoldCondensedItalic", "NimbusSansL-BoldCondensedItalic"
+map font 52 to "NimbusSansL-BoldItalic", "NimbusSansL-BoldItalic"
+map font 53 to "NimbusSansL-Regular", "NimbusSansL-Regular"
+map font 54 to "NimbusSansL-RegularCondensed", "NimbusSansL-RegularCondensed"
+map font 55 to "NimbusSansL-RegularCondensedItalic", "NimbusSansL-RegularCondensedItalic"
+map font 56 to "NimbusSansL-RegularItalic", "NimbusSansL-RegularItalic"
+map font 57 to "StandardSymbolsL-Regular", "StandardSymbolsL-Regular"
+map font 12 to "Symbol", "Symbol"
+map font 59 to "Symbol-Regular", "Symbol-Regular"
+map font 2 to "Times-Bold", "Times-Bold"
+map font 3 to "Times-BoldItalic", "Times-BoldItalic"
+map font 1 to "Times-Italic", "Times-Italic"
+map font 0 to "Times-Roman", "Times-Roman"
+map font 64 to "URWBookmanL-DemiBold", "URWBookmanL-DemiBold"
+map font 65 to "URWBookmanL-DemiBoldItalic", "URWBookmanL-DemiBoldItalic"
+map font 66 to "URWBookmanL-Light", "URWBookmanL-Light"
+map font 67 to "URWBookmanL-LightItalic", "URWBookmanL-LightItalic"
+map font 68 to "URWChanceryL-MediumItalic", "URWChanceryL-MediumItalic"
+map font 69 to "URWGothicL-Book", "URWGothicL-Book"
+map font 70 to "URWGothicL-BookOblique", "URWGothicL-BookOblique"
+map font 71 to "URWGothicL-Demi", "URWGothicL-Demi"
+map font 72 to "URWGothicL-DemiOblique", "URWGothicL-DemiOblique"
+map font 73 to "URWPalladioL-Bold", "URWPalladioL-Bold"
+map font 74 to "URWPalladioL-BoldItalic", "URWPalladioL-BoldItalic"
+map font 75 to "URWPalladioL-Italic", "URWPalladioL-Italic"
+map font 76 to "URWPalladioL-Roman", "URWPalladioL-Roman"
+map font 77 to "Utopia-Bold", "Utopia-Bold"
+map font 78 to "Utopia-BoldItalic", "Utopia-BoldItalic"
+map font 79 to "Utopia-Italic", "Utopia-Italic"
+map font 80 to "Utopia-Regular", "Utopia-Regular"
+map font 13 to "ZapfDingbats", "ZapfDingbats"
+map color 0 to (255, 255, 255), "white"
+map color 1 to (0, 0, 0), "black"
+map color 2 to (255, 0, 0), "red"
+map color 3 to (0, 255, 0), "green"
+map color 4 to (0, 0, 255), "blue"
+map color 5 to (255, 255, 0), "yellow"
+map color 6 to (188, 143, 143), "brown"
+map color 7 to (220, 220, 220), "grey"
+map color 8 to (148, 0, 211), "violet"
+map color 9 to (0, 255, 255), "cyan"
+map color 10 to (255, 0, 255), "magenta"
+map color 11 to (255, 165, 0), "orange"
+map color 12 to (114, 33, 188), "indigo"
+map color 13 to (103, 7, 72), "maroon"
+map color 14 to (64, 224, 208), "turquoise"
+map color 15 to (0, 139, 0), "green4"
+reference date 0
+date wrap off
+date wrap year 1950
+default linewidth 1.0
+default linestyle 1
+default color 1
+default pattern 1
+default font 0
+default char size 1.000000
+default symbol size 1.000000
+default sformat "%.8g"
+background color 0
+page background fill on
+timestamp off
+timestamp 0.03, 0.03
+timestamp color 1
+timestamp rot 0
+timestamp font 0
+timestamp char size 1.000000
+timestamp def "Mon May 12 15:26:28 2014"
+r0 off
+link r0 to g0
+r0 type above
+r0 linestyle 1
+r0 linewidth 1.0
+r0 color 1
+r0 line 0, 0, 0, 0
+r1 off
+link r1 to g0
+r1 type above
+r1 linestyle 1
+r1 linewidth 1.0
+r1 color 1
+r1 line 0, 0, 0, 0
+r2 off
+link r2 to g0
+r2 type above
+r2 linestyle 1
+r2 linewidth 1.0
+r2 color 1
+r2 line 0, 0, 0, 0
+r3 off
+link r3 to g0
+r3 type above
+r3 linestyle 1
+r3 linewidth 1.0
+r3 color 1
+r3 line 0, 0, 0, 0
+r4 off
+link r4 to g0
+r4 type above
+r4 linestyle 1
+r4 linewidth 1.0
+r4 color 1
+r4 line 0, 0, 0, 0
+g0 on
+g0 hidden false
+g0 type Fixed
+g0 stacked false
+g0 bar hgap 0.000000
+g0 fixedpoint off
+g0 fixedpoint type 0
+g0 fixedpoint xy 0.000000, 0.000000
+g0 fixedpoint format general general
+g0 fixedpoint prec 6, 6
+with g0
+    world 0, 0, 1920, 1080
+    stack world 0, 0, 0, 0
+    znorm 5000
+    view 0.150000, 0.150000, 1.150000, 0.850000
+    title ""
+    title font 0
+    title size 1.500000
+    title color 1
+    subtitle ""
+    subtitle font 0
+    subtitle size 1.000000
+    subtitle color 1
+    xaxes scale Normal
+    yaxes scale Normal
+    xaxes invert off
+    yaxes invert off
+    xaxis  on
+    xaxis  type zero false
+    xaxis  offset 0.000000 , 0.000000
+    xaxis  bar on
+    xaxis  bar color 1
+    xaxis  bar linestyle 1
+    xaxis  bar linewidth 1.0
+    xaxis  label ""
+    xaxis  label layout para
+    xaxis  label place auto
+    xaxis  label char size 1.000000
+    xaxis  label font 0
+    xaxis  label color 1
+    xaxis  label place normal
+    xaxis  tick on
+    xaxis  tick major 500
+    xaxis  tick minor ticks 1
+    xaxis  tick default 6
+    xaxis  tick place rounded true
+    xaxis  tick in
+    xaxis  tick major size 1.000000
+    xaxis  tick major color 1
+    xaxis  tick major linewidth 1.0
+    xaxis  tick major linestyle 1
+    xaxis  tick major grid off
+    xaxis  tick minor color 1
+    xaxis  tick minor linewidth 1.0
+    xaxis  tick minor linestyle 1
+    xaxis  tick minor grid off
+    xaxis  tick minor size 0.500000
+    xaxis  ticklabel on
+    xaxis  ticklabel format general
+    xaxis  ticklabel prec 5
+    xaxis  ticklabel formula ""
+    xaxis  ticklabel append ""
+    xaxis  ticklabel prepend ""
+    xaxis  ticklabel angle 0
+    xaxis  ticklabel skip 0
+    xaxis  ticklabel stagger 0
+    xaxis  ticklabel place normal
+    xaxis  ticklabel offset auto
+    xaxis  ticklabel offset 0.000000 , 0.010000
+    xaxis  ticklabel start type auto
+    xaxis  ticklabel start 0.000000
+    xaxis  ticklabel stop type auto
+    xaxis  ticklabel stop 0.000000
+    xaxis  ticklabel char size 1.000000
+    xaxis  ticklabel font 0
+    xaxis  ticklabel color 1
+    xaxis  tick place both
+    xaxis  tick spec type none
+    yaxis  on
+    yaxis  type zero false
+    yaxis  offset 0.000000 , 0.000000
+    yaxis  bar on
+    yaxis  bar color 1
+    yaxis  bar linestyle 1
+    yaxis  bar linewidth 1.0
+    yaxis  label ""
+    yaxis  label layout para
+    yaxis  label place auto
+    yaxis  label char size 1.000000
+    yaxis  label font 0
+    yaxis  label color 1
+    yaxis  label place normal
+    yaxis  tick on
+    yaxis  tick major 500
+    yaxis  tick minor ticks 1
+    yaxis  tick default 6
+    yaxis  tick place rounded true
+    yaxis  tick in
+    yaxis  tick major size 1.000000
+    yaxis  tick major color 1
+    yaxis  tick major linewidth 1.0
+    yaxis  tick major linestyle 1
+    yaxis  tick major grid off
+    yaxis  tick minor color 1
+    yaxis  tick minor linewidth 1.0
+    yaxis  tick minor linestyle 1
+    yaxis  tick minor grid off
+    yaxis  tick minor size 0.500000
+    yaxis  ticklabel on
+    yaxis  ticklabel format general
+    yaxis  ticklabel prec 5
+    yaxis  ticklabel formula ""
+    yaxis  ticklabel append ""
+    yaxis  ticklabel prepend ""
+    yaxis  ticklabel angle 0
+    yaxis  ticklabel skip 0
+    yaxis  ticklabel stagger 0
+    yaxis  ticklabel place normal
+    yaxis  ticklabel offset auto
+    yaxis  ticklabel offset 0.000000 , 0.010000
+    yaxis  ticklabel start type auto
+    yaxis  ticklabel start 0.000000
+    yaxis  ticklabel stop type auto
+    yaxis  ticklabel stop 0.000000
+    yaxis  ticklabel char size 1.000000
+    yaxis  ticklabel font 0
+    yaxis  ticklabel color 1
+    yaxis  tick place both
+    yaxis  tick spec type none
+    altxaxis  off
+    altyaxis  off
+    legend on
+    legend loctype view
+    legend 0.85, 0.8
+    legend box color 1
+    legend box pattern 1
+    legend box linewidth 1.0
+    legend box linestyle 1
+    legend box fill color 0
+    legend box fill pattern 1
+    legend font 0
+    legend char size 1.000000
+    legend color 1
+    legend length 4
+    legend vgap 1
+    legend hgap 1
+    legend invert false
+    frame type 0
+    frame linestyle 1
+    frame linewidth 1.0
+    frame color 1
+    frame pattern 0
+    frame background color 0
+    frame background pattern 0
+    s0 hidden false
+    s0 type xyvmap
+    s0 symbol 1
+    s0 symbol size 0.000000
+    s0 symbol color 1
+    s0 symbol pattern 1
+    s0 symbol fill color 1
+    s0 symbol fill pattern 0
+    s0 symbol linewidth 1.0
+    s0 symbol linestyle 1
+    s0 symbol char 65
+    s0 symbol char font 0
+    s0 symbol skip 0
+    s0 line type 0
+    s0 line linestyle 1
+    s0 line linewidth 1.0
+    s0 line color 1
+    s0 line pattern 1
+    s0 baseline type 0
+    s0 baseline off
+    s0 dropline off
+    s0 fill type 0
+    s0 fill rule 0
+    s0 fill color 1
+    s0 fill pattern 1
+    s0 avalue off
+    s0 avalue type 2
+    s0 avalue char size 1.000000
+    s0 avalue font 0
+    s0 avalue color 1
+    s0 avalue rot 0
+    s0 avalue format general
+    s0 avalue prec 3
+    s0 avalue prepend ""
+    s0 avalue append ""
+    s0 avalue offset 0.000000 , 0.000000
+    s0 errorbar on
+    s0 errorbar place both
+    s0 errorbar color 1
+    s0 errorbar pattern 1
+    s0 errorbar size 0.160000
+    s0 errorbar linewidth 1.0
+    s0 errorbar linestyle 1
+    s0 errorbar riser linewidth 1.0
+    s0 errorbar riser linestyle 1
+    s0 errorbar riser clip off
+    s0 errorbar riser clip length 0.100000
+    s0 comment "frame-0123.dat"
+    s0 legend  ""
diff --git a/host_applications/linux/apps/raspicam/tga.c b/host_applications/linux/apps/raspicam/tga.c
new file mode 100755 (executable)
index 0000000..7e64ae4
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, Tim Gover
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "tga.h"
+#include <string.h>
+
+#define TGA_WRITE(FP, F) \
+   if (fwrite((&F), sizeof(F), 1, (FP)) != 1) goto write_fail
+int write_tga(FILE *fp, int width, int height,
+      uint8_t *buffer, size_t buffer_size)
+{
+   struct tga_header header;
+   memset(&header, 0, sizeof(header));
+   header.image_type = tga_type_true_color;
+   header.image_info.width = width;
+   header.image_info.y_origin = height;
+   header.image_info.height = height;
+   header.image_info.bpp = 32;
+
+   TGA_WRITE(fp, header.id_length);
+   TGA_WRITE(fp, header.color_map_type);
+   TGA_WRITE(fp, header.image_type);
+   TGA_WRITE(fp, header.colormap_info.offset);
+   TGA_WRITE(fp, header.colormap_info.length);
+   TGA_WRITE(fp, header.colormap_info.bpp);
+   TGA_WRITE(fp, header.image_info.x_origin);
+   TGA_WRITE(fp, header.image_info.y_origin);
+   TGA_WRITE(fp, header.image_info.width);
+   TGA_WRITE(fp, header.image_info.height);
+   TGA_WRITE(fp, header.image_info.bpp);
+   TGA_WRITE(fp, header.image_info.descriptor);
+
+   if (fwrite(buffer, 1, buffer_size, fp) != buffer_size)
+      goto write_fail;
+
+   return 0;
+write_fail:
+   return -1;
+}
+
+#define TGA_READ(FP, F) if (fread((&F), sizeof(F), 1, (FP)) != 1) goto read_fail
+
+static int read_header(FILE *fp, struct tga_header *header) {
+    TGA_READ(fp, header->id_length);
+    TGA_READ(fp, header->color_map_type);
+    TGA_READ(fp, header->image_type);
+    TGA_READ(fp, header->colormap_info.offset);
+    TGA_READ(fp, header->colormap_info.length);
+    TGA_READ(fp, header->colormap_info.bpp);
+    TGA_READ(fp, header->image_info.x_origin);
+    TGA_READ(fp, header->image_info.y_origin);
+    TGA_READ(fp, header->image_info.width);
+    TGA_READ(fp, header->image_info.height);
+    TGA_READ(fp, header->image_info.bpp);
+    TGA_READ(fp, header->image_info.descriptor);
+
+    return 0;
+
+read_fail:
+    return -1;
+}
+
+unsigned char *load_tga(const char *filename, struct tga_header *header) {
+    unsigned char *image = NULL;
+    FILE *fp = fopen(filename, "r");
+    if (fp) {
+        if(read_header(fp, header) == 0) {
+            if (header->image_type == tga_type_true_color &&
+                (header->image_info.bpp == 24 ||
+                header->image_info.bpp == 32)) {
+                int buflen = header->image_info.width *
+                   header->image_info.height * (header->image_info.bpp / 8);
+                image = malloc(buflen);
+                if (image) {
+                    if (header->id_length)
+                        fseek(fp, SEEK_CUR, header->id_length);
+
+                    if (fread(image, 1, buflen, fp) != buflen) {
+                        free(image);
+                        image = NULL;
+                    }
+                }
+            }
+        }
+        fclose(fp);
+    }
+    return image;
+}
diff --git a/host_applications/linux/apps/raspicam/tga.h b/host_applications/linux/apps/raspicam/tga.h
new file mode 100755 (executable)
index 0000000..eb9a16c
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+Copyright (c) 2013, Tim Gover
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef TGA_H
+#define TGA_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+
+typedef enum {
+   tga_type_null = 0,
+   tga_type_color_map = 1,
+   tga_type_true_color = 2,
+   tga_type_grayscale = 3,
+   tga_type_rle_color_map = 9,
+   tga_type_rle_true_color = 10,
+   tga_type_rle_grayscale = 11,
+
+} tga_image_type;
+
+struct tga_colormap_info {
+   unsigned short offset;
+   unsigned short length;
+   unsigned char bpp;
+};
+
+struct tga_image_info {
+   unsigned short x_origin;
+   unsigned short y_origin;
+   unsigned short width;
+   unsigned short height;
+   unsigned char bpp;
+   unsigned char descriptor;
+};
+
+struct tga_header {
+   unsigned char id_length;
+   unsigned char color_map_type;
+   unsigned char image_type;
+   struct tga_colormap_info colormap_info;
+   struct tga_image_info image_info;
+};
+
+int write_tga(FILE* fp, int width, int height, uint8_t *buffer, size_t buffer_size);
+unsigned char *load_tga(const char *filename, struct tga_header *header);
+
+#endif /* TGA_H */
diff --git a/host_applications/linux/apps/smem/CMakeLists.txt b/host_applications/linux/apps/smem/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..0fa8328
--- /dev/null
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 2.8)
+
+get_filename_component (VIDEOCORE_ROOT ../../../.. ABSOLUTE)
+include (${VIDEOCORE_ROOT}/makefiles/cmake/global_settings.cmake)
+
+if (NOT WIN32)
+   add_definitions(-Wall -Werror)
+endif ()
+
+include_directories (
+   ${VIDEOCORE_HEADERS_BUILD_DIR}
+   ${VIDEOCORE_ROOT}
+   ${VIDEOCORE_ROOT}/host_applications/linux/libs/sm
+)
+
+add_executable(vcsmem smem.c)
+target_link_libraries(vcsmem vcos vcsm vchostif)
+
+install(TARGETS vcsmem RUNTIME DESTINATION bin)
+
diff --git a/host_applications/linux/apps/smem/smem.c b/host_applications/linux/apps/smem/smem.c
new file mode 100755 (executable)
index 0000000..618580e
--- /dev/null
@@ -0,0 +1,449 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+// ---- Include Files -------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <signal.h>
+#include <assert.h>
+
+#include <user-vcsm.h>
+#include "interface/vcos/vcos.h"
+
+// ---- Public Variables ----------------------------------------------------
+
+// ---- Private Constants and Types -----------------------------------------
+
+// Note: Exact match 32 chars.
+static char blah_blah[32] = "Testing shared memory interface!";
+
+enum
+{
+   OPT_ALLOC     = 'a',
+   OPT_STATUS    = 's',
+   OPT_PID       = 'p',
+   OPT_HELP      = 'h',
+
+   // Options from this point onwards don't have any short option equivalents
+   OPT_FIRST_LONG_OPT = 0x80,
+};
+
+static struct option long_opts[] =
+{
+   // name                 has_arg              flag     val
+   // -------------------  ------------------   ----     ---------------
+   { "alloc",              required_argument,   NULL,    OPT_ALLOC },
+   { "pid",                required_argument,   NULL,    OPT_PID },
+   { "status",             required_argument,   NULL,    OPT_STATUS },
+   { "help",               no_argument,         NULL,    OPT_HELP },
+   { 0,                    0,                   0,       0 }
+};
+
+// Maximum length of option string (3 characters max for each option + NULL)
+#define OPTSTRING_LEN  ( sizeof( long_opts ) / sizeof( *long_opts ) * 3 + 1 )
+
+// ---- Private Variables ---------------------------------------------------
+
+static VCOS_LOG_CAT_T smem_log_category;
+#define VCOS_LOG_CATEGORY (&smem_log_category)
+static VCOS_EVENT_T quit_event;
+
+// ---- Private Functions ---------------------------------------------------
+
+static void show_usage( void )
+{
+   vcos_log_info( "Usage: smem [OPTION]..." );
+   vcos_log_info( "  -a, --alloc=SIZE             Allocates a block of SIZE" );
+   vcos_log_info( "  -p, --pid=PID                Use PID for desired action" );
+   vcos_log_info( "  -s, --status=TYPE            Queries status of TYPE [for PID]" );
+   vcos_log_info( "                all                    all (for current pid)" );
+   vcos_log_info( "                vc                     videocore allocations" );
+   vcos_log_info( "                map                    host map status" );
+   vcos_log_info( "                map <pid>              host map status for pid" );
+   vcos_log_info( "                host <pid>             host allocations for pid" );
+   vcos_log_info( "  -h, --help                   Print this information" );
+}
+
+static void create_optstring( char *optstring )
+{
+   char *short_opts = optstring;
+   struct option *option;
+
+   // Figure out the short options from our options structure
+   for ( option = long_opts; option->name != NULL; option++ )
+   {
+      if (( option->flag == NULL ) && ( option->val < OPT_FIRST_LONG_OPT ))
+      {
+         *short_opts++ = (char)option->val;
+
+         if ( option->has_arg != no_argument )
+         {
+            *short_opts++ = ':';
+         }
+
+         // Optional arguments require two ':'
+         if ( option->has_arg == optional_argument )
+         {
+            *short_opts++ = ':';
+         }
+      }
+   }
+   *short_opts++ = '\0';
+}
+
+static int get_status( VCSM_STATUS_T mode, int pid )
+{
+   switch ( mode )
+   {
+      case VCSM_STATUS_VC_WALK_ALLOC:
+         vcsm_status( VCSM_STATUS_VC_WALK_ALLOC, -1 );
+      break;
+      
+      case VCSM_STATUS_HOST_WALK_MAP:
+         if ( pid != -1 )
+         {
+            vcsm_status( VCSM_STATUS_HOST_WALK_PID_MAP, pid );
+         }
+         else
+         {
+            vcsm_status( VCSM_STATUS_HOST_WALK_MAP, -1 );
+         }
+      break;
+
+      case VCSM_STATUS_HOST_WALK_PID_ALLOC:
+         vcsm_status( VCSM_STATUS_HOST_WALK_PID_ALLOC, pid );
+      break;
+
+      case VCSM_STATUS_VC_MAP_ALL:
+         vcsm_status( VCSM_STATUS_VC_WALK_ALLOC, -1 );
+         vcsm_status( VCSM_STATUS_HOST_WALK_MAP, -1 );
+      break;
+      
+      default:
+      break;
+   }
+
+   return 0;
+}
+
+static void control_c( int signum )
+{
+    (void)signum;
+
+    vcos_log_info( "Shutting down..." );
+
+    vcos_event_signal( &quit_event );
+}
+
+static int start_monitor( void )
+{
+   if ( vcos_event_create( &quit_event, "smem" ) != VCOS_SUCCESS )
+   {
+      vcos_log_info( "Failed to create quit event" );
+
+      return -1;
+   }
+
+   // Handle the INT and TERM signals so we can quit
+   signal( SIGINT, control_c );
+   signal( SIGTERM, control_c );
+
+   return 0;
+}
+
+// ---- Public Functions -----------------------------------------------------
+
+// #define DOUBLE_ALLOC
+#define RESIZE_ALLOC
+
+int main( int argc, char **argv )
+{
+   int32_t ret;
+   char optstring[OPTSTRING_LEN];
+   int  opt;
+   int  opt_alloc = 0;
+   int  opt_status = 0;
+   uint32_t alloc_size = 0;
+   int  opt_pid = -1;
+   VCSM_STATUS_T status_mode = VCSM_STATUS_NONE;
+
+   void *usr_ptr_1;
+   unsigned int usr_hdl_1;
+#if defined(DOUBLE_ALLOC) || defined(RESIZE_ALLOC)
+   void *usr_ptr_2;
+   unsigned int usr_hdl_2;
+#endif
+
+   // Initialize VCOS
+   vcos_init();
+
+   vcos_log_set_level(&smem_log_category, VCOS_LOG_INFO);
+   smem_log_category.flags.want_prefix = 0;
+   vcos_log_register( "smem", &smem_log_category );
+
+   // Create the option string that we will be using to parse the arguments
+   create_optstring( optstring );
+
+   // Parse the command line arguments
+   while (( opt = getopt_long_only( argc, argv, optstring, long_opts,
+                                    NULL )) != -1 )
+   {
+      switch ( opt )
+      {
+         case 0:
+         {
+            // getopt_long returns 0 for entries where flag is non-NULL
+            break;
+         }
+         case OPT_ALLOC:
+         {
+            char *end;
+            alloc_size = (uint32_t)strtoul( optarg, &end, 10 );
+            if (end == optarg)
+            {
+               vcos_log_info( "Invalid arguments '%s'", optarg );
+               goto err_out;
+            }
+
+            opt_alloc = 1;
+            break;
+         }
+         case OPT_PID:
+         {
+            char *end;
+            opt_pid = (int)strtol( optarg, &end, 10 );
+            if (end == optarg)
+            {
+               vcos_log_info( "Invalid arguments '%s'", optarg );
+               goto err_out;
+            }
+
+            break;
+         }
+         case OPT_STATUS:
+         {
+            char status_str[32];
+
+            /* coverity[secure_coding] String length specified, so can't overflow */
+            if ( sscanf( optarg, "%31s", status_str ) != 1 )
+            {
+               vcos_log_info( "Invalid arguments '%s'", optarg );
+               goto err_out;
+            }
+
+            if ( vcos_strcasecmp( status_str, "all" ) == 0 )
+            {
+               status_mode = VCSM_STATUS_VC_MAP_ALL;
+            }
+            else if ( vcos_strcasecmp( status_str, "vc" ) == 0 )
+            {
+               status_mode = VCSM_STATUS_VC_WALK_ALLOC;
+            }
+            else if ( vcos_strcasecmp( status_str, "map" ) == 0 )
+            {
+               status_mode = VCSM_STATUS_HOST_WALK_MAP;
+            }
+            else if ( vcos_strcasecmp( status_str, "host" ) == 0 )
+            {
+               status_mode = VCSM_STATUS_HOST_WALK_PID_ALLOC;
+            }
+            else
+            {
+               goto err_out;
+            }
+
+            opt_status = 1;
+            break;
+         }
+         default:
+         {
+            vcos_log_info( "Unrecognized option '%d'", opt );
+            goto err_usage;
+         }
+         case '?':
+         case OPT_HELP:
+         {
+            goto err_usage;
+         }
+      } // end switch
+   } // end while
+
+   argc -= optind;
+   argv += optind;
+
+   if (( optind == 1 ) || ( argc > 0 ))
+   {
+      if ( argc > 0 )
+      {
+         vcos_log_info( "Unrecognized argument -- '%s'", *argv );
+      }
+
+      goto err_usage;
+   }
+
+   // Start the shared memory support.
+   if ( vcsm_init() == -1 )
+   {
+      vcos_log_info( "Cannot initialize smem device" );
+      goto err_out;
+   }
+
+   if ( opt_alloc == 1 )
+   {
+      vcos_log_info( "Allocating 2 times %u-bytes in shared memory", alloc_size );
+
+      usr_hdl_1 = vcsm_malloc( alloc_size,
+                               "smem-test-alloc" );
+
+      vcos_log_info( "Allocation 1 result: user %x, vc-hdl %x",
+                     usr_hdl_1, vcsm_vc_hdl_from_hdl( usr_hdl_1 ) );
+
+#if defined(DOUBLE_ALLOC) || defined(RESIZE_ALLOC)
+      usr_hdl_2 = vcsm_malloc( alloc_size,
+                               NULL );
+      vcos_log_info( "Allocation 2 result: user %x",
+                     usr_hdl_2 );
+
+      usr_ptr_2 = vcsm_lock( usr_hdl_2 );
+      vcos_log_info( "Allocation 2 : lock %p",
+                     usr_ptr_2 );
+      vcos_log_info( "Allocation 2 : unlock %d",
+                     vcsm_unlock_hdl( usr_hdl_2 ) );
+#endif
+
+      // Do a simple write/read test.
+      if ( usr_hdl_1 != 0 )
+      {
+         usr_ptr_1 = vcsm_lock( usr_hdl_1 );
+         vcos_log_info( "Allocation 1 : lock %p",
+                        usr_ptr_1 );
+         if ( usr_ptr_1 )
+         {
+            memset ( usr_ptr_1,
+                     0,
+                     alloc_size );
+            memcpy ( usr_ptr_1,
+                     blah_blah,
+                     32 );
+            vcos_log_info( "Allocation 1 contains: \"%s\"",
+                           (char *)usr_ptr_1 );
+
+            vcos_log_info( "Allocation 1: vc-hdl %x",
+                           vcsm_vc_hdl_from_ptr ( usr_ptr_1 ) );
+            vcos_log_info( "Allocation 1: usr-hdl %x",
+                           vcsm_usr_handle ( usr_ptr_1 ) );
+            vcos_log_info( "Allocation 1 : unlock %d",
+                           vcsm_unlock_ptr( usr_ptr_1 ) );
+         }
+
+         usr_ptr_1 = vcsm_lock( usr_hdl_1 );
+         vcos_log_info( "Allocation 1 (relock) : lock %p",
+                        usr_ptr_1 );
+         if ( usr_ptr_1 )
+         {
+            vcos_log_info( "Allocation 1 (relock) : unlock %d",
+                           vcsm_unlock_hdl( usr_hdl_1 ) );
+         }
+      }
+
+#if defined(RESIZE_ALLOC)
+      ret = vcsm_resize( usr_hdl_1, 2 * alloc_size );
+      vcos_log_info( "Allocation 1 : resize %d", ret );
+      if ( ret == 0 )
+      {
+         usr_ptr_1 = vcsm_lock( usr_hdl_1 );
+         vcos_log_info( "Allocation 1 (resize) : lock %p",
+                        usr_ptr_1 );
+         if ( usr_ptr_1 )
+         {
+            memset ( usr_ptr_1,
+                     0,
+                     2 * alloc_size );
+            memcpy ( usr_ptr_1,
+                     blah_blah,
+                     32 );
+            vcos_log_info( "Allocation 1 (resized) contains: \"%s\"",
+                           (char *)usr_ptr_1 );
+            vcos_log_info( "Allocation 1 (resized) : unlock %d",
+                           vcsm_unlock_ptr( usr_ptr_1 ) );
+         }
+      }
+
+      // This checks that the memory can be remapped properly
+      // because the Block 1 expanded beyond Block 2 boundary.
+      //
+      usr_ptr_2 = vcsm_lock( usr_hdl_2 );
+      vcos_log_info( "Allocation 2 : lock %p",
+                     usr_ptr_2 );
+      vcos_log_info( "Allocation 2 : unlock %d",
+                     vcsm_unlock_hdl( usr_hdl_2 ) );
+
+      // This checks that we can free a memory block even if it
+      // is locked, which could be the case if the application 
+      // dies.
+      //
+      usr_ptr_2 = vcsm_lock( usr_hdl_2 );
+      vcos_log_info( "Allocation 2 : lock %p",
+                     usr_ptr_2 );
+      vcsm_free ( usr_hdl_2 );
+#endif
+
+#if defined(DOUBLE_ALLOC)
+#endif
+   }
+
+   if ( opt_status == 1 )
+   {
+      get_status( status_mode, opt_pid );
+   }
+   
+   // If we allocated something, wait for the signal to exit to give chance for the
+   // user to poke around the allocation test.
+   //
+   if ( opt_alloc == 1 )
+   {
+      start_monitor();
+      
+      vcos_event_wait( &quit_event );
+      vcos_event_delete( &quit_event );
+   }
+
+   // Terminate the shared memory support.
+   vcsm_exit ();
+   goto err_out;
+
+err_usage:
+   show_usage();
+
+err_out:
+   exit( 1 );
+}
diff --git a/host_applications/linux/apps/tvservice/CMakeLists.txt b/host_applications/linux/apps/tvservice/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..f5b19ee
--- /dev/null
@@ -0,0 +1,5 @@
+add_executable(tvservice tvservice.c)
+target_link_libraries(tvservice vchostif)
+
+install(TARGETS tvservice
+        RUNTIME DESTINATION bin)
diff --git a/host_applications/linux/apps/tvservice/tvservice.c b/host_applications/linux/apps/tvservice/tvservice.c
new file mode 100755 (executable)
index 0000000..7d37d0e
--- /dev/null
@@ -0,0 +1,1156 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+// ---- Include Files -------------------------------------------------------
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <signal.h>
+#include <assert.h>
+#include <string.h>
+
+#include "interface/vmcs_host/vc_tvservice.h"
+
+#define TV_SUPPORTED_MODE_T TV_SUPPORTED_MODE_NEW_T
+#define vc_tv_hdmi_get_supported_modes vc_tv_hdmi_get_supported_modes_new
+#define vc_tv_hdmi_power_on_explicit vc_tv_hdmi_power_on_explicit_new
+
+// ---- Public Variables ----------------------------------------------------
+
+// ---- Private Constants and Types -----------------------------------------
+
+// Logging macros (for remapping to other logging mechanisms, i.e., vcos_log)
+#define LOG_ERR(  fmt, arg... )  fprintf( stderr, "[E] " fmt "\n", ##arg )
+#define LOG_WARN( fmt, arg... )  fprintf( stderr, "[W] " fmt "\n", ##arg )
+#define LOG_INFO( fmt, arg... )  fprintf( stderr, "[I] " fmt "\n", ##arg )
+#define LOG_DBG(  fmt, arg... )  fprintf( stdout, "[D] " fmt "\n", ##arg )
+
+// Standard output log (for printing normal information to users)
+#define LOG_STD(  fmt, arg... )  fprintf( stdout, fmt "\n", ##arg )
+
+// Maximum length of option string (3 characters max for each option + NULL)
+#define OPTSTRING_LEN  ( sizeof( long_opts ) / sizeof( *long_opts ) * 3 + 1 )
+
+// Maximum mode ID
+#define MAX_MODE_ID (127)
+
+// Maximum status string length
+#define MAX_STATUS_STR_LENGTH (128)
+
+// ---- Private Variables ---------------------------------------------------
+
+enum
+{
+   OPT_PREFERRED = 'p',
+   OPT_EXPLICIT  = 'e',
+   OPT_NTSC      = 't',
+   OPT_OFF       = 'o',
+   OPT_SDTVON    = 'c',
+   OPT_MODES     = 'm',
+   OPT_MONITOR   = 'M',
+   OPT_STATUS    = 's',
+   OPT_DUMPEDID  = 'd',
+   OPT_AUDIOSUP  = 'a',
+   OPT_SHOWINFO  = 'i',
+   OPT_JSON      = 'j',
+   OPT_HELP      = 'h',
+   OPT_NAME      = 'n',
+   // Options from this point onwards don't have any short option equivalents
+   OPT_FIRST_LONG_OPT = 0x80,
+};
+
+static struct option long_opts[] =
+{
+   // name                 has_arg              flag     val
+   // -------------------  ------------------   ----     ---------------
+   { "preferred",          no_argument,         NULL,    OPT_PREFERRED },
+   { "explicit",           required_argument,   NULL,    OPT_EXPLICIT },
+   { "ntsc",               no_argument,         NULL,    OPT_NTSC },
+   { "off",                no_argument,         NULL,    OPT_OFF },
+   { "sdtvon",             required_argument,   NULL,    OPT_SDTVON },
+   { "modes",              required_argument,   NULL,    OPT_MODES },
+   { "monitor",            no_argument,         NULL,    OPT_MONITOR },
+   { "status",             no_argument,         NULL,    OPT_STATUS },
+   { "dumpedid",           required_argument,   NULL,    OPT_DUMPEDID},
+   { "audio",              no_argument,         NULL,    OPT_AUDIOSUP},
+   { "json",               no_argument,         NULL,    OPT_JSON },
+   { "info",               required_argument,   NULL,    OPT_SHOWINFO},
+   { "help",               no_argument,         NULL,    OPT_HELP },
+   { "name",               no_argument,         NULL,    OPT_NAME },
+   { 0,                    0,                   0,       0 }
+};
+
+static VCOS_EVENT_T quit_event;
+
+// ---- Private Functions ---------------------------------------------------
+
+static void show_usage( void )
+{
+   LOG_STD( "Usage: tvservice [OPTION]..." );
+   LOG_STD( "  -p, --preferred                   Power on HDMI with preferred settings" );
+   LOG_STD( "  -e, --explicit=\"GROUP MODE DRIVE\" Power on HDMI with explicit GROUP (CEA, DMT, CEA_3D_SBS, CEA_3D_TB, CEA_3D_FP, CEA_3D_FS)\n"
+            "                                      MODE (see --modes) and DRIVE (HDMI, DVI)" );
+   LOG_STD( "  -t, --ntsc                        Use NTSC frequency for HDMI mode (e.g. 59.94Hz rather than 60Hz)" );
+   LOG_STD( "  -c, --sdtvon=\"MODE ASPECT [P]\"    Power on SDTV with MODE (PAL or NTSC) and ASPECT (4:3 14:9 or 16:9) Add P for progressive" );
+   LOG_STD( "  -o, --off                         Power off the display" );
+   LOG_STD( "  -m, --modes=GROUP                 Get supported modes for GROUP (CEA, DMT)" );
+   LOG_STD( "  -M, --monitor                     Monitor HDMI events" );
+   LOG_STD( "  -s, --status                      Get HDMI status" );
+   LOG_STD( "  -a, --audio                       Get supported audio information" );
+   LOG_STD( "  -d, --dumpedid <filename>         Dump EDID information to file" );
+   LOG_STD( "  -j, --json                        Use JSON format for --modes output" );
+   LOG_STD( "  -n, --name                        Print the device ID from EDID" );
+   LOG_STD( "  -h, --help                        Print this information" );
+}
+
+static void create_optstring( char *optstring )
+{
+   char *short_opts = optstring;
+   struct option *option;
+
+   // Figure out the short options from our options structure
+   for ( option = long_opts; option->name != NULL; option++ )
+   {
+      if (( option->flag == NULL ) && ( option->val < OPT_FIRST_LONG_OPT ))
+      {
+         *short_opts++ = (char)option->val;
+
+         if ( option->has_arg != no_argument )
+         {
+            *short_opts++ = ':';
+         }
+
+         // Optional arguments require two ':'
+         if ( option->has_arg == optional_argument )
+         {
+            *short_opts++ = ':';
+         }
+      }
+   }
+   *short_opts++ = '\0';
+}
+
+/* Return the string presentation of aspect ratio */
+static const char *aspect_ratio_str(HDMI_ASPECT_T aspect_ratio) {
+   switch(aspect_ratio) {
+   case HDMI_ASPECT_4_3:
+      return "4:3";
+   case HDMI_ASPECT_14_9:
+      return "14:9";
+   case HDMI_ASPECT_16_9:
+      return "16:9";
+   case HDMI_ASPECT_5_4:
+      return "5:4";
+   case HDMI_ASPECT_16_10:
+      return "16:10";
+   case HDMI_ASPECT_15_9:
+      return "15:9";
+   case HDMI_ASPECT_64_27:
+      return "64:27 (21:9)";
+   default:
+      return "unknown AR";
+   }
+}
+
+/* Return the string presentation of aspect ratio */
+static const char *aspect_ratio_sd_str(SDTV_ASPECT_T aspect_ratio) {
+   switch(aspect_ratio) {
+   case SDTV_ASPECT_4_3:
+      return "4:3";
+   case SDTV_ASPECT_14_9:
+      return "14:9";
+   case SDTV_ASPECT_16_9:
+      return "16:9";
+   default:
+      return "unknown AR";
+   }
+}
+
+//Print a string and update the offset into the status buffer
+//Return non-zero if string is truncated, zero otherwise
+static int status_sprintf(char *buf, size_t buflen, size_t *offset, const char *fmt, ...) {
+   int ret;
+   size_t length;
+   va_list ap;
+   va_start(ap,fmt);
+   length = (size_t) vcos_safe_vsprintf(buf, buflen, *offset, fmt, ap);
+   va_end(ap);
+   if(length >= buflen) {
+      ret = -1;
+      *offset = buflen;
+   } else {
+      ret = 0;
+      *offset = length;
+   }
+   return ret;
+}
+
+/* Return the string representation of 3D support bit mask */
+static const char* threed_str(uint32_t struct_3d_mask, int json_output) {
+#define THREE_D_FORMAT_NAME_MAX_LEN 10 //Including the separator
+   static const char* three_d_format_names[] = { //See HDMI_3D_STRUCT_T bit fields
+      "FP", "F-Alt", "L-Alt", "SbS-Full",
+      "Ldep", "Ldep+Gfx", "TopBot", "SbS-HH",
+      "SbS-OLOR", "SbS-OLER", "SbS-ELOR", "SbS-ELER"
+   };
+   //Longest possible string is the concatenation of all of the above
+   static char struct_desc[vcos_countof(three_d_format_names)*THREE_D_FORMAT_NAME_MAX_LEN+4] = {0};
+   const size_t struct_desc_length = sizeof(struct_desc);
+   size_t j, added = 0, offset = 0;
+   int tmp = 0;
+   if(!json_output)
+      tmp = status_sprintf(struct_desc, struct_desc_length, &offset, "3D:");
+   if(struct_3d_mask) {
+      for(j = 0; !tmp && j < vcos_countof(three_d_format_names); j++) {
+         if(struct_3d_mask & (1 << j)) {
+            tmp = status_sprintf(struct_desc, struct_desc_length, &offset, json_output ? "\"%s\"," : "%s|", three_d_format_names[j]);
+            added++;
+         }
+      }
+      if(!tmp && added > 0)
+         struct_desc[strlen(struct_desc)-1] = '\0'; //Get rid of final "|"
+   } else if(!tmp && !added && !json_output) {
+      status_sprintf(struct_desc, struct_desc_length, &offset, "none");
+   }
+
+   return struct_desc;
+}
+
+static int get_modes( HDMI_RES_GROUP_T group, int json_output)
+{
+   static TV_SUPPORTED_MODE_T supported_modes[MAX_MODE_ID];
+   HDMI_RES_GROUP_T preferred_group;
+   uint32_t preferred_mode;
+   int num_modes;
+   int i;
+
+   vcos_assert(( group == HDMI_RES_GROUP_CEA ) ||
+               ( group == HDMI_RES_GROUP_DMT ));
+
+   memset(supported_modes, 0, sizeof(supported_modes));
+
+   num_modes = vc_tv_hdmi_get_supported_modes( group, supported_modes,
+                                               vcos_countof(supported_modes),
+                                               &preferred_group,
+                                               &preferred_mode );
+   if ( num_modes < 0 )
+   {
+      LOG_ERR( "Failed to get modes" );
+      return -1;
+   }
+
+   if (json_output)
+   {
+      LOG_STD( "[" );
+   }
+   else
+   {
+      LOG_STD( "Group %s has %u modes:",
+               HDMI_RES_GROUP_NAME(group), num_modes );
+   }
+
+   for ( i = 0; i < num_modes; i++ )
+   {
+      char p[8] = {0};
+      if( supported_modes[i].pixel_rep )
+         vcos_safe_sprintf(p, sizeof(p)-1, 0, "x%d ", supported_modes[i].pixel_rep);
+
+      if (json_output)
+      {
+         LOG_STD( "{ \"code\":%u, \"width\":%u, \"height\":%u, \"rate\":%u, \"aspect_ratio\":\"%s\", \"scan\":\"%s\", \"3d_modes\":[%s] }%s",
+                  supported_modes[i].code, supported_modes[i].width,
+                  supported_modes[i].height, supported_modes[i].frame_rate,
+                  aspect_ratio_str(supported_modes[i].aspect_ratio),
+                  supported_modes[i].scan_mode ? "i" : "p",
+                  supported_modes[i].struct_3d_mask ? threed_str(supported_modes[i].struct_3d_mask, 1) : "",
+                  (i+1 < num_modes) ? "," : "");
+      }
+      else
+      {
+         int preferred = supported_modes[i].group == preferred_group && supported_modes[i].code == preferred_mode;
+         LOG_STD( "%s mode %u: %ux%u @ %uHz %s, clock:%uMHz %s%s %s",
+                  preferred ? "  (prefer)" : supported_modes[i].native ? "  (native)" : "          ",
+                  supported_modes[i].code, supported_modes[i].width,
+                  supported_modes[i].height, supported_modes[i].frame_rate,
+                  aspect_ratio_str(supported_modes[i].aspect_ratio),
+                  supported_modes[i].pixel_freq / 1000000U, p,
+                  supported_modes[i].scan_mode ? "interlaced" : "progressive",
+                  supported_modes[i].struct_3d_mask ? threed_str(supported_modes[i].struct_3d_mask, 0) : "");
+      }
+   }
+
+   if (json_output)
+   {
+      LOG_STD( "]" );
+   }
+   return 0;
+}
+
+static const char *status_mode( TV_DISPLAY_STATE_T *tvstate ) {
+   static char mode_str[MAX_STATUS_STR_LENGTH] = {0};
+   int tmp = 0;
+   size_t offset = 0;
+   if(tvstate->state & ( VC_HDMI_HDMI | VC_HDMI_DVI )) {
+      //HDMI or DVI on
+      tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, (tvstate->state & VC_HDMI_HDMI) ? "HDMI" : "DVI");
+      if(!tmp) {
+         //We should still have space at this point
+         switch(tvstate->display.hdmi.group) {
+         case HDMI_RES_GROUP_CEA:
+            tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " CEA (%d)", tvstate->display.hdmi.mode); break;
+         case HDMI_RES_GROUP_DMT:
+            tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " DMT (%d)", tvstate->display.hdmi.mode); break;
+         default: break;
+         }
+      }
+      if(!tmp && tvstate->display.hdmi.format_3d) {
+         switch(tvstate->display.hdmi.format_3d) {
+         case HDMI_3D_FORMAT_SBS_HALF:
+            tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " 3D SbS"); break;
+         case HDMI_3D_FORMAT_TB_HALF:
+            tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " 3D T&B"); break;
+         case HDMI_3D_FORMAT_FRAME_PACKING:
+            tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " 3D FP"); break;
+         case HDMI_3D_FORMAT_FRAME_SEQUENTIAL:
+            tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " 3D FS"); break;
+         default: break;
+         }
+      }
+      if(!tmp) {
+         if (tvstate->state & VC_HDMI_HDMI)
+            //Only HDMI mode can signal pixel encoding in AVI infoframe
+            switch(tvstate->display.hdmi.pixel_encoding) {
+            case HDMI_PIXEL_ENCODING_RGB_LIMITED:
+               tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " RGB lim"); break;
+            case HDMI_PIXEL_ENCODING_RGB_FULL:
+               tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " RGB full"); break;
+            case HDMI_PIXEL_ENCODING_YCbCr444_LIMITED:
+               tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " YCbCr444 lim"); break;
+            case HDMI_PIXEL_ENCODING_YCbCr444_FULL:
+               tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " YCbCr444 full"); break;
+            case HDMI_PIXEL_ENCODING_YCbCr422_LIMITED:
+               tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " YCbCr422 lim"); break;
+            case HDMI_PIXEL_ENCODING_YCbCr422_FULL:
+               tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " YCbCr422 full"); break;
+            default: break;
+            }
+         else
+            //DVI will always be RGB, and CEA mode will have limited range, DMT mode full range
+            tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset,
+                        (tvstate->display.hdmi.group == HDMI_RES_GROUP_CEA)?
+                        " RGB lim" : " RGB full");
+      }
+
+      //This is the format's aspect ratio, not the one
+      //signaled in the AVI infoframe
+      if(!tmp)
+         tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " %s", aspect_ratio_str(tvstate->display.hdmi.aspect_ratio));
+
+      if(!tmp &&tvstate->display.hdmi.pixel_rep) {
+         tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " x%d", tvstate->display.hdmi.pixel_rep);
+      }
+      if(!tmp && tvstate->state & VC_HDMI_HDCP_AUTH) {
+         tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " HDCP");
+      }
+   } else if(tvstate->state & ( VC_SDTV_NTSC | VC_SDTV_PAL )) {
+      if(!tmp) {
+         if(tvstate->state & VC_SDTV_NTSC) {
+            tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, "NTSC");
+         } else {
+            tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, "PAL");
+         }
+      }
+      if(!tmp && tvstate->display.sdtv.cp_mode) {
+         switch(tvstate->display.sdtv.cp_mode) {
+         case SDTV_CP_MACROVISION_TYPE1:
+            tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " Macrovision type 1"); break;
+         case SDTV_CP_MACROVISION_TYPE2:
+            tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " Macrovision type 2"); break;
+         case SDTV_CP_MACROVISION_TYPE3:
+            tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " Macrovision type 3"); break;
+         case SDTV_CP_MACROVISION_TEST1:
+            tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " Macrovision test 1"); break;
+         case SDTV_CP_MACROVISION_TEST2:
+            tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " Macrovision test 2"); break;
+         case SDTV_CP_CGMS_COPYFREE:
+            tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " CGMS copy free"); break;
+         case SDTV_CP_CGMS_COPYNOMORE:
+            tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " CGMS copy no more"); break;
+         case SDTV_CP_CGMS_COPYONCE:
+            tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " CGMS copy once"); break;
+         case SDTV_CP_CGMS_COPYNEVER:
+            tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " CGMS copy never"); break;
+         case SDTV_CP_WSS_COPYFREE:
+            tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " WSS copy free"); break;
+         case SDTV_CP_WSS_COPYRIGHT_COPYFREE:
+            tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " WSS (c) copy free"); break;
+         case SDTV_CP_WSS_NOCOPY:
+            tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " WSS no copy"); break;
+         case SDTV_CP_WSS_COPYRIGHT_NOCOPY:
+            tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " WSS (c) no copy"); break;
+         default: break;
+         }
+      }
+      //This is the format's aspect ratio
+      tmp = status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, " %s", aspect_ratio_sd_str(tvstate->display.sdtv.display_options.aspect));
+   } else if (tvstate->state & VC_LCD_ATTACHED_DEFAULT) {
+      status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, "LCD");
+   } else {
+      status_sprintf(mode_str, MAX_STATUS_STR_LENGTH, &offset, "TV is off");
+   }
+
+   return mode_str;
+}
+
+static int get_status( void )
+{
+   TV_DISPLAY_STATE_T tvstate;
+   if( vc_tv_get_display_state( &tvstate ) == 0) {
+      //The width/height parameters are in the same position in the union
+      //for HDMI and SDTV
+      HDMI_PROPERTY_PARAM_T property;
+      property.property = HDMI_PROPERTY_PIXEL_CLOCK_TYPE;
+      vc_tv_hdmi_get_property(&property);
+      float frame_rate = property.param1 == HDMI_PIXEL_CLOCK_TYPE_NTSC ? tvstate.display.hdmi.frame_rate * (1000.0f/1001.0f) : tvstate.display.hdmi.frame_rate;
+
+      if(tvstate.display.hdmi.width && tvstate.display.hdmi.height) {
+         LOG_STD( "state 0x%x [%s], %ux%u @ %.2fHz, %s", tvstate.state,
+                  status_mode(&tvstate),
+                  tvstate.display.hdmi.width, tvstate.display.hdmi.height,
+                  frame_rate,
+                  tvstate.display.hdmi.scan_mode ? "interlaced" : "progressive" );
+      } else {
+         LOG_STD( "state 0x%x [%s]", tvstate.state, status_mode(&tvstate));
+      }
+   } else {
+      LOG_STD( "Error getting current display state");
+   }
+  return 0;
+}
+
+static int get_audiosup( void )
+{
+  uint8_t sample_rates[] = {32, 44, 48, 88, 96, 176, 192};
+  uint8_t sample_sizes[] = {16, 20, 24};
+  const char *formats[] = {"Reserved", "PCM", "AC3", "MPEG1", "MP3", "MPEG2", "AAC", "DTS", "ATRAC", "DSD", "EAC3", "DTS_HD", "MLP", "DST", "WMAPRO", "Extended"};
+  int i, j, k;
+  for (k=EDID_AudioFormat_ePCM; k<EDID_AudioFormat_eMaxCount; k++) {
+    int num_channels = 0, max_sample_rate = 0, max_sample_size = 0;
+    for (i=1; i<=8; i++) {
+      if (vc_tv_hdmi_audio_supported(k, i, EDID_AudioSampleRate_e44KHz, EDID_AudioSampleSize_16bit ) == 0)
+        num_channels = i;
+    }
+    for (i=0, j=EDID_AudioSampleRate_e32KHz; j<=EDID_AudioSampleRate_e192KHz; i++, j<<=1) {
+      if (vc_tv_hdmi_audio_supported(k, 1, j, EDID_AudioSampleSize_16bit ) == 0)
+        max_sample_rate = i;
+    }
+    if (k==EDID_AudioFormat_ePCM) {
+      for (i=0, j=EDID_AudioSampleSize_16bit; j<=EDID_AudioSampleSize_24bit; i++, j<<=1) {
+        if (vc_tv_hdmi_audio_supported(k, 1, EDID_AudioSampleRate_e44KHz, j ) == 0)
+          max_sample_size = i;
+      }
+      if (num_channels>0)
+        LOG_STD("%8s supported: Max channels: %d, Max samplerate:%4dkHz, Max samplesize %2d bits.", formats[k], num_channels, sample_rates[max_sample_rate], sample_sizes[max_sample_size]);
+    } else {
+      for (i=0; i<256; i++) {
+        if (vc_tv_hdmi_audio_supported(k, 1, EDID_AudioSampleRate_e44KHz, i ) == 0)
+          max_sample_size = i;
+      }
+      if (num_channels>0)
+        LOG_STD("%8s supported: Max channels: %d, Max samplerate:%4dkHz, Max rate %4d kb/s.", formats[k], num_channels, sample_rates[max_sample_rate], 8*max_sample_size);
+    }
+  }
+  return 0;
+}
+
+static int dump_edid( const char *filename )
+{
+   uint8_t buffer[128];
+   size_t written = 0, offset = 0;
+   int i, extensions = 0;
+   FILE *fp = NULL;
+   int siz = vc_tv_hdmi_ddc_read(offset, sizeof (buffer), buffer);
+   offset += sizeof( buffer);
+   /* First block always exist */
+   if (siz == sizeof(buffer) && (fp = fopen(filename, "wb")) != NULL) {
+      written += fwrite(buffer, 1, sizeof buffer, fp);
+      extensions = buffer[0x7e]; /* This tells you how many more blocks to read */
+      for(i = 0; i < extensions; i++, offset += sizeof( buffer)) {
+         siz = vc_tv_hdmi_ddc_read(offset, sizeof( buffer), buffer);
+         if(siz == sizeof(buffer)) {
+            written += fwrite(buffer, 1, sizeof (buffer), fp);
+         } else {
+            break;
+         }
+      }
+   } 
+   if (fp)
+      fclose(fp);
+   if(written) {
+      LOG_STD( "Written %d bytes to %s", written, filename);
+   } else {
+      LOG_STD( "Nothing written!");
+   }
+   return written < sizeof(buffer);
+}
+
+static int show_info( int on )
+{
+   return vc_tv_show_info(on);
+}
+
+static void control_c( int signum )
+{
+    (void)signum;
+
+    LOG_STD( "Shutting down..." );
+
+    vcos_event_signal( &quit_event );
+}
+
+static void tvservice_callback( void *callback_data,
+                                uint32_t reason,
+                                uint32_t param1,
+                                uint32_t param2 )
+{
+   (void)callback_data;
+   (void)param1;
+   (void)param2;
+
+   switch ( reason )
+   {
+      case VC_HDMI_UNPLUGGED:
+      {
+         LOG_INFO( "HDMI cable is unplugged" );
+         break;
+      }
+      case VC_HDMI_ATTACHED:
+      {
+         LOG_INFO( "HDMI is attached" );
+         break;
+      }
+      case VC_HDMI_DVI:
+      {
+         LOG_INFO( "HDMI in DVI mode" );
+         break;
+      }
+      case VC_HDMI_HDMI:
+      {
+         LOG_INFO( "HDMI in HDMI mode" );
+         break;
+      }
+      case VC_HDMI_HDCP_UNAUTH:
+      {
+         LOG_INFO( "HDCP authentication is broken" );
+         break;
+      }
+      case VC_HDMI_HDCP_AUTH:
+      {
+         LOG_INFO( "HDCP is active" );
+         break;
+      }
+      case VC_HDMI_HDCP_KEY_DOWNLOAD:
+      {
+         LOG_INFO( "HDCP key download" );
+         break;
+      }
+      case VC_HDMI_HDCP_SRM_DOWNLOAD:
+      {
+         LOG_INFO( "HDCP revocation list download" );
+         break;
+      }
+      default:
+      {
+         // Ignore all other reasons
+         LOG_INFO( "Callback with reason %d", reason );
+         break;
+      }
+   }
+}
+
+static int start_monitor( void )
+{
+   if ( vcos_event_create( &quit_event, "tvservice" ) != VCOS_SUCCESS )
+   {
+      LOG_ERR( "Failed to create quit event" );
+
+      return -1;
+   }
+
+   // Handle the INT and TERM signals so we can quit
+   signal( SIGINT, control_c );
+   signal( SIGTERM, control_c );
+
+   vc_tv_register_callback( &tvservice_callback, NULL );
+
+   return 0;
+}
+
+static int power_on_preferred( void )
+{
+   int ret;
+
+   LOG_STD( "Powering on HDMI with preferred settings" );
+
+   ret = vc_tv_hdmi_power_on_preferred();
+   if ( ret != 0 )
+   {
+      LOG_ERR( "Failed to power on HDMI with preferred settings" );
+   }
+
+   return ret;
+}
+
+static int power_on_explicit( HDMI_RES_GROUP_T group,
+                              uint32_t mode, uint32_t drive )
+{
+   int ret;
+
+   LOG_STD( "Powering on HDMI with explicit settings (%s mode %u)",
+            group == HDMI_RES_GROUP_CEA ? "CEA" : group == HDMI_RES_GROUP_DMT ? "DMT" : "CUSTOM", mode );
+
+   ret = vc_tv_hdmi_power_on_explicit( drive, group, mode );
+   if ( ret != 0 )
+   {
+      LOG_ERR( "Failed to power on HDMI with explicit settings (%s mode %u)",
+               group == HDMI_RES_GROUP_CEA ? "CEA" : group == HDMI_RES_GROUP_DMT ? "DMT" : "CUSTOM", mode );
+   }
+
+   return ret;
+}
+
+static int set_property(HDMI_PROPERTY_T prop, uint32_t param1, uint32_t param2)
+{
+   int ret;
+   HDMI_PROPERTY_PARAM_T property;
+   property.property = prop;
+   property.param1 = param1;
+   property.param2 = param2;
+   //LOG_DBG( "Setting property %d with params %d, %d", prop, param1, param2);
+   ret = vc_tv_hdmi_set_property(&property);
+   if(ret != 0)
+   {
+      LOG_ERR( "Failed to set property %d", prop);
+   }
+   return ret;
+}
+
+static int power_on_sdtv( SDTV_MODE_T mode,
+                              SDTV_ASPECT_T aspect, int sdtv_progressive )
+{
+   int ret;
+   SDTV_OPTIONS_T options;
+   memset(&options, 0, sizeof options);
+   options.aspect = aspect;
+   if (sdtv_progressive)
+      mode |= SDTV_MODE_PROGRESSIVE;
+   LOG_STD( "Powering on SDTV with explicit settings (mode:%d aspect:%d)",
+            mode, aspect );
+
+   ret = vc_tv_sdtv_power_on(mode, &options);
+   if ( ret != 0 )
+   {
+      LOG_ERR( "Failed to power on SDTV with explicit settings (mode:%d aspect:%d)",
+               mode, aspect );
+   }
+
+   return ret;
+}
+
+static int power_off( void )
+{
+   int ret;
+
+   LOG_STD( "Powering off HDMI");
+
+   ret = vc_tv_power_off();
+   if ( ret != 0 )
+   {
+      LOG_ERR( "Failed to power off HDMI" );
+   }
+
+   return ret;
+}
+
+// ---- Public Functions -----------------------------------------------------
+
+int main( int argc, char **argv )
+{
+   int32_t ret;
+   char optstring[OPTSTRING_LEN];
+   int  opt;
+   int  opt_preferred = 0;
+   int  opt_explicit = 0;
+   int  opt_ntsc = 0;
+   int  opt_sdtvon = 0;
+   int  opt_off = 0;
+   int  opt_modes = 0;
+   int  opt_monitor = 0;
+   int  opt_status = 0;
+   int  opt_audiosup = 0;
+   int  opt_dumpedid = 0;
+   int  opt_showinfo = 0;
+   int  opt_3d = 0;
+   int  opt_json = 0;
+   int  opt_name = 0;
+
+   char *dumpedid_filename = NULL;
+   VCHI_INSTANCE_T    vchi_instance;
+   VCHI_CONNECTION_T *vchi_connection;
+   HDMI_RES_GROUP_T power_on_explicit_group = HDMI_RES_GROUP_INVALID;
+   uint32_t         power_on_explicit_mode;
+   uint32_t         power_on_explicit_drive = HDMI_MODE_HDMI;
+   HDMI_RES_GROUP_T get_modes_group = HDMI_RES_GROUP_INVALID;
+   SDTV_MODE_T sdtvon_mode = SDTV_MODE_NTSC;
+   SDTV_ASPECT_T sdtvon_aspect = SDTV_ASPECT_UNKNOWN;
+   int sdtvon_progressive = 0;
+
+   // Initialize VCOS
+   vcos_init();
+
+   // Create the option string that we will be using to parse the arguments
+   create_optstring( optstring );
+
+   // Parse the command line arguments
+   while (( opt = getopt_long_only( argc, argv, optstring, long_opts,
+                                    NULL )) != -1 )
+   {
+      switch ( opt )
+      {
+         case 0:
+         {
+            // getopt_long returns 0 for entries where flag is non-NULL
+            break;
+         }
+         case OPT_PREFERRED:
+         {
+            opt_preferred = 1;
+            break;
+         }
+         case OPT_EXPLICIT:
+         {
+            char group_str[32], drive_str[32];
+
+            /* coverity[secure_coding] String length specified, so can't overflow */
+            int s = sscanf( optarg, "%31s %u %31s", group_str, &power_on_explicit_mode, drive_str );
+            if ( s != 2 && s != 3 )
+            {
+               LOG_ERR( "Invalid arguments '%s'", optarg );
+               goto err_out;
+            }
+
+            // Check the group first
+            if ( vcos_strcasecmp( "CEA", group_str ) == 0 )
+            {
+               power_on_explicit_group = HDMI_RES_GROUP_CEA;
+            }
+            else if ( vcos_strcasecmp( "DMT", group_str ) == 0 )
+            {
+               power_on_explicit_group = HDMI_RES_GROUP_DMT;
+            }
+            else if ( vcos_strcasecmp( "CEA_3D", group_str ) == 0  ||
+                      vcos_strcasecmp( "CEA_3D_SBS", group_str ) == 0)
+            {
+               power_on_explicit_group = HDMI_RES_GROUP_CEA;
+               opt_3d = 1;
+            }
+            else if ( vcos_strcasecmp( "CEA_3D_TB", group_str ) == 0 )
+            {
+               power_on_explicit_group = HDMI_RES_GROUP_CEA;
+               opt_3d = 2;
+            }
+            else if ( vcos_strcasecmp( "CEA_3D_FP", group_str ) == 0 )
+            {
+               power_on_explicit_group = HDMI_RES_GROUP_CEA;
+               opt_3d = 3;
+            }
+            else if ( vcos_strcasecmp( "CEA_3D_FS", group_str ) == 0 )
+            {
+               power_on_explicit_group = HDMI_RES_GROUP_CEA;
+               opt_3d = 4;
+            }
+            else
+            {
+               LOG_ERR( "Invalid group '%s'", group_str );
+               goto err_out;
+            }
+            if (s==3)
+            {
+               if (vcos_strcasecmp( "HDMI", drive_str ) == 0 )
+               {
+                  power_on_explicit_drive = HDMI_MODE_HDMI;
+               }
+               else if (vcos_strcasecmp( "DVI", drive_str ) == 0 )
+               {
+                  power_on_explicit_drive = HDMI_MODE_DVI;
+               }
+               else
+               {
+                  LOG_ERR( "Invalid drive '%s'", drive_str );
+                  goto err_out;
+               }
+            }
+            // Then check if mode is a sane number
+            if ( power_on_explicit_mode > MAX_MODE_ID )
+            {
+               LOG_ERR( "Invalid mode '%u'", power_on_explicit_mode );
+               goto err_out;
+            }
+
+            opt_explicit = 1;
+            break;
+         }
+         case OPT_NTSC:
+         {
+            opt_ntsc = 1;
+            break;
+         }
+         case OPT_SDTVON:
+         {
+            char mode_str[32], aspect_str[32], progressive_str[32];
+            int s = sscanf( optarg, "%s %s %s", mode_str, aspect_str, progressive_str );
+            if ( s != 2 && s != 3 )
+            {
+               LOG_ERR( "Invalid arguments '%s'", optarg );
+               goto err_out;
+            }
+
+            // Check the group first
+            if ( vcos_strcasecmp( "NTSC", mode_str ) == 0 )
+            {
+               sdtvon_mode = SDTV_MODE_NTSC;
+            }
+            else if ( vcos_strcasecmp( "NTSC_J", mode_str ) == 0 )
+            {
+               sdtvon_mode = SDTV_MODE_NTSC_J;
+            }
+            else if ( vcos_strcasecmp( "PAL", mode_str ) == 0 )
+            {
+               sdtvon_mode = SDTV_MODE_PAL;
+            }
+            else if ( vcos_strcasecmp( "PAL_M", mode_str ) == 0 )
+            {
+               sdtvon_mode = SDTV_MODE_PAL_M;
+            }
+            else
+            {
+               LOG_ERR( "Invalid mode '%s'", mode_str );
+               goto err_out;
+            }
+
+            if ( vcos_strcasecmp( "4:3", aspect_str ) == 0 )
+            {
+               sdtvon_aspect = SDTV_ASPECT_4_3;
+            }
+            else if ( vcos_strcasecmp( "14:9", aspect_str ) == 0 )
+            {
+               sdtvon_aspect = SDTV_ASPECT_14_9;
+            }
+            else if ( vcos_strcasecmp( "16:9", aspect_str ) == 0 )
+            {
+               sdtvon_aspect = SDTV_ASPECT_16_9;
+            }
+
+            if (s == 3 && vcos_strcasecmp( "P", progressive_str ) == 0 )
+            {
+              sdtvon_progressive = 1;
+            }
+            opt_sdtvon = 1;
+            break;
+         }
+         case OPT_OFF:
+         {
+            opt_off = 1;
+            break;
+         }
+         case OPT_MODES:
+         {
+            if ( vcos_strcasecmp( "CEA", optarg ) == 0 )
+            {
+               get_modes_group = HDMI_RES_GROUP_CEA;
+            }
+            else if ( vcos_strcasecmp( "DMT", optarg ) == 0 )
+            {
+               get_modes_group = HDMI_RES_GROUP_DMT;
+            }
+            else
+            {
+               LOG_ERR( "Invalid group '%s'", optarg );
+               goto err_out;
+            }
+
+            opt_modes = 1;
+            break;
+         }
+         case OPT_MONITOR:
+         {
+            opt_monitor = 1;
+            break;
+         }
+         case OPT_STATUS:
+         {
+            opt_status = 1;
+            break;
+         }
+         case OPT_AUDIOSUP:
+         {
+            opt_audiosup = 1;
+            break;
+         }
+         case OPT_DUMPEDID:
+         {
+            opt_dumpedid = 1;
+            dumpedid_filename = optarg;
+            break;
+         }
+         case OPT_SHOWINFO:
+         {
+            opt_showinfo = atoi(optarg)+1;
+            break;
+         }
+         case OPT_JSON:
+         {
+            opt_json = 1;
+            break;
+         }
+         case OPT_NAME:
+         {
+            opt_name = 1;
+            break;
+         }
+         default:
+         {
+            LOG_ERR( "Unrecognized option '%d'\n", opt );
+            goto err_usage;
+         }
+         case '?':
+         case OPT_HELP:
+         {
+            goto err_usage;
+         }
+      } // end switch
+   } // end while
+
+   argc -= optind;
+   argv += optind;
+
+   if (( optind == 1 ) || ( argc > 0 ))
+   {
+      if ( argc > 0 )
+      {
+         LOG_ERR( "Unrecognized argument -- '%s'", *argv );
+      }
+
+      goto err_usage;
+   }
+
+   if (( opt_preferred + opt_explicit + opt_sdtvon > 1 ))
+   {
+      LOG_ERR( "Conflicting power on options" );
+      goto err_usage;
+   }
+
+   if ((( opt_preferred == 1 ) || ( opt_explicit == 1 ) || ( opt_sdtvon == 1)) && ( opt_off == 1 ))
+   {
+      LOG_ERR( "Cannot power on and power off simultaneously" );
+      goto err_out;
+   }
+
+   // Initialize the VCHI connection
+   ret = vchi_initialise( &vchi_instance );
+   if ( ret != 0 )
+   {
+      LOG_ERR( "Failed to initialize VCHI (ret=%d)", ret );
+      goto err_out;
+   }
+
+   ret = vchi_connect( NULL, 0, vchi_instance );
+   if ( ret != 0)
+   {
+      LOG_ERR( "Failed to create VCHI connection (ret=%d)", ret );
+      goto err_out;
+   }
+
+//   LOG_INFO( "Starting tvservice" );
+
+   // Initialize the tvservice
+   vc_vchi_tv_init( vchi_instance, &vchi_connection, 1 );
+
+   if ( opt_monitor == 1 )
+   {
+      LOG_STD( "Starting to monitor for HDMI events" );
+
+      if ( start_monitor() != 0 )
+      {
+         goto err_stop_service;
+      }
+   }
+
+   if ( opt_modes == 1 )
+   {
+      if ( get_modes( get_modes_group, opt_json ) != 0 )
+      {
+         goto err_stop_service;
+      }
+   }
+
+   if ( opt_preferred == 1 )
+   {
+      if(set_property( HDMI_PROPERTY_3D_STRUCTURE, HDMI_3D_FORMAT_NONE, 0) != 0)
+      {
+         goto err_stop_service;
+      }
+      if ( power_on_preferred() != 0 )
+      {
+         goto err_stop_service;
+      }
+   }
+   else if ( opt_explicit == 1 )
+   {
+      //Distinguish between turning on 3D side by side and 3D top/bottom
+      if(opt_3d == 0 && set_property( HDMI_PROPERTY_3D_STRUCTURE, HDMI_3D_FORMAT_NONE, 0) != 0)
+      {
+         goto err_stop_service;
+      }
+      else if(opt_3d == 1 && set_property( HDMI_PROPERTY_3D_STRUCTURE, HDMI_3D_FORMAT_SBS_HALF, 0) != 0)
+      {
+         goto err_stop_service;
+      }
+      else if(opt_3d == 2 && set_property( HDMI_PROPERTY_3D_STRUCTURE, HDMI_3D_FORMAT_TB_HALF, 0) != 0)
+      {
+         goto err_stop_service;
+      }
+      else if(opt_3d == 3 && set_property( HDMI_PROPERTY_3D_STRUCTURE, HDMI_3D_FORMAT_FRAME_PACKING, 0) != 0)
+      {
+         goto err_stop_service;
+      }
+      else if(opt_3d == 4 && set_property( HDMI_PROPERTY_3D_STRUCTURE, HDMI_3D_FORMAT_FRAME_SEQUENTIAL, 0) != 0)
+      {
+         goto err_stop_service;
+      }
+      if (set_property( HDMI_PROPERTY_PIXEL_CLOCK_TYPE, opt_ntsc ? HDMI_PIXEL_CLOCK_TYPE_NTSC : HDMI_PIXEL_CLOCK_TYPE_PAL, 0) != 0)
+      {
+         goto err_stop_service;
+      }
+      if ( power_on_explicit( power_on_explicit_group,
+                              power_on_explicit_mode, power_on_explicit_drive ) != 0 )
+      {
+         goto err_stop_service;
+      }
+   }
+   else if ( opt_sdtvon == 1 )
+   {
+      if ( power_on_sdtv( sdtvon_mode,
+                              sdtvon_aspect, sdtvon_progressive ) != 0 )
+      {
+         goto err_stop_service;
+      }
+   }
+   else if (opt_off == 1 )
+   {
+      if ( power_off() != 0 )
+      {
+         goto err_stop_service;
+      }
+   }
+
+   if ( opt_status == 1 )
+   {
+      if ( get_status() != 0 )
+      {
+         goto err_stop_service;
+      }
+   }
+   
+   if ( opt_audiosup == 1 )
+   {
+      if ( get_audiosup() != 0 )
+      {
+         goto err_stop_service;
+      }
+   }
+   
+   if ( opt_dumpedid == 1 )
+   {
+      if ( dump_edid(dumpedid_filename) != 0 )
+      {
+         goto err_stop_service;
+      }
+   }
+
+   if ( opt_showinfo )
+   {
+      if ( show_info(opt_showinfo-1) != 0 )
+      {
+         goto err_stop_service;
+      }
+   }
+
+   if ( opt_name == 1 )
+   {
+      TV_DEVICE_ID_T id;
+      memset(&id, 0, sizeof(id));
+      if(vc_tv_get_device_id(&id) == 0) {
+         if(id.vendor[0] == '\0' || id.monitor_name[0] == '\0') {
+            LOG_ERR( "No device present" );
+         } else {
+            LOG_STD( "device_name=%s-%s", id.vendor, id.monitor_name);
+         }
+      } else {
+         LOG_ERR( "Failed to obtain device name" );
+      }
+   }
+
+   if ( opt_monitor == 1 )
+   {
+      // Wait until we get the signal to exit
+      vcos_event_wait( &quit_event );
+
+      vcos_event_delete( &quit_event );
+   }
+
+err_stop_service:
+//   LOG_INFO( "Stopping tvservice" );
+
+   // Stop the tvservice
+   vc_vchi_tv_stop();
+
+   // Disconnect the VCHI connection
+   vchi_disconnect( vchi_instance );
+
+   exit( 0 );
+
+err_usage:
+   show_usage();
+
+err_out:
+   exit( 1 );
+}
diff --git a/host_applications/linux/apps/vcmailbox/CMakeLists.txt b/host_applications/linux/apps/vcmailbox/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..016a4d9
--- /dev/null
@@ -0,0 +1,5 @@
+add_executable(vcmailbox vcmailbox.c)
+target_link_libraries(vcmailbox vchostif)
+
+install(TARGETS vcmailbox
+        RUNTIME DESTINATION bin)
diff --git a/host_applications/linux/apps/vcmailbox/vcmailbox.c b/host_applications/linux/apps/vcmailbox/vcmailbox.c
new file mode 100755 (executable)
index 0000000..9ce95f9
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+Copyright (c) 2015 Raspberry Pi (Trading) Ltd.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Utility for driving mailbox interface to VideoCore
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <assert.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>         /* ioctl */
+
+#define DEVICE_FILE_NAME "/dev/vcio"
+#define MAJOR_NUM 100
+#define IOCTL_MBOX_PROPERTY _IOWR(MAJOR_NUM, 0, char *)
+
+/*
+ * use ioctl to send mbox property message
+ */
+
+static int mbox_property(int file_desc, void *buf)
+{
+   int ret_val = ioctl(file_desc, IOCTL_MBOX_PROPERTY, buf);
+
+   if (ret_val < 0) {
+      printf("ioctl_set_msg failed:%d\n", ret_val);
+   }
+   return ret_val;
+}
+
+
+static int mbox_open()
+{
+   int file_desc;
+
+   // open a char device file used for communicating with kernel mbox driver
+   file_desc = open(DEVICE_FILE_NAME, 0);
+   if (file_desc < 0) {
+      printf("Can't open device file: %s\n", DEVICE_FILE_NAME);
+      printf("Try creating a device file with: sudo mknod %s c %d 0\n", DEVICE_FILE_NAME, MAJOR_NUM);
+      exit(-1);
+   }
+   return file_desc;
+}
+
+static void mbox_close(int file_desc) {
+  close(file_desc);
+}
+
+
+#define MAX_WORDS 256
+
+int main(int argc, char *argv[])
+{
+  int mb = mbox_open();
+  unsigned words[MAX_WORDS] = {};
+  int i;
+
+  if (argc < 2 || argc+1 >= MAX_WORDS)
+  {
+    printf("Usage %s [word0] [word1] ...\n", argv[0]);
+    return 1;
+  }
+
+  words[0] = (argc+2) * sizeof words[0];
+  words[1] = 0; // process request
+  for (i=1; i<argc; i++)
+    words[i+1] = strtoul(argv[i], 0, 0);
+
+  words[argc+1] = 0; // end tag
+
+  int s = mbox_property(mb, words);
+
+  mbox_close(mb);
+
+  for (i=0; i<argc+2; i++)
+     printf("0x%08x ", words[i]);
+  printf("\n");
+  return s;
+}
diff --git a/host_applications/linux/kernel_headers/vmcs_sm_ioctl.h b/host_applications/linux/kernel_headers/vmcs_sm_ioctl.h
new file mode 100755 (executable)
index 0000000..7cd8c2b
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined(__VMCS_SM_IOCTL_H__INCLUDED__)
+#define __VMCS_SM_IOCTL_H__INCLUDED__
+
+/* ---- Include Files ---------------------------------------------------- */
+
+#if defined(__KERNEL__)
+#include <linux/types.h>       /* Needed for standard types */
+#else
+#include <stdint.h>
+#endif
+
+#include <linux/ioctl.h>
+
+/* ---- Constants and Types ---------------------------------------------- */
+
+#define VMCS_SM_RESOURCE_NAME               32
+#define VMCS_SM_RESOURCE_NAME_DEFAULT       "sm-host-resource"
+
+/* Type define used to create unique IOCTL number */
+#define VMCS_SM_MAGIC_TYPE                  'I'
+
+/* IOCTL commands */
+enum vmcs_sm_cmd_e {
+       VMCS_SM_CMD_ALLOC = 0x5A,       /* Start at 0x5A arbitrarily */
+       VMCS_SM_CMD_ALLOC_SHARE,
+       VMCS_SM_CMD_LOCK,
+       VMCS_SM_CMD_LOCK_CACHE,
+       VMCS_SM_CMD_UNLOCK,
+       VMCS_SM_CMD_RESIZE,
+       VMCS_SM_CMD_UNMAP,
+       VMCS_SM_CMD_FREE,
+       VMCS_SM_CMD_FLUSH,
+       VMCS_SM_CMD_INVALID,
+
+       VMCS_SM_CMD_SIZE_USR_HANDLE,
+       VMCS_SM_CMD_CHK_USR_HANDLE,
+
+       VMCS_SM_CMD_MAPPED_USR_HANDLE,
+       VMCS_SM_CMD_MAPPED_USR_ADDRESS,
+       VMCS_SM_CMD_MAPPED_VC_HDL_FROM_ADDR,
+       VMCS_SM_CMD_MAPPED_VC_HDL_FROM_HDL,
+       VMCS_SM_CMD_MAPPED_VC_ADDR_FROM_HDL,
+
+       VMCS_SM_CMD_VC_WALK_ALLOC,
+       VMCS_SM_CMD_HOST_WALK_MAP,
+       VMCS_SM_CMD_HOST_WALK_PID_ALLOC,
+       VMCS_SM_CMD_HOST_WALK_PID_MAP,
+
+       VMCS_SM_CMD_CLEAN_INVALID,
+       VMCS_SM_CMD_CLEAN_INVALID2,
+
+       VMCS_SM_CMD_IMPORT_DMABUF,
+
+       VMCS_SM_CMD_LAST        /* Do no delete */
+};
+
+/* Cache type supported, conveniently matches the user space definition in
+** user-vcsm.h.
+*/
+enum vmcs_sm_cache_e {
+       VMCS_SM_CACHE_NONE,
+       VMCS_SM_CACHE_HOST,
+       VMCS_SM_CACHE_VC,
+       VMCS_SM_CACHE_BOTH,
+};
+
+/* IOCTL Data structures */
+struct vmcs_sm_ioctl_alloc {
+       /* user -> kernel */
+       unsigned int size;
+       unsigned int num;
+       enum vmcs_sm_cache_e cached;
+       char name[VMCS_SM_RESOURCE_NAME];
+
+       /* kernel -> user */
+       unsigned int handle;
+       /* unsigned int base_addr; */
+};
+
+struct vmcs_sm_ioctl_alloc_share {
+       /* user -> kernel */
+       unsigned int handle;
+       unsigned int size;
+};
+
+struct vmcs_sm_ioctl_free {
+       /* user -> kernel */
+       unsigned int handle;
+       /* unsigned int base_addr; */
+};
+
+struct vmcs_sm_ioctl_lock_unlock {
+       /* user -> kernel */
+       unsigned int handle;
+
+       /* kernel -> user */
+       unsigned int addr;
+};
+
+struct vmcs_sm_ioctl_lock_cache {
+       /* user -> kernel */
+       unsigned int handle;
+       enum vmcs_sm_cache_e cached;
+};
+
+struct vmcs_sm_ioctl_resize {
+       /* user -> kernel */
+       unsigned int handle;
+       unsigned int new_size;
+
+       /* kernel -> user */
+       unsigned int old_size;
+};
+
+struct vmcs_sm_ioctl_map {
+       /* user -> kernel */
+       /* and kernel -> user */
+       unsigned int pid;
+       unsigned int handle;
+       unsigned int addr;
+
+       /* kernel -> user */
+       unsigned int size;
+};
+
+struct vmcs_sm_ioctl_walk {
+       /* user -> kernel */
+       unsigned int pid;
+};
+
+struct vmcs_sm_ioctl_chk {
+       /* user -> kernel */
+       unsigned int handle;
+
+       /* kernel -> user */
+       unsigned int addr;
+       unsigned int size;
+       enum vmcs_sm_cache_e cache;
+};
+
+struct vmcs_sm_ioctl_size {
+       /* user -> kernel */
+       unsigned int handle;
+
+       /* kernel -> user */
+       unsigned int size;
+};
+
+struct vmcs_sm_ioctl_cache {
+       /* user -> kernel */
+       unsigned int handle;
+       unsigned int addr;
+       unsigned int size;
+};
+
+struct vmcs_sm_ioctl_clean_invalid {
+       /* user -> kernel */
+       struct {
+               unsigned int cmd;
+               unsigned int handle;
+               unsigned int addr;
+               unsigned int size;
+       } s[8];
+};
+
+struct vmcs_sm_ioctl_clean_invalid2 {
+       uint8_t op_count;
+       uint8_t zero[3];
+       struct vmcs_sm_ioctl_clean_invalid_block {
+               uint16_t invalidate_mode;
+               uint16_t block_count;
+               void *   start_address;
+               uint32_t block_size;
+               uint32_t inter_block_stride;
+       } s[0];
+};
+
+struct vmcs_sm_ioctl_import_dmabuf {
+       /* user -> kernel */
+       int dmabuf_fd;
+       enum vmcs_sm_cache_e cached;
+       char name[VMCS_SM_RESOURCE_NAME];
+
+       /* kernel -> user */
+       unsigned int handle;
+};
+
+/* IOCTL numbers */
+#define VMCS_SM_IOCTL_MEM_ALLOC\
+       _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_ALLOC,\
+        struct vmcs_sm_ioctl_alloc)
+#define VMCS_SM_IOCTL_MEM_ALLOC_SHARE\
+       _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_ALLOC_SHARE,\
+        struct vmcs_sm_ioctl_alloc_share)
+#define VMCS_SM_IOCTL_MEM_LOCK\
+       _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_LOCK,\
+        struct vmcs_sm_ioctl_lock_unlock)
+#define VMCS_SM_IOCTL_MEM_LOCK_CACHE\
+       _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_LOCK_CACHE,\
+        struct vmcs_sm_ioctl_lock_cache)
+#define VMCS_SM_IOCTL_MEM_UNLOCK\
+       _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_UNLOCK,\
+        struct vmcs_sm_ioctl_lock_unlock)
+#define VMCS_SM_IOCTL_MEM_RESIZE\
+       _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_RESIZE,\
+        struct vmcs_sm_ioctl_resize)
+#define VMCS_SM_IOCTL_MEM_FREE\
+       _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_FREE,\
+        struct vmcs_sm_ioctl_free)
+#define VMCS_SM_IOCTL_MEM_FLUSH\
+       _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_FLUSH,\
+        struct vmcs_sm_ioctl_cache)
+#define VMCS_SM_IOCTL_MEM_INVALID\
+       _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_INVALID,\
+        struct vmcs_sm_ioctl_cache)
+#define VMCS_SM_IOCTL_MEM_CLEAN_INVALID\
+       _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_CLEAN_INVALID,\
+        struct vmcs_sm_ioctl_clean_invalid)
+#define VMCS_SM_IOCTL_MEM_CLEAN_INVALID2\
+       _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_CLEAN_INVALID2,\
+        struct vmcs_sm_ioctl_clean_invalid2)
+
+#define VMCS_SM_IOCTL_SIZE_USR_HDL\
+       _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_SIZE_USR_HANDLE,\
+        struct vmcs_sm_ioctl_size)
+#define VMCS_SM_IOCTL_CHK_USR_HDL\
+       _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_CHK_USR_HANDLE,\
+        struct vmcs_sm_ioctl_chk)
+
+#define VMCS_SM_IOCTL_MAP_USR_HDL\
+       _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_USR_HANDLE,\
+        struct vmcs_sm_ioctl_map)
+#define VMCS_SM_IOCTL_MAP_USR_ADDRESS\
+       _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_USR_ADDRESS,\
+        struct vmcs_sm_ioctl_map)
+#define VMCS_SM_IOCTL_MAP_VC_HDL_FR_ADDR\
+       _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_VC_HDL_FROM_ADDR,\
+        struct vmcs_sm_ioctl_map)
+#define VMCS_SM_IOCTL_MAP_VC_HDL_FR_HDL\
+       _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_VC_HDL_FROM_HDL,\
+        struct vmcs_sm_ioctl_map)
+#define VMCS_SM_IOCTL_MAP_VC_ADDR_FR_HDL\
+       _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_MAPPED_VC_ADDR_FROM_HDL,\
+        struct vmcs_sm_ioctl_map)
+
+#define VMCS_SM_IOCTL_VC_WALK_ALLOC\
+       _IO(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_VC_WALK_ALLOC)
+#define VMCS_SM_IOCTL_HOST_WALK_MAP\
+       _IO(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_HOST_WALK_MAP)
+#define VMCS_SM_IOCTL_HOST_WALK_PID_ALLOC\
+       _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_HOST_WALK_PID_ALLOC,\
+        struct vmcs_sm_ioctl_walk)
+#define VMCS_SM_IOCTL_HOST_WALK_PID_MAP\
+       _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_HOST_WALK_PID_MAP,\
+        struct vmcs_sm_ioctl_walk)
+
+#define VMCS_SM_IOCTL_MEM_IMPORT_DMABUF\
+       _IOR(VMCS_SM_MAGIC_TYPE, VMCS_SM_CMD_IMPORT_DMABUF,\
+        struct vmcs_sm_ioctl_import_dmabuf)
+
+/* ---- Variable Externs ------------------------------------------------- */
+
+/* ---- Function Prototypes ---------------------------------------------- */
+
+#endif /* __VMCS_SM_IOCTL_H__INCLUDED__ */
diff --git a/host_applications/linux/libs/bcm_host/CMakeLists.txt b/host_applications/linux/libs/bcm_host/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..a863cb6
--- /dev/null
@@ -0,0 +1,25 @@
+
+if (WIN32)
+   set(VCOS_PLATFORM win32)
+else ()
+   set(VCOS_PLATFORM pthreads)
+   add_definitions(-Wall -Werror)
+endif ()
+
+# set this as we want all the source of vchostif to be available in libbcm_host
+set (CMAKE_SHARED_LINKER_FLAGS "-u vc_gpuserv_init ${CMAKE_SHARED_LINKER_FLAGS}")
+
+include_directories( ../../../.. 
+                    ../../../../interface/vcos/${VCOS_PLATFORM}
+                    ../../../../host_support/linux/added/include
+                    ../../../../host_applications/vmcs/test_apps/iltest
+                     ../../../../host_applications/framework/common )
+
+add_library(bcm_host ${SHARED} bcm_host.c 
+       ../../../../interface/vmcs_host/linux/vcfilesys.c 
+       ../../../../interface/vmcs_host/linux/vcfiled/vcfiled_check.c)
+
+target_link_libraries(bcm_host vcos vchostif)
+
+install(TARGETS bcm_host DESTINATION lib)
+
diff --git a/host_applications/linux/libs/bcm_host/bcm_host.c b/host_applications/linux/libs/bcm_host/bcm_host.c
new file mode 100755 (executable)
index 0000000..d8e82aa
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include "interface/vmcs_host/vc_dispmanx.h"
+#include "interface/vmcs_host/vc_vchi_gencmd.h"
+#include "interface/vmcs_host/vc_vchi_bufman.h"
+#include "interface/vmcs_host/vc_tvservice.h"
+#include "interface/vmcs_host/vc_cecservice.h"
+#include "interface/vchiq_arm/vchiq_if.h"
+
+static VCHI_INSTANCE_T global_initialise_instance;
+static VCHI_CONNECTION_T *global_connection;
+
+int32_t graphics_get_display_size( const uint16_t display_number,
+                                                    uint32_t *width,
+                                                    uint32_t *height)
+{
+   DISPMANX_DISPLAY_HANDLE_T display_handle = 0;
+   DISPMANX_MODEINFO_T mode_info;
+   int32_t success = -1;
+
+   // Display must be opened first.
+   display_handle = vc_dispmanx_display_open(display_number);
+
+   if (display_handle) {
+      success = vc_dispmanx_display_get_info(display_handle, &mode_info);
+         
+      if( success >= 0 )
+      {
+         if( NULL != width )
+         {
+            *width = mode_info.width;
+         }
+         
+         if( NULL != height )
+         {
+            *height = mode_info.height;
+         }
+      }
+      vc_dispmanx_display_close(display_handle);
+      display_handle = 0;
+   }
+
+   return success;
+}
+
+void host_app_message_handler(void)
+{
+   printf("host_app_message_handler\n");
+}
+
+void vc_host_get_vchi_state(VCHI_INSTANCE_T *initialise_instance, VCHI_CONNECTION_T **connection)
+{
+   if (initialise_instance) *initialise_instance = global_initialise_instance;
+   if (connection) *connection = global_connection;
+}
+
+void bcm_host_init(void)
+{
+   VCHIQ_INSTANCE_T vchiq_instance;
+   static int initted;
+   int success = -1;
+   char response[ 128 ];
+   
+   if (initted)
+       return;
+   initted = 1;
+   vcos_init();
+
+   if (vchiq_initialise(&vchiq_instance) != VCHIQ_SUCCESS)
+   {
+      printf("* failed to open vchiq instance\n");
+      exit(-1);
+   }
+
+   vcos_log("vchi_initialise");
+   success = vchi_initialise( &global_initialise_instance);
+   vcos_assert(success == 0);
+   vchiq_instance = (VCHIQ_INSTANCE_T)global_initialise_instance;
+
+   global_connection = vchi_create_connection(single_get_func_table(),
+                                              vchi_mphi_message_driver_func_table());
+
+   vcos_log("vchi_connect");
+   vchi_connect(&global_connection, 1, global_initialise_instance);
+  
+   vc_vchi_gencmd_init (global_initialise_instance, &global_connection, 1);
+   vc_vchi_dispmanx_init (global_initialise_instance, &global_connection, 1);
+   vc_vchi_tv_init (global_initialise_instance, &global_connection, 1);
+   vc_vchi_cec_init (global_initialise_instance, &global_connection, 1);
+   //vc_vchi_bufman_init (global_initialise_instance, &global_connection, 1);
+
+   if ( success == 0 )
+   {
+      success = vc_gencmd( response, sizeof(response), "set_vll_dir /sd/vlls" );
+      vcos_assert( success == 0 );
+   }
+}
+
+void bcm_host_deinit(void)
+{
+}
+
+// Fix linking problems. These are referenced by libs, but shouldn't be called
+void wfc_stream_await_buffer(void * stream)
+{
+   vcos_assert(0);
+}
+
+static unsigned get_dt_ranges(const char *filename, unsigned offset)
+{
+   unsigned address = ~0;
+   FILE *fp = fopen(filename, "rb");
+   if (fp)
+   {
+      unsigned char buf[4];
+      fseek(fp, offset, SEEK_SET);
+      if (fread(buf, 1, sizeof buf, fp) == sizeof buf)
+         address = buf[0] << 24 | buf[1] << 16 | buf[2] << 8 | buf[3] << 0;
+      fclose(fp);
+   }
+   return address;
+}
+
+unsigned bcm_host_get_peripheral_address(void)
+{
+   unsigned address = get_dt_ranges("/proc/device-tree/soc/ranges", 4);
+   return address == ~0 ? 0x20000000 : address;
+}
+
+unsigned bcm_host_get_peripheral_size(void)
+{
+   unsigned address = get_dt_ranges("/proc/device-tree/soc/ranges", 8);
+   return address == ~0 ? 0x01000000 : address;
+}
+
+unsigned bcm_host_get_sdram_address(void)
+{
+   unsigned address = get_dt_ranges("/proc/device-tree/axi/vc_mem/reg", 8);
+   return address == ~0 ? 0x40000000 : address;
+}
+
+
diff --git a/host_applications/linux/libs/bcm_host/include/bcm_host.h b/host_applications/linux/libs/bcm_host/include/bcm_host.h
new file mode 100755 (executable)
index 0000000..94478e2
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Header file with useful bits from other headers
+
+#ifndef BCM_HOST_H
+#define BCM_HOST_H
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void bcm_host_init(void);
+void bcm_host_deinit(void);
+
+int32_t graphics_get_display_size( const uint16_t display_number,
+                                                    uint32_t *width,
+                                                    uint32_t *height);
+
+unsigned bcm_host_get_peripheral_address(void);
+unsigned bcm_host_get_peripheral_size(void);
+unsigned bcm_host_get_sdram_address(void);
+
+#include "interface/vmcs_host/vc_dispmanx.h"
+#include "interface/vmcs_host/vc_tvservice.h"
+#include "interface/vmcs_host/vc_cec.h"
+#include "interface/vmcs_host/vc_cecservice.h"
+#include "interface/vmcs_host/vcgencmd.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/host_applications/linux/libs/debug_sym/CMakeLists.txt b/host_applications/linux/libs/debug_sym/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..568837f
--- /dev/null
@@ -0,0 +1,15 @@
+
+get_filename_component (VIDEOCORE_ROOT ../../../../ ABSOLUTE)
+include (${VIDEOCORE_ROOT}/makefiles/cmake/global_settings.cmake)
+
+include_directories (
+   ${VCOS_ROOT}/{RTOS}
+   ${VIDEOCORE_HEADERS_BUILD_DIR}
+   ../../../../host_support/include
+   ${VIDEOCORE_ROOT})
+
+add_library(debug_sym ${SHARED} debug_sym.c)
+add_library(debug_sym_static STATIC debug_sym.c)
+
+install(TARGETS debug_sym DESTINATION lib)
+install(TARGETS debug_sym_static DESTINATION lib)
diff --git a/host_applications/linux/libs/debug_sym/debug_sym.c b/host_applications/linux/libs/debug_sym/debug_sym.c
new file mode 100755 (executable)
index 0000000..c4480db
--- /dev/null
@@ -0,0 +1,834 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+*
+*  @file    debug_sym.c
+*
+*  @brief   The usermode process which implements displays the messages.
+*
+****************************************************************************/
+
+// ---- Include Files -------------------------------------------------------
+
+#include "interface/vcos/vcos.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#if defined(WIN32)
+# include <io.h>
+#elif defined(__CYGWIN__)
+# include <sys/mman.h>
+#else
+# include <sys/mman.h>
+# include <sys/ioctl.h>
+# include <vc_mem.h>
+#endif
+
+#include "debug_sym.h"
+#include "vc_debug_sym.h"
+
+
+// ---- Public Variables ----------------------------------------------------
+// ---- Private Constants and Types -----------------------------------------
+
+#define MAX_VC_SIZE  8     /* a sanity upper bound on memory size */
+
+#ifndef PAGE_SIZE
+# if defined(__CYGWIN__)
+#  define PAGE_SIZE   65536 /* Cygwin mmap requires rounding to SYSTEM_INFO.dwAllocationGranularity */
+# else
+#  define PAGE_SIZE   4096
+# endif
+#endif
+#ifndef PAGE_MASK
+# define PAGE_MASK   (~(PAGE_SIZE - 1))
+#endif
+
+// Offset within the videocore memory map to get the address of the symbol
+// table.
+#define VC_SYMBOL_BASE_OFFSET       VC_DEBUG_HEADER_OFFSET
+
+struct opaque_vc_mem_access_handle_t
+{
+    int                 memFd;
+    int                 memFdBase;     /* The VideoCore address mapped to offset 0 of memFd */
+    VC_MEM_ADDR_T       vcMemBase;     /* The VideoCore address of the start of the loaded image */
+    VC_MEM_ADDR_T       vcMemLoad;     /* The VideoCore address of the start of the code image */
+    VC_MEM_ADDR_T       vcMemEnd;      /* The VideoCore address of the end of the loaded image */
+    VC_MEM_SIZE_T       vcMemSize;     /* The amount of memory used by the loaded image */
+    VC_MEM_ADDR_T       vcMemPhys;     /* The VideoCore memory physical address */
+
+    VC_MEM_ADDR_T       vcSymbolTableOffset;
+    unsigned            numSymbols;
+    VC_DEBUG_SYMBOL_T  *symbol;
+    int                 use_vc_mem;    /* using mmap-ed memory rather than real file */
+};
+
+#if 1
+   #define DBG( fmt, ... )    vcos_log_trace( "%s: " fmt, __FUNCTION__, ##__VA_ARGS__ )
+   #define ERR( fmt, ... )    vcos_log_error( "%s: " fmt, __FUNCTION__, ##__VA_ARGS__ )
+#else
+   #define DBG( fmt, ... )    fprintf( stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__ )
+   #define ERR( fmt, ... )    fprintf( stderr, "%s: " fmt "\n", __FUNCTION__, ##__VA_ARGS__ )
+#endif
+
+typedef enum
+{
+    READ_MEM,
+    WRITE_MEM,
+} MEM_OP_T;
+
+#if defined( WIN32 )
+#define        open            _open
+#define        close           _close
+#define        O_SYNC          0
+#endif
+
+// ---- Private Variables ---------------------------------------------------
+
+#define  VCOS_LOG_CATEGORY (&debug_sym_log_category)
+static VCOS_LOG_CAT_T  debug_sym_log_category;
+
+// ---- Private Function Prototypes -----------------------------------------
+
+// ---- Functions -----------------------------------------------------------
+
+/****************************************************************************
+*
+*   Get access to the videocore memory space. Returns zero if the memory was
+*   opened successfully.
+*
+***************************************************************************/
+
+int OpenVideoCoreMemory( VC_MEM_ACCESS_HANDLE_T *vcHandlePtr  )
+{
+    return OpenVideoCoreMemoryFile( NULL, vcHandlePtr );
+}
+
+/****************************************************************************
+*
+*   Get access to the videocore memory space. Returns zero if the memory was
+*   opened successfully.
+*
+***************************************************************************/
+
+struct fb_dmacopy {
+       void *dst;
+       uint32_t src;
+       uint32_t length;
+};
+#define FBIODMACOPY _IOW('z', 0x22, struct fb_dmacopy)
+
+static int vc_mem_copy(void *dst, uint32_t src, uint32_t length)
+{
+    const char *filename = "/dev/fb0";
+    int memFd;
+    struct fb_dmacopy ioparam;
+
+    ioparam.dst = dst;
+    ioparam.src = src;
+    ioparam.length = length;
+
+    if (( memFd = open( filename, O_RDWR | O_SYNC )) < 0 )
+    {
+        ERR( "Unable to open '%s': %s(%d)\n", filename, strerror( errno ), errno );
+        return -errno;
+    }
+
+    if ( ioctl( memFd, FBIODMACOPY, &ioparam ) != 0 )
+    {
+        ERR( "Failed to get memory size via ioctl: %s(%d)\n",
+            strerror( errno ), errno );
+        close( memFd );
+        return -errno;
+    }
+    close( memFd );
+    return 0;
+}
+
+int OpenVideoCoreMemoryFile( const char *filename, VC_MEM_ACCESS_HANDLE_T *vcHandlePtr )
+{
+    return OpenVideoCoreMemoryFileWithOffset( filename, vcHandlePtr, 0 );
+}
+
+int OpenVideoCoreMemoryFileWithOffset( const char *filename, VC_MEM_ACCESS_HANDLE_T *vcHandlePtr, size_t loadOffset )
+{
+    int                     rc = 0;
+    VC_MEM_ACCESS_HANDLE_T  newHandle;
+    VC_DEBUG_SYMBOL_T       debug_sym;
+    VC_MEM_ADDR_T           symAddr;
+    size_t                  symTableSize;
+    unsigned                symIdx;
+
+    struct
+    {
+        VC_DEBUG_HEADER_T header;
+        VC_DEBUG_PARAMS_T params;
+
+    } vc_dbg;
+
+    vcos_log_register( "debug_sym", &debug_sym_log_category );
+
+    if (( newHandle = calloc( 1, sizeof( *newHandle ))) == NULL )
+    {
+        return -ENOMEM;
+    }
+
+    if ( filename == NULL )
+    {
+        newHandle->use_vc_mem = 1;
+        filename = "/dev/vc-mem";
+    }
+    else
+    {
+        newHandle->use_vc_mem = 0;
+    }
+
+    if (( newHandle->memFd = open( filename, ( newHandle->use_vc_mem ? O_RDWR : O_RDONLY ) | O_SYNC )) < 0 )
+    {
+        ERR( "Unable to open '%s': %s(%d)\n", filename, strerror( errno ), errno );
+        free(newHandle);
+        return -errno;
+    }
+    DBG( "Opened %s memFd = %d", filename, newHandle->memFd );
+
+    if ( newHandle->use_vc_mem )
+    {
+        newHandle->memFdBase = 0;
+
+#if defined(WIN32) || defined(__CYGWIN__)
+#define VC_MEM_SIZE  (128 * 1024 * 1024)
+        newHandle->vcMemSize = VC_MEM_SIZE;
+        newHandle->vcMemBase = 0;
+        newHandle->vcMemLoad = 0;
+        newHandle->vcMemPhys = 0;
+#else
+        if ( ioctl( newHandle->memFd, VC_MEM_IOC_MEM_SIZE, &newHandle->vcMemSize ) != 0 )
+        {
+            ERR( "Failed to get memory size via ioctl: %s(%d)\n",
+                strerror( errno ), errno );
+            free(newHandle);
+            return -errno;
+        }
+        if ( ioctl( newHandle->memFd, VC_MEM_IOC_MEM_BASE, &newHandle->vcMemBase ) != 0 )
+        {
+            ERR( "Failed to get memory base via ioctl: %s(%d)\n",
+                strerror( errno ), errno );
+            free(newHandle);
+            return -errno;
+        }
+        if ( ioctl( newHandle->memFd, VC_MEM_IOC_MEM_LOAD, &newHandle->vcMemLoad ) != 0 )
+        {
+            ERR( "Failed to get memory load via ioctl: %s(%d)\n",
+                strerror( errno ), errno );
+                               /* Backward compatibility. */
+            newHandle->vcMemLoad = newHandle->vcMemBase;
+        }
+        if ( ioctl( newHandle->memFd, VC_MEM_IOC_MEM_PHYS_ADDR, &newHandle->vcMemPhys ) != 0 )
+        {
+            ERR( "Failed to get memory physical address via ioctl: %s(%d)\n",
+                strerror( errno ), errno );
+            free(newHandle);
+            return -errno;
+        }
+#endif
+    }
+    else
+    {
+        off_t len = lseek( newHandle->memFd, 0, SEEK_END );
+        if ( len < 0 )
+        {
+            ERR( "Failed to seek to end of file: %s(%d)\n", strerror( errno ), errno );
+            free(newHandle);
+            return -errno;
+        }
+        newHandle->vcMemPhys = 0;
+        newHandle->vcMemSize = len;
+        newHandle->vcMemBase = 0;
+        newHandle->vcMemLoad = loadOffset;
+        newHandle->memFdBase = 0;
+    }
+
+    DBG( "vcMemSize = %08x", newHandle->vcMemSize );
+    DBG( "vcMemBase = %08x", newHandle->vcMemBase );
+    DBG( "vcMemLoad = %08x", newHandle->vcMemLoad );
+    DBG( "vcMemPhys = %08x", newHandle->vcMemPhys );
+
+    newHandle->vcMemEnd = newHandle->vcMemBase + newHandle->vcMemSize - 1;
+
+    // See if we can detect the symbol table
+    if ( !ReadVideoCoreMemory( newHandle,
+                               &newHandle->vcSymbolTableOffset,
+                               newHandle->vcMemLoad + VC_SYMBOL_BASE_OFFSET,
+                               sizeof( newHandle->vcSymbolTableOffset )))
+    {
+        ERR( "ReadVideoCoreMemory @VC_SYMBOL_BASE_OFFSET (0x%08x) failed\n", VC_SYMBOL_BASE_OFFSET );
+        rc = -EIO;
+        goto err_exit;
+    }
+
+    // When reading from a file, the VC binary is read into a buffer and the effective base is 0.
+    // But that may not be the actual base address the binary is intended to be loaded to.  The
+    // following reads the debug header to find out what the actual base address is.
+    if( !newHandle->use_vc_mem )
+    {
+        // Read the complete debug header
+        if ( !ReadVideoCoreMemory( newHandle,
+                                   &vc_dbg,
+                                   newHandle->vcMemLoad + VC_SYMBOL_BASE_OFFSET,
+                                   sizeof( vc_dbg )))
+        {
+            ERR( "ReadVideoCoreMemory @VC_SYMBOL_BASE_OFFSET (0x%08x) failed\n", VC_SYMBOL_BASE_OFFSET );
+            rc = -EIO;
+            goto err_exit;
+        }
+        // The vc_dbg header gives the "base" address of the VC binary,
+        // which debug_sym calls the "load" address, so we need to adjust
+        // it by loadOffset to find the base of the whole memory dump file
+        newHandle->memFdBase = vc_dbg.params.vcMemBase - loadOffset;
+        newHandle->vcMemBase = vc_dbg.params.vcMemBase - loadOffset;
+        newHandle->vcMemLoad = vc_dbg.params.vcMemBase;
+        newHandle->vcMemEnd = newHandle->memFdBase + newHandle->vcMemSize - 1;
+
+        DBG( "Updated from debug header:" );
+        DBG( "vcMemSize = %08x", newHandle->vcMemSize );
+        DBG( "vcMemBase = %08x", newHandle->vcMemBase );
+        DBG( "vcMemLoad = %08x", newHandle->vcMemLoad );
+        DBG( "vcMemPhys = %08x", newHandle->vcMemPhys );
+    }
+
+    DBG( "vcSymbolTableOffset = 0x%08x", newHandle->vcSymbolTableOffset );
+
+    // Make sure that the pointer points into the first few megabytes of
+    // the memory space.
+    if ( (newHandle->vcSymbolTableOffset - newHandle->vcMemLoad) > ( MAX_VC_SIZE * 1024 * 1024 ))
+    {
+        ERR( "newHandle->vcSymbolTableOffset (0x%x - 0x%x) > %dMB\n", newHandle->vcSymbolTableOffset, newHandle->vcMemLoad, MAX_VC_SIZE );
+        rc = -EIO;
+        goto err_exit;
+    }
+
+    // Make a pass to count how many symbols there are.
+
+    symAddr = newHandle->vcSymbolTableOffset;
+    newHandle->numSymbols = 0;
+    do
+    {
+        if ( !ReadVideoCoreMemory( newHandle,
+                                   &debug_sym,
+                                   symAddr,
+                                   sizeof( debug_sym )))
+        {
+            ERR( "ReadVideoCoreMemory @ symAddr(0x%08x) failed\n", symAddr );
+            rc = -EIO;
+            goto err_exit;
+        }
+
+        newHandle->numSymbols++;
+
+        DBG( "Symbol %d: label: 0x%p addr: 0x%08x size: %zu",
+             newHandle->numSymbols,
+             debug_sym.label,
+             debug_sym.addr,
+             debug_sym.size );
+
+        if ( newHandle->numSymbols > 1024 )
+        {
+            // Something isn't sane.
+
+            ERR( "numSymbols (%d) > 1024 - looks wrong\n", newHandle->numSymbols );
+            rc = -EIO;
+            goto err_exit;
+        }
+        symAddr += sizeof( debug_sym );
+
+    } while ( debug_sym.label != 0 );
+    newHandle->numSymbols--;
+
+    DBG( "Detected %d symbols", newHandle->numSymbols );
+
+    // Allocate some memory to hold the symbols, and read them in.
+
+    symTableSize = newHandle->numSymbols * sizeof( debug_sym );
+    if (( newHandle->symbol = malloc( symTableSize )) == NULL )
+    {
+        rc = -ENOMEM;
+        goto err_exit;
+    }
+    if ( !ReadVideoCoreMemory( newHandle,
+                               newHandle->symbol,
+                               newHandle->vcSymbolTableOffset,
+                               symTableSize ))
+    {
+        ERR( "ReadVideoCoreMemory @ newHandle->vcSymbolTableOffset(0x%08x) failed\n", newHandle->vcSymbolTableOffset );
+        rc = -EIO;
+        goto err_exit;
+    }
+
+    // The names of the symbols are pointers in videocore space. We want
+    // to have them available locally, so we make copies and fixup
+    // the pointer.
+
+    for ( symIdx = 0; symIdx < newHandle->numSymbols; symIdx++ )
+    {
+        VC_DEBUG_SYMBOL_T   *sym;
+        char                 symName[ 256 ];
+
+        sym = &newHandle->symbol[ symIdx ];
+
+        DBG( "Symbol %d: label: 0x%p addr: 0x%08x size: %zu",
+             symIdx,
+             sym->label,
+             sym->addr,
+             sym->size );
+
+        if ( !ReadVideoCoreMemory( newHandle,
+                                   symName,
+                                   TO_VC_MEM_ADDR(sym->label),
+                                   sizeof( symName )))
+        {
+            ERR( "ReadVideoCoreMemory @ sym->label(0x%08x) failed\n", TO_VC_MEM_ADDR(sym->label) );
+            rc = -EIO;
+            goto err_exit;
+        }
+        symName[ sizeof( symName ) - 1 ] = '\0';
+        sym->label = vcos_strdup( symName );
+
+        DBG( "Symbol %d (@0x%p): label: '%s' addr: 0x%08x size: %zu",
+             symIdx,
+             sym,
+             sym->label,
+             sym->addr,
+             sym->size );
+    }
+
+    *vcHandlePtr = newHandle;
+    return 0;
+
+err_exit:
+    close( newHandle->memFd );
+    free( newHandle );
+
+    return rc;
+}
+
+/****************************************************************************
+*
+*   Returns the number of symbols which were detected.
+*
+***************************************************************************/
+
+unsigned NumVideoCoreSymbols( VC_MEM_ACCESS_HANDLE_T vcHandle )
+{
+    return vcHandle->numSymbols;
+}
+
+/****************************************************************************
+*
+*   Returns the name, address and size of the i'th symbol.
+*
+***************************************************************************/
+
+int GetVideoCoreSymbol( VC_MEM_ACCESS_HANDLE_T vcHandle, unsigned idx, char *labelBuf, size_t labelBufSize, VC_MEM_ADDR_T *vcMemAddr, size_t *vcMemSize )
+{
+    VC_DEBUG_SYMBOL_T   *sym;
+
+    if ( idx >= vcHandle->numSymbols )
+    {
+        return -EINVAL;
+    }
+    sym = &vcHandle->symbol[ idx ];
+
+    strncpy( labelBuf, sym->label, labelBufSize );
+    labelBuf[labelBufSize - 1] = '\0';
+
+    if ( vcMemAddr != NULL )
+    {
+        *vcMemAddr = (VC_MEM_ADDR_T)sym->addr;
+    }
+    if ( vcMemSize != NULL )
+    {
+        *vcMemSize = sym->size;
+    }
+
+    return 0;
+}
+
+/****************************************************************************
+*
+*   Looks up the named, symbol. If the symbol is found, it's value and size
+*   are returned.
+*
+*   Returns  true if the lookup was successful.
+*
+***************************************************************************/
+
+int LookupVideoCoreSymbol( VC_MEM_ACCESS_HANDLE_T vcHandle, const char *symbol, VC_MEM_ADDR_T *vcMemAddr, size_t *vcMemSize )
+{
+    unsigned        idx;
+    char            symName[ 64 ];
+    VC_MEM_ADDR_T   symAddr = 0;
+    size_t          symSize = 0;
+
+    for ( idx = 0; idx < vcHandle->numSymbols; idx++ )
+    {
+        GetVideoCoreSymbol( vcHandle, idx, symName, sizeof( symName ), &symAddr, &symSize );
+        if ( strcmp( symbol, symName ) == 0 )
+        {
+            if ( vcMemAddr != NULL )
+            {
+                *vcMemAddr = symAddr;
+            }
+            if ( vcMemSize != 0 )
+            {
+                *vcMemSize = symSize;
+            }
+
+            DBG( "%s found, addr = 0x%08x size = %zu", symbol, symAddr, symSize );
+            return 1;
+        }
+    }
+
+    if ( vcMemAddr != NULL )
+    {
+        *vcMemAddr = 0;
+    }
+    if ( vcMemSize != 0 )
+    {
+        *vcMemSize = 0;
+    }
+    DBG( "%s not found", symbol );
+    return 0;
+}
+
+/****************************************************************************
+*
+*   Looks up the named, symbol. If the symbol is found, and it's size is equal
+*   to the sizeof a uint32_t, then true is returned.
+*
+***************************************************************************/
+
+int LookupVideoCoreUInt32Symbol( VC_MEM_ACCESS_HANDLE_T vcHandle,
+                                 const char *symbol,
+                                 VC_MEM_ADDR_T *vcMemAddr )
+{
+    size_t  vcMemSize;
+
+    if ( !LookupVideoCoreSymbol( vcHandle, symbol, vcMemAddr, &vcMemSize ))
+    {
+        return 0;
+    }
+
+    if ( vcMemSize != sizeof( uint32_t ))
+    {
+        ERR( "Symbol: '%s' has a size of %zu, expecting %zu", symbol, vcMemSize, sizeof( uint32_t ));
+        return 0;
+    }
+    return 1;
+}
+
+/****************************************************************************
+*
+*   Does Reads or Writes on the videocore memory.
+*
+***************************************************************************/
+
+static int AccessVideoCoreMemory( VC_MEM_ACCESS_HANDLE_T vcHandle,
+                                  MEM_OP_T               mem_op,
+                                  void                  *buf,
+                                  VC_MEM_ADDR_T          vcMemAddr,
+                                  size_t                 numBytes )
+{
+    VC_MEM_ADDR_T origVcMemAddr = vcMemAddr;
+    DBG( "%s %zu bytes @ 0x%08x", mem_op == WRITE_MEM ? "Write" : "Read", numBytes, vcMemAddr );
+
+    /*
+     * Since we'll be passed videocore pointers, we need to deal with the high bits.
+     *
+     * We need to strip off the high 2 bits to convert to a physical address, except
+     * for when the high 3 bits are equal to 011, which means that it corresponds to
+     * a peripheral and isn't accessible.
+     */
+
+    if ( IS_ALIAS_PERIPHERAL( vcMemAddr ))
+    {
+        // This is a peripheral address.
+
+        ERR( "Can't access peripheral address 0x%08x", vcMemAddr );
+        return 0;
+    }
+    vcMemAddr = TO_VC_MEM_ADDR(ALIAS_NORMAL( vcMemAddr ));
+
+    #if 0
+    if ( (vcMemAddr < vcHandle->vcMemBase) ||
+         (vcMemAddr > vcHandle->vcMemEnd) )
+    {
+        ERR( "Memory address 0x%08x is outside range 0x%08x-0x%08x", vcMemAddr,
+             vcHandle->vcMemBase, vcHandle->vcMemEnd );
+        return 0;
+    }
+    #endif
+    if (( vcMemAddr + numBytes - 1) > vcHandle->vcMemEnd )
+    {
+        ERR( "Memory address 0x%08x + numBytes 0x%08zx is > memory end 0x%08x",
+             vcMemAddr, numBytes, vcHandle->vcMemEnd );
+        return 0;
+    }
+
+    vcMemAddr -= vcHandle->memFdBase;
+
+#if defined( WIN32 )
+    if ( mem_op != READ_MEM )
+    {
+        ERR( "Only reads are supported" );
+        return 0;
+    }
+    if ( _lseek( vcHandle->memFd, vcMemAddr, SEEK_SET ) < 0 )
+    {
+        ERR( "_lseek position 0x%08x failed", vcMemAddr );
+        return  0;
+    }
+    if ( _read( vcHandle->memFd, buf, numBytes ) < 0 )
+    {
+        ERR( "_read failed: %s(%d)", strerror( errno ), errno );
+        return 0;
+    }
+#else
+    // DMA allows memory to be accessed above 1008M and is more coherent so try this first
+    if (mem_op == READ_MEM && vcHandle->use_vc_mem)
+    {
+        DBG( "AccessVideoCoreMemory: %p, %x, %d", buf, origVcMemAddr, numBytes );
+        int s = vc_mem_copy(buf, (uint32_t)origVcMemAddr, numBytes);
+        if (s == 0)
+            return 1;
+    }
+
+    {
+        uint8_t    *mapAddr;
+        size_t      mapSize;
+        size_t      memOffset;
+        off_t       vcMapAddr;
+        int         mmap_prot;
+
+        if ( mem_op == WRITE_MEM )
+        {
+            mmap_prot = PROT_WRITE;
+        }
+        else
+        {
+            mmap_prot = PROT_READ;
+        }
+
+        // We can only map pages on 4K boundaries, so round the address down and the size up.
+
+        memOffset = vcMemAddr & ~PAGE_MASK;
+
+        vcMapAddr = vcMemAddr & PAGE_MASK;
+
+        mapSize = ( memOffset + numBytes + PAGE_SIZE - 1 ) & PAGE_MASK;
+        if (( mapAddr = mmap( 0, mapSize, mmap_prot, MAP_SHARED, vcHandle->memFd, vcMapAddr )) == MAP_FAILED )
+        {
+           ERR( "mmap failed: %s(%d)", strerror( errno ), errno );
+           return 0;
+        }
+        if ( mem_op == WRITE_MEM )
+        {
+           memcpy( mapAddr + memOffset, buf, numBytes );
+        }
+        else
+        {
+           memcpy( buf, mapAddr + memOffset, numBytes );
+        }
+
+        munmap( mapAddr, mapSize );
+    }
+#endif
+
+    return 1;
+}
+
+
+/****************************************************************************
+*
+*   Reads 'numBytes' from the videocore memory starting at 'vcMemAddr'. The
+*   results are stored in 'buf'.
+*
+*   Returns true if the read was successful.
+*
+***************************************************************************/
+
+int ReadVideoCoreMemory( VC_MEM_ACCESS_HANDLE_T vcHandle, void *buf, VC_MEM_ADDR_T vcMemAddr, size_t numBytes )
+{
+    return AccessVideoCoreMemory( vcHandle, READ_MEM, buf, vcMemAddr, numBytes );
+}
+
+/****************************************************************************
+*
+*   Reads 'numBytes' from the videocore memory starting at 'vcMemAddr'. The
+*   results are stored in 'buf'.
+*
+*   Returns true if the read was successful.
+*
+***************************************************************************/
+
+int ReadVideoCoreMemoryBySymbol( VC_MEM_ACCESS_HANDLE_T vcHandle, const char *symbol, void *buf, size_t bufSize )
+{
+    VC_MEM_ADDR_T   vcMemAddr;
+    size_t          vcMemSize;
+
+    if ( !LookupVideoCoreSymbol( vcHandle, symbol, &vcMemAddr, &vcMemSize ))
+    {
+        ERR( "Symbol not found: '%s'", symbol );
+        return 0;
+    }
+
+    if ( vcMemSize > bufSize )
+    {
+        vcMemSize = bufSize;
+    }
+
+    if ( !ReadVideoCoreMemory( vcHandle, buf, vcMemAddr, vcMemSize ))
+    {
+        ERR( "Unable to read %zu bytes @ 0x%08x", vcMemSize, vcMemAddr );
+        return 0;
+    }
+    return 1;
+}
+
+/****************************************************************************
+*
+*   Looks up a symbol and reads the contents into a user supplied buffer.
+*
+*   Returns true if the read was successful.
+*
+***************************************************************************/
+
+int ReadVideoCoreStringBySymbol( VC_MEM_ACCESS_HANDLE_T vcHandle,
+                                 const char *symbol,
+                                 char *buf,
+                                 size_t bufSize )
+{
+    VC_MEM_ADDR_T   vcMemAddr;
+    size_t          vcMemSize;
+
+    if ( !LookupVideoCoreSymbol( vcHandle, symbol, &vcMemAddr, &vcMemSize ))
+    {
+        ERR( "Symbol not found: '%s'", symbol );
+        return 0;
+    }
+
+    if ( vcMemSize > bufSize )
+    {
+        vcMemSize = bufSize;
+    }
+
+    if ( !ReadVideoCoreMemory( vcHandle, buf, vcMemAddr, vcMemSize ))
+    {
+        ERR( "Unable to read %zu bytes @ 0x%08x", vcMemSize, vcMemAddr );
+        return 0;
+    }
+
+    // Make sure that the result is null-terminated
+
+    buf[vcMemSize-1] = '\0';
+    return 1;
+}
+
+/****************************************************************************
+*
+*   Writes 'numBytes' into the videocore memory starting at 'vcMemAddr'. The
+*   data is taken from 'buf'.
+*
+*   Returns true if the write was successful.
+*
+***************************************************************************/
+
+int WriteVideoCoreMemory( VC_MEM_ACCESS_HANDLE_T vcHandle,
+                          void *buf,
+                          VC_MEM_ADDR_T vcMemAddr,
+                          size_t numBytes )
+{
+    return AccessVideoCoreMemory( vcHandle, WRITE_MEM, buf, vcMemAddr, numBytes );
+}
+
+/****************************************************************************
+*
+*   Closes the memory space opened previously via OpenVideoCoreMemory.
+*
+***************************************************************************/
+
+void CloseVideoCoreMemory( VC_MEM_ACCESS_HANDLE_T vcHandle )
+{
+    unsigned i;
+    if ( vcHandle->symbol )
+        for ( i = 0; i < vcHandle->numSymbols; i++ )
+            free( (char *)vcHandle->symbol[i].label );
+    free( vcHandle->symbol );
+
+    if ( vcHandle->memFd >= 0 )
+        close( vcHandle->memFd );
+
+    free( vcHandle );
+}
+
+/****************************************************************************
+*
+*   Returns the base address of the videocore memory space.
+*
+***************************************************************************/
+
+VC_MEM_ADDR_T GetVideoCoreMemoryBase( VC_MEM_ACCESS_HANDLE_T vcHandle )
+{
+    return vcHandle->vcMemBase;
+}
+
+/****************************************************************************
+*
+*   Returns the size of the videocore memory space.
+*
+***************************************************************************/
+
+VC_MEM_SIZE_T GetVideoCoreMemorySize( VC_MEM_ACCESS_HANDLE_T vcHandle )
+{
+    return vcHandle->vcMemSize;
+}
+
+/****************************************************************************
+*
+*   Returns the videocore memory physical address.
+*
+***************************************************************************/
+
+VC_MEM_ADDR_T GetVideoCoreMemoryPhysicalAddress( VC_MEM_ACCESS_HANDLE_T vcHandle )
+{
+    return vcHandle->vcMemPhys;
+}
+
diff --git a/host_applications/linux/libs/debug_sym/debug_sym.h b/host_applications/linux/libs/debug_sym/debug_sym.h
new file mode 100755 (executable)
index 0000000..f05bfa5
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined( DEBUG_SYM_H )
+#define DEBUG_SYM_H
+
+/* ---- Include Files ----------------------------------------------------- */
+
+#include "interface/vcos/vcos.h"
+#include "interface/vcos/vcos_stdint.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ---- Constants and Types ---------------------------------------------- */
+
+typedef struct opaque_vc_mem_access_handle_t *VC_MEM_ACCESS_HANDLE_T;
+
+/* Since the VC might have a different memory model from the host
+ * (32-bit vs 64-bit), define fixed-width types that match the
+ * VC memory types */
+typedef uint32_t VC_MEM_ADDR_T;    /* equivalent to uintptr_t */
+typedef uint32_t VC_MEM_SIZE_T;    /* equivalent to size_t */
+typedef uint32_t VC_MEM_PTRDIFF_T; /* equivalent to ptrdiff_t */
+
+#define TO_VC_MEM_ADDR(ptr)    ((VC_MEM_ADDR_T)(unsigned long)(ptr))
+
+/* ---- Variable Externs ------------------------------------------------- */
+
+/* ---- Function Prototypes ---------------------------------------------- */
+
+/*
+ * The following were taken from vcinclude/hardware_vc4_bigisland.h
+ */
+
+#define ALIAS_NORMAL(x)             ((VC_MEM_ADDR_T)(((unsigned long)(x)&~0xc0000000uL)|0x00000000uL)) // normal cached data (uses main 128K L2 cache)
+#define IS_ALIAS_PERIPHERAL(x)      (((unsigned long)(x)>>29)==0x3uL)
+
+/*
+ * Get access to the videocore memory space. Returns zero if the memory was
+ * opened successfully, or a negative value (-errno) if the access could not
+ * be obtained.
+ */
+int OpenVideoCoreMemory( VC_MEM_ACCESS_HANDLE_T *handle  );
+
+/*
+ * Get access to the videocore space from a file. The file might be /dev/mem, or 
+ * it might be saved image on disk. 
+ */
+int OpenVideoCoreMemoryFile( const char *filename, VC_MEM_ACCESS_HANDLE_T *vcHandlePtr );
+
+/*
+ * Get access to the videocore space from a file, explicitly giving the
+ * offset of the load address (the start of the VC binary) relative to the
+ * start of the file.
+ * loadOffset is ignored if reading from memory instead of a saved image.
+ */
+int OpenVideoCoreMemoryFileWithOffset( const char *filename,
+                                       VC_MEM_ACCESS_HANDLE_T *vcHandlePtr,
+                                       size_t loadOffset );
+
+/*
+ * Returns the number of symbols which were detected.
+ */
+unsigned NumVideoCoreSymbols( VC_MEM_ACCESS_HANDLE_T handle );
+
+/*
+ * Returns the name, address and size of the i'th symbol.
+ */
+int GetVideoCoreSymbol( VC_MEM_ACCESS_HANDLE_T handle,
+                        unsigned idx,
+                        char *nameBuf,
+                        size_t nameBufSize,
+                        VC_MEM_ADDR_T *vcMemAddr,
+                        size_t *vcMemSize );
+
+/*
+ * Looks up the named, symbol. If the symbol is found, it's value and size
+ * are returned.
+ *
+ * Returns  true if the lookup was successful.
+ */
+int LookupVideoCoreSymbol( VC_MEM_ACCESS_HANDLE_T handle,
+                           const char *symbol,
+                           VC_MEM_ADDR_T *vcMemAddr,
+                           size_t *vcMemSize );
+
+/*
+ * Looks up the named, symbol. If the symbol is found, and it's size is equal
+ * to the sizeof a uint32_t, then true is returned.
+ */
+int LookupVideoCoreUInt32Symbol( VC_MEM_ACCESS_HANDLE_T handle,
+                                 const char *symbol,
+                                 VC_MEM_ADDR_T *vcMemAddr );
+
+/*
+ * Reads 'numBytes' from the videocore memory starting at 'vcMemAddr'. The
+ * results are stored in 'buf'.
+ *
+ * Returns true if the read was successful.
+ */
+int ReadVideoCoreMemory( VC_MEM_ACCESS_HANDLE_T handle,
+                         void *buf,
+                         VC_MEM_ADDR_T vcMemAddr,
+                         size_t numBytes );
+
+/*
+ * Reads an unsigned 32-bit value from videocore memory.
+ */
+VCOS_STATIC_INLINE int ReadVideoCoreUInt32( VC_MEM_ACCESS_HANDLE_T handle,
+                                       uint32_t *val,
+                                       VC_MEM_ADDR_T vcMemAddr )
+{
+    return ReadVideoCoreMemory( handle, val, vcMemAddr, sizeof( *val ));
+}
+
+/*
+ * Reads a block of memory using the address associated with a symbol.
+ */
+int ReadVideoCoreMemoryBySymbol( VC_MEM_ACCESS_HANDLE_T vcHandle,
+                                 const char            *symbol,
+                                 void                  *buf,
+                                 size_t                 numBytes );
+/*
+ * Reads an unsigned 32-bit value from videocore memory.
+ */
+VCOS_STATIC_INLINE int ReadVideoCoreUInt32BySymbol( VC_MEM_ACCESS_HANDLE_T handle,
+                                               const char *symbol,
+                                               uint32_t *val )
+{
+    return ReadVideoCoreMemoryBySymbol( handle, symbol, val, sizeof( *val ));
+}
+
+/*
+ * Looksup a string symbol by name, and reads the contents into a user
+ * supplied buffer.
+ */
+int ReadVideoCoreStringBySymbol( VC_MEM_ACCESS_HANDLE_T handle,
+                                 const char *symbol,
+                                 char *buf,
+                                 size_t bufSize );
+
+/*
+ * Writes 'numBytes' into the videocore memory starting at 'vcMemAddr'. The
+ * data is taken from 'buf'.
+ *
+ * Returns true if the write was successful.
+ */
+int WriteVideoCoreMemory( VC_MEM_ACCESS_HANDLE_T handle,
+                          void *buf,
+                          VC_MEM_ADDR_T vcMemAddr,
+                          size_t numBytes );
+
+/*
+ * Writes an unsigned 32-bit value into videocore memory.
+ */
+VCOS_STATIC_INLINE int WriteVideoCoreUInt32( VC_MEM_ACCESS_HANDLE_T handle,
+                                        uint32_t val,
+                                        VC_MEM_ADDR_T vcMemAddr )
+{
+    return WriteVideoCoreMemory( handle, &val, vcMemAddr, sizeof( val ));
+}
+
+/*
+ * Closes the memory space opened previously via OpenVideoCoreMemory.
+ */
+void CloseVideoCoreMemory( VC_MEM_ACCESS_HANDLE_T handle );
+
+/*
+ * Returns the base address of the videocore memory space.
+ */
+VC_MEM_ADDR_T GetVideoCoreMemoryBase( VC_MEM_ACCESS_HANDLE_T handle );
+
+/*
+ * Returns the size of the videocore memory space.
+ */
+VC_MEM_SIZE_T GetVideoCoreMemorySize( VC_MEM_ACCESS_HANDLE_T handle );
+
+/*
+ * Returns the videocore memory physical address.
+ */
+VC_MEM_ADDR_T GetVideoCoreMemoryPhysicalAddress( VC_MEM_ACCESS_HANDLE_T handle );
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* DEBUG_SYM_H */
+
diff --git a/host_applications/linux/libs/sm/CMakeLists.txt b/host_applications/linux/libs/sm/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..5ce5aca
--- /dev/null
@@ -0,0 +1,18 @@
+
+if (WIN32)
+   set(VCOS_PLATFORM win32)
+else ()
+   set(VCOS_PLATFORM pthreads)
+   add_definitions(-Wall -Werror)
+endif ()
+
+include_directories( ../../../..
+                     ../../../../interface/vcos/${VCOS_PLATFORM}
+                     ../../../../host_applications/linux/kernel_headers )
+
+add_library(vcsm ${SHARED} user-vcsm.c)
+
+target_link_libraries(vcsm vcos)
+
+install(TARGETS vcsm DESTINATION lib)
+install(FILES user-vcsm.h DESTINATION include/interface/vcsm)
diff --git a/host_applications/linux/libs/sm/user-vcsm.c b/host_applications/linux/libs/sm/user-vcsm.c
new file mode 100755 (executable)
index 0000000..391fd45
--- /dev/null
@@ -0,0 +1,1700 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+
+
+#include <vmcs_sm_ioctl.h>
+#include "user-vcsm.h"
+#include "interface/vcos/vcos.h"
+
+typedef struct
+{
+   VCSM_CACHE_TYPE_T cur;  /* Current pattern. */
+   VCSM_CACHE_TYPE_T new;  /* New pattern. */
+   VCSM_CACHE_TYPE_T res;  /* End result. */
+
+} VCSM_CACHE_MUTEX_LKUP_T;
+
+#define VCSM_DEVICE_NAME      "/dev/vcsm"
+#define VCSM_INVALID_HANDLE   (-1)
+
+static VCOS_LOG_CAT_T usrvcsm_log_category;
+#define VCOS_LOG_CATEGORY (&usrvcsm_log_category)
+static int vcsm_handle = VCSM_INVALID_HANDLE;
+static int vcsm_refcount;
+static unsigned int vcsm_page_size = 0;
+
+static VCOS_ONCE_T vcsm_once = VCOS_ONCE_INIT;
+static VCOS_MUTEX_T vcsm_mutex;
+/* Cache [(current, new) -> outcome] mapping table, ignoring identity.
+**
+** Note: Videocore cache mode cannot be udpated 'lock' time.
+*/
+static VCSM_CACHE_MUTEX_LKUP_T vcsm_cache_mutex_table[] =
+{
+     /* ------ CURRENT ------- *//* ---------- NEW --------- *//* --------- RESULT --------- */
+   { VCSM_CACHE_TYPE_NONE,       VCSM_CACHE_TYPE_HOST,         VCSM_CACHE_TYPE_HOST },
+   { VCSM_CACHE_TYPE_NONE,       VCSM_CACHE_TYPE_VC,           VCSM_CACHE_TYPE_NONE },
+   { VCSM_CACHE_TYPE_NONE,       VCSM_CACHE_TYPE_HOST_AND_VC,  VCSM_CACHE_TYPE_HOST },
+
+   { VCSM_CACHE_TYPE_HOST,       VCSM_CACHE_TYPE_NONE,         VCSM_CACHE_TYPE_NONE },
+   { VCSM_CACHE_TYPE_HOST,       VCSM_CACHE_TYPE_VC,           VCSM_CACHE_TYPE_HOST },
+   { VCSM_CACHE_TYPE_HOST,       VCSM_CACHE_TYPE_HOST_AND_VC,  VCSM_CACHE_TYPE_HOST },
+
+   { VCSM_CACHE_TYPE_VC,         VCSM_CACHE_TYPE_NONE,         VCSM_CACHE_TYPE_NONE },
+   { VCSM_CACHE_TYPE_VC,         VCSM_CACHE_TYPE_HOST,         VCSM_CACHE_TYPE_HOST_AND_VC },
+   { VCSM_CACHE_TYPE_VC,         VCSM_CACHE_TYPE_HOST_AND_VC,  VCSM_CACHE_TYPE_HOST_AND_VC },
+
+   { VCSM_CACHE_TYPE_HOST_AND_VC, VCSM_CACHE_TYPE_NONE,        VCSM_CACHE_TYPE_VC },
+   { VCSM_CACHE_TYPE_HOST_AND_VC, VCSM_CACHE_TYPE_HOST,        VCSM_CACHE_TYPE_HOST_AND_VC },
+   { VCSM_CACHE_TYPE_HOST_AND_VC, VCSM_CACHE_TYPE_VC,          VCSM_CACHE_TYPE_VC },
+
+   /* Used for lookup termination. */
+   { VCSM_CACHE_TYPE_NONE,        VCSM_CACHE_TYPE_NONE,        VCSM_CACHE_TYPE_NONE },
+};
+
+static VCSM_CACHE_TYPE_T vcsm_cache_table_lookup( VCSM_CACHE_TYPE_T current,
+                                                  VCSM_CACHE_TYPE_T new )
+{
+   VCSM_CACHE_MUTEX_LKUP_T *p_map = vcsm_cache_mutex_table;   
+
+   while ( !( (p_map->cur == VCSM_CACHE_TYPE_NONE) &&
+              (p_map->new == VCSM_CACHE_TYPE_NONE) ) )
+   {
+      if ( (p_map->cur == current) && (p_map->new == new) )
+      {
+         return p_map->res;
+      }
+
+      p_map++;
+   };
+
+   vcos_log_error( "[%s]: [%d]: no mapping found for current %d - new %d",
+                   __func__,
+                   getpid(),
+                   current,
+                   new );
+   return current;
+}
+
+/* A one off vcsm initialization routine
+*/
+static void vcsm_init_once(void)
+{
+   vcos_mutex_create(&vcsm_mutex, VCOS_FUNCTION);
+   vcos_log_set_level(&usrvcsm_log_category, VCOS_LOG_ERROR);
+   usrvcsm_log_category.flags.want_prefix = 0;
+   vcos_log_register( "usrvcsm", &usrvcsm_log_category );
+}
+
+
+/* Initialize the vcsm processing.
+**
+** Must be called once before attempting to do anything else.
+**
+** Returns 0 on success, -1 on error.
+*/
+int vcsm_init( void )
+{
+   int result  = VCSM_INVALID_HANDLE;
+   vcos_once(&vcsm_once, vcsm_init_once);
+
+   /* Only open the VCSM device once per process.
+   */
+   vcos_mutex_lock( &vcsm_mutex );
+   if ( vcsm_refcount != 0 )
+   {
+      goto out; /* VCSM already opened. Nothing to do. */
+   }
+
+   vcsm_handle    = open( VCSM_DEVICE_NAME, O_RDWR, 0 );
+   vcsm_page_size = getpagesize();
+
+
+out:
+   if ( vcsm_handle != VCSM_INVALID_HANDLE )
+   {
+      result = 0;
+      vcsm_refcount++;
+
+      vcos_log_trace( "[%s]: [%d]: %d (align: %u) - ref-cnt %u",
+                      __func__,
+                      getpid(),
+                      vcsm_handle,
+                      vcsm_page_size,
+                      vcsm_refcount );
+   }
+   vcos_mutex_unlock( &vcsm_mutex );
+   return result;
+}
+
+
+/* Terminates the vcsm processing.
+**
+** Must be called vcsm services are no longer needed, it will
+** take care of removing any allocation under the current process
+** control if deemed necessary.
+*/
+void vcsm_exit( void )
+{
+   vcos_mutex_lock( &vcsm_mutex );
+
+   if ( vcsm_refcount == 0 )
+   {
+      goto out; /* Shouldn't really happen. */
+   }
+
+   if ( --vcsm_refcount != 0 )
+   {
+      vcos_log_trace( "[%s]: [%d]: %d - ref-cnt: %u",
+                      __func__,
+                      getpid(),
+                      vcsm_handle,
+                      vcsm_refcount );
+
+      goto out; /* We're done. */
+   }
+
+   close( vcsm_handle );
+   vcsm_handle = VCSM_INVALID_HANDLE;
+
+out:
+   vcos_mutex_unlock( &vcsm_mutex );
+}
+
+
+/* Allocates a cached block of memory of size 'size' via the vcsm memory
+** allocator, the type of caching requested is passed as argument of the
+** function call.
+**
+** Returns:        0 on error
+**                 a non-zero opaque handle on success.
+**
+** On success, the user must invoke vcsm_lock with the returned opaque
+** handle to gain access to the memory associated with the opaque handle.
+** When finished using the memory, the user calls vcsm_unlock_xx (see those
+** function definition for more details on the one that can be used).
+** 
+** A well behaved application should make every attempt to lock/unlock
+** only for the duration it needs to access the memory data associated with
+** the opaque handle.
+*/
+unsigned int vcsm_malloc_cache( unsigned int size, VCSM_CACHE_TYPE_T cache, char *name )
+{
+   struct vmcs_sm_ioctl_alloc alloc;
+   unsigned int size_aligned = size;
+   void *usr_ptr = NULL;
+   int rc;
+
+   if ( (size == 0) || (vcsm_handle == VCSM_INVALID_HANDLE) ) 
+   {
+      vcos_log_error( "[%s]: [%d] [%s]: NULL size or invalid device!",
+                      __func__,
+                      getpid(),
+                      name );
+      return 0;
+   }
+
+   memset( &alloc, 0, sizeof(alloc) );
+
+   /* Ask for page aligned.
+   */
+   size_aligned = (size + vcsm_page_size - 1) & ~(vcsm_page_size - 1);
+
+   /* Allocate the buffer on videocore via the VCSM (Videocore Shared Memory)
+   ** interface.
+   */
+   alloc.size   = size_aligned;
+   alloc.num    = 1;
+   alloc.cached = (enum vmcs_sm_cache_e) cache;   /* Convenient one to one mapping. */
+   alloc.handle = 0;
+   if ( name != NULL )
+   {
+      memcpy ( alloc.name, name, 32 );
+   }
+   rc = ioctl( vcsm_handle,
+               VMCS_SM_IOCTL_MEM_ALLOC,
+               &alloc );
+
+   if ( rc < 0 || alloc.handle == 0 )
+   {
+      vcos_log_error( "[%s]: [%d] [%s]: ioctl mem-alloc FAILED [%d] (hdl: %x)",
+                      __func__,
+                      getpid(),
+                      alloc.name,
+                      rc,
+                      alloc.handle );
+      goto error;
+   }
+
+   vcos_log_trace( "[%s]: [%d] [%s]: ioctl mem-alloc %d (hdl: %x)",
+                   __func__,
+                   getpid(),
+                   alloc.name,
+                   rc,
+                   alloc.handle );
+
+   /* Map the buffer into user space.
+   */
+   usr_ptr = mmap( 0,
+                   alloc.size,
+                   PROT_READ | PROT_WRITE,
+                   MAP_SHARED,
+                   vcsm_handle,
+                   alloc.handle );
+
+   if ( usr_ptr == NULL )
+   {
+      vcos_log_error( "[%s]: [%d]: mmap FAILED (hdl: %x)",
+                      __func__,
+                      getpid(),
+                      alloc.handle );
+      goto error;
+   }
+
+   return alloc.handle;
+
+ error:
+   if ( alloc.handle )
+   {
+      vcsm_free( alloc.handle );
+   }
+   return 0;
+}
+
+
+/* Allocates a non-cached block of memory of size 'size' via the vcsm memory
+** allocator.
+**
+** Returns:        0 on error
+**                 a non-zero opaque handle on success.
+**
+** On success, the user must invoke vcsm_lock with the returned opaque
+** handle to gain access to the memory associated with the opaque handle.
+** When finished using the memory, the user calls vcsm_unlock_xx (see those
+** function definition for more details on the one that can be used).
+** 
+** A well behaved application should make every attempt to lock/unlock
+** only for the duration it needs to access the memory data associated with
+** the opaque handle.
+*/
+unsigned int vcsm_malloc( unsigned int size, char *name )
+{
+   return vcsm_malloc_cache( size, VCSM_CACHE_TYPE_NONE, name );
+}
+
+/* Shares an allocated block of memory.
+**
+** Returns:        0 on error
+**                 a non-zero opaque handle on success.
+**
+** On success, the user must invoke vcsm_lock with the returned opaque
+** handle to gain access to the memory associated with the opaque handle.
+** When finished using the memory, the user calls vcsm_unlock_xx (see those
+** function definition for more details on the one that can be used).
+**
+** A well behaved application should make every attempt to lock/unlock
+** only for the duration it needs to access the memory data associated with
+** the opaque handle.
+*/
+unsigned int vcsm_malloc_share( unsigned int handle )
+{
+   struct vmcs_sm_ioctl_alloc_share alloc;
+   void *usr_ptr = NULL;
+   int rc;
+
+   if ( vcsm_handle == VCSM_INVALID_HANDLE )
+   {
+      vcos_log_error( "[%s]: [%d]: NULL size or invalid device!",
+                      __func__,
+                      getpid() );
+      return 0;
+   }
+
+   memset( &alloc, 0, sizeof(alloc) );
+
+   /* Share the buffer on videocore via the VCSM (Videocore Shared Memory)
+   ** interface.
+   */
+   alloc.handle = handle;
+   rc = ioctl( vcsm_handle,
+               VMCS_SM_IOCTL_MEM_ALLOC_SHARE,
+               &alloc );
+
+   if ( rc < 0 || alloc.handle == 0 )
+   {
+      vcos_log_error( "[%s]: [%d]: ioctl mem-share FAILED [%d] (hdl: %x->%x)",
+                      __func__,
+                      getpid(),
+                      rc,
+                      handle,
+                      alloc.handle );
+      goto error;
+   }
+
+   vcos_log_trace( "[%s]: [%d]: ioctl mem-share %d (hdl: %x->%x)",
+                   __func__,
+                   getpid(),
+                   rc,
+                   handle,
+                   alloc.handle );
+
+   /* Map the buffer into user space.
+   */
+   usr_ptr = mmap( 0,
+                   alloc.size,
+                   PROT_READ | PROT_WRITE,
+                   MAP_SHARED,
+                   vcsm_handle,
+                   alloc.handle );
+
+   if ( usr_ptr == NULL )
+   {
+      vcos_log_error( "[%s]: [%d]: mmap FAILED (hdl: %x)",
+                      __func__,
+                      getpid(),
+                      alloc.handle );
+      goto error;
+   }
+
+   return alloc.handle;
+
+ error:
+   if ( alloc.handle )
+   {
+      vcsm_free( alloc.handle );
+   }
+   return 0;
+}
+
+/* Frees a block of memory that was successfully allocated by
+** a prior call the vcms_alloc.
+**
+** The handle should be considered invalid upon return from this
+** call.
+**
+** Whether any memory is actually freed up or not as the result of
+** this call will depends on many factors, if all goes well it will
+** be freed.  If something goes wrong, the memory will likely end up
+** being freed up as part of the vcsm_exit process.  In the end the
+** memory is guaranteed to be freed one way or another.
+*/
+void vcsm_free( unsigned int handle )
+{
+   int rc;
+   struct vmcs_sm_ioctl_free alloc_free;
+   struct vmcs_sm_ioctl_size sz;
+   struct vmcs_sm_ioctl_map map;
+   void *usr_ptr = NULL;
+
+   if ( (vcsm_handle == VCSM_INVALID_HANDLE) || (handle == 0) ) 
+   {
+      vcos_log_error( "[%s]: [%d]: invalid device or handle!",
+                      __func__,
+                      getpid() );
+
+      goto out;
+   }
+
+   memset( &sz, 0, sizeof(sz) );
+   memset( &alloc_free, 0, sizeof(alloc_free) );
+   memset( &map, 0, sizeof(map) );
+
+   /* Verify what we want is valid.
+   */
+   sz.handle = handle;
+
+   rc = ioctl( vcsm_handle,
+               VMCS_SM_IOCTL_SIZE_USR_HDL,
+               &sz );
+
+   vcos_log_trace( "[%s]: [%d]: ioctl size-usr-hdl %d (hdl: %x) - size %u",
+                   __func__,
+                   getpid(),
+                   rc,
+                   sz.handle,
+                   sz.size );
+
+   /* We will not be able to free up the resource!
+   **
+   ** However, the driver will take care of it eventually once the device is
+   ** closed (or dies), so this is not such a dramatic event...
+   */
+   if ( (rc < 0) || (sz.size == 0) )
+   {
+      goto out;
+   }
+
+   /* Un-map the buffer from user space, using the last known mapped
+   ** address valid.
+   */
+   usr_ptr = (void *) vcsm_usr_address( sz.handle );
+   if ( usr_ptr != NULL )
+   {
+      munmap( usr_ptr, sz.size );
+
+      vcos_log_trace( "[%s]: [%d]: ioctl unmap hdl: %x",
+                      __func__,
+                      getpid(),
+                      sz.handle );
+   }
+   else
+   {
+      vcos_log_trace( "[%s]: [%d]: freeing unmapped area (hdl: %x)",
+                      __func__,
+                      getpid(),
+                      map.handle );
+   }
+
+   /* Free the allocated buffer all the way through videocore.
+   */
+   alloc_free.handle    = sz.handle;
+
+   rc = ioctl( vcsm_handle,
+               VMCS_SM_IOCTL_MEM_FREE,
+               &alloc_free );
+
+   vcos_log_trace( "[%s]: [%d]: ioctl mem-free %d (hdl: %x)",
+                   __func__,
+                   getpid(),
+                   rc,
+                   alloc_free.handle );
+
+out:
+   return;
+}
+
+
+/* Queries the status of the the vcsm.
+**
+** Triggers dump of various kind of information, see the
+** different variants specified in VCSM_STATUS_T.
+**
+** Pid is optional.
+*/
+void vcsm_status( VCSM_STATUS_T status, int pid )
+{
+   struct vmcs_sm_ioctl_walk walk;
+
+   if ( vcsm_handle == VCSM_INVALID_HANDLE ) 
+   {
+      vcos_log_error( "[%s]: [%d]: invalid device!",
+                      __func__,
+                      getpid() );
+
+      return;
+   }
+
+   memset( &walk, 0, sizeof(walk) );
+
+   /* Allow user to specify the pid of interest if desired, otherwise
+   ** assume the current one.
+   */
+   walk.pid  = (pid == VCSM_INVALID_HANDLE) ? getpid() : pid;
+
+   switch ( status )
+   {
+      case VCSM_STATUS_VC_WALK_ALLOC:
+      {
+         ioctl( vcsm_handle,
+                VMCS_SM_IOCTL_VC_WALK_ALLOC,
+                NULL );
+      }
+      break;
+
+      case VCSM_STATUS_HOST_WALK_MAP:
+      {
+         ioctl( vcsm_handle,
+                VMCS_SM_IOCTL_HOST_WALK_MAP,
+                NULL );
+      }
+      break;
+
+      case VCSM_STATUS_HOST_WALK_PID_MAP:
+      {
+         ioctl( vcsm_handle,
+                VMCS_SM_IOCTL_HOST_WALK_PID_ALLOC,
+                &walk );
+      }
+      break;
+
+      case VCSM_STATUS_HOST_WALK_PID_ALLOC:
+      {
+         ioctl( vcsm_handle,
+                VMCS_SM_IOCTL_HOST_WALK_PID_MAP,
+                &walk );
+      }
+      break;
+
+      case VCSM_STATUS_NONE:
+      default:
+         vcos_log_error( "[%s]: [%d]: invalid argument %d",
+                         __func__,
+                         getpid(),
+                         status );
+      break;
+   }
+}
+
+
+/* Retrieves a videocore opaque handle from a mapped user address
+** pointer.  The videocore handle will correspond to the actual
+** memory mapped in videocore.
+**
+** Returns:        0 on error
+**                 a non-zero opaque handle on success.
+**
+** Note: the videocore opaque handle is distinct from the user
+**       opaque handle (allocated via vcsm_malloc) and it is only
+**       significant for such application which knows what to do
+**       with it, for the others it is just a number with little
+**       use since nothing can be done with it (in particular
+**       for safety reason it cannot be used to map anything).
+*/
+unsigned int vcsm_vc_hdl_from_ptr( void *usr_ptr )
+{
+   int rc;
+   struct vmcs_sm_ioctl_map map;
+
+   if ( (vcsm_handle == VCSM_INVALID_HANDLE) || (usr_ptr == NULL) )
+   {
+      vcos_log_error( "[%s]: [%d]: invalid device!",
+                      __func__,
+                      getpid() );
+
+      return 0;
+   }
+
+   memset( &map, 0, sizeof(map) );
+
+   map.pid  = getpid();
+   map.addr = (unsigned int) usr_ptr;
+
+   rc = ioctl( vcsm_handle,
+               VMCS_SM_IOCTL_MAP_VC_HDL_FR_ADDR,
+               &map );
+
+   if ( rc < 0 )
+   {
+      vcos_log_error( "[%s]: [%d]: ioctl mapped-usr-hdl FAILED [%d] (pid: %d, addr: %x)",
+                      __func__,
+                      getpid(),
+                      rc,
+                      map.pid,
+                      map.addr );
+
+      return 0;
+   }
+   else
+   {
+      vcos_log_trace( "[%s]: [%d]: ioctl mapped-usr-hdl %d (hdl: %x, addr: %x)",
+                      __func__,
+                      getpid(),
+                      rc,
+                      map.handle,
+                      map.addr );
+
+      return map.handle;
+   }
+}
+
+
+/* Retrieves a videocore opaque handle from a opaque handle
+** pointer.  The videocore handle will correspond to the actual
+** memory mapped in videocore.
+**
+** Returns:        0 on error
+**                 a non-zero opaque handle on success.
+**
+** Note: the videocore opaque handle is distinct from the user
+**       opaque handle (allocated via vcsm_malloc) and it is only
+**       significant for such application which knows what to do
+**       with it, for the others it is just a number with little
+**       use since nothing can be done with it (in particular
+**       for safety reason it cannot be used to map anything).
+*/
+unsigned int vcsm_vc_hdl_from_hdl( unsigned int handle )
+{
+   int rc;
+   struct vmcs_sm_ioctl_map map;
+
+   if ( (vcsm_handle == VCSM_INVALID_HANDLE) || (handle == 0) )
+   {
+      vcos_log_error( "[%s]: [%d]: invalid device or handle!",
+                      __func__,
+                      getpid() );
+
+      return 0;
+   }
+
+   memset( &map, 0, sizeof(map) );
+
+   map.pid    = getpid();
+   map.handle = handle;
+
+   rc = ioctl( vcsm_handle,
+               VMCS_SM_IOCTL_MAP_VC_HDL_FR_HDL,
+               &map );
+
+   if ( rc < 0 )
+   {
+      vcos_log_error( "[%s]: [%d]: ioctl mapped-usr-hdl FAILED [%d] (pid: %d, hdl: %x)",
+                      __func__,
+                      getpid(),
+                      rc,
+                      map.pid,
+                      map.handle );
+
+      return 0;
+   }
+   else
+   {
+      vcos_log_trace( "[%s]: [%d]: ioctl mapped-usr-hdl %d (hdl: %x)",
+                      __func__,
+                      getpid(),
+                      rc,
+                      map.handle );
+
+      return map.handle;
+   }
+}
+
+
+/* Retrieves a mapped user address from an opaque user
+** handle.
+**
+** Returns:        0 on error
+**                 a non-zero address on success.
+**
+** On success, the address corresponds to the pointer
+** which can access the data allocated via the vcsm_malloc
+** call.
+*/
+void *vcsm_usr_address( unsigned int handle )
+{
+   int rc;
+   struct vmcs_sm_ioctl_map map;
+
+   if ( (vcsm_handle == VCSM_INVALID_HANDLE) || (handle == 0) ) 
+   {
+      vcos_log_error( "[%s]: [%d]: invalid device or handle!",
+                      __func__,
+                      getpid() );
+
+      return NULL;
+   }
+
+   memset( &map, 0, sizeof(map) );
+
+   map.pid    = getpid();
+   map.handle = handle;
+
+   rc = ioctl( vcsm_handle,
+               VMCS_SM_IOCTL_MAP_USR_ADDRESS,
+               &map );
+
+   if ( rc < 0 )
+   {
+      vcos_log_error( "[%s]: [%d]: ioctl mapped-usr-address FAILED [%d] (pid: %d, addr: %x)",
+                      __func__,
+                      getpid(),
+                      rc,
+                      map.pid,
+                      map.addr );
+
+      return NULL;
+   }
+   else
+   {
+      vcos_log_trace( "[%s]: [%d]: ioctl mapped-usr-address %d (hdl: %x, addr: %x)",
+                      __func__,
+                      getpid(),
+                      rc,
+                      map.handle,
+                      map.addr );
+
+      return (void*)map.addr;
+   }
+}
+
+
+/* Retrieves a user opaque handle from a mapped user address
+** pointer.
+**
+** Returns:        0 on error
+**                 a non-zero opaque handle on success.
+*/
+unsigned int vcsm_usr_handle( void *usr_ptr )
+{
+   int rc;
+   struct vmcs_sm_ioctl_map map;
+
+   if ( (vcsm_handle == VCSM_INVALID_HANDLE) || (usr_ptr == NULL) ) 
+   {
+      vcos_log_error( "[%s]: [%d]: invalid device or null usr-ptr!",
+                      __func__,
+                      getpid() );
+
+      return 0;
+   }
+
+   memset( &map, 0, sizeof(map) );
+   
+   map.pid = getpid();
+   map.addr = (unsigned int) usr_ptr;
+
+   rc = ioctl( vcsm_handle,
+               VMCS_SM_IOCTL_MAP_USR_HDL,
+               &map );
+
+   if ( rc < 0 )
+   {
+      vcos_log_error( "[%s]: [%d]: ioctl mapped-usr-hdl FAILED [%d] (pid: %d, addr: %x)",
+                      __func__,
+                      getpid(),
+                      rc,
+                      map.pid,
+                      map.addr );
+
+      return 0;
+   }
+   else
+   {
+      vcos_log_trace( "[%s]: [%d]: ioctl mapped-usr-hdl %d (hdl: %x, addr: %x)",
+                      __func__,
+                      getpid(),
+                      rc,
+                      map.handle,
+                      map.addr );
+
+      return map.handle;                                 
+   }
+}
+
+
+/* Locks the memory associated with this opaque handle.
+**
+** Returns:        NULL on error
+**                 a valid pointer on success.
+**
+** A user MUST lock the handle received from vcsm_malloc
+** in order to be able to use the memory associated with it.
+**
+** On success, the pointer returned is only valid within
+** the lock content (ie until a corresponding vcsm_unlock_xx
+** is invoked).
+*/
+void *vcsm_lock( unsigned int handle )
+{
+   int rc;
+   struct vmcs_sm_ioctl_lock_unlock lock_unlock;
+   struct vmcs_sm_ioctl_size sz;
+   struct vmcs_sm_ioctl_map map;
+   struct vmcs_sm_ioctl_cache cache;
+   void *usr_ptr = NULL;
+
+   if ( (vcsm_handle == VCSM_INVALID_HANDLE) || (handle == 0) ) 
+   {
+      vcos_log_error( "[%s]: [%d]: invalid device or invalid handle!",
+                      __func__,
+                      getpid() );
+
+      goto out;
+   }
+
+   memset( &sz, 0, sizeof(sz) );
+   memset( &lock_unlock, 0, sizeof(lock_unlock) );
+   memset( &map, 0, sizeof(map) );
+   memset( &cache, 0, sizeof(cache) );
+
+   /* Verify what we want is valid.
+   */
+   sz.handle = handle;
+
+   rc = ioctl( vcsm_handle,
+               VMCS_SM_IOCTL_SIZE_USR_HDL,
+               &sz );
+
+   vcos_log_trace( "[%s]: [%d]: ioctl size-usr-hdl %d (hdl: %x) - size %u",
+                   __func__,
+                   getpid(),
+                   rc,
+                   sz.handle,
+                   sz.size );
+
+   /* We will not be able to lock the resource!
+   */
+   if ( (rc < 0) || (sz.size == 0) )
+   {
+      goto out;
+   }
+
+   /* Lock the allocated buffer all the way through videocore.
+   */
+   lock_unlock.handle    = sz.handle;
+
+   rc = ioctl( vcsm_handle,
+               VMCS_SM_IOCTL_MEM_LOCK,
+               &lock_unlock );
+
+   vcos_log_trace( "[%s]: [%d]: ioctl mem-lock %d (hdl: %x)",
+                   __func__,
+                   getpid(),
+                   rc,
+                   lock_unlock.handle );
+
+   /* We will not be able to lock the resource!
+   */
+   if ( rc < 0 )
+   {
+      goto out;
+   }
+
+   usr_ptr = (void *) lock_unlock.addr;
+
+   /* If applicable, invalidate the cache now.
+   */
+   if ( usr_ptr && sz.size )
+   {
+      cache.handle = sz.handle;
+      cache.addr   = (unsigned int) usr_ptr;
+      cache.size   = sz.size;
+
+      rc = ioctl( vcsm_handle,
+                  VMCS_SM_IOCTL_MEM_INVALID,
+                  &cache );
+
+      vcos_log_trace( "[%s]: [%d]: ioctl invalidate (cache) %d (hdl: %x, addr: %x, size: %u)",
+                      __func__,
+                      getpid(),
+                      rc,
+                      cache.handle,
+                      cache.addr,
+                      cache.size );
+
+      if ( rc < 0 )
+      {
+         vcos_log_error( "[%s]: [%d]: invalidate failed (rc: %d) - [%x;%x] - size: %u (hdl: %x) - cache incoherency",
+                         __func__,
+                         getpid(),
+                         rc,
+                         (unsigned int) cache.addr,
+                         (unsigned int) (cache.addr + cache.size),
+                         (unsigned int) (cache.addr + cache.size) - (unsigned int) cache.addr,
+                         cache.handle );
+      }
+   }
+
+   /* Done.
+   */
+   goto out;
+
+out:
+   return usr_ptr;
+}
+
+
+/* Locks the memory associated with this opaque handle.  The lock
+** also gives a chance to update the *host* cache behavior of the
+** allocated buffer if so desired.  The *videocore* cache behavior
+** of the allocated buffer cannot be changed by this call and such
+** attempt will be ignored.
+**
+** The system will attempt to honour the cache_update mode request,
+** the cache_result mode will provide the final answer on which cache
+** mode is really in use.  Failing to change the cache mode will not
+** result in a failure to lock the buffer as it is an application
+** decision to choose what to do if (cache_result != cache_update)
+**
+** The value returned in cache_result can only be considered valid if
+** the returned pointer is non NULL.  The cache_result pointer may be
+** NULL if the application does not care about the actual outcome of
+** its action with regards to the cache behavior change.
+**
+** Returns:        NULL on error
+**                 a valid pointer on success.
+**
+** A user MUST lock the handle received from vcsm_malloc
+** in order to be able to use the memory associated with it.
+**
+** On success, the pointer returned is only valid within
+** the lock content (ie until a corresponding vcsm_unlock_xx
+** is invoked).
+*/
+void *vcsm_lock_cache( unsigned int handle,
+                       VCSM_CACHE_TYPE_T cache_update,
+                       VCSM_CACHE_TYPE_T *cache_result )
+{
+   int rc;
+   struct vmcs_sm_ioctl_lock_cache lock_cache;
+   struct vmcs_sm_ioctl_chk chk;
+   struct vmcs_sm_ioctl_map map;
+   struct vmcs_sm_ioctl_cache cache;
+   struct vmcs_sm_ioctl_size sz;
+   void *usr_ptr = NULL;
+   VCSM_CACHE_TYPE_T new_cache;
+
+   if ( (vcsm_handle == VCSM_INVALID_HANDLE) || (handle == 0) ) 
+   {
+      vcos_log_error( "[%s]: [%d]: invalid device or invalid handle!",
+                      __func__,
+                      getpid() );
+
+      goto out;
+   }
+
+   memset( &chk, 0, sizeof(chk) );
+   memset( &sz, 0, sizeof(sz) );
+   memset( &lock_cache, 0, sizeof(lock_cache) );
+   memset( &map, 0, sizeof(map) );
+   memset( &cache, 0, sizeof(cache) );
+
+   /* Verify what we want is valid.
+   */
+   chk.handle = handle;
+
+   rc = ioctl( vcsm_handle,
+               VMCS_SM_IOCTL_CHK_USR_HDL,
+               &chk );
+
+   vcos_log_trace( "[%s]: [%d]: ioctl chk-usr-hdl %d (hdl: %x, addr: %x, sz: %u, cache: %d)",
+                   __func__,
+                   getpid(),
+                   rc,
+                   chk.handle,
+                   chk.addr,
+                   chk.size,
+                   chk.cache );
+
+   /* We will not be able to lock the resource!
+   */
+   if ( rc < 0 )
+   {
+      goto out;
+   }
+
+   /* Validate cache requirements.
+   */
+   if ( cache_update != (VCSM_CACHE_TYPE_T)chk.cache )
+   {
+      new_cache = vcsm_cache_table_lookup( (VCSM_CACHE_TYPE_T) chk.cache,
+                                           cache_update );
+      vcos_log_trace( "[%s]: [%d]: cache lookup hdl: %x: [cur %d ; req %d] -> new %d ",
+                      __func__,
+                      getpid(),
+                      chk.handle,
+                      (VCSM_CACHE_TYPE_T)chk.cache,
+                      cache_update,
+                      new_cache );
+
+      if ( (enum vmcs_sm_cache_e)new_cache == chk.cache )
+      {
+         /* Effectively no change.
+         */
+         if ( cache_result != NULL )
+         {
+            *cache_result = new_cache;
+         }
+         goto lock_default;
+      }
+   }
+   else
+   {
+      if ( cache_result != NULL )
+      {
+         *cache_result = (VCSM_CACHE_TYPE_T)chk.cache;
+      }
+      goto lock_default;
+   } 
+
+   /* At this point we know we want to lock the buffer and apply a cache
+   ** behavior change.  Start by cleaning out whatever is already setup.
+   */
+   if ( chk.addr && chk.size )
+   {
+      munmap( (void *)chk.addr, chk.size );
+
+      vcos_log_trace( "[%s]: [%d]: ioctl unmap hdl: %x",
+                      __func__,
+                      getpid(),
+                      chk.handle );
+   }
+
+   /* Lock and apply cache behavior change to the allocated buffer all the
+   ** way through videocore.
+   */
+   lock_cache.handle    = chk.handle;
+   lock_cache.cached    = (enum vmcs_sm_cache_e) new_cache;   /* Convenient one to one mapping. */
+
+   rc = ioctl( vcsm_handle,
+               VMCS_SM_IOCTL_MEM_LOCK_CACHE,
+               &lock_cache );
+
+   vcos_log_trace( "[%s]: [%d]: ioctl mem-lock-cache %d (hdl: %x)",
+                   __func__,
+                   getpid(),
+                   rc,
+                   lock_cache.handle );
+
+   /* We will not be able to lock the resource!
+   */
+   if ( rc < 0 )
+   {
+      goto out;
+   }
+
+   /* It is possible that this size was zero if the resource was
+   ** already un-mapped when we queried it, in such case we need
+   ** to figure out the size now to allow mapping to work.
+   */
+   if ( chk.size == 0 )
+   {
+      sz.handle = chk.handle;
+
+      rc = ioctl( vcsm_handle,
+                  VMCS_SM_IOCTL_SIZE_USR_HDL,
+                  &sz );
+
+      vcos_log_trace( "[%s]: [%d]: ioctl size-usr-hdl %d (hdl: %x) - size %u",
+                      __func__,
+                      getpid(),
+                      rc,
+                      sz.handle,
+                      sz.size );
+
+      /* We will not be able to map again the resource!
+      */
+      if ( (rc < 0) || (sz.size == 0) )
+      {
+         goto out;
+      }
+   }
+
+   /* Map the locked buffer into user space.
+   */
+   usr_ptr = mmap( 0,
+                   (chk.size != 0) ? chk.size : sz.size,
+                   PROT_READ | PROT_WRITE,
+                   MAP_SHARED,
+                   vcsm_handle,
+                   chk.handle );
+
+   if ( usr_ptr == NULL )
+   {
+      vcos_log_error( "[%s]: [%d]: mmap FAILED (hdl: %x)",
+                      __func__,
+                      getpid(),
+                      chk.handle );
+   }
+
+   /* If applicable, invalidate the cache now.
+   */
+   cache.size   = (chk.size != 0) ? chk.size : sz.size;
+   if ( usr_ptr && cache.size )
+   {
+      cache.handle = chk.handle;
+      cache.addr   = (unsigned int) usr_ptr;
+
+      rc = ioctl( vcsm_handle,
+                  VMCS_SM_IOCTL_MEM_INVALID,
+                  &cache );
+
+      vcos_log_trace( "[%s]: [%d]: ioctl invalidate (cache) %d (hdl: %x, addr: %x, size: %u)",
+                      __func__,
+                      getpid(),
+                      rc,
+                      cache.handle,
+                      cache.addr,
+                      cache.size );
+
+      if ( rc < 0 )
+      {
+         vcos_log_error( "[%s]: [%d]: invalidate failed (rc: %d) - [%x;%x] - size: %u (hdl: %x) - cache incoherency",
+                         __func__,
+                         getpid(),
+                         rc,
+                         (unsigned int) cache.addr,
+                         (unsigned int) (cache.addr + cache.size),
+                         (unsigned int) (cache.addr + cache.size) - (unsigned int) cache.addr,
+                         cache.handle );
+      }
+   }
+
+   /* Update the caller with the information it expects to see.
+   */
+   if ( cache_result != NULL )
+   {
+      *cache_result = new_cache;
+   }
+
+   /* Done.
+   */
+   goto out;
+
+
+lock_default:
+   usr_ptr = vcsm_lock ( handle );
+
+out:
+   return usr_ptr;
+}
+
+
+/* Unlocks the memory associated with this user mapped address.
+** Apply special processing that would override the otherwise
+** default behavior.
+**
+** If 'cache_no_flush' is specified:
+**    Do not flush cache as the result of the unlock (if cache
+**    flush was otherwise applicable in this case).
+**
+** Returns:        0 on success
+**                 -errno on error.
+**
+** After unlocking a mapped address, the user should no longer
+** attempt to reference it.
+*/
+int vcsm_unlock_ptr_sp( void *usr_ptr, int cache_no_flush )
+{
+   int rc;
+   struct vmcs_sm_ioctl_lock_unlock lock_unlock;
+   struct vmcs_sm_ioctl_map map;
+   struct vmcs_sm_ioctl_cache cache;
+
+   if ( (vcsm_handle == VCSM_INVALID_HANDLE) || (usr_ptr == NULL) ) 
+   {
+      vcos_log_error( "[%s]: [%d]: invalid device or invalid user-ptr!",
+                      __func__,
+                      getpid() );
+
+      rc = -EIO;
+      goto out;
+   }
+
+   memset( &map, 0, sizeof(map) );
+   memset( &lock_unlock, 0, sizeof(lock_unlock) );
+   memset( &cache, 0, sizeof(cache) );
+
+   /* Retrieve the handle of the memory we want to lock.
+   */
+   map.pid = getpid();
+   map.addr = (unsigned int) usr_ptr;
+
+   rc = ioctl( vcsm_handle,
+               VMCS_SM_IOCTL_MAP_USR_HDL,
+               &map );
+
+   vcos_log_trace( "[%s]: [%d]: ioctl mapped-usr-hdl %d (hdl: %x, addr: %x, sz: %u)",
+                   __func__,
+                   getpid(),
+                   rc,
+                   map.handle,
+                   map.addr,
+                   map.size );
+
+   /* We will not be able to flush/unlock the resource!
+   */
+   if ( rc < 0 )
+   {
+      goto out;
+   }
+
+   /* If applicable, flush the cache now.
+   */
+   if ( !cache_no_flush && map.addr && map.size )
+   {
+      cache.handle = map.handle;
+      cache.addr   = map.addr;
+      cache.size   = map.size;
+
+      rc = ioctl( vcsm_handle,
+                  VMCS_SM_IOCTL_MEM_FLUSH,
+                  &cache );
+
+      vcos_log_trace( "[%s]: [%d]: ioctl flush (cache) %d (hdl: %x, addr: %x, size: %u)",
+                      __func__,
+                      getpid(),
+                      rc,
+                      cache.handle,
+                      cache.addr,
+                      cache.size );
+
+      if ( rc < 0 )
+      {
+         vcos_log_error( "[%s]: [%d]: flush failed (rc: %d) - [%x;%x] - size: %u (hdl: %x) - cache incoherency",
+                         __func__,
+                         getpid(),
+                         rc,
+                         (unsigned int) cache.addr,
+                         (unsigned int) (cache.addr + cache.size),
+                         (unsigned int) (cache.addr + cache.size) - (unsigned int) cache.addr,
+                         cache.handle );
+      }
+   }
+
+   /* Unock the allocated buffer all the way through videocore.
+   */
+   lock_unlock.handle    = map.handle;  /* From above ioctl. */
+
+   rc = ioctl( vcsm_handle,
+               VMCS_SM_IOCTL_MEM_UNLOCK,
+               &lock_unlock );
+
+   vcos_log_trace( "[%s]: [%d]: ioctl mem-unlock %d (hdl: %x)",
+                   __func__,
+                   getpid(),
+                   rc,
+                   lock_unlock.handle );
+
+out:
+   return rc;
+}
+
+
+/* Unlocks the memory associated with this user mapped address.
+**
+** Returns:        0 on success
+**                 -errno on error.
+**
+** After unlocking a mapped address, the user should no longer
+** attempt to reference it.
+*/
+int vcsm_unlock_ptr( void *usr_ptr )
+{
+   return vcsm_unlock_ptr_sp( usr_ptr, 0 );
+}
+
+
+/* Unlocks the memory associated with this user opaque handle.
+** Apply special processing that would override the otherwise
+** default behavior.
+**
+** If 'cache_no_flush' is specified:
+**    Do not flush cache as the result of the unlock (if cache
+**    flush was otherwise applicable in this case).
+**
+** Returns:        0 on success
+**                 -errno on error.
+**
+** After unlocking an opaque handle, the user should no longer
+** attempt to reference the mapped addressed once associated
+** with it.
+*/
+int vcsm_unlock_hdl_sp( unsigned int handle, int cache_no_flush )
+{
+   int rc;
+   struct vmcs_sm_ioctl_lock_unlock lock_unlock;
+   struct vmcs_sm_ioctl_chk chk;
+   struct vmcs_sm_ioctl_cache cache;
+   struct vmcs_sm_ioctl_map map;
+
+   if ( (vcsm_handle == VCSM_INVALID_HANDLE) || (handle == 0) ) 
+   {
+      vcos_log_error( "[%s]: [%d]: invalid device or invalid handle!",
+                      __func__,
+                      getpid() );
+
+      rc = -EIO;
+      goto out;
+   }
+
+   memset( &chk, 0, sizeof(chk) );
+   memset( &lock_unlock, 0, sizeof(lock_unlock) );
+   memset( &cache, 0, sizeof(cache) );
+   memset( &map, 0, sizeof(map) );
+
+   /* Retrieve the handle of the memory we want to lock.
+   */
+   chk.handle = handle;
+
+   rc = ioctl( vcsm_handle,
+               VMCS_SM_IOCTL_CHK_USR_HDL,
+               &chk );
+
+   vcos_log_trace( "[%s]: [%d]: ioctl chk-usr-hdl %d (hdl: %x, addr: %x, sz: %u) nf %d",
+                   __func__,
+                   getpid(),
+                   rc,
+                   chk.handle,
+                   chk.addr,
+                   chk.size,
+                   cache_no_flush);
+
+   /* We will not be able to flush/unlock the resource!
+   */
+   if ( rc < 0 )
+   {
+      goto out;
+   }
+
+   /* If applicable, flush the cache now.
+   */
+   if ( !cache_no_flush && chk.addr && chk.size )
+   {
+      cache.handle = chk.handle;
+      cache.addr   = chk.addr;
+      cache.size   = chk.size;
+
+      rc = ioctl( vcsm_handle,
+                  VMCS_SM_IOCTL_MEM_FLUSH,
+                  &cache );
+
+      vcos_log_trace( "[%s]: [%d]: ioctl flush (cache) %d (hdl: %x)",
+                      __func__,
+                      getpid(),
+                      rc,
+                      cache.handle );
+
+      if ( rc < 0 )
+      {
+         vcos_log_error( "[%s]: [%d]: flush failed (rc: %d) - [%x;%x] - size: %u (hdl: %x) - cache incoherency",
+                         __func__,
+                         getpid(),
+                         rc,
+                         (unsigned int) cache.addr,
+                         (unsigned int) (cache.addr + cache.size),
+                         (unsigned int) (cache.addr + cache.size) - (unsigned int) cache.addr,
+                         cache.handle );
+      }
+   }
+
+   /* Unlock the allocated buffer all the way through videocore.
+   */
+   lock_unlock.handle    = chk.handle;
+
+   rc = ioctl( vcsm_handle,
+               VMCS_SM_IOCTL_MEM_UNLOCK,
+               &lock_unlock );
+
+   vcos_log_trace( "[%s]: [%d]: ioctl mem-unlock %d (hdl: %x)",
+                   __func__,
+                   getpid(),
+                   rc,
+                   lock_unlock.handle );
+
+out:
+   return rc;
+}
+
+
+/* Unlocks the memory associated with this user opaque handle.
+**
+** Returns:        0 on success
+**                 -errno on error.
+**
+** After unlocking an opaque handle, the user should no longer
+** attempt to reference the mapped addressed once associated
+** with it.
+*/
+int vcsm_unlock_hdl( unsigned int handle )
+{
+   return vcsm_unlock_hdl_sp( handle, 0 );
+}
+
+/* Resizes a block of memory allocated previously by vcsm_alloc.
+**
+** Returns:        0 on success
+**                 -errno on error.
+**
+** The handle must be unlocked by user prior to attempting any
+** resize action.
+**
+** On error, the original size allocated against the handle
+** remains available the same way it would be following a
+** successful vcsm_malloc.
+*/
+int vcsm_resize( unsigned int handle, unsigned int new_size )
+{
+   int rc;
+   struct vmcs_sm_ioctl_size sz;
+   struct vmcs_sm_ioctl_resize resize;
+   struct vmcs_sm_ioctl_lock_unlock lock_unlock;
+   struct vmcs_sm_ioctl_map map;
+   unsigned int size_aligned = new_size;
+   void *usr_ptr = NULL;
+
+   if ( (vcsm_handle == VCSM_INVALID_HANDLE) || (handle == 0) ) 
+   {
+      vcos_log_error( "[%s]: [%d]: invalid device or invalid handle!",
+                      __func__,
+                      getpid() );
+
+      rc = -EIO;
+      goto out;
+   }
+
+   memset( &sz, 0, sizeof(sz) );
+   memset( &resize, 0, sizeof(resize) );
+   memset( &lock_unlock, 0, sizeof(lock_unlock) );
+   memset( &map, 0, sizeof(map) );
+
+   /* Ask for page aligned.
+   */
+   size_aligned = (new_size + vcsm_page_size - 1) & ~(vcsm_page_size - 1);
+
+   /* Verify what we want is valid.
+   */
+   sz.handle = handle;
+
+   rc = ioctl( vcsm_handle,
+               VMCS_SM_IOCTL_SIZE_USR_HDL,
+               &sz );
+
+   vcos_log_trace( "[%s]: [%d]: ioctl size-usr-hdl %d (hdl: %x) - size %u",
+                   __func__,
+                   getpid(),
+                   rc,
+                   sz.handle,
+                   sz.size );
+
+   /* We will not be able to free up the resource!
+   **
+   ** However, the driver will take care of it eventually once the device is
+   ** closed (or dies), so this is not such a dramatic event...
+   */
+   if ( (rc < 0) || (sz.size == 0) )
+   {
+      goto out;
+   }
+
+   /* We first need to unmap the resource
+   */
+   usr_ptr = (void *) vcsm_usr_address( sz.handle );
+   if ( usr_ptr != NULL )
+   {
+      munmap( usr_ptr, sz.size );
+
+      vcos_log_trace( "[%s]: [%d]: ioctl unmap hdl: %x",
+                      __func__,
+                      getpid(),
+                      sz.handle );
+   }
+   else
+   {
+      vcos_log_trace( "[%s]: [%d]: freeing unmapped area (hdl: %x)",
+                      __func__,
+                      getpid(),
+                      map.handle );
+   }
+
+   /* Resize the allocated buffer all the way through videocore.
+   */
+   resize.handle    = sz.handle;
+   resize.new_size  = size_aligned;
+
+   rc = ioctl( vcsm_handle,
+               VMCS_SM_IOCTL_MEM_RESIZE,
+               &resize );
+
+   vcos_log_trace( "[%s]: [%d]: ioctl resize %d (hdl: %x)",
+                   __func__,
+                   getpid(),
+                   rc,
+                   resize.handle );
+
+   /* Although resized, the resource will not be usable.
+   */
+   if ( rc < 0 )
+   {
+      goto out;
+   }
+
+   /* Remap the resource
+   */
+   if (  mmap( 0,
+               resize.new_size,
+               PROT_READ | PROT_WRITE,
+               MAP_SHARED,
+               vcsm_handle,
+               resize.handle ) == NULL )
+   {
+      vcos_log_error( "[%s]: [%d]: mmap FAILED (hdl: %x)",
+                      __func__,
+                      getpid(),
+                      resize.handle );
+
+      /* At this point, it is not yet a problem that we failed to
+      ** map the buffer because it will not be used right away.
+      **
+      ** Possibly the mapping may work the next time the user tries
+      ** to lock the buffer for usage, and if it still fails, it will
+      ** be up to the user to deal with it.
+      */
+      // goto out;
+   }
+
+out:
+   return rc;
+}
+
+
+/* Flush or invalidate the memory associated with this user opaque handle
+**
+** Returns:        non-zero on error
+**
+** structure contains a list of flush/invalidate commands
+** See header file
+*/
+int vcsm_clean_invalid( struct vcsm_user_clean_invalid_s *s )
+{
+   int rc = 0;
+   struct vmcs_sm_ioctl_clean_invalid cache;
+
+   if ( vcsm_handle == VCSM_INVALID_HANDLE )
+   {
+      vcos_log_error( "[%s]: [%d]: invalid device or invalid handle!",
+                      __func__,
+                      getpid() );
+
+      rc = -1;
+      goto out;
+   }
+
+   memcpy( &cache, s, sizeof cache );
+
+   rc = ioctl( vcsm_handle,
+                VMCS_SM_IOCTL_MEM_CLEAN_INVALID,
+                &cache );
+
+   /* Done.
+   */
+   goto out;
+
+out:
+   return rc;
+}
+
+/* Flush or invalidate the memory associated with this user opaque handle
+**
+** Returns:        non-zero on error
+**
+** structure contains a list of flush/invalidate commands
+** See header file
+*/
+int vcsm_clean_invalid2( struct vcsm_user_clean_invalid2_s *s )
+{
+   int rc = 0;
+
+   if ( vcsm_handle == VCSM_INVALID_HANDLE )
+   {
+      vcos_log_error( "[%s]: [%d]: invalid device or invalid handle!",
+                      __func__,
+                      getpid() );
+
+      rc = -1;
+      goto out;
+   }
+
+   rc = ioctl( vcsm_handle,
+                VMCS_SM_IOCTL_MEM_CLEAN_INVALID2,
+                s );
+
+   /* Done.
+   */
+   goto out;
+
+out:
+   return rc;
+}
+
+/* Imports a dmabuf, and binds it to a VCSM handle and MEM_HANDLE_T
+**
+** Returns:        0 on error
+**                 a non-zero opaque handle on success.
+**
+** On success, the user must invoke vcsm_lock with the returned opaque
+** handle to gain access to the memory associated with the opaque handle.
+** When finished using the memory, the user calls vcsm_unlock_xx (see those
+** function definition for more details on the one that can be used).
+** Use vcsm_release to detach from the dmabuf (VideoCore may still hold
+** a reference to the buffer until it has finished with the buffer).
+**
+*/
+unsigned int vcsm_import_dmabuf( int dmabuf, char *name )
+{
+   struct vmcs_sm_ioctl_import_dmabuf import;
+   int rc;
+
+   if ( vcsm_handle == VCSM_INVALID_HANDLE )
+   {
+      vcos_log_error( "[%s]: [%d]: invalid device or invalid handle!",
+                      __func__,
+                      getpid() );
+
+      rc = -1;
+      goto error;
+   }
+
+   memset( &import, 0, sizeof(import) );
+
+   /* Map the buffer on videocore via the VCSM (Videocore Shared Memory) interface. */
+   import.dmabuf_fd = dmabuf;
+   import.cached = VMCS_SM_CACHE_NONE; //Support no caching for now - makes it easier for cache management
+   if ( name != NULL )
+   {
+      memcpy ( import.name, name, 32 );
+   }
+   rc = ioctl( vcsm_handle,
+               VMCS_SM_IOCTL_MEM_IMPORT_DMABUF,
+               &import );
+
+   if ( rc < 0 || import.handle == 0 )
+   {
+      vcos_log_error( "[%s]: [%d] [%s]: ioctl mem-import-dmabuf FAILED [%d] (hdl: %x)",
+                      __func__,
+                      getpid(),
+                      import.name,
+                      rc,
+                      import.handle );
+      goto error;
+   }
+
+   vcos_log_trace( "[%s]: [%d] [%s]: ioctl mem-import-dmabuf %d (hdl: %x)",
+                   __func__,
+                   getpid(),
+                   import.name,
+                   rc,
+                   import.handle );
+
+   return import.handle;
+
+error:
+   if ( import.handle )
+   {
+      vcsm_free( import.handle );
+   }
+   return 0;
+}
diff --git a/host_applications/linux/libs/sm/user-vcsm.h b/host_applications/linux/libs/sm/user-vcsm.h
new file mode 100755 (executable)
index 0000000..f3afaf8
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __USER_VCSM__H__INCLUDED__
+#define __USER_VCSM__H__INCLUDED__
+
+/* VideoCore Shared Memory - user interface library.
+**
+** This library provides all the necessary abstraction for any application to
+** make use of the shared memory service which is distributed across a kernel
+** driver and a videocore service.
+**
+** It is an application design decision to choose or not to use this service.
+**
+** The logical flow of operations that a user application needs to follow when
+** using this service is:
+**
+**       1) Initialize the service.
+**       2) Allocate shared memory blocks.
+**       3) Start using the allocated blocks.
+**          - In order to gain ownership on a block, lock the allocated block,
+**            locking a block returns a valid address that the user application
+**            can access.
+**          - When finished with using the block for the current execution cycle
+**            or function, and so when giving up the ownership, unlock the block.
+**       4) A block can be locked/unlocked as many times required - within or outside
+**          of - a specific execution context.
+**       5) To completely release an allocated block, free it.
+**       6) If the service is no longer required, terminate it.
+**
+**
+** Some generic considerations:
+
+** Allocating memory blocks.
+**
+**   Memory blocks can be allocated in different manners depending on the cache
+**   behavior desired.  A given block can either be:
+
+**       - Allocated in a non cached fashion all the way through host and videocore.
+**       - Allocated in a cached fashion on host OR videocore.
+**       - Allocated in a cached fashion on host AND videocore.
+**
+**   It is an application decision to determine how to allocate a block.  Evidently
+**   if the application will be doing substantial read/write accesses to a given block,
+**   it is recommended to allocate the block at least in a 'host cached' fashion for
+**   better results.
+**
+**
+** Locking memory blocks.
+**
+**   When the memory block has been allocated in a host cached fashion, locking the
+**   memory block (and so taking ownership of it) will trigger a cache invalidation.
+**
+**   For the above reason and when using host cached allocation, it is important that
+**   an application properly implements the lock/unlock mechanism to ensure cache will
+**   stay coherent, otherwise there is no guarantee it will at all be.
+**
+**   It is possible to dynamically change the host cache behavior (ie cached or non
+**   cached) of a given allocation without needing to free and re-allocate the block.
+**   This feature can be useful for such application which requires access to the block
+**   only at certain times and not otherwise.  By changing the cache behavior dynamically
+**   the application can optimize performances for a given duration of use.
+**   Such dynamic cache behavior remapping only applies to host cache and not videocore
+**   cache.  If one requires to change the videocore cache behavior, then a new block
+**   must be created to replace the old one.
+**
+**   On successful locking, a valid pointer is returned that the application can use
+**   to access to data inside the block.  There is no guarantee that the pointer will
+**   stay valid following the unlock action corresponding to this lock.
+**
+**
+** Unocking memory blocks.
+**
+**   When the memory block has been allocated in a host cached fashion, unlocking the
+**   memory block (and so forgiving its ownership) will trigger a cache flush unless
+**   explicitely asked not to flush the cache for performances reasons.
+**
+**   For the above reason and when using host cached allocation, it is important that
+**   an application properly implements the lock/unlock mechanism to ensure cache will
+**   stay coherent, otherwise there is no guarantee it will at all be.
+**
+**
+** A complete API is defined below.
+*/
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/* Different status that can be dumped.
+*/
+typedef enum
+{
+   VCSM_STATUS_VC_WALK_ALLOC = 0,   // Walks *all* the allocation on videocore.
+                                    // Result of the walk is seen in the videocore
+                                    // log.
+   VCSM_STATUS_HOST_WALK_MAP,       // Walks the *full* mapping allocation on host
+                                    // driver (ie for all processes).  Result of
+                                    // the walk is seen in the kernel log.
+   VCSM_STATUS_HOST_WALK_PID_MAP,   // Walks the per process mapping allocation on host
+                                    // driver (for current process).  Result of
+                                    // the walk is seen in the kernel log.
+   VCSM_STATUS_HOST_WALK_PID_ALLOC, // Walks the per process host allocation on host
+                                    // driver (for current process).  Result of
+                                    // the walk is seen in the kernel log.
+   VCSM_STATUS_VC_MAP_ALL,          // Equivalent to both VCSM_STATUS_VC_WALK_ALLOC and
+                                    // VCSM_STATUS_HOST_WALK_MAP.
+                                    //
+   VCSM_STATUS_NONE,                // Must be last - invalid.
+
+} VCSM_STATUS_T;
+
+/* Different kind of cache behavior.
+*/
+typedef enum
+{
+   VCSM_CACHE_TYPE_NONE = 0,        // No caching applies.
+   VCSM_CACHE_TYPE_HOST,            // Allocation is cached on host (user space).
+   VCSM_CACHE_TYPE_VC,              // Allocation is cached on videocore.
+   VCSM_CACHE_TYPE_HOST_AND_VC,     // Allocation is cached on both host and videocore.
+
+} VCSM_CACHE_TYPE_T;
+
+/* Initialize the vcsm processing.
+**
+** Must be called once before attempting to do anything else.
+**
+** Returns 0 on success, -1 on error.
+*/
+int vcsm_init( void );
+
+
+/* Terminates the vcsm processing.
+**
+** Must be called vcsm services are no longer needed, it will
+** take care of removing any allocation under the current process
+** control if deemed necessary.
+*/
+void vcsm_exit( void );
+
+
+/* Queries the status of the the vcsm.
+**
+** Triggers dump of various kind of information, see the
+** different variants specified in VCSM_STATUS_T.
+**
+** Pid is optional.
+*/
+void vcsm_status( VCSM_STATUS_T status, int pid );
+
+
+/* Allocates a non-cached block of memory of size 'size' via the vcsm memory
+** allocator.
+**
+** Returns:        0 on error
+**                 a non-zero opaque handle on success.
+**
+** On success, the user must invoke vcsm_lock with the returned opaque
+** handle to gain access to the memory associated with the opaque handle.
+** When finished using the memory, the user calls vcsm_unlock_xx (see those
+** function definition for more details on the one that can be used).
+** 
+** A well behaved application should make every attempt to lock/unlock
+** only for the duration it needs to access the memory data associated with
+** the opaque handle.
+*/
+unsigned int vcsm_malloc( unsigned int size, char *name );
+
+
+/* Allocates a cached block of memory of size 'size' via the vcsm memory
+** allocator, the type of caching requested is passed as argument of the
+** function call.
+**
+** Returns:        0 on error
+**                 a non-zero opaque handle on success.
+**
+** On success, the user must invoke vcsm_lock with the returned opaque
+** handle to gain access to the memory associated with the opaque handle.
+** When finished using the memory, the user calls vcsm_unlock_xx (see those
+** function definition for more details on the one that can be used).
+** 
+** A well behaved application should make every attempt to lock/unlock
+** only for the duration it needs to access the memory data associated with
+** the opaque handle.
+*/
+unsigned int vcsm_malloc_cache( unsigned int size, VCSM_CACHE_TYPE_T cache, char *name );
+
+
+/* Shares an allocated block of memory via the vcsm memory allocator.
+**
+** Returns:        0 on error
+**                 a non-zero opaque handle on success.
+**
+** On success, the user must invoke vcsm_lock with the returned opaque
+** handle to gain access to the memory associated with the opaque handle.
+** When finished using the memory, the user calls vcsm_unlock_xx (see those
+** function definition for more details on the one that can be used).
+**
+** A well behaved application should make every attempt to lock/unlock
+** only for the duration it needs to access the memory data associated with
+** the opaque handle.
+*/
+unsigned int vcsm_malloc_share( unsigned int handle );
+
+
+/* Resizes a block of memory allocated previously by vcsm_alloc.
+**
+** Returns:        0 on success
+**                 -errno on error.
+**
+** The handle must be unlocked by user prior to attempting any
+** resize action.
+**
+** On error, the original size allocated against the handle
+** remains available the same way it would be following a
+** successful vcsm_malloc.
+*/
+int vcsm_resize( unsigned int handle, unsigned int new_size );
+
+
+/* Frees a block of memory that was successfully allocated by
+** a prior call the vcms_alloc.
+**
+** The handle should be considered invalid upon return from this
+** call.
+**
+** Whether any memory is actually freed up or not as the result of
+** this call will depends on many factors, if all goes well it will
+** be freed.  If something goes wrong, the memory will likely end up
+** being freed up as part of the vcsm_exit process.  In the end the
+** memory is guaranteed to be freed one way or another.
+*/
+void vcsm_free( unsigned int handle );
+
+
+/* Retrieves a videocore opaque handle from a mapped user address
+** pointer.  The videocore handle will correspond to the actual
+** memory mapped in videocore.
+**
+** Returns:        0 on error
+**                 a non-zero opaque handle on success.
+**
+** Note: the videocore opaque handle is distinct from the user
+**       opaque handle (allocated via vcsm_malloc) and it is only
+**       significant for such application which knows what to do
+**       with it, for the others it is just a number with little
+**       use since nothing can be done with it (in particular
+**       for safety reason it cannot be used to map anything).
+*/
+unsigned int vcsm_vc_hdl_from_ptr( void *usr_ptr );
+
+
+/* Retrieves a videocore opaque handle from a opaque handle
+** pointer.  The videocore handle will correspond to the actual
+** memory mapped in videocore.
+**
+** Returns:        0 on error
+**                 a non-zero opaque handle on success.
+**
+** Note: the videocore opaque handle is distinct from the user
+**       opaque handle (allocated via vcsm_malloc) and it is only
+**       significant for such application which knows what to do
+**       with it, for the others it is just a number with little
+**       use since nothing can be done with it (in particular
+**       for safety reason it cannot be used to map anything).
+*/
+unsigned int vcsm_vc_hdl_from_hdl( unsigned int handle );
+
+
+/* Retrieves a user opaque handle from a mapped user address
+** pointer.
+**
+** Returns:        0 on error
+**                 a non-zero opaque handle on success.
+*/
+unsigned int vcsm_usr_handle( void *usr_ptr );
+
+
+/* Retrieves a mapped user address from an opaque user
+** handle.
+**
+** Returns:        0 on error
+**                 a non-zero address on success.
+**
+** On success, the address corresponds to the pointer
+** which can access the data allocated via the vcsm_malloc
+** call.
+*/
+void *vcsm_usr_address( unsigned int handle );
+
+
+/* Locks the memory associated with this opaque handle.
+**
+** Returns:        NULL on error
+**                 a valid pointer on success.
+**
+** A user MUST lock the handle received from vcsm_malloc
+** in order to be able to use the memory associated with it.
+**
+** On success, the pointer returned is only valid within
+** the lock content (ie until a corresponding vcsm_unlock_xx
+** is invoked).
+*/
+void *vcsm_lock( unsigned int handle );
+
+
+/* Locks the memory associated with this opaque handle.  The lock
+** also gives a chance to update the *host* cache behavior of the
+** allocated buffer if so desired.  The *videocore* cache behavior
+** of the allocated buffer cannot be changed by this call and such
+** attempt will be ignored.
+**
+** The system will attempt to honour the cache_update mode request,
+** the cache_result mode will provide the final answer on which cache
+** mode is really in use.  Failing to change the cache mode will not
+** result in a failure to lock the buffer as it is an application
+** decision to choose what to do if (cache_result != cache_update)
+**
+** The value returned in cache_result can only be considered valid if
+** the returned pointer is non NULL.  The cache_result pointer may be
+** NULL if the application does not care about the actual outcome of
+** its action with regards to the cache behavior change.
+**
+** Returns:        NULL on error
+**                 a valid pointer on success.
+**
+** A user MUST lock the handle received from vcsm_malloc
+** in order to be able to use the memory associated with it.
+**
+** On success, the pointer returned is only valid within
+** the lock content (ie until a corresponding vcsm_unlock_xx
+** is invoked).
+*/
+void *vcsm_lock_cache( unsigned int handle,
+                       VCSM_CACHE_TYPE_T cache_update,
+                       VCSM_CACHE_TYPE_T *cache_result );
+
+
+/* Unlocks the memory associated with this user mapped address.
+**
+** Returns:        0 on success
+**                 -errno on error.
+**
+** After unlocking a mapped address, the user should no longer
+** attempt to reference it.
+*/
+int vcsm_unlock_ptr( void *usr_ptr );
+
+
+/* Unlocks the memory associated with this user mapped address.
+** Apply special processing that would override the otherwise
+** default behavior.
+**
+** If 'cache_no_flush' is specified:
+**    Do not flush cache as the result of the unlock (if cache
+**    flush was otherwise applicable in this case).
+**
+** Returns:        0 on success
+**                 -errno on error.
+**
+** After unlocking a mapped address, the user should no longer
+** attempt to reference it.
+*/
+int vcsm_unlock_ptr_sp( void *usr_ptr, int cache_no_flush );
+
+
+/* Unlocks the memory associated with this user opaque handle.
+**
+** Returns:        0 on success
+**                 -errno on error.
+**
+** After unlocking an opaque handle, the user should no longer
+** attempt to reference the mapped addressed once associated
+** with it.
+*/
+int vcsm_unlock_hdl( unsigned int handle );
+
+
+/* Unlocks the memory associated with this user opaque handle.
+** Apply special processing that would override the otherwise
+** default behavior.
+**
+** If 'cache_no_flush' is specified:
+**    Do not flush cache as the result of the unlock (if cache
+**    flush was otherwise applicable in this case).
+**
+** Returns:        0 on success
+**                 -errno on error.
+**
+** After unlocking an opaque handle, the user should no longer
+** attempt to reference the mapped addressed once associated
+** with it.
+*/
+int vcsm_unlock_hdl_sp( unsigned int handle, int cache_no_flush );
+
+/* Clean and/or invalidate the memory associated with this user opaque handle
+**
+** Returns:        non-zero on error
+**
+** structure contains a list of flush/invalidate commands. Commands are:
+** 0: nop
+** 1: invalidate       given virtual range in L1/L2
+** 2: clean            given virtual range in L1/L2
+** 3: clean+invalidate given virtual range in L1/L2
+*/
+struct vcsm_user_clean_invalid_s {
+   struct {
+      unsigned int cmd;
+      unsigned int handle;
+      unsigned int addr;
+      unsigned int size;
+   } s[8];
+};
+
+int vcsm_clean_invalid( struct vcsm_user_clean_invalid_s *s );
+
+struct vcsm_user_clean_invalid2_s {
+       unsigned char op_count;
+       unsigned char zero[3];
+       struct vcsm_user_clean_invalid2_block_s {
+               unsigned short invalidate_mode;
+               unsigned short block_count;
+               void *   start_address;
+               unsigned int block_size;
+               unsigned int inter_block_stride;
+       } s[0];
+};
+
+int vcsm_clean_invalid2( struct vcsm_user_clean_invalid2_s *s );
+
+unsigned int vcsm_import_dmabuf( int dmabuf, char *name );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __USER_VCSM__H__INCLUDED__ */
+
diff --git a/host_applications/vmcs/test_apps/mmalcam/mmalcam.c b/host_applications/vmcs/test_apps/mmalcam/mmalcam.c
new file mode 100755 (executable)
index 0000000..294349e
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include "mmalcam.h"
+
+#include "interface/mmal/mmal_logging.h"
+
+#define VIEWFINDER_LAYER      2
+#define DEFAULT_VIDEO_FORMAT  "1280x720:h264";
+#define DEFAULT_BIT_RATE      5000000
+#define DEFAULT_CAM_NUM       0
+
+struct {
+   const char *name;
+   MMALCAM_CHANGE_T value;
+} mmalcam_change_table[] = {
+   { "image_effect", MMALCAM_CHANGE_IMAGE_EFFECT },
+   { "rotation", MMALCAM_CHANGE_ROTATION },
+   { "zoom", MMALCAM_CHANGE_ZOOM },
+   { "focus", MMALCAM_CHANGE_FOCUS },
+   { "drc", MMALCAM_CHANGE_DRC },
+   { "hdr", MMALCAM_CHANGE_HDR },
+   { "contrast", MMALCAM_CHANGE_CONTRAST },
+   { "brightness", MMALCAM_CHANGE_BRIGHTNESS },
+   { "saturation", MMALCAM_CHANGE_SATURATION },
+   { "sharpness", MMALCAM_CHANGE_SHARPNESS },
+};
+
+static int stop;
+static VCOS_THREAD_T camcorder_thread;
+static MMALCAM_BEHAVIOUR_T camcorder_behaviour;
+static uint32_t sleepy_time;
+static MMAL_BOOL_T stopped_already;
+
+/* Utility functions used by test program */
+static void *test_mmal_camcorder(void *id);
+static void test_signal_handler(int signum);
+static void test_mmalcam_dump_stats(const char *title, MMAL_PARAMETER_STATISTICS_T* stats);
+static int test_parse_cmdline(int argc, const char **argv);
+
+/*****************************************************************************/
+int main(int argc, const char **argv)
+{
+   VCOS_THREAD_ATTR_T attrs;
+   VCOS_STATUS_T status;
+   int result = 0;
+
+   vcos_log_register("mmalcam", VCOS_LOG_CATEGORY);
+   printf("MMAL Camera Test App\n");
+   signal(SIGINT, test_signal_handler);
+
+   camcorder_behaviour.layer = VIEWFINDER_LAYER;
+   camcorder_behaviour.vformat = DEFAULT_VIDEO_FORMAT;
+   camcorder_behaviour.zero_copy = 1;
+   camcorder_behaviour.bit_rate = DEFAULT_BIT_RATE;
+   camcorder_behaviour.focus_test = MMAL_PARAM_FOCUS_MAX;
+   camcorder_behaviour.camera_num = DEFAULT_CAM_NUM;
+
+   if(test_parse_cmdline(argc, argv))
+   {
+      result = -1;
+      goto error;
+   }
+
+   status = vcos_semaphore_create(&camcorder_behaviour.init_sem, "mmalcam-init", 0);
+   vcos_assert(status == VCOS_SUCCESS);
+
+   vcos_thread_attr_init(&attrs);
+   if (vcos_thread_create(&camcorder_thread, "mmal camcorder", &attrs, test_mmal_camcorder, &camcorder_behaviour) != VCOS_SUCCESS)
+   {
+      LOG_ERROR("Thread creation failure");
+      result = -2;
+      goto error;
+   }
+
+   vcos_semaphore_wait(&camcorder_behaviour.init_sem);
+   if (camcorder_behaviour.init_result != MMALCAM_INIT_SUCCESS)
+   {
+      LOG_ERROR("Initialisation failed: %d", camcorder_behaviour.init_result);
+      result = (int)camcorder_behaviour.init_result;
+      goto error;
+   }
+
+   if (sleepy_time != 0)
+   {
+      sleep(sleepy_time);
+      stop = 1;
+   }
+
+error:
+   LOG_TRACE("Waiting for camcorder thread to terminate");
+   vcos_thread_join(&camcorder_thread, NULL);
+
+   test_mmalcam_dump_stats("Render", &camcorder_behaviour.render_stats);
+   if (camcorder_behaviour.uri)
+      test_mmalcam_dump_stats("Encoder", &camcorder_behaviour.encoder_stats);
+
+   vcos_semaphore_delete(&camcorder_behaviour.init_sem);
+   return result;
+}
+
+
+/*****************************************************************************/
+static void *test_mmal_camcorder(void *id)
+{
+   MMALCAM_BEHAVIOUR_T *behaviour = (MMALCAM_BEHAVIOUR_T *)id;
+   int value;
+
+   value = test_mmal_start_camcorder(&stop, behaviour);
+
+   LOG_TRACE("Thread terminating, result %d", value);
+   return (void *)value;
+}
+
+/*****************************************************************************/
+static void test_signal_handler(int signum)
+{
+   (void)signum;
+
+   if (stopped_already)
+   {
+      LOG_ERROR("Killing program");
+      exit(255);
+   }
+   else
+   {
+      LOG_ERROR("Stopping normally. CTRL+C again to kill program");
+      stop = 1;
+      stopped_already = 1;
+   }
+}
+
+/*****************************************************************************/
+static void test_mmalcam_dump_stats(const char *title, MMAL_PARAMETER_STATISTICS_T* stats)
+{
+   printf("[%s]\n", title);
+   printf("buffer_count: %u\n", stats->buffer_count);
+   printf("frame_count: %u\n", stats->frame_count);
+   printf("frames_skipped: %u\n", stats->frames_skipped);
+   printf("frames_discarded: %u\n", stats->frames_discarded);
+   printf("eos_seen: %u\n", stats->eos_seen);
+   printf("maximum_frame_bytes: %u\n", stats->maximum_frame_bytes);
+   printf("total_bytes_hi: %u\n", (uint32_t)(stats->total_bytes >> 32));
+   printf("total_bytes_lo: %u\n", (uint32_t)(stats->total_bytes));
+   printf("corrupt_macroblocks: %u\n", stats->corrupt_macroblocks);
+}
+
+/*****************************************************************************/
+static MMAL_BOOL_T test_mmalcam_parse_rect(const char *str, MMAL_RECT_T *rect)
+{
+   /* coverity[secure_coding] Only reading integers, so can't overflow */
+   return sscanf(str, "%d,%d,%d,%d", &rect->x, &rect->y, &rect->width, &rect->height) == 4;
+}
+
+/*****************************************************************************/
+static int test_parse_cmdline(int argc, const char **argv)
+{
+   int i;
+   int passed_options = 0;
+
+   /* Parse the command line arguments */
+   for(i = 1; i < argc; i++)
+   {
+      if (!argv[i]) continue;
+
+      if (passed_options || argv[i][0] != '-')
+      {
+         /* Non-option argument */
+         continue;
+      }
+
+      /* We are now dealing with command line options */
+      switch(argv[i][1])
+      {
+      case '-': passed_options = 1; break;
+      case 'h': goto usage;
+      case 'o': if (i+1 >= argc) goto invalid_option;
+         camcorder_behaviour.uri = argv[++i];
+         break;
+      case 'v': if (i+1 >= argc) goto invalid_option;
+         camcorder_behaviour.vformat = argv[i+1];
+         break;
+      case 'r': if (i+1 >= argc) goto invalid_option;
+         if (!test_mmalcam_parse_rect(argv[i+1], &camcorder_behaviour.display_area)) goto invalid_option;
+         i++;
+         break;
+      case 'c': if (i+2 >= argc) goto invalid_option;
+         {
+            uint32_t table_index;
+
+            if (sscanf(argv[i+1], "%u", &camcorder_behaviour.seconds_per_change) != 1) goto invalid_option;
+
+            for (table_index = 0; table_index < countof(mmalcam_change_table); table_index++)
+               if (strcmp(mmalcam_change_table[table_index].name, argv[i+2]) == 0)
+                  break;
+            if (table_index >= countof(mmalcam_change_table)) goto invalid_option;
+
+            camcorder_behaviour.change = mmalcam_change_table[table_index].value;
+         }
+         break;
+      case 't': if (i+1 >= argc) goto invalid_option;
+         if (sscanf(argv[i+1], "%u", &sleepy_time) != 1) goto invalid_option;
+         i++;
+         break;
+      case 'f': if (i+1 >= argc) goto invalid_option;
+         camcorder_behaviour.frame_rate.den = 1;
+         if (sscanf(argv[i+1], "%u/%u", &camcorder_behaviour.frame_rate.num, &camcorder_behaviour.frame_rate.den) == 0) goto invalid_option;
+         i++;
+         break;
+      case 'x': camcorder_behaviour.tunneling = 1; break;
+      case 'z': camcorder_behaviour.zero_copy = (argv[i][2] != '!'); break;
+      case 'O': camcorder_behaviour.opaque = 1; break;
+      case 'b': if (i+1 >= argc) goto invalid_option;
+         if (sscanf(argv[i+1], "%u", &camcorder_behaviour.bit_rate) == 0) goto invalid_option;
+         i++;
+         break;
+      case 'a': if (i+1 >= argc) goto invalid_option;
+         if (sscanf(argv[i+1], "%u", &camcorder_behaviour.focus_test) == 0) goto invalid_option;
+         if (camcorder_behaviour.focus_test > MMAL_PARAM_FOCUS_EDOF) goto invalid_option;
+         i++;
+         break;
+      case 'n': if (i+1 >= argc) goto invalid_option;
+         if (sscanf(argv[i+1], "%u", &camcorder_behaviour.camera_num) == 0) goto invalid_option;
+         i++;
+         break;
+      default: goto invalid_option;
+      }
+      continue;
+   }
+
+   return 0;
+
+ invalid_option:
+   printf("invalid command line option (%s)\n", argv[i]);
+
+ usage:
+   {
+      const char *program;
+
+      program = strrchr(argv[0], '\\');
+      if (program)
+         program++;
+      else
+      {
+         program = strrchr(argv[0], '/');
+         if (program)
+            program++;
+         else
+            program = argv[0];
+      }
+      printf("usage: %s [options]\n", program);
+      printf("options list:\n");
+      printf(" -h          : help\n");
+      printf(" -o <file>   : write encoded output to <file>\n");
+      printf(" -v <format> : set video resolution and encoding format (defaults to '1280x720:h264')\n");
+      printf(" -r <r>      : put viewfinder at position <r>, given as x,y,width,height\n");
+      printf(" -c <n> <x>  : change camera parameter every <n> seconds.\n");
+      printf("                The parameter changed is defined by <x>, one of\n");
+      printf("                image_effect, rotation, zoom, focus, hdr, drc, contrast,\n");
+      printf("                brightness, saturation, sharpness\n");
+      printf(" -t <n>      : operate camera for <n> seconds\n");
+      printf(" -f <n>[/<d>]: set camera frame rate to <n>/<d>, where <d> is 1 if not given\n");
+      printf(" -x          : use tunneling\n");
+      printf(" -z          : use zero copy buffers (default)\n");
+      printf(" -z!         : use full copy buffers\n");
+      printf(" -O          : use opaque images\n");
+      printf(" -b <n>      : use <n> as the bitrate (bits/s)\n");
+      printf(" -a <n>      : Set to focus mode <n> (autofocus will cycle). Use MMAL_PARAM_FOCUS_T values.\n");
+      printf(" -n <n>      : Set camera number <n>. Use MMAL_PARAMETER_CAMERA_NUM values.\n");
+   }
+   return 1;
+}
diff --git a/host_applications/vmcs/test_apps/mmalcam/mmalcam.h b/host_applications/vmcs/test_apps/mmalcam/mmalcam.h
new file mode 100755 (executable)
index 0000000..c8b0031
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef MMALCAM_MMALCAM_H_
+#define MMALCAM_MMALCAM_H_
+
+#define VCOS_LOG_CATEGORY (&mmalcam_log_category)
+#include "interface/vcos/vcos.h"
+#include "interface/mmal/mmal.h"
+
+extern VCOS_LOG_CAT_T mmalcam_log_category;
+
+typedef enum
+{
+   MMALCAM_CHANGE_NONE,
+   MMALCAM_CHANGE_IMAGE_EFFECT,
+   MMALCAM_CHANGE_ROTATION,
+   MMALCAM_CHANGE_ZOOM,
+   MMALCAM_CHANGE_FOCUS,
+   MMALCAM_CHANGE_DRC,
+   MMALCAM_CHANGE_HDR,
+   MMALCAM_CHANGE_CONTRAST,
+   MMALCAM_CHANGE_BRIGHTNESS,
+   MMALCAM_CHANGE_SATURATION,
+   MMALCAM_CHANGE_SHARPNESS,
+} MMALCAM_CHANGE_T;
+
+typedef enum
+{
+   MMALCAM_INIT_SUCCESS,
+   MMALCAM_INIT_ERROR_EVENT_FLAGS,
+   MMALCAM_INIT_ERROR_VCSM_INIT,
+   MMALCAM_INIT_ERROR_CAMERA,
+   MMALCAM_INIT_ERROR_RENDER,
+   MMALCAM_INIT_ERROR_VIEWFINDER,
+   MMALCAM_INIT_ERROR_ENCODER,
+   MMALCAM_INIT_ERROR_ENCODER_IN,
+   MMALCAM_INIT_ERROR_ENCODER_OUT,
+   MMALCAM_INIT_ERROR_WRITER,
+   MMALCAM_INIT_ERROR_CAMERA_CAPTURE,
+} MMALCAM_INIT_STATUS_T;
+
+typedef struct MMALCAM_BEHAVIOUR_T
+{
+   const char *uri;                             /**< Output URI for recording */
+   const char *vformat;                         /**< Video resolution and encoding format */
+   MMAL_RECT_T display_area;                    /**< Size and position of viewfinder on screen */
+   uint32_t layer;                              /**< Layer number of the viewfinder */
+   MMALCAM_CHANGE_T change;                     /**< Camera change to make, if any */
+   uint32_t seconds_per_change;                 /**< Number of seconds between changes */
+   MMAL_RATIONAL_T frame_rate;                  /**< Frame rate, or zero for variable */
+   MMAL_BOOL_T zero_copy;                       /**< Enable zero copy if set */
+   MMAL_BOOL_T tunneling;                       /**< Enable port tunneling if set */
+   MMAL_BOOL_T opaque;                          /**< Enable opaque image support */
+   VCOS_SEMAPHORE_T init_sem;                   /**< Semaphore signalled once initialisation is complete */
+   MMALCAM_INIT_STATUS_T init_result;           /**< Result of initialisation */
+   MMAL_PARAMETER_STATISTICS_T render_stats;    /**< Video render stats */
+   MMAL_PARAMETER_STATISTICS_T encoder_stats;   /**< Video encoder output stats */
+   uint32_t bit_rate;                           /**< Video encoder bit rate */
+   MMAL_PARAM_FOCUS_T focus_test;               /**< Set to given focus, MMAL_PARAM_FOCUS_MAX to disable */
+   uint32_t camera_num;                         /**< camera number */
+} MMALCAM_BEHAVIOUR_T;
+
+/** Start the camcorder.
+ *
+ * Starts a viewfinder/preview on screen and optionally encodes the camera
+ * output to a URI.
+ *
+ * @param stop When this is set to 1 externally, the camcorder will be stopped.
+ * @param behaviour Defines the behaviour of the camcorder, for automation
+ *    purposes.
+ */
+int test_mmal_start_camcorder(volatile int *stop, MMALCAM_BEHAVIOUR_T *behaviour);
+
+#endif /* MMALCAM_MMALCAM_H_ */
diff --git a/host_applications/vmcs/test_apps/mmalcam/viewfinder.c b/host_applications/vmcs/test_apps/mmalcam/viewfinder.c
new file mode 100755 (executable)
index 0000000..4028a71
--- /dev/null
@@ -0,0 +1,1479 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdarg.h>
+
+#include "mmalcam.h"
+
+#include "interface/mmal/mmal.h"
+#include "interface/mmal/mmal_logging.h"
+#include "interface/mmal/util/mmal_util.h"
+#include "interface/mmal/util/mmal_default_components.h"
+
+#define USE_CONTAINER 0
+
+#if USE_CONTAINER
+#include "containers/containers.h"
+#include "containers/core/containers_utils.h" // FIXME
+#include "containers/containers_codecs.h"
+#endif
+
+/** Number of buffers we want to use for video render. Video render needs at least 2. */
+#define VIDEO_OUTPUT_BUFFERS_NUM 3
+
+/** After this many packets, the container (if any) will be closed and we
+ * start discarding encoded packets.
+ */
+#define MAX_PACKET_COUNT 150
+
+/** Initialise a parameter structure */
+#define INIT_PARAMETER(PARAM, PARAM_ID)   \
+   do {                                   \
+      memset(&(PARAM), 0, sizeof(PARAM)); \
+      (PARAM).hdr.id = PARAM_ID;          \
+      (PARAM).hdr.size = sizeof(PARAM);   \
+   } while (0)
+
+/* Utility functions to manipulate containers */
+#if USE_CONTAINER
+static VC_CONTAINER_T *test_container_open(const char *uri, MMAL_ES_FORMAT_T* format, MMAL_STATUS_T *status);
+static MMAL_STATUS_T test_container_write(VC_CONTAINER_T *container, MMAL_BUFFER_HEADER_T *buffer);
+static VC_CONTAINER_FOURCC_T test_container_encoding_to_codec(uint32_t encoding);
+#endif
+
+/* Utility function to create and setup the camera viewfinder component */
+static MMAL_COMPONENT_T *test_camera_create(MMALCAM_BEHAVIOUR_T *behaviour, MMAL_STATUS_T *status);
+static MMAL_BOOL_T mmalcam_next_effect(MMAL_COMPONENT_T *camera);
+static MMAL_BOOL_T mmalcam_next_rotation(MMAL_COMPONENT_T *camera);
+static MMAL_BOOL_T mmalcam_next_zoom(MMAL_COMPONENT_T *camera);
+static MMAL_BOOL_T mmalcam_next_focus(MMAL_COMPONENT_T *camera);
+static MMAL_BOOL_T mmalcam_reset_focus(MMAL_COMPONENT_T *camera, MMAL_PARAM_FOCUS_T focus_setting);
+static MMAL_BOOL_T mmalcam_next_drc(MMAL_COMPONENT_T *camera);
+static MMAL_BOOL_T mmalcam_next_hdr(MMAL_COMPONENT_T *camera);
+static MMAL_BOOL_T mmalcam_next_colour_param(MMAL_COMPONENT_T *camera, uint32_t id, int min, int max, const char *param_name);
+
+/* Utility function to create and setup the video render component */
+static MMAL_COMPONENT_T *test_video_render_create(MMALCAM_BEHAVIOUR_T *behaviour, MMAL_STATUS_T *status);
+
+/* Utility function to create and setup the video encoder component */
+static MMAL_COMPONENT_T *test_video_encoder_create(MMALCAM_BEHAVIOUR_T *behaviour, MMAL_STATUS_T *status);
+
+/*****************************************************************************/
+
+typedef enum {
+   MMAL_CAM_BUFFER_READY         = 1 << 0,
+   MMAL_CAM_AUTOFOCUS_COMPLETE   = 1 << 1,
+   MMAL_CAM_ANY_EVENT            = 0x7FFFFFFF
+} MMAL_CAM_EVENT_T;
+
+static VCOS_EVENT_FLAGS_T events;
+VCOS_LOG_CAT_T mmalcam_log_category;
+static MMAL_BOOL_T zero_copy;
+static MMAL_BOOL_T tunneling;
+
+static MMAL_BOOL_T enable_zero_copy(void)
+{
+   return zero_copy;
+}
+
+static MMAL_BOOL_T enable_tunneling(void)
+{
+   return tunneling;
+}
+
+/* Buffer header callbacks */
+static void control_bh_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   LOG_DEBUG("control_bh_cb %p,%p (cmd=0x%08x)", port, buffer, buffer->cmd);
+   if (buffer->cmd == MMAL_EVENT_PARAMETER_CHANGED)
+   {
+      MMAL_EVENT_PARAMETER_CHANGED_T *param = (MMAL_EVENT_PARAMETER_CHANGED_T *)buffer->data;
+
+      vcos_assert(buffer->length >= sizeof(MMAL_EVENT_PARAMETER_CHANGED_T));
+      vcos_assert(buffer->length == param->hdr.size);
+      switch (param->hdr.id)
+      {
+         case MMAL_PARAMETER_FOCUS_STATUS:
+            vcos_assert(param->hdr.size == sizeof(MMAL_PARAMETER_FOCUS_STATUS_T));
+            {
+               MMAL_PARAMETER_FOCUS_STATUS_T *focus_status = (MMAL_PARAMETER_FOCUS_STATUS_T *)param;
+               LOG_INFO("Focus status: %d", focus_status->status);
+               vcos_event_flags_set(&events, MMAL_CAM_AUTOFOCUS_COMPLETE, VCOS_OR);
+            }
+            break;
+         case MMAL_PARAMETER_CAMERA_NUM:
+            vcos_assert(param->hdr.size == sizeof(MMAL_PARAMETER_UINT32_T));
+            {
+               MMAL_PARAMETER_UINT32_T *camera_num = (MMAL_PARAMETER_UINT32_T *)param;
+               LOG_INFO("Camera number: %d", camera_num->value);
+            }
+            break;
+         default:
+            LOG_ERROR("Unexpected changed event for parameter 0x%08x", param->hdr.id);
+      }
+   }
+   else
+   {
+      LOG_ERROR("Unexpected event, 0x%08x", buffer->cmd);
+   }
+   mmal_buffer_header_release(buffer);
+}
+
+static void generic_output_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   if (buffer->cmd != 0)
+   {
+      LOG_INFO("%s callback: event %u not supported", port->name, buffer->cmd);
+      mmal_buffer_header_release(buffer);
+   }
+   else
+   {
+      MMAL_QUEUE_T *queue = (MMAL_QUEUE_T *)port->userdata;
+
+      LOG_DEBUG("%s callback", port->name);
+      mmal_queue_put(queue, buffer);
+   }
+
+   vcos_event_flags_set(&events, MMAL_CAM_BUFFER_READY, VCOS_OR);
+}
+
+static void generic_input_port_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   if (buffer->cmd != 0)
+   {
+      LOG_INFO("%s callback: event %u not supported", port->name, buffer->cmd);
+   }
+
+   mmal_buffer_header_release(buffer);
+   vcos_event_flags_set(&events, MMAL_CAM_BUFFER_READY, VCOS_OR);
+}
+
+static MMAL_STATUS_T setup_output_port(MMAL_PORT_T *output_port, MMAL_QUEUE_T **p_queue, MMAL_POOL_T **p_pool)
+{
+   MMAL_STATUS_T status = MMAL_ENOMEM;
+   MMAL_QUEUE_T *queue = NULL;
+   MMAL_POOL_T *pool = NULL;
+
+   /* Create a queue for frames filled by the output port.
+    * The main loop will pass these on to the input port. */
+   queue = mmal_queue_create();
+   if (!queue)
+   {
+      LOG_ERROR("failed to create queue for %s", output_port->name);
+      goto error;
+   }
+
+   /* Create pool of buffer headers for the output port to consume */
+   pool = mmal_port_pool_create(output_port, output_port->buffer_num, output_port->buffer_size);
+   if (!pool)
+   {
+      LOG_ERROR("failed to create pool for %s", output_port->name);
+      goto error;
+   }
+
+   output_port->userdata = (void *)queue;
+
+   status = mmal_port_enable(output_port, generic_output_port_cb);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("failed to enable %s", output_port->name);
+      goto error;
+   }
+
+   *p_queue = queue;
+   *p_pool = pool;
+
+   return MMAL_SUCCESS;
+
+error:
+   if (queue)
+      mmal_queue_destroy(queue);
+   if (pool)
+      mmal_pool_destroy(pool);
+
+   return status;
+}
+
+static MMAL_STATUS_T connect_ports(MMAL_PORT_T *output_port, MMAL_PORT_T *input_port, MMAL_QUEUE_T **p_queue, MMAL_POOL_T **p_pool)
+{
+   MMAL_STATUS_T status;
+
+   status = mmal_format_full_copy(input_port->format, output_port->format);
+   if (status != MMAL_SUCCESS)
+      return status;
+
+   status = mmal_port_format_commit(input_port);
+   if (status != MMAL_SUCCESS)
+      return status;
+
+   if (enable_tunneling())
+   {
+      status = mmal_port_connect(output_port, input_port);
+      if (status != MMAL_SUCCESS)
+         return status;
+
+      status = mmal_port_enable(output_port, NULL);
+      if (status != MMAL_SUCCESS)
+         mmal_port_disconnect(output_port);
+
+      return status;
+   }
+
+   /* Non-tunneling setup */
+   input_port->buffer_size = input_port->buffer_size_recommended;
+   if (input_port->buffer_size < input_port->buffer_size_min)
+      input_port->buffer_size = input_port->buffer_size_min;
+   input_port->buffer_num = input_port->buffer_num_recommended;
+   if (input_port->buffer_num < input_port->buffer_num_min)
+      input_port->buffer_num = input_port->buffer_num_min;
+   output_port->buffer_size = output_port->buffer_size_recommended;
+   if (output_port->buffer_size < output_port->buffer_size_min)
+      output_port->buffer_size = output_port->buffer_size_min;
+   output_port->buffer_num = output_port->buffer_num_recommended;
+   if (output_port->buffer_num < output_port->buffer_num_min)
+      output_port->buffer_num = output_port->buffer_num_min;
+
+   input_port->buffer_num = output_port->buffer_num =
+      MMAL_MAX(input_port->buffer_num, output_port->buffer_num);
+   input_port->buffer_size = output_port->buffer_size =
+      MMAL_MAX(input_port->buffer_size, output_port->buffer_size);
+
+   status = setup_output_port(output_port, p_queue, p_pool);
+   if (status != MMAL_SUCCESS)
+      goto error;
+
+   status = mmal_port_enable(input_port, generic_input_port_cb);
+   if (status != MMAL_SUCCESS)
+      goto error;
+
+   return status;
+
+error:
+   if (input_port->is_enabled)
+      mmal_port_disable(input_port);
+   if (output_port->is_enabled)
+      mmal_port_disable(output_port);
+   if (*p_pool)
+      mmal_pool_destroy(*p_pool);
+   if (*p_queue)
+      mmal_queue_destroy(*p_queue);
+
+   return status;
+}
+
+static MMAL_STATUS_T send_buffer_from_queue(MMAL_PORT_T *port, MMAL_QUEUE_T *queue)
+{
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   MMAL_BUFFER_HEADER_T *buffer;
+
+   if (!queue)
+      return MMAL_SUCCESS;
+
+   buffer = mmal_queue_get(queue);
+
+   if (buffer)
+   {
+      status = mmal_port_send_buffer(port, buffer);
+
+      if (status != MMAL_SUCCESS)
+      {
+         mmal_queue_put_back(queue, buffer);
+         LOG_DEBUG("%s send failed (%i)", port->name, status);
+      }
+   }
+
+   return status;
+}
+
+static MMAL_STATUS_T fill_port_from_pool(MMAL_PORT_T *port, MMAL_POOL_T *pool)
+{
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   MMAL_QUEUE_T *queue;
+
+   if (!pool)
+      return MMAL_SUCCESS;
+
+   queue = pool->queue;
+   while (status == MMAL_SUCCESS && mmal_queue_length(queue) > 0)
+      status = send_buffer_from_queue(port, queue);
+
+   return status;
+}
+
+static void disable_port(MMAL_PORT_T *port)
+{
+   if (port && port->is_enabled)
+      mmal_port_disable(port);
+}
+
+
+static int parse_vformat(const char* vformat, uint32_t *out_width,
+      uint32_t *out_height, uint32_t *out_encoding)
+{
+   char vcodec[8];
+   uint32_t width, height, encoding;
+
+   // coverity[secure_coding] Scanning integer values, and a string where the length is safe given vcodec declaration
+   if (sscanf(vformat, "%4ux%4u:%7s", &width, &height, vcodec) != 3)
+   {
+      fprintf(stderr, "Error, malformed or unsupported video format: %s\n", vformat);
+      return -1;
+   }
+
+   if (!vcos_strncasecmp(vcodec, "h263", 4))
+   {
+      encoding = MMAL_ENCODING_H263;
+      /* Special case, H263 supports a limited set of resolutions */
+      if (!((width ==  128 && height ==   96) ||
+            (width ==  176 && height ==  144) ||
+            (width ==  352 && height ==  288) ||
+            (width ==  704 && height ==  576) ||
+            (width == 1408 && height == 1152)))
+      {
+         fprintf(stderr,
+               "Error, only 128x96, 176x144, 352x288, 704x576 and 1408x1152 are supported for H263\n");
+         return -1;
+      }
+   }
+   else if (!vcos_strncasecmp(vcodec, "mp4v", 4))
+      encoding = MMAL_ENCODING_MP4V;
+   else if (!vcos_strncasecmp(vcodec, "h264", 4))
+      encoding = MMAL_ENCODING_H264;
+   else if (!vcos_strncasecmp(vcodec, "jpeg", 4))
+      encoding = MMAL_ENCODING_JPEG;
+   else
+   {
+      fprintf(stderr, "Error, unknown video encoding: %s\n", vcodec);
+      return -1;
+   }
+
+   if (out_width)
+      *out_width = width;
+   if (out_height)
+      *out_height = height;
+   if (out_encoding)
+      *out_encoding = encoding;
+   LOG_DEBUG("Video format: w:%d h:%d codec:%4.4s", width, height, (const char *)&encoding);
+
+   return 0;
+}
+
+/*****************************************************************************/
+int test_mmal_start_camcorder(volatile int *stop, MMALCAM_BEHAVIOUR_T *behaviour)
+{
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   MMAL_POOL_T *pool_viewfinder = 0, *pool_encoder_in = 0, *pool_encoder_out = 0;
+   MMAL_QUEUE_T *queue_viewfinder = 0, *queue_encoder_in = 0, *queue_encoder_out = 0;
+   MMAL_COMPONENT_T *camera = 0, *encoder = 0, *render = 0;
+   MMAL_PORT_T *viewfinder_port = 0, *video_port = 0, *still_port = 0;
+   MMAL_PORT_T *render_port = 0, *encoder_input = 0, *encoder_output = 0;
+   uint32_t ms_per_change, last_change_ms, set_focus_delay_ms;
+   int packet_count = 0;
+#if USE_CONTAINER
+   VC_CONTAINER_T *container = 0;
+#endif
+   FILE *output = NULL;
+
+   if(vcos_event_flags_create(&events, "MMALCam") != VCOS_SUCCESS)
+   {
+      behaviour->init_result = MMALCAM_INIT_ERROR_EVENT_FLAGS;
+      goto error;
+   }
+
+   zero_copy = behaviour->zero_copy;
+   tunneling = behaviour->tunneling;
+
+   /* Create and setup camera viewfinder component */
+   camera = test_camera_create(behaviour, &status);
+   if(!camera)
+   {
+      behaviour->init_result = MMALCAM_INIT_ERROR_CAMERA;
+      goto error;
+   }
+   viewfinder_port = camera->output[0];
+   video_port = camera->output[1];
+   still_port = camera->output[2];
+
+   /* Create and setup video render component */
+   render = test_video_render_create(behaviour, &status);
+   if(!render)
+   {
+      behaviour->init_result = MMALCAM_INIT_ERROR_RENDER;
+      goto error;
+   }
+   render_port = render->input[0];
+
+   status = connect_ports(viewfinder_port, render_port, &queue_viewfinder, &pool_viewfinder);
+   if (status != MMAL_SUCCESS)
+   {
+      behaviour->init_result = MMALCAM_INIT_ERROR_VIEWFINDER;
+      goto error;
+   }
+
+   if (behaviour->uri)
+   {
+      MMAL_PARAMETER_BOOLEAN_T camera_capture =
+            {{MMAL_PARAMETER_CAPTURE, sizeof(MMAL_PARAMETER_BOOLEAN_T)}, 1};
+
+      /* Create and setup video encoder component */
+      encoder = test_video_encoder_create(behaviour, &status);
+      if(!encoder)
+      {
+         behaviour->init_result = MMALCAM_INIT_ERROR_ENCODER;
+         goto error;
+      }
+      encoder_input = encoder->input[0];
+      encoder_output = encoder->output[0];
+
+      if (encoder_output->format->encoding == MMAL_ENCODING_JPEG)
+         video_port = still_port;
+
+      status = connect_ports(video_port, encoder_input, &queue_encoder_in, &pool_encoder_in);
+      if (status != MMAL_SUCCESS)
+      {
+         behaviour->init_result = MMALCAM_INIT_ERROR_ENCODER_IN;
+         goto error;
+      }
+
+      status = setup_output_port(encoder_output, &queue_encoder_out, &pool_encoder_out);
+      if (status != MMAL_SUCCESS)
+      {
+         behaviour->init_result = MMALCAM_INIT_ERROR_ENCODER_OUT;
+         goto error;
+      }
+
+      status = mmal_port_parameter_set(video_port, &camera_capture.hdr);
+      if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
+      {
+         behaviour->init_result = MMALCAM_INIT_ERROR_CAMERA_CAPTURE;
+         goto error;
+      }
+
+#if USE_CONTAINER
+      container = test_container_open(behaviour->uri, encoder_output->format, &status);
+      if (!container)
+      {
+         /* Notify user, carry on discarding encoded output buffers */
+         fprintf(stderr, "Error (%i) opening container: %s\n", status, behaviour->uri);
+      }
+#else
+      
+      output = fopen(behaviour->uri, "wb");
+      if(!output)
+      {
+         /* Notify user, carry on discarding encoded output buffers */
+         fprintf(stderr, "Error opening output file: %s\n", behaviour->uri);
+      }
+#endif
+   }
+
+   /* Initialisation now complete */
+   behaviour->init_result = MMALCAM_INIT_SUCCESS;
+   vcos_semaphore_post(&behaviour->init_sem);
+
+   ms_per_change = behaviour->seconds_per_change * 1000;
+   last_change_ms = vcos_get_ms();
+   set_focus_delay_ms = 1000;
+
+   while(1)
+   {
+      MMAL_BUFFER_HEADER_T *buffer;
+      VCOS_UNSIGNED set;
+
+      vcos_event_flags_get(&events, MMAL_CAM_ANY_EVENT, VCOS_OR_CONSUME, VCOS_TICKS_TO_MS(2), &set);
+      if(*stop) break;
+
+      if (behaviour->focus_test != MMAL_PARAM_FOCUS_MAX)
+      {
+         if (set & MMAL_CAM_AUTOFOCUS_COMPLETE ||
+               (set_focus_delay_ms && (vcos_get_ms() - last_change_ms) >= set_focus_delay_ms))
+         {
+            set_focus_delay_ms = 0;
+            mmalcam_reset_focus(camera, behaviour->focus_test);
+         }
+      }
+
+      /* Send empty buffers to the output ports */
+      status = fill_port_from_pool(viewfinder_port, pool_viewfinder);
+      if (status != MMAL_SUCCESS)
+         break;
+      status = fill_port_from_pool(video_port, pool_encoder_in);
+      if (status != MMAL_SUCCESS)
+         break;
+      status = fill_port_from_pool(encoder_output, pool_encoder_out);
+      if (status != MMAL_SUCCESS)
+         break;
+
+      /* Process filled output buffers */
+      status = send_buffer_from_queue(render_port, queue_viewfinder);
+      if (status != MMAL_SUCCESS)
+         break;
+      status = send_buffer_from_queue(encoder_input, queue_encoder_in);
+      if (status != MMAL_SUCCESS)
+         break;
+
+      /* Process output buffers from encoder */
+      if (queue_encoder_out)
+      {
+         buffer = mmal_queue_get(queue_encoder_out);
+         if (buffer)
+         {
+            if (output
+#if USE_CONTAINER
+                || container
+#endif
+                )
+            {
+               mmal_buffer_header_mem_lock(buffer);
+#if USE_CONTAINER
+               test_container_write(container, buffer);
+#else
+               LOG_ERROR("Write %d bytes of data from %p", buffer->length, buffer->data);
+               fwrite(buffer->data, 1, buffer->length, output);
+#endif
+               mmal_buffer_header_mem_unlock(buffer);
+               packet_count++;
+               if (packet_count > MAX_PACKET_COUNT)
+               {
+#if USE_CONTAINER
+                  vc_container_close(container);
+                  container = 0;
+#else
+                  fclose(output);
+#endif
+                  output = NULL;
+                  fprintf(stderr, "All packets written\n");
+               }
+            }
+            mmal_buffer_header_release(buffer);
+         }
+      }
+
+      /* Change a camera parameter if requested */
+      if (ms_per_change != 0)
+      {
+         if((vcos_get_ms() - last_change_ms) >= ms_per_change)
+         {
+            last_change_ms = vcos_get_ms();
+            switch (behaviour->change)
+            {
+               case MMALCAM_CHANGE_IMAGE_EFFECT:
+                  if (!mmalcam_next_effect(camera))
+                     *stop = 1;
+                  break;
+               case MMALCAM_CHANGE_ROTATION:
+                  if (!mmalcam_next_rotation(camera))
+                     *stop = 1;
+                  break;
+               case MMALCAM_CHANGE_ZOOM:
+                  if (!mmalcam_next_zoom(camera))
+                     *stop = 1;
+                  break;
+               case MMALCAM_CHANGE_FOCUS:
+                  if (!mmalcam_next_focus(camera))
+                     *stop = 1;
+                  break;
+               case MMALCAM_CHANGE_DRC:
+                  if (!mmalcam_next_drc(camera))
+                     *stop = 1;
+                  break;
+               case MMALCAM_CHANGE_HDR:
+                  if (!mmalcam_next_hdr(camera))
+                     *stop = 1;
+                  break;
+               case MMALCAM_CHANGE_CONTRAST:
+                  if (!mmalcam_next_colour_param(camera, MMAL_PARAMETER_CONTRAST, -100, 100, "contrast"))
+                     *stop = 1;
+                  break;
+               case MMALCAM_CHANGE_BRIGHTNESS:
+                  if (!mmalcam_next_colour_param(camera, MMAL_PARAMETER_BRIGHTNESS, 0, 100, "brightness"))
+                     *stop = 1;
+                  break;
+               case MMALCAM_CHANGE_SATURATION:
+                  if (!mmalcam_next_colour_param(camera, MMAL_PARAMETER_SATURATION, -100, 100, "saturation"))
+                     *stop = 1;
+                  break;
+               case MMALCAM_CHANGE_SHARPNESS:
+                  if (!mmalcam_next_colour_param(camera, MMAL_PARAMETER_SHARPNESS, -100, 100, "sharpness"))
+                     *stop = 1;
+                  break;
+               default:
+                  LOG_ERROR("Unexpected change behaviour: %d", behaviour->change);
+                  break;
+            }
+         }
+      }
+   }
+
+   /* Disable ports */
+   disable_port(viewfinder_port);
+   disable_port(render_port);
+   disable_port(video_port);
+   disable_port(encoder_input);
+   disable_port(encoder_output);
+
+   /* Disable components */
+   mmal_component_disable(render);
+   if (encoder)
+      mmal_component_disable(encoder);
+   mmal_component_disable(camera);
+
+   INIT_PARAMETER(behaviour->render_stats, MMAL_PARAMETER_STATISTICS);
+   mmal_port_parameter_get(render_port, &behaviour->render_stats.hdr);
+   if (encoder)
+   {
+      INIT_PARAMETER(behaviour->encoder_stats, MMAL_PARAMETER_STATISTICS);
+      mmal_port_parameter_get(encoder_output, &behaviour->encoder_stats.hdr);
+   }
+
+ error:
+   /* The pools need to be destroyed first since they are owned by the components */
+   if(pool_viewfinder)
+      mmal_port_pool_destroy(viewfinder_port, pool_viewfinder);
+   if(pool_encoder_in)
+      mmal_port_pool_destroy(video_port, pool_encoder_in);
+   if(pool_encoder_out)
+      mmal_port_pool_destroy(encoder_output, pool_encoder_out);
+
+   if(render)
+      mmal_component_destroy(render);
+   if(encoder)
+      mmal_component_destroy(encoder);
+   if(camera)
+      mmal_component_destroy(camera);
+
+   if(queue_viewfinder)
+      mmal_queue_destroy(queue_viewfinder);
+   if(queue_encoder_in)
+      mmal_queue_destroy(queue_encoder_in);
+   if(queue_encoder_out)
+      mmal_queue_destroy(queue_encoder_out);
+
+#if USE_CONTAINER
+   if(container)
+      vc_container_close(container);
+#endif
+   if(output)
+      fclose(output);
+
+   vcos_event_flags_delete(&events);
+
+   if (packet_count)
+      printf("Packet count: %d\n", packet_count);
+
+   if (behaviour->init_result != MMALCAM_INIT_SUCCESS)
+      vcos_semaphore_post(&behaviour->init_sem);
+
+   return (int)status;
+}
+
+/*****************************************************************************/
+static MMAL_COMPONENT_T *test_camera_create(MMALCAM_BEHAVIOUR_T *behaviour, MMAL_STATUS_T *status)
+{
+   MMAL_COMPONENT_T *camera = 0;
+   MMAL_ES_FORMAT_T *format;
+   MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T change_event_request =
+         {{MMAL_PARAMETER_CHANGE_EVENT_REQUEST, sizeof(MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T)}, 0, 1};
+   MMAL_PORT_T *viewfinder_port = NULL, *video_port = NULL, *still_port = NULL;
+   uint32_t width, height;
+   MMAL_PARAMETER_INT32_T camera_num =
+         {{MMAL_PARAMETER_CAMERA_NUM, sizeof(camera_num)},0};
+
+   /* Create the component */
+   *status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CAMERA, &camera);
+   if(*status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("couldn't create camera");
+      goto error;
+   }
+   if(!camera->output_num)
+   {
+      LOG_ERROR("camera doesn't have output ports");
+      *status = MMAL_EINVAL;
+      goto error;
+   }
+
+   viewfinder_port = camera->output[0];
+   video_port = camera->output[1];
+   still_port = camera->output[2];
+
+   change_event_request.change_id = MMAL_PARAMETER_FOCUS_STATUS;
+   *status = mmal_port_parameter_set(camera->control, &change_event_request.hdr);
+   if (*status != MMAL_SUCCESS && *status != MMAL_ENOSYS)
+   {
+      LOG_ERROR("No focus status change events");
+   }
+   camera_num.value = behaviour->camera_num;
+   *status = mmal_port_parameter_set(camera->control, &camera_num.hdr);
+   if (*status != MMAL_SUCCESS && *status != MMAL_ENOSYS)
+   {
+       LOG_ERROR("No camera number change events");
+   }
+   if (enable_zero_copy())
+   {
+      MMAL_PARAMETER_BOOLEAN_T param_zc =
+         {{MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T)}, 1};
+      *status = mmal_port_parameter_set(viewfinder_port, &param_zc.hdr);
+      if( *status != MMAL_SUCCESS && *status != MMAL_ENOSYS )
+      {
+         LOG_ERROR("failed to set zero copy on camera output");
+         goto error;
+      }
+      LOG_INFO("enabled zero copy on camera");
+      *status = mmal_port_parameter_set(video_port, &param_zc.hdr);
+      if( *status != MMAL_SUCCESS && *status != MMAL_ENOSYS )
+      {
+         LOG_ERROR("failed to set zero copy on camera output");
+         goto error;
+      }
+      *status = mmal_port_parameter_set(still_port, &param_zc.hdr);
+      if( *status != MMAL_SUCCESS && *status != MMAL_ENOSYS )
+      {
+         LOG_ERROR("failed to set zero copy on camera output");
+         goto error;
+      }
+   }
+
+   if ( behaviour->change == MMALCAM_CHANGE_HDR )
+   {
+      MMAL_PARAMETER_ALGORITHM_CONTROL_T algo_ctrl = {{MMAL_PARAMETER_ALGORITHM_CONTROL, sizeof(MMAL_PARAMETER_ALGORITHM_CONTROL_T)},
+                        MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_HIGH_DYNAMIC_RANGE, 1 };
+      mmal_port_parameter_set(camera->control, &algo_ctrl.hdr);
+   }
+
+   *status = mmal_port_enable(camera->control, control_bh_cb);
+   if (*status)
+   {
+      LOG_ERROR("control port couldn't be enabled: %d", *status);
+      goto error;
+   }
+
+   /* Set camera viewfinder port format */
+   if (parse_vformat(behaviour->vformat, &width, &height, NULL))
+   {
+      *status = MMAL_EINVAL;
+      goto error;
+   }
+
+   /* Default to integer frame rate in numerator */
+   if (!behaviour->frame_rate.den)
+      behaviour->frame_rate.den = 1;
+
+   {
+      MMAL_PARAMETER_CAMERA_CONFIG_T cam_config = {{MMAL_PARAMETER_CAMERA_CONFIG,sizeof(cam_config)},
+                              .max_stills_w =      width,
+                              .max_stills_h =      height,
+                              .stills_yuv422 =     0,
+                              .one_shot_stills =   0,
+                              .max_preview_video_w = width,
+                              .max_preview_video_h = height,
+                              .num_preview_video_frames = 3,
+                              .stills_capture_circular_buffer_height = 0,
+                              .fast_preview_resume = 0,
+                                          /* No way of using fast resume in Android, as preview
+                                           * automatically stops on capture.
+                                           */
+                              .use_stc_timestamp = MMAL_PARAM_TIMESTAMP_MODE_RESET_STC
+                              };
+
+      mmal_port_parameter_set(camera->control, &cam_config.hdr);
+   }
+
+   /* Set up the viewfinder port format */
+   format = viewfinder_port->format;
+   if (behaviour->opaque)
+      format->encoding = MMAL_ENCODING_OPAQUE;
+   else
+      format->encoding = MMAL_ENCODING_I420;
+
+   format->es->video.width = width;
+   format->es->video.height = height;
+   format->es->video.crop.x = 0;
+   format->es->video.crop.y = 0;
+   format->es->video.crop.width = width;
+   format->es->video.crop.height = height;
+   format->es->video.frame_rate = behaviour->frame_rate;
+
+   *status = mmal_port_format_commit(viewfinder_port);
+   if(*status)
+   {
+      LOG_ERROR("camera viewfinder format couldn't be set");
+      goto error;
+   }
+
+   /* Set the same format on the video (for encoder) port */
+   mmal_format_full_copy(video_port->format, format);
+   *status = mmal_port_format_commit(video_port);
+   if(*status)
+   {
+      LOG_ERROR("camera video format couldn't be set");
+      goto error;
+   }
+
+   /* Ensure there are enough buffers to avoid dropping frames */
+   if (video_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
+      video_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
+
+   /* Set the same format on the still (for encoder) port */
+   mmal_format_full_copy(still_port->format, format);
+   *status = mmal_port_format_commit(still_port);
+   if(*status)
+   {
+      LOG_ERROR("camera still format couldn't be set");
+      goto error;
+   }
+
+   /* Ensure there are enough buffers to avoid dropping frames */
+   if (still_port->buffer_num < VIDEO_OUTPUT_BUFFERS_NUM)
+      still_port->buffer_num = VIDEO_OUTPUT_BUFFERS_NUM;
+
+   /* Enable component */
+   *status = mmal_component_enable(camera);
+   if(*status)
+   {
+      LOG_ERROR("camera component couldn't be enabled");
+      goto error;
+   }
+
+   return camera;
+
+ error:
+   if(camera) mmal_component_destroy(camera);
+   return 0;
+}
+
+/*****************************************************************************/
+static MMAL_BOOL_T mmalcam_next_effect(MMAL_COMPONENT_T *camera)
+{
+   static const MMAL_PARAM_IMAGEFX_T effects[] = {
+               MMAL_PARAM_IMAGEFX_NONE,
+               MMAL_PARAM_IMAGEFX_NEGATIVE,
+               MMAL_PARAM_IMAGEFX_SOLARIZE
+            };
+   static unsigned int index;
+   MMAL_PARAMETER_IMAGEFX_T image_fx = {{ MMAL_PARAMETER_IMAGE_EFFECT, sizeof(image_fx)},0};
+   MMAL_PARAMETER_IMAGEFX_T image_fx_check = {{ MMAL_PARAMETER_IMAGE_EFFECT, sizeof(image_fx)},0};
+   MMAL_STATUS_T result;
+
+   index++;
+   if(index >= countof(effects))
+      index = 0;
+   image_fx.value = effects[index];
+   result = mmal_port_parameter_set(camera->control, &image_fx.hdr);
+   if (result != MMAL_SUCCESS)
+   {
+      LOG_ERROR("Failed to set image effect, %d", result);
+      return MMAL_FALSE;
+   }
+   result = mmal_port_parameter_get(camera->control, &image_fx_check.hdr);
+   if (result != MMAL_SUCCESS)
+   {
+      LOG_ERROR("Failed to retrieve image effect, %d", result);
+      return MMAL_FALSE;
+   }
+   if (memcmp(&image_fx, &image_fx_check, sizeof(image_fx)) != 0)
+   {
+      LOG_ERROR("Image effect set (%d) was not retrieved (%d)", image_fx.value, image_fx_check.value);
+      return MMAL_FALSE;
+   }
+   return MMAL_TRUE;
+}
+
+/*****************************************************************************/
+static MMAL_BOOL_T mmalcam_next_rotation(MMAL_COMPONENT_T *camera)
+{
+   static MMAL_PARAMETER_UINT32_T rotate = {{MMAL_PARAMETER_ROTATION,sizeof(rotate)},0};
+   MMAL_PARAMETER_UINT32_T rotate_check = {{MMAL_PARAMETER_ROTATION,sizeof(rotate_check)},0};
+   MMAL_STATUS_T result;
+
+   rotate.value += 90;
+   if(rotate.value == 360)
+      rotate.value = 0;
+   result = mmal_port_parameter_set(camera->output[0], &rotate.hdr);
+   if (result != MMAL_SUCCESS)
+   {
+      LOG_ERROR("Failed to set rotation, %d", result);
+      return MMAL_FALSE;
+   }
+   result = mmal_port_parameter_get(camera->output[0], &rotate_check.hdr);
+   if (result != MMAL_SUCCESS)
+   {
+      LOG_ERROR("Failed to retrieve rotation, %d", result);
+      return MMAL_FALSE;
+   }
+   if (memcmp(&rotate, &rotate_check, sizeof(rotate)) != 0)
+   {
+      LOG_ERROR("Rotation set (%d) was not retrieved (%d)", rotate.value, rotate_check.value);
+      return MMAL_FALSE;
+   }
+   return MMAL_TRUE;
+}
+
+/*****************************************************************************/
+static MMAL_BOOL_T mmalcam_next_zoom(MMAL_COMPONENT_T *camera)
+{
+   static MMAL_PARAMETER_SCALEFACTOR_T scale = {{MMAL_PARAMETER_ZOOM,sizeof(scale)},1<<16,1<<16};
+   static int32_t dirn = 1 << 14;
+   MMAL_PARAMETER_SCALEFACTOR_T scale_check = {{MMAL_PARAMETER_ZOOM,sizeof(scale_check)},0,0};
+   MMAL_STATUS_T result;
+
+   scale.scale_x += dirn;
+   scale.scale_y += dirn;
+   if (scale.scale_x >= 4<<16 || scale.scale_x <= 1<<16)
+      dirn = -dirn;
+   result = mmal_port_parameter_set(camera->control, &scale.hdr);
+   if (result != MMAL_SUCCESS)
+   {
+      LOG_ERROR("Failed to set scale, %d", result);
+      return MMAL_FALSE;
+   }
+   result = mmal_port_parameter_get(camera->control, &scale_check.hdr);
+   if (result != MMAL_SUCCESS)
+   {
+      LOG_ERROR("Failed to retrieve scale, %d", result);
+      return MMAL_FALSE;
+   }
+   if (memcmp(&scale, &scale_check, sizeof(scale)) != 0)
+   {
+      LOG_ERROR("Scale set (%d,%d) was not retrieved (%d,%d)",
+            scale.scale_x, scale.scale_y, scale_check.scale_x, scale_check.scale_y);
+      return MMAL_FALSE;
+   }
+   return MMAL_TRUE;
+}
+
+/*****************************************************************************/
+static MMAL_BOOL_T mmalcam_next_focus(MMAL_COMPONENT_T *camera)
+{
+   static const MMAL_PARAM_FOCUS_T focus_setting[] = {
+               MMAL_PARAM_FOCUS_AUTO,
+               MMAL_PARAM_FOCUS_AUTO_MACRO,
+               MMAL_PARAM_FOCUS_CAF,
+               MMAL_PARAM_FOCUS_FIXED_INFINITY,
+               MMAL_PARAM_FOCUS_FIXED_HYPERFOCAL,
+               MMAL_PARAM_FOCUS_FIXED_MACRO,
+               MMAL_PARAM_FOCUS_EDOF,
+            };
+   static unsigned int index;
+   static MMAL_PARAMETER_FOCUS_T focus = {{MMAL_PARAMETER_FOCUS,sizeof(focus)},0};
+   static MMAL_PARAMETER_FOCUS_T focus_check = {{MMAL_PARAMETER_FOCUS,sizeof(focus)},0};
+   MMAL_STATUS_T result;
+
+   index++;
+   if(index >= countof(focus_setting))
+      index = MMAL_FALSE;
+   focus.value = focus_setting[index];
+   result = mmal_port_parameter_set(camera->control, &focus.hdr);
+   if (result != MMAL_SUCCESS)
+   {
+      LOG_ERROR("Failed to set focus to %d", focus.value);
+      /* As this depends on the camera module, do not fail */
+      return MMAL_TRUE;
+   }
+   result = mmal_port_parameter_get(camera->control, &focus_check.hdr);
+   if (result != MMAL_SUCCESS)
+   {
+      LOG_ERROR("Failed to retrieve focus, %d", result);
+      return MMAL_FALSE;
+   }
+   /* Focus setting is asynchronous, so the value read back may not match what was set */
+   return MMAL_TRUE;
+}
+
+/*****************************************************************************/
+static MMAL_BOOL_T mmalcam_reset_focus(MMAL_COMPONENT_T *camera, MMAL_PARAM_FOCUS_T focus_setting)
+{
+   MMAL_PARAMETER_FOCUS_T focus = {{MMAL_PARAMETER_FOCUS, sizeof(focus)},MMAL_PARAM_FOCUS_FIXED_HYPERFOCAL};
+   MMAL_STATUS_T result;
+
+   result = mmal_port_parameter_set(camera->control, &focus.hdr);
+   if (result != MMAL_SUCCESS)
+   {
+      LOG_ERROR("Failed to set focus to HYPERFOCAL, result %d", result);
+      return MMAL_FALSE;
+   }
+   focus.value = focus_setting;
+   result = mmal_port_parameter_set(camera->control, &focus.hdr);
+   if (result != MMAL_SUCCESS)
+   {
+      LOG_ERROR("Failed to set focus to %d, result %d", focus_setting, result);
+      return MMAL_FALSE;
+   }
+   return MMAL_TRUE;
+}
+
+/*****************************************************************************/
+static MMAL_BOOL_T mmalcam_next_drc(MMAL_COMPONENT_T *camera)
+{
+   static const MMAL_PARAMETER_DRC_STRENGTH_T drc_setting[] = {
+               MMAL_PARAMETER_DRC_STRENGTH_OFF,
+               MMAL_PARAMETER_DRC_STRENGTH_LOW,
+               MMAL_PARAMETER_DRC_STRENGTH_MEDIUM,
+               MMAL_PARAMETER_DRC_STRENGTH_HIGH
+            };
+   static unsigned int index;
+   MMAL_STATUS_T result;
+   MMAL_PARAMETER_DRC_T drc = {{MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION,sizeof(drc)},0};
+   MMAL_PARAMETER_DRC_T drc_check = {{MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION,sizeof(drc_check)},0};
+
+   index++;
+   if(index >= countof(drc_setting))
+      index = 0;
+   drc.strength = drc_setting[index];
+
+   result = mmal_port_parameter_set(camera->control, &drc.hdr);
+   if (result != MMAL_SUCCESS)
+   {
+      LOG_ERROR("Failed to set drc, %d", result);
+      return MMAL_FALSE;
+   }
+   result = mmal_port_parameter_get(camera->control, &drc_check.hdr);
+   if (result != MMAL_SUCCESS)
+   {
+      LOG_ERROR("Failed to retrieve drc, %d", result);
+      return MMAL_FALSE;
+   }
+   if (memcmp(&drc, &drc_check, sizeof(drc)) != 0)
+   {
+      LOG_ERROR("DRC set (%d) was not retrieved (%d)", drc.strength, drc_check.strength);
+      return MMAL_FALSE;
+   }
+   return MMAL_TRUE;
+}
+
+/*****************************************************************************/
+static MMAL_BOOL_T mmalcam_next_hdr(MMAL_COMPONENT_T *camera)
+{
+   static const MMAL_BOOL_T hdr_setting[] = {
+               MMAL_FALSE,
+               MMAL_TRUE,
+            };
+   static unsigned int index;
+   MMAL_STATUS_T result;
+   MMAL_PARAMETER_BOOLEAN_T hdr = {{MMAL_PARAMETER_HIGH_DYNAMIC_RANGE,sizeof(hdr)},0};
+   MMAL_PARAMETER_BOOLEAN_T hdr_check = {{MMAL_PARAMETER_HIGH_DYNAMIC_RANGE,sizeof(hdr_check)},0};
+
+   index++;
+   if(index >= countof(hdr_setting))
+      index = 0;
+   hdr.enable = hdr_setting[index];
+
+   result = mmal_port_parameter_set(camera->control, &hdr.hdr);
+   if (result != MMAL_SUCCESS)
+   {
+      LOG_ERROR("Failed to set hdr, %d", result);
+      return MMAL_FALSE;
+   }
+   result = mmal_port_parameter_get(camera->control, &hdr_check.hdr);
+   if (result != MMAL_SUCCESS)
+   {
+      LOG_ERROR("Failed to retrieve hdr, %d", result);
+      return MMAL_FALSE;
+   }
+   if (memcmp(&hdr, &hdr_check, sizeof(hdr)) != 0)
+   {
+      LOG_ERROR("HDR set (%d) was not retrieved (%d)", hdr.enable, hdr_check.enable);
+      return MMAL_FALSE;
+   }
+   return MMAL_TRUE;
+}
+
+/*****************************************************************************/
+/* Contrast, brightness, saturation, and sharpness all take the same format,
+ * but need different parameter IDs, and brightness is 0-100, not -100 to 100.
+ */
+static MMAL_BOOL_T mmalcam_next_colour_param(MMAL_COMPONENT_T *camera, uint32_t id, int min, int max, const char *param_name)
+{
+   static MMAL_PARAMETER_RATIONAL_T param = {{MMAL_PARAMETER_GROUP_CAMERA,sizeof(param)},{0,100}};
+   MMAL_PARAMETER_RATIONAL_T param_check = {{MMAL_PARAMETER_GROUP_CAMERA,sizeof(param_check)},{0,100}};
+   MMAL_STATUS_T result;
+   param.hdr.id = id;
+   param_check.hdr.id = id;
+
+   param.value.num += 20;
+   if(param.value.num < min || param.value.num > max)
+      param.value.num = min;
+   result = mmal_port_parameter_set(camera->control, &param.hdr);
+   if (result != MMAL_SUCCESS)
+   {
+      LOG_ERROR("Failed to set %s, %d", param_name, result);
+      return MMAL_FALSE;
+   }
+   result = mmal_port_parameter_get(camera->control, &param_check.hdr);
+   if (result != MMAL_SUCCESS)
+   {
+      LOG_ERROR("Failed to retrieve %s, %d", param_name, result);
+      return MMAL_FALSE;
+   }
+   if (memcmp(&param, &param_check, sizeof(param)) != 0)
+   {
+      LOG_ERROR("%s set (%d/%d) was not retrieved (%d/%d)", param_name, 
+                  param.value.num, param.value.den, 
+                  param_check.value.num, param_check.value.den);
+      return MMAL_FALSE;
+   }
+   return MMAL_TRUE;
+}
+
+
+/*****************************************************************************/
+static MMAL_COMPONENT_T *test_video_render_create(MMALCAM_BEHAVIOUR_T *behaviour, MMAL_STATUS_T *status)
+{
+   MMAL_COMPONENT_T *render = 0;
+   MMAL_PORT_T *render_port = NULL;
+
+   *status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, &render);
+   if(*status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("couldn't create video render");
+      goto error;
+   }
+   if(!render->input_num)
+   {
+      LOG_ERROR("video render doesn't have input ports");
+      *status = MMAL_EINVAL;
+      goto error;
+   }
+
+   render_port = render->input[0];
+
+   /* Give higher priority to the overlay layer */
+   MMAL_DISPLAYREGION_T param;
+   param.hdr.id = MMAL_PARAMETER_DISPLAYREGION;
+   param.hdr.size = sizeof(MMAL_DISPLAYREGION_T);
+   param.set = MMAL_DISPLAY_SET_LAYER;
+   param.layer = behaviour->layer;
+   if (behaviour->display_area.width && behaviour->display_area.height)
+   {
+      param.set |= MMAL_DISPLAY_SET_DEST_RECT | MMAL_DISPLAY_SET_FULLSCREEN;
+      param.fullscreen = 0;
+      param.dest_rect = behaviour->display_area;
+   }
+   *status = mmal_port_parameter_set( render_port, &param.hdr );
+   if (*status != MMAL_SUCCESS && *status != MMAL_ENOSYS)
+   {
+      LOG_ERROR("could not set video render display properties (%u)", *status);
+      goto error;
+   }
+
+   if (enable_zero_copy())
+   {
+      MMAL_PARAMETER_BOOLEAN_T param_zc =
+         {{MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T)}, 1};
+      *status = mmal_port_parameter_set(render_port, &param_zc.hdr);
+      if (*status != MMAL_SUCCESS && *status != MMAL_ENOSYS)
+      {
+         LOG_ERROR("failed to set zero copy on render input");
+         goto error;
+      }
+      LOG_INFO("enabled zero copy on render");
+   }
+
+   if (behaviour->opaque)
+   {
+      render_port->format->encoding = MMAL_ENCODING_OPAQUE;
+   }
+
+   /* Enable component */
+   *status = mmal_component_enable(render);
+   if(*status)
+   {
+      LOG_ERROR("video render component couldn't be enabled (%u)", *status);
+      goto error;
+   }
+
+   return render;
+
+ error:
+   if(render) mmal_component_destroy(render);
+   return 0;
+}
+
+/*****************************************************************************/
+static MMAL_COMPONENT_T *test_video_encoder_create(MMALCAM_BEHAVIOUR_T *behaviour, MMAL_STATUS_T *status)
+{
+   MMAL_COMPONENT_T *encoder = 0;
+   MMAL_PORT_T *encoder_input = NULL, *encoder_output = NULL;
+   const char *component_name = MMAL_COMPONENT_DEFAULT_VIDEO_ENCODER;
+   uint32_t encoding;
+
+   /* Set the port format */
+   if (parse_vformat(behaviour->vformat, 0, 0, &encoding))
+   {
+      *status = MMAL_EINVAL;
+      goto error;
+   }
+
+   if (encoding == MMAL_ENCODING_JPEG)
+      component_name = MMAL_COMPONENT_DEFAULT_IMAGE_ENCODER;
+
+   *status = mmal_component_create(component_name, &encoder);
+   if(*status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("couldn't create video encoder");
+      goto error;
+   }
+   if(!encoder->input_num || !encoder->output_num)
+   {
+      LOG_ERROR("video encoder doesn't have input/output ports");
+      *status = MMAL_EINVAL;
+      goto error;
+   }
+
+   encoder_input = encoder->input[0];
+   encoder_output = encoder->output[0];
+
+   mmal_format_copy(encoder_output->format, encoder_input->format);
+   encoder_output->format->encoding = encoding;
+   encoder_output->format->bitrate = behaviour->bit_rate;
+   *status = mmal_port_format_commit(encoder_output);
+   if(*status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("format not set on video encoder output port");
+      goto error;
+   }
+   encoder_output->buffer_size = encoder_output->buffer_size_recommended;
+   if (encoder_output->buffer_size < encoder_output->buffer_size_min)
+      encoder_output->buffer_size = encoder_output->buffer_size_min;
+   encoder_output->buffer_num = encoder_output->buffer_num_recommended;
+   if (encoder_output->buffer_num < encoder_output->buffer_num_min)
+      encoder_output->buffer_num = encoder_output->buffer_num_min;
+
+   if (enable_zero_copy())
+   {
+      MMAL_PARAMETER_BOOLEAN_T param_zc =
+         {{MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T)}, 1};
+      *status = mmal_port_parameter_set(encoder_output, &param_zc.hdr);
+      if (*status != MMAL_SUCCESS && *status != MMAL_ENOSYS)
+      {
+         LOG_ERROR("failed to set zero copy on encoder output");
+         goto error;
+      }
+      *status = mmal_port_parameter_set(encoder_input, &param_zc.hdr);
+      if (*status != MMAL_SUCCESS && *status != MMAL_ENOSYS)
+      {
+         LOG_ERROR("failed to set zero copy on encoder input");
+         goto error;
+      }
+      LOG_INFO("enabled zero copy on encoder");
+   }
+
+   if (behaviour->opaque)
+   {
+      encoder_input->format->encoding = MMAL_ENCODING_OPAQUE;
+   }
+
+   /* Enable component */
+   *status = mmal_component_enable(encoder);
+   if(*status)
+   {
+      LOG_ERROR("video encoder component couldn't be enabled");
+      goto error;
+   }
+
+   return encoder;
+
+ error:
+   if(encoder) mmal_component_destroy(encoder);
+   return 0;
+}
+
+#if USE_CONTAINER
+/*****************************************************************************/
+static MMAL_STATUS_T test_container_to_mmal_status(VC_CONTAINER_STATUS_T status)
+{
+   switch (status)
+   {
+      case VC_CONTAINER_SUCCESS:
+      case VC_CONTAINER_ERROR_NOT_READY:
+         return MMAL_SUCCESS;
+      case VC_CONTAINER_ERROR_LIMIT_REACHED:
+      case VC_CONTAINER_ERROR_OUT_OF_SPACE:
+         return MMAL_ENOSPC;
+      case VC_CONTAINER_ERROR_URI_NOT_FOUND:
+         return MMAL_ENOENT;
+      default:
+         return MMAL_ENXIO;
+   }
+}
+
+/*****************************************************************************/
+static VC_CONTAINER_T *test_container_open(const char *uri, MMAL_ES_FORMAT_T *format, MMAL_STATUS_T *p_status)
+{
+   VC_CONTAINER_T *container = 0;
+   VC_CONTAINER_STATUS_T status = VC_CONTAINER_ERROR_FAILED;
+   VC_CONTAINER_ES_FORMAT_T *container_format = 0;
+
+   /* Open container */
+   container = vc_container_open_writer(uri, &status, 0, 0);
+   if(status != VC_CONTAINER_SUCCESS)
+   {
+      LOG_ERROR("error opening uri %s (%i)", uri, status);
+      goto error;
+   }
+
+   /* Set format from MMAL port format */
+   container_format = vc_container_format_create(0);
+   if (!container_format)
+   {
+      status = VC_CONTAINER_ERROR_OUT_OF_MEMORY;
+      LOG_ERROR("error (%i)", status);
+      goto error;
+   }
+
+   switch (format->type)
+   {
+      case MMAL_ES_TYPE_VIDEO: 
+         container_format->es_type = VC_CONTAINER_ES_TYPE_VIDEO;
+         break;
+      default:
+         status = VC_CONTAINER_ERROR_FORMAT_NOT_SUPPORTED;
+         LOG_ERROR("unsupported elementary stream format error (%i)", status);
+         goto error;
+   }
+
+   container_format->codec = test_container_encoding_to_codec(format->encoding);
+   if(format->encoding == MMAL_ENCODING_H264)
+      container_format->codec_variant = VC_FOURCC('a','v','c','C');
+   container_format->type->video.width = format->es->video.width;
+   container_format->type->video.height = format->es->video.height;
+   container_format->type->video.frame_rate_num = format->es->video.frame_rate.num;
+   container_format->type->video.frame_rate_den = format->es->video.frame_rate.den;
+   container_format->type->video.par_num = format->es->video.par.num;
+   container_format->type->video.par_den = format->es->video.par.den;
+   container_format->bitrate = format->bitrate;
+   container_format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
+
+   container_format->extradata_size = 0;
+
+   status = vc_container_control(container, VC_CONTAINER_CONTROL_TRACK_ADD, container_format);
+   if(status != VC_CONTAINER_SUCCESS)
+   {
+      LOG_ERROR("error adding track (%i)", status);
+      goto error;
+   }
+
+   vc_container_control(container, VC_CONTAINER_CONTROL_TRACK_ADD_DONE);
+
+end:
+   if (container_format)
+      vc_container_format_delete(container_format);
+   if (p_status) *p_status = test_container_to_mmal_status(status);
+   return container;
+error:
+   if (container)
+   {
+      vc_container_close(container);
+      container = 0;
+   }
+   goto end;
+}
+
+/*****************************************************************************/
+static MMAL_STATUS_T test_container_write(VC_CONTAINER_T *container, MMAL_BUFFER_HEADER_T *buffer)
+{
+   VC_CONTAINER_PACKET_T packet;
+   VC_CONTAINER_STATUS_T status;
+   memset(&packet, 0, sizeof(packet));
+   static int first_fragment = 1;
+
+#if 0
+   if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_CONFIG)
+      buffer->length = 0; /* Discard codec config data arriving in buffers */
+#endif
+
+   if (buffer->length == 0)
+      return MMAL_SUCCESS;
+
+   packet.track = 0;
+   packet.pts = buffer->pts == MMAL_TIME_UNKNOWN ? VC_CONTAINER_TIME_UNKNOWN : buffer->pts;
+   packet.dts = buffer->dts == MMAL_TIME_UNKNOWN ? VC_CONTAINER_TIME_UNKNOWN : buffer->dts;
+   if(buffer->flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
+      packet.flags |= VC_CONTAINER_PACKET_FLAG_KEYFRAME;
+   if(first_fragment || (buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_START))
+   {
+      packet.flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
+      first_fragment = 0;
+   }
+
+   if(buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END)
+   {
+      packet.flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
+      first_fragment = 1; /* Next buffer will be the first fragment */
+   }
+
+   packet.size = packet.buffer_size = buffer->length;
+   if ((packet.flags & VC_CONTAINER_PACKET_FLAG_FRAME) == VC_CONTAINER_PACKET_FLAG_FRAME)
+      packet.frame_size = packet.size;
+
+   vcos_assert(buffer->offset == 0);
+
+   packet.data = buffer->data;
+
+   LOG_DEBUG("writing packet: track %i, size %i/%i, pts %"PRId64", flags %x%s",
+         packet.track, packet.size, packet.frame_size, packet.pts,
+         packet.flags, (packet.flags & VC_CONTAINER_PACKET_FLAG_KEYFRAME) ? " (keyframe)" : "");
+
+   status = vc_container_write(container, &packet);
+
+   return test_container_to_mmal_status(status);
+}
+
+/*****************************************************************************/
+static struct {
+   VC_CONTAINER_FOURCC_T codec;
+   uint32_t encoding;
+} codec_to_encoding_table[] =
+{
+   {VC_CONTAINER_CODEC_H263,           MMAL_ENCODING_H263},
+   {VC_CONTAINER_CODEC_H264,           MMAL_ENCODING_H264},
+   {VC_CONTAINER_CODEC_MP4V,           MMAL_ENCODING_MP4V},
+   {VC_CONTAINER_CODEC_MP2V,           MMAL_ENCODING_MP2V},
+   {VC_CONTAINER_CODEC_MP1V,           MMAL_ENCODING_MP1V},
+   {VC_CONTAINER_CODEC_WMV3,           MMAL_ENCODING_WMV3},
+   {VC_CONTAINER_CODEC_WMV2,           MMAL_ENCODING_WMV2},
+   {VC_CONTAINER_CODEC_WMV1,           MMAL_ENCODING_WMV1},
+   {VC_CONTAINER_CODEC_WVC1,           MMAL_ENCODING_WVC1},
+   {VC_CONTAINER_CODEC_VP6,            MMAL_ENCODING_VP6},
+   {VC_CONTAINER_CODEC_VP7,            MMAL_ENCODING_VP7},
+   {VC_CONTAINER_CODEC_VP8,            MMAL_ENCODING_VP8},
+   {VC_CONTAINER_CODEC_THEORA,         MMAL_ENCODING_THEORA},
+   {VC_CONTAINER_CODEC_UNKNOWN,        MMAL_ENCODING_UNKNOWN}
+};
+
+static VC_CONTAINER_FOURCC_T test_container_encoding_to_codec(uint32_t encoding)
+{
+   unsigned int i;
+   for(i = 0; codec_to_encoding_table[i].codec != VC_CONTAINER_CODEC_UNKNOWN; i++)
+      if(codec_to_encoding_table[i].encoding == encoding) break;
+   return codec_to_encoding_table[i].codec;
+}
+#endif
diff --git a/host_applications/vmcs/test_apps/mmalplay/mmalplay.c b/host_applications/vmcs/test_apps/mmalplay/mmalplay.c
new file mode 100755 (executable)
index 0000000..cfb5478
--- /dev/null
@@ -0,0 +1,512 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <stdlib.h>
+#include <limits.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h>
+#include "mmalplay.h"
+
+#include "interface/mmal/mmal_logging.h"
+#include "interface/mmal/mmal_encodings.h"
+#include "interface/mmal/util/mmal_util.h"
+
+#define URI_FOR_THREAD_NAME_MAX  16
+#define THREAD_PREFIX   "mmal:"
+#define VERSION "0.9"
+
+/* Global options */
+static MMALPLAY_OPTIONS_T options;
+static int unclean_exit;
+
+typedef struct {
+   VCOS_MUTEX_T lock;
+   VCOS_THREAD_T thread;
+   const char *uri;
+   MMALPLAY_T *ctx;
+   MMALPLAY_OPTIONS_T options;
+   MMAL_STATUS_T status;
+   char name[sizeof(THREAD_PREFIX) + URI_FOR_THREAD_NAME_MAX];
+} FILE_PLAY_INFO_T;
+
+#define FILE_PLAY_MAX   16
+static FILE_PLAY_INFO_T play_info[FILE_PLAY_MAX];
+static int play_info_count;
+static uint32_t sleepy_time;
+static unsigned int verbosity;
+
+/* Utility functions used by test program */
+void test_signal_handler(int signum);
+static void *mmal_playback(void *id);
+static int test_parse_cmdline(int argc, const char **argv);
+
+/*****************************************************************************/
+int main(int argc, const char **argv)
+{
+   VCOS_THREAD_ATTR_T attrs;
+   int i;
+
+   vcos_init();
+   signal(SIGINT, test_signal_handler);
+
+   /* coverity[tainted_data] Ignore unnecessary warning about an attacker
+    * being able to pass an arbitrarily long "-vvvvv..." argument */
+   if (test_parse_cmdline(argc, argv))
+      return -1;
+
+   if (verbosity--)
+   {
+      static char value[512];
+      const char *levels[] = {"warn", "info", "trace"};
+      char *env = getenv("VC_LOGLEVEL");
+      if (verbosity >= MMAL_COUNTOF(levels)) verbosity = MMAL_COUNTOF(levels) - 1;
+      snprintf(value, sizeof(value)-1, "mmalplay:%s,mmal:%s,%s",
+               levels[verbosity], levels[verbosity], env ? env : "");
+      setenv("VC_LOGLEVEL", value, 1);
+   }
+
+   vcos_log_register("mmalplay", VCOS_LOG_CATEGORY);
+   LOG_INFO("MMAL Video Playback Test App");
+
+   vcos_thread_attr_init(&attrs);
+   for (i = 0; i < play_info_count; i++)
+   {
+      const char *uri = play_info[i].uri;
+
+      memcpy(play_info[i].name, THREAD_PREFIX, sizeof(THREAD_PREFIX));
+      if (strlen(uri) >= URI_FOR_THREAD_NAME_MAX)
+         uri += strlen(uri) - URI_FOR_THREAD_NAME_MAX;
+      strncat(play_info[i].name, uri, URI_FOR_THREAD_NAME_MAX);
+
+      vcos_mutex_create(&play_info[i].lock, "mmalplay");
+      play_info[i].options.render_layer = i;
+
+      if (vcos_thread_create(&play_info[i].thread, play_info[i].name, &attrs, mmal_playback, &play_info[i]) != VCOS_SUCCESS)
+      {
+         LOG_ERROR("Thread creation failure for URI %s", play_info[i].uri);
+         return -2;
+      }
+   }
+
+   if (sleepy_time != 0)
+   {
+      sleep(sleepy_time);
+      for (i = 0; i < play_info_count; i++)
+      {
+         vcos_mutex_lock(&play_info[i].lock);
+         if (play_info[i].ctx)
+            mmalplay_stop(play_info[i].ctx);
+         vcos_mutex_unlock(&play_info[i].lock);
+      }
+   }
+
+   LOG_TRACE("Waiting for threads to terminate");
+   for (i = 0; i < play_info_count; i++)
+   {
+      vcos_thread_join(&play_info[i].thread, NULL);
+      LOG_TRACE("Joined thread %d (%i)", i, play_info[i].status);
+   }
+
+   LOG_TRACE("Completed");
+
+   /* Check for errors */
+   for (i = 0; i < play_info_count; i++)
+   {
+      if (!play_info[i].status)
+         continue;
+
+      LOG_ERROR("Playback of %s failed (%i, %s)", play_info[i].uri,
+                play_info[i].status,
+                mmal_status_to_string(play_info[i].status));
+      fprintf(stderr, "playback of %s failed (%i, %s)\n", play_info[i].uri,
+              play_info[i].status,
+              mmal_status_to_string(play_info[i].status));
+      return play_info[i].status;
+   }
+
+   return 0;
+}
+
+/*****************************************************************************/
+static void *mmal_playback(void *id)
+{
+   FILE_PLAY_INFO_T *play_info = id;
+   MMALPLAY_OPTIONS_T opts;
+   MMAL_STATUS_T status;
+   MMALPLAY_T *ctx;
+
+   /* Setup the options */
+   opts = options;
+   opts.output_uri = play_info->options.output_uri;
+   opts.render_layer = play_info->options.render_layer;
+
+   vcos_mutex_lock(&play_info->lock);
+   ctx = mmalplay_create(play_info->uri, &opts, &status);
+   play_info->ctx = ctx;
+   vcos_mutex_unlock(&play_info->lock);
+   if (!ctx)
+      goto end;
+
+   if (!opts.disable_playback)
+      status = mmalplay_play(ctx);
+
+   if (unclean_exit)
+      goto end;
+
+   vcos_mutex_lock(&play_info->lock);
+   if (ctx)
+   {
+      /* coverity[use] Suppress ATOMICITY warning - ctx might have changed since
+       * we initialised it above, which is okay */
+      mmalplay_destroy(ctx);
+   }
+   play_info->ctx = 0;
+   vcos_mutex_unlock(&play_info->lock);
+
+ end:
+   LOG_TRACE("Thread %s terminating, result %d", play_info->name, status);
+   play_info->status = status;
+   return NULL;
+}
+
+/*****************************************************************************/
+void test_signal_handler(int signum)
+{
+   static MMAL_BOOL_T stopped_already = 0;
+   int i;
+   MMAL_PARAM_UNUSED(signum);
+
+   if (stopped_already)
+   {
+      LOG_ERROR("Killing program");
+      exit(255);
+   }
+   stopped_already = 1;
+
+   LOG_ERROR("BYE");
+   for (i = 0; i < play_info_count; i++)
+   {
+      vcos_mutex_lock(&play_info[i].lock);
+      if (play_info[i].ctx)
+         mmalplay_stop(play_info[i].ctx);
+      vcos_mutex_unlock(&play_info[i].lock);
+   }
+}
+
+/* Parse a string of the form: "fourcc:widthxheight" */
+static int get_format(const char *name, uint32_t *fourcc, unsigned int *width, unsigned int *height)
+{
+   char *delim, fcc[4] = {' ', ' ', ' ', ' '};
+   unsigned int value_u1, value_u2;
+   size_t size;
+
+   *width = *height = 0;
+   *fourcc = MMAL_ENCODING_UNKNOWN;
+
+   /* Fourcc is the first element */
+   delim = strchr(name, ':');
+   size = delim ? (size_t)(delim - name) : strlen(name);
+   memcpy(fcc, name, MMAL_MIN(size, sizeof(fcc)));
+
+   if (size == sizeof("yuv420")-1 && !memcmp(name, "yuv420", size))
+      *fourcc = MMAL_ENCODING_I420;
+   else if (size == sizeof("yuvuv")-1 && !memcmp(name, "yuvuv", size))
+      *fourcc = MMAL_ENCODING_YUVUV128;
+   else if (size == sizeof("opaque")-1 && !memcmp(name, "opaque", size))
+      *fourcc = MMAL_ENCODING_OPAQUE;
+   else if (size > 0 && size <= 4)
+      *fourcc = MMAL_FOURCC(fcc[0], fcc[1], fcc[2], fcc[3]);
+   else
+      return 1;
+
+   if (!delim)
+      return 0; /* Nothing more to parse */
+
+   /* Width/height are next */
+   /* coverity[secure_coding] Only reading integers, so can't overflow */
+   if (sscanf(delim+1, "%ux%u", &value_u1, &value_u2) != 2)
+      return 1;
+
+   *width = value_u1;
+   *height = value_u2;
+   return 0;
+}
+
+/*****************************************************************************/
+static int test_parse_cmdline(int argc, const char **argv)
+{
+   unsigned int value_u1 = 0, value_u2 = 0;
+   uint32_t color_format;
+   float value_f = 0;
+   int i, j;
+
+   /* Parse the command line arguments */
+   for(i = 1; i < argc; i++)
+   {
+      if(!argv[i]) continue;
+
+      if(argv[i][0] != '-')
+      {
+         /* Not an option argument so will be the input URI */
+         if (play_info_count >= FILE_PLAY_MAX)
+         {
+            fprintf(stderr, "Too many URIs!\n");
+            goto usage;
+         }
+         play_info[play_info_count++].uri = argv[i];
+         continue;
+      }
+
+      /* We are now dealing with command line options */
+      switch(argv[i][1])
+      {
+      case 'V':
+         printf("Version: %s\n", VERSION);
+         exit(0);
+      case 'v':
+         for (j = 1; argv[i][j] == 'v'; j++) verbosity++;
+         break;
+      case 'X':
+         unclean_exit = 1;
+         break;
+      case 'd':
+         options.tunnelling = 1;
+         break;
+      case 's':
+         if (!strcmp(argv[i]+1, "step"))
+         {
+            options.stepping = 1;
+            break;
+         }
+         /* coverity[secure_coding] Only reading numbers, so can't overflow */
+         else if (!argv[i][2] && ++i < argc &&
+                  sscanf(argv[i], "%f", &value_f) == 1)
+         {
+            options.seeking = value_f;
+            break;
+         }
+         goto usage;
+      case 'n':
+         switch (argv[i][2])
+         {
+            case 'p': options.disable_playback = 1; break;
+            case 'v':
+               if(argv[i][3] == 'd')
+                  options.disable_video_decode = 1;
+               else
+                  options.disable_video = 1;
+               break;
+            case 'a': options.disable_audio = 1; break;
+            default: break;
+         }
+         break;
+      case 'e':
+         if (argv[i][2] != 's')
+            goto usage;
+         options.enable_scheduling = 1; break;
+         break;
+      case 't':
+         /* coverity[secure_coding] Only reading integers, so can't overflow */
+         if (++i >= argc || sscanf(argv[i], "%u", &sleepy_time) != 1)
+            goto usage;    /* Time missing / invalid */
+         break;
+      case 'x':
+         /* coverity[secure_coding] Only reading integers, so can't overflow */
+         if (++i >= argc || sscanf(argv[i], "%u", &value_u1) != 1)
+            goto usage;
+         options.output_num = value_u1;
+         break;
+      case 'f':
+         if (i + 1 >= argc || get_format(argv[++i], &color_format, &value_u1, &value_u2))
+            goto usage;
+         if (argv[i-1][2] == 0)
+         {
+            options.output_format = color_format;
+            options.output_rect.width = value_u1;
+            options.output_rect.height = value_u2;
+         }
+         else if (argv[i-1][2] == 'r')
+         {
+            options.render_format = color_format;
+            options.render_rect.width = value_u1;
+            options.render_rect.height = value_u2;
+         }
+         else
+            goto usage;
+         break;
+      case 'c':
+         if (!argv[i][2])
+         {
+            options.copy_input = 1;
+            options.copy_output = 1;
+         }
+         else if (argv[i][2] == 'i')
+            options.copy_input = 1;
+         else if (argv[i][2] == 'o')
+            options.copy_output = 1;
+         break;
+      case 'm':
+         if (argv[i][2] == 'v')
+         {
+            if (argv[i][3] == 'r' && i < argc)
+               options.component_video_render = argv[++i];
+            else if (argv[i][3] == 'd' && i < argc)
+               options.component_video_decoder = argv[++i];
+            else if (argv[i][3] == 's' && i < argc)
+               options.component_splitter = argv[++i];
+            else if (argv[i][3] == 'c' && i < argc)
+               options.component_video_converter = argv[++i];
+            else if (argv[i][3] == 'h' && i < argc)
+               options.component_video_scheduler = argv[++i];
+            else
+               goto usage;
+         }
+         else if (argv[i][2] == 'a')
+         {
+            if (argv[i][3] == 'r' && i < argc)
+               options.component_audio_render = argv[++i];
+            else if (argv[i][3] == 'd' && i < argc)
+               options.component_audio_decoder = argv[++i];
+            else
+               goto usage;
+         }
+         else if (argv[i][2] == 'c')
+         {
+            if (argv[i][3] == 'r' && i < argc)
+               options.component_container_reader = argv[++i];
+            else
+               goto usage;
+         }
+         else
+            goto usage;
+         break;
+      case 'o':
+         if (++i >= argc || play_info_count >= FILE_PLAY_MAX)
+            goto usage;
+         play_info[play_info_count].options.output_uri = argv[i];
+         break;
+
+      case 'a':
+         if (++i >= argc)
+            goto usage;
+         options.audio_destination = argv[i];
+         break;
+
+      case 'r':
+         if (i + 1 >= argc)
+            goto usage;
+         if (argv[i][2] == 'a')
+            options.audio_destination = argv[++i];
+         else if (argv[i][2] == 'v')
+         {
+            /* coverity[secure_coding] Only reading integers, so can't overflow */
+            if (sscanf(argv[++i], "%u", &options.video_destination) != 1)
+               goto usage;
+         }
+         else
+            goto usage;
+         break;
+
+      case 'w':
+         options.window = 1;
+         break;
+
+      case 'p':
+         options.audio_passthrough = 1;
+         break;
+
+      case 'h': goto usage;
+      default: goto invalid_option;
+      }
+      continue;
+   }
+
+   /* Sanity check that we have at least an input uri */
+   if(!play_info_count)
+   {
+     fprintf(stderr, "missing uri argument\n");
+     goto usage;
+   }
+
+   return 0;
+
+invalid_option:
+   fprintf(stderr, "invalid command line option (%s)\n", argv[i]);
+
+usage:
+   {
+      const char *program;
+
+      program = strrchr(argv[0], '\\');
+      if (program)
+         program++;
+      if (!program)
+      {
+         program = strrchr(argv[0], '/');
+         if (program)
+            program++;
+      }
+      if (!program)
+         program = argv[0];
+
+      fprintf(stderr, "usage: %s [options] uri0 uri1 ... uriN\n", program);
+      fprintf(stderr, "options list:\n");
+      fprintf(stderr, " -h    : help\n");
+      fprintf(stderr, " -V    : print version and exit\n");
+      fprintf(stderr, " -v(vv): increase verbosity\n");
+      fprintf(stderr, " -np   : disable playback phase\n");
+      fprintf(stderr, " -nv   : disable video\n");
+      fprintf(stderr, " -nvd  : disable video decode\n");
+      fprintf(stderr, " -na   : disable audio\n");
+      fprintf(stderr, " -es   : enable scheduling\n");
+      fprintf(stderr, " -t <n>: play URI(s) for <n> seconds then stop\n");
+      fprintf(stderr, " -f <fourcc:widthxheight> : set format used on output of decoder\n");
+      fprintf(stderr, " -fr <fourcc:widthxheight> : set format used for rendering\n");
+      fprintf(stderr, " -c    : do full copy of data transferred to videocore\n");
+      fprintf(stderr, " -ci   : full copy for input buffers to decoder\n");
+      fprintf(stderr, " -co   : full copy for output buffers from decoder\n");
+      fprintf(stderr, " -X    : exit without tearing down the mmal pipeline (for testing)\n");
+      fprintf(stderr, " -x <n>: use <n> video render modules \n");
+      fprintf(stderr, " -d    : use direct port connections (aka tunnelling)\n");
+      fprintf(stderr, " -step : stepping (displays 1 frame at a time)\n");
+      fprintf(stderr, " -s <f>: seek to <f> seconds into the stream\n");
+      fprintf(stderr, " -o <s>: output uri\n");
+      fprintf(stderr, " -mcr <s>:  name of the container reader module to use\n");
+      fprintf(stderr, " -mvr <s>:  name of the video render module to use\n");
+      fprintf(stderr, " -mvd <s>:  name of the video decoder module to use\n");
+      fprintf(stderr, " -mvc <s>:  name of the video converter module to use\n");
+      fprintf(stderr, " -mvh <s>:  name of the video scheduler to use\n");
+      fprintf(stderr, " -mvs <s>:  name of the splitter module to use\n");
+      fprintf(stderr, " -mar <s>:  name of the audio render module to use\n");
+      fprintf(stderr, " -mad <s>:  name of the audio decoder module to use\n");
+      fprintf(stderr, " -ra <s>: set audio destination\n");
+      fprintf(stderr, " -rv <n>: set video destination\n");
+      fprintf(stderr, " -p    : use audio passthrough\n");
+      fprintf(stderr, " -w    : window mode (i.e. not fullscreen)\n");
+   }
+   return 1;
+}
diff --git a/host_applications/vmcs/test_apps/mmalplay/mmalplay.h b/host_applications/vmcs/test_apps/mmalplay/mmalplay.h
new file mode 100755 (executable)
index 0000000..284c188
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file
+ * MMAL test application which plays back video files
+ * Note: this is test code. Do not use this in your app. It *will* change or even be removed without notice.
+ */
+
+#include "interface/mmal/mmal.h"
+
+#define VCOS_LOG_CATEGORY (&mmalplay_log_category)
+#include "interface/vcos/vcos.h"
+
+extern VCOS_LOG_CAT_T mmalplay_log_category;
+
+/** MMALPLAY instance id.
+ */
+typedef struct MMALPLAY_T MMALPLAY_T;
+
+/** MMALPLAY configuration options.
+ */
+typedef struct {
+   uint32_t output_format;
+   MMAL_RECT_T output_rect;
+   uint32_t render_format;
+   MMAL_RECT_T render_rect;
+   uint32_t render_layer;
+
+   int copy_input;
+   int copy_output;
+
+   int tunnelling;
+   unsigned int output_num;
+
+   int disable_playback;
+   int disable_video;
+   int disable_audio;
+   int enable_scheduling;
+   int disable_video_decode;
+
+   const char *component_container_reader;
+   const char *component_video_decoder;
+   const char *component_splitter;
+   const char *component_video_render;
+   const char *component_video_converter;
+   const char *component_video_scheduler;
+
+   const char *component_audio_decoder;
+   const char *component_audio_render;
+
+   const char *audio_destination;
+   unsigned int video_destination;
+
+   const char *output_uri;
+
+   int window;
+
+   float seeking;
+   int stepping;
+
+   int audio_passthrough;
+} MMALPLAY_OPTIONS_T;
+
+/** Create an instance of mmalplay.
+ *
+ * @param uri URI for the video stream to play
+ * @param opts configuration options for the instance to be created
+ * @param status status of the operation
+ *
+ * @return a MMALPLAY_T instance id on success
+ */
+MMALPLAY_T *mmalplay_create(const char *uri, MMALPLAY_OPTIONS_T *opts, MMAL_STATUS_T *status);
+
+/** Start playback on an instance of mmalplay.
+ *
+ * @param MMALPLAY instance id
+ *
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmalplay_play(MMALPLAY_T *ctx);
+
+/** Stop the playback on an instance of mmalplay.
+ *
+ * @param MMALPLAY instance id
+ */
+void mmalplay_stop(MMALPLAY_T *ctx);
+
+/** Destroys an instance of mmalplay.
+ *
+ * @param MMALPLAY instance id
+ */
+void mmalplay_destroy(MMALPLAY_T *ctx);
diff --git a/host_applications/vmcs/test_apps/mmalplay/playback.c b/host_applications/vmcs/test_apps/mmalplay/playback.c
new file mode 100755 (executable)
index 0000000..66b1e47
--- /dev/null
@@ -0,0 +1,1249 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file
+ * MMAL test application which plays back video files
+ * Note: this is test code. Do not use this in your app. It *will* change or even be removed without notice.
+ */
+
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdarg.h>
+
+#include "mmalplay.h"
+
+VCOS_LOG_CAT_T mmalplay_log_category;
+
+#include "interface/mmal/mmal_logging.h"
+#include "interface/mmal/util/mmal_util.h"
+#include "interface/mmal/util/mmal_connection.h"
+#include "interface/mmal/util/mmal_util_params.h"
+#include "interface/mmal/util/mmal_default_components.h"
+
+#define MMALPLAY_STILL_IMAGE_PAUSE 2000
+
+#define MMALPLAY_MAX_STRING 128
+#define MMALPLAY_MAX_CONNECTIONS 16
+#define MMALPLAY_MAX_RENDERERS 3
+
+static unsigned int video_render_num;
+
+/** Structure describing a mmal component */
+typedef struct {
+   struct MMALPLAY_T *ctx;
+   MMAL_COMPONENT_T *comp;
+
+   /* Used for debug / statistics */
+   char name[MMALPLAY_MAX_STRING];
+   int64_t time_setup;
+   int64_t time_cleanup;
+} MMALPLAY_COMPONENT_T;
+
+/** Context for a mmalplay playback instance */
+struct MMALPLAY_T {
+   const char *uri;
+   VCOS_SEMAPHORE_T event;
+
+   unsigned int component_num;
+   MMALPLAY_COMPONENT_T component[MMALPLAY_MAX_CONNECTIONS*2];
+
+   unsigned int connection_num;
+   MMAL_CONNECTION_T *connection[MMALPLAY_MAX_CONNECTIONS];
+
+   MMAL_STATUS_T status;
+   unsigned int stop;
+
+   MMAL_BOOL_T is_still_image;
+   MMAL_PORT_T *reader_video;
+   MMAL_PORT_T *reader_audio;
+   MMAL_PORT_T *video_out_port;
+   MMAL_PORT_T *converter_out_port;
+   MMAL_PORT_T *audio_clock;
+   MMAL_PORT_T *video_clock;
+
+   MMALPLAY_OPTIONS_T options;
+
+   /* Used for debug / statistics */
+   int64_t time_playback;
+   unsigned int decoded_frames;
+};
+
+typedef struct MMALPLAY_CONNECTIONS_T {
+   unsigned int num;
+
+   struct {
+      MMAL_PORT_T *in;
+      MMAL_PORT_T *out;
+      uint32_t flags;
+   } connection[MMALPLAY_MAX_CONNECTIONS+1];
+
+} MMALPLAY_CONNECTIONS_T;
+#define MMALPLAY_CONNECTION_IN(cx) (cx)->connection[(cx)->num].in
+#define MMALPLAY_CONNECTION_OUT(cx) (cx)->connection[(cx)->num].out
+#define MMALPLAY_CONNECTION_ADD(cx) if (++(cx)->num > MMALPLAY_MAX_CONNECTIONS) goto error
+#define MMALPLAY_CONNECTION_SET(cx, f) do { (cx)->connection[(cx)->num].flags |= (f); } while(0)
+
+static MMAL_COMPONENT_T *mmalplay_component_create(MMALPLAY_T *ctx, const char *name, MMAL_STATUS_T *status);
+static MMAL_STATUS_T mmalplay_connection_create(MMALPLAY_T *ctx, MMAL_PORT_T *out, MMAL_PORT_T *in, uint32_t flags);
+
+/* Utility function to setup the container reader component */
+static MMAL_STATUS_T mmalplay_setup_container_reader(MMALPLAY_T *, MMAL_COMPONENT_T *,
+   const char *uri);
+/* Utility function to setup the container writer component */
+static MMAL_STATUS_T mmalplay_setup_container_writer(MMALPLAY_T *, MMAL_COMPONENT_T *,
+   const char *uri);
+/* Utility function to setup the video decoder component */
+static MMAL_STATUS_T mmalplay_setup_video_decoder(MMALPLAY_T *ctx, MMAL_COMPONENT_T *);
+/* Utility function to setup the splitter component */
+static MMAL_STATUS_T mmalplay_setup_splitter(MMALPLAY_T *ctx, MMAL_COMPONENT_T *);
+/* Utility function to setup the video converter component */
+static MMAL_STATUS_T mmalplay_setup_video_converter(MMALPLAY_T *ctx, MMAL_COMPONENT_T *);
+/* Utility function to setup the video render component */
+static MMAL_STATUS_T mmalplay_setup_video_render(MMALPLAY_T *ctx, MMAL_COMPONENT_T *);
+/* Utility function to setup the video scheduler component */
+static MMAL_STATUS_T mmalplay_setup_video_scheduler(MMALPLAY_T *ctx, MMAL_COMPONENT_T *);
+/* Utility function to setup the audio decoder component */
+static MMAL_STATUS_T mmalplay_setup_audio_decoder(MMALPLAY_T *ctx, MMAL_COMPONENT_T *);
+/* Utility function to setup the audio render component */
+static MMAL_STATUS_T mmalplay_setup_audio_render(MMALPLAY_T *ctx, MMAL_COMPONENT_T *);
+
+static void log_format(MMAL_ES_FORMAT_T *format, MMAL_PORT_T *port);
+
+/*****************************************************************************/
+
+/** Callback from a control port. Error and EOS events stop playback. */
+static void mmalplay_bh_control_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMALPLAY_T *ctx = (MMALPLAY_T *)port->userdata;
+   LOG_TRACE("%s(%p),%p,%4.4s", port->name, port, buffer, (char *)&buffer->cmd);
+
+   if (buffer->cmd == MMAL_EVENT_ERROR || buffer->cmd == MMAL_EVENT_EOS)
+   {
+      if (buffer->cmd == MMAL_EVENT_ERROR)
+      {
+         LOG_INFO("error event from %s: %s", port->name,
+                  mmal_status_to_string(*(MMAL_STATUS_T*)buffer->data));
+         ctx->status = *(MMAL_STATUS_T *)buffer->data;
+      }
+      else if (buffer->cmd == MMAL_EVENT_EOS)
+         LOG_INFO("%s: EOS received", port->name);
+      mmalplay_stop(ctx);
+   }
+
+   mmal_buffer_header_release(buffer);
+}
+
+/** Callback from the connection. Buffer is available. */
+static void mmalplay_connection_cb(MMAL_CONNECTION_T *connection)
+{
+   MMALPLAY_T *ctx = (MMALPLAY_T *)connection->user_data;
+   vcos_semaphore_post(&ctx->event);
+}
+
+/*****************************************************************************/
+static MMAL_STATUS_T mmalplay_event_handle(MMAL_CONNECTION_T *connection, MMAL_PORT_T *port,
+   MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+
+   LOG_INFO("%s(%p) received event %4.4s (%i bytes)", port->name, port,
+            (char *)&buffer->cmd, (int)buffer->length);
+
+   if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED && port->type == MMAL_PORT_TYPE_OUTPUT)
+   {
+      MMAL_EVENT_FORMAT_CHANGED_T *event = mmal_event_format_changed_get(buffer);
+      if (event)
+      {
+         LOG_INFO("----------Port format changed----------");
+         log_format(port->format, port);
+         LOG_INFO("-----------------to---------------------");
+         log_format(event->format, 0);
+         LOG_INFO(" buffers num (opt %i, min %i), size (opt %i, min: %i)",
+                  event->buffer_num_recommended, event->buffer_num_min,
+                  event->buffer_size_recommended, event->buffer_size_min);
+         LOG_INFO("----------------------------------------");
+      }
+
+      status = mmal_connection_event_format_changed(connection, buffer);
+   }
+
+   mmal_buffer_header_release(buffer);
+   return status;
+}
+
+static MMAL_STATUS_T mmalplay_pipeline_audio_create(MMALPLAY_T *ctx, MMAL_PORT_T *source,
+   MMALPLAY_CONNECTIONS_T *connections)
+{
+   MMAL_STATUS_T status;
+   MMAL_COMPONENT_T *component;
+   unsigned int save = connections->num;
+
+   if (!source  || ctx->options.disable_audio)
+      return MMAL_EINVAL;
+
+   MMALPLAY_CONNECTION_OUT(connections) = source;
+
+   /* Create and setup audio decoder component */
+   component = mmalplay_component_create(ctx, MMAL_COMPONENT_DEFAULT_AUDIO_DECODER, &status);
+   if (!component)
+      goto error;
+   MMALPLAY_CONNECTION_IN(connections) = component->input[0];
+   MMALPLAY_CONNECTION_ADD(connections);
+   MMALPLAY_CONNECTION_OUT(connections) = component->output[0];
+
+   /* Create and setup audio render component */
+   component = mmalplay_component_create(ctx, MMAL_COMPONENT_DEFAULT_AUDIO_RENDERER, &status);
+   if (!component)
+      goto error;
+   MMALPLAY_CONNECTION_IN(connections) = component->input[0];
+   MMALPLAY_CONNECTION_ADD(connections);
+
+   return MMAL_SUCCESS;
+
+ error:
+   connections->num = save;
+   return status == MMAL_SUCCESS ? MMAL_ENOSPC : status;
+}
+
+static MMAL_STATUS_T mmalplay_pipeline_video_create(MMALPLAY_T *ctx, MMAL_PORT_T *source,
+   MMALPLAY_CONNECTIONS_T *connections)
+{
+   MMAL_STATUS_T status;
+   MMAL_COMPONENT_T *component, *previous = NULL;
+   unsigned int i, save = connections->num;
+
+   if (!source || ctx->options.disable_video)
+      return MMAL_EINVAL;
+
+   MMALPLAY_CONNECTION_OUT(connections) = source;
+
+   if (ctx->options.output_uri)
+   {
+      /* Create and setup container writer component */
+      component = mmalplay_component_create(ctx, MMAL_COMPONENT_DEFAULT_CONTAINER_WRITER, &status);
+      if (!component)
+         goto error;
+      MMALPLAY_CONNECTION_IN(connections) = component->input[0];
+      MMALPLAY_CONNECTION_ADD(connections);
+      return MMAL_SUCCESS;
+   }
+
+   /* Create and setup video decoder component */
+   if (!ctx->options.disable_video_decode)
+   {
+      component = previous = mmalplay_component_create(ctx, MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, &status);
+      if (!component)
+         goto error;
+      MMALPLAY_CONNECTION_IN(connections) = component->input[0];
+      MMALPLAY_CONNECTION_ADD(connections);
+      MMALPLAY_CONNECTION_OUT(connections) = component->output[0];
+   }
+   else ctx->video_out_port = source;
+
+   if (ctx->options.enable_scheduling)
+   {
+      /* Create a scheduler component */
+      component = previous = mmalplay_component_create(ctx, MMAL_COMPONENT_DEFAULT_SCHEDULER, &status);
+      if (!component)
+         goto error;
+      MMALPLAY_CONNECTION_IN(connections) = component->input[0];
+      MMALPLAY_CONNECTION_ADD(connections);
+      MMALPLAY_CONNECTION_OUT(connections) = component->output[0];
+   }
+
+   /* Create and setup video converter component */
+   if (ctx->options.render_format ||
+       (ctx->options.render_rect.width && ctx->options.render_rect.height))
+   {
+      component = previous = mmalplay_component_create(ctx, MMAL_COMPONENT_DEFAULT_VIDEO_CONVERTER, &status);
+      if (!component)
+         goto error;
+      MMALPLAY_CONNECTION_IN(connections) = component->input[0];
+      MMALPLAY_CONNECTION_ADD(connections);
+      MMALPLAY_CONNECTION_OUT(connections) = component->output[0];
+   }
+
+   if (ctx->options.output_num > 1)
+   {
+      /* Create and setup splitter component */
+      component = previous = mmalplay_component_create(ctx, MMAL_COMPONENT_DEFAULT_SPLITTER, &status);
+      if (!component || component->output_num < ctx->options.output_num)
+         goto error;
+      MMALPLAY_CONNECTION_IN(connections) = component->input[0];
+      MMALPLAY_CONNECTION_ADD(connections);
+      MMALPLAY_CONNECTION_OUT(connections) = component->output[0];
+   }
+
+   /* Create and setup video render components */
+   for (i = 0; i < ctx->options.output_num; i++)
+   {
+      component = mmalplay_component_create(ctx, MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, &status);
+      if (!component)
+         goto error;
+      MMALPLAY_CONNECTION_OUT(connections) = previous ? previous->output[i] : source;
+      MMALPLAY_CONNECTION_IN(connections) = component->input[0];
+      MMALPLAY_CONNECTION_ADD(connections);
+   }
+
+   return MMAL_SUCCESS;
+
+ error:
+   connections->num = save;
+   return status == MMAL_SUCCESS ? MMAL_ENOSPC : status;
+}
+
+static MMAL_STATUS_T mmalplay_pipeline_clock_create(MMALPLAY_T *ctx, MMALPLAY_CONNECTIONS_T *connections)
+{
+   MMAL_STATUS_T status = MMAL_EINVAL;
+
+   if (!ctx->options.enable_scheduling)
+      return MMAL_SUCCESS;
+
+   if (!ctx->audio_clock || !ctx->video_clock)
+   {
+      LOG_ERROR("clock port(s) not present %p %p", ctx->audio_clock, ctx->video_clock);
+      return MMAL_SUCCESS;
+   }
+
+   /* Connect audio clock to video clock */
+   MMALPLAY_CONNECTION_SET(connections, MMAL_CONNECTION_FLAG_TUNNELLING);
+   MMALPLAY_CONNECTION_OUT(connections) = ctx->audio_clock;
+   MMALPLAY_CONNECTION_IN(connections) = ctx->video_clock;
+   MMALPLAY_CONNECTION_ADD(connections);
+
+   /* Set audio clock as master */
+   status = mmal_port_parameter_set_boolean(ctx->audio_clock, MMAL_PARAMETER_CLOCK_REFERENCE, MMAL_TRUE);
+   if (status != MMAL_SUCCESS)
+      LOG_ERROR("failed to set clock reference");
+
+ error:
+   return status;
+}
+
+/** Create an instance of mmalplay.
+ * Note: this is test code. Do not use it in your app. It *will* change or even be removed without notice.
+ */
+MMALPLAY_T *mmalplay_create(const char *uri, MMALPLAY_OPTIONS_T *opts, MMAL_STATUS_T *pstatus)
+{
+   MMAL_STATUS_T status = MMAL_SUCCESS, status_audio, status_video, status_clock;
+   MMALPLAY_T *ctx;
+   MMAL_COMPONENT_T *component;
+   MMALPLAY_CONNECTIONS_T connections;
+   unsigned int i;
+
+   LOG_TRACE("%s", uri);
+
+   if (pstatus) *pstatus = MMAL_ENOMEM;
+
+   /* Allocate and initialise context */
+   ctx = malloc(sizeof(MMALPLAY_T));
+   if (!ctx)
+      return NULL;
+   memset(ctx, 0, sizeof(*ctx));
+   memset(&connections, 0, sizeof(connections));
+   if (vcos_semaphore_create(&ctx->event, "MMALTest", 1) != VCOS_SUCCESS)
+   {
+      free(ctx);
+      return NULL;
+   }
+
+   ctx->uri = uri;
+   if (opts)
+      ctx->options = *opts;
+
+   ctx->options.output_num = MMAL_MAX(ctx->options.output_num, 1);
+   ctx->options.output_num = MMAL_MIN(ctx->options.output_num, MMALPLAY_MAX_RENDERERS);
+   connections.num = 0;
+
+   /* Create and setup the container reader component */
+   component = mmalplay_component_create(ctx, MMAL_COMPONENT_DEFAULT_CONTAINER_READER, &status);
+   if (!component)
+      goto error;
+
+   status_video = mmalplay_pipeline_video_create(ctx, ctx->reader_video, &connections);
+   status_audio = mmalplay_pipeline_audio_create(ctx, ctx->reader_audio, &connections);
+   status_clock = mmalplay_pipeline_clock_create(ctx, &connections);
+   if (status_video != MMAL_SUCCESS && status_audio != MMAL_SUCCESS && status_clock != MMAL_SUCCESS)
+   {
+      status = status_video;
+      goto error;
+   }
+
+   /* Create our connections */
+   for (i = 0; i < connections.num; i++)
+   {
+      status = mmalplay_connection_create(ctx, connections.connection[i].out, connections.connection[i].in,
+            connections.connection[i].flags);
+      if (status != MMAL_SUCCESS)
+         goto error;
+   }
+
+   /* Enable our connections */
+   for (i = 0; i < ctx->connection_num; i++)
+   {
+      status = mmal_connection_enable(ctx->connection[i]);
+      if (status != MMAL_SUCCESS)
+         goto error;
+   }
+
+   if (pstatus) *pstatus = MMAL_SUCCESS;
+   return ctx;
+
+ error:
+   mmalplay_destroy(ctx);
+   if (status == MMAL_SUCCESS) status = MMAL_ENOSPC;
+   if (pstatus) *pstatus = status;
+   return NULL;
+}
+
+/** Start playback on an instance of mmalplay.
+ * Note: this is test code. Do not use it in your app. It *will* change or even be removed without notice.
+ */
+MMAL_STATUS_T mmalplay_play(MMALPLAY_T *ctx)
+{
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   unsigned int i;
+
+   LOG_TRACE("%p, %s", ctx, ctx->uri);
+
+   ctx->time_playback = vcos_getmicrosecs();
+
+   /* Start the clocks */
+   if (ctx->video_clock)
+      mmal_port_parameter_set_boolean(ctx->video_clock, MMAL_PARAMETER_CLOCK_ACTIVE, MMAL_TRUE);
+   if (ctx->audio_clock)
+      mmal_port_parameter_set_boolean(ctx->audio_clock, MMAL_PARAMETER_CLOCK_ACTIVE, MMAL_TRUE);
+
+   while(1)
+   {
+      MMAL_BUFFER_HEADER_T *buffer;
+
+      vcos_semaphore_wait(&ctx->event);
+      if (ctx->stop || ctx->status != MMAL_SUCCESS)
+      {
+         status = ctx->status;
+         break;
+      }
+
+      /* Loop through all the connections */
+      for (i = 0; i < ctx->connection_num; i++)
+      {
+         MMAL_CONNECTION_T *connection = ctx->connection[i];
+
+         if (connection->flags & MMAL_CONNECTION_FLAG_TUNNELLING)
+            continue; /* Nothing else to do in tunnelling mode */
+
+         /* Send any queued buffer to the next component */
+         buffer = mmal_queue_get(connection->queue);
+         while (buffer)
+         {
+            if (buffer->cmd)
+            {
+               status = mmalplay_event_handle(connection, connection->out, buffer);
+               if (status != MMAL_SUCCESS)
+                  goto error;
+               buffer = mmal_queue_get(connection->queue);
+               continue;
+            }
+
+            /* Code specific to handling of the video output port */
+            if (connection->out == ctx->video_out_port)
+            {
+               if (buffer->length)
+                  ctx->decoded_frames++;
+
+               if (ctx->options.stepping)
+                  getchar();
+            }
+
+            status = mmal_port_send_buffer(connection->in, buffer);
+            if (status != MMAL_SUCCESS)
+            {
+               LOG_ERROR("mmal_port_send_buffer failed (%i)", status);
+               mmal_queue_put_back(connection->queue, buffer);
+               goto error;
+            }
+            buffer = mmal_queue_get(connection->queue);
+         }
+
+         /* Send empty buffers to the output port of the connection */
+         buffer = connection->pool ? mmal_queue_get(connection->pool->queue) : NULL;
+         while (buffer)
+         {
+            status = mmal_port_send_buffer(connection->out, buffer);
+            if (status != MMAL_SUCCESS)
+            {
+               LOG_ERROR("mmal_port_send_buffer failed (%i)", status);
+               mmal_queue_put_back(connection->pool->queue, buffer);
+               goto error;
+            }
+            buffer = mmal_queue_get(connection->pool->queue);
+         }
+      }
+   }
+
+ error:
+   ctx->time_playback = vcos_getmicrosecs() - ctx->time_playback;
+
+   /* For still images we want to pause a bit once they are displayed */
+   if (ctx->is_still_image && status == MMAL_SUCCESS)
+      vcos_sleep(MMALPLAY_STILL_IMAGE_PAUSE);
+
+   return status;
+}
+
+/** Stop the playback on an instance of mmalplay.
+ * Note: this is test code. Do not use it in your app. It *will* change or even be removed without notice.
+ */
+void mmalplay_stop(MMALPLAY_T *ctx)
+{
+   ctx->stop = 1;
+   vcos_semaphore_post(&ctx->event);
+}
+
+/** Destroys an instance of mmalplay.
+ * Note: this is test code. Do not use it in your app. It *will* change or even be removed without notice.
+ */
+void mmalplay_destroy(MMALPLAY_T *ctx)
+{
+   unsigned int i;
+
+   LOG_TRACE("%p, %s", ctx, ctx->uri);
+
+   /* Disable connections */
+   for (i = ctx->connection_num; i; i--)
+      mmal_connection_disable(ctx->connection[i-1]);
+
+   LOG_INFO("--- statistics ---");
+   LOG_INFO("decoded %i frames in %.2fs (%.2ffps)", (int)ctx->decoded_frames,
+            ctx->time_playback / 1000000.0, ctx->decoded_frames * 1000000.0 / ctx->time_playback);
+
+   for (i = 0; i < ctx->connection_num; i++)
+   {
+      LOG_INFO("%s", ctx->connection[i]->name);
+      LOG_INFO("- setup time: %ims",
+               (int)(ctx->connection[i]->time_setup / 1000));
+      LOG_INFO("- enable time: %ims, disable time: %ims",
+               (int)(ctx->connection[i]->time_enable / 1000),
+               (int)(ctx->connection[i]->time_disable / 1000));
+   }
+
+   /* Destroy connections */
+   for (i = ctx->connection_num; i; i--)
+      mmal_connection_destroy(ctx->connection[i-1]);
+
+   /* Destroy components */
+   for (i = ctx->component_num; i; i--)
+   {
+      ctx->component[i-1].time_cleanup = vcos_getmicrosecs();
+      mmal_component_destroy(ctx->component[i-1].comp);
+      ctx->component[i-1].time_cleanup = vcos_getmicrosecs() - ctx->component[i-1].time_cleanup;
+   }
+
+   vcos_semaphore_delete(&ctx->event);
+
+   for (i = 0; i < ctx->component_num; i++)
+   {
+      LOG_INFO("%s:", ctx->component[i].name);
+      LOG_INFO("- setup time: %ims, cleanup time: %ims",
+               (int)(ctx->component[i].time_setup / 1000),
+               (int)(ctx->component[i].time_cleanup / 1000));
+   }
+   LOG_INFO("-----------------");
+
+   free(ctx);
+}
+
+/*****************************************************************************/
+static MMAL_COMPONENT_T *mmalplay_component_create(MMALPLAY_T *ctx,
+   const char *name, MMAL_STATUS_T *status)
+{
+   MMALPLAY_COMPONENT_T *component = &ctx->component[ctx->component_num];
+   const char *component_name = name;
+
+   LOG_TRACE("%p, %s", ctx, name);
+
+   if (ctx->component_num >= MMAL_COUNTOF(ctx->component))
+   {
+      *status = MMAL_ENOSPC;
+      return NULL;
+   }
+
+   /* Decide whether we want an image decoder instead of a video_decoder */
+   if (ctx->is_still_image &&
+       !strcmp(name, MMAL_COMPONENT_DEFAULT_VIDEO_DECODER) && !ctx->options.component_video_decoder)
+      ctx->options.component_video_decoder = MMAL_COMPONENT_DEFAULT_IMAGE_DECODER;
+
+   /* Override name if requested by the user */
+   if (!strcmp(name, MMAL_COMPONENT_DEFAULT_VIDEO_DECODER) && ctx->options.component_video_decoder)
+      component_name = ctx->options.component_video_decoder;
+   else if (!strcmp(name, MMAL_COMPONENT_DEFAULT_SPLITTER) && ctx->options.component_splitter)
+      component_name = ctx->options.component_splitter;
+   else if (!strcmp(name, MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER) && ctx->options.component_video_render)
+      component_name = ctx->options.component_video_render;
+   else if (!strcmp(name, MMAL_COMPONENT_DEFAULT_VIDEO_CONVERTER) && ctx->options.component_video_converter)
+      component_name = ctx->options.component_video_converter;
+   else if (!strcmp(name, MMAL_COMPONENT_DEFAULT_SCHEDULER) && ctx->options.component_video_scheduler)
+      component_name = ctx->options.component_video_scheduler;
+   else if (!strcmp(name, MMAL_COMPONENT_DEFAULT_AUDIO_DECODER) && ctx->options.component_audio_decoder)
+      component_name = ctx->options.component_audio_decoder;
+   else if (!strcmp(name, MMAL_COMPONENT_DEFAULT_AUDIO_RENDERER) && ctx->options.component_audio_render)
+      component_name = ctx->options.component_audio_render;
+   else if (!strcmp(name, MMAL_COMPONENT_DEFAULT_CONTAINER_READER) && ctx->options.component_container_reader)
+      component_name = ctx->options.component_container_reader;
+
+   component->comp = NULL;
+   vcos_safe_strcpy(component->name, component_name, sizeof(component->name), 0);
+   component->time_setup = vcos_getmicrosecs();
+
+   /* Create the component */
+   *status = mmal_component_create(component_name, &component->comp);
+   if(*status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("couldn't create %s", component_name);
+      goto error;
+   }
+
+   if (!strcmp(name, MMAL_COMPONENT_DEFAULT_CONTAINER_READER))
+      *status = mmalplay_setup_container_reader(ctx, component->comp, ctx->uri);
+   else if (!strcmp(name, MMAL_COMPONENT_DEFAULT_CONTAINER_WRITER))
+      *status = mmalplay_setup_container_writer(ctx, component->comp, ctx->options.output_uri);
+   else if (!strcmp(name, MMAL_COMPONENT_DEFAULT_VIDEO_DECODER))
+      *status = mmalplay_setup_video_decoder(ctx, component->comp);
+   else if (!strcmp(name, MMAL_COMPONENT_DEFAULT_SPLITTER))
+      *status = mmalplay_setup_splitter(ctx, component->comp);
+   else if (!strcmp(name, MMAL_COMPONENT_DEFAULT_VIDEO_CONVERTER))
+      *status = mmalplay_setup_video_converter(ctx, component->comp);
+   else if (!strcmp(name, MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER))
+      *status = mmalplay_setup_video_render(ctx, component->comp);
+   else if (!strcmp(name, MMAL_COMPONENT_DEFAULT_SCHEDULER))
+      *status = mmalplay_setup_video_scheduler(ctx, component->comp);
+   else if (!strcmp(name, MMAL_COMPONENT_DEFAULT_AUDIO_DECODER))
+      *status = mmalplay_setup_audio_decoder(ctx, component->comp);
+   else if (!strcmp(name, MMAL_COMPONENT_DEFAULT_AUDIO_RENDERER))
+      *status = mmalplay_setup_audio_render(ctx, component->comp);
+
+   if (*status != MMAL_SUCCESS)
+      goto error;
+
+   /* Enable component */
+   *status = mmal_component_enable(component->comp);
+   if(*status)
+   {
+      LOG_ERROR("%s couldn't be enabled", component_name);
+      goto error;
+   }
+
+   /* Enable control port. The callback specified here is the function which
+    * will be called when an empty buffer header comes back to the port. */
+   component->comp->control->userdata = (void *)ctx;
+   *status = mmal_port_enable(component->comp->control, mmalplay_bh_control_cb);
+   if (*status)
+   {
+      LOG_ERROR("control port couldn't be enabled");
+      goto error;
+   }
+
+   component->time_setup = vcos_getmicrosecs() - component->time_setup;
+   ctx->component_num++;
+   return component->comp;
+
+ error:
+   component->time_setup = vcos_getmicrosecs() - component->time_setup;
+   if (component->comp)
+      mmal_component_destroy(component->comp);
+   return NULL;
+}
+
+/*****************************************************************************/
+static MMAL_STATUS_T mmalplay_connection_create(MMALPLAY_T *ctx, MMAL_PORT_T *out, MMAL_PORT_T *in, uint32_t flags)
+{
+   MMAL_CONNECTION_T **connection = &ctx->connection[ctx->connection_num];
+   uint32_t encoding_override = MMAL_ENCODING_UNKNOWN;
+   MMAL_RECT_T *rect_override = NULL;
+   MMAL_BOOL_T format_override = MMAL_FALSE;
+   MMAL_STATUS_T status;
+
+   if (ctx->connection_num >= MMAL_COUNTOF(ctx->connection))
+      return MMAL_ENOMEM;
+
+   /* Globally enable tunnelling if requested by the user */
+   flags |= ctx->options.tunnelling ? MMAL_CONNECTION_FLAG_TUNNELLING : 0;
+
+   /* Apply any override to the format specified by the user */
+   if (out == ctx->video_out_port)
+   {
+      encoding_override = ctx->options.output_format;
+      rect_override = &ctx->options.output_rect;
+   }
+   else if (out == ctx->converter_out_port)
+   {
+      encoding_override = ctx->options.render_format;
+      rect_override = &ctx->options.render_rect;
+   }
+
+   if (encoding_override != MMAL_ENCODING_UNKNOWN &&
+       encoding_override != out->format->encoding)
+   {
+      out->format->encoding = encoding_override;
+      format_override = MMAL_TRUE;
+   }
+
+   if (rect_override && rect_override->width && rect_override->height)
+   {
+      out->format->es->video.crop = *rect_override;
+      out->format->es->video.width = rect_override->width;
+      out->format->es->video.height = rect_override->height;
+      format_override = MMAL_TRUE;
+   }
+
+   if (format_override)
+   {
+      status = mmal_port_format_commit(out);
+      if (status != MMAL_SUCCESS)
+      {
+         LOG_ERROR("cannot override format on output port %s", out->name);
+         return status;
+      }
+   }
+
+   /* Create the actual connection */
+   status = mmal_connection_create(connection, out, in, flags);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("cannot create connection");
+      return status;
+   }
+
+   /* Set our connection callback */
+   (*connection)->callback = mmalplay_connection_cb;
+   (*connection)->user_data = (void *)ctx;
+
+   log_format(out->format, out);
+   log_format(in->format, in);
+
+   ctx->connection_num++;
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+static MMAL_STATUS_T mmalplay_setup_video_decoder(MMALPLAY_T *ctx, MMAL_COMPONENT_T *decoder)
+{
+   MMAL_PARAMETER_BOOLEAN_T param_zc =
+      {{MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T)}, 1};
+   MMAL_STATUS_T status = MMAL_EINVAL;
+
+   if(!decoder->input_num || !decoder->output_num)
+   {
+      LOG_ERROR("%s doesn't have input/output ports", decoder->name);
+      goto error;
+   }
+
+   /* Enable Zero Copy if requested. This needs to be sent before enabling the port. */
+   if (!ctx->options.copy_input)
+   {
+      status = mmal_port_parameter_set(decoder->input[0], &param_zc.hdr);
+      if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
+      {
+         LOG_ERROR("failed to set zero copy on %s", decoder->input[0]->name);
+         goto error;
+      }
+   }
+   if (!ctx->options.copy_output)
+   {
+      status = mmal_port_parameter_set(decoder->output[0], &param_zc.hdr);
+      if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
+      {
+         LOG_ERROR("failed to set zero copy on %s", decoder->output[0]->name);
+         goto error;
+      }
+   }
+
+   ctx->video_out_port = decoder->output[0];
+   status = MMAL_SUCCESS;
+
+ error:
+   return status;
+}
+
+/*****************************************************************************/
+static MMAL_STATUS_T mmalplay_setup_splitter(MMALPLAY_T *ctx, MMAL_COMPONENT_T *splitter)
+{
+   MMAL_STATUS_T status = MMAL_EINVAL;
+
+   if(!splitter->input_num || !splitter->output_num)
+   {
+      LOG_ERROR("%s doesn't have input ports", splitter->name);
+      goto error;
+   }
+   if(splitter->output_num < ctx->options.output_num)
+   {
+      LOG_ERROR("%s doesn't have enough output ports (%u/%u)", splitter->name,
+                (unsigned int)splitter->output_num, ctx->options.output_num);
+      goto error;
+   }
+
+   /* Enable Zero Copy if requested. This needs to be sent before enabling the port. */
+   if (!ctx->options.copy_output)
+   {
+      MMAL_PARAMETER_BOOLEAN_T param_zc =
+         {{MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T)}, 1};
+      unsigned int i;
+
+      status = mmal_port_parameter_set(splitter->input[0], &param_zc.hdr);
+      if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
+      {
+         LOG_ERROR("failed to set zero copy on %s", splitter->input[0]->name);
+         goto error;
+      }
+      for (i = 0; i < splitter->output_num; i++)
+      {
+         status = mmal_port_parameter_set(splitter->output[i], &param_zc.hdr);
+         if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
+         {
+            LOG_ERROR("failed to set zero copy on %s", splitter->output[i]->name);
+            goto error;
+         }
+      }
+   }
+
+   status = MMAL_SUCCESS;
+
+ error:
+   return status;
+}
+
+/*****************************************************************************/
+static MMAL_STATUS_T mmalplay_setup_video_converter(MMALPLAY_T *ctx, MMAL_COMPONENT_T *converter)
+{
+   MMAL_PARAMETER_BOOLEAN_T param_zc =
+      {{MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T)}, 1};
+   MMAL_STATUS_T status = MMAL_EINVAL;
+
+   if(!converter->input_num || !converter->output_num)
+   {
+      LOG_ERROR("%s doesn't have input/output ports", converter->name);
+      goto error;
+   }
+
+   /* Enable Zero Copy if requested. This needs to be sent before enabling the port. */
+   if (!ctx->options.copy_output)
+   {
+      status = mmal_port_parameter_set(converter->input[0], &param_zc.hdr);
+      if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
+      {
+         LOG_ERROR("failed to set zero copy on %s", converter->input[0]->name);
+         goto error;
+      }
+      status = mmal_port_parameter_set(converter->output[0], &param_zc.hdr);
+      if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
+      {
+         LOG_ERROR("failed to set zero copy on %s", converter->output[0]->name);
+         goto error;
+      }
+   }
+
+   ctx->converter_out_port = converter->output[0];
+   status = MMAL_SUCCESS;
+
+ error:
+   return status;
+}
+
+/*****************************************************************************/
+static MMAL_STATUS_T mmalplay_setup_video_render(MMALPLAY_T *ctx, MMAL_COMPONENT_T *render)
+{
+   MMAL_STATUS_T status = MMAL_EINVAL;
+   unsigned int render_num;
+
+   if(!render->input_num)
+   {
+      LOG_ERROR("%s doesn't have input ports", render->name);
+      goto error;
+   }
+
+   render_num = video_render_num++;
+
+   /* Give higher priority to the overlay layer */
+   MMAL_DISPLAYREGION_T param;
+   param.hdr.id = MMAL_PARAMETER_DISPLAYREGION;
+   param.hdr.size = sizeof(MMAL_DISPLAYREGION_T);
+   param.set = MMAL_DISPLAY_SET_LAYER|MMAL_DISPLAY_SET_NUM;
+   param.layer = ctx->options.render_layer + 2;   /* Offset of two to put it above the Android UI layer */
+   param.display_num = ctx->options.video_destination;
+   if (ctx->options.window)
+   {
+      param.dest_rect.x = 0;
+      param.dest_rect.width = 512;
+      param.dest_rect.height = 256;
+      param.dest_rect.y = param.dest_rect.height * render_num;
+      param.mode = MMAL_DISPLAY_MODE_LETTERBOX;
+      param.fullscreen = 0;
+      param.set |= MMAL_DISPLAY_SET_DEST_RECT|MMAL_DISPLAY_SET_MODE|MMAL_DISPLAY_SET_FULLSCREEN;
+   }
+   status = mmal_port_parameter_set( render->input[0], &param.hdr );
+   if(status != MMAL_SUCCESS && status != MMAL_ENOSYS)
+   {
+      LOG_ERROR("could not set video render layer on %s", render->input[0]->name);
+      goto error;
+   }
+
+   /* Enable Zero Copy if requested. This needs to be sent before enabling the port. */
+   if (!ctx->options.copy_output)
+   {
+      MMAL_PARAMETER_BOOLEAN_T param_zc =
+         {{MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T)}, 1};
+      status = mmal_port_parameter_set(render->input[0], &param_zc.hdr);
+      if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
+      {
+         LOG_ERROR("failed to set zero copy on %s", render->input[0]->name);
+         goto error;
+      }
+   }
+
+   status = MMAL_SUCCESS;
+
+ error:
+   return status;
+}
+
+/*****************************************************************************/
+static MMAL_STATUS_T mmalplay_setup_container_reader(MMALPLAY_T *ctx,
+   MMAL_COMPONENT_T *reader, const char *uri)
+{
+   MMAL_PARAMETER_SEEK_T seek = {{MMAL_PARAMETER_SEEK, sizeof(MMAL_PARAMETER_SEEK_T)},0,0};
+   MMAL_PARAMETER_STRING_T *param = 0;
+   unsigned int param_size, track_audio, track_video;
+   MMAL_STATUS_T status = MMAL_EINVAL;
+   uint32_t encoding;
+   size_t uri_len;
+
+   if(!reader->output_num)
+   {
+      LOG_ERROR("%s doesn't have output ports", reader->name);
+      goto error;
+   }
+
+   /* Open the given URI */
+   uri_len = strlen(uri);
+   param_size = sizeof(MMAL_PARAMETER_STRING_T) + uri_len;
+   param = malloc(param_size);
+   if(!param)
+   {
+      LOG_ERROR("out of memory");
+      status = MMAL_ENOMEM;
+      goto error;
+   }
+   memset(param, 0, param_size);
+   param->hdr.id = MMAL_PARAMETER_URI;
+   param->hdr.size = param_size;
+   vcos_safe_strcpy(param->str, uri, uri_len + 1, 0);
+   status = mmal_port_parameter_set(reader->control, &param->hdr);
+   if(status != MMAL_SUCCESS && status != MMAL_ENOSYS)
+   {
+      LOG_ERROR("%s could not open file %s", reader->name, uri);
+      goto error;
+   }
+   status = MMAL_SUCCESS;
+
+   /* Look for a video track */
+   for(track_video = 0; track_video < reader->output_num; track_video++)
+      if(reader->output[track_video]->format->type == MMAL_ES_TYPE_VIDEO) break;
+   if(track_video != reader->output_num)
+   {
+      ctx->reader_video = reader->output[track_video];
+      /* Try to detect still images */
+      encoding = ctx->reader_video->format->encoding;
+      if (encoding == MMAL_ENCODING_JPEG ||
+          encoding == MMAL_ENCODING_GIF  ||
+          encoding == MMAL_ENCODING_PNG  ||
+          encoding == MMAL_ENCODING_PPM  ||
+          encoding == MMAL_ENCODING_TGA  ||
+          encoding == MMAL_ENCODING_BMP)
+         ctx->is_still_image = 1;
+   }
+
+   /* Look for an audio track */
+   for(track_audio = 0; track_audio < reader->output_num; track_audio++)
+      if(reader->output[track_audio]->format->type == MMAL_ES_TYPE_AUDIO) break;
+   if(track_audio != reader->output_num)
+      ctx->reader_audio = reader->output[track_audio];
+
+   if(track_video == reader->output_num &&
+      track_audio == reader->output_num)
+   {
+      LOG_ERROR("no track to decode");
+      status = MMAL_EINVAL;
+      goto error;
+   }
+
+   LOG_INFO("----Reader input port format-----");
+   if(track_video != reader->output_num)
+      log_format(reader->output[track_video]->format, 0);
+   if(track_audio != reader->output_num)
+      log_format(reader->output[track_audio]->format, 0);
+
+   if(ctx->options.seeking)
+   {
+      LOG_DEBUG("seek to %fs", ctx->options.seeking);
+      seek.offset = ctx->options.seeking * INT64_C(1000000);
+      status = mmal_port_parameter_set(reader->control, &seek.hdr);
+      if(status != MMAL_SUCCESS)
+         LOG_ERROR("failed to seek to %fs", ctx->options.seeking);
+   }
+
+ error:
+   if(param)
+      free(param);
+   return status;
+}
+
+/*****************************************************************************/
+static MMAL_STATUS_T mmalplay_setup_container_writer(MMALPLAY_T *ctx,
+   MMAL_COMPONENT_T *writer, const char *uri)
+{
+   MMAL_PARAMETER_URI_T *param = 0;
+   unsigned int param_size;
+   MMAL_STATUS_T status = MMAL_EINVAL;
+   size_t uri_len;
+   MMAL_PARAM_UNUSED(ctx);
+
+   if(!writer->input_num)
+   {
+      LOG_ERROR("%s doesn't have input ports", writer->name);
+      goto error;
+   }
+
+   /* Open the given URI */
+   uri_len = strlen(uri);
+   param_size = sizeof(MMAL_PARAMETER_HEADER_T) + uri_len;
+   param = malloc(param_size);
+   if(!param)
+   {
+      LOG_ERROR("out of memory");
+      status = MMAL_ENOMEM;
+      goto error;
+   }
+   memset(param, 0, param_size);
+   param->hdr.id = MMAL_PARAMETER_URI;
+   param->hdr.size = param_size;
+   vcos_safe_strcpy(param->uri, uri, uri_len + 1, 0);
+   status = mmal_port_parameter_set(writer->control, &param->hdr);
+   if(status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("could not open file %s", uri);
+      goto error;
+   }
+
+ error:
+   if(param)
+      free(param);
+   return status;
+}
+
+/*****************************************************************************/
+static MMAL_STATUS_T mmalplay_setup_video_scheduler(MMALPLAY_T *ctx, MMAL_COMPONENT_T *scheduler)
+{
+   MMAL_STATUS_T status = MMAL_EINVAL;
+
+   if (!scheduler->input_num || !scheduler->output_num || !scheduler->clock_num)
+   {
+      LOG_ERROR("%s doesn't have input/output/clock ports", scheduler->name);
+      goto error;
+   }
+
+   /* Enable Zero Copy if requested. This needs to be sent before enabling the port. */
+   if (!ctx->options.copy_output)
+   {
+      status = mmal_port_parameter_set_boolean(scheduler->input[0],
+            MMAL_PARAMETER_ZERO_COPY, MMAL_TRUE);
+      if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
+      {
+         LOG_ERROR("failed to set zero copy on %s", scheduler->input[0]->name);
+         goto error;
+      }
+      status = mmal_port_parameter_set_boolean(scheduler->output[0],
+            MMAL_PARAMETER_ZERO_COPY, MMAL_TRUE);
+      if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
+      {
+         LOG_ERROR("failed to set zero copy on %s", scheduler->output[0]->name);
+         goto error;
+      }
+   }
+
+   /* Save a copy of the clock port to connect to the audio clock port */
+   ctx->video_clock = scheduler->clock[0];
+
+   status = MMAL_SUCCESS;
+
+ error:
+   return status;
+}
+
+/*****************************************************************************/
+static MMAL_STATUS_T mmalplay_setup_audio_decoder(MMALPLAY_T *ctx, MMAL_COMPONENT_T *decoder)
+{
+   MMAL_STATUS_T status = MMAL_EINVAL;
+
+   if (!decoder->input_num || !decoder->output_num)
+   {
+      LOG_ERROR("%s doesn't have input/output ports", decoder->name);
+      goto error;
+   }
+
+   if (ctx->options.audio_passthrough)
+   {
+      status = mmal_port_parameter_set_boolean(decoder->control,
+         MMAL_PARAMETER_AUDIO_PASSTHROUGH, MMAL_TRUE);
+      if (status != MMAL_SUCCESS)
+         LOG_INFO("could not set audio passthrough mode");
+   }
+
+   /* Enable Zero Copy if requested. This needs to be sent before enabling the port. */
+   if (!ctx->options.copy_input)
+   {
+      status = mmal_port_parameter_set_boolean(decoder->input[0],
+            MMAL_PARAMETER_ZERO_COPY, MMAL_TRUE);
+      if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
+      {
+         LOG_ERROR("failed to set zero copy on %s", decoder->input[0]->name);
+         goto error;
+      }
+   }
+   if (!ctx->options.copy_output)
+   {
+      status = mmal_port_parameter_set_boolean(decoder->output[0],
+            MMAL_PARAMETER_ZERO_COPY, MMAL_TRUE);
+      if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
+      {
+         LOG_ERROR("failed to set zero copy on %s", decoder->output[0]->name);
+         goto error;
+      }
+   }
+
+   status = MMAL_SUCCESS;
+
+ error:
+   return status;
+}
+
+/*****************************************************************************/
+static MMAL_STATUS_T mmalplay_setup_audio_render(MMALPLAY_T *ctx, MMAL_COMPONENT_T *render)
+{
+   MMAL_STATUS_T status = MMAL_EINVAL;
+
+   /* Set the audio destination - not all audio render components support this */
+   if (ctx->options.audio_destination)
+   {
+      status = mmal_port_parameter_set_string(render->control,
+            MMAL_PARAMETER_AUDIO_DESTINATION, ctx->options.audio_destination);
+      if (status != MMAL_SUCCESS)
+         LOG_INFO("could not set audio destination");
+   }
+
+   /* Enable Zero Copy if requested. This needs to be sent before enabling the port. */
+   if (!ctx->options.copy_output)
+   {
+      status = mmal_port_parameter_set_boolean(render->input[0],
+            MMAL_PARAMETER_ZERO_COPY, MMAL_TRUE);
+      if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
+      {
+         LOG_ERROR("failed to set zero copy on %s", render->input[0]->name);
+         goto error;
+      }
+   }
+
+   if (render->clock_num)
+      ctx->audio_clock = render->clock[0];
+   else
+      LOG_ERROR("%s doesn't have a clock port", render->name);
+
+   status = MMAL_SUCCESS;
+
+ error:
+   return status;
+}
+
+/*****************************************************************************/
+static void log_format(MMAL_ES_FORMAT_T *format, MMAL_PORT_T *port)
+{
+   const char *name_type;
+
+   if(port)
+      LOG_INFO("%s:%s:%i", port->component->name,
+               port->type == MMAL_PORT_TYPE_CONTROL ? "ctr" :
+                  port->type == MMAL_PORT_TYPE_INPUT ? "in" :
+                  port->type == MMAL_PORT_TYPE_OUTPUT ? "out" : "invalid",
+               (int)port->index);
+
+   switch(format->type)
+   {
+   case MMAL_ES_TYPE_AUDIO: name_type = "audio"; break;
+   case MMAL_ES_TYPE_VIDEO: name_type = "video"; break;
+   case MMAL_ES_TYPE_SUBPICTURE: name_type = "subpicture"; break;
+   default: name_type = "unknown"; break;
+   }
+
+   LOG_INFO("type: %s, fourcc: %4.4s", name_type, (char *)&format->encoding);
+   LOG_INFO(" bitrate: %i, framed: %i", format->bitrate,
+            !!(format->flags & MMAL_ES_FORMAT_FLAG_FRAMED));
+   LOG_INFO(" extra data: %i, %p", format->extradata_size, format->extradata);
+   switch(format->type)
+   {
+   case MMAL_ES_TYPE_AUDIO:
+      LOG_INFO(" samplerate: %i, channels: %i, bps: %i, block align: %i",
+               format->es->audio.sample_rate, format->es->audio.channels,
+               format->es->audio.bits_per_sample, format->es->audio.block_align);
+      break;
+
+   case MMAL_ES_TYPE_VIDEO:
+      LOG_INFO(" width: %i, height: %i, (%i,%i,%i,%i)",
+               format->es->video.width, format->es->video.height,
+               format->es->video.crop.x, format->es->video.crop.y,
+               format->es->video.crop.width, format->es->video.crop.height);
+      LOG_INFO(" pixel aspect ratio: %i/%i, frame rate: %i/%i",
+               format->es->video.par.num, format->es->video.par.den,
+               format->es->video.frame_rate.num, format->es->video.frame_rate.den);
+      break;
+
+   case MMAL_ES_TYPE_SUBPICTURE:
+      break;
+
+   default: break;
+   }
+
+   if(!port)
+      return;
+
+   LOG_INFO(" buffers num: %i(opt %i, min %i), size: %i(opt %i, min: %i), align: %i",
+            port->buffer_num, port->buffer_num_recommended, port->buffer_num_min,
+            port->buffer_size, port->buffer_size_recommended, port->buffer_size_min,
+            port->buffer_alignment_min);
+}
diff --git a/host_applications/vmcs/vmcs_config.h.in b/host_applications/vmcs/vmcs_config.h.in
new file mode 100755 (executable)
index 0000000..ab32da1
--- /dev/null
@@ -0,0 +1,29 @@
+
+#ifndef VMCS_CONFIG_H
+#define VMCS_CONFIG_H
+
+/*
+ * Autogenerated by cmake from host_applications/vmcs/vmcs_config.h.in
+ */
+
+/** Root location to look for installed resources.
+  */
+#define VMCS_INSTALL_PREFIX     "${CMAKE_INSTALL_PREFIX}"
+
+/** Where to start looking for media files.
+  */
+#define VMCS_MEDIA_ROOT         "/sd"
+
+/** We can't use pakfs - it relies on vc_filesys since only
+  * VC understands PAK files, but vc_filesys can only be used
+  * by VC itself or in response to a VC request inside the file
+  * server.
+  */
+#define NO_PAKFS  1
+
+/** Don't try to check the disks after iltests. That's just silly
+  * on linux.
+  */
+#define ILTEST_NO_DISK_CHECKS
+
+#endif
diff --git a/host_support/include/vc_debug_sym.h b/host_support/include/vc_debug_sym.h
new file mode 100755 (executable)
index 0000000..4c4c37f
--- /dev/null
@@ -0,0 +1,186 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined( VC_DEBUG_SYM_H )
+#define VC_DEBUG_SYM_H
+
+/* ---- Include Files ----------------------------------------------------- */
+
+#include <stddef.h>
+#include "interface/vcos/vcos_stdint.h"
+
+/* ---- Constants and Types ---------------------------------------------- */
+
+typedef struct
+{
+    const char *label;
+    uint32_t    addr;
+    size_t      size;
+
+} VC_DEBUG_SYMBOL_T;
+
+/*
+ * Debug header+params are constructed by makefiles/internals/memorymap.mk
+ * (first .text section) and stored in the VC binary
+ */
+typedef struct
+{
+    uint32_t    symbolTableOffset;
+    uint32_t    magic;
+    uint32_t    paramSize;
+} VC_DEBUG_HEADER_T;
+
+typedef struct
+{
+    uint32_t    vcMemBase; /* base address of loaded binary */
+    uint32_t    vcMemSize;
+    uint32_t    vcEntryPoint;
+    uint32_t    symbolTableLength;
+} VC_DEBUG_PARAMS_T;
+
+#define VC_DEBUG_HEADER_MAGIC  (('V' << 0) + ('C' << 8) + ('D' << 16) + ('H' << 24))
+
+// Offset within the videocore memory map to get the address of the debug header.
+#define VC_DEBUG_HEADER_OFFSET 0x2800
+
+#if (defined( __VC4_BIG_ISLAND__ ) || defined (PLATFORM_RASPBERRYPI)) && !defined( __COVERITY__ )
+
+    /* Use of the debug symbols only makes sense on machines which have
+     * some type of shared memory architecture.
+     */
+
+#   define  USE_VC_DEBUG_SYMS   1
+#else
+#   define  USE_VC_DEBUG_SYMS   0
+#endif
+
+#if USE_VC_DEBUG_SYMS
+#   define  VCDBG_PRAGMA(foo) pragma foo
+#else
+#   define  VCDBG_PRAGMA(foo)
+#endif
+
+/*
+ * NOTE: The section name has to start with .init or the linker will
+ *       purge it out of the image (since nobody has any references to these).
+ */
+
+#if USE_VC_DEBUG_SYMS
+#define VC_DEBUG_SYMBOL(name,label,addr,size) \
+    VCDBG_PRAGMA( Data(LIT, ".init.vc_debug_sym" ); ) \
+    static const VC_DEBUG_SYMBOL_T vc_sym_##name = { label, (uint32_t)addr, size }; \
+    VCDBG_PRAGMA( Data )
+#else
+#define VC_DEBUG_SYMBOL(name,label,addr,size)
+#endif
+
+#define VC_DEBUG_VAR(var)   VC_DEBUG_SYMBOL(var,#var,&var,sizeof(var))
+
+/*
+ * When using VC_DEBUG_VAR, you typically want to use uncached memory, otherwise 
+ * it will go in cached memory and the host won't get a coherent view of the 
+ * memory. So we take advantage of the .ucdata section which gets linked into 
+ * the uncached memory space. 
+ *  
+ * Now this causes another problem, namely that the videocore linker ld/st 
+ * instructions only have 27-bit relocations, and accessing a global from 
+ * uncached memory is more than 27-bits away. So we create a couple of macros 
+ * which can be used to declare a variable and put it into the .ucdata section 
+ * and another macro which will dereference it as if it were a pointer. 
+ *  
+ * To use: 
+ *  
+ *      VC_DEBUG_DECLARE_UNCACHED_VAR( int, foo, 0xCafeBeef );
+ *      #define foo VC_DEBUG_ACCESS_UNCACHED_VAR(foo)
+ */
+
+#define VC_DEBUG_DECLARE_UNCACHED_VAR(var_type,var_name,var_init) \
+    VCDBG_PRAGMA( Data(".ucdata"); ) \
+    var_type var_name = (var_init); \
+    VCDBG_PRAGMA( Data(); ) \
+    var_type *vc_var_ptr_##var_name = &var_name; \
+    VC_DEBUG_VAR(var_name)
+
+#define VC_DEBUG_EXTERN_UNCACHED_VAR(var_type,var_name) \
+    extern var_type var_name; \
+    static var_type *vc_var_ptr_##var_name = &var_name
+
+#define VC_DEBUG_DECLARE_UNCACHED_STATIC_VAR(var_type,var_name,var_init) \
+    VCDBG_PRAGMA( Data(".ucdata"); ) \
+    static var_type var_name = (var_init); \
+    VCDBG_PRAGMA( Data(); ) \
+    static var_type *vc_var_ptr_##var_name = &var_name; \
+    VC_DEBUG_VAR(var_name)
+
+#define VC_DEBUG_DECLARE_UNCACHED_VAR_ZERO(var_type,var_name) \
+    VCDBG_PRAGMA( Data(".ucdata"); ) \
+    var_type var_name = {0}; \
+    VCDBG_PRAGMA( Data(); ) \
+    var_type *vc_var_ptr_##var_name = &var_name; \
+    VC_DEBUG_VAR(var_name)
+
+#define VC_DEBUG_DECLARE_UNCACHED_STATIC_VAR_ZERO(var_type,var_name) \
+    VCDBG_PRAGMA( Data(".ucdata"); ) \
+    static var_type var_name = {0}; \
+    VCDBG_PRAGMA( Data(); ) \
+    static var_type *vc_var_ptr_##var_name = &var_name; \
+    VC_DEBUG_VAR(var_name)
+
+#define VC_DEBUG_ACCESS_UNCACHED_VAR(var_name) (*vc_var_ptr_##var_name)
+
+/*
+ * Declare a constant character string. This doesn't need to be uncached
+ * since it never changes.
+ */
+
+#define VC_DEBUG_DECLARE_STRING_VAR(var_name,var_init) \
+    const char var_name[] = var_init; \
+    VC_DEBUG_VAR(var_name)
+
+/*
+ * Since some variable aren't actually referenced by the videocore 
+ * this variant uses a .init.* section to ensure that the variable 
+ * doesn't get pruned by the linker.
+ */
+
+#define VC_DEBUG_DECLARE_UNCACHED_STATIC_VAR_NO_PTR(var_type,var_name,var_init) \
+    VCDBG_PRAGMA( Data(".init.ucdata"); ) \
+    static var_type var_name = (var_init); \
+    VCDBG_PRAGMA( Data(); ) \
+    VC_DEBUG_VAR(var_name)
+
+/* ---- Variable Externs ------------------------------------------------- */
+
+#if USE_VC_DEBUG_SYMS
+extern VC_DEBUG_SYMBOL_T    __VC_DEBUG_SYM_START[];
+extern VC_DEBUG_SYMBOL_T    __VC_DEBUG_SYM_END[];
+#endif
+
+/* ---- Function Prototypes ---------------------------------------------- */
+
+#endif /* VC_DEBUG_SYM_H */
+
diff --git a/host_support/include/vc_mem.h b/host_support/include/vc_mem.h
new file mode 100755 (executable)
index 0000000..7de7e0b
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#if !defined( VC_MEM_H )
+#define VC_MEM_H
+
+#include <linux/ioctl.h>
+
+#define VC_MEM_IOC_MAGIC  'v'
+
+#define VC_MEM_IOC_MEM_PHYS_ADDR    _IOR( VC_MEM_IOC_MAGIC, 0, unsigned long )
+#define VC_MEM_IOC_MEM_SIZE         _IOR( VC_MEM_IOC_MAGIC, 1, unsigned int )
+#define VC_MEM_IOC_MEM_BASE         _IOR( VC_MEM_IOC_MAGIC, 2, unsigned int )
+#define VC_MEM_IOC_MEM_LOAD         _IOR( VC_MEM_IOC_MAGIC, 3, unsigned int )
+#define VC_MEM_IOC_MEM_COPY         _IOWR( VC_MEM_IOC_MAGIC, 4, char *)
+
+#if defined( __KERNEL__ )
+#define VC_MEM_TO_ARM_ADDR_MASK 0x3FFFFFFF
+
+extern unsigned long mm_vc_mem_phys_addr;
+extern unsigned int  mm_vc_mem_size;
+extern unsigned int  mm_vc_mem_base;
+extern int vc_mem_get_current_size( void );
+extern int vc_mem_get_current_base( void );
+extern int vc_mem_access_mem( int write_mem, void *buf, uint32_t vc_mem_addr, size_t num_bytes );
+#endif
+
+#endif  /* VC_MEM_H */
+
diff --git a/interface/khronos/CMakeLists.txt b/interface/khronos/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..9ad615b
--- /dev/null
@@ -0,0 +1,95 @@
+
+# Khronos
+#
+# Note: in Android the linker is unable or unwilling to resolve
+# dynamically using already loaded symbols. The libraries here
+# have quite a few circular dependencies, and so the only way
+# to make it work seems to be to have everything static.
+
+set(EGL_SOURCE
+   egl/egl_client_config.c
+   egl/egl_client_context.c
+   egl/egl_client.c
+   egl/egl_client_get_proc.c
+   egl/egl_client_surface.c
+   ext/egl_brcm_driver_monitor_client.c
+   ext/egl_brcm_perf_monitor_client.c
+   ext/egl_brcm_global_image_client.c
+   ext/egl_brcm_flush_client.c
+   ext/egl_khr_image_client.c
+   ext/egl_khr_sync_client.c
+   ext/gl_oes_egl_image_client.c
+   ext/egl_khr_lock_surface_client.c
+   ext/ext_gl_debug_marker.c
+   common/khrn_int_image.c
+   common/khrn_int_util.c
+   common/khrn_options.c
+   common/khrn_client_global_image_map.c
+   common/linux/khrn_client_rpc_linux.c
+   common/linux/khrn_client_platform_linux.c
+   vg/vg_int_mat3x3.c
+   vg/vg_client.c
+   common/khrn_client.c
+   ext/egl_openmaxil_client.c
+#   ../vmcs_host/vc_vchi_dispmanx.c
+   ext/gl_oes_draw_texture_client.c
+   ext/gl_oes_query_matrix_client.c
+   ext/gl_oes_framebuffer_object.c
+   ext/gl_oes_map_buffer.c
+   ext/gl_oes_matrix_palette_client.c)
+set(GLES_SOURCE
+   glxx/glxx_client.c)
+set(VG_SOURCE
+   vg/vg_client.c
+   vg/vg_int_mat3x3.c)
+set(WFC_SOURCE
+   wf/wfc_client_stream.c
+   wf/wfc_client.c
+   wf/wfc_client_server_api.c
+   wf/wfc_client_ipc.c
+   common/openwfc/khrn_client_platform_openwfc.c)
+set(CLIENT_SOURCE
+   common/khrn_client_pointermap.c
+   common/khrn_client_vector.c
+   common/khrn_int_hash.c
+   common/khrn_int_hash_asm.s
+   common/khrn_client_cache.c)
+
+add_library(EGL ${SHARED} ${EGL_SOURCE})
+add_library(GLESv2 ${SHARED} ${GLES_SOURCE})
+add_library(OpenVG ${SHARED} ${VG_SOURCE})
+add_library(WFC ${SHARED} ${WFC_SOURCE})
+add_library(khrn_client ${CLIENT_SOURCE})
+
+# TODO do we need EGL_static and GLESv2_static now that khrn_static exists?
+add_library(EGL_static STATIC ${EGL_SOURCE})
+add_library(GLESv2_static STATIC ${GLES_SOURCE})
+add_library(khrn_static STATIC
+   ${EGL_SOURCE} ${GLES_SOURCE} ${VG_SOURCE} ${WFC_SOURCE} ${CLIENT_SOURCE})
+
+if(KHRONOS_HAVE_VCSM)
+include_directories (../../host_applications/linux/libs/sm )
+set(VCSM_LIBS vcsm)
+add_definitions(-DKHRONOS_HAVE_VCSM)
+endif()
+
+target_link_libraries(EGL khrn_client vchiq_arm vcos bcm_host ${VCSM_LIBS} -lm)
+target_link_libraries(GLESv2 EGL khrn_client vcos)
+target_link_libraries(WFC EGL)
+target_link_libraries(OpenVG EGL)
+
+install(TARGETS EGL GLESv2 OpenVG WFC khrn_client DESTINATION lib)
+install(TARGETS EGL_static GLESv2_static khrn_static DESTINATION lib)
+
+# recommended names to use to avoid conflicts with mesa libs
+add_library(brcmEGL ${SHARED} ${EGL_SOURCE})
+add_library(brcmGLESv2 ${SHARED} ${GLES_SOURCE})
+add_library(brcmOpenVG ${SHARED} ${VG_SOURCE})
+add_library(brcmWFC ${SHARED} ${WFC_SOURCE})
+
+target_link_libraries(brcmEGL khrn_client vchiq_arm vcos bcm_host ${VCSM_LIBS} -lm)
+target_link_libraries(brcmGLESv2 brcmEGL khrn_client vcos)
+target_link_libraries(brcmWFC brcmEGL)
+target_link_libraries(brcmOpenVG brcmEGL)
+
+install(TARGETS brcmEGL brcmGLESv2 brcmOpenVG brcmWFC DESTINATION lib)
diff --git a/interface/khronos/common/abstract/khrn_client_platform_filler_abstract.h b/interface/khronos/common/abstract/khrn_client_platform_filler_abstract.h
new file mode 100755 (executable)
index 0000000..1ae14d3
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_CLIENT_PLATFORM_ABSTRACT_H
+#define KHRN_CLIENT_PLATFORM_ABSTRACT_H
+
+#include "interface/vcos/vcos.h"
+
+typedef int KHR_STATUS_T;
+#define KHR_SUCCESS  0
+/*
+   mutex
+*/
+
+typedef struct PLATFORM_MUTEX_T
+{
+   /* nothing needed here */
+#if defined(_MSC_VER) || defined(__CC_ARM)
+   char dummy;    /* empty structures are not allowed */
+#endif
+} PLATFORM_MUTEX_T;
+
+
+VCOS_STATIC_INLINE
+VCOS_STATUS_T platform_mutex_create(PLATFORM_MUTEX_T *mutex) {
+   UNUSED(mutex);
+   // Nothing to do
+   return VCOS_SUCCESS;
+}
+
+VCOS_STATIC_INLINE
+void platform_mutex_destroy(PLATFORM_MUTEX_T *mutex)
+{
+   UNUSED(mutex);
+   /* Nothing to do */
+}
+
+VCOS_STATIC_INLINE
+void platform_mutex_acquire(PLATFORM_MUTEX_T *mutex)
+{
+   UNUSED(mutex);
+   /* Nothing to do */
+}
+
+VCOS_STATIC_INLINE
+void platform_mutex_release(PLATFORM_MUTEX_T *mutex)
+{
+   UNUSED(mutex);
+   /* Nothing to do */
+}
+
+/*
+   named counting semaphore
+*/
+
+typedef VCOS_NAMED_SEMAPHORE_T PLATFORM_SEMAPHORE_T;
+
+/*
+   VCOS_STATUS_T khronos_platform_semaphore_create(PLATFORM_SEMAPHORE_T *sem, int name[3], int count);
+
+   Preconditions:
+      sem is a valid pointer to an uninitialised variable
+      name is a valid pointer to three elements
+
+   Postconditions:
+      If return value is KHR_SUCCESS then sem contains a valid PLATFORM_SEMAPHORE_T
+*/
+
+extern VCOS_STATUS_T khronos_platform_semaphore_create(PLATFORM_SEMAPHORE_T *sem, int name[3], int count);
+extern void khronos_platform_semaphore_destroy(PLATFORM_SEMAPHORE_T *sem);
+extern void khronos_platform_semaphore_acquire(PLATFORM_SEMAPHORE_T *sem);
+extern void khronos_platform_semaphore_release(PLATFORM_SEMAPHORE_T *sem);
+
+/*
+   thread-local storage
+*/
+
+typedef void *PLATFORM_TLS_T;
+
+extern VCOS_STATUS_T platform_tls_create(PLATFORM_TLS_T *tls);
+extern void platform_tls_destroy(PLATFORM_TLS_T tls);
+extern void platform_tls_set(PLATFORM_TLS_T tls, void *v);
+extern void *platform_tls_get(PLATFORM_TLS_T tls);
+extern void* platform_tls_get_check(PLATFORM_TLS_T tls);
+extern void platform_tls_remove(PLATFORM_TLS_T tls);
+
+#endif
+
+
diff --git a/interface/khronos/common/direct/khrn_client_platform_filler_direct.h b/interface/khronos/common/direct/khrn_client_platform_filler_direct.h
new file mode 100755 (executable)
index 0000000..5ba6865
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_CLIENT_PLATFORM_FILLER_DIRECT_H
+#define KHRN_CLIENT_PLATFORM_FILLER_DIRECT_H
+
+#include "interface/vcos/vcos.h"
+
+typedef int KHR_STATUS_T;
+#define KHR_SUCCESS  0
+/*
+   mutex
+*/
+
+typedef struct PLATFORM_MUTEX_T
+{
+   /* nothing needed here */
+#if defined(_MSC_VER) || defined(__CC_ARM)
+   char dummy;    /* empty structures are not allowed */
+#endif
+} PLATFORM_MUTEX_T;
+
+
+VCOS_STATIC_INLINE
+VCOS_STATUS_T platform_mutex_create(PLATFORM_MUTEX_T *mutex) {
+   UNUSED(mutex);
+   // Nothing to do
+   return VCOS_SUCCESS;
+}
+
+VCOS_STATIC_INLINE
+void platform_mutex_destroy(PLATFORM_MUTEX_T *mutex)
+{
+   UNUSED(mutex);
+   /* Nothing to do */
+}
+
+VCOS_STATIC_INLINE
+void platform_mutex_acquire(PLATFORM_MUTEX_T *mutex)
+{
+   UNUSED(mutex);
+   /* Nothing to do */
+}
+
+VCOS_STATIC_INLINE
+void platform_mutex_release(PLATFORM_MUTEX_T *mutex)
+{
+   UNUSED(mutex);
+   /* Nothing to do */
+}
+
+/*
+   named counting semaphore
+*/
+
+typedef VCOS_NAMED_SEMAPHORE_T PLATFORM_SEMAPHORE_T;
+
+/*
+   VCOS_STATUS_T khronos_platform_semaphore_create(PLATFORM_SEMAPHORE_T *sem, int name[3], int count);
+
+   Preconditions:
+      sem is a valid pointer to an uninitialised variable
+      name is a valid pointer to three elements
+
+   Postconditions:
+      If return value is KHR_SUCCESS then sem contains a valid PLATFORM_SEMAPHORE_T
+*/
+
+extern VCOS_STATUS_T khronos_platform_semaphore_create(PLATFORM_SEMAPHORE_T *sem, int name[3], int count);
+extern void khronos_platform_semaphore_destroy(PLATFORM_SEMAPHORE_T *sem);
+extern void khronos_platform_semaphore_acquire(PLATFORM_SEMAPHORE_T *sem);
+extern void khronos_platform_semaphore_release(PLATFORM_SEMAPHORE_T *sem);
+
+/*
+   thread-local storage
+*/
+
+typedef void *PLATFORM_TLS_T;
+
+extern VCOS_STATUS_T platform_tls_create(PLATFORM_TLS_T *tls);
+extern void platform_tls_destroy(PLATFORM_TLS_T tls);
+extern void platform_tls_set(PLATFORM_TLS_T tls, void *v);
+extern void *platform_tls_get(PLATFORM_TLS_T tls);
+extern void* platform_tls_get_check(PLATFORM_TLS_T tls);
+extern void platform_tls_remove(PLATFORM_TLS_T tls);
+
+#endif
+
+
diff --git a/interface/khronos/common/khrn_client.c b/interface/khronos/common/khrn_client.c
new file mode 100755 (executable)
index 0000000..ef4babd
--- /dev/null
@@ -0,0 +1,612 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#define VCOS_LOG_CATEGORY (&khrn_client_log)
+#include "interface/khronos/common/khrn_int_common.h"
+
+#include "interface/khronos/common/khrn_client_check_types.h"
+#include "interface/khronos/common/khrn_client.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+#include "interface/khronos/egl/egl_client_config.h"
+#include "interface/khronos/glxx/glxx_client.h"
+
+#if defined(V3D_LEAN)
+#include "interface/khronos/common/khrn_int_misc_impl.h"
+#endif
+
+#if EGL_KHR_sync
+#include "interface/khronos/ext/egl_khr_sync_client.h"
+#endif
+
+#if EGL_BRCM_perf_monitor
+#include "interface/khronos/ext/egl_brcm_perf_monitor_client.h"
+#endif
+
+#if EGL_BRCM_driver_monitor
+#include "interface/khronos/ext/egl_brcm_driver_monitor_client.h"
+#endif
+
+#ifdef RPC_LIBRARY
+#include "middleware/dlloader/dlfcn.h"
+#include "applications/vmcs/khronos/khronos_server.h"
+#endif
+
+VCOS_LOG_CAT_T khrn_client_log = VCOS_LOG_INIT("khrn_client", VCOS_LOG_WARN);
+
+/*
+   void client_try_unload_server(CLIENT_PROCESS_STATE_T *process)
+
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   -
+
+   Invariants preserved:
+
+   -
+
+   Invariants used:
+
+   -
+*/
+
+void client_try_unload_server(CLIENT_PROCESS_STATE_T *process)
+{
+   if (/* some context is current */
+      (process->context_current_count != 0) ||
+      /* egl is initialised */
+      process->inited) {
+      return;
+   }
+
+   /*
+      Prompt the server to unload Khronos VLL if it can,
+      and wait until it is done
+   */
+#ifdef RPC_LIBRARY   //TODO: not thread safe
+   if (process->connected) {
+      const KHRONOS_FUNC_TABLE_T *func_table;
+      func_table = khronos_server_lock_func_table(client_library_get_connection());
+      if (func_table != NULL)
+      {
+         func_table->khrn_misc_try_unload_impl();
+         khronos_server_disconnect();
+      }
+      khronos_server_unlock_func_table();
+
+      process->connected = false;
+   }
+#else
+   {
+      CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+      RPC_INT_RES(RPC_CALL0_RES(khrn_misc_try_unload_impl, thread, KHRNMISCTRYUNLOAD_ID)); // return unimportant - read is just to cause blocking
+   }
+#endif
+}
+
+/*
+   void client_process_state_init(CLIENT_PROCESS_STATE_T *state)
+
+   Implementation notes:
+
+   Does nothing if already initialised.
+
+   Preconditions:
+
+   process is a valid pointer
+   Thread owns EGL lock
+   client_process_state_term must be called at some point after calling this function if we return true.
+
+   Postconditions:
+
+   Either:
+   - an error occurred and false is returned, or
+   - process->inited is true
+
+   Invariants preserved:
+
+   All invariants on CLIENT_PROCESS_STATE_T
+   (CLIENT_PROCESS_STATE_INITED_SANITY)
+
+   Invariants used:
+
+   -
+*/
+
+bool client_process_state_init(CLIENT_PROCESS_STATE_T *process)
+{
+   if (!process->inited) {
+      if (!khrn_pointer_map_init(&process->contexts, 64))
+         return false;
+
+      if (!khrn_pointer_map_init(&process->surfaces, 64))
+      {
+         khrn_pointer_map_term(&process->contexts);
+         return false;
+      }
+      if (!khrn_pointer_map_init(&process->windows, 64))
+      {
+         khrn_pointer_map_term(&process->contexts);
+         khrn_pointer_map_term(&process->surfaces);
+         return false;
+      }
+      
+#if EGL_KHR_sync
+      if (!khrn_pointer_map_init(&process->syncs, 64))
+      {
+         khrn_pointer_map_term(&process->contexts);
+         khrn_pointer_map_term(&process->surfaces);
+         khrn_pointer_map_term(&process->windows);
+         return false;
+      }
+#endif
+#if EGL_BRCM_global_image && EGL_KHR_image
+      khrn_global_image_map_init(&process->global_image_egl_images, 8);
+#endif
+      process->next_surface = 1;
+      process->next_context = 1;
+#if EGL_KHR_sync
+      process->next_sync = 0x80000001;
+#endif
+#if EGL_BRCM_global_image && EGL_KHR_image
+      process->next_global_image_egl_image = 1 << 31;
+#endif
+
+#if EGL_BRCM_perf_monitor
+      process->perf_monitor_inited = false;
+#endif
+
+#ifdef RPC_LIBRARY
+      if (!process->connected) {
+         process->khrn_connection.make_current_func = client_library_send_make_current;
+         khronos_server_lock_func_table(&process->khrn_connection);
+         khronos_server_connect(&process->khrn_connection);
+         khronos_server_unlock_func_table();
+         RPC_CALL0(khrn_misc_startup_impl, NULL, no_id);
+
+         process->connected = true;
+      }
+#endif
+
+      process->inited = true;
+   }
+
+#ifndef ABSTRACT_PLATFORM
+#if defined(ANDROID) && !defined (ANDROID_HWCOMPOSER)
+   egl_config_install_configs(1); // T-format configs
+#else
+   egl_config_install_configs(0); // RSO configs
+#endif
+#endif
+
+   return true;
+}
+
+#include "interface/khronos/common/khrn_client_cr.c"
+
+/*
+   void client_process_state_term(CLIENT_PROCESS_STATE_T *process)
+
+   Implementation notes:
+
+   Does nothing if already terminated.
+
+   Preconditions:
+
+   process is a valid pointer
+   Thread owns EGL lock
+
+   Postconditions:
+
+   process->inited is false.
+
+   Invariants preserved:
+
+   (EGL_CONTEXT_IS_DESTROYED)
+   (CLIENT_PROCESS_STATE_INITED_SANITY)
+
+   Invariants used:
+
+   -
+*/
+
+void client_process_state_term(CLIENT_PROCESS_STATE_T *process)
+{
+   if (process->inited) {
+      khrn_pointer_map_iterate(&process->contexts, callback_destroy_context, NULL);
+      khrn_pointer_map_term(&process->contexts);
+
+      khrn_pointer_map_iterate(&process->surfaces, callback_destroy_surface, NULL);
+      khrn_pointer_map_term(&process->surfaces);
+
+      khrn_pointer_map_term(&process->windows);
+      
+#if EGL_KHR_sync
+      egl_sync_destroy_all(&process->syncs);
+      khrn_pointer_map_term(&process->syncs);
+#endif
+
+#if EGL_BRCM_global_image && EGL_KHR_image
+      khrn_global_image_map_term(&process->global_image_egl_images);
+#endif
+
+#if EGL_BRCM_perf_monitor
+      egl_perf_monitor_term(process);
+#endif
+
+#if EGL_BRCM_driver_monitor
+      egl_driver_monitor_term(process);
+#endif
+
+      process->inited = false;
+   }
+}
+
+CLIENT_PROCESS_STATE_T client_process_state = {
+#ifdef RPC_LIBRARY
+   false, /* not connected */
+#endif
+   0, /* nothing current */
+   false}; /* not inited */
+
+void client_thread_state_init(CLIENT_THREAD_STATE_T *state)
+{
+   state->error = EGL_SUCCESS;
+
+   state->bound_api = EGL_OPENGL_ES_API;
+
+   state->opengl.context = 0;
+   state->opengl.draw = 0;
+   state->opengl.read = 0;
+
+   state->openvg.context = 0;
+   state->openvg.draw = 0;
+   state->openvg.read = 0;
+
+   state->high_priority = false;
+
+   state->merge_pos = 0;
+   state->merge_end = 0;
+
+       state->glgeterror_hack = 0;
+       state->async_error_notification = false;
+}
+
+void client_thread_state_term(CLIENT_THREAD_STATE_T *state)
+{
+   // TODO: termination
+   platform_term_rpc( state );
+}
+
+EGL_CONTEXT_T *client_egl_get_context(CLIENT_THREAD_STATE_T *thread, CLIENT_PROCESS_STATE_T *process, EGLContext ctx)
+{
+   EGL_CONTEXT_T *context = (EGL_CONTEXT_T *)khrn_pointer_map_lookup(&process->contexts, (uint32_t)(size_t)ctx);
+
+   vcos_assert(!context || !context->is_destroyed);
+
+   if (!context)
+      thread->error = EGL_BAD_CONTEXT;
+
+   return context;
+}
+
+EGL_SURFACE_T *client_egl_get_surface(CLIENT_THREAD_STATE_T *thread, CLIENT_PROCESS_STATE_T *process, EGLSurface surf)
+{
+   EGL_SURFACE_T *surface = (EGL_SURFACE_T *)khrn_pointer_map_lookup(&process->surfaces, (uint32_t)(size_t)surf);
+
+   vcos_assert (!surface || !surface->is_destroyed);
+
+   if (!surface)
+      thread->error = EGL_BAD_SURFACE;
+
+#if EGL_KHR_lock_surface
+   if (surface && surface->is_locked) {
+      thread->error = EGL_BAD_ACCESS;
+      surface = NULL;
+   }
+#endif
+
+   return surface;
+}
+
+/*
+   We don't actually insist that the surface is locked. But unlike client_egl_get_surface, we don't throw an
+   error if it isn't.
+*/
+EGL_SURFACE_T *client_egl_get_locked_surface(CLIENT_THREAD_STATE_T *thread, CLIENT_PROCESS_STATE_T *process, EGLSurface surf)
+{
+   EGL_SURFACE_T *surface = (EGL_SURFACE_T *)khrn_pointer_map_lookup(&process->surfaces, (uint32_t)(size_t)surf);
+
+   vcos_assert (!surface || !surface->is_destroyed);
+
+   if (!surface)
+      thread->error = EGL_BAD_SURFACE;
+
+   return surface;
+}
+
+/*
+ * just return if we've seen window before 
+ */
+EGLNativeWindowType client_egl_get_window(CLIENT_THREAD_STATE_T *thread, CLIENT_PROCESS_STATE_T *process, EGLNativeWindowType window)
+{
+   EGLNativeWindowType win = (EGLNativeWindowType)khrn_pointer_map_lookup(&process->windows, (uint32_t)(size_t)window);
+
+   return win;
+}
+
+static uint32_t convert_gltype(EGL_CONTEXT_TYPE_T type)
+{
+   switch (type) {
+   case OPENGL_ES_11: return EGL_SERVER_GL11;
+   case OPENGL_ES_20: return EGL_SERVER_GL20;
+   default:           UNREACHABLE(); return 0;
+   }
+}
+
+void client_send_make_current(CLIENT_THREAD_STATE_T *thread)
+{
+   uint64_t pid                  = rpc_get_client_id(thread);
+   uint32_t gltype               = thread->opengl.context ? convert_gltype(thread->opengl.context->type) : 0;
+   EGL_GL_CONTEXT_ID_T servergl  = thread->opengl.context ? thread->opengl.context->servercontext : EGL_SERVER_NO_GL_CONTEXT;
+   EGL_SURFACE_ID_T servergldraw = thread->opengl.draw    ? thread->opengl.draw->serverbuffer     : EGL_SERVER_NO_SURFACE;
+   EGL_SURFACE_ID_T serverglread = thread->opengl.read    ? thread->opengl.read->serverbuffer     : EGL_SERVER_NO_SURFACE;
+   EGL_VG_CONTEXT_ID_T servervg  = thread->openvg.context ? thread->openvg.context->servercontext : EGL_SERVER_NO_VG_CONTEXT;
+   EGL_SURFACE_ID_T servervgsurf = thread->openvg.draw    ? thread->openvg.draw->serverbuffer     : EGL_SERVER_NO_SURFACE;
+
+   /*
+      if the size of this call in the merge buffer changes,
+      CLIENT_MAKE_CURRENT_SIZE in khrn_client.h should be updated
+   */
+
+
+   if (!thread->opengl.context || !thread->opengl.draw)
+   {
+      vcos_log_trace("Send null make current %x %x",
+                 (unsigned int)(char *)thread->opengl.context, (unsigned int)(char *)thread->opengl.draw);
+   }
+   else
+   {
+      vcos_log_trace("Send make current %d[%d %s%s] %d[%d %d%s]",
+            (int)thread->opengl.context->name,
+            thread->opengl.context->servercontext,
+            thread->opengl.context->is_current ? " C" : "",
+            thread->opengl.context->is_destroyed ? " D" : "",
+            (int)thread->opengl.draw->name,
+            thread->opengl.draw->serverbuffer,
+            thread->opengl.draw->context_binding_count,
+            thread->opengl.draw->is_destroyed ? " D" : "");
+   }
+
+   RPC_CALL8_MAKECURRENT(eglIntMakeCurrent_impl,
+                         thread,
+                         EGLINTMAKECURRENT_ID,
+                         RPC_UINT((uint32_t)pid),
+                         RPC_UINT((uint32_t)(pid >> 32)),
+                         RPC_UINT(gltype),
+                         RPC_UINT(servergl),
+                         RPC_UINT(servergldraw),
+                         RPC_UINT(serverglread),
+                         RPC_UINT(servervg),
+                         RPC_UINT(servervgsurf));
+}
+
+PLATFORM_TLS_T client_tls;
+PLATFORM_MUTEX_T client_mutex;
+#ifdef CLIENT_THREAD_IS_PROCESS 
+PLATFORM_TLS_T client_tls_process;
+PLATFORM_TLS_T client_tls_mutex;
+#endif
+
+bool client_process_attach()
+{
+   KHR_STATUS_T status;
+   status = platform_tls_create(&client_tls);
+   if (status != KHR_SUCCESS) {
+      return false;
+   }
+
+#ifdef CLIENT_THREAD_IS_PROCESS
+   status = platform_tls_create(&client_tls_process);
+   if (status != KHR_SUCCESS) {
+      return false;
+   }
+       
+   status = platform_tls_create(&client_tls_mutex);
+   if (status != KHR_SUCCESS) {
+      return false;
+   }
+#endif
+
+   status = platform_mutex_create(&client_mutex);
+
+   if (status != KHR_SUCCESS) {
+      platform_tls_destroy(client_tls);
+      return false;
+   }
+   if (!RPC_INIT()) {
+      platform_mutex_destroy(&client_mutex);
+      platform_tls_destroy(client_tls);
+      return false;
+   }
+   return true;
+}
+
+bool client_thread_attach()
+{
+   CLIENT_THREAD_STATE_T *state = (CLIENT_THREAD_STATE_T *)khrn_platform_malloc(sizeof(CLIENT_THREAD_STATE_T), "CLIENT_THREAD_STATE_T");
+
+   if (!state)
+      return false;
+
+   client_thread_state_init(state);
+
+   platform_tls_set(client_tls, state);
+
+#ifdef CLIENT_THREAD_IS_PROCESS
+       {  //add mutex into thread's tls
+               KHR_STATUS_T status;
+               PLATFORM_MUTEX_T *local_mutex = (PLATFORM_MUTEX_T*)vcos_tls_get(client_tls_mutex);
+               
+               if (!local_mutex)
+               {                       
+                       local_mutex = (PLATFORM_MUTEX_T*)khrn_platform_malloc(sizeof(PLATFORM_MUTEX_T),"thread mutex");
+                       if (!local_mutex)
+                               return false;
+                       
+                       status = platform_mutex_create(local_mutex);                    
+                       if (status != KHR_SUCCESS) {
+                               khrn_platform_free(local_mutex);
+                               return false;
+                       }
+                       
+                       vcos_tls_set(client_tls_mutex,local_mutex);
+               }
+       }
+#endif 
+
+#ifndef RPC_LIBRARY    //TODO
+   client_send_make_current(state);
+#endif
+   return true;
+}
+
+void client_thread_detach(void *dummy)
+{
+   CLIENT_THREAD_STATE_T *state = CLIENT_GET_THREAD_STATE();
+   UNUSED(dummy);
+
+   platform_tls_remove(client_tls);
+   client_thread_state_term(state);
+
+   khrn_platform_free(state);
+   platform_maybe_free_process();
+       
+#ifdef CLIENT_THREAD_IS_PROCESS
+       {
+               CLIENT_PROCESS_STATE_T *process = CLIENT_GET_PROCESS_STATE();   
+       khrn_platform_free(process);
+               platform_tls_remove(client_tls_process);
+       }
+
+       {
+               PLATFORM_MUTEX_T *local_mutex = (PLATFORM_MUTEX_T*)vcos_tls_get(client_tls_mutex);
+               vcos_assert(local_mutex);
+
+               platform_mutex_destroy(local_mutex);
+
+               khrn_platform_free(local_mutex);
+               platform_tls_remove(client_tls_mutex);
+       }
+#endif
+}
+
+void client_process_detach()
+{
+   RPC_TERM();
+   platform_tls_destroy(client_tls);
+   platform_mutex_destroy(&client_mutex);
+
+#ifdef CLIENT_THREAD_IS_PROCESS        
+       platform_tls_destroy(client_tls_process);
+#endif
+}
+
+#ifdef RPC_LIBRARY
+KHRONOS_SERVER_CONNECTION_T *client_library_get_connection(void)
+{
+   return &client_process_state.khrn_connection;
+}
+
+#endif
+
+#if defined(RPC_LIBRARY) || defined(RPC_DIRECT_MULTI)
+
+void client_library_send_make_current(const KHRONOS_FUNC_TABLE_T *func_table)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (thread->opengl.context || thread->openvg.context)
+   {
+      uint64_t pid                  = rpc_get_client_id(thread);
+      uint32_t gltype               = thread->opengl.context ? convert_gltype(thread->opengl.context->type) : 0;
+      EGL_GL_CONTEXT_ID_T servergl  = thread->opengl.context ? thread->opengl.context->servercontext : EGL_SERVER_NO_GL_CONTEXT;
+      EGL_SURFACE_ID_T servergldraw = thread->opengl.draw    ? thread->opengl.draw->serverbuffer     : EGL_SERVER_NO_SURFACE;
+      EGL_SURFACE_ID_T serverglread = thread->opengl.read    ? thread->opengl.read->serverbuffer     : EGL_SERVER_NO_SURFACE;
+      EGL_VG_CONTEXT_ID_T servervg  = thread->openvg.context ? thread->openvg.context->servercontext : EGL_SERVER_NO_VG_CONTEXT;
+      EGL_SURFACE_ID_T servervgsurf = thread->openvg.draw    ? thread->openvg.draw->serverbuffer     : EGL_SERVER_NO_SURFACE;
+
+      /*
+         if the size of this call in the merge buffer changes,
+         CLIENT_MAKE_CURRENT_SIZE in khrn_client.h should be updated
+      */
+
+      func_table->eglIntMakeCurrent_impl(
+                (uint32_t)pid,
+                (uint32_t)(pid >> 32),
+                gltype,
+                servergl,
+                servergldraw,
+                serverglread,
+                servervg,
+                servervgsurf);
+   }
+}
+
+#endif
+
+#ifdef GL_GET_ERROR_ASYNC
+static void callback_set_error(KHRN_POINTER_MAP_T *map, uint32_t key, void *value, void *data)
+{
+   EGL_CONTEXT_T *context = (EGL_CONTEXT_T *)value;
+
+   UNUSED(map);
+   UNUSED_NDEBUG(key);
+   
+   vcos_assert( context != NULL );
+   vcos_assert((uintptr_t)key == (uintptr_t)context->name);
+   
+   if (context->servercontext == *((uint32_t *)data)){
+      CLIENT_THREAD_STATE_T *thread = context->thread;
+      /* todo: VG */      
+      if (thread && IS_OPENGLES_11_OR_20(thread)) {
+         vcos_log_error("GL OOM context %d", context->servercontext);
+         glxx_set_error(GLXX_GET_CLIENT_STATE(thread), GL_OUT_OF_MEMORY);
+      }
+   }
+}
+
+void client_set_error(uint32_t server_context_name)
+{
+   CLIENT_PROCESS_STATE_T *process;
+   CLIENT_LOCK();
+   process = CLIENT_GET_PROCESS_STATE();
+   khrn_pointer_map_iterate(&process->contexts, callback_set_error, &server_context_name);
+   CLIENT_UNLOCK();
+}
+#endif
diff --git a/interface/khronos/common/khrn_client.h b/interface/khronos/common/khrn_client.h
new file mode 100755 (executable)
index 0000000..804039b
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef KHRN_CLIENT_H
+#define KHRN_CLIENT_H
+
+typedef struct CLIENT_PROCESS_STATE CLIENT_PROCESS_STATE_T;
+typedef struct CLIENT_THREAD_STATE CLIENT_THREAD_STATE_T;
+
+
+#include "interface/khronos/common/khrn_client_platform.h"
+
+#include "interface/khronos/egl/egl_client_context.h"
+#include "interface/khronos/egl/egl_client_surface.h"
+#include "interface/khronos/include/EGL/eglext.h"
+
+#include "interface/khronos/common/khrn_client_pointermap.h"
+
+#ifdef RPC_LIBRARY
+#include "middleware/khronos/common/khrn_misc.h"
+#include "applications/vmcs/khronos/khronos_server.h"
+#elif defined(RPC_DIRECT_MULTI)
+#include "middleware/khronos/common/khrn_misc.h"
+#endif
+
+
+/* must be after EGL/eglext.h */
+#if EGL_BRCM_global_image && EGL_KHR_image
+   #include "interface/khronos/common/khrn_client_global_image_map.h"
+#endif
+
+extern void client_try_unload_server(CLIENT_PROCESS_STATE_T *process);
+
+/*
+   per-thread state
+
+   - EGL error
+   - EGL bound API
+   - EGL context and surfaces for each API
+
+   - RPC merge buffer
+*/
+
+#define MERGE_BUFFER_SIZE  4080
+
+typedef struct {
+   EGL_CONTEXT_T *context;
+   EGL_SURFACE_T *draw;
+   EGL_SURFACE_T *read;
+} EGL_CURRENT_T;
+
+struct CLIENT_THREAD_STATE {
+   /*
+      error
+
+      Invariant:
+      (CLIENT_THREAD_STATE_ERROR)
+      error is one of
+         EGL_SUCCESS
+         EGL_NOT_INITIALIZED
+         EGL_BAD_ACCESS
+         EGL_BAD_ALLOC
+         EGL_BAD_ATTRIBUTE
+         EGL_BAD_CONTEXT
+         EGL_BAD_CONFIG
+         EGL_BAD_CURRENT SURFACE
+         EGL_BAD_DISPLAY
+         EGL_BAD_SURFACE
+         EGL_BAD_MATCH
+         EGL_BAD_PARAMETER
+         EGL_BAD_NATIVE PIXMAP
+         EGL_BAD_NATIVE WINDOW
+         EGL_CONTEXT_LOST
+   */
+   EGLint error;
+
+   EGLenum bound_api;
+
+   /*
+      handles to current display, context and surfaces for each API
+
+      Availability:
+
+      Thread owns EGL lock
+   */
+
+   EGL_CURRENT_T opengl;
+   EGL_CURRENT_T openvg;
+
+   /*
+      rpc stuff
+   */
+
+   bool high_priority;
+
+   uint8_t merge_buffer[MERGE_BUFFER_SIZE];
+
+   uint32_t merge_pos;
+   uint32_t merge_end;
+
+       /* Try to reduce impact of repeated consecutive glGetError() calls */
+       int32_t glgeterror_hack;
+       bool async_error_notification;
+};
+
+extern void client_thread_state_init(CLIENT_THREAD_STATE_T *state);
+extern void client_thread_state_term(CLIENT_THREAD_STATE_T *state);
+
+extern PLATFORM_TLS_T client_tls;
+
+/*
+   CLIENT_GET_THREAD_STATE
+
+   Implementation notes:
+
+   TODO: make sure this gets code-reviewed
+
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   Result is a valid pointer to a thread-local CLIENT_THREAD_STATE_T structure.
+
+   Invariants preserved:
+
+   -
+
+   Invariants used:
+
+   -
+*/
+
+static INLINE CLIENT_THREAD_STATE_T *CLIENT_GET_THREAD_STATE(void)
+{
+       CLIENT_THREAD_STATE_T *tls;
+       tls = (CLIENT_THREAD_STATE_T *)platform_tls_get(client_tls);
+       if( tls && tls->glgeterror_hack ) {
+               tls->glgeterror_hack--;
+       }
+   return tls;
+}
+
+static INLINE CLIENT_THREAD_STATE_T *CLIENT_GET_CHECK_THREAD_STATE(void)
+{
+   return (CLIENT_THREAD_STATE_T *)platform_tls_get_check(client_tls);
+}
+
+/*
+   per-process state
+
+   - EGL initialization stage
+   - EGL contexts and surfaces
+   - EGL counters
+*/
+
+struct CLIENT_PROCESS_STATE {
+#ifdef RPC_LIBRARY
+   /*
+   called khronos_server_connect? this is valid even if !inited
+   */
+   bool connected;
+#endif
+
+   /*
+   number of current contexts across all threads in this process. this is valid
+   even if !inited
+   */
+   uint32_t context_current_count;
+
+   /*
+   inited
+
+   Specifies whether the structure has been initialised and all of the other members are valid.
+   inited is true between eglInitialise/eglTerminate. threads can still have
+   things current when !inited
+
+   Invariants:
+   (CLIENT_PROCESS_STATE_INITED_SANITY)
+   Only client_process_state_init/client_process_state_term modify this value
+   */
+   bool inited;
+
+   /*
+   contexts
+
+   A map from context id (EGLContext) to EGL_CONTEXT_T
+   TODO: use pointers as key rather than integers
+
+   Validity: inited is true
+
+   Invariants:
+   (CLIENT_PROCESS_STATE_CONTEXTS)
+   If id is a key in contexts:
+      contexts[id].name == id
+      contexts[id].is_destroyed == false
+   */
+   KHRN_POINTER_MAP_T contexts;
+
+   /*
+   surfaces
+
+   A map from context id (EGLContext) to EGL_SURFACE_T
+
+   Validity: inited is true
+
+   Invariants:
+   (CLIENT_PROCESS_STATE_SURFACES)
+   If id is a key in surfaces:
+      surfaces[id].name == id
+      surfaces[id].is_destroyed == false
+   */
+   KHRN_POINTER_MAP_T surfaces;
+   
+   
+   /*
+    * some platforms (e.g. Android) need to maintain a list of
+    * known windows
+    */
+   KHRN_POINTER_MAP_T windows;
+   
+#if EGL_KHR_sync
+
+   /*
+   syncs
+
+   Validity: inited is true
+   */
+   KHRN_POINTER_MAP_T syncs;
+#endif
+#if EGL_BRCM_global_image && EGL_KHR_image
+   KHRN_GLOBAL_IMAGE_MAP_T global_image_egl_images;
+#endif
+
+
+   /*
+      next_surface
+
+      Implementation notes:
+      TODO: these could theoretically overflow
+
+      Validity: inited is true
+
+      Invariant:
+      (CLIENT_PROCESS_STATE_NEXT_SURFACE)
+      next_surface is greater than every key in surfaces
+      next_surface >= 1
+   */
+   uint32_t next_surface;
+   /*
+      next_context
+
+      Validity: inited is true
+   */
+   uint32_t next_context;
+#if EGL_KHR_sync
+   /*
+      next_sync
+
+      Validity: inited is true
+   */
+   uint32_t next_sync;
+#endif
+#if EGL_BRCM_global_image && EGL_KHR_image
+   uint32_t next_global_image_egl_image;
+#endif
+
+#if EGL_BRCM_perf_monitor
+   /*
+      perf_monitor_inited
+
+      Validity: inited is true
+   */
+   bool perf_monitor_inited;
+#endif
+
+#if EGL_BRCM_driver_monitor
+   /*
+      driver_monitor_inited
+
+      Validity: inited is true
+   */
+   bool driver_monitor_inited;
+#endif
+
+#ifdef RPC_LIBRARY
+   KHRONOS_SERVER_CONNECTION_T khrn_connection;
+#endif
+};
+
+extern bool client_process_state_init(CLIENT_PROCESS_STATE_T *process);
+extern void client_process_state_term(CLIENT_PROCESS_STATE_T *process);
+
+extern CLIENT_PROCESS_STATE_T client_process_state;
+
+/*
+   CLIENT_GET_PROCESS_STATE()
+
+   Returns the process-global CLIENT_PROCESS_STATE_T object.
+*/
+#ifdef CLIENT_THREAD_IS_PROCESS
+extern PLATFORM_TLS_T client_tls_process;
+extern PLATFORM_TLS_T client_tls_mutex;
+extern void *platform_tls_get_process(PLATFORM_TLS_T tls);
+#endif
+static INLINE CLIENT_PROCESS_STATE_T *CLIENT_GET_PROCESS_STATE(void)
+{
+#ifdef CLIENT_THREAD_IS_PROCESS
+       //each thread has its own client_process_state  
+       return (CLIENT_PROCESS_STATE_T *)platform_tls_get_process(client_tls_process);
+#else
+   return &client_process_state;
+#endif
+}
+
+/*
+   exposed bits of EGL
+*/
+
+CLIENT_PROCESS_STATE_T *client_egl_get_process_state(CLIENT_THREAD_STATE_T *thread, EGLDisplay dpy, EGLBoolean check_inited);
+EGL_CONTEXT_T *client_egl_get_context(CLIENT_THREAD_STATE_T *thread, CLIENT_PROCESS_STATE_T *process, EGLContext ctx);
+EGL_SURFACE_T *client_egl_get_surface(CLIENT_THREAD_STATE_T *thread, CLIENT_PROCESS_STATE_T *process, EGLSurface surf);
+EGL_SURFACE_T *client_egl_get_locked_surface(CLIENT_THREAD_STATE_T *thread, CLIENT_PROCESS_STATE_T *process, EGLSurface surf);
+
+EGLNativeWindowType client_egl_get_window(CLIENT_THREAD_STATE_T *thread, CLIENT_PROCESS_STATE_T *process, EGLNativeWindowType window);
+/*
+   client state
+*/
+
+#define CLIENT_MAKE_CURRENT_SIZE 36 /* RPC_CALL8 */
+extern void client_send_make_current(CLIENT_THREAD_STATE_T *thread);
+
+extern void client_set_error(uint32_t server_context_name);
+/*
+   big giant lock
+*/
+
+extern PLATFORM_MUTEX_T client_mutex;
+
+/*
+   CLIENT_LOCK()
+
+   Acquires EGL lock.
+
+   Implementation notes:
+
+   TODO make sure this gets reviewed
+
+   Preconditions:
+
+   TODO: check mutex hierarchy methodology
+   Mutex: >(MUTEX_EGL_LOCK)
+   Is being called from a function which _always_ subsequently calls CLIENT_UNLOCK()
+
+   Postconditions:
+
+   Mutex: (MUTEX_EGL_LOCK)
+   Thread owns EGL lock
+*/
+
+static INLINE void CLIENT_LOCK(void)
+{
+      platform_client_lock();
+}
+
+/*
+   CLIENT_UNLOCK()
+
+   Releases EGL lock.
+
+   Implementation notes:
+
+   TODO make sure this gets reviewed
+
+   Preconditions:
+
+   Mutex: (MUTEX_EGL_LOCK)
+   Thread owns EGL lock
+   Is being called from a function which has _always_ previously called CLIENT_LOCK()
+
+   Postconditions:
+   Mutex: >(MUTEX_EGL_LOCK)
+*/
+
+static INLINE void CLIENT_UNLOCK(void)
+{
+    platform_client_release();
+}
+
+/*
+   bool CLIENT_LOCK_AND_GET_STATES(EGLDisplay dpy, CLIENT_THREAD_STATE_T **thread, CLIENT_PROCESS_STATE_T **process)
+
+   Try to acquire EGL lock and get thread and process state.
+
+   Implementation notes:
+
+   TODO make sure this gets reviewed
+
+   Preconditions:
+
+   thread is a valid pointer to a thread*
+   process is a valid pointer to a process*
+   Mutex: >(MUTEX_EGL_LOCK)
+   Is being called from a function which calls CLIENT_UNLOCK() if we return true
+
+   Postconditions:
+
+   The following conditions cause error to assume the specified value
+
+      EGL_BAD_DISPLAY               An EGLDisplay argument does not name a valid EGLDisplay
+      EGL_NOT_INITIALIZED           EGL is not initialized for the specified display.
+
+   if more than one condition holds, the first error is generated.
+
+   Either:
+      Mutex: (MUTEX_EGL_LOCK)
+      Thread owns EGL lock
+      result is true
+   Or:
+      Nothing changes
+      result is false
+*/
+
+static INLINE bool CLIENT_LOCK_AND_GET_STATES(EGLDisplay dpy, CLIENT_THREAD_STATE_T **thread, CLIENT_PROCESS_STATE_T **process)
+{
+   *thread = CLIENT_GET_THREAD_STATE();
+   CLIENT_LOCK();
+   *process = client_egl_get_process_state(*thread, dpy, EGL_TRUE);
+   if (*process != NULL)
+      return true;
+   else
+   {
+      CLIENT_UNLOCK();
+      return false;
+   }
+}
+
+/*
+   process and thread attach/detach hooks
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+extern bool client_process_attach(void);
+extern bool client_thread_attach(void);
+extern void client_thread_detach(void *dummy);
+extern void client_process_detach(void);
+
+#ifdef RPC_LIBRARY
+extern KHRONOS_SERVER_CONNECTION_T *client_library_get_connection(void);
+extern void client_library_send_make_current(const KHRONOS_FUNC_TABLE_T *func_table);
+#elif defined(RPC_DIRECT_MULTI)
+extern void client_library_send_make_current(const KHRONOS_FUNC_TABLE_T *func_table);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/interface/khronos/common/khrn_client_cache.c b/interface/khronos/common/khrn_client_cache.c
new file mode 100755 (executable)
index 0000000..c706791
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/khronos/common/khrn_int_common.h"
+
+#include "interface/khronos/common/khrn_client_cache.h"
+#include "interface/khronos/common/khrn_client_platform.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+
+#include "interface/khronos/common/khrn_int_hash.h"
+#include "interface/khronos/common/khrn_int_util.h"
+
+#ifdef RPC_DIRECT
+#include "interface/khronos/glxx/glxx_int_impl.h"
+#endif
+
+#include <assert.h>
+
+#if defined(SIMPENROSE)
+#include "tools/v3d/simpenrose/simpenrose.h"
+#endif
+
+static void link_insert(CACHE_LINK_T *link, CACHE_LINK_T *prev, CACHE_LINK_T *next)
+{
+   vcos_assert(prev->next == next);
+   vcos_assert(next->prev == prev);
+
+   link->prev = prev;
+   link->next = next;
+   prev->next = link;
+   next->prev = link;
+}
+
+static void link_remove(CACHE_LINK_T *link)
+{
+   link->next->prev = link->prev;
+   link->prev->next = link->next;
+}
+
+static void tree_init(uint8_t *tree, int depth)
+{
+   int i;
+
+   tree[0] = depth + 1;
+
+   for (i = 1; i < 1 << depth; i++)
+      tree[i] = tree[i >> 1] - 1;
+}
+
+static int heap_avail(KHRN_CACHE_T *cache, int size)
+{
+   return cache->tree && cache->tree[1] >= size;
+}
+
+static int heap_alloc(KHRN_CACHE_T *cache, int size)
+{
+   int node, fixup;
+   int i;
+
+   assert(heap_avail(cache, size));
+
+   node = 1;
+   for (i = 0; i < cache->client_depth - size; i++) {
+      node <<= 1;
+      if (cache->tree[node + 1] >= size && (cache->tree[node] < size || cache->tree[node] > cache->tree[node + 1]))
+         node++;
+   }
+
+   cache->tree[node] = 0;
+
+   for (fixup = node; cache->tree[fixup ^ 1] < cache->tree [fixup >> 1]; fixup >>= 1)
+      cache->tree[fixup >> 1] = _max(cache->tree[fixup], cache->tree[fixup ^ 1]);
+
+   return node * (1 << (size - 1)) - (1 << (cache->client_depth - 1));
+}
+
+static void heap_free(KHRN_CACHE_T *cache, int block)
+{
+   int node = block + (1 << (cache->client_depth - 1));
+   int reset = 1;
+
+   while (cache->tree[node] > 0) {
+      node >>= 1;
+      reset++;
+   }
+
+   cache->tree[node] = reset;
+
+   while (cache->tree[node] == cache->tree[node ^ 1]) {
+      node >>= 1;
+      cache->tree[node] = cache->tree[node] + 1;
+   }
+
+   while (cache->tree[node] > cache->tree[node >> 1]) {
+      cache->tree[node >> 1] = cache->tree[node];
+      node >>= 1;
+   }
+}
+
+static uint32_t hash(const void *data, int len, int sig)
+{
+   int hash;
+
+//   if (len > 256)     // TODO: turn this on later
+//      len = 256;
+
+   if (!((size_t)data & 3) && !(len & 3))
+      hash = khrn_hashword((uint32_t *)data, len >> 2, 0);
+   else
+      hash = khrn_hashlittle(data, len, 0);
+
+   return (hash & ~0xf) | sig;
+}
+
+int khrn_cache_init(KHRN_CACHE_T *cache)
+{
+   cache->tree = NULL;
+   cache->data = NULL;
+
+   cache->client_depth = 0;
+   cache->server_depth = 0;
+
+   cache->start.prev = NULL;
+   cache->start.next = &cache->end;
+   cache->end.prev = &cache->start;
+   cache->end.next = NULL;
+
+   return khrn_pointer_map_init(&cache->map, 64);
+}
+
+void khrn_cache_term(KHRN_CACHE_T *cache)
+{
+   khrn_platform_free(cache->tree);
+   khrn_platform_free(cache->data);
+
+   khrn_pointer_map_term(&cache->map);
+}
+
+static void send_create(CLIENT_THREAD_STATE_T *thread, int base)
+{
+   RPC_CALL1(glintCacheCreate_impl,
+             thread, 
+             GLINTCACHECREATE_ID,
+             RPC_UINT(base));
+}
+
+static void send_delete(CLIENT_THREAD_STATE_T *thread, int base)
+{
+   RPC_CALL1(glintCacheDelete_impl,
+             thread, 
+             GLINTCACHEDELETE_ID,
+             RPC_UINT(base));
+}
+
+static int send_grow(CLIENT_THREAD_STATE_T *thread)
+{
+   return RPC_BOOLEAN_RES(RPC_CALL0_RES(glintCacheGrow_impl,
+                                        thread, 
+                                        GLINTCACHEGROW_ID));
+}
+
+static void send_data(CLIENT_THREAD_STATE_T *thread, int base, const void *data, int len)
+{
+   int off = 0;
+
+   while (len > 0) {
+      int chunk = _min(len, MERGE_BUFFER_SIZE-CLIENT_MAKE_CURRENT_SIZE-12-8);
+
+      RPC_CALL3_IN_CTRL(glintCacheData_impl,
+                        thread, 
+                        GLINTCACHEDATA_ID,
+                        RPC_UINT(base + off),
+                        RPC_SIZEI(chunk),
+                        (char *)data + off,
+                        chunk);
+
+      off += chunk;
+      len -= chunk;
+   }
+}
+
+static void discard(CLIENT_THREAD_STATE_T *thread, KHRN_CACHE_T *cache, CACHE_ENTRY_T *entry)
+{
+   heap_free(cache, (int)((uint8_t *)entry - cache->data) >> CACHE_LOG2_BLOCK_SIZE);
+
+   khrn_pointer_map_delete(&cache->map, entry->key);
+
+   link_remove(&entry->link);
+
+   send_delete(thread, (int)((uint8_t *)entry - cache->data));
+}
+
+static void *relocate(void *data, void *user)
+{
+   return (uint8_t *)data - ((uint8_t **)user)[0] + ((uint8_t **)user)[1];
+}
+
+static void callback(KHRN_POINTER_MAP_T *map, uint32_t key, void *value, void *user)
+{
+   CACHE_ENTRY_T *entry = (CACHE_ENTRY_T *)value;
+
+   entry->link.prev = (CACHE_LINK_T *)relocate(entry->link.prev, user);
+   entry->link.next = (CACHE_LINK_T *)relocate(entry->link.next, user);
+
+   // Coverity has rightly pointed out that the allocations done in the next codeline can fail
+   // verify will only assert the code in debug mode. Use in release mode stays the same as before...
+   verify(khrn_pointer_map_insert(map, key, relocate(value, user)));
+}
+
+static int grow(CLIENT_THREAD_STATE_T *thread, KHRN_CACHE_T *cache)
+{
+   /*
+      try to grow the server cache
+   */
+
+   uint8_t *tree;
+   uint8_t *data;
+   int i;
+
+   if (cache->server_depth == cache->client_depth) {
+      if (cache->server_depth < CACHE_MAX_DEPTH && send_grow(thread))
+         cache->server_depth++;
+      else
+         return 0;
+   }
+
+   tree = (uint8_t *)khrn_platform_malloc(1 << (cache->client_depth + 1), "KHRN_CACHE_T.tree");
+   data = (uint8_t *)khrn_platform_malloc(1 << (cache->client_depth + CACHE_LOG2_BLOCK_SIZE), "KHRN_CACHE_T.data");
+
+   if (!tree || !data) {
+      khrn_platform_free(tree);
+      khrn_platform_free(data);
+      return 0;
+   }
+
+   /*
+      set up new tree structure
+   */
+
+   tree_init(tree, cache->client_depth + 1);
+
+   if (cache->client_depth) {
+      for (i = 1; i < 1 << cache->client_depth; i++)
+         tree[i ^ 3 << _msb(i)] = cache->tree[i];
+
+      tree[1] = tree[3] + (tree[2] == tree[3]);
+   }
+
+   /*
+      relocate pointermap and linked list pointers
+   */
+   {
+      uint8_t *user[2];
+         user[0] = cache->data;
+         user[1] = data;
+
+      khrn_pointer_map_iterate(&cache->map, callback, user);
+
+      cache->start.next->prev = &cache->start;
+      if (cache->start.next != &cache->end)
+         cache->start.next = (CACHE_LINK_T *)relocate(cache->start.next, user);
+
+      cache->end.prev->next = &cache->end;
+      if (cache->end.prev != &cache->start)
+         cache->end.prev = (CACHE_LINK_T *)relocate(cache->end.prev, user);
+   }
+
+   /*
+      set up new data block
+   */
+
+   if (cache->data)
+      platform_memcpy(data, cache->data, 1 << (cache->client_depth + CACHE_LOG2_BLOCK_SIZE - 1));
+
+   /*
+      free old blocks, update structure
+   */
+
+   khrn_platform_free(cache->tree);
+   khrn_platform_free(cache->data);
+
+   cache->tree = tree;
+   cache->data = data;
+
+   cache->client_depth++;
+
+   return 1;
+}
+
+#ifdef SIMPENROSE_RECORD_OUTPUT
+static bool xxx_first = true;
+#endif
+int khrn_cache_lookup(CLIENT_THREAD_STATE_T *thread, KHRN_CACHE_T *cache, const void *data, int len, int sig)
+{
+   int key = hash(data, len, sig);
+
+   CACHE_ENTRY_T *entry = (CACHE_ENTRY_T *)khrn_pointer_map_lookup(&cache->map, key);
+
+#ifdef SIMPENROSE_RECORD_OUTPUT
+   if (xxx_first)
+   {
+      /* Cannot grow cache while things are locked for recording. So grow it now as much as we think we'll need */
+      uint32_t i;
+      xxx_first = false;
+      for (i = 0; i < 15; i++)
+         grow(thread, cache);
+   }
+#endif
+
+   if (entry && entry->len >= len && !memcmp(entry->data, data, len)) {
+      /*
+         move link to end of discard queue
+      */
+
+      link_remove(&entry->link);
+      link_insert(&entry->link, cache->end.prev, &cache->end);
+   } else {
+      int size = _max(_msb(len + sizeof(CACHE_ENTRY_T) - 1) + 2 - CACHE_LOG2_BLOCK_SIZE, 1);
+      int block;
+
+      CACHE_LINK_T *link;
+
+      if (entry)
+         discard(thread, cache, entry);
+
+      while (!heap_avail(cache, size) && grow(thread, cache));
+
+      for (link = cache->start.next; link != &cache->end && !heap_avail(cache, size); link = link->next)
+         discard(thread, cache, (CACHE_ENTRY_T *)link);
+
+      if (!heap_avail(cache, size))
+         return -1;
+
+      block = heap_alloc(cache, size);
+
+      entry = (CACHE_ENTRY_T *)(cache->data + (block << CACHE_LOG2_BLOCK_SIZE));
+      entry->len = len;
+      entry->key = key;
+      platform_memcpy(entry->data, data, len);
+
+      if (!khrn_pointer_map_insert(&cache->map, key, entry)) {
+         heap_free(cache, block);
+         return -1;
+      }
+
+      link_insert(&entry->link, cache->end.prev, &cache->end);
+
+      send_create(thread, (int)((uint8_t *)entry - cache->data));
+      send_data(thread, (int)(entry->data - cache->data), data, len);
+   }
+
+   return (int)((uint8_t *)entry - cache->data);
+}
+
+int khrn_cache_get_entries(KHRN_CACHE_T *cache)
+{
+   return cache->map.entries;
+}
diff --git a/interface/khronos/common/khrn_client_cache.h b/interface/khronos/common/khrn_client_cache.h
new file mode 100755 (executable)
index 0000000..b4a16ac
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef KHRN_CLIENT_CACHE_H
+#define KHRN_CLIENT_CACHE_H
+
+//#define WORKAROUND_HW2551     // define to pad header structure to 32 bytes
+
+#include "interface/khronos/common/khrn_client_pointermap.h"
+#include "interface/khronos/common/khrn_client.h"
+
+typedef struct CACHE_LINK_S {
+   struct CACHE_LINK_S *prev;
+   struct CACHE_LINK_S *next;
+} CACHE_LINK_T;
+
+typedef struct {
+   CACHE_LINK_T link;
+
+   int len;
+   int key;
+
+#ifdef WORKAROUND_HW2551
+   uint8_t pad[16];
+#endif
+
+   //on the server side
+   //we store a KHRN_INTERLOCK_T in the 
+   //same space as this struct
+   uint8_t pad_for_interlock[24];
+
+   uint8_t data[1];
+} CACHE_ENTRY_T;
+
+typedef struct {
+   uint8_t *tree;
+   uint8_t *data;
+
+   int client_depth;
+   int server_depth;
+
+   CACHE_LINK_T start;
+   CACHE_LINK_T end;
+
+   KHRN_POINTER_MAP_T map;
+} KHRN_CACHE_T;
+
+#define CACHE_LOG2_BLOCK_SIZE    6
+#define CACHE_MAX_DEPTH          16
+
+#define CACHE_SIG_ATTRIB_0    0
+#define CACHE_SIG_ATTRIB_1    1
+#define CACHE_SIG_ATTRIB_2    2
+#define CACHE_SIG_ATTRIB_3    3
+#define CACHE_SIG_ATTRIB_4    4
+#define CACHE_SIG_ATTRIB_5    5
+#define CACHE_SIG_ATTRIB_6    6
+#define CACHE_SIG_ATTRIB_7    7
+
+#define CACHE_SIG_INDEX       8
+
+extern int khrn_cache_init(KHRN_CACHE_T *cache);
+extern void khrn_cache_term(KHRN_CACHE_T *cache);
+
+extern int khrn_cache_lookup(CLIENT_THREAD_STATE_T *thread, KHRN_CACHE_T *cache, const void *data, int len, int sig);
+extern int khrn_cache_get_entries(KHRN_CACHE_T *cache);
+
+#endif
+
diff --git a/interface/khronos/common/khrn_client_check_types.h b/interface/khronos/common/khrn_client_check_types.h
new file mode 100755 (executable)
index 0000000..aec389b
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_CLIENT_CHECK_TYPES_H
+#define KHRN_CLIENT_CHECK_TYPES_H
+
+#include "interface/khronos/common/khrn_int_util.h"
+
+#include "interface/khronos/include/EGL/egl.h"
+#include "interface/khronos/include/GLES/gl.h"
+#include "interface/khronos/include/VG/openvg.h"
+
+/*
+   egl types
+*/
+
+vcos_static_assert(sizeof(EGLint) == 4);
+vcos_static_assert(sizeof(EGLBoolean) == 4);
+vcos_static_assert(sizeof(EGLenum) == 4);
+vcos_static_assert(sizeof(EGLConfig) == 4);
+vcos_static_assert(sizeof(EGLContext) == 4);
+vcos_static_assert(sizeof(EGLDisplay) == 4);
+vcos_static_assert(sizeof(EGLSurface) == 4);
+vcos_static_assert(sizeof(EGLClientBuffer) == 4);
+vcos_static_assert(sizeof(NativeDisplayType) == 4);
+vcos_static_assert(sizeof(NativePixmapType) == 4);
+vcos_static_assert(sizeof(NativeWindowType) == 4);
+
+/*
+   gl types
+*/
+
+vcos_static_assert(sizeof(GLenum) == 4);
+vcos_static_assert(sizeof(GLboolean) == 1);
+vcos_static_assert(sizeof(GLbitfield) == 4);
+vcos_static_assert(sizeof(GLbyte) == 1);
+vcos_static_assert(sizeof(GLshort) == 2);
+vcos_static_assert(sizeof(GLint) == 4);
+vcos_static_assert(sizeof(GLsizei) == 4);
+vcos_static_assert(sizeof(GLubyte) == 1);
+vcos_static_assert(sizeof(GLushort) == 2);
+vcos_static_assert(sizeof(GLuint) == 4);
+vcos_static_assert(sizeof(GLfloat) == 4);
+vcos_static_assert(sizeof(GLclampf) == 4);
+vcos_static_assert(sizeof(GLfixed) == 4);
+vcos_static_assert(sizeof(GLclampx) == 4);
+vcos_static_assert(sizeof(GLintptr) == 4);
+vcos_static_assert(sizeof(GLsizeiptr) == 4);
+
+/*
+   vg types
+*/
+
+vcos_static_assert(sizeof(VGfloat) == 4);
+vcos_static_assert(sizeof(VGbyte) == 1);
+vcos_static_assert(sizeof(VGubyte) == 1);
+vcos_static_assert(sizeof(VGshort) == 2);
+vcos_static_assert(sizeof(VGint) == 4);
+vcos_static_assert(sizeof(VGuint) == 4);
+vcos_static_assert(sizeof(VGbitfield) == 4);
+vcos_static_assert(sizeof(VGboolean) == 4);
+
+#endif
diff --git a/interface/khronos/common/khrn_client_cr.c b/interface/khronos/common/khrn_client_cr.c
new file mode 100755 (executable)
index 0000000..becfa16
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+static void callback_destroy_context(KHRN_POINTER_MAP_T *map, uint32_t key, void *value, void *data)
+{
+   EGL_CONTEXT_T *context = (EGL_CONTEXT_T *)value;
+
+   UNUSED(map);
+   UNUSED(data);
+   UNUSED_NDEBUG(key);
+
+   vcos_assert( context != NULL );
+   vcos_assert((uintptr_t)key == (uintptr_t)context->name);
+
+   vcos_assert(!context->is_destroyed);
+
+   context->is_destroyed = true;
+   egl_context_maybe_free(context);
+}
+
+/*
+   void callback_destroy_surface(KHRN_POINTER_MAP_T *map, uint32_t key, void *value, void *data)
+
+   Implementation notes:
+
+   Passed as a callback to khrn_pointer_map_iterate.
+
+   Preconditions:
+
+   Thread owns EGL lock
+
+   map is the CLIENT_PROCESS_STATE_T.surfaces
+   value is a pointer to a valid EGL_SURFACE_T
+   key is a key in map
+   map[key] == value
+
+   Postconditions:
+
+   Does not alter map
+   value is a dead pointer (i.e. either a pointer to a freed thing or something we don't hold a reference to)
+
+   Invariants preserved:
+
+   (EGL_SURFACE_IS_DESTROYED)
+
+   Invariants used:
+
+   (CLIENT_PROCESS_STATE_SURFACES)
+   (EGL_SURFACE_BINDING_COUNT)
+*/
+
+static void callback_destroy_surface(KHRN_POINTER_MAP_T *map, uint32_t key, void *value, void *data)
+{
+   EGL_SURFACE_T *surface = (EGL_SURFACE_T *)value;
+
+   UNUSED(map);
+   UNUSED(data);
+   UNUSED_NDEBUG(key);
+
+   vcos_assert( surface != NULL );
+   vcos_assert((uintptr_t)key == (uintptr_t)surface->name);
+
+   surface->is_destroyed = true;
+   egl_surface_maybe_free(surface);
+}
+
+/*
+   CLIENT_PROCESS_STATE_T *client_egl_get_process_state(CLIENT_THREAD_STATE_T *thread, EGLDisplay dpy, EGLBoolean check_inited)
+
+   Returns the process-global CLIENT_PROCESS_STATE_T object. If check_inited is true, also insists that the process state
+   is inited.
+
+   Implementation notes:
+
+   -
+
+   Preconditions:
+
+   thread is a valid pointer
+   Thread owns EGL lock
+
+   Postconditions:
+
+   The following conditions cause error to assume the specified value
+
+      EGL_BAD_DISPLAY               An EGLDisplay argument does not name a valid EGLDisplay
+      EGL_NOT_INITIALIZED           check_inited is true and EGL is not initialized for the specified display.
+
+   if more than one condition holds, the first error is generated.
+
+   If error, NULL is returned. Otherwise a pointer is returned which is valid for the lifetime of the process.
+
+   Invariants preserved:
+
+   -
+
+   Invariants used:
+
+   -
+*/
+
+CLIENT_PROCESS_STATE_T *client_egl_get_process_state(CLIENT_THREAD_STATE_T *thread, EGLDisplay dpy, EGLBoolean check_inited)
+{
+   if ((size_t)dpy == 1) {
+      CLIENT_PROCESS_STATE_T *process = CLIENT_GET_PROCESS_STATE();
+
+      if (check_inited && !process->inited) {
+         thread->error = EGL_NOT_INITIALIZED;
+         return NULL;
+      } else
+         return process;
+   } else {
+      thread->error = EGL_BAD_DISPLAY;
+      return NULL;
+   }
+}
diff --git a/interface/khronos/common/khrn_client_global_image_map.c b/interface/khronos/common/khrn_client_global_image_map.c
new file mode 100755 (executable)
index 0000000..3da1f90
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/khronos/common/khrn_int_common.h"
+#include "interface/khronos/common/khrn_client_platform.h"
+#include "interface/khronos/include/EGL/egl.h"
+#include "interface/khronos/include/EGL/eglext.h"
+
+#if EGL_BRCM_global_image && EGL_KHR_image
+
+static INLINE void acquire_value(uint64_t value)
+{
+   platform_acquire_global_image((uint32_t)value, (uint32_t)(value >> 32));
+}
+
+static INLINE void release_value(uint64_t value)
+{
+   platform_release_global_image((uint32_t)value, (uint32_t)(value >> 32));
+}
+
+#define KHRN_GENERIC_MAP_VALUE_NONE ((uint64_t)0)
+#define KHRN_GENERIC_MAP_VALUE_DELETED ((uint64_t)-1)
+#define KHRN_GENERIC_MAP_ACQUIRE_VALUE acquire_value
+#define KHRN_GENERIC_MAP_RELEASE_VALUE release_value
+#define KHRN_GENERIC_MAP_ALLOC khrn_platform_malloc
+#define KHRN_GENERIC_MAP_FREE khrn_platform_free
+
+#define CLIENT_GLOBAL_IMAGE_MAP_C
+#include "interface/khronos/common/khrn_client_global_image_map.h"
+
+#endif
diff --git a/interface/khronos/common/khrn_client_global_image_map.h b/interface/khronos/common/khrn_client_global_image_map.h
new file mode 100755 (executable)
index 0000000..d916485
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_CLIENT_GLOBAL_IMAGE_MAP_H
+#define KHRN_CLIENT_GLOBAL_IMAGE_MAP_H
+
+#define khrn_generic_map(X) khrn_global_image_map_##X
+#define KHRN_GENERIC_MAP(X) KHRN_GLOBAL_IMAGE_MAP_##X
+#define KHRN_GENERIC_MAP_KEY_T uint32_t
+#define KHRN_GENERIC_MAP_VALUE_T uint64_t
+
+#ifdef CLIENT_GLOBAL_IMAGE_MAP_C
+   #include "interface/khronos/common/khrn_int_generic_map.c"
+#else
+   #include "interface/khronos/common/khrn_int_generic_map.h"
+#endif
+
+#undef KHRN_GENERIC_MAP_VALUE_T
+#undef KHRN_GENERIC_MAP_KEY_T
+#undef KHRN_GENERIC_MAP
+#undef khrn_generic_map
+
+#endif
diff --git a/interface/khronos/common/khrn_client_mangle.h b/interface/khronos/common/khrn_client_mangle.h
new file mode 100755 (executable)
index 0000000..b3c04f4
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRONOS_MANGLE_H
+#if defined KHRONOS_NAME_MANGLING || defined REMOTE_API_LOGGING || defined BCG_MULTI_THREADED
+
+/* EGL Functions */
+
+#define eglGetError mangled_eglGetError
+#define eglGetDisplay mangled_eglGetDisplay
+#define eglInitialize mangled_eglInitialize
+#define eglTerminate mangled_eglTerminate
+#define eglQueryString mangled_eglQueryString
+#define eglGetConfigs mangled_eglGetConfigs
+#define eglChooseConfig mangled_eglChooseConfig
+#define eglGetConfigAttrib mangled_eglGetConfigAttrib
+#define eglCreateWindowSurface mangled_eglCreateWindowSurface
+#define eglCreatePbufferSurface mangled_eglCreatePbufferSurface
+#define eglCreatePixmapSurface mangled_eglCreatePixmapSurface
+#define eglDestroySurface mangled_eglDestroySurface
+#define eglQuerySurface mangled_eglQuerySurface
+#define eglBindAPI mangled_eglBindAPI
+#define eglQueryAPI mangled_eglQueryAPI
+#define eglWaitClient mangled_eglWaitClient
+#define eglReleaseThread mangled_eglReleaseThread
+#define eglCreatePbufferFromClientBuffer mangled_eglCreatePbufferFromClientBuffer
+#define eglSurfaceAttrib mangled_eglSurfaceAttrib
+#define eglBindTexImage mangled_eglBindTexImage
+#define eglReleaseTexImage mangled_eglReleaseTexImage
+#define eglSwapInterval mangled_eglSwapInterval
+#define eglCreateContext mangled_eglCreateContext
+#define eglDestroyContext mangled_eglDestroyContext
+#define eglMakeCurrent mangled_eglMakeCurrent
+#define eglGetCurrentContext mangled_eglGetCurrentContext
+#define eglGetCurrentSurface mangled_eglGetCurrentSurface
+#define eglGetCurrentDisplay mangled_eglGetCurrentDisplay
+#define eglQueryContext mangled_eglQueryContext
+#define eglWaitGL mangled_eglWaitGL
+#define eglWaitNative mangled_eglWaitNative
+#define eglSwapBuffers mangled_eglSwapBuffers
+#define eglCopyBuffers mangled_eglCopyBuffers
+#define eglGetProcAddress mangled_eglGetProcAddress
+#define eglClientWaitSyncKHR mangled_eglClientWaitSyncKHR
+#define eglCreateImageKHR mangled_eglCreateImageKHR
+#define eglCreateSyncKHR mangled_eglCreateSyncKHR
+#define eglDestroyImageKHR mangled_eglDestroyImageKHR
+#define eglDestroySyncKHR mangled_eglDestroySyncKHR
+#define eglGetSyncAttribKHR mangled_eglGetSyncAttribKHR
+#define eglGetSyncAttribKHR mangled_eglGetSyncAttribKHR
+#define eglQueryProfilingDataNOK mangled_eglQueryProfilingDataNOK
+#define eglSignalSyncKHR mangled_eglSignalSyncKHR
+#define eglLockSurfaceKHR mangled_eglLockSurfaceKHR
+#define eglUnlockSurfaceKHR mangled_eglUnlockSurfaceKHR
+#define glEGLImageTargetRenderbufferStorageOES mangled_glEGLImageTargetRenderbufferStorageOES
+#define glEGLImageTargetTexture2DOES mangled_glEGLImageTargetTexture2DOES
+#define eglAcquireGlobalImageBRCM mangled_eglAcquireGlobalImageBRCM
+#define eglCreateCopyGlobalImageBRCM mangled_eglCreateCopyGlobalImageBRCM
+#define eglCreateGlobalImageBRCM mangled_eglCreateGlobalImageBRCM
+#define eglReleaseGlobalImageBRCM mangled_eglReleaseGlobalImageBRCM
+#define eglInitGlobalImageBRCM mangled_eglInitGlobalImageBRCM
+#define eglTermGlobalImageBRCM mangled_eglTermGlobalImageBRCM
+
+/* OpenGL ES 1.1 and 2.0 functions */
+
+#define glAlphaFunc mangled_glAlphaFunc
+#define glClearColor mangled_glClearColor
+#define glClearDepthf mangled_glClearDepthf
+#define glClipPlanef mangled_glClipPlanef
+#define glColor4f mangled_glColor4f
+#define glDepthRangef mangled_glDepthRangef
+#define glFogf mangled_glFogf
+#define glFogfv mangled_glFogfv
+#define glFrustumf mangled_glFrustumf
+#define glGetClipPlanef mangled_glGetClipPlanef
+#define glGetFloatv mangled_glGetFloatv
+#define glGetLightfv mangled_glGetLightfv
+#define glGetMaterialfv mangled_glGetMaterialfv
+#define glGetTexEnvfv mangled_glGetTexEnvfv
+#define glGetTexParameterfv mangled_glGetTexParameterfv
+#define glLightModelf mangled_glLightModelf
+#define glLightModelfv mangled_glLightModelfv
+#define glLightf mangled_glLightf
+#define glLightfv mangled_glLightfv
+#define glLineWidth mangled_glLineWidth
+#define glLoadMatrixf mangled_glLoadMatrixf
+#define glMaterialf mangled_glMaterialf
+#define glMaterialfv mangled_glMaterialfv
+#define glMultMatrixf mangled_glMultMatrixf
+#define glMultiTexCoord4f mangled_glMultiTexCoord4f
+#define glNormal3f mangled_glNormal3f
+#define glOrthof mangled_glOrthof
+#define glPointParameterf mangled_glPointParameterf
+#define glPointParameterfv mangled_glPointParameterfv
+#define glPointSize mangled_glPointSize
+#define glPolygonOffset mangled_glPolygonOffset
+#define glRotatef mangled_glRotatef
+#define glScalef mangled_glScalef
+#define glTexEnvf mangled_glTexEnvf
+#define glTexEnvfv mangled_glTexEnvfv
+#define glTexParameterf mangled_glTexParameterf
+#define glTexParameterfv mangled_glTexParameterfv
+#define glTranslatef mangled_glTranslatef
+
+#define glActiveTexture mangled_glActiveTexture
+#define glAlphaFuncx mangled_glAlphaFuncx
+#define glBindBuffer mangled_glBindBuffer
+#define glBindTexture mangled_glBindTexture
+#define glBlendFunc mangled_glBlendFunc
+#define glBlendColor mangled_glBlendColor
+#define glBufferData mangled_glBufferData
+#define glBlendEquation mangled_glBlendEquation
+#define glBufferSubData mangled_glBufferSubData
+#define glClear mangled_glClear
+#define glClearColorx mangled_glClearColorx
+#define glClearDepthx mangled_glClearDepthx
+#define glClearStencil mangled_glClearStencil
+#define glClientActiveTexture mangled_glClientActiveTexture
+#define glClipPlanex mangled_glClipPlanex
+#define glColor4ub mangled_glColor4ub
+#define glColor4x mangled_glColor4x
+#define glColorMask mangled_glColorMask
+#define glColorPointer mangled_glColorPointer
+#define glCompressedTexImage2D mangled_glCompressedTexImage2D
+#define glCompressedTexSubImage2D mangled_glCompressedTexSubImage2D
+#define glCopyTexImage2D mangled_glCopyTexImage2D
+#define glCopyTexSubImage2D mangled_glCopyTexSubImage2D
+#define glCullFace mangled_glCullFace
+#define glDeleteBuffers mangled_glDeleteBuffers
+#define glDeleteTextures mangled_glDeleteTextures
+#define glDepthFunc mangled_glDepthFunc
+#define glDepthMask mangled_glDepthMask
+#define glDepthRangex mangled_glDepthRangex
+#define glDisable mangled_glDisable
+#define glDisableClientState mangled_glDisableClientState
+#define glDrawArrays mangled_glDrawArrays
+#define glDrawElements mangled_glDrawElements
+#define glEnable mangled_glEnable
+#define glEnableClientState mangled_glEnableClientState
+#define glFinish mangled_glFinish
+#define glFlush mangled_glFlush
+#define glFogx mangled_glFogx
+#define glFogxv mangled_glFogxv
+#define glFrontFace mangled_glFrontFace
+#define glFrustumx mangled_glFrustumx
+#define glGetBooleanv mangled_glGetBooleanv
+#define glGetBufferParameteriv mangled_glGetBufferParameteriv
+#define glGetClipPlanex mangled_glGetClipPlanex
+#define glGenBuffers mangled_glGenBuffers
+#define glGenTextures mangled_glGenTextures
+#define glGetError mangled_glGetError
+#define glGetFixedv mangled_glGetFixedv
+#define glGetIntegerv mangled_glGetIntegerv
+#define glGetLightxv mangled_glGetLightxv
+#define glGetMaterialxv mangled_glGetMaterialxv
+#define glGetPointerv mangled_glGetPointerv
+#define glGetString mangled_glGetString
+#define glGetTexEnviv mangled_glGetTexEnviv
+#define glGetTexEnvxv mangled_glGetTexEnvxv
+#define glGetTexParameteriv mangled_glGetTexParameteriv
+#define glGetTexParameterxv mangled_glGetTexParameterxv
+#define glHint mangled_glHint
+#define glIsBuffer mangled_glIsBuffer
+#define glIsEnabled mangled_glIsEnabled
+#define glIsTexture mangled_glIsTexture
+#define glLightModelx mangled_glLightModelx
+#define glLightModelxv mangled_glLightModelxv
+#define glLightx mangled_glLightx
+#define glLightxv mangled_glLightxv
+#define glLineWidthx mangled_glLineWidthx
+#define glLoadIdentity mangled_glLoadIdentity
+#define glLoadMatrixx mangled_glLoadMatrixx
+#define glLogicOp mangled_glLogicOp
+#define glMaterialx mangled_glMaterialx
+#define glMaterialxv mangled_glMaterialxv
+#define glMatrixMode mangled_glMatrixMode
+#define glMultMatrixx mangled_glMultMatrixx
+#define glMultiTexCoord4x mangled_glMultiTexCoord4x
+#define glNormal3x mangled_glNormal3x
+#define glNormalPointer mangled_glNormalPointer
+#define glOrthox mangled_glOrthox
+#define glPixelStorei mangled_glPixelStorei
+#define glPointParameterx mangled_glPointParameterx
+#define glPointParameterxv mangled_glPointParameterxv
+#define glPointSizex mangled_glPointSizex
+#define glPolygonOffsetx mangled_glPolygonOffsetx
+#define glPopMatrix mangled_glPopMatrix
+#define glPushMatrix mangled_glPushMatrix
+#define glReadPixels mangled_glReadPixels
+#define glRotatex mangled_glRotatex
+#define glSampleCoverage mangled_glSampleCoverage
+#define glSampleCoveragex mangled_glSampleCoveragex
+#define glScalex mangled_glScalex
+#define glScissor mangled_glScissor
+#define glShadeModel mangled_glShadeModel
+#define glStencilFunc mangled_glStencilFunc
+#define glStencilMask mangled_glStencilMask
+#define glStencilOp mangled_glStencilOp
+#define glTexCoordPointer mangled_glTexCoordPointer
+#define glTexEnvi mangled_glTexEnvi
+#define glTexEnvx mangled_glTexEnvx
+#define glTexEnviv mangled_glTexEnviv
+#define glTexEnvxv mangled_glTexEnvxv
+#define glTexImage2D mangled_glTexImage2D
+#define glTexParameteri mangled_glTexParameteri
+#define glTexParameterx mangled_glTexParameterx
+#define glTexParameteriv mangled_glTexParameteriv
+#define glTexParameterxv mangled_glTexParameterxv
+#define glTexSubImage2D mangled_glTexSubImage2D
+#define glTranslatex mangled_glTranslatex
+#define glVertexPointer mangled_glVertexPointer
+#define glViewport mangled_glViewport
+
+#define glAttachShader mangled_glAttachShader
+#define glBindAttribLocation mangled_glBindAttribLocation
+#define glBlendEquationSeparate mangled_glBlendEquationSeparate
+#define glBlendFuncSeparate mangled_glBlendFuncSeparate
+#define glCreateProgram mangled_glCreateProgram
+#define glCreateShader mangled_glCreateShader
+#define glDeleteProgram mangled_glDeleteProgram
+#define glDeleteShader mangled_glDeleteShader
+#define glDetachShader mangled_glDetachShader
+#define glDisableVertexAttribArray mangled_glDisableVertexAttribArray
+#define glEnableVertexAttribArray mangled_glEnableVertexAttribArray
+#define glGetActiveAttrib mangled_glGetActiveAttrib
+#define glGetActiveUniform mangled_glGetActiveUniform
+#define glGetAttachedShaders mangled_glGetAttachedShaders
+#define glGetAttribLocation mangled_glGetAttribLocation
+#define glGetProgramiv mangled_glGetProgramiv
+#define glGetProgramInfoLog mangled_glGetProgramInfoLog
+#define glGetUniformfv mangled_glGetUniformfv
+#define glGetUniformiv mangled_glGetUniformiv
+#define glGetUniformLocation mangled_glGetUniformLocation
+#define glGetVertexAttribfv mangled_glGetVertexAttribfv
+#define glGetVertexAttribiv mangled_glGetVertexAttribiv
+#define glGetVertexAttribPointerv mangled_glGetVertexAttribPointerv
+#define glIsProgram mangled_glIsProgram
+#define glIsShader mangled_glIsShader
+#define glLinkProgram mangled_glLinkProgram
+#define glStencilFuncSeparate mangled_glStencilFuncSeparate
+#define glStencilMaskSeparate mangled_glStencilMaskSeparate
+#define glStencilOpSeparate mangled_glStencilOpSeparate
+#define glUniform1i mangled_glUniform1i
+#define glUniform2i mangled_glUniform2i
+#define glUniform3i mangled_glUniform3i
+#define glUniform4i mangled_glUniform4i
+#define glUniform1f mangled_glUniform1f
+#define glUniform2f mangled_glUniform2f
+#define glUniform3f mangled_glUniform3f
+#define glUniform4f mangled_glUniform4f
+#define glUniform1iv mangled_glUniform1iv
+#define glUniform2iv mangled_glUniform2iv
+#define glUniform3iv mangled_glUniform3iv
+#define glUniform4iv mangled_glUniform4iv
+#define glUniform1fv mangled_glUniform1fv
+#define glUniform2fv mangled_glUniform2fv
+#define glUniform3fv mangled_glUniform3fv
+#define glUniform4fv mangled_glUniform4fv
+#define glUniformMatrix2fv mangled_glUniformMatrix2fv
+#define glUniformMatrix3fv mangled_glUniformMatrix3fv
+#define glUniformMatrix4fv mangled_glUniformMatrix4fv
+#define glUseProgram mangled_glUseProgram
+#define glValidateProgram mangled_glValidateProgram
+#define glVertexAttrib1f mangled_glVertexAttrib1f
+#define glVertexAttrib2f mangled_glVertexAttrib2f
+#define glVertexAttrib3f mangled_glVertexAttrib3f
+#define glVertexAttrib4f mangled_glVertexAttrib4f
+#define glVertexAttrib1fv mangled_glVertexAttrib1fv
+#define glVertexAttrib2fv mangled_glVertexAttrib2fv
+#define glVertexAttrib3fv mangled_glVertexAttrib3fv
+#define glVertexAttrib4fv mangled_glVertexAttrib4fv
+#define glVertexAttribPointer mangled_glVertexAttribPointer
+#define glCompileShader mangled_glCompileShader
+#define glGetShaderiv mangled_glGetShaderiv
+#define glGetShaderInfoLog mangled_glGetShaderInfoLog
+#define glGetShaderSource mangled_glGetShaderSource
+#define glReleaseShaderCompiler mangled_glReleaseShaderCompiler
+#define glShaderSource mangled_glShaderSource
+#define glShaderBinary mangled_glShaderBinary
+#define glGetShaderPrecisionFormat mangled_glGetShaderPrecisionFormat
+#define glIsRenderbuffer mangled_glIsRenderbuffer
+#define glBindRenderbuffer mangled_glBindRenderbuffer
+#define glDeleteRenderbuffers mangled_glDeleteRenderbuffers
+#define glGenRenderbuffers mangled_glGenRenderbuffers
+#define glRenderbufferStorage mangled_glRenderbufferStorage
+#define glGetRenderbufferParameteriv mangled_glGetRenderbufferParameteriv
+#define glIsFramebuffer mangled_glIsFramebuffer
+#define glBindFramebuffer mangled_glBindFramebuffer
+#define glDeleteFramebuffers mangled_glDeleteFramebuffers
+#define glGenFramebuffers mangled_glGenFramebuffers
+#define glCheckFramebufferStatus mangled_glCheckFramebufferStatus
+#define glFramebufferTexture2D mangled_glFramebufferTexture2D
+#define glFramebufferRenderbuffer mangled_glFramebufferRenderbuffer
+#define glGetFramebufferAttachmentParameteriv mangled_glGetFramebufferAttachmentParameteriv
+#define glGenerateMipmap mangled_glGenerateMipmap
+
+#define glPointSizePointerOES mangled_glPointSizePointerOES
+#define glDiscardFramebufferEXT mangled_glDiscardFramebufferEXT
+#define glInsertEventMarkerEXT mangled_glInsertEventMarkerEXT
+#define glPushGroupMarkerEXT mangled_glPushGroupMarkerEXT
+#define glPopGroupMarkerEXT mangled_glPopGroupMarkerEXT
+
+#define glDrawTexfOES mangled_glDrawTexfOES
+#define glDrawTexfvOES mangled_glDrawTexfvOES
+#define glDrawTexiOES mangled_glDrawTexiOES
+#define glDrawTexivOES mangled_glDrawTexivOES
+#define glDrawTexsOES mangled_glDrawTexsOES
+#define glDrawTexsvOES mangled_glDrawTexsvOES
+#define glDrawTexxOES mangled_glDrawTexxOES
+#define glDrawTexxvOES mangled_glDrawTexxvOES
+
+#define glIsRenderbufferOES mangled_glIsRenderbufferOES
+#define glBindRenderbufferOES mangled_glBindRenderbufferOES
+#define glDeleteRenderbuffersOES mangled_glDeleteRenderbuffersOES
+#define glGenRenderbuffersOES mangled_glGenRenderbuffersOES
+#define glRenderbufferStorageOES mangled_glRenderbufferStorageOES
+#define glGetRenderbufferParameterivOES mangled_glGetRenderbufferParameterivOES
+#define glIsFramebufferOES mangled_glIsFramebufferOES
+#define glBindFramebufferOES mangled_glBindFramebufferOES
+#define glDeleteFramebuffersOES mangled_glDeleteFramebuffersOES
+#define glGenFramebuffersOES mangled_glGenFramebuffersOES
+#define glCheckFramebufferStatusOES mangled_glCheckFramebufferStatusOES
+#define glFramebufferRenderbufferOES mangled_glFramebufferRenderbufferOES
+#define glFramebufferTexture2DOES mangled_glFramebufferTexture2DOES
+#define glGetFramebufferAttachmentParameterivOES mangled_glGetFramebufferAttachmentParameterivOES
+#define glGenerateMipmapOES mangled_glGenerateMipmapOES
+
+#endif
+
+#if defined KHRONOS_NAME_MANGLING || defined BCG_MULTI_THREADED
+
+#define vgCreateEGLImageTargetKHR mangled_vgCreateEGLImageTargetKHR
+
+#define vgGetError mangled_vgGetError
+#define vgFlush mangled_vgFlush
+#define vgFinish mangled_vgFinish
+#define vgSetf mangled_vgSetf
+#define vgSeti mangled_vgSeti
+#define vgSetfv mangled_vgSetfv
+#define vgSetiv mangled_vgSetiv
+#define vgGetf mangled_vgGetf
+#define vgGeti mangled_vgGeti
+#define vgGetVectorSize mangled_vgGetVectorSize
+#define vgGetfv mangled_vgGetfv
+#define vgGetiv mangled_vgGetiv
+#define vgSetParameterf mangled_vgSetParameterf
+#define vgSetParameteri mangled_vgSetParameteri
+#define vgSetParameterfv mangled_vgSetParameterfv
+#define vgSetParameteriv mangled_vgSetParameteriv
+#define vgGetParameterf mangled_vgGetParameterf
+#define vgGetParameteri mangled_vgGetParameteri
+#define vgGetParameterVectorSize mangled_vgGetParameterVectorSize
+#define vgGetParameterfv mangled_vgGetParameterfv
+#define vgGetParameteriv mangled_vgGetParameteriv
+#define vgLoadIdentity mangled_vgLoadIdentity
+#define vgLoadMatrix mangled_vgLoadMatrix
+#define vgGetMatrix mangled_vgGetMatrix
+#define vgMultMatrix mangled_vgMultMatrix
+#define vgTranslate mangled_vgTranslate
+#define vgScale mangled_vgScale
+#define vgShear mangled_vgShear
+#define vgRotate mangled_vgRotate
+#define vgMask mangled_vgMask
+#define vgRenderToMask mangled_vgRenderToMask
+#define vgCreateMaskLayer mangled_vgCreateMaskLayer
+#define vgDestroyMaskLayer mangled_vgDestroyMaskLayer
+#define vgFillMaskLayer mangled_vgFillMaskLayer
+#define vgCopyMask mangled_vgCopyMask
+#define vgClear mangled_vgClear
+#define vgCreatePath mangled_vgCreatePath
+#define vgClearPath mangled_vgClearPath
+#define vgDestroyPath mangled_vgDestroyPath
+#define vgRemovePathCapabilities mangled_vgRemovePathCapabilities
+#define vgGetPathCapabilities mangled_vgGetPathCapabilities
+#define vgAppendPath mangled_vgAppendPath
+#define vgAppendPathData mangled_vgAppendPathData
+#define vgModifyPathCoords mangled_vgModifyPathCoords
+#define vgTransformPath mangled_vgTransformPath
+#define vgInterpolatePath mangled_vgInterpolatePath
+#define vgPathLength mangled_vgPathLength
+#define vgPointAlongPath mangled_vgPointAlongPath
+#define vgPathBounds mangled_vgPathBounds
+#define vgPathTransformedBounds mangled_vgPathTransformedBounds
+#define vgDrawPath mangled_vgDrawPath
+#define vgCreatePaint mangled_vgCreatePaint
+#define vgDestroyPaint mangled_vgDestroyPaint
+#define vgSetPaint mangled_vgSetPaint
+#define vgGetPaint mangled_vgGetPaint
+#define vgSetColor mangled_vgSetColor
+#define vgGetColor mangled_vgGetColor
+#define vgPaintPattern mangled_vgPaintPattern
+#define vgCreateImage mangled_vgCreateImage
+#define vgDestroyImage mangled_vgDestroyImage
+#define vgClearImage mangled_vgClearImage
+#define vgImageSubData mangled_vgImageSubData
+#define vgGetImageSubData mangled_vgGetImageSubData
+#define vgChildImage mangled_vgChildImage
+#define vgGetParent mangled_vgGetParent
+#define vgCopyImage mangled_vgCopyImage
+#define vgDrawImage mangled_vgDrawImage
+#define vgSetPixels mangled_vgSetPixels
+#define vgWritePixels mangled_vgWritePixels
+#define vgGetPixels mangled_vgGetPixels
+#define vgReadPixels mangled_vgReadPixels
+#define vgCopyPixels mangled_vgCopyPixels
+#define vgCreateFont mangled_vgCreateFont
+#define vgDestroyFont mangled_vgDestroyFont
+#define vgSetGlyphToPath mangled_vgSetGlyphToPath
+#define vgSetGlyphToImage mangled_vgSetGlyphToImage
+#define vgClearGlyph mangled_vgClearGlyph
+#define vgDrawGlyph mangled_vgDrawGlyph
+#define vgDrawGlyphs mangled_vgDrawGlyphs
+#define vgColorMatrix mangled_vgColorMatrix
+#define vgConvolve mangled_vgConvolve
+#define vgSeparableConvolve mangled_vgSeparableConvolve
+#define vgGaussianBlur mangled_vgGaussianBlur
+#define vgLookup mangled_vgLookup
+#define vgLookupSingle mangled_vgLookupSingle
+#define vgHardwareQuery mangled_vgHardwareQuery
+#define vgGetString mangled_vgGetString
+#define vgCreateEGLImageTargetKHR mangled_vgCreateEGLImageTargetKHR
+
+#define vguArc mangled_vguArc
+#define vguComputeWarpQuadToQuad mangled_vguComputeWarpQuadToQuad
+#define vguComputeWarpQuadToSquare mangled_vguComputeWarpQuadToSquare
+#define vguComputeWarpSquareToQuad mangled_vguComputeWarpSquareToQuad
+#define vguEllipse mangled_vguEllipse
+#define vguLine mangled_vguLine
+#define vguPolygon mangled_vguPolygon
+#define vguRect mangled_vguRect
+#define vguRoundRect mangled_vguRoundRect
+
+#if !defined(REMOTE_API_LOGGING) && !defined(BCG_MULTI_THREADED)
+/* Internal functions */
+#define egl_surface_create mangled_egl_surface_create
+#define egl_surface_from_vg_image mangled_egl_surface_from_vg_image
+#define egl_surface_term mangled_egl_surface_term
+#define egl_surface_set_attrib mangled_egl_surface_set_attrib
+#define egl_context_create mangled_egl_context_create
+#define egl_context_term mangled_egl_context_term
+#endif
+
+#endif   //KHRONOS_NAME_MANGLING
+#endif   //KHRONOS_MANGLED_H
diff --git a/interface/khronos/common/khrn_client_platform.h b/interface/khronos/common/khrn_client_platform.h
new file mode 100755 (executable)
index 0000000..1c9da3a
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef KHRN_CLIENT_PLATFORM_H
+#define KHRN_CLIENT_PLATFORM_H
+
+#include "interface/khronos/include/EGL/egl.h"
+#include "interface/khronos/include/EGL/eglext.h"
+#include "interface/khronos/common/khrn_int_common.h"
+#include "interface/khronos/common/khrn_int_image.h"
+#include "interface/khronos/egl/egl_int.h"
+#include <stdlib.h> // for size_t
+
+/* Per-platform types are defined in here. Most platforms can be supported
+ * via vcos, but 'direct' has its own header and types, which is why
+ * the indirection is required.
+ */
+#if defined(ABSTRACT_PLATFORM)
+#include "interface/khronos/common/abstract/khrn_client_platform_filler_abstract.h"
+#elif defined(RPC_DIRECT) && !defined(RPC_LIBRARY) && !defined(RPC_DIRECT_MULTI)
+#include "interface/khronos/common/direct/khrn_client_platform_filler_direct.h"
+#elif defined(KHRN_VCOS_VCHIQ)
+#include "interface/khronos/common/vcos_vchiq/khrn_client_platform_filler_vcos_vchiq.h"
+#else
+#include "interface/khronos/common/vcos/khrn_client_platform_filler_vcos.h"
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+   named counting semaphore
+*/
+
+/* Uses forward declared ref to avoid problems with mixing direct and vcos-based
+ * semaphores.
+ */
+
+
+/*
+   workaround for broken platforms which don't detect threads exiting
+*/
+extern void platform_hint_thread_finished(void);
+
+/*
+   heap
+*/
+
+/*
+   void *khrn_platform_malloc(size_t size, const char *desc)
+
+   Preconditions:
+
+   desc is a literal, null-terminated string
+   The caller of this function is contracted to later call khrn_platform_free
+   (or pass such responsibility on) if we don't return NULL
+
+   Postconditions:
+
+   Return value is NULL or a memory allocation of at least size bytes,
+   valid until khrn_platform_free is called. The memory is sufficiently
+   aligned that it can be used for normal data structures.
+*/
+
+extern void *khrn_platform_malloc(size_t size, const char *desc);
+
+/*
+   void khrn_platform_free(void *v)
+
+   Preconditions:
+
+   v is a valid pointer returned from khrn_platform_malloc
+
+   Postconditions:
+
+   v is freed
+
+   Invariants preserved:
+
+   -
+
+   Invariants used:
+
+   -
+*/
+extern void khrn_platform_free(void *v);
+
+extern void khrn_platform_maybe_free_process(void);
+
+/*
+   uint64_t khronos_platform_get_process_id()
+
+   get process id
+
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   Repeated calls within a process return the same value. Calls from a different process
+   return a different value.
+*/
+
+extern uint64_t khronos_platform_get_process_id(void);
+
+/*
+   window system
+*/
+
+#define PLATFORM_WIN_NONE     ((uint32_t)0xffffffff)
+
+#ifdef EGL_SERVER_SMALLINT
+
+static INLINE EGLNativeWindowType platform_canonical_win(EGLNativeWindowType win)
+{
+   switch ((uintptr_t)win) {
+   case (uintptr_t)NATIVE_WINDOW_800_480:   return PACK_NATIVE_WINDOW(800, 480, 0, 1);
+   case (uintptr_t)NATIVE_WINDOW_640_480:   return PACK_NATIVE_WINDOW(640, 480, 0, 1);
+   case (uintptr_t)NATIVE_WINDOW_320_240:   return PACK_NATIVE_WINDOW(320, 240, 0, 1);
+   case (uintptr_t)NATIVE_WINDOW_240_320:   return PACK_NATIVE_WINDOW(240, 320, 0, 1);
+   case (uintptr_t)NATIVE_WINDOW_64_64:     return PACK_NATIVE_WINDOW(64, 64, 0, 1);
+   case (uintptr_t)NATIVE_WINDOW_400_480_A: return PACK_NATIVE_WINDOW(400, 480, 0, 2);
+   case (uintptr_t)NATIVE_WINDOW_400_480_B: return PACK_NATIVE_WINDOW(400, 480, 1, 2);
+   case (uintptr_t)NATIVE_WINDOW_512_512:   return PACK_NATIVE_WINDOW(512, 512, 0, 1);
+   case (uintptr_t)NATIVE_WINDOW_360_640:   return PACK_NATIVE_WINDOW(360, 640, 0, 1);
+   case (uintptr_t)NATIVE_WINDOW_640_360:   return PACK_NATIVE_WINDOW(640, 360, 0, 1);
+   case (uintptr_t)NATIVE_WINDOW_1280_720:  return PACK_NATIVE_WINDOW(1280, 720, 0, 1);
+   case (uintptr_t)NATIVE_WINDOW_1920_1080: return PACK_NATIVE_WINDOW(1920, 1080, 0, 1);
+   case (uintptr_t)NATIVE_WINDOW_480_320:   return PACK_NATIVE_WINDOW(480, 320, 0, 1);
+   case (uintptr_t)NATIVE_WINDOW_1680_1050: return PACK_NATIVE_WINDOW(1680, 1050, 0, 1);
+   default:                                 return win;
+   }
+}
+
+static INLINE uint32_t platform_get_handle(EGLDisplay dpy, EGLNativeWindowType win)
+{
+#ifdef ABSTRACT_PLATFORM
+   return (uint32_t)win;
+#else
+   return (uint32_t)(size_t)platform_canonical_win(win);
+#endif /* ABSTRACT_PLATFORM */
+}
+
+#ifndef ABSTRACT_PLATFORM
+static INLINE void platform_get_dimensions(EGLDisplay dpy,
+      EGLNativeWindowType win, uint32_t *width, uint32_t *height, uint32_t *swapchain_count)
+{
+   win = platform_canonical_win(win);
+   *width = UNPACK_NATIVE_WINDOW_W(win);
+   *height = UNPACK_NATIVE_WINDOW_H(win);
+#ifdef KHRN_SIMPLE_MULTISAMPLE
+   *width *= 2;
+   *height *= 2;
+#endif
+   *swapchain_count = 0;
+}
+#else
+void platform_get_dimensions(EGLDisplay dpy,
+      EGLNativeWindowType win, uint32_t *width, uint32_t *height, uint32_t *swapchain_count);
+void platform_lock(void * opaque_buffer_handle);
+void platform_unlock(void * opaque_buffer_handle);
+#endif /* ABSTRACT_PLATFORM */
+#else
+
+/*
+   uint32_t platform_get_handle(EGLNativeWindowType win)
+
+   Implementation notes:
+
+   Platform-specific implementation.
+
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   If win is a valid client-side handle to window W
+      Then return value is a server-side handle to window W.
+      Else return value is PLATFORM_WIN_NONE
+*/
+extern uint32_t platform_get_handle(EGLDisplay dpy, EGLNativeWindowType win);
+
+/*
+   void platform_get_dimensions(EGLNativeWindowType win, uint32_t *width, uint32_t *height, uint32_t *swapchain_count)
+
+   Implementation notes:
+
+   Platform-specific implementation.
+
+   Preconditions:
+
+   win is a valid client-side window handle
+   width, height are valid pointers
+
+   Postconditions:
+
+   -
+*/
+extern void platform_get_dimensions(EGLDisplay dpy, EGLNativeWindowType win,
+      uint32_t *width, uint32_t *height, uint32_t *swapchain_count);
+#endif
+extern void platform_surface_update(uint32_t handle);
+
+/*
+   bool platform_get_pixmap_info(EGLNativePixmapType pixmap, KHRN_IMAGE_WRAP_T *image);
+
+   Preconditions:
+
+   image is a valid pointer
+
+   Postconditions:
+
+   Either:
+   - false is returned because pixmap is an invalid pixmap handle, or
+   - true is returned and image is set up to describe the pixmap, and if it's a
+     client-side pixmap the pointer is also set
+*/
+
+extern bool platform_get_pixmap_info(EGLNativePixmapType pixmap, KHRN_IMAGE_WRAP_T *image);
+/*
+   should look something like this:
+
+   if (regular server-side pixmap) {
+      handle[0] = handle;
+   } else if (global image server-side pixmap) {
+      handle[0] = id[0];
+      handle[1] = id[1];
+   }
+*/
+extern void platform_get_pixmap_server_handle(EGLNativePixmapType pixmap, uint32_t *handle);
+
+extern void platform_wait_EGL(uint32_t handle);
+extern void platform_retrieve_pixmap_completed(EGLNativePixmapType pixmap);
+extern void platform_send_pixmap_completed(EGLNativePixmapType pixmap);
+
+/*
+   bool platform_match_pixmap_api_support(EGLNativePixmapType pixmap, uint32_t api_support);
+
+   Preconditions:
+
+   pixmap is probably a valid native pixmap handle
+   api_support is a bitmap which is a subset of (EGL_OPENGL_ES_BIT | EGL_OPENVG_BIT | EGL_OPENGL_ES2_BIT)
+
+   Postconditions:
+
+   If result is true then rendering to this pixmap using these APIs is supported on this platform
+*/
+
+extern bool platform_match_pixmap_api_support(EGLNativePixmapType pixmap, uint32_t api_support);
+
+#if EGL_BRCM_global_image && EGL_KHR_image
+extern bool platform_use_global_image_as_egl_image(uint32_t id_0, uint32_t id_1, EGLNativePixmapType pixmap, EGLint *error);
+extern void platform_acquire_global_image(uint32_t id_0, uint32_t id_1);
+extern void platform_release_global_image(uint32_t id_0, uint32_t id_1);
+extern void platform_get_global_image_info(uint32_t id_0, uint32_t id_1,
+   uint32_t *pixel_format, uint32_t *width, uint32_t *height);
+#endif
+
+/* Platform optimised versions of memcpy and memcmp */
+extern uint32_t platform_memcmp(const void * aLeft, const void * aRight, size_t aLen);
+extern void platform_memcpy(void * aTrg, const void * aSrc, size_t aLength);
+
+struct CLIENT_THREAD_STATE;
+extern void platform_client_lock(void);
+extern void platform_client_release(void);
+extern void platform_init_rpc(struct CLIENT_THREAD_STATE *state);
+extern void platform_term_rpc(struct CLIENT_THREAD_STATE *state);
+extern void platform_maybe_free_process(void);
+extern void platform_destroy_winhandle(void *a, uint32_t b);
+
+extern uint32_t platform_get_color_format ( uint32_t format );
+
+#if !defined(__SYMBIAN32__)
+// hack for now - we want prototypes
+extern void egl_gce_win_change_image(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+extern EGLDisplay khrn_platform_set_display_id(EGLNativeDisplayType display_id);
+
+extern uint32_t khrn_platform_get_window_position(EGLNativeWindowType win);
+
+extern void khrn_platform_release_pixmap_info(EGLNativePixmapType pixmap, KHRN_IMAGE_WRAP_T *image);
+extern void khrn_platform_bind_pixmap_to_egl_image(EGLNativePixmapType pixmap, EGLImageKHR egl_image, bool send);
+extern void khrn_platform_unbind_pixmap_from_egl_image(EGLImageKHR egl_image);
+extern uint32_t platform_get_color_format ( uint32_t format );
+extern void platform_dequeue(EGLDisplay dpy, EGLNativeWindowType window);
+#include "interface/khronos/include/WF/wfc.h"
+typedef struct
+{
+   WFCDevice device;
+   WFCContext context;
+   WFCSource source;
+   WFCint src_x, src_y, src_width, src_height;
+   WFCint dest_width, dest_height;
+   uint32_t stop_bouncing;
+   uint32_t num_of_elements;
+   WFCElement *element;
+} WFC_BOUNCE_DATA_T;
+
+void *platform_wfc_bounce_thread(void *param);
+
+#endif // KHRN_CLIENT_PLATFORM_H
diff --git a/interface/khronos/common/khrn_client_pointermap.c b/interface/khronos/common/khrn_client_pointermap.c
new file mode 100755 (executable)
index 0000000..ebd0243
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/khronos/common/khrn_int_common.h"
+#include "interface/khronos/common/khrn_client_platform.h"
+
+#define KHRN_GENERIC_MAP_VALUE_NONE NULL
+#define KHRN_GENERIC_MAP_VALUE_DELETED ((void *)(uintptr_t)-1)
+#define KHRN_GENERIC_MAP_ALLOC khrn_platform_malloc
+#define KHRN_GENERIC_MAP_FREE khrn_platform_free
+
+#define CLIENT_POINTER_MAP_C
+#include "interface/khronos/common/khrn_client_pointermap.h"
diff --git a/interface/khronos/common/khrn_client_pointermap.h b/interface/khronos/common/khrn_client_pointermap.h
new file mode 100755 (executable)
index 0000000..6a5d239
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_CLIENT_POINTERMAP_H
+#define KHRN_CLIENT_POINTERMAP_H
+
+#define khrn_generic_map(X) khrn_pointer_map_##X
+#define KHRN_GENERIC_MAP(X) KHRN_POINTER_MAP_##X
+#define KHRN_GENERIC_MAP_KEY_T uint32_t
+#define KHRN_GENERIC_MAP_VALUE_T void *
+
+#ifdef CLIENT_POINTER_MAP_C
+   #include "interface/khronos/common/khrn_int_generic_map.c"
+#else
+   #include "interface/khronos/common/khrn_int_generic_map.h"
+#endif
+
+#undef KHRN_GENERIC_MAP_VALUE_T
+#undef KHRN_GENERIC_MAP_KEY_T
+#undef KHRN_GENERIC_MAP
+#undef khrn_generic_map
+
+#endif
diff --git a/interface/khronos/common/khrn_client_rpc.h b/interface/khronos/common/khrn_client_rpc.h
new file mode 100755 (executable)
index 0000000..dc4351d
--- /dev/null
@@ -0,0 +1,838 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_CLIENT_RPC_H
+#define KHRN_CLIENT_RPC_H
+
+#define RPC_DELAYED_USE_OF_POINTERS
+
+#include "interface/khronos/common/khrn_int_util.h"
+#include "interface/khronos/common/khrn_client.h"
+
+#include <stdlib.h> /* for size_t */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+# if defined(__SYMBIAN32__)  //use functions defined in khrpc.cpp
+#include "rpc_platform.h"
+#endif
+
+#ifdef RPC_DIRECT
+
+#include "middleware/khronos/egl/egl_server.h" /* for egl_server_unlock_states() */
+#if !defined(V3D_LEAN) || defined(RPC_DIRECT_MULTI)
+#include "middleware/khronos/common/khrn_misc.h"
+#endif
+
+#ifdef RPC_LIBRARY
+#include "interface/khronos/common/khrn_client.h" /* for khrn_client_get_func_table() */
+#include "applications/vmcs/khronos/khronos_server.h"
+#endif
+
+#ifdef RPC_DIRECT_MULTI
+#include "interface/khronos/common/khrn_client.h" /* for khrn_client_get_func_table() */
+
+extern int client_library_get_connection(void);
+extern const KHRONOS_FUNC_TABLE_T *khronos_server_lock_func_table(int);
+extern void khronos_server_unlock_func_table(void);
+
+#endif
+
+/******************************************************************************
+type packing/unpacking macros
+******************************************************************************/
+
+#define RPC_FLOAT(f)        (f)
+#define RPC_ENUM(e)         (e)
+#define RPC_INT(i)          (i)
+#define RPC_INTPTR(p)       (p)
+#define RPC_UINT(u)         (u)
+#define RPC_SIZEI(s)        (s)
+#define RPC_SIZEIPTR(p)     (p)
+#define RPC_BOOLEAN(b)      (b)
+#define RPC_BITFIELD(b)     (b)
+#define RPC_FIXED(f)        (f)
+#define RPC_HANDLE(h)       (h)
+#define RPC_EGLID(i)        (i)
+
+#if defined(RPC_LIBRARY) || defined(RPC_DIRECT_MULTI)
+static INLINE float RPC_FLOAT_RES(float f) { khronos_server_unlock_func_table(); return f; }
+static INLINE GLenum RPC_ENUM_RES(GLenum e) { khronos_server_unlock_func_table(); return e; }
+static INLINE int RPC_INT_RES(int i) { khronos_server_unlock_func_table(); return i; }
+static INLINE uint32_t RPC_UINT_RES(uint32_t u) { khronos_server_unlock_func_table(); return u; }
+static INLINE bool RPC_BOOLEAN_RES(bool b) { khronos_server_unlock_func_table(); return b; }
+//static INLINE GLbitfield RPC_BITFIELD_RES(GLbitfield b) { khronos_server_unlock_func_table(); return b; }
+static INLINE VGHandle RPC_HANDLE_RES(VGHandle h) { khronos_server_unlock_func_table(); return h; }
+#else
+#define RPC_FLOAT_RES(f)    (f)
+#define RPC_ENUM_RES(e)     (e)
+#define RPC_INT_RES(i)      (i)
+#define RPC_UINT_RES(u)     (u)
+#define RPC_BOOLEAN_RES(b)  (b)
+#define RPC_BITFIELD_RES(b) (b)
+#define RPC_HANDLE_RES(h)   (h)
+#endif
+
+/******************************************************************************
+rpc call macros
+******************************************************************************/
+
+#ifdef RPC_DIRECT_MULTI
+extern bool rpc_direct_multi_init(void);
+extern void rpc_term(void);
+#define RPC_INIT() rpc_direct_multi_init()
+#define RPC_TERM() rpc_term()
+#else
+#define RPC_INIT() true
+#define RPC_TERM() 
+#endif
+
+#define RPC_FLUSH(thread) RPC_CALL0(khrn_misc_rpc_flush_impl, thread, no_id)
+#define RPC_HIGH_PRIORITY_BEGIN(thread)
+#define RPC_HIGH_PRIORITY_END(thread)
+
+#if defined(RPC_LIBRARY) || defined(RPC_DIRECT_MULTI)
+#define RPC_DO(fn, args) ((khronos_server_lock_func_table(client_library_get_connection())->fn args),khronos_server_unlock_func_table())
+#define RPC_DO_RES(fn, args) (khronos_server_lock_func_table(client_library_get_connection())->fn args)
+#else
+#define RPC_DO(fn, args) fn args
+#define RPC_DO_RES(fn, args) fn args
+#endif
+/*
+   RPC_CALL[n](fn, id, RPC_THING(p0), RPC_THING(p1), ...)
+
+   Implementation notes:
+
+   In direct mode, fn is called directly and id is ignored.
+   Otherwise fn is ignored and an RPC message is constructed based on id.
+
+   Preconditions:
+
+   p0, p1, etc. satisfy the precondition to fn
+   id matches fn
+   Server is up (except for a special initialise call)
+
+   Postconditions:
+
+   We promise to call fn on the server at some point in the future. The RPC calls for this
+   thread will occur in the same order they are made on the client.
+   All postconditions of fn will be satisfied (on the server)
+
+   Invariants preserved:
+
+   -
+
+   Invariants used:
+
+   -
+*/
+#define RPC_CALL8_MAKECURRENT(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7)                                             RPC_CALL8(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7)
+
+#define RPC_CALL0(fn, thread, id)                                          RPC_DO(fn, ())
+#define RPC_CALL1(fn, thread, id, p0)                                      RPC_DO(fn, (p0))
+#define RPC_CALL2(fn, thread, id, p0, p1)                                  RPC_DO(fn, (p0, p1))
+#define RPC_CALL3(fn, thread, id, p0, p1, p2)                              RPC_DO(fn, (p0, p1, p2))
+#define RPC_CALL4(fn, thread, id, p0, p1, p2, p3)                          RPC_DO(fn, (p0, p1, p2, p3))
+#define RPC_CALL5(fn, thread, id, p0, p1, p2, p3, p4)                      RPC_DO(fn, (p0, p1, p2, p3, p4))
+#define RPC_CALL6(fn, thread, id, p0, p1, p2, p3, p4, p5)                  RPC_DO(fn, (p0, p1, p2, p3, p4, p5))
+#define RPC_CALL7(fn, thread, id, p0, p1, p2, p3, p4, p5, p6)              RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6))
+#define RPC_CALL8(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7)          RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6, p7))
+#define RPC_CALL9(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8)      RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6, p7, p8))
+#define RPC_CALL10(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9) RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9))
+#define RPC_CALL11(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10))
+#define RPC_CALL16(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15) \
+   RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15))
+
+/*
+   RPC_THING_RES(RPC_CALL[n]_RES(fn, id, RPC_THING(p0), RPC_THING(p1), ...))
+
+   Implementation notes:
+
+   In direct mode, fn is called directly and id is ignored.
+   Otherwise fn is ignored and an RPC message is constructed based on id.
+
+   Preconditions:
+
+   p0, p1, etc. satisfy the precondition to fn
+   id matches fn
+   Server is up (except for a special initialise call)
+
+   Postconditions:
+
+   The call to fn on the server has completed
+   We return the return value of fn, and all postconditions of fn are satisfied (on the server)
+
+   Invariants preserved:
+
+   -
+
+   Invariants used:
+
+   -
+*/
+
+#define RPC_CALL0_RES(fn, thread, id)                                                    RPC_DO_RES(fn, ())
+#define RPC_CALL1_RES(fn, thread, id, p0)                                                RPC_DO_RES(fn, (p0))
+#define RPC_CALL2_RES(fn, thread, id, p0, p1)                                            RPC_DO_RES(fn, (p0, p1))
+#define RPC_CALL3_RES(fn, thread, id, p0, p1, p2)                                        RPC_DO_RES(fn, (p0, p1, p2))
+#define RPC_CALL4_RES(fn, thread, id, p0, p1, p2, p3)                                    RPC_DO_RES(fn, (p0, p1, p2, p3))
+#define RPC_CALL5_RES(fn, thread, id, p0, p1, p2, p3, p4)                                RPC_DO_RES(fn, (p0, p1, p2, p3, p4))
+#define RPC_CALL6_RES(fn, thread, id, p0, p1, p2, p3, p4, p5)                            RPC_DO_RES(fn, (p0, p1, p2, p3, p4, p5))
+#define RPC_CALL7_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6)                        RPC_DO_RES(fn, (p0, p1, p2, p3, p4, p5, p6))
+#define RPC_CALL8_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7)                    RPC_DO_RES(fn, (p0, p1, p2, p3, p4, p5, p6, p7))
+#define RPC_CALL9_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8)                RPC_DO_RES(fn, (p0, p1, p2, p3, p4, p5, p6, p7, p8))
+#define RPC_CALL10_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)           RPC_DO_RES(fn, (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9))
+#define RPC_CALL11_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)      RPC_DO_RES(fn, (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10))
+#define RPC_CALL12_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) RPC_DO_RES(fn, (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11))
+
+/*
+   message with data in/out via control channel
+*/
+
+#define RPC_CALL1_IN_CTRL(fn, thread, id, in, len)                                      RPC_DO(fn, (in))
+#define RPC_CALL2_IN_CTRL(fn, thread, id, p0, in, len)                                  RPC_DO(fn, (p0, in))
+#define RPC_CALL3_IN_CTRL(fn, thread, id, p0, p1, in, len)                              RPC_DO(fn, (p0, p1, in))
+#define RPC_CALL4_IN_CTRL(fn, thread, id, p0, p1, p2, in, len)                          RPC_DO(fn, (p0, p1, p2, in))
+#define RPC_CALL5_IN_CTRL(fn, thread, id, p0, p1, p2, p3, in, len)                      RPC_DO(fn, (p0, p1, p2, p3, in))
+#define RPC_CALL6_IN_CTRL(fn, thread, id, p0, p1, p2, p3, p4, in, len)                  RPC_DO(fn, (p0, p1, p2, p3, p4, in))
+#define RPC_CALL7_IN_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, in, len)              RPC_DO(fn, (p0, p1, p2, p3, p4, p5, in))
+#define RPC_CALL8_IN_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, in, len)          RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6, in))
+#define RPC_CALL9_IN_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, in, len)      RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6, p7, in))
+#define RPC_CALL10_IN_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, in, len) RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6, p7, p8, in))
+
+/*
+   RPC_CALL[n]_OUT_CTRL(fn, id, RPC_THING(p0), RPC_THING(p1), ..., out)
+
+   Implementation notes:
+
+   In direct mode, fn is called directly and id is ignored.
+   Otherwise fn is ignored and an RPC message is constructed based on id.
+   The dispatch code is responsible for calculating the length of the returned data.
+
+   Preconditions:
+
+   p0, p1, ..., out satisfy the precondition to fn
+   id matches fn
+   Server is up (except for a special initialise call)
+
+   Postconditions:
+
+   The call to fn on the server has completed
+   We return whatever fn returned in out
+
+   Invariants preserved:
+
+   -
+
+   Invariants used:
+
+   -
+*/
+
+#define RPC_CALL1_OUT_CTRL(fn, thread, id, out)                                               RPC_DO(fn, (out))
+#define RPC_CALL2_OUT_CTRL(fn, thread, id, p0, out)                                           RPC_DO(fn, (p0, out))
+#define RPC_CALL3_OUT_CTRL(fn, thread, id, p0, p1, out)                                       RPC_DO(fn, (p0, p1, out))
+#define RPC_CALL4_OUT_CTRL(fn, thread, id, p0, p1, p2, out)                                   RPC_DO(fn, (p0, p1, p2, out))
+#define RPC_CALL5_OUT_CTRL(fn, thread, id, p0, p1, p2, p3, out)                               RPC_DO(fn, (p0, p1, p2, p3, out))
+#define RPC_CALL6_OUT_CTRL(fn, thread, id, p0, p1, p2, p3, p4, out)                           RPC_DO(fn, (p0, p1, p2, p3, p4, out))
+#define RPC_CALL7_OUT_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, out)                       RPC_DO(fn, (p0, p1, p2, p3, p4, p5, out))
+#define RPC_CALL8_OUT_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, out)                   RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6, out))
+#define RPC_CALL9_OUT_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, out)               RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6, p7, out))
+#define RPC_CALL10_OUT_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, out)          RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6, p7, p8, out))
+#define RPC_CALL11_OUT_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, out)      RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, out))
+#define RPC_CALL12_OUT_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, out) RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, out))
+#define RPC_CALL13_OUT_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, out)      RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, out))
+#define RPC_CALL14_OUT_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, out) RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, out))
+#define RPC_CALL15_OUT_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, out) RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, out))
+
+#define RPC_CALL1_OUT_CTRL_RES(fn, thread, id, out)                                      RPC_DO_RES(fn, (out))
+#define RPC_CALL2_OUT_CTRL_RES(fn, thread, id, p0, out)                                  RPC_DO_RES(fn, (p0, out))
+#define RPC_CALL3_OUT_CTRL_RES(fn, thread, id, p0, p1, out)                              RPC_DO_RES(fn, (p0, p1, out))
+#define RPC_CALL4_OUT_CTRL_RES(fn, thread, id, p0, p1, p2, out)                          RPC_DO_RES(fn, (p0, p1, p2, out))
+#define RPC_CALL5_OUT_CTRL_RES(fn, thread, id, p0, p1, p2, p3, out)                      RPC_DO_RES(fn, (p0, p1, p2, p3, out))
+#define RPC_CALL6_OUT_CTRL_RES(fn, thread, id, p0, p1, p2, p3, p4, out)                  RPC_DO_RES(fn, (p0, p1, p2, p3, p4, out))
+#define RPC_CALL7_OUT_CTRL_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, out)              RPC_DO_RES(fn, (p0, p1, p2, p3, p4, p5, out))
+#define RPC_CALL8_OUT_CTRL_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, out)          RPC_DO_RES(fn, (p0, p1, p2, p3, p4, p5, p6, out))
+#define RPC_CALL9_OUT_CTRL_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, out)      RPC_DO_RES(fn, (p0, p1, p2, p3, p4, p5, p6, p7, out))
+#define RPC_CALL10_OUT_CTRL_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, out) RPC_DO_RES(fn, (p0, p1, p2, p3, p4, p5, p6, p7, p8, out))
+
+/*
+   message with data in/out via bulk channel
+*/
+
+#define RPC_CALL1_IN_BULK(fn, thread, id, in, len)                                      RPC_DO(fn, (in))
+#define RPC_CALL2_IN_BULK(fn, thread, id, p0, in, len)                                  RPC_DO(fn, (p0, in))
+#define RPC_CALL3_IN_BULK(fn, thread, id, p0, p1, in, len)                              RPC_DO(fn, (p0, p1, in))
+#define RPC_CALL4_IN_BULK(fn, thread, id, p0, p1, p2, in, len)                          RPC_DO(fn, (p0, p1, p2, in))
+#define RPC_CALL5_IN_BULK(fn, thread, id, p0, p1, p2, p3, in, len)                      RPC_DO(fn, (p0, p1, p2, p3, in))
+#define RPC_CALL6_IN_BULK(fn, thread, id, p0, p1, p2, p3, p4, in, len)                  RPC_DO(fn, (p0, p1, p2, p3, p4, in))
+#define RPC_CALL7_IN_BULK(fn, thread, id, p0, p1, p2, p3, p4, p5, in, len)              RPC_DO(fn, (p0, p1, p2, p3, p4, p5, in))
+#define RPC_CALL8_IN_BULK(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, in, len)          RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6, in))
+#define RPC_CALL9_IN_BULK(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, in, len)      RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6, p7, in))
+#define RPC_CALL10_IN_BULK(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, in, len) RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6, p7, p8, in))
+
+#define RPC_CALL1_OUT_BULK(fn, thread, id, out)                                      RPC_DO(fn, (out))
+#define RPC_CALL2_OUT_BULK(fn, thread, id, p0, out)                                  RPC_DO(fn, (p0, out))
+#define RPC_CALL3_OUT_BULK(fn, thread, id, p0, p1, out)                              RPC_DO(fn, (p0, p1, out))
+#define RPC_CALL4_OUT_BULK(fn, thread, id, p0, p1, p2, out)                          RPC_DO(fn, (p0, p1, p2, out))
+#define RPC_CALL5_OUT_BULK(fn, thread, id, p0, p1, p2, p3, out)                      RPC_DO(fn, (p0, p1, p2, p3, out))
+#define RPC_CALL6_OUT_BULK(fn, thread, id, p0, p1, p2, p3, p4, out)                  RPC_DO(fn, (p0, p1, p2, p3, p4, out))
+#define RPC_CALL7_OUT_BULK(fn, thread, id, p0, p1, p2, p3, p4, p5, out)              RPC_DO(fn, (p0, p1, p2, p3, p4, p5, out))
+#define RPC_CALL8_OUT_BULK(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, out)          RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6, out))
+#define RPC_CALL9_OUT_BULK(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, out)      RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6, p7, out))
+#define RPC_CALL10_OUT_BULK(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, out) RPC_DO(fn, (p0, p1, p2, p3, p4, p5, p6, p7, p8, out))
+
+#define RPC_CALL1_IN_BULK_RES(fn, thread, id, in, len)                                      RPC_DO_RES(fn, (in))
+#define RPC_CALL2_IN_BULK_RES(fn, thread, id, p0, in, len)                                  RPC_DO_RES(fn, (p0, in))
+#define RPC_CALL3_IN_BULK_RES(fn, thread, id, p0, p1, in, len)                              RPC_DO_RES(fn, (p0, p1, in))
+#define RPC_CALL4_IN_BULK_RES(fn, thread, id, p0, p1, p2, in, len)                          RPC_DO_RES(fn, (p0, p1, p2, in))
+#define RPC_CALL5_IN_BULK_RES(fn, thread, id, p0, p1, p2, p3, in, len)                      RPC_DO_RES(fn, (p0, p1, p2, p3, in))
+#define RPC_CALL6_IN_BULK_RES(fn, thread, id, p0, p1, p2, p3, p4, in, len)                  RPC_DO_RES(fn, (p0, p1, p2, p3, p4, in))
+#define RPC_CALL7_IN_BULK_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, in, len)              RPC_DO_RES(fn, (p0, p1, p2, p3, p4, p5, in))
+#define RPC_CALL8_IN_BULK_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, in, len)          RPC_DO_RES(fn, (p0, p1, p2, p3, p4, p5, p6, in))
+#define RPC_CALL9_IN_BULK_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, in, len)      RPC_DO_RES(fn, (p0, p1, p2, p3, p4, p5, p6, p7, in))
+#define RPC_CALL10_IN_BULK_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, in, len) RPC_DO_RES(fn, (p0, p1, p2, p3, p4, p5, p6, p7, p8, in))
+
+#define RPC_CALL1_OUT_BULK_RES(fn, thread, id, out)                                      RPC_DO_RES(fn, (out))
+#define RPC_CALL2_OUT_BULK_RES(fn, thread, id, p0, out)                                  RPC_DO_RES(fn, (p0, out))
+#define RPC_CALL3_OUT_BULK_RES(fn, thread, id, p0, p1, out)                              RPC_DO_RES(fn, (p0, p1, out))
+#define RPC_CALL4_OUT_BULK_RES(fn, thread, id, p0, p1, p2, out)                          RPC_DO_RES(fn, (p0, p1, p2, out))
+#define RPC_CALL5_OUT_BULK_RES(fn, thread, id, p0, p1, p2, p3, out)                      RPC_DO_RES(fn, (p0, p1, p2, p3, out))
+#define RPC_CALL6_OUT_BULK_RES(fn, thread, id, p0, p1, p2, p3, p4, out)                  RPC_DO_RES(fn, (p0, p1, p2, p3, p4, out))
+#define RPC_CALL7_OUT_BULK_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, out)              RPC_DO_RES(fn, (p0, p1, p2, p3, p4, p5, out))
+#define RPC_CALL8_OUT_BULK_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, out)          RPC_DO_RES(fn, (p0, p1, p2, p3, p4, p5, p6, out))
+#define RPC_CALL9_OUT_BULK_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, out)      RPC_DO_RES(fn, (p0, p1, p2, p3, p4, p5, p6, p7, out))
+#define RPC_CALL10_OUT_BULK_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, out) RPC_DO_RES(fn, (p0, p1, p2, p3, p4, p5, p6, p7, p8, out))
+
+#else /* RPC_DIRECT */
+
+#include "interface/khronos/common/khrn_int_ids.h"
+
+#include "interface/khronos/include/GLES/gl.h"
+#include "interface/khronos/include/VG/openvg.h"
+
+#include <string.h>
+
+/******************************************************************************
+core api
+******************************************************************************/
+
+extern bool khclient_rpc_init(void);
+extern void rpc_term(void);
+
+extern void rpc_flush(CLIENT_THREAD_STATE_T *thread);
+extern void rpc_high_priority_begin(CLIENT_THREAD_STATE_T *thread);
+extern void rpc_high_priority_end(CLIENT_THREAD_STATE_T *thread);
+
+extern uint64_t rpc_get_client_id(CLIENT_THREAD_STATE_T *thread);
+
+static INLINE uint32_t rpc_pad_ctrl(uint32_t len) { return (len + 0x3) & ~0x3; }
+static INLINE uint32_t rpc_pad_bulk(uint32_t len) { return len; }
+
+/* returns the length of the remainder of the merge buffer (after a flush if this length would be < len_min) */
+extern uint32_t rpc_send_ctrl_longest(CLIENT_THREAD_STATE_T *thread, uint32_t len_min);
+
+extern void rpc_send_ctrl_begin(CLIENT_THREAD_STATE_T *thread, uint32_t len); /* sum of padded lengths -- use rpc_pad_ctrl */
+extern void rpc_send_ctrl_write(CLIENT_THREAD_STATE_T *thread, const uint32_t msg[], uint32_t msglen); /* len bytes read, rpc_pad_ctrl(len) bytes written */
+extern void rpc_send_ctrl_end(CLIENT_THREAD_STATE_T *thread);
+
+extern void rpc_send_bulk(CLIENT_THREAD_STATE_T *thread, const void *in, uint32_t len); /* len bytes read, rpc_pad_bulk(len) bytes written. in must remain valid until the next "releasing" rpc_end call */
+extern void rpc_send_bulk_gather(CLIENT_THREAD_STATE_T *thread, const void *in, uint32_t len, int32_t stride, uint32_t n); /* n * len bytes read, rpc_pad_bulk(n * len) bytes written */
+
+typedef enum {
+   RPC_RECV_FLAG_RES          = 1 << 0,
+   RPC_RECV_FLAG_CTRL         = 1 << 1,
+   RPC_RECV_FLAG_BULK         = 1 << 2, /* len bytes written, rpc_pad_bulk(len) bytes read */
+   RPC_RECV_FLAG_BULK_SCATTER = 1 << 3, /* len = { len, stride, n, first_mask, last_mask }, n * len bytes written, rpc_pad_bulk(n * len) bytes read */
+   RPC_RECV_FLAG_LEN          = 1 << 4  /* len provided by other side */
+} RPC_RECV_FLAG_T;
+
+extern uint32_t rpc_recv(CLIENT_THREAD_STATE_T *thread, void *out, uint32_t *len, RPC_RECV_FLAG_T flags);
+extern void rpc_recv_bulk_gather(CLIENT_THREAD_STATE_T *thread, void *out, uint32_t *len, RPC_RECV_FLAG_T flags); /* n * len bytes read, rpc_pad_bulk(n * len) bytes written */
+
+/*
+   all rpc macros and rpc_send_ctrl_begin/rpc_send_ctrl_write/rpc_send_ctrl_end
+   are atomic by themselves and do not require calls to rpc_begin/rpc_end
+
+   rpc_begin/rpc_end can be nested, ie the following code will not deadlock:
+
+   rpc_begin(thread);
+   rpc_begin(thread);
+   rpc_end(thread);
+   rpc_end(thread);
+*/
+
+extern void rpc_begin(CLIENT_THREAD_STATE_T *thread);
+extern void rpc_end(CLIENT_THREAD_STATE_T *thread);
+
+
+/******************************************************************************
+helpers
+******************************************************************************/
+
+static INLINE void rpc_gather(void *out, const void *in, uint32_t len, int32_t stride, uint32_t n)
+{
+   uint32_t i;
+   for (i = 0; i != n; ++i) {
+      memcpy((uint8_t *)out + (i * len), in, len);
+      in = (const uint8_t *)in + stride;
+   }
+}
+
+static INLINE void rpc_scatter(void *out, uint32_t len, int32_t stride, uint32_t n, uint32_t first_mask, uint32_t last_mask, const void *in)
+{
+   uint32_t i;
+   for (i = 0; i != n; ++i) {
+      uint32_t first = 0, last = 0;
+      if (first_mask) { first = ((uint8_t *)out)[0] & first_mask; }
+      if (last_mask) { last = ((uint8_t *)out)[len - 1] & last_mask; }
+      memcpy(out, (const uint8_t *)in + (i * len), len);
+      if (first_mask) { ((uint8_t *)out)[0] = (uint8_t)((((uint8_t *)out)[0] & ~first_mask) | first); }
+      if (last_mask) { ((uint8_t *)out)[len - 1] = (uint8_t)((((uint8_t *)out)[len - 1] & ~last_mask) | last); }
+      out = (uint8_t *)out + stride;
+   }
+}
+
+/******************************************************************************
+type packing/unpacking macros
+******************************************************************************/
+
+#define RPC_FLOAT(f)        (float_to_bits(f))
+#define RPC_ENUM(e)         ((uint32_t)(e))
+#define RPC_INT(i)          ((uint32_t)(i))
+#define RPC_INTPTR(p)       ((uint32_t)(p))
+#define RPC_UINT(u)         ((uint32_t)(u))
+#define RPC_SIZEI(s)        ((uint32_t)(s))
+#define RPC_SIZEIPTR(p)     ((uint32_t)(p))
+#define RPC_BOOLEAN(b)      ((uint32_t)(b))
+#define RPC_BITFIELD(b)     ((uint32_t)(b))
+#define RPC_FIXED(f)        ((uint32_t)(f))
+#define RPC_HANDLE(h)       ((uint32_t)(h))
+#define RPC_EGLID(i)        ((uint32_t)(size_t)(i))
+
+#define RPC_FLOAT_RES(f)    (float_from_bits(f))
+#define RPC_ENUM_RES(e)     ((GLenum)(e))
+#define RPC_INT_RES(i)      ((GLint)(i))
+#define RPC_UINT_RES(u)     ((GLuint)(u))
+#define RPC_BOOLEAN_RES(b)  (!!(b))
+#define RPC_BITFIELD_RES(b) ((GLbitfield)(b))
+#define RPC_HANDLE_RES(h)   ((VGHandle)(h))
+
+/******************************************************************************
+rpc call macros
+******************************************************************************/
+
+#define RPC_INIT() khclient_rpc_init()
+#define RPC_TERM() rpc_term()
+
+#define RPC_FLUSH(thread) rpc_flush(thread)
+#define RPC_HIGH_PRIORITY_BEGIN(thread) rpc_high_priority_begin(thread)
+#define RPC_HIGH_PRIORITY_END(thread) rpc_high_priority_end(thread)
+
+#define RPC_CALL8_MAKECURRENT(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7)                                             rpc_call8_makecurrent(thread, id, p0, p1, p2, p3, p4, p5, p6, p7)
+void rpc_call8_makecurrent(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7);
+uint32_t khronos_kernel_semaphore_create( uint32_t name, uint32_t count );
+uint32_t khronos_kernel_semaphore_acquire( uint32_t semaphore );
+uint32_t khronos_kernel_semaphore_acquire_and_release( uint32_t semaphore );
+uint32_t khronos_kernel_semaphore_release( uint32_t semaphore );
+uint32_t khronos_kernel_semaphore_destroy( uint32_t semaphore );
+
+/*
+   helper macros (shouldn't be used directly)
+*/
+
+# if defined(__SYMBIAN32__)  //use functions defined in khrpc.cpp
+#else
+#ifdef __HIGHC__
+   /*
+      use XXX.../XXX syntax for variadic macros
+   */
+
+   #define RPC_CALL(thread, ARGS...) \
+      do { \
+         uint32_t message_[] = { ARGS }; \
+         rpc_send_ctrl_begin(thread, sizeof(message_)); \
+         rpc_send_ctrl_write(thread, message_, sizeof(message_)); \
+         rpc_send_ctrl_end(thread); \
+      } while (0)
+
+   #define RPC_CALL_IN_CTRL(thread, IN, LEN, ARGS...) \
+      do { \
+         const void *in_ = IN; \
+         uint32_t len_ = LEN; \
+         uint32_t message_[] = { ARGS }; \
+         rpc_send_ctrl_begin(thread, sizeof(message_) + rpc_pad_ctrl(len_)); \
+         rpc_send_ctrl_write(thread, message_, sizeof(message_)); \
+         rpc_send_ctrl_write(thread, (uint32_t *)in_, len_); \
+         rpc_send_ctrl_end(thread); \
+      } while (0)
+
+   #define RPC_CALL_IN_BULK(thread, IN, LEN, ARGS...) \
+      do { \
+         const void *in_ = IN; \
+         uint32_t len_ = LEN; \
+         uint32_t message_[] = { ARGS, in_ ? len_ : LENGTH_SIGNAL_NULL }; \
+         rpc_send_ctrl_begin(thread, sizeof(message_)); \
+         rpc_send_ctrl_write(thread, message_, sizeof(message_)); \
+         rpc_send_ctrl_end(thread); \
+         rpc_send_bulk(thread, in_, len_); \
+      } while (0)
+#else
+   /*
+      use c99 .../__VA_ARGS__ syntax for variadic macros
+   */
+
+   #define RPC_CALL(thread, ...) \
+      do { \
+         uint32_t message_[] = { __VA_ARGS__ }; \
+         rpc_send_ctrl_begin(thread, sizeof(message_)); \
+         rpc_send_ctrl_write(thread, message_, sizeof(message_)); \
+         rpc_send_ctrl_end(thread); \
+      } while (0)
+
+   #define RPC_CALL_IN_CTRL(thread, IN, LEN, ...) \
+      do { \
+         const void *in_ = IN; \
+         uint32_t len_ = LEN; \
+         uint32_t message_[] = { __VA_ARGS__ }; \
+         rpc_send_ctrl_begin(thread, sizeof(message_) + rpc_pad_ctrl(len_)); \
+         rpc_send_ctrl_write(thread, message_, sizeof(message_)); \
+         rpc_send_ctrl_write(thread, in_, len_); \
+         rpc_send_ctrl_end(thread); \
+      } while (0)
+
+   #define RPC_CALL_IN_BULK(thread, IN, LEN, ...) \
+      do { \
+         const void *in_ = IN; \
+         uint32_t len_ = LEN; \
+         uint32_t message_[] = { __VA_ARGS__, in_ ? len_ : LENGTH_SIGNAL_NULL }; \
+         rpc_send_ctrl_begin(thread, sizeof(message_)); \
+         rpc_send_ctrl_write(thread, message_, sizeof(message_)); \
+         rpc_send_ctrl_end(thread); \
+         rpc_send_bulk(thread, in_, len_); \
+      } while (0)
+
+#endif
+#endif
+
+/*
+   just message
+*/
+
+# if !defined(__SYMBIAN32__)  //use functions defined in khrpc.cpp
+static INLINE void rpc_call0(CLIENT_THREAD_STATE_T *thread, uint32_t id)                                                                                                                                    { RPC_CALL(thread, id);                                         }
+static INLINE void rpc_call1(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0)                                                                                                                       { RPC_CALL(thread, id, p0);                                     }
+static INLINE void rpc_call2(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1)                                                                                                          { RPC_CALL(thread, id, p0, p1);                                 }
+static INLINE void rpc_call3(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2)                                                                                             { RPC_CALL(thread, id, p0, p1, p2);                             }
+static INLINE void rpc_call4(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3)                                                                                { RPC_CALL(thread, id, p0, p1, p2, p3);                         }
+static INLINE void rpc_call5(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4)                                                                   { RPC_CALL(thread, id, p0, p1, p2, p3, p4);                     }
+static INLINE void rpc_call6(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5)                                                      { RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5);                 }
+static INLINE void rpc_call7(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6)                                         { RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6);             }
+static INLINE void rpc_call8(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7)                            { RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7);         }
+static INLINE void rpc_call9(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, uint32_t p8)               { RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8);     }
+static INLINE void rpc_call10(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, uint32_t p8, uint32_t p9) { RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9); }
+static INLINE void rpc_call16(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7,
+   uint32_t p8, uint32_t p9, uint32_t p10, uint32_t p11, uint32_t p12, uint32_t p13, uint32_t p14, uint32_t p15)
+   { RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15); }
+static INLINE void rpc_call18(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7,
+   uint32_t p8, uint32_t p9, uint32_t p10, uint32_t p11, uint32_t p12, uint32_t p13, uint32_t p14, uint32_t p15, uint32_t p16, uint32_t p17)
+   { RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17); }
+
+#endif
+
+#define RPC_CALL0(fn, thread, id)                                          rpc_call0(thread, id)
+#define RPC_CALL1(fn, thread, id, p0)                                      rpc_call1(thread, id, p0)
+#define RPC_CALL2(fn, thread, id, p0, p1)                                  rpc_call2(thread, id, p0, p1)
+#define RPC_CALL3(fn, thread, id, p0, p1, p2)                              rpc_call3(thread, id, p0, p1, p2)
+#define RPC_CALL4(fn, thread, id, p0, p1, p2, p3)                          rpc_call4(thread, id, p0, p1, p2, p3)
+#define RPC_CALL5(fn, thread, id, p0, p1, p2, p3, p4)                      rpc_call5(thread, id, p0, p1, p2, p3, p4)
+#define RPC_CALL6(fn, thread, id, p0, p1, p2, p3, p4, p5)                  rpc_call6(thread, id, p0, p1, p2, p3, p4, p5)
+#define RPC_CALL7(fn, thread, id, p0, p1, p2, p3, p4, p5, p6)              rpc_call7(thread, id, p0, p1, p2, p3, p4, p5, p6)
+#define RPC_CALL8(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7)          rpc_call8(thread, id, p0, p1, p2, p3, p4, p5, p6, p7)
+#define RPC_CALL9(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8)      rpc_call9(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8)
+#define RPC_CALL10(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9) rpc_call10(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)
+#define RPC_CALL11(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) rpc_call10(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)
+#define RPC_CALL16(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15) \
+   rpc_call16(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15)
+#define RPC_CALL18(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17) \
+   rpc_call18(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, p17)
+
+/*
+   RPC_THING_RES(rpc_call[n]_res(id, RPC_THING(p0), RPC_THING(p1), ...))
+
+   Implementation notes:
+
+   -
+
+   Preconditions:
+
+   Not in RPC_DIRECT mode
+   p0, p1, etc. satisfy the preconditions of the operation identified by id
+   Server is up (except for a special initialise call)
+
+   Postconditions:
+
+   The operation identified by id has completed on the server
+   We return the result of this operation, and all postconditions are satisfied (on the server)
+
+   Invariants preserved:
+
+   -
+
+   Invariants used:
+
+   -
+*/
+
+# if !defined(__SYMBIAN32__)  //use functions defined in khrpc.cpp
+static INLINE uint32_t rpc_call0_res(CLIENT_THREAD_STATE_T *thread, uint32_t id)                                                                                                                                                                { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id);                                                   res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call1_res(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0)                                                                                                                                                   { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0);                                               res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call2_res(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1)                                                                                                                                      { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1);                                           res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call3_res(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2)                                                                                                                         { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2);                                       res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call4_res(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3)                                                                                                            { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3);                                   res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call5_res(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4)                                                                                               { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4);                               res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call6_res(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5)                                                                                  { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5);                           res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call7_res(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6)                                                                     { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6);                       res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call8_res(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7)                                                        { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7);                   res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call9_res(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, uint32_t p8)                                           { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8);               res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call10_res(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, uint32_t p8, uint32_t p9)                             { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);           res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call11_res(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, uint32_t p8, uint32_t p9, uint32_t p10)               { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10);      res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call12_res(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, uint32_t p8, uint32_t p9, uint32_t p10, uint32_t p11) { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11); res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+#endif
+
+#define RPC_CALL0_RES(fn, thread, id)                                                    rpc_call0_res(thread, id)
+#define RPC_CALL1_RES(fn, thread, id, p0)                                                rpc_call1_res(thread, id, p0)
+#define RPC_CALL2_RES(fn, thread, id, p0, p1)                                            rpc_call2_res(thread, id, p0, p1)
+#define RPC_CALL3_RES(fn, thread, id, p0, p1, p2)                                        rpc_call3_res(thread, id, p0, p1, p2)
+#define RPC_CALL4_RES(fn, thread, id, p0, p1, p2, p3)                                    rpc_call4_res(thread, id, p0, p1, p2, p3)
+#define RPC_CALL5_RES(fn, thread, id, p0, p1, p2, p3, p4)                                rpc_call5_res(thread, id, p0, p1, p2, p3, p4)
+#define RPC_CALL6_RES(fn, thread, id, p0, p1, p2, p3, p4, p5)                            rpc_call6_res(thread, id, p0, p1, p2, p3, p4, p5)
+#define RPC_CALL7_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6)                        rpc_call7_res(thread, id, p0, p1, p2, p3, p4, p5, p6)
+#define RPC_CALL8_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7)                    rpc_call8_res(thread, id, p0, p1, p2, p3, p4, p5, p6, p7)
+#define RPC_CALL9_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8)                rpc_call9_res(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8)
+#define RPC_CALL10_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)           rpc_call10_res(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)
+#define RPC_CALL11_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)      rpc_call11_res(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10)
+#define RPC_CALL12_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) rpc_call12_res(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11)
+
+/*
+   message with data in/out via control channel
+*/
+
+# if !defined(__SYMBIAN32__)  //use functions defined in khrpc.cpp
+static INLINE void rpc_call1_in_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, const void *in, uint32_t len)                                                                                                                       { RPC_CALL_IN_CTRL(thread, in, len, id);                                     }
+static INLINE void rpc_call2_in_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, const void *in, uint32_t len)                                                                                                          { RPC_CALL_IN_CTRL(thread, in, len, id, p0);                                 }
+static INLINE void rpc_call3_in_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, const void *in, uint32_t len)                                                                                             { RPC_CALL_IN_CTRL(thread, in, len, id, p0, p1);                             }
+static INLINE void rpc_call4_in_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, const void *in, uint32_t len)                                                                                { RPC_CALL_IN_CTRL(thread, in, len, id, p0, p1, p2);                         }
+static INLINE void rpc_call5_in_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, const void *in, uint32_t len)                                                                   { RPC_CALL_IN_CTRL(thread, in, len, id, p0, p1, p2, p3);                     }
+static INLINE void rpc_call6_in_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, const void *in, uint32_t len)                                                      { RPC_CALL_IN_CTRL(thread, in, len, id, p0, p1, p2, p3, p4);                 }
+static INLINE void rpc_call7_in_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, const void *in, uint32_t len)                                         { RPC_CALL_IN_CTRL(thread, in, len, id, p0, p1, p2, p3, p4, p5);             }
+static INLINE void rpc_call8_in_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, const void *in, uint32_t len)                            { RPC_CALL_IN_CTRL(thread, in, len, id, p0, p1, p2, p3, p4, p5, p6);         }
+static INLINE void rpc_call9_in_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, const void *in, uint32_t len)               { RPC_CALL_IN_CTRL(thread, in, len, id, p0, p1, p2, p3, p4, p5, p6, p7);     }
+static INLINE void rpc_call10_in_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, uint32_t p8, const void *in, uint32_t len) { RPC_CALL_IN_CTRL(thread, in, len, id, p0, p1, p2, p3, p4, p5, p6, p7, p8); }
+
+#endif
+
+#define RPC_CALL1_IN_CTRL(fn, thread, id, in, len)                                      rpc_call1_in_ctrl(thread, id, in, len)
+#define RPC_CALL2_IN_CTRL(fn, thread, id, p0, in, len)                                  rpc_call2_in_ctrl(thread, id, p0, in, len)
+#define RPC_CALL3_IN_CTRL(fn, thread, id, p0, p1, in, len)                              rpc_call3_in_ctrl(thread, id, p0, p1, in, len)
+#define RPC_CALL4_IN_CTRL(fn, thread, id, p0, p1, p2, in, len)                          rpc_call4_in_ctrl(thread, id, p0, p1, p2, in, len)
+#define RPC_CALL5_IN_CTRL(fn, thread, id, p0, p1, p2, p3, in, len)                      rpc_call5_in_ctrl(thread, id, p0, p1, p2, p3, in, len)
+#define RPC_CALL6_IN_CTRL(fn, thread, id, p0, p1, p2, p3, p4, in, len)                  rpc_call6_in_ctrl(thread, id, p0, p1, p2, p3, p4, in, len)
+#define RPC_CALL7_IN_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, in, len)              rpc_call7_in_ctrl(thread, id, p0, p1, p2, p3, p4, p5, in, len)
+#define RPC_CALL8_IN_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, in, len)          rpc_call8_in_ctrl(thread, id, p0, p1, p2, p3, p4, p5, p6, in, len)
+#define RPC_CALL9_IN_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, in, len)      rpc_call9_in_ctrl(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, in, len)
+#define RPC_CALL10_IN_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, in, len) rpc_call10_in_ctrl(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, in, len)
+
+# if !defined(__SYMBIAN32__)  //use functions defined in khrpc.cpp
+static INLINE void rpc_call1_out_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, void *out)                                                                                                                                                  { rpc_begin(thread); RPC_CALL(thread, id);                                              rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call2_out_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, void *out)                                                                                                                                     { rpc_begin(thread); RPC_CALL(thread, id, p0);                                          rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call3_out_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, void *out)                                                                                                                        { rpc_begin(thread); RPC_CALL(thread, id, p0, p1);                                      rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call4_out_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, void *out)                                                                                                           { rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2);                                  rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call5_out_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, void *out)                                                                                              { rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3);                              rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call6_out_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, void *out)                                                                                 { rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4);                          rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call7_out_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, void *out)                                                                    { rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5);                      rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call8_out_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, void *out)                                                       { rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6);                  rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call9_out_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, void *out)                                          { rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7);              rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call10_out_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, uint32_t p8, void *out)                            { rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8);          rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call11_out_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, uint32_t p8, uint32_t p9, void *out)               { rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9);      rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call12_out_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, uint32_t p8, uint32_t p9, uint32_t p10, void *out) { rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10); rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call13_out_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, uint32_t p8, uint32_t p9, uint32_t p10, uint32_t p11, void *out)               { rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11);      rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call14_out_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, uint32_t p8, uint32_t p9, uint32_t p10, uint32_t p11, uint32_t p12, void *out) { rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12); rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call15_out_ctrl(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, uint32_t p8, uint32_t p9, uint32_t p10, uint32_t p11, uint32_t p12, uint32_t p13, void *out) { rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13); rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+#endif
+
+#define RPC_CALL1_OUT_CTRL(fn, thread, id, out)                                               rpc_call1_out_ctrl(thread, id, out)
+#define RPC_CALL2_OUT_CTRL(fn, thread, id, p0, out)                                           rpc_call2_out_ctrl(thread, id, p0, out)
+#define RPC_CALL3_OUT_CTRL(fn, thread, id, p0, p1, out)                                       rpc_call3_out_ctrl(thread, id, p0, p1, out)
+#define RPC_CALL4_OUT_CTRL(fn, thread, id, p0, p1, p2, out)                                   rpc_call4_out_ctrl(thread, id, p0, p1, p2, out)
+#define RPC_CALL5_OUT_CTRL(fn, thread, id, p0, p1, p2, p3, out)                               rpc_call5_out_ctrl(thread, id, p0, p1, p2, p3, out)
+#define RPC_CALL6_OUT_CTRL(fn, thread, id, p0, p1, p2, p3, p4, out)                           rpc_call6_out_ctrl(thread, id, p0, p1, p2, p3, p4, out)
+#define RPC_CALL7_OUT_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, out)                       rpc_call7_out_ctrl(thread, id, p0, p1, p2, p3, p4, p5, out)
+#define RPC_CALL8_OUT_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, out)                   rpc_call8_out_ctrl(thread, id, p0, p1, p2, p3, p4, p5, p6, out)
+#define RPC_CALL9_OUT_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, out)               rpc_call9_out_ctrl(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, out)
+#define RPC_CALL10_OUT_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, out)          rpc_call10_out_ctrl(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, out)
+#define RPC_CALL11_OUT_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, out)      rpc_call11_out_ctrl(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, out)
+#define RPC_CALL12_OUT_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, out) rpc_call12_out_ctrl(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, out)
+#define RPC_CALL13_OUT_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, out)      rpc_call13_out_ctrl(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, out)
+#define RPC_CALL14_OUT_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, out) rpc_call14_out_ctrl(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, out)
+#define RPC_CALL15_OUT_CTRL(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, out) rpc_call15_out_ctrl(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, out)
+
+# if !defined(__SYMBIAN32__)  //use functions defined in khrpc.cpp
+static INLINE uint32_t rpc_call1_out_ctrl_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, void *out)                                                                                                                       { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id);                                     res = rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_RES | RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call2_out_ctrl_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, void *out)                                                                                                          { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0);                                 res = rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_RES | RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call3_out_ctrl_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, void *out)                                                                                             { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1);                             res = rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_RES | RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call4_out_ctrl_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, void *out)                                                                                { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2);                         res = rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_RES | RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call5_out_ctrl_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, void *out)                                                                   { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3);                     res = rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_RES | RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call6_out_ctrl_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, void *out)                                                      { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4);                 res = rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_RES | RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call7_out_ctrl_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, void *out)                                         { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5);             res = rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_RES | RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call8_out_ctrl_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, void *out)                            { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6);         res = rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_RES | RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call9_out_ctrl_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, void *out)               { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7);     res = rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_RES | RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call10_out_ctrl_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, uint32_t p8, void *out) { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8); res = rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_RES | RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN)); rpc_end(thread); return res; }
+#endif
+
+#define RPC_CALL1_OUT_CTRL_RES(fn, thread, id, out)                                      rpc_call1_out_ctrl_res(thread, id, out)
+#define RPC_CALL2_OUT_CTRL_RES(fn, thread, id, p0, out)                                  rpc_call2_out_ctrl_res(thread, id, p0, out)
+#define RPC_CALL3_OUT_CTRL_RES(fn, thread, id, p0, p1, out)                              rpc_call3_out_ctrl_res(thread, id, p0, p1, out)
+#define RPC_CALL4_OUT_CTRL_RES(fn, thread, id, p0, p1, p2, out)                          rpc_call4_out_ctrl_res(thread, id, p0, p1, p2, out)
+#define RPC_CALL5_OUT_CTRL_RES(fn, thread, id, p0, p1, p2, p3, out)                      rpc_call5_out_ctrl_res(thread, id, p0, p1, p2, p3, out)
+#define RPC_CALL6_OUT_CTRL_RES(fn, thread, id, p0, p1, p2, p3, p4, out)                  rpc_call6_out_ctrl_res(thread, id, p0, p1, p2, p3, p4, out)
+#define RPC_CALL7_OUT_CTRL_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, out)              rpc_call7_out_ctrl_res(thread, id, p0, p1, p2, p3, p4, p5, out)
+#define RPC_CALL8_OUT_CTRL_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, out)          rpc_call8_out_ctrl_res(thread, id, p0, p1, p2, p3, p4, p5, p6, out)
+#define RPC_CALL9_OUT_CTRL_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, out)      rpc_call9_out_ctrl_res(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, out)
+#define RPC_CALL10_OUT_CTRL_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, out) rpc_call10_out_ctrl_res(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, out)
+
+/*
+   message with data in/out via bulk channel
+
+   if in is NULL, no bulk transfer will be performed and LENGTH_SIGNAL_NULL will
+   be passed instead of len
+*/
+
+# if !defined(__SYMBIAN32__)  //use functions defined in khrpc.cpp
+static INLINE void rpc_call1_in_bulk(CLIENT_THREAD_STATE_T *thread,uint32_t id, const void *in, uint32_t len)                                                                                                                       { rpc_begin(thread); RPC_CALL_IN_BULK(thread, in, len, id);                                     rpc_end(thread); }
+static INLINE void rpc_call2_in_bulk(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, const void *in, uint32_t len)                                                                                                          { rpc_begin(thread); RPC_CALL_IN_BULK(thread, in, len, id, p0);                                 rpc_end(thread); }
+static INLINE void rpc_call3_in_bulk(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, const void *in, uint32_t len)                                                                                             { rpc_begin(thread); RPC_CALL_IN_BULK(thread, in, len, id, p0, p1);                             rpc_end(thread); }
+static INLINE void rpc_call4_in_bulk(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, const void *in, uint32_t len)                                                                                { rpc_begin(thread); RPC_CALL_IN_BULK(thread, in, len, id, p0, p1, p2);                         rpc_end(thread); }
+static INLINE void rpc_call5_in_bulk(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, const void *in, uint32_t len)                                                                   { rpc_begin(thread); RPC_CALL_IN_BULK(thread, in, len, id, p0, p1, p2, p3);                     rpc_end(thread); }
+static INLINE void rpc_call6_in_bulk(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, const void *in, uint32_t len)                                                      { rpc_begin(thread); RPC_CALL_IN_BULK(thread, in, len, id, p0, p1, p2, p3, p4);                 rpc_end(thread); }
+static INLINE void rpc_call7_in_bulk(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, const void *in, uint32_t len)                                         { rpc_begin(thread); RPC_CALL_IN_BULK(thread, in, len, id, p0, p1, p2, p3, p4, p5);             rpc_end(thread); }
+static INLINE void rpc_call8_in_bulk(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, const void *in, uint32_t len)                            { rpc_begin(thread); RPC_CALL_IN_BULK(thread, in, len, id, p0, p1, p2, p3, p4, p5, p6);         rpc_end(thread); }
+static INLINE void rpc_call9_in_bulk(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, const void *in, uint32_t len)               { rpc_begin(thread); RPC_CALL_IN_BULK(thread, in, len, id, p0, p1, p2, p3, p4, p5, p6, p7);     rpc_end(thread); }
+static INLINE void rpc_call10_in_bulk(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, uint32_t p8, const void *in, uint32_t len) { rpc_begin(thread); RPC_CALL_IN_BULK(thread, in, len, id, p0, p1, p2, p3, p4, p5, p6, p7, p8); rpc_end(thread); }
+#endif
+
+#define RPC_CALL1_IN_BULK(fn, thread, id, in, len)                                      rpc_call1_in_bulk(thread, id, in, len)
+#define RPC_CALL2_IN_BULK(fn, thread, id, p0, in, len)                                  rpc_call2_in_bulk(thread, id, p0, in, len)
+#define RPC_CALL3_IN_BULK(fn, thread, id, p0, p1, in, len)                              rpc_call3_in_bulk(thread, id, p0, p1, in, len)
+#define RPC_CALL4_IN_BULK(fn, thread, id, p0, p1, p2, in, len)                          rpc_call4_in_bulk(thread, id, p0, p1, p2, in, len)
+#define RPC_CALL5_IN_BULK(fn, thread, id, p0, p1, p2, p3, in, len)                      rpc_call5_in_bulk(thread, id, p0, p1, p2, p3, in, len)
+#define RPC_CALL6_IN_BULK(fn, thread, id, p0, p1, p2, p3, p4, in, len)                  rpc_call6_in_bulk(thread, id, p0, p1, p2, p3, p4, in, len)
+#define RPC_CALL7_IN_BULK(fn, thread, id, p0, p1, p2, p3, p4, p5, in, len)              rpc_call7_in_bulk(thread, id, p0, p1, p2, p3, p4, p5, in, len)
+#define RPC_CALL8_IN_BULK(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, in, len)          rpc_call8_in_bulk(thread, id, p0, p1, p2, p3, p4, p5, p6, in, len)
+#define RPC_CALL9_IN_BULK(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, in, len)      rpc_call9_in_bulk(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, in, len)
+#define RPC_CALL10_IN_BULK(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, in, len) rpc_call10_in_bulk(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, in, len)
+
+# if !defined(__SYMBIAN32__)  //use functions defined in khrpc.cpp
+static INLINE void rpc_call1_out_bulk(CLIENT_THREAD_STATE_T *thread,uint32_t id, void *out)                                                                                                                       { rpc_begin(thread); RPC_CALL(thread, id);                                     rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call2_out_bulk(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, void *out)                                                                                                          { rpc_begin(thread); RPC_CALL(thread, id, p0);                                 rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call3_out_bulk(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, void *out)                                                                                             { rpc_begin(thread); RPC_CALL(thread, id, p0, p1);                             rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call4_out_bulk(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, void *out)                                                                                { rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2);                         rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call5_out_bulk(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, void *out)                                                                   { rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3);                     rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call6_out_bulk(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, void *out)                                                      { rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4);                 rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call7_out_bulk(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, void *out)                                         { rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5);             rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call8_out_bulk(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, void *out)                            { rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6);         rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call9_out_bulk(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, void *out)               { rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7);     rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+static INLINE void rpc_call10_out_bulk(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, uint32_t p8, void *out) { rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8); rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_LEN)); rpc_end(thread); }
+#endif
+
+#define RPC_CALL1_OUT_BULK(fn, thread, id, out)                                      rpc_call1_out_bulk(thread, id, out)
+#define RPC_CALL2_OUT_BULK(fn, thread, id, p0, out)                                  rpc_call2_out_bulk(thread, id, p0, out)
+#define RPC_CALL3_OUT_BULK(fn, thread, id, p0, p1, out)                              rpc_call3_out_bulk(thread, id, p0, p1, out)
+#define RPC_CALL4_OUT_BULK(fn, thread, id, p0, p1, p2, out)                          rpc_call4_out_bulk(thread, id, p0, p1, p2, out)
+#define RPC_CALL5_OUT_BULK(fn, thread, id, p0, p1, p2, p3, out)                      rpc_call5_out_bulk(thread, id, p0, p1, p2, p3, out)
+#define RPC_CALL6_OUT_BULK(fn, thread, id, p0, p1, p2, p3, p4, out)                  rpc_call6_out_bulk(thread, id, p0, p1, p2, p3, p4, out)
+#define RPC_CALL7_OUT_BULK(fn, thread, id, p0, p1, p2, p3, p4, p5, out)              rpc_call7_out_bulk(thread, id, p0, p1, p2, p3, p4, p5, out)
+#define RPC_CALL8_OUT_BULK(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, out)          rpc_call8_out_bulk(thread, id, p0, p1, p2, p3, p4, p5, p6, out)
+#define RPC_CALL9_OUT_BULK(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, out)      rpc_call9_out_bulk(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, out)
+#define RPC_CALL10_OUT_BULK(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, out) rpc_call10_out_bulk(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, out)
+
+# if !defined(__SYMBIAN32__)  //use functions defined in khrpc.cpp
+static INLINE uint32_t rpc_call1_in_bulk_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, const void *in, uint32_t len)                                                                                                                       { uint32_t res; rpc_begin(thread); RPC_CALL_IN_BULK(thread, in, len, id);                                     res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call2_in_bulk_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, const void *in, uint32_t len)                                                                                                          { uint32_t res; rpc_begin(thread); RPC_CALL_IN_BULK(thread, in, len, id, p0);                                 res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call3_in_bulk_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, const void *in, uint32_t len)                                                                                             { uint32_t res; rpc_begin(thread); RPC_CALL_IN_BULK(thread, in, len, id, p0, p1);                             res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call4_in_bulk_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, const void *in, uint32_t len)                                                                                { uint32_t res; rpc_begin(thread); RPC_CALL_IN_BULK(thread, in, len, id, p0, p1, p2);                         res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call5_in_bulk_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, const void *in, uint32_t len)                                                                   { uint32_t res; rpc_begin(thread); RPC_CALL_IN_BULK(thread, in, len, id, p0, p1, p2, p3);                     res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call6_in_bulk_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, const void *in, uint32_t len)                                                      { uint32_t res; rpc_begin(thread); RPC_CALL_IN_BULK(thread, in, len, id, p0, p1, p2, p3, p4);                 res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call7_in_bulk_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, const void *in, uint32_t len)                                         { uint32_t res; rpc_begin(thread); RPC_CALL_IN_BULK(thread, in, len, id, p0, p1, p2, p3, p4, p5);             res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call8_in_bulk_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, const void *in, uint32_t len)                            { uint32_t res; rpc_begin(thread); RPC_CALL_IN_BULK(thread, in, len, id, p0, p1, p2, p3, p4, p5, p6);         res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call9_in_bulk_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, const void *in, uint32_t len)               { uint32_t res; rpc_begin(thread); RPC_CALL_IN_BULK(thread, in, len, id, p0, p1, p2, p3, p4, p5, p6, p7);     res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call10_in_bulk_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, uint32_t p8, const void *in, uint32_t len) { uint32_t res; rpc_begin(thread); RPC_CALL_IN_BULK(thread, in, len, id, p0, p1, p2, p3, p4, p5, p6, p7, p8); res = rpc_recv(thread, NULL, NULL, RPC_RECV_FLAG_RES); rpc_end(thread); return res; }
+#endif
+
+#define RPC_CALL1_IN_BULK_RES(fn, thread, id, in, len)                                      rpc_call1_in_bulk_res(thread, id, in, len)
+#define RPC_CALL2_IN_BULK_RES(fn, thread, id, p0, in, len)                                  rpc_call2_in_bulk_res(thread, id, p0, in, len)
+#define RPC_CALL3_IN_BULK_RES(fn, thread, id, p0, p1, in, len)                              rpc_call3_in_bulk_res(thread, id, p0, p1, in, len)
+#define RPC_CALL4_IN_BULK_RES(fn, thread, id, p0, p1, p2, in, len)                          rpc_call4_in_bulk_res(thread, id, p0, p1, p2, in, len)
+#define RPC_CALL5_IN_BULK_RES(fn, thread, id, p0, p1, p2, p3, in, len)                      rpc_call5_in_bulk_res(thread, id, p0, p1, p2, p3, in, len)
+#define RPC_CALL6_IN_BULK_RES(fn, thread, id, p0, p1, p2, p3, p4, in, len)                  rpc_call6_in_bulk_res(thread, id, p0, p1, p2, p3, p4, in, len)
+#define RPC_CALL7_IN_BULK_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, in, len)              rpc_call7_in_bulk_res(thread, id, p0, p1, p2, p3, p4, p5, in, len)
+#define RPC_CALL8_IN_BULK_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, in, len)          rpc_call8_in_bulk_res(thread, id, p0, p1, p2, p3, p4, p5, p6, in, len)
+#define RPC_CALL9_IN_BULK_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, in, len)      rpc_call9_in_bulk_res(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, in, len)
+#define RPC_CALL10_IN_BULK_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, in, len) rpc_call10_in_bulk_res(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, in, len)
+
+# if !defined(__SYMBIAN32__)  //use functions defined in khrpc.cpp
+static INLINE uint32_t rpc_call1_out_bulk_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, void *out)                                                                                                                       { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id);                                     res = rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_RES | RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_LEN)); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call2_out_bulk_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, void *out)                                                                                                          { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0);                                 res = rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_RES | RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_LEN)); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call3_out_bulk_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, void *out)                                                                                             { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1);                             res = rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_RES | RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_LEN)); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call4_out_bulk_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, void *out)                                                                                { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2);                         res = rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_RES | RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_LEN)); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call5_out_bulk_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, void *out)                                                                   { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3);                     res = rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_RES | RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_LEN)); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call6_out_bulk_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, void *out)                                                      { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4);                 res = rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_RES | RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_LEN)); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call7_out_bulk_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, void *out)                                         { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5);             res = rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_RES | RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_LEN)); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call8_out_bulk_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, void *out)                            { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6);         res = rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_RES | RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_LEN)); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call9_out_bulk_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, void *out)               { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7);     res = rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_RES | RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_LEN)); rpc_end(thread); return res; }
+static INLINE uint32_t rpc_call10_out_bulk_res(CLIENT_THREAD_STATE_T *thread,uint32_t id, uint32_t p0, uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7, uint32_t p8, void *out) { uint32_t res; rpc_begin(thread); RPC_CALL(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8); res = rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_RES | RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_LEN)); rpc_end(thread); return res; }
+#endif
+
+#define RPC_CALL1_OUT_BULK_RES(fn, thread, id, out)                                      rpc_call1_out_bulk_res(thread, id, out)
+#define RPC_CALL2_OUT_BULK_RES(fn, thread, id, p0, out)                                  rpc_call2_out_bulk_res(thread, id, p0, out)
+#define RPC_CALL3_OUT_BULK_RES(fn, thread, id, p0, p1, out)                              rpc_call3_out_bulk_res(thread, id, p0, p1, out)
+#define RPC_CALL4_OUT_BULK_RES(fn, thread, id, p0, p1, p2, out)                          rpc_call4_out_bulk_res(thread, id, p0, p1, p2, out)
+#define RPC_CALL5_OUT_BULK_RES(fn, thread, id, p0, p1, p2, p3, out)                      rpc_call5_out_bulk_res(thread, id, p0, p1, p2, p3, out)
+#define RPC_CALL6_OUT_BULK_RES(fn, thread, id, p0, p1, p2, p3, p4, out)                  rpc_call6_out_bulk_res(thread, id, p0, p1, p2, p3, p4, out)
+#define RPC_CALL7_OUT_BULK_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, out)              rpc_call7_out_bulk_res(thread, id, p0, p1, p2, p3, p4, p5, out)
+#define RPC_CALL8_OUT_BULK_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, out)          rpc_call8_out_bulk_res(thread, id, p0, p1, p2, p3, p4, p5, p6, out)
+#define RPC_CALL9_OUT_BULK_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, out)      rpc_call9_out_bulk_res(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, out)
+#define RPC_CALL10_OUT_BULK_RES(fn, thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, out) rpc_call10_out_bulk_res(thread, id, p0, p1, p2, p3, p4, p5, p6, p7, p8, out)
+
+#endif /* RPC_DIRECT */
+
+#ifdef __cplusplus
+ }
+#endif
+#endif
diff --git a/interface/khronos/common/khrn_client_unmangle.h b/interface/khronos/common/khrn_client_unmangle.h
new file mode 100755 (executable)
index 0000000..4f3ce49
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRONOS_MANGLE_H
+#if defined KHRONOS_NAME_MANGLING || defined REMOTE_API_LOGGING || defined BCG_MULTI_THREADED
+
+/* EGL Functions */
+
+#undef eglGetError
+#undef eglGetDisplay
+#undef eglInitialize
+#undef eglTerminate
+#undef eglQueryString
+#undef eglGetConfigs
+#undef eglChooseConfig
+#undef eglGetConfigAttrib
+#undef eglCreateWindowSurface
+#undef eglCreatePbufferSurface
+#undef eglCreatePixmapSurface
+#undef eglDestroySurface
+#undef eglQuerySurface
+#undef eglBindAPI
+#undef eglQueryAPI
+#undef eglWaitClient
+#undef eglReleaseThread
+#undef eglCreatePbufferFromClientBuffer
+#undef eglSurfaceAttrib
+#undef eglBindTexImage
+#undef eglReleaseTexImage
+#undef eglSwapInterval
+#undef eglCreateContext
+#undef eglDestroyContext
+#undef eglMakeCurrent
+#undef eglGetCurrentContext
+#undef eglGetCurrentSurface
+#undef eglGetCurrentDisplay
+#undef eglQueryContext
+#undef eglWaitGL
+#undef eglWaitNative
+#undef eglSwapBuffers
+#undef eglCopyBuffers
+#undef eglGetProcAddress
+#undef eglClientWaitSyncKHR
+#undef eglCreateImageKHR
+#undef eglCreateSyncKHR
+#undef eglDestroyImageKHR
+#undef eglDestroySyncKHR
+#undef eglGetSyncAttribKHR
+#undef eglGetSyncAttribKHR
+#undef eglQueryProfilingDataNOK
+#undef eglSignalSyncKHR
+#undef eglLockSurfaceKHR
+#undef eglUnlockSurfaceKHR
+#undef glEGLImageTargetRenderbufferStorageOES
+#undef glEGLImageTargetTexture2DOES
+#undef eglAcquireGlobalImageBRCM
+#undef eglCreateCopyGlobalImageBRCM
+#undef eglCreateGlobalImageBRCM
+#undef eglReleaseGlobalImageBRCM
+#undef eglInitGlobalImageBRCM
+#undef eglTermGlobalImageBRCM
+
+/* OpenGL ES 1.1 and 2.0 functions */
+
+#undef glAlphaFunc
+#undef glClearColor
+#undef glClearDepthf
+#undef glClipPlanef
+#undef glColor4f
+#undef glDepthRangef
+#undef glFogf
+#undef glFogfv
+#undef glFrustumf
+#undef glGetClipPlanef
+#undef glGetFloatv
+#undef glGetLightfv
+#undef glGetMaterialfv
+#undef glGetTexEnvfv
+#undef glGetTexParameterfv
+#undef glLightModelf
+#undef glLightModelfv
+#undef glLightf
+#undef glLightfv
+#undef glLineWidth
+#undef glLoadMatrixf
+#undef glMaterialf
+#undef glMaterialfv
+#undef glMultMatrixf
+#undef glMultiTexCoord4f
+#undef glNormal3f
+#undef glOrthof
+#undef glPointParameterf
+#undef glPointParameterfv
+#undef glPointSize
+#undef glPolygonOffset
+#undef glRotatef
+#undef glScalef
+#undef glTexEnvf
+#undef glTexEnvfv
+#undef glTexParameterf
+#undef glTexParameterfv
+#undef glTranslatef
+
+#undef glActiveTexture
+#undef glAlphaFuncx
+#undef glBindBuffer
+#undef glBindTexture
+#undef glBlendFunc
+#undef glBlendColor
+#undef glBufferData
+#undef glBlendEquation
+#undef glBufferSubData
+#undef glClear
+#undef glClearColorx
+#undef glClearDepthx
+#undef glClearStencil
+#undef glClientActiveTexture
+#undef glClipPlanex
+#undef glColor4ub
+#undef glColor4x
+#undef glColorMask
+#undef glColorPointer
+#undef glCompressedTexImage2D
+#undef glCompressedTexSubImage2D
+#undef glCopyTexImage2D
+#undef glCopyTexSubImage2D
+#undef glCullFace
+#undef glDeleteBuffers
+#undef glDeleteTextures
+#undef glDepthFunc
+#undef glDepthMask
+#undef glDepthRangex
+#undef glDisable
+#undef glDisableClientState
+#undef glDrawArrays
+#undef glDrawElements
+#undef glEnable
+#undef glEnableClientState
+#undef glFinish
+#undef glFlush
+#undef glFogx
+#undef glFogxv
+#undef glFrontFace
+#undef glFrustumx
+#undef glGetBooleanv
+#undef glGetBufferParameteriv
+#undef glGetClipPlanex
+#undef glGenBuffers
+#undef glGenTextures
+#undef glGetError
+#undef glGetFixedv
+#undef glGetIntegerv
+#undef glGetLightxv
+#undef glGetMaterialxv
+#undef glGetPointerv
+#undef glGetString
+#undef glGetTexEnviv
+#undef glGetTexEnvxv
+#undef glGetTexParameteriv
+#undef glGetTexParameterxv
+#undef glHint
+#undef glIsBuffer
+#undef glIsEnabled
+#undef glIsTexture
+#undef glLightModelx
+#undef glLightModelxv
+#undef glLightx
+#undef glLightxv
+#undef glLineWidthx
+#undef glLoadIdentity
+#undef glLoadMatrixx
+#undef glLogicOp
+#undef glMaterialx
+#undef glMaterialxv
+#undef glMatrixMode
+#undef glMultMatrixx
+#undef glMultiTexCoord4x
+#undef glNormal3x
+#undef glNormalPointer
+#undef glOrthox
+#undef glPixelStorei
+#undef glPointParameterx
+#undef glPointParameterxv
+#undef glPointSizex
+#undef glPolygonOffsetx
+#undef glPopMatrix
+#undef glPushMatrix
+#undef glReadPixels
+#undef glRotatex
+#undef glSampleCoverage
+#undef glSampleCoveragex
+#undef glScalex
+#undef glScissor
+#undef glShadeModel
+#undef glStencilFunc
+#undef glStencilMask
+#undef glStencilOp
+#undef glTexCoordPointer
+#undef glTexEnvi
+#undef glTexEnvx
+#undef glTexEnviv
+#undef glTexEnvxv
+#undef glTexImage2D
+#undef glTexParameteri
+#undef glTexParameterx
+#undef glTexParameteriv
+#undef glTexParameterxv
+#undef glTexSubImage2D
+#undef glTranslatex
+#undef glVertexPointer
+#undef glViewport
+
+#undef glAttachShader
+#undef glBindAttribLocation
+#undef glBlendEquationSeparate
+#undef glBlendFuncSeparate
+#undef glCreateProgram
+#undef glCreateShader
+#undef glDeleteProgram
+#undef glDeleteShader
+#undef glDetachShader
+#undef glDisableVertexAttribArray
+#undef glEnableVertexAttribArray
+#undef glGetActiveAttrib
+#undef glGetActiveUniform
+#undef glGetAttachedShaders
+#undef glGetAttribLocation
+#undef glGetProgramiv
+#undef glGetProgramInfoLog
+#undef glGetUniformfv
+#undef glGetUniformiv
+#undef glGetUniformLocation
+#undef glGetVertexAttribfv
+#undef glGetVertexAttribiv
+#undef glGetVertexAttribPointerv
+#undef glIsProgram
+#undef glIsShader
+#undef glLinkProgram
+#undef glStencilFuncSeparate
+#undef glStencilMaskSeparate
+#undef glStencilOpSeparate
+#undef glUniform1i
+#undef glUniform2i
+#undef glUniform3i
+#undef glUniform4i
+#undef glUniform1f
+#undef glUniform2f
+#undef glUniform3f
+#undef glUniform4f
+#undef glUniform1iv
+#undef glUniform2iv
+#undef glUniform3iv
+#undef glUniform4iv
+#undef glUniform1fv
+#undef glUniform2fv
+#undef glUniform3fv
+#undef glUniform4fv
+#undef glUniformMatrix2fv
+#undef glUniformMatrix3fv
+#undef glUniformMatrix4fv
+#undef glUseProgram
+#undef glValidateProgram
+#undef glVertexAttrib1f
+#undef glVertexAttrib2f
+#undef glVertexAttrib3f
+#undef glVertexAttrib4f
+#undef glVertexAttrib1fv
+#undef glVertexAttrib2fv
+#undef glVertexAttrib3fv
+#undef glVertexAttrib4fv
+#undef glVertexAttribPointer
+#undef glCompileShader
+#undef glGetShaderiv
+#undef glGetShaderInfoLog
+#undef glGetShaderSource
+#undef glReleaseShaderCompiler
+#undef glShaderSource
+#undef glShaderBinary
+#undef glGetShaderPrecisionFormat
+#undef glIsRenderbuffer
+#undef glBindRenderbuffer
+#undef glDeleteRenderbuffers
+#undef glGenRenderbuffers
+#undef glRenderbufferStorage
+#undef glGetRenderbufferParameteriv
+#undef glIsFramebuffer
+#undef glBindFramebuffer
+#undef glDeleteFramebuffers
+#undef glGenFramebuffers
+#undef glCheckFramebufferStatus
+#undef glFramebufferTexture2D
+#undef glFramebufferRenderbuffer
+#undef glGetFramebufferAttachmentParameteriv
+#undef glGenerateMipmap
+
+#undef glPointSizePointerOES
+#undef glDiscardFramebufferEXT
+#undef glInsertEventMarkerEXT
+#undef glPushGroupMarkerEXT
+#undef glPopGroupMarkerEXT
+
+#undef glDrawTexfOES
+#undef glDrawTexfvOES
+#undef glDrawTexiOES
+#undef glDrawTexivOES
+#undef glDrawTexsOES
+#undef glDrawTexsvOES
+#undef glDrawTexxOES
+#undef glDrawTexxvOES
+
+#undef glIsRenderbufferOES
+#undef glBindRenderbufferOES
+#undef glDeleteRenderbuffersOES
+#undef glGenRenderbuffersOES
+#undef glRenderbufferStorageOES
+#undef glGetRenderbufferParameterivOES
+#undef glIsFramebufferOES
+#undef glBindFramebufferOES
+#undef glDeleteFramebuffersOES
+#undef glGenFramebuffersOES
+#undef glCheckFramebufferStatusOES
+#undef glFramebufferRenderbufferOES
+#undef glFramebufferTexture2DOES
+#undef glGetFramebufferAttachmentParameterivOES
+#undef glGenerateMipmapOES
+
+/* Internal functions */
+#undef egl_surface_create
+#undef egl_surface_from_vg_image
+#undef egl_surface_term
+#undef egl_surface_set_attrib
+#undef egl_context_create
+#undef egl_context_term
+
+#endif
+
+#if defined KHRONOS_NAME_MANGLING || defined BCG_MULTI_THREADED
+
+/* OpenVG functions */
+
+#undef vgCreateEGLImageTargetKHR
+
+#undef vgGetError
+#undef vgFlush
+#undef vgFinish
+#undef vgSetf
+#undef vgSeti
+#undef vgSetfv
+#undef vgSetiv
+#undef vgGetf
+#undef vgGeti
+#undef vgGetVectorSize
+#undef vgGetfv
+#undef vgGetiv
+#undef vgSetParameterf
+#undef vgSetParameteri
+#undef vgSetParameterfv
+#undef vgSetParameteriv
+#undef vgGetParameterf
+#undef vgGetParameteri
+#undef vgGetParameterVectorSize
+#undef vgGetParameterfv
+#undef vgGetParameteriv
+#undef vgLoadIdentity
+#undef vgLoadMatrix
+#undef vgGetMatrix
+#undef vgMultMatrix
+#undef vgTranslate
+#undef vgScale
+#undef vgShear
+#undef vgRotate
+#undef vgMask
+#undef vgRenderToMask
+#undef vgCreateMaskLayer
+#undef vgDestroyMaskLayer
+#undef vgFillMaskLayer
+#undef vgCopyMask
+#undef vgClear
+#undef vgCreatePath
+#undef vgClearPath
+#undef vgDestroyPath
+#undef vgRemovePathCapabilities
+#undef vgGetPathCapabilities
+#undef vgAppendPath
+#undef vgAppendPathData
+#undef vgModifyPathCoords
+#undef vgTransformPath
+#undef vgInterpolatePath
+#undef vgPathLength
+#undef vgPointAlongPath
+#undef vgPathBounds
+#undef vgPathTransformedBounds
+#undef vgDrawPath
+#undef vgCreatePaint
+#undef vgDestroyPaint
+#undef vgSetPaint
+#undef vgGetPaint
+#undef vgSetColor
+#undef vgGetColor
+#undef vgPaintPattern
+#undef vgCreateImage
+#undef vgDestroyImage
+#undef vgClearImage
+#undef vgImageSubData
+#undef vgGetImageSubData
+#undef vgChildImage
+#undef vgGetParent
+#undef vgCopyImage
+#undef vgDrawImage
+#undef vgSetPixels
+#undef vgWritePixels
+#undef vgGetPixels
+#undef vgReadPixels
+#undef vgCopyPixels
+#undef vgCreateFont
+#undef vgDestroyFont
+#undef vgSetGlyphToPath
+#undef vgSetGlyphToImage
+#undef vgClearGlyph
+#undef vgDrawGlyph
+#undef vgDrawGlyphs
+#undef vgColorMatrix
+#undef vgConvolve
+#undef vgSeparableConvolve
+#undef vgGaussianBlur
+#undef vgLookup
+#undef vgLookupSingle
+#undef vgHardwareQuery
+#undef vgGetString
+#undef vgCreateEGLImageTargetKHR
+
+#undef vguArc
+#undef vguComputeWarpQuadToQuad
+#undef vguComputeWarpQuadToSquare
+#undef vguComputeWarpSquareToQuad
+#undef vguEllipse
+#undef vguLine
+#undef vguPolygon
+#undef vguRect
+#undef vguRoundRect
+
+#endif   //KHRONOS_NAME_MANGLING
+#endif   //KHRONOS_MANGLED_H
diff --git a/interface/khronos/common/khrn_client_vector.c b/interface/khronos/common/khrn_client_vector.c
new file mode 100755 (executable)
index 0000000..2ef9d34
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/khronos/common/khrn_int_common.h"
+
+#include "interface/khronos/common/khrn_client_platform.h"
+#include "interface/khronos/common/khrn_client_vector.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+void khrn_vector_init(KHRN_VECTOR_T *vector, uint32_t capacity)
+{
+   vector->data = (capacity == 0) ? NULL : khrn_platform_malloc(capacity, "KHRN_VECTOR_T.data");
+   vector->capacity = vector->data ? capacity : 0;
+   vector->size = 0;
+}
+
+void khrn_vector_term(KHRN_VECTOR_T *vector)
+{
+   if (vector->data) {
+      khrn_platform_free(vector->data);
+   }
+}
+
+bool khrn_vector_extend(KHRN_VECTOR_T *vector, uint32_t size)
+{
+   uint32_t req_capacity = vector->size + size;
+   if (req_capacity > vector->capacity) {
+      uint32_t new_capacity = _max(vector->capacity + (vector->capacity >> 1), req_capacity);
+      void *new_data = khrn_platform_malloc(new_capacity, "KHRN_VECTOR_T.data");
+      if (!new_data) {
+         new_capacity = req_capacity;
+         new_data = khrn_platform_malloc(new_capacity, "KHRN_VECTOR_T.data");
+         if (!new_data) {
+            return false;
+         }
+      }
+      if (vector->data) {
+         memcpy(new_data, vector->data, vector->size);
+         khrn_platform_free(vector->data);
+      }
+      vector->data = new_data;
+      vector->capacity = new_capacity;
+   }
+   vector->size += size;
+   return true;
+}
+
+void khrn_vector_clear(KHRN_VECTOR_T *vector)
+{
+   if (vector->data) {
+      khrn_platform_free(vector->data);
+   }
+   vector->data = NULL;
+   vector->capacity = 0;
+   vector->size = 0;
+}
diff --git a/interface/khronos/common/khrn_client_vector.h b/interface/khronos/common/khrn_client_vector.h
new file mode 100755 (executable)
index 0000000..48bdc49
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_CLIENT_VECTOR_H
+#define KHRN_CLIENT_VECTOR_H
+
+typedef struct {
+   void *data;
+   uint32_t capacity;
+   uint32_t size;
+} KHRN_VECTOR_T;
+
+extern void khrn_vector_init(KHRN_VECTOR_T *vector, uint32_t capacity);
+extern void khrn_vector_term(KHRN_VECTOR_T *vector);
+
+extern bool khrn_vector_extend(KHRN_VECTOR_T *vector, uint32_t size);
+extern void khrn_vector_clear(KHRN_VECTOR_T *vector);
+
+#endif
diff --git a/interface/khronos/common/khrn_int_color.h b/interface/khronos/common/khrn_int_color.h
new file mode 100755 (executable)
index 0000000..84a4dc5
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_INT_COLOR_H
+#define KHRN_INT_COLOR_H
+
+#include "interface/khronos/common/khrn_int_util.h"
+
+extern const uint8_t COLOR_S_TO_LIN[256];
+extern const uint16_t COLOR_S_TO_LIN16[256];
+extern const uint8_t COLOR_LIN_TO_S[256];
+extern const uint8_t COLOR_LIN16_TO_S[320];
+extern const uint32_t COLOR_RECIP[256];
+
+static INLINE uint32_t color_clamp_times_256(float x)
+{
+   return (uint32_t)(_minf(_maxf(x, 0.0f), 255.0f / 256.0f) * 256.0f);
+}
+
+//Note: this will not do the same as hardware if you put NaN in.
+static INLINE uint32_t color_floats_to_rgba(float r, float g, float b, float a)
+{
+   return
+      (color_clamp_times_256(r) << 0) |
+      (color_clamp_times_256(g) << 8) |
+      (color_clamp_times_256(b) << 16) |
+      (color_clamp_times_256(a) << 24);
+}
+
+static INLINE uint32_t color_floats_to_rgba_clean(const float *color)
+{
+   return color_floats_to_rgba(clean_float(color[0]), clean_float(color[1]), clean_float(color[2]), clean_float(color[3]));
+}
+
+static INLINE void khrn_color_rgba_to_floats(float *floats, uint32_t rgba)
+{
+   floats[0] = (float)((rgba >> 0) & 0xff) * (1.0f / 255.0f);
+   floats[1] = (float)((rgba >> 8) & 0xff) * (1.0f / 255.0f);
+   floats[2] = (float)((rgba >> 16) & 0xff) * (1.0f / 255.0f);
+   floats[3] = (float)((rgba >> 24) & 0xff) * (1.0f / 255.0f);
+}
+
+extern uint32_t khrn_color_rgba_pre(uint32_t rgba);
+extern uint32_t khrn_color_rgba_unpre(uint32_t rgba);
+extern uint32_t khrn_color_rgba_rz(uint32_t rgba);
+extern uint32_t khrn_color_rgba_clamp_to_a(uint32_t rgba);
+extern uint32_t khrn_color_rgba_s_to_lin(uint32_t rgba);
+extern uint32_t khrn_color_rgba_lin_to_s(uint32_t rgba);
+extern uint32_t khrn_color_rgba_to_la_lin(uint32_t rgba);
+extern uint32_t khrn_color_rgba_to_la_s(uint32_t rgba);
+
+static INLINE uint32_t khrn_color_rgba_flip(uint32_t rgba)
+{
+   return
+      (((rgba >> 0) & 0xff) << 24) |
+      (((rgba >> 8) & 0xff) << 16) |
+      (((rgba >> 16) & 0xff) << 8) |
+      (((rgba >> 24) & 0xff) << 0);
+}
+
+extern uint32_t khrn_color_rgba_add_dither(uint32_t rgba, int r, int g, int b, int a);
+
+extern uint32_t khrn_color_rgba_transform(uint32_t rgba, const float *color_transform);
+
+#endif
diff --git a/interface/khronos/common/khrn_int_common.h b/interface/khronos/common/khrn_int_common.h
new file mode 100755 (executable)
index 0000000..4d4ff8a
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_INT_COMMON_H
+#define KHRN_INT_COMMON_H
+#ifdef __cplusplus
+extern "C" {
+#endif\
+
+#include "helpers/v3d/v3d_ver.h"
+
+#define VC_KHRN_VERSION 1
+//#define KHRN_NOT_REALLY_DUALCORE   // Use dual core codebase but switch master thread to vpu1
+//#define KHRN_SIMPLE_MULTISAMPLE
+//#define USE_CTRL_FOR_DATA
+
+//#define GLXX_FORCE_MULTISAMPLE
+
+//#define KHRN_COMMAND_MODE_DISPLAY    /* Platforms where we need to submit updates even for single-buffered surfaces */
+
+/* As BCG runs from cached memory, all allocations have to be the max of the CPU cache (calculated in the platform layer) and
+   the size of the cache line on the L3 */
+#define BCG_GCACHE_LINE_SIZE        256
+
+#ifdef _VIDEOCORE
+   #define KHRN_VECTOR_CORE            /* have a vector core for image processing operations */
+   #define KHRN_HW_KICK_POWERMAN       /* khrn_hw_kick() kicks the clock using powerman */
+#endif
+
+#if defined(SIMPENROSE) || defined(KHRN_CARBON)
+   /* for simplicity and determinism, the driver is single threaded when running
+    * on simpenrose and carbon */
+   #define KHRN_SINGLE_THREADED
+#endif
+
+#ifdef KHRN_SINGLE_THREADED
+   #define KHRN_LLAT_NO_THREAD
+   #define KHRN_WORKER_USE_LLAT
+   #define EGL_DISP_USE_LLAT
+#else
+   #if !VCOS_HAVE_RTOS
+      #define KHRN_WORKER_USE_LLAT
+   #endif
+   #define EGL_DISP_USE_LLAT
+#endif
+
+#define KHRN_LLAT_OTHER_CORE
+#ifndef V3D_LEAN
+   #define KHRN_WORKER_OTHER_CORE
+#endif
+
+#if defined(ANDROID)
+#define GL_GET_ERROR_ASYNC /* enabled with property brcm.graphics.async_errors "true" */
+#endif
+
+#if defined(ANDROID)
+#define KHDISPATCH_WORKSPACE_READAHEAD_BUFFERS 15 /* only VCHIQ */
+#else
+#define KHDISPATCH_WORKSPACE_READAHEAD_BUFFERS 0
+#endif
+#define KHDISPATCH_WORKSPACE_BUFFERS (KHDISPATCH_WORKSPACE_READAHEAD_BUFFERS + 1)
+#if defined(RPC_DIRECT) || defined(ANDROID)
+#include <limits.h>
+#define KHDISPATCH_WORKSPACE_SIZE (0x200000 / KHDISPATCH_WORKSPACE_BUFFERS)
+#else
+#define KHDISPATCH_WORKSPACE_SIZE ((1024 * 1024) / KHDISPATCH_WORKSPACE_BUFFERS) /* should be a multiple of 16, todo: how big does this need to be? (vg needs 8kB) */
+#endif
+
+#define KHDISPATCH_CTRL_THRESHOLD 2032
+/* todo: use v3d_ver.h stuff... */
+
+#ifdef __BCM2708A0__
+#define WORKAROUND_HW1297
+#define WORKAROUND_HW1451
+#define WORKAROUND_HW1632
+#define WORKAROUND_HW1637
+#define WORKAROUND_HW2038
+#define WORKAROUND_HW2136
+#define WORKAROUND_HW2187
+#define WORKAROUND_HW2366
+#define WORKAROUND_HW2384
+#define WORKAROUND_HW2422
+#define WORKAROUND_HW2479
+#define WORKAROUND_HW2487
+#define WORKAROUND_HW2488
+#define WORKAROUND_HW2522
+#define WORKAROUND_HW2781
+#define KHRN_HW_SINGLE_TEXTURE_UNIT /* Only single texture unit available */
+#endif
+#define WORKAROUND_HW2116
+#define WORKAROUND_HW2806
+#define WORKAROUND_HW2885
+#define WORKAROUND_HW2903
+#define WORKAROUND_HW2905
+#define WORKAROUND_HW2924
+#if !defined(KHRN_CARBON) /* hw-2959 fixed in latest rtl... */
+#define WORKAROUND_HW2959
+#define WORKAROUND_HW2989
+#endif
+
+#if !V3D_VER_AT_LEAST(3,0)
+#define WORKAROUND_GFXH30
+#endif
+
+#ifndef NULL
+# ifdef __cplusplus
+#  define NULL 0
+# else
+#  define NULL ((void *)0)
+# endif
+#endif
+
+#include "interface/vcos/vcos_assert.h"
+#include <string.h> /* size_t */
+
+#ifdef _MSC_VER
+#define INLINE __inline
+typedef unsigned long long uint64_t;
+#else
+#ifdef __GNUC__
+/* Just using inline doesn't work for gcc (at least on MIPS), so use the gcc attribute.
+   This gives a pretty decent performance boost */
+#define INLINE inline __attribute__((always_inline))
+#else
+#define INLINE inline
+#endif
+#endif
+
+#include "interface/vcos/vcos_stdbool.h"
+
+#ifdef NDEBUG
+   #define verify(X) X
+#else
+   #define verify(X) vcos_assert(X)
+#endif
+#define UNREACHABLE() vcos_assert(0)
+
+#ifdef _MSC_VER
+   #define UNUSED(X) X
+#else
+   #define UNUSED(X) (void)(X)
+#endif
+
+#define UNUSED_NDEBUG(X) UNUSED(X)
+
+#define KHRN_NO_SEMAPHORE 0xffffffff
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif
+
diff --git a/interface/khronos/common/khrn_int_generic_map.c b/interface/khronos/common/khrn_int_generic_map.c
new file mode 100755 (executable)
index 0000000..aad4ab1
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/khronos/common/khrn_client_platform.h"
+#include "interface/khronos/common/khrn_int_generic_map.h"
+#include "interface/khronos/common/khrn_int_util.h"
+
+#ifndef KHRN_GENERIC_MAP_CMP_VALUE
+#define KHRN_GENERIC_MAP_CMP_VALUE(x, y) (x==y)
+#endif
+
+static INLINE uint32_t hash(KHRN_GENERIC_MAP_KEY_T key, uint32_t capacity)
+{
+   return (uint32_t)key & (capacity - 1);
+}
+
+static KHRN_GENERIC_MAP(ENTRY_T) *get_entry(KHRN_GENERIC_MAP(ENTRY_T) *base, uint32_t capacity, KHRN_GENERIC_MAP_KEY_T key)
+{
+   uint32_t h = hash(key, capacity);
+   while (!KHRN_GENERIC_MAP_CMP_VALUE(base[h].value, KHRN_GENERIC_MAP_VALUE_NONE)) {
+      if (base[h].key == key) {
+         return (KHRN_GENERIC_MAP_CMP_VALUE(base[h].value, KHRN_GENERIC_MAP_VALUE_DELETED)) ? NULL : (base + h);
+      }
+      if (++h == capacity) {
+         h = 0;
+      }
+   }
+   return NULL;
+}
+
+static KHRN_GENERIC_MAP(ENTRY_T) *get_free_entry(KHRN_GENERIC_MAP(ENTRY_T) *base, uint32_t capacity, KHRN_GENERIC_MAP_KEY_T key)
+{
+   uint32_t h = hash(key, capacity);
+   while ((!KHRN_GENERIC_MAP_CMP_VALUE(base[h].value, KHRN_GENERIC_MAP_VALUE_DELETED)) && (!KHRN_GENERIC_MAP_CMP_VALUE(base[h].value, KHRN_GENERIC_MAP_VALUE_NONE))) {
+      if (++h == capacity) {
+         h = 0;
+      }
+   }
+   return base + h;
+}
+
+static bool realloc_storage(KHRN_GENERIC_MAP(T) *map, uint32_t new_capacity)
+{
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+   MEM_HANDLE_T handle = map->storage;
+   KHRN_GENERIC_MAP(ENTRY_T) *base;
+#else
+   KHRN_GENERIC_MAP(ENTRY_T) *base = map->storage;
+#endif
+   uint32_t capacity = map->capacity;
+   uint32_t i;
+
+   /*
+      new map
+   */
+
+   if (!khrn_generic_map(init)(map, new_capacity)) {
+      /* khrn_generic_map(init) fills in struct only once it is sure to succeed,
+       * so if we get here struct will be unmodified */
+      return false;
+   }
+
+   /*
+      copy entries across to new map and destroy old map
+   */
+
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+   base = (KHRN_GENERIC_MAP(ENTRY_T) *)mem_lock(handle);
+#endif
+   for (i = 0; i != capacity; ++i) {
+      if ((!KHRN_GENERIC_MAP_CMP_VALUE(base[i].value, KHRN_GENERIC_MAP_VALUE_DELETED)) && (!KHRN_GENERIC_MAP_CMP_VALUE(base[i].value, KHRN_GENERIC_MAP_VALUE_NONE))) {
+         verify(khrn_generic_map(insert)(map, base[i].key, base[i].value)); /* khrn_generic_map(insert) can only fail if the map is too small */
+#ifdef KHRN_GENERIC_MAP_RELEASE_VALUE
+         KHRN_GENERIC_MAP_RELEASE_VALUE(base[i].value); /* new reference added by khrn_generic_map(insert) */
+#endif
+      }
+   }
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+   mem_unlock(handle);
+   mem_release(handle);
+#else
+   KHRN_GENERIC_MAP_FREE(base);
+#endif
+
+   return true;
+}
+
+bool khrn_generic_map(init)(KHRN_GENERIC_MAP(T) *map, uint32_t capacity)
+{
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+   MEM_HANDLE_T handle;
+#else
+   KHRN_GENERIC_MAP(ENTRY_T) *base;
+   uint32_t i;
+#endif
+
+   /*
+      we need (capacity - 1) > (capacity / 2) and (capacity - 1) > ((3 * capacity) / 4)
+      to ensure we always have at least 1 unused slot
+
+      the smallest number that satisfies these constraints is 8 (7 > 4, 7 > 6)
+   */
+
+   vcos_assert(capacity >= 8);
+   vcos_assert(is_power_of_2(capacity)); /* hash stuff assumes this */
+
+   /*
+      alloc and clear storage
+   */
+
+   #define STRINGIZE2(X) #X
+   #define STRINGIZE(X) STRINGIZE2(X) /* X will be expanded here */
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+   handle = mem_alloc_ex(capacity * sizeof(KHRN_GENERIC_MAP(ENTRY_T)), alignof(KHRN_GENERIC_MAP(ENTRY_T)),
+      MEM_FLAG_INIT, STRINGIZE(KHRN_GENERIC_MAP(T)) ".storage", MEM_COMPACT_DISCARD); /* no term (struct containing KHRN_GENERIC_MAP(T) must call khrn_generic_map(term)()) */
+   if (handle == MEM_INVALID_HANDLE) {
+      return false;
+   }
+   /* all values already initialised to KHRN_GENERIC_MAP_VALUE_NONE */
+#else
+   base = (KHRN_GENERIC_MAP(ENTRY_T) *)KHRN_GENERIC_MAP_ALLOC(capacity * sizeof(KHRN_GENERIC_MAP(ENTRY_T)),
+      STRINGIZE(KHRN_GENERIC_MAP(T)) ".storage");
+   if (!base) {
+      return false;
+   }
+   for (i = 0; i != capacity; ++i) {
+      base[i].value = KHRN_GENERIC_MAP_VALUE_NONE;
+   }
+#endif
+   #undef STRINGIZE
+   #undef STRINGIZE2
+
+   /*
+      fill in struct (do this only once we are sure to succeed --
+      realloc_storage and khrn_generic_map(term) under gl object semantics rely
+      on this behaviour)
+   */
+
+   map->entries = 0;
+   map->deletes = 0;
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+   map->storage = handle;
+#else
+   map->storage = base;
+#endif
+   map->capacity = capacity;
+
+   return true;
+}
+
+/*
+   in KHRN_GENERIC_MAP_RELOCATABLE mode, khrn_generic_map(term) may be called:
+   - before init: map->storage will be MEM_INVALID_HANDLE.
+   - after init fails: map is unchanged.
+   - after term: map->storage will have been set back to MEM_INVALID_HANDLE.
+*/
+
+void khrn_generic_map(term)(KHRN_GENERIC_MAP(T) *map)
+{
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+   if (map->storage != MEM_INVALID_HANDLE) {
+#endif
+#ifdef KHRN_GENERIC_MAP_RELEASE_VALUE
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+      KHRN_GENERIC_MAP(ENTRY_T) *base = (KHRN_GENERIC_MAP(ENTRY_T) *)mem_lock(map->storage);
+#else
+      KHRN_GENERIC_MAP(ENTRY_T) *base = map->storage;
+#endif
+      uint32_t i;
+      for (i = 0; i != map->capacity; ++i) {
+         if ((!KHRN_GENERIC_MAP_CMP_VALUE(base[i].value, KHRN_GENERIC_MAP_VALUE_DELETED)) && (!KHRN_GENERIC_MAP_CMP_VALUE(base[i].value, KHRN_GENERIC_MAP_VALUE_NONE))) {
+            KHRN_GENERIC_MAP_RELEASE_VALUE(base[i].value);
+         }
+      }
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+      mem_unlock(map->storage);
+#endif
+#endif
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+      mem_release(map->storage);
+      map->storage = MEM_INVALID_HANDLE;
+   }
+#else
+   KHRN_GENERIC_MAP_FREE(map->storage);
+#endif
+}
+
+bool khrn_generic_map(insert)(KHRN_GENERIC_MAP(T) *map, KHRN_GENERIC_MAP_KEY_T key, KHRN_GENERIC_MAP_VALUE_T value)
+{
+   uint32_t capacity = map->capacity;
+   KHRN_GENERIC_MAP(ENTRY_T) *entry;
+
+   vcos_assert(!KHRN_GENERIC_MAP_CMP_VALUE(value, KHRN_GENERIC_MAP_VALUE_DELETED));
+   vcos_assert(!KHRN_GENERIC_MAP_CMP_VALUE(value, KHRN_GENERIC_MAP_VALUE_NONE));
+
+   entry = get_entry(
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+      (KHRN_GENERIC_MAP(ENTRY_T) *)mem_lock(map->storage),
+#else
+      map->storage,
+#endif
+      capacity, key);
+   if (entry) {
+#ifdef KHRN_GENERIC_MAP_ACQUIRE_VALUE
+      KHRN_GENERIC_MAP_ACQUIRE_VALUE(value);
+#endif
+#ifdef KHRN_GENERIC_MAP_RELEASE_VALUE
+      KHRN_GENERIC_MAP_RELEASE_VALUE(entry->value);
+#endif
+      entry->value = value;
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+      mem_unlock(map->storage);
+#endif
+   } else {
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+      mem_unlock(map->storage);
+#endif
+
+      if (map->entries > (capacity / 2)) {
+         capacity *= 2;
+         if (!realloc_storage(map, capacity)) { return false; }
+      } else if ((map->entries + map->deletes) > ((3 * capacity) / 4)) {
+         if (!realloc_storage(map, capacity)) { return false; }
+      }
+
+#ifdef KHRN_GENERIC_MAP_ACQUIRE_VALUE
+      KHRN_GENERIC_MAP_ACQUIRE_VALUE(value);
+#endif
+      entry = get_free_entry(
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+         (KHRN_GENERIC_MAP(ENTRY_T) *)mem_lock(map->storage),
+#else
+         map->storage,
+#endif
+         capacity, key);
+      if (KHRN_GENERIC_MAP_CMP_VALUE(entry->value, KHRN_GENERIC_MAP_VALUE_DELETED)) {
+         vcos_assert(map->deletes > 0);
+         --map->deletes;
+      }
+      entry->key = key;
+      entry->value = value;
+      ++map->entries;
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+      mem_unlock(map->storage);
+#endif
+   }
+
+   return true;
+}
+
+bool khrn_generic_map(delete)(KHRN_GENERIC_MAP(T) *map, KHRN_GENERIC_MAP_KEY_T key)
+{
+   KHRN_GENERIC_MAP(ENTRY_T) *entry = get_entry(
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+      (KHRN_GENERIC_MAP(ENTRY_T) *)mem_lock(map->storage),
+#else
+      map->storage,
+#endif
+      map->capacity, key);
+   if (entry) {
+#ifdef KHRN_GENERIC_MAP_RELEASE_VALUE
+      KHRN_GENERIC_MAP_RELEASE_VALUE(entry->value);
+#endif
+      entry->value = KHRN_GENERIC_MAP_VALUE_DELETED;
+      ++map->deletes;
+      vcos_assert(map->entries > 0);
+      --map->entries;
+   }
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+   mem_unlock(map->storage);
+#endif
+   return !!entry;
+}
+
+uint32_t khrn_generic_map(get_count)(KHRN_GENERIC_MAP(T) *map)
+{
+   return map->entries;
+}
+
+KHRN_GENERIC_MAP_VALUE_T khrn_generic_map(lookup)(KHRN_GENERIC_MAP(T) *map, KHRN_GENERIC_MAP_KEY_T key)
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+{
+   KHRN_GENERIC_MAP_VALUE_T value = khrn_generic_map(lookup_locked)(map, key, mem_lock(map->storage));
+   mem_unlock(map->storage);
+   return value;
+}
+
+KHRN_GENERIC_MAP_VALUE_T khrn_generic_map(lookup_locked)(KHRN_GENERIC_MAP(T) *map, KHRN_GENERIC_MAP_KEY_T key, void *storage)
+#endif
+{
+   KHRN_GENERIC_MAP(ENTRY_T) *entry = get_entry(
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+      (KHRN_GENERIC_MAP(ENTRY_T) *)storage,
+#else
+      map->storage,
+#endif
+      map->capacity, key);
+   return entry ? entry->value : KHRN_GENERIC_MAP_VALUE_NONE;
+}
+
+void khrn_generic_map(iterate)(KHRN_GENERIC_MAP(T) *map, KHRN_GENERIC_MAP(CALLBACK_T) func, void *data)
+{
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+   KHRN_GENERIC_MAP(ENTRY_T) *base = (KHRN_GENERIC_MAP(ENTRY_T) *)mem_lock(map->storage);
+#else
+   KHRN_GENERIC_MAP(ENTRY_T) *base = map->storage;
+#endif
+   uint32_t i;
+   for (i = 0; i != map->capacity; ++i) {
+      if ((!KHRN_GENERIC_MAP_CMP_VALUE(base[i].value, KHRN_GENERIC_MAP_VALUE_DELETED)) && (!KHRN_GENERIC_MAP_CMP_VALUE(base[i].value, KHRN_GENERIC_MAP_VALUE_NONE))) {
+         func(map, base[i].key, base[i].value, data);
+      }
+   }
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+   mem_unlock(map->storage);
+#endif
+}
diff --git a/interface/khronos/common/khrn_int_generic_map.h b/interface/khronos/common/khrn_int_generic_map.h
new file mode 100755 (executable)
index 0000000..66533f9
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+   #include "middleware/khronos/common/khrn_mem.h"
+#endif
+
+typedef struct {
+   KHRN_GENERIC_MAP_KEY_T key;
+   KHRN_GENERIC_MAP_VALUE_T value;
+} KHRN_GENERIC_MAP(ENTRY_T);
+
+typedef struct {
+   uint32_t entries;
+   uint32_t deletes;
+
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+   MEM_HANDLE_T storage;
+#else
+   KHRN_GENERIC_MAP(ENTRY_T) *storage;
+#endif
+   uint32_t capacity;
+} KHRN_GENERIC_MAP(T);
+
+/*
+   bool khrn_generic_map(init)(KHRN_GENERIC_MAP(T) *map, uint32_t capacity)
+
+   Initialises the map
+
+   Preconditions:
+
+   map is a valid pointer to an uninitialised KHRN_GENERIC_MAP(T) structure
+   capacity >= 8
+
+   Postconditions:
+
+   Either:
+   - true is returned and the structure that map points to is valid, or
+   - false is returned and map is still uninitialised
+*/
+
+extern bool khrn_generic_map(init)(KHRN_GENERIC_MAP(T) *map, uint32_t capacity);
+
+/*
+   void khrn_generic_map(term)(KHRN_GENERIC_MAP(T) *map)
+
+   Terminates the map
+
+   Preconditions:
+
+   map is a valid pointer to a map whose values are of type X:
+   - where type X does not imply any external references, or
+   - KHRN_GENERIC_MAP_RELEASE_VALUE releases all of these references, or
+   - the map is empty
+
+   Postconditions:
+
+   The structure map points to is uninitialised
+*/
+
+extern void khrn_generic_map(term)(KHRN_GENERIC_MAP(T) *map);
+
+/*
+   bool khrn_generic_map(insert)(KHRN_GENERIC_MAP(T) *map, KHRN_GENERIC_MAP_KEY_T key, KHRN_GENERIC_MAP_VALUE_T value)
+
+   Inserts value into map with key key. If another value is already in the map
+   with this key, the function will not fail; the new value replaces the old
+
+   Preconditions:
+
+   map is a valid pointer to a map whose values are of type X
+   value is a valid value of type X
+
+   Postconditions:
+
+   If the function succeeds:
+   - true is returned
+   - key key is now associated with value
+   otherwise:
+   - false is returned
+   - map is unchanged
+*/
+
+extern bool khrn_generic_map(insert)(KHRN_GENERIC_MAP(T) *map, KHRN_GENERIC_MAP_KEY_T key, KHRN_GENERIC_MAP_VALUE_T value);
+
+/*
+   bool khrn_generic_map(delete)(KHRN_GENERIC_MAP(T) *map, KHRN_GENERIC_MAP_KEY_T key)
+
+   If present, deletes the element identified by key from the map and returns
+   true. If not present, returns false
+
+   Preconditions:
+
+   map is a valid pointer to a map
+
+   Postconditions:
+
+   key is not present in map
+*/
+
+extern bool khrn_generic_map(delete)(KHRN_GENERIC_MAP(T) *map, KHRN_GENERIC_MAP_KEY_T key);
+
+extern uint32_t khrn_generic_map(get_count)(KHRN_GENERIC_MAP(T) *map);
+
+/*
+   KHRN_GENERIC_MAP_VALUE_T khrn_generic_map(lookup)(KHRN_GENERIC_MAP(T) *map, KHRN_GENERIC_MAP_KEY_T key)
+
+   Returns the element of the map identified by key, or
+   KHRN_GENERIC_MAP_VALUE_NONE if no such element exists in the map
+
+   Preconditions:
+
+   map is a valid pointer to a map whose elements are of type X
+
+   Postconditions:
+
+   result is either KHRN_GENERIC_MAP_VALUE_NONE or a valid value of type X
+*/
+
+extern KHRN_GENERIC_MAP_VALUE_T khrn_generic_map(lookup)(KHRN_GENERIC_MAP(T) *map, KHRN_GENERIC_MAP_KEY_T key);
+
+/*
+   KHRN_GENERIC_MAP_VALUE_T khrn_generic_map(lookup_locked)(KHRN_GENERIC_MAP(T) *map, KHRN_GENERIC_MAP_KEY_T key, void *storage)
+
+   Returns the element of the map identified by key, or
+   KHRN_GENERIC_MAP_VALUE_NONE if no such element exists in the map
+
+   Preconditions:
+
+   map is a valid pointer to a map whose elements are of type X
+   storage is the locked pointer to map->storage
+
+   Postconditions:
+
+   result is either KHRN_GENERIC_MAP_VALUE_NONE or a valid value of type X
+*/
+
+#ifdef KHRN_GENERIC_MAP_RELOCATABLE
+   extern KHRN_GENERIC_MAP_VALUE_T khrn_generic_map(lookup_locked)(KHRN_GENERIC_MAP(T) *map, KHRN_GENERIC_MAP_KEY_T key, void *storage);
+#endif
+
+/*
+   void khrn_generic_map(iterate)(KHRN_GENERIC_MAP(T) *map, KHRN_GENERIC_MAP(CALLBACK_T) func, void *data)
+
+   Runs the given callback function once for every (key, value) pair in the map.
+   Also passes data to the function
+
+   Implementation notes:
+
+   The iterator function is allowed to delete the element it is given, but not
+   modify the structure of map in any other way (eg by adding new elements)
+
+   Preconditions:
+
+   map is a valid pointer to a map of element type X
+   data, map satisfy P
+   func satisfies:
+   [
+      void func(KHRN_GENERIC_MAP(T) *map, KHRN_GENERIC_MAP_KEY_T key, KHRN_GENERIC_MAP_VALUE_T value, void *data)
+
+      Preconditions:
+
+      data, map satisfy P
+      value is of type X
+      key is a key in map
+      map[key] == value
+
+      Postconditions:
+
+      func does not alter map, except possibly by deleting the element it is given
+      value is of type Y
+   ]
+
+   Postconditions:
+
+   func has been called on every (key, value) pair in the map
+   map is a valid pointer to a map of element type Y
+*/
+
+typedef void (*KHRN_GENERIC_MAP(CALLBACK_T))(KHRN_GENERIC_MAP(T) *map, KHRN_GENERIC_MAP_KEY_T key, KHRN_GENERIC_MAP_VALUE_T value, void *);
+extern void khrn_generic_map(iterate)(KHRN_GENERIC_MAP(T) *map, KHRN_GENERIC_MAP(CALLBACK_T) func, void *);
diff --git a/interface/khronos/common/khrn_int_hash.c b/interface/khronos/common/khrn_int_hash.c
new file mode 100755 (executable)
index 0000000..cdaa4f1
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+-------------------------------------------------------------------------------
+These are functions for producing 32-bit hashes for hash table lookup.
+khrn_hashword(), khrn_hashlittle(), hashlittle2(), hashbig(), mix(), and final() 
+are externally useful functions.  Routines to test the hash are included 
+if SELF_TEST is defined.  You can use this free for any purpose.  It's in
+the public domain.  It has no warranty.
+
+You probably want to use khrn_hashlittle().  khrn_hashlittle() and hashbig()
+hash byte arrays.  khrn_hashlittle() is is faster than hashbig() on
+little-endian machines.  Intel and AMD are little-endian machines.
+On second thought, you probably want hashlittle2(), which is identical to
+khrn_hashlittle() except it returns two 32-bit hashes for the price of one.  
+You could implement hashbig2() if you wanted but I haven't bothered here.
+
+If you want to find a hash of, say, exactly 7 integers, do
+  a = i1;  b = i2;  c = i3;
+  mix(a,b,c);
+  a += i4; b += i5; c += i6;
+  mix(a,b,c);
+  a += i7;
+  final(a,b,c);
+then use c as the hash value.  If you have a variable length array of
+4-byte integers to hash, use khrn_hashword().  If you have a byte array (like
+a character string), use khrn_hashlittle().  If you have several byte arrays, or
+a mix of things, see the comments above khrn_hashlittle().  
+
+Why is this so big?  I read 12 bytes at a time into 3 4-byte integers, 
+then mix those integers.  This is fast (you can do a lot more thorough
+mixing with 12*3 instructions on 3 integers than you can with 3 instructions
+on 1 byte), but shoehorning those bytes into integers efficiently is messy.
+-------------------------------------------------------------------------------
+*/
+
+#include "interface/khronos/common/khrn_int_common.h"
+
+#include "interface/khronos/common/khrn_int_hash.h"    // get definitions of rot, mix and final
+
+# define HASH_LITTLE_ENDIAN 1
+# define HASH_BIG_ENDIAN 0
+
+#ifndef __arm__  // Use the version in khrn_int_hash_asm.s instead
+/*
+--------------------------------------------------------------------
+ This works on all machines.  To be useful, it requires
+ -- that the key be an array of uint32_t's, and
+ -- that the length be the number of uint32_t's in the key
+
+ The function khrn_hashword() is identical to khrn_hashlittle() on little-endian
+ machines, and identical to hashbig() on big-endian machines,
+ except that the length has to be measured in uint32_ts rather than in
+ bytes.  khrn_hashlittle() is more complicated than khrn_hashword() only because
+ khrn_hashlittle() has to dance around fitting the key bytes into registers.
+--------------------------------------------------------------------
+*/
+uint32_t khrn_hashword(
+const uint32_t *k,                   /* the key, an array of uint32_t values */
+int             length,               /* the length of the key, in uint32_ts */
+uint32_t        initval)         /* the previous hash, or an arbitrary value */
+{
+  uint32_t a,b,c;
+  /* Set up the internal state */
+  a = b = c = 0xdeadbeef + (((uint32_t)length)<<2) + initval;
+  /*------------------------------------------------- handle most of the key */
+  while (length > 3)
+  {
+    a += k[0];
+    b += k[1];
+    c += k[2];
+    mix(a,b,c);
+    length -= 3;
+    k += 3;
+  }
+
+  /*------------------------------------------- handle the last 3 uint32_t's */
+  switch(length)                     /* all the case statements fall through */
+  { 
+  case 3 : c+=k[2];
+  case 2 : b+=k[1];
+  case 1 : a+=k[0];
+    final(a,b,c);
+  case 0:     /* case 0: nothing left to add */
+    break;
+  }
+  /*------------------------------------------------------ report the result */
+  return c;
+}
+
+#endif
+
+/*
+-------------------------------------------------------------------------------
+khrn_hashlittle() -- hash a variable-length key into a 32-bit value
+  k       : the key (the unaligned variable-length array of bytes)
+  length  : the length of the key, counting by bytes
+  initval : can be any 4-byte value
+Returns a 32-bit value.  Every bit of the key affects every bit of
+the return value.  Two keys differing by one or two bits will have
+totally different hash values.
+
+The best hash table sizes are powers of 2.  There is no need to do
+mod a prime (mod is sooo slow!).  If you need less than 32 bits,
+use a bitmask.  For example, if you need only 10 bits, do
+  h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+
+If you are hashing n strings (uint8_t **)k, do it like this:
+  for (i=0, h=0; i<n; ++i) h = khrn_hashlittle( k[i], len[i], h);
+
+By Bob Jenkins, 2006.  bob_jenkins@burtleburtle.net.  You may use this
+code any way you wish, private, educational, or commercial.  It's free.
+
+Use for hash table lookup, or anything where one collision in 2^^32 is
+acceptable.  Do NOT use for cryptographic purposes.
+-------------------------------------------------------------------------------
+*/
+uint32_t khrn_hashlittle( const void *key, int length, uint32_t initval)
+{
+  uint32_t a,b,c;                                          /* internal state */
+  union { const void *ptr; int i; } u;                     /* needed for Mac Powerbook G4 */
+
+  /* Set up the internal state */
+  a = b = c = 0xdeadbeef + ((uint32_t)length) + initval;
+
+  u.ptr = key;
+  if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+    const uint32_t *k = (const uint32_t *)key;         /* read 32-bit chunks */
+
+    /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+    while (length > 12)
+    {
+      a += k[0];
+      b += k[1];
+      c += k[2];
+      mix(a,b,c);
+      length -= 12;
+      k += 3;
+    }
+
+    /*----------------------------- handle the last (probably partial) block */
+    /* 
+     * "k[2]&0xffffff" actually reads beyond the end of the string, but
+     * then masks off the part it's not allowed to read.  Because the
+     * string is aligned, the masked-off tail is in the same word as the
+     * rest of the string.  Every machine with memory protection I've seen
+     * does it on word boundaries, so is OK with this.  But VALGRIND will
+     * still catch it and complain.  The masking trick does make the hash
+     * noticeably faster for short strings (like English words).
+     */
+#ifndef VALGRIND
+
+    switch(length)
+    {
+    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+    case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+    case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+    case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+    case 8 : b+=k[1]; a+=k[0]; break;
+    case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+    case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+    case 5 : b+=k[1]&0xff; a+=k[0]; break;
+    case 4 : a+=k[0]; break;
+    case 3 : a+=k[0]&0xffffff; break;
+    case 2 : a+=k[0]&0xffff; break;
+    case 1 : a+=k[0]&0xff; break;
+    case 0 : return c;              /* zero length strings require no mixing */
+    }
+
+#else /* make valgrind happy */
+
+    k8 = (const uint8_t *)k;
+    switch(length)
+    {
+    case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+    case 11: c+=((uint32_t)k8[10])<<16;  /* fall through */
+    case 10: c+=((uint32_t)k8[9])<<8;    /* fall through */
+    case 9 : c+=k8[8];                   /* fall through */
+    case 8 : b+=k[1]; a+=k[0]; break;
+    case 7 : b+=((uint32_t)k8[6])<<16;   /* fall through */
+    case 6 : b+=((uint32_t)k8[5])<<8;    /* fall through */
+    case 5 : b+=k8[4];                   /* fall through */
+    case 4 : a+=k[0]; break;
+    case 3 : a+=((uint32_t)k8[2])<<16;   /* fall through */
+    case 2 : a+=((uint32_t)k8[1])<<8;    /* fall through */
+    case 1 : a+=k8[0]; break;
+    case 0 : return c;
+    }
+
+#endif /* !valgrind */
+
+  } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+    const uint16_t *k = (const uint16_t *)key;         /* read 16-bit chunks */
+    const uint8_t  *k8;
+
+    /*--------------- all but last block: aligned reads and different mixing */
+    while (length > 12)
+    {
+      a += k[0] + (((uint32_t)k[1])<<16);
+      b += k[2] + (((uint32_t)k[3])<<16);
+      c += k[4] + (((uint32_t)k[5])<<16);
+      mix(a,b,c);
+      length -= 12;
+      k += 6;
+    }
+
+    /*----------------------------- handle the last (probably partial) block */
+    k8 = (const uint8_t *)k;
+    switch(length)
+    {
+    case 12: c+=k[4]+(((uint32_t)k[5])<<16);
+             b+=k[2]+(((uint32_t)k[3])<<16);
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 11: c+=((uint32_t)k8[10])<<16;     /* fall through */
+    case 10: c+=k[4];
+             b+=k[2]+(((uint32_t)k[3])<<16);
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 9 : c+=k8[8];                      /* fall through */
+    case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 7 : b+=((uint32_t)k8[6])<<16;      /* fall through */
+    case 6 : b+=k[2];
+             a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 5 : b+=k8[4];                      /* fall through */
+    case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
+             break;
+    case 3 : a+=((uint32_t)k8[2])<<16;      /* fall through */
+    case 2 : a+=k[0];
+             break;
+    case 1 : a+=k8[0];
+             break;
+    case 0 : return c;                     /* zero length requires no mixing */
+    }
+
+  } else {                        /* need to read the key one byte at a time */
+    const uint8_t *k = (const uint8_t *)key;
+
+    /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+    while (length > 12)
+    {
+      a += k[0];
+      a += ((uint32_t)k[1])<<8;
+      a += ((uint32_t)k[2])<<16;
+      a += ((uint32_t)k[3])<<24;
+      b += k[4];
+      b += ((uint32_t)k[5])<<8;
+      b += ((uint32_t)k[6])<<16;
+      b += ((uint32_t)k[7])<<24;
+      c += k[8];
+      c += ((uint32_t)k[9])<<8;
+      c += ((uint32_t)k[10])<<16;
+      c += ((uint32_t)k[11])<<24;
+      mix(a,b,c);
+      length -= 12;
+      k += 12;
+    }
+
+    /*-------------------------------- last block: affect all 32 bits of (c) */
+    switch(length)                   /* all the case statements fall through */
+    {                                           /* Comments to pacify Coverity */
+    case 12: c+=((uint32_t)k[11])<<24;          /* fall through */
+    case 11: c+=((uint32_t)k[10])<<16;          /* fall through */
+    case 10: c+=((uint32_t)k[9])<<8;            /* fall through */
+    case 9 : c+=k[8];                           /* fall through */
+    case 8 : b+=((uint32_t)k[7])<<24;           /* fall through */
+    case 7 : b+=((uint32_t)k[6])<<16;           /* fall through */
+    case 6 : b+=((uint32_t)k[5])<<8;            /* fall through */
+    case 5 : b+=k[4];                           /* fall through */
+    case 4 : a+=((uint32_t)k[3])<<24;           /* fall through */
+    case 3 : a+=((uint32_t)k[2])<<16;           /* fall through */
+    case 2 : a+=((uint32_t)k[1])<<8;            /* fall through */
+    case 1 : a+=k[0];
+             break;
+    case 0 : return c;
+    }
+  }
+
+  final(a,b,c);
+  return c;
+}
diff --git a/interface/khronos/common/khrn_int_hash.h b/interface/khronos/common/khrn_int_hash.h
new file mode 100755 (executable)
index 0000000..5b36345
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_INT_HASH_H
+#define KHRN_INT_HASH_H
+
+/*
+-------------------------------------------------------------------------------
+These are functions for producing 32-bit hashes for hash table lookup.
+khrn_hashword(), khrn_hashlittle(), hashlittle2(), hashbig(), mix(), and final()
+are externally useful functions.  Routines to test the hash are included
+if SELF_TEST is defined.  You can use this free for any purpose.  It's in
+the public domain.  It has no warranty.
+
+You probably want to use khrn_hashlittle().  khrn_hashlittle() and hashbig()
+hash byte arrays.  khrn_hashlittle() is is faster than hashbig() on
+little-endian machines.  Intel and AMD are little-endian machines.
+On second thought, you probably want hashlittle2(), which is identical to
+khrn_hashlittle() except it returns two 32-bit hashes for the price of one.
+You could implement hashbig2() if you wanted but I haven't bothered here.
+
+If you want to find a hash of, say, exactly 7 integers, do
+  a = i1;  b = i2;  c = i3;
+  mix(a,b,c);
+  a += i4; b += i5; c += i6;
+  mix(a,b,c);
+  a += i7;
+  final(a,b,c);
+then use c as the hash value.  If you have a variable length array of
+4-byte integers to hash, use khrn_hashword().  If you have a byte array (like
+a character string), use khrn_hashlittle().  If you have several byte arrays, or
+a mix of things, see the comments above khrn_hashlittle().
+
+Why is this so big?  I read 12 bytes at a time into 3 4-byte integers,
+then mix those integers.  This is fast (you can do a lot more thorough
+mixing with 12*3 instructions on 3 integers than you can with 3 instructions
+on 1 byte), but shoehorning those bytes into integers efficiently is messy.
+-------------------------------------------------------------------------------
+*/
+
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+/*
+-------------------------------------------------------------------------------
+mix -- mix 3 32-bit values reversibly.
+
+This is reversible, so any information in (a,b,c) before mix() is
+still in (a,b,c) after mix().
+
+If four pairs of (a,b,c) inputs are run through mix(), or through
+mix() in reverse, there are at least 32 bits of the output that
+are sometimes the same for one pair and different for another pair.
+This was tested for:
+* pairs that differed by one bit, by two bits, in any combination
+  of top bits of (a,b,c), or in any combination of bottom bits of
+  (a,b,c).
+* "differ" is defined as +, -, ^, or ~^.  For + and -, I transformed
+  the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+  is commonly produced by subtraction) look like a single 1-bit
+  difference.
+* the base values were pseudorandom, all zero but one bit set, or
+  all zero plus a counter that starts at zero.
+
+Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
+satisfy this are
+    4  6  8 16 19  4
+    9 15  3 18 27 15
+   14  9  3  7 17  3
+Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
+for "differ" defined as + with a one-bit base and a two-bit delta.  I
+used http://burtleburtle.net/bob/hash/avalanche.html to choose
+the operations, constants, and arrangements of the variables.
+
+This does not achieve avalanche.  There are input bits of (a,b,c)
+that fail to affect some output bits of (a,b,c), especially of a.  The
+most thoroughly mixed value is c, but it doesn't really even achieve
+avalanche in c.
+
+This allows some parallelism.  Read-after-writes are good at doubling
+the number of bits affected, so the goal of mixing pulls in the opposite
+direction as the goal of parallelism.  I did what I could.  Rotates
+seem to cost as much as shifts on every machine I could lay my hands
+on, and rotates are much kinder to the top and bottom bits, so I used
+rotates.
+-------------------------------------------------------------------------------
+*/
+#define mix(a,b,c) \
+do { \
+  a -= c;  a ^= rot(c, 4);  c += b; \
+  b -= a;  b ^= rot(a, 6);  a += c; \
+  c -= b;  c ^= rot(b, 8);  b += a; \
+  a -= c;  a ^= rot(c,16);  c += b; \
+  b -= a;  b ^= rot(a,19);  a += c; \
+  c -= b;  c ^= rot(b, 4);  b += a; \
+} while (0)
+
+/*
+-------------------------------------------------------------------------------
+final -- final mixing of 3 32-bit values (a,b,c) into c
+
+Pairs of (a,b,c) values differing in only a few bits will usually
+produce values of c that look totally different.  This was tested for
+* pairs that differed by one bit, by two bits, in any combination
+  of top bits of (a,b,c), or in any combination of bottom bits of
+  (a,b,c).
+* "differ" is defined as +, -, ^, or ~^.  For + and -, I transformed
+  the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+  is commonly produced by subtraction) look like a single 1-bit
+  difference.
+* the base values were pseudorandom, all zero but one bit set, or
+  all zero plus a counter that starts at zero.
+
+These constants passed:
+ 14 11 25 16 4 14 24
+ 12 14 25 16 4 14 24
+and these came close:
+  4  8 15 26 3 22 24
+ 10  8 15 26 3 22 24
+ 11  8 15 26 3 22 24
+-------------------------------------------------------------------------------
+*/
+#define final(a,b,c) \
+do { \
+  c ^= b; c -= rot(b,14); \
+  a ^= c; a -= rot(c,11); \
+  b ^= a; b -= rot(a,25); \
+  c ^= b; c -= rot(b,16); \
+  a ^= c; a -= rot(c,4);  \
+  b ^= a; b -= rot(a,14); \
+  c ^= b; c -= rot(b,24); \
+} while (0)
+
+uint32_t khrn_hashword(const uint32_t *key, int length, uint32_t initval);
+uint32_t khrn_hashlittle(const void *key, int length, uint32_t initval);
+
+#endif
+
diff --git a/interface/khronos/common/khrn_int_hash_asm.s b/interface/khronos/common/khrn_int_hash_asm.s
new file mode 100755 (executable)
index 0000000..e882a34
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+Copyright (c) 2013, Raspberry Pi Foundation
+Copyright (c) 2013, RISC OS Open Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+/* Prevent the stack from becoming executable */
+#if defined(__linux__) && defined(__ELF__)
+.section .note.GNU-stack,"",%progbits
+#endif
+
+    .text
+    .arch armv6
+    .object_arch armv4
+    .arm
+    .altmacro
+    .p2align 2
+
+.macro myfunc fname
+ .func fname
+ .global fname
+ /* For ELF format also set function visibility to hidden */
+#ifdef __ELF__
+ .hidden fname
+ .type fname, %function
+#endif
+fname:
+.endm
+
+.macro hashmix A, B, C
+        sub     A, A, C
+        eor     A, A, C, ror #32-4
+        add     C, C, B
+        sub     B, B, A
+        eor     B, B, A, ror #32-6
+        add     A, A, C
+        sub     C, C, B
+        eor     C, C, B, ror #32-8
+        add     B, B, A
+        sub     A, A, C
+        eor     A, A, C, ror #32-16
+        add     C, C, B
+        sub     B, B, A
+        eor     B, B, A, ror #32-19
+        add     A, A, C
+        sub     C, C, B
+        eor     C, C, B, ror #32-4
+        add     B, B, A
+.endm
+
+.macro hashfinal A, B, C
+        eor     C, C, B
+        sub     C, C, B, ror #32-14
+        eor     A, A, C
+        sub     A, A, C, ror #32-11
+        eor     B, B, A
+        sub     B, B, A, ror #32-25
+        eor     C, C, B
+        sub     C, C, B, ror #32-16
+        eor     A, A, C
+        sub     A, A, C, ror #32-4
+        eor     B, B, A
+        sub     B, B, A, ror #32-14
+        eor     C, C, B
+        sub     C, C, B, ror #32-24
+.endm
+
+/*
+ * uint32_t khrn_hashword(const uint32_t *k, int length, uint32_t initval);
+ * On entry:
+ * a1 = pointer to buffer
+ * a2 = number of 32-bit words
+ * a3 = seed
+ * On exit:
+ * a1 = hash value
+ */
+
+.set prefetch_distance, 2
+
+myfunc khrn_hashword
+        S       .req    a1
+        N       .req    a2
+        AA      .req    a3
+        BB      .req    a4
+        CC      .req    v1
+        DAT0    .req    v2
+        DAT1    .req    ip
+        DAT2    .req    lr
+
+        ldr     BB, =0xDEADBEEF
+        push    {CC, DAT0, lr}
+        add     AA, AA, N, lsl #2
+        add     AA, AA, BB
+        mov     BB, AA
+        mov     CC, AA
+
+        /* To preload ahead as we go, we need at least (prefetch_distance+2) 32-byte blocks */
+        cmp     N, #(prefetch_distance+2)*32/4
+        blo     170f
+
+        /* Long case */
+        /* Adjust N to simplify inner loop termination. We want it to
+         * stop when there are (prefetch_distance+1) complete cache
+         * lines to go. */
+        sub     N, N, #(prefetch_distance+2)*32/4
+        bic     DAT0, S, #31
+ .set OFFSET, 0
+ .rept prefetch_distance+1
+        pld     [DAT0, #OFFSET]
+  .set OFFSET, OFFSET+32
+ .endr
+        and     DAT1, S, #0x1C
+        cmp     DAT1, #0x0C
+        bhs     156f
+154:    /* Now at first complete triple-word within cacheline, with at
+         * least one prefetch to go (but no prefetch required until we
+         * have processed at least 2 triple-words) */
+        ldmia   S!, {DAT0, DAT1, DAT2}
+        sub     N, N, #12/4
+        add     AA, AA, DAT0
+        add     BB, BB, DAT1
+        add     CC, CC, DAT2
+        hashmix AA, BB, CC
+156:    ldmia   S!, {DAT0, DAT1, DAT2}
+        sub     N, N, #12/4
+        add     AA, AA, DAT0
+        add     BB, BB, DAT1
+        add     CC, CC, DAT2
+        hashmix AA, BB, CC
+        tst     S, #0x10
+        bne     156b
+        bic     DAT0, S, #0x1F
+        and     DAT1, S, #0x1F
+        pld     [DAT0, #prefetch_distance*32]
+        adds    DAT1, N, DAT1, lsr #2
+        bpl     154b
+        /* Just before the final (prefetch_distance+1) 32-byte blocks,
+         * deal with final preload */
+        cmp     DAT1, #-32/4
+        beq     157f
+        pld     [DAT0, #(prefetch_distance+1)*32]
+157:    add     N, N, #(prefetch_distance+2)*32/4 - 1 - 3
+158:    ldmia   S!, {DAT0, DAT1, DAT2}
+        add     AA, AA, DAT0
+        add     BB, BB, DAT1
+        add     CC, CC, DAT2
+        hashmix AA, BB, CC
+        subs    N, N, #3
+        bhs     158b
+        cmp     N, #-2
+        ldr     DAT0, [S], #4
+        ldrhs   DAT1, [S], #4
+        ldrhi   DAT2, [S], #4
+        add     AA, AA, DAT0
+        addhs   BB, BB, DAT1
+        addhi   CC, CC, DAT2
+        hashfinal AA, BB, CC
+        mov     a1, CC
+        pop     {CC, DAT0, pc}
+
+170:    /* Short case */
+        cmp     N, #1
+        blo     199f
+        bic     DAT0, S, #31
+        pld     [DAT0]
+        add     DAT1, S, N, lsl #2
+        sub     DAT1, DAT1, #1
+        bic     DAT1, DAT1, #31
+        cmp     DAT1, DAT0
+        beq     92f
+91:     add     DAT0, DAT0, #32
+        cmp     DAT0, DAT1
+        pld     [DAT0]
+        bne     91b
+92:     sub     N, N, #1
+        b       176f
+175:    ldmia   S!, {DAT0, DAT1, DAT2}
+        add     AA, AA, DAT0
+        add     BB, BB, DAT1
+        add     CC, CC, DAT2
+        hashmix AA, BB, CC
+176:    subs    N, N, #3
+        bhs     175b
+        cmp     N, #-2
+        ldr     DAT0, [S], #4
+        ldrhs   DAT1, [S], #4
+        ldrhi   DAT2, [S], #4
+        add     AA, AA, DAT0
+        addhs   BB, BB, DAT1
+        addhi   CC, CC, DAT2
+        hashfinal AA, BB, CC
+199:    mov     a1, CC
+        pop     {CC, DAT0, pc}
+
+        .unreq  S
+        .unreq  N
+        .unreq  AA
+        .unreq  BB
+        .unreq  CC
+        .unreq  DAT0
+        .unreq  DAT1
+        .unreq  DAT2
+.endfunc
+
+.ltorg
+
diff --git a/interface/khronos/common/khrn_int_ids.h b/interface/khronos/common/khrn_int_ids.h
new file mode 100755 (executable)
index 0000000..8378f4a
--- /dev/null
@@ -0,0 +1,440 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_INT_IDS_H
+#define KHRN_INT_IDS_H
+
+/*
+   dispatch class ids
+*/
+
+#define GLBASE_ID_11                   0x1000
+#define GLBASE_ID_20                   0x2000
+#define VGBASE_ID                      0x3000
+#define EGLBASE_ID                     0x4000
+
+#define KHRNMISC_ID                    0x6000
+#define GLBASE_ID                      0x7000
+
+#define GET_BASE_ID(x)                 ((x) & 0xf000)
+
+/*
+   common OpenGL ES 1.1 and 2.0 dispatch ids
+*/
+
+#define GLACTIVETEXTURE_ID                       0x7001
+#define GLBINDBUFFER_ID                          0x7002
+#define GLBINDTEXTURE_ID                         0x7003
+#define GLBUFFERDATA_ID                          0x7004
+#define GLBUFFERSUBDATA_ID                       0x7005
+#define GLCLEAR_ID                               0x7006
+#define GLCLEARCOLOR_ID                          0x7007
+#define GLCLEARDEPTHF_ID                         0x7008
+#define GLCLEARSTENCIL_ID                        0x700a
+#define GLCOLORMASK_ID                           0x700b
+#define GLCOMPRESSEDTEXIMAGE2D_ID                0x700c
+#define GLCOMPRESSEDTEXSUBIMAGE2D_ID             0x700d
+#define GLCOPYTEXIMAGE2D_ID                      0x700e
+#define GLCOPYTEXSUBIMAGE2D_ID                   0x700f
+#define GLCULLFACE_ID                            0x7010
+#define GLDELETEBUFFERS_ID                       0x7011
+#define GLDELETETEXTURES_ID                      0x7012
+#define GLDEPTHFUNC_ID                           0x7013
+#define GLDEPTHMASK_ID                           0x7014
+#define GLDEPTHRANGEF_ID                         0x7015
+#define GLDISABLE_ID                             0x7016
+#define GLINTDRAWELEMENTS_ID                     0x7018
+#define GLENABLE_ID                              0x701a
+#define GLFINISH_ID                              0x701b
+#define GLFLUSH_ID                               0x701c
+#define GLFRONTFACE_ID                           0x701d
+#define GLGENBUFFERS_ID                          0x701e
+#define GLGENTEXTURES_ID                         0x701f
+#define GLGETBOOLEANV_ID                         0x7020
+#define GLGETBUFFERPARAMETERIV_ID                0x7021
+#define GLGETERROR_ID                            0x7022
+#define GLGETFLOATV_ID                           0x7023
+#define GLGETINTEGERV_ID                         0x7024
+#define GLGETTEXPARAMETERFV_ID                   0x7025
+#define GLGETTEXPARAMETERIV_ID                   0x7026
+#define GLHINT_ID                                0x7027
+#define GLISBUFFER_ID                            0x7028
+#define GLISENABLED_ID                           0x702a
+#define GLISTEXTURE_ID                           0x702b
+#define GLLINEWIDTH_ID                           0x702c
+#define GLPOLYGONOFFSET_ID                       0x702d
+#define GLREADPIXELS_ID                          0x702e
+#define GLSAMPLECOVERAGE_ID                      0x702f
+#define GLSCISSOR_ID                             0x7030
+#define GLTEXIMAGE2D_ID                          0x7031
+#define GLTEXPARAMETERF_ID                       0x7032
+#define GLTEXPARAMETERI_ID                       0x7033
+#define GLTEXSUBIMAGE2D_ID                       0x7034
+#define GLVIEWPORT_ID                            0x7035
+#define GLINTFINDMAX_ID                          0x7036
+#define GLINTCACHECREATE_ID                      0x7037
+#define GLINTCACHEDELETE_ID                      0x7038
+#define GLINTCACHEDATA_ID                        0x703a
+#define GLINTCACHEGROW_ID                        0x703b
+#define GLINTCACHEUSE_ID                         0x708c
+#define GLBLENDFUNCSEPARATE_ID                   0x708d
+#define GLSTENCILFUNCSEPARATE_ID                 0x708e
+#define GLSTENCILMASKSEPARATE_ID                 0x708f
+#define GLSTENCILOPSEPARATE_ID                   0x7090
+#define GLEGLIMAGETARGETTEXTURE2DOES_ID          0x7091 /* GL_OES_EGL_image */
+#define GLGLOBALIMAGETEXTURE2DOES_ID             0x7092 /* GL_OES_EGL_image/EGL_BRCM_global_image */
+#define GLDISCARDFRAMEBUFFEREXT_ID               0x7100
+/* GL_OES_framebuffer_object */
+#define GLISRENDERBUFFER_ID                      0x7101
+#define GLBINDRENDERBUFFER_ID                    0x7102
+#define GLDELETERENDERBUFFERS_ID                 0x7103
+#define GLGENRENDERBUFFERS_ID                    0x7104
+#define GLRENDERBUFFERSTORAGE_ID                 0x7105
+#define GLGETRENDERBUFFERPARAMETERIV_ID          0x7106
+#define GLISFRAMEBUFFER_ID                       0x7107
+#define GLBINDFRAMEBUFFER_ID                     0x7108
+#define GLDELETEFRAMEBUFFERS_ID                  0x7109
+#define GLGENFRAMEBUFFERS_ID                     0x710a
+#define GLCHECKFRAMEBUFFERSTATUS_ID              0x710b
+#define GLFRAMEBUFFERTEXTURE2D_ID                0x710c
+#define GLFRAMEBUFFERRENDERBUFFER_ID             0x710d
+#define GLGETFRAMEBUFFERATTACHMENTPARAMETERIV_ID 0x710e
+#define GLGENERATEMIPMAP_ID                      0x710f
+#define GLTEXPARAMETERFV_ID                      0x7110
+#define GLTEXPARAMETERIV_ID                      0x7111
+#define GLINSERTEVENTMARKEREXT_ID                0x7112
+#define GLPUSHGROUPMARKEREXT_ID                  0x7113
+#define GLPOPGROUPMARKEREXT_ID                   0x7114
+#define TEXSUBIMAGE2DASYNC_ID                    0x7115
+#define GLPIXELSTOREI_ID                         0x7116
+#define GLINTATTRIBPOINTER_ID                    0x7117
+#define GLINTATTRIB_ID                           0x7118
+#define GLINTATTRIBENABLE_ID                     0x7119
+
+
+/*
+   OpenGL ES 1.1 specific dispatch ids
+*/
+#define GLALPHAFUNC_ID_11                 0x1001
+#define GLALPHAFUNCX_ID_11                0x1002
+#define GLCLEARCOLORX_ID_11               0x1004
+#define GLCLEARDEPTHX_ID_11               0x1005
+#define GLCLIPPLANEF_ID_11                0x1006
+#define GLCLIPPLANEX_ID_11                0x1007
+//#define GLCOLORPOINTER_ID_11              0x1008
+#define GLCLIENTACTIVETEXTURE_ID_11       0x1009
+#define GLDEPTHRANGEX_ID_11               0x100a
+#define GLFOGF_ID_11                      0x100b
+#define GLFOGX_ID_11                      0x100c
+#define GLFOGFV_ID_11                     0x100d
+#define GLFOGXV_ID_11                     0x100e
+#define GLFRUSTUMF_ID_11                  0x100f
+#define GLFRUSTUMX_ID_11                  0x1020
+#define GLGETCLIPPLANEF_ID_11             0x1021
+#define GLGETCLIPPLANEX_ID_11             0x1022
+#define GLGETFIXEDV_ID_11                 0x1023
+#define GLGETLIGHTFV_ID_11                0x1024
+#define GLGETLIGHTXV_ID_11                0x1025
+#define GLGETMATERIALFV_ID_11             0x1026
+#define GLGETMATERIALXV_ID_11             0x1027
+#define GLGETTEXENVFV_ID_11               0x1028
+#define GLGETTEXENVIV_ID_11               0x102a
+#define GLGETTEXENVXV_ID_11               0x102b
+#define GLGETTEXPARAMETERXV_ID_11         0x102c
+#define GLLIGHTF_ID_11                    0x102d
+#define GLLIGHTX_ID_11                    0x102e
+#define GLLIGHTFV_ID_11                   0x102f
+#define GLLIGHTXV_ID_11                   0x1030
+#define GLLIGHTMODELF_ID_11               0x1031
+#define GLLIGHTMODELX_ID_11               0x1032
+#define GLLIGHTMODELFV_ID_11              0x1033
+#define GLLIGHTMODELXV_ID_11              0x1034
+#define GLLINEWIDTHX_ID_11                0x1035
+#define GLLOADIDENTITY_ID_11              0x1036
+#define GLLOADMATRIXF_ID_11               0x1037
+#define GLLOADMATRIXX_ID_11               0x1038
+#define GLLOGICOP_ID_11                   0x103a
+#define GLMATERIALF_ID_11                 0x103b
+#define GLMATERIALX_ID_11                 0x103c
+#define GLMATERIALFV_ID_11                0x103d
+#define GLMATERIALXV_ID_11                0x103e
+#define GLMATRIXMODE_ID_11                0x103f
+#define GLMULTMATRIXF_ID_11               0x1040
+#define GLMULTMATRIXX_ID_11               0x1041
+//#define GLNORMALPOINTER_ID_11             0x1042
+#define GLORTHOF_ID_11                    0x1043
+#define GLORTHOX_ID_11                    0x1044
+//#define GLPIXELSTOREI_ID_11               0x1045
+#define GLPOINTPARAMETERF_ID_11           0x1046
+#define GLPOINTPARAMETERX_ID_11           0x1047
+#define GLPOINTPARAMETERFV_ID_11          0x1048
+#define GLPOINTPARAMETERXV_ID_11          0x104a
+#define GLPOLYGONOFFSETX_ID_11            0x104b
+#define GLPOPMATRIX_ID_11                 0x104c
+#define GLPUSHMATRIX_ID_11                0x104d
+#define GLROTATEF_ID_11                   0x104e
+#define GLROTATEX_ID_11                   0x104f
+#define GLSAMPLECOVERAGEX_ID_11           0x1050
+#define GLSCALEF_ID_11                    0x1051
+#define GLSCALEX_ID_11                    0x1052
+#define GLSHADEMODEL_ID_11                0x1053
+#define GLTEXENVF_ID_11                   0x1057
+#define GLTEXENVI_ID_11                   0x1058
+#define GLTEXENVX_ID_11                   0x105a
+#define GLTEXENVFV_ID_11                  0x105b
+#define GLTEXENVIV_ID_11                  0x105c
+#define GLTEXENVXV_ID_11                  0x105d
+#define GLTEXPARAMETERX_ID_11             0x105e
+#define GLTRANSLATEF_ID_11                0x105f
+#define GLTRANSLATEX_ID_11                0x1060
+//#define GLTEXCOORDPOINTER_ID_11           0x1061
+//#define GLVERTEXPOINTER_ID_11             0x1062
+
+//#define GLPOINTSIZEPOINTEROES_ID_11       0x1063
+#define GLINTCOLOR_ID_11                  0x1064
+#define GLQUERYMATRIXXOES_ID_11           0x1065
+#define GLTEXPARAMETERXV_ID_11            0x1067
+#define GLDRAWTEXFOES_ID_11               0x1068
+
+#define GLCURRENTPALETTEMATRIXOES_ID_11   0x1069               /* GL_OES_matrix_palette */
+#define GLLOADPALETTEFROMMODELVIEWMATRIXOES_ID_11     0x1070   /* GL_OES_matrix_palette */
+//#define GLMATRIXINDEXPOINTEROES_ID_11     0x1071               /* GL_OES_matrix_palette */
+//#define GLWEIGHTPOINTEROES_ID_11          0x1072               /* GL_OES_matrix_palette */
+
+/*
+   OpenGL ES 2.0 dispatch ids
+*/
+#define GLATTACHSHADER_ID_20                             0x2001
+#define GLBINDATTRIBLOCATION_ID_20                       0x2002
+#define GLBLENDCOLOR_ID_20                               0x2005
+#define GLBLENDEQUATIONSEPARATE_ID_20                    0x2006
+#define GLCOMPILESHADER_ID_20                            0x200a
+#define GLCREATEPROGRAM_ID_20                            0x200b
+#define GLCREATESHADER_ID_20                             0x200c
+#define GLDELETEPROGRAM_ID_20                            0x200e
+#define GLDELETESHADER_ID_20                             0x2010
+#define GLDETACHSHADER_ID_20                             0x2011
+#define GLGETATTRIBLOCATION_ID_20                        0x2017
+#define GLGETACTIVEATTRIB_ID_20                          0x2018
+#define GLGETACTIVEUNIFORM_ID_20                         0x201a
+#define GLGETATTACHEDSHADERS_ID_20                       0x201b
+#define GLGETPROGRAMIV_ID_20                             0x201d
+#define GLGETPROGRAMINFOLOG_ID_20                        0x201e
+#define GLGETSHADERIV_ID_20                              0x2020
+#define GLGETSHADERINFOLOG_ID_20                         0x2021
+#define GLGETSHADERSOURCE_ID_20                          0x2022
+#define GLGETSHADERPRECISIONFORMAT_ID_20                 0x2023
+#define GLGETUNIFORMFV_ID_20                             0x2024
+#define GLGETUNIFORMIV_ID_20                             0x2025
+#define GLGETUNIFORMLOCATION_ID_20                       0x2026
+#define GLISPROGRAM_ID_20                                0x2028
+#define GLISSHADER_ID_20                                 0x202b
+#define GLLINKPROGRAM_ID_20                              0x202c
+//#define GLPIXELSTOREI_ID_20                              0x202d
+#define GLPOINTSIZE_ID_20                                0x202e
+#define GLSHADERSOURCE_ID_20                             0x2030
+#define GLTEXPARAMETERIV_ID_20                           0x2034
+#define GLUNIFORM1F_ID_20                                0x2035
+#define GLUNIFORM2F_ID_20                                0x2036
+#define GLUNIFORM3F_ID_20                                0x2037
+#define GLUNIFORM4F_ID_20                                0x2038
+#define GLUNIFORM1I_ID_20                                0x203a
+#define GLUNIFORM2I_ID_20                                0x203b
+#define GLUNIFORM3I_ID_20                                0x203c
+#define GLUNIFORM4I_ID_20                                0x203d
+#define GLUNIFORM1FV_ID_20                               0x203e
+#define GLUNIFORM2FV_ID_20                               0x203f
+#define GLUNIFORM3FV_ID_20                               0x2040
+#define GLUNIFORM4FV_ID_20                               0x2041
+#define GLUNIFORM1IV_ID_20                               0x2042
+#define GLUNIFORM2IV_ID_20                               0x2043
+#define GLUNIFORM3IV_ID_20                               0x2044
+#define GLUNIFORM4IV_ID_20                               0x2045
+#define GLUNIFORMMATRIX2FV_ID_20                         0x2046
+#define GLUNIFORMMATRIX3FV_ID_20                         0x2047
+#define GLUNIFORMMATRIX4FV_ID_20                         0x2048
+#define GLUSEPROGRAM_ID_20                               0x204a
+#define GLVALIDATEPROGRAM_ID_20                          0x204b
+//#define GLVERTEXATTRIBPOINTER_ID_20                      0x204c
+#define GLEGLIMAGETARGETRENDERBUFFERSTORAGEOES_ID_20     0x204d /* GL_OES_EGL_image */
+#define GLGLOBALIMAGERENDERBUFFERSTORAGEOES_ID_20        0x204e /* GL_OES_EGL_image/EGL_BRCM_global_image */
+
+/*
+   OpenVG dispatch ids
+*/
+
+#define VGCLEARERROR_ID                      0x3000
+#define VGSETERROR_ID                        0x3001
+#define VGGETERROR_ID                        0x3002
+#define VGFLUSH_ID                           0x3003
+#define VGFINISH_ID                          0x3004
+#define VGCREATESTEMS_ID                     0x3005
+#define VGDESTROYSTEM_ID                     0x3006
+#define VGSETIV_ID                           0x3007
+#define VGSETFV_ID                           0x3008
+#define VGGETFV_ID                           0x3009
+#define VGSETPARAMETERIV_ID                  0x300a
+#define VGSETPARAMETERFV_ID                  0x300b
+#define VGGETPARAMETERIV_ID                  0x300c
+#define VGLOADMATRIX_ID                      0x300d
+#define VGMASK_ID                            0x300e
+#define VGRENDERTOMASK_ID                    0x300f /* vg 1.1 */
+#define VGCREATEMASKLAYER_ID                 0x3010 /* vg 1.1 */
+#define VGDESTROYMASKLAYER_ID                0x3011 /* vg 1.1 */
+#define VGFILLMASKLAYER_ID                   0x3012 /* vg 1.1 */
+#define VGCOPYMASK_ID                        0x3013 /* vg 1.1 */
+#define VGCLEAR_ID                           0x3014
+#define VGCREATEPATH_ID                      0x3015
+#define VGCLEARPATH_ID                       0x3016
+#define VGDESTROYPATH_ID                     0x3017
+#define VGREMOVEPATHCAPABILITIES_ID          0x3018
+#define VGAPPENDPATH_ID                      0x3019
+#define VGAPPENDPATHDATA_ID                  0x301a
+#define VGMODIFYPATHCOORDS_ID                0x301b
+#define VGTRANSFORMPATH_ID                   0x301c
+#define VGINTERPOLATEPATH_ID                 0x301d
+#define VGPATHLENGTH_ID                      0x301e
+#define VGPOINTALONGPATH_ID                  0x301f
+#define VGPATHBOUNDS_ID                      0x3020
+#define VGPATHTRANSFORMEDBOUNDS_ID           0x3021
+#define VGDRAWPATH_ID                        0x3022
+#define VGCREATEPAINT_ID                     0x3023
+#define VGDESTROYPAINT_ID                    0x3024
+#define VGSETPAINT_ID                        0x3025
+#define VGPAINTPATTERN_ID                    0x3026
+#define VGCREATEIMAGE_ID                     0x3027
+#define VGDESTROYIMAGE_ID                    0x3028
+#define VGCLEARIMAGE_ID                      0x3029
+#define VGIMAGESUBDATA_ID                    0x302a
+#define VGGETIMAGESUBDATA_ID                 0x302b
+#define VGCHILDIMAGE_ID                      0x302c
+#define VGGETPARENT_ID                       0x302d
+#define VGCOPYIMAGE_ID                       0x302e
+#define VGDRAWIMAGE_ID                       0x302f
+#define VGSETPIXELS_ID                       0x3030
+#define VGWRITEPIXELS_ID                     0x3031
+#define VGGETPIXELS_ID                       0x3032
+#define VGREADPIXELS_ID                      0x3033
+#define VGCOPYPIXELS_ID                      0x3034
+#define VGCREATEFONT_ID                      0x3035 /* vg 1.1 */
+#define VGDESTROYFONT_ID                     0x3036 /* vg 1.1 */
+#define VGSETGLYPHTOPATH_ID                  0x3037 /* vg 1.1 */
+#define VGSETGLYPHTOIMAGE_ID                 0x3038 /* vg 1.1 */
+#define VGCLEARGLYPH_ID                      0x3039 /* vg 1.1 */
+#define VGDRAWGLYPH_ID                       0x303a /* vg 1.1 */
+#define VGDRAWGLYPHS_ID                      0x303b /* vg 1.1 */
+#define VGCOLORMATRIX_ID                     0x303c
+#define VGCONVOLVE_ID                        0x303d
+#define VGSEPARABLECONVOLVE_ID               0x303e
+#define VGGAUSSIANBLUR_ID                    0x303f
+#define VGLOOKUP_ID                          0x3040
+#define VGLOOKUPSINGLE_ID                    0x3041
+#define VGULINE_ID                           0x3042 /* vgu */
+#define VGUPOLYGON_ID                        0x3043 /* vgu */
+#define VGURECT_ID                           0x3044 /* vgu */
+#define VGUROUNDRECT_ID                      0x3045 /* vgu */
+#define VGUELLIPSE_ID                        0x3046 /* vgu */
+#define VGUARC_ID                            0x3047 /* vgu */
+#define VGCREATEEGLIMAGETARGETKHR_ID         0x3048 /* VG_KHR_EGL_image */
+#define VGCREATEIMAGEFROMGLOBALIMAGE_ID      0x3049 /* VG_KHR_EGL_image/EGL_BRCM_global_image */
+
+/*
+   EGL dispatch ids
+*/
+
+#define EGLINTCREATESURFACE_ID            0x4000
+#define EGLINTCREATEGLES11_ID             0x4001
+#define EGLINTCREATEGLES20_ID             0x4002
+#define EGLINTCREATEVG_ID                 0x4003
+#define EGLINTDESTROYSURFACE_ID           0x4004
+#define EGLINTDESTROYGL_ID                0x4005
+#define EGLINTDESTROYVG_ID                0x4006
+/*#define EGLINTRESIZESURFACE_ID            0x4007*/
+#define EGLINTMAKECURRENT_ID              0x4008
+#define EGLINTFLUSHANDWAIT_ID             0x4009
+#define EGLINTSWAPBUFFERS_ID              0x400a
+#define EGLINTSELECTMIPMAP_ID             0x400b
+#define EGLINTFLUSH_ID                    0x400c
+#define EGLINTGETCOLORDATA_ID             0x400d
+#define EGLINTSETCOLORDATA_ID             0x400e
+#define EGLINTBINDTEXIMAGE_ID             0x400f
+#define EGLINTRELEASETEXIMAGE_ID          0x4010
+#define EGLINTCREATEPBUFFERFROMVGIMAGE_ID 0x4011
+#define EGLINTCREATEWRAPPEDSURFACE_ID     0x4012
+#define EGLCREATEIMAGEKHR_ID              0x4013 /* EGL_KHR_image */
+#define EGLDESTROYIMAGEKHR_ID             0x4014 /* EGL_KHR_image */
+#define EGLINTOPENMAXILDONEMARKER_ID      0x4015 /* EGL-OpenMAX interworking (Broadcom-specific) */
+#define EGLINTSWAPINTERVAL_ID             0x4016
+#define EGLINTGETPROCESSMEMUSAGE_ID       0x4017 /* EGL_BRCM_mem_usage */
+#define EGLINTGETGLOBALMEMUSAGE_ID        0x4018
+#define EGLCREATEGLOBALIMAGEBRCM_ID       0x4019 /* EGL_BRCM_global_image */
+#define EGLFILLGLOBALIMAGEBRCM_ID         0x401a /* EGL_BRCM_global_image */
+#define EGLCREATECOPYGLOBALIMAGEBRCM_ID   0x401b /* EGL_BRCM_global_image */
+#define EGLDESTROYGLOBALIMAGEBRCM_ID      0x401c /* EGL_BRCM_global_image */
+#define EGLQUERYGLOBALIMAGEBRCM_ID        0x401d /* EGL_BRCM_global_image */
+#define EGLINTCREATESYNC_ID               0x401e /* EGL_KHR_fence_sync */
+#define EGLINTDESTROYSYNC_ID              0x401f /* EGL_KHR_fence_sync */
+#define EGLINITPERFMONITORBRCM_ID         0x4020 /* EGL_BRCM_perf_monitor */
+#define EGLTERMPERFMONITORBRCM_ID         0x4021 /* EGL_BRCM_perf_monitor */
+#define EGLINTDESTROYBYPID_ID             0x4022
+#define EGLINTIMAGESETCOLORDATA_ID        0x4023 /* EGL_KHR_image (client-side pixmaps etc.) */
+#define EGLPERFSTATSRESETBRCM_ID          0x4024 /* EGL_BRCM_perf_stats */
+#define EGLPERFSTATSGETBRCM_ID            0x4025 /* EGL_BRCM_perf_stats */
+#define EGLINTCREATEENDPOINTIMAGE_ID      0x4026 /* EGL_NOK_image_endpoint */
+#define EGLINTDESTROYENDPOINTIMAGE_ID     0x4027 /* EGL_NOK_image_endpoint */
+#define EGLINTACQUIREENDPOINTIMAGE_ID     0x4028 /* EGL_NOK_image_endpoint */
+#define EGLINITDRIVERMONITORBRCM_ID       0x4029 /* EGL_BRCM_driver_monitor */
+#define EGLTERMDRIVERMONITORBRCM_ID       0x402a /* EGL_BRCM_driver_monitor */
+#define EGLGETDRIVERMONITORXMLBRCM_ID     0x402b /* EGL_BRCM_driver_monitor */
+#define EGLDIRECTRENDERINGPOINTER_ID      0x402c /* DIRECT_RENDERING */
+#define EGLPUSHRENDERINGIMAGE_ID          0x402d /* Android GL App supportN */
+#define EGLINTUPDATETEXTURE_ID            0x402e /* Android GL App supportN */
+#define EGLINTCREATESYNCFENCE_ID          0x402f /* EGL_KHR_fence_sync */
+
+/*
+   Miscellaneous driver control functions (not related to any particular API)
+*/
+
+#define KHRNMISCTRYUNLOAD_ID           0x6000
+#define KHRNMISCBULKRXREQUIRED_ID      0x6001 /* bulk transfer client->server advance notifier */
+
+/*
+   signalling length used to indicate a NULL argument
+*/
+
+#define LENGTH_SIGNAL_NULL             0xffffffff
+
+/*
+   async (KHAN) channel commands
+*/
+
+#define ASYNC_COMMAND_WAIT    0
+#define ASYNC_COMMAND_POST    1
+#define ASYNC_COMMAND_DESTROY 2
+#define ASYNC_RENDER_COMPLETE 3
+#define ASYNC_ERROR_NOTIFY    4
+#endif
diff --git a/interface/khronos/common/khrn_int_image.c b/interface/khronos/common/khrn_int_image.c
new file mode 100755 (executable)
index 0000000..9852339
--- /dev/null
@@ -0,0 +1,299 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/khronos/common/khrn_int_common.h"
+
+#include "interface/khronos/common/khrn_int_image.h"
+#include "interface/khronos/common/khrn_int_util.h"
+
+/******************************************************************************
+formats
+******************************************************************************/
+
+uint32_t khrn_image_get_bpp(KHRN_IMAGE_FORMAT_T format)
+{
+   vcos_assert(format != IMAGE_FORMAT_INVALID);
+
+   switch (format & IMAGE_FORMAT_COMP_MASK) {
+   case IMAGE_FORMAT_UNCOMP:
+      switch (format & IMAGE_FORMAT_PIXEL_SIZE_MASK) {
+         case IMAGE_FORMAT_1:  return 1;
+         case IMAGE_FORMAT_4:  return 4;
+         case IMAGE_FORMAT_8:  return 8;
+         case IMAGE_FORMAT_16: return 16;
+         case IMAGE_FORMAT_24: return 24;
+         case IMAGE_FORMAT_32: return 32;
+         case IMAGE_FORMAT_64: return 64;
+         default:              UNREACHABLE(); return 0;
+      }
+   case IMAGE_FORMAT_ETC1: return 4;
+   case IMAGE_FORMAT_YUYV: return 16;
+   default:                UNREACHABLE(); return 0;
+   }
+}
+
+/*
+   returns the number of red bits in each pixel of an image of the
+   specified format, or zero if not an RGB or RGBA format
+*/
+
+uint32_t khrn_image_get_red_size(KHRN_IMAGE_FORMAT_T format)
+{
+   if (khrn_image_is_color(format) && (format & IMAGE_FORMAT_RGB)) {
+      switch (format & (IMAGE_FORMAT_PIXEL_SIZE_MASK | IMAGE_FORMAT_PIXEL_LAYOUT_MASK)) {
+      case (IMAGE_FORMAT_32 | IMAGE_FORMAT_8888): return 8;
+      case (IMAGE_FORMAT_24 | IMAGE_FORMAT_888):  return 8;
+      case (IMAGE_FORMAT_16 | IMAGE_FORMAT_4444): return 4;
+      case (IMAGE_FORMAT_16 | IMAGE_FORMAT_5551): return 5;
+      case (IMAGE_FORMAT_16 | IMAGE_FORMAT_565):  return 5;
+      default:                                    UNREACHABLE(); return 0;
+      }
+   } else {
+      return 0;
+   }
+}
+
+/*
+   returns the number of green bits in each pixel of an image of the
+   specified format, or zero if not an RGB or RGBA format
+*/
+
+uint32_t khrn_image_get_green_size(KHRN_IMAGE_FORMAT_T format)
+{
+   if (khrn_image_is_color(format) && (format & IMAGE_FORMAT_RGB)) {
+      switch (format & (IMAGE_FORMAT_PIXEL_SIZE_MASK | IMAGE_FORMAT_PIXEL_LAYOUT_MASK)) {
+      case (IMAGE_FORMAT_32 | IMAGE_FORMAT_8888): return 8;
+      case (IMAGE_FORMAT_24 | IMAGE_FORMAT_888):  return 8;
+      case (IMAGE_FORMAT_16 | IMAGE_FORMAT_4444): return 4;
+      case (IMAGE_FORMAT_16 | IMAGE_FORMAT_5551): return 5;
+      case (IMAGE_FORMAT_16 | IMAGE_FORMAT_565):  return 6;
+      default:                                    UNREACHABLE(); return 0;
+      }
+   } else {
+      return 0;
+   }
+}
+
+/*
+   returns the number of blue bits in each pixel of an image of the
+   specified format, or zero if not an RGB or RGBA format
+*/
+
+uint32_t khrn_image_get_blue_size(KHRN_IMAGE_FORMAT_T format)
+{
+   if (khrn_image_is_color(format) && (format & IMAGE_FORMAT_RGB)) {
+      switch (format & (IMAGE_FORMAT_PIXEL_SIZE_MASK | IMAGE_FORMAT_PIXEL_LAYOUT_MASK)) {
+      case (IMAGE_FORMAT_32 | IMAGE_FORMAT_8888): return 8;
+      case (IMAGE_FORMAT_24 | IMAGE_FORMAT_888):  return 8;
+      case (IMAGE_FORMAT_16 | IMAGE_FORMAT_4444): return 4;
+      case (IMAGE_FORMAT_16 | IMAGE_FORMAT_5551): return 5;
+      case (IMAGE_FORMAT_16 | IMAGE_FORMAT_565):  return 5;
+      default:                                    UNREACHABLE(); return 0;
+      }
+   } else {
+      return 0;
+   }
+}
+
+/*
+   returns the number of alpha bits in each pixel of an image of the
+   specified format, or zero if not an alpha or RGBA format
+*/
+
+uint32_t khrn_image_get_alpha_size(KHRN_IMAGE_FORMAT_T format)
+{
+   if (khrn_image_is_color(format) && (format & IMAGE_FORMAT_A)) {
+      switch (format & (IMAGE_FORMAT_PIXEL_SIZE_MASK | IMAGE_FORMAT_PIXEL_LAYOUT_MASK)) {
+      case (IMAGE_FORMAT_32 | IMAGE_FORMAT_8888): return 8;
+      case (IMAGE_FORMAT_16 | IMAGE_FORMAT_4444): return 4;
+      case (IMAGE_FORMAT_16 | IMAGE_FORMAT_5551): return 1;
+      case (IMAGE_FORMAT_16 | IMAGE_FORMAT_88):   return 8;
+      case IMAGE_FORMAT_8:                        return 8;
+      case IMAGE_FORMAT_4:                        return 4;
+      case IMAGE_FORMAT_1:                        return 1;
+      default:                                    UNREACHABLE(); return 0;
+      }
+   } else {
+      return 0;
+   }
+}
+
+/*
+   returns the number of depth bits in each pixel of an image of the
+   specified format, or zero if not a depth or depth+stencil format
+*/
+
+uint32_t khrn_image_get_z_size(KHRN_IMAGE_FORMAT_T format)
+{
+   if (khrn_image_is_depth(format) && (format & IMAGE_FORMAT_Z)) {
+      if (format == DEPTH_32_TLBD || format == DEPTH_COL_64_TLBD)
+         return 24;
+      switch (format & IMAGE_FORMAT_PIXEL_SIZE_MASK) {
+      case IMAGE_FORMAT_32: return 24;
+      case IMAGE_FORMAT_16: return 16;
+      default:              UNREACHABLE(); return 0;
+      }
+   } else {
+      return 0;
+   }
+}
+
+/*
+   returns the number of stencil bits in each pixel of an image of the
+   specified format, or zero if not a depth+stencil format
+*/
+
+uint32_t khrn_image_get_stencil_size(KHRN_IMAGE_FORMAT_T format)
+{
+   if (khrn_image_is_depth(format) && (format & IMAGE_FORMAT_STENCIL)) {
+      if (format == DEPTH_32_TLBD || format == DEPTH_COL_64_TLBD)
+         return 8;
+      vcos_assert((format & IMAGE_FORMAT_PIXEL_SIZE_MASK) == IMAGE_FORMAT_32);
+      return 8;
+   } else {
+      return 0;
+   }
+}
+
+uint32_t khrn_image_get_log2_brcm2_width(KHRN_IMAGE_FORMAT_T format)
+{
+   vcos_assert(khrn_image_is_brcm1(format) || khrn_image_is_brcm2(format));
+
+   switch (format & IMAGE_FORMAT_COMP_MASK) {
+   case IMAGE_FORMAT_UNCOMP:
+   {
+      switch (format & IMAGE_FORMAT_PIXEL_SIZE_MASK) {
+      case IMAGE_FORMAT_1:  return 6;
+      case IMAGE_FORMAT_4:  return 4;
+      case IMAGE_FORMAT_8:  return 3;
+      case IMAGE_FORMAT_16: return 3;
+      case IMAGE_FORMAT_32: return 2;
+      default:              UNREACHABLE(); return 0;
+      }
+   }
+   case IMAGE_FORMAT_ETC1: return 3;
+   case IMAGE_FORMAT_YUYV: return 3;
+   default:                UNREACHABLE(); return 0;
+   }
+}
+
+uint32_t khrn_image_get_log2_brcm2_height(KHRN_IMAGE_FORMAT_T format)
+{
+   vcos_assert(khrn_image_is_brcm1(format) || khrn_image_is_brcm2(format));
+
+   switch (format & IMAGE_FORMAT_COMP_MASK) {
+   case IMAGE_FORMAT_UNCOMP:
+   {
+      switch (format & IMAGE_FORMAT_PIXEL_SIZE_MASK) {
+      case IMAGE_FORMAT_1:  return 3;
+      case IMAGE_FORMAT_4:  return 3;
+      case IMAGE_FORMAT_8:  return 3;
+      case IMAGE_FORMAT_16: return 2;
+      case IMAGE_FORMAT_32: return 2;
+      default:              UNREACHABLE(); return 0;
+      }
+   }
+   case IMAGE_FORMAT_ETC1: return 4;
+   case IMAGE_FORMAT_YUYV: return 2;
+   default:                UNREACHABLE(); return 0;
+   }
+}
+
+uint32_t khrn_image_get_log2_brcm1_width(KHRN_IMAGE_FORMAT_T format)
+{
+   return khrn_image_get_log2_brcm2_width(format) + 3;
+}
+
+uint32_t khrn_image_get_log2_brcm1_height(KHRN_IMAGE_FORMAT_T format)
+{
+   return khrn_image_get_log2_brcm2_height(format) + 3;
+}
+
+/******************************************************************************
+image handling
+******************************************************************************/
+
+uint32_t khrn_image_pad_width(KHRN_IMAGE_FORMAT_T format, uint32_t width)
+{
+   vcos_assert(format != IMAGE_FORMAT_INVALID);
+
+   switch (format & IMAGE_FORMAT_MEM_LAYOUT_MASK) {
+   case IMAGE_FORMAT_RSO:
+      vcos_assert(!(khrn_image_get_bpp(format) & 7));
+      return width;
+   case IMAGE_FORMAT_BRCM1:  return round_up(width, (uint32_t) (1 << khrn_image_get_log2_brcm1_width(format)));
+   case IMAGE_FORMAT_BRCM2:  return round_up(width, (uint32_t) (1 << khrn_image_get_log2_brcm2_width(format)));
+   case IMAGE_FORMAT_BRCM4: return round_up(width, 64);
+   default:               UNREACHABLE(); return 0;
+   }
+}
+
+uint32_t khrn_image_pad_height(KHRN_IMAGE_FORMAT_T format, uint32_t height)
+{
+   vcos_assert(format != IMAGE_FORMAT_INVALID);
+
+   switch (format & IMAGE_FORMAT_MEM_LAYOUT_MASK) {
+   case IMAGE_FORMAT_RSO: return height;
+   case IMAGE_FORMAT_BRCM1:  return round_up(height, (uint32_t) (1 << khrn_image_get_log2_brcm1_height(format)));
+   case IMAGE_FORMAT_BRCM2:  return round_up(height, (uint32_t) (1 << khrn_image_get_log2_brcm2_height(format)));
+   case IMAGE_FORMAT_BRCM4: return round_up(height, 64);
+   default:               UNREACHABLE(); return 0;
+   }
+}
+
+uint32_t khrn_image_get_stride(KHRN_IMAGE_FORMAT_T format, uint32_t width)
+{
+   return (khrn_image_pad_width(format, width) * khrn_image_get_bpp(format)) >> 3;
+}
+
+uint32_t khrn_image_get_size(KHRN_IMAGE_FORMAT_T format, uint32_t width, uint32_t height)
+{
+   uint32_t size = khrn_image_get_stride(format, width) * khrn_image_pad_height(format, height);
+#ifdef WORKAROUND_HW2038
+   if (khrn_image_is_brcm1(format) || khrn_image_is_brcm2(format)) {
+      uint32_t log2_brcm2_width = khrn_image_get_log2_brcm2_width(format);
+      uint32_t log2_brcm2_height = khrn_image_get_log2_brcm2_height(format);
+      uint32_t width_in_brcm2s = (width + ((1 << log2_brcm2_width) - 1)) >> log2_brcm2_width;
+      uint32_t height_in_brcm2s = (height + ((1 << log2_brcm2_height) - 1)) >> log2_brcm2_height;
+      uint32_t hw2038_size =
+         ((((height_in_brcm2s - 1) >> 3) << 7) +
+         ((width_in_brcm2s - 1) >> 3) + 1) << 6;
+      size = _max(size, hw2038_size);
+   } /* else: can't bind it as a texture */
+#endif
+   return size;
+}
+
+void khrn_image_wrap(KHRN_IMAGE_WRAP_T *wrap, KHRN_IMAGE_FORMAT_T format, uint32_t width, uint32_t height, int32_t stride, void *storage)
+{
+   wrap->format = format;
+   wrap->width = (uint16_t)width;
+   wrap->height = (uint16_t)height;
+   wrap->stride = stride;
+   wrap->aux = NULL;
+   wrap->storage = storage;
+}
diff --git a/interface/khronos/common/khrn_int_image.h b/interface/khronos/common/khrn_int_image.h
new file mode 100755 (executable)
index 0000000..de0f7cc
--- /dev/null
@@ -0,0 +1,383 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_INT_IMAGE_H
+#define KHRN_INT_IMAGE_H
+
+#include "interface/khronos/common/khrn_int_util.h"
+
+/******************************************************************************
+formats
+******************************************************************************/
+
+typedef enum {
+   /*
+      layout of KHRN_IMAGE_FORMAT_T bits
+
+      When changing this, remember to change
+      middleware/khronos/common/2708/khrn_image_4.inc too
+   */
+
+   IMAGE_FORMAT_MEM_LAYOUT_MASK = 0x7 << 0,
+   IMAGE_FORMAT_MEM_LAYOUT_SHIFT = 0,
+   IMAGE_FORMAT_MEM_LAYOUT_BC = 3,
+
+   IMAGE_FORMAT_RSO   = 0 << 0, /* raster scan order */
+   IMAGE_FORMAT_BRCM1    = 1 << 0,
+   IMAGE_FORMAT_BRCM2    = 2 << 0,
+   IMAGE_FORMAT_BRCM3 = 3 << 0,
+   IMAGE_FORMAT_BRCM4 = 4 << 0,
+
+   IMAGE_FORMAT_COMP_MASK = 0x3 << 6,
+
+   IMAGE_FORMAT_UNCOMP      = 0 << 6,
+   IMAGE_FORMAT_ETC1        = 1 << 6,
+   IMAGE_FORMAT_YUYV        = 3 << 6,
+
+   /* uncomp */
+
+   IMAGE_FORMAT_PIXEL_SIZE_MASK = 0x7 << 3,
+   IMAGE_FORMAT_PIXEL_SIZE_SHIFT = 3,
+
+   IMAGE_FORMAT_1  = 0 << 3,
+   IMAGE_FORMAT_4  = 1 << 3,
+   IMAGE_FORMAT_8  = 2 << 3,
+   IMAGE_FORMAT_16 = 3 << 3,
+   IMAGE_FORMAT_24 = 4 << 3,
+   IMAGE_FORMAT_32 = 5 << 3,
+   IMAGE_FORMAT_64 = 6 << 3,
+
+   IMAGE_FORMAT_PIXEL_TYPE_MASK = 0x3 << 8,
+
+   IMAGE_FORMAT_COLOR   = 0 << 8,
+   IMAGE_FORMAT_PALETTE = 1 << 8,
+   IMAGE_FORMAT_SAMPLE  = 2 << 8,
+   IMAGE_FORMAT_DEPTH   = 3 << 8, /* packed z and stencil */
+
+   /* uncomp, color */
+
+   IMAGE_FORMAT_RGB = 1 << 10,
+   IMAGE_FORMAT_L   = 1 << 11,
+   IMAGE_FORMAT_A   = 1 << 12,
+
+   IMAGE_FORMAT_XBGRX = 0 << 13, /* r in low bits */
+   IMAGE_FORMAT_XRGBX = 1 << 13, /* r in high bits */
+
+   IMAGE_FORMAT_YUYV_STD = 0 << 13, /* Standard ordering */
+   IMAGE_FORMAT_YUYV_REV = 1 << 13, /* Reversed (UYVY) ordering */
+
+   IMAGE_FORMAT_AX = 0 << 14, /* alpha/x in high bits */
+   IMAGE_FORMAT_XA = 1 << 14, /* alpha/x in low bits */
+
+   IMAGE_FORMAT_PIXEL_LAYOUT_MASK = 0x7 << 15,
+
+   /* pixel size used to differentiate between eg 4444 and 8888 */
+   /* unspecified (0) means one channel occupying entire pixel */
+   /* IMAGE_FORMAT_32 */
+   IMAGE_FORMAT_8888 = 1 << 15,
+   /* IMAGE_FORMAT_24 */
+   IMAGE_FORMAT_888  = 1 << 15,
+   /* IMAGE_FORMAT_16 */
+   IMAGE_FORMAT_4444 = 1 << 15,
+   IMAGE_FORMAT_5551 = 2 << 15, /* (or 1555) */
+   IMAGE_FORMAT_565  = 3 << 15,
+   IMAGE_FORMAT_88   = 4 << 15,
+
+   IMAGE_FORMAT_PRE = 1 << 18, /* premultiplied (for vg) */
+   IMAGE_FORMAT_LIN = 1 << 19, /* linear (for vg) */
+
+   /* uncomp, depth */
+
+   IMAGE_FORMAT_Z       = 1 << 10,
+   IMAGE_FORMAT_STENCIL = 1 << 11,
+
+   /*
+      some IMAGE_FORMAT_Ts
+
+      Components are listed with the most significant bits first.
+      
+      On little-endian systems, it is as if a pixel was loaded as a little-endian
+      integer. This means they are in the *opposite* order to how they appear in memory (e.g. in ABGR_8888
+      format, the first byte would be the red component of the first pixel).
+
+      On big-endian systems, it is as if a pixel was loaded as a big-endian integer.
+      This means that the components are written in the same order that they appear in
+      memory (e.g. in ABGR_8888 format, the first byte would be alpha).
+   */
+
+   #define IMAGE_FORMAT_PACK(A, B, C, D, E, F, G, H, I) \
+      (IMAGE_FORMAT_##A | IMAGE_FORMAT_##B | IMAGE_FORMAT_##C | IMAGE_FORMAT_##D | IMAGE_FORMAT_##E | \
+      IMAGE_FORMAT_##F | IMAGE_FORMAT_##G | IMAGE_FORMAT_##H | IMAGE_FORMAT_##I)
+   #define IMAGE_FORMAT__ 0
+
+   RGBA_8888 = IMAGE_FORMAT_PACK(_, UNCOMP, 32, COLOR  , RGB, A, XRGBX, XA, 8888),
+   BGRA_8888 = IMAGE_FORMAT_PACK(_, UNCOMP, 32, COLOR  , RGB, A, XBGRX, XA, 8888),
+   ARGB_8888 = IMAGE_FORMAT_PACK(_, UNCOMP, 32, COLOR  , RGB, A, XRGBX, AX, 8888),
+   ABGR_8888 = IMAGE_FORMAT_PACK(_, UNCOMP, 32, COLOR  , RGB, A, XBGRX, AX, 8888),
+   RGBX_8888 = IMAGE_FORMAT_PACK(_, UNCOMP, 32, COLOR  , RGB, _, XRGBX, XA, 8888),
+   BGRX_8888 = IMAGE_FORMAT_PACK(_, UNCOMP, 32, COLOR  , RGB, _, XBGRX, XA, 8888),
+   XRGB_8888 = IMAGE_FORMAT_PACK(_, UNCOMP, 32, COLOR  , RGB, _, XRGBX, AX, 8888),
+   XBGR_8888 = IMAGE_FORMAT_PACK(_, UNCOMP, 32, COLOR  , RGB, _, XBGRX, AX, 8888),
+   RGB_888   = IMAGE_FORMAT_PACK(_, UNCOMP, 24, COLOR  , RGB, _, XRGBX, _ , 888 ),
+   BGR_888   = IMAGE_FORMAT_PACK(_, UNCOMP, 24, COLOR  , RGB, _, XBGRX, _ , 888 ),
+   RGBA_4444 = IMAGE_FORMAT_PACK(_, UNCOMP, 16, COLOR  , RGB, A, XRGBX, XA, 4444),
+   BGRA_4444 = IMAGE_FORMAT_PACK(_, UNCOMP, 16, COLOR  , RGB, A, XBGRX, XA, 4444),
+   ARGB_4444 = IMAGE_FORMAT_PACK(_, UNCOMP, 16, COLOR  , RGB, A, XRGBX, AX, 4444),
+   ABGR_4444 = IMAGE_FORMAT_PACK(_, UNCOMP, 16, COLOR  , RGB, A, XBGRX, AX, 4444),
+   RGBA_5551 = IMAGE_FORMAT_PACK(_, UNCOMP, 16, COLOR  , RGB, A, XRGBX, XA, 5551),
+   BGRA_5551 = IMAGE_FORMAT_PACK(_, UNCOMP, 16, COLOR  , RGB, A, XBGRX, XA, 5551),
+   ARGB_1555 = IMAGE_FORMAT_PACK(_, UNCOMP, 16, COLOR  , RGB, A, XRGBX, AX, 5551),
+   ABGR_1555 = IMAGE_FORMAT_PACK(_, UNCOMP, 16, COLOR  , RGB, A, XBGRX, AX, 5551),
+   RGB_565   = IMAGE_FORMAT_PACK(_, UNCOMP, 16, COLOR  , RGB, _, XRGBX, _ , 565 ),
+   BGR_565   = IMAGE_FORMAT_PACK(_, UNCOMP, 16, COLOR  , RGB, _, XBGRX, _ , 565 ),
+   LA_88     = IMAGE_FORMAT_PACK(_, UNCOMP, 16, COLOR  , L  , A, _    , XA, 88  ),
+   AL_88     = IMAGE_FORMAT_PACK(_, UNCOMP, 16, COLOR  , L  , A, _    , AX, 88  ),
+   L_8       = IMAGE_FORMAT_PACK(_, UNCOMP, 8 , COLOR  , L  , _, _    , _ , _   ),
+   L_1       = IMAGE_FORMAT_PACK(_, UNCOMP, 1 , COLOR  , L  , _, _    , _ , _   ),
+   A_8       = IMAGE_FORMAT_PACK(_, UNCOMP, 8 , COLOR  , _  , A, _    , _ , _   ),
+   A_4       = IMAGE_FORMAT_PACK(_, UNCOMP, 4 , COLOR  , _  , A, _    , _ , _   ),
+   A_1       = IMAGE_FORMAT_PACK(_, UNCOMP, 1 , COLOR  , _  , A, _    , _ , _   ),
+   PALETTE_4 = IMAGE_FORMAT_PACK(_, UNCOMP, 4 , PALETTE, _  , _, _    , _ , _   ),
+   SAMPLE_16 = IMAGE_FORMAT_PACK(_, UNCOMP, 16, SAMPLE , _  , _, _    , _ , _   ),
+   SAMPLE_8  = IMAGE_FORMAT_PACK(_, UNCOMP, 8 , SAMPLE , _  , _, _    , _ , _   ),
+   DEPTH_32  = IMAGE_FORMAT_PACK(_, UNCOMP, 32, DEPTH  , Z, STENCIL, _, _ , _   ),
+   DEPTH_16  = IMAGE_FORMAT_PACK(_, UNCOMP, 16, DEPTH  , Z, _      , _, _ , _   ),
+   ETC1      = IMAGE_FORMAT_PACK(_, ETC1  , _ , _      , _  , _, _    , _ , _   ),
+   DEPTH_64  = IMAGE_FORMAT_PACK(_, UNCOMP, 64, DEPTH  , Z, STENCIL, _, _ , _   ),
+   YUV_422     = IMAGE_FORMAT_PACK(_, YUYV  , _ , _      , _  , _, YUYV_STD , _ , _   ),
+   YUV_422_REV = IMAGE_FORMAT_PACK(_, YUYV  , _ , _      , _  , _, YUYV_REV , _ , _   ),
+
+   #undef IMAGE_FORMAT__
+   #undef IMAGE_FORMAT_PACK
+
+   /* texture unit formats */
+   ABGR_8888_TF = ABGR_8888 | IMAGE_FORMAT_BRCM1,
+   ARGB_8888_TF = ARGB_8888 | IMAGE_FORMAT_BRCM1,
+   RGBA_8888_TF = RGBA_8888 | IMAGE_FORMAT_BRCM1,
+   XBGR_8888_TF = XBGR_8888 | IMAGE_FORMAT_BRCM1,
+   XRGB_8888_TF = XRGB_8888 | IMAGE_FORMAT_BRCM1,
+   RGBX_8888_TF = RGBX_8888 | IMAGE_FORMAT_BRCM1,
+   RGBA_4444_TF = RGBA_4444 | IMAGE_FORMAT_BRCM1,
+   RGBA_5551_TF = RGBA_5551 | IMAGE_FORMAT_BRCM1,
+   RGB_565_TF   = RGB_565   | IMAGE_FORMAT_BRCM1,
+   BGR_565_TF   = BGR_565   | IMAGE_FORMAT_BRCM1,
+   L_8_TF       = L_8       | IMAGE_FORMAT_BRCM1,
+   A_8_TF       = A_8       | IMAGE_FORMAT_BRCM1,
+   AL_88_TF     = AL_88     | IMAGE_FORMAT_BRCM1,
+   LA_88_TF     = LA_88     | IMAGE_FORMAT_BRCM1,
+   ETC1_TF      = ETC1      | IMAGE_FORMAT_BRCM1,
+   PALETTE_4_TF = PALETTE_4 | IMAGE_FORMAT_BRCM1,
+   SAMPLE_8_TF  = SAMPLE_8  | IMAGE_FORMAT_BRCM1,
+   SAMPLE_16_TF = SAMPLE_16 | IMAGE_FORMAT_BRCM1,
+   L_1_TF       = L_1       | IMAGE_FORMAT_BRCM1,
+   A_4_TF       = A_4       | IMAGE_FORMAT_BRCM1,
+   A_1_TF       = A_1       | IMAGE_FORMAT_BRCM1,
+   DEPTH_16_TF  = DEPTH_16  | IMAGE_FORMAT_BRCM1,
+   DEPTH_32_TF  = DEPTH_32  | IMAGE_FORMAT_BRCM1,
+
+   /* their linear T equivalents */
+   ABGR_8888_LT = ABGR_8888 | IMAGE_FORMAT_BRCM2,
+   ARGB_8888_LT = ARGB_8888 | IMAGE_FORMAT_BRCM2,
+   RGBA_8888_LT = RGBA_8888 | IMAGE_FORMAT_BRCM2,
+   XBGR_8888_LT = XBGR_8888 | IMAGE_FORMAT_BRCM2,
+   XRGB_8888_LT = XRGB_8888 | IMAGE_FORMAT_BRCM2,
+   RGBX_8888_LT = RGBX_8888 | IMAGE_FORMAT_BRCM2,
+   RGBA_4444_LT = RGBA_4444 | IMAGE_FORMAT_BRCM2,
+   RGBA_5551_LT = RGBA_5551 | IMAGE_FORMAT_BRCM2,
+   RGB_565_LT   = RGB_565   | IMAGE_FORMAT_BRCM2,
+   L_8_LT       = L_8       | IMAGE_FORMAT_BRCM2,
+   A_8_LT       = A_8       | IMAGE_FORMAT_BRCM2,
+   AL_88_LT     = AL_88     | IMAGE_FORMAT_BRCM2,
+   LA_88_LT     = LA_88     | IMAGE_FORMAT_BRCM2,
+   ETC1_LT      = ETC1      | IMAGE_FORMAT_BRCM2,
+   PALETTE_4_LT = PALETTE_4 | IMAGE_FORMAT_BRCM2,
+   SAMPLE_8_LT  = SAMPLE_8  | IMAGE_FORMAT_BRCM2,
+   SAMPLE_16_LT = SAMPLE_16 | IMAGE_FORMAT_BRCM2,
+   L_1_LT       = L_1       | IMAGE_FORMAT_BRCM2,
+   A_4_LT       = A_4       | IMAGE_FORMAT_BRCM2,
+   A_1_LT       = A_1       | IMAGE_FORMAT_BRCM2,
+   DEPTH_16_LT  = DEPTH_16  | IMAGE_FORMAT_BRCM2,
+   DEPTH_32_LT  = DEPTH_32  | IMAGE_FORMAT_BRCM2,
+
+   /* some raster order formats */
+   RGBA_8888_RSO = RGBA_8888 | IMAGE_FORMAT_RSO,
+   BGRA_8888_RSO = BGRA_8888 | IMAGE_FORMAT_RSO,
+   ARGB_8888_RSO = ARGB_8888 | IMAGE_FORMAT_RSO,
+   ABGR_8888_RSO = ABGR_8888 | IMAGE_FORMAT_RSO,
+   RGBX_8888_RSO = RGBX_8888 | IMAGE_FORMAT_RSO,
+   BGRX_8888_RSO = BGRX_8888 | IMAGE_FORMAT_RSO,
+   XRGB_8888_RSO = XRGB_8888 | IMAGE_FORMAT_RSO,
+   XBGR_8888_RSO = XBGR_8888 | IMAGE_FORMAT_RSO,
+   BGR_888_RSO   = BGR_888   | IMAGE_FORMAT_RSO,
+   RGB_888_RSO   = RGB_888   | IMAGE_FORMAT_RSO,
+   RGBA_4444_RSO = RGBA_4444 | IMAGE_FORMAT_RSO,
+   BGRA_4444_RSO = BGRA_4444 | IMAGE_FORMAT_RSO,
+   ARGB_4444_RSO = ARGB_4444 | IMAGE_FORMAT_RSO,
+   ABGR_4444_RSO = ABGR_4444 | IMAGE_FORMAT_RSO,
+   RGBA_5551_RSO = RGBA_5551 | IMAGE_FORMAT_RSO,
+   BGRA_5551_RSO = BGRA_5551 | IMAGE_FORMAT_RSO,
+   ARGB_1555_RSO = ARGB_1555 | IMAGE_FORMAT_RSO,
+   ABGR_1555_RSO = ABGR_1555 | IMAGE_FORMAT_RSO,
+   RGB_565_RSO   = RGB_565   | IMAGE_FORMAT_RSO,
+   BGR_565_RSO   = BGR_565   | IMAGE_FORMAT_RSO,
+   AL_88_RSO     = AL_88     | IMAGE_FORMAT_RSO,
+   LA_88_RSO     = LA_88     | IMAGE_FORMAT_RSO,
+   L_8_RSO       = L_8       | IMAGE_FORMAT_RSO,
+   L_1_RSO       = L_1       | IMAGE_FORMAT_RSO,
+   A_8_RSO       = A_8       | IMAGE_FORMAT_RSO,
+   A_4_RSO       = A_4       | IMAGE_FORMAT_RSO,
+   A_1_RSO       = A_1       | IMAGE_FORMAT_RSO,
+
+   YUV_422_RSO     = YUV_422     | IMAGE_FORMAT_RSO,
+   YUV_422_REV_RSO = YUV_422_REV | IMAGE_FORMAT_RSO,
+
+   ARGB_8888_PRE = ARGB_8888 | IMAGE_FORMAT_PRE,
+
+   /* TLB dump formats */
+   DEPTH_32_TLBD = DEPTH_32  | IMAGE_FORMAT_BRCM4,
+   DEPTH_COL_64_TLBD = DEPTH_64 | IMAGE_FORMAT_BRCM4,
+   COL_32_TLBD = BGRA_8888 | IMAGE_FORMAT_BRCM4,
+
+   IMAGE_FORMAT_INVALID = 0xffffffff
+} KHRN_IMAGE_FORMAT_T;
+
+static INLINE bool khrn_image_is_rso(KHRN_IMAGE_FORMAT_T format)
+{
+   vcos_assert(format != IMAGE_FORMAT_INVALID);
+   return (format & IMAGE_FORMAT_MEM_LAYOUT_MASK) == IMAGE_FORMAT_RSO;
+}
+
+static INLINE bool khrn_image_is_brcm1(KHRN_IMAGE_FORMAT_T format)
+{
+   vcos_assert(format != IMAGE_FORMAT_INVALID);
+   return (format & IMAGE_FORMAT_MEM_LAYOUT_MASK) == IMAGE_FORMAT_BRCM1;
+}
+
+static INLINE bool khrn_image_is_brcm2(KHRN_IMAGE_FORMAT_T format)
+{
+   vcos_assert(format != IMAGE_FORMAT_INVALID);
+   return (format & IMAGE_FORMAT_MEM_LAYOUT_MASK) == IMAGE_FORMAT_BRCM2;
+}
+
+static INLINE KHRN_IMAGE_FORMAT_T khrn_image_to_rso_format(KHRN_IMAGE_FORMAT_T format)
+{
+   vcos_assert(format != IMAGE_FORMAT_INVALID);
+   return (KHRN_IMAGE_FORMAT_T)((format & ~IMAGE_FORMAT_MEM_LAYOUT_MASK) | IMAGE_FORMAT_RSO);
+}
+
+static INLINE KHRN_IMAGE_FORMAT_T khrn_image_to_tf_format(KHRN_IMAGE_FORMAT_T format)
+{
+   vcos_assert(format != IMAGE_FORMAT_INVALID);
+   return (KHRN_IMAGE_FORMAT_T)((format & ~IMAGE_FORMAT_MEM_LAYOUT_MASK) | IMAGE_FORMAT_BRCM1);
+}
+
+static INLINE KHRN_IMAGE_FORMAT_T khrn_image_to_lt_format(KHRN_IMAGE_FORMAT_T format)
+{
+   vcos_assert(format != IMAGE_FORMAT_INVALID);
+   return (KHRN_IMAGE_FORMAT_T)((format & ~IMAGE_FORMAT_MEM_LAYOUT_MASK) | IMAGE_FORMAT_BRCM2);
+}
+
+static INLINE bool khrn_image_is_uncomp(KHRN_IMAGE_FORMAT_T format)
+{
+   vcos_assert(format != IMAGE_FORMAT_INVALID);
+   return (format & IMAGE_FORMAT_COMP_MASK) == IMAGE_FORMAT_UNCOMP;
+}
+
+static INLINE bool khrn_image_is_color(KHRN_IMAGE_FORMAT_T format)
+{
+   vcos_assert(format != IMAGE_FORMAT_INVALID);
+   return (format & (IMAGE_FORMAT_COMP_MASK | IMAGE_FORMAT_PIXEL_TYPE_MASK)) == (IMAGE_FORMAT_UNCOMP | IMAGE_FORMAT_COLOR);
+}
+
+static INLINE bool khrn_image_is_gray(KHRN_IMAGE_FORMAT_T format)
+{
+   vcos_assert(format != IMAGE_FORMAT_INVALID);
+   return (format & (IMAGE_FORMAT_L)) != 0;
+}
+
+static INLINE bool khrn_image_is_paletted(KHRN_IMAGE_FORMAT_T format)
+{
+   vcos_assert(format != IMAGE_FORMAT_INVALID);
+   return (format & (IMAGE_FORMAT_COMP_MASK | IMAGE_FORMAT_PIXEL_TYPE_MASK)) == (IMAGE_FORMAT_UNCOMP | IMAGE_FORMAT_PALETTE);
+}
+
+static INLINE bool khrn_image_is_depth(KHRN_IMAGE_FORMAT_T format)
+{
+   vcos_assert(format != IMAGE_FORMAT_INVALID);
+   return (format & (IMAGE_FORMAT_COMP_MASK | IMAGE_FORMAT_PIXEL_TYPE_MASK)) == (IMAGE_FORMAT_UNCOMP | IMAGE_FORMAT_DEPTH);
+}
+
+static INLINE bool khrn_image_is_etc1(KHRN_IMAGE_FORMAT_T format)
+{
+   vcos_assert(format != IMAGE_FORMAT_INVALID);
+   return (format & IMAGE_FORMAT_COMP_MASK) == IMAGE_FORMAT_ETC1;
+}
+
+static INLINE bool khrn_image_is_yuv422(KHRN_IMAGE_FORMAT_T format)
+{
+   vcos_assert(format != IMAGE_FORMAT_INVALID);
+   return (format & IMAGE_FORMAT_COMP_MASK) == IMAGE_FORMAT_YUYV;
+}
+
+extern uint32_t khrn_image_get_bpp(KHRN_IMAGE_FORMAT_T format);
+
+extern uint32_t khrn_image_get_red_size(KHRN_IMAGE_FORMAT_T format);
+extern uint32_t khrn_image_get_green_size(KHRN_IMAGE_FORMAT_T format);
+extern uint32_t khrn_image_get_blue_size(KHRN_IMAGE_FORMAT_T format);
+extern uint32_t khrn_image_get_alpha_size(KHRN_IMAGE_FORMAT_T format);
+extern uint32_t khrn_image_get_z_size(KHRN_IMAGE_FORMAT_T format);
+extern uint32_t khrn_image_get_stencil_size(KHRN_IMAGE_FORMAT_T format);
+
+extern uint32_t khrn_image_get_log2_brcm2_width(KHRN_IMAGE_FORMAT_T format);
+extern uint32_t khrn_image_get_log2_brcm2_height(KHRN_IMAGE_FORMAT_T format);
+extern uint32_t khrn_image_get_log2_brcm1_width(KHRN_IMAGE_FORMAT_T format);
+extern uint32_t khrn_image_get_log2_brcm1_height(KHRN_IMAGE_FORMAT_T format);
+
+/******************************************************************************
+image handling
+******************************************************************************/
+
+typedef struct {
+   KHRN_IMAGE_FORMAT_T format;
+
+   uint16_t width;
+   uint16_t height;
+
+   int32_t stride; /* in bytes */
+
+   void *aux;
+   void *storage;
+} KHRN_IMAGE_WRAP_T;
+
+extern uint32_t khrn_image_pad_width(KHRN_IMAGE_FORMAT_T format, uint32_t width);
+extern uint32_t khrn_image_pad_height(KHRN_IMAGE_FORMAT_T format, uint32_t height);
+extern uint32_t khrn_image_get_stride(KHRN_IMAGE_FORMAT_T format, uint32_t width);
+extern uint32_t khrn_image_get_size(KHRN_IMAGE_FORMAT_T format, uint32_t width, uint32_t height);
+
+extern void khrn_image_wrap(KHRN_IMAGE_WRAP_T *wrap, KHRN_IMAGE_FORMAT_T format, uint32_t width, uint32_t height, int32_t stride, void *storage);
+
+#endif
diff --git a/interface/khronos/common/khrn_int_math.h b/interface/khronos/common/khrn_int_math.h
new file mode 100755 (executable)
index 0000000..b20e0d4
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_INT_MATH_H
+#define KHRN_INT_MATH_H
+
+#include "interface/khronos/common/khrn_int_util.h"
+#include <math.h>
+#ifndef __VIDEOCORE__  // threadsx/nucleus define LONG which clashses
+#include "interface/vcos/vcos.h"
+#endif
+
+#define PI 3.1415926535897932384626433832795f
+#define SQRT_2 1.4142135623730950488016887242097f
+#define EPS 1.0e-10f
+
+static INLINE float floor_(float x)
+{
+   return floorf(x);
+}
+
+static INLINE float ceil_(float x)
+{
+   return ceilf(x);
+}
+
+/*
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   returns the magnitude of x. returns +infinity if x is infinite. returns a nan
+   if x is nan.
+*/
+
+static INLINE float absf_(float x)
+{
+   return (x < 0.0f) ? -x : x;
+}
+
+static INLINE float modf_(float x, float y)
+{
+   return fmodf(x, y);
+}
+
+static INLINE void sin_cos_(float *s, float *c, float angle)
+{
+   *s = sinf(angle);
+   *c = cosf(angle);
+}
+
+static INLINE float sin_(float angle)
+{
+   return sinf(angle);
+}
+
+static INLINE float cos_(float angle)
+{
+   return cosf(angle);
+}
+
+static INLINE float atan2_(float y, float x)
+{
+   return atan2f(y, x);
+}
+
+extern float acos_(float x);
+
+static INLINE float exp_(float x)
+{
+   return expf(x);
+}
+
+extern float mod_one_(float x);
+
+#ifdef _VIDEOCORE
+#include <vc/intrinsics.h>
+
+static INLINE float nan_recip_(float x)
+{
+   float est = _frecip(x);          /* initial estimate, accurate to ~12 bits */
+   return est * (2.0f - (x * est)); /* refine with newton-raphson to get accuracy to ~24 bits */
+}
+
+static INLINE float rsqrt_(float x)
+{
+#ifndef NDEBUG
+   vcos_verify(x > 0.0f);
+#endif
+   float est = _frsqrt(x);                         /* initial estimate, accurate to ~12 bits */
+   return est * (1.5f - ((x * 0.5f) * est * est)); /* refine with newton-raphson to get accuracy to ~24 bits */
+}
+#else
+static INLINE float nan_recip_(float x)
+{
+   return 1.0f / x;
+}
+
+static INLINE float rsqrt_(float x)
+{
+#ifndef NDEBUG
+   vcos_verify(x > 0.0f);
+#endif
+   return 1.0f / sqrtf(x);
+}
+#endif
+
+static INLINE float recip_(float x)
+{
+#ifndef NDEBUG
+   vcos_verify(x != 0.0f);
+#endif
+   return nan_recip_(x);
+}
+
+static INLINE bool is_nan_(float x)
+{
+   uint32_t bits = float_to_bits(x);
+   return ((bits & 0x7f800000) == 0x7f800000) && /* max exponent */
+      (bits << 9); /* non-zero mantissa */
+}
+
+static INLINE bool nan_lt_(float x, float y)
+{
+   return
+#ifndef KHRN_NAN_COMPARISONS_CORRECT
+      !is_nan_(x) && !is_nan_(y) &&
+#endif
+      (x < y);
+}
+
+static INLINE bool nan_gt_(float x, float y)
+{
+   return
+#ifndef KHRN_NAN_COMPARISONS_CORRECT
+      !is_nan_(x) && !is_nan_(y) &&
+#endif
+      (x > y);
+}
+
+static INLINE bool nan_ne_(float x, float y)
+{
+   return
+#ifndef KHRN_NAN_COMPARISONS_CORRECT
+      !is_nan_(x) && !is_nan_(y) &&
+#endif
+      (x != y);
+}
+
+static INLINE float sqrt_(float x)
+{
+   vcos_assert(!nan_lt_(x, 0.0f));
+   return sqrtf(x);
+}
+
+#endif
diff --git a/interface/khronos/common/khrn_int_misc_impl.h b/interface/khronos/common/khrn_int_misc_impl.h
new file mode 100755 (executable)
index 0000000..989e5f0
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#if defined(KHRN_IMPL_STRUCT)
+#define FN(type, name, args) type (*name) args;
+#elif defined(KHRN_IMPL_STRUCT_INIT)
+#define FN(type, name, args) name,
+#else
+#define FN(type, name, args) extern type name args;
+#endif
+
+FN(void, khrn_misc_startup_impl, (void))
+FN(int, khrn_misc_try_unload_impl, (void))
+FN(void, khrn_misc_fifo_finish_impl, (void))
+FN(void, khrn_misc_rpc_flush_impl, (void))
+
+#undef FN
diff --git a/interface/khronos/common/khrn_int_util.c b/interface/khronos/common/khrn_int_util.c
new file mode 100755 (executable)
index 0000000..320183a
--- /dev/null
@@ -0,0 +1,163 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/khronos/common/khrn_int_common.h"
+
+#include "interface/khronos/common/khrn_int_util.h"
+#include "interface/khronos/include/GLES/gl.h"
+#include "interface/khronos/include/GLES2/gl2.h"
+#include "interface/khronos/include/GLES2/gl2ext.h"
+
+void khrn_clip_range(
+   int32_t *min_x0_io, int32_t *l0_io,
+   int32_t min_x1, int32_t l1)
+{
+   int32_t min_x0;
+   int32_t l0;
+   int32_t max_x0;
+   int32_t max_x1;
+
+   vcos_assert((*l0_io >= 0) && (l1 >= 0));
+
+   min_x0 = *min_x0_io;
+   l0 = *l0_io;
+
+   max_x0 = _adds(min_x0, l0);
+   max_x1 = min_x1 + l1;
+
+   if (min_x0 < min_x1) {
+      min_x0 = min_x1;
+   }
+   if (max_x0 > max_x1) {
+      max_x0 = max_x1;
+   }
+
+   l0 = _max(_subs(max_x0, min_x0), 0);
+
+   *min_x0_io = (l0 == 0) ? min_x1 : min_x0;
+   *l0_io = l0;
+}
+
+void khrn_clip_range2(
+   int32_t *min_ax0_io, int32_t *min_bx0_io, int32_t *l0_io,
+   int32_t min_ax1, int32_t al1,
+   int32_t min_bx1, int32_t bl1)
+{
+   int32_t min_ax0;
+   int32_t min_bx0;
+   int32_t l0;
+   int32_t max_ax0;
+   int32_t max_bx0;
+   int32_t max_ax1;
+   int32_t max_bx1;
+
+   vcos_assert((*l0_io >= 0) && (al1 >= 0) && (bl1 >= 0));
+
+   min_ax0 = *min_ax0_io;
+   min_bx0 = *min_bx0_io;
+   l0 = *l0_io;
+
+   l0 = _adds(_max(min_ax0, min_bx0), l0) - _max(min_ax0, min_bx0); /* clamp l0 to avoid overflow */
+   max_ax0 = min_ax0 + l0;
+   max_bx0 = min_bx0 + l0;
+   max_ax1 = min_ax1 + al1;
+   max_bx1 = min_bx1 + bl1;
+
+   /*
+      if any of the following _adds/_subs overflow, we will get either
+      min_ax0 >= max_ax0 or min_bx0 >= max_bx0, so l0 will be 0
+   */
+
+   if (min_ax0 < min_ax1) {
+      min_bx0 = _adds(min_bx0, _subs(min_ax1, min_ax0));
+      min_ax0 = min_ax1;
+   }
+   if (max_ax0 > max_ax1) {
+      max_bx0 = _subs(max_bx0, _subs(max_ax0, max_ax1));
+      max_ax0 = max_ax1;
+   }
+
+   if (min_bx0 < min_bx1) {
+      min_ax0 = _adds(min_ax0, _subs(min_bx1, min_bx0));
+      min_bx0 = min_bx1;
+   }
+   if (max_bx0 > max_bx1) {
+      max_ax0 = _subs(max_ax0, _subs(max_bx0, max_bx1));
+      max_bx0 = max_bx1;
+   }
+
+   l0 = _max(_subs(max_ax0, min_ax0), 0);
+   vcos_assert(l0 == _max(_subs(max_bx0, min_bx0), 0));
+
+   *min_ax0_io = (l0 == 0) ? min_ax1 : min_ax0;
+   *min_bx0_io = (l0 == 0) ? min_bx1 : min_bx0;
+   *l0_io = l0;
+}
+
+void khrn_clip_rect(
+   int32_t *x0, int32_t *y0, int32_t *w0, int32_t *h0,
+   int32_t x1, int32_t y1, int32_t w1, int32_t h1)
+{
+   khrn_clip_range(x0, w0, x1, w1);
+   khrn_clip_range(y0, h0, y1, h1);
+}
+
+void khrn_clip_rect2(
+   int32_t *ax0, int32_t *ay0, int32_t *bx0, int32_t *by0, int32_t *w0, int32_t *h0,
+   int32_t ax1, int32_t ay1, int32_t aw1, int32_t ah1,
+   int32_t bx1, int32_t by1, int32_t bw1, int32_t bh1)
+{
+   khrn_clip_range2(ax0, bx0, w0, ax1, aw1, bx1, bw1);
+   khrn_clip_range2(ay0, by0, h0, ay1, ah1, by1, bh1);
+}
+
+int khrn_get_type_size(int type)
+{
+   switch ((GLenum)type) {
+   case GL_BYTE:
+   case GL_UNSIGNED_BYTE:
+      return 1;
+   case GL_SHORT:
+   case GL_UNSIGNED_SHORT:
+   case GL_HALF_FLOAT_OES:
+      return 2;
+   case GL_FIXED:
+   case GL_FLOAT:
+      return 4;
+   default:
+      UNREACHABLE();
+      return 0;
+   }
+}
+
+#ifdef _VIDEOCORE
+
+void khrn_barrier(void)
+{
+}
+
+#endif
diff --git a/interface/khronos/common/khrn_int_util.h b/interface/khronos/common/khrn_int_util.h
new file mode 100755 (executable)
index 0000000..8d8eeef
--- /dev/null
@@ -0,0 +1,511 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_INT_UTIL_H
+#define KHRN_INT_UTIL_H
+
+#include <ctype.h>
+#include <float.h>
+#include <math.h>
+
+#include "interface/khronos/common/khrn_int_common.h"
+#if !defined(__VIDEOCORE__) && !defined(WIN32)  // threadsx/nucleus define LONG which clashses
+#include "interface/vcos/vcos.h"
+#endif
+
+/******************************************************************************
+replacements for videocore intrinsics
+******************************************************************************/
+
+#ifdef _VIDEOCORE
+#include <vc/intrinsics.h>
+#define _minf(x,y) _min((float)(x),(float)(y))
+#define _maxf(x,y) _max((float)(x),(float)(y))
+#else
+static INLINE int32_t _bmask(int32_t x, int32_t y)
+{
+   return x & ((1 << (y & 0x1f)) - 1);
+}
+
+static INLINE int32_t _min(int32_t x, int32_t y)
+{
+   return x < y ? x : y;
+}
+
+static INLINE int32_t _max(int32_t x, int32_t y)
+{
+   return x > y ? x : y;
+}
+
+#if defined(_MSC_VER)
+static INLINE int32_t _msb(uint32_t x)
+{
+   int32_t l = -1;
+
+   if (x)
+      __asm {
+         bsr eax, x
+         mov l, eax
+      }
+
+   return l;
+}
+#elif defined __CC_ARM
+static INLINE int32_t _msb(uint32_t x)
+{
+   return 31 - __clz(x);
+}
+#elif defined(__GNUC__)
+static INLINE int32_t _msb(uint32_t x)
+{
+   return x ? (31 - __builtin_clz(x)) : -1;
+}
+#else
+static INLINE int32_t _msb(uint32_t x) /* unsigned to get lsr */
+{
+   int32_t msb = -1;
+   while (x != 0) {
+      ++msb;
+      x >>= 1;
+   }
+   return msb;
+}
+#endif
+
+static INLINE uint32_t _count(uint32_t x)
+{
+   uint32_t count = 0;
+   while (x != 0) {
+      x &= x - 1;
+      ++count;
+   }
+   return count;
+}
+
+#if defined __CC_ARM && __TARGET_ARCH_THUMB >= 4
+static INLINE uint32_t _bitrev(uint32_t x, uint32_t y)
+{
+   return __rbit(x) >> (32-y);
+}
+#else
+static INLINE uint32_t _bitrev(uint32_t x, uint32_t y)
+{
+   uint32_t bitrev = 0;
+   uint32_t i;
+   for (i = 0; i != y; ++i) {
+      bitrev |= ((x >> i) & 1) << (y - i - 1);
+   }
+   return bitrev;
+}
+#endif
+
+#ifdef __CC_ARM
+static INLINE int32_t _adds(int32_t x, int32_t y)
+{
+   return __qadd(x, y);
+}
+
+static INLINE int32_t _subs(int32_t x, int32_t y)
+{
+   return __qsub(x, y);
+}
+
+static INLINE uint32_t _ror(uint32_t x, uint32_t y)
+{
+   return __ror(x, y);
+}
+#else
+static INLINE int32_t _adds(int32_t x, int32_t y)
+{
+   int32_t z = x + y;
+   return (y > 0) ? ((z < x) ? (int32_t)0x7fffffff : z) : ((z > x) ? (int32_t)0x80000000 : z);
+}
+
+static INLINE int32_t _subs(int32_t x, int32_t y)
+{
+   int32_t z = x - y;
+   return (y > 0) ? ((z > x) ? (int32_t)0x80000000 : z) : ((z < x) ? (int32_t)0x7fffffff : z);
+}
+
+static INLINE uint32_t _ror(uint32_t x, uint32_t y)
+{
+   return (x << (32 - y)) | (x >> y);
+}
+#endif // __CC_ARM
+
+static INLINE int32_t _abs(int32_t x)
+{
+   return x > 0 ? x : -x;
+}
+
+static INLINE float _minf(float x, float y)
+{
+   return x < y ? x : y;
+}
+
+static INLINE float _maxf(float x, float y)
+{
+   return x > y ? x : y;
+}
+
+#endif // !_VIDEOCORE
+
+
+/******************************************************************************
+misc stuff
+******************************************************************************/
+
+#define ARR_COUNT(ARR) (sizeof(ARR) / sizeof(*(ARR)))
+
+/* sign-extend 16-bit value with range [-0x4000, 0xbfff] */
+static INLINE int32_t s_ext_off16(int32_t x)
+{
+   return ((int32_t)(int16_t)(x - 0x4000)) + 0x4000;
+}
+
+static INLINE bool is_power_of_2(uint32_t x)
+{
+   return (x != 0) && ((x & (x - 1)) == 0);
+}
+
+static INLINE uint32_t next_power_of_2(uint32_t x)
+{
+   return is_power_of_2(x) ? x : (uint32_t)(1 << (_msb(x) + 1));
+}
+
+static INLINE uint32_t round_up(uint32_t x, uint32_t y)
+{
+   vcos_assert(is_power_of_2(y));
+   return (x + (y - 1)) & ~(y - 1);
+}
+
+static INLINE void *round_up_ptr(void *x, uint32_t y)
+{
+   vcos_assert(is_power_of_2(y));
+   return (void *)(((uintptr_t)x + (uintptr_t)(y - 1)) & ~(uintptr_t)(y - 1));
+}
+
+static INLINE uint32_t mod(int32_t x, int32_t y)
+{
+   int32_t m = x % y;
+   return (m < 0) ? (m + y) : m;
+}
+
+extern int khrn_get_type_size(int type /* GLenum*/);
+
+static INLINE int find_max(int count, int size, const void *indices)
+{
+   int i;
+   int32_t max = -1;
+
+   switch (size) {
+   case 1:
+   {
+      uint8_t *u = (uint8_t *)indices;
+
+      for (i = 0; i < count; i++)
+         max = _max( max, (int32_t) u[i]);
+
+      break;
+   }
+   case 2:
+   {
+      uint16_t *u = (uint16_t *)indices;
+
+      for (i = 0; i < count; i++)
+         max = _max( max, (int32_t) u[i]);
+
+      break;
+   }
+   default:
+      UNREACHABLE();
+      break;
+   }
+
+   return (int) max;
+}
+
+/******************************************************************************
+for poking around inside floats (we assume ieee-754)
+******************************************************************************/
+
+typedef union {
+   float f;
+   uint32_t bits;
+} KHRN_FLOAT_BITS_T;
+
+static INLINE uint32_t float_to_bits(float f)
+{
+   KHRN_FLOAT_BITS_T t;
+   t.f = f;
+   return t.bits;
+}
+
+static INLINE float float_from_bits(uint32_t bits)
+{
+   KHRN_FLOAT_BITS_T t;
+   t.bits = bits;
+   return t.f;
+}
+
+/******************************************************************************
+input cleaning stuff
+******************************************************************************/
+
+#include "interface/khronos/common/khrn_int_util_cr.h"
+
+static INLINE void clean_floats(float *dst, const float *src, uint32_t count)
+{
+   uint32_t i;
+   for (i = 0; i != count; ++i) {
+      dst[i] = clean_float(src[i]);
+   }
+}
+
+/******************************************************************************
+float to int conversions
+******************************************************************************/
+
+static INLINE float r2ni_to_r2n_bias(float f, int32_t shift)
+{
+   vcos_assert((shift >= -129) && (shift <= 124));
+   return f + float_from_bits(((127 - (shift + 2)) << 23) | 0x7fffff);
+}
+
+/*
+   convert float to integer value with shift
+   saturating, round to nearest
+
+   on videocore, we support shifts in [-32, 31]. we only need to support shifts
+   of 0 and 16 for client-side code
+*/
+
+static INLINE int32_t float_to_int_shift(float f, int32_t shift)
+{
+#ifdef _VIDEOCORE
+   /* floattouint is wrapping, round to negative infinity. shift should be in [-32, 31] */
+   vcos_assert((shift >= -32) && (shift <= 31));
+   f = r2ni_to_r2n_bias(f, shift);
+   if (f < float_from_bits((1 << 31) | ((127 + (31 - shift)) << 23))) { return 0x80000000; }
+   if (f > float_from_bits(((127 + (30 - shift)) << 23) | 0x7fffff))  { return 0x7fffffff; }
+   return _floattouint(f, shift);
+#else
+   vcos_assert((shift >= 0) && (shift <= 31));
+   f *= (float)(uint32_t)(1 << shift);
+   f += (f < 0.0f) ? -0.49999997f : 0.49999997f; /* assume float -> int conversion is round to zero */
+   if (f < -2.14748365e9f) { return 0x80000000; }
+   if (f > 2.14748352e9f)  { return 0x7fffffff; }
+   return (int32_t)f;
+#endif
+}
+
+/*
+   convert float to 48-bit integer value with shift
+   saturating, round to nearest
+
+   this is only supported on videocore. shift should be in [-16, 31]
+*/
+
+#ifdef _VIDEOCORE
+static INLINE int64_t float_to_int48_shift(float f, int32_t shift)
+{
+   /* floattouint is wrapping, round to negative infinity. shift should be in [-32, 31] */
+   vcos_assert((shift >= -16) && (shift <= 31));
+   f = r2ni_to_r2n_bias(f, shift);
+   if (f < float_from_bits((1 << 31) | ((127 + (47 - shift)) << 23))) { return 0xffff800000000000ll; }
+   if (f > float_from_bits(((127 + (46 - shift)) << 23) | 0x7fffff))  { return 0x00007fffffffffffll; }
+   return ((int64_t)(int32_t)_floattouint(f, shift - 16) << 16) | _floattouint(f, shift);
+}
+#endif
+
+/*
+   convert float to integer value
+   saturating, round to nearest
+*/
+
+static INLINE int32_t float_to_int(float f)
+{
+   return float_to_int_shift(f, 0);
+}
+
+/*
+   convert float to integer value
+   saturating, round to negative inf
+*/
+
+static INLINE int32_t float_to_int_floor(float f)
+{
+   /*
+      special-case handling of small negative floats
+      this is so we return -1 for negative denormals (which the vg cts requires)
+      (we shouldn't need this if the fp library/hw properly handle denormals)
+   */
+
+   uint32_t u = float_to_bits(f);
+   if (((u & (1 << 31)) && (u + u)) && (f > -1.0f)) {
+      return -1;
+   }
+
+   f = floorf(f); /* assume float -> int conversion is round to zero */
+   if (f < -2.14748365e9f) { return 0x80000000; }
+   if (f > 2.14748352e9f) { return 0x7fffffff; }
+   return (int32_t)f;
+}
+
+/*
+   convert float to integer value
+   saturating, round to zero
+*/
+
+static INLINE int32_t float_to_int_zero(float f)
+{
+   /* assume float -> int conversion is round to zero */
+   if (f < -2.14748365e9f) { return 0x80000000; }
+   if (f > 2.14748352e9f) { return 0x7fffffff; }
+   return (int32_t)f;
+}
+
+/*
+   convert float to 16.16 fixed point value
+   saturating, round to nearest
+
+   Khronos documentation:
+
+   If a value is so large in magnitude that it cannot be represented with the
+   requested type, then the nearest value representable using the requested type
+   is returned.
+*/
+
+static INLINE int32_t float_to_fixed(float f)
+{
+   return float_to_int_shift(f, 16);
+}
+
+/******************************************************************************
+exact float tests (in case fp library/hw don't handle denormals correctly)
+******************************************************************************/
+
+static INLINE bool floats_identical(float x, float y)
+{
+   return float_to_bits(x) == float_to_bits(y);
+}
+
+static INLINE bool is_zero(float f)
+{
+   uint32_t u = float_to_bits(f);
+   return !(u + u);
+}
+
+static INLINE bool is_le_zero(float f)
+{
+   uint32_t u = float_to_bits(f);
+   return (u & (1 << 31)) || !u;
+}
+
+/******************************************************************************
+alignment stuff
+******************************************************************************/
+
+#ifdef _MSC_VER
+   #define alignof(T) __alignof(T)
+#elif defined(__CC_ARM)
+   #define alignof(T) __alignof__(T)
+#else
+   #define alignof(T) (sizeof(struct { T t; char ch; }) - sizeof(T))
+#endif
+
+/*
+   must use both ALIGNED and ALIGN_TO...
+   ALIGNED(16) int align_me[10];
+   ALIGN_TO(align_me, 16);
+*/
+
+#ifdef _MSC_VER
+   #define ALIGNED(ALIGNMENT) __declspec(align(ALIGNMENT))
+   #define ALIGN_TO(X, ALIGNMENT)
+#elif defined(__GNUC__)
+   #define ALIGNED(ALIGNMENT) __attribute__ ((aligned(ALIGNMENT)))
+   #define ALIGN_TO(X, ALIGNMENT)
+#elif defined(__HIGHC__)
+   #define ALIGNED(ALIGMENT)
+   #define ALIGN_TO(X, ALIGNMENT) pragma Align_to(ALIGNMENT, X)
+#else
+   /* leave undefined (will get error on use) */
+#endif
+
+/******************************************************************************
+range/rect intersect stuff
+******************************************************************************/
+
+extern void khrn_clip_range(
+   int32_t *x0, int32_t *l0,
+   int32_t x1, int32_t l1);
+
+extern void khrn_clip_range2(
+   int32_t *ax0, int32_t *bx0, int32_t *l0,
+   int32_t ax1, int32_t al1,
+   int32_t bx1, int32_t bl1);
+
+extern void khrn_clip_rect(
+   int32_t *x0, int32_t *y0, int32_t *w0, int32_t *h0,
+   int32_t x1, int32_t y1, int32_t w1, int32_t h1);
+
+extern void khrn_clip_rect2(
+   int32_t *ax0, int32_t *ay0, int32_t *bx0, int32_t *by0, int32_t *w0, int32_t *h0,
+   int32_t ax1, int32_t ay1, int32_t aw1, int32_t ah1,
+   int32_t bx1, int32_t by1, int32_t bw1, int32_t bh1);
+
+static INLINE bool khrn_ranges_intersect(
+   int32_t x0, int32_t l0,
+   int32_t x1, int32_t l1)
+{
+   return (x0 < (x1 + l1)) && (x1 < (x0 + l0));
+}
+
+static INLINE bool khrn_rects_intersect(
+   int32_t x0, int32_t y0, int32_t w0, int32_t h0,
+   int32_t x1, int32_t y1, int32_t w1, int32_t h1)
+{
+   return khrn_ranges_intersect(x0, w0, x1, w1) && khrn_ranges_intersect(y0, h0, y1, h1);
+}
+
+/******************************************************************************
+memory barrier
+******************************************************************************/
+
+#ifdef KHRN_SINGLE_THREADED
+   /* everything is done in one thread, no need for barriers */
+   static INLINE void khrn_barrier(void) {}
+#elif defined(_VIDEOCORE)
+   /* don't need a real memory barrier
+    * extern function should do as a compiler barrier, but todo: is there a better way? */
+   extern void khrn_barrier(void);
+#else
+   /* leave undefined (will get error on use) */
+#endif
+
+#endif
diff --git a/interface/khronos/common/khrn_int_util_cr.h b/interface/khronos/common/khrn_int_util_cr.h
new file mode 100755 (executable)
index 0000000..ca28eeb
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+static INLINE bool clean_boolean(int b)
+{
+   return !!b;
+}
+
+/*
+   clean_float(float f)
+
+   Implementation notes:
+
+   'Cleans' a floating point number by converting -INF to -FLT_MAX, INF to FLT_MAX and
+   any NaN to zero. Khronos spec says nothing about what happens if an unclean float is
+   passed to a function, so this at least guarantees reasonable behaviour.
+
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   result r is not NaN or infinite
+*/
+
+static INLINE float clean_float(float f)
+{
+   uint32_t u = float_to_bits(f);
+
+   if (u == 0x7f800000)
+      return FLT_MAX;
+   if (u == (uint32_t)0xff800000)
+      return -FLT_MAX;
+   if ((u & 0x7f800000) == 0x7f800000)
+      return 0;                              // force NaN to zero
+
+   return f;
+}
+
+/*
+   clampf(float x, float l, float u)
+
+   Implementation notes:
+
+   Khronos makes frequent use of the datatype clampf, which is defined as
+
+      floating-point value clamped to [0, 1]
+
+   This function is used in many places to clamp a floating point value to lie in a range
+   (almost always 0..1) and also to implicitly remove any NaNs or infinities.
+
+   Preconditions:
+
+   l and u are not NaN or infinity and l <= u
+
+   Postconditions:
+
+   result r is not NaN or an infinity, and l <= r <= u
+*/
+
+static INLINE float clampf(float x, float l, float u)
+{
+   vcos_assert(l <= u);
+
+   x = clean_float(x);
+
+   return _maxf(_minf(x, u), l);
+}
+
+/*
+   fixed_to_float(int f)
+
+   Implementation notes:
+
+   OpenGL ES 1.1 makes use of the datatype 'fixed' which is defined as a:
+
+      signed 2s complement 16.16 scaled integer
+
+   This function is used to convert a fixed value to its floating point equivalent, with
+   some loss of precision. We believe this is justified as the state tables in the spec
+   talk about storing all these values as type R (floating-point number).
+
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   result r is not NaN or an infinity
+*/
+
+static INLINE float fixed_to_float(int f)
+{
+   return (float)f / 65536.0f;
+}
+
+/*
+   clampi(int x, int l, int u)
+
+   Implementation notes:
+
+   Preconditions:
+
+   l <= u
+
+   Postconditions:
+
+   result r satisfies l <= r <= u
+*/
+
+static INLINE int clampi(int x, int l, int u)
+{
+   vcos_assert(l <= u);
+
+   return (int) _max(_min( (int32_t)x, (int32_t)u), (int32_t)l);
+}
diff --git a/interface/khronos/common/khrn_options.c b/interface/khronos/common/khrn_options.c
new file mode 100755 (executable)
index 0000000..b2a6a1f
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/khronos/common/khrn_options.h"
+
+#include <memory.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+KHRN_OPTIONS_T khrn_options;
+
+/* For now, we will use environment variables for the options.
+   We might, at some point, want to use ini files perhaps */
+static bool read_bool_option(const char *name, bool cur)
+{
+   char *val = getenv(name);
+
+   if (val == NULL)
+      return cur;
+
+   if (val[0] == 't' || val[0] == 'T' || val[0] == '1')
+      return true;
+
+   return false;
+}
+
+static uint32_t read_uint32_option(const char *name, uint32_t cur)
+{
+   char *val = getenv(name);
+
+   if (val == NULL)
+      return cur;
+
+   if (val[0] != '\0')
+      return atoi(val);
+
+   return 0;
+}
+
+void khrn_init_options(void)
+{
+   /* Default values are all 0 */
+   memset(&khrn_options, 0, sizeof(KHRN_OPTIONS_T));
+
+#ifndef DISABLE_OPTION_PARSING
+   /* Now read the options */
+   khrn_options.gl_error_assist        = read_bool_option(  "V3D_GL_ERROR_ASSIST",        khrn_options.gl_error_assist);
+   khrn_options.double_buffer          = read_bool_option(  "V3D_DOUBLE_BUFFER",          khrn_options.double_buffer);
+   khrn_options.no_bin_render_overlap  = read_bool_option(  "V3D_NO_BIN_RENDER_OVERLAP",  khrn_options.no_bin_render_overlap);
+   khrn_options.reg_dump_on_lock       = read_bool_option(  "V3D_REG_DUMP_ON_LOCK",       khrn_options.reg_dump_on_lock);
+   khrn_options.clif_dump_on_lock      = read_bool_option(  "V3D_CLIF_DUMP_ON_LOCK",      khrn_options.clif_dump_on_lock);
+   khrn_options.force_dither_off       = read_bool_option(  "V3D_FORCE_DITHER_OFF",       khrn_options.force_dither_off);
+
+   khrn_options.bin_block_size         = read_uint32_option("V3D_BIN_BLOCK_SIZE",         khrn_options.bin_block_size);
+   khrn_options.max_bin_blocks         = read_uint32_option("V3D_MAX_BIN_BLOCKS",         khrn_options.max_bin_blocks);
+#endif
+}
+
+void khrn_error_assist(GLenum error, const char *func)
+{
+   if (khrn_options.gl_error_assist && error != GL_NO_ERROR)
+   {
+      fprintf(stderr, "V3D ERROR ASSIST : ");
+      switch (error)
+      {
+      case GL_INVALID_ENUM      : fprintf(stderr, "GL_INVALID_ENUM in %s\n", func); break;
+      case GL_INVALID_VALUE     : fprintf(stderr, "GL_INVALID_VALUE in %s\n", func); break;
+      case GL_INVALID_OPERATION : fprintf(stderr, "GL_INVALID_OPERATION in %s\n", func); break;
+      case GL_OUT_OF_MEMORY     : fprintf(stderr, "GL_OUT_OF_MEMORY in %s\n", func); break;
+      default                   : fprintf(stderr, "ERROR CODE %d in %s\n", (int)error, func); break;
+      }
+      fflush(stderr);
+   }
+}
diff --git a/interface/khronos/common/khrn_options.h b/interface/khronos/common/khrn_options.h
new file mode 100755 (executable)
index 0000000..9db6bca
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_OPTIONS_H
+#define KHRN_OPTIONS_H
+
+#include "interface/khronos/common/khrn_int_common.h"
+#include "interface/khronos/include/GLES/gl.h"
+
+typedef struct {
+   bool     gl_error_assist;           /* Outputs useful info when the error occurs */
+   bool     double_buffer;             /* Defaults to triple-buffered */
+   bool     no_bin_render_overlap;     /* Prevent bin/render overlap */
+   bool     reg_dump_on_lock;          /* Dump h/w registers if the h/w locks-up */
+   bool     clif_dump_on_lock;         /* Dump clif file and memory on h/w lock-up */
+   bool     force_dither_off;          /* Ensure dithering is always off */
+   uint32_t bin_block_size;            /* Set the size of binning memory blocks */
+   uint32_t max_bin_blocks;            /* Set the maximum number of binning block in use */
+
+} KHRN_OPTIONS_T;
+
+extern KHRN_OPTIONS_T khrn_options;
+
+extern void khrn_init_options(void);
+extern void khrn_error_assist(GLenum error, const char *func);
+
+#ifdef WIN32
+#undef __func__
+#define __func__ __FUNCTION__
+#endif
+
+#endif
diff --git a/interface/khronos/common/linux/khrn_client_platform_linux.c b/interface/khronos/common/linux/khrn_client_platform_linux.c
new file mode 100755 (executable)
index 0000000..710d20f
--- /dev/null
@@ -0,0 +1,829 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#define VCOS_LOG_CATEGORY (&khrn_client_log)
+
+#include "interface/khronos/common/khrn_client_platform.h"
+#include "interface/khronos/common/khrn_client.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+#include "interface/khronos/common/khrn_int_ids.h"
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#ifdef WANT_X
+#include "X11/Xlib.h"
+#endif
+
+extern VCOS_LOG_CAT_T khrn_client_log;
+
+extern void vc_vchi_khronos_init();
+
+static void send_bound_pixmaps(void);
+#ifdef WANT_X
+static void dump_hierarchy(Window w, Window thisw, Window look, int level);
+static void dump_ancestors(Window w);
+#endif
+
+//see helpers\scalerlib\scalerlib_misc.c
+//int32_t scalerlib_convert_vcimage_to_display_element()
+//dark blue, 1<<3 in 888
+#define CHROMA_KEY_565 0x0001
+//
+
+#ifdef WANT_X
+static Display *hacky_display = 0;
+
+static XErrorHandler old_handler = (XErrorHandler) 0 ;
+static int application_error_handler(Display *display, XErrorEvent *theEvent)
+{
+   vcos_log_trace(
+               "Ignoring Xlib error: error code %d request code %d\n",
+               theEvent->error_code,
+               theEvent->request_code) ;
+   return 0 ;
+}
+#endif
+
+
+VCOS_STATUS_T khronos_platform_semaphore_create(PLATFORM_SEMAPHORE_T *sem, int name[3], int count)
+{
+   char buf[64];
+   vcos_snprintf(buf,sizeof(buf),"KhanSemaphore%08x%08x%08x", name[0], name[1], name[2]);
+   return vcos_named_semaphore_create(sem, buf, count);
+}
+
+uint64_t khronos_platform_get_process_id()
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   return rpc_get_client_id(thread);
+}
+
+static bool process_attached = false;
+
+void *platform_tls_get(PLATFORM_TLS_T tls)
+{
+   void *ret;
+
+   if (!process_attached)
+      /* TODO: this isn't thread safe */
+   {
+      vcos_log_trace("Attaching process");
+      client_process_attach();
+      process_attached = true;
+      tls = client_tls;
+
+      vc_vchi_khronos_init();
+   }
+
+   ret = vcos_tls_get(tls);
+   if (!ret)
+   {
+     /* The problem here is that on VCFW, the first notification we get that a thread
+       * exists at all is when it calls an arbitrary EGL function. We need to detect this
+       * case and initiliase the per-thread state.
+       *
+       * On Windows this gets done in DllMain.
+       */
+      client_thread_attach();
+      vcos_thread_at_exit(client_thread_detach, NULL);
+      ret = vcos_tls_get(tls);
+   }
+   return ret;
+}
+
+void *platform_tls_get_check(PLATFORM_TLS_T tls)
+{
+   return platform_tls_get(tls);
+}
+
+/* ----------------------------------------------------------------------
+ * workaround for broken platforms which don't detect threads exiting
+ * -------------------------------------------------------------------- */
+void platform_hint_thread_finished()
+{
+   /*
+      todo: should we do this:
+
+      vcos_thread_deregister_at_exit(client_thread_detach);
+      client_thread_detach();
+
+      here?
+   */
+}
+
+#ifndef KHRN_PLATFORM_VCOS_NO_MALLOC
+
+/**
+   Allocate memory
+
+   @param size Size in bytes of memory block to allocate
+   @return pointer to memory block
+**/
+void *khrn_platform_malloc(size_t size, const char * name)
+{
+   return vcos_malloc(size, name);
+}
+
+/**
+   Free memory
+
+   @param v Pointer to  memory area to free
+**/
+void khrn_platform_free(void *v)
+{
+   if (v)
+   {
+      vcos_free(v);
+   }
+}
+
+#endif
+
+
+#ifdef WANT_X
+static XImage *current_ximage = NULL;
+
+static KHRN_IMAGE_FORMAT_T ximage_to_image_format(int bits_per_pixel, unsigned long red_mask, unsigned long green_mask, unsigned long blue_mask)
+{
+   if (bits_per_pixel == 16 /*&& red_mask == 0xf800 && green_mask == 0x07e0 && blue_mask == 0x001f*/)
+      return RGB_565_RSO;
+   //else if (bits_per_pixel == 24 && red_mask == 0xff0000 && green_mask == 0x00ff00 && blue_mask == 0x0000ff)
+   //   return RGB_888_RSO;
+   else if (bits_per_pixel == 24 && red_mask == 0x0000ff && green_mask == 0x00ff00 && blue_mask == 0xff0000)
+      return BGR_888_RSO;
+   else if (bits_per_pixel == 32 /*&& red_mask == 0x0000ff && green_mask == 0x00ff00 && blue_mask == 0xff0000*/)
+      return ABGR_8888_RSO; //meego uses alpha channel
+   else if (bits_per_pixel == 32 && red_mask == 0xff0000 && green_mask == 0x00ff00 && blue_mask == 0x0000ff)
+      return ARGB_8888_RSO;
+   else
+   {
+      vcos_log_warn("platform_get_pixmap_info unknown image format\n");
+      return IMAGE_FORMAT_INVALID;
+   }
+}
+
+bool platform_get_pixmap_info(EGLNativePixmapType pixmap, KHRN_IMAGE_WRAP_T *image)
+{
+   Window r;
+   int x, y;
+   unsigned int w, h, b, d;
+   KHRN_IMAGE_FORMAT_T format;
+   XImage *xi;
+   XWindowAttributes attr;
+   Status rc;
+
+   vcos_log_trace("platform_get_pixmap_info !!!");
+
+   if (!XGetGeometry(hacky_display, (Drawable)pixmap, &r, &x, &y, &w, &h, &b, &d))
+      return false;
+
+   vcos_log_trace("platform_get_pixmap_info %d geometry = %d %d %d %d",(int)pixmap,
+              x, y, w, h);
+
+   xi = XGetImage(hacky_display, (Drawable)pixmap, 0, 0, w, h, 0xffffffff, ZPixmap);
+   if (xi == NULL)
+      return false;
+
+   vcos_log_trace("platform_get_pixmap_info ximage = %d %d %d 0x%08x %d %x %x %x",
+              xi->width, xi->height, xi->bytes_per_line, (uint32_t)xi->data,
+              xi->bits_per_pixel, (uint32_t)xi->red_mask,
+              (uint32_t)xi->green_mask, (uint32_t)xi->blue_mask);
+
+   format = ximage_to_image_format(xi->bits_per_pixel, xi->red_mask, xi->green_mask, xi->blue_mask);
+   if (format == IMAGE_FORMAT_INVALID)
+   {
+      XDestroyImage(xi);
+      return false;
+   }
+
+   image->format = format;
+   image->width = xi->width;
+   image->height = xi->height;
+   image->stride = xi->bytes_per_line;
+   image->aux = NULL;
+   image->storage = xi->data;
+
+//hacking to see if this pixmap is actually the offscreen pixmap for the window that is our current surface
+   {
+      int xw, yw;
+      unsigned int ww, hw, bw, dw;
+      unsigned long pixel;
+      Window rw,win  = (Window)CLIENT_GET_THREAD_STATE()->opengl.draw->win;
+      vcos_log_trace("current EGL surface win %d ", (int)win);
+      if(win!=0)
+      {
+         /* Install our error handler to override Xlib's termination behavior */
+         old_handler = XSetErrorHandler(application_error_handler) ;
+
+         XGetGeometry(hacky_display, (Drawable)win, &rw, &xw, &yw, &ww, &hw, &bw, &dw);
+         vcos_log_trace("%dx%d", ww, hw);
+         if(ww==w && hw==h)
+         {
+            //this pixmap is the same size as our current window
+            pixel = XGetPixel(xi,w/2,h/2);
+            vcos_log_trace("Pixmap centre pixel 0x%lx%s",pixel,pixel==CHROMA_KEY_565 ? "- chroma key!!" : "");
+            if(pixel == CHROMA_KEY_565)//the pixmap is also full of our magic chroma key colour, we want to copy the server side EGL surface.
+               image->aux = (void *)CLIENT_GET_THREAD_STATE()->opengl.draw->serverbuffer ;
+         }
+
+         (void) XSetErrorHandler(old_handler) ;
+      }
+   }
+//
+
+   current_ximage = xi;
+   return true;
+}
+
+void khrn_platform_release_pixmap_info(EGLNativePixmapType pixmap, KHRN_IMAGE_WRAP_T *image)
+{
+   XDestroyImage(current_ximage);
+   current_ximage = NULL;
+}
+#else
+static KHRN_IMAGE_FORMAT_T convert_format(uint32_t format)
+{
+   switch (format & ~EGL_PIXEL_FORMAT_USAGE_MASK_BRCM) {
+      case EGL_PIXEL_FORMAT_ARGB_8888_PRE_BRCM: return (KHRN_IMAGE_FORMAT_T)(ABGR_8888 | IMAGE_FORMAT_PRE);
+      case EGL_PIXEL_FORMAT_ARGB_8888_BRCM:     return ABGR_8888;
+      case EGL_PIXEL_FORMAT_XRGB_8888_BRCM:     return XBGR_8888;
+      case EGL_PIXEL_FORMAT_RGB_565_BRCM:       return RGB_565;
+      case EGL_PIXEL_FORMAT_A_8_BRCM:           return A_8;
+      default:
+         vcos_assert(0);
+         return (KHRN_IMAGE_FORMAT_T)0;
+   }
+}
+
+bool platform_get_pixmap_info(EGLNativePixmapType pixmap, KHRN_IMAGE_WRAP_T *image)
+{
+   image->format = convert_format(((uint32_t *)pixmap)[4]);
+   image->width = ((uint32_t *)pixmap)[2];
+   image->height = ((uint32_t *)pixmap)[3];
+
+   /* can't actually access data */
+   image->stride = 0;
+   image->aux = 0;
+   image->storage = 0;
+
+   return image->format != 0;
+}
+void khrn_platform_release_pixmap_info(EGLNativePixmapType pixmap, KHRN_IMAGE_WRAP_T *image)
+{
+   /* Nothing to do */
+}
+#endif
+
+void platform_get_pixmap_server_handle(EGLNativePixmapType pixmap, uint32_t *handle)
+{
+   handle[0] = ((uint32_t *)pixmap)[0];
+   handle[1] = ((uint32_t *)pixmap)[1];
+}
+
+bool platform_match_pixmap_api_support(EGLNativePixmapType pixmap, uint32_t api_support)
+{
+   return
+      (!(api_support & EGL_OPENGL_BIT) || (((uint32_t *)pixmap)[4] & EGL_PIXEL_FORMAT_RENDER_GL_BRCM)) &&
+      (!(api_support & EGL_OPENGL_ES_BIT) || (((uint32_t *)pixmap)[4] & EGL_PIXEL_FORMAT_RENDER_GLES_BRCM)) &&
+      (!(api_support & EGL_OPENGL_ES2_BIT) || (((uint32_t *)pixmap)[4] & EGL_PIXEL_FORMAT_RENDER_GLES2_BRCM)) &&
+      (!(api_support & EGL_OPENVG_BIT) || (((uint32_t *)pixmap)[4] & EGL_PIXEL_FORMAT_RENDER_VG_BRCM));
+}
+
+#if EGL_BRCM_global_image && EGL_KHR_image
+
+bool platform_use_global_image_as_egl_image(uint32_t id_0, uint32_t id_1, EGLNativePixmapType pixmap, EGLint *error)
+{
+   return true;
+}
+
+void platform_acquire_global_image(uint32_t id_0, uint32_t id_1)
+{
+}
+
+void platform_release_global_image(uint32_t id_0, uint32_t id_1)
+{
+}
+
+void platform_get_global_image_info(uint32_t id_0, uint32_t id_1,
+   uint32_t *pixel_format, uint32_t *width, uint32_t *height)
+{
+   EGLint id[2] = {id_0, id_1};
+   EGLint width_height_pixel_format[3];
+   verify(eglQueryGlobalImageBRCM(id, width_height_pixel_format));
+   width_height_pixel_format[2] |=
+      /* this isn't right (the flags should be those passed in to
+       * eglCreateGlobalImageBRCM), but this stuff is just for basic testing, so
+       * it doesn't really matter */
+      EGL_PIXEL_FORMAT_RENDER_GLES_BRCM | EGL_PIXEL_FORMAT_RENDER_GLES2_BRCM |
+      EGL_PIXEL_FORMAT_RENDER_VG_BRCM | EGL_PIXEL_FORMAT_VG_IMAGE_BRCM |
+      EGL_PIXEL_FORMAT_GLES_TEXTURE_BRCM | EGL_PIXEL_FORMAT_GLES2_TEXTURE_BRCM;
+   if (pixel_format) { *pixel_format = width_height_pixel_format[2]; }
+   if (width) { *width = width_height_pixel_format[0]; }
+   if (height) { *height = width_height_pixel_format[1]; }
+}
+
+#endif
+
+void platform_client_lock(void)
+{
+   platform_mutex_acquire(&client_mutex);
+}
+
+void platform_client_release(void)
+{
+   platform_mutex_release(&client_mutex);
+}
+
+void platform_init_rpc(struct CLIENT_THREAD_STATE *state)
+{
+   assert(1);
+}
+
+void platform_term_rpc(struct CLIENT_THREAD_STATE *state)
+{
+   assert(1);
+}
+
+void platform_maybe_free_process(void)
+{
+   assert(1);
+}
+
+void platform_destroy_winhandle(void *a, uint32_t b)
+{
+   assert(1);
+}
+
+void platform_surface_update(uint32_t handle)
+{
+   /*
+   XXX This seems as good a place as any to do the client side pixmap hack.
+   (called from eglSwapBuffers)
+   */
+   send_bound_pixmaps();
+}
+
+void egl_gce_win_change_image(void)
+{
+   assert(0);
+}
+
+void platform_retrieve_pixmap_completed(EGLNativePixmapType pixmap)
+{
+   assert(0);
+}
+
+void platform_send_pixmap_completed(EGLNativePixmapType pixmap)
+{
+   assert(0);
+}
+
+uint32_t platform_memcmp(const void * aLeft, const void * aRight, size_t aLen)
+{
+   return memcmp(aLeft, aRight, aLen);
+}
+
+void platform_memcpy(void * aTrg, const void * aSrc, size_t aLength)
+{
+   memcpy(aTrg, aSrc, aLength);
+}
+
+
+#ifdef WANT_X
+uint32_t platform_get_handle(EGLNativeWindowType win)
+{
+   return (uint32_t)win;
+}
+
+void platform_get_dimensions(EGLDisplay dpy, EGLNativeWindowType win,
+      uint32_t *width, uint32_t *height, uint32_t *swapchain_count)
+{
+   Window w = (Window) win;
+   XWindowAttributes attr;
+   GC gc;
+   Status rc = XGetWindowAttributes(hacky_display, w, &attr);
+
+   // check rc is OK and if it is (vcos_assert(rc == 0);?????)
+   *width = attr.width;
+   *height = attr.height;
+   *swapchain_count = 0;
+
+        /* Hackily assume if this function is called then they want to fill with GL stuff. So fill window with chromakey. */
+   vcos_log_trace("Calling XCreateGC %d",(int)w);
+
+        gc = XCreateGC(hacky_display, w, 0, NULL);
+        XSetForeground(hacky_display, gc, CHROMA_KEY_565);
+
+   vcos_log_trace("Calling XFillRectangle %d %dx%d",(int)w,attr.width, attr.height);
+
+        XFillRectangle(hacky_display, w, gc, 0, 0, attr.width, attr.height);
+
+   vcos_log_trace("Calling XFreeGC");
+
+        XFreeGC(hacky_display, gc);
+
+   vcos_log_trace("Done platform_get_dimensions");
+    //debugging
+    dump_hierarchy(attr.root, w, 0, 0);
+}
+#endif
+
+#ifdef WANT_X
+EGLDisplay khrn_platform_set_display_id(EGLNativeDisplayType display_id)
+{
+   if(hacky_display==0)
+   {
+          hacky_display = (Display *)display_id;
+          return (EGLDisplay)1;
+       }
+       else
+          return EGL_NO_DISPLAY;
+}
+#else
+EGLDisplay khrn_platform_set_display_id(EGLNativeDisplayType display_id)
+{
+   if (display_id == EGL_DEFAULT_DISPLAY)
+      return (EGLDisplay)1;
+   else
+      return EGL_NO_DISPLAY;
+}
+#endif
+
+#ifdef WANT_X
+static void dump_hierarchy(Window w, Window thisw, Window look, int level)
+{
+   Window root_dummy, parent_dummy, *children;
+   unsigned int i, nchildren;
+   XWindowAttributes attr;
+
+   XGetWindowAttributes(hacky_display, w, &attr);
+   XQueryTree(hacky_display, w, &root_dummy, &parent_dummy, &children, &nchildren);
+
+   for (i = 0; i < level; i++)
+   {
+         vcos_log_trace(" ");
+   }
+   vcos_log_trace( "%d %d%s%s",
+              attr.map_state, (int)w,
+              (w==look)?" <-- LOOK FOR ME!":((w==thisw)?" <-- THIS WINDOW":""),
+              children?"":" no children");
+
+   if (children)
+   {
+      for (i = 0; i < nchildren; i++)
+      {
+         dump_hierarchy(children[i], thisw, look, level + 1);
+      }
+      XFree(children);
+   }
+}
+
+static void dump_ancestors(Window w)
+{
+   Window root_dummy, *children;
+   unsigned int i, nchildren;
+
+   Window grandparent,parent = w, child = 0;
+   unsigned int rlayer = ~0;
+   bool bidirectional;
+   vcos_log_trace("walking back up hierarchy");
+   while(parent)
+   {
+      bidirectional = false;
+      if(!XQueryTree(hacky_display, parent, &root_dummy, &grandparent, &children, &nchildren))
+         break;
+      if (children)
+      {
+         for (i = 0; i < nchildren; i++)
+         {
+            if (children[i] == child)
+            {
+               bidirectional = true;
+               rlayer = i;
+            }
+         }
+         XFree(children);
+      }
+      vcos_log_trace("%s%s%d", bidirectional ? "<" : "", (child>0) ? "->" : "", (int)parent);
+
+      child = parent;
+      parent = grandparent;
+
+   }
+   vcos_log_trace("->end");
+}
+
+
+uint32_t khrn_platform_get_window_position(EGLNativeWindowType win)
+{
+   Window w = (Window) win;
+   Window dummy;
+   XWindowAttributes attr;
+   Window look_for_me, root_dummy, root_dummy2, parent_dummy, *children;
+   int x, y;
+   unsigned int layer, i, nchildren;
+
+   //the assumption is that windows are at the 2nd level i.e. in the below
+   //root_dummy/attr.root -> look_for_me -> w
+   vcos_log_trace("Start khrn_platform_get_window_position");
+
+   XGetWindowAttributes(hacky_display, w, &attr);
+
+   vcos_log_trace("XGetWindowAttributes");
+
+   if (attr.map_state == IsViewable)
+   {
+      XTranslateCoordinates(hacky_display, w, attr.root, 0, 0, &x, &y, &dummy);
+
+      vcos_log_trace("XTranslateCoordinates");
+
+      XQueryTree(hacky_display, w, &root_dummy, &look_for_me, &children, &nchildren);
+      if (children) XFree(children);
+      XQueryTree(hacky_display, attr.root, &root_dummy2, &parent_dummy, &children, &nchildren);
+
+      vcos_log_trace("XQueryTree");
+
+      layer = ~0;
+
+      vcos_log_trace("Dumping hierarchy %d %d (%d)", (int)w, (int)look_for_me, (int)root_dummy);
+      dump_hierarchy(attr.root, w, look_for_me, 0);
+
+      if (children)
+      {
+         for (i = 0; i < nchildren; i++)
+         {
+            if (children[i] == look_for_me)
+               layer = i;
+         }
+         XFree(children);
+      }
+
+      vcos_log_trace("XFree");
+
+      if (layer == ~0)
+      {
+         vcos_log_error("EGL window isn't child of root", i);
+
+         //to try and find out where this window has gone, let us walk back up the hierarchy
+         dump_ancestors(w);
+         return ~0;
+      }
+      else
+      {
+         vcos_log_trace("End khrn_platform_get_window_position - visible");
+         return x | y << 12 | layer << 24;
+      }
+   }
+   else
+   {
+      vcos_log_trace("End khrn_platform_get_window_position - invisible");
+
+      return ~0;      /* Window is invisible */
+   }
+}
+#else
+static int xxx_position = 0;
+uint32_t khrn_platform_get_window_position(EGLNativeWindowType win)
+{
+   return xxx_position;
+}
+#endif
+
+#define NUM_PIXMAP_BINDINGS 16
+static struct
+{
+   bool used;
+   bool send;
+   EGLNativePixmapType pixmap;
+   EGLImageKHR egl_image;
+} pixmap_binding[NUM_PIXMAP_BINDINGS];
+
+static void set_egl_image_color_data(EGLImageKHR egl_image, KHRN_IMAGE_WRAP_T *image)
+{
+   int line_size = (image->stride < 0) ? -image->stride : image->stride;
+   int lines = KHDISPATCH_WORKSPACE_SIZE / line_size;
+   int offset = 0;
+   int height = image->height;
+
+   if (khrn_image_is_brcm1(image->format))
+      lines &= ~63;
+
+   assert(lines > 0);
+
+   while (height > 0) {
+      int batch = _min(lines, height);
+      uint32_t len = batch * line_size;
+
+      CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+      int adjusted_offset = (image->stride < 0) ? (offset + (batch - 1)) : offset;
+
+      RPC_CALL8_IN_BULK(eglIntImageSetColorData_impl,
+         thread,
+         EGLINTIMAGESETCOLORDATA_ID,
+         RPC_EGLID(egl_image),
+         RPC_UINT(image->format),
+         RPC_UINT(0),
+         RPC_INT(offset),
+         RPC_UINT(image->width),
+         RPC_INT(batch),
+         RPC_UINT(image->stride),
+         (const char *)image->storage + adjusted_offset * image->stride,
+         len);
+
+      offset += batch;
+      height -= batch;
+   }
+}
+
+static void send_bound_pixmap(int i)
+{
+   KHRN_IMAGE_WRAP_T image;
+
+   vcos_log_trace("send_bound_pixmap %d %d", i, (int)pixmap_binding[i].egl_image);
+
+   vcos_assert(i >= 0 && i < NUM_PIXMAP_BINDINGS);
+   vcos_assert(pixmap_binding[i].used);
+
+   platform_get_pixmap_info(pixmap_binding[i].pixmap, &image);
+   set_egl_image_color_data(pixmap_binding[i].egl_image, &image);
+   khrn_platform_release_pixmap_info(pixmap_binding[i].pixmap, &image);
+}
+
+static void send_bound_pixmaps(void)
+{
+   int i;
+   for (i = 0; i < NUM_PIXMAP_BINDINGS; i++)
+   {
+      if (pixmap_binding[i].used && pixmap_binding[i].send)
+      {
+         send_bound_pixmap(i);
+      }
+   }
+}
+
+void khrn_platform_bind_pixmap_to_egl_image(EGLNativePixmapType pixmap, EGLImageKHR egl_image, bool send)
+{
+   int i;
+   for (i = 0; i < NUM_PIXMAP_BINDINGS; i++)
+   {
+      if (!pixmap_binding[i].used)
+      {
+
+         vcos_log_trace("khrn_platform_bind_pixmap_to_egl_image %d", i);
+
+         pixmap_binding[i].used = true;
+         pixmap_binding[i].pixmap = pixmap;
+         pixmap_binding[i].egl_image = egl_image;
+         pixmap_binding[i].send = send;
+         if(send)
+            send_bound_pixmap(i);
+         return;
+      }
+   }
+   vcos_assert(0);  /* Not enough NUM_PIXMAP_BINDINGS? */
+}
+
+void khrn_platform_unbind_pixmap_from_egl_image(EGLImageKHR egl_image)
+{
+   int i;
+   for (i = 0; i < NUM_PIXMAP_BINDINGS; i++)
+   {
+      if (pixmap_binding[i].used && pixmap_binding[i].egl_image == egl_image)
+      {
+         pixmap_binding[i].used = false;
+      }
+   }
+}
+
+
+#ifdef EGL_SERVER_DISPMANX
+#define NUM_WIN 6
+
+static bool have_default_dwin[NUM_WIN];
+static EGL_DISPMANX_WINDOW_T default_dwin[NUM_WIN];
+
+static EGL_DISPMANX_WINDOW_T *check_default(EGLNativeWindowType win)
+{
+   int wid = (int)win;
+   if(wid>-NUM_WIN && wid <=0) {
+      /*
+       * Special identifiers indicating the default windows. Either use the
+       * one we've got or create a new one
+       * simple hack for VMCSX_VC4_1.0 release to demonstrate concurrent running of apps under linux
+
+       * win ==  0 => full screen window on display 0
+       * win == -1 => 1/4 screen top left window on display 0
+       * win == -2 => 1/4 screen top right window on display 0
+       * win == -3 => 1/4 screen bottom left window on display 0
+       * win == -4 => 1/4 screen bottom right window on display 0
+       * win == -5 => full screen window on display 2
+
+       * it is expected that Open WFC will provide a proper mechanism in the near future
+       */
+      wid = -wid;
+
+      if (!have_default_dwin[wid]) {
+         DISPMANX_DISPLAY_HANDLE_T display = vc_dispmanx_display_open( (wid == 5) ? 2 : 0 );
+         DISPMANX_MODEINFO_T info;
+         vc_dispmanx_display_get_info(display, &info);
+         int32_t dw = info.width, dh = info.height;
+
+         DISPMANX_UPDATE_HANDLE_T update = vc_dispmanx_update_start( 0 );
+         VC_DISPMANX_ALPHA_T alpha = {DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS, 255, 0};
+         VC_RECT_T dst_rect;
+         VC_RECT_T src_rect;
+
+         int x = 0, y = 0, width = 0, height = 0, layer = 0;
+
+         switch(wid)
+         {
+         case 0:
+            x = 0;    y = 0;    width = dw;   height = dh;   layer = 0; break;
+         case 1:
+            x = 0;    y = 0;    width = dw/2; height = dh/2; layer = 0; break;
+         case 2:
+            x = dw/2; y = 0;    width = dw/2; height = dh/2; layer = 0; break;
+         case 3:
+            x = 0;    y = dh/2; width = dw/2; height = dh/2; layer = 0; break;
+         case 4:
+            x = dw/2; y = dh/2; width = dw/2; height = dh/2; layer = 0; break;
+         case 5:
+            x = 0;    y = 0;    width = dw;   height = dh;   layer = 0; break;
+         }
+
+         src_rect.x = 0;
+         src_rect.y = 0;
+         src_rect.width = width << 16;
+         src_rect.height = height << 16;
+
+         dst_rect.x = x;
+         dst_rect.y = y;
+         dst_rect.width = width;
+         dst_rect.height = height;
+
+         default_dwin[wid].element = vc_dispmanx_element_add ( update, display,
+            layer, &dst_rect, 0/*src*/,
+            &src_rect, DISPMANX_PROTECTION_NONE, &alpha, 0/*clamp*/, 0/*transform*/);
+
+         default_dwin[wid].width = width;
+         default_dwin[wid].height = height;
+
+         vc_dispmanx_update_submit_sync( update );
+
+         have_default_dwin[wid] = true;
+      }
+      return &default_dwin[wid];
+   } else
+      return (EGL_DISPMANX_WINDOW_T*)win;
+}
+
+
+void platform_get_dimensions(EGLDisplay dpy, EGLNativeWindowType win,
+      uint32_t *width, uint32_t *height, uint32_t *swapchain_count)
+{
+   EGL_DISPMANX_WINDOW_T *dwin = check_default(win);
+   vcos_assert(dwin);
+   vcos_assert(dwin->width < 1<<16); // sanity check
+   vcos_assert(dwin->height < 1<<16); // sanity check
+   *width = dwin->width;
+   *height = dwin->height;
+   *swapchain_count = 0;
+}
+
+uint32_t platform_get_handle(EGLDisplay dpy, EGLNativeWindowType win)
+{
+   EGL_DISPMANX_WINDOW_T *dwin = check_default(win);
+   vcos_assert(dwin);
+   vcos_assert(dwin->width < 1<<16); // sanity check
+   vcos_assert(dwin->height < 1<<16); // sanity check
+   return dwin->element;
+}
+
+#endif
+
+uint32_t platform_get_color_format ( uint32_t format ) { return format; }
+void platform_dequeue(EGLDisplay dpy, EGLNativeWindowType window) {}
diff --git a/interface/khronos/common/linux/khrn_client_rpc_linux.c b/interface/khronos/common/linux/khrn_client_rpc_linux.c
new file mode 100755 (executable)
index 0000000..5ad01c0
--- /dev/null
@@ -0,0 +1,528 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#define VCOS_LOG_CATEGORY (&khrn_client_log)
+
+#include "vchiq.h"
+#include "interface/khronos/common/khrn_int_common.h"
+#include "interface/khronos/common/khrn_int_ids.h"
+
+#include "interface/khronos/common/khrn_client.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+
+
+#include <string.h>
+#include <stdio.h>
+
+extern VCOS_LOG_CAT_T khrn_client_log;
+
+static void *workspace; /* for scatter/gather bulks */
+static PLATFORM_MUTEX_T mutex;
+
+#define FOURCC_KHAN VCHIQ_MAKE_FOURCC('K', 'H', 'A', 'N')
+#define FOURCC_KHRN VCHIQ_MAKE_FOURCC('K', 'H', 'R', 'N')
+#define FOURCC_KHHN VCHIQ_MAKE_FOURCC('K', 'H', 'H', 'N')
+
+static VCHIQ_INSTANCE_T khrn_vchiq_instance;
+
+static VCHIQ_SERVICE_HANDLE_T vchiq_khan_service;
+static VCHIQ_SERVICE_HANDLE_T vchiq_khrn_service;
+static VCHIQ_SERVICE_HANDLE_T vchiq_khhn_service;
+
+static VCHIU_QUEUE_T khrn_queue;
+static VCHIU_QUEUE_T khhn_queue;
+
+static VCOS_EVENT_T bulk_event;
+
+VCHIQ_STATUS_T khrn_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
+                  VCHIQ_SERVICE_HANDLE_T handle, void *bulk_userdata)
+{
+   switch (reason) {
+   case VCHIQ_MESSAGE_AVAILABLE:
+      vchiu_queue_push(&khrn_queue, header);
+      break;
+   case VCHIQ_BULK_TRANSMIT_DONE:
+   case VCHIQ_BULK_RECEIVE_DONE:
+      vcos_event_signal(&bulk_event);
+      break;
+   case VCHIQ_SERVICE_OPENED:
+   case VCHIQ_SERVICE_CLOSED:
+   case VCHIQ_BULK_TRANSMIT_ABORTED:
+   case VCHIQ_BULK_RECEIVE_ABORTED:
+      UNREACHABLE(); /* not implemented */
+   }
+
+   return VCHIQ_SUCCESS;
+}
+
+VCHIQ_STATUS_T khhn_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
+                  VCHIQ_SERVICE_HANDLE_T handle, void *bulk_userdata)
+{
+   switch (reason) {
+   case VCHIQ_MESSAGE_AVAILABLE:
+      vchiu_queue_push(&khhn_queue, header);
+      break;
+   case VCHIQ_BULK_TRANSMIT_DONE:
+   case VCHIQ_BULK_RECEIVE_DONE:
+      vcos_event_signal(&bulk_event);
+      break;
+   case VCHIQ_SERVICE_OPENED:
+   case VCHIQ_SERVICE_CLOSED:
+   case VCHIQ_BULK_TRANSMIT_ABORTED:
+   case VCHIQ_BULK_RECEIVE_ABORTED:
+      UNREACHABLE(); /* not implemented */      
+   }
+
+   return VCHIQ_SUCCESS;
+}
+
+VCHIQ_STATUS_T khan_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
+                  VCHIQ_SERVICE_HANDLE_T handle, void *bulk_userdata)
+{
+   switch (reason) {
+   case VCHIQ_MESSAGE_AVAILABLE:
+   {
+      int32_t *data = (int32_t *) header->data;
+      int32_t command = data[0];
+      int32_t *msg = &data[1];
+      vcos_assert(header->size == 16);
+
+      // TODO should be able to remove this eventually.
+      // If incoming message is not addressed to this process, then ignore it.
+      // Correct process should then pick it up.
+      uint64_t pid = vchiq_get_client_id(handle);
+      if((msg[0] != (uint32_t) pid) || (msg[1] != (uint32_t) (pid >> 32)))
+      {
+         printf("khan_callback: message for wrong process; pid = %X, msg pid = %X\n",
+            (uint32_t) pid, msg[0]);
+         return VCHIQ_SUCCESS;
+      } // if
+
+      if (command == ASYNC_COMMAND_DESTROY)
+      {
+         /* todo: destroy */
+      }
+      else
+      {
+         PLATFORM_SEMAPHORE_T sem;
+         if (khronos_platform_semaphore_create(&sem, msg, 1) == KHR_SUCCESS)
+         {
+            switch (command) {
+            case ASYNC_COMMAND_WAIT:
+               khronos_platform_semaphore_acquire(&sem);
+               break;
+            case ASYNC_COMMAND_POST:
+               khronos_platform_semaphore_release(&sem);
+               break;
+            default:
+               vcos_assert_msg(0, "khan_callback: unknown message type");
+               break;
+            }
+            khronos_platform_semaphore_destroy(&sem);
+         }
+      } // else
+      vchiq_release_message(handle, header);
+      break;
+   }
+   case VCHIQ_BULK_TRANSMIT_DONE:
+   case VCHIQ_BULK_RECEIVE_DONE:
+      UNREACHABLE();
+      break;
+   case VCHIQ_SERVICE_OPENED:
+      vcos_assert_msg(0, "khan_callback: VCHIQ_SERVICE_OPENED");
+      break;
+   case VCHIQ_SERVICE_CLOSED:
+      vcos_assert_msg(0, "khan_callback: VCHIQ_SERVICE_CLOSED");
+      break;
+   case VCHIQ_BULK_TRANSMIT_ABORTED:
+   case VCHIQ_BULK_RECEIVE_ABORTED:
+   default:
+      UNREACHABLE(); /* not implemented */      
+   }
+
+   return VCHIQ_SUCCESS;
+}
+
+void vc_vchi_khronos_init()
+{
+   VCOS_STATUS_T status = vcos_event_create(&bulk_event, NULL);
+   UNUSED_NDEBUG(status);
+   vcos_assert(status == VCOS_SUCCESS);
+   
+   if (vchiq_initialise(&khrn_vchiq_instance) != VCHIQ_SUCCESS)
+   {
+      vcos_log_error("* failed to open vchiq device");
+      
+      exit(1);
+   }
+
+   vcos_log_trace("gldemo: connecting");
+
+   if (vchiq_connect(khrn_vchiq_instance) != VCHIQ_SUCCESS)
+   {
+      vcos_log_error("* failed to connect");
+      
+      exit(1);
+   }
+
+   VCHIQ_STATUS_T khan_return, khrn_return, khhn_return;
+   VCHIQ_SERVICE_PARAMS_T params;
+
+   params.userdata = NULL;
+   params.version = VC_KHRN_VERSION;
+   params.version_min = VC_KHRN_VERSION;
+
+   params.fourcc = FOURCC_KHAN;
+   params.callback = khan_callback;
+   khan_return = vchiq_open_service(khrn_vchiq_instance, &params, &vchiq_khan_service);
+
+   params.fourcc = FOURCC_KHRN;
+   params.callback = khrn_callback;
+   khrn_return = vchiq_open_service(khrn_vchiq_instance, &params, &vchiq_khrn_service);
+
+   params.fourcc = FOURCC_KHHN;
+   params.callback = khhn_callback;
+   khhn_return = vchiq_open_service(khrn_vchiq_instance, &params, &vchiq_khhn_service);
+
+   if (khan_return != VCHIQ_SUCCESS ||
+       khrn_return != VCHIQ_SUCCESS ||
+       khhn_return != VCHIQ_SUCCESS)
+   {
+      vcos_log_error("* failed to add service - already in use?");
+      
+      exit(1);
+   }
+   vchiu_queue_init(&khrn_queue, 64);
+   vchiu_queue_init(&khhn_queue, 64);
+
+   vcos_log_trace("gldemo: connected");
+
+   /*
+      attach to process (there's just one)
+   */
+
+//   bool success = client_process_attach();
+//   vcos_assert(success);
+}
+
+bool khclient_rpc_init(void)
+{
+   workspace = NULL;
+   return platform_mutex_create(&mutex) == KHR_SUCCESS;
+}
+
+void rpc_term(void)
+{
+   if (workspace) { khrn_platform_free(workspace); }
+   platform_mutex_destroy(&mutex);
+}
+
+static VCHIQ_SERVICE_HANDLE_T get_handle(CLIENT_THREAD_STATE_T *thread)
+{
+   VCHIQ_SERVICE_HANDLE_T result = (thread->high_priority ? vchiq_khhn_service : vchiq_khrn_service);
+       return result;
+}
+
+static VCHIU_QUEUE_T *get_queue(CLIENT_THREAD_STATE_T *thread)
+{
+   return thread->high_priority ? &khhn_queue : &khrn_queue;
+}
+
+static void check_workspace(uint32_t size)
+{
+   /* todo: find a better way to handle scatter/gather bulks */
+   vcos_assert(size <= KHDISPATCH_WORKSPACE_SIZE);
+   if (!workspace) {
+      workspace = khrn_platform_malloc(KHDISPATCH_WORKSPACE_SIZE, "rpc_workspace");
+      vcos_assert(workspace);
+   }
+}
+
+static void merge_flush(CLIENT_THREAD_STATE_T *thread)
+{
+   vcos_log_trace("merge_flush start");
+   
+   vcos_assert(thread->merge_pos >= CLIENT_MAKE_CURRENT_SIZE);
+
+   /*
+      don't transmit just a make current -- in the case that there is only a
+      make current in the merge buffer, we have already sent a control message
+      for the rpc call (and with it a make current) and own the big lock
+   */
+
+   if (thread->merge_pos > CLIENT_MAKE_CURRENT_SIZE) {
+      VCHIQ_ELEMENT_T element;
+      
+      rpc_begin(thread);
+
+      element.data = thread->merge_buffer;
+      element.size = thread->merge_pos;
+
+      VCHIQ_STATUS_T success = vchiq_queue_message(get_handle(thread), &element, 1);
+      UNUSED_NDEBUG(success);      
+      vcos_assert(success == VCHIQ_SUCCESS);
+
+      thread->merge_pos = 0;
+
+      client_send_make_current(thread);
+
+      vcos_assert(thread->merge_pos == CLIENT_MAKE_CURRENT_SIZE);
+      
+      rpc_end(thread);
+   }
+   vcos_log_trace( "merge_flush end");
+   
+}
+
+void rpc_flush(CLIENT_THREAD_STATE_T *thread)
+{
+   merge_flush(thread);
+}
+
+void rpc_high_priority_begin(CLIENT_THREAD_STATE_T *thread)
+{
+   vcos_assert(!thread->high_priority);
+   merge_flush(thread);
+   thread->high_priority = true;
+}
+
+void rpc_high_priority_end(CLIENT_THREAD_STATE_T *thread)
+{
+   vcos_assert(thread->high_priority);
+   merge_flush(thread);
+   thread->high_priority = false;
+}
+
+uint32_t rpc_send_ctrl_longest(CLIENT_THREAD_STATE_T *thread, uint32_t len_min)
+{
+   uint32_t len = MERGE_BUFFER_SIZE - thread->merge_pos;
+   if (len < len_min) {
+      len = MERGE_BUFFER_SIZE - CLIENT_MAKE_CURRENT_SIZE;
+   }
+   return len;
+}
+
+void rpc_send_ctrl_begin(CLIENT_THREAD_STATE_T *thread, uint32_t len)
+{
+   //CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   vcos_assert(len == rpc_pad_ctrl(len));
+   if ((thread->merge_pos + len) > MERGE_BUFFER_SIZE) {
+      merge_flush(thread);
+   }
+
+   thread->merge_end = thread->merge_pos + len;
+}
+
+void rpc_send_ctrl_write(CLIENT_THREAD_STATE_T *thread, const uint32_t in[], uint32_t len) /* len bytes read, rpc_pad_ctrl(len) bytes written */
+{
+   //CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   memcpy(thread->merge_buffer + thread->merge_pos, in, len);
+   thread->merge_pos += rpc_pad_ctrl(len);
+   vcos_assert(thread->merge_pos <= MERGE_BUFFER_SIZE);
+}
+
+void rpc_send_ctrl_end(CLIENT_THREAD_STATE_T *thread)
+{
+   //CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   vcos_assert(thread->merge_pos == thread->merge_end);
+}
+
+static void send_bulk(CLIENT_THREAD_STATE_T *thread, const void *in, uint32_t len)
+{
+   if (len <= KHDISPATCH_CTRL_THRESHOLD) {
+      VCHIQ_ELEMENT_T element;
+
+      element.data = in;
+      element.size = len;
+
+      VCHIQ_STATUS_T vchiq_status = vchiq_queue_message(get_handle(thread), &element, 1);
+      UNUSED_NDEBUG(vchiq_status);
+      vcos_assert(vchiq_status == VCHIQ_SUCCESS);
+   } else {
+      VCHIQ_STATUS_T vchiq_status = vchiq_queue_bulk_transmit(get_handle(thread), in, rpc_pad_bulk(len), NULL);
+      UNUSED_NDEBUG(vchiq_status);      
+      vcos_assert(vchiq_status == VCHIQ_SUCCESS);
+      VCOS_STATUS_T vcos_status = vcos_event_wait(&bulk_event);
+      UNUSED_NDEBUG(vcos_status);      
+      vcos_assert(vcos_status == VCOS_SUCCESS);
+   }
+}
+
+static void recv_bulk(CLIENT_THREAD_STATE_T *thread, void *out, uint32_t len)
+{
+   if (len <= KHDISPATCH_CTRL_THRESHOLD) {
+      VCHIQ_HEADER_T *header = vchiu_queue_pop(get_queue(thread));
+      vcos_assert(header->size == len);
+      memcpy(out, header->data, len);
+      vchiq_release_message(get_handle(thread), header);
+   } else {
+      VCHIQ_STATUS_T vchiq_status = vchiq_queue_bulk_receive(get_handle(thread), out, rpc_pad_bulk(len), NULL);
+      UNUSED_NDEBUG(vchiq_status);
+      vcos_assert(vchiq_status == VCHIQ_SUCCESS);
+      VCOS_STATUS_T vcos_status = vcos_event_wait(&bulk_event);
+      UNUSED_NDEBUG(vcos_status);      
+      vcos_assert(vcos_status == VCOS_SUCCESS);
+   }
+}
+
+void rpc_send_bulk(CLIENT_THREAD_STATE_T *thread, const void *in, uint32_t len)
+{
+   if (in && len) {
+      //CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+      merge_flush(thread);
+
+      send_bulk(thread, in, len);
+   }
+}
+
+void rpc_send_bulk_gather(CLIENT_THREAD_STATE_T *thread, const void *in, uint32_t len, int32_t stride, uint32_t n)
+{
+#if 1
+   if (in && len) {
+      //CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+      merge_flush(thread);
+
+      if (len == stride) {
+         /* hopefully should be the common case */
+         send_bulk(thread, in, n * len);
+      } else {
+         check_workspace(n * len);
+         rpc_gather(workspace, in, len, stride, n);
+         send_bulk(thread, workspace, n * len);
+      }
+   }
+#else
+   UNREACHABLE();
+#endif
+}
+
+uint32_t rpc_recv(CLIENT_THREAD_STATE_T *thread, void *out, uint32_t *len_io, RPC_RECV_FLAG_T flags)
+{
+   uint32_t res = 0;
+   uint32_t len;
+   bool recv_ctrl;
+
+   if (!len_io) { len_io = &len; }
+
+   recv_ctrl = flags & (RPC_RECV_FLAG_RES | RPC_RECV_FLAG_CTRL | RPC_RECV_FLAG_LEN); /* do we want to receive anything in the control channel at all? */
+   vcos_assert(recv_ctrl || (flags & RPC_RECV_FLAG_BULK)); /* must receive something... */
+   vcos_assert(!(flags & RPC_RECV_FLAG_CTRL) || !(flags & RPC_RECV_FLAG_BULK)); /* can't receive user data over both bulk and control... */
+
+   if (recv_ctrl || len_io[0]) { /* do nothing if we're just receiving bulk of length 0 */
+      merge_flush(thread);
+
+      if (recv_ctrl) {
+         VCHIQ_HEADER_T *header = vchiu_queue_pop(get_queue(thread));
+         uint8_t *ctrl = (uint8_t *)header->data;
+         vcos_assert(header->size >= (!!(flags & RPC_RECV_FLAG_LEN)*4 + !!(flags & RPC_RECV_FLAG_RES)*4) );
+         if (flags & RPC_RECV_FLAG_LEN) {
+            len_io[0] = *((uint32_t *)ctrl);
+            ctrl += 4;
+         }
+         if (flags & RPC_RECV_FLAG_RES) {
+            res = *((uint32_t *)ctrl);
+            ctrl += 4;
+         }
+         if (flags & RPC_RECV_FLAG_CTRL) {
+            memcpy(out, ctrl, len_io[0]);
+            ctrl += len_io[0];
+         }
+         vcos_assert(ctrl == ((uint8_t *)header->data + header->size));
+         vchiq_release_message(get_handle(thread), header);
+      }
+
+      if ((flags & RPC_RECV_FLAG_BULK) && len_io[0]) {
+         if (flags & RPC_RECV_FLAG_BULK_SCATTER) {
+            if ((len_io[0] == len_io[1]) && !len_io[3] && !len_io[4]) {
+               /* hopefully should be the common case */
+               recv_bulk(thread, out, len_io[2] * len_io[0]);
+            } else {
+               check_workspace(len_io[2] * len_io[0]);
+               recv_bulk(thread, workspace, len_io[2] * len_io[0]);
+               rpc_scatter(out, len_io[0], len_io[1], len_io[2], len_io[3], len_io[4], workspace);
+            }
+         } else {
+            recv_bulk(thread, out, len_io[0]);
+         }
+      }
+   }
+
+   return res;
+}
+
+void rpc_begin(CLIENT_THREAD_STATE_T *thread)
+{
+   UNUSED(thread);
+   platform_mutex_acquire(&mutex);
+}
+
+void rpc_end(CLIENT_THREAD_STATE_T *thread)
+{
+   UNUSED(thread);
+   platform_mutex_release(&mutex);
+}
+
+void rpc_use(CLIENT_THREAD_STATE_T *thread)
+{ // TODO - implement this for linux
+   UNUSED(thread);
+}
+
+void rpc_release(CLIENT_THREAD_STATE_T *thread)
+{ // TODO - implement this for linux
+   UNUSED(thread);
+}
+
+void rpc_call8_makecurrent(CLIENT_THREAD_STATE_T *thread, uint32_t id, uint32_t p0,
+   uint32_t p1, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6, uint32_t p7)
+{
+   uint32_t data;
+   if (thread->merge_pos == CLIENT_MAKE_CURRENT_SIZE && (memcpy(&data,thread->merge_buffer,sizeof(data)), data == EGLINTMAKECURRENT_ID))
+   {
+      rpc_begin(thread);
+      vcos_log_trace("rpc_call8_makecurrent collapse onto previous makecurrent");
+
+      thread->merge_pos = 0;
+      
+      RPC_CALL8(eglIntMakeCurrent_impl, thread, EGLINTMAKECURRENT_ID, p0, p1, p2, p3, p4, p5, p6, p7);
+      vcos_assert(thread->merge_pos == CLIENT_MAKE_CURRENT_SIZE);
+
+      rpc_end(thread);
+   }
+   else
+   {
+      RPC_CALL8(eglIntMakeCurrent_impl, thread, EGLINTMAKECURRENT_ID, p0, p1, p2, p3, p4, p5, p6, p7);
+   }
+}
+
+uint64_t rpc_get_client_id(CLIENT_THREAD_STATE_T *thread)
+{
+   return vchiq_get_client_id(get_handle(thread));
+}
diff --git a/interface/khronos/common/openwfc/khrn_client_platform_openwfc.c b/interface/khronos/common/openwfc/khrn_client_platform_openwfc.c
new file mode 100755 (executable)
index 0000000..7eadcfb
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+//==============================================================================
+
+#include "interface/khronos/common/khrn_client_platform.h"
+
+#include "interface/khronos/include/WF/wfc.h"
+#include "interface/khronos/wf/wfc_int.h"
+
+//==============================================================================
+
+typedef struct
+{
+   WFCDevice device;
+   WFCContext context;
+   WFCElement element;
+} WFC_DATA_T;
+
+#define OPENWFC_BOUNCE
+
+//==============================================================================
+
+static EGL_DISPMANX_WINDOW_T *check_default(EGLNativeWindowType win);
+
+//==============================================================================
+
+static bool have_default_dwin;
+static EGL_DISPMANX_WINDOW_T default_dwin;
+
+static WFC_DATA_T wfc_data;
+
+//==============================================================================
+
+uint32_t platform_get_handle(EGLDisplay dpy, EGLNativeWindowType win)
+{
+   EGL_DISPMANX_WINDOW_T *dwin = check_default(win);
+   return dwin->element;  /* same handles used on host and videocore sides */
+}
+
+//------------------------------------------------------------------------------
+
+void platform_get_dimensions(EGLDisplay dpy, EGLNativeWindowType win,
+      uint32_t *width, uint32_t *height, uint32_t *swapchain_count)
+{
+   EGL_DISPMANX_WINDOW_T *dwin = check_default(win);
+
+   *width =  dwin->width;
+   *height = dwin->height;
+   *swapchain_count = 0;
+}
+
+//------------------------------------------------------------------------------
+
+#define NUM_OF_ELEMENTS    2
+
+void *platform_wfc_bounce_thread(void *param)
+// Thread function for making previously-created source bounce around the screen.
+{
+   WFC_BOUNCE_DATA_T *bounce_data = (WFC_BOUNCE_DATA_T *) param;
+
+   uint32_t i;
+   int32_t xstep[NUM_OF_ELEMENTS], ystep[NUM_OF_ELEMENTS];
+   WFCint dest_rect[NUM_OF_ELEMENTS][WFC_RECT_SIZE];
+   WFCint src_rect[WFC_RECT_SIZE];
+   WFCElement element_local[NUM_OF_ELEMENTS];
+
+   uint32_t num_of_elements = NUM_OF_ELEMENTS;
+   WFCElement *element = element_local;
+
+   // Get context (i.e. screen) dimensions.
+   int32_t ctx_width;
+   int32_t ctx_height;
+   int32_t dest_width, dest_height;
+
+   int32_t x, y;
+
+   bool use_local_elements = (bounce_data->num_of_elements == 0);
+   if(!use_local_elements)
+   {
+      vcos_assert(bounce_data->num_of_elements <= NUM_OF_ELEMENTS);
+      vcos_assert(bounce_data->element != NULL);
+      num_of_elements = bounce_data->num_of_elements;
+      element = bounce_data->element;
+   } // if
+
+   // Initialise values
+   ctx_width = wfcGetContextAttribi(bounce_data->device,
+      bounce_data->context, WFC_CONTEXT_TARGET_WIDTH);
+   ctx_height = wfcGetContextAttribi(bounce_data->device,
+      bounce_data->context, WFC_CONTEXT_TARGET_HEIGHT);
+
+   // Change background colour
+   wfcSetContextAttribi(bounce_data->device,
+      bounce_data->context, WFC_CONTEXT_BG_COLOR, 0x0000FFFF);
+
+   float scale = 0.4;
+   if(num_of_elements == 1)
+      {scale = 0.75;}
+
+   dest_width = bounce_data->dest_width * scale;
+   dest_height = bounce_data->dest_height * scale;
+
+   // Define source rectangle
+   src_rect[WFC_RECT_X] = bounce_data->src_x;
+   src_rect[WFC_RECT_Y] = bounce_data->src_y;
+   src_rect[WFC_RECT_WIDTH] = bounce_data->src_width;
+   src_rect[WFC_RECT_HEIGHT] = bounce_data->src_height;
+
+   for(i = 0; i < num_of_elements; i++)
+   {
+      if(use_local_elements)
+      {
+         // Create and set up element
+         element[i] = wfcCreateElement(bounce_data->device,
+            bounce_data->context, NO_ATTRIBUTES);
+         vcos_assert(element[i] != WFC_INVALID_HANDLE);
+
+         wfcInsertElement(bounce_data->device, element[i], WFC_INVALID_HANDLE);
+         if(vcos_verify(wfcGetError(bounce_data->device) == WFC_ERROR_NONE)) {};
+      } // if
+      else
+      {
+         // Element created in calling app, so use that
+         element[i] = bounce_data->element[i];
+      } // else
+
+      wfcSetElementAttribiv(bounce_data->device, element[i],
+         WFC_ELEMENT_SOURCE_RECTANGLE, WFC_RECT_SIZE, src_rect);
+
+      // Attach existing source
+      wfcSetElementAttribi(bounce_data->device, element[i],
+         WFC_ELEMENT_SOURCE, bounce_data->source);
+
+      if(num_of_elements > 1)
+      {
+         wfcSetElementAttribi(bounce_data->device, element[i],
+            WFC_ELEMENT_TRANSPARENCY_TYPES, WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA);
+         wfcSetElementAttribf(bounce_data->device, element[i],
+            WFC_ELEMENT_GLOBAL_ALPHA, 0.75);
+      } // if
+
+      // Define initial destination rectangle
+      dest_rect[i][WFC_RECT_X] = i * 100;
+      dest_rect[i][WFC_RECT_Y] = i * 10;
+      dest_rect[i][WFC_RECT_WIDTH] = dest_width;
+      dest_rect[i][WFC_RECT_HEIGHT] = dest_height;
+      wfcSetElementAttribiv(bounce_data->device, element[i],
+         WFC_ELEMENT_DESTINATION_RECTANGLE, WFC_RECT_SIZE, dest_rect[i]);
+
+      xstep[i] = (i + 1) * 2;
+      ystep[i] = (i + 1) * 2;
+   } // for
+
+   while(!bounce_data->stop_bouncing)
+   {
+      for(i = 0; i < num_of_elements; i++)
+      {
+         // Compute new x and y values.
+         x = dest_rect[i][WFC_RECT_X];
+         y = dest_rect[i][WFC_RECT_Y];
+
+         x += xstep[i];
+         if(x + dest_width >= ctx_width)
+            {x = ctx_width - dest_width - 1; xstep[i] *= -1;}
+         else if(x < 0)
+            {x = 0; xstep[i] *= -1;}
+
+         y += ystep[i];
+         if(y + dest_height >= ctx_height)
+            {y = ctx_height - dest_height - 1; ystep[i] *= -1;}
+         else if(y < 0)
+            {y = 0; ystep[i] *= -1;}
+
+         dest_rect[i][WFC_RECT_X] = x;
+         dest_rect[i][WFC_RECT_Y] = y;
+
+         // Set updated destination rectangle
+         wfcSetElementAttribiv(bounce_data->device, element[i],
+            WFC_ELEMENT_DESTINATION_RECTANGLE, WFC_RECT_SIZE, dest_rect[i]);
+      } // for
+
+      wfcCommit(bounce_data->device, bounce_data->context, WFC_TRUE);
+      vcos_sleep(30);
+   } // while
+
+   // Remove elements
+   if(use_local_elements)
+   {
+      for(i = 0; i < num_of_elements; i++)
+      {
+         wfcDestroyElement(bounce_data->device, element[i]);
+      } // for
+   } // if
+
+   // Change background colour
+   wfcSetContextAttribi(bounce_data->device,
+      bounce_data->context, WFC_CONTEXT_BG_COLOR, 0xFF0000FF);
+
+   wfcCommit(bounce_data->device, bounce_data->context, WFC_TRUE);
+
+   return NULL;
+} // platform_bounce_thread
+
+//==============================================================================
+
+static EGL_DISPMANX_WINDOW_T *check_default(EGLNativeWindowType win)
+{
+   // Window already exists, so return it.
+   if(win != 0)
+      {return (EGL_DISPMANX_WINDOW_T*) win;}
+
+   // Window doesn't exist (= 0), but one has previously been created, so use
+   // that.
+   if(have_default_dwin)
+      {return &default_dwin;}
+
+   // Window doesn't exist, and hasn't previously been created, so make it so.
+   wfc_data.device = wfcCreateDevice(WFC_DEFAULT_DEVICE_ID, NO_ATTRIBUTES);
+   vcos_assert(wfc_data.device != WFC_INVALID_HANDLE);
+   wfc_data.context = wfcCreateOnScreenContext(wfc_data.device, 0, NO_ATTRIBUTES);
+   vcos_assert(wfc_data.context != WFC_INVALID_HANDLE);
+
+   WFCint context_width = wfcGetContextAttribi
+      (wfc_data.device, wfc_data.context, WFC_CONTEXT_TARGET_WIDTH);
+   WFCint context_height = wfcGetContextAttribi
+      (wfc_data.device, wfc_data.context, WFC_CONTEXT_TARGET_HEIGHT);
+
+#ifdef OPENWFC_BOUNCE
+   // Create and attach source
+   default_dwin.element = 1; // Use arbitrary non-zero value for stream number.
+   WFCNativeStreamType stream = (WFCNativeStreamType) default_dwin.element;
+   vcos_assert(stream != WFC_INVALID_HANDLE);
+   WFCSource source = wfcCreateSourceFromStream(wfc_data.device, wfc_data.context, stream, NO_ATTRIBUTES);
+   vcos_assert(source != WFC_INVALID_HANDLE);
+
+   static VCOS_THREAD_T bounce_thread_data;
+   static WFC_BOUNCE_DATA_T bounce_data;
+
+   bounce_data.device = wfc_data.device;
+   bounce_data.context = wfc_data.context;
+   bounce_data.source = source;
+   bounce_data.src_width = context_width;
+   bounce_data.src_height = context_height;
+   bounce_data.dest_width = context_width;
+   bounce_data.dest_height = context_height;
+   bounce_data.stop_bouncing = 0;
+
+   VCOS_STATUS_T status;
+   status = vcos_thread_create(&bounce_thread_data, "bounce_thread", NULL,
+      platform_wfc_bounce_thread, &bounce_data);
+   vcos_assert(status == VCOS_SUCCESS);
+#else
+   WFCint rect_src[WFC_RECT_SIZE] = { 0, 0, 0, 0 };
+   WFCint rect_dest[WFC_RECT_SIZE] = { 0, 0, 0, 0 };
+
+   wfc_data.element = wfcCreateElement(wfc_data.device, wfc_data.context, NO_ATTRIBUTES);
+   vcos_assert(wfc_data.element != WFC_INVALID_HANDLE);
+   default_dwin.element = wfc_data.element;
+
+   wfcInsertElement(wfc_data.device, wfc_data.element, WFC_INVALID_HANDLE);
+   if(vcos_verify(wfcGetError(wfc_data.device) == WFC_ERROR_NONE)) {};
+
+   /* Set element attributes */
+   rect_src[WFC_RECT_X] = 0;
+   rect_src[WFC_RECT_Y] = 0;
+   rect_src[WFC_RECT_WIDTH] = context_width;
+   rect_src[WFC_RECT_HEIGHT] = context_height;
+   wfcSetElementAttribiv(wfc_data.device, wfc_data.element,
+      WFC_ELEMENT_SOURCE_RECTANGLE, WFC_RECT_SIZE, rect_src);
+
+   rect_dest[WFC_RECT_X] = 0;
+   rect_dest[WFC_RECT_Y] = 0;
+   rect_dest[WFC_RECT_WIDTH] = context_width;
+   rect_dest[WFC_RECT_HEIGHT] = context_height;
+   wfcSetElementAttribiv(wfc_data.device, wfc_data.element,
+      WFC_ELEMENT_DESTINATION_RECTANGLE, WFC_RECT_SIZE, rect_dest);
+
+   // Create and attach source
+   default_dwin.element = wfc_data.element; // Stream and element handles given same value.
+   WFCNativeStreamType stream = (WFCNativeStreamType) default_dwin.element;
+   vcos_assert(stream != WFC_INVALID_HANDLE);
+   WFCSource source = wfcCreateSourceFromStream(wfc_data.device, wfc_data.context, stream, NO_ATTRIBUTES);
+   vcos_assert(source != WFC_INVALID_HANDLE);
+
+   wfcSetElementAttribi(wfc_data.device, wfc_data.element, WFC_ELEMENT_SOURCE, source);
+#endif
+
+   // Send to display
+   wfcCommit(wfc_data.device, wfc_data.context, WFC_TRUE);
+
+   // Enable this and future commits to be enacted immediately
+   wfcActivate(wfc_data.device, wfc_data.context);
+
+   default_dwin.width = 800;
+   default_dwin.height = 480;
+
+   have_default_dwin = true;
+
+   return &default_dwin;
+
+} // check_default()
+
+//==============================================================================
diff --git a/interface/khronos/common/vcos/khrn_client_platform_filler_vcos.h b/interface/khronos/common/vcos/khrn_client_platform_filler_vcos.h
new file mode 100755 (executable)
index 0000000..a877594
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_CLIENT_PLATFORM_FILLER_VCOS_H
+#define KHRN_CLIENT_PLATFORM_FILLER_VCOS_H
+
+#include "interface/vcos/vcos.h"
+#include "interface/vcos/vcos_reentrant_mutex.h"
+
+typedef VCOS_STATUS_T KHR_STATUS_T;
+#define KHR_SUCCESS VCOS_SUCCESS
+#define KHR_EAGAIN VCOS_EAGAIN
+
+/*
+   mutex
+*/
+
+typedef VCOS_REENTRANT_MUTEX_T PLATFORM_MUTEX_T;
+
+/* return !VCOS_SUCCESS on failure */
+VCOS_STATIC_INLINE
+KHR_STATUS_T platform_mutex_create(PLATFORM_MUTEX_T *mutex) {
+  return vcos_reentrant_mutex_create(mutex, NULL);
+}
+
+VCOS_STATIC_INLINE
+void platform_mutex_destroy(PLATFORM_MUTEX_T *mutex) {
+   vcos_reentrant_mutex_delete(mutex);
+}
+
+VCOS_STATIC_INLINE
+void platform_mutex_acquire(PLATFORM_MUTEX_T *mutex) {
+   vcos_reentrant_mutex_lock(mutex);
+}
+
+VCOS_STATIC_INLINE
+void platform_mutex_release(PLATFORM_MUTEX_T *mutex) {
+   vcos_reentrant_mutex_unlock(mutex);
+}
+
+/*
+   named counting semaphore
+*/
+
+typedef VCOS_NAMED_SEMAPHORE_T PLATFORM_SEMAPHORE_T;
+
+/* return !VCOS_SUCCESS on failure */
+
+extern
+KHR_STATUS_T khronos_platform_semaphore_create(PLATFORM_SEMAPHORE_T *sem, int name[3], int count);
+
+VCOS_STATIC_INLINE
+void khronos_platform_semaphore_destroy(PLATFORM_SEMAPHORE_T *sem) {
+   vcos_named_semaphore_delete(sem);
+}
+
+VCOS_STATIC_INLINE
+void khronos_platform_semaphore_acquire(PLATFORM_SEMAPHORE_T *sem) {
+   vcos_named_semaphore_wait(sem);
+}
+
+VCOS_STATIC_INLINE
+KHR_STATUS_T khronos_platform_semaphore_try_acquire(PLATFORM_SEMAPHORE_T *sem) {
+   return vcos_named_semaphore_trywait(sem);
+}
+
+VCOS_STATIC_INLINE
+void khronos_platform_semaphore_release(PLATFORM_SEMAPHORE_T *sem) {
+   vcos_named_semaphore_post(sem);
+}
+
+/*
+   thread-local storage
+*/
+
+typedef VCOS_TLS_KEY_T PLATFORM_TLS_T;
+
+/* return !VCOS_SUCCCESS on failure */
+VCOS_STATIC_INLINE
+KHR_STATUS_T platform_tls_create(VCOS_TLS_KEY_T *key) {
+   return vcos_tls_create(key);
+}
+
+#define platform_tls_destroy(tls) vcos_tls_delete(tls)
+
+extern void platform_tls_remove(PLATFORM_TLS_T tls);
+
+/* This has to be per-platform because different platforms do
+ * thread attachment differently.
+ */
+extern void *platform_tls_get(PLATFORM_TLS_T tls);
+extern void* platform_tls_get_check(PLATFORM_TLS_T tls);
+
+#define platform_tls_set(tls, v) vcos_tls_set(tls, v)
+#define platform_tls_remove(tls) vcos_tls_set(tls,NULL)
+
+#endif
+
diff --git a/interface/khronos/common/vcos_vchiq/khrn_client_platform_filler_vcos_vchiq.h b/interface/khronos/common/vcos_vchiq/khrn_client_platform_filler_vcos_vchiq.h
new file mode 100755 (executable)
index 0000000..ac8b0e2
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_CLIENT_PLATFORM_FILLER_VCOS_VCHIQ_H
+#define KHRN_CLIENT_PLATFORM_FILLER_VCOS_VCHIQ_H
+
+#include "interface/vcos/vcos.h"
+#include "interface/vcos/vcos_reentrant_mutex.h"
+
+typedef VCOS_STATUS_T KHR_STATUS_T;
+#define KHR_SUCCESS VCOS_SUCCESS
+
+/*
+   mutex
+*/
+
+typedef VCOS_REENTRANT_MUTEX_T PLATFORM_MUTEX_T;
+
+/* return !VCOS_SUCCESS on failure */
+VCOS_STATIC_INLINE
+KHR_STATUS_T platform_mutex_create(PLATFORM_MUTEX_T *mutex) {
+  return vcos_reentrant_mutex_create(mutex, NULL);
+}
+
+VCOS_STATIC_INLINE
+void platform_mutex_destroy(PLATFORM_MUTEX_T *mutex) {
+   vcos_reentrant_mutex_delete(mutex);
+}
+
+VCOS_STATIC_INLINE
+void platform_mutex_acquire(PLATFORM_MUTEX_T *mutex) {
+   vcos_reentrant_mutex_lock(mutex);
+}
+
+VCOS_STATIC_INLINE
+void platform_mutex_release(PLATFORM_MUTEX_T *mutex) {
+   vcos_reentrant_mutex_unlock(mutex);
+}
+
+/*
+   named counting semaphore
+*/
+
+typedef VCOS_NAMED_SEMAPHORE_T PLATFORM_SEMAPHORE_T;
+
+/* return !VCOS_SUCCESS on failure */
+
+extern
+KHR_STATUS_T khronos_platform_semaphore_create(PLATFORM_SEMAPHORE_T *sem, int name[3], int count);
+
+VCOS_STATIC_INLINE
+void khronos_platform_semaphore_destroy(PLATFORM_SEMAPHORE_T *sem) {
+   vcos_named_semaphore_delete(sem);
+}
+
+VCOS_STATIC_INLINE
+void khronos_platform_semaphore_acquire(PLATFORM_SEMAPHORE_T *sem) {
+   vcos_named_semaphore_wait(sem);
+}
+
+VCOS_STATIC_INLINE
+void khronos_platform_semaphore_release(PLATFORM_SEMAPHORE_T *sem) {
+   vcos_named_semaphore_post(sem);
+}
+
+/*
+   thread-local storage
+*/
+
+typedef VCOS_TLS_KEY_T PLATFORM_TLS_T;
+
+/* return !VCOS_SUCCCESS on failure */
+VCOS_STATIC_INLINE
+KHR_STATUS_T platform_tls_create(VCOS_TLS_KEY_T *key) {
+   return vcos_tls_create(key);
+}
+
+#define platform_tls_destroy(tls) vcos_tls_delete(tls)
+
+extern void platform_tls_remove(PLATFORM_TLS_T tls);
+
+/* This has to be per-platform because different platforms do
+ * thread attachment differently.
+ */
+extern void *platform_tls_get(PLATFORM_TLS_T tls);
+
+
+#define platform_tls_set(tls, v) vcos_tls_set(tls, v)
+#define platform_tls_remove(tls) vcos_tls_set(tls,NULL)
+
+#endif
+
diff --git a/interface/khronos/egl/egl_client.c b/interface/khronos/egl/egl_client.c
new file mode 100755 (executable)
index 0000000..9d617c8
--- /dev/null
@@ -0,0 +1,2511 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+   Global preconditions?
+
+   Server is up (needed by RPC_CALL[n]_RES)
+
+
+   Spec ambiguity:
+
+   What should we do if eglGetError is called twice? Currently we reset the error to EGL_SUCCESS.
+
+   eglGetConfigs:
+   "The number of configurations is returned in num config"
+   We assume this refers to the number of configurations returned, rather than the total number of
+   configurations available. (These are different values if config_size is too small).
+
+   eglChooseConfig:
+   Fail if the same attribute is specified more than once?
+   (I can't find anything in the spec saying what to do in this case)
+
+   In general, which attribute values are accepted and which raise
+   EGL_BAD_ATTRIBUTE is vague.
+
+   In particular, what do we do about the "ignored" and conditionally
+   ignored ones?
+
+   Currently ignoring ("ignored"):
+   case EGL_MAX_PBUFFER_HEIGHT:
+   case EGL_MAX_PBUFFER_PIXELS:
+   case EGL_MAX_PBUFFER_WIDTH:
+   case EGL_NATIVE_VISUAL_ID:
+
+   Currently not ignoring ("conditionally ignored")
+   case EGL_TRANSPARENT_BLUE_VALUE:
+   case EGL_TRANSPARENT_GREEN_VALUE:
+   case EGL_TRANSPARENT_RED_VALUE:
+
+   Currently ignoring ("conditionally ignored")
+   case EGL_NATIVE_VISUAL_TYPE:
+
+   The following sentences in the spec seem to contradict each other:
+   "If EGL_MATCH_NATIVE_PIXMAP is specified in attrib list, it must be followed
+by an attribute value"
+
+   "If EGL_DONT_CARE is specified as an attribute value, then the
+   attribute will not be checked. EGL_DONT_CARE may be specified for all attributes
+   except EGL_LEVEL."
+
+   In addition, EGL_NONE is listed as the default match value for EGL_MATCH_NATIVE_PIXMAP.
+   What happens if EGL_DONT_CARE or EGL_NONE is a valid native pixmap value?
+
+   What we actually do is we always treat the value supplied with EGL_MATCH_NATIVE_PIXMAP
+   as a valid handle (and fail if it's invalid), and ignore it only if it's not in the list
+   at all.
+
+
+   EGL_MATCH_NATIVE_PIXMAP: todo: we'll set thread->error to something like EGL_BAD_ATTRIBUTE; should we be setting it to EGL_BAD_NATIVE_PIXMAP?
+   What is EGL_PRESERVED_RESOURCES?
+
+
+
+   Do we need to do anything for EGL_LEVEL?
+
+   What is EGL_PRESERVED_RESOURCES?
+   What exactly are EGL_NATIVE_VISUAL_ID, EGL_NATIVE_VISUAL_TYPE?
+
+
+   Implementation notes:
+
+   We only support one display. This is assumed to have a native display_id
+   of 0 (==EGL_DEFAULT_DISPLAY) and an EGLDisplay id of 1
+
+   All EGL client functions preserve the invariant (CLIENT_THREAD_STATE_ERROR)
+
+   It would be nice for the EGL version to only be defined in one place (rather than both eglInitialize and eglQueryString).
+
+   We allow implicit casts from bool to EGLint
+
+
+   We make the following assumptions:
+
+      EGL_CONFIG_CAVEAT (all EGL_NONE)
+      EGL_COLOR_BUFFER_TYPE (all EGL_RGB_BUFFER)
+      EGL_SAMPLES (if EGL_SAMPLES is 1 then all 4 else all 0)
+      EGL_NATIVE_RENDERABLE is true
+      EGL_MAX_PBUFFER_WIDTH, EGL_MAX_PBUFFER_HEIGHT, EGL_MIN_SWAP_INTERVAL, EGL_MAX_SWAP_INTERVAL are the same for all configs
+
+      All configs support all of:
+         (EGL_PBUFFER_BIT | EGL_PIXMAP_BIT | EGL_WINDOW_BIT | EGL_VG_COLORSPACE_LINEAR_BIT | EGL_VG_ALPHA_FORMAT_PRE_BIT | EGL_MULTISAMPLE_RESOLVE_BOX_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT);
+
+
+   EGL_OPTIMAL_FORMAT_BIT_KHR: Considered optimal if no format conversion needs doing
+
+   EGL_TRANSPARENT_TYPE is always EGL_NONE because we don't support EGL_TRANSPARENT_RGB. Should there be an EGL_TRANSPARENT_ALPHA?
+*/
+
+#define VCOS_LOG_CATEGORY (&egl_client_log_cat)
+
+#include "interface/khronos/common/khrn_client_mangle.h"
+
+#include "interface/khronos/common/khrn_int_common.h"
+#include "interface/khronos/common/khrn_options.h"
+
+#include "interface/khronos/egl/egl_client_surface.h"
+#include "interface/khronos/egl/egl_client_context.h"
+#include "interface/khronos/egl/egl_client_config.h"
+
+#include "interface/khronos/common/khrn_client.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+
+#ifdef RPC_DIRECT
+#include "interface/khronos/egl/egl_int_impl.h"
+#endif
+
+#if defined(WIN32) || defined(__mips__)
+#include "interface/khronos/common/khrn_int_misc_impl.h"
+#endif
+
+#ifdef KHRONOS_EGL_PLATFORM_OPENWFC
+#include "interface/khronos/wf/wfc_client_stream.h"
+#endif
+
+#if defined(RPC_DIRECT_MULTI)
+#include "middleware/khronos/egl/egl_server.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+
+#include "interface/khronos/egl/egl_client_cr.c"
+
+VCOS_LOG_CAT_T egl_client_log_cat;
+
+static void egl_current_release(CLIENT_PROCESS_STATE_T *process, EGL_CURRENT_T *current);
+void egl_gl_flush_callback(bool wait);
+void egl_vg_flush_callback(bool wait);
+
+/*
+TODO: do an RPC call to make sure the Khronos vll is loaded (and that it stays loaded until eglTerminate)
+Also affects global image (and possibly others?)
+   EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
+
+   Khronos documentation:
+
+   EGL may be initialized on a display by calling
+   EGLBoolean eglInitialize(EGLDisplay dpy, EGLint
+   *major, EGLint *minor);
+   EGL TRUE is returned on success, and major and minor are updated with the major
+   and minor version numbers of the EGL implementation (for example, in an EGL
+   1.2 implementation, the values of *major and *minor would be 1 and 2, respectively).
+   major and minor are not updated if they are specified as NULL.
+   EGL FALSE is returned on failure and major and minor are not updated. An
+   EGL BAD DISPLAY error is generated if the dpy argument does not refer to a valid
+   EGLDisplay. An EGL NOT INITIALIZED error is generated if EGL cannot be
+   initialized for an otherwise valid dpy.
+   Initializing an already-initialized display is allowed, but the only effect of such
+   a call is to return EGL TRUE and update the EGL version numbers. An initialized
+   display may be used from other threads in the same address space without being
+   initalized again in those threads.
+
+   Implementation notes:
+
+   client_egl_get_process_state sets some errors for us.
+
+   Preconditions:
+
+   major is NULL or a valid pointer
+   minor is NULL or a valid pointer
+   eglTerminate(dpy) must be called at some point after calling this function if we return EGL_TRUE.
+
+   Postconditions:
+
+   The following conditions cause error to assume the specified value
+
+      EGL_BAD_DISPLAY               An EGLDisplay argument does not name a valid EGLDisplay
+      EGL_NOT_INITIALIZED           EGL is not initialized, or could not be initialized, for the specified display.
+      EGL_SUCCESS                   Function succeeded.
+
+   if more than one condition holds, the first error is generated.
+
+   Invariants preserved:
+
+   -
+
+   Invariants used:
+
+   -
+*/
+
+EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   EGLBoolean result;
+
+   CLIENT_LOCK();
+
+   {
+      CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_FALSE);
+
+      if (process) {
+         if (!client_process_state_init(process))
+         {
+            thread->error = EGL_NOT_INITIALIZED;
+            result = EGL_FALSE;
+         }
+         else
+         {
+            thread->error = EGL_SUCCESS;
+            result = EGL_TRUE;
+         }
+      } else
+         result = EGL_FALSE;
+
+      if (result) {
+         if (major)
+            *major = 1;
+         if (minor)
+            *minor = 4;
+      }
+   }
+
+   CLIENT_UNLOCK();
+
+   vcos_log_set_level(&egl_client_log_cat, VCOS_LOG_WARN);
+   vcos_log_register("egl_client", &egl_client_log_cat);
+   vcos_log_info("eglInitialize end. dpy=%d.", (int)dpy);
+   khrn_init_options();
+
+   return result;
+}
+
+/*
+   EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy)
+
+   Khronos documentation:
+
+   To release resources associated with use of EGL and client APIs on a display,
+   call
+   EGLBoolean eglTerminate(EGLDisplay dpy);
+   Termination marks all EGL-specific resources associated with the specified display
+   for deletion. If contexts or surfaces created with respect to dpy are current (see
+   section 3.7.3) to any thread, then they are not actually released while they remain
+   current. Such contexts and surfaces will be destroyed, and all future references to
+   them will become invalid, as soon as any otherwise valid eglMakeCurrent call is
+   made from the thread they are bound to.
+   eglTerminate returns EGL TRUE on success.
+   If the dpy argument does not refer to a valid EGLDisplay, EGL FALSE is
+   returned, and an EGL BAD DISPLAY error is generated.
+   Termination of a display that has already been terminated, or has not yet been
+   initialized, is allowed, but the only effect of such a call is to return EGL TRUE, since
+   there are no EGL resources associated with the display to release. A terminated
+   display may be re-initialized by calling eglInitialize again. When re-initializing
+   a terminated display, resources which were marked for deletion as a result of the
+   earlier termination remain so marked, and references to them are not valid.
+
+   Implementation notes:
+
+   -
+
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   The following conditions cause error to assume the specified value
+
+      EGL_BAD_DISPLAY               An EGLDisplay argument does not name a valid EGLDisplay
+      EGL_SUCCESS                   Function succeeded.
+
+   if more than one condition holds, the first error is generated.
+
+   Invariants preserved:
+
+   -
+
+   Invariants used:
+
+   -
+*/
+
+EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   vcos_log_trace("eglTerminate start. dpy=%d", (int)dpy);
+
+#ifdef RPC_DIRECT_MULTI
+       return true;  //it is moved to khronos_exit
+#else
+   {
+      EGLBoolean result;
+      CLIENT_LOCK();
+
+      {
+         CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_FALSE);
+
+         if (process) {
+            client_process_state_term(process);
+
+            thread->error = EGL_SUCCESS;
+            result = EGL_TRUE;
+
+            client_try_unload_server(process);
+         } else
+            result = EGL_FALSE;
+      }
+
+      CLIENT_UNLOCK();
+
+      vcos_log_trace("eglTerminate end. dpy=%d", (int)dpy);
+      vcos_log_unregister(&egl_client_log_cat);
+      return result;
+   }
+#endif
+}
+
+/*
+   EGLAPI const char EGLAPIENTRY * eglQueryString(EGLDisplay dpy, EGLint name)
+
+   Khronos documentation:
+
+   3.3 EGL Versioning
+const char *eglQueryString(EGLDisplay dpy, EGLint
+name);
+eglQueryString returns a pointer to a static, zero-terminated string describing
+some aspect of the EGL implementation running on the specified display.
+name may be one of EGL CLIENT APIS, EGL EXTENSIONS, EGL VENDOR, or
+EGL VERSION.
+The EGL CLIENT APIS string describes which client rendering APIs are supported.
+It is zero-terminated and contains a space-separated list of API names,
+which must include at least one of \91\91OpenGL ES\92\92 or \91\91OpenVG\92\92.
+Version 1.3 - December 4, 2006
+3.4. CONFIGURATION MANAGEMENT 13
+The EGL EXTENSIONS string describes which EGL extensions are supported
+by the EGL implementation running on the specified display. The string is zeroterminated
+and contains a space-separated list of extension names; extension names
+themselves do not contain spaces. If there are no extensions to EGL, then the empty
+string is returned.
+The format and contents of the EGL VENDOR string is implementation dependent.
+The format of the EGL VERSION string is:
+<major version.minor version><space><vendor specific info>
+Both the major and minor portions of the version number are numeric. Their values
+must match the major and minor values returned by eglInitialize (see section 3.2).
+The vendor-specific information is optional; if present, its format and contents are
+implementation specific.
+On failure, NULL is returned. An EGL NOT INITIALIZED error is generated if
+EGL is not initialized for dpy. An EGL BAD PARAMETER error is generated if name
+is not one of the values described above.
+
+   Implementation notes:
+
+   We support the following extensions but they can be removed from the driver if defined to zero.
+      EGL_KHR_image extensions
+      EGL_KHR_lock_surface
+
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   The following conditions cause error to assume the specified value
+
+      EGL_BAD_DISPLAY               An EGLDisplay argument does not name a valid EGLDisplay
+      EGL_NOT_INITIALIZED           EGL is not initialized for the specified display.
+      EGL_BAD_PARAMETER             name is not one of {EGL_CLIENT_APIS, EGL_EXTENSIONS, EGL_VENDOR, EGL_VERSION}
+      EGL_SUCCESS                   Function succeeded.
+
+   if more than one condition holds, the first error is generated.
+
+   Return value is NULL or a pointer to a null-terminated string which is valid forever.
+
+   Invariants preserved:
+
+   -
+
+   Invariants used:
+
+   -
+*/
+
+EGLAPI const char EGLAPIENTRY * eglQueryString(EGLDisplay dpy, EGLint name)
+{
+   CLIENT_THREAD_STATE_T *thread;
+   CLIENT_PROCESS_STATE_T *process;
+   const char *result = NULL;
+
+   if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
+   {
+      thread->error = EGL_SUCCESS;
+      switch (name) {
+      case EGL_CLIENT_APIS:
+         result = "OpenGL_ES OpenVG";
+         break;
+      case EGL_EXTENSIONS:
+         //TODO: this list isn't quite correct
+         result = ""
+#if EGL_KHR_image
+            "EGL_KHR_image EGL_KHR_image_base EGL_KHR_image_pixmap EGL_KHR_vg_parent_image EGL_KHR_gl_texture_2D_image EGL_KHR_gl_texture_cubemap_image "
+#endif
+#if EGL_KHR_lock_surface
+            "EGL_KHR_lock_surface "
+#endif
+#if EGL_ANDROID_swap_rectangle
+            "EGL_ANDROID_swap_rectangle "
+#endif
+#ifdef ANDROID
+            "EGL_ANDROID_image_native_buffer "
+#endif
+#ifdef ANDROID
+#ifdef EGL_KHR_fence_sync
+            "EGL_KHR_fence_sync "
+#endif
+#endif
+            ;
+         break;
+      case EGL_VENDOR:
+         result = "Broadcom";
+         break;
+      case EGL_VERSION:
+         result = "1.4";
+         break;
+      default:
+         thread->error = EGL_BAD_PARAMETER;
+         result = NULL;
+      }
+      CLIENT_UNLOCK();
+   } else
+      result = NULL;
+
+   return result;
+}
+
+/*
+   EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list)
+
+   Khronos documentation:
+
+   3.5.1 Creating On-Screen Rendering Surfaces
+   To create an on-screen rendering surface, first create a native platform window
+   with attributes corresponding to the desired EGLConfig (e.g. with the same color
+   depth, with other constraints specific to the platform). Using the platform-specific
+   type EGLNativeWindowType, which is the type of a handle to that native window,
+   then call:
+
+   EGLSurface eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win,
+   const EGLint *attrib_list);
+
+   eglCreateWindowSurface creates an onscreen EGLSurface and returns a handle
+   to it. Any EGL context created with a compatible EGLConfig can be used to
+   render into this surface.
+
+   attrib list specifies a list of attributes for the window. The list has the same
+   structure as described for eglChooseConfig. Attributes that can be specified in
+   attrib list include EGL_RENDER_BUFFER, EGL_VG_COLORSPACE, and EGL_VG_ALPHA_FORMAT.
+   It is possible that some platforms will define additional attributes specific to
+   those environments, as an EGL extension.
+
+   attrib list may be NULL or empty (first attribute is EGL_NONE), in which case
+   all attributes assumes their default value as described below.
+   EGL_RENDER_BUFFER specifies which buffer should be used for client API
+   rendering to the window, as described in section 2.2.2. If its value is EGL_SINGLE_BUFFER,
+   then client APIs should render directly into the visible window.
+
+   If its value is EGL_BACK_BUFFER, then all client APIs should render into the back
+   buffer. The default value of EGL_RENDER_BUFFER is EGL_BACK_BUFFER.
+
+   Client APIs may not be able to respect the requested rendering buffer. To
+   determine the actual buffer being rendered to by a context, call eglQueryContext
+   (see section 3.7.4).
+
+   EGL_VG_COLORSPACE specifies the color space used by OpenVG when
+   rendering to the surface. If its value is EGL_VG_COLORSPACE_sRGB, then
+   a non-linear, perceptually uniform color space is assumed, with a corresponding
+   VGImageFormat of form VG_s*. If its value is EGL_VG_-
+   COLORSPACE_LINEAR, then a linear color space is assumed, with a corresponding
+   VGImageFormat of form VG_l*. The default value of EGL_VG_COLORSPACE
+   is EGL_VG_COLORSPACE_sRGB.
+
+   EGL_VG_ALPHA_FORMAT specifies how alpha values are interpreted by
+   OpenVG when rendering to the surface. If its value is EGL_VG_ALPHA_FORMAT_-
+   NONPRE, then alpha values are not premultipled. If its value is EGL_VG_ALPHA_-
+   FORMAT_PRE, then alpha values are premultiplied. The default value of EGL_VG_-
+   ALPHA_FORMAT is EGL_VG_ALPHA_FORMAT_NONPRE.
+
+   Note that the EGL_VG_COLORSPACE and EGL_VG_ALPHA_FORMAT attributes
+   are used only by OpenVG . EGL itself, and other client APIs such as OpenGL and
+   OpenGL ES , do not distinguish multiple colorspace models. Refer to section 11.2
+   of the OpenVG 1.0 specification for more information.
+
+   Similarly, the EGL_VG_ALPHA_FORMAT attribute does not necessarily control
+   or affect the window system\92s interpretation of alpha values, even when the window
+   system makes use of alpha to composite surfaces at display time. The window system's
+   use and interpretation of alpha values is outside the scope of EGL. However,
+   the preferred behavior is for window systems to ignore the value of EGL_VG_-
+   ALPHA_FORMAT when compositing window surfaces.
+
+   On failure eglCreateWindowSurface returns EGL_NO_SURFACE. If the attributes
+   of win do not correspond to config, then an EGL_BAD_MATCH error is generated.
+   If config does not support rendering to windows (the EGL_SURFACE_TYPE
+   attribute does not contain EGL_WINDOW_BIT), an EGL_BAD_MATCH error is generated.
+   If config does not support the colorspace or alpha format attributes specified
+   in attrib list (as defined for eglCreateWindowSurface), an EGL_BAD_MATCH error
+   is generated. If config is not a valid EGLConfig, an EGL_BAD_CONFIG error
+   is generated. If win is not a valid native window handle, then an EGL_BAD_NATIVE_WINDOW
+   error should be generated. If there is already an EGLConfig
+   associated with win (as a result of a previous eglCreateWindowSurface call), then
+   an EGL_BAD_ALLOC error is generated. Finally, if the implementation cannot allocate
+   resources for the new EGL window, an EGL_BAD_ALLOC error is generated.
+
+   Implementation notes:
+
+   -
+
+   Preconditions:
+
+   attrib_list is NULL or a pointer to an EGL_NONE-terminated list of attribute/value pairs
+
+   Postconditions:
+
+   The following conditions cause error to assume the specified value
+
+      EGL_BAD_DISPLAY               An EGLDisplay argument does not name a valid EGLDisplay
+      EGL_NOT_INITIALIZED           EGL is not initialized for the specified display.
+      EGL_BAD_CONFIG                config is not a valid EGLConfig
+      EGL_BAD_NATIVE_WINDOW         win is not a valid native window handle
+      EGL_BAD_ATTRIBUTE             attrib_list contains an undefined EGL attribute or an attribute value that is unrecognized or out of range.
+           (TODO: EGL_BAD_ATTRIBUTE not mentioned in spec)
+      EGL_BAD_NATIVE_WINDOW         window is larger than EGL_CONFIG_MAX_WIDTH x EGL_CONFIG_MAX_HEIGHT
+           (TODO: Maybe EGL_BAD_ALLOC might be more appropriate?)
+      EGL_BAD_ALLOC                 implementation cannot allocate resources for the new EGL window
+           (TODO: If there is already an EGLConfig associated with win)
+      EGL_SUCCESS                   Function succeeded.
+
+   if more than one condition holds, the first error is generated.
+
+   Return value is EGL_NO_SURFACE or an EGLSurface handle which is valid until the EGL session ends or
+   eglDestroySurface is called.
+
+   Invariants preserved:
+
+   (CLIENT_PROCESS_STATE_SURFACES)
+   (CLIENT_PROCESS_STATE_NEXT_SURFACE)
+
+   Invariants used:
+
+   -
+*/
+
+EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list)
+{
+   CLIENT_THREAD_STATE_T *thread;
+   CLIENT_PROCESS_STATE_T *process;
+   EGLSurface result;
+
+   vcos_log_trace("eglCreateWindowSurface for window %p", win);
+
+   if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
+   {
+      uint32_t handle = platform_get_handle(dpy, win);
+
+      if ((int)(size_t)config < 1 || (int)(size_t)config > EGL_MAX_CONFIGS) {
+         thread->error = EGL_BAD_CONFIG;
+         result = EGL_NO_SURFACE;
+      } else if (handle == PLATFORM_WIN_NONE) {
+         // The platform reports that this is an invalid window handle
+         thread->error = EGL_BAD_NATIVE_WINDOW;
+         result = EGL_NO_SURFACE;
+      } else {
+         bool linear = false;
+         bool premult = false;
+         bool single = false;
+
+         if (!egl_surface_check_attribs(WINDOW, attrib_list, &linear, &premult, &single, 0, 0, 0, 0, 0, 0)) {
+            thread->error = EGL_BAD_ATTRIBUTE;
+            result = EGL_NO_SURFACE;
+         } else {
+            EGL_SURFACE_T *surface;
+
+            uint32_t width, height;
+            uint32_t num_buffers = 3;
+            uint32_t swapchain_count;
+
+            platform_get_dimensions(dpy,
+                  win, &width, &height, &swapchain_count);
+
+            if (swapchain_count > 0)
+               num_buffers = swapchain_count;
+            else
+            {
+               if (khrn_options.double_buffer)
+                  num_buffers = 2;
+            }
+
+            if (width <= 0 || width > EGL_CONFIG_MAX_WIDTH || height <= 0 || height > EGL_CONFIG_MAX_HEIGHT) {
+               /* TODO: Maybe EGL_BAD_ALLOC might be more appropriate? */
+               thread->error = EGL_BAD_NATIVE_WINDOW;
+               result = EGL_NO_SURFACE;
+            } else {
+               surface = egl_surface_create(
+                                (EGLSurface)(size_t)process->next_surface,
+                                WINDOW,
+                                linear ? LINEAR : SRGB,
+                                premult ? PRE : NONPRE,
+#ifdef DIRECT_RENDERING
+                                1,
+#else
+                                (uint32_t)(single ? 1 : num_buffers),
+#endif
+                                width, height,
+                                config,
+                                win,
+                                handle,
+                                false,
+                                false,
+                                false,
+                                EGL_NO_TEXTURE,
+                                EGL_NO_TEXTURE,
+                                0, 0);
+
+               if (surface) {
+                  if (khrn_pointer_map_insert(&process->surfaces, process->next_surface, surface)) {
+                     thread->error = EGL_SUCCESS;
+                     result = (EGLSurface)(size_t)process->next_surface++;
+                  } else {
+                     thread->error = EGL_BAD_ALLOC;
+                     result = EGL_NO_SURFACE;
+                     egl_surface_free(surface);
+                  }
+               } else {
+                  thread->error = EGL_BAD_ALLOC;
+                  result = EGL_NO_SURFACE;
+               }
+            }
+         }
+      }
+      CLIENT_UNLOCK();
+   }
+   else
+      result = EGL_NO_SURFACE;
+
+   vcos_log_trace("eglCreateWindowSurface end %i", (int) result);
+
+   return result;
+}
+
+/*
+   EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list)
+
+   Khronos documentation:
+
+   3.5.2 Creating Off-Screen Rendering Surfaces
+   EGL supports off-screen rendering surfaces in pbuffers. Pbuffers differ from windows
+   in the following ways:
+
+   1. Pbuffers are typically allocated in offscreen (non-visible) graphics memory
+   and are intended only for accelerated offscreen rendering. Allocation can fail
+   if there are insufficient graphics resources (implementations are not required
+   to virtualize framebuffer memory). Clients should deallocate pbuffers when
+   they are no longer in use, since graphics memory is often a scarce resource.
+
+   2. Pbuffers are EGL resources and have no associated native window or native
+   window type. It may not be possible to render to pbuffers using native
+   rendering APIs.
+
+   To create a pbuffer, call
+
+      EGLSurface eglCreatePbufferSurface(EGLDisplay dpy,
+         EGLConfig config, const EGLint
+         *attrib_list);
+
+   This creates a single pbuffer surface and returns a handle to it.
+   attrib list specifies a list of attributes for the pbuffer. The list has the same
+   structure as described for eglChooseConfig. Attributes that can be specified in
+   attrib list include EGL_WIDTH, EGL_HEIGHT, EGL_LARGEST_PBUFFER, EGL_TEXTURE_FORMAT,
+   EGL_TEXTURE_TARGET, EGL_MIPMAP_TEXTURE, EGL_VG_COLORSPACE, and EGL_VG_ALPHA_FORMAT.
+
+   It is possible that some platforms will define additional attributes specific to
+   those environments, as an EGL extension.
+
+   attrib list may be NULL or empty (first attribute is EGL_NONE), in which case
+   all the attributes assume their default values as described below.
+
+   EGL_WIDTH and EGL_HEIGHT specify the pixel width and height of the rectangular
+   pbuffer. If the value of EGLConfig attribute EGL_TEXTURE_FORMAT is
+   not EGL_NO_TEXTURE, then the pbuffer width and height specify the size of the
+   level zero texture image. The default values for EGL_WIDTH and EGL_HEIGHT are
+   zero.
+
+   EGL_TEXTURE_FORMAT specifies the format of the OpenGL ES texture that
+   will be created when a pbuffer is bound to a texture map. It can be set to EGL_-
+   TEXTURE_RGB, EGL_TEXTURE_RGBA, or EGL_NO_TEXTURE. The default value of
+   EGL_TEXTURE_FORMAT is EGL_NO_TEXTURE.
+
+   EGL_TEXTURE_TARGET specifies the target for the OpenGL ES texture that
+   will be created when the pbuffer is created with a texture format of EGL_-
+   TEXTURE_RGB or EGL_TEXTURE_RGBA. The target can be set to EGL_NO_-
+   TEXTURE or EGL_TEXTURE_2D. The default value of EGL_TEXTURE_TARGET is
+   EGL_NO_TEXTURE.
+
+   EGL_MIPMAP_TEXTURE indicates whether storage for OpenGL ES mipmaps
+   should be allocated. Space for mipmaps will be set aside if the attribute value
+   is EGL_TRUE and EGL_TEXTURE_FORMAT is not EGL_NO_TEXTURE. The default
+   value for EGL_MIPMAP_TEXTURE is EGL_FALSE.
+
+   Use EGL_LARGEST_PBUFFER to get the largest available pbuffer when the allocation
+   of the pbuffer would otherwise fail. The width and height of the allocated
+   pbuffer will never exceed the values of EGL_WIDTH and EGL_HEIGHT, respectively.
+   If the pbuffer will be used as a OpenGL ES texture (i.e., the value of
+   EGL_TEXTURE_TARGET is EGL_TEXTURE_2D, and the value of EGL_TEXTURE_-
+   FORMAT is EGL_TEXTURE_RGB or EGL_TEXTURE_RGBA), then the aspect ratio
+   will be preserved and the new width and height will be valid sizes for the texture
+   target (e.g. if the underlying OpenGL ES implementation does not support
+   non-power-of-two textures, both the width and height will be a power of 2). Use
+   eglQuerySurface to retrieve the dimensions of the allocated pbuffer. The default
+   value of EGL_LARGEST_PBUFFER is EGL_FALSE.
+
+   EGL_VG_COLORSPACE and EGL_VG_ALPHA_FORMAT have the same meaning
+   and default values as when used with eglCreateWindowSurface.
+   The resulting pbuffer will contain color buffers and ancillary buffers as specified
+   by config.
+
+   The contents of the depth and stencil buffers may not be preserved when rendering
+   an OpenGL ES texture to the pbuffer and switching which image of the
+   texture is rendered to (e.g., switching from rendering one mipmap level to rendering
+   another).
+
+   On failure eglCreatePbufferSurface returns EGL_NO_SURFACE. If the pbuffer
+   could not be created due to insufficient resources, then an EGL_BAD_ALLOC error
+   is generated. If config is not a valid EGLConfig, an EGL_BAD_CONFIG error is
+   generated. If the value specified for either EGL_WIDTH or EGL_HEIGHT is less
+   than zero, an EGL_BAD_PARAMETER error is generated. If config does not support
+   pbuffers, an EGL_BAD_MATCH error is generated. In addition, an EGL_BAD_MATCH
+   error is generated if any of the following conditions are true:
+
+   The EGL_TEXTURE_FORMAT attribute is not EGL_NO_TEXTURE, and EGL_WIDTH
+   and/or EGL_HEIGHT specify an invalid size (e.g., the texture size is
+   not a power of two, and the underlying OpenGL ES implementation does not
+   support non-power-of-two textures).
+
+   The EGL_TEXTURE_FORMAT attribute is EGL_NO_TEXTURE, and EGL_TEXTURE_TARGET
+   is something other than EGL_NO_TEXTURE; or, EGL_TEXTURE_FORMAT is something
+   other than EGL_NO_TEXTURE, and EGL_TEXTURE_TARGET is EGL_NO_TEXTURE.
+
+   Finally, an EGL_BAD_ATTRIBUTE error is generated if any of the EGL_TEXTURE_FORMAT,
+   EGL_TEXTURE_TARGET, or EGL_MIPMAP_TEXTURE attributes
+   are specified, but config does not support OpenGL ES rendering (e.g.
+   the EGL_RENDERABLE_TYPE attribute does not include at least one of EGL_OPENGL_ES_BIT
+   or EGL_OPENGL_ES2_BIT.
+
+   Implementation notes:
+
+   -
+
+   attrib_list is NULL or a pointer to an EGL_NONE-terminated list of attribute/value pairs
+
+   Postconditions:
+
+   The following conditions cause error to assume the specified value
+
+      EGL_BAD_DISPLAY               An EGLDisplay argument does not name a valid EGLDisplay
+      EGL_NOT_INITIALIZED           EGL is not initialized for the specified display.
+      EGL_BAD_CONFIG                config is not a valid EGLConfig
+      EGL_BAD_ATTRIBUTE             attrib_list contains an undefined EGL attribute or an attribute value that is unrecognized or out of range.
+           (TODO: EGL_BAD_ATTRIBUTE not mentioned in spec)
+      EGL_BAD_MATCH                 config doesn't support EGL_BIND_TO_TEXTURE_RGB(A) and you specify EGL_TEXTURE_FORMAT=EGL_TEXTURE_RGB(A)
+           (TODO: no mention of this in the spec)
+      EGL_BAD_ALLOC                 requested dimensions are larger than EGL_CONFIG_MAX_WIDTH x EGL_CONFIG_MAX_HEIGHT
+           (TODO: no mention of this in the spec)
+      EGL_BAD_ALLOC                 implementation cannot allocate resources for the new EGL window
+           (TODO: If there is already an EGLConfig associated with win)
+      EGL_SUCCESS                   Function succeeded.
+
+   if more than one condition holds, the first error is generated.
+
+   Return value is EGL_NO_SURFACE or an EGLSurface handle which is valid until the EGL session ends or
+   eglDestroySurface is called.
+
+   Invariants preserved:
+
+   (CLIENT_PROCESS_STATE_SURFACES)
+   (CLIENT_PROCESS_STATE_NEXT_SURFACE)
+
+   Invariants used:
+
+   -
+*/
+
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config,
+               const EGLint *attrib_list)
+{
+   CLIENT_THREAD_STATE_T *thread;
+   CLIENT_PROCESS_STATE_T *process;
+   EGLSurface result;
+
+   if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
+   {
+      if ((int)(size_t)config < 1 || (int)(size_t)config > EGL_MAX_CONFIGS) {
+         thread->error = EGL_BAD_CONFIG;
+         result = EGL_NO_SURFACE;
+      } else {
+         int width = 0;
+         int height = 0;
+         bool largest_pbuffer = 0;
+         EGLenum texture_format = EGL_NO_TEXTURE;
+         EGLenum texture_target = EGL_NO_TEXTURE;
+         bool mipmap_texture = EGL_FALSE;
+         bool linear = EGL_FALSE;
+         bool premult = EGL_FALSE;
+
+         if (!egl_surface_check_attribs(PBUFFER, attrib_list, &linear, &premult, 0, &width, &height, &largest_pbuffer, &texture_format, &texture_target, &mipmap_texture)) {
+            thread->error = EGL_BAD_ATTRIBUTE;
+            result = EGL_NO_SURFACE;
+         } else if (
+            (texture_format != EGL_NO_TEXTURE && (width == 0 || height == 0)) ||
+            ((texture_format == EGL_NO_TEXTURE) != (texture_target == EGL_NO_TEXTURE)) ||
+            !egl_config_bindable((int)(size_t)config - 1, texture_format)
+         ) {
+
+         /*
+         "In addition, an EGL_BAD_MATCH
+         error is generated if any of the following conditions are true:
+         - The EGL_TEXTURE_FORMAT attribute is not EGL_NO_TEXTURE, and
+         EGL_WIDTH and/or EGL_HEIGHT specify an invalid size (e.g., the texture size
+         is not a power of two, and the underlying OpenGL ES implementation does
+         not support non-power-of-two textures).
+         - The EGL_TEXTURE_FORMAT attribute is EGL_NO_TEXTURE, and
+         EGL_TEXTURE_TARGET is something other than EGL_NO_TEXTURE; or,
+         EGL_TEXTURE_FORMAT is something other than EGL_NO_TEXTURE, and
+         EGL_TEXTURE_TARGET is EGL_NO_TEXTURE."
+          */
+
+         /*
+         TODO It doesn't seem to explicitly say it in the spec, but I'm also
+         generating EGL_BAD_MATCH if the config doesn't support EGL_BIND_TO_TEXTURE_RGB(A)
+         and you specify EGL_TEXTURE_FORMAT=EGL_TEXTURE_RGB(A)
+         */
+            thread->error = EGL_BAD_MATCH;
+            result = EGL_NO_SURFACE;
+         } else if ((width > EGL_CONFIG_MAX_WIDTH || height > EGL_CONFIG_MAX_HEIGHT) && !largest_pbuffer) {
+            /*
+               TODO no mention of this in the spec, but clearly we fail if we try to allocate
+               an oversize pbuffer without the largest_pbuffer stuff enabled
+            */
+
+            thread->error = EGL_BAD_ALLOC;
+            result = EGL_NO_SURFACE;
+         } else {
+            EGL_SURFACE_T *surface = egl_surface_create(
+                             (EGLSurface)(size_t)process->next_surface,
+                             PBUFFER,
+                             linear ? LINEAR : SRGB,
+                             premult ? PRE : NONPRE,
+                             1,
+                             width, height,
+                             config,
+                             0,
+                             PLATFORM_WIN_NONE,
+                             largest_pbuffer,
+                             true,
+                             mipmap_texture,
+                             texture_format,
+                             texture_target,
+                             0, 0);
+
+            if (surface) {
+               if (khrn_pointer_map_insert(&process->surfaces, process->next_surface, surface)) {
+                  thread->error = EGL_SUCCESS;
+                  result = (EGLSurface)(size_t)process->next_surface++;
+               } else {
+                  thread->error = EGL_BAD_ALLOC;
+                  result = EGL_NO_SURFACE;
+                  egl_surface_free(surface);
+               }
+            } else {
+               thread->error = EGL_BAD_ALLOC;
+               result = EGL_NO_SURFACE;
+            }
+         }
+      }
+      CLIENT_UNLOCK();
+   }
+   else
+      result = EGL_NO_SURFACE;
+
+   return result;
+}
+
+typedef struct {
+   CLIENT_PROCESS_STATE_T *process;
+   EGLNativePixmapType pixmap;
+   uint32_t pixmap_server_handle[2];
+   int is_dup;
+} PIXMAP_CHECK_DATA_T;
+
+static void callback_check_duplicate_pixmap(KHRN_POINTER_MAP_T *map, uint32_t key, void *value, void *data)
+{
+   PIXMAP_CHECK_DATA_T *pixmap_check_data = (PIXMAP_CHECK_DATA_T *)data;
+   EGL_SURFACE_T *surface = (EGL_SURFACE_T *)value;
+
+   UNUSED_NDEBUG(map);
+   UNUSED_NDEBUG(key);
+
+   vcos_assert(map == &pixmap_check_data->process->surfaces);
+   vcos_assert(surface != NULL);
+   vcos_assert((uintptr_t)key == (uintptr_t)surface->name);
+
+   if ((surface->type == PIXMAP) && ((pixmap_check_data->pixmap_server_handle[0] || (pixmap_check_data->pixmap_server_handle[1] != (uint32_t)-1)) ?
+      /* compare server handles for server-side pixmaps */
+      ((surface->pixmap_server_handle[0] == pixmap_check_data->pixmap_server_handle[0]) &&
+      (surface->pixmap_server_handle[1] == pixmap_check_data->pixmap_server_handle[1])) :
+      /* compare EGLNativePixmapType for client-side pixmaps */
+      (!surface->pixmap_server_handle[0] && (surface->pixmap_server_handle[1] == (uint32_t)-1) &&
+      (surface->pixmap == pixmap_check_data->pixmap)))) {
+      pixmap_check_data->is_dup = 1;
+   }
+}
+
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config,
+              EGLNativePixmapType pixmap,
+              const EGLint *attrib_list)
+{
+   CLIENT_THREAD_STATE_T *thread;
+   CLIENT_PROCESS_STATE_T *process;
+   EGLSurface result;
+
+   vcos_log_trace("eglCreatePixmapSurface");
+
+   if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
+   {
+      if ((int)(size_t)config < 1 || (int)(size_t)config > EGL_MAX_CONFIGS) {
+         thread->error = EGL_BAD_CONFIG;
+         result = EGL_NO_SURFACE;
+      } else {
+         bool linear = false;
+         bool premult = false;
+
+         if (!egl_surface_check_attribs(PIXMAP, attrib_list, &linear, &premult, 0, 0, 0, 0, 0, 0, 0)) {
+            thread->error = EGL_BAD_ATTRIBUTE;
+            result = EGL_NO_SURFACE;
+         } else {
+            EGL_SURFACE_T *surface;
+
+            KHRN_IMAGE_WRAP_T image;
+            if (!platform_get_pixmap_info(pixmap, &image)) {
+               thread->error = EGL_BAD_NATIVE_PIXMAP;
+               result = EGL_NO_SURFACE;
+            } else {
+               uint32_t server_handle[2] = {0, (uint32_t)-1};
+               platform_get_pixmap_server_handle(pixmap, server_handle);
+
+#if !EGL_BRCM_global_image
+               if (server_handle[1] != -1) {
+                  thread->error = EGL_BAD_PARAMETER;
+                  result = EGL_NO_SURFACE;
+               } else
+#endif
+               if (image.width > EGL_CONFIG_MAX_WIDTH || image.height > EGL_CONFIG_MAX_HEIGHT) {
+                  /* Maybe EGL_BAD_ALLOC might be more appropriate? */
+                  thread->error = EGL_BAD_NATIVE_WINDOW;
+                  result = EGL_NO_SURFACE;
+               } else if (!egl_config_match_pixmap_info((int)(size_t)config - 1, &image) ||
+                  !platform_match_pixmap_api_support(pixmap, egl_config_get_api_support((int)(size_t)config - 1))
+#if EGL_BRCM_global_image
+                  || ((server_handle[1] != (uint32_t)(-1)) && (
+                  (!(image.format & IMAGE_FORMAT_LIN) != !linear) ||
+                  (!(image.format & IMAGE_FORMAT_PRE) != !premult)))
+#endif
+                  ) {
+                  thread->error = EGL_BAD_MATCH;
+                  result = EGL_NO_SURFACE;
+               } else {
+                  /*
+                   * Check that we didn't already use this pixmap in an
+                   * earlier call to eglCreatePixmapSurface()
+                   */
+                  PIXMAP_CHECK_DATA_T pixmap_check_data;
+                  pixmap_check_data.process = process;
+                  pixmap_check_data.pixmap = pixmap;
+                  pixmap_check_data.pixmap_server_handle[0] = 0;
+                  pixmap_check_data.pixmap_server_handle[1] = (uint32_t)-1;
+                  platform_get_pixmap_server_handle(pixmap, pixmap_check_data.pixmap_server_handle);
+                  pixmap_check_data.is_dup = 0;
+
+                  khrn_pointer_map_iterate(&process->surfaces, callback_check_duplicate_pixmap, &pixmap_check_data);
+
+                  if (pixmap_check_data.is_dup) {
+                     thread->error = EGL_BAD_ALLOC;
+                     result = EGL_NO_SURFACE;
+                  } else {
+                     surface = egl_surface_create(
+                                   (EGLSurface)(size_t)process->next_surface,
+                                   PIXMAP,
+                                   linear ? LINEAR : SRGB,
+                                   premult ? PRE : NONPRE,
+                                   1,
+                                   image.width, image.height,
+                                   config,
+                                   0,
+                                   PLATFORM_WIN_NONE,
+                                   false,
+                                   false,
+                                   false,
+                                   EGL_NO_TEXTURE,
+                                   EGL_NO_TEXTURE,
+                                   pixmap, ((server_handle[0] == 0) && (server_handle[1] == (uint32_t)(-1))) ? NULL : server_handle);
+
+                     if (surface) {
+                        if (khrn_pointer_map_insert(&process->surfaces, process->next_surface, surface)) {
+                           thread->error = EGL_SUCCESS;
+                           result = (EGLSurface)(size_t)process->next_surface++;
+                        } else {
+                           thread->error = EGL_BAD_ALLOC;
+                           result = EGL_NO_SURFACE;
+                           egl_surface_free(surface);
+                        }
+                     } else {
+                        thread->error = EGL_BAD_ALLOC;
+                        result = EGL_NO_SURFACE;
+                     }
+                  }
+               }
+            }
+         }
+      }
+      CLIENT_UNLOCK();
+   }
+   else
+      result = EGL_NO_SURFACE;
+
+   return result;
+}
+
+//TODO: if this is a pixmap surface, should we make sure the pixmap gets
+//updated?
+//TODO: should this be a blocking call to the server, so that we know the EGL surface is really
+//destroyed before subsequently destroying the associated window?
+//TODO: is it safe for asynchronous swap notifications to come back after the surface has been
+//destroyed, or do we need to wait for them? (and how?)
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay dpy, EGLSurface surf)
+{
+   CLIENT_THREAD_STATE_T *thread;
+   CLIENT_PROCESS_STATE_T *process;
+   EGLBoolean result;
+
+   vcos_log_trace("eglDestroySurface: surf=%d.\n calling CLIENT_LOCK_AND_GET_STATES...", (int)surf);
+
+   if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
+   {
+      EGL_SURFACE_T *surface;
+
+      thread->error = EGL_SUCCESS;
+
+      vcos_log_trace("eglDestroySurface: calling client_egl_get_surface...");
+      surface = client_egl_get_surface(thread, process, surf);
+
+      if (surface) {
+         surface->is_destroyed = true;
+         khrn_pointer_map_delete(&process->surfaces, (uint32_t)(uintptr_t)surf);
+         vcos_log_trace("eglDestroySurface: calling egl_surface_maybe_free...");
+         egl_surface_maybe_free(surface);
+      }
+
+      result = (thread->error == EGL_SUCCESS ? EGL_TRUE : EGL_FALSE );
+
+      CLIENT_UNLOCK();
+   } else
+      result = EGL_FALSE;
+
+   vcos_log_trace("eglDestroySurface: end");
+   return result;
+}
+
+EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surf,
+            EGLint attribute, EGLint *value)
+{
+   CLIENT_THREAD_STATE_T *thread;
+   CLIENT_PROCESS_STATE_T *process;
+   EGLBoolean result;
+
+   if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
+   {
+      EGL_SURFACE_T *surface;
+
+      thread->error = EGL_SUCCESS;
+
+      surface = client_egl_get_locked_surface(thread, process, surf);
+
+      if (surface) {
+#if EGL_KHR_lock_surface
+         switch (attribute)
+         {
+         case EGL_BITMAP_POINTER_KHR:
+         case EGL_BITMAP_PITCH_KHR:
+         case EGL_BITMAP_ORIGIN_KHR:
+         case EGL_BITMAP_PIXEL_RED_OFFSET_KHR:
+         case EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR:
+         case EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR:
+         case EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR:
+         case EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR:
+            thread->error = egl_surface_get_mapped_buffer_attrib(surface, attribute, value);
+
+            CLIENT_UNLOCK();
+            return (thread->error == EGL_SUCCESS ? EGL_TRUE : EGL_FALSE );
+         default:
+            /* Other attributes can only be queried if the surface is unlocked */
+            if (surface->is_locked) {
+               thread->error = EGL_BAD_ACCESS;
+               CLIENT_UNLOCK();
+               return EGL_FALSE;
+            }
+         }
+#endif
+         if (!egl_surface_get_attrib(surface, attribute, value))
+            thread->error = EGL_BAD_ATTRIBUTE;
+      }
+
+      result = (thread->error == EGL_SUCCESS ? EGL_TRUE : EGL_FALSE );
+
+      CLIENT_UNLOCK();
+   } else
+      result = EGL_FALSE;
+
+   return result;
+}
+
+EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   switch (api) {
+   case EGL_OPENVG_API:
+   case EGL_OPENGL_ES_API:
+      thread->bound_api = api;
+
+      thread->error = EGL_SUCCESS;
+      return EGL_TRUE;
+   default:
+      thread->error = EGL_BAD_PARAMETER;
+      return EGL_FALSE;
+   }
+}
+
+EGLAPI EGLenum EGLAPIENTRY eglQueryAPI(void)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   return thread->bound_api;
+}
+
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient(void)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   //TODO: "If the surface associated with the calling thread's current context is no
+   //longer valid, EGL_FALSE is returned and an EGL_BAD_CURRENT_SURFACE error is
+   //generated".
+
+   (void) RPC_INT_RES(RPC_CALL2_RES(eglIntFlushAndWait_impl,
+                 thread,
+                 EGLINTFLUSHANDWAIT_ID,
+                 RPC_UINT(thread->bound_api == EGL_OPENGL_ES_API),
+                 RPC_UINT(thread->bound_api == EGL_OPENVG_API)));   // return unimportant - read is just to cause blocking
+
+   if (thread->bound_api == EGL_OPENGL_ES_API)
+      egl_gl_flush_callback(true);
+   else
+      egl_vg_flush_callback(true);
+
+   thread->error = EGL_SUCCESS;
+   return EGL_TRUE;
+}
+
+//TODO: update pixmap surfaces?
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread(void)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   bool destroy = false;
+
+
+   vcos_log_trace("eglReleaseThread start.");
+
+   CLIENT_LOCK();
+
+   {
+      CLIENT_PROCESS_STATE_T *process = CLIENT_GET_PROCESS_STATE();
+
+      if (process) {
+         egl_current_release(process, &thread->opengl);
+         egl_current_release(process, &thread->openvg);
+
+#ifdef RPC_LIBRARY
+         /* TODO: not thread safe */
+         const KHRONOS_FUNC_TABLE_T *func_table = khronos_server_lock_func_table(client_library_get_connection());
+         if (func_table) {
+            func_table->khrn_misc_rpc_flush_impl();
+         }
+         khronos_server_unlock_func_table();
+#else
+         RPC_FLUSH(thread);
+#endif
+
+#ifndef RPC_DIRECT_MULTI
+                       //move it to khronos_exit()
+         client_try_unload_server(process);
+#endif
+
+         thread->error = EGL_SUCCESS;
+         destroy = true;
+      }
+   }
+
+   CLIENT_UNLOCK();
+
+   if (destroy)
+      platform_hint_thread_finished();
+
+   vcos_log_trace("eglReleaseThread end.");
+
+   return EGL_TRUE;
+
+   //TODO free thread state?
+}
+
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer(
+         EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
+         EGLConfig config, const EGLint *attrib_list)
+{
+   CLIENT_THREAD_STATE_T *thread;
+   CLIENT_PROCESS_STATE_T *process;
+   EGLSurface result;
+
+   if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
+   {
+#ifndef NO_OPENVG
+      if (buftype != EGL_OPENVG_IMAGE) {
+         thread->error = EGL_BAD_PARAMETER;
+         result = EGL_NO_SURFACE;
+      } else if ((int)(size_t)config < 1 || (int)(size_t)config > EGL_MAX_CONFIGS) {
+         thread->error = EGL_BAD_CONFIG;
+         result = EGL_NO_SURFACE;
+      } else {
+         bool largest_pbuffer = 0;
+         EGLenum texture_format = EGL_NO_TEXTURE;
+         EGLenum texture_target = EGL_NO_TEXTURE;
+         bool mipmap_texture = EGL_FALSE;
+
+         /* Ignore the width and height as specified by attrib_list */
+         /* Also ignore linear and premult */
+         if (!egl_surface_check_attribs(PBUFFER, attrib_list, 0, 0, 0, 0, 0, &largest_pbuffer, &texture_format, &texture_target, &mipmap_texture)) {
+            thread->error = EGL_BAD_ATTRIBUTE;
+            result = EGL_NO_SURFACE;
+         } else if (
+            (texture_format == EGL_NO_TEXTURE) != (texture_target == EGL_NO_TEXTURE) ||
+            !egl_config_bindable((int)(size_t)config - 1, texture_format)
+         ) {
+
+         /*
+         "In addition, an EGL_BAD_MATCH
+         error is generated if any of the following conditions are true:
+         - The EGL_TEXTURE_FORMAT attribute is not EGL_NO_TEXTURE, and
+         EGL_WIDTH and/or EGL_HEIGHT specify an invalid size (e.g., the texture size
+         is not a power of two, and the underlying OpenGL ES implementation does
+         not support non-power-of-two textures).
+         - The EGL_TEXTURE_FORMAT attribute is EGL_NO_TEXTURE, and
+         EGL_TEXTURE_TARGET is something other than EGL_NO_TEXTURE; or,
+         EGL_TEXTURE_FORMAT is something other than EGL_NO_TEXTURE, and
+         EGL_TEXTURE_TARGET is EGL_NO_TEXTURE."
+          */
+
+         /*
+         It doesn't seem to explicitly say it in the spec, but I'm also
+         generating EGL_BAD_MATCH if the config doesn't support EGL_BIND_TO_TEXTURE_RGB(A)
+         and you specify EGL_TEXTURE_FORMAT=EGL_TEXTURE_RGB(A)
+         */
+            thread->error = EGL_BAD_MATCH;
+            result = EGL_NO_SURFACE;
+         } else {
+            EGLint error;
+            EGL_SURFACE_T *surface = egl_surface_from_vg_image(
+                       (VGImage)(size_t)buffer,
+                       (EGLSurface)(size_t)process->next_surface,
+                       config,
+                       largest_pbuffer,
+                       mipmap_texture,
+                       texture_format,
+                       texture_target,
+                       &error);
+
+            if (surface) {
+               if (khrn_pointer_map_insert(&process->surfaces, process->next_surface, surface)) {
+                  thread->error = EGL_SUCCESS;
+                  result = (EGLSurface)(size_t)process->next_surface++;
+               } else {
+                  thread->error = EGL_BAD_ALLOC;
+                  result = EGL_NO_SURFACE;
+                  egl_surface_free(surface);
+               }
+            } else {
+               thread->error = error;
+               result = EGL_NO_SURFACE;
+            }
+         }
+      }
+#else
+      UNUSED(buftype);
+      UNUSED(buffer);
+      UNUSED(config);
+      UNUSED(attrib_list);
+
+      thread->error = EGL_BAD_PARAMETER;
+      result = EGL_NO_SURFACE;
+#endif /* NO_OPENVG */
+      CLIENT_UNLOCK();
+   }
+   else
+      result = EGL_NO_SURFACE;
+
+   return result;
+}
+
+EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surf,
+             EGLint attribute, EGLint value)
+{
+   CLIENT_THREAD_STATE_T *thread;
+   CLIENT_PROCESS_STATE_T *process;
+   EGLBoolean result;
+
+   if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
+   {
+      EGL_SURFACE_T *surface;
+
+      thread->error = EGL_SUCCESS;
+
+      surface = client_egl_get_surface(thread, process, surf);
+
+      if (surface)
+         thread->error = egl_surface_set_attrib(surface, attribute, value);
+
+      result = (thread->error == EGL_SUCCESS ? EGL_TRUE : EGL_FALSE );
+      CLIENT_UNLOCK();
+   } else
+      result = EGL_FALSE;
+
+   return result;
+}
+
+EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage(EGLDisplay dpy, EGLSurface surf, EGLint buffer)
+{
+   CLIENT_THREAD_STATE_T *thread;
+   CLIENT_PROCESS_STATE_T *process;
+   EGLBoolean result;
+
+   if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
+   {
+//TODO: is behaviour correct if there is no current rendering context?
+      EGL_SURFACE_T *surface;
+
+      thread->error = EGL_SUCCESS;
+
+      surface = client_egl_get_surface(thread, process, surf);
+
+      if (surface) {
+         if (surface->texture_format != EGL_NO_TEXTURE) {
+            if (buffer == EGL_BACK_BUFFER) {
+               if (surface->type == PBUFFER && surface->texture_target == EGL_TEXTURE_2D) {
+                  result = (EGLBoolean) RPC_BOOLEAN_RES(RPC_CALL1_RES(eglIntBindTexImage_impl,
+                     thread,
+                     EGLINTBINDTEXIMAGE_ID,
+                     surface->serverbuffer));
+                  if (result != EGL_TRUE) {
+                     // If buffer is already bound to a texture then an
+                     // EGL_BAD_ACCESS error is returned.
+                     // But we don't know whether it is or not until we call
+                     // the server.
+                     thread->error = EGL_BAD_ACCESS;
+                  }
+               } else {
+                  thread->error = EGL_BAD_SURFACE;
+                  result = EGL_FALSE;
+               }
+            } else {
+               thread->error = EGL_BAD_PARAMETER;
+               result = EGL_FALSE;
+            }
+         } else {
+            thread->error = EGL_BAD_MATCH;
+            result = EGL_FALSE;
+         }
+      }
+
+      result = (thread->error == EGL_SUCCESS ? EGL_TRUE : EGL_FALSE );
+      CLIENT_UNLOCK();
+   } else
+      result = EGL_FALSE;
+
+   return result;
+}
+
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage(EGLDisplay dpy, EGLSurface surf, EGLint buffer)
+{
+   CLIENT_THREAD_STATE_T *thread;
+   CLIENT_PROCESS_STATE_T *process;
+   EGLBoolean result;
+
+   if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
+   {
+      EGL_SURFACE_T *surface;
+
+      thread->error = EGL_SUCCESS;
+
+      surface = client_egl_get_surface(thread, process, surf);
+
+      if (surface) {
+         if (surface->texture_format != EGL_NO_TEXTURE) {
+            if (buffer == EGL_BACK_BUFFER) {
+               if (surface->type == PBUFFER) {
+                  //TODO: not a "bound" pbuffer?
+                  RPC_CALL1(eglIntReleaseTexImage_impl,
+                     thread,
+                     EGLINTRELEASETEXIMAGE_ID,
+                     surface->serverbuffer);
+               } else {
+                  thread->error = EGL_BAD_SURFACE;
+                  result = EGL_FALSE;
+               }
+            } else {
+               thread->error = EGL_BAD_PARAMETER;
+               result = EGL_FALSE;
+            }
+         } else {
+            thread->error = EGL_BAD_MATCH;
+            result = EGL_FALSE;
+         }
+      }
+
+      result = (thread->error == EGL_SUCCESS ? EGL_TRUE : EGL_FALSE );
+      CLIENT_UNLOCK();
+   } else
+      result = EGL_FALSE;
+
+   return result;
+}
+
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval)
+{
+   CLIENT_THREAD_STATE_T *thread;
+   CLIENT_PROCESS_STATE_T *process;
+   EGLBoolean result;
+
+   if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
+   {
+      EGL_CURRENT_T *current;
+      EGL_SURFACE_T *surface;
+
+      /* the spec says "the window associated with the current context". it
+       * doesn't explicitly say "the current context for the current rendering
+       * api" (which it does in most other places), but i'm assuming that's what
+       * it means */
+
+      if (thread->bound_api == EGL_OPENVG_API)
+         current = &thread->openvg;
+      else
+         current = &thread->opengl;
+
+      surface = current->draw;
+
+      if (surface) {
+         if (surface->type == WINDOW) {
+            if (interval < EGL_CONFIG_MIN_SWAP_INTERVAL)
+               interval = EGL_CONFIG_MIN_SWAP_INTERVAL;
+            if (interval > EGL_CONFIG_MAX_SWAP_INTERVAL)
+               interval = EGL_CONFIG_MAX_SWAP_INTERVAL;
+
+            surface->swap_interval = (uint32_t) interval;
+         }
+
+         RPC_CALL2(eglIntSwapInterval_impl,
+            thread,
+            EGLINTSWAPINTERVAL_ID,
+            surface->serverbuffer,
+            surface->swap_interval);
+
+         /* TODO: should we raise an error if it's not a window
+          * surface, or silently ignore it?
+          */
+         thread->error = EGL_SUCCESS;
+         result = EGL_TRUE;
+      } else {
+         /*
+         "If there is no current context
+         on the calling thread, a EGL BAD CONTEXT error is generated. If there is no surface
+         bound to the current context, a EGL BAD SURFACE error is generated."
+
+         TODO
+         This doesn't make sense to me - the current context always has surfaces
+         bound to it, so which error do we raise?
+         */
+         thread->error = EGL_BAD_SURFACE;
+         result = EGL_FALSE;
+      }
+      CLIENT_UNLOCK();
+   }
+   else
+      result = EGL_FALSE;
+
+   return result;
+}
+
+EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_ctx, const EGLint *attrib_list)
+{
+   CLIENT_THREAD_STATE_T *thread;
+   CLIENT_PROCESS_STATE_T *process;
+   EGLContext result;
+
+vcos_log_trace("eglCreateContext start");
+
+   if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
+   {
+      if ((int)(size_t)config < 1 || (int)(size_t)config > EGL_MAX_CONFIGS) {
+         thread->error = EGL_BAD_CONFIG;
+         result = EGL_NO_CONTEXT;
+      } else {
+         EGLint max_version = (EGLint) (thread->bound_api == EGL_OPENGL_ES_API ? 2 : 1);
+         EGLint version = 1;
+
+         if (!egl_context_check_attribs(attrib_list, max_version, &version)) {
+            thread->error = EGL_BAD_ATTRIBUTE;
+            result = EGL_NO_CONTEXT;
+         } else if (!(egl_config_get_api_support((int)(intptr_t)config - 1) &
+            ((thread->bound_api == EGL_OPENVG_API) ? EGL_OPENVG_BIT :
+            ((version == 1) ? EGL_OPENGL_ES_BIT : EGL_OPENGL_ES2_BIT)))) {
+            thread->error = EGL_BAD_CONFIG;
+            result = EGL_NO_CONTEXT;
+         } else {
+            EGL_CONTEXT_T *share_context;
+
+            if (share_ctx != EGL_NO_CONTEXT) {
+               share_context = client_egl_get_context(thread, process, share_ctx);
+
+               if (share_context) {
+                  if ((share_context->type == OPENVG && thread->bound_api != EGL_OPENVG_API) ||
+                     (share_context->type != OPENVG && thread->bound_api == EGL_OPENVG_API)) {
+                     thread->error = EGL_BAD_MATCH;
+                     share_context = NULL;
+                  }
+               } else {
+                  thread->error = EGL_BAD_CONTEXT;
+               }
+            } else {
+               share_context = NULL;
+            }
+
+            if (share_ctx == EGL_NO_CONTEXT || share_context) {
+               EGL_CONTEXT_T *context;
+               EGL_CONTEXT_TYPE_T type;
+
+#ifndef NO_OPENVG
+               if (thread->bound_api == EGL_OPENVG_API)
+                  type = OPENVG;
+               else
+#endif
+                  if (version == 1)
+                     type = OPENGL_ES_11;
+                  else
+                     type = OPENGL_ES_20;
+
+               context = egl_context_create(
+                                share_context,
+                                (EGLContext)(size_t)process->next_context,
+                                dpy, config, type);
+
+               if (context) {
+                  if (khrn_pointer_map_insert(&process->contexts, process->next_context, context)) {
+                     thread->error = EGL_SUCCESS;
+                     result = (EGLContext)(size_t)process->next_context++;
+                  } else {
+                     thread->error = EGL_BAD_ALLOC;
+                     result = EGL_NO_CONTEXT;
+                     egl_context_term(context);
+                     khrn_platform_free(context);
+                  }
+               } else {
+                  thread->error = EGL_BAD_ALLOC;
+                  result = EGL_NO_CONTEXT;
+               }
+            } else {
+               /* thread->error set above */
+               result = EGL_NO_CONTEXT;
+            }
+         }
+      }
+      CLIENT_UNLOCK();
+   }
+   else
+      result = EGL_NO_CONTEXT;
+
+   vcos_log_trace("eglCreateContext end");
+
+   return result;
+}
+
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx)
+{
+   CLIENT_THREAD_STATE_T *thread;
+   CLIENT_PROCESS_STATE_T *process;
+   EGLBoolean result;
+
+   vcos_log_trace("eglDestroyContext ctx=%d.", (int)ctx);
+
+   if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
+   {
+      EGL_CONTEXT_T *context;
+
+      thread->error = EGL_SUCCESS;
+
+      context = client_egl_get_context(thread, process, ctx);
+
+      if (context) {
+         context->is_destroyed = true;
+         khrn_pointer_map_delete(&process->contexts, (uint32_t)(uintptr_t)ctx);
+         egl_context_maybe_free(context);
+      }
+      result = thread->error == EGL_SUCCESS;
+      CLIENT_UNLOCK();
+   }
+   else
+      result = EGL_FALSE;
+
+   return result;
+}
+
+static void egl_current_release(CLIENT_PROCESS_STATE_T *process, EGL_CURRENT_T *current)
+{
+   if (current->context) {
+      EGL_CONTEXT_T *context = current->context;
+      vcos_assert(context->is_current);
+      context->is_current = false;
+      context->renderbuffer = EGL_NONE;
+      egl_context_set_callbacks(context, NULL, NULL, NULL, NULL);
+
+      current->context = 0;
+
+      egl_context_maybe_free(context);
+
+      vcos_assert(process->context_current_count > 0);
+      process->context_current_count--;
+   }
+   if (current->draw) {
+      EGL_SURFACE_T *draw = current->draw;
+
+      vcos_assert(draw->context_binding_count > 0);
+      draw->context_binding_count--;
+
+      current->draw = 0;
+
+      egl_surface_maybe_free(draw);
+   }
+   if (current->read) {
+      EGL_SURFACE_T *read = current->read;
+
+      vcos_assert(read->context_binding_count > 0);
+      read->context_binding_count--;
+
+      current->read = 0;
+
+      egl_surface_maybe_free(read);
+   }
+}
+
+static void set_color_data(EGL_SURFACE_ID_T surface_id, KHRN_IMAGE_WRAP_T *image)
+{
+   int line_size = (image->stride < 0) ? -image->stride : image->stride;
+   int lines = KHDISPATCH_WORKSPACE_SIZE / line_size;
+   int offset = 0;
+   int height = image->height;
+
+   if (khrn_image_is_brcm1(image->format))
+      lines &= ~63;
+
+   vcos_assert(lines > 0);
+
+   while (height > 0) {
+      int batch = _min(lines, height);
+#ifndef RPC_DIRECT
+      uint32_t len = batch * line_size;
+#endif
+
+      CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+      int adjusted_offset = (image->stride < 0) ? (offset + (batch - 1)) : offset;
+
+      RPC_CALL7_IN_BULK(eglIntSetColorData_impl,
+         thread,
+         EGLINTSETCOLORDATA_ID,
+         surface_id,
+         image->format,
+         image->width,
+         batch,
+         image->stride,
+         offset,
+         (const char *)image->storage + adjusted_offset * image->stride,
+         len);
+
+      offset += batch;
+      height -= batch;
+   }
+}
+
+static void send_pixmap(EGL_SURFACE_T *surface)
+{
+   if (surface && surface->type == PIXMAP && !surface->pixmap_server_handle[0] && (surface->pixmap_server_handle[1] == (uint32_t)-1) && !surface->server_owned) {
+      KHRN_IMAGE_WRAP_T image;
+
+      if (!platform_get_pixmap_info(surface->pixmap, &image)) {
+         (void)vcos_verify(0); /* the pixmap has become invalid... */
+         return;
+      }
+
+      set_color_data(surface->serverbuffer, &image);
+
+      platform_send_pixmap_completed(surface->pixmap);
+
+      surface->server_owned = true;
+
+      khrn_platform_release_pixmap_info(surface->pixmap, &image);
+   }
+}
+
+void egl_gl_render_callback(void)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   CLIENT_LOCK();
+
+   send_pixmap(thread->opengl.draw);
+
+   CLIENT_UNLOCK();
+}
+
+void egl_vg_render_callback(void)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   CLIENT_LOCK();
+
+   send_pixmap(thread->openvg.draw);
+
+   CLIENT_UNLOCK();
+}
+
+static void get_color_data(EGL_SURFACE_ID_T surface_id, KHRN_IMAGE_WRAP_T *image)
+{
+   int line_size = (image->stride < 0) ? -image->stride : image->stride;
+   int lines = KHDISPATCH_WORKSPACE_SIZE / line_size;
+   int offset = 0;
+   int height = image->height;
+
+   if (khrn_image_is_brcm1(image->format))
+      lines &= ~63;
+
+   vcos_assert(lines > 0);
+
+   while (height > 0) {
+      int batch = _min(lines, height);
+
+      CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+      int adjusted_offset = (image->stride < 0) ? (offset + (batch - 1)) : offset;
+
+      RPC_CALL7_OUT_BULK(eglIntGetColorData_impl,
+         thread,
+         EGLINTGETCOLORDATA_ID,
+         surface_id,
+         image->format,
+         image->width,
+         batch,
+         image->stride,
+         offset,
+         (char *)image->storage + adjusted_offset * image->stride);
+
+      offset += batch;
+      height -= batch;
+   }
+}
+
+static void retrieve_pixmap(EGL_SURFACE_T *surface, bool wait)
+{
+   UNUSED(wait);
+
+   /*TODO: currently we always wait */
+   if (surface && surface->type == PIXMAP && !surface->pixmap_server_handle[0] && (surface->pixmap_server_handle[1] == (uint32_t)-1) && surface->server_owned) {
+      KHRN_IMAGE_WRAP_T image;
+
+      if (!platform_get_pixmap_info(surface->pixmap, &image)) {
+         (void)vcos_verify(0); /* the pixmap has become invalid... */
+         return;
+      }
+
+      get_color_data(surface->serverbuffer, &image);
+
+//Do any platform specific syncronisation or notification of modification
+      platform_retrieve_pixmap_completed(surface->pixmap);
+
+      surface->server_owned = false;
+      khrn_platform_release_pixmap_info(surface->pixmap, &image);
+   }
+}
+
+void egl_gl_flush_callback(bool wait)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   CLIENT_LOCK();
+
+   retrieve_pixmap(thread->opengl.draw, wait);
+
+   CLIENT_UNLOCK();
+}
+
+void egl_vg_flush_callback(bool wait)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   CLIENT_LOCK();
+
+   retrieve_pixmap(thread->openvg.draw, wait);
+
+   CLIENT_UNLOCK();
+}
+
+static bool context_and_surface_are_compatible(EGL_CONTEXT_T *context, EGL_SURFACE_T *surface)
+{
+   /*
+      from section 2.2 of the (1.3) spec, a context and surface are compatible
+      if:
+      1) they support the same type of color buffer (rgb or luminance). this is
+         trivially true for us as we only support rgb color buffers
+      2) they have color buffers and ancillary buffers of the same depth
+      3) the surface was created with respect to an EGLConfig supporting client
+         api rendering of the same type as the api type of the context
+      4) they were created with respect to the same EGLDisplay. this is
+         trivially true for us as we only have one EGLDisplay
+   */
+
+   uint32_t api_type = 0;
+   switch (context->type) {
+   case OPENGL_ES_11: api_type = EGL_OPENGL_ES_BIT; break;
+   case OPENGL_ES_20: api_type = EGL_OPENGL_ES2_BIT; break;
+   case OPENVG:       api_type = EGL_OPENVG_BIT; break;
+   default:           UNREACHABLE();
+   }
+
+   return
+      egl_config_bpps_match((int)(intptr_t)context->configname - 1, (int)(intptr_t)surface->config - 1) && /* (2) */
+      (egl_config_get_api_support((int)(intptr_t)surface->config - 1) & api_type); /* (3) */
+}
+
+static bool egl_current_set(CLIENT_PROCESS_STATE_T *process, CLIENT_THREAD_STATE_T *thread, EGL_CURRENT_T *current, EGL_CONTEXT_T *context, EGL_SURFACE_T *draw, EGL_SURFACE_T *read)
+{
+   bool result = false;
+
+   UNUSED(process);
+
+   if (context->is_current && context->thread != thread) {
+      // Fail - context is current to some other thread
+      thread->error = EGL_BAD_ACCESS;
+   } else if (draw->context_binding_count && draw->thread != thread) {
+      // Fail - draw surface is bound to context which is current to another thread
+      thread->error = EGL_BAD_ACCESS;
+   } else if (read->context_binding_count && read->thread != thread) {
+      // Fail - read surface is bound to context which is current to another thread
+      thread->error = EGL_BAD_ACCESS;
+   } else if (!context_and_surface_are_compatible(context, draw)) {
+      // Fail - draw surface is not compatible with context
+      thread->error = EGL_BAD_MATCH;
+   } else if (!context_and_surface_are_compatible(context, read)) {
+      // Fail - read surface is not compatible with context
+      thread->error = EGL_BAD_MATCH;
+   } else {
+      egl_current_release(process, current);
+
+      context->is_current = true;
+      context->thread = thread;
+
+      /* TODO: GLES supposedly doesn't support single-buffered rendering. Should we take this into account? */
+      context->renderbuffer = egl_surface_get_render_buffer(draw);
+
+      // Check surfaces are not bound to a different thread, and increase their reference count
+
+      draw->thread = thread;
+      draw->context_binding_count++;
+
+      read->thread = thread;
+      read->context_binding_count++;
+
+      current->context = context;
+      current->draw = draw;
+      current->read = read;
+
+      process->context_current_count++;
+
+      result = true;
+   }
+   if (draw->type == PIXMAP) {
+      egl_context_set_callbacks(context, egl_gl_render_callback, egl_gl_flush_callback, egl_vg_render_callback, egl_vg_flush_callback);
+   } else {
+      egl_context_set_callbacks(context, NULL,NULL, NULL, NULL);
+   }
+
+   return result;
+}
+
+static void flush_current_api(CLIENT_THREAD_STATE_T *thread)
+{
+   RPC_CALL2(eglIntFlush_impl,
+                 thread,
+                 EGLINTFLUSH_ID,
+                 RPC_UINT(thread->bound_api == EGL_OPENGL_ES_API),
+                 RPC_UINT(thread->bound_api == EGL_OPENVG_API));
+   RPC_FLUSH(thread);
+
+   if (thread->bound_api == EGL_OPENGL_ES_API)
+      egl_gl_flush_callback(false);
+   else
+      egl_vg_flush_callback(false);
+}
+
+EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy, EGLSurface dr, EGLSurface rd, EGLContext ctx)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   EGLBoolean result;
+   CLIENT_PROCESS_STATE_T *process = NULL; /* init to avoid warnings */
+
+   CLIENT_LOCK();
+
+   vcos_log_trace("Actual eglMakeCurrent %d %d %x", (int)ctx, (int)dr, (unsigned int) thread->error);
+
+   /*
+      check whether we are trying to release the current context
+      Note that we can do this even if the display isn't initted.
+   */
+
+   if (dr == EGL_NO_SURFACE && rd == EGL_NO_SURFACE && ctx == EGL_NO_CONTEXT) {
+      process = client_egl_get_process_state(thread, dpy, EGL_FALSE);
+
+      if (process) {
+         /* spec says we should flush in this case */
+         flush_current_api(thread);
+
+         egl_current_release(process,
+            (thread->bound_api == EGL_OPENVG_API) ? &thread->openvg : &thread->opengl);
+
+         client_send_make_current(thread);
+
+         client_try_unload_server(process);
+
+         thread->error = EGL_SUCCESS;
+         result = EGL_TRUE;
+      } else {
+         result = EGL_FALSE;
+      }
+   } else  if (dr == EGL_NO_SURFACE || rd == EGL_NO_SURFACE || ctx == EGL_NO_CONTEXT) {
+      thread->error = EGL_BAD_MATCH;
+      result = EGL_FALSE;
+   } else {
+      /*
+         get display
+      */
+
+      process = client_egl_get_process_state(thread, dpy, EGL_TRUE);
+
+      if (!process)
+         result = EGL_FALSE;
+      else {
+         /*
+            get context
+         */
+
+         EGL_CONTEXT_T *context = client_egl_get_context(thread, process, ctx);
+
+         if (!context) {
+            result = EGL_FALSE;
+         }  else {
+
+            /*
+               get surfaces
+            */
+
+            EGL_SURFACE_T *draw = client_egl_get_surface(thread, process, dr);
+            EGL_SURFACE_T *read = client_egl_get_surface(thread, process, rd);
+
+            if (!draw || !read) {
+               result = EGL_FALSE;
+            } else if (context->type == OPENVG && dr != rd) {
+               thread->error = EGL_BAD_MATCH;   //TODO: what error are we supposed to return here?
+               result = EGL_FALSE;
+            } else {
+               EGL_CURRENT_T *current;
+
+               if (context->type == OPENVG)
+                  current = &thread->openvg;
+               else
+                  current = &thread->opengl;
+
+               if (!egl_current_set(process, thread, current, context, draw, read))
+                  result = EGL_FALSE;
+               else {
+                  client_send_make_current(thread);
+
+                  thread->error = EGL_SUCCESS;
+                  result = EGL_TRUE;
+               }
+            }
+         }
+      }
+   }
+
+   CLIENT_UNLOCK();
+
+   vcos_log_trace("Actual eglMakeCurrent end %d %d %d %x", (int)ctx, (int)dr, result, (unsigned int)thread->error);
+
+   return result;
+}
+
+EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext(void)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   EGLContext result;
+
+   CLIENT_LOCK();
+
+   {
+      EGL_CURRENT_T *current;
+
+      if (thread->bound_api == EGL_OPENVG_API)
+         current = &thread->openvg;
+      else
+         current = &thread->opengl;
+
+      if (!current->context)
+         result = EGL_NO_CONTEXT;
+      else
+         result = current->context->name;
+
+      thread->error = EGL_SUCCESS;
+   }
+
+   CLIENT_UNLOCK();
+
+   return result;
+}
+
+EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   EGLSurface result;
+
+   CLIENT_LOCK();
+
+   {
+      EGL_CURRENT_T *current;
+      EGL_SURFACE_T *surface;
+
+      if (thread->bound_api == EGL_OPENVG_API)
+         current = &thread->openvg;
+      else
+         current = &thread->opengl;
+
+      switch (readdraw) {
+      case EGL_READ:
+         surface = current->read;
+         thread->error = EGL_SUCCESS;
+         break;
+      case EGL_DRAW:
+         surface = current->draw;
+         thread->error = EGL_SUCCESS;
+         break;
+      default:
+         surface = 0;
+         thread->error = EGL_BAD_PARAMETER;
+         break;
+      }
+
+      if (!surface)
+         result = EGL_NO_SURFACE;
+      else
+         result = surface->name;
+   }
+
+   CLIENT_UNLOCK();
+
+   return result;
+}
+
+EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   EGLDisplay result;
+
+   CLIENT_LOCK();
+
+   {
+      EGL_CURRENT_T *current;
+
+      if (thread->bound_api == EGL_OPENVG_API)
+         current = &thread->openvg;
+      else
+         current = &thread->opengl;
+
+      if (!current->context)
+         result = EGL_NO_DISPLAY;
+      else
+         result = current->context->display;
+
+      thread->error = EGL_SUCCESS;
+   }
+
+   CLIENT_UNLOCK();
+
+   return result;
+}
+
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value)
+{
+   CLIENT_THREAD_STATE_T *thread;
+   CLIENT_PROCESS_STATE_T *process;
+   EGLBoolean result;
+
+   if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
+   {
+      if (!value) {
+         thread->error = EGL_BAD_PARAMETER;
+         result = EGL_FALSE;
+      } else {
+         EGL_CONTEXT_T *context;
+
+         thread->error = EGL_SUCCESS;
+
+         context = client_egl_get_context(thread, process, ctx);
+
+         if (context) {
+            if (!egl_context_get_attrib(context, attribute, value))
+               thread->error = EGL_BAD_ATTRIBUTE;
+
+         }
+         result = thread->error == EGL_SUCCESS;
+      }
+      CLIENT_UNLOCK();
+   }
+   else
+      result = EGL_FALSE;
+
+   return result;
+}
+
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL(void)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   EGLBoolean result;
+
+   //TODO: "If the surface associated with the calling thread's current context is no
+   //longer valid, EGL_FALSE is returned and an EGL_BAD_CURRENT_SURFACE error is
+   //generated".
+   (void) RPC_INT_RES(RPC_CALL2_RES(eglIntFlushAndWait_impl,
+                 thread,
+                 EGLINTFLUSHANDWAIT_ID,
+                 RPC_UINT(true),
+                 RPC_UINT(false)));   // return unimportant - read is just to cause blocking
+
+   egl_gl_flush_callback(true);
+
+   thread->error = EGL_SUCCESS;
+   result = EGL_TRUE;
+
+   return result;
+}
+
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   EGLBoolean result;
+
+   //TODO: "If the surface associated with the calling thread's current context is no
+   //longer valid, EGL_FALSE is returned and an EGL_BAD_CURRENT_SURFACE error is
+   //generated".
+
+   if (engine == EGL_CORE_NATIVE_ENGINE) {
+   //TODO: currently nothing we can do here
+      thread->error = EGL_SUCCESS;
+      result = EGL_TRUE;
+   } else {
+      thread->error = EGL_BAD_PARAMETER;
+      result = EGL_FALSE;
+   }
+
+   return result;
+}
+
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surf)
+{
+#ifdef DIRECT_RENDERING
+   /* Wrapper layer shouldn't call eglSwapBuffers */
+   UNREACHABLE();
+   return EGL_FALSE;
+#else
+   CLIENT_THREAD_STATE_T *thread;
+   CLIENT_PROCESS_STATE_T *process;
+   EGLBoolean result;
+
+   vcos_log_trace("eglSwapBuffers start. dpy=%d. surf=%d.", (int)dpy, (int)surf);
+
+   if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
+   {
+      EGL_SURFACE_T *surface;
+
+      thread->error = EGL_SUCCESS;
+
+      surface = client_egl_get_surface(thread, process, surf);
+
+      vcos_log_trace("eglSwapBuffers get surface %x",(int)surface);
+
+      if (surface) {
+
+#if !(EGL_KHR_lock_surface)
+         /* Surface to be displayed must be bound to current context and API */
+         /* This check is disabled if we have the EGL_KHR_lock_surface extension */
+         if (thread->bound_api == EGL_OPENGL_ES_API && surface != thread->opengl.draw && surface != thread->opengl.read
+          || thread->bound_api == EGL_OPENVG_API    && surface != thread->openvg.draw) {
+            thread->error = EGL_BAD_SURFACE;
+         } else
+#endif
+         {
+
+            if (surface->type == WINDOW) {
+               uint32_t width, height, swapchain_count;
+
+               /* the egl spec says eglSwapBuffers is supposed to be a no-op for
+                * single-buffered surfaces, but we pass it through as the
+                * semantics are potentially useful:
+                * - any ops outstanding on the surface are flushed
+                * - the surface is resubmitted to the display once the
+                *   outstanding ops complete (for displays which have their own
+                *   memory, this is useful)
+                * - the surface is resized to fit the backing window */
+
+               // We need to check at this point if the surface has resized, and pass
+               // size data down to the server.
+
+               width = surface->width;
+               height = surface->height;
+
+               platform_get_dimensions(dpy, surface->win,
+                     &width, &height, &swapchain_count);
+
+               if((width!=surface->width)||(height!=surface->height)) {
+                  uint32_t handle = platform_get_handle(dpy, surface->win);
+                  surface->internal_handle = handle;
+                  surface->width = width;
+                  surface->height = height;
+               }
+
+               vcos_log_trace("eglSwapBuffers comparison: %d %d, %d %d",
+                        surface->width, surface->base_width, surface->height,
+                        surface->base_height);
+
+               /* TODO: raise EGL_BAD_ALLOC if we try to enlarge window and then run out of memory
+
+                  if (surface->width <= surface->base_width && surface->height <= surface->base_height ||
+                  surface->width <= surface->base_height && surface->height <= surface->base_width)
+                  */
+               // We don't call flush_current_api() here because it's only relevant
+               // for pixmap surfaces (eglIntSwapBuffers takes care of flushing on
+               // the server side).
+
+               platform_surface_update(surface->internal_handle);
+
+               vcos_log_trace("eglSwapBuffers server call");
+
+               RPC_CALL6(eglIntSwapBuffers_impl,
+                     thread,
+                     EGLINTSWAPBUFFERS_ID,
+                     RPC_UINT(surface->serverbuffer),
+                     RPC_UINT(surface->width),
+                     RPC_UINT(surface->height),
+                     RPC_UINT(surface->internal_handle),
+                     RPC_UINT(surface->swap_behavior == EGL_BUFFER_PRESERVED ? 1 : 0),
+                     RPC_UINT(khrn_platform_get_window_position(surface->win)));
+
+               RPC_FLUSH(thread);
+
+#ifdef ANDROID
+               CLIENT_UNLOCK();
+               platform_dequeue(dpy, surface->win);
+               CLIENT_LOCK();
+#else
+
+#  ifdef KHRONOS_EGL_PLATFORM_OPENWFC
+               wfc_stream_await_buffer((WFCNativeStreamType) surface->internal_handle);
+#  else
+#     ifndef RPC_LIBRARY
+               if (surface->buffers > 1) {
+                  //TODO implement khan (khronos async notification) receiver for linux
+#        ifndef RPC_DIRECT_MULTI
+                  vcos_log_trace("eglSwapBuffers waiting for semaphore");
+                  khronos_platform_semaphore_acquire(&surface->avail_buffers);
+#        endif
+               }
+#     endif // RPC_LIBRARY
+#  endif // KHRONOS_EGL_PLATFORM_OPENWFC
+
+#endif   /* ANDROID */
+
+            } else {
+#ifdef KHRN_COMMAND_MODE_DISPLAY
+//Check for single buffered windows surface (and VG) in which case call vgFlush to allow screen update for command mode screens
+               EGL_SURFACE_T *surface = CLIENT_GET_THREAD_STATE()->openvg.draw;
+               if (surface->type == WINDOW && surface->buffers==1 && thread->bound_api == EGL_OPENVG_API) {
+                  vgFlush();
+               }
+#endif
+            }
+            // else do nothing. eglSwapBuffers has no effect on pixmap or pbuffer surfaces
+         }
+      }
+
+      result = (thread->error == EGL_SUCCESS);
+      CLIENT_UNLOCK();
+   }
+   else
+      result = EGL_FALSE;
+
+   vcos_log_trace("eglSwapBuffers end");
+
+   return result;
+#endif // DIRECT_RENDERING
+}
+
+EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers(EGLDisplay dpy, EGLSurface surf, EGLNativePixmapType target)
+{
+   CLIENT_THREAD_STATE_T *thread;
+   CLIENT_PROCESS_STATE_T *process;
+   EGLBoolean result;
+
+   if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
+   {
+      EGL_SURFACE_T *surface;
+
+      thread->error = EGL_SUCCESS;
+
+      surface = client_egl_get_surface(thread, process, surf);
+
+      if ((thread->bound_api == EGL_OPENGL_ES_API && surface != thread->opengl.draw && surface != thread->opengl.read)
+       || (thread->bound_api == EGL_OPENVG_API    && surface != thread->openvg.draw)) {
+         /* Surface to be displayed must be bound to current context and API */
+         /* TODO remove this restriction, as we'll need to for eglSwapBuffers? */
+         thread->error = EGL_BAD_SURFACE;
+      } else if (surface) {
+         KHRN_IMAGE_WRAP_T image;
+
+         if (!platform_get_pixmap_info(target, &image)) {
+            thread->error = EGL_BAD_NATIVE_PIXMAP;
+         } else {
+            if (image.width != surface->width || image.height != surface->height) {
+               thread->error = EGL_BAD_MATCH;
+            } else {
+               //Bear in mind it's possible to call eglCopyBuffers on a pixmap
+               //surface which will result in the data being transferred twice, onto
+               //two different native pixmaps.
+
+               //TODO: flush the other API too?
+                  //TODO: is this necessary?
+               flush_current_api(thread);
+
+                  get_color_data(surface->serverbuffer, &image);
+            }
+            khrn_platform_release_pixmap_info(target, &image);
+         }
+      }
+
+      result = (thread->error == EGL_SUCCESS);
+      CLIENT_UNLOCK();
+   }
+   else
+      result = EGL_FALSE;
+
+   return result;
+}
+
+//#define EXPORT_DESTROY_BY_PID          // define me to export a utility function which will destroy the resources associated with a given process
+#ifdef EXPORT_DESTROY_BY_PID
+EGLAPI void EGLAPIENTRY eglDestroyByPidBRCM(EGLDisplay dpy, uint32_t pid_0, uint32_t pid_1)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   EGLBoolean result;
+
+   CLIENT_LOCK();
+
+   {
+      CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE);
+
+      if (!process)
+         result = 0;
+      else {
+         RPC_CALL2(eglIntDestroyByPid_impl,
+                   thread,
+                   EGLINTDESTROYBYPID_ID,
+                   RPC_UINT(pid_0),
+                   RPC_UINT(pid_1));
+
+         result = 1;
+      }
+   }
+
+   CLIENT_UNLOCK();
+}
+#endif
+
+#ifdef DIRECT_RENDERING
+EGLAPI EGLBoolean EGLAPIENTRY eglDirectRenderingPointer(EGLDisplay dpy, EGLSurface surf, void *image)
+{
+   CLIENT_THREAD_STATE_T *thread;
+   CLIENT_PROCESS_STATE_T *process;
+   EGLBoolean result = EGL_FALSE;
+
+   if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
+   {
+      EGL_SURFACE_T *surface;
+
+      thread->error = EGL_SUCCESS;
+
+      surface = client_egl_get_surface(thread, process, surf);
+
+      if (surface)
+      {
+         KHRN_IMAGE_WRAP_T *image_wrap = (KHRN_IMAGE_WRAP_T *)image;
+         surface->width = image_wrap->width;
+         surface->height = image_wrap->height;
+         RPC_CALL6(eglDirectRenderingPointer_impl,
+                 thread,
+                 EGLDIRECTRENDERINGPOINTER_ID,
+                 surface->serverbuffer,
+                 (uint32_t)image_wrap->storage,
+                 image_wrap->format,
+                 image_wrap->width,
+                 image_wrap->height,
+                 image_wrap->stride);
+      }
+
+      result = (thread->error == EGL_SUCCESS ? EGL_TRUE : EGL_FALSE );
+
+      CLIENT_UNLOCK();
+   }
+
+   return result;
+}
+#endif
+
+#if EGL_proc_state_valid
+EGLAPI void EGLAPIENTRY eglProcStateValid( EGLDisplay dpy, EGLBoolean *result )
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   CLIENT_LOCK();
+
+   vcos_log_trace("eglProcStateValid dpy=%d", (int)dpy );
+
+   {
+      CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE);
+
+      if (!process) {
+         *result = EGL_FALSE;
+      }
+      else {
+         *result = EGL_TRUE;
+      }
+   }
+
+   CLIENT_UNLOCK();
+
+   vcos_log_trace("eglProcStateValid result=%d", *result );
+   return;
+}
+#endif
+
diff --git a/interface/khronos/egl/egl_client_config.c b/interface/khronos/egl/egl_client_config.c
new file mode 100755 (executable)
index 0000000..6e0e061
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/khronos/common/khrn_int_common.h"
+#include "interface/khronos/common/khrn_client_platform.h"
+#include "interface/khronos/include/EGL/eglext.h"
+
+#include "interface/khronos/egl/egl_client_config.h"
+
+//#define BGR_FB
+
+typedef uint32_t FEATURES_T;
+
+#define FEATURES_PACK(r, g, b, a, d, s, m, mask, lockable) ((FEATURES_T)((((uint32_t)(r)) << 28 | (g) << 24 | (b) << 20 | (a) << 16 | (d) << 8 | (s) << 4 | (m) << 3 | ((mask) >> 3) << 2) | (lockable) << 1))
+
+typedef struct {
+   FEATURES_T features;
+   KHRN_IMAGE_FORMAT_T color, depth, multisample, mask;
+} FEATURES_AND_FORMATS_T;
+
+/*
+   formats
+
+   For 0 <= id < EGL_MAX_CONFIGS:
+      formats[id].features is valid
+*/
+
+static FEATURES_AND_FORMATS_T formats[EGL_MAX_CONFIGS] = {
+//                                        LOCKABLE
+//                                    MASK |
+//                R  G  B  A   D  S  M  |  |   COLOR      DEPTH                 MULTISAMPLE           MASK
+   {FEATURES_PACK(8, 8, 8, 8, 24, 8, 0, 0, 0), ABGR_8888, DEPTH_32_TLBD,        IMAGE_FORMAT_INVALID, IMAGE_FORMAT_INVALID},
+   {FEATURES_PACK(8, 8, 8, 0, 24, 8, 0, 0, 0), XBGR_8888, DEPTH_32_TLBD,        IMAGE_FORMAT_INVALID, IMAGE_FORMAT_INVALID},
+   {FEATURES_PACK(8, 8, 8, 8, 24, 0, 0, 0, 0), ABGR_8888, DEPTH_32_TLBD,        IMAGE_FORMAT_INVALID, IMAGE_FORMAT_INVALID},
+   {FEATURES_PACK(8, 8, 8, 0, 24, 0, 0, 0, 0), XBGR_8888, DEPTH_32_TLBD,        IMAGE_FORMAT_INVALID, IMAGE_FORMAT_INVALID},
+   {FEATURES_PACK(8, 8, 8, 8,  0, 8, 0, 0, 0), ABGR_8888, DEPTH_32_TLBD,        IMAGE_FORMAT_INVALID, IMAGE_FORMAT_INVALID},
+   {FEATURES_PACK(8, 8, 8, 0,  0, 8, 0, 0, 0), XBGR_8888, DEPTH_32_TLBD,        IMAGE_FORMAT_INVALID, IMAGE_FORMAT_INVALID},
+   {FEATURES_PACK(8, 8, 8, 8,  0, 0, 0, 0, 0), ABGR_8888, IMAGE_FORMAT_INVALID, IMAGE_FORMAT_INVALID, IMAGE_FORMAT_INVALID},
+   {FEATURES_PACK(8, 8, 8, 0,  0, 0, 0, 0, 0), XBGR_8888, IMAGE_FORMAT_INVALID, IMAGE_FORMAT_INVALID, IMAGE_FORMAT_INVALID},
+
+   {FEATURES_PACK(8, 8, 8, 8, 24, 8, 1, 0, 0), ABGR_8888, DEPTH_32_TLBD /*?*/,  DEPTH_COL_64_TLBD,    IMAGE_FORMAT_INVALID},
+   {FEATURES_PACK(8, 8, 8, 0, 24, 8, 1, 0, 0), XBGR_8888, DEPTH_32_TLBD /*?*/,  DEPTH_COL_64_TLBD,    IMAGE_FORMAT_INVALID},
+   {FEATURES_PACK(8, 8, 8, 8, 24, 0, 1, 0, 0), ABGR_8888, DEPTH_32_TLBD /*?*/,  DEPTH_COL_64_TLBD,    IMAGE_FORMAT_INVALID},
+   {FEATURES_PACK(8, 8, 8, 0, 24, 0, 1, 0, 0), XBGR_8888, DEPTH_32_TLBD /*?*/,  DEPTH_COL_64_TLBD,    IMAGE_FORMAT_INVALID},
+   {FEATURES_PACK(8, 8, 8, 8,  0, 8, 1, 0, 0), ABGR_8888, DEPTH_32_TLBD /*?*/,  DEPTH_COL_64_TLBD,    IMAGE_FORMAT_INVALID},
+   {FEATURES_PACK(8, 8, 8, 0,  0, 8, 1, 0, 0), XBGR_8888, DEPTH_32_TLBD /*?*/,  DEPTH_COL_64_TLBD,    IMAGE_FORMAT_INVALID},
+   {FEATURES_PACK(8, 8, 8, 8,  0, 0, 1, 0, 0), ABGR_8888, IMAGE_FORMAT_INVALID, COL_32_TLBD,          IMAGE_FORMAT_INVALID},
+   {FEATURES_PACK(8, 8, 8, 0,  0, 0, 1, 0, 0), XBGR_8888, IMAGE_FORMAT_INVALID, COL_32_TLBD,          IMAGE_FORMAT_INVALID},
+
+   {FEATURES_PACK(5, 6, 5, 0, 24, 8, 0, 0, 0), RGB_565,   DEPTH_32_TLBD,        IMAGE_FORMAT_INVALID, IMAGE_FORMAT_INVALID},
+   {FEATURES_PACK(5, 6, 5, 0, 24, 0, 0, 0, 0), RGB_565,   DEPTH_32_TLBD,        IMAGE_FORMAT_INVALID, IMAGE_FORMAT_INVALID},
+   {FEATURES_PACK(5, 6, 5, 0,  0, 8, 0, 0, 0), RGB_565,   DEPTH_32_TLBD,        IMAGE_FORMAT_INVALID, IMAGE_FORMAT_INVALID},
+   {FEATURES_PACK(5, 6, 5, 0,  0, 0, 0, 0, 0), RGB_565,   IMAGE_FORMAT_INVALID, IMAGE_FORMAT_INVALID, IMAGE_FORMAT_INVALID},
+
+   {FEATURES_PACK(5, 6, 5, 0, 24, 8, 1, 0, 0), RGB_565,   DEPTH_32_TLBD /*?*/,  DEPTH_COL_64_TLBD,    IMAGE_FORMAT_INVALID},
+   {FEATURES_PACK(5, 6, 5, 0, 24, 0, 1, 0, 0), RGB_565,   DEPTH_32_TLBD /*?*/,  DEPTH_COL_64_TLBD,    IMAGE_FORMAT_INVALID},
+   {FEATURES_PACK(5, 6, 5, 0,  0, 8, 1, 0, 0), RGB_565,   DEPTH_32_TLBD /*?*/,  DEPTH_COL_64_TLBD,    IMAGE_FORMAT_INVALID},
+   {FEATURES_PACK(5, 6, 5, 0,  0, 0, 1, 0, 0), RGB_565,   IMAGE_FORMAT_INVALID, COL_32_TLBD,          IMAGE_FORMAT_INVALID},
+
+#ifndef EGL_NO_ALPHA_MASK_CONFIGS
+   {FEATURES_PACK(8, 8, 8, 8,  0, 0, 0, 8, 0), ABGR_8888, IMAGE_FORMAT_INVALID, IMAGE_FORMAT_INVALID, A_8_RSO},
+   {FEATURES_PACK(8, 8, 8, 0,  0, 0, 0, 8, 0), XBGR_8888, IMAGE_FORMAT_INVALID, IMAGE_FORMAT_INVALID, A_8_RSO},
+   {FEATURES_PACK(5, 6, 5, 0,  0, 0, 0, 8, 0), RGB_565,   IMAGE_FORMAT_INVALID, IMAGE_FORMAT_INVALID, A_8_RSO},
+#endif
+
+   {FEATURES_PACK(5, 6, 5, 0, 16, 0, 0, 0, 0), RGB_565,   DEPTH_32_TLBD,        IMAGE_FORMAT_INVALID, IMAGE_FORMAT_INVALID},
+
+};
+
+void egl_config_install_configs(int type)
+{
+   uint32_t i;
+   for (i = 0; i != ARR_COUNT(formats); ++i) {
+      formats[i].color = (type == 0) ?
+         khrn_image_to_rso_format(formats[i].color) :
+         khrn_image_to_tf_format(formats[i].color);
+   }
+}
+
+static bool bindable_rgb(FEATURES_T features);
+static bool bindable_rgba(FEATURES_T features);
+
+#include "interface/khronos/egl/egl_client_config_cr.c"
+
+/*
+   KHRN_IMAGE_FORMAT_T egl_config_get_color_format(int id)
+
+   Implementation notes:
+
+   We may return an image format which cannot be rendered to.
+
+   Preconditions:
+
+   0 <= id < EGL_MAX_CONFIGS
+
+   Postconditions:
+
+   Return value is a hardware framebuffer-supported uncompressed color KHRN_IMAGE_FORMAT_T
+*/
+
+KHRN_IMAGE_FORMAT_T egl_config_get_color_format(int id)
+{
+   vcos_assert(id >= 0 && id < EGL_MAX_CONFIGS);
+
+   return formats[id].color;
+}
+
+/*
+   KHRN_IMAGE_FORMAT_T egl_config_get_depth_format(int id)
+
+   Preconditions:
+
+   0 <= id < EGL_MAX_CONFIGS
+
+   Postconditions:
+
+   Return value is a hardware framebuffer-supported depth KHRN_IMAGE_FORMAT_T or IMAGE_FORMAT_INVALID
+*/
+
+KHRN_IMAGE_FORMAT_T egl_config_get_depth_format(int id)
+{
+   vcos_assert(id >= 0 && id < EGL_MAX_CONFIGS);
+
+   return formats[id].depth;
+}
+
+/*
+   KHRN_IMAGE_FORMAT_T egl_config_get_mask_format(int id)
+
+   Preconditions:
+
+   0 <= id < EGL_MAX_CONFIGS
+
+   Postconditions:
+
+   Return value is a hardware framebuffer-supported mask KHRN_IMAGE_FORMAT_T or IMAGE_FORMAT_INVALID
+*/
+
+KHRN_IMAGE_FORMAT_T egl_config_get_mask_format(int id)
+{
+   vcos_assert(id >= 0 && id < EGL_MAX_CONFIGS);
+
+   return formats[id].mask;
+}
+
+/*
+   KHRN_IMAGE_FORMAT_T egl_config_get_multisample_format(int id)
+
+   Preconditions:
+
+   0 <= id < EGL_MAX_CONFIGS
+
+   Postconditions:
+
+   Return value is a hardware framebuffer-supported multisample color format or IMAGE_FORMAT_INVALID
+*/
+
+KHRN_IMAGE_FORMAT_T egl_config_get_multisample_format(int id)
+{
+   vcos_assert(id >= 0 && id < EGL_MAX_CONFIGS);
+
+   return formats[id].multisample;
+}
+
+/*
+   bool egl_config_get_multisample(int id)
+
+   Preconditions:
+
+   0 <= id < EGL_MAX_CONFIGS
+
+   Postconditions:
+
+   -
+*/
+
+bool egl_config_get_multisample(int id)
+{
+   vcos_assert(id >= 0 && id < EGL_MAX_CONFIGS);
+
+   return FEATURES_UNPACK_MULTI(formats[id].features);
+}
+
+/*
+   bool bindable_rgb(FEATURES_T features)
+   bool bindable_rgba(FEATURES_T features)
+
+   Preconditions:
+
+   features is a valid FEATURES_T
+
+   Postconditions:
+
+   -
+*/
+
+static bool bindable_rgb(FEATURES_T features)
+{
+   return !FEATURES_UNPACK_MULTI(features) && !FEATURES_UNPACK_ALPHA(features);
+}
+
+static bool bindable_rgba(FEATURES_T features)
+{
+   return !FEATURES_UNPACK_MULTI(features);
+}
+
+bool egl_config_bindable(int id, EGLenum format)
+{
+   vcos_assert(id >= 0 && id < EGL_MAX_CONFIGS);
+   switch (format) {
+   case EGL_NO_TEXTURE:
+      return true;
+   case EGL_TEXTURE_RGB:
+      return bindable_rgb(formats[id].features);
+   case EGL_TEXTURE_RGBA:
+      return bindable_rgba(formats[id].features);
+   default:
+      UNREACHABLE();
+      return false;
+   }
+}
+
+/*
+   bool egl_config_match_pixmap_info(int id, KHRN_IMAGE_WRAP_T *image)
+
+   TODO: decide how tolerant we should be when matching to native pixmaps.
+   At present they match if the red, green, blue and alpha channels
+   all have the same bit depths.
+
+   Preconditions:
+
+   0 <= id < EGL_MAX_CONFIGS
+   image is a pointer to a valid KHRN_IMAGE_WRAP_T, possibly with null data pointer
+   match is a bitmask which is a subset of PLATFORM_PIXMAP_MATCH_NONRENDERABLE|PLATFORM_PIXMAP_MATCH_RENDERABLE
+
+   Postconditions:
+
+   -
+*/
+
+bool egl_config_match_pixmap_info(int id, KHRN_IMAGE_WRAP_T *image)
+{
+   FEATURES_T features = formats[id].features;
+   KHRN_IMAGE_FORMAT_T format = image->format;
+
+   vcos_assert(id >= 0 && id < EGL_MAX_CONFIGS);
+
+   return
+      khrn_image_get_red_size(format)   == FEATURES_UNPACK_RED(features) &&
+      khrn_image_get_green_size(format) == FEATURES_UNPACK_GREEN(features) &&
+      khrn_image_get_blue_size(format)  == FEATURES_UNPACK_BLUE(features) &&
+      khrn_image_get_alpha_size(format) == FEATURES_UNPACK_ALPHA(features);
+}
+
+/*
+   uint32_t egl_config_get_api_support(int id)
+
+   Preconditions:
+
+   0 <= id < EGL_MAX_CONFIGS
+
+   Postconditions:
+
+   Result is a bitmap which is a subset of (EGL_OPENGL_ES_BIT | EGL_OPENVG_BIT | EGL_OPENGL_ES2_BIT)
+*/
+
+uint32_t egl_config_get_api_support(int id)
+{
+   /* no configs are api-specific (ie if you can use a config with gl, you can
+    * use it with vg too, and vice-versa). however, some configs have color
+    * buffer formats that are incompatible with the hardware, and so can't be
+    * used with any api. such configs may still be useful eg with the surface
+    * locking extension... */
+
+#if EGL_KHR_lock_surface
+   /* to reduce confusion, just say no for all lockable configs. this #if can be
+    * safely commented out -- the color buffer format check below will catch
+    * lockable configs we actually can't use */
+   if (egl_config_is_lockable(id)) {
+      return 0;
+   }
+#endif
+
+   switch (egl_config_get_color_format(id)) {
+   case ABGR_8888_RSO: case ABGR_8888_TF: case ABGR_8888_LT:
+   case XBGR_8888_RSO: case XBGR_8888_TF: case XBGR_8888_LT:
+   case ARGB_8888_RSO: case ARGB_8888_TF: case ARGB_8888_LT:
+   case XRGB_8888_RSO: case XRGB_8888_TF: case XRGB_8888_LT:
+   case RGB_565_RSO: case RGB_565_TF: case RGB_565_LT:
+#ifndef NO_OPENVG
+      return (uint32_t)(EGL_OPENGL_ES_BIT | EGL_OPENVG_BIT | EGL_OPENGL_ES2_BIT);
+#else
+      return (uint32_t)(EGL_OPENGL_ES_BIT | EGL_OPENGL_ES2_BIT);
+#endif
+   default:
+      break;
+   }
+   return 0;
+}
+
+/*
+   uint32_t egl_config_get_api_conformance(int id)
+
+   Preconditions:
+
+   0 <= id < EGL_MAX_CONFIGS
+
+   Postconditions:
+
+   Result is a bitmap which is a subset of (EGL_OPENGL_ES_BIT | EGL_OPENVG_BIT | EGL_OPENGL_ES2_BIT)
+*/
+
+uint32_t egl_config_get_api_conformance(int id)
+{
+   /* vg doesn't support multisampled surfaces properly */
+   return egl_config_get_api_support(id) & ~(FEATURES_UNPACK_MULTI(formats[id].features) ? EGL_OPENVG_BIT : 0);
+}
+
+bool egl_config_bpps_match(int id0, int id1) /* bpps of all buffers match */
+{
+   FEATURES_T config0 = formats[id0].features;
+   FEATURES_T config1 = formats[id1].features;
+
+   return
+      FEATURES_UNPACK_RED(config0)     == FEATURES_UNPACK_RED(config1) &&
+      FEATURES_UNPACK_GREEN(config0)   == FEATURES_UNPACK_GREEN(config1) &&
+      FEATURES_UNPACK_BLUE(config0)    == FEATURES_UNPACK_BLUE(config1) &&
+      FEATURES_UNPACK_ALPHA(config0)   == FEATURES_UNPACK_ALPHA(config1) &&
+      FEATURES_UNPACK_DEPTH(config0)   == FEATURES_UNPACK_DEPTH(config1) &&
+      FEATURES_UNPACK_STENCIL(config0) == FEATURES_UNPACK_STENCIL(config1) &&
+      FEATURES_UNPACK_MASK(config0)    == FEATURES_UNPACK_MASK(config1);
+}
+
+#if EGL_KHR_lock_surface
+
+/*
+   KHRN_IMAGE_FORMAT_T egl_config_get_mapped_format(int id)
+
+   Returns the format of the mapped buffer when an EGL surface is locked.
+
+   Preconditions:
+
+   0 <= id < EGL_MAX_CONFIGS
+   egl_config_is_lockable(id)
+
+   Postconditions:
+
+   Return value is RGB_565_RSO or ARGB_8888_RSO
+*/
+
+KHRN_IMAGE_FORMAT_T egl_config_get_mapped_format(int id)
+{
+   KHRN_IMAGE_FORMAT_T result;
+
+   vcos_assert(id >= 0 && id < EGL_MAX_CONFIGS);
+   vcos_assert(FEATURES_UNPACK_LOCKABLE(formats[id].features));
+
+   /* If any t-format images were lockable, we would convert to raster format here */
+   result = egl_config_get_color_format(id);
+   vcos_assert(khrn_image_is_rso(result));
+   return result;
+}
+
+/*
+   bool egl_config_is_lockable(int id)
+
+   Preconditions:
+
+   0 <= id < EGL_MAX_CONFIGS
+
+   Postconditions:
+
+   -
+*/
+
+bool egl_config_is_lockable(int id)
+{
+   vcos_assert(id >= 0 && id < EGL_MAX_CONFIGS);
+   return FEATURES_UNPACK_LOCKABLE(formats[id].features);
+}
+
+#endif
+
+
+
+
diff --git a/interface/khronos/egl/egl_client_config.h b/interface/khronos/egl/egl_client_config.h
new file mode 100755 (executable)
index 0000000..8b924af
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef EGL_CLIENT_CONFIG_H
+#define EGL_CLIENT_CONFIG_H
+
+#include "interface/khronos/common/khrn_client_platform.h"
+
+#include "interface/khronos/include/EGL/egl.h"
+#include "interface/khronos/include/EGL/eglext.h"
+
+#include "interface/khronos/common/khrn_int_image.h"
+
+#include "interface/khronos/egl/egl_int_config.h"
+
+#if defined(__BCM2708A0__) || defined(__BCM35230A0__)
+   #define EGL_NO_ALPHA_MASK_CONFIGS
+#endif
+
+#ifdef EGL_NO_ALPHA_MASK_CONFIGS
+   #define EGL_MAX_CONFIGS 25
+#else
+   #define EGL_MAX_CONFIGS 28
+#endif
+
+/*
+   EGL_CONFIG_MIN_SWAP_INTERVAL
+
+   Khronos config attrib name: EGL_MIN_SWAP_INTERVAL
+
+   0 <= EGL_CONFIG_MIN_SWAP_INTERVAL <= 1
+*/
+#define EGL_CONFIG_MIN_SWAP_INTERVAL 0
+
+/*
+   EGL_CONFIG_MAX_SWAP_INTERVAL
+
+   Khronos config attrib name: EGL_MAX_SWAP_INTERVAL
+
+   1 <= EGL_CONFIG_MAX_SWAP_INTERVAL
+   EGL_CONFIG_MIN_SWAP_INTERVAL <= EGL_CONFIG_MAX_SWAP_INTERVAL
+*/
+#define EGL_CONFIG_MAX_SWAP_INTERVAL 0x7fffffff
+/*
+   EGL_CONFIG_MAX_WIDTH
+
+   Khronos config attrib name: EGL_MAX_PBUFFER_WIDTH
+
+   EGL_CONFIG_MAX_WIDTH > 0
+*/
+#define EGL_CONFIG_MAX_WIDTH 2048
+/*
+   EGL_CONFIG_MAX_HEIGHT
+
+   Khronos config attrib name: EGL_MAX_PBUFFER_HEIGHT
+
+   EGL_CONFIG_MAX_HEIGHT > 0
+*/
+#define EGL_CONFIG_MAX_HEIGHT 2048
+
+/*
+   EGLConfig egl_config_from_id(int id)
+
+   Converts between our internally-used index and EGLConfig (by adding 1).
+
+   Preconditions:
+
+   0 <= id < EGL_MAX_CONFIGS
+
+   Postconditions:
+
+   Return value is a valid EGLConfig
+*/
+
+static INLINE EGLConfig egl_config_from_id(int id)
+{
+   return (EGLConfig)(size_t)(id + 1);
+}
+
+/*
+   int egl_config_to_id(EGLConfig config)
+
+   Inverse of egl_config_from_id
+
+   Preconditions:
+
+   config is a valid EGLConfig
+
+   Postconditions:
+
+   0 <= result < EGL_MAX_CONFIGS
+
+*/
+
+static INLINE int egl_config_to_id(EGLConfig config)
+{
+   return (int)(size_t)config - 1;
+}
+
+extern void egl_config_sort(int *ids, bool use_red, bool use_green, bool use_blue, bool use_alpha);
+extern bool egl_config_check_attribs(const EGLint *attrib_list, bool *use_red, bool *use_green, bool *use_blue, bool *use_alpha);
+extern bool egl_config_filter(int id, const EGLint *attrib_list);
+extern bool egl_config_get_attrib(int id, EGLint attrib, EGLint *value);
+extern void egl_config_install_configs(int type);
+
+extern KHRN_IMAGE_FORMAT_T egl_config_get_color_format(int id);
+extern KHRN_IMAGE_FORMAT_T egl_config_get_depth_format(int id);
+extern KHRN_IMAGE_FORMAT_T egl_config_get_mask_format(int id);
+extern KHRN_IMAGE_FORMAT_T egl_config_get_multisample_format(int id);
+extern bool egl_config_get_multisample(int id);
+extern bool egl_config_bindable(int id, EGLenum format);
+extern bool egl_config_match_pixmap_info(int id, KHRN_IMAGE_WRAP_T *image);
+extern uint32_t egl_config_get_api_support(int id);
+extern bool egl_config_bpps_match(int id0, int id1); /* bpps of all buffers match */
+extern uint32_t egl_config_get_api_conformance(int id);
+
+#if EGL_KHR_lock_surface
+extern KHRN_IMAGE_FORMAT_T egl_config_get_mapped_format(int id);
+extern bool egl_config_is_lockable(int id);
+#endif
+
+#endif
diff --git a/interface/khronos/egl/egl_client_config_cr.c b/interface/khronos/egl/egl_client_config_cr.c
new file mode 100755 (executable)
index 0000000..8aa3602
--- /dev/null
@@ -0,0 +1,776 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+   A FEATURES_T is a structure represented by a bit pattern
+
+   Constructed with FEATURES_PACK(red, green, blue, alpha, depth, stencil, multi, mask, lockable)
+
+   Attributes are returned with
+      FEATURES_UNPACK_RED(c)     
+      FEATURES_UNPACK_GREEN(c)   
+      FEATURES_UNPACK_BLUE(c)    
+      FEATURES_UNPACK_ALPHA(c)   
+      FEATURES_UNPACK_DEPTH(c)   
+      FEATURES_UNPACK_STENCIL(c) 
+      FEATURES_UNPACK_MULTI(c)   
+      FEATURES_UNPACK_MASK(c)    
+      FEATURES_UNPACK_LOCKABLE(c)
+
+   Additionally,
+      FEATURES_UNPACK_COLOR(c) = red + green + blue + alpha
+
+   Attributes can take the following values:
+      0 <= red <= 15
+      0 <= green <= 15
+      0 <= blue <= 15
+      0 <= alpha <= 15
+      0 <= depth <= 255
+      0 <= stencil <= 15
+      multi in {0,1}
+      mask in {0,8}
+      lockable in {0,1}
+
+*/
+
+
+#define FEATURES_UNPACK_RED(c)        ((EGLint)((c) >> 28 & 0xf))
+#define FEATURES_UNPACK_GREEN(c)      ((EGLint)((c) >> 24 & 0xf))
+#define FEATURES_UNPACK_BLUE(c)       ((EGLint)((c) >> 20 & 0xf))
+#define FEATURES_UNPACK_ALPHA(c)      ((EGLint)((c) >> 16 & 0xf))
+#define FEATURES_UNPACK_DEPTH(c)      ((EGLint)((c) >> 8 & 0xff))
+#define FEATURES_UNPACK_STENCIL(c)    ((EGLint)((c) >> 4 & 0xf))
+#define FEATURES_UNPACK_MULTI(c)      ((EGLint)((c) >> 3 & 0x1))
+#define FEATURES_UNPACK_MASK(c)       ((EGLint)(((c) >> 2 & 0x1) << 3))
+#define FEATURES_UNPACK_LOCKABLE(c)   ((c) >> 1 & 0x1)
+
+#define FEATURES_UNPACK_COLOR(c)      (FEATURES_UNPACK_RED(c)+FEATURES_UNPACK_GREEN(c)+FEATURES_UNPACK_BLUE(c)+FEATURES_UNPACK_ALPHA(c))
+
+/*
+   bool egl_config_check_attribs(const EGLint *attrib_list, bool *use_red, bool *use_green, bool *use_blue, bool *use_alpha)
+
+   Checks whether all attributes and values are valid. Returns whether the list includes each of
+   EGL_RED_SIZE, EGL_GREEN_SIZE, EGL_BLUE_SIZE, EGL_ALPHA_SIZE
+
+   We use the table in eglGetConfigAttrib to guide us as to which values are valid.
+
+   Implementation notes:
+
+   -
+
+   Preconditions:
+
+   use_red, use_green, use_blue, use_alpha are valid pointers
+   attrib_list is NULL or a pointer to an EGL_NONE-terminated list of attribute/value pairs
+
+   Postconditions:   
+
+   If list is valid then we return true and:
+      use_red is set to true   iff attrib_list includes EGL_RED_SIZE and the corresponding value is not 0 or EGL_DONT_CARE
+      use_green, use_blue, use_alpha similarly
+      all attributes in list are valid
+   Else we return false.
+
+   Invariants preserved:
+
+   -
+
+   Invariants used:
+
+   -
+*/
+
+bool egl_config_check_attribs(const EGLint *attrib_list, bool *use_red, bool *use_green, bool *use_blue, bool *use_alpha)
+{
+   if (!attrib_list)
+      return true;
+
+   while (*attrib_list != EGL_NONE) {
+      EGLint name = *attrib_list++;
+      EGLint value = *attrib_list++;
+
+      if (name == EGL_RED_SIZE && value != 0 && value != EGL_DONT_CARE)
+         *use_red = true;
+
+      if (name == EGL_GREEN_SIZE && value != 0 && value != EGL_DONT_CARE)
+         *use_green = true;
+
+      if (name == EGL_BLUE_SIZE && value != 0 && value != EGL_DONT_CARE)
+         *use_blue = true;
+
+      if (name == EGL_ALPHA_SIZE && value != 0 && value != EGL_DONT_CARE)
+         *use_alpha = true;
+
+      switch (name) {
+      case EGL_BUFFER_SIZE:
+      case EGL_RED_SIZE:
+      case EGL_GREEN_SIZE:
+      case EGL_BLUE_SIZE:
+      case EGL_LUMINANCE_SIZE:
+      case EGL_ALPHA_SIZE:
+      case EGL_ALPHA_MASK_SIZE:
+         if (value != EGL_DONT_CARE && value < 0) return false;
+         break;
+      case EGL_BIND_TO_TEXTURE_RGB:
+      case EGL_BIND_TO_TEXTURE_RGBA:
+         if (value != EGL_DONT_CARE && value != EGL_FALSE && value != EGL_TRUE)
+            return false;
+         break;
+      case EGL_COLOR_BUFFER_TYPE:
+         if (value != EGL_DONT_CARE && value != EGL_RGB_BUFFER && value != EGL_LUMINANCE_BUFFER)
+            return false;
+         break;
+      case EGL_CONFIG_CAVEAT:
+         if (value != EGL_DONT_CARE && value != EGL_NONE && value != EGL_SLOW_CONFIG && value != EGL_NON_CONFORMANT_CONFIG)
+            return false;
+         break;
+      case EGL_CONFIG_ID:
+         if (value != EGL_DONT_CARE && value < 1)
+            return false;
+         break;
+      case EGL_CONFORMANT:
+         if (value != EGL_DONT_CARE && (value & ~(EGL_OPENGL_BIT|EGL_OPENGL_ES_BIT|EGL_OPENGL_ES2_BIT|EGL_OPENVG_BIT)))
+            return false;
+         break;
+      case EGL_DEPTH_SIZE:
+         if (value != EGL_DONT_CARE && value < 0) return false;
+         break;
+      case EGL_LEVEL:
+         break;
+      case EGL_MATCH_NATIVE_PIXMAP:
+         /* 1.4 Spec is poor here - says that value has to be a valid handle, but also says that any attribute
+          * value (other than EGL_LEVEL) can be EGL_DONT_CARE. It also says that the default value is EGL_NONE,
+          * but that doesn't really make sense - sensible to assume that the default is EGL_DONT_CARE, and don't
+          * support EGL_NONE as an explicit parameter. (Could theoretically collide with a real handle...)
+          */
+         if (value != EGL_DONT_CARE) {
+            KHRN_IMAGE_WRAP_T image;
+            if (!platform_get_pixmap_info((EGLNativePixmapType)(intptr_t)value, &image))
+               return false;
+            khrn_platform_release_pixmap_info((EGLNativePixmapType)(intptr_t)value, &image);
+         }
+         break;
+      case EGL_MAX_PBUFFER_WIDTH:
+      case EGL_MAX_PBUFFER_HEIGHT:
+      case EGL_MAX_PBUFFER_PIXELS:
+         break;
+      case EGL_MAX_SWAP_INTERVAL:
+      case EGL_MIN_SWAP_INTERVAL:
+         if (value != EGL_DONT_CARE && value < 0) return false;
+         break;
+      case EGL_NATIVE_RENDERABLE:
+         if (value != EGL_DONT_CARE && value != EGL_FALSE && value != EGL_TRUE)
+            return false;
+         break;
+      case EGL_NATIVE_VISUAL_ID:
+      case EGL_NATIVE_VISUAL_TYPE:
+         break;
+      case EGL_RENDERABLE_TYPE:
+         if (value != EGL_DONT_CARE && (value & ~(EGL_OPENGL_BIT|EGL_OPENGL_ES_BIT|EGL_OPENGL_ES2_BIT|EGL_OPENVG_BIT)))
+            return false;
+         break;
+      case EGL_SAMPLE_BUFFERS:
+      case EGL_SAMPLES:
+      case EGL_STENCIL_SIZE:
+         if (value != EGL_DONT_CARE && value < 0) return false;
+         break;
+      case EGL_SURFACE_TYPE:
+      {
+         int valid_bits = EGL_WINDOW_BIT|EGL_PIXMAP_BIT|EGL_PBUFFER_BIT|
+            EGL_MULTISAMPLE_RESOLVE_BOX_BIT|EGL_SWAP_BEHAVIOR_PRESERVED_BIT|
+            EGL_VG_COLORSPACE_LINEAR_BIT|EGL_VG_ALPHA_FORMAT_PRE_BIT;
+#if EGL_KHR_lock_surface
+         valid_bits |= EGL_LOCK_SURFACE_BIT_KHR|EGL_OPTIMAL_FORMAT_BIT_KHR;
+#endif
+         if (value != EGL_DONT_CARE && (value & ~valid_bits))
+            return false;
+         break;
+      }
+      case EGL_TRANSPARENT_TYPE:
+         if (value != EGL_DONT_CARE && value != EGL_NONE && value != EGL_TRANSPARENT_RGB)
+            return false;
+         break;
+      case EGL_TRANSPARENT_RED_VALUE:
+      case EGL_TRANSPARENT_GREEN_VALUE:
+      case EGL_TRANSPARENT_BLUE_VALUE:
+         if (value != EGL_DONT_CARE && value < 0) return false;
+         break;
+#if EGL_KHR_lock_surface
+      case EGL_MATCH_FORMAT_KHR:
+         switch (value) {
+         case EGL_DONT_CARE:
+         case EGL_NONE:
+         case EGL_FORMAT_RGB_565_EXACT_KHR:
+         case EGL_FORMAT_RGB_565_KHR:
+         case EGL_FORMAT_RGBA_8888_EXACT_KHR:
+         case EGL_FORMAT_RGBA_8888_KHR:
+            break;
+         default:
+            return false;
+         }
+         break;
+#endif
+#if EGL_ANDROID_recordable
+      case EGL_RECORDABLE_ANDROID:
+         switch (value) {
+         case EGL_DONT_CARE:
+         case EGL_TRUE:
+         case EGL_FALSE:
+            break;
+         default:
+            return false;
+         }
+         break;
+#endif
+      default:
+         return false;
+      }
+   }
+
+   return true;
+}
+
+/*
+   bool less_than(int id0, int id1, bool use_red, bool use_green, bool use_blue, bool use_alpha)
+
+   total ordering on configs; sort in
+
+   - decreasing order of color buffer depth, ignoring components for which we have not expressed a preference
+   - increasing order of color buffer depth
+   - increasing order of multisample buffers
+   - increasing order of depth buffer depth
+   - increasing order of stencil buffer depth
+   - increasing order of mask buffer depth
+
+   Implementation notes:
+
+   We ignore:
+      EGL_CONFIG_CAVEAT (all EGL_NONE)
+      EGL_COLOR_BUFFER_TYPE (all EGL_RGB_BUFFER)
+      EGL_SAMPLES (if EGL_SAMPLES is 1 then all 4 else all 0)
+      EGL_NATIVE_VISUAL_TYPE (all EGL_NONE)
+      EGL_CONFIG_ID (already sorted in this order and sort algorithm is stable)
+
+   Khrnonos documentation:
+
+   Sorting of EGLConfigs
+   If more than one matching EGLConfig is found, then a list of EGLConfigs
+   is returned. The list is sorted by proceeding in ascending order of the \94Sort Priority\94
+   column of table 3.4. That is, configurations that are not ordered by a lower
+   numbered rule are sorted by the next higher numbered rule.
+   Sorting for each rule is either numerically Smaller or Larger as described in the
+   \94Sort Order\94 column, or a Special sort order as described for each sort rule below:
+   1. Special: by EGL CONFIG CAVEAT where the precedence is EGL NONE,
+   EGL SLOW CONFIG, EGL NON CONFORMANT CONFIG.
+   2. Special:
+   by EGL COLOR BUFFER TYPE where the precedence is EGL RGB BUFFER,
+   EGL LUMINANCE BUFFER.
+   3. Special: by larger total number of color bits (for an RGB color buffer,
+   this is the sum of EGL RED SIZE, EGL GREEN SIZE, EGL BLUE SIZE,
+   and EGL ALPHA SIZE; for a luminance color buffer, the sum of
+   EGL LUMINANCE SIZE and EGL ALPHA SIZE) [3]. If the requested number
+   of bits in attrib list for a particular color component is 0 or EGL_DONT_CARE,
+   then the number of bits for that component is not considered.
+   4. Smaller EGL BUFFER SIZE.
+   5. Smaller EGL SAMPLE BUFFERS.
+   6. Smaller EGL SAMPLES.
+   7. Smaller EGL DEPTH SIZE.
+   8. Smaller EGL STENCIL SIZE.
+   9. Smaller EGL ALPHA MASK SIZE.
+   10. Special: by EGL NATIVE VISUAL TYPE (the actual sort order is
+   implementation-defined, depending on the meaning of native visual types).
+   11. Smaller EGL CONFIG ID (this is always the last sorting rule, and guarantees
+   a unique ordering).
+   EGLConfigs are not sorted with respect to the parameters
+   EGL BIND TO TEXTURE RGB, EGL BIND TO TEXTURE RGBA, EGL CONFORMANT,
+   EGL LEVEL, EGL NATIVE RENDERABLE, EGL MAX SWAP INTERVAL,
+   EGL MIN SWAP INTERVAL, EGL RENDERABLE TYPE, EGL SURFACE TYPE,
+   EGL TRANSPARENT TYPE, EGL TRANSPARENT RED VALUE,
+   EGL TRANSPARENT GREEN VALUE, and EGL TRANSPARENT BLUE VALUE.
+
+   3This rule places configs with deeper color buffers first in the list returned by eglChooseConfig.
+Applications may find this counterintuitive, and need to perform additional processing on the list of
+configs to find one best matching their requirements. For example, specifying RGBA depths of 5651
+could return a list whose first config has a depth of 8888.
+
+
+   Preconditions:
+
+   0 <= id0 < EGL_MAX_CONFIGS
+   0 <= id1 < EGL_MAX_CONFIGS
+
+   Postconditions:   
+
+   -
+
+   Invariants preserved:
+
+   -
+
+   Invariants used:
+
+   -
+*/
+
+static bool less_than(int id0, int id1, bool use_red, bool use_green, bool use_blue, bool use_alpha)
+{
+   FEATURES_T features0 = formats[id0].features;
+   FEATURES_T features1 = formats[id1].features;
+
+   EGLint all0 = FEATURES_UNPACK_COLOR(features0);
+   EGLint all1 = FEATURES_UNPACK_COLOR(features1);
+
+   EGLint multi0 = FEATURES_UNPACK_MULTI(features0);
+   EGLint multi1 = FEATURES_UNPACK_MULTI(features1);
+
+   EGLint depth0 = FEATURES_UNPACK_DEPTH(features0);
+   EGLint depth1 = FEATURES_UNPACK_DEPTH(features1);
+
+   EGLint stencil0 = FEATURES_UNPACK_STENCIL(features0);
+   EGLint stencil1 = FEATURES_UNPACK_STENCIL(features1);
+
+   EGLint mask0 = FEATURES_UNPACK_MASK(features0);
+   EGLint mask1 = FEATURES_UNPACK_MASK(features1);
+
+   int used0 = 0;
+   int used1 = 0;
+
+   if (use_red) {
+      used0 += FEATURES_UNPACK_RED(features0);
+      used1 += FEATURES_UNPACK_RED(features1);
+   }
+   if (use_green) {
+      used0 += FEATURES_UNPACK_GREEN(features0);
+      used1 += FEATURES_UNPACK_GREEN(features1);
+   }
+   if (use_blue) {
+      used0 += FEATURES_UNPACK_BLUE(features0);
+      used1 += FEATURES_UNPACK_BLUE(features1);
+   }
+   if (use_alpha) {
+      used0 += FEATURES_UNPACK_ALPHA(features0);
+      used1 += FEATURES_UNPACK_ALPHA(features1);
+   }
+
+   return used0 > used1    ||    (used0 == used1 &&
+      (all0 < all1         ||     (all0 == all1 &&
+      (multi0 < multi1     ||   (multi0 == multi1 &&
+      (depth0 < depth1     ||   (depth0 == depth1 &&
+      (stencil0 < stencil1 || (stencil0 == stencil1 &&
+      (mask0 < mask1))))))))));
+}
+
+/*
+   void egl_config_sort(int *ids, EGLBoolean use_red, EGLBoolean use_green, EGLBoolean use_blue, EGLBoolean use_alpha)
+
+   Sorts a list of EGL_CONFIG_IDs
+
+   Implementation notes:
+
+   Uses bubble sort
+
+   Preconditions:
+
+   ids is a pointer to EGL_MAX_CONFIGS elements
+   0 <= ids[i] < EGL_MAX_CONFIG for 0 <= i < EGL_MAX_CONFIG
+
+   Postconditions:   
+
+   ids is a permutation of the original
+
+   Invariants preserved:
+
+   -
+
+   Invariants used:
+
+   -
+*/
+
+void egl_config_sort(int *ids, bool use_red, bool use_green, bool use_blue, bool use_alpha)
+{
+   int i, j;
+
+   for (i = 1; i < EGL_MAX_CONFIGS; i++)
+      for (j = 0; j < EGL_MAX_CONFIGS - i; j++)
+         if (less_than(ids[j + 1], ids[j], use_red, use_green, use_blue, use_alpha)) {
+            int temp = ids[j];
+            ids[j] = ids[j + 1];
+            ids[j + 1] = temp;
+         }
+}
+
+/*
+   bool egl_config_get_attrib(int id, EGLint attrib, EGLint *value)
+
+   Returns the value of the given attribute of the given config. Returns false
+   if there is no such attribute.
+
+   Implementation notes:
+
+   We match EGL_MATCH_NATIVE_PIXMAP here
+   too, because it *is* a valid attribute according to eglGetConfigAttrib
+   (even though it doesn't return anything meaningful) and we need it for
+   egl_config_filter.
+
+   Preconditions:
+
+   0 <= id < EGL_MAX_CONFIGS
+   value is a valid pointer
+
+   Postconditions:   
+
+   If attrib is a valid attribute then true is returned and *value is set
+   Else false is returned
+
+   Invariants preserved:
+
+   -
+
+   Invariants used:
+
+   -
+*/
+
+bool egl_config_get_attrib(int id, EGLint attrib, EGLint *value)
+{
+   FEATURES_T features = formats[id].features;
+
+   switch (attrib) {
+   case EGL_BUFFER_SIZE:
+      *value = FEATURES_UNPACK_COLOR(features);
+      return true;
+   case EGL_RED_SIZE:
+      *value = FEATURES_UNPACK_RED(features);
+      return true;
+   case EGL_GREEN_SIZE:
+      *value = FEATURES_UNPACK_GREEN(features);
+      return true;
+   case EGL_BLUE_SIZE:
+      *value = FEATURES_UNPACK_BLUE(features);
+      return true;
+   case EGL_LUMINANCE_SIZE:
+      *value = 0;
+      return true;
+   case EGL_ALPHA_SIZE:
+      *value = FEATURES_UNPACK_ALPHA(features);
+      return true;
+   case EGL_ALPHA_MASK_SIZE:
+      *value = FEATURES_UNPACK_MASK(features);
+      return true;
+   case EGL_BIND_TO_TEXTURE_RGB:
+      *value = bindable_rgb(features);
+      return true;
+   case EGL_BIND_TO_TEXTURE_RGBA:
+      *value = bindable_rgba(features);
+      return true;
+   case EGL_COLOR_BUFFER_TYPE:
+      *value = EGL_RGB_BUFFER;
+      return true;
+   case EGL_CONFIG_CAVEAT:
+      *value = EGL_NONE;
+      return true;
+   case EGL_CONFIG_ID:
+      *value = (EGLint)(uintptr_t)egl_config_from_id(id);
+      return true;
+   case EGL_CONFORMANT:
+      *value = egl_config_get_api_conformance(id);
+      return true;
+   case EGL_DEPTH_SIZE:
+      *value = FEATURES_UNPACK_DEPTH(features);
+      return true;
+   case EGL_LEVEL:
+      *value = 0;
+      return true;
+   case EGL_MATCH_NATIVE_PIXMAP:
+      *value = 0;
+      return true;
+   case EGL_MAX_PBUFFER_WIDTH:
+      *value = EGL_CONFIG_MAX_WIDTH;
+      return true;
+   case EGL_MAX_PBUFFER_HEIGHT:
+      *value = EGL_CONFIG_MAX_HEIGHT;
+      return true;
+   case EGL_MAX_PBUFFER_PIXELS:
+      *value = EGL_CONFIG_MAX_WIDTH * EGL_CONFIG_MAX_HEIGHT;
+      return true;
+   case EGL_MAX_SWAP_INTERVAL:
+      *value = EGL_CONFIG_MAX_SWAP_INTERVAL;
+      return true;
+   case EGL_MIN_SWAP_INTERVAL:
+      *value = EGL_CONFIG_MIN_SWAP_INTERVAL;
+      return true;
+   case EGL_NATIVE_RENDERABLE:
+      *value = EGL_TRUE;
+      return true;
+   case EGL_NATIVE_VISUAL_ID:
+      *value = platform_get_color_format(egl_config_get_color_format(id));
+      return true;
+   case EGL_NATIVE_VISUAL_TYPE:
+      *value = EGL_NONE;
+      return true;
+   case EGL_RENDERABLE_TYPE:
+      *value = egl_config_get_api_support(id);
+      return true;
+   case EGL_SAMPLE_BUFFERS:
+      *value = FEATURES_UNPACK_MULTI(features);
+      return true;
+   case EGL_SAMPLES:
+      *value = FEATURES_UNPACK_MULTI(features) * 4;
+      return true;
+   case EGL_STENCIL_SIZE:
+      *value = FEATURES_UNPACK_STENCIL(features);
+      return true;
+   case EGL_SURFACE_TYPE:
+      *value = (EGLint)(EGL_PBUFFER_BIT | EGL_PIXMAP_BIT | EGL_WINDOW_BIT | EGL_VG_COLORSPACE_LINEAR_BIT | EGL_VG_ALPHA_FORMAT_PRE_BIT | EGL_MULTISAMPLE_RESOLVE_BOX_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT);
+#if EGL_KHR_lock_surface
+      if (egl_config_is_lockable(id))
+      {
+         *value |= EGL_LOCK_SURFACE_BIT_KHR;
+         if (egl_config_get_mapped_format(id) == egl_config_get_color_format(id))
+            *value |= EGL_OPTIMAL_FORMAT_BIT_KHR;      /* Considered optimal if no format conversion needs doing. Currently all lockable surfaces are optimal */
+      }
+#endif
+      return true;
+   case EGL_TRANSPARENT_TYPE:
+      *value = EGL_NONE;
+      return true;
+   case EGL_TRANSPARENT_RED_VALUE:
+   case EGL_TRANSPARENT_GREEN_VALUE:
+   case EGL_TRANSPARENT_BLUE_VALUE:
+      *value = 0;
+      return true;
+#if EGL_KHR_lock_surface
+   case EGL_MATCH_FORMAT_KHR:
+      if (!egl_config_is_lockable(id))
+         *value = EGL_NONE;
+      else {
+         switch (egl_config_get_mapped_format(id))
+         {
+         case RGB_565_RSO:
+            *value = EGL_FORMAT_RGB_565_EXACT_KHR;
+            break;
+         case ARGB_8888_RSO:
+            *value = EGL_FORMAT_RGBA_8888_EXACT_KHR;
+            break;
+         default:
+            UNREACHABLE();
+         }
+      }
+      return true;
+#endif
+#if EGL_ANDROID_recordable
+   case EGL_RECORDABLE_ANDROID:
+      *value = EGL_TRUE;
+      return true;
+#endif
+   default:
+      return false;
+   }
+}
+
+/*
+   bool egl_config_filter(int id, const EGLint *attrib_list)
+
+   Returns whether the given EGL config satisfies the supplied attrib_list.
+
+   Implementation notes:
+
+   The following attributes:
+   EGL_COLOR_BUFFER_TYPE
+   EGL_LEVEL
+   EGL_RENDERABLE_TYPE
+   EGL_SURFACE_TYPE
+   EGL_TRANSPARENT_TYPE
+   (possibly EGL_MATCH_NATIVE_PIXMAP - see comment)
+
+   have default values not equivalent to EGL_DONT_CARE. But all of our configs
+   match the default value in all of these cases so we can treat the default as
+   EGL_DONT_CARE for all attributes.
+
+   Preconditions:
+
+   attrib_list is NULL or a pointer to an EGL_NONE-terminated list of valid attribute/value pairs
+   0 <= id < EGL_MAX_CONFIGS
+
+   Postconditions:   
+
+   -
+
+   Invariants preserved:
+
+   -
+
+   Invariants used:
+
+   -
+*/
+
+bool egl_config_filter(int id, const EGLint *attrib_list)
+{
+   if (!attrib_list)
+      return true;
+
+   while (*attrib_list != EGL_NONE) {
+      EGLint name = *attrib_list++;
+      EGLint value = *attrib_list++;
+      EGLint actual_value;
+
+      if (!egl_config_get_attrib(id, name, &actual_value) )
+      {
+         UNREACHABLE();
+         return false;
+      }
+
+      switch (name) {
+         /* Selection Criteria: AtLeast */
+      case EGL_BUFFER_SIZE:
+      case EGL_RED_SIZE:
+      case EGL_GREEN_SIZE:
+      case EGL_BLUE_SIZE:
+      case EGL_LUMINANCE_SIZE:
+      case EGL_ALPHA_SIZE:
+      case EGL_ALPHA_MASK_SIZE:
+      case EGL_DEPTH_SIZE:
+      case EGL_SAMPLE_BUFFERS:
+      case EGL_SAMPLES:
+      case EGL_STENCIL_SIZE:
+         if (value != EGL_DONT_CARE && value > actual_value)
+            return false;
+         break;
+
+         /* Selection Criteria: Exact */
+         /*
+            Excluding EGL_TRANSPARENT_x_VALUE and EGL_MATCH_FORMAT_KHR which are listed in
+            the table as Exact, but seem to have special rules attached to them.
+
+            Excluding EGL_NATIVE_VISUAL_TYPE which is in the ignore list
+            Excluding EGL_LEVEL because EGL_DONT_CARE is not allowed
+         */
+      case EGL_BIND_TO_TEXTURE_RGB:
+      case EGL_BIND_TO_TEXTURE_RGBA:
+      case EGL_COLOR_BUFFER_TYPE:
+      case EGL_CONFIG_CAVEAT:
+      case EGL_CONFIG_ID:
+      case EGL_MAX_SWAP_INTERVAL:
+      case EGL_MIN_SWAP_INTERVAL:
+      case EGL_NATIVE_RENDERABLE:
+      case EGL_TRANSPARENT_TYPE:
+#if EGL_ANDROID_recordable
+      case EGL_RECORDABLE_ANDROID:
+#endif
+         if (value != EGL_DONT_CARE && value != actual_value)
+            return false;
+         break;
+
+      case EGL_LEVEL:
+         if (value != actual_value)
+            return false;
+         break;
+
+         /* Selection Criteria: Mask */
+      case EGL_CONFORMANT:
+      case EGL_RENDERABLE_TYPE:
+      case EGL_SURFACE_TYPE:
+         if (value != EGL_DONT_CARE && (value & ~actual_value))
+            return false;
+         break;
+
+         /* Selection Criteria: Special */
+      case EGL_MATCH_NATIVE_PIXMAP:
+         if (value != EGL_DONT_CARE) { /* see comments in egl_config_check_attribs */
+            EGLNativePixmapType pixmap = (EGLNativePixmapType)(intptr_t)value;
+            KHRN_IMAGE_WRAP_T image;
+            if (!platform_get_pixmap_info(pixmap, &image)) {
+               /* 
+                  Not actually unreachable in theory!
+                  We should have detected this in egl_config_check_attribs
+                  It's possible that the validity of pixmap has changed since then however...
+               */
+               UNREACHABLE();
+               return false;
+            }
+            if (!egl_config_match_pixmap_info(id, &image) ||
+               !platform_match_pixmap_api_support(pixmap, egl_config_get_api_support(id)))
+            {
+               khrn_platform_release_pixmap_info(pixmap, &image);
+               return false;
+            }
+
+            khrn_platform_release_pixmap_info(pixmap, &image);
+         }
+         break;
+#if EGL_KHR_lock_surface
+      case EGL_MATCH_FORMAT_KHR:
+         if (!(value == EGL_DONT_CARE || value == actual_value
+            || (value == EGL_FORMAT_RGB_565_KHR && actual_value == EGL_FORMAT_RGB_565_EXACT_KHR)
+            || (value == EGL_FORMAT_RGBA_8888_KHR && actual_value == EGL_FORMAT_RGBA_8888_EXACT_KHR)))
+         {
+            return false;
+         }
+         break;
+#endif
+
+         /* Attributes we can completely ignore */
+      case EGL_MAX_PBUFFER_WIDTH:
+      case EGL_MAX_PBUFFER_HEIGHT:
+      case EGL_MAX_PBUFFER_PIXELS:
+      case EGL_NATIVE_VISUAL_ID:
+         /*
+         "If EGL_MAX_PBUFFER_WIDTH, EGL_MAX_PBUFFER_HEIGHT,
+         EGL_MAX_PBUFFER_PIXELS, or EGL_NATIVE_VISUAL_ID are specified in
+         attrib_list, then they are ignored"
+         */
+
+      case EGL_NATIVE_VISUAL_TYPE:
+         /*
+         "if there are no native visual types, then the EGL NATIVE VISUAL TYPE attribute is
+         ignored."
+         */
+
+      case EGL_TRANSPARENT_BLUE_VALUE:
+      case EGL_TRANSPARENT_GREEN_VALUE:
+      case EGL_TRANSPARENT_RED_VALUE:
+         /*
+          "If EGL_TRANSPARENT_TYPE is set to EGL_NONE in attrib_list, then
+         the EGL_TRANSPARENT_RED_VALUE, EGL_TRANSPARENT_GREEN_VALUE, and
+         EGL_TRANSPARENT_BLUE_VALUE attributes are ignored."
+
+         Possible spec deviation if EGL_TRANSPARENT_TYPE is specified as EGL_DONT_CARE
+         and EGL_TRANSPARENT_*_VALUE is also specified?
+         */
+
+         break;
+
+      default:
+         UNREACHABLE();
+         break;
+      }
+   }
+
+   return true;
+}
diff --git a/interface/khronos/egl/egl_client_context.c b/interface/khronos/egl/egl_client_context.c
new file mode 100755 (executable)
index 0000000..b4dc116
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/khronos/common/khrn_int_common.h"
+
+#include "interface/khronos/glxx/glxx_client.h"
+#include "interface/khronos/vg/vg_client.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+
+#include "interface/khronos/egl/egl_client_context.h"
+#include "interface/khronos/egl/egl_client_surface.h"
+
+#ifdef RPC_DIRECT
+#include "interface/khronos/egl/egl_int_impl.h"
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+
+EGLBoolean egl_context_check_attribs(const EGLint *attrib_list, EGLint max_version, EGLint *version)
+{
+   if (!attrib_list)
+      return EGL_TRUE;
+
+   while (1) {
+      switch (*attrib_list++) {
+      case EGL_CONTEXT_CLIENT_VERSION:
+      {
+         EGLint value = *attrib_list++;
+
+         if (value < 1 || value > max_version)
+            return EGL_FALSE;
+         else
+            *version = value;
+
+         break;
+      }
+      case EGL_NONE:
+         return EGL_TRUE;
+      default:
+         return EGL_FALSE;
+      }
+   }
+}
+
+EGL_CONTEXT_T *egl_context_create(EGL_CONTEXT_T *share_context, EGLContext name, EGLDisplay display, EGLConfig configname, EGL_CONTEXT_TYPE_T type)
+{
+   EGL_CONTEXT_T *context = (EGL_CONTEXT_T *)khrn_platform_malloc(sizeof(EGL_CONTEXT_T), "EGL_CONTEXT_T");
+   if (!context)
+      return 0;
+
+   context->name = name;
+   context->display = display;
+   context->configname = configname;
+
+   context->type = type;
+
+   context->renderbuffer = EGL_NONE;
+
+   context->is_current = false;
+   context->is_destroyed = false;
+
+   switch (type) {
+#ifndef NO_OPENVG
+   case OPENVG:
+   {
+      VG_CLIENT_SHARED_STATE_T *shared_state;
+      if (share_context) {
+         shared_state = ((VG_CLIENT_STATE_T *)share_context->state)->shared_state;
+         vg_client_shared_state_acquire(shared_state);
+      } else {
+         shared_state = vg_client_shared_state_alloc();
+         if (!shared_state) {
+            khrn_platform_free(context);
+            return 0;
+         }
+      }
+
+      context->state = vg_client_state_alloc(shared_state);
+      vg_client_shared_state_release(shared_state);
+      if (!context->state) {
+         khrn_platform_free(context);
+         return 0;
+      }
+
+      {
+      CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+         /* uint64_t pid = khronos_platform_get_process_id(); */ /* unused */
+      context->servercontext = RPC_UINT_RES(RPC_CALL2_RES(eglIntCreateVG_impl,
+                                                             thread,
+                                                             EGLINTCREATEVG_ID,
+                                                             share_context ? share_context->servercontext : 0,
+                                                          share_context ? share_context->type : OPENVG/*ignored*/));
+      }
+      if (!context->servercontext) {
+         vg_client_state_free((VG_CLIENT_STATE_T *)context->state);
+         khrn_platform_free(context);
+         return 0;
+      }
+
+      break;
+   }
+#endif /* NO_OPENVG */
+   case OPENGL_ES_11:
+   {
+      GLXX_CLIENT_STATE_T *state = (GLXX_CLIENT_STATE_T *)khrn_platform_malloc(sizeof(GLXX_CLIENT_STATE_T), "GLXX_CLIENT_STATE_T");
+      if (!state) {
+         khrn_platform_free(context);
+         return 0;
+      }
+
+      context->state = state;
+      if (gl11_client_state_init(state)) {
+         CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+         context->servercontext = RPC_UINT_RES(RPC_CALL2_RES(eglIntCreateGLES11_impl,
+                                                             thread,
+                                                             EGLINTCREATEGLES11_ID,
+                                                             share_context ? share_context->servercontext : 0,
+                                                             share_context ? share_context->type : OPENGL_ES_11/*ignored*/));
+         if (!context->servercontext) {
+            glxx_client_state_free(state);
+            khrn_platform_free(context);
+            return 0;
+         }
+      }
+      break;
+   }
+   case OPENGL_ES_20:
+   {
+      GLXX_CLIENT_STATE_T *state = (GLXX_CLIENT_STATE_T *)khrn_platform_malloc(sizeof(GLXX_CLIENT_STATE_T), "GLXX_CLIENT_STATE_T");
+      if (!state) {
+         khrn_platform_free(context);
+         return 0;
+      }
+
+      context->state = state;
+
+      if (gl20_client_state_init(state)) {
+         CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+         context->servercontext = RPC_UINT_RES(RPC_CALL2_RES(eglIntCreateGLES20_impl,
+                                                             thread,
+                                                             EGLINTCREATEGLES20_ID,
+                                                             share_context ? share_context->servercontext : 0,
+                                                             share_context ? share_context->type : OPENGL_ES_20/*ignored*/));
+         if (!context->servercontext) {
+            glxx_client_state_free(state);
+            khrn_platform_free(context);
+            return 0;
+         }
+      }
+      break;
+   }
+   default:
+      UNREACHABLE();
+      break;
+   }
+
+   return context;
+}
+
+void egl_context_term(EGL_CONTEXT_T *context)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   /* If we're current then there should still be a reference to us */
+   /* (if this wasn't the case we should call egl_context_release_surfaces here) */
+   vcos_assert(!context->is_current);
+   vcos_assert(context->is_destroyed);
+
+   switch (context->type) {
+#ifndef NO_OPENVG
+   case OPENVG:
+      RPC_CALL1(eglIntDestroyVG_impl,
+                thread,
+                EGLINTDESTROYVG_ID,
+                RPC_UINT(context->servercontext));
+      RPC_FLUSH(thread);
+      vg_client_state_free((VG_CLIENT_STATE_T *)context->state);
+      break;
+#endif
+   case OPENGL_ES_11:
+   case OPENGL_ES_20:
+       RPC_CALL1(eglIntDestroyGL_impl,
+                thread,
+                EGLINTDESTROYGL_ID,
+                RPC_UINT(context->servercontext));
+      RPC_FLUSH(thread);
+      glxx_client_state_free((GLXX_CLIENT_STATE_T *)context->state);
+      break;
+   default:
+      UNREACHABLE();
+   }
+
+   context->state = 0;
+}
+
+EGLBoolean egl_context_get_attrib(EGL_CONTEXT_T *context, EGLint attrib, EGLint *value)
+{
+   switch (attrib) {
+   case EGL_CONFIG_ID:
+      *value = (int)(intptr_t)context->configname;
+      return EGL_TRUE;
+   case EGL_CONTEXT_CLIENT_TYPE:
+      switch (context->type) {
+      case OPENGL_ES_11:
+      case OPENGL_ES_20:
+         *value = EGL_OPENGL_ES_API;
+         break;
+      case OPENVG:
+         *value = EGL_OPENVG_API;
+         break;
+      default:
+         UNREACHABLE();
+         break;
+      }
+      return EGL_TRUE;
+   case EGL_CONTEXT_CLIENT_VERSION:
+      switch (context->type) {
+      case OPENGL_ES_11:
+      case OPENVG:
+         *value = 1;
+         break;
+      case OPENGL_ES_20:
+         *value = 2;
+         break;
+      default:
+         UNREACHABLE();
+         break;
+      }
+      return EGL_TRUE;
+   case EGL_RENDER_BUFFER:
+   {
+      /* TODO: GLES supposedly doesn't support single-buffered rendering. Should we take this into account? */
+      *value = context->renderbuffer;
+      return EGL_TRUE;
+   }
+   default:
+      return EGL_FALSE;
+   }
+}
+
+void egl_context_set_callbacks(EGL_CONTEXT_T *context,
+                               void (*gl_render_callback)(void),
+                               void (*gl_flush_callback)(bool),
+                               void (*vg_render_callback)(void),
+                               void (*vg_flush_callback)(bool))
+{
+   switch (context->type) {
+      case OPENGL_ES_11:
+      {
+         GLXX_CLIENT_STATE_T *state = (GLXX_CLIENT_STATE_T *)context->state;
+         state->render_callback = gl_render_callback;
+         state->flush_callback = gl_flush_callback;
+         break;
+      }
+      case OPENGL_ES_20:
+      {
+         GLXX_CLIENT_STATE_T *state = (GLXX_CLIENT_STATE_T *)context->state;
+         state->render_callback = gl_render_callback;
+         state->flush_callback = gl_flush_callback;
+         break;
+      }
+      case OPENVG:
+      {
+         VG_CLIENT_STATE_T *state = (VG_CLIENT_STATE_T *)context->state;
+         state->render_callback = vg_render_callback;
+         state->flush_callback = vg_flush_callback;
+         break;
+      }
+      default:
+         UNREACHABLE();
+   }
+}
+
+
+/*
+   void egl_context_maybe_free(EGL_CONTEXT_T *context)
+
+   Frees a map together with its server-side resources if:
+    - it has been destroyed
+    - it is no longer current
+
+   Implementation notes:
+
+   -
+
+   Preconditions:
+
+   context is a valid pointer
+
+   Postconditions:
+
+   Either:
+   - context->is_destroyed is false (we don't change this), or
+   - context->is_current is true, or
+   - context has been deleted.
+
+   Invariants preserved:
+
+   -
+
+   Invariants used:
+
+   -
+ */
+void egl_context_maybe_free(EGL_CONTEXT_T *context)
+{
+   vcos_assert(context);
+
+   if (!context->is_destroyed)
+      return;
+
+   if (context->is_current)
+      return;
+
+   egl_context_term(context);
+   khrn_platform_free(context);
+}
diff --git a/interface/khronos/egl/egl_client_context.h b/interface/khronos/egl/egl_client_context.h
new file mode 100755 (executable)
index 0000000..cde547f
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef EGL_CLIENT_CONTEXT_H
+#define EGL_CLIENT_CONTEXT_H
+
+#include "interface/khronos/egl/egl_int.h"
+
+typedef struct {
+   EGLContext name;
+   EGLDisplay display;
+   EGLConfig configname;
+
+   EGL_CONTEXT_TYPE_T type;
+
+   EGLint renderbuffer;    //EGL_NONE, EGL_BACK_BUFFER or EGL_SINGLE_BUFFER
+
+   void *state;                                 // GLXX_CLIENT_STATE_T or VG_CLIENT_STATE_T
+   EGL_CONTEXT_ID_T servercontext;
+
+   struct CLIENT_THREAD_STATE *thread;          // If we are current, which the client state for the thread are we associated with.
+
+   /*
+      is_current
+
+      Invariant:
+
+      (EGL_CONTEXT_IS_CURRENT)
+      Iff true, the context is current to some thread.
+   */
+   bool is_current;   
+   /*
+      is_destroyed
+
+      Invariant:
+
+      (EGL_CONTEXT_IS_DESTROYED)
+      Iff true, is not a member of the CLIENT_PROCESS_STATE_T.contexts
+   */
+   bool is_destroyed;
+} EGL_CONTEXT_T;
+
+extern EGLBoolean egl_context_check_attribs(const EGLint *attrib_list, EGLint max_version, EGLint *version);
+
+extern EGL_CONTEXT_T *egl_context_create(EGL_CONTEXT_T *share_context, EGLContext name, EGLDisplay display, EGLConfig configname, EGL_CONTEXT_TYPE_T type);
+extern void egl_context_term(EGL_CONTEXT_T *context);
+
+extern void egl_context_set_callbacks(EGL_CONTEXT_T *context,
+                                      void (*gl_render_callback)(void),
+                                      void (*gl_flush_callback)(bool),
+                                      void (*vg_render_callback)(void),
+                                      void (*vg_flush_callback)(bool));
+
+extern EGLBoolean egl_context_get_attrib(EGL_CONTEXT_T *context, EGLint attrib, EGLint *value);
+extern void egl_context_maybe_free(EGL_CONTEXT_T *context);
+
+#endif
diff --git a/interface/khronos/egl/egl_client_cr.c b/interface/khronos/egl/egl_client_cr.c
new file mode 100755 (executable)
index 0000000..8e0e0e6
--- /dev/null
@@ -0,0 +1,579 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+   EGLAPI EGLint EGLAPIENTRY eglGetError(void)
+
+   Khronos documentation:
+
+   3.1 Errors
+   Where possible, when an EGL function fails it has no side effects.
+   EGL functions usually return an indicator of success or failure; either an
+   EGLBoolean EGL TRUE or EGL FALSE value, or in the form of an out-of-band
+   return value indicating failure, such as returning EGL NO CONTEXT instead of a requested
+   context handle. Additional information about the success or failure of the
+   most recent EGL function called in a specific thread, in the form of an error code,
+   can be obtained by calling
+   EGLint eglGetError();
+   The error codes that may be returned from eglGetError, and their meanings,
+   are:
+   EGL SUCCESS
+   Function succeeded.
+   EGL NOT INITIALIZED
+   EGL is not initialized, or could not be initialized, for the specified display.
+   EGL BAD ACCESS
+   EGL cannot access a requested resource (for example, a context is bound in
+   another thread).
+   EGL BAD ALLOC
+   EGL failed to allocate resources for the requested operation.
+   9
+   10 CHAPTER 3. EGL FUNCTIONS AND ERRORS
+   EGL BAD ATTRIBUTE
+   An unrecognized attribute or attribute value was passed in an attribute list.
+   EGL BAD CONTEXT
+   An EGLContext argument does not name a valid EGLContext.
+   EGL BAD CONFIG
+   An EGLConfig argument does not name a valid EGLConfig.
+   EGL BAD CURRENT SURFACE
+   The current surface of the calling thread is a window, pbuffer, or pixmap that
+   is no longer valid.
+   EGL BAD DISPLAY
+   An EGLDisplay argument does not name a valid EGLDisplay; or, EGL
+   is not initialized on the specified EGLDisplay.
+   EGL BAD SURFACE
+   An EGLSurface argument does not name a valid surface (window, pbuffer,
+   or pixmap) configured for rendering.
+   EGL BAD MATCH
+   Arguments are inconsistent; for example, an otherwise valid context requires
+   buffers (e.g. depth or stencil) not allocated by an otherwise valid surface.
+   EGL BAD PARAMETER
+   One or more argument values are invalid.
+   EGL BAD NATIVE PIXMAP
+   An EGLNativePixmapType argument does not refer to a valid native
+   pixmap.
+   EGL BAD NATIVE WINDOW
+   An EGLNativeWindowType argument does not refer to a valid native
+   window.
+   EGL CONTEXT LOST
+   A power management event has occurred. The application must destroy all
+   contexts and reinitialise client API state and objects to continue rendering,
+   as described in section 2.6.
+   When there is no status to return (in other words, when eglGetError is called
+   as the first EGL call in a thread, or immediately after calling eglReleaseThread),
+   EGL SUCCESS will be returned.
+
+   Implementation notes:
+
+   What should we do if eglGetError is called twice? Currently we reset the error to EGL_SUCCESS.
+
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   Result is in the list (CLIENT_THREAD_STATE_ERROR)
+
+   Invariants preserved:
+
+   -
+
+   Invariants used:
+
+   (CLIENT_THREAD_STATE_ERROR)
+*/
+
+EGLAPI EGLint EGLAPIENTRY eglGetError(void)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_CHECK_THREAD_STATE();
+
+   if (thread)
+   {
+      EGLint result;
+
+      vcos_assert( thread != NULL );
+
+      result = thread->error;
+      thread->error = EGL_SUCCESS;
+
+      return result;
+   }
+   else
+      return EGL_SUCCESS;
+}
+
+/*
+   EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id)
+
+   Khronos documentation:
+
+   3.2 Initialization
+Initialization must be performed once for each display prior to calling most other
+EGL or client API functions. A display can be obtained by calling
+EGLDisplay eglGetDisplay(EGLNativeDisplayType
+display id);
+The type and format of display id are implementation-specific, and it describes a
+specific display provided by the system EGL is running on. For example, an EGL
+implementation under X windows would require display id to be an X Display,
+while an implementation under Microsoft Windows would require display id to be
+a Windows Device Context. If display id is EGL DEFAULT DISPLAY, a default
+display is returned.
+If no display matching display id is available, EGL NO DISPLAY is returned;
+no error condition is raised in this case.
+
+   Implementation notes:
+
+   We only support one display. This is assumed to have a native display_id
+   of 0 (==EGL_DEFAULT_DISPLAY) and an EGLDisplay id of 1
+
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   -
+
+   Invariants preserved:
+
+   -
+
+   Invariants used:
+
+   -
+*/
+
+EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_CHECK_THREAD_STATE();
+   if (thread)
+      thread->error = EGL_SUCCESS;
+
+   return khrn_platform_set_display_id(display_id);
+}
+
+
+//eglInitialize
+//eglTerminate
+//eglQueryString
+
+/*
+   EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config)
+
+   Khronos documentation:
+
+3.4.1 Querying Configurations
+Use
+EGLBoolean eglGetConfigs(EGLDisplay dpy,
+EGLConfig *configs, EGLint config size,
+EGLint *num config);
+to get the list of all EGLConfigs that are available on the specified display. configs
+is a pointer to a buffer containing config size elements. On success, EGL TRUE is
+returned. The number of configurations is returned in num config, and elements 0
+through num config - 1 of configs are filled in with the valid EGLConfigs. No
+more than config size EGLConfigs will be returned even if more are available on
+the specified display. However, if eglGetConfigs is called with configs = NULL,
+then no configurations are returned, but the total number of configurations available
+will be returned in num config.
+On failure, EGL FALSE is returned. An EGL NOT INITIALIZED error is generated
+if EGL is not initialized on dpy. An EGL BAD PARAMETER error is generated
+if num config is NULL.
+
+   Implementation notes:
+
+   -
+
+   Preconditions:
+
+   configs is NULL or a valid pointer to config_size elements
+   num_config is NULL or a valid pointer
+
+   Postconditions:
+
+   The following conditions cause error to assume the specified value
+
+      EGL_BAD_DISPLAY               An EGLDisplay argument does not name a valid EGLDisplay
+      EGL_NOT_INITIALIZED           EGL is not initialized for the specified display.
+      EGL_BAD_PARAMETER             num_config is null
+      EGL_SUCCESS                   Function succeeded.
+
+   if more than one condition holds, the first error is generated.
+
+   Invariants preserved:
+
+   -
+
+   Invariants used:
+
+   -
+*/
+
+EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config)
+{
+   CLIENT_THREAD_STATE_T *thread;
+   CLIENT_PROCESS_STATE_T *process;
+   EGLBoolean result;
+
+   if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
+   {
+      if (!num_config) {
+         thread->error = EGL_BAD_PARAMETER;
+         result = EGL_FALSE;
+      } else if (!configs) {
+         thread->error = EGL_SUCCESS;
+         *num_config = EGL_MAX_CONFIGS;
+         result = EGL_TRUE;
+      } else {
+         int i;
+         for (i = 0; i < EGL_MAX_CONFIGS && i < config_size; i++)
+            configs[i] = egl_config_from_id(i);
+
+         thread->error = EGL_SUCCESS;
+         *num_config = i;
+         result = EGL_TRUE;
+      }
+      CLIENT_UNLOCK();
+   }
+   else
+      result = EGL_FALSE;
+
+   return result;
+}
+
+/*
+   EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config)
+
+   Khronos documentation:
+
+   Use
+EGLBoolean eglChooseConfig(EGLDisplay dpy, const
+EGLint *attrib list, EGLConfig *configs,
+EGLint config size, EGLint *num config);
+to get EGLConfigs that match a list of attributes. The return value and the meaning
+of configs, config size, and num config are the same as for eglGetConfigs.
+However, only configurations matching attrib list, as discussed below, will be returned.
+On failure, EGL FALSE is returned. An EGL BAD ATTRIBUTE error is generated
+if attrib list contains an undefined EGL attribute or an attribute value that is
+unrecognized or out of range.
+All attribute names in attrib list are immediately followed by the corresponding
+desired value. The list is terminated with EGL NONE. If an attribute is not specified
+in attrib list, then the default value (listed in Table 3.4) is used (it is said to be
+specified implicitly). If EGL_DONT_CARE is specified as an attribute value, then the
+attribute will not be checked. EGL_DONT_CARE may be specified for all attributes
+except EGL LEVEL. If attrib list is NULL or empty (first attribute is EGL NONE),
+then selection and sorting of EGLConfigs is done according to the default criteria
+in Tables 3.4 and 3.1, as described below under Selection and Sorting.
+Selection of EGLConfigs
+Attributes are matched in an attribute-specific manner, as shown in the \94Selection
+Critera\94 column of table 3.4. The criteria listed in the table have the following
+meanings:
+AtLeast Only EGLConfigs with an attribute value that meets or exceeds the
+specified value are selected.
+Exact Only EGLConfigs whose attribute value equals the specified value are
+matched.
+Mask Only EGLConfigs for which the bits set in the attribute value include all
+the bits that are set in the specified value are selected (additional bits might
+be set in the attribute value).
+Special As described for the specific attribute.
+Some of the attributes must match the specified value exactly; others, such as
+EGL RED SIZE, must meet or exceed the specified minimum values.
+To retrieve an EGLConfig given its unique integer ID, use the
+EGL CONFIG ID attribute. When EGL CONFIG ID is specified, all other attributes
+are ignored, and only the EGLConfig with the given ID is returned.
+If EGL MAX PBUFFER WIDTH, EGL MAX PBUFFER HEIGHT,
+EGL MAX PBUFFER PIXELS, or EGL NATIVE VISUAL ID are specified in
+attrib list, then they are ignored (however, if present, these attributes must still be
+Version 1.3 - December 4, 2006
+3.4. CONFIGURATION MANAGEMENT 21
+followed by an attribute value in attrib list). If EGL SURFACE TYPE is specified
+in attrib list and the mask that follows does not have EGL WINDOW BIT set, or if
+there are no native visual types, then the EGL NATIVE VISUAL TYPE attribute is
+ignored.
+If EGL TRANSPARENT TYPE is set to EGL NONE in attrib list, then
+the EGL TRANSPARENT RED VALUE, EGL TRANSPARENT GREEN VALUE, and
+EGL TRANSPARENT BLUE VALUE attributes are ignored.
+If EGL MATCH NATIVE PIXMAP is specified in attrib list, it must be followed
+by an attribute value which is the handle of a valid native pixmap. Only
+EGLConfigs which support rendering to that pixmap will match this attribute2.
+If no EGLConfig matching the attribute list exists, then the call succeeds, but
+num config is set to 0.
+
+Attribute                  Default       Selection Sort    Sort
+                                         Criteria  Order   Priority
+EGL_BUFFER_SIZE            0              AtLeast  Smaller 4
+EGL_RED_SIZE               0              AtLeast  Special 3
+EGL_GREEN_SIZE             0              AtLeast  Special 3
+EGL_BLUE_SIZE              0              AtLeast  Special 3
+EGL_LUMINANCE_SIZE         0              AtLeast  Special 3
+EGL_ALPHA_SIZE             0              AtLeast  Special 3
+EGL_ALPHA_MASK_SIZE        0              AtLeast  Smaller 9
+EGL_BIND_TO_TEXTURE_RGB    EGL_DONT_CARE  Exact    None
+EGL_BIND_TO_TEXTURE_RGBA   EGL_DONT_CARE  Exact    None
+EGL_COLOR_BUFFER_TYPE      EGL_RGB BUFFER Exact    None    2
+EGL_CONFIG_CAVEAT          EGL_DONT_CARE  Exact    Special 1
+EGL_CONFIG_ID              EGL_DONT_CARE  Exact    Smaller 11 (last)
+EGL_CONFORMANT             0              Mask     None
+EGL_DEPTH_SIZE             0              AtLeast  Smaller 7
+EGL_LEVEL                  0              Exact    None
+EGL_MATCH_NATIVE_PIXMAP    EGL_NONE       Special  None
+EGL_MAX_SWAP_INTERVAL      EGL_DONT_CARE  Exact    None
+EGL_MIN_SWAP_INTERVAL      EGL_DONT_CARE  Exact    None
+EGL_NATIVE_RENDERABLE      EGL_DONT_CARE  Exact    None
+EGL_NATIVE_VISUAL_TYPE     EGL_DONT_CARE  Exact    Special 10
+EGL_RENDERABLE_TYPE        EGL_OPENGL_ES_BIT Mask  None
+EGL_SAMPLE_BUFFERS         0              AtLeast  Smaller 5
+EGL_SAMPLES                0              AtLeast  Smaller 6
+EGL_STENCIL_SIZE           0              AtLeast  Smaller 8
+EGL_SURFACE_TYPE           EGL_WINDOW_BIT Mask     None
+EGL_TRANSPARENT_TYPE       EGL_NONE       Exact    None
+EGL_TRANSPARENT_RED_VALUE  EGL_DONT_CARE  Exact    None
+EGL_TRANSPARENT_GREEN_VALUE EGL_DONT_CARE Exact    None
+EGL_TRANSPARENT_BLUE_VALUE EGL_DONT_CARE  Exact    None
+Table 3.4: Default values and match criteria for EGLConfig attributes.
+
+
+2 The special match criteria for EGL MATCH NATIVE PIXMAP was introduced due to the
+difficulty of determining an EGLConfig equivalent to a native pixmap using only color component
+depths.
+3This rule places configs with deeper color buffers first in the list returned by eglChooseConfig.
+Applications may find this counterintuitive, and need to perform additional processing on the list of
+configs to find one best matching their requirements. For example, specifying RGBA depths of 5651
+could return a list whose first config has a depth of 8888.
+
+   Implementation notes:
+
+   Configurations are not always returned in the same order; the sort order depends on
+   whether we care about EGL_RED_SIZE, EGL_GREEN_SIZE, etc. So we need to extract the information
+   about which of these we care about, then pass this to a sorting function.
+
+   Preconditions:
+
+   configs is NULL or a valid pointer to config_size elements
+   num_config is NULL or a valid pointer
+   attrib_list is NULL or a pointer to an EGL_NONE-terminated list of attribute/value pairs
+
+   Postconditions:
+
+   The following conditions cause error to assume the specified value
+
+      EGL_BAD_DISPLAY               An EGLDisplay argument does not name a valid EGLDisplay
+      EGL_NOT_INITIALIZED           EGL is not initialized for dpy
+      EGL_BAD_PARAMETER             num_config is null
+      EGL_BAD_ATTRIBUTE             attrib_list contains an undefined EGL attribute
+      EGL_BAD_ATTRIBUTE             attrib_list contains an attribute value that is unrecognized or out of range.
+      EGL_SUCCESS                   Function succeeded.
+
+   if more than one condition holds, the first error is generated.
+
+   Invariants preserved:
+
+   -
+
+   Invariants used:
+
+   -
+*/
+
+static EGLBoolean choose_config(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config, bool sane)
+{
+   CLIENT_THREAD_STATE_T *thread;
+   CLIENT_PROCESS_STATE_T *process;
+   EGLBoolean result;
+
+   if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
+   {
+      if (!num_config) {
+         thread->error = EGL_BAD_PARAMETER;
+         result = EGL_FALSE;
+      } else {
+         /*
+            check for invalid attributes, and find color components for which
+            we have expressed a preference
+         */
+
+         bool use_red = false;
+         bool use_green = false;
+         bool use_blue = false;
+         bool use_alpha = false;
+
+         if (!egl_config_check_attribs(attrib_list, &use_red, &use_green, &use_blue, &use_alpha)) {
+            thread->error = EGL_BAD_ATTRIBUTE;
+            result = EGL_FALSE;
+         } else {
+
+            /*
+               sort configs
+            */
+
+            int ids[EGL_MAX_CONFIGS];
+            int i, j;
+
+            for (i = 0; i < EGL_MAX_CONFIGS; i++)
+               ids[i] = i;
+
+            egl_config_sort(ids,
+               !sane && use_red, !sane && use_green,
+               !sane && use_blue, !sane && use_alpha);
+
+            /*
+               return configs
+            */
+
+            j = 0;
+            for (i = 0; i < EGL_MAX_CONFIGS; i++) {
+               if (egl_config_filter(ids[i], attrib_list)) {
+                  if (configs && j < config_size) {
+                     configs[j] = egl_config_from_id(ids[i]);
+                     j++;
+                  } else if (!configs) {
+                     // If configs==NULL then we count all configs
+                     // Otherwise we only count the configs we return
+                     j++;
+                  }
+               }
+            }
+
+            thread->error = EGL_SUCCESS;
+            *num_config = j;
+            result = EGL_TRUE;
+         }
+      }
+
+      CLIENT_UNLOCK();
+   }
+   else
+      result = EGL_FALSE;
+
+   return result;
+}
+
+EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config)
+{
+   return choose_config(dpy, attrib_list, configs, config_size, num_config, false);
+}
+
+#if EGL_BRCM_sane_choose_config
+EGLAPI EGLBoolean EGLAPIENTRY eglSaneChooseConfigBRCM(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config)
+{
+   return choose_config(dpy, attrib_list, configs, config_size, num_config, true);
+}
+#endif
+
+/*
+   EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value)
+
+   Khronos documentation:
+   3.4.3 Querying Configuration Attributes
+   To get the value of an EGLConfig attribute, use
+   EGLBoolean eglGetConfigAttrib(EGLDisplay dpy,
+   EGLConfig config, EGLint attribute, EGLint
+   *value);
+   If eglGetConfigAttrib succeeds then it returns EGL_TRUE and the value for the
+   specified attribute is returned in value. Otherwise it returns EGL_FALSE. If attribute
+   is not a valid attribute then EGL_BAD_ATTRIBUTE is generated.
+   Refer to Table 3.1 and Table 3.4 for a list of valid EGL attributes.
+
+EGL_BUFFER_SIZE               integer    depth of the color buffer
+EGL_RED_SIZE                  integer    bits of Red in the color buffer
+EGL_GREEN_SIZE                integer    bits of Green in the color buffer
+EGL_BLUE_SIZE                 integer    bits of Blue in the color buffer
+EGL_LUMINANCE_SIZE            integer    bits of Luminance in the color buffer
+EGL_ALPHA_SIZE                integer    bits of Alpha in the color buffer
+EGL_ALPHA_MASK_SIZE           integer    bits of Alpha Mask in the mask buffer
+EGL_BIND_TO_TEXTURE_RGB       boolean    True if bindable to RGB textures.
+EGL_BIND_TO_TEXTURE_RGBA      boolean    True if bindable to RGBA textures.
+EGL_COLOR_BUFFER_TYPE         enum       color buffer type
+EGL_CONFIG_CAVEAT             enum       any caveats for the configuration
+EGL_CONFIG_ID                 integer    unique EGLConfig identifier
+EGL_CONFORMANT                bitmask    whether contexts created with this config are conformant
+EGL_DEPTH_SIZE                integer    bits of Z in the depth buffer
+EGL_LEVEL                     integer    frame buffer level
+EGL_MAX_PBUFFER_WIDTH         integer    maximum width of pbuffer
+EGL_MAX_PBUFFER_HEIGHT        integer    maximum height of pbuffer
+EGL_MAX_PBUFFER_PIXELS        integer    maximum size of pbuffer
+EGL_MAX_SWAP_INTERVAL         integer    maximum swap interval
+EGL_MIN_SWAP_INTERVAL         integer    minimum swap interval
+EGL_NATIVE_RENDERABLE         boolean    EGL_TRUE if native rendering APIs can render to surface
+EGL_NATIVE_VISUAL_ID          integer    handle of corresponding native visual
+EGL_NATIVE_VISUAL_TYPE        integer    native visual type of the associated visual
+EGL_RENDERABLE_TYPE           bitmask    which client APIs are supported
+EGL_SAMPLE_BUFFERS            integer    number of multisample buffers
+EGL_SAMPLES                   integer    number of samples per pixel
+EGL_STENCIL_SIZE              integer    bits of Stencil in the stencil buffer
+EGL_SURFACE_TYPE              bitmask    which types of EGL surfaces are supported.
+EGL_TRANSPARENT_TYPE          enum       type of transparency supported
+EGL_TRANSPARENT_RED_VALUE     integer    transparent red value
+EGL_TRANSPARENT_GREEN_VALUE   integer    transparent green value
+EGL_TRANSPARENT_BLUE_VALUE    integer    transparent blue value
+
+   Preconditions:
+
+   value is null or a valid pointer
+
+   Postconditions:
+
+   The following conditions cause error to assume the specified value
+
+      EGL_BAD_DISPLAY               An EGLDisplay argument does not name a valid EGLDisplay
+      EGL_NOT_INITIALIZED           EGL is not initialized for the specified display.
+      EGL_BAD_PARAMETER             value is null
+      EGL_BAD_CONFIG                config does not name a valid EGLConfig
+      EGL_BAD_ATTRIBUTE             attribute is not a valid attribute
+      EGL_SUCCESS                   Function succeeded.
+
+   if more than one condition holds, the first error is generated.
+
+*/
+
+EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value)
+{
+   CLIENT_THREAD_STATE_T *thread;
+   CLIENT_PROCESS_STATE_T *process;
+   EGLBoolean result;
+
+   if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process))
+   {
+      if (!value) {
+         thread->error = EGL_BAD_PARAMETER;
+         result = EGL_FALSE;
+      } else if (egl_config_to_id(config) < 0 || egl_config_to_id(config) >= EGL_MAX_CONFIGS) {
+         thread->error = EGL_BAD_CONFIG;
+         result = EGL_FALSE;
+      } else if (!egl_config_get_attrib(egl_config_to_id(config), attribute, value)) {
+         thread->error = EGL_BAD_ATTRIBUTE;
+         result = EGL_FALSE;
+      } else {
+         thread->error = EGL_SUCCESS;
+         result = EGL_TRUE;
+      }
+      CLIENT_UNLOCK();
+   }
+   else
+      result = EGL_FALSE;
+
+   return result;
+}
diff --git a/interface/khronos/egl/egl_client_get_proc.c b/interface/khronos/egl/egl_client_get_proc.c
new file mode 100755 (executable)
index 0000000..4cfa9ff
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/khronos/common/khrn_client_unmangle.h"
+#include "interface/khronos/include/GLES/gl.h"
+#include "interface/khronos/include/GLES/glext.h"
+#include "interface/khronos/include/GLES2/gl2.h"
+#include "interface/khronos/include/GLES2/gl2ext.h"
+
+#include "interface/khronos/common/khrn_int_common.h"
+#include "interface/khronos/common/khrn_options.h"
+
+#include "interface/khronos/egl/egl_client_surface.h"
+#include "interface/khronos/egl/egl_client_context.h"
+#include "interface/khronos/egl/egl_client_config.h"
+
+#include "interface/khronos/common/khrn_client.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+#include "interface/khronos/include/VG/vgext.h"
+
+#ifdef RPC_DIRECT
+#include "interface/khronos/egl/egl_int_impl.h"
+#endif
+
+#if defined(WIN32) || defined(__mips__)
+#include "interface/khronos/common/khrn_int_misc_impl.h"
+#endif
+
+#ifdef KHRONOS_EGL_PLATFORM_OPENWFC
+#include "interface/khronos/wf/wfc_client_stream.h"
+#endif
+
+#if defined(RPC_DIRECT_MULTI)
+#include "middleware/khronos/egl/egl_server.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Mangle eglGetProcAddress */
+#include "interface/khronos/common/khrn_client_mangle.h"
+
+EGLAPI void EGLAPIENTRY (* eglGetProcAddress(const char *procname))(void)
+{
+/* Don't mangle the rest */
+#include "interface/khronos/common/khrn_client_unmangle.h"
+#include "interface/khronos/include/EGL/eglext.h"
+
+   /* TODO: any other functions we need to return here?    */
+   if(!procname) return (void(*)(void)) NULL;
+
+#if EGL_KHR_image
+   if (!strcmp(procname, "eglCreateImageKHR"))
+      return (void(*)(void))eglCreateImageKHR;
+   if (!strcmp(procname, "eglDestroyImageKHR"))
+      return (void(*)(void))eglDestroyImageKHR;
+#endif
+#ifdef GL_EXT_discard_framebuffer
+   if (!strcmp(procname, "glDiscardFramebufferEXT"))
+      return (void(*)(void))glDiscardFramebufferEXT;
+#endif
+#ifdef GL_EXT_debug_marker
+   if (!strcmp(procname, "glInsertEventMarkerEXT"))
+      return (void(*)(void))glInsertEventMarkerEXT;
+   if (!strcmp(procname, "glPushGroupMarkerEXT"))
+      return (void(*)(void))glPushGroupMarkerEXT;
+   if (!strcmp(procname, "glPopGroupMarkerEXT"))
+      return (void(*)(void))glPopGroupMarkerEXT;
+#endif
+#if GL_OES_point_size_array
+   if (!strcmp(procname, "glPointSizePointerOES"))
+      return (void(*)(void))glPointSizePointerOES;
+#endif
+#if GL_OES_EGL_image
+   if (!strcmp(procname, "glEGLImageTargetTexture2DOES"))
+      return (void(*)(void))glEGLImageTargetTexture2DOES;
+   if (!strcmp(procname, "glEGLImageTargetRenderbufferStorageOES"))
+      return (void(*)(void))glEGLImageTargetRenderbufferStorageOES;
+#endif
+#if GL_OES_matrix_palette
+   if (!strcmp(procname, "glCurrentPaletteMatrixOES"))
+      return (void(*)(void))glCurrentPaletteMatrixOES;
+   if (!strcmp(procname, "glLoadPaletteFromModelViewMatrixOES"))
+      return (void(*)(void))glLoadPaletteFromModelViewMatrixOES;
+   if (!strcmp(procname, "glMatrixIndexPointerOES"))
+      return (void(*)(void))glMatrixIndexPointerOES;
+   if (!strcmp(procname, "glWeightPointerOES"))
+      return (void(*)(void))glWeightPointerOES;
+#endif
+#ifndef NO_OPENVG
+#if VG_KHR_EGL_image
+   if (!strcmp(procname, "vgCreateEGLImageTargetKHR"))
+      return (void(*)(void))vgCreateEGLImageTargetKHR;
+#endif
+#endif /* NO_OPENVG */
+#if EGL_KHR_lock_surface
+   if (!strcmp(procname, "eglLockSurfaceKHR"))
+      return (void(*)(void))eglLockSurfaceKHR;
+   if (!strcmp(procname, "eglUnlockSurfaceKHR"))
+      return (void(*)(void))eglUnlockSurfaceKHR;
+#endif
+#if EGL_KHR_sync
+   if (!strcmp(procname, "eglCreateSyncKHR"))
+      return (void(*)(void))eglCreateSyncKHR;
+   if (!strcmp(procname, "eglDestroySyncKHR"))
+      return (void(*)(void))eglDestroySyncKHR;
+   if (!strcmp(procname, "eglClientWaitSyncKHR"))
+      return (void(*)(void))eglClientWaitSyncKHR;
+   if (!strcmp(procname, "eglSignalSyncKHR"))
+      return (void(*)(void))eglSignalSyncKHR;
+   if (!strcmp(procname, "eglGetSyncAttribKHR"))
+      return (void(*)(void))eglGetSyncAttribKHR;
+#endif
+#if EGL_BRCM_perf_monitor
+   if (!strcmp(procname, "eglInitPerfMonitorBRCM"))
+      return (void(*)(void))eglInitPerfMonitorBRCM;
+   if (!strcmp(procname, "eglTermPerfMonitorBRCM"))
+      return (void(*)(void))eglTermPerfMonitorBRCM;
+#endif
+#if EGL_BRCM_driver_monitor
+   if (!strcmp(procname, "eglInitDriverMonitorBRCM"))
+      return (void(*)(void))eglInitDriverMonitorBRCM;
+   if (!strcmp(procname, "eglGetDriverMonitorXMLBRCM"))
+      return (void(*)(void))eglGetDriverMonitorXMLBRCM;
+   if (!strcmp(procname, "eglTermDriverMonitorBRCM"))
+      return (void(*)(void))eglTermDriverMonitorBRCM;
+#endif
+#if EGL_BRCM_perf_stats
+   if (!strcmp(procname, "eglPerfStatsResetBRCM"))
+      return (void(*)(void))eglPerfStatsResetBRCM;
+   if (!strcmp(procname, "eglPerfStatsGetBRCM"))
+      return (void(*)(void))eglPerfStatsGetBRCM;
+#endif
+#if EGL_BRCM_mem_usage
+   if (!strcmp(procname, "eglProcessMemUsageGetBRCM"))
+      return (void(*)(void))eglProcessMemUsageGetBRCM;
+#endif
+#ifdef EXPORT_DESTROY_BY_PID
+   if (!strcmp(procname, "eglDestroyByPidBRCM"))
+      return (void(*)(void))eglDestroyByPidBRCM;
+#endif
+#if GL_OES_draw_texture
+   if (!strcmp(procname, "glDrawTexsOES"))
+      return (void(*)(void))glDrawTexsOES;
+   if (!strcmp(procname, "glDrawTexiOES"))
+      return (void(*)(void))glDrawTexiOES;
+   if (!strcmp(procname, "glDrawTexxOES"))
+      return (void(*)(void))glDrawTexxOES;
+   if (!strcmp(procname, "glDrawTexsvOES"))
+      return (void(*)(void))glDrawTexsvOES;
+   if (!strcmp(procname, "glDrawTexivOES"))
+      return (void(*)(void))glDrawTexivOES;
+   if (!strcmp(procname, "glDrawTexxvOES"))
+      return (void(*)(void))glDrawTexxvOES;
+   if (!strcmp(procname, "glDrawTexfOES"))
+      return (void(*)(void))glDrawTexfOES;
+   if (!strcmp(procname, "glDrawTexfvOES"))
+      return (void(*)(void))glDrawTexfvOES;
+#endif
+
+#if GL_OES_query_matrix
+   if (!strcmp(procname, "glQueryMatrixxOES"))
+      return (void(*)(void))glQueryMatrixxOES;
+#endif
+
+#if GL_OES_framebuffer_object
+   if (!strcmp(procname, "glIsRenderbufferOES"))
+      return (void(*)(void))glIsRenderbufferOES;
+   if (!strcmp(procname, "glBindRenderbufferOES"))
+      return (void(*)(void))glBindRenderbufferOES;
+   if (!strcmp(procname, "glDeleteRenderbuffersOES"))
+      return (void(*)(void))glDeleteRenderbuffersOES;
+   if (!strcmp(procname, "glGenRenderbuffersOES"))
+      return (void(*)(void))glGenRenderbuffersOES;
+   if (!strcmp(procname, "glRenderbufferStorageOES"))
+      return (void(*)(void))glRenderbufferStorageOES;
+   if (!strcmp(procname, "glGetRenderbufferParameterivOES"))
+      return (void(*)(void))glGetRenderbufferParameterivOES;
+   if (!strcmp(procname, "glIsFramebufferOES"))
+      return (void(*)(void))glIsFramebufferOES;
+   if (!strcmp(procname, "glBindFramebufferOES"))
+      return (void(*)(void))glBindFramebufferOES;
+   if (!strcmp(procname, "glDeleteFramebuffersOES"))
+      return (void(*)(void))glDeleteFramebuffersOES;
+   if (!strcmp(procname, "glGenFramebuffersOES"))
+      return (void(*)(void))glGenFramebuffersOES;
+   if (!strcmp(procname, "glCheckFramebufferStatusOES"))
+      return (void(*)(void))glCheckFramebufferStatusOES;
+   if (!strcmp(procname, "glFramebufferRenderbufferOES"))
+      return (void(*)(void))glFramebufferRenderbufferOES;
+   if (!strcmp(procname, "glFramebufferTexture2DOES"))
+      return (void(*)(void))glFramebufferTexture2DOES;
+   if (!strcmp(procname, "glGetFramebufferAttachmentParameterivOES"))
+      return (void(*)(void))glGetFramebufferAttachmentParameterivOES;
+   if (!strcmp(procname, "glGenerateMipmapOES"))
+      return (void(*)(void))glGenerateMipmapOES;
+#endif
+
+#if GL_OES_mapbuffer
+   if (!strcmp(procname, "glGetBufferPointervOES"))
+      return (void(*)(void))glGetBufferPointervOES;
+   if (!strcmp(procname, "glMapBufferOES"))
+      return (void(*)(void))glMapBufferOES;
+   if (!strcmp(procname, "glUnmapBufferOES"))
+      return (void(*)(void))glUnmapBufferOES;
+#endif
+
+#if EGL_proc_state_valid
+   if (!strcmp(procname, "eglProcStateValid"))
+      return (void(*)(void))eglProcStateValid;
+#endif
+
+#if EGL_BRCM_flush
+   if (!strcmp(procname, "eglFlushBRCM"))
+      return (void(*)(void))eglFlushBRCM;
+#endif
+
+#if EGL_BRCM_global_image
+   if (!strcmp(procname, "eglCreateGlobalImageBRCM"))
+      return (void(*)(void))eglCreateGlobalImageBRCM;
+   if (!strcmp(procname, "eglCreateCopyGlobalImageBRCM"))
+      return (void(*)(void))eglCreateCopyGlobalImageBRCM;
+   if (!strcmp(procname, "eglDestroyGlobalImageBRCM"))
+      return (void(*)(void))eglDestroyGlobalImageBRCM;
+   if (!strcmp(procname, "eglQueryGlobalImageBRCM"))
+      return (void(*)(void))eglQueryGlobalImageBRCM;
+#endif
+
+   return (void(*)(void)) NULL;
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/interface/khronos/egl/egl_client_surface.c b/interface/khronos/egl/egl_client_surface.c
new file mode 100755 (executable)
index 0000000..6846dfa
--- /dev/null
@@ -0,0 +1,918 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define VCOS_LOG_CATEGORY (&egl_client_log_cat)
+
+#include "interface/khronos/common/khrn_int_common.h"
+
+#include "interface/khronos/common/khrn_client_rpc.h"
+#include "interface/khronos/common/khrn_client_platform.h"
+
+#include "interface/khronos/egl/egl_client_surface.h"
+#include "interface/khronos/egl/egl_client_config.h"
+
+#include "interface/khronos/common/khrn_client.h"
+
+#ifdef KHRONOS_EGL_PLATFORM_OPENWFC
+#include "interface/khronos/wf/wfc_int.h"
+#include "interface/khronos/wf/wfc_client_stream.h"
+#endif
+
+#ifdef RPC_DIRECT
+#include "interface/khronos/egl/egl_int_impl.h"
+#endif
+
+#include <stdlib.h>
+
+
+/*
+   surface_pool
+
+   cache for a small number of pre-allocated surface objects
+
+   Validity:
+   surfaces[i] is valid if allocated & (1<<i)
+*/
+
+#define EGL_SURFACE_POOL_SIZE 2
+static struct
+{
+   EGL_SURFACE_T surfaces[EGL_SURFACE_POOL_SIZE];
+   uint32_t allocated;
+} surface_pool;
+
+extern VCOS_LOG_CAT_T egl_client_log_cat;
+
+/*
+   EGL_SURFACE_T* egl_surface_pool_alloc(void)
+
+   Implementation notes:
+
+   We have a small static pool of structures (surface_pool) which we try and allocate out of
+   in order to reduce memory fragmentation. When we have run out of space in the pool we
+   resort to khrn_platform_malloc.
+
+   Preconditions:
+
+   Whoever calls this must initialise (or free) the returned structure in order to satisfy the invariant
+   on surface_pool.
+
+   Postconditions:
+
+   Return value is NULL or an uninitialised EGL_SURFACE_T structure, valid until egl_surface_pool_free
+   is called.
+*/
+
+static EGL_SURFACE_T* egl_surface_pool_alloc(void)
+{
+   int i = 0;
+
+   while(surface_pool.allocated & (1 << i))
+      i++;
+
+   if (i < EGL_SURFACE_POOL_SIZE)
+   {
+      surface_pool.allocated |= 1 << i;
+      return &surface_pool.surfaces[i];
+   }
+   else
+   {
+      return (EGL_SURFACE_T*)khrn_platform_malloc(sizeof(EGL_SURFACE_T), "EGL_SURFACE_T");
+   }
+}
+
+static void egl_surface_pool_free(EGL_SURFACE_T* surface)
+{
+   unsigned int i = 0;
+
+   /* todo: this doesn't belong here */
+   //semaphore now gets destroyed on async callback from VC
+   if (surface->avail_buffers_valid)
+      khronos_platform_semaphore_destroy(&surface->avail_buffers);
+   surface->avail_buffers_valid = false;
+
+   i = (unsigned int) (surface - surface_pool.surfaces);
+
+   if (i < EGL_SURFACE_POOL_SIZE)
+   {
+      surface_pool.allocated &= ~(1 << i);
+   }
+   else
+   {
+      khrn_platform_free((void*)surface);
+   }
+}
+
+/*
+   EGLBoolean egl_surface_check_attribs_window(const EGLint *attrib_list, EGLBoolean *linear, EGLBoolean *premult, EGLBoolean *single)
+
+   TODO: are we actually supposed to validate our parameters and generate an
+   error if they're wrong? I can't find an explicit mention in the spec about it.
+   (except for EGL_WIDTH and EGL_HEIGHT in pbuffer)
+
+   Preconditions:
+
+   type in {WINDOW, PBUFFER, PIXMAP}
+   attrib_list is NULL or a pointer to an EGL_NONE-terminated list of attribute/value pairs
+   linear, premult are NULL or valid pointers
+   If type == WINDOW then single is NULL or a valid pointer
+   If type == PBUFFER then width, height, largest_pbuffer, texture_format, texture_target, mipmap_texture are NULL or valid pointers
+
+   Postconditions:
+
+   -
+*/
+
+bool egl_surface_check_attribs(
+   EGL_SURFACE_TYPE_T type,
+   const EGLint *attrib_list,
+   bool *linear,
+   bool *premult,
+   bool *single,
+   int *width,
+   int *height,
+   bool *largest_pbuffer,
+   EGLenum *texture_format,
+   EGLenum *texture_target,
+   bool *mipmap_texture
+   )
+{
+   if (!attrib_list)
+      return true;
+
+   while (*attrib_list != EGL_NONE) {
+      int name = *attrib_list++;
+      int value = *attrib_list++;
+
+      switch (name) {
+      case EGL_VG_COLORSPACE:
+         if (value != EGL_VG_COLORSPACE_sRGB && value != EGL_VG_COLORSPACE_LINEAR)
+            return false;
+         if (value == EGL_VG_COLORSPACE_LINEAR && linear != NULL)
+            *linear = true;
+         break;
+      case EGL_VG_ALPHA_FORMAT:
+         if (value != EGL_VG_ALPHA_FORMAT_NONPRE && value != EGL_VG_ALPHA_FORMAT_PRE)
+            return false;
+         if (value == EGL_VG_ALPHA_FORMAT_PRE && premult != NULL)
+            *premult = true;
+         break;
+
+      /* For WINDOW types only */
+      case EGL_RENDER_BUFFER:
+         if (type != WINDOW || (value != EGL_SINGLE_BUFFER && value != EGL_BACK_BUFFER))
+            return false;
+         if (value == EGL_SINGLE_BUFFER && single != NULL)
+            *single = true;
+         break;
+
+      /* For PBUFFER types only */
+      case EGL_WIDTH:
+         if (type != PBUFFER || value < 0)
+            return false;
+         if (width != NULL)
+            *width = value;
+         break;
+      case EGL_HEIGHT:
+         if (type != PBUFFER || value < 0)
+            return false;
+         if (height != NULL)
+            *height = value;
+         break;
+      case EGL_LARGEST_PBUFFER:
+         if (type != PBUFFER || (value != EGL_FALSE && value != EGL_TRUE))
+            return false;
+         if (largest_pbuffer != NULL)
+            *largest_pbuffer = value;
+         break;
+      case EGL_TEXTURE_FORMAT:
+         if (type != PBUFFER || (value != EGL_NO_TEXTURE && value != EGL_TEXTURE_RGB && value != EGL_TEXTURE_RGBA))
+            return false;
+         if (texture_format != NULL)
+            *texture_format = value;
+         break;
+      case EGL_TEXTURE_TARGET:
+         if (type != PBUFFER || (value != EGL_NO_TEXTURE && value != EGL_TEXTURE_2D))
+            return false;
+         if (texture_target != NULL)
+            *texture_target = value;
+         break;
+      case EGL_MIPMAP_TEXTURE:
+         if (type != PBUFFER || (value != EGL_FALSE && value != EGL_TRUE))
+            return false;
+         if (mipmap_texture != NULL)
+            *mipmap_texture = value;
+         break;
+      default:
+         return false;
+      }
+   }
+
+   return true;
+}
+
+/*
+   EGL_SURFACE_T *egl_surface_create(
+      EGLSurface name,
+      EGL_SURFACE_TYPE_T type,
+      EGL_SURFACE_COLORSPACE_T colorspace,
+      EGL_SURFACE_ALPHAFORMAT_T alphaformat,
+      uint32_t buffers,
+      uint32_t width,
+      uint32_t height,
+      EGLConfig config,
+      EGLNativeWindowType win,
+      uint32_t serverwin,
+      bool largest_pbuffer,
+      bool mipmap_texture,
+      EGLenum texture_format,
+      EGLenum texture_target,
+      EGLNativePixmapType pixmap,
+      const uint32_t *pixmap_server_handle)
+
+   Implementation notes:
+
+   TODO: respect largest_pbuffer?
+
+   Preconditions:
+      type in {WINDOW,PBUFFER,PIXMAP}
+      colorspace in {SRGB,LINEAR}
+      alphaformat in {NONPRE,PRE}
+      1 <= buffers <= EGL_MAX_BUFFERS
+      0 < width, 0 < height
+      If !largest_pbuffer then width <= EGL_CONFIG_MAX_WIDTH, height <= EGL_CONFIG_MAX_HEIGHT
+      config is a valid EGL config
+
+      If type == WINDOW then
+         win is a valid client-side handle to window W
+         serverwin is a valid server-side handle to window W
+      else
+         win == 0
+         serverwin == PLATFORM_WIN_NONE
+
+      If type == PBBUFFER then
+         texture_format in {EGL_NO_TEXTURE, EGL_TEXTURE_RGB, EGL_TEXTURE_RGBA}
+         texture_target in {EGL_NO_TEXTURE, EGL_TEXTURE_2D}
+      else
+         largest_pbuffer == mipmap_texture == false
+         texture_format == texture_target == EGL_NO_TEXTURE
+
+      If type == PIXMAP then
+         pixmap is a valid client-side handle to pixmap P
+         If pixmap is a server-side pixmap then
+            pixmap_server_handle is a pointer to two elements, representing a valid server-side handle to pixmap P
+         else
+            pixmap_server_handle == 0
+      else
+         pixmap == pixmap_server_handle == 0
+
+   Postconditions:
+      Return value is NULL or an EGL_SURFACE_T structure, valid until egl_surface_free is called
+
+   Invariants preserved:
+      All invaraints on EGL_SURFACE_T
+*/
+
+EGL_SURFACE_T *egl_surface_create(
+   EGLSurface name,
+   EGL_SURFACE_TYPE_T type,
+   EGL_SURFACE_COLORSPACE_T colorspace,
+   EGL_SURFACE_ALPHAFORMAT_T alphaformat,
+   uint32_t buffers,
+   uint32_t width,
+   uint32_t height,
+   EGLConfig config,
+   EGLNativeWindowType win,
+   uint32_t serverwin,
+   bool largest_pbuffer,
+   bool texture_compatibility,
+   bool mipmap_texture,
+   EGLenum texture_format,
+   EGLenum texture_target,
+   EGLNativePixmapType pixmap,
+   const uint32_t *pixmap_server_handle)
+{
+   KHRN_IMAGE_FORMAT_T color;
+   KHRN_IMAGE_FORMAT_T depth;
+   KHRN_IMAGE_FORMAT_T mask;
+   KHRN_IMAGE_FORMAT_T multi;
+   uint32_t configid;
+   uint32_t sem_name;
+   EGLint   config_depth_bits;
+   EGLint   config_stencil_bits;
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   EGL_SURFACE_T *surface = egl_surface_pool_alloc();
+
+   //vcos_assert(width > 0 && height > 0);
+   vcos_assert((width <= EGL_CONFIG_MAX_WIDTH && height <= EGL_CONFIG_MAX_HEIGHT) || largest_pbuffer);
+
+   if (!surface) {
+      return 0;
+   }
+
+   /* TODO: respect largest_pbuffer? */
+
+   surface->name = name;
+   surface->type = type;
+
+   surface->colorspace = colorspace;
+   surface->alphaformat = alphaformat;
+
+   surface->config = config;
+   surface->win = win;
+   surface->width = width;
+   surface->height = height;
+   surface->swap_interval = 1;
+
+   surface->base_width = width;
+   surface->base_height = height;
+
+   surface->internal_handle = serverwin;
+
+   surface->largest_pbuffer = largest_pbuffer;
+   surface->mipmap_texture = mipmap_texture;
+   surface->mipmap_level = 0;
+   surface->texture_format = texture_format;
+   surface->texture_target = texture_target;
+   surface->pixmap = pixmap;
+   surface->pixmap_server_handle[0] = 0;
+   surface->pixmap_server_handle[1] = (uint32_t)-1;
+   surface->server_owned = false;
+   surface->swap_behavior = buffers > 1 ? EGL_BUFFER_DESTROYED : EGL_BUFFER_PRESERVED;
+   surface->multisample_resolve = EGL_MULTISAMPLE_RESOLVE_DEFAULT;
+
+   surface->context_binding_count = 0;
+   surface->is_destroyed = false;
+
+#if EGL_KHR_lock_surface
+   surface->is_locked = false;
+   surface->mapped_buffer = 0;
+#endif
+
+   configid = egl_config_to_id(config);
+   color = egl_config_get_color_format(configid);
+   if (texture_compatibility) { color = khrn_image_to_tf_format(color); }
+   if (alphaformat == PRE) { color = (KHRN_IMAGE_FORMAT_T)(color | IMAGE_FORMAT_PRE); }
+   if (colorspace == LINEAR) { color = (KHRN_IMAGE_FORMAT_T)(color | IMAGE_FORMAT_LIN); }
+   depth = egl_config_get_depth_format(configid);
+   mask = egl_config_get_mask_format(configid);
+   multi = egl_config_get_multisample_format(configid);
+
+   /* Find depth and stencil bits from chosen config (these may NOT be the same as the underlying format!) */
+   egl_config_get_attrib(configid, EGL_DEPTH_SIZE, &config_depth_bits);
+   egl_config_get_attrib(configid, EGL_STENCIL_SIZE, &config_stencil_bits);
+
+   vcos_assert(color != IMAGE_FORMAT_INVALID);
+
+#ifdef KHRONOS_EGL_PLATFORM_OPENWFC
+   // Create stream for this window
+   if(type != PBUFFER)
+   {
+      WFCNativeStreamType stream = (WFCNativeStreamType) surface->internal_handle;
+      vcos_assert(stream != WFC_INVALID_HANDLE);
+      uint32_t failure = wfc_stream_create(stream, WFC_STREAM_FLAGS_EGL);
+      vcos_log_trace("Creating stream with handle %X", stream);
+      vcos_assert(failure == 0);
+   } // if
+#endif
+
+   surface->buffers = buffers;
+
+   if (pixmap_server_handle) {
+      vcos_assert(type == PIXMAP);
+      surface->pixmap_server_handle[0] = pixmap_server_handle[0];
+      surface->pixmap_server_handle[1] = pixmap_server_handle[1];
+      surface->serverbuffer = RPC_UINT_RES(RPC_CALL7_RES(eglIntCreateWrappedSurface_impl,
+                                                         thread,
+                                                         EGLINTCREATEWRAPPEDSURFACE_ID,
+                                                         RPC_UINT(pixmap_server_handle[0]),
+                                                         RPC_UINT(pixmap_server_handle[1]),
+                                                         RPC_UINT(depth),
+                                                         RPC_UINT(mask),
+                                                         RPC_UINT(multi),
+                                                         RPC_UINT(config_depth_bits),
+                                                         RPC_UINT(config_stencil_bits)));
+      surface->avail_buffers_valid = false;
+   } else {
+#ifdef __SYMBIAN32__
+      uint32_t nbuff = 0;
+      surface->avail_buffers_valid = 0;
+
+      if (surface->buffers > 1) {
+         uint64_t pid = rpc_get_client_id(thread);
+         int sem[3] = { (int)pid, (int)(pid >> 32), (int)name };
+         if (khronos_platform_semaphore_create(&surface->avail_buffers, sem, surface->buffers) == KHR_SUCCESS)
+            surface->avail_buffers_valid = 1;
+            nbuff = (int)surface->avail_buffers;
+      }
+
+      if (surface->buffers == 1 || surface->avail_buffers_valid) {
+         uint32_t results[3];
+
+         RPC_CALL15_OUT_CTRL(eglIntCreateSurface_impl,
+                             thread,
+                             EGLINTCREATESURFACE_ID,
+                             RPC_UINT(serverwin),
+                             RPC_UINT(buffers),
+                             RPC_UINT(width),
+                             RPC_UINT(height),
+                             RPC_UINT(color),
+                             RPC_UINT(depth),
+                             RPC_UINT(mask),
+                             RPC_UINT(multi),
+                             RPC_UINT(largest_pbuffer),
+                             RPC_UINT(mipmap_texture),
+                             RPC_UINT(config_depth_bits),
+                             RPC_UINT(config_stencil_bits),
+                             RPC_UINT((int)nbuff),
+                             RPC_UINT(type),
+                             results);
+#else
+      surface->avail_buffers_valid = false;
+
+      sem_name = KHRN_NO_SEMAPHORE;
+#ifndef KHRONOS_EGL_PLATFORM_OPENWFC
+      if (surface->buffers > 1) {
+         uint64_t pid = rpc_get_client_id(thread);
+         int sem[3];
+         sem[0] = (int)pid; sem[1] = (int)(pid >> 32); sem[2] = (int)name;
+
+         sem_name = (int)name;
+         if (khronos_platform_semaphore_create(&surface->avail_buffers, sem, surface->buffers) == KHR_SUCCESS)
+            surface->avail_buffers_valid = true;
+      }
+      if (sem_name == KHRN_NO_SEMAPHORE || surface->avail_buffers_valid) {
+#else
+      sem_name = (uint32_t)surface->internal_handle;
+      vcos_log_trace("Surface create has semaphore %X", sem_name);
+#endif
+         uint32_t results[3];
+
+         RPC_CALL15_OUT_CTRL(eglIntCreateSurface_impl,
+                             thread,
+                             EGLINTCREATESURFACE_ID,
+                             RPC_UINT(serverwin),
+                             RPC_UINT(buffers),
+                             RPC_UINT(width),
+                             RPC_UINT(height),
+                             RPC_UINT(color),
+                             RPC_UINT(depth),
+                             RPC_UINT(mask),
+                             RPC_UINT(multi),
+                             RPC_UINT(largest_pbuffer),
+                             RPC_UINT(mipmap_texture),
+                             RPC_UINT(config_depth_bits),
+                             RPC_UINT(config_stencil_bits),
+                             RPC_UINT(sem_name),
+                             RPC_UINT(type),
+                             results);
+#endif
+         surface->width = results[0];
+         surface->height = results[1];
+         surface->serverbuffer = results[2];
+#ifndef KHRONOS_EGL_PLATFORM_OPENWFC
+      } else {
+         surface->serverbuffer = 0;
+      }
+#endif
+   }
+
+   if (surface->serverbuffer)
+      return surface;
+   else {
+      /* Server failed to create a surface due to out-of-memory or
+         we failed to create the named semaphore object. */
+      egl_surface_pool_free(surface);
+      return 0;
+   }
+}
+
+#ifndef NO_OPENVG
+
+/* Either returns a valid EGL_SURFACE_T, or returns null and sets error appropriately */
+
+EGL_SURFACE_T *egl_surface_from_vg_image(
+   VGImage vg_handle,
+   EGLSurface name,
+   EGLConfig config,
+   EGLBoolean largest_pbuffer,
+   EGLBoolean mipmap_texture,
+   EGLenum texture_format,
+   EGLenum texture_target,
+   EGLint *error)
+{
+   KHRN_IMAGE_FORMAT_T color;
+   KHRN_IMAGE_FORMAT_T depth;
+   KHRN_IMAGE_FORMAT_T mask;
+   KHRN_IMAGE_FORMAT_T multi;
+   EGLint   config_depth_bits;
+   EGLint   config_stencil_bits;
+   uint32_t results[5];
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   EGL_SURFACE_T *surface = egl_surface_pool_alloc();
+
+   if (!surface) {
+      *error = EGL_BAD_ALLOC;
+      return 0;
+   }
+
+   /* TODO: respect largest_pbuffer? */
+
+   surface->name = name;
+   surface->type = PBUFFER;
+
+   surface->config = config;
+   surface->win = 0;
+   surface->swap_interval = 1;
+
+   surface->largest_pbuffer = largest_pbuffer;
+   surface->mipmap_texture = mipmap_texture;
+   surface->mipmap_level = 0;
+   surface->texture_format = texture_format;
+   surface->texture_target = texture_target;
+   surface->pixmap = 0;
+   surface->pixmap_server_handle[0] = 0;
+   surface->pixmap_server_handle[1] = (uint32_t)-1;
+   surface->server_owned = false;
+
+   surface->context_binding_count = 0;
+   surface->is_destroyed = false;
+
+#if EGL_KHR_lock_surface
+   surface->is_locked = false;
+   surface->mapped_buffer = 0;
+#endif
+
+   color = egl_config_get_color_format((int)(size_t)config - 1);
+   depth = egl_config_get_depth_format((int)(size_t)config - 1);
+   mask = egl_config_get_mask_format((int)(size_t)config - 1);
+   multi = egl_config_get_multisample_format((int)(size_t)config - 1);
+
+   /* Find depth and stencil bits from chosen config (these may NOT be the same as the underlying format!) */
+   egl_config_get_attrib((int)(size_t)config - 1, EGL_DEPTH_SIZE, &config_depth_bits);
+   egl_config_get_attrib((int)(size_t)config - 1, EGL_STENCIL_SIZE, &config_stencil_bits);
+
+   vcos_assert(color != IMAGE_FORMAT_INVALID);
+
+   surface->buffers = 1;
+
+   RPC_CALL9_OUT_CTRL(eglIntCreatePbufferFromVGImage_impl,
+                     thread,
+                     EGLINTCREATEPBUFFERFROMVGIMAGE_ID,
+                     RPC_UINT(vg_handle),
+                     RPC_UINT(color),
+                     RPC_UINT(depth),
+                     RPC_UINT(mask),
+                     RPC_UINT(multi),
+                     RPC_UINT(mipmap_texture),
+                     RPC_UINT(config_depth_bits),
+                     RPC_UINT(config_stencil_bits),
+                     results);
+
+   surface->avail_buffers_valid = false;
+
+   if (results[0]) {
+      KHRN_IMAGE_FORMAT_T format = (KHRN_IMAGE_FORMAT_T)results[4];
+
+      surface->serverbuffer = results[0];
+      surface->width = results[2];
+      surface->height = results[3];
+
+      /* TODO: picking apart image formats like this seems messy */
+      surface->colorspace = (format & IMAGE_FORMAT_LIN) ? LINEAR : SRGB;
+      surface->alphaformat = (format & IMAGE_FORMAT_PRE) ? PRE : NONPRE;
+      *error = EGL_SUCCESS;
+      return surface;
+   } else {
+      *error = results[1];
+      egl_surface_pool_free(surface);
+      return 0;
+   }
+}
+
+#endif /* NO_OPENVG */
+
+/*
+   void egl_surface_free(EGL_SURFACE_T *surface)
+
+   Preconditions:
+
+   surface is a valid EGL_SURFACE_T returned from egl_surface_create or egl_surface_from_vg_image
+
+   Postconditions:
+
+   surface is freed and any associated server-side resources are dereferenced.
+*/
+
+void egl_surface_free(EGL_SURFACE_T *surface)
+{
+   CLIENT_THREAD_STATE_T *thread;
+
+   vcos_log_trace("egl_surface_free");
+
+   thread = CLIENT_GET_THREAD_STATE();
+
+   if( surface->type == WINDOW ) {
+      vcos_log_trace("egl_surface_free: calling platform_destroy_winhandle...");
+      platform_destroy_winhandle( surface->win, surface->internal_handle );
+   }
+   /* return value ignored -- read performed to ensure blocking. we want this to
+    * block so clients can safely destroy the surface's window as soon as the
+    * egl call that destroys the surface returns (usually eglDestroySurface, but
+    * could be eg eglMakeCurrent) */
+   vcos_log_trace("egl_surface_free: calling eglIntDestroySurface_impl via RPC...; "
+      "thread = 0x%X; serverbuffer = 0x%X",
+      (uint32_t) thread, (uint32_t) surface->serverbuffer);
+   (void)RPC_INT_RES(RPC_CALL1_RES(eglIntDestroySurface_impl,
+                                   thread,
+                                   EGLINTDESTROYSURFACE_ID,
+                                   RPC_UINT(surface->serverbuffer)));
+
+#ifdef KHRONOS_EGL_PLATFORM_OPENWFC
+   if(surface->internal_handle != PLATFORM_WIN_NONE) // TODO what about pbuffers?
+   {
+      vcos_log_trace("egl_surface_free: calling wfc_stream_destroy...");
+      wfc_stream_destroy((WFCNativeStreamType) surface->internal_handle);
+   }
+#endif
+
+   vcos_log_trace("egl_surface_free: calling egl_surface_pool_free...");
+   egl_surface_pool_free(surface);
+
+   vcos_log_trace("egl_surface_free: end");
+}
+
+EGLint egl_surface_get_render_buffer(EGL_SURFACE_T *surface)
+{
+   switch (surface->type) {
+   case WINDOW:
+      if (surface->buffers == 1)
+         return EGL_SINGLE_BUFFER;
+      else
+         return EGL_BACK_BUFFER;
+   case PBUFFER:
+      return EGL_BACK_BUFFER;
+   case PIXMAP:
+      return EGL_SINGLE_BUFFER;
+   default:
+      UNREACHABLE();
+      return EGL_NONE;
+   }
+}
+
+EGLBoolean egl_surface_get_attrib(EGL_SURFACE_T *surface, EGLint attrib, EGLint *value)
+{
+   switch (attrib) {
+   case EGL_VG_ALPHA_FORMAT:
+      if (surface->alphaformat == NONPRE)
+         *value = EGL_VG_ALPHA_FORMAT_NONPRE;
+      else
+         *value = EGL_VG_ALPHA_FORMAT_PRE;
+      return EGL_TRUE;
+   case EGL_VG_COLORSPACE:
+      if (surface->colorspace == SRGB)
+         *value = EGL_VG_COLORSPACE_sRGB;
+      else
+         *value = EGL_VG_COLORSPACE_LINEAR;
+      return EGL_TRUE;
+   case EGL_CONFIG_ID:
+      *value = (EGLint)(size_t)surface->config;
+      return EGL_TRUE;
+   case EGL_HEIGHT:
+      *value = surface->height;
+      return EGL_TRUE;
+   case EGL_HORIZONTAL_RESOLUTION:
+   case EGL_VERTICAL_RESOLUTION:
+      *value = EGL_UNKNOWN;
+      return EGL_TRUE;
+   case EGL_LARGEST_PBUFFER:
+      // For a window or pixmap surface, the contents of value are not modified.
+      if (surface->type == PBUFFER)
+         *value = surface->largest_pbuffer;
+      return EGL_TRUE;
+   case EGL_MIPMAP_TEXTURE:
+      // Querying EGL_MIPMAP_TEXTURE for a non-pbuffer surface is not
+      // an error, but value is not modified.
+      if (surface->type == PBUFFER)
+         *value = surface->mipmap_texture;
+      return EGL_TRUE;
+   case EGL_MIPMAP_LEVEL:
+      // Querying EGL_MIPMAP_LEVEL for a non-pbuffer surface is not
+      // an error, but value is not modified.
+      if (surface->type == PBUFFER)
+         *value = surface->mipmap_level;
+      return EGL_TRUE;
+   case EGL_PIXEL_ASPECT_RATIO:
+      *value = EGL_DISPLAY_SCALING;
+      return EGL_TRUE;
+   case EGL_RENDER_BUFFER:
+      *value = egl_surface_get_render_buffer(surface);
+      return EGL_TRUE;
+   case EGL_SWAP_BEHAVIOR:
+      *value = surface->swap_behavior;
+      return EGL_TRUE;
+   case EGL_MULTISAMPLE_RESOLVE:
+      *value = surface->multisample_resolve;
+      return EGL_TRUE;
+   case EGL_TEXTURE_FORMAT:
+      // Querying EGL_TEXTURE_FORMAT for a non-pbuffer surface is not
+      // an error, but value is not modified.
+      if (surface->type == PBUFFER)
+         *value = surface->texture_format;
+      return EGL_TRUE;
+   case EGL_TEXTURE_TARGET:
+      // Querying EGL_TEXTURE_TARGET for a non-pbuffer surface is not
+      // an error, but value is not modified.
+      if (surface->type == PBUFFER)
+         *value = surface->texture_target;
+      return EGL_TRUE;
+   case EGL_WIDTH:
+      *value = surface->width;
+      return EGL_TRUE;
+   default:
+      return EGL_FALSE;
+   }
+}
+
+EGLint egl_surface_set_attrib(EGL_SURFACE_T *surface, EGLint attrib, EGLint value)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   switch (attrib) {
+   case EGL_MIPMAP_LEVEL:
+      if (surface->type == PBUFFER) {
+         RPC_CALL2(eglIntSelectMipmap_impl,
+                   thread, 
+                   EGLINTSELECTMIPMAP_ID,
+                   RPC_UINT(surface->serverbuffer),
+                   RPC_INT(value));
+
+         surface->mipmap_level = value;
+      }
+      return EGL_SUCCESS;
+   case EGL_SWAP_BEHAVIOR:
+      switch (value) {
+      case EGL_BUFFER_PRESERVED:
+      case EGL_BUFFER_DESTROYED:
+         surface->swap_behavior = value;
+         return EGL_SUCCESS;
+      default:
+         return EGL_BAD_PARAMETER;
+      }
+   case EGL_MULTISAMPLE_RESOLVE:
+      switch (value) {
+      case EGL_MULTISAMPLE_RESOLVE_DEFAULT:
+      case EGL_MULTISAMPLE_RESOLVE_BOX:
+         surface->multisample_resolve = value;
+         return EGL_SUCCESS;
+      default:
+         return EGL_BAD_PARAMETER;
+      }
+   default:
+      return EGL_BAD_ATTRIBUTE;
+   }
+}
+
+#if EGL_KHR_lock_surface
+
+EGLint egl_surface_get_mapped_buffer_attrib(EGL_SURFACE_T *surface, EGLint attrib, EGLint *value)
+{
+   KHRN_IMAGE_FORMAT_T format;
+   bool is565;
+
+   vcos_assert(surface);
+
+   if (attrib == EGL_BITMAP_POINTER_KHR || attrib == EGL_BITMAP_PITCH_KHR) {
+      // Querying either of these causes the buffer to be mapped (if it isn't already)
+      // They also require that the surface is locked
+
+      if (!surface->is_locked) {
+         return EGL_BAD_ACCESS;   // TODO is this the right error?
+      }
+
+      if (!surface->mapped_buffer) {
+         uint32_t size;
+         void *buffer;
+         format = egl_config_get_mapped_format((int)((intptr_t)surface->config - 1)); // type juggling to avoid pointer truncation warnings
+         size = khrn_image_get_size(format, surface->width, surface->height);
+         buffer = khrn_platform_malloc(size, "EGL_SURFACE_T.mapped_buffer");
+
+         if (!buffer) {
+            return EGL_BAD_ALLOC;
+         }
+
+         surface->mapped_buffer = buffer;
+      }
+   }
+
+   if (!egl_config_is_lockable((int)((intptr_t)surface->config-1))) {    // type juggling to avoid pointer truncation warnings
+      // Calling any of these on unlockable surfaces is allowed but returns undefined results
+      *value = 0;
+      return EGL_SUCCESS;
+   }
+
+   format = egl_config_get_mapped_format((int)((intptr_t)surface->config-1));  // type juggling to avoid pointer truncation warnings
+   vcos_assert(format == RGB_565_RSO || format == ARGB_8888_RSO);
+   is565 = (format == RGB_565_RSO);       // else 888
+
+   switch (attrib) {
+   case EGL_BITMAP_POINTER_KHR:
+      *value = (EGLint)(intptr_t)surface->mapped_buffer; // type juggling to avoid pointer truncation warnings
+      return EGL_SUCCESS;
+   case EGL_BITMAP_PITCH_KHR:
+      *value = khrn_image_get_stride(format, surface->width);
+      return EGL_SUCCESS;
+   case EGL_BITMAP_ORIGIN_KHR:
+      *value = EGL_LOWER_LEFT_KHR;     // TODO: is this correct?
+      return EGL_SUCCESS;
+   case EGL_BITMAP_PIXEL_RED_OFFSET_KHR:
+      *value = is565 ? 11 : 0;         // TODO: I've probably got these wrong too
+      return EGL_SUCCESS;
+   case EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR:
+      *value = is565 ? 5 : 8;
+      return EGL_SUCCESS;
+   case EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR:
+      *value = is565 ? 0 : 16;
+      return EGL_SUCCESS;
+   case EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR:
+      *value = is565 ? 0 : 24;
+      return EGL_SUCCESS;
+   case EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR:
+      *value = 0;
+      return EGL_SUCCESS;
+   default:
+      UNREACHABLE();
+      return EGL_BAD_PARAMETER;
+   }
+}
+#endif
+
+
+/*
+   void egl_surface_maybe_free(EGL_SURFACE_T *surface)
+
+   Frees a surface together with its server-side resources if:
+   - it has been destroyed
+   - it is no longer current
+
+   Implementation notes:
+
+   -
+
+   Preconditions:
+
+   surface is a valid pointer
+
+   Postconditions:
+
+   Either:
+   - surface->is_destroyed is false (we don't change this), or
+   - surface->context_binding_count > 0, or
+   - surface has been deleted.
+
+   Invariants preserved:
+
+   -
+
+   Invariants used:
+
+   -
+ */
+
+void egl_surface_maybe_free(EGL_SURFACE_T *surface)
+{
+   vcos_assert(surface);
+
+   if (!surface->is_destroyed)
+      return;
+
+   if (surface->context_binding_count)
+      return;
+
+   egl_surface_free(surface);
+}
diff --git a/interface/khronos/egl/egl_client_surface.h b/interface/khronos/egl/egl_client_surface.h
new file mode 100755 (executable)
index 0000000..c99d44c
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef EGL_CLIENT_SURFACE_H
+#define EGL_CLIENT_SURFACE_H
+
+#include "interface/khronos/include/EGL/egl.h"
+#include "interface/khronos/include/EGL/eglext.h"
+#include "interface/khronos/include/VG/openvg.h"
+#include "interface/khronos/egl/egl_int.h"
+
+#include "interface/khronos/common/khrn_client_platform.h"
+
+typedef enum {
+   WINDOW,
+   PBUFFER,
+   PIXMAP
+} EGL_SURFACE_TYPE_T;
+
+typedef enum {
+   SRGB,
+   LINEAR
+} EGL_SURFACE_COLORSPACE_T;
+
+typedef enum {
+   NONPRE,
+   PRE
+} EGL_SURFACE_ALPHAFORMAT_T;
+
+typedef struct {
+   EGLSurface name;
+
+   /*
+      type
+
+      Invariants:
+
+      (EGL_SURFACE_TYPE)
+      type in {WINDOW, PBUFFER, PIXMAP}
+   */
+   EGL_SURFACE_TYPE_T type;
+
+   /*
+      colorspace
+
+      Invariants:
+
+      (EGL_SURFACE_COLORSPACE)
+      colorspace in {SRGB, LINEAR}
+   */
+   EGL_SURFACE_COLORSPACE_T colorspace;
+
+   /*
+      alphaformat
+
+      Invariants:
+
+      (EGL_SURFACE_ALPHAFORMAT)
+      alphaformat in {NONPRE, PRE}
+   */
+   EGL_SURFACE_ALPHAFORMAT_T alphaformat;
+
+   /*
+      config
+
+      Invariants:
+
+      (EGL_SURFACE_CONFIG)
+      config is a valid EGLConfig
+   */
+   EGLConfig config;
+
+   uint32_t base_width;
+   uint32_t base_height;
+
+   /*
+      buffers
+
+      Usually 1 or 3.
+
+      Invariants:
+
+      (EGL_SURFACE_BUFFERS)
+      1 <= buffers <= EGL_MAX_BUFFERS
+   */
+   uint32_t buffers;
+
+   /*
+      width
+
+      Invariants:
+
+      (EGL_SURFACE_WIDTH)
+      1 <= width <= EGL_CONFIG_MAX_WIDTH
+   */
+   uint32_t width;
+
+   /*
+      height
+
+      Invariants:
+
+      (EGL_SURFACE_HEIGHT)
+      1 <= height <= EGL_CONFIG_MAX_HEIGHT
+   */
+   uint32_t height;
+
+   EGL_SURFACE_ID_T serverbuffer;
+
+   /*
+      context_binding_count
+
+      Invariant:
+
+      (EGL_SURFACE_BINDING_COUNT)
+      If we are current, how many times we are bound to the current context. Otherwise 0.
+   */
+   uint32_t context_binding_count;
+   struct CLIENT_THREAD_STATE *thread;    // If we are current, which the EGL client state for the thread are we associated with.
+
+#if EGL_KHR_lock_surface
+   EGLBoolean is_locked;
+   void *mapped_buffer;
+#endif
+
+   /*
+      is_destroyed
+
+      Invariant:
+
+      (EGL_SURFACE_IS_DESTROYED)
+      Iff true, is not a member of the CLIENT_PROCESS_STATE_T.surfaces
+   */
+   bool is_destroyed;
+
+   /*
+      swap_behavior
+
+      Invariant:
+
+      (EGL_SURFACE_SWAP_BEHAVIOUR)
+      swap_behavior in {EGL_BUFFER_DESTROYED, EGL_BUFFER_PRESERVED}
+   */
+   EGLint swap_behavior;
+
+   /*
+      multisample_resolve
+
+      Invariant:
+
+      (EGL_SURFACE_MULTISAMPLE_RESOLVE)
+      multisample_resolve == EGL_MULTISAMPLE_RESOLVE_DEFAULT
+   */
+   EGLint multisample_resolve;
+
+   /* For WINDOW types only */
+
+   /*
+      win
+
+      Validity:
+      type == WINDOW
+   */
+   EGLNativeWindowType win;
+   /*
+      win
+
+      Validity:
+      type == WINDOW
+   */
+   uint32_t swap_interval;
+   uint32_t internal_handle;              // stores "serverwin"
+
+   /*
+      avail_buffers
+
+      named counting semaphore, only used for triple-buffered window surfaces
+
+      Validity:
+      avail_buffers_valid
+   */
+   PLATFORM_SEMAPHORE_T avail_buffers;
+   bool avail_buffers_valid;
+
+   /* For PBUFFER types only */
+
+   /*
+      largest_pbuffer
+
+      Validity:
+      type == PBUFFER
+   */
+   bool largest_pbuffer;
+
+   /*
+      mipmap_texture
+
+      Validity:
+      type == PBUFFER
+   */
+   bool mipmap_texture;
+
+   /*
+      mipmap_level
+
+      Validity:
+      type == PBUFFER
+   */
+   uint32_t mipmap_level;
+
+   /*
+      texture_format
+
+      Validity:
+      type == PBUFFER
+
+      Invariant:
+      texture_format in {EGL_NO_TEXTURE, EGL_TEXTURE_RGB, EGL_TEXTURE_RGBA}
+   */
+   EGLenum texture_format;
+
+   /*
+      texture_target
+
+      Validity:
+      type == PBUFFER
+
+      Invariant:
+      texture_target in {EGL_NO_TEXTURE, EGL_TEXTURE_2D}
+   */
+   EGLenum texture_target;
+
+   /* For PIXMAP types only */
+
+   /*
+      pixmap
+
+      Validity:
+      type == PIXMAP
+
+      Invariant:
+      pixmap is a valid client-side pixmap handle for pixmap P
+   */
+   EGLNativePixmapType pixmap;
+
+   /*
+      pixmap_server_handle
+
+      Validity:
+      type == PIXMAP
+
+      Invariant:
+      If P is a server-side pixmap then
+         pixmap_server_handle is a valid server-side handle for pixmap P
+      else
+         pixmap_server_handle = [0, -1]
+   */
+   uint32_t pixmap_server_handle[2];
+
+   /*
+      pixmap_server_handle
+
+      Validity:
+      type == PIXMAP
+   */
+   bool server_owned;
+} EGL_SURFACE_T;
+
+extern bool egl_surface_check_attribs(
+   EGL_SURFACE_TYPE_T type,
+   const EGLint *attrib_list,
+   bool *linear,
+   bool *premult,
+   bool *single,
+   int *width,
+   int *height,
+   bool *largest_pbuffer,
+   EGLenum *texture_format,
+   EGLenum *texture_target,
+   bool *mipmap_texture
+);
+struct CLIENT_PROCESS_STATE;
+
+extern EGL_SURFACE_T *egl_surface_create(
+   EGLSurface name,
+   EGL_SURFACE_TYPE_T type,
+   EGL_SURFACE_COLORSPACE_T colorspace,
+   EGL_SURFACE_ALPHAFORMAT_T alphaformat,
+   uint32_t buffers,
+   uint32_t width,
+   uint32_t height,
+   EGLConfig config,
+   EGLNativeWindowType win,
+   uint32_t serverwin,
+   bool largest_pbuffer,
+   bool texture_compatibility,
+   bool mipmap_texture,
+   EGLenum texture_format,
+   EGLenum texture_target,
+   EGLNativePixmapType pixmap,
+   const uint32_t *pixmap_server_handle);
+extern EGL_SURFACE_T *egl_surface_from_vg_image(
+   VGImage vg_handle,
+   EGLSurface name,
+   EGLConfig config,
+   EGLBoolean largest_pbuffer,
+   EGLBoolean mipmap_texture,
+   EGLenum texture_format,
+   EGLenum texture_target,
+   EGLint *error);
+extern void egl_surface_free(EGL_SURFACE_T *surface);
+
+extern EGLBoolean egl_surface_get_attrib(EGL_SURFACE_T *surface, EGLint attrib, EGLint *value);
+extern EGLint egl_surface_set_attrib(EGL_SURFACE_T *surface, EGLint attrib, EGLint value);
+extern EGLint egl_surface_get_render_buffer(EGL_SURFACE_T *surface);
+
+#if EGL_KHR_lock_surface
+extern EGLint egl_surface_get_mapped_buffer_attrib(EGL_SURFACE_T *surface, EGLint attrib, EGLint *value);
+#endif
+extern void egl_surface_maybe_free(EGL_SURFACE_T *surface);
+
+#endif
diff --git a/interface/khronos/egl/egl_int.h b/interface/khronos/egl/egl_int.h
new file mode 100755 (executable)
index 0000000..5be4b42
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef EGL_INT_H
+#define EGL_INT_H
+
+typedef enum {
+   OPENGL_ES_11,
+   OPENGL_ES_20,
+   OPENVG
+} EGL_CONTEXT_TYPE_T;
+
+// A single colour buffer. Optional ancillary buffers. If triple-buffered,
+// three EGL_SERVER_SURFACE_T's share ancillary buffers
+typedef uint32_t EGL_SURFACE_ID_T;
+
+// Either a GLES1.1 or GLES2.0 server state
+typedef uint32_t EGL_GL_CONTEXT_ID_T;
+
+typedef uint32_t EGL_VG_CONTEXT_ID_T;
+
+typedef uint32_t EGL_CONTEXT_ID_T;
+
+#define EGL_SERVER_NO_SURFACE 0
+#define EGL_SERVER_NO_GL_CONTEXT 0
+#define EGL_SERVER_NO_VG_CONTEXT 0
+
+#define EGL_SERVER_GL11 1
+#define EGL_SERVER_GL20 2
+
+typedef uint32_t EGL_SYNC_ID_T;
+
+#endif
diff --git a/interface/khronos/egl/egl_int_config.h b/interface/khronos/egl/egl_int_config.h
new file mode 100755 (executable)
index 0000000..96cbdab
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef EGL_INT_CONFIG_H
+#define EGL_INT_CONFIG_H
+
+#define EGL_CONFIG_MAX_WIDTH 2048
+#define EGL_CONFIG_MAX_HEIGHT 2048
+
+#endif
diff --git a/interface/khronos/egl/egl_int_impl.h b/interface/khronos/egl/egl_int_impl.h
new file mode 100755 (executable)
index 0000000..8a5734c
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#if defined(KHRN_IMPL_STRUCT)
+#define FN(type, name, args) type (*name) args;
+#elif defined(KHRN_IMPL_STRUCT_INIT)
+#define FN(type, name, args) name,
+#else
+#define FN(type, name, args) extern type name args;
+#endif
+
+#include "interface/khronos/include/EGL/egl.h"
+#include "interface/khronos/include/EGL/eglext.h"
+#ifndef KHRN_NO_WFC
+#include "interface/khronos/include/WF/wfc.h"
+#endif
+#include "interface/khronos/include/VG/openvg.h"
+#include "interface/khronos/common/khrn_int_image.h"
+#include "interface/khronos/egl/egl_int.h"
+
+FN(int, eglIntCreateSurface_impl, (
+   uint32_t win,
+   uint32_t buffers,
+   uint32_t width,
+   uint32_t height,
+   KHRN_IMAGE_FORMAT_T colorformat,
+   KHRN_IMAGE_FORMAT_T depthstencilformat,
+   KHRN_IMAGE_FORMAT_T maskformat,
+   KHRN_IMAGE_FORMAT_T multisampleformat,
+   uint32_t largest,
+   uint32_t mipmap,
+   uint32_t config_depth_bits,
+   uint32_t config_stencil_bits,
+   uint32_t sem,
+   uint32_t type,
+   uint32_t *results))
+
+FN(int, eglIntCreatePbufferFromVGImage_impl, (
+   VGImage vg_handle,
+   KHRN_IMAGE_FORMAT_T colorformat,
+   KHRN_IMAGE_FORMAT_T depthstencilformat,
+   KHRN_IMAGE_FORMAT_T maskformat,
+   KHRN_IMAGE_FORMAT_T multisampleformat,
+   uint32_t mipmap,
+   uint32_t config_depth_bits,
+   uint32_t config_stencil_bits,
+   uint32_t *results))
+
+FN(EGL_SURFACE_ID_T, eglIntCreateWrappedSurface_impl, (
+   uint32_t handle_0, uint32_t handle_1,
+   KHRN_IMAGE_FORMAT_T depthstencilformat,
+   KHRN_IMAGE_FORMAT_T maskformat,
+   KHRN_IMAGE_FORMAT_T multisample,
+   uint32_t config_depth_bits,
+   uint32_t config_stencil_bits))
+
+// Create server states. To actually use these, call, eglIntMakeCurrent.
+FN(EGL_GL_CONTEXT_ID_T, eglIntCreateGLES11_impl, (EGL_GL_CONTEXT_ID_T share_id, EGL_CONTEXT_TYPE_T share_type))
+FN(EGL_GL_CONTEXT_ID_T, eglIntCreateGLES20_impl, (EGL_GL_CONTEXT_ID_T share, EGL_CONTEXT_TYPE_T share_type))
+FN(EGL_VG_CONTEXT_ID_T, eglIntCreateVG_impl, (EGL_VG_CONTEXT_ID_T share, EGL_CONTEXT_TYPE_T share_type))
+
+// Disassociates surface or context objects from their handles. The objects
+// themselves still exist as long as there is a reference to them. In
+// particular, if you delete part of a triple buffer group, the remaining color
+// buffers plus the ancillary buffers all survive.
+// If, eglIntDestroySurface is called on a locked surface then that ID is
+// guaranteed not to be reused until the surface is unlocked (otherwise a call
+// to makevcimage or unlock might target the wrong surface)
+FN(int, eglIntDestroySurface_impl, (EGL_SURFACE_ID_T))
+FN(void, eglIntDestroyGL_impl, (EGL_GL_CONTEXT_ID_T))
+FN(void, eglIntDestroyVG_impl, (EGL_VG_CONTEXT_ID_T))
+
+// Selects the given process id for all operations. Most resource creation is
+//  associated with the currently selected process id
+// Selects the given context, draw and read surfaces for GL operations.
+// Selects the given context and surface for VG operations.
+// Any of the surfaces may be identical to each other.
+// If the GL context or surfaces have changed then GL will be flushed. Similarly for VG.
+// If any of the surfaces have been resized then the color and ancillary buffers
+//  are freed and recreated in the new size.
+FN(void, eglIntMakeCurrent_impl, (uint32_t pid_0, uint32_t pid_1, uint32_t glversion, EGL_GL_CONTEXT_ID_T, EGL_SURFACE_ID_T, EGL_SURFACE_ID_T, EGL_VG_CONTEXT_ID_T, EGL_SURFACE_ID_T))
+
+// Flushes one or both context, and waits for the flushes to complete before returning.
+// Equivalent to:
+// if (flushgl) glFinish())
+// if (flushvg) vgFinish())
+FN(int, eglIntFlushAndWait_impl, (uint32_t flushgl, uint32_t flushvg))
+FN(void, eglIntFlush_impl, (uint32_t flushgl, uint32_t flushvg))
+
+FN(void, eglIntSwapBuffers_impl, (EGL_SURFACE_ID_T s, uint32_t width, uint32_t height, uint32_t handle, uint32_t preserve, uint32_t position))
+FN(void, eglIntSelectMipmap_impl, (EGL_SURFACE_ID_T s, int level))
+
+FN(void, eglIntGetColorData_impl, (EGL_SURFACE_ID_T s, KHRN_IMAGE_FORMAT_T format, uint32_t width, uint32_t height, int32_t stride, uint32_t y_offset, void *data))
+FN(void, eglIntSetColorData_impl, (EGL_SURFACE_ID_T s, KHRN_IMAGE_FORMAT_T format, uint32_t width, uint32_t height, int32_t stride, uint32_t y_offset, const void *data))
+
+FN(bool, eglIntBindTexImage_impl, (EGL_SURFACE_ID_T s))
+FN(void, eglIntReleaseTexImage_impl, (EGL_SURFACE_ID_T s))
+
+FN(void, eglIntSwapInterval_impl, (EGL_SURFACE_ID_T s, uint32_t swap_interval))
+
+FN(void, eglIntGetProcessMemUsage_impl, (uint32_t id_0, uint32_t id_1, uint32_t buffer_len, char *buffer))
+FN(void, eglIntGetGlobalMemUsage_impl, (uint32_t *result))
+
+FN(EGL_SYNC_ID_T, eglIntCreateSync_impl, (uint32_t type, uint32_t condition, int32_t threshold, uint32_t sem))
+FN(void, eglIntCreateSyncFence_impl, (uint32_t condition, int32_t threshold, uint32_t sem))
+
+FN(void, eglIntDestroySync_impl, (EGL_SYNC_ID_T))
+
+FN(void, eglIntDestroyByPid_impl, (uint32_t pid_0, uint32_t pid_1))
+
+FN(void, eglIntCheckCurrent_impl, (uint32_t pid_0, uint32_t pid_1))
+
+#if EGL_KHR_image
+FN(int, eglCreateImageKHR_impl, (uint32_t glversion, EGL_CONTEXT_ID_T ctx, EGLenum target, uint32_t buffer, KHRN_IMAGE_FORMAT_T buffer_format, uint32_t buffer_width, uint32_t buffer_height, uint32_t buffer_stride, EGLint texture_level, EGLint *results))
+FN(EGLBoolean, eglDestroyImageKHR_impl, (EGLImageKHR image))
+#endif
+
+#if EGL_BRCM_global_image
+FN(void, eglCreateGlobalImageBRCM_impl, (EGLint width, EGLint height, EGLint pixel_format, EGLint *id))
+FN(void, eglFillGlobalImageBRCM_impl, (EGLint id_0, EGLint id_1, EGLint y, EGLint height, const void *data, EGLint data_stride, EGLint data_pixel_format))
+FN(void, eglCreateCopyGlobalImageBRCM_impl, (EGLint src_id_0, EGLint src_id_1, EGLint *id))
+FN(bool, eglDestroyGlobalImageBRCM_impl, (EGLint id_0, EGLint id_1))
+FN(bool, eglQueryGlobalImageBRCM_impl, (EGLint id_0, EGLint id_1, EGLint *width_height_pixel_format))
+#endif
+
+#if EGL_BRCM_perf_monitor
+FN(bool, eglInitPerfMonitorBRCM_impl, (void))
+FN(void, eglTermPerfMonitorBRCM_impl, (void))
+#endif
+
+#if EGL_BRCM_driver_monitor
+FN(bool, eglInitDriverMonitorBRCM_impl, (EGLint hw_bank, EGLint l3c_bank))
+FN(void, eglTermDriverMonitorBRCM_impl, (void))
+FN(void, eglGetDriverMonitorXMLBRCM_impl, (EGLint bufSize, char *xmlStats))
+#endif
+
+#if EGL_BRCM_perf_stats
+FN(void, eglPerfStatsResetBRCM_impl, ())
+FN(void, eglPerfStatsGetBRCM_impl, (EGLint buffer_len, EGLBoolean reset, char *buffer))
+#endif
+
+FN(int, eglIntOpenMAXILDoneMarker_impl, (void* component_handle, EGLImageKHR egl_image))
+
+FN(void, eglIntImageSetColorData_impl, (EGLImageKHR image, KHRN_IMAGE_FORMAT_T format,
+        uint32_t x_offset, uint32_t y_offset,
+        uint32_t width, uint32_t height, int32_t stride, const void *data))
+
+#ifdef ANDROID
+#ifndef KHRN_NO_WFC
+FN(void, eglPushRenderingImage_impl, (uint64_t pid, uint32_t window, EGLImageKHR image))
+#endif
+#endif
+
+#ifdef DIRECT_RENDERING
+FN(void, eglDirectRenderingPointer_impl, (EGL_SURFACE_ID_T surface, uint32_t buffer, KHRN_IMAGE_FORMAT_T buffer_format, uint32_t buffer_width, uint32_t buffer_height, uint32_t buffer_stride))
+#endif
+
+#undef FN
diff --git a/interface/khronos/ext/egl_brcm_driver_monitor_client.c b/interface/khronos/ext/egl_brcm_driver_monitor_client.c
new file mode 100755 (executable)
index 0000000..7aa521a
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define EGL_EGLEXT_PROTOTYPES /* we want the prototypes so the compiler will check that the signatures match */
+
+#include "interface/khronos/common/khrn_int_common.h"
+
+#include "interface/khronos/common/khrn_client.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+
+#include "interface/khronos/egl/egl_client_config.h"
+
+#include "interface/khronos/ext/egl_brcm_driver_monitor_client.h"
+
+#include "interface/khronos/include/EGL/egl.h"
+#include "interface/khronos/include/EGL/eglext.h"
+
+#if EGL_BRCM_driver_monitor
+
+EGLAPI EGLBoolean EGLAPIENTRY eglInitDriverMonitorBRCM(EGLDisplay dpy, EGLint hw_bank, EGLint l3c_bank)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   EGLBoolean result;
+
+   CLIENT_LOCK();
+
+   {
+      CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE);
+
+      if (process) 
+      {
+         if (!process->driver_monitor_inited)
+            process->driver_monitor_inited = RPC_BOOLEAN_RES(RPC_CALL2_RES(eglInitDriverMonitorBRCM_impl,
+                                                         thread,
+                                                         EGLINITDRIVERMONITORBRCM_ID,
+                                                         hw_bank, l3c_bank));
+
+         if (process->driver_monitor_inited) 
+         {
+            thread->error = EGL_SUCCESS;
+            result = EGL_TRUE;
+         } 
+         else 
+         {
+            thread->error = EGL_BAD_ALLOC;
+            result = EGL_FALSE;
+         }
+      } 
+      else
+         result = EGL_FALSE;
+   }
+
+   CLIENT_UNLOCK();
+
+   return result;
+}
+
+void egl_driver_monitor_term(CLIENT_PROCESS_STATE_T *process)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   if (process->driver_monitor_inited) 
+   {
+      RPC_CALL0(eglTermDriverMonitorBRCM_impl,
+                thread,  
+                EGLTERMDRIVERMONITORBRCM_ID);
+
+      process->driver_monitor_inited = false;
+   }
+}
+
+EGLAPI void EGLAPIENTRY eglGetDriverMonitorXMLBRCM(EGLDisplay dpy, EGLint bufSize, EGLint *length, char *xmlStats)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   CLIENT_LOCK();
+
+   {
+      CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE);
+
+      if (process) 
+      {
+         if (process->driver_monitor_inited && xmlStats != NULL)
+         {
+            RPC_CALL2_OUT_BULK(eglGetDriverMonitorXMLBRCM_impl,
+               thread,
+               EGLGETDRIVERMONITORXMLBRCM_ID, bufSize, xmlStats);
+
+            if (length != NULL)
+               *length = strlen(xmlStats);
+         }
+      }
+   }
+
+   CLIENT_UNLOCK();
+}
+
+EGLAPI EGLBoolean EGLAPIENTRY eglTermDriverMonitorBRCM(EGLDisplay dpy)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   EGLBoolean result;
+
+   CLIENT_LOCK();
+
+   {
+      CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE);
+
+      if (process) 
+      {
+         egl_driver_monitor_term(process);
+
+         thread->error = EGL_SUCCESS;
+         result = EGL_TRUE;
+      } 
+      else
+         result = EGL_FALSE;
+   }
+
+   CLIENT_UNLOCK();
+
+   return result;
+}
+
+#endif
diff --git a/interface/khronos/ext/egl_brcm_driver_monitor_client.h b/interface/khronos/ext/egl_brcm_driver_monitor_client.h
new file mode 100755 (executable)
index 0000000..5d3fc9e
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "interface/khronos/common/khrn_client.h"
+
+void egl_driver_monitor_term(CLIENT_PROCESS_STATE_T *process);
diff --git a/interface/khronos/ext/egl_brcm_flush_client.c b/interface/khronos/ext/egl_brcm_flush_client.c
new file mode 100755 (executable)
index 0000000..e958f31
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define EGL_EGLEXT_PROTOTYPES /* we want the prototypes so the compiler will check that the signatures match */
+
+#include "interface/khronos/common/khrn_int_common.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+#include "interface/khronos/include/EGL/egl.h"
+#include "interface/khronos/include/EGL/eglext.h"
+#include "interface/khronos/common/khrn_int_misc_impl.h"
+
+#if EGL_BRCM_flush
+
+/*
+   any commands issued by the current thread before calling eglFlushBRCM() are
+   guaranteed to complete before any commands issued by *any* thread after
+   eglFlushBRCM() returns
+*/
+
+EGLAPI void EGLAPIENTRY eglFlushBRCM(void)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   RPC_FLUSH(thread);
+}
+
+#endif
diff --git a/interface/khronos/ext/egl_brcm_global_image_client.c b/interface/khronos/ext/egl_brcm_global_image_client.c
new file mode 100755 (executable)
index 0000000..67a3d43
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define EGL_EGLEXT_PROTOTYPES /* we want the prototypes so the compiler will check that the signatures match */
+
+#include "interface/khronos/common/khrn_int_common.h"
+#include "interface/khronos/common/khrn_client.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+#include "interface/khronos/egl/egl_client_config.h"
+#include "interface/khronos/include/EGL/egl.h"
+#include "interface/khronos/include/EGL/eglext.h"
+
+#if EGL_BRCM_global_image
+
+static EGLint get_bytes_per_pixel(EGLint pixel_format) /* returns 0 for invalid pixel formats */
+{
+   switch (pixel_format & ~EGL_PIXEL_FORMAT_USAGE_MASK_BRCM) {
+   case EGL_PIXEL_FORMAT_ARGB_8888_PRE_BRCM: return 4;
+   case EGL_PIXEL_FORMAT_ARGB_8888_BRCM:     return 4;
+   case EGL_PIXEL_FORMAT_XRGB_8888_BRCM:     return 4;
+   case EGL_PIXEL_FORMAT_RGB_565_BRCM:       return 2;
+   case EGL_PIXEL_FORMAT_A_8_BRCM:           return 1;
+   default:                                  return 0; /* invalid */
+   }
+}
+
+/*
+   failure is indicated by (!id[0] && !id[1]). call eglGetError for the error code
+
+   possible failures:
+   - width/height <= 0 or > EGL_CONFIG_MAX_WIDTH/EGL_CONFIG_MAX_HEIGHT (EGL_BAD_PARAMETER)
+   - pixel_format invalid (EGL_BAD_PARAMETER)
+   - insufficient resources (EGL_BAD_ALLOC)
+
+   data may be NULL (in which case the image contents are undefined)
+*/
+
+EGLAPI void EGLAPIENTRY eglCreateGlobalImageBRCM(EGLint width, EGLint height, EGLint pixel_format, const void *data, EGLint data_stride, EGLint *id)
+{
+   EGLint bytes_per_pixel;
+
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   /*
+      check params
+   */
+
+   bytes_per_pixel = get_bytes_per_pixel(pixel_format);
+   if ((width <= 0) || (width > EGL_CONFIG_MAX_WIDTH) ||
+      (height <= 0) || (height > EGL_CONFIG_MAX_HEIGHT) ||
+      (bytes_per_pixel == 0)) {
+      thread->error = EGL_BAD_PARAMETER;
+      id[0] = 0; id[1] = 0;
+      return;
+   }
+
+   /*
+      create the image
+   */
+
+   RPC_CALL4_OUT_CTRL(eglCreateGlobalImageBRCM_impl,
+                      thread,
+                      EGLCREATEGLOBALIMAGEBRCM_ID,
+                      RPC_INT(width),
+                      RPC_INT(height),
+                      RPC_INT(pixel_format),
+                      id);
+   if (!id[0] && !id[1]) {
+      thread->error = EGL_BAD_ALLOC;
+      return;
+   }
+
+   /*
+      fill the image in if necessary (this can't fail)
+   */
+
+   if (data) {
+      #ifdef RPC_DIRECT
+         RPC_CALL7(eglFillGlobalImageBRCM_impl, thread, no_id, id[0], id[1], 0, height, data, data_stride, pixel_format);
+      #else
+         EGLint y = 0;
+
+         EGLint chunk_height_max = KHDISPATCH_WORKSPACE_SIZE / (width * bytes_per_pixel);
+         vcos_assert(chunk_height_max != 0);
+
+         while (height != 0) {
+            VGint chunk_height = _min(height, chunk_height_max);
+
+            uint32_t message[] = {
+               EGLFILLGLOBALIMAGEBRCM_ID,
+               RPC_INT(id[0]),
+               RPC_INT(id[1]),
+               RPC_INT(y),
+               RPC_INT(chunk_height),
+               RPC_INT(width * bytes_per_pixel),
+               RPC_INT(pixel_format) };
+
+            CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+            rpc_begin(thread);
+            rpc_send_ctrl_begin(thread, sizeof(message));
+            rpc_send_ctrl_write(thread, message, sizeof(message));
+            rpc_send_ctrl_end(thread);
+            rpc_send_bulk_gather(thread, data, width * bytes_per_pixel, data_stride, chunk_height);
+            data = (const uint8_t *)data + (chunk_height * data_stride);
+            rpc_end(thread);
+
+            height -= chunk_height;
+            y += chunk_height;
+         }
+      #endif
+   }
+}
+
+/*
+   failure is indicated by (!id[0] && !id[1]). call eglGetError for the error code
+
+   possible failures:
+   - src_id invalid (EGL_BAD_PARAMETER)
+   - insufficient resources (EGL_BAD_ALLOC)
+*/
+
+EGLAPI void EGLAPIENTRY eglCreateCopyGlobalImageBRCM(const EGLint *src_id, EGLint *id)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   /*
+      create the image
+   */
+
+   RPC_CALL3_OUT_CTRL(eglCreateCopyGlobalImageBRCM_impl,
+                      thread,
+                      EGLCREATECOPYGLOBALIMAGEBRCM_ID,
+                      RPC_INT(src_id[0]),
+                      RPC_INT(src_id[1]),
+                      id);
+   if (!id[0] && !id[1]) { /* not enough memory */
+      thread->error = EGL_BAD_ALLOC;
+   }
+   if ((id[0] == -1) && (id[1] == -1)) { /* src_id was invalid */
+      thread->error = EGL_BAD_PARAMETER;
+      id[0] = 0; id[1] = 0;
+   }
+}
+
+/*
+   failure is indicated by returning EGL_FALSE. call eglGetError for the error code
+
+   possible failures:
+   - id invalid (EGL_BAD_PARAMETER)
+*/
+
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyGlobalImageBRCM(const EGLint *id)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   /*
+      destroy the image
+   */
+
+   if (!RPC_BOOLEAN_RES(RPC_CALL2_RES(eglDestroyGlobalImageBRCM_impl,
+                                      thread,
+                                      EGLDESTROYGLOBALIMAGEBRCM_ID,
+                                      RPC_INT(id[0]),
+                                      RPC_INT(id[1])))) {
+      thread->error = EGL_BAD_PARAMETER;
+      return EGL_FALSE;
+   }
+
+   return EGL_TRUE;
+}
+
+/*
+   failure is indicated by returning EGL_FALSE. call eglGetError for the error code
+
+   possible failures:
+   - id invalid (EGL_BAD_PARAMETER)
+*/
+
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryGlobalImageBRCM(const EGLint *id, EGLint *width_height_pixel_format)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   if (!RPC_BOOLEAN_RES(RPC_CALL3_OUT_CTRL_RES(eglQueryGlobalImageBRCM_impl,
+                                               thread,
+                                               EGLQUERYGLOBALIMAGEBRCM_ID,
+                                               RPC_INT(id[0]),
+                                               RPC_INT(id[1]),
+                                               width_height_pixel_format))) {
+      thread->error = EGL_BAD_PARAMETER;
+      return EGL_FALSE;
+   }
+
+   return EGL_TRUE;
+}
+
+#endif
diff --git a/interface/khronos/ext/egl_brcm_perf_monitor_client.c b/interface/khronos/ext/egl_brcm_perf_monitor_client.c
new file mode 100755 (executable)
index 0000000..16d5164
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define EGL_EGLEXT_PROTOTYPES /* we want the prototypes so the compiler will check that the signatures match */
+
+#include "interface/khronos/common/khrn_int_common.h"
+
+#include "interface/khronos/common/khrn_client.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+
+#include "interface/khronos/egl/egl_client_config.h"
+
+#include "interface/khronos/ext/egl_brcm_perf_monitor_client.h"
+
+#include "interface/khronos/include/EGL/egl.h"
+#include "interface/khronos/include/EGL/eglext.h"
+
+#if EGL_BRCM_perf_monitor
+
+EGLAPI EGLBoolean EGLAPIENTRY eglInitPerfMonitorBRCM(EGLDisplay dpy)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   EGLBoolean result;
+
+   CLIENT_LOCK();
+
+   {
+      CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE);
+
+      if (process) {
+         if (!process->perf_monitor_inited)
+            process->perf_monitor_inited = RPC_BOOLEAN_RES(RPC_CALL0_RES(eglInitPerfMonitorBRCM_impl,
+                                                         EGLINITPERFMONITORBRCM_ID));
+
+         if (process->perf_monitor_inited) {
+            thread->error = EGL_SUCCESS;
+            result = EGL_TRUE;
+         } else {
+            thread->error = EGL_BAD_ALLOC;
+            result = EGL_FALSE;
+         }
+      } else
+         result = EGL_FALSE;
+   }
+
+   CLIENT_UNLOCK();
+
+   return result;
+}
+
+void egl_perf_monitor_term(CLIENT_PROCESS_STATE_T *process)
+{
+   if (process->perf_monitor_inited) {
+      RPC_CALL0(eglTermPerfMonitorBRCM_impl,
+                EGLTERMPERFMONITORBRCM_ID);
+
+      process->perf_monitor_inited = false;
+   }
+}
+
+EGLAPI EGLBoolean EGLAPIENTRY eglTermPerfMonitorBRCM(EGLDisplay dpy)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   EGLBoolean result;
+
+   CLIENT_LOCK();
+
+   {
+      CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE);
+
+      if (process) {
+         egl_perf_monitor_term(process);
+
+         thread->error = EGL_SUCCESS;
+         result = EGL_TRUE;
+      } else
+         result = EGL_FALSE;
+   }
+
+   CLIENT_UNLOCK();
+
+   return result;
+}
+
+#endif
+
+#if EGL_BRCM_perf_stats
+
+EGLAPI void eglPerfStatsResetBRCM(void)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   RPC_CALL0(eglPerfStatsResetBRCM_impl, thread, EGLPERFSTATSRESETBRCM_ID);
+}
+
+EGLAPI void eglPerfStatsGetBRCM(char *buffer, EGLint buffer_len, EGLBoolean reset)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   // int len = _min(_max(buffer_len, 0), KHDISPATCH_WORKSPACE_SIZE);
+
+   RPC_CALL3_OUT_BULK(eglPerfStatsGetBRCM_impl,
+                      thread,
+                      EGLPERFSTATSGETBRCM_ID,
+                      RPC_INT(buffer_len),
+                      RPC_BOOLEAN(reset),
+                      buffer);
+}
+
+#endif
+
+#if EGL_BRCM_mem_usage
+
+EGLAPI void eglProcessMemUsageGetBRCM(uint32_t id_0, uint32_t id_1, char *buffer, uint32_t buffer_len)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   RPC_CALL4_OUT_BULK(eglIntGetProcessMemUsage_impl,
+                      thread,
+                      EGLINTGETPROCESSMEMUSAGE_ID,
+                      RPC_UINT(id_0),
+                      RPC_UINT(id_1),
+                      RPC_UINT(buffer_len),
+                      buffer);
+}
+
+#endif
diff --git a/interface/khronos/ext/egl_brcm_perf_monitor_client.h b/interface/khronos/ext/egl_brcm_perf_monitor_client.h
new file mode 100755 (executable)
index 0000000..bf91787
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "interface/khronos/common/khrn_client.h"
+
+void egl_perf_monitor_term(CLIENT_PROCESS_STATE_T *process);
diff --git a/interface/khronos/ext/egl_khr_image_client.c b/interface/khronos/ext/egl_khr_image_client.c
new file mode 100755 (executable)
index 0000000..4743ee8
--- /dev/null
@@ -0,0 +1,530 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define EGL_EGLEXT_PROTOTYPES /* we want the prototypes so the compiler will check that the signatures match */
+
+#define VCOS_LOG_CATEGORY (&egl_khr_image_client_log)
+#include "interface/khronos/common/khrn_client_mangle.h"
+
+#include "interface/khronos/common/khrn_int_common.h"
+
+#include "interface/khronos/common/khrn_client.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+
+#include "interface/khronos/include/EGL/egl.h"
+#include "interface/khronos/include/EGL/eglext.h"
+#include "interface/khronos/include/EGL/eglext_brcm.h"
+#include "interface/khronos/include/GLES/gl.h"
+
+#include "interface/vcos/vcos.h"
+
+#if EGL_ANDROID_image_native_buffer
+#include <gralloc_brcm.h>
+#endif
+
+#if defined(ANDROID) && defined(KHRN_BCG_ANDROID)
+#include "gralloc_priv.h"
+#include "middleware/khronos/common/2708/khrn_prod_4.h"
+#endif
+
+#ifdef KHRONOS_HAVE_VCSM
+#include "user-vcsm.h"
+#else
+#include <dlfcn.h>
+#include <dlfcn.h>
+typedef enum
+{
+   VCSM_CACHE_TYPE_NONE = 0,        // No caching applies.
+   VCSM_CACHE_TYPE_HOST,            // Allocation is cached on host (user space).
+   VCSM_CACHE_TYPE_VC,              // Allocation is cached on videocore.
+   VCSM_CACHE_TYPE_HOST_AND_VC,     // Allocation is cached on both host and videocore.
+
+} VCSM_CACHE_TYPE_T;
+static unsigned int (*vcsm_malloc_cache)(unsigned int size, VCSM_CACHE_TYPE_T cache, char *name);
+static unsigned int (*vcsm_vc_hdl_from_hdl)(unsigned int handle);
+static void (*vcsm_free) (unsigned int handle);
+#endif /* KHRONOS_HAVE_VCSM */
+
+static VCOS_LOG_CAT_T egl_khr_image_client_log = VCOS_LOG_INIT("egl_khr_image_client", VCOS_LOG_WARN);
+
+static bool egl_init_vcsm()
+{
+#ifdef KHRONOS_HAVE_VCSM
+    return true;
+#else
+    static bool warn_once;
+    bool success = false;
+
+    if (vcsm_malloc_cache)
+       return true;
+
+    if (! vcsm_malloc_cache) {
+        /* Try LD_LIBRARY_PATH first */
+        void *dl = dlopen("libvcsm.so", RTLD_LAZY);
+
+        if (!dl)
+           dl = dlopen("/opt/vc/lib/libvcsm.so", RTLD_LAZY);
+
+        if (dl)
+        {
+           vcsm_malloc_cache = dlsym(dl, "vcsm_malloc_cache");
+           vcsm_vc_hdl_from_hdl = dlsym(dl, "vcsm_vc_hdl_from_hdl");
+           vcsm_free = dlsym(dl, "vcsm_free");
+
+           if (vcsm_malloc_cache && vcsm_vc_hdl_from_hdl && vcsm_free) 
+           {
+              success = true;
+           }
+           else
+           {
+              vcsm_malloc_cache = NULL;
+              vcsm_vc_hdl_from_hdl = NULL;
+              vcsm_free = NULL;
+           }
+        }
+    }
+    if (! success && ! warn_once)
+    {
+        vcos_log_error("Unable to load libvcsm.so for target EGL_IMAGE_BRCM_VCSM");
+        warn_once = false;
+    }
+    return success;
+#endif /* KHRONOS_HAVE_VCSM */
+}
+
+EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attr_list)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   EGLImageKHR result = EGL_NO_IMAGE_KHR;
+
+   CLIENT_LOCK();
+
+   vcos_log_info("eglCreateImageKHR: dpy %p ctx %p target %x buf %p\n",
+                                      dpy, ctx, target, buffer);
+
+   {
+      CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE);
+
+      if (process) {
+         EGL_CONTEXT_T *context;
+         bool ctx_error;
+         if (target == EGL_NATIVE_PIXMAP_KHR
+#ifdef EGL_BRCM_image_wrap
+            || target == EGL_IMAGE_WRAP_BRCM
+#endif
+#ifdef EGL_BRCM_image_wrap_bcg
+            || target == EGL_IMAGE_WRAP_BRCM_BCG
+#endif
+#if EGL_ANDROID_image_native_buffer
+            || target == EGL_NATIVE_BUFFER_ANDROID
+            || target == EGL_IMAGE_BRCM_RAW_PIXELS
+#endif
+            || target == EGL_IMAGE_BRCM_MULTIMEDIA
+            || target == EGL_IMAGE_BRCM_MULTIMEDIA_Y
+            || target == EGL_IMAGE_BRCM_MULTIMEDIA_U
+            || target == EGL_IMAGE_BRCM_MULTIMEDIA_V
+            || target == EGL_IMAGE_BRCM_DUPLICATE
+            || target == EGL_IMAGE_BRCM_VCSM
+            ) {
+            context = NULL;
+            ctx_error = ctx != EGL_NO_CONTEXT;
+         } else {
+            context = client_egl_get_context(thread, process, ctx);
+            ctx_error = !context;
+         }
+         if (ctx_error) {
+            thread->error = EGL_BAD_PARAMETER;
+         }
+         else {
+            uint32_t buf[2];
+            KHRN_IMAGE_FORMAT_T buffer_format = IMAGE_FORMAT_INVALID;
+            uint32_t buffer_width = 0;
+            uint32_t buffer_height = 0;
+            uint32_t buffer_stride = 0;
+            bool buf_error = false;
+            if (target == EGL_NATIVE_PIXMAP_KHR) {
+               buf[0] = 0; buf[1] = (uint32_t)(-1);
+               platform_get_pixmap_server_handle((EGLNativePixmapType)buffer, buf);
+#if EGL_BRCM_global_image
+               if ((buf[0] == 0) && (buf[1] == (uint32_t)(-1))) { /* allow either regular or global image server-side pixmaps */
+#else
+               if ((buf[0] == 0) || (buf[1] != (uint32_t)(-1))) { /* only allow regular server-side pixmaps */
+#endif
+                  /* This is a client-side pixmap! TODO: implement these properly */
+                  KHRN_IMAGE_WRAP_T image;
+                  if (platform_get_pixmap_info((EGLNativePixmapType)buffer, &image))
+                  {
+//meego hack          
+                     if(image.aux!=0)
+                     {
+                        //image.aux refers to a server side EGL surface 
+                        //that already contains the data we're interested in
+                        buf[0] = (uint32_t)image.aux;
+                        target = EGL_IMAGE_FROM_SURFACE_BRCM;
+                        khrn_platform_release_pixmap_info((EGLNativePixmapType)buffer, &image);                        
+                     }
+//                                         
+                     else
+                     {
+                        buf[0] = image.width | image.height << 16;
+                        target = EGL_NATIVE_PIXMAP_CLIENT_SIDE_BRCM;
+                        khrn_platform_release_pixmap_info((EGLNativePixmapType)buffer, &image);
+                     }
+
+                  }
+                  else
+                  {
+                     buf_error = true;
+                  }
+               }
+#if EGL_BRCM_image_wrap
+            } else if (target == EGL_IMAGE_WRAP_BRCM) {
+               KHRN_IMAGE_WRAP_T *wrap_buffer = (KHRN_IMAGE_WRAP_T *)buffer;
+
+               buf[0] = (uint32_t)wrap_buffer->storage;
+               buffer_format = wrap_buffer->format;
+               buffer_width = wrap_buffer->width;
+               buffer_height = wrap_buffer->height;
+               buffer_stride = wrap_buffer->stride;
+#endif
+#if EGL_BRCM_image_wrap_bcg
+            } else if (target == EGL_IMAGE_WRAP_BRCM_BCG) {
+               EGL_IMAGE_WRAP_BRCM_BCG_IMAGE_T *wrap_buffer = (EGL_IMAGE_WRAP_BRCM_BCG_IMAGE_T *)buffer;
+
+               buf[0] = (uint32_t)wrap_buffer->storage;
+               buffer_width = wrap_buffer->width;
+               buffer_height = wrap_buffer->height;
+               buffer_stride = wrap_buffer->stride;
+
+               switch(wrap_buffer->format)
+               {
+               case BEGL_BufferFormat_eR8G8B8A8_TFormat:          buffer_format = ABGR_8888_TF;          break;
+               case BEGL_BufferFormat_eX8G8B8A8_TFormat:          buffer_format = XBGR_8888_TF;          break;
+               case BEGL_BufferFormat_eR5G6B5_TFormat:            buffer_format = RGB_565_TF;            break;
+               case BEGL_BufferFormat_eR5G5B5A1_TFormat:          buffer_format = RGBA_5551_TF;          break;
+               case BEGL_BufferFormat_eR4G4B4A4_TFormat:          buffer_format = RGBA_4444_TF;          break;
+
+               case BEGL_BufferFormat_eR8G8B8A8_LTFormat:         buffer_format = ABGR_8888_LT;          break;
+               case BEGL_BufferFormat_eX8G8B8A8_LTFormat:         buffer_format = XBGR_8888_LT;          break;
+               case BEGL_BufferFormat_eR5G6B5_LTFormat:           buffer_format = RGB_565_LT;            break;
+               case BEGL_BufferFormat_eR5G5B5A1_LTFormat:         buffer_format = RGBA_5551_LT;          break;
+               case BEGL_BufferFormat_eR4G4B4A4_LTFormat:         buffer_format = RGBA_4444_LT;          break;
+
+               default:
+                  buf_error = true;
+               }
+#endif
+#if EGL_ANDROID_image_native_buffer
+#ifdef KHRN_BCG_ANDROID
+            } else if (target == EGL_NATIVE_BUFFER_ANDROID) {
+               android_native_buffer_t *android_buffer = (android_native_buffer_t *)buffer;
+               vcos_assert(ANDROID_NATIVE_BUFFER_MAGIC == android_buffer->common.magic);
+               /* TODO check that handle is a valid gralloc handle */
+               /* These are shadow width/height and format, not to be confused with the
+                  underlying formats configuration */
+
+               buf[0] = (uint32_t)khrn_hw_unaddr(((struct private_handle_t *)android_buffer->handle)->oglPhysicalAddress);
+
+               buffer_format = ((struct private_handle_t *)android_buffer->handle)->oglFormat;
+               buffer_width = android_buffer->width;
+               buffer_height = android_buffer->height;
+               buffer_stride = ((struct private_handle_t *)android_buffer->handle)->oglStride;
+
+               switch (((struct private_handle_t *)android_buffer->handle)->oglFormat)
+               {
+                  case BEGL_BufferFormat_eR8G8B8A8_TFormat:       buffer_format = ABGR_8888_TF;    break;
+                  case BEGL_BufferFormat_eX8G8B8A8_TFormat:       buffer_format = XBGR_8888_TF;    break;
+                  case BEGL_BufferFormat_eR5G6B5_TFormat:         buffer_format = RGB_565_TF;      break;
+                  case BEGL_BufferFormat_eR5G5B5A1_TFormat:       buffer_format = RGBA_5551_TF;    break;
+                  case BEGL_BufferFormat_eR4G4B4A4_TFormat:       buffer_format = RGBA_4444_TF;    break;
+                  case BEGL_BufferFormat_eR8G8B8A8_LTFormat:      buffer_format = ABGR_8888_LT;    break;
+                  case BEGL_BufferFormat_eX8G8B8A8_LTFormat:      buffer_format = XBGR_8888_LT;    break;
+                  case BEGL_BufferFormat_eR5G6B5_LTFormat:        buffer_format = RGB_565_LT;      break;
+                  case BEGL_BufferFormat_eR5G5B5A1_LTFormat:      buffer_format = RGBA_5551_LT;    break;
+                  case  BEGL_BufferFormat_eR4G4B4A4_LTFormat:     buffer_format = RGBA_4444_LT;    break;
+                  default :                                       buf_error = true;                break;
+               }
+#else
+            } else if (target == EGL_NATIVE_BUFFER_ANDROID) {
+               gralloc_private_handle_t *gpriv = gralloc_private_handle_from_client_buffer(buffer);
+               int res_type = gralloc_private_handle_get_res_type(gpriv);
+
+               if (res_type == GRALLOC_PRIV_TYPE_GL_RESOURCE) {
+                  /* just return the a copy of the EGLImageKHR gralloc created earlier
+                     see hardware/broadcom/videocore/components/graphics/gralloc/ */
+                  target = EGL_IMAGE_BRCM_DUPLICATE;
+                  buf[0] = (uint32_t)gralloc_private_handle_get_egl_image(gpriv);
+                  vcos_log_trace("%s: converting buffer %p egl_image %d to EGL_IMAGE_BRCM_DUPLICATE",
+                        __FUNCTION__, buffer, buf[0]);
+               }
+               else if (res_type == GRALLOC_PRIV_TYPE_MM_RESOURCE) {
+                  /* MM image is potentially going to be used as a texture so
+                   * VC EGL needs to acquire a reference to the underlying vc_image.
+                   * So, we create the image in the normal way.
+                   * EGL_NATIVE_BUFFER_ANDROID is passed as the target.
+                   */
+                  if (gpriv->gl_format == GRALLOC_MAGICS_HAL_PIXEL_FORMAT_OPAQUE)
+                     target = EGL_IMAGE_BRCM_MULTIMEDIA;
+                  else
+                     target = EGL_IMAGE_BRCM_RAW_PIXELS;
+                  buffer_width = gpriv->w;
+                  buffer_height = gpriv->h;
+                  buffer_stride = gpriv->stride;
+
+                  buf[0] = gralloc_private_handle_get_vc_handle(gpriv);
+                  vcos_log_trace("%s: converting buffer %p handle %u to EGL_IMAGE_BRCM_MULTIMEDIA",
+                        __FUNCTION__, buffer, buf[0]);
+               }
+               else {
+                  vcos_log_error("%s: unknown gralloc resource type %x", __FUNCTION__, res_type);
+               }
+#endif
+#else /* Not Android */
+            } else if (target == EGL_IMAGE_BRCM_VCSM && egl_init_vcsm()) {
+                  struct egl_image_brcm_vcsm_info *info = (struct egl_image_brcm_vcsm_info *) buffer;
+                  buf_error = true;
+                  vcos_log_info("%s: EGL_IMAGE_BRCM_VCSM", __FUNCTION__); // FIXME
+
+#define IS_POT(X) ((X) && (((X) & (~(X) + 1)) == (X)))
+#define VALID_RSO_DIM(X) (IS_POT(X) && (X) >= 64 && (X) <= 2048)
+
+                  // Allocate the VCSM buffer. This could be moved to VideoCore.
+                  if (info && VALID_RSO_DIM(info->width) && VALID_RSO_DIM(info->height)) {
+                      unsigned int vcsm_handle;
+                      buffer_width = info->width;
+                      buffer_height = info->height;
+                      buffer_format = ABGR_8888_RSO; // Only format supported
+                      buffer_stride = buffer_width << 2;
+
+                      vcsm_handle = vcsm_malloc_cache(buffer_stride * buffer_height,
+                              VCSM_CACHE_TYPE_HOST, "EGL_IMAGE_BRCM_VCSM");
+                      if (vcsm_handle) {
+                          buf[0] = vcsm_vc_hdl_from_hdl(vcsm_handle);
+                          info->vcsm_handle = vcsm_handle;
+                          if (buf[0])
+                              buf_error = false;
+                          else {
+                              vcos_log_error("%s: bad VCSM handle %u", __FUNCTION__, vcsm_handle);
+                              vcsm_free(vcsm_handle);
+                          }
+
+                         vcos_log_trace("%s: VCSM %u VC %u %ux%u %u", __FUNCTION__, vcsm_handle,
+                                 buf[0], buffer_width, buffer_height, buffer_stride);
+                      }
+                  } else {
+                      vcos_log_error("VCSM buffer dimension but be POT between 64 and 2048\n");
+                  }
+            } else if (target == EGL_IMAGE_BRCM_MULTIMEDIA) {
+                  buf[0] = (uint32_t)buffer;
+                  vcos_log_trace("%s: converting buffer handle %u to EGL_IMAGE_BRCM_MULTIMEDIA",
+                        __FUNCTION__, buf[0]);
+            } else if (target == EGL_IMAGE_BRCM_MULTIMEDIA_Y) {
+                  buf[0] = (uint32_t)buffer;
+                  vcos_log_trace("%s: converting buffer handle %u to EGL_IMAGE_BRCM_MULTIMEDIA_Y",
+                        __FUNCTION__, buf[0]);
+            } else if (target == EGL_IMAGE_BRCM_MULTIMEDIA_U) {
+                  buf[0] = (uint32_t)buffer;
+                  vcos_log_trace("%s: converting buffer handle %u to EGL_IMAGE_BRCM_MULTIMEDIA_U",
+                        __FUNCTION__, buf[0]);
+            } else if (target == EGL_IMAGE_BRCM_MULTIMEDIA_V) {
+                  buf[0] = (uint32_t)buffer;
+                  vcos_log_trace("%s: converting buffer handle %u to EGL_IMAGE_BRCM_MULTIMEDIA_V",
+                        __FUNCTION__, buf[0]);
+#endif
+            } else {
+               vcos_log_trace("%s:target type %x buffer %p handled on server", __FUNCTION__, target, buffer);
+               buf[0] = (uint32_t)buffer;
+            }
+            if (buf_error) {
+               thread->error = EGL_BAD_PARAMETER;
+            }
+            else {
+               EGLint texture_level = 0;
+               bool attr_error = false;
+               if (attr_list) {
+                  while (!attr_error && *attr_list != EGL_NONE) {
+                     switch (*attr_list++) {
+                     case EGL_GL_TEXTURE_LEVEL_KHR:
+                        texture_level = *attr_list++;
+                        break;
+                     case EGL_IMAGE_PRESERVED_KHR:
+                     {
+                        EGLint preserved = *attr_list++;
+                        if ((preserved != EGL_FALSE) && (preserved != EGL_TRUE)) {
+                           attr_error = true;
+                        } /* else: ignore the actual value -- we always preserve */
+                        break;
+                     }
+                     default:
+                        attr_error = true;
+                     }
+                  }
+               }
+               if (attr_error) {
+                  thread->error = EGL_BAD_PARAMETER;
+               }
+               else {
+#if EGL_BRCM_global_image
+                  if ((target == EGL_NATIVE_PIXMAP_KHR) && (buf[1] != (uint32_t)-1)) {
+                     if (platform_use_global_image_as_egl_image(buf[0], buf[1], (EGLNativePixmapType)buffer, &thread->error)) {
+                        if (!khrn_global_image_map_insert(&process->global_image_egl_images,
+                           process->next_global_image_egl_image,
+                           buf[0] | ((uint64_t)buf[1] << 32))) {
+                           thread->error = EGL_BAD_ALLOC;
+                        } else {
+                           result = (EGLImageKHR)(uintptr_t)process->next_global_image_egl_image;
+                           thread->error = EGL_SUCCESS;
+                           do {
+                              process->next_global_image_egl_image = (1 << 31) |
+                                 (process->next_global_image_egl_image + 1);
+                           } while (khrn_global_image_map_lookup(&process->global_image_egl_images,
+                              process->next_global_image_egl_image));
+                        }
+                     }
+                  } else
+#endif
+                  {
+                     EGLint results[2];
+
+                     vcos_log_info("%s: width %d height %d target %x buffer %p", __FUNCTION__, buffer_width, buffer_height, target, buffer);
+                     RPC_CALL10_OUT_CTRL(eglCreateImageKHR_impl,
+                        thread,
+                        EGLCREATEIMAGEKHR_ID,
+                        RPC_UINT(context ? (context->type == OPENGL_ES_20 ? 2 : 1) : 0),
+                        RPC_UINT(context ? context->servercontext : 0),
+                        RPC_ENUM(target),
+                        RPC_UINT(buf[0]),
+                        RPC_UINT(buffer_format),
+                        RPC_UINT(buffer_width),
+                        RPC_UINT(buffer_height),
+                        RPC_UINT(buffer_stride),
+                        RPC_INT(texture_level),
+                        results);
+
+                     result = (EGLImageKHR)(intptr_t)results[0];
+                     thread->error = results[1];
+
+                     if (target == EGL_NATIVE_PIXMAP_CLIENT_SIDE_BRCM || target == EGL_IMAGE_FROM_SURFACE_BRCM)
+                     {
+                        khrn_platform_bind_pixmap_to_egl_image((EGLNativePixmapType)buffer, result, target == EGL_NATIVE_PIXMAP_CLIENT_SIDE_BRCM);
+                     }
+                  }
+               }
+            }
+         }
+      }
+   }
+
+   CLIENT_UNLOCK();
+   if (result == EGL_NO_IMAGE_KHR) {
+      vcos_log_error("%s:  failed to create image for buffer %p target %d error 0x%x",
+            __FUNCTION__, buffer, target, thread->error);
+   } else {
+      vcos_log_trace("%s: returning EGLImageKHR %p for buffer %p target %d",
+            __FUNCTION__, result, buffer, target);
+   }
+   return result;
+}
+
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   EGLBoolean result;
+
+   vcos_log_trace("eglDestroyImageKHR image=%d.\n", (int)image);
+   
+   CLIENT_LOCK();
+
+   {
+      CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE);
+      vcos_log_trace("%s: process %p image %p", __FUNCTION__, process, image);
+
+      if (!process)
+         result = EGL_FALSE;
+      else {
+         khrn_platform_unbind_pixmap_from_egl_image(image);
+#if EGL_BRCM_global_image
+         if ((uintptr_t)image & (1 << 31)) {
+            result = khrn_global_image_map_delete(&process->global_image_egl_images, (uint32_t)(uintptr_t)image) ?
+               EGL_TRUE : EGL_FALSE;
+         } else
+#endif
+         {
+            vcos_log_trace("%s: process %p image %p calling eglDestroyImageKHR_impl", 
+                  __FUNCTION__, process, image);
+            result = RPC_BOOLEAN_RES(RPC_CALL1_RES(eglDestroyImageKHR_impl,
+               thread,
+               EGLDESTROYIMAGEKHR_ID,
+               RPC_EGLID(image)));
+         }
+
+         if (!result) {
+            thread->error = EGL_BAD_PARAMETER;
+         }
+      }
+   }
+
+   CLIENT_UNLOCK();
+
+   return result;
+}
+
+void eglIntImageSetColorData(EGLDisplay dpy,
+      EGLImageKHR image, KHRN_IMAGE_FORMAT_T format,
+      uint32_t x_offset, uint32_t y_offset,
+      uint32_t width, uint32_t height,
+      int32_t stride, const void *data)
+{
+   CLIENT_THREAD_STATE_T *thread;
+   CLIENT_PROCESS_STATE_T *process;
+
+   if (CLIENT_LOCK_AND_GET_STATES(dpy, &thread, &process)) {
+
+      size_t chunk = KHDISPATCH_WORKSPACE_SIZE / stride;
+      const uint8_t *p = (uint8_t *)data + (y_offset*stride);
+      size_t remaining = height;
+      size_t y = y_offset;
+
+      vcos_log_trace("[%s] egl im %d (%d,%d,%d,%d)",__FUNCTION__, (uint32_t)image, x_offset, y_offset, width, height);
+
+      while (remaining) {
+         size_t n = _min(remaining, chunk);
+         size_t size = n * stride;
+
+         RPC_CALL8_IN_BULK(eglIntImageSetColorData_impl,
+               thread, EGLINTIMAGESETCOLORDATA_ID,
+               RPC_UINT(image), format, x_offset, y, width, n, stride,
+               p, size);
+
+         p += size;
+         y += n;
+         remaining -= n;
+      }
+
+      CLIENT_UNLOCK();
+   }
+}
diff --git a/interface/khronos/ext/egl_khr_lock_surface_client.c b/interface/khronos/ext/egl_khr_lock_surface_client.c
new file mode 100755 (executable)
index 0000000..c28911a
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define EGL_EGLEXT_PROTOTYPES /* we want the prototypes so the compiler will check that the signatures match */
+
+#include "interface/khronos/common/khrn_client_mangle.h"
+
+#include "interface/khronos/common/khrn_int_common.h"
+#include "interface/khronos/include/EGL/egl.h"
+#include "interface/khronos/include/EGL/eglext.h"
+#include "interface/khronos/common/khrn_client.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+#include "interface/khronos/egl/egl_client_config.h"
+#ifdef RPC_DIRECT
+#include "interface/khronos/egl/egl_int_impl.h"
+#endif
+#include <assert.h>
+
+static bool lock_surface_check_attribs(const EGLint *attrib_list, bool *preserve_pixels, uint32_t *lock_usage_hint)
+{
+   if (!attrib_list)
+      return EGL_TRUE;
+
+   while (1) {
+      int name = *attrib_list++;
+      if (name == EGL_NONE)
+         return EGL_TRUE;
+      else {
+         int value = *attrib_list++;
+         switch (name) {
+         case EGL_MAP_PRESERVE_PIXELS_KHR:
+            *preserve_pixels = value ? true : false;
+            break;
+         case EGL_LOCK_USAGE_HINT_KHR:
+            if (value & ~(EGL_READ_SURFACE_BIT_KHR | EGL_WRITE_SURFACE_BIT_KHR))
+               return EGL_FALSE;
+
+            *lock_usage_hint = value;
+            break;
+         default:
+            return EGL_FALSE;
+         }
+      }
+   }
+}
+
+EGLAPI EGLBoolean EGLAPIENTRY eglLockSurfaceKHR (EGLDisplay dpy, EGLSurface surf, const EGLint *attrib_list)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   EGLBoolean result;
+
+   CLIENT_LOCK();
+
+   {
+      CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE);
+
+      if (!process)
+         result = 0;
+      else {
+         EGL_SURFACE_T *surface = client_egl_get_surface(thread, process, surf);
+
+         if (surface) {
+            bool preserve_pixels = false;
+            uint32_t lock_usage_hint = EGL_READ_SURFACE_BIT_KHR | EGL_WRITE_SURFACE_BIT_KHR;   /* we completely ignore this */
+
+            assert(!surface->is_locked);
+
+            if (!lock_surface_check_attribs(attrib_list, &preserve_pixels, &lock_usage_hint)) {
+               thread->error = EGL_BAD_ATTRIBUTE;
+               result = EGL_FALSE;
+            } else if (!egl_config_is_lockable((int)(intptr_t)surface->config - 1)) {
+               /* Only lockable surfaces can be locked (obviously) */
+               thread->error = EGL_BAD_ACCESS;
+               result = EGL_FALSE;
+            } else if (surface->context_binding_count) {
+               /* Cannot lock a surface if it is bound to a context */
+               thread->error = EGL_BAD_ACCESS;
+               result = EGL_FALSE;
+            } else if (preserve_pixels) {
+               /* TODO: we don't need to support this. What error should we return? */
+               thread->error = EGL_BAD_ATTRIBUTE;
+               return EGL_FALSE;
+            } else {
+               /* Don't allocate the buffer here. This happens during "mapping", in eglQuerySurface. */
+               surface->mapped_buffer = 0;
+               surface->is_locked = true;
+               thread->error = EGL_SUCCESS;
+               result = EGL_TRUE;
+            }
+         } else
+            result = EGL_FALSE;
+      }
+   }
+
+   CLIENT_UNLOCK();
+   return result;
+}
+
+EGLAPI EGLBoolean EGLAPIENTRY eglUnlockSurfaceKHR (EGLDisplay dpy, EGLSurface surf)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   EGLBoolean result;
+
+   CLIENT_LOCK();
+
+   {
+      CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE);
+
+      if (!process)
+         result = 0;
+      else {
+         EGL_SURFACE_T *surface = client_egl_get_locked_surface(thread, process, surf);
+
+         if (!surface) {
+            result = EGL_FALSE;
+         } else if (!surface->is_locked) {
+            thread->error = EGL_BAD_ACCESS;
+            result = EGL_FALSE;
+         } else {
+            assert(surface->is_locked);
+            if (surface->mapped_buffer) {
+               KHRN_IMAGE_FORMAT_T format = egl_config_get_mapped_format((int)(intptr_t)surface->config - 1);
+               uint32_t stride = khrn_image_get_stride(format, surface->width);
+               int lines, offset, height;
+
+               lines = KHDISPATCH_WORKSPACE_SIZE / stride;
+               offset = 0;
+               height = surface->height;
+
+               while (height > 0) {
+                  int batch = _min(lines, height);
+#ifndef RPC_DIRECT
+                  uint32_t len = batch * stride;
+#endif
+
+                  RPC_CALL7_IN_BULK(eglIntSetColorData_impl,
+                     thread,
+                     EGLINTSETCOLORDATA_ID,
+                     surface->serverbuffer,
+                     format,
+                     surface->width,
+                     batch,
+                     stride,
+                     offset,
+                     (const char *)surface->mapped_buffer + offset * stride,
+                     len);
+
+                  offset += batch;
+                  height -= batch;
+               }
+
+               khrn_platform_free(surface->mapped_buffer);
+            }
+
+            surface->mapped_buffer = 0;
+            surface->is_locked = false;
+            thread->error = EGL_SUCCESS;
+            result = EGL_TRUE;
+         }
+      }
+   }
+
+   CLIENT_UNLOCK();
+   return result;
+}
+
diff --git a/interface/khronos/ext/egl_khr_sync_client.c b/interface/khronos/ext/egl_khr_sync_client.c
new file mode 100755 (executable)
index 0000000..f05e221
--- /dev/null
@@ -0,0 +1,405 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define EGL_EGLEXT_PROTOTYPES /* we want the prototypes so the compiler will check that the signatures match */
+
+#ifndef SYNC_FENCE_KHR_SHORTCUT
+//#define SYNC_FENCE_KHR_SHORTCUT 0 /* notifications made in driver back-end */
+#define SYNC_FENCE_KHR_SHORTCUT 1 /* notifications made in dispatch */
+#endif
+
+//==============================================================================
+
+#include "interface/khronos/common/khrn_client_mangle.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+
+#include "interface/khronos/ext/egl_khr_sync_client.h"
+#include "interface/khronos/include/EGL/egl.h"
+#include "interface/khronos/include/EGL/eglext.h"
+
+#if defined(V3D_LEAN)
+#include "interface/khronos/common/khrn_int_misc_impl.h"
+#endif
+
+//==============================================================================
+
+typedef struct {
+   EGLint condition;
+   EGLint threshold;
+   EGLint status;
+   EGLenum type;
+
+   int name[3]; // Used as ID in khronos_platform_semaphore_create
+
+   EGL_SYNC_ID_T serversync;
+
+   /*
+      we keep one master handle to the named semaphore in existence for the
+      lifetime of the sync object, allowing both wait functions and the KHAN
+      message handler to "open, post/wait, close".
+   */
+
+   PLATFORM_SEMAPHORE_T master;
+} EGL_SYNC_T;
+
+//==============================================================================
+
+static EGL_SYNC_T *egl_sync_create(EGLSyncKHR sync, EGLenum type,
+      EGLint condition, EGLint threshold, EGLint status)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   EGL_SYNC_T *sync_ptr = (EGL_SYNC_T *)khrn_platform_malloc(sizeof(EGL_SYNC_T), "EGL_SYNC_T");
+   uint64_t pid = rpc_get_client_id(thread);
+   uint32_t sem;
+
+   if (!sync_ptr)
+      return 0;
+
+   sync_ptr->condition = condition;
+   sync_ptr->threshold = threshold;
+   sync_ptr->type = type;
+   sync_ptr->status = status;
+
+   sync_ptr->name[0] = (int)pid;
+   sync_ptr->name[1] = (int)(pid >> 32);
+   sync_ptr->name[2] = (int)sync;
+
+   if (khronos_platform_semaphore_create(&sync_ptr->master, sync_ptr->name, 0) != KHR_SUCCESS) {
+      khrn_platform_free(sync_ptr);
+      return 0;
+   }
+
+   sem = (uint32_t) sync;
+#if SYNC_FENCE_KHR_SHORTCUT == 1
+   if (type == EGL_SYNC_FENCE_KHR){
+      RPC_CALL3(eglIntCreateSyncFence_impl,
+                               thread,
+                               EGLINTCREATESYNCFENCE_ID,
+                               RPC_UINT(condition),
+                               RPC_INT(threshold),
+                               RPC_UINT(sem));
+   } else 
+#endif
+   {
+      sync_ptr->serversync = RPC_UINT_RES(RPC_CALL4_RES(eglIntCreateSync_impl,
+                                                 thread,
+                                                 EGLINTCREATESYNC_ID,
+                                                 RPC_UINT(type),
+                                                 RPC_UINT(condition),
+                                                 RPC_INT(threshold),
+                                                 RPC_UINT(sem)));
+      if (!sync_ptr->serversync) {
+         khronos_platform_semaphore_destroy(&sync_ptr->master);
+         khrn_platform_free(sync_ptr);
+         return 0;
+      }
+   }
+   return sync_ptr;
+}
+
+//------------------------------------------------------------------------------
+
+static void egl_sync_term(EGL_SYNC_T *sync_master)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+#if SYNC_FENCE_KHR_SHORTCUT == 1
+   if (sync_master->type != EGL_SYNC_FENCE_KHR)
+#endif
+   {
+      RPC_CALL1(eglIntDestroySync_impl,
+                thread,
+                EGLINTDESTROYSYNC_ID,
+                RPC_UINT(sync_master->serversync));
+   }
+   khronos_platform_semaphore_destroy(&sync_master->master);
+}
+
+//------------------------------------------------------------------------------
+
+static void egl_sync_destroy_iterator
+   (KHRN_POINTER_MAP_T *sync_map, uint32_t sync, void *sync_handle, void *data)
+{
+   EGL_SYNC_T *sync_ptr = (EGL_SYNC_T *) sync;
+
+   UNUSED(sync_map);
+   UNUSED(sync_handle);
+   UNUSED(data);
+
+   vcos_assert(sync_ptr != NULL);
+
+   egl_sync_term(sync_ptr);
+   khrn_platform_free(sync_ptr);
+}
+
+//------------------------------------------------------------------------------
+
+static EGLBoolean egl_sync_check_attribs(const EGLint *attrib_list, EGLenum type,
+      EGLint *condition, EGLint *threshold, EGLint *status)
+{
+   switch (type) {
+   case EGL_SYNC_FENCE_KHR:
+      *condition = EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR;
+      *threshold = 0;
+      *status = EGL_UNSIGNALED_KHR;
+      break;
+   default :
+      *condition = EGL_NONE;
+      *threshold = 0;
+      *status = 0;
+      break;
+   }
+
+   if (attrib_list) {
+      while (1) {
+         int name = *attrib_list++;
+         if (name == EGL_NONE)
+            break;
+         else {
+            /* int value = * */attrib_list++; /* at present no name/value pairs are handled */
+            switch (name) {
+            default:
+               return EGL_FALSE;
+            }
+         }
+      }
+   }
+
+   return ((type == EGL_SYNC_FENCE_KHR) || (type == 0));
+}
+
+//------------------------------------------------------------------------------
+
+static EGLBoolean egl_sync_get_attrib(EGL_SYNC_T *sync, EGLint attrib, EGLint *value)
+{
+   switch (attrib) {
+   case EGL_SYNC_TYPE_KHR:
+      *value = sync->type;
+      return EGL_TRUE;
+   case EGL_SYNC_STATUS_KHR:
+      *value = sync->status;
+      return EGL_TRUE;
+   case EGL_SYNC_CONDITION_KHR:
+      *value = sync->condition;
+      return EGL_TRUE;
+   default:
+      return EGL_FALSE;
+   }
+}
+
+//==============================================================================
+
+EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   EGLSyncKHR sync = EGL_NO_SYNC_KHR;
+
+   CLIENT_LOCK();
+
+   {
+      CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE);
+
+      EGLint condition;
+      EGLint threshold;
+      EGLint status;
+
+      if (process)
+      {
+         if (egl_sync_check_attribs(attrib_list, type, &condition, &threshold, &status)) {
+            EGL_SYNC_T *sync_ptr = egl_sync_create((EGLSyncKHR)(size_t)process->next_sync, type, condition, threshold, status);
+
+            if (sync_ptr) {
+               if (khrn_pointer_map_insert(&process->syncs, process->next_sync, sync_ptr)) {
+                  thread->error = EGL_SUCCESS;
+                  sync = (EGLSurface)(size_t)process->next_sync++;
+               } else {
+                  thread->error = EGL_BAD_ALLOC;
+                  egl_sync_term(sync_ptr);
+                  khrn_platform_free(sync_ptr);
+               }
+            } else
+               thread->error = EGL_BAD_ALLOC;
+         }
+      }
+   }
+
+   CLIENT_UNLOCK();
+
+   return sync;
+}
+
+//------------------------------------------------------------------------------
+// TODO: should we make sure any syncs have come back before destroying the object?
+
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   EGLBoolean result;
+
+   CLIENT_LOCK();
+
+   {
+      CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE);
+
+      if (process) {
+         EGL_SYNC_T *sync_ptr = (EGL_SYNC_T *)khrn_pointer_map_lookup(&process->syncs, (uint32_t)(size_t)sync);
+
+         if (sync_ptr) {
+            thread->error = EGL_SUCCESS;
+
+            khrn_pointer_map_delete(&process->syncs, (uint32_t)(uintptr_t)sync);
+
+            egl_sync_term(sync_ptr);
+            khrn_platform_free(sync_ptr);
+         } else
+            thread->error = EGL_BAD_PARAMETER;
+
+         result = (thread->error == EGL_SUCCESS ? EGL_TRUE : EGL_FALSE);
+      } else {
+         result = EGL_FALSE;
+      }
+   }
+
+   CLIENT_UNLOCK();
+
+   return result;
+}
+
+//------------------------------------------------------------------------------
+
+EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   UNUSED(timeout);
+
+   CLIENT_LOCK();
+
+   {
+      CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE);
+
+      if (process) {
+         EGL_SYNC_T *sync_ptr = (EGL_SYNC_T *)khrn_pointer_map_lookup(&process->syncs, (uint32_t)(size_t)sync);
+
+         if (sync_ptr) {
+            PLATFORM_SEMAPHORE_T semaphore;
+            if( khronos_platform_semaphore_create(&semaphore, sync_ptr->name, 1) == KHR_SUCCESS) {
+               if (flags & EGL_SYNC_FLUSH_COMMANDS_BIT_KHR)
+                  RPC_FLUSH(thread);
+
+               CLIENT_UNLOCK();
+
+               khronos_platform_semaphore_acquire(&semaphore);
+               khronos_platform_semaphore_release(&semaphore);
+               khronos_platform_semaphore_destroy(&semaphore);
+               return EGL_CONDITION_SATISFIED_KHR;
+            } else
+               thread->error = EGL_BAD_ALLOC;         // not strictly allowed by the spec, but indicates that we failed to create a reference to the named semaphore
+         } else
+            thread->error = EGL_BAD_PARAMETER;
+      }
+   }
+
+   CLIENT_UNLOCK();
+
+   return EGL_FALSE;
+}
+
+//------------------------------------------------------------------------------
+
+EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   UNUSED(mode);
+
+   CLIENT_LOCK();
+
+   {
+      CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE);
+
+      if (process) {
+         EGL_SYNC_T *sync_ptr = (EGL_SYNC_T *)khrn_pointer_map_lookup(&process->syncs, (uint32_t)(size_t)sync);
+
+         if (sync_ptr)
+            thread->error = EGL_BAD_MATCH;
+         else
+            thread->error = EGL_BAD_PARAMETER;
+      }
+   }
+
+   CLIENT_UNLOCK();
+
+   return EGL_FALSE;
+}
+
+//------------------------------------------------------------------------------
+
+EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   EGLBoolean result = EGL_FALSE;
+
+   CLIENT_LOCK();
+
+   {
+      CLIENT_PROCESS_STATE_T *process = client_egl_get_process_state(thread, dpy, EGL_TRUE);
+
+      if (process)
+      {
+         if (value)
+         {
+            EGL_SYNC_T *sync_ptr = (EGL_SYNC_T *)khrn_pointer_map_lookup(&process->syncs, (uint32_t)(size_t)sync);
+
+            if (sync_ptr) {
+               if (egl_sync_get_attrib(sync_ptr, attribute, value)) {
+                  thread->error = EGL_SUCCESS;
+                  result = EGL_TRUE;
+               } else
+                  thread->error = EGL_BAD_ATTRIBUTE;
+            } else
+               thread->error = EGL_BAD_PARAMETER;
+         }
+         else
+         {
+            thread->error = EGL_BAD_PARAMETER;
+         }
+      }
+   }
+
+   CLIENT_UNLOCK();
+
+   return result;
+}
+
+//------------------------------------------------------------------------------
+
+void egl_sync_destroy_all(KHRN_POINTER_MAP_T *sync_map)
+{
+   khrn_pointer_map_iterate(sync_map, egl_sync_destroy_iterator, NULL);
+}
+
+//==============================================================================
diff --git a/interface/khronos/ext/egl_khr_sync_client.h b/interface/khronos/ext/egl_khr_sync_client.h
new file mode 100755 (executable)
index 0000000..221372c
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include "interface/khronos/common/khrn_client.h"
+
+#ifdef RPC_DIRECT
+#include "middleware/khronos/egl/egl_server.h"
+#endif
+
+void egl_sync_destroy_all(KHRN_POINTER_MAP_T *sync_map);
diff --git a/interface/khronos/ext/egl_openmaxil_client.c b/interface/khronos/ext/egl_openmaxil_client.c
new file mode 100755 (executable)
index 0000000..28efa43
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define EGL_EGLEXT_PROTOTYPES /* we want the prototypes so the compiler will check that the signatures match */
+
+#include "interface/khronos/ext/egl_openmaxil_client.h"
+
+#include "interface/khronos/common/khrn_client.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+#include <assert.h>
+
+int eglIntOpenMAXILDoneMarker (void* component_handle, EGLImageKHR egl_image)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   int res;
+
+   res = RPC_INT_RES(RPC_CALL2_RES(eglIntOpenMAXILDoneMarker_impl,
+        thread, EGLINTOPENMAXILDONEMARKER_ID, RPC_EGLID(component_handle), RPC_EGLID(egl_image)));
+
+   return res;
+}
diff --git a/interface/khronos/ext/egl_openmaxil_client.h b/interface/khronos/ext/egl_openmaxil_client.h
new file mode 100755 (executable)
index 0000000..c41e727
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/khronos/include/EGL/egl.h"
+#include "interface/khronos/include/EGL/eglext.h"
+
+extern int eglIntOpenMAXILDoneMarker (void* component_handle, EGLImageKHR egl_image);
diff --git a/interface/khronos/ext/ext_gl_debug_marker.c b/interface/khronos/ext/ext_gl_debug_marker.c
new file mode 100755 (executable)
index 0000000..0fa7b29
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define GL_GLEXT_PROTOTYPES /* we want the prototypes so the compiler will check that the signatures match */
+
+#include "interface/khronos/common/khrn_client_mangle.h"
+
+#include "interface/khronos/common/khrn_int_common.h"
+
+#include "interface/khronos/glxx/glxx_client.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+
+#ifdef RPC_DIRECT
+#include "interface/khronos/glxx/glxx_int_impl.h"
+#include "interface/khronos/glxx/gl20_int_impl.h"
+#endif
+
+#include "interface/khronos/include/GLES2/gl2.h"
+#include "interface/khronos/include/GLES2/gl2ext.h"
+
+GL_API void GL_APIENTRY glInsertEventMarkerEXT(GLsizei length, const GLchar *marker)
+{
+   /* Do nothing.
+      When SpyHook is enabled, it will trap this function and pass to SpyTool.
+      That's all that is needed
+   */
+   UNUSED(length);
+   UNUSED(marker);
+}
+
+GL_API void GL_APIENTRY glPushGroupMarkerEXT(GLsizei length, const GLchar *marker)
+{
+   /* Do nothing.
+      When SpyHook is enabled, it will trap this function and pass to SpyTool.
+      That's all that is needed
+   */
+   UNUSED(length);
+   UNUSED(marker);
+}
+
+GL_API void GL_APIENTRY glPopGroupMarkerEXT(void)
+{
+   /* Do nothing.
+      When SpyHook is enabled, it will trap this function and pass to SpyTool.
+      That's all that is needed
+   */
+}
diff --git a/interface/khronos/ext/gl_oes_draw_texture_client.c b/interface/khronos/ext/gl_oes_draw_texture_client.c
new file mode 100755 (executable)
index 0000000..dfb6fbc
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define GL_GLEXT_PROTOTYPES /* we want the prototypes so the compiler will check that the signatures match */
+
+#include "interface/khronos/common/khrn_client_mangle.h"
+
+#include "interface/khronos/common/khrn_int_common.h"
+
+#include "interface/khronos/glxx/glxx_client.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+
+#ifdef RPC_DIRECT
+#include "interface/khronos/glxx/glxx_int_impl.h"
+#include "interface/khronos/glxx/gl11_int_impl.h"
+#endif
+
+#include "interface/khronos/include/GLES/gl.h"
+#include "interface/khronos/include/GLES/glext.h"
+
+/* GL_OES_draw_texture */
+
+GL_API void GL_APIENTRY glDrawTexsOES (GLshort x, GLshort y, GLshort z, GLshort width, GLshort height) 
+{
+   glDrawTexfOES((GLfloat)x,(GLfloat)y,(GLfloat)x, (GLfloat)width,(GLfloat)height);
+}
+
+GL_API void GL_APIENTRY glDrawTexiOES (GLint x, GLint y, GLint z, GLint width, GLint height)
+{
+   glDrawTexfOES((GLfloat)x,(GLfloat)y,(GLfloat)x, (GLfloat)width,(GLfloat)height);
+}
+
+GL_API void GL_APIENTRY glDrawTexxOES (GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height)
+{
+   glDrawTexfOES(fixed_to_float(x), fixed_to_float(y), fixed_to_float(x), fixed_to_float(width), fixed_to_float(height));
+}
+
+GL_API void GL_APIENTRY glDrawTexsvOES (const GLshort *coords)
+{
+   glDrawTexfOES((GLfloat)coords[0],(GLfloat)coords[1],(GLfloat)coords[2], (GLfloat)coords[3],(GLfloat)coords[4]);
+}
+
+GL_API void GL_APIENTRY glDrawTexivOES (const GLint *coords)
+{
+   glDrawTexfOES((GLfloat)coords[0],(GLfloat)coords[1],(GLfloat)coords[2], (GLfloat)coords[3],(GLfloat)coords[4]);
+}
+
+GL_API void GL_APIENTRY glDrawTexxvOES (const GLfixed *coords)
+{
+   glDrawTexfOES(fixed_to_float(coords[0]), fixed_to_float(coords[1]), fixed_to_float(coords[2]), fixed_to_float(coords[3]), fixed_to_float(coords[4]));
+}
+
+GL_API void GL_APIENTRY glDrawTexfOES (GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL5(glDrawTexfOES_impl_11,
+                thread,
+                GLDRAWTEXFOES_ID_11,
+                RPC_FLOAT(x),
+                RPC_FLOAT(y),
+                RPC_FLOAT(z),
+                RPC_FLOAT(width),
+                RPC_FLOAT(height));
+   }
+}
+
+GL_API void GL_APIENTRY glDrawTexfvOES (const GLfloat *coords)
+{
+   glDrawTexfOES((GLfloat)coords[0],(GLfloat)coords[1],(GLfloat)coords[2], (GLfloat)coords[3],(GLfloat)coords[4]);
+}
diff --git a/interface/khronos/ext/gl_oes_egl_image_client.c b/interface/khronos/ext/gl_oes_egl_image_client.c
new file mode 100755 (executable)
index 0000000..f9b7287
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define GL_GLEXT_PROTOTYPES /* we want the prototypes so the compiler will check that the signatures match */
+#define VCOS_LOG_CATEGORY (&gl_oes_egl_image_client_log)
+
+#include "interface/khronos/common/khrn_client_mangle.h"
+
+#include "interface/khronos/common/khrn_int_common.h"
+
+#include "interface/khronos/glxx/glxx_client.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+
+#ifdef RPC_DIRECT
+#include "interface/khronos/glxx/glxx_int_impl.h"
+#include "interface/khronos/glxx/gl20_int_impl.h"
+#endif
+
+#include "interface/khronos/include/GLES2/gl2.h"
+#include "interface/khronos/include/GLES2/gl2ext.h"
+
+VCOS_LOG_CAT_T gl_oes_egl_image_client_log = VCOS_LOG_INIT("gl_oes_egl_image", VCOS_LOG_WARN);
+
+static void set_error(GLXX_CLIENT_STATE_T *state, GLenum error)
+{
+   if (state->error == GL_NO_ERROR)
+      state->error = error;
+}
+
+static bool check_global_image_egl_image(GLuint global_image_id[2],
+   GLeglImageOES image, CLIENT_THREAD_STATE_T *thread,
+   bool render) /* else texture */
+{
+   CLIENT_PROCESS_STATE_T *process = CLIENT_GET_PROCESS_STATE();
+   uint64_t id;
+   uint32_t format, width, height;
+
+   CLIENT_LOCK();
+   id = process->inited ? khrn_global_image_map_lookup(&process->global_image_egl_images, (uint32_t)(uintptr_t)image) : 0;
+   CLIENT_UNLOCK();
+   if (!id) {
+      return false;
+   }
+   global_image_id[0] = (GLuint)id;
+   global_image_id[1] = (GLuint)(id >> 32);
+
+   platform_get_global_image_info(global_image_id[0], global_image_id[1], &format, &width, &height);
+
+   if (!(format & ((thread->opengl.context->type == OPENGL_ES_11) ?
+      (render ? EGL_PIXEL_FORMAT_RENDER_GLES_BRCM : EGL_PIXEL_FORMAT_GLES_TEXTURE_BRCM) :
+      (render ? EGL_PIXEL_FORMAT_RENDER_GLES2_BRCM : EGL_PIXEL_FORMAT_GLES2_TEXTURE_BRCM))) ||
+      (width == 0) || (height == 0)) {
+      return false;
+   }
+
+   /* format and max width/height checks done on server */
+
+   return true;
+}
+
+GL_API void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   if (IS_OPENGLES_11_OR_20(thread)) {
+#if EGL_BRCM_global_image
+      if ((uintptr_t)image & (1u << 31)) {
+         GLuint global_image_id[2];
+         if (check_global_image_egl_image(global_image_id, image, thread, false)) {
+            RPC_CALL3(glGlobalImageTexture2DOES_impl,
+                      thread,
+                      GLGLOBALIMAGETEXTURE2DOES_ID,
+                      RPC_ENUM(target),
+                      RPC_UINT(global_image_id[0]),
+                      RPC_UINT(global_image_id[1]));
+         } else {
+            set_error(GLXX_GET_CLIENT_STATE(thread), GL_INVALID_VALUE);
+         }
+      } else {
+#endif
+         RPC_CALL2(glEGLImageTargetTexture2DOES_impl,
+                   thread,
+                   GLEGLIMAGETARGETTEXTURE2DOES_ID,
+                   RPC_ENUM(target),
+                   RPC_EGLID(image));
+         RPC_FLUSH(thread);
+#if EGL_BRCM_global_image
+      }
+#endif
+   }
+}
+
+GL_API void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   if (IS_OPENGLES_11(thread)) {
+      /* OES_framebuffer_object not supported for GLES1.1 */
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+      if (state->error == GL_NO_ERROR)
+         state->error = GL_INVALID_OPERATION;
+   }
+   else if (IS_OPENGLES_20(thread)) {
+#if EGL_BRCM_global_image
+      if ((uintptr_t)image & (1u << 31)) {
+         GLuint global_image_id[2];
+         if (check_global_image_egl_image(global_image_id, image, thread, true)) {
+            RPC_CALL3(glGlobalImageRenderbufferStorageOES_impl_20,
+                      thread,
+                      GLGLOBALIMAGERENDERBUFFERSTORAGEOES_ID_20,
+                      RPC_ENUM(target),
+                      RPC_UINT(global_image_id[0]),
+                      RPC_UINT(global_image_id[1]));
+         } else {
+            set_error(GLXX_GET_CLIENT_STATE(thread), GL_INVALID_VALUE);
+         }
+      } else {
+#endif
+         RPC_CALL2(glEGLImageTargetRenderbufferStorageOES_impl_20,
+                   thread,
+                   GLEGLIMAGETARGETRENDERBUFFERSTORAGEOES_ID_20,
+                   RPC_ENUM(target),
+                   RPC_EGLID(image));
+#if EGL_BRCM_global_image
+      }
+#endif
+   }
+}
diff --git a/interface/khronos/ext/gl_oes_framebuffer_object.c b/interface/khronos/ext/gl_oes_framebuffer_object.c
new file mode 100755 (executable)
index 0000000..fe607d4
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define GL_GLEXT_PROTOTYPES /* we want the prototypes so the compiler will check that the signatures match */
+
+#include "interface/khronos/common/khrn_client_mangle.h"
+
+#include "interface/khronos/common/khrn_int_common.h"
+
+#include "interface/khronos/glxx/glxx_client.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+
+#ifdef RPC_DIRECT
+#include "interface/khronos/glxx/glxx_int_impl.h"
+#include "interface/khronos/glxx/gl11_int_impl.h"
+#endif
+
+#include "interface/khronos/include/GLES/gl.h"
+#include "interface/khronos/include/GLES/glext.h"
+
+extern GLboolean glxx_client_IsRenderbuffer(GLuint renderbuffer);
+extern void glxx_client_BindRenderbuffer(GLenum target, GLuint renderbuffer);
+extern void glxx_client_DeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers);
+extern void glxx_client_GenRenderbuffers(GLsizei n, GLuint *renderbuffers);
+extern void glxx_client_RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+extern void glxx_client_GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params);
+extern GLboolean glxx_client_IsFramebuffer(GLuint framebuffer);
+extern void glxx_client_BindFramebuffer(GLenum target, GLuint framebuffer);
+extern void glxx_client_DeleteFramebuffers(GLsizei n, const GLuint *framebuffers);
+extern void glxx_client_GenFramebuffers(GLsizei n, GLuint *framebuffers);
+extern GLenum glxx_client_CheckFramebufferStatus(GLenum target);
+extern void glxx_client_FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+extern void glxx_client_FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+extern void glxx_client_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint *params);
+extern void glxx_client_GenerateMipmap(GLenum target);
+
+GL_API GLboolean GL_APIENTRY glIsRenderbufferOES (GLuint renderbuffer)
+{
+   return glxx_client_IsRenderbuffer(renderbuffer);
+}
+
+GL_API void GL_APIENTRY glBindRenderbufferOES (GLenum target, GLuint renderbuffer)
+{
+   glxx_client_BindRenderbuffer(target, renderbuffer);
+}
+
+GL_API void GL_APIENTRY glDeleteRenderbuffersOES (GLsizei n, const GLuint* renderbuffers)
+{
+   glxx_client_DeleteRenderbuffers(n, renderbuffers);
+}
+
+GL_API void GL_APIENTRY glGenRenderbuffersOES (GLsizei n, GLuint* renderbuffers)
+{
+   glxx_client_GenRenderbuffers(n, renderbuffers);
+}
+
+GL_API void GL_APIENTRY glRenderbufferStorageOES (GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+{
+   glxx_client_RenderbufferStorage(target, internalformat, width, height);
+}
+
+GL_API void GL_APIENTRY glGetRenderbufferParameterivOES (GLenum target, GLenum pname, GLint* params)
+{
+   glxx_client_GetRenderbufferParameteriv(target, pname, params);
+}
+
+GL_API GLboolean GL_APIENTRY glIsFramebufferOES (GLuint framebuffer)
+{
+   return glxx_client_IsFramebuffer(framebuffer);
+}
+
+GL_API void GL_APIENTRY glBindFramebufferOES (GLenum target, GLuint framebuffer)
+{
+   glxx_client_BindFramebuffer(target, framebuffer);
+}
+
+GL_API void GL_APIENTRY glDeleteFramebuffersOES (GLsizei n, const GLuint* framebuffers)
+{
+   glxx_client_DeleteFramebuffers(n, framebuffers);
+}
+
+GL_API void GL_APIENTRY glGenFramebuffersOES (GLsizei n, GLuint* framebuffers)
+{
+   glxx_client_GenFramebuffers(n, framebuffers);
+}
+
+GL_API GLenum GL_APIENTRY glCheckFramebufferStatusOES (GLenum target)
+{
+   return glxx_client_CheckFramebufferStatus(target);
+}
+
+GL_API void GL_APIENTRY glFramebufferRenderbufferOES (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+{
+   glxx_client_FramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
+}
+
+GL_API void GL_APIENTRY glFramebufferTexture2DOES (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+{
+   glxx_client_FramebufferTexture2D(target, attachment, textarget, texture, level);
+}
+
+GL_API void GL_APIENTRY glGetFramebufferAttachmentParameterivOES (GLenum target, GLenum attachment, GLenum pname, GLint* params)
+{
+   glxx_client_GetFramebufferAttachmentParameteriv(target, attachment, pname, params);
+}
+
+GL_API void GL_APIENTRY glGenerateMipmapOES (GLenum target)
+{
+   glxx_client_GenerateMipmap(target);
+}
diff --git a/interface/khronos/ext/gl_oes_map_buffer.c b/interface/khronos/ext/gl_oes_map_buffer.c
new file mode 100755 (executable)
index 0000000..8ebbcac
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#define GL_GLEXT_PROTOTYPES /* we want the prototypes so the compiler will check that the signatures match */
+
+#include "interface/khronos/common/khrn_int_common.h"
+
+#include "interface/khronos/glxx/glxx_client.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+
+#ifdef RPC_DIRECT
+#include "interface/khronos/glxx/glxx_int_impl.h"
+#include "interface/khronos/glxx/gl11_int_impl.h"
+#endif
+
+#include "interface/khronos/include/GLES/gl.h"
+#include "interface/khronos/include/GLES/glext.h"
+
+
+GL_API void* GL_APIENTRY glMapBufferOES (GLenum target, GLenum access)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   void *pointer = 0;
+   if (IS_OPENGLES_11_OR_20(thread)) {
+
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+      if(target != GL_ARRAY_BUFFER && target != GL_ELEMENT_ARRAY_BUFFER)
+      {
+         glxx_set_error(state, GL_INVALID_ENUM);
+      }
+      else if(access != GL_WRITE_ONLY_OES)
+      {
+         glxx_set_error(state, GL_INVALID_ENUM);
+      }
+      else
+      {
+         GLXX_BUFFER_INFO_T buffer;
+         glxx_buffer_info_get(state, target, &buffer);
+
+         if(buffer.id !=0 && buffer.cached_size > 0)
+         {
+            if(buffer.mapped_pointer != 0)
+            {
+               /* already mapped */
+               glxx_set_error(state, GL_INVALID_OPERATION);
+            }
+            else
+            {
+               
+               pointer = khrn_platform_malloc(buffer.cached_size,"glxx_mapped_buffer");
+
+               if(pointer != 0)
+               {
+                  buffer.mapped_pointer = pointer;
+                  buffer.mapped_size = buffer.cached_size;
+               }
+               else
+               {
+                  buffer.mapped_pointer = 0;
+                  buffer.mapped_size = 0;
+                  glxx_set_error(state, GL_OUT_OF_MEMORY);
+               }
+               glxx_buffer_info_set(state, target, &buffer);
+            }
+         }
+         else
+         {
+            glxx_set_error(state, GL_INVALID_OPERATION);
+         }
+      }
+   }
+   /*
+   RPC_CALL3_OUT_CTRL(glMapBufferOES_impl,
+                      thread,
+                      GLMAPBUFFEROES_ID,
+                      RPC_ENUM(target),
+                      RPC_ENUM(access),
+                      &pointer);
+   */
+
+   return pointer;
+}
+
+GL_API GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   GLboolean success = GL_FALSE;
+
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      //use buffer sub data to flush through
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+      if(target != GL_ARRAY_BUFFER && target != GL_ELEMENT_ARRAY_BUFFER)
+      {
+         glxx_set_error(state, GL_INVALID_ENUM);
+      }
+      else
+      {
+         GLXX_BUFFER_INFO_T buffer;
+         glxx_buffer_info_get(state, target, &buffer);
+
+         if(buffer.id !=0)
+         {
+            if(buffer.mapped_pointer)
+            {
+               void * p = buffer.mapped_pointer;
+               GLsizeiptr size = buffer.mapped_size;
+               
+               buffer.mapped_pointer = 0;
+               buffer.mapped_size = 0;
+               glxx_buffer_info_set(state, target, &buffer);
+
+               glBufferSubData (target, 0, size, p);
+               khrn_platform_free(p);
+            }
+         }         
+      }
+   }
+
+   /*
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      success = RPC_BOOLEAN_RES(RPC_CALL1_RES(glUnmapBufferOES_impl,
+                         thread,      
+                         GLUNMAPBUFFEROES_ID,
+                         RPC_ENUM(target)));
+   */
+
+   return success;
+}
+
+GL_API void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, GLvoid ** params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   params[0] = (void *)0;
+
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+      if(target != GL_ARRAY_BUFFER && target != GL_ELEMENT_ARRAY_BUFFER)
+      {
+         glxx_set_error(state, GL_INVALID_ENUM);
+      }
+      else if(pname != GL_BUFFER_MAP_POINTER_OES)
+      {
+         glxx_set_error(state, GL_INVALID_ENUM);
+      }
+      else
+      {
+         GLXX_BUFFER_INFO_T buffer;
+         glxx_buffer_info_get(state, target, &buffer);
+
+         if(buffer.id !=0)
+         {
+            params[0] = (void *)buffer.mapped_pointer;
+         }
+      }
+   }
+
+   /*
+   
+      RPC_CALL3_OUT_CTRL(glGetBufferPointervOES_impl,
+                         thread,      
+                         GLGETBUFFERPOINTERVOES_ID,
+                         RPC_ENUM(target),
+                         RPC_ENUM(pname),
+                         params);
+
+   */
+}
diff --git a/interface/khronos/ext/gl_oes_matrix_palette_client.c b/interface/khronos/ext/gl_oes_matrix_palette_client.c
new file mode 100755 (executable)
index 0000000..316dcf6
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define GL_GLEXT_PROTOTYPES /* we want the prototypes so the compiler will check that the signatures match */
+
+#include "interface/khronos/common/khrn_int_common.h"
+
+#include "interface/khronos/glxx/glxx_client.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+
+#include "interface/khronos/glxx/gl11_int_config.h"
+
+#include "interface/khronos/include/GLES/glext.h"
+
+#ifdef RPC_DIRECT
+#include "interface/khronos/glxx/gl11_int_impl.h"
+#endif
+
+#if GL_OES_matrix_palette
+
+static void set_error(GLXX_CLIENT_STATE_T *state, GLenum e) {
+   if (state->error == GL_NO_ERROR) state->error = e;
+}
+
+static void set_client_state_error(GLenum e) {
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+   set_error(state, e);
+}
+
+GL_API void GL_APIENTRY glCurrentPaletteMatrixOES(GLuint index) {
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      if (index > GL11_CONFIG_MAX_PALETTE_MATRICES_OES - 1) set_client_state_error(GL_INVALID_VALUE);
+      else {
+         RPC_CALL1(glCurrentPaletteMatrixOES_impl,
+                   thread,
+                   GLCURRENTPALETTEMATRIXOES_ID_11,
+                   RPC_UINT(index)                 );
+      }
+   }
+}
+
+GL_API void GL_APIENTRY glLoadPaletteFromModelViewMatrixOES() {
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL0(glLoadPaletteFromModelViewMatrixOES_impl,
+                thread,
+                GLLOADPALETTEFROMMODELVIEWMATRIXOES_ID_11);
+   }
+}
+
+static GLboolean is_matrix_index_type(GLenum type) {
+   return (type == GL_UNSIGNED_BYTE);
+}
+
+static GLboolean is_matrix_palette_size(GLint size) {
+   /* TODO: Should size 0 be allowed or not? */
+   return size > 0 && size <= GL11_CONFIG_MAX_VERTEX_UNITS_OES;
+}
+
+/* TODO: This is copied from glxx_client.c. Find a better method */
+static GLboolean is_aligned( GLenum type, size_t value)
+{
+   switch (type) {
+   case GL_BYTE:
+   case GL_UNSIGNED_BYTE:
+      return GL_TRUE;
+   case GL_SHORT:
+   case GL_UNSIGNED_SHORT:
+      return (value & 1) == 0;
+   case GL_FIXED:
+   case GL_FLOAT:
+      return (value & 3) == 0;
+   default:
+      UNREACHABLE();
+      return GL_FALSE;
+   }
+}
+
+GL_API void GL_APIENTRY glMatrixIndexPointerOES(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+{
+   if (is_matrix_index_type(type)) {
+      if (is_matrix_palette_size(size) && is_aligned(type, (size_t)pointer) && is_aligned(type, (size_t)stride) && stride >= 0) {
+         glintAttribPointer(GLXX_API_11, GL11_IX_MATRIX_INDEX, size, type, GL_FALSE, stride, pointer);
+      } else
+         glxx_set_error_api(GLXX_API_11, GL_INVALID_VALUE);
+   } else
+      glxx_set_error_api(GLXX_API_11, GL_INVALID_ENUM);
+}
+
+static GLboolean is_matrix_weight_type(GLenum type) {
+   return type == GL_FIXED ||
+          type == GL_FLOAT;
+}
+
+GL_API void GL_APIENTRY glWeightPointerOES(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+{
+   if (is_matrix_weight_type(type)) {
+      if (is_matrix_palette_size(size) && is_aligned(type, (size_t)pointer) && is_aligned(type, (size_t)stride) && stride >= 0) {
+         glintAttribPointer(GLXX_API_11, GL11_IX_MATRIX_WEIGHT, size, type, GL_FALSE, stride, pointer);
+      } else
+         glxx_set_error_api(GLXX_API_11, GL_INVALID_VALUE);
+   } else
+      glxx_set_error_api(GLXX_API_11, GL_INVALID_ENUM);
+}
+
+#endif /* GL_OES_matrix_palette */
diff --git a/interface/khronos/ext/gl_oes_query_matrix_client.c b/interface/khronos/ext/gl_oes_query_matrix_client.c
new file mode 100755 (executable)
index 0000000..ef5efa4
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define GL_GLEXT_PROTOTYPES /* we want the prototypes so the compiler will check that the signatures match */
+
+#include "interface/khronos/common/khrn_int_common.h"
+
+#include "interface/khronos/glxx/glxx_client.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+
+#ifdef RPC_DIRECT
+#include "interface/khronos/glxx/glxx_int_impl.h"
+#include "interface/khronos/glxx/gl11_int_impl.h"
+#endif
+
+#include "interface/khronos/include/GLES/gl.h"
+#include "interface/khronos/include/GLES/glext.h"
+
+GL_API GLbitfield GL_APIENTRY glQueryMatrixxOES( GLfixed mantissa[16], GLint exponent[16] )
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      int i;
+      RPC_CALL1_OUT_CTRL(glQueryMatrixxOES_impl_11,
+                            thread,
+                            GLQUERYMATRIXXOES_ID_11,
+                            mantissa);
+               
+      for(i=0;i<16;i++)
+         exponent[i] = 0;
+         
+      return 0;                            
+   }
+   
+   return 0xff; /* all components invalid */
+}
diff --git a/interface/khronos/glxx/gl11_int_config.h b/interface/khronos/glxx/gl11_int_config.h
new file mode 100755 (executable)
index 0000000..3cd1334
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef GL11_INT_CONFIG_H
+#define GL11_INT_CONFIG_H
+
+#define GL11_CONFIG_MAX_TEXTURE_UNITS              4
+#define GL11_CONFIG_MAX_LIGHTS                     8
+#define GL11_CONFIG_MAX_PLANES                     1
+#define GL11_CONFIG_MAX_STACK_DEPTH               16
+
+#define GL11_CONFIG_MIN_ALIASED_POINT_SIZE      1.0f
+#define GL11_CONFIG_MAX_ALIASED_POINT_SIZE    256.0f
+#define GL11_CONFIG_MIN_SMOOTH_POINT_SIZE       1.0f
+#define GL11_CONFIG_MAX_SMOOTH_POINT_SIZE     256.0f
+#define GL11_CONFIG_MIN_ALIASED_LINE_WIDTH      0.0f
+#define GL11_CONFIG_MAX_ALIASED_LINE_WIDTH     16.0f
+#define GL11_CONFIG_MIN_SMOOTH_LINE_WIDTH       0.0f
+#define GL11_CONFIG_MAX_SMOOTH_LINE_WIDTH      16.0f
+
+/* GL_OES_matrix_palette */
+#define GL11_CONFIG_MAX_VERTEX_UNITS_OES           3
+#define GL11_CONFIG_MAX_PALETTE_MATRICES_OES       64
+
+#endif
diff --git a/interface/khronos/glxx/gl11_int_impl.h b/interface/khronos/glxx/gl11_int_impl.h
new file mode 100755 (executable)
index 0000000..e5d0c02
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#if defined(KHRN_IMPL_STRUCT)
+#define FN(type, name, args) type (*name) args;
+#elif defined(KHRN_IMPL_STRUCT_INIT)
+#define FN(type, name, args) name,
+#else
+#define FN(type, name, args) extern type name args;
+#endif
+
+//gl 1.1 specific functions
+FN(void, glAlphaFunc_impl_11, (GLenum func, GLclampf ref))
+FN(void, glAlphaFuncx_impl_11, (GLenum func, GLclampx ref))
+FN(void, glClearColorx_impl_11, (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha))
+FN(void, glClearDepthx_impl_11, (GLclampx depth))
+FN(void, glClientActiveTexture_impl_11, (GLenum texture))
+FN(void, glClipPlanef_impl_11, (GLenum plane, const GLfloat *equation))
+FN(void, glClipPlanex_impl_11, (GLenum plane, const GLfixed *equation))
+FN(void, glDepthRangex_impl_11, (GLclampx zNear, GLclampx zFar))
+FN(void, glFogf_impl_11, (GLenum pname, GLfloat param))
+FN(void, glFogfv_impl_11, (GLenum pname, const GLfloat *params))
+FN(void, glFrustumf_impl_11, (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar))
+FN(void, glFogx_impl_11, (GLenum pname, GLfixed param))
+FN(void, glFogxv_impl_11, (GLenum pname, const GLfixed *params))
+FN(void, glFrustumx_impl_11, (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar))
+FN(void, glGetClipPlanex_impl_11, (GLenum pname, GLfixed eqn[4]))
+FN(int, glGetLightfv_impl_11, (GLenum light, GLenum pname, GLfloat *params))
+FN(int, glGetLightxv_impl_11, (GLenum light, GLenum pname, GLfixed *params))
+FN(int, glGetMaterialxv_impl_11, (GLenum face, GLenum pname, GLfixed *params))
+FN(int, glGetMaterialfv_impl_11, (GLenum face, GLenum pname, GLfloat *params))
+FN(void, glGetClipPlanef_impl_11, (GLenum pname, GLfloat eqn[4]))
+FN(int, glGetFixedv_impl_11, (GLenum pname, GLfixed *params))
+FN(int, glGetTexEnvfv_impl_11, (GLenum env, GLenum pname, GLfloat *params))
+FN(int, glGetTexEnviv_impl_11, (GLenum env, GLenum pname, GLint *params))
+FN(int, glGetTexEnvxv_impl_11, (GLenum env, GLenum pname, GLfixed *params))
+FN(int, glGetTexParameterxv_impl_11, (GLenum target, GLenum pname, GLfixed *params))
+FN(void, glLightModelf_impl_11, (GLenum pname, GLfloat param))
+FN(void, glLightModelfv_impl_11, (GLenum pname, const GLfloat *params))
+FN(void, glLightf_impl_11, (GLenum light, GLenum pname, GLfloat param))
+FN(void, glLightfv_impl_11, (GLenum light, GLenum pname, const GLfloat *params))
+FN(void, glLightModelx_impl_11, (GLenum pname, GLfixed param))
+FN(void, glLightModelxv_impl_11, (GLenum pname, const GLfixed *params))
+FN(void, glLightx_impl_11, (GLenum light, GLenum pname, GLfixed param))
+FN(void, glLightxv_impl_11, (GLenum light, GLenum pname, const GLfixed *params))
+FN(void, glLineWidthx_impl_11, (GLfixed width))
+FN(void, glLoadIdentity_impl_11, (void))
+FN(void, glLoadMatrixf_impl_11, (const GLfloat *m))
+FN(void, glLoadMatrixx_impl_11, (const GLfixed *m))
+FN(void, glLogicOp_impl_11, (GLenum opcode))
+FN(void, glMaterialf_impl_11, (GLenum face, GLenum pname, GLfloat param))
+FN(void, glMaterialfv_impl_11, (GLenum face, GLenum pname, const GLfloat *params))
+FN(void, glMultMatrixf_impl_11, (const GLfloat *m))
+FN(void, glOrthof_impl_11, (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar))
+FN(void, glPolygonOffsetx_impl_11, (GLfixed factor, GLfixed units))
+FN(void, glPointParameterf_impl_11, (GLenum pname, GLfloat param))
+FN(void, glPointParameterfv_impl_11, (GLenum pname, const GLfloat *params))
+FN(void, glRotatef_impl_11, (GLfloat angle, GLfloat x, GLfloat y, GLfloat z))
+FN(void, glSampleCoveragex_impl_11, (GLclampx value, GLboolean invert))
+FN(void, glScalef_impl_11, (GLfloat x, GLfloat y, GLfloat z))
+FN(void, glShadeModel_impl_11, (GLenum model))
+FN(void, glTexEnvf_impl_11, (GLenum target, GLenum pname, GLfloat param))
+FN(void, glTexEnvfv_impl_11, (GLenum target, GLenum pname, const GLfloat *params))
+FN(void, glTexEnvi_impl_11, (GLenum target, GLenum pname, GLint param))
+FN(void, glTexEnviv_impl_11, (GLenum target, GLenum pname, const GLint *params))
+FN(void, glTexEnvx_impl_11, (GLenum target, GLenum pname, GLfixed param))
+FN(void, glTexEnvxv_impl_11, (GLenum target, GLenum pname, const GLfixed *params))
+FN(void, glTexParameterx_impl_11, (GLenum target, GLenum pname, GLfixed param))
+FN(void, glTexParameterxv_impl_11, (GLenum target, GLenum pname, const GLfixed *params))
+FN(void, glTranslatef_impl_11, (GLfloat x, GLfloat y, GLfloat z))
+FN(void, glMaterialx_impl_11, (GLenum face, GLenum pname, GLfixed param))
+FN(void, glMaterialxv_impl_11, (GLenum face, GLenum pname, const GLfixed *params))
+FN(void, glMatrixMode_impl_11, (GLenum mode))
+FN(void, glMultMatrixx_impl_11, (const GLfixed *m))
+FN(void, glOrthox_impl_11, (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar))
+FN(void, glPointParameterx_impl_11, (GLenum pname, GLfixed param))
+FN(void, glPointParameterxv_impl_11, (GLenum pname, const GLfixed *params))
+//FN(void, glPointSizePointerOES_impl_11, (void))
+FN(void, glPopMatrix_impl_11, (void))
+FN(void, glPushMatrix_impl_11, (void))
+FN(void, glRotatex_impl_11, (GLfixed angle, GLfixed x, GLfixed y, GLfixed z))
+FN(void, glScalex_impl_11, (GLfixed x, GLfixed y, GLfixed z))
+FN(void, glTranslatex_impl_11, (GLfixed x, GLfixed y, GLfixed z))
+
+//FN(void, glColorPointer_impl_11, (void))
+//FN(void, glNormalPointer_impl_11, (void))
+//FN(void, glTexCoordPointer_impl_11, (GLenum unit))
+//FN(void, glVertexPointer_impl_11, (void))
+
+/*****************************************************************************************/
+/*                                 OES extension functions                               */
+/*****************************************************************************************/
+
+//gl 1.1 specific
+FN(void, glintColor_impl_11, (float red, float green, float blue, float alpha))
+FN(void, glQueryMatrixxOES_impl_11, (GLfixed mantissa[16]))
+FN(void, glDrawTexfOES_impl_11, (GLfloat Xs, GLfloat Ys, GLfloat Zs, GLfloat Ws, GLfloat Hs))
+
+#if GL_OES_matrix_palette
+FN(void, glCurrentPaletteMatrixOES_impl, (GLuint index))
+FN(void, glLoadPaletteFromModelViewMatrixOES_impl, (void))
+//FN(void, glMatrixIndexPointerOES_impl, (void))
+//FN(void, glWeightPointerOES_impl, (void))
+#endif
+
+#undef FN
diff --git a/interface/khronos/glxx/gl20_int_impl.h b/interface/khronos/glxx/gl20_int_impl.h
new file mode 100755 (executable)
index 0000000..2e4008a
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#if defined(KHRN_IMPL_STRUCT)
+#define FN(type, name, args) type (*name) args;
+#elif defined(KHRN_IMPL_STRUCT_INIT)
+#define FN(type, name, args) name,
+#else
+#define FN(type, name, args) extern type name args;
+#endif
+
+//gl 2.0 specific
+FN(void, glAttachShader_impl_20, (GLuint program, GLuint shader))
+FN(void, glBindAttribLocation_impl_20, (GLuint program, GLuint index, const char *name))
+FN(void, glBlendColor_impl_20, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)) // S
+FN(void, glBlendEquationSeparate_impl_20, (GLenum modeRGB, GLenum modeAlpha)) // S
+FN(GLuint, glCreateProgram_impl_20, (void))
+FN(GLuint, glCreateShader_impl_20, (GLenum type))
+FN(void, glDeleteProgram_impl_20, (GLuint program))
+FN(void, glDeleteShader_impl_20, (GLuint shader))
+FN(void, glDetachShader_impl_20, (GLuint program, GLuint shader))
+//FN(void, glDisableVertexAttribArray_impl_20, (GLuint index))
+//FN(void, glEnableVertexAttribArray_impl_20, (GLuint index))
+FN(void, glGetActiveAttrib_impl_20, (GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name))
+FN(void, glGetActiveUniform_impl_20, (GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name))
+FN(void, glGetAttachedShaders_impl_20, (GLuint program, GLsizei maxcount, GLsizei *count, GLuint *shaders))
+FN(int, glGetAttribLocation_impl_20, (GLuint program, const char *name))
+FN(int, glGetProgramiv_impl_20, (GLuint program, GLenum pname, GLint *params))
+FN(void, glGetProgramInfoLog_impl_20, (GLuint program, GLsizei bufsize, GLsizei *length, char *infolog))
+FN(int, glGetUniformfv_impl_20, (GLuint program, GLint location, GLfloat *params))
+FN(int, glGetUniformiv_impl_20, (GLuint program, GLint location, GLint *params))
+FN(int, glGetUniformLocation_impl_20, (GLuint program, const char *name))
+//FN(void, glGetVertexAttribfv_impl_20, (GLuint index, GLenum pname, GLfloat *params))
+//FN(void, glGetVertexAttribiv_impl_20, (GLuint index, GLenum pname, GLint *params))
+//FN(void, glGetVertexAttribPointerv_impl_20, (GLuint index, GLenum pname, void **pointer))
+FN(GLboolean, glIsProgram_impl_20, (GLuint program))
+FN(GLboolean, glIsShader_impl_20, (GLuint shader))
+FN(void, glLinkProgram_impl_20, (GLuint program))
+FN(void, glPointSize_impl_20, (GLfloat size)) // S
+FN(void, glUniform1i_impl_20, (GLint location, GLint x))
+FN(void, glUniform2i_impl_20, (GLint location, GLint x, GLint y))
+FN(void, glUniform3i_impl_20, (GLint location, GLint x, GLint y, GLint z))
+FN(void, glUniform4i_impl_20, (GLint location, GLint x, GLint y, GLint z, GLint w))
+FN(void, glUniform1f_impl_20, (GLint location, GLfloat x))
+FN(void, glUniform2f_impl_20, (GLint location, GLfloat x, GLfloat y))
+FN(void, glUniform3f_impl_20, (GLint location, GLfloat x, GLfloat y, GLfloat z))
+FN(void, glUniform4f_impl_20, (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w))
+FN(void, glUniform1iv_impl_20, (GLint location, GLsizei count, int size, const GLint *v))
+FN(void, glUniform2iv_impl_20, (GLint location, GLsizei count, int size, const GLint *v))
+FN(void, glUniform3iv_impl_20, (GLint location, GLsizei count, int size, const GLint *v))
+FN(void, glUniform4iv_impl_20, (GLint location, GLsizei count, int size, const GLint *v))
+FN(void, glUniform1fv_impl_20, (GLint location, GLsizei count, int size, const GLfloat *v))
+FN(void, glUniform2fv_impl_20, (GLint location, GLsizei count, int size, const GLfloat *v))
+FN(void, glUniform3fv_impl_20, (GLint location, GLsizei count, int size, const GLfloat *v))
+FN(void, glUniform4fv_impl_20, (GLint location, GLsizei count, int size, const GLfloat *v))
+FN(void, glUniformMatrix2fv_impl_20, (GLint location, GLsizei count, GLboolean transpose, int size, const GLfloat *value))
+FN(void, glUniformMatrix3fv_impl_20, (GLint location, GLsizei count, GLboolean transpose, int size, const GLfloat *value))
+FN(void, glUniformMatrix4fv_impl_20, (GLint location, GLsizei count, GLboolean transpose, int size, const GLfloat *value))
+FN(void, glUseProgram_impl_20, (GLuint program)) // S
+FN(void, glValidateProgram_impl_20, (GLuint program))
+//FN(void, glVertexAttrib1f_impl_20, (GLuint indx, GLfloat x))
+//FN(void, glVertexAttrib2f_impl_20, (GLuint indx, GLfloat x, GLfloat y))
+//FN(void, glVertexAttrib3f_impl_20, (GLuint indx, GLfloat x, GLfloat y, GLfloat z))
+//FN(void, glVertexAttrib4f_impl_20, (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w))
+//FN(void, glVertexAttrib1fv_impl_20, (GLuint indx, const GLfloat *values))
+//FN(void, glVertexAttrib2fv_impl_20, (GLuint indx, const GLfloat *values))
+//FN(void, glVertexAttrib3fv_impl_20, (GLuint indx, const GLfloat *values))
+//FN(void, glVertexAttrib4fv_impl_20, (GLuint indx, const GLfloat *values))
+
+
+/* OES_shader_source */
+FN(void, glCompileShader_impl_20, (GLuint shader))
+FN(int, glGetShaderiv_impl_20, (GLuint shader, GLenum pname, GLint *params))
+FN(void, glGetShaderInfoLog_impl_20, (GLuint shader, GLsizei bufsize, GLsizei *length, char *infolog))
+FN(void, glGetShaderSource_impl_20, (GLuint shader, GLsizei bufsize, GLsizei *length, char *source))
+FN(void, glShaderSource_impl_20, (GLuint shader, GLsizei count, const char **string, const GLint *length))
+//FN(void, glGetShaderPrecisionFormat_impl_20, (GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision))
+FN(void, glGetShaderPrecisionFormat_impl_20, (GLenum shadertype, GLenum precisiontype, GLint *result))
+
+/*****************************************************************************************/
+/*                                 OES extension functions                               */
+/*****************************************************************************************/
+
+//gl 2.0 specific
+
+//FN(void, glVertexAttribPointer_impl_20, (GLuint indx))
+
+#if GL_OES_EGL_image
+FN(void, glEGLImageTargetRenderbufferStorageOES_impl_20, (GLenum target, GLeglImageOES image))
+#if EGL_BRCM_global_image
+FN(void, glGlobalImageRenderbufferStorageOES_impl_20, (GLenum target, GLuint id_0, GLuint id_1))
+#endif
+#endif
+
+#undef FN
diff --git a/interface/khronos/glxx/glxx_client.c b/interface/khronos/glxx/glxx_client.c
new file mode 100755 (executable)
index 0000000..0321d88
--- /dev/null
@@ -0,0 +1,5733 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#define VCOS_LOG_CATEGORY (&gl_client_log)
+#include "interface/khronos/common/khrn_client_mangle.h"
+
+#include "interface/khronos/common/khrn_int_common.h"
+#include "interface/khronos/common/khrn_options.h"
+
+#include "interface/khronos/glxx/glxx_client.h"
+#include "interface/khronos/glxx/gl11_int_config.h"
+#include "interface/khronos/include/GLES/glext.h"
+#include "interface/khronos/include/GLES2/gl2ext.h"
+
+#ifdef RPC_DIRECT
+#include "interface/khronos/glxx/gl11_int_impl.h"
+#include "interface/khronos/glxx/gl20_int_impl.h"
+#include "interface/khronos/glxx/glxx_int_impl.h"
+#if defined(V3D_LEAN)
+#include "interface/khronos/common/khrn_int_misc_impl.h"
+#endif
+#endif
+
+#include "interface/khronos/common/khrn_client_rpc.h"
+#include "interface/khronos/common/khrn_int_util.h"
+//#include "../khronos.h"
+
+#ifdef RPC_DIRECT
+#ifdef RPC_DELAYED_USE_OF_POINTERS
+#include "middleware/khronos/common/khrn_hw.h"
+#endif
+#endif
+
+#include <string.h>
+#include <stdlib.h>
+#include <math.h>
+
+VCOS_LOG_CAT_T gl_client_log = VCOS_LOG_INIT("gl_client", VCOS_LOG_WARN);
+
+#ifdef __HIGHC__
+#pragma warning( disable : 4100 4127 4204)             // unreferenced formal parameter, constant conditional expression, non-constant initializer
+#endif
+
+#ifdef GL11_CLIENT_SINGLE
+GLXX_CLIENT_STATE_T gl11_client_state;
+#endif
+
+#ifdef GL20_CLIENT_SINGLE
+GLXX_CLIENT_STATE_T gl20_client_state;
+#endif
+
+#define SET_SERIALIZED_ATTRIB(target, b, x, k) { (target)[0] = RPC_INT((x).size); \
+                                                 (target)[1] = RPC_ENUM((x).type); \
+                                                 (target)[2] = RPC_BOOLEAN((x).normalized), \
+                                                 (target)[3] = RPC_SIZEI((x).stride); \
+                                                 (target)[4] = RPC_UINT((b ? (uint32_t)(k + offsetof(CACHE_ENTRY_T, data)) : (uint32_t)(uintptr_t)(x).pointer)); \
+                                                 (target)[5] = RPC_UINT((x).buffer); }
+
+#define SERIALIZE_ATTRIB(b, x, k) RPC_INT((x).size), \
+                              RPC_ENUM((x).type), \
+                              RPC_BOOLEAN((x).normalized), \
+                              RPC_SIZEI((x).stride), \
+                              RPC_UINT((b ? (uint32_t)(k + offsetof(CACHE_ENTRY_T, data)) : (uint32_t)(uintptr_t)(x).pointer)), \
+                              RPC_UINT((x).buffer)
+
+#define SET_SERIALIZED_ATTRIB_VALUE(target, x) { target[0] = RPC_FLOAT((x).value[0]); \
+                                                target[1] = RPC_FLOAT((x).value[1]); \
+                                                target[2] = RPC_FLOAT((x).value[2]); \
+                                                target[3] = RPC_FLOAT((x).value[3]); }
+
+#define SERIALIZE_ATTRIB_VALUE(x) RPC_FLOAT((x).value[0]), \
+                                  RPC_FLOAT((x).value[1]), \
+                                  RPC_FLOAT((x).value[2]), \
+                                  RPC_FLOAT((x).value[3])
+
+#ifdef DISABLE_OPTION_PARSING
+static void set_error(GLXX_CLIENT_STATE_T *state, GLenum error)
+{
+   if (state->error == GL_NO_ERROR)
+      state->error = error;
+}
+#else
+static void set_error_ex(GLXX_CLIENT_STATE_T *state, GLenum error, const char *func)
+{
+   khrn_error_assist(error, func);
+
+   if (state->error == GL_NO_ERROR)
+      state->error = error;
+}
+#define set_error(a, b) set_error_ex(a, b, __func__)
+#endif
+
+void glxx_set_error(GLXX_CLIENT_STATE_T *state, GLenum error)
+{
+   set_error(state,error);
+}
+
+void glxx_set_error_api(uint32_t api, GLenum error)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_API(thread, api))
+   {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+      glxx_set_error(state, error);
+   }
+}
+
+#ifndef RPC_DIRECT
+static void read_out_bulk(CLIENT_THREAD_STATE_T *thread, void *out)
+{
+   rpc_recv(thread, out, NULL, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_LEN));
+}
+#endif
+
+static GLuint get_bound_buffer(GLXX_CLIENT_STATE_T *state, GLenum target)
+{
+   GLuint buffer = 0;
+
+   switch (target) {
+   case GL_ARRAY_BUFFER:
+      buffer = state->bound_buffer.array;
+      break;
+   case GL_ELEMENT_ARRAY_BUFFER:
+      buffer = state->bound_buffer.element_array;
+      break;
+   default:
+      break;
+   }
+   return buffer;
+}
+
+void glxx_buffer_info_set(GLXX_CLIENT_STATE_T *state, GLenum target, GLXX_BUFFER_INFO_T* buffer_info)
+{
+   GLuint buffer = get_bound_buffer(state, target);
+
+   if(buffer != 0)
+   {
+      GLXX_BUFFER_INFO_T *stored = khrn_pointer_map_lookup(&state->buffers, buffer);
+      if(!stored)
+      {
+         stored = khrn_platform_malloc(sizeof(GLXX_BUFFER_INFO_T), "GLXX_BUFFER_INFO_T");
+         khrn_pointer_map_insert(&state->buffers, buffer, stored);
+      }
+      buffer_info->id = buffer;
+      //copy into stored
+      *stored = *buffer_info;
+   }
+}
+
+void glxx_buffer_info_get(GLXX_CLIENT_STATE_T *state, GLenum target, GLXX_BUFFER_INFO_T* buffer_info)
+{
+   GLuint buffer = get_bound_buffer(state, target);
+
+   memset(buffer_info,0,sizeof(GLXX_BUFFER_INFO_T));
+
+   buffer_info->id = 0;
+
+   if(buffer != 0)
+   {
+      GLXX_BUFFER_INFO_T *stored = khrn_pointer_map_lookup(&state->buffers, buffer);
+      if(stored)
+         *buffer_info = *stored;
+   }
+}
+
+static void buffer_info_delete(GLXX_CLIENT_STATE_T *state, GLuint buffer)
+{
+   GLXX_BUFFER_INFO_T *stored = khrn_pointer_map_lookup(&state->buffers, buffer);
+   if(stored)
+   {
+      khrn_platform_free(stored);
+      khrn_pointer_map_delete(&state->buffers,buffer);
+   }
+}
+
+GL_API void GL_APIENTRY glActiveTexture (GLenum texture)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+      if (texture >= GL_TEXTURE0 && texture < GL_TEXTURE0 + GL11_CONFIG_MAX_TEXTURE_UNITS)
+         state->active_texture.server = texture;
+
+      RPC_CALL1(glActiveTexture_impl,
+                thread,
+                GLACTIVETEXTURE_ID,
+                RPC_ENUM(texture));
+   }
+
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL1(glActiveTexture_impl,
+                thread,
+                GLACTIVETEXTURE_ID,
+                RPC_ENUM(texture));
+   }
+}
+
+GL_API void GL_APIENTRY glAlphaFunc (GLenum func, GLclampf ref)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL2(glAlphaFunc_impl_11,
+                thread,
+                GLALPHAFUNC_ID_11,
+                RPC_ENUM(func),
+                RPC_FLOAT(ref));
+   }
+}
+
+GL_API void GL_APIENTRY glAlphaFuncx (GLenum func, GLclampx ref)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL2(glAlphaFuncx_impl_11,
+                thread,
+                GLALPHAFUNCX_ID_11,
+                RPC_ENUM(func),
+                RPC_FIXED(ref));
+   }
+}
+
+GL_API void GL_APIENTRY glAttachShader (GLuint program, GLuint shader)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL2(glAttachShader_impl_20,
+                thread,
+                GLATTACHSHADER_ID_20,
+                RPC_UINT(program),
+                RPC_UINT(shader));
+   }
+}
+
+GL_API void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const char *name)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL3_IN_BULK(glBindAttribLocation_impl_20,
+                        thread,
+                        GLBINDATTRIBLOCATION_ID_20,
+                        RPC_UINT(program),
+                        RPC_UINT(index),
+                        name,
+                        strlen(name) + 1);
+   }
+}
+
+GL_API void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+   if(IS_OPENGLES_11_OR_20(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+      vcos_assert(state != NULL);
+
+      switch (target) {
+      case GL_ARRAY_BUFFER:
+         state->bound_buffer.array = buffer;
+         break;
+      case GL_ELEMENT_ARRAY_BUFFER:
+         state->bound_buffer.element_array = buffer;
+         break;
+      default:
+         // do nothing, server will signal error
+         break;
+      }
+
+      RPC_CALL2(glBindBuffer_impl,
+                thread,
+                GLBINDBUFFER_ID,
+                RPC_ENUM(target),
+                RPC_UINT(buffer));
+   }
+
+}
+
+GL_API void GL_APIENTRY glBindTexture (GLenum target, GLuint texture)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      vcos_log_trace("[%s] target 0x%x texture %d", __FUNCTION__, target, texture);
+      RPC_CALL2(glBindTexture_impl,
+                thread,
+                GLBINDTEXTURE_ID,
+                RPC_ENUM(target),
+                RPC_UINT(texture));
+   }
+}
+
+GL_API void GL_APIENTRY glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) // S
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL4(glBlendColor_impl_20,
+                thread,
+                GLBLENDCOLOR_ID_20,
+                RPC_FLOAT(red),
+                RPC_FLOAT(green),
+                RPC_FLOAT(blue),
+                RPC_FLOAT(alpha));
+   }
+}
+
+GL_API void GL_APIENTRY glBlendEquation( GLenum mode ) // S
+{
+   glBlendEquationSeparate(mode, mode);
+}
+
+GL_API void GL_APIENTRY glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) // S
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL2(glBlendEquationSeparate_impl_20,
+                thread,
+                GLBLENDEQUATIONSEPARATE_ID_20,
+                RPC_ENUM(modeRGB),
+                RPC_ENUM(modeAlpha));
+   }
+}
+
+static void set_blend_func (CLIENT_THREAD_STATE_T *thread, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) {
+   RPC_CALL4(glBlendFuncSeparate_impl,
+             thread,
+             GLBLENDFUNCSEPARATE_ID,
+             RPC_ENUM(srcRGB),
+             RPC_ENUM(dstRGB),
+             RPC_ENUM(srcAlpha),
+             RPC_ENUM(dstAlpha));
+}
+
+GL_API void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) set_blend_func(thread, sfactor, dfactor, sfactor, dfactor);
+}
+
+GL_API void GL_APIENTRY glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) // S
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) set_blend_func(thread, srcRGB, dstRGB, srcAlpha, dstAlpha);
+}
+
+GL_API void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+      GLXX_BUFFER_INFO_T buffer;
+      glxx_buffer_info_get(state, target, &buffer);
+      if(buffer.id != ~0 && buffer.mapped_pointer != 0)
+      {
+         /* buffer is mapped */
+         set_error(state, GL_INVALID_OPERATION);
+      }
+      else
+      {
+         if( ((target == GL_ARRAY_BUFFER && state->bound_buffer.array != 0) ||
+              (target == GL_ELEMENT_ARRAY_BUFFER && state->bound_buffer.element_array != 0)) &&
+             (usage ==  GL_STATIC_DRAW || usage == GL_DYNAMIC_DRAW) &&
+             size >=0
+           )
+         {
+
+            /* server call should succeed in setting buffer size unless out of memory */
+            /* cache size so we can use it in mapBuffer without a round trip */
+            buffer.cached_size = size;
+            glxx_buffer_info_set(state, target, &buffer);
+         }
+         else
+         {
+            buffer.cached_size = 0;
+            glxx_buffer_info_set(state, target, &buffer);
+         }
+
+         RPC_CALL4_IN_BULK(glBufferData_impl,
+                           thread,
+                           GLBUFFERDATA_ID,
+                           RPC_ENUM(target),
+                           RPC_SIZEIPTR(size),
+                           RPC_ENUM(usage),
+                           NULL,
+                           0);
+
+         if (data) {
+            int offset = 0;
+
+            while (size > 0) {
+               int32_t batch = _min(KHDISPATCH_WORKSPACE_SIZE, (int32_t) size);
+
+               RPC_CALL4_IN_BULK(glBufferSubData_impl,
+                                 thread,
+                                 GLBUFFERSUBDATA_ID,
+                                 RPC_ENUM(target),
+                                 RPC_INTPTR(offset),
+                                 RPC_SIZEIPTR(batch),
+                                 (char *)data + offset,
+                                 (size_t) batch);
+
+               offset += batch;
+               size -= batch;
+            }
+         }
+      }
+   }
+}
+
+GL_API void GL_APIENTRY glBufferSubData (GLenum target, GLintptr base, GLsizeiptr size, const GLvoid *data)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+      GLXX_BUFFER_INFO_T buffer;
+      glxx_buffer_info_get(state, target, &buffer);
+      if(buffer.id != ~0 && buffer.mapped_pointer != 0)
+      {
+         /* buffer is mapped */
+         set_error(state, GL_INVALID_OPERATION);
+      }
+      else
+      {
+         if (data) {
+            int offset = 0;
+
+            while (size > 0) {
+               int32_t batch = _min(KHDISPATCH_WORKSPACE_SIZE, (int32_t)size);
+
+               RPC_CALL4_IN_BULK(glBufferSubData_impl,
+                                 thread,
+                                 GLBUFFERSUBDATA_ID,
+                                 RPC_ENUM(target),
+                                 RPC_INTPTR(base+offset),
+                                 RPC_SIZEIPTR(batch),
+                                 (char *)data + offset,
+                                 (size_t) batch);
+
+               offset += batch;
+               size -= batch;
+            }
+         }
+      }
+   }
+}
+
+GL_API void GL_APIENTRY glClear (GLbitfield mask)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+      //TODO: pixmap behaviour can be better optimized to handle clears
+      if (state->render_callback)
+         state->render_callback();
+
+      RPC_CALL1(glClear_impl,
+                thread,
+                GLCLEAR_ID,
+                RPC_BITFIELD(mask));
+   }
+}
+
+GL_API void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL4(glClearColor_impl,
+                thread,
+                GLCLEARCOLOR_ID,
+                RPC_FLOAT(red),
+                RPC_FLOAT(green),
+                RPC_FLOAT(blue),
+                RPC_FLOAT(alpha));
+   }
+}
+
+GL_API void GL_APIENTRY glClearColorx (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL4(glClearColorx_impl_11,
+                thread,
+                GLCLEARCOLORX_ID_11,
+                RPC_FIXED(red),
+                RPC_FIXED(green),
+                RPC_FIXED(blue),
+                RPC_FIXED(alpha));
+   }
+}
+
+GL_API void GL_APIENTRY glClearDepthf (GLclampf depth)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL1(glClearDepthf_impl,
+                thread,
+                GLCLEARDEPTHF_ID,
+                RPC_FLOAT(depth));
+   }
+}
+
+GL_API void GL_APIENTRY glClearDepthx (GLclampx depth)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL1(glClearDepthx_impl_11,
+                thread,
+                GLCLEARDEPTHX_ID_11,
+                RPC_FIXED(depth));
+   }
+}
+
+GL_API void GL_APIENTRY glClearStencil (GLint s)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL1(glClearStencil_impl,
+                thread,
+                GLCLEARSTENCIL_ID,
+                RPC_INT(s));
+   }
+}
+
+GL_API void GL_APIENTRY glClientActiveTexture (GLenum texture)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+      vcos_assert(state != NULL);
+
+      if (texture >= GL_TEXTURE0 && texture < GL_TEXTURE0 + GL11_CONFIG_MAX_TEXTURE_UNITS)
+      {
+         state->active_texture.client = texture;
+         RPC_CALL1(glClientActiveTexture_impl_11,
+                thread,
+                GLCLIENTACTIVETEXTURE_ID_11,
+                RPC_ENUM(texture));
+      }
+      else
+         set_error(state, GL_INVALID_ENUM);
+   }
+}
+
+GL_API void GL_APIENTRY glClipPlanef (GLenum plane, const GLfloat *equation)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL2_IN_CTRL(glClipPlanef_impl_11,
+                        thread,
+                        GLCLIPPLANEF_ID_11,
+                        RPC_ENUM(plane),
+                        equation,
+                        4 * sizeof(GLfloat));
+   }
+}
+
+GL_API void GL_APIENTRY glClipPlanex (GLenum plane, const GLfixed *equation)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL2_IN_CTRL(glClipPlanex_impl_11,
+                        thread,
+                        GLCLIPPLANEX_ID_11,
+                        RPC_ENUM(plane),
+                        equation,
+                        4 * sizeof(GLfixed));
+   }
+}
+
+GL_API void GL_APIENTRY glColor4f (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha)
+{
+   glintColor(
+      clampf(red, 0.0f, 1.0f),
+      clampf(green, 0.0f, 1.0f),
+      clampf(blue, 0.0f, 1.0f),
+      clampf(alpha, 0.0f, 1.0f));
+}
+
+GL_API void GL_APIENTRY glColor4ub (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha)
+{
+   glintColor(
+      (float)red / 255.0f,
+      (float)green / 255.0f,
+      (float)blue / 255.0f,
+      (float)alpha / 255.0f);
+}
+
+GL_API void GL_APIENTRY glColor4x (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha)
+{
+   glintColor(
+      clampf(fixed_to_float(red), 0.0f, 1.0f),
+      clampf(fixed_to_float(green), 0.0f, 1.0f),
+      clampf(fixed_to_float(blue), 0.0f, 1.0f),
+      clampf(fixed_to_float(alpha), 0.0f, 1.0f));
+}
+
+GL_API void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL4(glColorMask_impl,
+                thread,
+                GLCOLORMASK_ID,
+                RPC_BOOLEAN(red),
+                RPC_BOOLEAN(green),
+                RPC_BOOLEAN(blue),
+                RPC_BOOLEAN(alpha));
+   }
+}
+
+static bool is_color_size(GLint size)
+{
+   return size == 4;
+}
+
+static bool is_color_type(GLenum type)
+{
+   return type == GL_UNSIGNED_BYTE ||
+          type == GL_FIXED ||
+          type == GL_FLOAT;
+}
+
+static bool is_aligned( GLenum type, size_t value)
+{
+   switch (type) {
+   case GL_BYTE:
+   case GL_UNSIGNED_BYTE:
+      return GL_TRUE;
+   case GL_SHORT:
+   case GL_UNSIGNED_SHORT:
+      return (value & 1) == 0;
+   case GL_FIXED:
+   case GL_FLOAT:
+      return (value & 3) == 0;
+   default:
+      UNREACHABLE();
+      return GL_FALSE;
+   }
+}
+
+GL_API void GL_APIENTRY glColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+{
+   if (is_color_type(type)) {
+      if (is_color_size(size) && is_aligned(type, (size_t)pointer) && is_aligned(type, (size_t)stride) && stride >= 0) {
+         glintAttribPointer(GLXX_API_11, GL11_IX_COLOR, size, type, GL_TRUE, stride, pointer);
+      } else
+         glxx_set_error_api(GLXX_API_11, GL_INVALID_VALUE);
+   } else
+      glxx_set_error_api(GLXX_API_11, GL_INVALID_ENUM);
+}
+
+static uint32_t get_palette_size(GLenum internalformat)
+{
+   switch (internalformat)
+   {
+   case GL_PALETTE4_RGB8_OES: return 16 * 3;
+   case GL_PALETTE4_RGBA8_OES: return 16 * 4;
+   case GL_PALETTE4_R5_G6_B5_OES: return 16 * 2;
+   case GL_PALETTE4_RGBA4_OES: return 16 * 2;
+   case GL_PALETTE4_RGB5_A1_OES: return 16 * 2;
+   case GL_PALETTE8_RGB8_OES: return 256 * 3;
+   case GL_PALETTE8_RGBA8_OES: return 256 * 4;
+   case GL_PALETTE8_R5_G6_B5_OES: return 256 * 2;
+   case GL_PALETTE8_RGBA4_OES: return 256 * 2;
+   case GL_PALETTE8_RGB5_A1_OES: return 256 * 2;
+   default:
+      UNREACHABLE();
+      return 0;
+   }
+}
+
+GL_API void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   GLboolean res;
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+      switch (internalformat)
+      {
+         case GL_ETC1_RGB8_OES:
+         {
+            uint32_t pitch = 2 * ((width + 3) / 4);
+            uint32_t lines = pitch ? (uint32_t)(KHDISPATCH_WORKSPACE_SIZE / pitch) : (uint32_t)height;
+
+            res = RPC_BOOLEAN_RES(RPC_CALL8_IN_BULK_RES(glCompressedTexImage2D_impl,
+                              thread,
+                              GLCOMPRESSEDTEXIMAGE2D_ID,
+                              RPC_ENUM  (target),
+                              RPC_INT   (level),
+                              RPC_ENUM  (internalformat),
+                              RPC_SIZEI (width),
+                              RPC_SIZEI (height),
+                              RPC_INT   (border),
+                              RPC_SIZEI (imageSize),
+                              NULL,
+                              0));
+
+            if (res && data && lines && width && height) {
+               int offset = 0;
+
+               while (height > 0) {
+                  int32_t batch = (_min(lines, (int32_t)height) + 3) & ~3;
+
+                  RPC_CALL9_IN_BULK(glCompressedTexSubImage2D_impl,
+                                    thread,
+                                    GLCOMPRESSEDTEXSUBIMAGE2D_ID,
+                                    RPC_ENUM(target),
+                                    RPC_INT(level),
+                                    RPC_INT(0),
+                                    RPC_INT(offset),
+                                    RPC_SIZEI(width),
+                                    RPC_SIZEI(batch),
+                                    RPC_ENUM(internalformat),
+                                    batch * pitch,
+                                    (char *)data + offset * pitch,
+                                    batch * pitch);
+
+                  offset += batch;
+                  height -= batch;
+               }
+            }
+            break;
+         }
+         case GL_PALETTE4_RGB8_OES:
+         case GL_PALETTE4_RGBA8_OES:
+         case GL_PALETTE4_R5_G6_B5_OES:
+         case GL_PALETTE4_RGBA4_OES:
+         case GL_PALETTE4_RGB5_A1_OES:
+         case GL_PALETTE8_RGB8_OES:
+         case GL_PALETTE8_RGBA8_OES:
+         case GL_PALETTE8_R5_G6_B5_OES:
+         case GL_PALETTE8_RGBA4_OES:
+         case GL_PALETTE8_RGB5_A1_OES:
+         {
+            int palette_size = get_palette_size(internalformat);
+
+            level = -level;
+            res = RPC_BOOLEAN_RES(RPC_CALL8_IN_BULK_RES(glCompressedTexImage2D_impl,
+                              thread,
+                              GLCOMPRESSEDTEXIMAGE2D_ID,
+                              RPC_ENUM  (target),
+                              RPC_INT   (level),
+                              RPC_ENUM  (internalformat),
+                              RPC_SIZEI (width),
+                              RPC_SIZEI (height),
+                              RPC_INT   (border),
+                              RPC_SIZEI (imageSize),
+                              data,
+                              palette_size));
+
+            if (res && data && width && height) {
+               int offset = palette_size;
+               while (offset < imageSize) {
+                  int32_t batch = _min(KHDISPATCH_WORKSPACE_SIZE, imageSize - offset);
+
+                  RPC_CALL9_IN_BULK(glCompressedTexSubImage2D_impl,
+                                    thread,
+                                    GLCOMPRESSEDTEXSUBIMAGE2D_ID,
+                                    RPC_ENUM(target),
+                                    RPC_INT(level),
+                                    RPC_INT(offset - palette_size),
+                                    RPC_INT(0),
+                                    RPC_SIZEI(width),
+                                    RPC_SIZEI(height),
+                                    RPC_ENUM(internalformat),
+                                    batch,
+                                    (char *)data + offset,
+                                    batch);
+
+                  offset += batch;
+               }
+            }
+            break;
+         }
+         default:
+            set_error(state, GL_INVALID_ENUM );
+            break;
+      }
+   }
+}
+
+GL_API void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   UNUSED(target);
+   UNUSED(level);
+   UNUSED(xoffset);
+   UNUSED(yoffset);
+   UNUSED(width);
+   UNUSED(height);
+   UNUSED(imageSize);
+   UNUSED(data);
+
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+      switch (format)
+      {
+      case GL_ETC1_RGB8_OES:
+         // Cannot specify subimages of ETC1 textures
+         set_error(state, GL_INVALID_OPERATION);
+         break;
+      case GL_PALETTE4_RGB8_OES:
+      case GL_PALETTE4_RGBA8_OES:
+      case GL_PALETTE4_R5_G6_B5_OES:
+      case GL_PALETTE4_RGBA4_OES:
+      case GL_PALETTE4_RGB5_A1_OES:
+      case GL_PALETTE8_RGB8_OES:
+      case GL_PALETTE8_RGBA8_OES:
+      case GL_PALETTE8_R5_G6_B5_OES:
+      case GL_PALETTE8_RGBA4_OES:
+      case GL_PALETTE8_RGB5_A1_OES:
+         // Cannot specify subimages of paletted textures
+         set_error(state, GL_INVALID_OPERATION);
+         break;
+      default:
+         // Some format we don't recognise
+         set_error(state, GL_INVALID_VALUE);
+         break;
+      }
+   }
+}
+
+GL_API void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL8(glCopyTexImage2D_impl,
+                thread,
+                GLCOPYTEXIMAGE2D_ID,
+                RPC_ENUM(target),
+                RPC_INT(level),
+                RPC_ENUM(internalformat),
+                RPC_INT(x),
+                RPC_INT(y),
+                RPC_SIZEI(width),
+                RPC_SIZEI(height),
+                RPC_INT(border));
+   }
+}
+
+GL_API void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL8(glCopyTexSubImage2D_impl,
+                thread,
+                GLCOPYTEXSUBIMAGE2D_ID,
+                RPC_ENUM(target),
+                RPC_INT(level),
+                RPC_INT(xoffset),
+                RPC_INT(yoffset),
+                RPC_INT(x),
+                RPC_INT(y),
+                RPC_SIZEI(width),
+                RPC_SIZEI(height));
+   }
+}
+
+GL_API GLuint GL_APIENTRY glCreateProgram (void)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      return RPC_UINT_RES(RPC_CALL0_RES(glCreateProgram_impl_20,
+                                        thread,
+                                        GLCREATEPROGRAM_ID_20));
+   }
+
+   return 0;
+}
+
+GL_API GLuint GL_APIENTRY glCreateShader (GLenum type)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      return RPC_UINT_RES(RPC_CALL1_RES(glCreateShader_impl_20,
+                                        thread,
+                                        GLCREATESHADER_ID_20,
+                                        RPC_ENUM(type)));
+   }
+
+   return 0;
+}
+
+GL_API void GL_APIENTRY glCullFace (GLenum mode)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL1(glCullFace_impl,
+                thread,
+                GLCULLFACE_ID,
+                RPC_ENUM(mode));
+   }
+}
+
+GL_API void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   int offset = 0;
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+      int i, j;
+
+      for (i = 0; i < n; i++) {
+         GLuint buffer = buffers[i];
+
+         if (state->bound_buffer.array == buffer)
+            state->bound_buffer.array = 0;
+         if (state->bound_buffer.element_array == buffer)
+            state->bound_buffer.element_array = 0;
+
+         for (j = 0; j < GLXX_CONFIG_MAX_VERTEX_ATTRIBS; j++)
+            if (state->attrib[j].buffer == buffer)
+               state->attrib[j].buffer = 0;
+
+         buffer_info_delete(state, buffer);
+      }
+   }
+
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      do {
+         int32_t items = (int32_t)( KHDISPATCH_WORKSPACE_SIZE / sizeof(GLuint) );
+         int32_t batch = _min(items, (int32_t) n);
+
+         RPC_CALL2_IN_BULK(glDeleteBuffers_impl,
+                           thread,
+                           GLDELETEBUFFERS_ID,
+                           RPC_SIZEI(batch),
+                           buffers + offset,
+                           batch > 0 ? batch * sizeof(GLuint) : 0);
+
+         offset += batch;
+         n -= batch;
+      } while (n > 0);
+   }
+}
+
+GL_API void GL_APIENTRY glDeleteProgram (GLuint program)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL1(glDeleteProgram_impl_20,
+                thread,
+                GLDELETEPROGRAM_ID_20,
+                RPC_UINT(program));
+   }
+}
+
+GL_API void GL_APIENTRY glDeleteShader (GLuint shader)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL1(glDeleteShader_impl_20,
+                thread,
+                GLDELETESHADER_ID_20,
+                RPC_UINT(shader));
+   }
+}
+
+GL_API void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   int offset = 0;
+
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      do {
+         int32_t items = (int32_t)(KHDISPATCH_WORKSPACE_SIZE / sizeof(GLuint));
+         int32_t batch = _min(items, (int32_t)n);
+
+         RPC_CALL2_IN_BULK(glDeleteTextures_impl,
+                           thread,
+                           GLDELETETEXTURES_ID,
+                           RPC_SIZEI(batch),
+                           textures + offset,
+                           batch > 0 ? batch * sizeof(GLuint) : 0);
+
+         offset += batch;
+         n -= batch;
+      } while (n > 0);
+   }
+}
+
+GL_API void GL_APIENTRY glDepthFunc (GLenum func)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL1(glDepthFunc_impl,
+                thread,
+                GLDEPTHFUNC_ID,
+                RPC_ENUM(func));
+   }
+}
+
+GL_API void GL_APIENTRY glDepthMask (GLboolean flag)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL1(glDepthMask_impl,
+                thread,
+                GLDEPTHMASK_ID,
+                RPC_BOOLEAN(flag));
+   }
+}
+
+GL_API void GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL2(glDepthRangef_impl,
+                thread,
+                GLDEPTHRANGEF_ID,
+                RPC_FLOAT(zNear),
+                RPC_FLOAT(zFar));
+   }
+}
+
+GL_API void GL_APIENTRY glDepthRangex (GLclampx zNear, GLclampx zFar)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL2(glDepthRangex_impl_11,
+                thread,
+                GLDEPTHRANGEX_ID_11,
+                RPC_FIXED(zNear),
+                RPC_FIXED(zFar));
+   }
+}
+
+GL_API void GL_APIENTRY glDetachShader (GLuint program, GLuint shader)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL2(glDetachShader_impl_20,
+                thread,
+                GLDETACHSHADER_ID_20,
+                RPC_UINT(program),
+                RPC_UINT(shader));
+   }
+}
+
+GL_API void GL_APIENTRY glDisable (GLenum cap)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL1(glDisable_impl,
+               thread,
+                GLDISABLE_ID,
+                RPC_ENUM(cap));
+   }
+}
+
+static void set_enabled_11(GLenum array, GLboolean enabled)
+{
+   switch (array) {
+   case GL_VERTEX_ARRAY:
+      glintAttribEnable(GLXX_API_11, GL11_IX_VERTEX, enabled);
+      break;
+   case GL_NORMAL_ARRAY:
+      glintAttribEnable(GLXX_API_11, GL11_IX_NORMAL, enabled);
+      break;
+   case GL_COLOR_ARRAY:
+      glintAttribEnable(GLXX_API_11, GL11_IX_COLOR, enabled);
+      break;
+   case GL_POINT_SIZE_ARRAY_OES:
+      glintAttribEnable(GLXX_API_11, GL11_IX_POINT_SIZE, enabled);
+      break;
+#if GL_OES_matrix_palette
+   case GL_MATRIX_INDEX_ARRAY_OES:
+      glintAttribEnable(GLXX_API_11, GL11_IX_MATRIX_INDEX, enabled);
+      break;
+   case GL_WEIGHT_ARRAY_OES:
+      glintAttribEnable(GLXX_API_11, GL11_IX_MATRIX_WEIGHT, enabled);
+      break;
+#endif
+   case GL_TEXTURE_COORD_ARRAY:
+      glintAttribEnable(GLXX_API_11, GL11_IX_CLIENT_ACTIVE_TEXTURE, enabled);
+      break;
+   default:
+      glxx_set_error_api(GLXX_API_11, GL_INVALID_ENUM);
+      break;
+   }
+}
+
+GL_API void GL_APIENTRY glDisableClientState (GLenum array)
+{
+   set_enabled_11(array, GL_FALSE);
+}
+
+GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index)
+{
+   glintAttribEnable(GLXX_API_20, index, GL_FALSE);
+}
+
+static int align_length(int length)
+{
+   return (length + 15) & ~15;
+}
+
+static int calc_length(int max, int size, GLenum type, int stride)
+{
+   if (max >= 0) {
+      int type_size = khrn_get_type_size( (int)type);
+
+      return align_length(size * type_size + max * (stride ? stride : size * type_size));
+   } else
+      return 0;
+}
+
+static GLboolean is_index_type(GLenum type)
+{
+   return type == GL_UNSIGNED_BYTE ||
+          type == GL_UNSIGNED_SHORT;
+}
+
+typedef struct MERGE_INFO
+{
+   bool send;
+
+   const char *start;
+   const char *end;
+
+   int next;
+} MERGE_INFO_T;
+
+static void draw_arrays_or_elements(CLIENT_THREAD_STATE_T *thread, GLXX_CLIENT_STATE_T *state, GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
+{
+   uint32_t indices_offset = 0;
+   GLuint indices_buffer;
+   bool send_indices;
+   int max = 0;
+   int indices_length = 0;
+   int indices_key = 0;
+   int first = 0;
+   int i, j, k;
+   MERGE_INFO_T merge[GLXX_CONFIG_MAX_VERTEX_ATTRIBS];
+   GLXX_CACHE_INFO_T cache_info;
+
+   vcos_assert(state != NULL);
+
+   if (state->render_callback && (IS_OPENGLES_11(thread) || state->default_framebuffer))
+      state->render_callback();
+
+   if(count<0)
+   {
+      glxx_set_error(state, GL_INVALID_VALUE);
+      return;
+   }
+
+   cache_info.send_any = 0;
+   for (i = 0; i < GLXX_CONFIG_MAX_VERTEX_ATTRIBS; i++)
+   {
+      if (state->attrib[i].enabled && state->attrib[i].buffer == 0)
+      {
+         cache_info.send_any = 1;
+
+         /* TODO: what should we do if people give us null pointers? */
+         if (state->attrib[i].pointer == NULL)
+            return;
+      }
+   }
+
+   if(type==0)
+   {
+      first = (int)indices;
+      indices_offset = first;
+      indices_buffer = 0;
+      send_indices = 0;
+      indices_key = 0;
+
+      max = first + count - 1;
+   }
+   else
+   {
+      send_indices = count >= 0 && state->bound_buffer.element_array == 0;
+      indices_buffer = state->bound_buffer.element_array;
+
+      indices_length = align_length(count * khrn_get_type_size( (int) type ));
+      if (send_indices)
+      {
+         max = find_max(count, khrn_get_type_size( (int)type ), indices);
+         indices_key = khrn_cache_lookup(thread, &state->cache, indices, indices_length, 0);
+         indices_offset = indices_key + offsetof(CACHE_ENTRY_T, data);
+      }
+      else
+      {
+         indices_key = 0;
+         indices_offset = (uint32_t)indices;
+
+         if (cache_info.send_any)
+            max = RPC_INT_RES(RPC_CALL3_RES(
+               glintFindMax_impl,
+               thread,
+               GLINTFINDMAX_ID,
+               RPC_SIZEI(count),
+               RPC_ENUM(type),
+               RPC_UINT(indices_offset)));
+         else
+            max = -1;
+      }
+   }
+
+   if (cache_info.send_any)
+   {
+      /* Merge overlapping arrays */
+      for (i = 0; i < GLXX_CONFIG_MAX_VERTEX_ATTRIBS; i++)
+      {
+         if (state->attrib[i].enabled && state->attrib[i].buffer == 0)
+         {
+            merge[i].send = true;
+            merge[i].start = state->attrib[i].pointer;
+            merge[i].end = (const char *)state->attrib[i].pointer + calc_length(max, state->attrib[i].size, state->attrib[i].type, state->attrib[i].stride);
+            merge[i].next = -1;
+
+            for (j = 0; j < i; j++)
+            {
+               if (merge[j].send && merge[j].next == -1)
+               {
+                  const char *start = merge[i].start < merge[j].start ? merge[i].start : merge[j].start;
+                  const char *end = merge[i].end > merge[j].end ? merge[i].end : merge[j].end;
+
+                  if ((uint32_t)(end - start) < (uint32_t)((merge[i].end - merge[i].start) + (merge[j].end - merge[j].start)))
+                  {
+                     if (merge[i].start < merge[j].start)
+                     {
+                        k = i;
+                        while (merge[k].next != -1)
+                           k = merge[k].next;
+                        merge[k].end = end;
+                        merge[j].next = i;
+                     }
+                     else
+                     {
+                        vcos_assert(merge[j].next == -1);
+                        merge[j].end = end;
+                        merge[i].next = j;
+                     }
+                  }
+               }
+            }
+         }
+         else
+         {
+            merge[i].send = false;
+         }
+      }
+
+      /* Perform cache lookups */
+      for (i = 0; i < GLXX_CONFIG_MAX_VERTEX_ATTRIBS; i++)
+      {
+         if (merge[i].send && merge[i].next == -1)
+         {
+            int key = khrn_cache_lookup(thread, &state->cache, merge[i].start, merge[i].end - merge[i].start, CACHE_SIG_ATTRIB_0 + i);
+            if (key == -1)
+            {
+               glxx_set_error(state, GL_OUT_OF_MEMORY);
+               return;
+            }
+            cache_info.entries[i].cache_offset = key + offsetof(CACHE_ENTRY_T, data);
+            cache_info.entries[i].has_interlock = 1;
+         }
+         else
+         {
+            cache_info.entries[i].cache_offset = ~0;
+         }
+      }
+
+      /* Fill in the rest of cache_info (for the merged attribs which didn't force their own cache lookup) */
+      for (i = 0; i < GLXX_CONFIG_MAX_VERTEX_ATTRIBS; i++)
+      {
+         if (merge[i].send && merge[i].next != -1)
+         {
+            k = i;
+            while (merge[k].next != -1)
+               k = merge[k].next;
+
+            vcos_assert(k != -1);
+            vcos_assert(cache_info.entries[k].cache_offset != ~0);
+            cache_info.entries[i].cache_offset = cache_info.entries[k].cache_offset + ((size_t)state->attrib[i].pointer - (size_t)state->attrib[k].pointer);
+            cache_info.entries[i].has_interlock = 0;
+         }
+      }
+
+      /* Execute draw call, sending attrib cache information */
+      RPC_CALL5_IN_CTRL(glintDrawElements_impl,
+                thread,
+                GLINTDRAWELEMENTS_ID,
+                RPC_ENUM(mode),
+                RPC_SIZEI(count),
+                RPC_ENUM(type),
+                RPC_UINT(indices_offset),
+                &cache_info,
+                sizeof(cache_info));
+   }
+   else
+   {
+      /* Execute draw call without sending any attrib cache information (except for send_any==0) */
+      RPC_CALL5_IN_CTRL(glintDrawElements_impl,
+                thread,
+                GLINTDRAWELEMENTS_ID,
+                RPC_ENUM(mode),
+                RPC_SIZEI(count),
+                RPC_ENUM(type),
+                RPC_UINT(indices_offset),
+                &cache_info,
+                4/*sizeof(cache_info.send_any)*/);
+   }
+}
+
+GL_API void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+      draw_arrays_or_elements(thread, state, mode, count, 0, (void *)first);
+   }
+}
+
+
+GL_API void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+      if (!is_index_type(type)) {
+         set_error(state, GL_INVALID_ENUM);
+         return;
+      }
+      if (!is_aligned(type, (size_t)indices)) {
+         set_error(state, GL_INVALID_VALUE);
+         return;
+      }
+      draw_arrays_or_elements(thread, state, mode, count, type, indices);
+   }
+}
+
+GL_API void GL_APIENTRY glEnable (GLenum cap)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL1(glEnable_impl,
+                thread,
+                GLENABLE_ID,
+                RPC_ENUM(cap));
+   }
+}
+
+GL_API void GL_APIENTRY glEnableClientState (GLenum array)
+{
+   set_enabled_11(array, GL_TRUE);
+}
+
+GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index)
+{
+   glintAttribEnable(GLXX_API_20, index, GL_TRUE);
+}
+
+GL_API void GL_APIENTRY glFinish (void)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+      (void) RPC_UINT_RES(RPC_CALL0_RES(glFinish_impl,
+                    thread,
+                    GLFINISH_ID));  // Return ignored - read performed to force blocking
+
+      if (state->flush_callback)
+         state->flush_callback(true);
+   }
+}
+
+GL_API void GL_APIENTRY glFlush (void)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+      RPC_CALL0(glFlush_impl,
+                    thread,
+                    GLFLUSH_ID);
+
+      if (state->flush_callback)
+         state->flush_callback(false);
+   }
+
+   //TODO: where exactly should we put RPC_FLUSH? Are there any other functions
+   //which need it? (e.g. eglSwapBuffers)
+   RPC_FLUSH(thread);
+}
+
+GL_API void GL_APIENTRY glFogf (GLenum pname, GLfloat param)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL2(glFogf_impl_11,
+                thread,
+                GLFOGF_ID_11,
+                RPC_ENUM(pname),
+                RPC_FLOAT(param));
+   }
+}
+
+GL_API void GL_APIENTRY glFogfv (GLenum pname, const GLfloat *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      /*
+         the only supported fog params are
+
+         FOG_MODE (1)
+         FOG_DENSITY (1)
+         FOG_START (1)
+         FOG_END (1)
+         FOG_COLOR (4)
+
+         so we need to transmit 4 words of parameter data
+      */
+
+      RPC_CALL2_IN_CTRL(glFogfv_impl_11,
+                        thread,
+                        GLFOGFV_ID_11,
+                        RPC_ENUM(pname),
+                        params,
+                        4 * sizeof(GLfloat));
+   }
+}
+
+GL_API void GL_APIENTRY glFogx (GLenum pname, GLfixed param)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL2(glFogx_impl_11,
+               thread,
+               GLFOGX_ID_11,
+               RPC_ENUM(pname),
+               RPC_FIXED(param));
+   }
+}
+
+GL_API void GL_APIENTRY glFogxv (GLenum pname, const GLfixed *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      /*
+         the only supported fog params are
+
+         FOG_MODE (1)
+         FOG_DENSITY (1)
+         FOG_START (1)
+         FOG_END (1)
+         FOG_COLOR (4)
+
+         so we need to transmit 4 words of parameter data
+      */
+
+      RPC_CALL2_IN_CTRL(glFogxv_impl_11,
+                        thread,
+                        GLFOGXV_ID_11,
+                        RPC_ENUM(pname),
+                        params,
+                        4 * sizeof(GLfixed));
+   }
+}
+
+GL_API void GL_APIENTRY glFrontFace (GLenum mode)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL1(glFrontFace_impl,
+                thread,
+                GLFRONTFACE_ID,
+                RPC_ENUM(mode));
+   }
+}
+
+GL_API void GL_APIENTRY glFrustumf (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL6(glFrustumf_impl_11,
+                thread,
+                GLFRUSTUMF_ID_11,
+                RPC_FLOAT(left),
+                RPC_FLOAT(right),
+                RPC_FLOAT(bottom),
+                RPC_FLOAT(top),
+                RPC_FLOAT(zNear),
+                RPC_FLOAT(zFar));
+   }
+}
+
+GL_API void GL_APIENTRY glFrustumx (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL6(glFrustumx_impl_11,
+                thread,
+                GLFRUSTUMX_ID_11,
+                RPC_FIXED(left),
+                RPC_FIXED(right),
+                RPC_FIXED(bottom),
+                RPC_FIXED(top),
+                RPC_FIXED(zNear),
+                RPC_FIXED(zFar));
+   }
+}
+
+GL_API void GL_APIENTRY glGenBuffers (GLsizei n, GLuint *buffers)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      int offset = 0;
+
+      do {
+         int32_t items = (int32_t) (KHDISPATCH_WORKSPACE_SIZE / sizeof(GLuint));
+         int32_t batch = _min(items, (int32_t) n);
+
+         RPC_CALL2_OUT_BULK(glGenBuffers_impl,
+                            thread,
+                            GLGENBUFFERS_ID,
+                            RPC_SIZEI(batch),
+                            (GLuint*)(buffers + offset));
+
+         offset += batch;
+         n -= batch;
+      } while (n > 0);
+   }
+}
+
+GL_API void GL_APIENTRY glGenTextures (GLsizei n, GLuint *textures)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      int offset = 0;
+
+      do {
+         int32_t items = (int32_t) (KHDISPATCH_WORKSPACE_SIZE / sizeof(GLuint));
+         int32_t batch = _min(items, (int32_t)n);
+
+         RPC_CALL2_OUT_BULK(glGenTextures_impl,
+                            thread,
+                            GLGENTEXTURES_ID,
+                            RPC_SIZEI(batch),
+                            textures + offset);
+
+         offset += batch;
+         n -= batch;
+      } while (n > 0);
+   }
+}
+
+GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+#ifdef RPC_DIRECT
+      RPC_CALL7(glGetActiveAttrib_impl_20, thread, no_id, program, index, bufsize, length, size, type, name);
+#else
+      GLuint result[3];
+
+      rpc_begin(thread);
+
+      RPC_CALL4_OUT_CTRL(no_function,
+                         thread,
+                         GLGETACTIVEATTRIB_ID_20,
+                         RPC_UINT(program),
+                         RPC_UINT(index),
+                         RPC_SIZEI(bufsize),
+                         result);
+
+      if (length)
+         *length = (GLsizei)result[0];
+      if (size)
+         *size = (GLint)result[1];
+      if (type)
+         *type = (GLenum)result[2];
+
+      read_out_bulk(thread, name);
+
+      rpc_end(thread);
+#endif
+   }
+}
+
+GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei *length, GLint *size, GLenum *type, char *name)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+#ifdef RPC_DIRECT
+      RPC_CALL7(glGetActiveUniform_impl_20, thread, no_id, program, index, bufsize, length, size, type, name);
+#else
+      GLuint result[3];
+
+      rpc_begin(thread);
+
+      RPC_CALL4_OUT_CTRL(no_function,
+                         thread,
+                         GLGETACTIVEUNIFORM_ID_20,
+                         RPC_UINT(program),
+                         RPC_UINT(index),
+                         RPC_SIZEI(bufsize),
+                         result);
+
+      if (length)
+         *length = (GLsizei)result[0];
+      if (size)
+         *size = (GLint)result[1];
+      if (type)
+         *type = (GLenum)result[2];
+
+      read_out_bulk(thread, name);
+
+      rpc_end(thread);
+#endif
+   }
+}
+
+GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei *count, GLuint *shaders)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+#ifdef RPC_DIRECT
+   RPC_CALL4(glGetAttachedShaders_impl_20, thread, no_id, program, maxcount, count, shaders);
+#else
+   GLuint i;
+
+   GLuint result[3];
+
+   RPC_CALL3_OUT_CTRL(no_function,
+                      thread,
+                      GLGETATTACHEDSHADERS_ID_20,
+                      RPC_UINT(program),
+                      RPC_SIZEI(maxcount),
+                      result);
+
+   if (count)
+      *count = (GLsizei) result[0];
+
+   for (i = 0; i < 2; i++)
+      if ((GLuint)maxcount > i && result[0] > i)
+         shaders[i] = result[i + 1];
+#endif
+   }
+}
+
+GL_APICALL int GL_APIENTRY glGetAttribLocation (GLuint program, const char *name)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      return RPC_INT_RES(RPC_CALL2_IN_BULK_RES(glGetAttribLocation_impl_20,
+                                               thread,
+                                               GLGETATTRIBLOCATION_ID_20,
+                                               RPC_UINT(program),
+                                               name,
+                                               strlen(name) + 1));
+   }
+
+   return 0;
+}
+
+/*
+   native client-side boolean variables
+
+   VERTEX ARRAY IsEnabled
+   NORMAL ARRAY IsEnabled
+   COLOR ARRAY IsEnabled
+   TEXTURE COORD ARRAY IsEnabled
+   POINT SIZE ARRAY OES IsEnabled
+   MATRIX INDEX ARRAY OES IsEnabled
+   WEIGHT ARRAY OES IsEnabled
+*/
+
+static int get_boolean_internal_11(CLIENT_THREAD_STATE_T *thread, GLenum pname, GLboolean *params)
+{
+   GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+   vcos_assert(state != NULL);
+
+   switch (pname) {
+   case GL_VERTEX_ARRAY:
+      params[0] = state->attrib[GL11_IX_VERTEX].enabled;
+      return 1;
+   case GL_NORMAL_ARRAY:
+      params[0] = state->attrib[GL11_IX_NORMAL].enabled;
+      return 1;
+   case GL_COLOR_ARRAY:
+      params[0] = state->attrib[GL11_IX_COLOR].enabled;
+      return 1;
+   case GL_TEXTURE_COORD_ARRAY:
+      params[0] = state->attrib[state->active_texture.client - GL_TEXTURE0 + GL11_IX_TEXTURE_COORD].enabled;
+      return 1;
+   case GL_POINT_SIZE_ARRAY_OES:
+      params[0] = state->attrib[GL11_IX_POINT_SIZE].enabled;
+      return 1;
+   case GL_MATRIX_INDEX_ARRAY_OES:
+      params[0] = state->attrib[GL11_IX_MATRIX_INDEX].enabled;
+      return 1;
+   case GL_WEIGHT_ARRAY_OES:
+      params[0] = state->attrib[GL11_IX_MATRIX_WEIGHT].enabled;
+      return 1;
+   default:
+      UNREACHABLE();
+      break;
+   }
+
+   return 0;
+}
+
+/*
+   native client-side floating-point state variables
+
+   CURRENT_COLOR
+   CURRENT_TEXTURE_COORDS
+   CURRENT_NORMAL
+   POINT_SIZE
+*/
+
+static int get_float_internal_11(CLIENT_THREAD_STATE_T *thread, GLenum pname, GLfloat *params)
+{
+   GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+   int i;
+
+   switch (pname) {
+   case GL_CURRENT_TEXTURE_COORDS:
+   {
+      /*
+         apparently we need the current texture coordinates for the _server_ active texture unit
+      */
+
+      for (i = 0; i < 4; i++)
+         params[i] = state->attrib[state->active_texture.server - GL_TEXTURE0 + GL11_IX_TEXTURE_COORD].value[i];
+      return 4;
+   }
+   case GL_CURRENT_COLOR:
+   {
+      for (i = 0; i < 4; i++)
+         params[i] = state->attrib[GL11_IX_COLOR].value[i];
+      return 4;
+   }
+   case GL_CURRENT_NORMAL:
+   {
+      for (i = 0; i < 3; i++)
+         params[i] = state->attrib[GL11_IX_NORMAL].value[i];
+      return 3;
+   }
+   case GL_POINT_SIZE:
+      params[0] = state->attrib[GL11_IX_POINT_SIZE].value[0];
+      return 1;
+   default:
+      UNREACHABLE();
+      break;
+   }
+
+   return 0;
+}
+
+/*
+   native client-side integer state variables
+
+   CLIENT ACTIVE TEXTURE GetIntegerv
+   VERTEX ARRAY SIZE GetIntegerv
+   VERTEX ARRAY TYPE GetIntegerv
+   VERTEX ARRAY STRIDE GetIntegerv
+   NORMAL ARRAY TYPE GetIntegerv
+   NORMAL ARRAY STRIDE GetIntegerv
+   COLOR ARRAY SIZE GetIntegerv
+   COLOR ARRAY TYPE GetIntegerv
+   COLOR ARRAY STRIDE GetIntegerv
+   TEXTURE COORD ARRAY SIZE GetIntegerv
+   TEXTURE COORD ARRAY TYPE GetIntegerv
+   TEXTURE COORD ARRAY STRIDE GetIntegerv
+   POINT SIZE ARRAY TYPE OES GetIntegerv
+   POINT SIZE ARRAY STRIDE OES GetIntegerv
+
+   MATRIX_INDEX_ARRAY_SIZE_OES GetInegerv
+   MATRIX_INDEX_ARRAY_TYPE_OES GetInegerv
+   MATRIX_INDEX_ARRAY_STRIDE_OES GetInegerv
+   WEIGHT_ARRAY_SIZE_OES GetInegerv
+   WEIGHT_ARRAY_TYPE_OES GetInegerv
+   WEIGHT_ARRAY_STRIDE_OES GetInegerv
+
+   VERTEX ARRAY BUFFER BINDING GetIntegerv
+   NORMAL ARRAY BUFFER BINDING GetIntegerv
+   COLOR ARRAY BUFFER BINDING GetIntegerv
+   TEXTURE COORD ARRAY BUFFER BINDING GetIntegerv
+   POINT SIZE ARRAY BUFFER BINDING OES GetIntegerv
+   MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES GetIntegerv
+   WEIGHT_ARRAY_BUFFER_BINDING_OES GetIntegerv
+
+   UNPACK ALIGNMENT GetIntegerv
+   PACK ALIGNMENT GetIntegerv
+*/
+
+static int get_integer_internal_11(CLIENT_THREAD_STATE_T *thread, GLenum pname, GLint *params)
+{
+   GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+   vcos_assert(state != NULL);
+
+   switch (pname) {
+   case GL_CLIENT_ACTIVE_TEXTURE:
+      params[0] = (GLint) state->active_texture.client;
+      return 1;
+   case GL_VERTEX_ARRAY_SIZE:
+      params[0] = (GLint) state->attrib[GL11_IX_VERTEX].size;
+      return 1;
+   case GL_VERTEX_ARRAY_TYPE:
+      params[0] = (GLint) state->attrib[GL11_IX_VERTEX].type;
+      return 1;
+   case GL_VERTEX_ARRAY_STRIDE:
+      params[0] = (GLint) state->attrib[GL11_IX_VERTEX].stride;
+      return 1;
+   case GL_NORMAL_ARRAY_TYPE:
+      params[0] = (GLint) state->attrib[GL11_IX_NORMAL].type;
+      return 1;
+   case GL_NORMAL_ARRAY_STRIDE:
+      params[0] = (GLint) state->attrib[GL11_IX_NORMAL].stride;
+      return 1;
+   case GL_COLOR_ARRAY_SIZE:
+      params[0] = (GLint) state->attrib[GL11_IX_COLOR].size;
+      return 1;
+   case GL_COLOR_ARRAY_TYPE:
+      params[0] = (GLint) state->attrib[GL11_IX_COLOR].type;
+      return 1;
+   case GL_COLOR_ARRAY_STRIDE:
+      params[0] = (GLint) state->attrib[GL11_IX_COLOR].stride;
+      return 1;
+   case GL_TEXTURE_COORD_ARRAY_SIZE:
+      params[0] = (GLint) state->attrib[state->active_texture.client - GL_TEXTURE0 + GL11_IX_TEXTURE_COORD].size;
+      return 1;
+   case GL_TEXTURE_COORD_ARRAY_TYPE:
+      params[0] = (GLint) state->attrib[state->active_texture.client - GL_TEXTURE0 + GL11_IX_TEXTURE_COORD].type;
+      return 1;
+   case GL_TEXTURE_COORD_ARRAY_STRIDE:
+      params[0] = (GLint) state->attrib[state->active_texture.client - GL_TEXTURE0 + GL11_IX_TEXTURE_COORD].stride;
+      return 1;
+   case GL_POINT_SIZE_ARRAY_TYPE_OES:
+      params[0] = (GLint) state->attrib[GL11_IX_POINT_SIZE].type;
+      return 1;
+   case GL_POINT_SIZE_ARRAY_STRIDE_OES:
+      params[0] = (GLint) state->attrib[GL11_IX_POINT_SIZE].stride;
+      return 1;
+   case GL_MATRIX_INDEX_ARRAY_SIZE_OES:
+      params[0] = (GLint) state->attrib[GL11_IX_MATRIX_INDEX].size;
+      return 1;
+   case GL_MATRIX_INDEX_ARRAY_TYPE_OES:
+      params[0] = (GLint) state->attrib[GL11_IX_MATRIX_INDEX].type;
+      return 1;
+   case GL_MATRIX_INDEX_ARRAY_STRIDE_OES:
+      params[0] = (GLint) state->attrib[GL11_IX_MATRIX_INDEX].stride;
+      return 1;
+   case GL_WEIGHT_ARRAY_SIZE_OES:
+      params[0] = (GLint) state->attrib[GL11_IX_MATRIX_WEIGHT].size;
+      return 1;
+   case GL_WEIGHT_ARRAY_TYPE_OES:
+      params[0] = (GLint) state->attrib[GL11_IX_MATRIX_WEIGHT].type;
+      return 1;
+   case GL_WEIGHT_ARRAY_STRIDE_OES:
+      params[0] = (GLint) state->attrib[GL11_IX_MATRIX_WEIGHT].stride;
+      return 1;
+   case GL_ARRAY_BUFFER_BINDING:
+      params[0] = (GLint) state->bound_buffer.array;
+      return 1;
+   case GL_ELEMENT_ARRAY_BUFFER_BINDING:
+      params[0] = (GLint) state->bound_buffer.element_array;
+      return 1;
+   case GL_VERTEX_ARRAY_BUFFER_BINDING:
+      params[0] = (GLint) state->attrib[GL11_IX_VERTEX].buffer;
+      return 1;
+   case GL_NORMAL_ARRAY_BUFFER_BINDING:
+      params[0] = (GLint) state->attrib[GL11_IX_NORMAL].buffer;
+      return 1;
+   case GL_COLOR_ARRAY_BUFFER_BINDING:
+      params[0] = (GLint) state->attrib[GL11_IX_COLOR].buffer;
+      return 1;
+   case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING:
+      /*
+      TODO is this right?
+      Most texture state variables are qualified by the value of ACTIVE TEXTURE
+to determine which server texture state vector is queried. Client texture
+state variables such as texture coordinate array pointers are qualified by the
+value of CLIENT ACTIVE TEXTURE. Tables 6.3, 6.4, 6.7, 6.13, 6.15, and 6.21
+indicate those state variables which are qualified by ACTIVE TEXTURE or
+CLIENT ACTIVE TEXTURE during state queries
+      */
+      params[0] = (GLint) state->attrib[state->active_texture.client - GL_TEXTURE0 + GL11_IX_TEXTURE_COORD].buffer;
+      return 1;
+   case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES:
+      params[0] = (GLint) state->attrib[GL11_IX_POINT_SIZE].buffer;
+      return 1;
+   case GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES:
+      params[0] = (GLint) state->attrib[GL11_IX_MATRIX_INDEX].buffer;
+      return 1;
+   case GL_WEIGHT_ARRAY_BUFFER_BINDING_OES:
+      params[0] = (GLint) state->attrib[GL11_IX_MATRIX_WEIGHT].buffer;
+      return 1;
+
+   case GL_UNPACK_ALIGNMENT:
+      params[0] = (GLint) state->alignment.unpack;
+      return 1;
+   case GL_PACK_ALIGNMENT:
+      params[0] = (GLint) state->alignment.pack;
+      return 1;
+
+   //TODO: these are horrible and don't make any sense
+   //Is this a sensible thing to return?
+   case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES:
+      params[0] = (GLint) GL_UNSIGNED_BYTE;
+      return 1;
+   case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES:
+      params[0] = (GLint) GL_RGBA;
+      return 1;
+   //end TODO
+
+   default:
+      UNREACHABLE();
+      break;
+   }
+
+   return 0;
+}
+
+static int get_integer_internal_20(CLIENT_THREAD_STATE_T *thread, GLenum pname, GLint *params)
+{
+   GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+   vcos_assert(state != NULL);
+
+   switch (pname) {
+   case GL_UNPACK_ALIGNMENT:
+      params[0] = state->alignment.unpack;
+      return 1;
+   case GL_PACK_ALIGNMENT:
+      params[0] = state->alignment.pack;
+      return 1;
+   default:
+      UNREACHABLE();
+      break;
+   }
+
+   return 0;
+}
+
+GL_API void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      switch (pname) {
+      case GL_VERTEX_ARRAY:
+      case GL_NORMAL_ARRAY:
+      case GL_COLOR_ARRAY:
+      case GL_TEXTURE_COORD_ARRAY:
+      case GL_POINT_SIZE_ARRAY_OES:
+         get_boolean_internal_11(thread, pname, params);
+         break;
+      case GL_CLIENT_ACTIVE_TEXTURE:
+      case GL_VERTEX_ARRAY_SIZE:
+      case GL_VERTEX_ARRAY_TYPE:
+      case GL_VERTEX_ARRAY_STRIDE:
+      case GL_NORMAL_ARRAY_TYPE:
+      case GL_NORMAL_ARRAY_STRIDE:
+      case GL_COLOR_ARRAY_SIZE:
+      case GL_COLOR_ARRAY_TYPE:
+      case GL_COLOR_ARRAY_STRIDE:
+      case GL_TEXTURE_COORD_ARRAY_SIZE:
+      case GL_TEXTURE_COORD_ARRAY_TYPE:
+      case GL_TEXTURE_COORD_ARRAY_STRIDE:
+      case GL_POINT_SIZE_ARRAY_TYPE_OES:
+      case GL_POINT_SIZE_ARRAY_STRIDE_OES:
+      case GL_ARRAY_BUFFER_BINDING:
+      case GL_ELEMENT_ARRAY_BUFFER_BINDING:
+      case GL_VERTEX_ARRAY_BUFFER_BINDING:
+      case GL_NORMAL_ARRAY_BUFFER_BINDING:
+      case GL_COLOR_ARRAY_BUFFER_BINDING:
+      case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING:
+      case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES:
+      case GL_UNPACK_ALIGNMENT:
+      case GL_PACK_ALIGNMENT:
+      case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES:
+      case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES:
+      {
+         GLint temp;
+
+         get_integer_internal_11(thread, pname, &temp);
+
+         params[0] = temp != 0;
+         break;
+      }
+      case GL_CURRENT_TEXTURE_COORDS:
+      case GL_CURRENT_COLOR:
+      case GL_CURRENT_NORMAL:
+      case GL_POINT_SIZE:
+      {
+         GLfloat temp[4];
+         GLuint count = (GLuint) get_float_internal_11(thread, pname, temp);
+         GLuint i;
+
+         vcos_assert(count <= 4);
+
+         for (i = 0; i < count; i++)
+            params[i] = temp[i] != 0.0f;
+
+         break;
+      }
+      default:
+         RPC_CALL2_OUT_CTRL(glGetBooleanv_impl,
+                            thread,
+                            GLGETBOOLEANV_ID,
+                            RPC_ENUM(pname),
+                            params);
+         break;
+      }
+   }
+
+   if (IS_OPENGLES_20(thread)) {
+      switch (pname) {
+      case GL_UNPACK_ALIGNMENT:
+      case GL_PACK_ALIGNMENT:
+      {
+         GLint temp = 0;
+
+         get_integer_internal_20(thread, pname, &temp);
+
+         params[0] = temp != 0;
+         break;
+      }
+      default:
+         RPC_CALL2_OUT_CTRL(glGetBooleanv_impl,
+                            thread,
+                            GLGETBOOLEANV_ID,
+                            RPC_ENUM(pname),
+                            params);
+         break;
+      }
+
+   }
+}
+
+GL_API void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      switch(pname) {
+      case GL_BUFFER_ACCESS_OES:
+      {
+         GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+         if(get_bound_buffer(state, target) != 0)
+         {
+            params[0] = GL_WRITE_ONLY_OES;
+         }
+         else
+         {
+            params[0] = 0;
+         }
+         break;
+      }
+      case GL_BUFFER_MAPPED_OES:
+      {
+         GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+         GLXX_BUFFER_INFO_T buffer;
+         glxx_buffer_info_get(state, target, &buffer);
+         if(buffer.id != 0 && buffer.mapped_pointer != 0)
+         {
+            params[0] = GL_TRUE;
+         }
+         else
+         {
+            params[0] = GL_FALSE;
+         }
+         break;
+      }
+      default:
+         RPC_CALL3_OUT_CTRL(glGetBufferParameteriv_impl,
+                            thread,
+                            GLGETBUFFERPARAMETERIV_ID,
+                            RPC_ENUM(target),
+                            RPC_ENUM(pname),
+                            params);
+
+         if(pname == GL_BUFFER_SIZE)
+         {
+            GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+            GLXX_BUFFER_INFO_T buffer;
+            buffer.cached_size = params[0];
+            glxx_buffer_info_set(state, target, &buffer);
+         }
+      }
+   }
+}
+
+GL_API void GL_APIENTRY glGetClipPlanef (GLenum pname, GLfloat eqn[4])
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL2_OUT_CTRL(glGetClipPlanef_impl_11,
+                         thread,
+                         GLGETCLIPPLANEF_ID_11,
+                         RPC_ENUM(pname),
+                         eqn);
+   }
+}
+
+GL_API void GL_APIENTRY glGetClipPlanex (GLenum pname, GLfixed eqn[4])
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL2_OUT_CTRL(glGetClipPlanex_impl_11,
+                         thread,
+                         GLGETCLIPPLANEX_ID_11,
+                         RPC_ENUM(pname),
+                         eqn);
+   }
+}
+
+GL_API GLenum GL_APIENTRY glGetError (void)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE(); /* Decrements glgeterror_hack variable for every API call made */
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+      GLenum result = state->error;
+
+      if ((result == GL_NO_ERROR) && !thread->async_error_notification) {
+         /* Don't query the server if our previous API call was glGetError() */
+         if (0 == thread->glgeterror_hack ) {
+            result = RPC_ENUM_RES(RPC_CALL0_RES(glGetError_impl,
+                                                thread,
+                                                GLGETERROR_ID));
+         }
+
+         if(result != GL_NO_ERROR) {
+            vcos_log_warn("glGetError 0x%x", result);
+            thread->glgeterror_hack = 0;
+         } else {
+            thread->glgeterror_hack = 2;
+         }
+      }
+      state->error = GL_NO_ERROR;
+
+      return result;
+   }
+
+   return 0;
+}
+
+GL_API void GL_APIENTRY glGetFixedv (GLenum pname, GLfixed *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      switch (pname) {
+      case GL_VERTEX_ARRAY:
+      case GL_NORMAL_ARRAY:
+      case GL_COLOR_ARRAY:
+      case GL_TEXTURE_COORD_ARRAY:
+      case GL_POINT_SIZE_ARRAY_OES:
+      {
+         GLboolean temp[4];
+
+         int count = get_boolean_internal_11(thread, pname, temp);
+         int i;
+
+         vcos_assert(count <= 4);
+
+         for (i = 0; i < count; i++)
+            params[i] = temp[i] ? (GLfixed)float_to_fixed(1.0f) : (GLfixed)float_to_fixed(0.0f);
+
+         break;
+      }
+      case GL_CURRENT_TEXTURE_COORDS:
+      case GL_CURRENT_COLOR:
+      case GL_CURRENT_NORMAL:
+      case GL_POINT_SIZE:
+      {
+         GLfloat temp[4];
+
+         int count = get_float_internal_11(thread, pname, temp);
+         int i;
+
+         vcos_assert(count <= 4);
+
+         for (i = 0; i < count; i++)
+            params[i] = (GLfixed) float_to_fixed(temp[i]);
+
+         break;
+      }
+      case GL_CLIENT_ACTIVE_TEXTURE:
+      case GL_VERTEX_ARRAY_SIZE:
+      case GL_VERTEX_ARRAY_TYPE:
+      case GL_VERTEX_ARRAY_STRIDE:
+      case GL_NORMAL_ARRAY_TYPE:
+      case GL_NORMAL_ARRAY_STRIDE:
+      case GL_COLOR_ARRAY_SIZE:
+      case GL_COLOR_ARRAY_TYPE:
+      case GL_COLOR_ARRAY_STRIDE:
+      case GL_TEXTURE_COORD_ARRAY_SIZE:
+      case GL_TEXTURE_COORD_ARRAY_TYPE:
+      case GL_TEXTURE_COORD_ARRAY_STRIDE:
+      case GL_POINT_SIZE_ARRAY_TYPE_OES:
+      case GL_POINT_SIZE_ARRAY_STRIDE_OES:
+      case GL_ARRAY_BUFFER_BINDING:
+      case GL_ELEMENT_ARRAY_BUFFER_BINDING:
+      case GL_VERTEX_ARRAY_BUFFER_BINDING:
+      case GL_NORMAL_ARRAY_BUFFER_BINDING:
+      case GL_COLOR_ARRAY_BUFFER_BINDING:
+      case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING:
+      case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES:
+      case GL_UNPACK_ALIGNMENT:
+      case GL_PACK_ALIGNMENT:
+      case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES:
+      case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES:
+      {
+         GLint temp;
+
+         get_integer_internal_11(thread, pname, &temp);
+
+         params[0] = (GLfixed) float_to_fixed((GLfloat)temp);
+         break;
+      }
+      default:
+         RPC_CALL2_OUT_CTRL(glGetFixedv_impl_11,
+                            thread,
+                            GLGETFIXEDV_ID_11,
+                            RPC_ENUM(pname),
+                            params);
+         break;
+      }
+   }
+}
+
+GL_API void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      switch (pname) {
+      case GL_VERTEX_ARRAY:
+      case GL_NORMAL_ARRAY:
+      case GL_COLOR_ARRAY:
+      case GL_TEXTURE_COORD_ARRAY:
+      case GL_POINT_SIZE_ARRAY_OES:
+      {
+         GLboolean temp[4];
+         GLuint count = (GLuint) get_boolean_internal_11(thread, pname, temp);
+         GLuint i;
+
+         vcos_assert(count <= 4);
+
+         for (i = 0; i < count; i++)
+            params[i] = temp[i] ? 1.0f : 0.0f;
+
+         break;
+      }
+      case GL_CURRENT_TEXTURE_COORDS:
+      case GL_CURRENT_COLOR:
+      case GL_CURRENT_NORMAL:
+      case GL_POINT_SIZE:
+         get_float_internal_11(thread, pname, params);
+
+         break;
+      case GL_CLIENT_ACTIVE_TEXTURE:
+      case GL_VERTEX_ARRAY_SIZE:
+      case GL_VERTEX_ARRAY_TYPE:
+      case GL_VERTEX_ARRAY_STRIDE:
+      case GL_NORMAL_ARRAY_TYPE:
+      case GL_NORMAL_ARRAY_STRIDE:
+      case GL_COLOR_ARRAY_SIZE:
+      case GL_COLOR_ARRAY_TYPE:
+      case GL_COLOR_ARRAY_STRIDE:
+      case GL_TEXTURE_COORD_ARRAY_SIZE:
+      case GL_TEXTURE_COORD_ARRAY_TYPE:
+      case GL_TEXTURE_COORD_ARRAY_STRIDE:
+      case GL_POINT_SIZE_ARRAY_TYPE_OES:
+      case GL_POINT_SIZE_ARRAY_STRIDE_OES:
+      case GL_ARRAY_BUFFER_BINDING:
+      case GL_ELEMENT_ARRAY_BUFFER_BINDING:
+      case GL_VERTEX_ARRAY_BUFFER_BINDING:
+      case GL_NORMAL_ARRAY_BUFFER_BINDING:
+      case GL_COLOR_ARRAY_BUFFER_BINDING:
+      case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING:
+      case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES:
+      case GL_UNPACK_ALIGNMENT:
+      case GL_PACK_ALIGNMENT:
+      case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES:
+      case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES:
+      {
+         GLint temp;
+
+         get_integer_internal_11(thread, pname, &temp);
+
+         params[0] = (GLfloat)temp;
+         break;
+      }
+      default:
+         RPC_CALL2_OUT_CTRL(glGetFloatv_impl,
+                            thread,
+                            GLGETFLOATV_ID,
+                            RPC_ENUM(pname),
+                            params);
+         break;
+      }
+   }
+   else if (IS_OPENGLES_20(thread)) {
+      switch (pname) {
+      case GL_UNPACK_ALIGNMENT:
+      case GL_PACK_ALIGNMENT:
+      {
+         GLint temp = 0;
+
+         get_integer_internal_20(thread, pname, &temp);
+
+         params[0] = (GLfloat)temp;
+         break;
+      }
+      default:
+         RPC_CALL2_OUT_CTRL(glGetFloatv_impl,
+                            thread,
+                            GLGETFLOATV_ID,
+                            RPC_ENUM(pname),
+                            params);
+         break;
+      }
+   }
+}
+
+GL_API void GL_APIENTRY glGetIntegerv (GLenum pname, GLint *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      switch (pname) {
+      case GL_VERTEX_ARRAY:
+      case GL_NORMAL_ARRAY:
+      case GL_COLOR_ARRAY:
+      case GL_TEXTURE_COORD_ARRAY:
+      case GL_POINT_SIZE_ARRAY_OES:
+      {
+         GLboolean temp[4];
+         GLuint count = (GLuint) get_boolean_internal_11(thread, pname, temp);
+         GLuint i;
+
+         vcos_assert(count <= 4);
+
+         for (i = 0; i < count; i++)
+            params[i] = temp[i] ? 1 : 0;
+
+         break;
+      }
+      case GL_CURRENT_COLOR:
+      case GL_CURRENT_NORMAL:
+      {
+         GLfloat temp[4];
+         GLuint count = (GLuint) get_float_internal_11(thread, pname, temp);
+         GLuint i;
+
+         vcos_assert(count <= 4);
+
+         for (i = 0; i < count; i++)
+            params[i] = (GLint)floor((4294967295.0f * temp[i] - 1.0f) / 2.0f + 0.5f);
+
+         //TODO: that the above is correct wrt table 2.7 in the GL spec
+
+         break;
+      }
+      case GL_CURRENT_TEXTURE_COORDS:
+      case GL_POINT_SIZE:
+      {
+         GLfloat temp[4];
+         GLuint count = (GLuint) get_float_internal_11(thread, pname, temp);
+         GLuint i;
+
+         vcos_assert(count <= 4);
+
+         for (i = 0; i < count; i++)
+            params[i] = (GLint) float_to_int(temp[i]);
+
+         break;
+      }
+      case GL_CLIENT_ACTIVE_TEXTURE:
+      case GL_VERTEX_ARRAY_SIZE:
+      case GL_VERTEX_ARRAY_TYPE:
+      case GL_VERTEX_ARRAY_STRIDE:
+      case GL_NORMAL_ARRAY_TYPE:
+      case GL_NORMAL_ARRAY_STRIDE:
+      case GL_COLOR_ARRAY_SIZE:
+      case GL_COLOR_ARRAY_TYPE:
+      case GL_COLOR_ARRAY_STRIDE:
+      case GL_TEXTURE_COORD_ARRAY_SIZE:
+      case GL_TEXTURE_COORD_ARRAY_TYPE:
+      case GL_TEXTURE_COORD_ARRAY_STRIDE:
+      case GL_POINT_SIZE_ARRAY_TYPE_OES:
+      case GL_POINT_SIZE_ARRAY_STRIDE_OES:
+      case GL_MATRIX_INDEX_ARRAY_SIZE_OES:
+      case GL_MATRIX_INDEX_ARRAY_TYPE_OES:
+      case GL_MATRIX_INDEX_ARRAY_STRIDE_OES:
+      case GL_WEIGHT_ARRAY_SIZE_OES:
+      case GL_WEIGHT_ARRAY_TYPE_OES:
+      case GL_WEIGHT_ARRAY_STRIDE_OES:
+      case GL_ARRAY_BUFFER_BINDING:
+      case GL_ELEMENT_ARRAY_BUFFER_BINDING:
+      case GL_VERTEX_ARRAY_BUFFER_BINDING:
+      case GL_NORMAL_ARRAY_BUFFER_BINDING:
+      case GL_COLOR_ARRAY_BUFFER_BINDING:
+      case GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING:
+      case GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES:
+      case GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES:
+      case GL_WEIGHT_ARRAY_BUFFER_BINDING_OES:
+      case GL_UNPACK_ALIGNMENT:
+      case GL_PACK_ALIGNMENT:
+      case GL_IMPLEMENTATION_COLOR_READ_TYPE_OES:
+      case GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES:
+         get_integer_internal_11(thread, pname, params);
+         break;
+      default:
+         RPC_CALL2_OUT_CTRL(glGetIntegerv_impl,
+                            thread,
+                            GLGETINTEGERV_ID,
+                            RPC_ENUM(pname),
+                            params);
+         break;
+      }
+   }
+   else if (IS_OPENGLES_20(thread)) {
+      switch (pname) {
+      case GL_UNPACK_ALIGNMENT:
+      case GL_PACK_ALIGNMENT:
+         get_integer_internal_20(thread, pname, params);
+         break;
+      default:
+         RPC_CALL2_OUT_CTRL(glGetIntegerv_impl,
+                            thread,
+                            GLGETINTEGERV_ID,
+                            RPC_ENUM(pname),
+                            params);
+         break;
+      }
+   }
+}
+
+GL_API void GL_APIENTRY glGetLightfv (GLenum light, GLenum pname, GLfloat *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL3_OUT_CTRL(glGetLightfv_impl_11,
+                         thread,
+                         GLGETLIGHTFV_ID_11,
+                         RPC_ENUM(light),
+                         RPC_ENUM(pname),
+                         params);
+   }
+}
+
+GL_API void GL_APIENTRY glGetLightxv (GLenum light, GLenum pname, GLfixed *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL3_OUT_CTRL(glGetLightxv_impl_11,
+                         thread,
+                         GLGETLIGHTXV_ID_11,
+                         RPC_ENUM(light),
+                         RPC_ENUM(pname),
+                         params);
+   }
+}
+
+GL_API void GL_APIENTRY glGetMaterialfv (GLenum face, GLenum pname, GLfloat *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL3_OUT_CTRL(glGetMaterialfv_impl_11,
+                         thread,
+                         GLGETMATERIALFV_ID_11,
+                         RPC_ENUM(face),
+                         RPC_ENUM(pname),
+                         params);
+   }
+}
+
+GL_API void GL_APIENTRY glGetMaterialxv (GLenum face, GLenum pname, GLfixed *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL3_OUT_CTRL(glGetMaterialxv_impl_11,
+                         thread,
+                         GLGETMATERIALXV_ID_11,
+                         RPC_ENUM(face),
+                         RPC_ENUM(pname),
+                         params);
+   }
+}
+
+/*
+   VERTEX ARRAY POINTER GetPointerv
+   NORMAL ARRAY POINTER GetPointerv
+   COLOR ARRAY POINTER GetPointerv
+   TEXTURE COORD ARRAY POINTER GetPointerv
+   POINT SIZE ARRAY POINTER OES GetPointerv
+   MATRIX_INDEX_ARRAY_POINTER_OES GetPointerv
+   WEIGHT_ARRAY_POINTER_OES GetPointerv
+*/
+
+GL_API void GL_APIENTRY glGetPointerv (GLenum pname, GLvoid **params)
+{
+   void *result = NULL;
+
+   switch (pname) {
+   case GL_VERTEX_ARRAY_POINTER:
+      result = glintAttribGetPointer(GLXX_API_11, GL11_IX_VERTEX);
+      break;
+   case GL_NORMAL_ARRAY_POINTER:
+      result = glintAttribGetPointer(GLXX_API_11, GL11_IX_NORMAL);
+      break;
+   case GL_COLOR_ARRAY_POINTER:
+      result = glintAttribGetPointer(GLXX_API_11, GL11_IX_COLOR);
+      break;
+   case GL_TEXTURE_COORD_ARRAY_POINTER:
+      result = glintAttribGetPointer(GLXX_API_11, GL11_IX_CLIENT_ACTIVE_TEXTURE);
+      break;
+   case GL_POINT_SIZE_ARRAY_POINTER_OES:
+      result = glintAttribGetPointer(GLXX_API_11, GL11_IX_POINT_SIZE);
+      break;
+#if GL_OES_matrix_palette
+   case GL_MATRIX_INDEX_ARRAY_POINTER_OES:
+      result = glintAttribGetPointer(GLXX_API_11, GL11_IX_MATRIX_INDEX);
+      break;
+   case GL_WEIGHT_ARRAY_POINTER_OES:
+      result = glintAttribGetPointer(GLXX_API_11, GL11_IX_MATRIX_WEIGHT);
+      break;
+#endif
+   default:
+      glxx_set_error_api(GLXX_API_11, GL_INVALID_ENUM);
+      break;
+   }
+
+   if (result != NULL)
+      params[0] = result;
+}
+
+GL_APICALL void GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL3_OUT_CTRL(glGetProgramiv_impl_20,
+                         thread,
+                         GLGETPROGRAMIV_ID_20,
+                         RPC_UINT(program),
+                         RPC_ENUM(pname),
+                         params);
+   }
+}
+
+GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei *length, char *infolog)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+#ifdef RPC_DIRECT
+      RPC_CALL4(glGetProgramInfoLog_impl_20, thread, no_id, program, bufsize, length, infolog);
+#else
+      GLuint result[1];
+
+      rpc_begin(thread);
+
+      RPC_CALL3_OUT_CTRL(no_function,
+                         thread,
+                         GLGETPROGRAMINFOLOG_ID_20,
+                         RPC_UINT(program),
+                         RPC_SIZEI(bufsize),
+                         result);
+
+      if (length)
+         *length = (GLsizei)result[0];
+
+      read_out_bulk(thread, infolog);
+
+      rpc_end(thread);
+#endif
+   }
+}
+
+GL_API const GLubyte * GL_APIENTRY glGetString (GLenum name)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+      vcos_assert(state != NULL);
+
+      switch (name) {
+      case GL_VENDOR:
+#ifndef NDEBUG
+         return (const GLubyte *)"Broadcom DEBUG";
+#else
+         return (const GLubyte *)"Broadcom";
+#endif
+      case GL_RENDERER:
+         return (const GLubyte *)"VideoCore IV HW";
+      case GL_VERSION:
+         return (const GLubyte *)"OpenGL ES-CM 1.1";
+      case GL_EXTENSIONS:
+         return (const GLubyte *)"GL_OES_compressed_ETC1_RGB8_texture "
+                                 "GL_OES_compressed_paletted_texture "
+                                 "GL_OES_texture_npot "  /*TODO is npot right? I can't find it in glext.h */
+                                 "GL_OES_EGL_image "
+                                 "GL_OES_EGL_image_external "
+                                 "GL_EXT_discard_framebuffer "
+                                 "GL_OES_query_matrix "
+                                 "GL_OES_framebuffer_object "
+                                 "GL_OES_rgb8_rgba8 "
+                                 "GL_OES_depth24 "
+                                 "GL_OES_depth32 "
+                                 "GL_OES_stencil8 "
+                                 "GL_OES_draw_texture "
+                                 "GL_OES_mapbuffer "
+#if GL_EXT_texture_format_BGRA8888
+                                 "GL_EXT_texture_format_BGRA8888 "
+#endif
+#if GL_APPLE_rgb_422
+                                 "GL_APPLE_rgb_422 "
+#endif
+#if GL_OES_matrix_palette
+                                 "GL_OES_matrix_palette "
+#endif
+#ifdef GL_EXT_debug_marker
+                                 "GL_EXT_debug_marker "
+#endif
+                                 ;
+      default:
+         set_error(state, GL_INVALID_ENUM);
+         return NULL;
+      }
+   }
+   else if (IS_OPENGLES_20(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+      vcos_assert(state != NULL);
+
+      switch (name) {
+      case GL_VENDOR:
+#ifndef NDEBUG
+         return (const GLubyte *)"Broadcom DEBUG";
+#else
+         return (const GLubyte *)"Broadcom";
+#endif
+      case GL_RENDERER:
+         return (const GLubyte *)"VideoCore IV HW";
+      case GL_VERSION:
+         return (const GLubyte *)"OpenGL ES 2.0";
+      case GL_SHADING_LANGUAGE_VERSION:
+         return (const GLubyte *)"OpenGL ES GLSL ES 1.00";
+      case GL_EXTENSIONS:
+         return (const GLubyte *)"GL_OES_compressed_ETC1_RGB8_texture "
+                                 "GL_OES_compressed_paletted_texture "
+                                 "GL_OES_texture_npot "
+                                 "GL_OES_depth24 "
+                                 "GL_OES_vertex_half_float "
+                                 "GL_OES_EGL_image "
+                                 "GL_OES_EGL_image_external "
+                                 "GL_EXT_discard_framebuffer "
+                                 "GL_OES_rgb8_rgba8 "
+                                 "GL_OES_depth32 "
+                                 "GL_OES_mapbuffer "
+#if GL_EXT_texture_format_BGRA8888
+                                 "GL_EXT_texture_format_BGRA8888 "
+#endif
+#if GL_APPLE_rgb_422
+                                 "GL_APPLE_rgb_422 "
+#endif
+#ifdef GL_EXT_debug_marker
+                                 "GL_EXT_debug_marker "
+#endif
+                                 ;
+      default:
+         set_error(state, GL_INVALID_ENUM);
+         return NULL;
+      }
+   }
+
+   return NULL;
+}
+
+GL_API void GL_APIENTRY glGetTexEnviv (GLenum env, GLenum pname, GLint *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL3_OUT_CTRL(glGetTexEnviv_impl_11,
+                         thread,
+                         GLGETTEXENVIV_ID_11,
+                         RPC_ENUM(env),
+                         RPC_ENUM(pname),
+                         params);
+   }
+}
+
+GL_API void GL_APIENTRY glGetTexEnvfv (GLenum env, GLenum pname, GLfloat *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL3_OUT_CTRL(glGetTexEnvfv_impl_11,
+                         thread,
+                         GLGETTEXENVFV_ID_11,
+                         RPC_ENUM(env),
+                         RPC_ENUM(pname),
+                         params);
+   }
+}
+
+GL_API void GL_APIENTRY glGetTexEnvxv (GLenum env, GLenum pname, GLfixed *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL3_OUT_CTRL(glGetTexEnvxv_impl_11,
+                         thread,
+                         GLGETTEXENVXV_ID_11,
+                         RPC_ENUM(env),
+                         RPC_ENUM(pname),
+                         params);
+   }
+}
+
+GL_API void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL3_OUT_CTRL(glGetTexParameteriv_impl,
+                         thread,
+                         GLGETTEXPARAMETERIV_ID,
+                         RPC_ENUM(target),
+                         RPC_ENUM(pname),
+                         params);
+   }
+}
+
+GL_API void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL3_OUT_CTRL(glGetTexParameterfv_impl,
+                         thread,
+                         GLGETTEXPARAMETERFV_ID,
+                         RPC_ENUM(target),
+                         RPC_ENUM(pname),
+                         params);
+   }
+}
+
+GL_API void GL_APIENTRY glGetTexParameterxv (GLenum target, GLenum pname, GLfixed *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL3_OUT_CTRL(glGetTexParameterxv_impl_11,
+                         thread,
+                         GLGETTEXPARAMETERXV_ID_11,
+                         RPC_ENUM(target),
+                         RPC_ENUM(pname),
+                         params);
+   }
+}
+
+GL_APICALL void GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL3_OUT_CTRL(glGetUniformfv_impl_20,
+                         thread,
+                         GLGETUNIFORMFV_ID_20,
+                         RPC_UINT(program),
+                         RPC_INT(location),
+                         params);
+   }
+}
+
+GL_APICALL void GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL3_OUT_CTRL(glGetUniformiv_impl_20,
+                         thread,
+                         GLGETUNIFORMIV_ID_20,
+                         RPC_UINT(program),
+                         RPC_INT(location),
+                         params);
+   }
+}
+
+GL_APICALL int GL_APIENTRY glGetUniformLocation (GLuint program, const char *name)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      return RPC_INT_RES(RPC_CALL2_IN_BULK_RES(glGetUniformLocation_impl_20,
+                                               thread,
+                                               GLGETUNIFORMLOCATION_ID_20,
+                                               RPC_UINT(program),
+                                               name,
+                                               strlen(name) + 1));
+   }
+
+   return 0;
+}
+
+/*
+   GetVertexAttrib
+
+   VERTEX ATTRIB ARRAY ENABLED False GetVertexAttrib
+   VERTEX ATTRIB ARRAY SIZE 4 GetVertexAttrib
+   VERTEX ATTRIB ARRAY STRIDE 0 GetVertexAttrib
+   VERTEX ATTRIB ARRAY TYPE FLOAT GetVertexAttrib
+   VERTEX ATTRIB ARRAY NORMALIZED False GetVertexAttrib
+   VERTEX ATTRIB ARRAY BUFFER BINDING 0 GetVertexAttrib
+
+   CURRENT VERTEX ATTRIB 0,0,0,1 GetVertexAttributes
+*/
+
+GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+      vcos_assert(state != NULL);
+
+      if (index < GL20_CONFIG_MAX_VERTEX_ATTRIBS)
+         switch (pname) {
+         case GL_CURRENT_VERTEX_ATTRIB:
+            params[0] = state->attrib[index].value[0];
+            params[1] = state->attrib[index].value[1];
+            params[2] = state->attrib[index].value[2];
+            params[3] = state->attrib[index].value[3];
+            break;
+
+         //TODO: is this the best way to handle conversions? We duplicate
+         //the entire switch statement.
+         case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
+            params[0] = state->attrib[index].enabled ? 1.0f : 0.0f;
+            break;
+         case GL_VERTEX_ATTRIB_ARRAY_SIZE:
+            params[0] = (GLfloat)state->attrib[index].size;
+            break;
+         case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
+            params[0] = (GLfloat)state->attrib[index].stride;
+            break;
+         case GL_VERTEX_ATTRIB_ARRAY_TYPE:
+            params[0] = (GLfloat)state->attrib[index].type;
+            break;
+         case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
+            params[0] = state->attrib[index].normalized ? 1.0f : 0.0f;
+            break;
+         case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
+            params[0] = (GLfloat)state->attrib[index].buffer;
+            break;
+
+
+
+         default:
+            set_error(state, GL_INVALID_ENUM);
+            break;
+         }
+      else
+         set_error(state, GL_INVALID_VALUE);
+   }
+}
+
+GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+      vcos_assert(state != NULL);
+
+      if (index < GL20_CONFIG_MAX_VERTEX_ATTRIBS)
+         switch (pname) {
+         case GL_VERTEX_ATTRIB_ARRAY_ENABLED:
+            params[0] = (GLint) state->attrib[index].enabled ? GL_TRUE : GL_FALSE;
+            break;
+         case GL_VERTEX_ATTRIB_ARRAY_SIZE:
+            params[0] = (GLint) state->attrib[index].size;
+            break;
+         case GL_VERTEX_ATTRIB_ARRAY_STRIDE:
+            params[0] = (GLint) state->attrib[index].stride;
+            break;
+         case GL_VERTEX_ATTRIB_ARRAY_TYPE:
+            params[0] = (GLint) state->attrib[index].type;
+            break;
+         case GL_VERTEX_ATTRIB_ARRAY_NORMALIZED:
+            params[0] = (GLint) state->attrib[index].normalized ? GL_TRUE : GL_FALSE;
+            break;
+         case GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING:
+            params[0] = (GLint) state->attrib[index].buffer;
+            break;
+
+
+         //TODO: is this the best way to handle conversions? We duplicate
+         //the entire switch statement.
+         case GL_CURRENT_VERTEX_ATTRIB:
+            params[0] = (GLint)state->attrib[index].value[0];
+            params[1] = (GLint)state->attrib[index].value[1];
+            params[2] = (GLint)state->attrib[index].value[2];
+            params[3] = (GLint)state->attrib[index].value[3];
+            break;
+
+         default:
+            set_error(state, GL_INVALID_ENUM);
+            break;
+         }
+      else
+         set_error(state, GL_INVALID_VALUE);
+   }
+}
+
+/*
+   GetVertexAttribPointer
+
+   VERTEX ATTRIB ARRAY POINTER NULL GetVertexAttribPointer
+*/
+
+GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void **pointer)
+{
+   void *result = NULL;
+
+   if (pname == GL_VERTEX_ATTRIB_ARRAY_POINTER)
+      result = glintAttribGetPointer(GLXX_API_20, index);
+   else
+      glxx_set_error_api(GLXX_API_20, GL_INVALID_ENUM);
+
+   if (result != NULL)
+      *pointer = result;
+}
+
+GL_API void GL_APIENTRY glHint (GLenum target, GLenum mode)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL2(glHint_impl,
+                thread,
+                GLHINT_ID,
+                RPC_ENUM(target),
+                RPC_ENUM(mode));
+   }
+}
+
+GL_API GLboolean GL_APIENTRY glIsBuffer (GLuint buffer)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      return RPC_BOOLEAN_RES(RPC_CALL1_RES(glIsBuffer_impl,
+                                           thread,
+                                           GLISBUFFER_ID,
+                                           RPC_UINT(buffer)));
+   }
+
+   return 0;
+}
+
+GL_API GLboolean GL_APIENTRY glIsEnabled (GLenum cap)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      switch (cap) {
+      case GL_VERTEX_ARRAY:
+      case GL_NORMAL_ARRAY:
+      case GL_COLOR_ARRAY:
+      case GL_POINT_SIZE_ARRAY_OES:
+      case GL_TEXTURE_COORD_ARRAY:
+      case GL_MATRIX_INDEX_ARRAY_OES:
+      case GL_WEIGHT_ARRAY_OES:
+      {
+         GLboolean temp = 0;
+         GLuint count = (GLuint) get_boolean_internal_11(thread, cap, &temp);
+         UNUSED_NDEBUG(count);
+         vcos_assert(count == 1);
+
+         return temp;
+      }
+      default:
+         return RPC_BOOLEAN_RES(RPC_CALL1_RES(glIsEnabled_impl,
+                                              thread,
+                                              GLISENABLED_ID,
+                                              RPC_ENUM(cap)));
+      }
+   }
+   else if (IS_OPENGLES_20(thread)) {
+      return RPC_BOOLEAN_RES(RPC_CALL1_RES(glIsEnabled_impl,
+                                           thread,
+                                           GLISENABLED_ID,
+                                           RPC_ENUM(cap)));
+   }
+
+   return 0;
+}
+
+GL_API GLboolean GL_APIENTRY glIsProgram (GLuint program)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      return RPC_BOOLEAN_RES(RPC_CALL1_RES(glIsProgram_impl_20,
+                                           thread,
+                                           GLISPROGRAM_ID_20,
+                                           RPC_UINT(program)));
+   }
+
+   return 0;
+}
+
+GL_API GLboolean GL_APIENTRY glIsShader (GLuint shader)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      return RPC_BOOLEAN_RES(RPC_CALL1_RES(glIsShader_impl_20,
+                                           thread,
+                                           GLISSHADER_ID_20,
+                                           RPC_UINT(shader)));
+   }
+
+   return 0;
+}
+
+GL_API GLboolean GL_APIENTRY glIsTexture (GLuint texture)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      return RPC_BOOLEAN_RES(RPC_CALL1_RES(glIsTexture_impl,
+                                           thread,
+                                           GLISTEXTURE_ID,
+                                           RPC_UINT(texture)));
+   }
+   return 0;
+}
+
+GL_API void GL_APIENTRY glLightModelf (GLenum pname, GLfloat param)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL2(glLightModelf_impl_11,
+                thread,
+                GLLIGHTMODELF_ID_11,
+                RPC_ENUM(pname),
+                RPC_FLOAT(param));
+   }
+}
+
+GL_API void GL_APIENTRY glLightModelfv (GLenum pname, const GLfloat *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      /*
+         the only supported lighting model params are
+
+         LIGHT_MODEL_AMBIENT (4)
+         LIGHT_MODEL_TWO_SIDE (1)
+
+         so we need to transmit 4 words of parameter data
+      */
+
+      RPC_CALL2_IN_CTRL(glLightModelfv_impl_11,
+                        thread,
+                        GLLIGHTMODELFV_ID_11,
+                        RPC_ENUM(pname),
+                        params,
+                        4 * sizeof(GLfloat));
+   }
+}
+
+GL_API void GL_APIENTRY glLightModelx (GLenum pname, GLfixed param)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL2(glLightModelx_impl_11,
+                thread,
+                GLLIGHTMODELX_ID_11,
+                RPC_ENUM(pname),
+                RPC_FIXED(param));
+   }
+}
+
+GL_API void GL_APIENTRY glLightModelxv (GLenum pname, const GLfixed *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      /*
+         the only supported lighting model params are
+
+         LIGHT_MODEL_AMBIENT (4)
+         LIGHT_MODEL_TWO_SIDE (1)
+
+         so we need to transmit 4 words of parameter data
+      */
+
+      RPC_CALL2_IN_CTRL(glLightModelxv_impl_11,
+                        thread,
+                        GLLIGHTMODELXV_ID_11,
+                        RPC_ENUM(pname),
+                        params,
+                        4 * sizeof(GLfixed));
+   }
+}
+
+GL_API void GL_APIENTRY glLightf (GLenum light, GLenum pname, GLfloat param)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL3(glLightf_impl_11,
+                thread,
+                GLLIGHTF_ID_11,
+                RPC_ENUM(light),
+                RPC_ENUM(pname),
+                RPC_FLOAT(param));
+   }
+}
+
+GL_API void GL_APIENTRY glLightfv (GLenum light, GLenum pname, const GLfloat *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      /*
+         the only supported light params are
+
+         AMBIENT (4)
+         DIFFUSE (4)
+         SPECULAR (4)
+         POSITION (4)
+         SPOT_DIRECTION (3)
+         SPOT_EXPONENT (1)
+         SPOT_CUTOFF (1)
+         CONSTANT_ATTENUATION (1)
+         LINEAR_ATTENUATION (1)
+         QUADRATIC_ATTENUATION (1)
+
+         so we need to transmit 4 words of parameter data
+      */
+
+      RPC_CALL3_IN_CTRL(glLightfv_impl_11,
+                        thread,
+                        GLLIGHTFV_ID_11,
+                        RPC_ENUM(light),
+                        RPC_ENUM(pname),
+                        params,
+                        4 * sizeof(GLfloat));
+   }
+}
+
+GL_API void GL_APIENTRY glLightx (GLenum light, GLenum pname, GLfixed param)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL3(glLightx_impl_11,
+                thread,
+                GLLIGHTX_ID_11,
+                RPC_ENUM(light),
+                RPC_ENUM(pname),
+                RPC_FIXED(param));
+   }
+}
+
+GL_API void GL_APIENTRY glLightxv (GLenum light, GLenum pname, const GLfixed *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      /*
+         the only supported light params are
+
+         AMBIENT (4)
+         DIFFUSE (4)
+         SPECULAR (4)
+         POSITION (4)
+         SPOT_DIRECTION (3)
+         SPOT_EXPONENT (1)
+         SPOT_CUTOFF (1)
+         CONSTANT_ATTENUATION (1)
+         LINEAR_ATTENUATION (1)
+         QUADRATIC_ATTENUATION (1)
+
+         so we need to transmit 4 words of parameter data
+      */
+
+      RPC_CALL3_IN_CTRL(glLightxv_impl_11,
+                        thread,
+                        GLLIGHTXV_ID_11,
+                        RPC_ENUM(light),
+                        RPC_ENUM(pname),
+                        params,
+                        4 * sizeof(GLfixed));
+   }
+}
+
+GL_API void GL_APIENTRY glLineWidth (GLfloat width)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL1(glLineWidth_impl,
+                thread,
+                GLLINEWIDTH_ID,
+                RPC_FLOAT(width));
+   }
+}
+
+GL_API void GL_APIENTRY glLineWidthx (GLfixed width)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL1(glLineWidthx_impl_11,
+                thread,
+                GLLINEWIDTHX_ID_11,
+                RPC_FIXED(width));
+   }
+}
+
+GL_API void GL_APIENTRY glLinkProgram (GLuint program)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL1(glLinkProgram_impl_20,
+               thread,
+               GLLINKPROGRAM_ID_20,
+               RPC_UINT(program));
+   }
+}
+
+GL_API void GL_APIENTRY glLoadIdentity (void)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL0(glLoadIdentity_impl_11,
+                thread,
+                GLLOADIDENTITY_ID_11);
+   }
+}
+
+GL_API void GL_APIENTRY glLoadMatrixf (const GLfloat *m)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL1_IN_CTRL(glLoadMatrixf_impl_11,
+                       thread,
+                       GLLOADMATRIXF_ID_11,
+                       m,
+                       16 * sizeof(GLfloat));
+   }
+}
+
+GL_API void GL_APIENTRY glLoadMatrixx (const GLfixed *m)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL1_IN_CTRL(glLoadMatrixx_impl_11,
+                        thread,
+                        GLLOADMATRIXX_ID_11,
+                        m,
+                        16 * sizeof(GLfixed));
+   }
+}
+
+GL_API void GL_APIENTRY glLogicOp (GLenum opcode)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL1(glLogicOp_impl_11,
+                thread,
+                GLLOGICOP_ID_11,
+                RPC_ENUM(opcode));
+   }
+}
+
+GL_API void GL_APIENTRY glMaterialf (GLenum face, GLenum pname, GLfloat param)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL3(glMaterialf_impl_11,
+                thread,
+                GLMATERIALF_ID_11,
+                RPC_ENUM(face),
+                RPC_ENUM(pname),
+                RPC_FLOAT(param));
+   }
+}
+
+GL_API void GL_APIENTRY glMaterialfv (GLenum face, GLenum pname, const GLfloat *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      /*
+         the only supported material params are
+
+         AMBIENT (4)
+         DIFFUSE (4)
+         SPECULAR (4)
+         EMISSION (4)
+         SHININESS (1)
+
+         so we need to transmit 4 words of parameter data
+      */
+
+      RPC_CALL3_IN_CTRL(glMaterialfv_impl_11,
+                        thread,
+                        GLMATERIALFV_ID_11,
+                        RPC_ENUM(face),
+                        RPC_ENUM(pname),
+                        params,
+                        4 * sizeof(GLfloat));
+   }
+}
+
+GL_API void GL_APIENTRY glMaterialx (GLenum face, GLenum pname, GLfixed param)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL3(glMaterialx_impl_11,
+                thread,
+                GLMATERIALX_ID_11,
+                RPC_ENUM(face),
+                RPC_ENUM(pname),
+                RPC_FIXED(param));
+   }
+}
+
+GL_API void GL_APIENTRY glMaterialxv (GLenum face, GLenum pname, const GLfixed *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      /*
+         the only supported material params are
+
+         AMBIENT (4)
+         DIFFUSE (4)
+         SPECULAR (4)
+         EMISSION (4)
+         SHININESS (1)
+
+         so we need to transmit 4 words of parameter data
+      */
+
+      RPC_CALL3_IN_CTRL(glMaterialxv_impl_11,
+                        thread,
+                        GLMATERIALXV_ID_11,
+                        RPC_ENUM(face),
+                        RPC_ENUM(pname),
+                        params,
+                        4 * sizeof(GLfixed));
+   }
+}
+
+GL_API void GL_APIENTRY glMatrixMode (GLenum mode)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL1(glMatrixMode_impl_11,
+                thread,
+                GLMATRIXMODE_ID_11,
+                RPC_ENUM(mode));
+   }
+}
+
+GL_API void GL_APIENTRY glMultMatrixf (const GLfloat *m)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL1_IN_CTRL(glMultMatrixf_impl_11,
+                        thread,
+                        GLMULTMATRIXF_ID_11,
+                        m,
+                        16 * sizeof(GLfloat));
+   }
+}
+
+GL_API void GL_APIENTRY glMultMatrixx (const GLfixed *m)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL1_IN_CTRL(glMultMatrixx_impl_11,
+                        thread,
+                        GLMULTMATRIXX_ID_11,
+                        m,
+                        16 * sizeof(GLfixed));
+   }
+}
+
+GL_API void GL_APIENTRY glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q)
+{
+   if (target >= GL_TEXTURE0 && target < GL_TEXTURE0 + GL11_CONFIG_MAX_TEXTURE_UNITS) {
+      uint32_t indx = GL11_IX_TEXTURE_COORD + target - GL_TEXTURE0;
+      glintAttrib(GLXX_API_11, indx, s, t, r, q);
+   } else
+      glxx_set_error_api(GLXX_API_11, GL_INVALID_ENUM);
+}
+
+GL_API void GL_APIENTRY glMultiTexCoord4x (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q)
+{
+   if (target >= GL_TEXTURE0 && target < GL_TEXTURE0 + GL11_CONFIG_MAX_TEXTURE_UNITS) {
+      uint32_t indx = GL11_IX_TEXTURE_COORD + target - GL_TEXTURE0;
+      glintAttrib(GLXX_API_11, indx, fixed_to_float(s), fixed_to_float(t), fixed_to_float(r), fixed_to_float(q));
+   } else
+      glxx_set_error_api(GLXX_API_11, GL_INVALID_ENUM);
+}
+
+GL_API void GL_APIENTRY glNormal3f (GLfloat nx, GLfloat ny, GLfloat nz)
+{
+   glintAttrib(GLXX_API_11, GL11_IX_NORMAL, nx, ny, nz, 0.0f);
+}
+
+GL_API void GL_APIENTRY glNormal3x (GLfixed nx, GLfixed ny, GLfixed nz)
+{
+   glintAttrib(GLXX_API_11, GL11_IX_NORMAL, fixed_to_float(nx), fixed_to_float(ny), fixed_to_float(nz), 0.0f);
+}
+
+static bool is_normal_type(GLenum type)
+{
+   return type == GL_BYTE ||
+          type == GL_SHORT ||
+          type == GL_FIXED ||
+          type == GL_FLOAT;
+}
+
+GL_API void GL_APIENTRY glNormalPointer (GLenum type, GLsizei stride, const GLvoid *pointer)
+{
+   if (is_normal_type(type)) {
+      if (is_aligned(type, (size_t)pointer) && is_aligned(type, (size_t)stride) && stride >= 0) {
+         glintAttribPointer(GLXX_API_11, GL11_IX_NORMAL, 3, type, GL_TRUE, stride, pointer);
+      } else
+         glxx_set_error_api(GLXX_API_11, GL_INVALID_VALUE);
+   } else
+      glxx_set_error_api(GLXX_API_11, GL_INVALID_ENUM);
+}
+
+GL_API void GL_APIENTRY glOrthof (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL6(glOrthof_impl_11,
+                thread,
+                GLORTHOF_ID_11,
+                RPC_FLOAT(left),
+                RPC_FLOAT(right),
+                RPC_FLOAT(bottom),
+                RPC_FLOAT(top),
+                RPC_FLOAT(zNear),
+                RPC_FLOAT(zFar));
+   }
+}
+
+GL_API void GL_APIENTRY glOrthox (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL6(glOrthox_impl_11,
+                thread,
+                GLORTHOX_ID_11,
+                RPC_FIXED(left),
+                RPC_FIXED(right),
+                RPC_FIXED(bottom),
+                RPC_FIXED(top),
+                RPC_FIXED(zNear),
+                RPC_FIXED(zFar));
+   }
+}
+
+static GLboolean is_alignment(GLint param)
+{
+   return param == 1 ||
+          param == 2 ||
+          param == 4 ||
+          param == 8;
+}
+
+GL_API void GL_APIENTRY glPixelStorei (GLenum pname, GLint param)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      if (is_alignment(param)) {
+         GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+         vcos_assert(state != NULL);
+
+         switch (pname) {
+         case GL_PACK_ALIGNMENT:
+            state->alignment.pack = param;
+            break;
+         case GL_UNPACK_ALIGNMENT:
+            state->alignment.unpack = param;
+            break;
+         }
+      }
+   }
+}
+
+GL_API void GL_APIENTRY glPointParameterf (GLenum pname, GLfloat param)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL2(glPointParameterf_impl_11,
+                thread,
+                GLPOINTPARAMETERF_ID_11,
+                RPC_ENUM(pname),
+                RPC_FLOAT(param));
+   }
+}
+
+GL_API void GL_APIENTRY glPointParameterfv (GLenum pname, const GLfloat *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      /*
+         the only supported material params are
+
+         POINT_SIZE_MIN (1)
+         POINT_SIZE_MAX (1)
+         POINT_FADE_THRESHOLD_SIZE (1)
+         POINT_DISTANCE_ATTENUATION (3)
+
+         so we need to transmit 3 words of parameter data
+      */
+
+      RPC_CALL2_IN_CTRL(glPointParameterfv_impl_11,
+                        thread,
+                        GLPOINTPARAMETERFV_ID_11,
+                        RPC_ENUM(pname),
+                        params,
+                        3 * sizeof(GLfloat));
+   }
+}
+
+GL_API void GL_APIENTRY glPointParameterx (GLenum pname, GLfixed param)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL2(glPointParameterx_impl_11,
+                thread,
+                GLPOINTPARAMETERX_ID_11,
+                RPC_ENUM(pname),
+                RPC_FIXED(param));
+   }
+}
+
+GL_API void GL_APIENTRY glPointParameterxv (GLenum pname, const GLfixed *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      /*
+         the only supported material params are
+
+         POINT_SIZE_MIN (1)
+         POINT_SIZE_MAX (1)
+         POINT_FADE_THRESHOLD_SIZE (1)
+         POINT_DISTANCE_ATTENUATION (3)
+
+         so we need to transmit 3 words of parameter data
+      */
+
+      RPC_CALL2_IN_CTRL(glPointParameterxv_impl_11,
+                        thread,
+                        GLPOINTPARAMETERXV_ID_11,
+                        RPC_ENUM(pname),
+                        params,
+                        3 * sizeof(GLfixed));
+   }
+}
+
+GL_API void GL_APIENTRY glPointSize (GLfloat size)
+{
+   size = clean_float(size);
+
+   if (size > 0.0f)
+      glintAttrib(GLXX_API_11, GL11_IX_POINT_SIZE, size, 0.0f, 0.0f, 0.0f);
+   else
+      glxx_set_error_api(GLXX_API_11, GL_INVALID_VALUE);
+}
+
+GL_API void GL_APIENTRY glPointSizex (GLfixed size)
+{
+   if (size > 0)
+      glintAttrib(GLXX_API_11, GL11_IX_POINT_SIZE, fixed_to_float(size), 0.0f, 0.0f, 0.0f);
+   else
+      glxx_set_error_api(GLXX_API_11, GL_INVALID_VALUE);
+}
+
+GL_API void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL2(glPolygonOffset_impl,
+                thread,
+                GLPOLYGONOFFSET_ID,
+                RPC_FLOAT(factor),
+                RPC_FLOAT(units));
+   }
+}
+
+GL_API void GL_APIENTRY glPolygonOffsetx (GLfixed factor, GLfixed units)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL2(glPolygonOffsetx_impl_11,
+                thread,
+                GLPOLYGONOFFSETX_ID_11,
+                RPC_FIXED(factor),
+                RPC_FIXED(units));
+   }
+}
+
+GL_API void GL_APIENTRY glPopMatrix (void)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL0(glPopMatrix_impl_11,
+                thread,
+                GLPOPMATRIX_ID_11);
+   }
+}
+
+GL_API void GL_APIENTRY glPushMatrix (void)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL0(glPushMatrix_impl_11,
+                thread,
+                GLPUSHMATRIX_ID_11);
+   }
+}
+
+/*
+   we need to calculate on the client side how much data to transfer to the
+   server on a call to glTexImage2D()
+
+   from section 3.6 of the OpenGL ES 1.1 spec
+
+   the first element of the Nth row is indicated by
+
+   p + Nk
+
+   where N is the row number (counting from zero) and k is defined as
+
+   k = nl                  if s >= a
+     = a/s * ceil(snl/a)   otherwise
+
+   where n is the number of elements in a group, l is the number of groups in
+   the row, a is the value of UNPACK ALIGNMENT, and s is the size, in units of GL
+   ubytes, of an element.
+
+   this code is
+*/
+
+static uint32_t get_pitch(uint32_t w, GLenum format, GLenum type, uint32_t a)
+{
+   uint32_t n = 0;
+   uint32_t s = 0;
+   uint32_t k = 0;
+
+   switch (format) {
+   case GL_RGBA:
+#if GL_EXT_texture_format_BGRA8888
+   case GL_BGRA_EXT:
+#endif
+#if GL_texture_format_RGBX8888_BRCM
+   case GL_RGBX_BRCM:
+#endif
+      switch (type) {
+      case GL_UNSIGNED_BYTE:
+         n = 4;
+         s = 1;
+         break;
+      case GL_UNSIGNED_SHORT_4_4_4_4:
+      case GL_UNSIGNED_SHORT_5_5_5_1:
+         n = 1;
+         s = 2;
+         break;
+      }
+      break;
+   case GL_RGB:
+      switch (type) {
+      case GL_UNSIGNED_BYTE:
+         n = 3;
+         s = 1;
+         break;
+      case GL_UNSIGNED_SHORT_5_6_5:
+         n = 1;
+         s = 2;
+         break;
+      }
+      break;
+   case GL_LUMINANCE_ALPHA:
+      n = 2;
+      s = 1;
+      break;
+   case GL_LUMINANCE:
+   case GL_ALPHA:
+      n = 1;
+      s = 1;
+      break;
+#if GL_APPLE_rgb_422
+   case GL_RGB_422_APPLE:
+      n = 1;
+      s = 2;
+      break;
+#endif
+   }
+
+   if (s != 0) {   /* Avoid division by zero errors on invalid formats */
+      if (s < a)
+         k = (a / s) * ((s * n * w + a - 1) / a);
+      else
+         k = n * w;
+   }
+
+   switch (format) {
+   case GL_RGBA:
+#if GL_EXT_texture_format_BGRA8888
+   case GL_BGRA_EXT:
+#endif
+#if GL_texture_format_RGBX8888_BRCM
+   case GL_RGBX_BRCM:
+#endif
+      switch (type) {
+      case GL_UNSIGNED_BYTE:
+         return k;
+      case GL_UNSIGNED_SHORT_4_4_4_4:
+      case GL_UNSIGNED_SHORT_5_5_5_1:
+         return k * 2;
+      }
+      break;
+   case GL_RGB:
+      switch (type) {
+      case GL_UNSIGNED_BYTE:
+         return k;
+      case GL_UNSIGNED_SHORT_5_6_5:
+         return k * 2;
+      }
+      break;
+   case GL_LUMINANCE_ALPHA:
+   case GL_LUMINANCE:
+   case GL_ALPHA:
+      return k;
+#if GL_APPLE_rgb_422
+   case GL_RGB_422_APPLE:
+      return k * 2;
+#endif
+   }
+
+   return 0;      // transfer no data, format will be rejected by server
+}
+
+GL_API void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+      uint32_t pitch = get_pitch( (uint32_t)width, format, type, (uint32_t) state->alignment.pack);
+      uint32_t lines = pitch ? (uint32_t) (KHDISPATCH_WORKSPACE_SIZE / pitch) : (uint32_t)height;
+
+      if (pixels && lines) {
+         int offset = 0;
+
+         while (height > 0) {
+            int32_t batch = _min(lines, (int32_t) height);
+
+            RPC_CALL8_OUT_BULK(glReadPixels_impl,
+                               thread,
+                               GLREADPIXELS_ID,
+                               RPC_INT(x),
+                               RPC_INT(y + offset),
+                               RPC_SIZEI(width),
+                               RPC_SIZEI(batch),
+                               RPC_ENUM(format),
+                               RPC_ENUM(type),
+                               RPC_INT(state->alignment.pack),
+                               (char *)pixels + offset * pitch);
+
+            offset += batch;
+            height -= batch;
+         }
+      }
+
+      // We do not call flush_callback as the spec does not imply a full flush
+      // at this point (I think).
+   }
+}
+
+GL_API void GL_APIENTRY glRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL4(glRotatef_impl_11,
+                thread,
+                GLROTATEF_ID_11,
+                RPC_FLOAT(angle),
+                RPC_FLOAT(x),
+                RPC_FLOAT(y),
+                RPC_FLOAT(z));
+   }
+}
+
+GL_API void GL_APIENTRY glRotatex (GLfixed angle, GLfixed x, GLfixed y, GLfixed z)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL4(glRotatex_impl_11,
+                thread,
+                GLROTATEX_ID_11,
+                RPC_FIXED(angle),
+                RPC_FIXED(x),
+                RPC_FIXED(y),
+                RPC_FIXED(z));
+   }
+}
+
+GL_API void GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL2(glSampleCoverage_impl,
+                thread,
+                GLSAMPLECOVERAGE_ID,
+                RPC_FLOAT(value),
+                RPC_BOOLEAN(invert));
+   }
+}
+
+GL_API void GL_APIENTRY glSampleCoveragex (GLclampx value, GLboolean invert)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL2(glSampleCoveragex_impl_11,
+                thread,
+                GLSAMPLECOVERAGEX_ID_11,
+                RPC_FIXED(value),
+                RPC_BOOLEAN(invert));
+   }
+}
+
+GL_API void GL_APIENTRY glScalef (GLfloat x, GLfloat y, GLfloat z)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL3(glScalef_impl_11,
+                thread,
+                GLSCALEF_ID_11,
+                RPC_FLOAT(x),
+                RPC_FLOAT(y),
+                RPC_FLOAT(z));
+   }
+}
+
+GL_API void GL_APIENTRY glScalex (GLfixed x, GLfixed y, GLfixed z)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL3(glScalex_impl_11,
+                thread,
+                GLSCALEX_ID_11,
+                RPC_FIXED(x),
+                RPC_FIXED(y),
+                RPC_FIXED(z));
+   }
+}
+
+GL_API void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL4(glScissor_impl,
+                thread,
+                GLSCISSOR_ID,
+                RPC_INT(x),
+                RPC_INT(y),
+                RPC_SIZEI(width),
+                RPC_SIZEI(height));
+   }
+}
+
+GL_API void GL_APIENTRY glShadeModel (GLenum mode)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL1(glShadeModel_impl_11,
+                thread,
+                GLSHADEMODEL_ID_11,
+                RPC_ENUM(mode));
+   }
+}
+
+static void set_stencil_func(CLIENT_THREAD_STATE_T *thread, GLenum face, GLenum func, GLint ref, GLuint mask) {
+   RPC_CALL4(glStencilFuncSeparate_impl,
+             thread,
+             GLSTENCILFUNCSEPARATE_ID,
+             RPC_ENUM(face),
+             RPC_ENUM(func),
+             RPC_INT(ref),
+             RPC_UINT(mask));
+}
+
+GL_API void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) set_stencil_func(thread, GL_FRONT_AND_BACK, func, ref, mask);
+}
+
+GL_API void GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask) // S
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) set_stencil_func(thread, face, func, ref, mask);
+}
+
+static void set_stencil_mask(CLIENT_THREAD_STATE_T *thread, GLenum face, GLuint mask) {
+   RPC_CALL2(glStencilMaskSeparate_impl,
+             thread,
+             GLSTENCILMASKSEPARATE_ID,
+             RPC_ENUM(face),
+             RPC_UINT(mask));
+}
+
+GL_API void GL_APIENTRY glStencilMask (GLuint mask)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) set_stencil_mask(thread, GL_FRONT_AND_BACK, mask);
+}
+
+GL_API void GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask) // S
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) set_stencil_mask(thread, face, mask);
+}
+
+static void set_stencil_op(CLIENT_THREAD_STATE_T *thread, GLenum face, GLenum fail, GLenum zfail, GLenum zpass) {
+   RPC_CALL4(glStencilOpSeparate_impl,
+             thread,
+             GLSTENCILOPSEPARATE_ID,
+             RPC_ENUM(face),
+             RPC_ENUM(fail),
+             RPC_ENUM(zfail),
+             RPC_ENUM(zpass));
+}
+
+GL_API void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) set_stencil_op(thread, GL_FRONT_AND_BACK, fail, zfail, zpass);
+}
+
+GL_API void GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass) // S
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) set_stencil_op(thread, face, fail, zfail, zpass);
+}
+
+static bool is_texture_coord_size(GLint size)
+{
+   return size == 2 ||
+          size == 3 ||
+          size == 4;
+}
+
+static bool is_texture_coord_type(GLenum type)
+{
+   return type == GL_BYTE ||
+          type == GL_SHORT ||
+          type == GL_FIXED ||
+          type == GL_FLOAT;
+}
+
+GL_API void GL_APIENTRY glTexCoordPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+{
+   if (is_texture_coord_type(type)) {
+      if (is_texture_coord_size(size) && is_aligned(type, (size_t)pointer) && is_aligned(type, (size_t)stride) && stride >= 0) {
+         glintAttribPointer(GLXX_API_11, GL11_IX_CLIENT_ACTIVE_TEXTURE, size, type, GL_FALSE, stride, pointer);
+      } else
+         glxx_set_error_api(GLXX_API_11, GL_INVALID_VALUE);
+   } else
+      glxx_set_error_api(GLXX_API_11, GL_INVALID_ENUM);
+}
+
+GL_API void GL_APIENTRY glTexEnvi (GLenum target, GLenum pname, GLint param)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL3(glTexEnvi_impl_11,
+                thread,
+                GLTEXENVI_ID_11,
+                RPC_ENUM(target),
+                RPC_ENUM(pname),
+                RPC_INT(param));
+   }
+}
+
+GL_API void GL_APIENTRY glTexEnviv (GLenum target, GLenum pname, const GLint *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      /*
+         the only supported texture environment params are
+
+         COORD_REPLACE_OES (1)
+         TEXTURE_ENV_MODE (1)
+         TEXTURE_ENV_COLOR (4)
+         COMBINE_RGB (1)
+         RGB_SCALE (1)
+         SRC0_RGB (1)
+         SRC1_RGB (1)
+         SRC2_RGB (1)
+         OPERAND0_RGB (1)
+         OPERAND1_RGB (1)
+         OPERAND2_RGB (1)
+         COMBINE_ALPHA (1)
+         ALPHA_SCALE (1)
+         SRC0_ALPHA (1)
+         SRC1_ALPHA (1)
+         SRC2_ALPHA (1)
+         OPERAND0_ALPHA (1)
+         OPERAND1_ALPHA (1)
+         OPERAND2_ALPHA (1)
+
+         so we need to transmit 4 words of parameter data
+      */
+
+      RPC_CALL3_IN_CTRL(glTexEnviv_impl_11,
+                        thread,
+                        GLTEXENVIV_ID_11,
+                        RPC_ENUM(target),
+                        RPC_ENUM(pname),
+                        params,
+                        4 * sizeof(GLint));
+   }
+}
+
+GL_API void GL_APIENTRY glTexEnvf (GLenum target, GLenum pname, GLfloat param)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL3(glTexEnvf_impl_11,
+                thread,
+                GLTEXENVF_ID_11,
+                RPC_ENUM(target),
+                RPC_ENUM(pname),
+                RPC_FLOAT(param));
+   }
+}
+
+GL_API void GL_APIENTRY glTexEnvfv (GLenum target, GLenum pname, const GLfloat *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      /*
+         the only supported texture environment params are
+
+         COORD_REPLACE_OES (1)
+         TEXTURE_ENV_MODE (1)
+         TEXTURE_ENV_COLOR (4)
+         COMBINE_RGB (1)
+         RGB_SCALE (1)
+         SRC0_RGB (1)
+         SRC1_RGB (1)
+         SRC2_RGB (1)
+         OPERAND0_RGB (1)
+         OPERAND1_RGB (1)
+         OPERAND2_RGB (1)
+         COMBINE_ALPHA (1)
+         ALPHA_SCALE (1)
+         SRC0_ALPHA (1)
+         SRC1_ALPHA (1)
+         SRC2_ALPHA (1)
+         OPERAND0_ALPHA (1)
+         OPERAND1_ALPHA (1)
+         OPERAND2_ALPHA (1)
+
+         so we need to transmit 4 words of parameter data
+      */
+
+      RPC_CALL3_IN_CTRL(glTexEnvfv_impl_11,
+                        thread,
+                        GLTEXENVFV_ID_11,
+                        RPC_ENUM(target),
+                        RPC_ENUM(pname),
+                        params,
+                        4 * sizeof(GLfloat));
+   }
+}
+
+GL_API void GL_APIENTRY glTexEnvx (GLenum target, GLenum pname, GLfixed param)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL3(glTexEnvx_impl_11,
+                thread,
+                GLTEXENVX_ID_11,
+                RPC_ENUM(target),
+                RPC_ENUM(pname),
+                RPC_FIXED(param));
+   }
+}
+
+GL_API void GL_APIENTRY glTexEnvxv (GLenum target, GLenum pname, const GLfixed *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      /*
+         the only supported texture environment params are
+
+         COORD_REPLACE_OES (1)
+         TEXTURE_ENV_MODE (1)
+         TEXTURE_ENV_COLOR (4)
+         COMBINE_RGB (1)
+         RGB_SCALE (1)
+         SRC0_RGB (1)
+         SRC1_RGB (1)
+         SRC2_RGB (1)
+         OPERAND0_RGB (1)
+         OPERAND1_RGB (1)
+         OPERAND2_RGB (1)
+         COMBINE_ALPHA (1)
+         ALPHA_SCALE (1)
+         SRC0_ALPHA (1)
+         SRC1_ALPHA (1)
+         SRC2_ALPHA (1)
+         OPERAND0_ALPHA (1)
+         OPERAND1_ALPHA (1)
+         OPERAND2_ALPHA (1)
+
+         so we need to transmit 4 words of parameter data
+      */
+
+      RPC_CALL3_IN_CTRL(glTexEnvxv_impl_11,
+                        thread,
+                        GLTEXENVXV_ID_11,
+                        RPC_ENUM(target),
+                        RPC_ENUM(pname),
+                        params,
+                        4 * sizeof(GLfixed));
+   }
+}
+
+GL_API void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   GLboolean res;
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+      uint32_t pitch = get_pitch( (uint32_t)width, format, type, (uint32_t)state->alignment.unpack);
+      uint32_t lines = pitch ? (uint32_t)(KHDISPATCH_WORKSPACE_SIZE / pitch) : (uint32_t)height;
+
+      res = RPC_BOOLEAN_RES(RPC_CALL10_IN_BULK_RES(glTexImage2D_impl,
+                        thread,
+                        GLTEXIMAGE2D_ID,
+                        RPC_ENUM(target),
+                        RPC_INT(level),
+                        RPC_ENUM(internalformat),
+                        RPC_SIZEI(width),
+                        RPC_SIZEI(height),
+                        RPC_INT(border),
+                        RPC_ENUM(format),
+                        RPC_ENUM(type),
+                        RPC_INT(state->alignment.unpack),
+                        NULL,
+                        0));
+
+      if (res && pixels && lines) {
+         int offset = 0;
+
+         while (height > 0) {
+            int32_t batch = _min(lines, (int32_t)height);
+
+            RPC_CALL10_IN_BULK(glTexSubImage2D_impl,
+                              thread,
+                              GLTEXSUBIMAGE2D_ID,
+                              RPC_ENUM(target),
+                              RPC_INT(level),
+                              RPC_INT(0),
+                              RPC_INT(offset),
+                              RPC_SIZEI(width),
+                              RPC_SIZEI(batch),
+                              RPC_ENUM(format),
+                              RPC_ENUM(type),
+                              RPC_INT(state->alignment.unpack),
+                              (char *)pixels + offset * pitch,
+                              batch * pitch);
+
+            offset += batch;
+            height -= batch;
+         }
+      }
+   }
+}
+
+GL_API void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL3(glTexParameteri_impl,
+                thread,
+                GLTEXPARAMETERI_ID,
+                RPC_ENUM(target),
+                RPC_ENUM(pname),
+                RPC_INT(param));
+   }
+}
+
+GL_API void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL3(glTexParameterf_impl,
+                thread,
+                GLTEXPARAMETERF_ID,
+                RPC_ENUM(target),
+                RPC_ENUM(pname),
+                RPC_FLOAT(param));
+   }
+}
+
+GL_API void GL_APIENTRY glTexParameterx (GLenum target, GLenum pname, GLfixed param)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL3(glTexParameterx_impl_11,
+                thread,
+                GLTEXPARAMETERX_ID_11,
+                RPC_ENUM(target),
+                RPC_ENUM(pname),
+                RPC_FIXED(param));
+   }
+}
+
+GL_API void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   /*
+      the only supported texture params are
+
+      TEXTURE_MIN_FILTER
+      TEXTURE_MAG_FILTER
+      TEXTURE_WRAP_S
+      TEXTURE_WRAP_T
+
+      each of which takes a single argument
+
+      and for 1.1
+      TEXTURE_CROP_RECT_OES
+      which takes 4 ints
+   */
+
+   if (IS_OPENGLES_11(thread)) {
+      if(pname != GL_TEXTURE_CROP_RECT_OES) {
+         glTexParameteri(target, pname, params[0]);
+      }
+      else {
+         RPC_CALL3_IN_CTRL(glTexParameteriv_impl,
+                thread,
+                GLTEXPARAMETERIV_ID,
+                RPC_ENUM(target),
+                RPC_ENUM(pname),
+                params,
+                4 * sizeof(GLint));
+      }
+   }
+   else if(IS_OPENGLES_20(thread))
+      glTexParameteri(target, pname, params[0]);
+}
+
+GL_API void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   /*
+      the only supported texture params are
+
+      TEXTURE_MIN_FILTER
+      TEXTURE_MAG_FILTER
+      TEXTURE_WRAP_S
+      TEXTURE_WRAP_T
+
+      each of which takes a single argument
+
+      and for 1.1
+      TEXTURE_CROP_RECT_OES
+      which takes 4 ints
+   */
+
+   if (IS_OPENGLES_11(thread)) {
+      if(pname != GL_TEXTURE_CROP_RECT_OES) {
+         glTexParameterf(target, pname, params[0]);
+      }
+      else {
+         RPC_CALL3_IN_CTRL(glTexParameterfv_impl,
+                thread,
+                GLTEXPARAMETERFV_ID,
+                RPC_ENUM(target),
+                RPC_ENUM(pname),
+                params,
+                4 * sizeof(GLfloat));
+      }
+   }
+   else if(IS_OPENGLES_20(thread))
+      glTexParameterf(target, pname, params[0]);
+}
+
+GL_API void GL_APIENTRY glTexParameterxv (GLenum target, GLenum pname, const GLfixed *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   /*
+      the only supported texture params are
+
+      TEXTURE_MIN_FILTER
+      TEXTURE_MAG_FILTER
+      TEXTURE_WRAP_S
+      TEXTURE_WRAP_T
+
+      each of which takes a single argument
+
+      and for 1.1
+      TEXTURE_CROP_RECT_OES
+      which takes 4 ints
+   */
+
+   if (IS_OPENGLES_11(thread)) {
+      if(pname != GL_TEXTURE_CROP_RECT_OES) {
+         glTexParameterx(target, pname, params[0]);
+      }
+      else {
+         RPC_CALL3_IN_CTRL(glTexParameterxv_impl_11,
+                thread,
+                GLTEXPARAMETERXV_ID_11,
+                RPC_ENUM(target),
+                RPC_ENUM(pname),
+                params,
+                4 * sizeof(GLfixed));
+      }
+   }
+   else if(IS_OPENGLES_20(thread))
+      glTexParameterx(target, pname, params[0]);
+}
+
+GL_API void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+      uint32_t pitch = get_pitch( (uint32_t)width, format, type, (uint32_t)state->alignment.unpack);
+      uint32_t lines = pitch ? (uint32_t)(KHDISPATCH_WORKSPACE_SIZE / pitch) : (uint32_t)height;
+
+      if (pixels && lines) {
+         int offset = 0;
+
+         while (height > 0) {
+            int32_t batch = _min(lines, (int32_t)height);
+
+            RPC_CALL10_IN_BULK(glTexSubImage2D_impl,
+                              thread,
+                              GLTEXSUBIMAGE2D_ID,
+                              RPC_ENUM(target),
+                              RPC_INT(level),
+                              RPC_INT(xoffset),
+                              RPC_INT(yoffset+offset),
+                              RPC_SIZEI(width),
+                              RPC_SIZEI(batch),
+                              RPC_ENUM(format),
+                              RPC_ENUM(type),
+                              RPC_INT(state->alignment.unpack),
+                              (char *)pixels + offset * pitch,
+                              batch * pitch);
+
+            offset += batch;
+            height -= batch;
+         }
+      }
+   }
+}
+
+GL_API void GL_APIENTRY texSubImage2DAsync (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLint hpixels)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+      RPC_CALL10(texSubImage2DAsync_impl,
+                        thread,
+                        TEXSUBIMAGE2DASYNC_ID,
+                        RPC_ENUM(target),
+                        RPC_INT(level),
+                        RPC_INT(xoffset),
+                        RPC_INT(yoffset),
+                        RPC_SIZEI(width),
+                        RPC_SIZEI(height),
+                        RPC_ENUM(format),
+                        RPC_ENUM(type),
+                        RPC_INT(state->alignment.unpack),
+                        RPC_INT(hpixels));
+   }
+}
+
+GL_API void GL_APIENTRY glTranslatef (GLfloat x, GLfloat y, GLfloat z)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL3(glTranslatef_impl_11,
+                thread,
+                GLTRANSLATEF_ID_11,
+                RPC_FLOAT(x),
+                RPC_FLOAT(y),
+                RPC_FLOAT(z));
+   }
+}
+
+GL_API void GL_APIENTRY glTranslatex (GLfixed x, GLfixed y, GLfixed z)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread)) {
+      RPC_CALL3(glTranslatex_impl_11,
+                thread,
+                GLTRANSLATEX_ID_11,
+                RPC_FIXED(x),
+                RPC_FIXED(y),
+                RPC_FIXED(z));
+   }
+}
+
+GL_API void GL_APIENTRY glUniform1i (GLint location, GLint x)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL2(glUniform1i_impl_20,
+                thread,
+                GLUNIFORM1I_ID_20,
+                RPC_INT(location),
+                RPC_INT(x));
+   }
+}
+
+GL_API void GL_APIENTRY glUniform2i (GLint location, GLint x, GLint y)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL3(glUniform2i_impl_20,
+                thread,
+                GLUNIFORM2I_ID_20,
+                RPC_INT(location),
+                RPC_INT(x),
+                RPC_INT(y));
+   }
+}
+
+GL_API void GL_APIENTRY glUniform3i (GLint location, GLint x, GLint y, GLint z)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL4(glUniform3i_impl_20,
+                thread,
+                GLUNIFORM3I_ID_20,
+                RPC_INT(location),
+                RPC_INT(x),
+                RPC_INT(y),
+                RPC_INT(z));
+   }
+}
+
+GL_API void GL_APIENTRY glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL5(glUniform4i_impl_20,
+                thread,
+                GLUNIFORM4I_ID_20,
+                RPC_INT(location),
+                RPC_INT(x),
+                RPC_INT(y),
+                RPC_INT(z),
+                RPC_INT(w));
+   }
+}
+
+GL_API void GL_APIENTRY glUniform1f (GLint location, GLfloat x)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL2(glUniform1f_impl_20,
+                thread,
+                GLUNIFORM1F_ID_20,
+                RPC_INT(location),
+                RPC_FLOAT(x));
+   }
+}
+
+GL_API void GL_APIENTRY glUniform2f (GLint location, GLfloat x, GLfloat y)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL3(glUniform2f_impl_20,
+                thread,
+                GLUNIFORM2F_ID_20,
+                RPC_INT(location),
+                RPC_FLOAT(x),
+                RPC_FLOAT(y));
+   }
+}
+
+GL_API void GL_APIENTRY glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL4(glUniform3f_impl_20,
+                thread,
+                GLUNIFORM3F_ID_20,
+                RPC_INT(location),
+                RPC_FLOAT(x),
+                RPC_FLOAT(y),
+                RPC_FLOAT(z));
+   }
+}
+
+GL_API void GL_APIENTRY glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL5(glUniform4f_impl_20,
+                thread,
+                GLUNIFORM4F_ID_20,
+                RPC_INT(location),
+                RPC_FLOAT(x),
+                RPC_FLOAT(y),
+                RPC_FLOAT(z),
+                RPC_FLOAT(w));
+   }
+}
+
+/*
+   clamp the size of uniform data to the maximum conceivable value (128 vec4s)
+*/
+
+#define MAX_UNIFORM_SIZE 2048
+
+static INLINE int clamp_uniform_size(int size)
+{
+   return (int) _min( (int32_t)size, MAX_UNIFORM_SIZE);
+}
+
+GL_API void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint *v)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      int size = clamp_uniform_size( (int)(count * 1 * sizeof(GLint)));
+
+      RPC_CALL4_IN_CTRL(glUniform1iv_impl_20,
+                        thread,
+                        GLUNIFORM1IV_ID_20,
+                        RPC_INT(location),
+                        RPC_SIZEI(count),
+                        RPC_INT(size),
+                        v,
+                        (size_t)size);
+   }
+}
+
+GL_API void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint *v)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      int size = clamp_uniform_size( (int)(count * 2 * sizeof(GLint)));
+
+      RPC_CALL4_IN_CTRL(glUniform2iv_impl_20,
+                        thread,
+                        GLUNIFORM2IV_ID_20,
+                        RPC_INT(location),
+                        RPC_SIZEI(count),
+                        RPC_INT(size),
+                        v,
+                        (size_t)size);
+   }
+}
+
+GL_API void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint *v)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      int size = clamp_uniform_size( (int)(count * 3 * sizeof(GLint)));
+
+      RPC_CALL4_IN_CTRL(glUniform3iv_impl_20,
+                        thread,
+                        GLUNIFORM3IV_ID_20,
+                        RPC_INT(location),
+                        RPC_SIZEI(count),
+                        RPC_INT(size),
+                        v,
+                        (size_t)size);
+   }
+}
+
+GL_API void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint *v)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      int size = clamp_uniform_size( (int)(count * 4 * sizeof(GLint)));
+
+      RPC_CALL4_IN_CTRL(glUniform4iv_impl_20,
+                        thread,
+                        GLUNIFORM4IV_ID_20,
+                        RPC_INT(location),
+                        RPC_SIZEI(count),
+                        RPC_INT(size),
+                        v,
+                        (size_t)size);
+   }
+}
+
+GL_API void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat *v)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      int size = clamp_uniform_size( (int)(count * 1 * sizeof(GLfloat)));
+
+      RPC_CALL4_IN_CTRL(glUniform1fv_impl_20,
+                        thread,
+                        GLUNIFORM1FV_ID_20,
+                        RPC_INT(location),
+                        RPC_SIZEI(count),
+                        RPC_INT(size),
+                        v,
+                        (size_t)size);
+   }
+}
+
+GL_API void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat *v)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      int size = clamp_uniform_size( (int)(count * 2 * sizeof(GLfloat)));
+
+      RPC_CALL4_IN_CTRL(glUniform2fv_impl_20,
+                        thread,
+                        GLUNIFORM2FV_ID_20,
+                        RPC_INT(location),
+                        RPC_SIZEI(count),
+                        RPC_INT(size),
+                        v,
+                        (size_t)size);
+   }
+}
+
+GL_API void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat *v)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      int size = clamp_uniform_size( (int)(count * 3 * sizeof(GLfloat)));
+
+      RPC_CALL4_IN_CTRL(glUniform3fv_impl_20,
+                        thread,
+                        GLUNIFORM3FV_ID_20,
+                        RPC_INT(location),
+                        RPC_SIZEI(count),
+                        RPC_INT(size),
+                        v,
+                        (size_t)size);
+   }
+}
+
+GL_API void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat *v)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      int size = clamp_uniform_size( (int)(count * 4 * sizeof(GLfloat)));
+
+      RPC_CALL4_IN_CTRL(glUniform4fv_impl_20,
+                        thread,
+                        GLUNIFORM4FV_ID_20,
+                        RPC_INT(location),
+                        RPC_SIZEI(count),
+                        RPC_INT(size),
+                        v,
+                        (size_t)size);
+   }
+}
+
+/*
+   If transpose is GL_FALSE, each matrix is assumed to be supplied in column major order.
+   If transpose is GL_TRUE, each matrix is assumed to be supplied in row major order.
+*/
+
+GL_API void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      int size = clamp_uniform_size( (int)(count * 2 * 2 * sizeof(GLfloat)));
+
+      RPC_CALL5_IN_CTRL(glUniformMatrix2fv_impl_20,
+                        thread,
+                        GLUNIFORMMATRIX2FV_ID_20,
+                        RPC_INT(location),
+                        RPC_SIZEI(count),
+                        RPC_BOOLEAN(transpose),
+                        RPC_INT(size),
+                        value,
+                        (size_t)size);
+   }
+}
+
+GL_API void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      int size = clamp_uniform_size( (int)(count * 3 * 3 * sizeof(GLfloat)));
+
+      RPC_CALL5_IN_CTRL(glUniformMatrix3fv_impl_20,
+                        thread,
+                        GLUNIFORMMATRIX3FV_ID_20,
+                        RPC_INT(location),
+                        RPC_SIZEI(count),
+                        RPC_BOOLEAN(transpose),
+                        RPC_INT(size),
+                        value,
+                        (size_t)size);
+   }
+}
+
+GL_API void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      int size = clamp_uniform_size( (int)(count * 4 * 4 * sizeof(GLfloat)));
+
+      RPC_CALL5_IN_CTRL(glUniformMatrix4fv_impl_20,
+                        thread,
+                        GLUNIFORMMATRIX4FV_ID_20,
+                        RPC_INT(location),
+                        RPC_SIZEI(count),
+                        RPC_BOOLEAN(transpose),
+                        RPC_INT(size),
+                        value,
+                        (size_t)size);
+   }
+}
+
+GL_API void GL_APIENTRY glUseProgram (GLuint program) // S
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL1(glUseProgram_impl_20,
+                thread,
+                GLUSEPROGRAM_ID_20,
+                RPC_UINT(program));
+   }
+}
+
+GL_API void GL_APIENTRY glValidateProgram (GLuint program)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL1(glValidateProgram_impl_20,
+                thread,
+                GLVALIDATEPROGRAM_ID_20,
+                RPC_UINT(program));
+   }
+}
+
+GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint indx, GLfloat x)
+{
+   glintAttrib(GLXX_API_20, indx, x, 0.0f, 0.0f, 1.0f);
+}
+
+GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y)
+{
+   glintAttrib(GLXX_API_20, indx, x, y, 0.0f, 1.0f);
+}
+
+GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z)
+{
+   glintAttrib(GLXX_API_20, indx, x, y, z, 1.0f);
+}
+
+GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w)
+{
+   glintAttrib(GLXX_API_20, indx, x, y, z, w);
+}
+
+GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint indx, const GLfloat *values)
+{
+   glintAttrib(GLXX_API_20, indx, values[0], 0.0f, 0.0f, 1.0f);
+}
+
+GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint indx, const GLfloat *values)
+{
+   glintAttrib(GLXX_API_20, indx, values[0], values[1], 0.0f, 1.0f);
+}
+
+GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint indx, const GLfloat *values)
+{
+   glintAttrib(GLXX_API_20, indx, values[0], values[1], values[2], 1.0f);
+}
+
+GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint indx, const GLfloat *values)
+{
+   glintAttrib(GLXX_API_20, indx, values[0], values[1], values[2], values[3]);
+}
+
+static bool is_vertex_attrib_size(GLint size)
+{
+   return size >= 1 && size <= 4;
+}
+
+static bool is_vertex_attrib_type(GLenum type)
+{
+   return type == GL_BYTE ||
+          type == GL_UNSIGNED_BYTE ||
+          type == GL_SHORT ||
+          type == GL_UNSIGNED_SHORT ||
+          type == GL_FLOAT ||
+          type == GL_FIXED ||
+          type == GL_HALF_FLOAT_OES;
+}
+
+GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void *ptr)
+{
+   if (is_vertex_attrib_size(size) && stride >= 0) {
+      if (is_vertex_attrib_type(type) || type == GL_HALF_FLOAT_OES) {
+         glintAttribPointer(GLXX_API_20, indx, size, type, normalized, stride, ptr);
+      } else
+         glxx_set_error_api(GLXX_API_20, GL_INVALID_ENUM);
+   } else
+      glxx_set_error_api(GLXX_API_20, GL_INVALID_VALUE);
+}
+
+static bool is_vertex_size(GLint size)
+{
+   return size == 2 ||
+          size == 3 ||
+          size == 4;
+}
+
+static bool is_vertex_type(GLenum type)
+{
+   return type == GL_BYTE ||
+          type == GL_SHORT ||
+          type == GL_FIXED ||
+          type == GL_FLOAT;
+}
+
+GL_API void GL_APIENTRY glVertexPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer)
+{
+   if (is_vertex_type(type)) {
+      if (is_vertex_size(size) && is_aligned(type, (size_t)pointer) && is_aligned(type, (size_t)stride) && stride >= 0) {
+         glintAttribPointer(GLXX_API_11, GL11_IX_VERTEX, size, type, GL_FALSE, stride, pointer);
+      } else
+         glxx_set_error_api(GLXX_API_11, GL_INVALID_VALUE);
+   } else
+      glxx_set_error_api(GLXX_API_11, GL_INVALID_ENUM);
+}
+
+GL_API void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL4(glViewport_impl,
+                thread,
+                GLVIEWPORT_ID,
+                RPC_INT(x),
+                RPC_INT(y),
+                RPC_SIZEI(width),
+                RPC_SIZEI(height));
+   }
+}
+/*****************************************************************************************/
+/*                             OES extension functions                           */
+/*****************************************************************************************/
+
+static bool is_point_size_type(GLenum type)
+{
+   return type == GL_FIXED ||
+          type == GL_FLOAT;
+}
+
+GL_API void GL_APIENTRY glPointSizePointerOES (GLenum type, GLsizei stride, const GLvoid *pointer)
+{
+   if (is_point_size_type(type)) {
+      if (is_aligned(type, (size_t)pointer) && is_aligned(type, (size_t)stride) && stride >= 0) {
+         glintAttribPointer(GLXX_API_11, GL11_IX_POINT_SIZE, 1, type, GL_FALSE, stride, pointer);
+      } else
+         glxx_set_error_api(GLXX_API_11, GL_INVALID_VALUE);
+   } else
+      glxx_set_error_api(GLXX_API_11, GL_INVALID_ENUM);
+}
+
+/* OES_shader_source */
+GL_APICALL void GL_APIENTRY glCompileShader (GLuint shader)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL1(glCompileShader_impl_20,
+                thread,
+                GLCOMPILESHADER_ID_20,
+                RPC_UINT(shader));
+   }
+}
+
+GL_APICALL void GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      RPC_CALL3_OUT_CTRL(glGetShaderiv_impl_20,
+                         thread,
+                         GLGETSHADERIV_ID_20,
+                         RPC_ENUM(shader),
+                         RPC_ENUM(pname),
+                         params);
+   }
+}
+
+GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei *length, char *infolog)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+#ifdef RPC_DIRECT
+      RPC_CALL4(glGetShaderInfoLog_impl_20, thread, no_id, shader, bufsize, length, infolog);
+#else
+      GLuint result[1];
+
+      rpc_begin(thread);
+
+      RPC_CALL3_OUT_CTRL(no_function,
+                         thread,
+                         GLGETSHADERINFOLOG_ID_20,
+                         RPC_UINT(shader),
+                         RPC_SIZEI(bufsize),
+                         result);
+
+      if (length)
+         *length = (GLsizei)result[0];
+
+      read_out_bulk(thread, infolog);
+
+      rpc_end(thread);
+#endif
+   }
+}
+
+GL_APICALL void GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei *length, char *source)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+#ifdef RPC_DIRECT
+      RPC_CALL4(glGetShaderSource_impl_20, thread, no_id, shader, bufsize, length, source);
+#else
+      GLuint result[1];
+
+      rpc_begin(thread);
+
+      RPC_CALL3_OUT_CTRL(no_function,
+                         thread,
+                         GLGETSHADERSOURCE_ID_20,
+                         RPC_UINT(shader),
+                         RPC_SIZEI(bufsize),
+                         result);
+
+      if (length)
+         *length = (GLsizei)result[0];
+
+      read_out_bulk(thread, source);
+
+      rpc_end(thread);
+#endif
+   }
+}
+
+GL_APICALL void GL_APIENTRY glReleaseShaderCompiler(void)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+   }
+}
+
+GL_APICALL void GL_APIENTRY glShaderBinary (GLint n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLint length)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   UNUSED(n);
+   UNUSED(shaders);
+   UNUSED(binaryformat);
+   UNUSED(binary);
+   UNUSED(length);
+
+   if (IS_OPENGLES_20(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+      set_error(state, GL_INVALID_ENUM);
+   }
+}
+
+GL_APICALL void GL_APIENTRY glShaderSource(GLuint shader, GLsizei count, const char **string, const GLint *length)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+#ifdef RPC_DIRECT
+      RPC_CALL4(glShaderSource_impl_20, thread, no_id, shader,
+                             count,
+                             string,
+                             length);
+#else
+      /*
+         calculate total workspace required for string, length and source
+      */
+#ifdef __SYMBIAN32__
+
+      int total = (int)(rpc_pad_bulk(count * 4) + rpc_pad_bulk(count * 4));
+      int i;
+
+      for (i = 0; i < count; i++) {
+         if (!length || length[i] < 0)
+            total += rpc_pad_bulk(string[i] ? (int)strlen(string[i]) + 1 : 1);
+         else
+            total += rpc_pad_bulk(length[i]);
+      }
+
+      rpc_begin(thread);
+
+      // Assume worst-case (need to compute and send all lengths) - include
+      // the 5 words we're sending in the RPC_CALL4() (do we need to do this?)
+      //
+      rpc_send_ctrl_begin(thread, (count + 5) * sizeof(GLint) );
+
+      RPC_CALL4(no_function,
+                thread,
+                GLSHADERSOURCE_ID_20,
+                RPC_UINT(shader),
+                RPC_SIZEI(count),
+                RPC_INT(total),
+                RPC_BOOLEAN(length ? 1 : 0));
+
+      if (length)
+         rpc_send_bulk(thread, length, count * sizeof(GLint));
+
+//Send all lengths before the first bulk transfer of a line of source code
+//NB this is a temporary fix until issues, with our bulk transfers and the
+//rpc assumptions, have been resolved
+//NB assumes that the line count numbers all fit in the merge buffer
+//which is why a more permanent fix is needed
+      for (i = 0; i < count; i++) {
+         GLint len;
+
+         if (!length || length[i] < 0) {
+            len = string[i] ? (GLint) strlen(string[i]) + 1 : 1;
+
+//            rpc_send_bulk(&len, sizeof(GLint)); /* todo: this now violates the semantics of rpc_send_bulk. todo: check for other violations in GL */
+
+            rpc_send_ctrl_write(thread, (uint32_t *)&len, sizeof(GLint));
+         }
+      }
+
+      rpc_send_ctrl_end(thread);  //no more ctrl data to send
+
+      for (i = 0; i < count; i++) {
+         GLint len;
+
+         if (!length || length[i] < 0) {
+            len = string[i] ? strlen(string[i]) + 1 : 1;
+         } else
+            len = length[i];
+
+         /* TODO: we currently treat null strings as empty strings
+          * But we shouldn't need to deal with them (VND-116)
+          */
+         rpc_send_bulk(thread, string[i] ? string[i] : "", (uint32_t)len);
+      }
+      rpc_end(thread);
+#else
+      CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+      int total = (int)(rpc_pad_bulk(count * 4) + rpc_pad_bulk(count * 4) + rpc_pad_bulk(sizeof(GLint)));
+      int i;
+
+      for (i = 0; i < count; i++)
+         if (!length || length[i] < 0)
+            total += rpc_pad_bulk(string[i] ? (int)strlen(string[i]) + 1 : 1);
+         else
+            total += rpc_pad_bulk(length[i]);
+
+      rpc_begin(thread);
+
+      RPC_CALL4(no_function,
+                thread,
+                GLSHADERSOURCE_ID_20,
+                RPC_UINT(shader),
+                RPC_SIZEI(count),
+                RPC_INT(total),
+                RPC_BOOLEAN(length ? 1 : 0));
+
+      if (length)
+         rpc_send_bulk(thread, length, count * sizeof(GLint));
+
+      for (i = 0; i < count; i++) {
+         GLint len;
+
+         if (!length || length[i] < 0) {
+            len = string[i] ? (GLint) strlen(string[i]) + 1 : 1;
+
+            rpc_send_bulk(thread, &len, sizeof(GLint)); /* todo: this now violates the semantics of rpc_send_bulk. todo: check for other violations in GL */
+         } else
+            len = length[i];
+
+         /* TODO: we currently treat null strings as empty strings
+          * But we shouldn't need to deal with them (VND-116)
+          */
+         rpc_send_bulk(thread, string[i] ? string[i] : "", (uint32_t)len);
+      }
+
+      rpc_end(thread);
+#endif
+#endif
+   }
+}
+
+/* OES_framebuffer_object */
+
+GLboolean glxx_client_IsRenderbuffer(GLuint renderbuffer)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      return RPC_BOOLEAN_RES(RPC_CALL1_RES(glIsRenderbuffer_impl,
+                                           thread,
+                                           GLISRENDERBUFFER_ID,
+                                           RPC_UINT(renderbuffer)));
+   }
+
+   return 0;
+}
+
+
+GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer(GLuint renderbuffer)
+{
+   return glxx_client_IsRenderbuffer(renderbuffer);
+}
+
+void glxx_client_BindRenderbuffer(GLenum target, GLuint renderbuffer)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL2(glBindRenderbuffer_impl,
+                thread,
+                GLBINDRENDERBUFFER_ID,
+                RPC_ENUM(target),
+                RPC_UINT(renderbuffer));
+   }
+}
+
+GL_APICALL void GL_APIENTRY glBindRenderbuffer(GLenum target, GLuint renderbuffer)
+{
+   glxx_client_BindRenderbuffer(target, renderbuffer);
+}
+
+
+void glxx_client_DeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   int offset = 0;
+
+   do {
+      int32_t items = (int32_t) (KHDISPATCH_WORKSPACE_SIZE / sizeof(GLuint));
+      int32_t batch = _min(items, (int32_t)n);
+
+      if (IS_OPENGLES_11_OR_20(thread)) {
+         RPC_CALL2_IN_BULK(glDeleteRenderbuffers_impl,
+                           thread,
+                           GLDELETERENDERBUFFERS_ID,
+                           RPC_SIZEI(batch),
+                           renderbuffers + offset,
+                           batch > 0 ? batch * sizeof(GLuint) : 0);
+      }
+
+      offset += batch;
+      n -= batch;
+   } while (n > 0);
+}
+
+GL_APICALL void GL_APIENTRY glDeleteRenderbuffers(GLsizei n, const GLuint *renderbuffers)
+{
+   glxx_client_DeleteRenderbuffers(n, renderbuffers);
+}
+
+void glxx_client_GenRenderbuffers(GLsizei n, GLuint *renderbuffers)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   int offset = 0;
+
+   do {
+      int32_t items = (int32_t)(KHDISPATCH_WORKSPACE_SIZE / sizeof(GLuint));
+      int32_t batch = _min(items, (int32_t)n);
+
+      if (IS_OPENGLES_11_OR_20(thread)) {
+         RPC_CALL2_OUT_BULK(glGenRenderbuffers_impl,
+                            thread,
+                            GLGENRENDERBUFFERS_ID,
+                            RPC_SIZEI(batch),
+                            renderbuffers + offset);
+      }
+
+      offset += batch;
+      n -= batch;
+   } while (n > 0);
+}
+
+GL_APICALL void GL_APIENTRY glGenRenderbuffers(GLsizei n, GLuint *renderbuffers)
+{
+   glxx_client_GenRenderbuffers(n, renderbuffers);
+}
+
+void glxx_client_RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL4(glRenderbufferStorage_impl,
+                thread,
+                GLRENDERBUFFERSTORAGE_ID,
+                RPC_ENUM(target),
+                RPC_ENUM(internalformat),
+                RPC_SIZEI(width),
+                RPC_SIZEI(height));
+   }
+}
+
+GL_APICALL void GL_APIENTRY glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
+{
+   glxx_client_RenderbufferStorage(target, internalformat, width, height);
+}
+
+void glxx_client_GetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL3_OUT_CTRL(glGetRenderbufferParameteriv_impl,
+                         thread,
+                         GLGETRENDERBUFFERPARAMETERIV_ID,
+                         RPC_ENUM(target),
+                         RPC_ENUM(pname),
+                         params);
+   }
+}
+
+GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params)
+{
+   glxx_client_GetRenderbufferParameteriv(target, pname, params);
+}
+
+GLboolean glxx_client_IsFramebuffer(GLuint framebuffer)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      return RPC_BOOLEAN_RES(RPC_CALL1_RES(glIsFramebuffer_impl,
+                                           thread,
+                                           GLISFRAMEBUFFER_ID,
+                                           RPC_UINT(framebuffer)));
+   }
+
+   return 0;
+}
+
+GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer(GLuint framebuffer)
+{
+   return glxx_client_IsFramebuffer(framebuffer);
+}
+
+/*
+   Spec deviation:
+      eglMakeCurrent(gles2.0 context, pixmap surface)
+      glBindFramebuffer(invalid framebuffer id)
+      glDrawSomeStuff()
+      glFinish()
+      Pixmap will not have been updated, as client assumes that rendering is
+      taking place outside of the default framebuffer
+*/
+
+void glxx_client_BindFramebuffer(GLenum target, GLuint framebuffer)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+      RPC_CALL2(glBindFramebuffer_impl,
+                thread,
+                GLBINDFRAMEBUFFER_ID,
+                RPC_ENUM(target),
+                RPC_UINT(framebuffer));
+
+      //TODO: this may be set incorrectly if there's an error
+      state->default_framebuffer = (framebuffer == 0);
+   }
+}
+
+GL_APICALL void GL_APIENTRY glBindFramebuffer(GLenum target, GLuint framebuffer)
+{
+   glxx_client_BindFramebuffer(target, framebuffer);
+}
+
+void glxx_client_DeleteFramebuffers(GLsizei n, const GLuint *framebuffers)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   int offset = 0;
+
+   do {
+      int32_t items = (int32_t)(KHDISPATCH_WORKSPACE_SIZE / sizeof(GLuint));
+      int32_t batch = _min(items, (int32_t)n);
+
+      if (IS_OPENGLES_11_OR_20(thread)) {
+         RPC_CALL2_IN_BULK(glDeleteFramebuffers_impl,
+                           thread,
+                           GLDELETEFRAMEBUFFERS_ID,
+                           RPC_SIZEI(batch),
+                           framebuffers + offset,
+                           batch > 0 ? batch * sizeof(GLuint) : 0);
+      }
+
+      offset += batch;
+      n -= batch;
+   } while (n > 0);
+}
+
+GL_APICALL void GL_APIENTRY glDeleteFramebuffers(GLsizei n, const GLuint *framebuffers)
+{
+   glxx_client_DeleteFramebuffers(n, framebuffers);
+}
+
+void glxx_client_GenFramebuffers(GLsizei n, GLuint *framebuffers)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   int offset = 0;
+
+   do {
+      int32_t items = (int32_t)(KHDISPATCH_WORKSPACE_SIZE / sizeof(GLuint));
+      int32_t batch = _min(items, (int32_t)n);
+
+      if (IS_OPENGLES_11_OR_20(thread)) {
+         RPC_CALL2_OUT_BULK(glGenFramebuffers_impl,
+                            thread,
+                            GLGENFRAMEBUFFERS_ID,
+                            RPC_SIZEI(batch),
+                            framebuffers + offset);
+      }
+
+      offset += batch;
+      n -= batch;
+   } while (n > 0);
+}
+
+GL_APICALL void GL_APIENTRY glGenFramebuffers(GLsizei n, GLuint *framebuffers)
+{
+   glxx_client_GenFramebuffers(n, framebuffers);
+}
+
+GLenum glxx_client_CheckFramebufferStatus(GLenum target)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      return RPC_ENUM_RES(RPC_CALL1_RES(glCheckFramebufferStatus_impl,
+                           thread,
+                           GLCHECKFRAMEBUFFERSTATUS_ID,
+                           RPC_ENUM(target)));
+   }
+
+   return GL_NONE;
+}
+
+GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus(GLenum target)
+{
+   return glxx_client_CheckFramebufferStatus(target);
+}
+
+void glxx_client_FramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL5(glFramebufferTexture2D_impl,
+                thread,
+                GLFRAMEBUFFERTEXTURE2D_ID,
+                RPC_ENUM(target),
+                RPC_ENUM(attachment),
+                RPC_ENUM(textarget),
+                RPC_UINT(texture),
+                RPC_INT(level));
+   }
+}
+
+GL_APICALL void GL_APIENTRY glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level)
+{
+   glxx_client_FramebufferTexture2D(target, attachment, textarget, texture, level);
+}
+
+void glxx_client_FramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL4(glFramebufferRenderbuffer_impl,
+                thread,
+                GLFRAMEBUFFERRENDERBUFFER_ID,
+                RPC_ENUM(target),
+                RPC_ENUM(attachment),
+                RPC_ENUM(renderbuffertarget),
+                RPC_UINT(renderbuffer));
+   }
+}
+
+GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer)
+{
+   glxx_client_FramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
+}
+
+void glxx_client_GetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint *params)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL4_OUT_CTRL(glGetFramebufferAttachmentParameteriv_impl,
+                         thread,
+                         GLGETFRAMEBUFFERATTACHMENTPARAMETERIV_ID,
+                         RPC_ENUM(target),
+                         RPC_ENUM(attachment),
+                         RPC_ENUM(pname),
+                         params);
+   }
+}
+
+GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint *params)
+{
+   glxx_client_GetFramebufferAttachmentParameteriv(target, attachment, pname, params);
+}
+
+void glxx_client_GenerateMipmap(GLenum target)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread)) {
+      RPC_CALL1(glGenerateMipmap_impl,
+                thread,
+                GLGENERATEMIPMAP_ID,
+                RPC_ENUM(target));
+   }
+}
+
+GL_APICALL void GL_APIENTRY glGenerateMipmap(GLenum target)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      glxx_client_GenerateMipmap(target);
+   }
+}
+
+/* OES_shader_source + OES_shader_binary */
+GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint *range, GLint *precision)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_20(thread)) {
+      GLint result[3];
+
+      RPC_CALL3_OUT_CTRL(glGetShaderPrecisionFormat_impl_20,
+                         thread,
+                         GLGETSHADERPRECISIONFORMAT_ID_20,
+                         RPC_ENUM(shadertype),
+                         RPC_ENUM(precisiontype),
+                         result);
+
+      if (range) {
+         range[0] = result[0];
+         range[1] = result[1];
+      }
+      if (precision)
+         *precision = result[2];
+   }
+}
+
+GL_APICALL void GL_APIENTRY glDiscardFramebufferEXT(GLenum target, GLsizei numAttachments, const GLenum *attachments)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11_OR_20(thread))
+   {
+      RPC_CALL3_IN_CTRL(glDiscardFramebufferEXT_impl,
+                thread,
+                GLDISCARDFRAMEBUFFEREXT_ID,
+                RPC_ENUM(target),
+                RPC_SIZEI(numAttachments),
+                attachments,
+                numAttachments * sizeof(GLenum));
+   }
+}
+
+static void glxx_client_state_init(GLXX_CLIENT_STATE_T *state)
+{
+   int i;
+
+   state->error = GL_NO_ERROR;
+
+   state->alignment.pack = 4;
+   state->alignment.unpack = 4;
+
+   state->bound_buffer.array = 0;
+   state->bound_buffer.element_array = 0;
+
+   for (i = 0; i < GLXX_CONFIG_MAX_VERTEX_ATTRIBS; i++) {
+      state->attrib[i].enabled = GL_FALSE;
+      state->attrib[i].size = 4;
+      state->attrib[i].type = GL_FLOAT;
+      state->attrib[i].normalized = GL_FALSE;
+      state->attrib[i].stride = 0;
+      state->attrib[i].pointer = NULL;
+      state->attrib[i].buffer = 0;
+      state->attrib[i].value[0] = 0.0f;
+      state->attrib[i].value[1] = 0.0f;
+      state->attrib[i].value[2] = 0.0f;
+      state->attrib[i].value[3] = 1.0f;
+   }
+
+   state->render_callback = NULL;
+   state->flush_callback = NULL;
+
+   //buffer info
+   khrn_pointer_map_init(&state->buffers,8);
+
+}
+
+int gl11_client_state_init(GLXX_CLIENT_STATE_T *state)
+{
+   state->type = OPENGL_ES_11;
+
+   //perform common initialisation
+   glxx_client_state_init(state);
+   //gl2.0 specific
+
+   state->active_texture.client = GL_TEXTURE0;
+   state->active_texture.server = GL_TEXTURE0;
+
+   gl11_attrib_init(state->attrib);
+
+#ifdef GLXX_NO_VERTEX_CACHE
+   return 1;
+#else
+   return khrn_cache_init(&state->cache);
+#endif
+}
+
+int gl20_client_state_init(GLXX_CLIENT_STATE_T *state)
+{
+   state->type = OPENGL_ES_20;
+
+   //perform common initialisation
+   glxx_client_state_init(state);
+   //gl2.0 specific
+
+   state->default_framebuffer = true;
+
+   gl20_attrib_init(state->attrib);
+
+#ifdef GLXX_NO_VERTEX_CACHE
+   return 1;
+#else
+   return khrn_cache_init(&state->cache);
+#endif
+}
+
+static void callback_delete_buffer_info(KHRN_POINTER_MAP_T *map, uint32_t key, void *value, void *data)
+{
+   UNUSED(map);
+   UNUSED(data);
+   UNUSED(key);
+   khrn_platform_free(value);
+}
+
+void glxx_client_state_free(GLXX_CLIENT_STATE_T *state)
+{
+   khrn_pointer_map_iterate(&state->buffers, callback_delete_buffer_info, NULL);
+   khrn_pointer_map_term(&state->buffers);
+#ifndef GLXX_NO_VERTEX_CACHE
+   khrn_cache_term(&state->cache);
+#endif
+   khrn_platform_free(state);
+}
+
+static bool attrib_translate(GLXX_CLIENT_STATE_T *state, uint32_t *indx)
+{
+   if (state->type == OPENGL_ES_11)
+   {
+      if (*indx == GL11_IX_CLIENT_ACTIVE_TEXTURE)
+      {
+         *indx = GL11_IX_TEXTURE_COORD + state->active_texture.client - GL_TEXTURE0;
+      }
+      vcos_assert(*indx < GL11_IX_MAX_ATTRIBS);
+      return true;
+   }
+   else
+   {
+      vcos_assert(state->type == OPENGL_ES_20);
+      if (*indx < GL20_CONFIG_MAX_VERTEX_ATTRIBS)
+      {
+         return true;
+      }
+      else
+      {
+         glxx_set_error(state, GL_INVALID_VALUE);
+         return false;
+      }
+   }
+}
+
+void glintAttribPointer (uint32_t api, uint32_t indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *ptr)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_API(thread, api))
+   {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+      if (attrib_translate(state, &indx))
+      {
+         state->attrib[indx].size = size;
+         state->attrib[indx].type = type;
+         state->attrib[indx].normalized = normalized;
+         state->attrib[indx].stride = stride;
+         state->attrib[indx].pointer = ptr;
+         state->attrib[indx].buffer = state->bound_buffer.array;
+
+         RPC_CALL7(glintAttribPointer_impl,
+                   thread,
+                   GLINTATTRIBPOINTER_ID,
+                   RPC_UINT(api),
+                   RPC_UINT(indx),
+                   RPC_INT(size),
+                   RPC_ENUM(type),
+                   RPC_BOOLEAN(normalized),
+                   RPC_SIZEI(stride),
+                   RPC_INTPTR((GLintptr)ptr));
+      }
+   }
+}
+
+void glintAttrib (uint32_t api, uint32_t indx, float x, float y, float z, float w)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_API(thread, api))
+   {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+      if (attrib_translate(state, &indx))
+      {
+         vcos_assert(indx < GLXX_CONFIG_MAX_VERTEX_ATTRIBS);
+         state->attrib[indx].value[0] = x;
+         state->attrib[indx].value[1] = y;
+         state->attrib[indx].value[2] = z;
+         state->attrib[indx].value[3] = w;
+
+         RPC_CALL6(glintAttrib_impl,
+                   thread,
+                   GLINTATTRIB_ID,
+                   RPC_UINT(api),
+                   RPC_UINT(indx),
+                   RPC_FLOAT(x),
+                   RPC_FLOAT(y),
+                   RPC_FLOAT(z),
+                   RPC_FLOAT(w));
+      }
+   }
+}
+
+/*
+Separate path for glColor because it needs to update the material
+*/
+
+void glintColor (float x, float y, float z, float w)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_11(thread))
+   {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+
+      state->attrib[GL11_IX_COLOR].value[0] = x;
+      state->attrib[GL11_IX_COLOR].value[1] = y;
+      state->attrib[GL11_IX_COLOR].value[2] = z;
+      state->attrib[GL11_IX_COLOR].value[3] = w;
+
+      RPC_CALL4(glintColor_impl_11,
+                thread,
+                GLINTCOLOR_ID_11,
+                RPC_FLOAT(x),
+                RPC_FLOAT(y),
+                RPC_FLOAT(z),
+                RPC_FLOAT(w));
+   }
+}
+
+void glintAttribEnable(uint32_t api, uint32_t indx, bool enabled)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_API(thread, api))
+   {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+      if (attrib_translate(state, &indx))
+      {
+         state->attrib[indx].enabled = enabled;
+
+         RPC_CALL3(glintAttribEnable_impl,
+                   thread,
+                   GLINTATTRIBENABLE_ID,
+                   RPC_UINT(api),
+                   RPC_UINT(indx),
+                   RPC_BOOLEAN(enabled));
+      }
+   }
+}
+
+void *glintAttribGetPointer(uint32_t api, uint32_t indx)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (IS_OPENGLES_API(thread, api))
+   {
+      GLXX_CLIENT_STATE_T *state = GLXX_GET_CLIENT_STATE(thread);
+      if (attrib_translate(state, &indx))
+         return (void *)state->attrib[indx].pointer;
+   }
+   return NULL;
+}
+
+//TODO we need these to get the conformance test to build
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+GL_API void GL_APIENTRY glTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels) { UNUSED(target); UNUSED(level); UNUSED(internalformat); UNUSED(width); UNUSED(height); UNUSED(depth); UNUSED(border); UNUSED(format); UNUSED(type); UNUSED(pixels); }
+GL_API void GL_APIENTRY glTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels) { UNUSED(target); UNUSED(level); UNUSED(xoffset); UNUSED(yoffset); UNUSED(zoffset); UNUSED(width); UNUSED(height); UNUSED(depth); UNUSED(format); UNUSED(type); UNUSED(pixels); }
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/interface/khronos/glxx/glxx_client.h b/interface/khronos/glxx/glxx_client.h
new file mode 100755 (executable)
index 0000000..82c1d03
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef GLXX_CLIENT_H
+#define GLXX_CLIENT_H
+
+#include "interface/khronos/common/khrn_client.h"
+#include "interface/khronos/common/khrn_client_platform.h"
+#include "interface/khronos/common/khrn_client_cache.h"
+
+#include "interface/khronos/egl/egl_client_context.h"
+
+#include "interface/khronos/glxx/glxx_int_attrib.h"
+#include "interface/khronos/glxx/glxx_int_config.h"
+
+/*
+   Called just before a rendering command (i.e. anything which could modify
+   the draw surface) is executed
+ */
+typedef void (*GL_RENDER_CALLBACK_T)(void);
+
+/*
+   Called just after rendering has been compeleted (i.e. flush or finish).
+   wait should be true for finish-like behaviour, false for flush-like
+   behaviour
+*/
+typedef void (*GL_FLUSH_CALLBACK_T)(bool wait);
+
+/*
+   GL 1.1 and 2.0 client state structure
+*/
+
+typedef struct buffer_info {
+   GLuint id;
+   GLsizeiptr cached_size;
+   void * mapped_pointer;
+   GLsizeiptr mapped_size;
+} GLXX_BUFFER_INFO_T;
+
+typedef struct {
+   
+   GLenum error;
+   
+   /*
+      Open GL version
+
+      Invariants:
+
+      OPENGL_ES_11 or OPENGL_ES_20
+   */
+   
+   unsigned int type;    
+
+   /*
+      alignments
+
+      used to work out how much data to send for glTexImage2D()
+   */
+
+   struct {
+      GLint pack;
+      GLint unpack;
+   } alignment;
+
+   struct {
+      GLuint array;
+      GLuint element_array;
+   } bound_buffer;
+
+   GLXX_ATTRIB_T attrib[GLXX_CONFIG_MAX_VERTEX_ATTRIBS];
+
+   GL_RENDER_CALLBACK_T render_callback;
+   GL_FLUSH_CALLBACK_T flush_callback;
+
+   KHRN_CACHE_T cache;
+   
+   //gl 1.1 specific
+   struct {
+      GLenum client;
+      GLenum server;
+   } active_texture;
+
+   //gl 2.0 specific
+   bool default_framebuffer;   //render_callback only called if we're rendering to default framebuffer
+
+   KHRN_POINTER_MAP_T buffers;
+
+} GLXX_CLIENT_STATE_T;
+
+extern int gl11_client_state_init(GLXX_CLIENT_STATE_T *state);
+extern int gl20_client_state_init(GLXX_CLIENT_STATE_T *state);
+
+extern void glxx_client_state_free(GLXX_CLIENT_STATE_T *state);
+
+#define GLXX_GET_CLIENT_STATE(thread) glxx_get_client_state(thread)
+
+static INLINE GLXX_CLIENT_STATE_T *glxx_get_client_state(CLIENT_THREAD_STATE_T *thread)
+{
+   EGL_CONTEXT_T *context = thread->opengl.context;
+   GLXX_CLIENT_STATE_T * state;
+   vcos_assert( context != NULL );
+   vcos_assert(context->type == OPENGL_ES_11 || context->type == OPENGL_ES_20);
+   state = (GLXX_CLIENT_STATE_T *)context->state;
+   vcos_assert(context->type == state->type);
+   return state;
+}
+
+#define GLXX_API_11 (1<<(OPENGL_ES_11))
+#define GLXX_API_20 (1<<(OPENGL_ES_20))
+#define GLXX_API_11_OR_20 (GLXX_API_11|GLXX_API_20)
+
+static INLINE bool glxx_api_ok(uint32_t api, EGL_CONTEXT_TYPE_T type)
+{
+   return !!(api & (1<<type));
+}
+
+#define IS_OPENGLES_11(thread)       is_opengles_api(thread, GLXX_API_11)
+#define IS_OPENGLES_20(thread)       is_opengles_api(thread, GLXX_API_20)
+#define IS_OPENGLES_11_OR_20(thread) is_opengles_api(thread, GLXX_API_11_OR_20)
+#define IS_OPENGLES_API(thread, api) is_opengles_api(thread, api)
+
+static INLINE bool is_opengles_api(CLIENT_THREAD_STATE_T *thread, uint32_t api)
+{
+   EGL_CONTEXT_T *context = thread->opengl.context;
+   return context && glxx_api_ok(api, context->type);
+}
+
+extern void glxx_buffer_info_get(GLXX_CLIENT_STATE_T *state, GLenum target, GLXX_BUFFER_INFO_T* buffer);
+extern void glxx_buffer_info_set(GLXX_CLIENT_STATE_T *state, GLenum target, GLXX_BUFFER_INFO_T* buffer);
+extern void glxx_set_error(GLXX_CLIENT_STATE_T *state, GLenum error);
+extern void glxx_set_error_api(uint32_t api, GLenum error);
+
+/* Fake GL API calls */
+void glintAttribPointer (uint32_t api, uint32_t indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid *ptr);
+void glintAttrib (uint32_t api, uint32_t indx, float x, float y, float z, float w);
+void glintColor(float red, float green, float blue, float alpha);
+void glintAttribEnable(uint32_t api, uint32_t indx, bool enabled);
+void *glintAttribGetPointer(uint32_t api, uint32_t indx);
+
+#endif
diff --git a/interface/khronos/glxx/glxx_int_attrib.h b/interface/khronos/glxx/glxx_int_attrib.h
new file mode 100755 (executable)
index 0000000..20a992a
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef GLXX_INT_ATTRIB_H
+#define GLXX_INT_ATTRIB_H
+
+#include "interface/khronos/include/GLES/gl.h"
+#include "interface/khronos/include/GLES2/gl2.h"
+#include "interface/khronos/glxx/gl11_int_config.h"
+#include "interface/khronos/glxx/glxx_int_config.h"
+
+#include <stddef.h>
+
+typedef struct {
+   GLboolean enabled;
+
+   GLint size;
+   GLenum type;
+   GLboolean normalized;
+   GLsizei stride;
+
+   const GLvoid *pointer;
+
+   GLuint buffer;
+
+   GLfloat value[4];
+} GLXX_ATTRIB_T;
+
+
+/* GL 1.1 specific For indexing into arrays of handles/pointers */
+#define GL11_IX_COLOR 1//0
+#define GL11_IX_NORMAL 2//1
+#define GL11_IX_VERTEX 0//2
+#define GL11_IX_TEXTURE_COORD 3
+#define GL11_IX_POINT_SIZE 7
+#define GL11_IX_MATRIX_WEIGHT 8
+#define GL11_IX_MATRIX_INDEX 9
+#define GL11_IX_MAX_ATTRIBS 10
+
+/* Special values passed to glintAttrib etc. instead of indices */
+#define GL11_IX_CLIENT_ACTIVE_TEXTURE 0x80000000
+
+static INLINE void gl20_attrib_init(GLXX_ATTRIB_T *attrib)
+{
+   uint32_t i;
+   for (i = 0; i < GLXX_CONFIG_MAX_VERTEX_ATTRIBS; i++)
+   {
+      attrib[i].enabled = GL_FALSE;
+      attrib[i].size = 4;
+      attrib[i].type = GL_FLOAT;
+      attrib[i].normalized = GL_FALSE;
+      attrib[i].stride = 0;
+      attrib[i].pointer = NULL;
+      attrib[i].buffer = 0;
+      attrib[i].value[0] = 0.0f;
+      attrib[i].value[1] = 0.0f;
+      attrib[i].value[2] = 0.0f;
+      attrib[i].value[3] = 1.0f;
+   }
+}
+
+static INLINE void gl11_attrib_init(GLXX_ATTRIB_T *attrib)
+{
+   int32_t i, indx;
+
+   gl20_attrib_init(attrib);
+
+   //vertex
+   attrib[GL11_IX_VERTEX].size = 4;
+   attrib[GL11_IX_VERTEX].normalized = GL_FALSE;
+   attrib[GL11_IX_VERTEX].value[0] = 0.0f;
+   attrib[GL11_IX_VERTEX].value[1] = 0.0f;
+   attrib[GL11_IX_VERTEX].value[2] = 0.0f;
+   attrib[GL11_IX_VERTEX].value[3] = 1.0f;
+
+   //color
+   attrib[GL11_IX_COLOR].size = 4;
+   attrib[GL11_IX_COLOR].normalized = GL_TRUE;
+   attrib[GL11_IX_COLOR].value[0] = 1.0f;
+   attrib[GL11_IX_COLOR].value[1] = 1.0f;
+   attrib[GL11_IX_COLOR].value[2] = 1.0f;
+   attrib[GL11_IX_COLOR].value[3] = 1.0f;
+
+   //normal
+   attrib[GL11_IX_NORMAL].size = 3;
+   attrib[GL11_IX_NORMAL].normalized = GL_TRUE;
+   attrib[GL11_IX_NORMAL].value[0] = 0.0f;
+   attrib[GL11_IX_NORMAL].value[1] = 0.0f;
+   attrib[GL11_IX_NORMAL].value[2] = 1.0f;
+
+   for (i = 0; i < GL11_CONFIG_MAX_TEXTURE_UNITS; i++) {
+      indx = GL11_IX_TEXTURE_COORD + i;
+      attrib[indx].size = 4;
+      attrib[indx].normalized = GL_FALSE;
+      attrib[indx].value[0] = 0.0f;
+      attrib[indx].value[1] = 0.0f;
+      attrib[indx].value[2] = 0.0f;
+      attrib[indx].value[3] = 1.0f;
+   }
+
+   //point size
+   attrib[GL11_IX_POINT_SIZE].size = 1;
+   attrib[GL11_IX_POINT_SIZE].normalized = GL_FALSE;
+   attrib[GL11_IX_POINT_SIZE].value[0] = 1.0f;
+}
+
+typedef struct
+{
+   uint32_t cache_offset;     /* How far into the cache this attrib starts */
+   uint32_t has_interlock;    /* (Boolean) Whether there is an interlock immediately before this attrib. */
+} GLXX_CACHE_INFO_ENTRY_T;
+
+typedef struct
+{
+   uint32_t send_any;         /* True if we're sending any vertices. If false, remainder of structure is invalid. */
+   GLXX_CACHE_INFO_ENTRY_T entries[GLXX_CONFIG_MAX_VERTEX_ATTRIBS];
+} GLXX_CACHE_INFO_T;
+
+#endif
diff --git a/interface/khronos/glxx/glxx_int_config.h b/interface/khronos/glxx/glxx_int_config.h
new file mode 100755 (executable)
index 0000000..04bc1ea
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef GLXX_INT_CONFIG_H
+#define GLXX_INT_CONFIG_H
+#define GLXX_CONFIG_MAX_VERTEX_ATTRIBS            10
+/* GL 2.0 exposes a maximum of 8 attributes */
+#define GL20_CONFIG_MAX_VERTEX_ATTRIBS             8
+#define GLXX_CONFIG_MAX_TEXTURE_UNITS              8  /* this is
+                                                         max(GL20_CONFIG_MAX_COMBINED_TEXTURE_UNITS,GL11_CONFIG_MAX_TEXTURE_UNITS*/
+#define GLXX_CONFIG_SAMPLES                        4
+#define GLXX_CONFIG_SUBPIXEL_BITS                  4
+
+#define GLXX_CONFIG_MAX_VIEWPORT_SIZE           2048
+#define GLXX_CONFIG_MAX_RENDERBUFFER_SIZE       2048
+
+#endif
diff --git a/interface/khronos/glxx/glxx_int_impl.h b/interface/khronos/glxx/glxx_int_impl.h
new file mode 100755 (executable)
index 0000000..4192a3d
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#if defined(KHRN_IMPL_STRUCT)
+#define FN(type, name, args) type (*name) args;
+#elif defined(KHRN_IMPL_STRUCT_INIT)
+#define FN(type, name, args) name,
+#else
+#define FN(type, name, args) extern type name args;
+#endif
+
+#if defined(V3D_LEAN)
+#include "interface/khronos/include/GLES/gl.h"
+#include "interface/khronos/include/GLES/glext.h"
+#include "interface/khronos/glxx/glxx_int_attrib.h"
+#endif
+
+FN(void, glActiveTexture_impl, (GLenum texture))
+FN(void, glBindBuffer_impl, (GLenum target, GLuint buffer))
+FN(void, glBindTexture_impl, (GLenum target, GLuint texture))
+FN(void, glBlendFuncSeparate_impl, (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha)) // S
+FN(void, glBufferData_impl, (GLenum target, GLsizeiptr size, GLenum usage, const GLvoid *data))
+FN(void, glBufferSubData_impl, (GLenum target, GLintptr offset, GLsizeiptr size, const void *data))
+FN(void, glClear_impl, (GLbitfield mask))
+FN(void, glClearColor_impl, (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha))
+FN(void, glClearDepthf_impl, (GLclampf depth)) // S
+FN(void, glClearStencil_impl, (GLint s)) // S
+FN(void, glColorMask_impl, (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha)) // S
+FN(GLboolean, glCompressedTexImage2D_impl, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void *data))
+FN(void, glCompressedTexSubImage2D_impl, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void *data))
+FN(void, glCopyTexImage2D_impl, (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border))
+FN(void, glCopyTexSubImage2D_impl, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height))
+FN(void, glCullFace_impl, (GLenum mode)) // S
+FN(void, glDeleteBuffers_impl, (GLsizei n, const GLuint *buffers))
+FN(void, glDeleteTextures_impl, (GLsizei n, const GLuint *textures))
+FN(void, glDepthFunc_impl, (GLenum func)) // S
+FN(void, glDepthMask_impl, (GLboolean flag)) // S
+FN(void, glDepthRangef_impl, (GLclampf zNear, GLclampf zFar)) // S
+FN(void, glDisable_impl, (GLenum cap)) // S
+FN(void, glEnable_impl, (GLenum cap)) // S
+FN(GLuint, glFinish_impl, (void))
+FN(void, glFlush_impl, (void))
+FN(void, glFrontFace_impl, (GLenum mode)) // S
+FN(void, glGenBuffers_impl, (GLsizei n, GLuint *buffers))
+FN(void, glGenTextures_impl, (GLsizei n, GLuint *textures))
+FN(GLenum, glGetError_impl, (void))
+FN(int, glGetBooleanv_impl, (GLenum pname, GLboolean *params))
+FN(int, glGetBufferParameteriv_impl, (GLenum target, GLenum pname, GLint *params))
+FN(int, glGetFloatv_impl, (GLenum pname, GLfloat *params))
+FN(int, glGetIntegerv_impl, (GLenum pname, GLint *params))
+FN(int, glGetTexParameteriv_impl, (GLenum target, GLenum pname, GLint *params))
+FN(int, glGetTexParameterfv_impl, (GLenum target, GLenum pname, GLfloat *params))
+FN(void, glHint_impl, (GLenum target, GLenum mode))
+FN(GLboolean, glIsBuffer_impl, (GLuint buffer))
+FN(GLboolean, glIsEnabled_impl, (GLenum cap))
+FN(GLboolean, glIsTexture_impl, (GLuint texture))
+FN(void, glLineWidth_impl, (GLfloat width)) // S
+FN(void, glPolygonOffset_impl, (GLfloat factor, GLfloat units)) // S
+FN(void, glReadPixels_impl, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint alignment, void *pixels))
+FN(void, glSampleCoverage_impl, (GLclampf value, GLboolean invert)) // S
+FN(void, glScissor_impl, (GLint x, GLint y, GLsizei width, GLsizei height)) // S
+FN(void, glStencilFuncSeparate_impl, (GLenum face, GLenum func, GLint ref, GLuint mask)) // S
+FN(void, glStencilMaskSeparate_impl, (GLenum face, GLuint mask)) // S
+FN(void, glStencilOpSeparate_impl, (GLenum face, GLenum fail, GLenum zfail, GLenum zpass)) // S
+FN(GLboolean, glTexImage2D_impl, (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, GLint alignment, const GLvoid *pixels))
+FN(void, glTexParameteri_impl, (GLenum target, GLenum pname, GLint param))
+FN(void, glTexParameterf_impl, (GLenum target, GLenum pname, GLfloat param))
+FN(void, glTexParameteriv_impl, (GLenum target, GLenum pname, const GLint *params))
+FN(void, glTexParameterfv_impl, (GLenum target, GLenum pname, const GLfloat *params))
+FN(void, glTexSubImage2D_impl, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint alignment, const void *pixels))
+FN(void, texSubImage2DAsync_impl, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, GLint alignment, GLint hdata))
+FN(void, glViewport_impl, (GLint x, GLint y, GLsizei width, GLsizei height)) // S
+
+/*****************************************************************************************/
+/*                                 EXT extension functions                               */
+/*****************************************************************************************/
+FN(void, glDiscardFramebufferEXT_impl, (GLenum target, GLsizei numAttachments, const GLenum *attachments))
+
+/*****************************************************************************************/
+/*                                 OES extension functions                               */
+/*****************************************************************************************/
+
+FN(int, glintFindMax_impl, (GLsizei count, GLenum type, uint32_t indices_offset))
+FN(void, glintCacheCreate_impl, (GLsizei offset))
+FN(void, glintCacheDelete_impl, (GLsizei offset))
+FN(void, glintCacheData_impl, (GLsizei offset, GLsizei length, const GLvoid *data))
+FN(GLboolean, glintCacheGrow_impl, (void))
+FN(void, glintCacheUse_impl, (GLsizei count, GLsizei *offset))
+
+FN(void, glintAttribPointer_impl, (uint32_t api, uint32_t indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, GLintptr ptr))
+FN(void, glintAttrib_impl, (uint32_t api, uint32_t indx, float x, float y, float z, float w))
+FN(void, glintAttribEnable_impl, (uint32_t api, uint32_t indx, bool enabled))
+FN(void, glintDrawElements_impl, (GLenum mode, GLsizei count, GLenum type, uint32_t indices_offset, GLXX_CACHE_INFO_T *cache_info))
+
+#if GL_OES_EGL_image
+FN(void, glEGLImageTargetTexture2DOES_impl, (GLenum target, GLeglImageOES image))
+#if EGL_BRCM_global_image
+FN(void, glGlobalImageTexture2DOES_impl, (GLenum target, GLuint id_0, GLuint id_1))
+#endif
+#endif
+
+/* OES_framebuffer_object for ES 1.1 and core in ES 2.0 */
+FN(GLboolean, glIsRenderbuffer_impl, (GLuint renderbuffer))
+FN(void, glBindRenderbuffer_impl, (GLenum target, GLuint renderbuffer))
+FN(void, glDeleteRenderbuffers_impl, (GLsizei n, const GLuint *renderbuffers))
+FN(void, glGenRenderbuffers_impl, (GLsizei n, GLuint *renderbuffers))
+FN(void, glRenderbufferStorage_impl, (GLenum target, GLenum internalformat, GLsizei width, GLsizei height))
+FN(int, glGetRenderbufferParameteriv_impl, (GLenum target, GLenum pname, GLint* params))
+FN(GLboolean, glIsFramebuffer_impl, (GLuint framebuffer))
+FN(void, glBindFramebuffer_impl, (GLenum target, GLuint framebuffer))
+FN(void, glDeleteFramebuffers_impl, (GLsizei n, const GLuint *framebuffers))
+FN(void, glGenFramebuffers_impl, (GLsizei n, GLuint *framebuffers))
+FN(GLenum, glCheckFramebufferStatus_impl, (GLenum target))
+FN(void, glFramebufferTexture2D_impl, (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level))
+FN(void, glFramebufferRenderbuffer_impl, (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer))
+FN(int, glGetFramebufferAttachmentParameteriv_impl, (GLenum target, GLenum attachment, GLenum pname, GLint *params))
+FN(void, glGenerateMipmap_impl, (GLenum target))
+
+#undef FN
diff --git a/interface/khronos/include/EGL/egl.h b/interface/khronos/include/EGL/egl.h
new file mode 100755 (executable)
index 0000000..0471e5a
--- /dev/null
@@ -0,0 +1,329 @@
+/* -*- mode: c; tab-width: 8; -*- */
+/* vi: set sw=4 ts=8: */
+/* Reference version of egl.h for EGL 1.4.
+ * $Revision: 9356 $ on $Date: 2009-10-21 02:52:25 -0700 (Wed, 21 Oct 2009) $
+ */
+
+/*
+** Copyright (c) 2007-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+#ifndef __egl_h_
+#define __egl_h_
+
+/* All platform-dependent types and macro boilerplate (such as EGLAPI
+ * and EGLAPIENTRY) should go in eglplatform.h.
+ */
+#include "eglplatform.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* EGL Types */
+/* EGLint is defined in eglplatform.h */
+typedef unsigned int EGLBoolean;
+typedef unsigned int EGLenum;
+typedef void *EGLConfig;
+typedef void *EGLContext;
+typedef void *EGLDisplay;
+typedef void *EGLSurface;
+typedef void *EGLClientBuffer;
+
+/* EGL Versioning */
+#define EGL_VERSION_1_0                        1
+#define EGL_VERSION_1_1                        1
+#define EGL_VERSION_1_2                        1
+#define EGL_VERSION_1_3                        1
+#define EGL_VERSION_1_4                        1
+
+/* EGL Enumerants. Bitmasks and other exceptional cases aside, most
+ * enums are assigned unique values starting at 0x3000.
+ */
+
+/* EGL aliases */
+#define EGL_FALSE                      ((EGLBoolean)0)
+#define EGL_TRUE                       ((EGLBoolean)1)
+
+/* Out-of-band handle values */
+#define EGL_DEFAULT_DISPLAY            ((EGLNativeDisplayType)0)
+#define EGL_NO_CONTEXT                 ((EGLContext)0)
+#define EGL_NO_DISPLAY                 ((EGLDisplay)0)
+#define EGL_NO_SURFACE                 ((EGLSurface)0)
+
+/* Out-of-band attribute value */
+#define EGL_DONT_CARE                  ((EGLint)-1)
+
+/* Errors / GetError return values */
+#define EGL_SUCCESS                    0x3000
+#define EGL_NOT_INITIALIZED            0x3001
+#define EGL_BAD_ACCESS                 0x3002
+#define EGL_BAD_ALLOC                  0x3003
+#define EGL_BAD_ATTRIBUTE              0x3004
+#define EGL_BAD_CONFIG                 0x3005
+#define EGL_BAD_CONTEXT                        0x3006
+#define EGL_BAD_CURRENT_SURFACE                0x3007
+#define EGL_BAD_DISPLAY                        0x3008
+#define EGL_BAD_MATCH                  0x3009
+#define EGL_BAD_NATIVE_PIXMAP          0x300A
+#define EGL_BAD_NATIVE_WINDOW          0x300B
+#define EGL_BAD_PARAMETER              0x300C
+#define EGL_BAD_SURFACE                        0x300D
+#define EGL_CONTEXT_LOST               0x300E  /* EGL 1.1 - IMG_power_management */
+
+/* Reserved 0x300F-0x301F for additional errors */
+
+/* Config attributes */
+#define EGL_BUFFER_SIZE                        0x3020
+#define EGL_ALPHA_SIZE                 0x3021
+#define EGL_BLUE_SIZE                  0x3022
+#define EGL_GREEN_SIZE                 0x3023
+#define EGL_RED_SIZE                   0x3024
+#define EGL_DEPTH_SIZE                 0x3025
+#define EGL_STENCIL_SIZE               0x3026
+#define EGL_CONFIG_CAVEAT              0x3027
+#define EGL_CONFIG_ID                  0x3028
+#define EGL_LEVEL                      0x3029
+#define EGL_MAX_PBUFFER_HEIGHT         0x302A
+#define EGL_MAX_PBUFFER_PIXELS         0x302B
+#define EGL_MAX_PBUFFER_WIDTH          0x302C
+#define EGL_NATIVE_RENDERABLE          0x302D
+#define EGL_NATIVE_VISUAL_ID           0x302E
+#define EGL_NATIVE_VISUAL_TYPE         0x302F
+#define EGL_SAMPLES                    0x3031
+#define EGL_SAMPLE_BUFFERS             0x3032
+#define EGL_SURFACE_TYPE               0x3033
+#define EGL_TRANSPARENT_TYPE           0x3034
+#define EGL_TRANSPARENT_BLUE_VALUE     0x3035
+#define EGL_TRANSPARENT_GREEN_VALUE    0x3036
+#define EGL_TRANSPARENT_RED_VALUE      0x3037
+#define EGL_NONE                       0x3038  /* Attrib list terminator */
+#define EGL_BIND_TO_TEXTURE_RGB                0x3039
+#define EGL_BIND_TO_TEXTURE_RGBA       0x303A
+#define EGL_MIN_SWAP_INTERVAL          0x303B
+#define EGL_MAX_SWAP_INTERVAL          0x303C
+#define EGL_LUMINANCE_SIZE             0x303D
+#define EGL_ALPHA_MASK_SIZE            0x303E
+#define EGL_COLOR_BUFFER_TYPE          0x303F
+#define EGL_RENDERABLE_TYPE            0x3040
+#define EGL_MATCH_NATIVE_PIXMAP                0x3041  /* Pseudo-attribute (not queryable) */
+#define EGL_CONFORMANT                 0x3042
+
+/* Reserved 0x3041-0x304F for additional config attributes */
+
+/* Config attribute values */
+#define EGL_SLOW_CONFIG                        0x3050  /* EGL_CONFIG_CAVEAT value */
+#define EGL_NON_CONFORMANT_CONFIG      0x3051  /* EGL_CONFIG_CAVEAT value */
+#define EGL_TRANSPARENT_RGB            0x3052  /* EGL_TRANSPARENT_TYPE value */
+#define EGL_RGB_BUFFER                 0x308E  /* EGL_COLOR_BUFFER_TYPE value */
+#define EGL_LUMINANCE_BUFFER           0x308F  /* EGL_COLOR_BUFFER_TYPE value */
+
+/* More config attribute values, for EGL_TEXTURE_FORMAT */
+#define EGL_NO_TEXTURE                 0x305C
+#define EGL_TEXTURE_RGB                        0x305D
+#define EGL_TEXTURE_RGBA               0x305E
+#define EGL_TEXTURE_2D                 0x305F
+
+/* Config attribute mask bits */
+#define EGL_PBUFFER_BIT                        0x0001  /* EGL_SURFACE_TYPE mask bits */
+#define EGL_PIXMAP_BIT                 0x0002  /* EGL_SURFACE_TYPE mask bits */
+#define EGL_WINDOW_BIT                 0x0004  /* EGL_SURFACE_TYPE mask bits */
+#define EGL_VG_COLORSPACE_LINEAR_BIT   0x0020  /* EGL_SURFACE_TYPE mask bits */
+#define EGL_VG_ALPHA_FORMAT_PRE_BIT    0x0040  /* EGL_SURFACE_TYPE mask bits */
+#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200 /* EGL_SURFACE_TYPE mask bits */
+#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400 /* EGL_SURFACE_TYPE mask bits */
+
+#define EGL_OPENGL_ES_BIT              0x0001  /* EGL_RENDERABLE_TYPE mask bits */
+#define EGL_OPENVG_BIT                 0x0002  /* EGL_RENDERABLE_TYPE mask bits */
+#define EGL_OPENGL_ES2_BIT             0x0004  /* EGL_RENDERABLE_TYPE mask bits */
+#define EGL_OPENGL_BIT                 0x0008  /* EGL_RENDERABLE_TYPE mask bits */
+
+/* QueryString targets */
+#define EGL_VENDOR                     0x3053
+#define EGL_VERSION                    0x3054
+#define EGL_EXTENSIONS                 0x3055
+#define EGL_CLIENT_APIS                        0x308D
+
+/* QuerySurface / SurfaceAttrib / CreatePbufferSurface targets */
+#define EGL_HEIGHT                     0x3056
+#define EGL_WIDTH                      0x3057
+#define EGL_LARGEST_PBUFFER            0x3058
+#define EGL_TEXTURE_FORMAT             0x3080
+#define EGL_TEXTURE_TARGET             0x3081
+#define EGL_MIPMAP_TEXTURE             0x3082
+#define EGL_MIPMAP_LEVEL               0x3083
+#define EGL_RENDER_BUFFER              0x3086
+#define EGL_VG_COLORSPACE              0x3087
+#define EGL_VG_ALPHA_FORMAT            0x3088
+#define EGL_HORIZONTAL_RESOLUTION      0x3090
+#define EGL_VERTICAL_RESOLUTION                0x3091
+#define EGL_PIXEL_ASPECT_RATIO         0x3092
+#define EGL_SWAP_BEHAVIOR              0x3093
+#define EGL_MULTISAMPLE_RESOLVE                0x3099
+
+/* EGL_RENDER_BUFFER values / BindTexImage / ReleaseTexImage buffer targets */
+#define EGL_BACK_BUFFER                        0x3084
+#define EGL_SINGLE_BUFFER              0x3085
+
+/* OpenVG color spaces */
+#define EGL_VG_COLORSPACE_sRGB         0x3089  /* EGL_VG_COLORSPACE value */
+#define EGL_VG_COLORSPACE_LINEAR       0x308A  /* EGL_VG_COLORSPACE value */
+
+/* OpenVG alpha formats */
+#define EGL_VG_ALPHA_FORMAT_NONPRE     0x308B  /* EGL_ALPHA_FORMAT value */
+#define EGL_VG_ALPHA_FORMAT_PRE                0x308C  /* EGL_ALPHA_FORMAT value */
+
+/* Constant scale factor by which fractional display resolutions &
+ * aspect ratio are scaled when queried as integer values.
+ */
+#define EGL_DISPLAY_SCALING            10000
+
+/* Unknown display resolution/aspect ratio */
+#define EGL_UNKNOWN                    ((EGLint)-1)
+
+/* Back buffer swap behaviors */
+#define EGL_BUFFER_PRESERVED           0x3094  /* EGL_SWAP_BEHAVIOR value */
+#define EGL_BUFFER_DESTROYED           0x3095  /* EGL_SWAP_BEHAVIOR value */
+
+/* CreatePbufferFromClientBuffer buffer types */
+#define EGL_OPENVG_IMAGE               0x3096
+
+/* QueryContext targets */
+#define EGL_CONTEXT_CLIENT_TYPE                0x3097
+
+/* CreateContext attributes */
+#define EGL_CONTEXT_CLIENT_VERSION     0x3098
+
+/* Multisample resolution behaviors */
+#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A /* EGL_MULTISAMPLE_RESOLVE value */
+#define EGL_MULTISAMPLE_RESOLVE_BOX    0x309B  /* EGL_MULTISAMPLE_RESOLVE value */
+
+/* BindAPI/QueryAPI targets */
+#define EGL_OPENGL_ES_API              0x30A0
+#define EGL_OPENVG_API                 0x30A1
+#define EGL_OPENGL_API                 0x30A2
+
+/* GetCurrentSurface targets */
+#define EGL_DRAW                       0x3059
+#define EGL_READ                       0x305A
+
+/* WaitNative engines */
+#define EGL_CORE_NATIVE_ENGINE         0x305B
+
+/* EGL 1.2 tokens renamed for consistency in EGL 1.3 */
+#define EGL_COLORSPACE                 EGL_VG_COLORSPACE
+#define EGL_ALPHA_FORMAT               EGL_VG_ALPHA_FORMAT
+#define EGL_COLORSPACE_sRGB            EGL_VG_COLORSPACE_sRGB
+#define EGL_COLORSPACE_LINEAR          EGL_VG_COLORSPACE_LINEAR
+#define EGL_ALPHA_FORMAT_NONPRE                EGL_VG_ALPHA_FORMAT_NONPRE
+#define EGL_ALPHA_FORMAT_PRE           EGL_VG_ALPHA_FORMAT_PRE
+
+/* EGL extensions must request enum blocks from the Khronos
+ * API Registrar, who maintains the enumerant registry. Submit
+ * a bug in Khronos Bugzilla against task "Registry".
+ */
+
+
+
+/* EGL Functions */
+
+EGLAPI EGLint EGLAPIENTRY eglGetError(void);
+
+EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id);
+EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor);
+EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy);
+
+EGLAPI const char * EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs,
+                        EGLint config_size, EGLint *num_config);
+EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list,
+                          EGLConfig *configs, EGLint config_size,
+                          EGLint *num_config);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config,
+                             EGLint attribute, EGLint *value);
+
+EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config,
+                                 EGLNativeWindowType win,
+                                 const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config,
+                                  const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config,
+                                 EGLNativePixmapType pixmap,
+                                 const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay dpy, EGLSurface surface);
+EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surface,
+                          EGLint attribute, EGLint *value);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api);
+EGLAPI EGLenum EGLAPIENTRY eglQueryAPI(void);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient(void);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread(void);
+
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer(
+             EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer,
+             EGLConfig config, const EGLint *attrib_list);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface,
+                           EGLint attribute, EGLint value);
+EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+
+
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval);
+
+
+EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config,
+                           EGLContext share_context,
+                           const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx);
+EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy, EGLSurface draw,
+                         EGLSurface read, EGLContext ctx);
+
+EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext(void);
+EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw);
+EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx,
+                          EGLint attribute, EGLint *value);
+
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL(void);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine);
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface);
+EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers(EGLDisplay dpy, EGLSurface surface,
+                         EGLNativePixmapType target);
+
+/* This is a generic function pointer type, whose name indicates it must
+ * be cast to the proper type *and calling convention* before use.
+ */
+typedef void (*__eglMustCastToProperFunctionPointerType)(void);
+
+/* Now, define eglGetProcAddress using the generic function ptr. type */
+EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY
+       eglGetProcAddress(const char *procname);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __egl_h_ */
diff --git a/interface/khronos/include/EGL/eglext.h b/interface/khronos/include/EGL/eglext.h
new file mode 100755 (executable)
index 0000000..89a3369
--- /dev/null
@@ -0,0 +1,205 @@
+#ifndef __eglext_h_
+#define __eglext_h_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Copyright (c) 2007-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+#include "eglplatform.h"
+
+/* We want this */
+#ifndef EGL_EGLEXT_PROTOTYPES
+#define EGL_EGLEXT_PROTOTYPES
+#endif
+
+/*************************************************************/
+
+/* Header file version number */
+/* Current version at http://www.khronos.org/registry/egl/ */
+/* $Revision: 7244 $ on $Date: 2009-01-20 17:06:59 -0800 (Tue, 20 Jan 2009) $ */
+#define EGL_EGLEXT_VERSION 3
+
+#ifndef EGL_KHR_config_attribs
+#define EGL_KHR_config_attribs 1
+#define EGL_CONFORMANT_KHR                     0x3042  /* EGLConfig attribute */
+#define EGL_VG_COLORSPACE_LINEAR_BIT_KHR       0x0020  /* EGL_SURFACE_TYPE bitfield */
+#define EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR                0x0040  /* EGL_SURFACE_TYPE bitfield */
+#endif
+
+#ifndef EGL_KHR_lock_surface
+#define EGL_KHR_lock_surface 1
+#define EGL_READ_SURFACE_BIT_KHR               0x0001  /* EGL_LOCK_USAGE_HINT_KHR bitfield */
+#define EGL_WRITE_SURFACE_BIT_KHR              0x0002  /* EGL_LOCK_USAGE_HINT_KHR bitfield */
+#define EGL_LOCK_SURFACE_BIT_KHR               0x0080  /* EGL_SURFACE_TYPE bitfield */
+#define EGL_OPTIMAL_FORMAT_BIT_KHR             0x0100  /* EGL_SURFACE_TYPE bitfield */
+#define EGL_MATCH_FORMAT_KHR                   0x3043  /* EGLConfig attribute */
+#define EGL_FORMAT_RGB_565_EXACT_KHR           0x30C0  /* EGL_MATCH_FORMAT_KHR value */
+#define EGL_FORMAT_RGB_565_KHR                 0x30C1  /* EGL_MATCH_FORMAT_KHR value */
+#define EGL_FORMAT_RGBA_8888_EXACT_KHR         0x30C2  /* EGL_MATCH_FORMAT_KHR value */
+#define EGL_FORMAT_RGBA_8888_KHR               0x30C3  /* EGL_MATCH_FORMAT_KHR value */
+#define EGL_MAP_PRESERVE_PIXELS_KHR            0x30C4  /* eglLockSurfaceKHR attribute */
+#define EGL_LOCK_USAGE_HINT_KHR                        0x30C5  /* eglLockSurfaceKHR attribute */
+#define EGL_BITMAP_POINTER_KHR                 0x30C6  /* eglQuerySurface attribute */
+#define EGL_BITMAP_PITCH_KHR                   0x30C7  /* eglQuerySurface attribute */
+#define EGL_BITMAP_ORIGIN_KHR                  0x30C8  /* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_RED_OFFSET_KHR                0x30C9  /* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR      0x30CA  /* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR       0x30CB  /* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR      0x30CC  /* eglQuerySurface attribute */
+#define EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR  0x30CD  /* eglQuerySurface attribute */
+#define EGL_LOWER_LEFT_KHR                     0x30CE  /* EGL_BITMAP_ORIGIN_KHR value */
+#define EGL_UPPER_LEFT_KHR                     0x30CF  /* EGL_BITMAP_ORIGIN_KHR value */
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglLockSurfaceKHR (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglUnlockSurfaceKHR (EGLDisplay display, EGLSurface surface);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface);
+#endif
+
+#ifndef EGL_KHR_image
+#define EGL_KHR_image 1
+#define EGL_NATIVE_PIXMAP_KHR                  0x30B0  /* eglCreateImageKHR target */
+typedef void *EGLImageKHR;
+#define EGL_NO_IMAGE_KHR                       ((EGLImageKHR)0)
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image);
+#endif
+
+#ifndef EGL_KHR_vg_parent_image
+#define EGL_KHR_vg_parent_image 1
+#define EGL_VG_PARENT_IMAGE_KHR                        0x30BA  /* eglCreateImageKHR target */
+#endif
+
+#ifndef EGL_KHR_gl_texture_2D_image
+#define EGL_KHR_gl_texture_2D_image 1
+#define EGL_GL_TEXTURE_2D_KHR                  0x30B1  /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_LEVEL_KHR               0x30BC  /* eglCreateImageKHR attribute */
+#endif
+
+#ifndef EGL_KHR_gl_texture_cubemap_image
+#define EGL_KHR_gl_texture_cubemap_image 1
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR 0x30B3  /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR 0x30B4  /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR 0x30B5  /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR 0x30B6  /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR 0x30B7  /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR 0x30B8  /* eglCreateImageKHR target */
+#endif
+
+#ifndef EGL_KHR_gl_texture_3D_image
+#define EGL_KHR_gl_texture_3D_image 0
+#define EGL_GL_TEXTURE_3D_KHR                  0x30B2  /* eglCreateImageKHR target */
+#define EGL_GL_TEXTURE_ZOFFSET_KHR             0x30BD  /* eglCreateImageKHR attribute */
+#endif
+
+#ifndef EGL_KHR_gl_renderbuffer_image
+#define EGL_KHR_gl_renderbuffer_image 1
+#define EGL_GL_RENDERBUFFER_KHR                        0x30B9  /* eglCreateImageKHR target */
+#endif
+
+#ifndef EGL_KHR_image_base
+#define EGL_KHR_image_base 1
+/* Most interfaces defined by EGL_KHR_image_pixmap above */
+#define EGL_IMAGE_PRESERVED_KHR                        0x30D2  /* eglCreateImageKHR attribute */
+#endif
+
+#ifndef EGL_KHR_image_pixmap
+#define EGL_KHR_image_pixmap 1
+/* Interfaces defined by EGL_KHR_image above */
+#endif
+
+#ifndef EGL_KHR_fence_sync
+#define EGL_KHR_fence_sync 1
+#define GL_OES_EGL_sync 1
+#endif
+
+#ifndef EGL_KHR_sync
+#define EGL_KHR_sync 1
+#endif
+
+#if ((EGL_KHR_sync == 1) || (EGL_KHR_fence_sync == 1))
+#define EGL_KHR_sync 1 /* EGL_KHR_fence_sync depends on this stuff */
+/*
+* EGLSyncKHR is an opaque handle to an EGL sync object
+*/
+
+typedef void* EGLSyncKHR;
+
+/*
+* EGLTimeKHR is a 64-bit unsigned integer representing intervals
+* in nanoseconds.
+*/
+
+typedef khronos_utime_nanoseconds_t EGLTimeKHR;
+
+#define EGL_SYNC_FENCE_KHR                      0x30F9
+#define EGL_SYNC_REUSABLE_KHR                   0x30FA
+#define EGL_SYNC_TYPE_KHR                       0x30F7
+#define EGL_SYNC_STATUS_KHR                     0x30F1
+#define EGL_SYNC_CONDITION_KHR                  0x30F8
+#define EGL_SIGNALED_KHR                        0x30F2
+#define EGL_UNSIGNALED_KHR                      0x30F3
+#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR    0x30F0
+#define EGL_SYNC_FLUSH_COMMANDS_BIT_KHR         0x0001
+#define EGL_TIMEOUT_EXPIRED_KHR                 0x30F5
+#define EGL_CONDITION_SATISFIED_KHR             0x30F6
+
+#define EGL_FOREVER_KHR                         0xFFFFFFFFFFFFFFFFull
+
+#define EGL_NO_SYNC_KHR                         ((EGLSyncKHR)0)
+
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSyncKHR(EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncKHR(EGLDisplay dpy, EGLSyncKHR sync);
+EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
+EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNCKHRPROC) (EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync);
+typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#include "eglext_brcm.h"
+
+#if defined(ANDROID)
+#include "eglext_android.h"
+#include "eglext_nvidia.h"
+#endif
+
+#endif
diff --git a/interface/khronos/include/EGL/eglext_android.h b/interface/khronos/include/EGL/eglext_android.h
new file mode 100755 (executable)
index 0000000..9a4320d
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#if defined(ANDROID)
+
+#ifndef EGLEXT_ANDROID_H
+#define EGLEXT_ANDROID_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef EGL_ANDROID_image_native_buffer
+   #define EGL_ANDROID_image_native_buffer 1
+   #if defined(EGL_EGLEXT_ANDROID_STRUCT_HEADER)
+      #include <system/window.h>
+   #else
+      struct android_native_buffer_t;
+   #endif
+   #define EGL_NATIVE_BUFFER_ANDROID       0x3140  /* eglCreateImageKHR target */
+#endif
+
+/* Structure layout for android native buffers.
+ *
+ * Note: this will be harmonized with gralloc_brcm.h.
+ */
+typedef enum
+{
+   EGL_BRCM_ANDROID_BUFFER_TYPE_GL_RESOURCE = 0,
+   EGL_BRCM_ANDROID_BUFFER_TYPE_MM_RESOURCE,
+} EGL_BRCM_ANDROID_BUFFER_TYPE_T;
+
+/* By default Android always define this internally, also due to a missing
+** proper pending #define in the Android frameworks/base/opengl/libs/egl/egl.cpp
+** module we cannot actually disable EGL_ANDROID_swap_rectangle support via build
+** configuration (ie setting 'TARGET_GLOBAL_CPPFLAGS += -DEGL_ANDROID_swap_rectangle=0'
+** in our BoardConfig.mk) which would be the preferred mechanism, instead we therefore
+** have to match Android behavior and define by default what is expected to be supported,
+** as well as provide an implementation for it (which implementation may be empty as
+** long as it satisfies Android expectations).
+*/
+#ifndef EGL_ANDROID_swap_rectangle
+#define EGL_ANDROID_swap_rectangle 1
+#endif
+
+#if EGL_ANDROID_swap_rectangle
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSetSwapRectangleANDROID (EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSWAPRECTANGLEANDROIDPROC) (EGLDisplay dpy, EGLSurface draw, EGLint left, EGLint top, EGLint width, EGLint height);
+#endif /* EGL_ANDROID_swap_rectangle */
+
+
+#ifndef EGL_ANDROID_render_buffer
+#define EGL_ANDROID_render_buffer 1
+#endif
+
+#if EGL_ANDROID_render_buffer
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLClientBuffer EGLAPIENTRY eglGetRenderBufferANDROID (EGLDisplay dpy, EGLSurface sur);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETRENDERBUFFERANDROIDPROC) (EGLDisplay dpy, EGLSurface sur);
+#endif /* EGL_ANDROID_swap_rectangle */
+
+#ifndef EGL_ANDROID_recordable
+#define EGL_ANDROID_recordable   1
+#define EGL_RECORDABLE_ANDROID   0x3142
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EGLEXT_ANDROID_H */
+
+#endif /* defined(ANDROID) */
diff --git a/interface/khronos/include/EGL/eglext_brcm.h b/interface/khronos/include/EGL/eglext_brcm.h
new file mode 100755 (executable)
index 0000000..e1570ee
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef EGLEXT_BRCM_H
+#define EGLEXT_BRCM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define EGL_NATIVE_PIXMAP_CLIENT_SIDE_BRCM 0x99930B0   /* eglCreateImageKHR server-side target */
+#define EGL_IMAGE_FROM_SURFACE_BRCM 0x99930B1 /* eglCreateImageKHR server-side target */
+/* Multimedia target - created by gralloc */
+#define EGL_IMAGE_BRCM_MULTIMEDIA         0x99930B2
+#define EGL_IMAGE_BRCM_DUPLICATE         0x99930B3 /* a new EGL Image pointing at the same underlying object */
+#define EGL_IMAGE_BRCM_RAW_PIXELS        0x99930B4 /* Raw YUV multimedia pixels */
+
+/* Fastpath for creating greyscale textures from a single plane of a
+ * MMAL opaque buffers. */
+#define EGL_IMAGE_BRCM_MULTIMEDIA_Y      0x99930C0
+#define EGL_IMAGE_BRCM_MULTIMEDIA_U      0x99930C1
+#define EGL_IMAGE_BRCM_MULTIMEDIA_V      0x99930C2
+
+/* EGL image buffer allocated in shared memory */
+#define EGL_IMAGE_BRCM_VCSM              0x99930C3
+struct egl_image_brcm_vcsm_info {
+   unsigned width;
+   unsigned height;
+   unsigned int vcsm_handle;
+};
+
+#ifndef EGL_BRCM_sane_choose_config
+#define EGL_BRCM_sane_choose_config 1
+#endif
+#if EGL_BRCM_sane_choose_config
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSaneChooseConfigBRCM(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSANECHOOSECONFIGBRCM)(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
+#endif
+
+#ifndef EGL_BRCM_global_image
+#define EGL_BRCM_global_image 1
+#endif
+#if EGL_BRCM_global_image
+#define EGL_PIXEL_FORMAT_ARGB_8888_PRE_BRCM 0
+#define EGL_PIXEL_FORMAT_ARGB_8888_BRCM     1
+#define EGL_PIXEL_FORMAT_XRGB_8888_BRCM     2
+#define EGL_PIXEL_FORMAT_RGB_565_BRCM       3
+#define EGL_PIXEL_FORMAT_A_8_BRCM           4
+#define EGL_PIXEL_FORMAT_RENDER_GL_BRCM     (1 << 3)
+#define EGL_PIXEL_FORMAT_RENDER_GLES_BRCM   (1 << 4)
+#define EGL_PIXEL_FORMAT_RENDER_GLES2_BRCM  (1 << 5)
+#define EGL_PIXEL_FORMAT_RENDER_VG_BRCM     (1 << 6)
+#define EGL_PIXEL_FORMAT_RENDER_MASK_BRCM   0x78
+#define EGL_PIXEL_FORMAT_VG_IMAGE_BRCM      (1 << 7)
+#define EGL_PIXEL_FORMAT_GLES_TEXTURE_BRCM  (1 << 8)
+#define EGL_PIXEL_FORMAT_GLES2_TEXTURE_BRCM (1 << 9)
+#define EGL_PIXEL_FORMAT_TEXTURE_MASK_BRCM  0x380
+#define EGL_PIXEL_FORMAT_USAGE_MASK_BRCM    0x3f8
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI void EGLAPIENTRY eglCreateGlobalImageBRCM(EGLint width, EGLint height, EGLint pixel_format, const void *data, EGLint data_stride, EGLint *id);
+EGLAPI void EGLAPIENTRY eglCreateCopyGlobalImageBRCM(const EGLint *src_id, EGLint *id);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyGlobalImageBRCM(const EGLint *id);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryGlobalImageBRCM(const EGLint *id, EGLint *width_height_pixel_format);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef void (EGLAPIENTRYP PFNEGLCREATEGLOBALIMAGEBRCMPROC)(EGLint width, EGLint height, EGLint pixel_format, const void *data, EGLint data_stride, EGLint *id);
+typedef void (EGLAPIENTRYP PFNEGLCREATECOPYGLOBALIMAGEBRCMPROC)(const EGLint *src_id, EGLint *id);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYGLOBALIMAGEBRCMPROC)(const EGLint *id);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYGLOBALIMAGEBRCMPROC)(const EGLint *id, EGLint *width_height_pixel_format);
+#endif
+
+#ifndef EGL_BRCM_perf_monitor
+#define EGL_BRCM_perf_monitor 0
+#endif
+#if EGL_BRCM_perf_monitor
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglInitPerfMonitorBRCM(EGLDisplay display);
+EGLAPI EGLBoolean EGLAPIENTRY eglTermPerfMonitorBRCM(EGLDisplay display);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef void (EGLAPIENTRYP PFNEGLINITPERFMONITORBRCMPROC)(EGLDisplay display);
+typedef void (EGLAPIENTRYP PFNEGLTERMPERFMONITORBRCMPROC)(EGLDisplay display);
+#endif
+
+#ifndef EGL_BRCM_driver_monitor
+#define EGL_BRCM_driver_monitor 1
+#endif
+#if EGL_BRCM_driver_monitor
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglInitDriverMonitorBRCM(EGLDisplay display, EGLint hw_bank, EGLint l3c_bank);
+EGLAPI void EGLAPIENTRY eglGetDriverMonitorXMLBRCM(EGLDisplay display, EGLint bufSize, EGLint *length, char *xmlStats);
+EGLAPI EGLBoolean EGLAPIENTRY eglTermDriverMonitorBRCM(EGLDisplay display);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef void (EGLAPIENTRYP PFNEGLINITDRIVERMONITORBRCMPROC)(EGLDisplay display, EGLint hw_bank, EGLint l3c_bank);
+typedef void (EGLAPIENTRYP PFNEGLGETDRIVERMONITORXMLBRCMPROC)(EGLDisplay display, EGLint bufSize, EGLint *length, char *xmlStats);
+typedef void (EGLAPIENTRYP PFNEGLTERMDRIVERMONITORBRCMPROC)(EGLDisplay display);
+#endif
+
+#ifndef EGL_BRCM_perf_stats
+#define EGL_BRCM_perf_stats 0
+#endif
+#if EGL_BRCM_perf_stats
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI void eglPerfStatsResetBRCM(void);
+EGLAPI void eglPerfStatsGetBRCM(char *buffer, EGLint buffer_len, EGLBoolean reset);
+#endif
+typedef void (EGLAPIENTRYP PFNEGLPERFSTATSRESETBRCM) (void);
+typedef void (EGLAPIENTRYP PFNEGLPERFSTATSGETBRCM) (char *buffer, EGLint buffer_len, EGLBoolean reset);
+#endif
+
+#ifndef EGL_proc_state_valid
+#define EGL_proc_state_valid 1
+#endif
+#if EGL_proc_state_valid
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI void EGLAPIENTRY eglProcStateValid( EGLDisplay dpy, EGLBoolean *result );
+#endif
+typedef void (EGLAPIENTRYP PFNEGLPROCSTATEVALID) ( EGLDisplay dpy, EGLBoolean *valid );
+#endif
+
+#ifndef EGL_BRCM_flush
+#define EGL_BRCM_flush 1
+#endif
+#if EGL_BRCM_flush
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI void EGLAPIENTRY eglFlushBRCM(void);
+#endif /* EGL_EGLEXT_PROTOTYPES */
+typedef void (EGLAPIENTRYP PFNEGLFLUSHBRCMPROC)(void);
+#endif
+
+#ifndef EGL_BRCM_image_wrap
+#define EGL_BRCM_image_wrap 1
+#define EGL_IMAGE_WRAP_BRCM 0x9993140
+#endif
+
+#ifndef EGL_BRCM_image_wrap_bcg
+#define EGL_BRCM_image_wrap_bcg 0
+#define EGL_IMAGE_WRAP_BRCM_BCG 0x9993141
+
+#if EGL_BRCM_image_wrap_bcg
+typedef struct {
+   BEGL_BufferFormat format;
+
+   uint16_t width;
+   uint16_t height;
+
+   int32_t stride; /* in bytes */
+
+   void *storage;
+} EGL_IMAGE_WRAP_BRCM_BCG_IMAGE_T;
+#endif
+
+#endif
+
+#ifndef EGL_BRCM_mem_usage
+#define EGL_BRCM_mem_usage 0
+#endif
+#if EGL_BRCM_mem_usage
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI void eglProcessMemUsageGetBRCM(uint32_t id_0, uint32_t id_1, char *buffer, uint32_t buffer_len);
+#endif
+typedef void (EGLAPIENTRYP PFNEGLPROCESSMEMUSAGEGETBRCM) (uint32_t id_0, uint32_t id_1, char *buffer, uint32_t buffer_len);
+#endif
+
+/*
+Only enable this #define if the application (or wrapper layer) is going to call eglDirectRenderingPointer
+when appropriate (i.e. the first time eglMakeCurrent is called, and then at eglSwapBuffers)
+
+Only used for testing purposes on 2763
+*/
+//#define DIRECT_RENDERING
+
+#ifdef DIRECT_RENDERING
+EGLAPI EGLBoolean EGLAPIENTRY eglDirectRenderingPointer(EGLDisplay dpy, EGLSurface surf, void *image /* KHRN_IMAGE_WRAP_T */);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/interface/khronos/include/EGL/eglext_nvidia.h b/interface/khronos/include/EGL/eglext_nvidia.h
new file mode 100755 (executable)
index 0000000..4108d23
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#if defined(ANDROID)
+
+#ifndef EGLEXT_NVIDIA_H
+#define EGLEXT_NVIDIA_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef EGL_NV_system_time
+#define EGL_NV_system_time 1
+typedef khronos_int64_t EGLint64NV;
+typedef khronos_uint64_t EGLuint64NV;
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeFrequencyNV(void);
+EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeNV(void);
+#endif
+typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC)(void);
+typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMENVPROC)(void);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EGLEXT_NVIDIA_H */
+
+#endif /* defined(ANDROID) */
diff --git a/interface/khronos/include/EGL/eglplatform.h b/interface/khronos/include/EGL/eglplatform.h
new file mode 100755 (executable)
index 0000000..1f7c930
--- /dev/null
@@ -0,0 +1,205 @@
+#ifndef __eglplatform_h_
+#define __eglplatform_h_
+
+/*
+** Copyright (c) 2007-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+/* Platform-specific types and definitions for egl.h
+ * $Revision: 12306 $ on $Date: 2010-08-25 09:51:28 -0700 (Wed, 25 Aug 2010) $
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file.  Please submit changes
+ * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
+ * by filing a bug against product "EGL" component "Registry".
+ */
+
+#include "../KHR/khrplatform.h"
+
+#ifdef ABSTRACT_PLATFORM
+#include "begl_memplatform.h"
+#include "begl_hwplatform.h"
+#include "begl_dispplatform.h"
+#endif /* ABSTRACT_PLATFORM */
+
+/* Macros used in EGL function prototype declarations.
+ *
+ * EGL functions should be prototyped as:
+ *
+ * EGLAPI return-type EGLAPIENTRY eglFunction(arguments);
+ * typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments);
+ *
+ * KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h
+ */
+
+#ifndef EGLAPI
+#define EGLAPI KHRONOS_APICALL
+#endif
+
+#ifndef EGLAPIENTRY
+#define EGLAPIENTRY  KHRONOS_APIENTRY
+#endif
+#ifndef EGLAPIENTRYP
+#define EGLAPIENTRYP EGLAPIENTRY *
+#endif
+#ifndef EGLAPI
+#ifdef KHAPI
+#define EGLAPI KHAPI
+#else
+#define EGLAPI extern
+#endif
+#endif
+
+/* The types NativeDisplayType, NativeWindowType, and NativePixmapType
+ * are aliases of window-system-dependent types, such as X Display * or
+ * Windows Device Context. They must be defined in platform-specific
+ * code below. The EGL-prefixed versions of Native*Type are the same
+ * types, renamed in EGL 1.3 so all types in the API start with "EGL".
+ *
+ * Khronos STRONGLY RECOMMENDS that you use the default definitions
+ * provided below, since these changes affect both binary and source
+ * portability of applications using EGL running on different EGL
+ * implementations.
+ */
+
+/* Unix (tentative)
+    #include <X headers>
+    typedef Display *NativeDisplayType;
+      - or maybe, if encoding "hostname:display.head"
+    typedef const char *NativeWindowType;
+        etc.
+ */
+#if (defined (__ANDROID__) || defined(ANDROID)) && defined(KHRN_BCG_ANDROID)
+
+struct android_native_window_t;
+struct egl_native_pixmap_t;
+
+typedef struct android_native_window_t* EGLNativeWindowType;
+typedef struct egl_native_pixmap_t*     EGLNativePixmapType;
+typedef void *EGLNativeDisplayType;
+
+#else
+
+typedef void *EGLNativeDisplayType;
+typedef void *EGLNativePixmapType;
+typedef void *EGLNativeWindowType;
+#endif
+
+#ifndef EGL_SERVER_SMALLINT
+
+#include "interface/vmcs_host/vc_dispmanx.h"
+/* TODO: EGLNativeWindowType is really one of these but I'm leaving it
+ * as void* for now, in case changing it would cause problems
+ */
+typedef struct {
+   DISPMANX_ELEMENT_HANDLE_T element;
+   int width;   /* This is necessary because dispmanx elements are not queriable. */
+   int height;
+} EGL_DISPMANX_WINDOW_T;
+#elif defined (ABSTRACT_PLATFORM)
+
+#else
+
+/* window I of a horizontal strip of N WxH windows */
+#define PACK_NATIVE_WINDOW(W, H, I, N) ((NativeWindowType)((W) | ((H) << 12) | ((I) << 24) | ((N) << 28)))
+#define UNPACK_NATIVE_WINDOW_W(WIN) ((unsigned int)(WIN) & 0xfff)
+#define UNPACK_NATIVE_WINDOW_H(WIN) (((unsigned int)(WIN) >> 12) & 0xfff)
+#define UNPACK_NATIVE_WINDOW_I(WIN) (((unsigned int)(WIN) >> 24) & 0xf)
+#define UNPACK_NATIVE_WINDOW_N(WIN) ((unsigned int)(WIN) >> 28)
+
+/* todo: can we change these to use PACK_NATIVE_WINDOW and get rid of platform_canonical_win from platform.h? */
+#define NATIVE_WINDOW_800_480    ((NativeWindowType)0)
+#define NATIVE_WINDOW_640_480    ((NativeWindowType)1)
+#define NATIVE_WINDOW_320_240    ((NativeWindowType)2)
+#define NATIVE_WINDOW_240_320    ((NativeWindowType)3)
+#define NATIVE_WINDOW_64_64      ((NativeWindowType)4)
+#define NATIVE_WINDOW_400_480_A  ((NativeWindowType)5)
+#define NATIVE_WINDOW_400_480_B  ((NativeWindowType)6)
+#define NATIVE_WINDOW_512_512    ((NativeWindowType)7)
+#define NATIVE_WINDOW_360_640    ((NativeWindowType)8)
+#define NATIVE_WINDOW_640_360    ((NativeWindowType)9)
+#define NATIVE_WINDOW_1280_720   ((NativeWindowType)10)
+#define NATIVE_WINDOW_1920_1080  ((NativeWindowType)11)
+#define NATIVE_WINDOW_480_320    ((NativeWindowType)12)
+#define NATIVE_WINDOW_1680_1050  ((NativeWindowType)13)
+#endif
+
+/* EGL 1.2 types, renamed for consistency in EGL 1.3 */
+typedef EGLNativeDisplayType NativeDisplayType;
+typedef EGLNativePixmapType  NativePixmapType;
+typedef EGLNativeWindowType  NativeWindowType;
+
+
+/* Define EGLint. This must be a signed integral type large enough to contain
+ * all legal attribute names and values passed into and out of EGL, whether
+ * their type is boolean, bitmask, enumerant (symbolic constant), integer,
+ * handle, or other.  While in general a 32-bit integer will suffice, if
+ * handles are 64 bit types, then EGLint should be defined as a signed 64-bit
+ * integer type.
+ */
+typedef khronos_int32_t EGLint;
+
+#ifdef ABSTRACT_PLATFORM
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*
+The client application, or default platform library must register valid versions of each of these
+interfaces before any EGL or GL functions are invoked, using the following functions provided by the 3D driver.
+*/
+typedef struct
+{
+   BEGL_MemoryInterface  *memInterface;     /* Memory interface which will called by the 3d driver */
+   BEGL_HWInterface      *hwInterface;      /* Hardware interface which will be called by the driver */
+   BEGL_DisplayInterface *displayInterface; /* Display interface which will be called by the driver */
+
+   BEGL_DisplayCallbacks displayCallbacks; /* Callback pointers set by BEGL_GetDefaultDriverInterfaces, for client to call into driver */
+   int hwInterfaceCloned;
+   int memInterfaceCloned;
+   void *memInterfaceFn;
+   void *hwInterfaceFn;
+} BEGL_DriverInterfaces;
+
+/* Register application level overrides for any or all of the abstract API calls made by the 3D driver. */
+EGLAPI void EGLAPIENTRY BEGL_RegisterDriverInterfaces(BEGL_DriverInterfaces *iface);
+
+/* Get a pointer to the registered driver interfaces, can be used to override partial defaults - see android platform layer(s) for example */
+EGLAPI BEGL_DriverInterfaces * BEGL_GetDriverInterfaces(void);
+
+/* Initializes all interfaces in the structure to NULL, fills out Callbacks with appropriate function pointers */
+EGLAPI void EGLAPIENTRY BEGL_GetDefaultDriverInterfaces(BEGL_DriverInterfaces *iface);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ABSTRACT_PLATFORM */
+
+#if 0
+#include "interface/khronos/common/khrn_client_mangle.h"
+#endif
+
+#endif /* __eglplatform_h */
diff --git a/interface/khronos/include/GLES/gl.h b/interface/khronos/include/GLES/gl.h
new file mode 100755 (executable)
index 0000000..f284663
--- /dev/null
@@ -0,0 +1,798 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef __gl_h_
+#define __gl_h_
+
+/* $Revision: 10601 $ on $Date:: 2010-03-04 22:15:27 -0800 #$ */
+
+#include "glplatform.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+#ifndef __gl2_h_
+typedef void             GLvoid;
+typedef char             GLchar;
+typedef unsigned int     GLenum;
+typedef unsigned char    GLboolean;
+typedef unsigned int     GLbitfield;
+typedef khronos_int8_t   GLbyte;
+typedef short            GLshort;
+typedef int              GLint;
+typedef int              GLsizei;
+typedef khronos_uint8_t  GLubyte;
+typedef unsigned short   GLushort;
+typedef unsigned int     GLuint;
+typedef khronos_float_t  GLfloat;
+typedef khronos_float_t  GLclampf;
+typedef khronos_int32_t  GLfixed;
+
+typedef khronos_intptr_t GLintptr;
+typedef khronos_ssize_t  GLsizeiptr;
+#endif
+typedef khronos_int32_t  GLclampx;
+
+/*************************************************************/
+
+/* OpenGL ES core versions */
+#define GL_VERSION_ES_CM_1_0          1
+#define GL_VERSION_ES_CL_1_0          1
+#define GL_VERSION_ES_CM_1_1          1
+#define GL_VERSION_ES_CL_1_1          1
+
+/* ClearBufferMask */
+#define GL_DEPTH_BUFFER_BIT               0x00000100
+#define GL_STENCIL_BUFFER_BIT             0x00000400
+#define GL_COLOR_BUFFER_BIT               0x00004000
+
+/* Boolean */
+#define GL_FALSE                          (GLboolean)0
+#define GL_TRUE                           (GLboolean)1
+
+/* BeginMode */
+#define GL_POINTS                         0x0000
+#define GL_LINES                          0x0001
+#define GL_LINE_LOOP                      0x0002
+#define GL_LINE_STRIP                     0x0003
+#define GL_TRIANGLES                      0x0004
+#define GL_TRIANGLE_STRIP                 0x0005
+#define GL_TRIANGLE_FAN                   0x0006
+
+/* AlphaFunction */
+#define GL_NEVER                          0x0200
+#define GL_LESS                           0x0201
+#define GL_EQUAL                          0x0202
+#define GL_LEQUAL                         0x0203
+#define GL_GREATER                        0x0204
+#define GL_NOTEQUAL                       0x0205
+#define GL_GEQUAL                         0x0206
+#define GL_ALWAYS                         0x0207
+
+/* BlendingFactorDest */
+#define GL_ZERO                           0
+#define GL_ONE                            1
+#define GL_SRC_COLOR                      0x0300
+#define GL_ONE_MINUS_SRC_COLOR            0x0301
+#define GL_SRC_ALPHA                      0x0302
+#define GL_ONE_MINUS_SRC_ALPHA            0x0303
+#define GL_DST_ALPHA                      0x0304
+#define GL_ONE_MINUS_DST_ALPHA            0x0305
+
+/* BlendingFactorSrc */
+/*      GL_ZERO */
+/*      GL_ONE */
+#define GL_DST_COLOR                      0x0306
+#define GL_ONE_MINUS_DST_COLOR            0x0307
+#define GL_SRC_ALPHA_SATURATE             0x0308
+/*      GL_SRC_ALPHA */
+/*      GL_ONE_MINUS_SRC_ALPHA */
+/*      GL_DST_ALPHA */
+/*      GL_ONE_MINUS_DST_ALPHA */
+
+/* ClipPlaneName */
+#define GL_CLIP_PLANE0                    0x3000
+#define GL_CLIP_PLANE1                    0x3001
+#define GL_CLIP_PLANE2                    0x3002
+#define GL_CLIP_PLANE3                    0x3003
+#define GL_CLIP_PLANE4                    0x3004
+#define GL_CLIP_PLANE5                    0x3005
+
+/* ColorMaterialFace */
+/*      GL_FRONT_AND_BACK */
+
+/* ColorMaterialParameter */
+/*      GL_AMBIENT_AND_DIFFUSE */
+
+/* ColorPointerType */
+/*      GL_UNSIGNED_BYTE */
+/*      GL_FLOAT */
+/*      GL_FIXED */
+
+/* CullFaceMode */
+#define GL_FRONT                          0x0404
+#define GL_BACK                           0x0405
+#define GL_FRONT_AND_BACK                 0x0408
+
+/* DepthFunction */
+/*      GL_NEVER */
+/*      GL_LESS */
+/*      GL_EQUAL */
+/*      GL_LEQUAL */
+/*      GL_GREATER */
+/*      GL_NOTEQUAL */
+/*      GL_GEQUAL */
+/*      GL_ALWAYS */
+
+/* EnableCap */
+#define GL_FOG                            0x0B60
+#define GL_LIGHTING                       0x0B50
+#define GL_TEXTURE_2D                     0x0DE1
+#define GL_CULL_FACE                      0x0B44
+#define GL_ALPHA_TEST                     0x0BC0
+#define GL_BLEND                          0x0BE2
+#define GL_COLOR_LOGIC_OP                 0x0BF2
+#define GL_DITHER                         0x0BD0
+#define GL_STENCIL_TEST                   0x0B90
+#define GL_DEPTH_TEST                     0x0B71
+/*      GL_LIGHT0 */
+/*      GL_LIGHT1 */
+/*      GL_LIGHT2 */
+/*      GL_LIGHT3 */
+/*      GL_LIGHT4 */
+/*      GL_LIGHT5 */
+/*      GL_LIGHT6 */
+/*      GL_LIGHT7 */
+#define GL_POINT_SMOOTH                   0x0B10
+#define GL_LINE_SMOOTH                    0x0B20
+#define GL_SCISSOR_TEST                   0x0C11
+#define GL_COLOR_MATERIAL                 0x0B57
+#define GL_NORMALIZE                      0x0BA1
+#define GL_RESCALE_NORMAL                 0x803A
+#define GL_POLYGON_OFFSET_FILL            0x8037
+#define GL_VERTEX_ARRAY                   0x8074
+#define GL_NORMAL_ARRAY                   0x8075
+#define GL_COLOR_ARRAY                    0x8076
+#define GL_TEXTURE_COORD_ARRAY            0x8078
+#define GL_MULTISAMPLE                    0x809D
+#define GL_SAMPLE_ALPHA_TO_COVERAGE       0x809E
+#define GL_SAMPLE_ALPHA_TO_ONE            0x809F
+#define GL_SAMPLE_COVERAGE                0x80A0
+
+/* ErrorCode */
+#define GL_NO_ERROR                       0
+#define GL_INVALID_ENUM                   0x0500
+#define GL_INVALID_VALUE                  0x0501
+#define GL_INVALID_OPERATION              0x0502
+#define GL_STACK_OVERFLOW                 0x0503
+#define GL_STACK_UNDERFLOW                0x0504
+#define GL_OUT_OF_MEMORY                  0x0505
+
+/* FogMode */
+/*      GL_LINEAR */
+#define GL_EXP                            0x0800
+#define GL_EXP2                           0x0801
+
+/* FogParameter */
+#define GL_FOG_DENSITY                    0x0B62
+#define GL_FOG_START                      0x0B63
+#define GL_FOG_END                        0x0B64
+#define GL_FOG_MODE                       0x0B65
+#define GL_FOG_COLOR                      0x0B66
+
+/* FrontFaceDirection */
+#define GL_CW                             0x0900
+#define GL_CCW                            0x0901
+
+/* GetPName */
+#define GL_CURRENT_COLOR                  0x0B00
+#define GL_CURRENT_NORMAL                 0x0B02
+#define GL_CURRENT_TEXTURE_COORDS         0x0B03
+#define GL_POINT_SIZE                     0x0B11
+#define GL_POINT_SIZE_MIN                 0x8126
+#define GL_POINT_SIZE_MAX                 0x8127
+#define GL_POINT_FADE_THRESHOLD_SIZE      0x8128
+#define GL_POINT_DISTANCE_ATTENUATION     0x8129
+#define GL_SMOOTH_POINT_SIZE_RANGE        0x0B12
+#define GL_LINE_WIDTH                     0x0B21
+#define GL_SMOOTH_LINE_WIDTH_RANGE        0x0B22
+#define GL_ALIASED_POINT_SIZE_RANGE       0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE       0x846E
+#define GL_CULL_FACE_MODE                 0x0B45
+#define GL_FRONT_FACE                     0x0B46
+#define GL_SHADE_MODEL                    0x0B54
+#define GL_DEPTH_RANGE                    0x0B70
+#define GL_DEPTH_WRITEMASK                0x0B72
+#define GL_DEPTH_CLEAR_VALUE              0x0B73
+#define GL_DEPTH_FUNC                     0x0B74
+#define GL_STENCIL_CLEAR_VALUE            0x0B91
+#define GL_STENCIL_FUNC                   0x0B92
+#define GL_STENCIL_VALUE_MASK             0x0B93
+#define GL_STENCIL_FAIL                   0x0B94
+#define GL_STENCIL_PASS_DEPTH_FAIL        0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS        0x0B96
+#define GL_STENCIL_REF                    0x0B97
+#define GL_STENCIL_WRITEMASK              0x0B98
+#define GL_MATRIX_MODE                    0x0BA0
+#define GL_VIEWPORT                       0x0BA2
+#define GL_MODELVIEW_STACK_DEPTH          0x0BA3
+#define GL_PROJECTION_STACK_DEPTH         0x0BA4
+#define GL_TEXTURE_STACK_DEPTH            0x0BA5
+#define GL_MODELVIEW_MATRIX               0x0BA6
+#define GL_PROJECTION_MATRIX              0x0BA7
+#define GL_TEXTURE_MATRIX                 0x0BA8
+#define GL_ALPHA_TEST_FUNC                0x0BC1
+#define GL_ALPHA_TEST_REF                 0x0BC2
+#define GL_BLEND_DST                      0x0BE0
+#define GL_BLEND_SRC                      0x0BE1
+#define GL_LOGIC_OP_MODE                  0x0BF0
+#define GL_SCISSOR_BOX                    0x0C10
+#define GL_SCISSOR_TEST                   0x0C11
+#define GL_COLOR_CLEAR_VALUE              0x0C22
+#define GL_COLOR_WRITEMASK                0x0C23
+#define GL_UNPACK_ALIGNMENT               0x0CF5
+#define GL_PACK_ALIGNMENT                 0x0D05
+#define GL_MAX_LIGHTS                     0x0D31
+#define GL_MAX_CLIP_PLANES                0x0D32
+#define GL_MAX_TEXTURE_SIZE               0x0D33
+#define GL_MAX_MODELVIEW_STACK_DEPTH      0x0D36
+#define GL_MAX_PROJECTION_STACK_DEPTH     0x0D38
+#define GL_MAX_TEXTURE_STACK_DEPTH        0x0D39
+#define GL_MAX_VIEWPORT_DIMS              0x0D3A
+#define GL_MAX_TEXTURE_UNITS              0x84E2
+#define GL_SUBPIXEL_BITS                  0x0D50
+#define GL_RED_BITS                       0x0D52
+#define GL_GREEN_BITS                     0x0D53
+#define GL_BLUE_BITS                      0x0D54
+#define GL_ALPHA_BITS                     0x0D55
+#define GL_DEPTH_BITS                     0x0D56
+#define GL_STENCIL_BITS                   0x0D57
+#define GL_POLYGON_OFFSET_UNITS           0x2A00
+#define GL_POLYGON_OFFSET_FILL            0x8037
+#define GL_POLYGON_OFFSET_FACTOR          0x8038
+#define GL_TEXTURE_BINDING_2D             0x8069
+#define GL_VERTEX_ARRAY_SIZE              0x807A
+#define GL_VERTEX_ARRAY_TYPE              0x807B
+#define GL_VERTEX_ARRAY_STRIDE            0x807C
+#define GL_NORMAL_ARRAY_TYPE              0x807E
+#define GL_NORMAL_ARRAY_STRIDE            0x807F
+#define GL_COLOR_ARRAY_SIZE               0x8081
+#define GL_COLOR_ARRAY_TYPE               0x8082
+#define GL_COLOR_ARRAY_STRIDE             0x8083
+#define GL_TEXTURE_COORD_ARRAY_SIZE       0x8088
+#define GL_TEXTURE_COORD_ARRAY_TYPE       0x8089
+#define GL_TEXTURE_COORD_ARRAY_STRIDE     0x808A
+#define GL_VERTEX_ARRAY_POINTER           0x808E
+#define GL_NORMAL_ARRAY_POINTER           0x808F
+#define GL_COLOR_ARRAY_POINTER            0x8090
+#define GL_TEXTURE_COORD_ARRAY_POINTER    0x8092
+#define GL_SAMPLE_BUFFERS                 0x80A8
+#define GL_SAMPLES                        0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE          0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT         0x80AB
+
+/* GetTextureParameter */
+/*      GL_TEXTURE_MAG_FILTER */
+/*      GL_TEXTURE_MIN_FILTER */
+/*      GL_TEXTURE_WRAP_S */
+/*      GL_TEXTURE_WRAP_T */
+
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS     0x86A3
+
+/* HintMode */
+#define GL_DONT_CARE                      0x1100
+#define GL_FASTEST                        0x1101
+#define GL_NICEST                         0x1102
+
+/* HintTarget */
+#define GL_PERSPECTIVE_CORRECTION_HINT    0x0C50
+#define GL_POINT_SMOOTH_HINT              0x0C51
+#define GL_LINE_SMOOTH_HINT               0x0C52
+#define GL_FOG_HINT                       0x0C54
+#define GL_GENERATE_MIPMAP_HINT           0x8192
+
+/* LightModelParameter */
+#define GL_LIGHT_MODEL_AMBIENT            0x0B53
+#define GL_LIGHT_MODEL_TWO_SIDE           0x0B52
+
+/* LightParameter */
+#define GL_AMBIENT                        0x1200
+#define GL_DIFFUSE                        0x1201
+#define GL_SPECULAR                       0x1202
+#define GL_POSITION                       0x1203
+#define GL_SPOT_DIRECTION                 0x1204
+#define GL_SPOT_EXPONENT                  0x1205
+#define GL_SPOT_CUTOFF                    0x1206
+#define GL_CONSTANT_ATTENUATION           0x1207
+#define GL_LINEAR_ATTENUATION             0x1208
+#define GL_QUADRATIC_ATTENUATION          0x1209
+
+/* DataType */
+#define GL_BYTE                           0x1400
+#define GL_UNSIGNED_BYTE                  0x1401
+#define GL_SHORT                          0x1402
+#define GL_UNSIGNED_SHORT                 0x1403
+#define GL_FLOAT                          0x1406
+#define GL_FIXED                          0x140C
+
+/* LogicOp */
+#define GL_CLEAR                          0x1500
+#define GL_AND                            0x1501
+#define GL_AND_REVERSE                    0x1502
+#define GL_COPY                           0x1503
+#define GL_AND_INVERTED                   0x1504
+#define GL_NOOP                           0x1505
+#define GL_XOR                            0x1506
+#define GL_OR                             0x1507
+#define GL_NOR                            0x1508
+#define GL_EQUIV                          0x1509
+#define GL_INVERT                         0x150A
+#define GL_OR_REVERSE                     0x150B
+#define GL_COPY_INVERTED                  0x150C
+#define GL_OR_INVERTED                    0x150D
+#define GL_NAND                           0x150E
+#define GL_SET                            0x150F
+
+/* MaterialFace */
+/*      GL_FRONT_AND_BACK */
+
+/* MaterialParameter */
+#define GL_EMISSION                       0x1600
+#define GL_SHININESS                      0x1601
+#define GL_AMBIENT_AND_DIFFUSE            0x1602
+/*      GL_AMBIENT */
+/*      GL_DIFFUSE */
+/*      GL_SPECULAR */
+
+/* MatrixMode */
+#define GL_MODELVIEW                      0x1700
+#define GL_PROJECTION                     0x1701
+#define GL_TEXTURE                        0x1702
+
+/* NormalPointerType */
+/*      GL_BYTE */
+/*      GL_SHORT */
+/*      GL_FLOAT */
+/*      GL_FIXED */
+
+/* PixelFormat */
+#define GL_ALPHA                          0x1906
+#define GL_RGB                            0x1907
+#define GL_RGBA                           0x1908
+#define GL_LUMINANCE                      0x1909
+#define GL_LUMINANCE_ALPHA                0x190A
+
+/* PixelStoreParameter */
+#define GL_UNPACK_ALIGNMENT               0x0CF5
+#define GL_PACK_ALIGNMENT                 0x0D05
+
+/* PixelType */
+/*      GL_UNSIGNED_BYTE */
+#define GL_UNSIGNED_SHORT_4_4_4_4         0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1         0x8034
+#define GL_UNSIGNED_SHORT_5_6_5           0x8363
+
+/* ShadingModel */
+#define GL_FLAT                           0x1D00
+#define GL_SMOOTH                         0x1D01
+
+/* StencilFunction */
+/*      GL_NEVER */
+/*      GL_LESS */
+/*      GL_EQUAL */
+/*      GL_LEQUAL */
+/*      GL_GREATER */
+/*      GL_NOTEQUAL */
+/*      GL_GEQUAL */
+/*      GL_ALWAYS */
+
+/* StencilOp */
+/*      GL_ZERO */
+#define GL_KEEP                           0x1E00
+#define GL_REPLACE                        0x1E01
+#define GL_INCR                           0x1E02
+#define GL_DECR                           0x1E03
+/*      GL_INVERT */
+
+/* StringName */
+#define GL_VENDOR                         0x1F00
+#define GL_RENDERER                       0x1F01
+#define GL_VERSION                        0x1F02
+#define GL_EXTENSIONS                     0x1F03
+
+/* TexCoordPointerType */
+/*      GL_SHORT */
+/*      GL_FLOAT */
+/*      GL_FIXED */
+/*      GL_BYTE */
+
+/* TextureEnvMode */
+#define GL_MODULATE                       0x2100
+#define GL_DECAL                          0x2101
+/*      GL_BLEND */
+#define GL_ADD                            0x0104
+/*      GL_REPLACE */
+
+/* TextureEnvParameter */
+#define GL_TEXTURE_ENV_MODE               0x2200
+#define GL_TEXTURE_ENV_COLOR              0x2201
+
+/* TextureEnvTarget */
+#define GL_TEXTURE_ENV                    0x2300
+
+/* TextureMagFilter */
+#define GL_NEAREST                        0x2600
+#define GL_LINEAR                         0x2601
+
+/* TextureMinFilter */
+/*      GL_NEAREST */
+/*      GL_LINEAR */
+#define GL_NEAREST_MIPMAP_NEAREST         0x2700
+#define GL_LINEAR_MIPMAP_NEAREST          0x2701
+#define GL_NEAREST_MIPMAP_LINEAR          0x2702
+#define GL_LINEAR_MIPMAP_LINEAR           0x2703
+
+/* TextureParameterName */
+#define GL_TEXTURE_MAG_FILTER             0x2800
+#define GL_TEXTURE_MIN_FILTER             0x2801
+#define GL_TEXTURE_WRAP_S                 0x2802
+#define GL_TEXTURE_WRAP_T                 0x2803
+#define GL_GENERATE_MIPMAP                0x8191
+
+/* TextureTarget */
+/*      GL_TEXTURE_2D */
+
+/* TextureUnit */
+#define GL_TEXTURE0                       0x84C0
+#define GL_TEXTURE1                       0x84C1
+#define GL_TEXTURE2                       0x84C2
+#define GL_TEXTURE3                       0x84C3
+#define GL_TEXTURE4                       0x84C4
+#define GL_TEXTURE5                       0x84C5
+#define GL_TEXTURE6                       0x84C6
+#define GL_TEXTURE7                       0x84C7
+#define GL_TEXTURE8                       0x84C8
+#define GL_TEXTURE9                       0x84C9
+#define GL_TEXTURE10                      0x84CA
+#define GL_TEXTURE11                      0x84CB
+#define GL_TEXTURE12                      0x84CC
+#define GL_TEXTURE13                      0x84CD
+#define GL_TEXTURE14                      0x84CE
+#define GL_TEXTURE15                      0x84CF
+#define GL_TEXTURE16                      0x84D0
+#define GL_TEXTURE17                      0x84D1
+#define GL_TEXTURE18                      0x84D2
+#define GL_TEXTURE19                      0x84D3
+#define GL_TEXTURE20                      0x84D4
+#define GL_TEXTURE21                      0x84D5
+#define GL_TEXTURE22                      0x84D6
+#define GL_TEXTURE23                      0x84D7
+#define GL_TEXTURE24                      0x84D8
+#define GL_TEXTURE25                      0x84D9
+#define GL_TEXTURE26                      0x84DA
+#define GL_TEXTURE27                      0x84DB
+#define GL_TEXTURE28                      0x84DC
+#define GL_TEXTURE29                      0x84DD
+#define GL_TEXTURE30                      0x84DE
+#define GL_TEXTURE31                      0x84DF
+#define GL_ACTIVE_TEXTURE                 0x84E0
+#define GL_CLIENT_ACTIVE_TEXTURE          0x84E1
+
+/* TextureWrapMode */
+#define GL_REPEAT                         0x2901
+#define GL_CLAMP_TO_EDGE                  0x812F
+
+/* VertexPointerType */
+/*      GL_SHORT */
+/*      GL_FLOAT */
+/*      GL_FIXED */
+/*      GL_BYTE */
+
+/* LightName */
+#define GL_LIGHT0                         0x4000
+#define GL_LIGHT1                         0x4001
+#define GL_LIGHT2                         0x4002
+#define GL_LIGHT3                         0x4003
+#define GL_LIGHT4                         0x4004
+#define GL_LIGHT5                         0x4005
+#define GL_LIGHT6                         0x4006
+#define GL_LIGHT7                         0x4007
+
+/* Buffer Objects */
+#define GL_ARRAY_BUFFER                   0x8892
+#define GL_ELEMENT_ARRAY_BUFFER           0x8893
+
+#define GL_ARRAY_BUFFER_BINDING               0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING       0x8895
+#define GL_VERTEX_ARRAY_BUFFER_BINDING        0x8896
+#define GL_NORMAL_ARRAY_BUFFER_BINDING        0x8897
+#define GL_COLOR_ARRAY_BUFFER_BINDING         0x8898
+#define GL_TEXTURE_COORD_ARRAY_BUFFER_BINDING 0x889A
+
+#define GL_STATIC_DRAW                    0x88E4
+#define GL_DYNAMIC_DRAW                   0x88E8
+
+#define GL_BUFFER_SIZE                    0x8764
+#define GL_BUFFER_USAGE                   0x8765
+
+/* Texture combine + dot3 */
+#define GL_SUBTRACT                       0x84E7
+#define GL_COMBINE                        0x8570
+#define GL_COMBINE_RGB                    0x8571
+#define GL_COMBINE_ALPHA                  0x8572
+#define GL_RGB_SCALE                      0x8573
+#define GL_ADD_SIGNED                     0x8574
+#define GL_INTERPOLATE                    0x8575
+#define GL_CONSTANT                       0x8576
+#define GL_PRIMARY_COLOR                  0x8577
+#define GL_PREVIOUS                       0x8578
+#define GL_OPERAND0_RGB                   0x8590
+#define GL_OPERAND1_RGB                   0x8591
+#define GL_OPERAND2_RGB                   0x8592
+#define GL_OPERAND0_ALPHA                 0x8598
+#define GL_OPERAND1_ALPHA                 0x8599
+#define GL_OPERAND2_ALPHA                 0x859A
+
+#define GL_ALPHA_SCALE                    0x0D1C
+
+#define GL_SRC0_RGB                       0x8580
+#define GL_SRC1_RGB                       0x8581
+#define GL_SRC2_RGB                       0x8582
+#define GL_SRC0_ALPHA                     0x8588
+#define GL_SRC1_ALPHA                     0x8589
+#define GL_SRC2_ALPHA                     0x858A
+
+#define GL_DOT3_RGB                       0x86AE
+#define GL_DOT3_RGBA                      0x86AF
+
+/*------------------------------------------------------------------------*
+ * required OES extension tokens
+ *------------------------------------------------------------------------*/
+
+/* OES_read_format */
+#ifndef GL_OES_read_format
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE_OES                   0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT_OES                 0x8B9B
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_PALETTE4_RGB8_OES                                    0x8B90
+#define GL_PALETTE4_RGBA8_OES                                   0x8B91
+#define GL_PALETTE4_R5_G6_B5_OES                                0x8B92
+#define GL_PALETTE4_RGBA4_OES                                   0x8B93
+#define GL_PALETTE4_RGB5_A1_OES                                 0x8B94
+#define GL_PALETTE8_RGB8_OES                                    0x8B95
+#define GL_PALETTE8_RGBA8_OES                                   0x8B96
+#define GL_PALETTE8_R5_G6_B5_OES                                0x8B97
+#define GL_PALETTE8_RGBA4_OES                                   0x8B98
+#define GL_PALETTE8_RGB5_A1_OES                                 0x8B99
+#endif
+
+/* OES_point_size_array */
+#ifndef GL_OES_point_size_array
+#define GL_POINT_SIZE_ARRAY_OES                                 0x8B9C
+#define GL_POINT_SIZE_ARRAY_TYPE_OES                            0x898A
+#define GL_POINT_SIZE_ARRAY_STRIDE_OES                          0x898B
+#define GL_POINT_SIZE_ARRAY_POINTER_OES                         0x898C
+#define GL_POINT_SIZE_ARRAY_BUFFER_BINDING_OES                  0x8B9F
+#endif
+
+/* GL_OES_point_sprite */
+#ifndef GL_OES_point_sprite
+#define GL_POINT_SPRITE_OES                                     0x8861
+#define GL_COORD_REPLACE_OES                                    0x8862
+#endif
+
+/*************************************************************/
+
+/* Available only in Common profile */
+GL_API void GL_APIENTRY glAlphaFunc (GLenum func, GLclampf ref);
+GL_API void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_API void GL_APIENTRY glClearDepthf (GLclampf depth);
+GL_API void GL_APIENTRY glClipPlanef (GLenum plane, const GLfloat *equation);
+GL_API void GL_APIENTRY glColor4f (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
+GL_API void GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar);
+GL_API void GL_APIENTRY glFogf (GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glFogfv (GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glFrustumf (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+GL_API void GL_APIENTRY glGetClipPlanef (GLenum pname, GLfloat eqn[4]);
+GL_API void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat *params);
+GL_API void GL_APIENTRY glGetLightfv (GLenum light, GLenum pname, GLfloat *params);
+GL_API void GL_APIENTRY glGetMaterialfv (GLenum face, GLenum pname, GLfloat *params);
+GL_API void GL_APIENTRY glGetTexEnvfv (GLenum env, GLenum pname, GLfloat *params);
+GL_API void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat *params);
+GL_API void GL_APIENTRY glLightModelf (GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glLightModelfv (GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glLightf (GLenum light, GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glLightfv (GLenum light, GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glLineWidth (GLfloat width);
+GL_API void GL_APIENTRY glLoadMatrixf (const GLfloat *m);
+GL_API void GL_APIENTRY glMaterialf (GLenum face, GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glMaterialfv (GLenum face, GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glMultMatrixf (const GLfloat *m);
+GL_API void GL_APIENTRY glMultiTexCoord4f (GLenum target, GLfloat s, GLfloat t, GLfloat r, GLfloat q);
+GL_API void GL_APIENTRY glNormal3f (GLfloat nx, GLfloat ny, GLfloat nz);
+GL_API void GL_APIENTRY glOrthof (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+GL_API void GL_APIENTRY glPointParameterf (GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glPointParameterfv (GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glPointSize (GLfloat size);
+GL_API void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);
+GL_API void GL_APIENTRY glRotatef (GLfloat angle, GLfloat x, GLfloat y, GLfloat z);
+GL_API void GL_APIENTRY glScalef (GLfloat x, GLfloat y, GLfloat z);
+GL_API void GL_APIENTRY glTexEnvf (GLenum target, GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glTexEnvfv (GLenum target, GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glTranslatef (GLfloat x, GLfloat y, GLfloat z);
+
+/* Available in both Common and Common-Lite profiles */
+GL_API void GL_APIENTRY glActiveTexture (GLenum texture);
+GL_API void GL_APIENTRY glAlphaFuncx (GLenum func, GLclampx ref);
+GL_API void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer);
+GL_API void GL_APIENTRY glBindTexture (GLenum target, GLuint texture);
+GL_API void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);
+GL_API void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage);
+GL_API void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data);
+GL_API void GL_APIENTRY glClear (GLbitfield mask);
+GL_API void GL_APIENTRY glClearColorx (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha);
+GL_API void GL_APIENTRY glClearDepthx (GLclampx depth);
+GL_API void GL_APIENTRY glClearStencil (GLint s);
+GL_API void GL_APIENTRY glClientActiveTexture (GLenum texture);
+GL_API void GL_APIENTRY glClipPlanex (GLenum plane, const GLfixed *equation);
+GL_API void GL_APIENTRY glColor4ub (GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha);
+GL_API void GL_APIENTRY glColor4x (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+GL_API void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+GL_API void GL_APIENTRY glColorPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+GL_API void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid *data);
+GL_API void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid *data);
+GL_API void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GL_API void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_API void GL_APIENTRY glCullFace (GLenum mode);
+GL_API void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint *buffers);
+GL_API void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint *textures);
+GL_API void GL_APIENTRY glDepthFunc (GLenum func);
+GL_API void GL_APIENTRY glDepthMask (GLboolean flag);
+GL_API void GL_APIENTRY glDepthRangex (GLclampx zNear, GLclampx zFar);
+GL_API void GL_APIENTRY glDisable (GLenum cap);
+GL_API void GL_APIENTRY glDisableClientState (GLenum array);
+GL_API void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
+GL_API void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices);
+GL_API void GL_APIENTRY glEnable (GLenum cap);
+GL_API void GL_APIENTRY glEnableClientState (GLenum array);
+GL_API void GL_APIENTRY glFinish (void);
+GL_API void GL_APIENTRY glFlush (void);
+GL_API void GL_APIENTRY glFogx (GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glFogxv (GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glFrontFace (GLenum mode);
+GL_API void GL_APIENTRY glFrustumx (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+GL_API void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean *params);
+GL_API void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint *params);
+GL_API void GL_APIENTRY glGetClipPlanex (GLenum pname, GLfixed eqn[4]);
+GL_API void GL_APIENTRY glGenBuffers (GLsizei n, GLuint *buffers);
+GL_API void GL_APIENTRY glGenTextures (GLsizei n, GLuint *textures);
+GL_API GLenum GL_APIENTRY glGetError (void);
+GL_API void GL_APIENTRY glGetFixedv (GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetIntegerv (GLenum pname, GLint *params);
+GL_API void GL_APIENTRY glGetLightxv (GLenum light, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetMaterialxv (GLenum face, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetPointerv (GLenum pname, GLvoid **params);
+GL_API const GLubyte * GL_APIENTRY glGetString (GLenum name);
+GL_API void GL_APIENTRY glGetTexEnviv (GLenum env, GLenum pname, GLint *params);
+GL_API void GL_APIENTRY glGetTexEnvxv (GLenum env, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint *params);
+GL_API void GL_APIENTRY glGetTexParameterxv (GLenum target, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glHint (GLenum target, GLenum mode);
+GL_API GLboolean GL_APIENTRY glIsBuffer (GLuint buffer);
+GL_API GLboolean GL_APIENTRY glIsEnabled (GLenum cap);
+GL_API GLboolean GL_APIENTRY glIsTexture (GLuint texture);
+GL_API void GL_APIENTRY glLightModelx (GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glLightModelxv (GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glLightx (GLenum light, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glLightxv (GLenum light, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glLineWidthx (GLfixed width);
+GL_API void GL_APIENTRY glLoadIdentity (void);
+GL_API void GL_APIENTRY glLoadMatrixx (const GLfixed *m);
+GL_API void GL_APIENTRY glLogicOp (GLenum opcode);
+GL_API void GL_APIENTRY glMaterialx (GLenum face, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glMaterialxv (GLenum face, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glMatrixMode (GLenum mode);
+GL_API void GL_APIENTRY glMultMatrixx (const GLfixed *m);
+GL_API void GL_APIENTRY glMultiTexCoord4x (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+GL_API void GL_APIENTRY glNormal3x (GLfixed nx, GLfixed ny, GLfixed nz);
+GL_API void GL_APIENTRY glNormalPointer (GLenum type, GLsizei stride, const GLvoid *pointer);
+GL_API void GL_APIENTRY glOrthox (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+GL_API void GL_APIENTRY glPixelStorei (GLenum pname, GLint param);
+GL_API void GL_APIENTRY glPointParameterx (GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glPointParameterxv (GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glPointSizex (GLfixed size);
+GL_API void GL_APIENTRY glPolygonOffsetx (GLfixed factor, GLfixed units);
+GL_API void GL_APIENTRY glPopMatrix (void);
+GL_API void GL_APIENTRY glPushMatrix (void);
+GL_API void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
+GL_API void GL_APIENTRY glRotatex (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
+GL_API void GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert);
+GL_API void GL_APIENTRY glSampleCoveragex (GLclampx value, GLboolean invert);
+GL_API void GL_APIENTRY glScalex (GLfixed x, GLfixed y, GLfixed z);
+GL_API void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
+GL_API void GL_APIENTRY glShadeModel (GLenum mode);
+GL_API void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask);
+GL_API void GL_APIENTRY glStencilMask (GLuint mask);
+GL_API void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
+GL_API void GL_APIENTRY glTexCoordPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+GL_API void GL_APIENTRY glTexEnvi (GLenum target, GLenum pname, GLint param);
+GL_API void GL_APIENTRY glTexEnvx (GLenum target, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glTexEnviv (GLenum target, GLenum pname, const GLint *params);
+GL_API void GL_APIENTRY glTexEnvxv (GLenum target, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
+GL_API void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
+GL_API void GL_APIENTRY glTexParameterx (GLenum target, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint *params);
+GL_API void GL_APIENTRY glTexParameterxv (GLenum target, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
+GL_API void GL_APIENTRY texSubImage2DAsync (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLint hpixels);
+GL_API void GL_APIENTRY glTranslatex (GLfixed x, GLfixed y, GLfixed z);
+GL_API void GL_APIENTRY glVertexPointer (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+GL_API void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
+
+/*------------------------------------------------------------------------*
+ * Required OES extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_read_format */
+#ifndef GL_OES_read_format
+#define GL_OES_read_format 1
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_OES_compressed_paletted_texture 1
+#endif
+
+/* GL_OES_point_size_array */
+#ifndef GL_OES_point_size_array
+#define GL_OES_point_size_array 1
+GL_API void GL_APIENTRY glPointSizePointerOES (GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+/* GL_OES_point_sprite */
+#ifndef GL_OES_point_sprite
+#define GL_OES_point_sprite 1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl_h_ */
+
diff --git a/interface/khronos/include/GLES/glext.h b/interface/khronos/include/GLES/glext.h
new file mode 100755 (executable)
index 0000000..20ad001
--- /dev/null
@@ -0,0 +1,1147 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef __glext_h_
+#define __glext_h_
+
+/* $Revision: 13240 $ on $Date:: 2010-12-17 15:16:00 -0800 #$ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* We want this */
+#ifndef GL_GLEXT_PROTOTYPES
+#define GL_GLEXT_PROTOTYPES
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+#ifndef GL_APIENTRYP
+#   define GL_APIENTRYP GL_APIENTRY*
+#endif
+
+/*------------------------------------------------------------------------*
+ * OES extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_blend_equation_separate */
+#ifndef GL_OES_blend_equation_separate
+/* BLEND_EQUATION_RGB_OES same as BLEND_EQUATION_OES */
+#define GL_BLEND_EQUATION_RGB_OES                               0x8009
+#define GL_BLEND_EQUATION_ALPHA_OES                             0x883D
+#endif
+
+/* GL_OES_blend_func_separate */
+#ifndef GL_OES_blend_func_separate
+#define GL_BLEND_DST_RGB_OES                                    0x80C8
+#define GL_BLEND_SRC_RGB_OES                                    0x80C9
+#define GL_BLEND_DST_ALPHA_OES                                  0x80CA
+#define GL_BLEND_SRC_ALPHA_OES                                  0x80CB
+#endif
+
+/* GL_OES_blend_subtract */
+#ifndef GL_OES_blend_subtract
+#define GL_BLEND_EQUATION_OES                                   0x8009
+#define GL_FUNC_ADD_OES                                         0x8006
+#define GL_FUNC_SUBTRACT_OES                                    0x800A
+#define GL_FUNC_REVERSE_SUBTRACT_OES                            0x800B
+#endif
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_ETC1_RGB8_OES                                        0x8D64
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_DEPTH_COMPONENT24_OES                                0x81A6
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_DEPTH_COMPONENT32_OES                                0x81A7
+#endif
+
+/* GL_OES_draw_texture */
+#ifndef GL_OES_draw_texture
+#define GL_TEXTURE_CROP_RECT_OES                                0x8B9D
+#endif
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+typedef void* GLeglImageOES;
+#endif
+
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
+/* GLeglImageOES defined in GL_OES_EGL_image already. */
+#define GL_TEXTURE_EXTERNAL_OES                                 0x8D65
+#define GL_TEXTURE_BINDING_EXTERNAL_OES                         0x8D67
+#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES                     0x8D68
+#endif
+
+/* GL_OES_element_index_uint */
+#ifndef GL_OES_element_index_uint
+#define GL_UNSIGNED_INT                                         0x1405
+#endif
+
+/* GL_OES_fixed_point */
+#ifndef GL_OES_fixed_point
+#define GL_FIXED_OES                                            0x140C
+#endif
+
+/* GL_OES_framebuffer_object */
+#ifndef GL_OES_framebuffer_object
+#define GL_NONE_OES                                             0
+#define GL_FRAMEBUFFER_OES                                      0x8D40
+#define GL_RENDERBUFFER_OES                                     0x8D41
+#define GL_RGBA4_OES                                            0x8056
+#define GL_RGB5_A1_OES                                          0x8057
+#define GL_RGB565_OES                                           0x8D62
+#define GL_DEPTH_COMPONENT16_OES                                0x81A5
+#define GL_RENDERBUFFER_WIDTH_OES                               0x8D42
+#define GL_RENDERBUFFER_HEIGHT_OES                              0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT_OES                     0x8D44
+#define GL_RENDERBUFFER_RED_SIZE_OES                            0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE_OES                          0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE_OES                           0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE_OES                          0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE_OES                          0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE_OES                        0x8D55
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE_OES               0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME_OES               0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES             0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE_OES     0x8CD3
+#define GL_COLOR_ATTACHMENT0_OES                                0x8CE0
+#define GL_DEPTH_ATTACHMENT_OES                                 0x8D00
+#define GL_STENCIL_ATTACHMENT_OES                               0x8D20
+#define GL_FRAMEBUFFER_COMPLETE_OES                             0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_OES                0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_OES        0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_OES                0x8CD9
+#define GL_FRAMEBUFFER_INCOMPLETE_FORMATS_OES                   0x8CDA
+#define GL_FRAMEBUFFER_UNSUPPORTED_OES                          0x8CDD
+#define GL_FRAMEBUFFER_BINDING_OES                              0x8CA6
+#define GL_RENDERBUFFER_BINDING_OES                             0x8CA7
+#define GL_MAX_RENDERBUFFER_SIZE_OES                            0x84E8
+#define GL_INVALID_FRAMEBUFFER_OPERATION_OES                    0x0506
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_WRITE_ONLY_OES                                       0x88B9
+#define GL_BUFFER_ACCESS_OES                                    0x88BB
+#define GL_BUFFER_MAPPED_OES                                    0x88BC
+#define GL_BUFFER_MAP_POINTER_OES                               0x88BD
+#endif
+
+/* GL_OES_matrix_get */
+#ifndef GL_OES_matrix_get
+#define GL_MODELVIEW_MATRIX_FLOAT_AS_INT_BITS_OES               0x898D
+#define GL_PROJECTION_MATRIX_FLOAT_AS_INT_BITS_OES              0x898E
+#define GL_TEXTURE_MATRIX_FLOAT_AS_INT_BITS_OES                 0x898F
+#endif
+
+/* GL_OES_matrix_palette */
+#ifndef GL_OES_matrix_palette
+#define GL_MAX_VERTEX_UNITS_OES                                 0x86A4
+#define GL_MAX_PALETTE_MATRICES_OES                             0x8842
+#define GL_MATRIX_PALETTE_OES                                   0x8840
+#define GL_MATRIX_INDEX_ARRAY_OES                               0x8844
+#define GL_WEIGHT_ARRAY_OES                                     0x86AD
+#define GL_CURRENT_PALETTE_MATRIX_OES                           0x8843
+#define GL_MATRIX_INDEX_ARRAY_SIZE_OES                          0x8846
+#define GL_MATRIX_INDEX_ARRAY_TYPE_OES                          0x8847
+#define GL_MATRIX_INDEX_ARRAY_STRIDE_OES                        0x8848
+#define GL_MATRIX_INDEX_ARRAY_POINTER_OES                       0x8849
+#define GL_MATRIX_INDEX_ARRAY_BUFFER_BINDING_OES                0x8B9E
+#define GL_WEIGHT_ARRAY_SIZE_OES                                0x86AB
+#define GL_WEIGHT_ARRAY_TYPE_OES                                0x86A9
+#define GL_WEIGHT_ARRAY_STRIDE_OES                              0x86AA
+#define GL_WEIGHT_ARRAY_POINTER_OES                             0x86AC
+#define GL_WEIGHT_ARRAY_BUFFER_BINDING_OES                      0x889E
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_DEPTH_STENCIL_OES                                    0x84F9
+#define GL_UNSIGNED_INT_24_8_OES                                0x84FA
+#define GL_DEPTH24_STENCIL8_OES                                 0x88F0
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_RGB8_OES                                             0x8051
+#define GL_RGBA8_OES                                            0x8058
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_STENCIL_INDEX1_OES                                   0x8D46
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_STENCIL_INDEX4_OES                                   0x8D47
+#endif
+
+/* GL_OES_stencil8 */
+#ifndef GL_OES_stencil8
+#define GL_STENCIL_INDEX8_OES                                   0x8D48
+#endif
+
+/* GL_OES_stencil_wrap */
+#ifndef GL_OES_stencil_wrap
+#define GL_INCR_WRAP_OES                                        0x8507
+#define GL_DECR_WRAP_OES                                        0x8508
+#endif
+
+/* GL_OES_texture_cube_map */
+#ifndef GL_OES_texture_cube_map
+#define GL_NORMAL_MAP_OES                                       0x8511
+#define GL_REFLECTION_MAP_OES                                   0x8512
+#define GL_TEXTURE_CUBE_MAP_OES                                 0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP_OES                         0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X_OES                      0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X_OES                      0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y_OES                      0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_OES                      0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z_OES                      0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_OES                      0x851A
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE_OES                        0x851C
+#define GL_TEXTURE_GEN_MODE_OES                                 0x2500
+#define GL_TEXTURE_GEN_STR_OES                                  0x8D60
+#endif
+
+/* GL_OES_texture_mirrored_repeat */
+#ifndef GL_OES_texture_mirrored_repeat
+#define GL_MIRRORED_REPEAT_OES                                  0x8370
+#endif
+
+/* GL_OES_vertex_array_object */
+#ifndef GL_OES_vertex_array_object
+#define GL_VERTEX_ARRAY_BINDING_OES                             0x85B5
+#endif
+
+/*------------------------------------------------------------------------*
+ * AMD extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_3DC_X_AMD                                            0x87F9
+#define GL_3DC_XY_AMD                                           0x87FA
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_ATC_RGB_AMD                                          0x8C92
+#define GL_ATC_RGBA_EXPLICIT_ALPHA_AMD                          0x8C93
+#define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD                      0x87EE
+#endif
+
+/*------------------------------------------------------------------------*
+ * APPLE extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_APPLE_texture_2D_limited_npot */
+/* No new tokens introduced by this extension. */
+
+/* GL_APPLE_framebuffer_multisample */
+#ifndef GL_APPLE_framebuffer_multisample
+#define GL_RENDERBUFFER_SAMPLES_APPLE                           0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE             0x8D56
+#define GL_MAX_SAMPLES_APPLE                                    0x8D57
+#define GL_READ_FRAMEBUFFER_APPLE                               0x8CA8
+#define GL_DRAW_FRAMEBUFFER_APPLE                               0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_APPLE                       0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_APPLE                       0x8CAA
+#endif
+
+/* GL_APPLE_texture_format_BGRA8888 */
+#ifndef GL_APPLE_texture_format_BGRA8888
+#define GL_BGRA_EXT                                             0x80E1
+#endif
+
+/* GL_APPLE_texture_max_level */
+#ifndef GL_APPLE_texture_max_level
+#define GL_TEXTURE_MAX_LEVEL_APPLE                              0x813D
+#endif
+
+/* GL_APPLE_rgb_422 */
+#ifndef GL_APPLE_rgb_422
+#define GL_APPLE_rgb_422 1
+#define GL_RGB_422_APPLE                                        0x8A1F
+#define GL_UNSIGNED_SHORT_8_8_APPLE                             0x85BA
+#define GL_UNSIGNED_SHORT_8_8_REV_APPLE                         0x85BB
+#endif
+/*------------------------------------------------------------------------*
+ * ARM extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_ARM_rgba8 */
+/* No new tokens introduced by this extension. */
+
+/*------------------------------------------------------------------------*
+ * EXT extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_blend_minmax */
+#ifndef GL_EXT_blend_minmax
+#define GL_MIN_EXT                                              0x8007
+#define GL_MAX_EXT                                              0x8008
+#endif
+
+/* GL_EXT_discard_framebuffer */
+#ifndef GL_EXT_discard_framebuffer
+#define GL_COLOR_EXT                                            0x1800
+#define GL_DEPTH_EXT                                            0x1801
+#define GL_STENCIL_EXT                                          0x1802
+#endif
+
+/* GL_EXT_multi_draw_arrays */
+/* No new tokens introduced by this extension. */
+
+/* GL_EXT_read_format_bgra */
+#ifndef GL_EXT_read_format_bgra
+#define GL_BGRA_EXT                                             0x80E1
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT                       0x8365
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT                       0x8366
+#endif
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT                           0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT                       0x84FF
+#endif
+
+/* GL_EXT_texture_format_BGRA8888 */
+#ifndef GL_EXT_texture_format_BGRA8888
+#define GL_BGRA_EXT                                             0x80E1
+#endif
+
+#ifndef GL_texture_format_RGBX8888_BRCM
+#define GL_RGBX_BRCM                                            0x80EE
+#endif
+
+/* GL_EXT_texture_lod_bias */
+#ifndef GL_EXT_texture_lod_bias
+#define GL_MAX_TEXTURE_LOD_BIAS_EXT                             0x84FD
+#define GL_TEXTURE_FILTER_CONTROL_EXT                           0x8500
+#define GL_TEXTURE_LOD_BIAS_EXT                                 0x8501
+#endif
+
+/*------------------------------------------------------------------------*
+ * IMG extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_IMG_read_format */
+#ifndef GL_IMG_read_format
+#define GL_BGRA_IMG                                             0x80E1
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV_IMG                       0x8365
+#endif
+
+/* GL_IMG_texture_compression_pvrtc */
+#ifndef GL_IMG_texture_compression_pvrtc
+#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG                      0x8C00
+#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG                      0x8C01
+#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG                     0x8C02
+#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG                     0x8C03
+#endif
+
+/* GL_IMG_texture_env_enhanced_fixed_function */
+#ifndef GL_IMG_texture_env_enhanced_fixed_function
+#define GL_MODULATE_COLOR_IMG                                   0x8C04
+#define GL_RECIP_ADD_SIGNED_ALPHA_IMG                           0x8C05
+#define GL_TEXTURE_ALPHA_MODULATE_IMG                           0x8C06
+#define GL_FACTOR_ALPHA_MODULATE_IMG                            0x8C07
+#define GL_FRAGMENT_ALPHA_MODULATE_IMG                          0x8C08
+#define GL_ADD_BLEND_IMG                                        0x8C09
+#define GL_DOT3_RGBA_IMG                                        0x86AF
+#endif
+
+/* GL_IMG_user_clip_plane */
+#ifndef GL_IMG_user_clip_plane
+#define GL_CLIP_PLANE0_IMG                                      0x3000
+#define GL_CLIP_PLANE1_IMG                                      0x3001
+#define GL_CLIP_PLANE2_IMG                                      0x3002
+#define GL_CLIP_PLANE3_IMG                                      0x3003
+#define GL_CLIP_PLANE4_IMG                                      0x3004
+#define GL_CLIP_PLANE5_IMG                                      0x3005
+#define GL_MAX_CLIP_PLANES_IMG                                  0x0D32
+#endif
+
+/* GL_IMG_multisampled_render_to_texture */
+#ifndef GL_IMG_multisampled_render_to_texture
+#define GL_RENDERBUFFER_SAMPLES_IMG                             0x9133
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG               0x9134
+#define GL_MAX_SAMPLES_IMG                                      0x9135
+#define GL_TEXTURE_SAMPLES_IMG                                  0x9136
+#endif
+
+/*------------------------------------------------------------------------*
+ * NV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_NV_fence */
+#ifndef GL_NV_fence
+#define GL_ALL_COMPLETED_NV                                     0x84F2
+#define GL_FENCE_STATUS_NV                                      0x84F3
+#define GL_FENCE_CONDITION_NV                                   0x84F4
+#endif
+
+/*------------------------------------------------------------------------*
+ * QCOM extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_QCOM_driver_control */
+/* No new tokens introduced by this extension. */
+
+/* GL_QCOM_extended_get */
+#ifndef GL_QCOM_extended_get
+#define GL_TEXTURE_WIDTH_QCOM                                   0x8BD2
+#define GL_TEXTURE_HEIGHT_QCOM                                  0x8BD3
+#define GL_TEXTURE_DEPTH_QCOM                                   0x8BD4
+#define GL_TEXTURE_INTERNAL_FORMAT_QCOM                         0x8BD5
+#define GL_TEXTURE_FORMAT_QCOM                                  0x8BD6
+#define GL_TEXTURE_TYPE_QCOM                                    0x8BD7
+#define GL_TEXTURE_IMAGE_VALID_QCOM                             0x8BD8
+#define GL_TEXTURE_NUM_LEVELS_QCOM                              0x8BD9
+#define GL_TEXTURE_TARGET_QCOM                                  0x8BDA
+#define GL_TEXTURE_OBJECT_VALID_QCOM                            0x8BDB
+#define GL_STATE_RESTORE                                        0x8BDC
+#endif
+
+/* GL_QCOM_extended_get2 */
+/* No new tokens introduced by this extension. */
+
+/* GL_QCOM_perfmon_global_mode */
+#ifndef GL_QCOM_perfmon_global_mode
+#define GL_PERFMON_GLOBAL_MODE_QCOM                             0x8FA0
+#endif
+
+/* GL_QCOM_writeonly_rendering */
+#ifndef GL_QCOM_writeonly_rendering
+#define GL_WRITEONLY_RENDERING_QCOM                             0x8823
+#endif
+
+/* GL_QCOM_tiled_rendering */
+#ifndef GL_QCOM_tiled_rendering
+#define GL_COLOR_BUFFER_BIT0_QCOM                               0x00000001
+#define GL_COLOR_BUFFER_BIT1_QCOM                               0x00000002
+#define GL_COLOR_BUFFER_BIT2_QCOM                               0x00000004
+#define GL_COLOR_BUFFER_BIT3_QCOM                               0x00000008
+#define GL_COLOR_BUFFER_BIT4_QCOM                               0x00000010
+#define GL_COLOR_BUFFER_BIT5_QCOM                               0x00000020
+#define GL_COLOR_BUFFER_BIT6_QCOM                               0x00000040
+#define GL_COLOR_BUFFER_BIT7_QCOM                               0x00000080
+#define GL_DEPTH_BUFFER_BIT0_QCOM                               0x00000100
+#define GL_DEPTH_BUFFER_BIT1_QCOM                               0x00000200
+#define GL_DEPTH_BUFFER_BIT2_QCOM                               0x00000400
+#define GL_DEPTH_BUFFER_BIT3_QCOM                               0x00000800
+#define GL_DEPTH_BUFFER_BIT4_QCOM                               0x00001000
+#define GL_DEPTH_BUFFER_BIT5_QCOM                               0x00002000
+#define GL_DEPTH_BUFFER_BIT6_QCOM                               0x00004000
+#define GL_DEPTH_BUFFER_BIT7_QCOM                               0x00008000
+#define GL_STENCIL_BUFFER_BIT0_QCOM                             0x00010000
+#define GL_STENCIL_BUFFER_BIT1_QCOM                             0x00020000
+#define GL_STENCIL_BUFFER_BIT2_QCOM                             0x00040000
+#define GL_STENCIL_BUFFER_BIT3_QCOM                             0x00080000
+#define GL_STENCIL_BUFFER_BIT4_QCOM                             0x00100000
+#define GL_STENCIL_BUFFER_BIT5_QCOM                             0x00200000
+#define GL_STENCIL_BUFFER_BIT6_QCOM                             0x00400000
+#define GL_STENCIL_BUFFER_BIT7_QCOM                             0x00800000
+#define GL_MULTISAMPLE_BUFFER_BIT0_QCOM                         0x01000000
+#define GL_MULTISAMPLE_BUFFER_BIT1_QCOM                         0x02000000
+#define GL_MULTISAMPLE_BUFFER_BIT2_QCOM                         0x04000000
+#define GL_MULTISAMPLE_BUFFER_BIT3_QCOM                         0x08000000
+#define GL_MULTISAMPLE_BUFFER_BIT4_QCOM                         0x10000000
+#define GL_MULTISAMPLE_BUFFER_BIT5_QCOM                         0x20000000
+#define GL_MULTISAMPLE_BUFFER_BIT6_QCOM                         0x40000000
+#define GL_MULTISAMPLE_BUFFER_BIT7_QCOM                         0x80000000
+#endif
+
+/*------------------------------------------------------------------------*
+ * BRCM extension tokens
+ * TODO: these aren't official yet
+ *------------------------------------------------------------------------*/
+#ifndef GL_BRCM_side_by_side_stero_hint
+#define GL_SIDE_BY_SIDE_STEREO_HINT_BRCM                        0x8193         /* GET AN OFFICIAL ENUM */
+#endif
+
+/*------------------------------------------------------------------------*
+ * End of extension tokens, start of corresponding extension functions
+ *------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------*
+ * OES extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_blend_equation_separate */
+#ifndef GL_OES_blend_equation_separate
+#define GL_OES_blend_equation_separate 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glBlendEquationSeparateOES (GLenum modeRGB, GLenum modeAlpha);
+#endif
+typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONSEPARATEOESPROC) (GLenum modeRGB, GLenum modeAlpha);
+#endif
+
+/* GL_OES_blend_func_separate */
+#ifndef GL_OES_blend_func_separate
+#define GL_OES_blend_func_separate 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glBlendFuncSeparateOES (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+#endif
+typedef void (GL_APIENTRYP PFNGLBLENDFUNCSEPARATEOESPROC) (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+#endif
+
+/* GL_OES_blend_subtract */
+#ifndef GL_OES_blend_subtract
+#define GL_OES_blend_subtract 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glBlendEquationOES (GLenum mode);
+#endif
+typedef void (GL_APIENTRYP PFNGLBLENDEQUATIONOESPROC) (GLenum mode);
+#endif
+
+/* GL_OES_byte_coordinates */
+#ifndef GL_OES_byte_coordinates
+#define GL_OES_byte_coordinates 0
+#endif
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_OES_compressed_ETC1_RGB8_texture 1
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_OES_depth24 0
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_OES_depth32 0
+#endif
+
+/* GL_OES_draw_texture */
+#ifndef GL_OES_draw_texture
+#define GL_OES_draw_texture 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glDrawTexsOES (GLshort x, GLshort y, GLshort z, GLshort width, GLshort height);
+GL_API void GL_APIENTRY glDrawTexiOES (GLint x, GLint y, GLint z, GLint width, GLint height);
+GL_API void GL_APIENTRY glDrawTexxOES (GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height);
+GL_API void GL_APIENTRY glDrawTexsvOES (const GLshort *coords);
+GL_API void GL_APIENTRY glDrawTexivOES (const GLint *coords);
+GL_API void GL_APIENTRY glDrawTexxvOES (const GLfixed *coords);
+GL_API void GL_APIENTRY glDrawTexfOES (GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height);
+GL_API void GL_APIENTRY glDrawTexfvOES (const GLfloat *coords);
+#endif
+typedef void (GL_APIENTRYP PFNGLDRAWTEXSOESPROC) (GLshort x, GLshort y, GLshort z, GLshort width, GLshort height);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXIOESPROC) (GLint x, GLint y, GLint z, GLint width, GLint height);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXXOESPROC) (GLfixed x, GLfixed y, GLfixed z, GLfixed width, GLfixed height);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXSVOESPROC) (const GLshort *coords);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXIVOESPROC) (const GLint *coords);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXXVOESPROC) (const GLfixed *coords);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXFOESPROC) (GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height);
+typedef void (GL_APIENTRYP PFNGLDRAWTEXFVOESPROC) (const GLfloat *coords);
+#endif
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+#define GL_OES_EGL_image 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image);
+GL_API void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image);
+#endif
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
+#endif
+
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
+#define GL_OES_EGL_image_external 1
+/* glEGLImageTargetTexture2DOES defined in GL_OES_EGL_image already. */
+#endif
+
+/* GL_OES_element_index_uint */
+#ifndef GL_OES_element_index_uint
+#define GL_OES_element_index_uint 0
+#endif
+
+/* GL_OES_extended_matrix_palette */
+#ifndef GL_OES_extended_matrix_palette
+#define GL_OES_extended_matrix_palette 0
+#endif
+
+/* GL_OES_fbo_render_mipmap */
+#ifndef GL_OES_fbo_render_mipmap
+#define GL_OES_fbo_render_mipmap 0
+#endif
+
+/* GL_OES_fixed_point */
+#ifndef GL_OES_fixed_point
+#define GL_OES_fixed_point 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glAlphaFuncxOES (GLenum func, GLclampx ref);
+GL_API void GL_APIENTRY glClearColorxOES (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha);
+GL_API void GL_APIENTRY glClearDepthxOES (GLclampx depth);
+GL_API void GL_APIENTRY glClipPlanexOES (GLenum plane, const GLfixed *equation);
+GL_API void GL_APIENTRY glColor4xOES (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+GL_API void GL_APIENTRY glDepthRangexOES (GLclampx zNear, GLclampx zFar);
+GL_API void GL_APIENTRY glFogxOES (GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glFogxvOES (GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glFrustumxOES (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+GL_API void GL_APIENTRY glGetClipPlanexOES (GLenum pname, GLfixed eqn[4]);
+GL_API void GL_APIENTRY glGetFixedvOES (GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetLightxvOES (GLenum light, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetMaterialxvOES (GLenum face, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetTexEnvxvOES (GLenum env, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glGetTexParameterxvOES (GLenum target, GLenum pname, GLfixed *params);
+GL_API void GL_APIENTRY glLightModelxOES (GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glLightModelxvOES (GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glLightxOES (GLenum light, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glLightxvOES (GLenum light, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glLineWidthxOES (GLfixed width);
+GL_API void GL_APIENTRY glLoadMatrixxOES (const GLfixed *m);
+GL_API void GL_APIENTRY glMaterialxOES (GLenum face, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glMaterialxvOES (GLenum face, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glMultMatrixxOES (const GLfixed *m);
+GL_API void GL_APIENTRY glMultiTexCoord4xOES (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+GL_API void GL_APIENTRY glNormal3xOES (GLfixed nx, GLfixed ny, GLfixed nz);
+GL_API void GL_APIENTRY glOrthoxOES (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+GL_API void GL_APIENTRY glPointParameterxOES (GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glPointParameterxvOES (GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glPointSizexOES (GLfixed size);
+GL_API void GL_APIENTRY glPolygonOffsetxOES (GLfixed factor, GLfixed units);
+GL_API void GL_APIENTRY glRotatexOES (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
+GL_API void GL_APIENTRY glSampleCoveragexOES (GLclampx value, GLboolean invert);
+GL_API void GL_APIENTRY glScalexOES (GLfixed x, GLfixed y, GLfixed z);
+GL_API void GL_APIENTRY glTexEnvxOES (GLenum target, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glTexEnvxvOES (GLenum target, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glTexParameterxOES (GLenum target, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glTexParameterxvOES (GLenum target, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glTranslatexOES (GLfixed x, GLfixed y, GLfixed z);
+#endif
+typedef void (GL_APIENTRYP PFNGLALPHAFUNCXOESPROC) (GLenum func, GLclampx ref);
+typedef void (GL_APIENTRYP PFNGLCLEARCOLORXOESPROC) (GLclampx red, GLclampx green, GLclampx blue, GLclampx alpha);
+typedef void (GL_APIENTRYP PFNGLCLEARDEPTHXOESPROC) (GLclampx depth);
+typedef void (GL_APIENTRYP PFNGLCLIPPLANEXOESPROC) (GLenum plane, const GLfixed *equation);
+typedef void (GL_APIENTRYP PFNGLCOLOR4XOESPROC) (GLfixed red, GLfixed green, GLfixed blue, GLfixed alpha);
+typedef void (GL_APIENTRYP PFNGLDEPTHRANGEXOESPROC) (GLclampx zNear, GLclampx zFar);
+typedef void (GL_APIENTRYP PFNGLFOGXOESPROC) (GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLFOGXVOESPROC) (GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLFRUSTUMXOESPROC) (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+typedef void (GL_APIENTRYP PFNGLGETCLIPPLANEXOESPROC) (GLenum pname, GLfixed eqn[4]);
+typedef void (GL_APIENTRYP PFNGLGETFIXEDVOESPROC) (GLenum pname, GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLGETLIGHTXVOESPROC) (GLenum light, GLenum pname, GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLGETMATERIALXVOESPROC) (GLenum face, GLenum pname, GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLGETTEXENVXVOESPROC) (GLenum env, GLenum pname, GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLGETTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLLIGHTMODELXOESPROC) (GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLLIGHTMODELXVOESPROC) (GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLLIGHTXOESPROC) (GLenum light, GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLLIGHTXVOESPROC) (GLenum light, GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLLINEWIDTHXOESPROC) (GLfixed width);
+typedef void (GL_APIENTRYP PFNGLLOADMATRIXXOESPROC) (const GLfixed *m);
+typedef void (GL_APIENTRYP PFNGLMATERIALXOESPROC) (GLenum face, GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLMATERIALXVOESPROC) (GLenum face, GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLMULTMATRIXXOESPROC) (const GLfixed *m);
+typedef void (GL_APIENTRYP PFNGLMULTITEXCOORD4XOESPROC) (GLenum target, GLfixed s, GLfixed t, GLfixed r, GLfixed q);
+typedef void (GL_APIENTRYP PFNGLNORMAL3XOESPROC) (GLfixed nx, GLfixed ny, GLfixed nz);
+typedef void (GL_APIENTRYP PFNGLORTHOXOESPROC) (GLfixed left, GLfixed right, GLfixed bottom, GLfixed top, GLfixed zNear, GLfixed zFar);
+typedef void (GL_APIENTRYP PFNGLPOINTPARAMETERXOESPROC) (GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLPOINTPARAMETERXVOESPROC) (GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLPOINTSIZEXOESPROC) (GLfixed size);
+typedef void (GL_APIENTRYP PFNGLPOLYGONOFFSETXOESPROC) (GLfixed factor, GLfixed units);
+typedef void (GL_APIENTRYP PFNGLROTATEXOESPROC) (GLfixed angle, GLfixed x, GLfixed y, GLfixed z);
+typedef void (GL_APIENTRYP PFNGLSAMPLECOVERAGEXOESPROC) (GLclampx value, GLboolean invert);
+typedef void (GL_APIENTRYP PFNGLSCALEXOESPROC) (GLfixed x, GLfixed y, GLfixed z);
+typedef void (GL_APIENTRYP PFNGLTEXENVXOESPROC) (GLenum target, GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLTEXENVXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLTEXPARAMETERXOESPROC) (GLenum target, GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLTEXPARAMETERXVOESPROC) (GLenum target, GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLTRANSLATEXOESPROC) (GLfixed x, GLfixed y, GLfixed z);
+#endif
+
+/* GL_OES_framebuffer_object */
+#ifndef GL_OES_framebuffer_object
+#define GL_OES_framebuffer_object 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API GLboolean GL_APIENTRY glIsRenderbufferOES (GLuint renderbuffer);
+GL_API void GL_APIENTRY glBindRenderbufferOES (GLenum target, GLuint renderbuffer);
+GL_API void GL_APIENTRY glDeleteRenderbuffersOES (GLsizei n, const GLuint* renderbuffers);
+GL_API void GL_APIENTRY glGenRenderbuffersOES (GLsizei n, GLuint* renderbuffers);
+GL_API void GL_APIENTRY glRenderbufferStorageOES (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GL_API void GL_APIENTRY glGetRenderbufferParameterivOES (GLenum target, GLenum pname, GLint* params);
+GL_API GLboolean GL_APIENTRY glIsFramebufferOES (GLuint framebuffer);
+GL_API void GL_APIENTRY glBindFramebufferOES (GLenum target, GLuint framebuffer);
+GL_API void GL_APIENTRY glDeleteFramebuffersOES (GLsizei n, const GLuint* framebuffers);
+GL_API void GL_APIENTRY glGenFramebuffersOES (GLsizei n, GLuint* framebuffers);
+GL_API GLenum GL_APIENTRY glCheckFramebufferStatusOES (GLenum target);
+GL_API void GL_APIENTRY glFramebufferRenderbufferOES (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GL_API void GL_APIENTRY glFramebufferTexture2DOES (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GL_API void GL_APIENTRY glGetFramebufferAttachmentParameterivOES (GLenum target, GLenum attachment, GLenum pname, GLint* params);
+GL_API void GL_APIENTRY glGenerateMipmapOES (GLenum target);
+#endif
+typedef GLboolean (GL_APIENTRYP PFNGLISRENDERBUFFEROESPROC) (GLuint renderbuffer);
+typedef void (GL_APIENTRYP PFNGLBINDRENDERBUFFEROESPROC) (GLenum target, GLuint renderbuffer);
+typedef void (GL_APIENTRYP PFNGLDELETERENDERBUFFERSOESPROC) (GLsizei n, const GLuint* renderbuffers);
+typedef void (GL_APIENTRYP PFNGLGENRENDERBUFFERSOESPROC) (GLsizei n, GLuint* renderbuffers);
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLGETRENDERBUFFERPARAMETERIVOESPROC) (GLenum target, GLenum pname, GLint* params);
+typedef GLboolean (GL_APIENTRYP PFNGLISFRAMEBUFFEROESPROC) (GLuint framebuffer);
+typedef void (GL_APIENTRYP PFNGLBINDFRAMEBUFFEROESPROC) (GLenum target, GLuint framebuffer);
+typedef void (GL_APIENTRYP PFNGLDELETEFRAMEBUFFERSOESPROC) (GLsizei n, const GLuint* framebuffers);
+typedef void (GL_APIENTRYP PFNGLGENFRAMEBUFFERSOESPROC) (GLsizei n, GLuint* framebuffers);
+typedef GLenum (GL_APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSOESPROC) (GLenum target);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEROESPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DOESPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+typedef void (GL_APIENTRYP PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVOESPROC) (GLenum target, GLenum attachment, GLenum pname, GLint* params);
+typedef void (GL_APIENTRYP PFNGLGENERATEMIPMAPOESPROC) (GLenum target);
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_OES_mapbuffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void* GL_APIENTRY glMapBufferOES (GLenum target, GLenum access);
+GL_API GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target);
+GL_API void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, GLvoid ** params);
+#endif
+typedef void* (GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access);
+typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFEROESPROC) (GLenum target);
+typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, GLvoid ** params);
+#endif
+
+/* GL_OES_matrix_get */
+#ifndef GL_OES_matrix_get
+#define GL_OES_matrix_get 0
+#endif
+
+/* GL_OES_matrix_palette */
+#ifndef GL_OES_matrix_palette
+#define GL_OES_matrix_palette 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glCurrentPaletteMatrixOES (GLuint matrixpaletteindex);
+GL_API void GL_APIENTRY glLoadPaletteFromModelViewMatrixOES (void);
+GL_API void GL_APIENTRY glMatrixIndexPointerOES (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+GL_API void GL_APIENTRY glWeightPointerOES (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+typedef void (GL_APIENTRYP PFNGLCURRENTPALETTEMATRIXOESPROC) (GLuint matrixpaletteindex);
+typedef void (GL_APIENTRYP PFNGLLOADPALETTEFROMMODELVIEWMATRIXOESPROC) (void);
+typedef void (GL_APIENTRYP PFNGLMATRIXINDEXPOINTEROESPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+typedef void (GL_APIENTRYP PFNGLWEIGHTPOINTEROESPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_OES_packed_depth_stencil 0
+#endif
+
+/* GL_OES_query_matrix */
+#ifndef GL_OES_query_matrix
+#define GL_OES_query_matrix 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API GLbitfield GL_APIENTRY glQueryMatrixxOES (GLfixed mantissa[16], GLint exponent[16]);
+#endif
+typedef GLbitfield (GL_APIENTRYP PFNGLQUERYMATRIXXOESPROC) (GLfixed mantissa[16], GLint exponent[16]);
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_OES_rgb8_rgba8 1
+#endif
+
+/* GL_OES_single_precision */
+#ifndef GL_OES_single_precision
+#define GL_OES_single_precision 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glDepthRangefOES (GLclampf zNear, GLclampf zFar);
+GL_API void GL_APIENTRY glFrustumfOES (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+GL_API void GL_APIENTRY glOrthofOES (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+GL_API void GL_APIENTRY glClipPlanefOES (GLenum plane, const GLfloat *equation);
+GL_API void GL_APIENTRY glGetClipPlanefOES (GLenum pname, GLfloat eqn[4]);
+GL_API void GL_APIENTRY glClearDepthfOES (GLclampf depth);
+#endif
+typedef void (GL_APIENTRYP PFNGLDEPTHRANGEFOESPROC) (GLclampf zNear, GLclampf zFar);
+typedef void (GL_APIENTRYP PFNGLFRUSTUMFOESPROC) (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+typedef void (GL_APIENTRYP PFNGLORTHOFOESPROC) (GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat zNear, GLfloat zFar);
+typedef void (GL_APIENTRYP PFNGLCLIPPLANEFOESPROC) (GLenum plane, const GLfloat *equation);
+typedef void (GL_APIENTRYP PFNGLGETCLIPPLANEFOESPROC) (GLenum pname, GLfloat eqn[4]);
+typedef void (GL_APIENTRYP PFNGLCLEARDEPTHFOESPROC) (GLclampf depth);
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_OES_stencil1 0
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_OES_stencil4 0
+#endif
+
+/* GL_OES_stencil8 */
+#ifndef GL_OES_stencil8
+#define GL_OES_stencil8 1
+#endif
+
+/* GL_OES_stencil_wrap */
+#ifndef GL_OES_stencil_wrap
+#define GL_OES_stencil_wrap 0
+#endif
+
+/* GL_OES_texture_cube_map */
+#ifndef GL_OES_texture_cube_map
+#define GL_OES_texture_cube_map 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glTexGenfOES (GLenum coord, GLenum pname, GLfloat param);
+GL_API void GL_APIENTRY glTexGenfvOES (GLenum coord, GLenum pname, const GLfloat *params);
+GL_API void GL_APIENTRY glTexGeniOES (GLenum coord, GLenum pname, GLint param);
+GL_API void GL_APIENTRY glTexGenivOES (GLenum coord, GLenum pname, const GLint *params);
+GL_API void GL_APIENTRY glTexGenxOES (GLenum coord, GLenum pname, GLfixed param);
+GL_API void GL_APIENTRY glTexGenxvOES (GLenum coord, GLenum pname, const GLfixed *params);
+GL_API void GL_APIENTRY glGetTexGenfvOES (GLenum coord, GLenum pname, GLfloat *params);
+GL_API void GL_APIENTRY glGetTexGenivOES (GLenum coord, GLenum pname, GLint *params);
+GL_API void GL_APIENTRY glGetTexGenxvOES (GLenum coord, GLenum pname, GLfixed *params);
+#endif
+typedef void (GL_APIENTRYP PFNGLTEXGENFOESPROC) (GLenum coord, GLenum pname, GLfloat param);
+typedef void (GL_APIENTRYP PFNGLTEXGENFVOESPROC) (GLenum coord, GLenum pname, const GLfloat *params);
+typedef void (GL_APIENTRYP PFNGLTEXGENIOESPROC) (GLenum coord, GLenum pname, GLint param);
+typedef void (GL_APIENTRYP PFNGLTEXGENIVOESPROC) (GLenum coord, GLenum pname, const GLint *params);
+typedef void (GL_APIENTRYP PFNGLTEXGENXOESPROC) (GLenum coord, GLenum pname, GLfixed param);
+typedef void (GL_APIENTRYP PFNGLTEXGENXVOESPROC) (GLenum coord, GLenum pname, const GLfixed *params);
+typedef void (GL_APIENTRYP PFNGLGETTEXGENFVOESPROC) (GLenum coord, GLenum pname, GLfloat *params);
+typedef void (GL_APIENTRYP PFNGLGETTEXGENIVOESPROC) (GLenum coord, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLGETTEXGENXVOESPROC) (GLenum coord, GLenum pname, GLfixed *params);
+#endif
+
+/* GL_OES_texture_env_crossbar */
+#ifndef GL_OES_texture_env_crossbar
+#define GL_OES_texture_env_crossbar 0
+#endif
+
+/* GL_OES_texture_mirrored_repeat */
+#ifndef GL_OES_texture_mirrored_repeat
+#define GL_OES_texture_mirrored_repeat 0
+#endif
+
+/* GL_OES_vertex_array_object */
+#ifndef GL_OES_vertex_array_object
+#define GL_OES_vertex_array_object 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glBindVertexArrayOES (GLuint array);
+GL_API void GL_APIENTRY glDeleteVertexArraysOES (GLsizei n, const GLuint *arrays);
+GL_API void GL_APIENTRY glGenVertexArraysOES (GLsizei n, GLuint *arrays);
+GL_API GLboolean GL_APIENTRY glIsVertexArrayOES (GLuint array);
+#endif
+typedef void (GL_APIENTRYP PFNGLBINDVERTEXARRAYOESPROC) (GLuint array);
+typedef void (GL_APIENTRYP PFNGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays);
+typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays);
+typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array);
+#endif
+
+/*------------------------------------------------------------------------*
+ * AMD extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_AMD_compressed_3DC_texture 0
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_AMD_compressed_ATC_texture 0
+#endif
+
+/*------------------------------------------------------------------------*
+ * APPLE extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_APPLE_texture_2D_limited_npot */
+#ifndef GL_APPLE_texture_2D_limited_npot
+#define GL_APPLE_texture_2D_limited_npot 0
+#endif
+
+/* GL_APPLE_framebuffer_multisample */
+#ifndef GL_APPLE_framebuffer_multisample
+#define GL_APPLE_framebuffer_multisample 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glRenderbufferStorageMultisampleAPPLE (GLenum, GLsizei, GLenum, GLsizei, GLsizei);
+GL_API void GL_APIENTRY glResolveMultisampleFramebufferAPPLE (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEAPPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC) (void);
+#endif
+
+/* GL_APPLE_texture_format_BGRA8888 */
+#ifndef GL_APPLE_texture_format_BGRA8888
+#define GL_APPLE_texture_format_BGRA8888 0
+#endif
+
+/* GL_APPLE_texture_max_level */
+#ifndef GL_APPLE_texture_max_level
+#define GL_APPLE_texture_max_level 0
+#endif
+
+/*------------------------------------------------------------------------*
+ * ARM extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_ARM_rgba8 */
+#ifndef GL_ARM_rgba8
+#define GL_ARM_rgba8 0
+#endif
+
+/*------------------------------------------------------------------------*
+ * EXT extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_blend_minmax */
+#ifndef GL_EXT_blend_minmax
+#define GL_EXT_blend_minmax 0
+#endif
+
+/* GL_EXT_discard_framebuffer */
+#ifndef GL_EXT_discard_framebuffer
+#define GL_EXT_discard_framebuffer 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glDiscardFramebufferEXT (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+#endif
+typedef void (GL_APIENTRYP PFNGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+#endif
+
+/* GL_EXT_debug_marker */
+#ifndef GL_EXT_debug_marker
+#define GL_EXT_debug_marker 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar *marker);
+GL_API void GL_APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar *marker);
+GL_API void GL_APIENTRY glPopGroupMarkerEXT (void);
+#endif
+typedef void (GL_APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (GL_APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (GL_APIENTRYP PFNGLPOPGROUPMARKEREXTPROC) (void);
+#endif
+
+/* GL_EXT_multi_draw_arrays */
+#ifndef GL_EXT_multi_draw_arrays
+#define GL_EXT_multi_draw_arrays 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glMultiDrawArraysEXT (GLenum, GLint *, GLsizei *, GLsizei);
+GL_API void GL_APIENTRY glMultiDrawElementsEXT (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (GL_APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);
+typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);
+#endif
+
+/* GL_EXT_read_format_bgra */
+#ifndef GL_EXT_read_format_bgra
+#define GL_EXT_read_format_bgra 0
+#endif
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_EXT_texture_filter_anisotropic 0
+#endif
+
+/* GL_EXT_texture_format_BGRA8888 */
+#ifndef GL_EXT_texture_format_BGRA8888
+#define GL_EXT_texture_format_BGRA8888 1
+#endif
+
+#ifndef GL_texture_format_RGBX8888_BRCM
+#define GL_texture_format_RGBX8888_BRCM 1
+#endif
+
+/* GL_EXT_texture_lod_bias */
+#ifndef GL_EXT_texture_lod_bias
+#define GL_EXT_texture_lod_bias 0
+#endif
+
+/*------------------------------------------------------------------------*
+ * IMG extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_IMG_read_format */
+#ifndef GL_IMG_read_format
+#define GL_IMG_read_format 0
+#endif
+
+/* GL_IMG_texture_compression_pvrtc */
+#ifndef GL_IMG_texture_compression_pvrtc
+#define GL_IMG_texture_compression_pvrtc 0
+#endif
+
+/* GL_IMG_texture_env_enhanced_fixed_function */
+#ifndef GL_IMG_texture_env_enhanced_fixed_function
+#define GL_IMG_texture_env_enhanced_fixed_function 0
+#endif
+
+/* GL_IMG_user_clip_plane */
+#ifndef GL_IMG_user_clip_plane
+#define GL_IMG_user_clip_plane 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glClipPlanefIMG (GLenum, const GLfloat *);
+GL_API void GL_APIENTRY glClipPlanexIMG (GLenum, const GLfixed *);
+#endif
+typedef void (GL_APIENTRYP PFNGLCLIPPLANEFIMGPROC) (GLenum p, const GLfloat *eqn);
+typedef void (GL_APIENTRYP PFNGLCLIPPLANEXIMGPROC) (GLenum p, const GLfixed *eqn);
+#endif
+
+/* GL_IMG_multisampled_render_to_texture */
+#ifndef GL_IMG_multisampled_render_to_texture
+#define GL_IMG_multisampled_render_to_texture 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glRenderbufferStorageMultisampleIMG (GLenum, GLsizei, GLenum, GLsizei, GLsizei);
+GL_API void GL_APIENTRY glFramebufferTexture2DMultisampleIMG (GLenum, GLenum, GLenum, GLuint, GLint, GLsizei);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEIMG) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEIMG) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#endif
+
+/*------------------------------------------------------------------------*
+ * NV extension functions
+ *------------------------------------------------------------------------*/
+
+/* NV_fence */
+#ifndef GL_NV_fence
+#define GL_NV_fence 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glDeleteFencesNV (GLsizei, const GLuint *);
+GL_API void GL_APIENTRY glGenFencesNV (GLsizei, GLuint *);
+GL_API GLboolean GL_APIENTRY glIsFenceNV (GLuint);
+GL_API GLboolean GL_APIENTRY glTestFenceNV (GLuint);
+GL_API void GL_APIENTRY glGetFenceivNV (GLuint, GLenum, GLint *);
+GL_API void GL_APIENTRY glFinishFenceNV (GLuint);
+GL_API void GL_APIENTRY glSetFenceNV (GLuint, GLenum);
+#endif
+typedef void (GL_APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences);
+typedef void (GL_APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences);
+typedef GLboolean (GL_APIENTRYP PFNGLISFENCENVPROC) (GLuint fence);
+typedef GLboolean (GL_APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence);
+typedef void (GL_APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence);
+typedef void (GL_APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);
+#endif
+
+/*------------------------------------------------------------------------*
+ * QCOM extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_QCOM_driver_control */
+#ifndef GL_QCOM_driver_control
+#define GL_QCOM_driver_control 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glGetDriverControlsQCOM (GLint *num, GLsizei size, GLuint *driverControls);
+GL_API void GL_APIENTRY glGetDriverControlStringQCOM (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);
+GL_API void GL_APIENTRY glEnableDriverControlQCOM (GLuint driverControl);
+GL_API void GL_APIENTRY glDisableDriverControlQCOM (GLuint driverControl);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSQCOMPROC) (GLint *num, GLsizei size, GLuint *driverControls);
+typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSTRINGQCOMPROC) (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);
+typedef void (GL_APIENTRYP PFNGLENABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
+typedef void (GL_APIENTRYP PFNGLDISABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
+#endif
+
+/* GL_QCOM_extended_get */
+#ifndef GL_QCOM_extended_get
+#define GL_QCOM_extended_get 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glExtGetTexturesQCOM (GLuint *textures, GLint maxTextures, GLint *numTextures);
+GL_API void GL_APIENTRY glExtGetBuffersQCOM (GLuint *buffers, GLint maxBuffers, GLint *numBuffers);
+GL_API void GL_APIENTRY glExtGetRenderbuffersQCOM (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers);
+GL_API void GL_APIENTRY glExtGetFramebuffersQCOM (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers);
+GL_API void GL_APIENTRY glExtGetTexLevelParameterivQCOM (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params);
+GL_API void GL_APIENTRY glExtTexObjectStateOverrideiQCOM (GLenum target, GLenum pname, GLint param);
+GL_API void GL_APIENTRY glExtGetTexSubImageQCOM (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels);
+GL_API void GL_APIENTRY glExtGetBufferPointervQCOM (GLenum target, GLvoid **params);
+#endif
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXTURESQCOMPROC) (GLuint *textures, GLint maxTextures, GLint *numTextures);
+typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERSQCOMPROC) (GLuint *buffers, GLint maxBuffers, GLint *numBuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETRENDERBUFFERSQCOMPROC) (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETFRAMEBUFFERSQCOMPROC) (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXLEVELPARAMETERIVQCOMPROC) (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLEXTTEXOBJECTSTATEOVERRIDEIQCOMPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXSUBIMAGEQCOMPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels);
+typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERPOINTERVQCOMPROC) (GLenum target, GLvoid **params);
+#endif
+
+/* GL_QCOM_extended_get2 */
+#ifndef GL_QCOM_extended_get2
+#define GL_QCOM_extended_get2 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glExtGetShadersQCOM (GLuint *shaders, GLint maxShaders, GLint *numShaders);
+GL_API void GL_APIENTRY glExtGetProgramsQCOM (GLuint *programs, GLint maxPrograms, GLint *numPrograms);
+GL_API GLboolean GL_APIENTRY glExtIsProgramBinaryQCOM (GLuint program);
+GL_API void GL_APIENTRY glExtGetProgramBinarySourceQCOM (GLuint program, GLenum shadertype, GLchar *source, GLint *length);
+#endif
+typedef void (GL_APIENTRYP PFNGLEXTGETSHADERSQCOMPROC) (GLuint *shaders, GLint maxShaders, GLint *numShaders);
+typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMSQCOMPROC) (GLuint *programs, GLint maxPrograms, GLint *numPrograms);
+typedef GLboolean (GL_APIENTRYP PFNGLEXTISPROGRAMBINARYQCOMPROC) (GLuint program);
+typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMBINARYSOURCEQCOMPROC) (GLuint program, GLenum shadertype, GLchar *source, GLint *length);
+#endif
+
+/* GL_QCOM_perfmon_global_mode */
+#ifndef GL_QCOM_perfmon_global_mode
+#define GL_QCOM_perfmon_global_mode 0
+#endif
+
+/* GL_QCOM_writeonly_rendering */
+#ifndef GL_QCOM_writeonly_rendering
+#define GL_QCOM_writeonly_rendering 0
+#endif
+
+/* GL_QCOM_tiled_rendering */
+#ifndef GL_QCOM_tiled_rendering
+#define GL_QCOM_tiled_rendering 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_API void GL_APIENTRY glStartTilingQCOM (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask);
+GL_API void GL_APIENTRY glEndTilingQCOM (GLbitfield preserveMask);
+#endif
+typedef void (GL_APIENTRYP PFNGLSTARTTILINGQCOMPROC) (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask);
+typedef void (GL_APIENTRYP PFNGLENDTILINGQCOMPROC) (GLbitfield preserveMask);
+#endif
+
+/*------------------------------------------------------------------------*
+ * BRCM extension functions
+ * TODO: these aren't official yet
+ *------------------------------------------------------------------------*/
+#ifndef GL_BRCM_side_by_side_stero_hint
+#define GL_BRCM_side_by_side_stero_hint 1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __glext_h_ */
diff --git a/interface/khronos/include/GLES/glplatform.h b/interface/khronos/include/GLES/glplatform.h
new file mode 100755 (executable)
index 0000000..cad1905
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef __glplatform_h_
+#define __glplatform_h_
+
+/* $Revision: 10601 $ on $Date:: 2010-03-04 22:15:27 -0800 #$ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/* Platform-specific types and definitions for OpenGL ES 1.X  gl.h
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file.  Please submit changes
+ * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
+ * by filing a bug against product "OpenGL-ES" component "Registry".
+ */
+
+#include "../KHR/khrplatform.h"
+
+#ifndef GL_API
+#define GL_API      KHRONOS_APICALL
+#endif
+
+#ifndef GL_APIENTRY
+#define GL_APIENTRY KHRONOS_APIENTRY
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __glplatform_h_ */
diff --git a/interface/khronos/include/GLES2/gl2.h b/interface/khronos/include/GLES2/gl2.h
new file mode 100755 (executable)
index 0000000..a14ed58
--- /dev/null
@@ -0,0 +1,649 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef __gl2_h_
+#define __gl2_h_
+
+/* $Revision: 10602 $ on $Date:: 2010-03-05 06:35:34 +0000 #$ */
+
+#include "gl2platform.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/*-------------------------------------------------------------------------
+ * Data type definitions
+ *-----------------------------------------------------------------------*/
+
+#ifndef __gl_h_
+typedef void             GLvoid;
+typedef char             GLchar;
+typedef unsigned int     GLenum;
+typedef unsigned char    GLboolean;
+typedef unsigned int     GLbitfield;
+typedef khronos_int8_t   GLbyte;
+typedef short            GLshort;
+typedef int              GLint;
+typedef int              GLsizei;
+typedef khronos_uint8_t  GLubyte;
+typedef unsigned short   GLushort;
+typedef unsigned int     GLuint;
+typedef khronos_float_t  GLfloat;
+typedef khronos_float_t  GLclampf;
+typedef khronos_int32_t  GLfixed;
+
+/* GL types for handling large vertex buffer objects */
+typedef khronos_intptr_t GLintptr;
+typedef khronos_ssize_t  GLsizeiptr;
+#endif
+
+/* OpenGL ES core versions */
+#define GL_ES_VERSION_2_0                 1
+
+/* ClearBufferMask */
+#define GL_DEPTH_BUFFER_BIT               0x00000100
+#define GL_STENCIL_BUFFER_BIT             0x00000400
+#define GL_COLOR_BUFFER_BIT               0x00004000
+
+/* Boolean */
+#define GL_FALSE                          (GLboolean)0
+#define GL_TRUE                           (GLboolean)1
+
+/* BeginMode */
+#define GL_POINTS                         0x0000
+#define GL_LINES                          0x0001
+#define GL_LINE_LOOP                      0x0002
+#define GL_LINE_STRIP                     0x0003
+#define GL_TRIANGLES                      0x0004
+#define GL_TRIANGLE_STRIP                 0x0005
+#define GL_TRIANGLE_FAN                   0x0006
+
+/* AlphaFunction (not supported in ES20) */
+/*      GL_NEVER */
+/*      GL_LESS */
+/*      GL_EQUAL */
+/*      GL_LEQUAL */
+/*      GL_GREATER */
+/*      GL_NOTEQUAL */
+/*      GL_GEQUAL */
+/*      GL_ALWAYS */
+
+/* BlendingFactorDest */
+#define GL_ZERO                           0
+#define GL_ONE                            1
+#define GL_SRC_COLOR                      0x0300
+#define GL_ONE_MINUS_SRC_COLOR            0x0301
+#define GL_SRC_ALPHA                      0x0302
+#define GL_ONE_MINUS_SRC_ALPHA            0x0303
+#define GL_DST_ALPHA                      0x0304
+#define GL_ONE_MINUS_DST_ALPHA            0x0305
+
+/* BlendingFactorSrc */
+/*      GL_ZERO */
+/*      GL_ONE */
+#define GL_DST_COLOR                      0x0306
+#define GL_ONE_MINUS_DST_COLOR            0x0307
+#define GL_SRC_ALPHA_SATURATE             0x0308
+/*      GL_SRC_ALPHA */
+/*      GL_ONE_MINUS_SRC_ALPHA */
+/*      GL_DST_ALPHA */
+/*      GL_ONE_MINUS_DST_ALPHA */
+
+/* BlendEquationSeparate */
+#define GL_FUNC_ADD                       0x8006
+#define GL_BLEND_EQUATION                 0x8009
+#define GL_BLEND_EQUATION_RGB             0x8009    /* same as BLEND_EQUATION */
+#define GL_BLEND_EQUATION_ALPHA           0x883D
+
+/* BlendSubtract */
+#define GL_FUNC_SUBTRACT                  0x800A
+#define GL_FUNC_REVERSE_SUBTRACT          0x800B
+
+/* Separate Blend Functions */
+#define GL_BLEND_DST_RGB                  0x80C8
+#define GL_BLEND_SRC_RGB                  0x80C9
+#define GL_BLEND_DST_ALPHA                0x80CA
+#define GL_BLEND_SRC_ALPHA                0x80CB
+#define GL_CONSTANT_COLOR                 0x8001
+#define GL_ONE_MINUS_CONSTANT_COLOR       0x8002
+#define GL_CONSTANT_ALPHA                 0x8003
+#define GL_ONE_MINUS_CONSTANT_ALPHA       0x8004
+#define GL_BLEND_COLOR                    0x8005
+
+/* Buffer Objects */
+#define GL_ARRAY_BUFFER                   0x8892
+#define GL_ELEMENT_ARRAY_BUFFER           0x8893
+#define GL_ARRAY_BUFFER_BINDING           0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING   0x8895
+
+#define GL_STREAM_DRAW                    0x88E0
+#define GL_STATIC_DRAW                    0x88E4
+#define GL_DYNAMIC_DRAW                   0x88E8
+
+#define GL_BUFFER_SIZE                    0x8764
+#define GL_BUFFER_USAGE                   0x8765
+
+#define GL_CURRENT_VERTEX_ATTRIB          0x8626
+
+/* CullFaceMode */
+#define GL_FRONT                          0x0404
+#define GL_BACK                           0x0405
+#define GL_FRONT_AND_BACK                 0x0408
+
+/* DepthFunction */
+/*      GL_NEVER */
+/*      GL_LESS */
+/*      GL_EQUAL */
+/*      GL_LEQUAL */
+/*      GL_GREATER */
+/*      GL_NOTEQUAL */
+/*      GL_GEQUAL */
+/*      GL_ALWAYS */
+
+/* EnableCap */
+#define GL_TEXTURE_2D                     0x0DE1
+#define GL_CULL_FACE                      0x0B44
+#define GL_BLEND                          0x0BE2
+#define GL_DITHER                         0x0BD0
+#define GL_STENCIL_TEST                   0x0B90
+#define GL_DEPTH_TEST                     0x0B71
+#define GL_SCISSOR_TEST                   0x0C11
+#define GL_POLYGON_OFFSET_FILL            0x8037
+#define GL_SAMPLE_ALPHA_TO_COVERAGE       0x809E
+#define GL_SAMPLE_COVERAGE                0x80A0
+
+/* ErrorCode */
+#define GL_NO_ERROR                       0
+#define GL_INVALID_ENUM                   0x0500
+#define GL_INVALID_VALUE                  0x0501
+#define GL_INVALID_OPERATION              0x0502
+#define GL_OUT_OF_MEMORY                  0x0505
+
+/* FrontFaceDirection */
+#define GL_CW                             0x0900
+#define GL_CCW                            0x0901
+
+/* GetPName */
+#define GL_LINE_WIDTH                     0x0B21
+#define GL_ALIASED_POINT_SIZE_RANGE       0x846D
+#define GL_ALIASED_LINE_WIDTH_RANGE       0x846E
+#define GL_CULL_FACE_MODE                 0x0B45
+#define GL_FRONT_FACE                     0x0B46
+#define GL_DEPTH_RANGE                    0x0B70
+#define GL_DEPTH_WRITEMASK                0x0B72
+#define GL_DEPTH_CLEAR_VALUE              0x0B73
+#define GL_DEPTH_FUNC                     0x0B74
+#define GL_STENCIL_CLEAR_VALUE            0x0B91
+#define GL_STENCIL_FUNC                   0x0B92
+#define GL_STENCIL_FAIL                   0x0B94
+#define GL_STENCIL_PASS_DEPTH_FAIL        0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS        0x0B96
+#define GL_STENCIL_REF                    0x0B97
+#define GL_STENCIL_VALUE_MASK             0x0B93
+#define GL_STENCIL_WRITEMASK              0x0B98
+#define GL_STENCIL_BACK_FUNC              0x8800
+#define GL_STENCIL_BACK_FAIL              0x8801
+#define GL_STENCIL_BACK_PASS_DEPTH_FAIL   0x8802
+#define GL_STENCIL_BACK_PASS_DEPTH_PASS   0x8803
+#define GL_STENCIL_BACK_REF               0x8CA3
+#define GL_STENCIL_BACK_VALUE_MASK        0x8CA4
+#define GL_STENCIL_BACK_WRITEMASK         0x8CA5
+#define GL_VIEWPORT                       0x0BA2
+#define GL_SCISSOR_BOX                    0x0C10
+/*      GL_SCISSOR_TEST */
+#define GL_COLOR_CLEAR_VALUE              0x0C22
+#define GL_COLOR_WRITEMASK                0x0C23
+#define GL_UNPACK_ALIGNMENT               0x0CF5
+#define GL_PACK_ALIGNMENT                 0x0D05
+#define GL_MAX_TEXTURE_SIZE               0x0D33
+#define GL_MAX_VIEWPORT_DIMS              0x0D3A
+#define GL_SUBPIXEL_BITS                  0x0D50
+#define GL_RED_BITS                       0x0D52
+#define GL_GREEN_BITS                     0x0D53
+#define GL_BLUE_BITS                      0x0D54
+#define GL_ALPHA_BITS                     0x0D55
+#define GL_DEPTH_BITS                     0x0D56
+#define GL_STENCIL_BITS                   0x0D57
+#define GL_POLYGON_OFFSET_UNITS           0x2A00
+/*      GL_POLYGON_OFFSET_FILL */
+#define GL_POLYGON_OFFSET_FACTOR          0x8038
+#define GL_TEXTURE_BINDING_2D             0x8069
+#define GL_SAMPLE_BUFFERS                 0x80A8
+#define GL_SAMPLES                        0x80A9
+#define GL_SAMPLE_COVERAGE_VALUE          0x80AA
+#define GL_SAMPLE_COVERAGE_INVERT         0x80AB
+
+/* GetTextureParameter */
+/*      GL_TEXTURE_MAG_FILTER */
+/*      GL_TEXTURE_MIN_FILTER */
+/*      GL_TEXTURE_WRAP_S */
+/*      GL_TEXTURE_WRAP_T */
+
+#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2
+#define GL_COMPRESSED_TEXTURE_FORMATS     0x86A3
+
+/* HintMode */
+#define GL_DONT_CARE                      0x1100
+#define GL_FASTEST                        0x1101
+#define GL_NICEST                         0x1102
+
+/* HintTarget */
+#define GL_GENERATE_MIPMAP_HINT            0x8192
+
+/* DataType */
+#define GL_BYTE                           0x1400
+#define GL_UNSIGNED_BYTE                  0x1401
+#define GL_SHORT                          0x1402
+#define GL_UNSIGNED_SHORT                 0x1403
+#define GL_INT                            0x1404
+#define GL_UNSIGNED_INT                   0x1405
+#define GL_FLOAT                          0x1406
+#define GL_FIXED                          0x140C
+
+/* PixelFormat */
+#define GL_DEPTH_COMPONENT                0x1902
+#define GL_ALPHA                          0x1906
+#define GL_RGB                            0x1907
+#define GL_RGBA                           0x1908
+#define GL_LUMINANCE                      0x1909
+#define GL_LUMINANCE_ALPHA                0x190A
+
+/* PixelType */
+/*      GL_UNSIGNED_BYTE */
+#define GL_UNSIGNED_SHORT_4_4_4_4         0x8033
+#define GL_UNSIGNED_SHORT_5_5_5_1         0x8034
+#define GL_UNSIGNED_SHORT_5_6_5           0x8363
+
+/* Shaders */
+#define GL_FRAGMENT_SHADER                  0x8B30
+#define GL_VERTEX_SHADER                    0x8B31
+#define GL_MAX_VERTEX_ATTRIBS               0x8869
+#define GL_MAX_VERTEX_UNIFORM_VECTORS       0x8DFB
+#define GL_MAX_VARYING_VECTORS              0x8DFC
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS   0x8B4C
+#define GL_MAX_TEXTURE_IMAGE_UNITS          0x8872
+#define GL_MAX_FRAGMENT_UNIFORM_VECTORS     0x8DFD
+#define GL_SHADER_TYPE                      0x8B4F
+#define GL_DELETE_STATUS                    0x8B80
+#define GL_LINK_STATUS                      0x8B82
+#define GL_VALIDATE_STATUS                  0x8B83
+#define GL_ATTACHED_SHADERS                 0x8B85
+#define GL_ACTIVE_UNIFORMS                  0x8B86
+#define GL_ACTIVE_UNIFORM_MAX_LENGTH        0x8B87
+#define GL_ACTIVE_ATTRIBUTES                0x8B89
+#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH      0x8B8A
+#define GL_SHADING_LANGUAGE_VERSION         0x8B8C
+#define GL_CURRENT_PROGRAM                  0x8B8D
+
+/* StencilFunction */
+#define GL_NEVER                          0x0200
+#define GL_LESS                           0x0201
+#define GL_EQUAL                          0x0202
+#define GL_LEQUAL                         0x0203
+#define GL_GREATER                        0x0204
+#define GL_NOTEQUAL                       0x0205
+#define GL_GEQUAL                         0x0206
+#define GL_ALWAYS                         0x0207
+
+/* StencilOp */
+/*      GL_ZERO */
+#define GL_KEEP                           0x1E00
+#define GL_REPLACE                        0x1E01
+#define GL_INCR                           0x1E02
+#define GL_DECR                           0x1E03
+#define GL_INVERT                         0x150A
+#define GL_INCR_WRAP                      0x8507
+#define GL_DECR_WRAP                      0x8508
+
+/* StringName */
+#define GL_VENDOR                         0x1F00
+#define GL_RENDERER                       0x1F01
+#define GL_VERSION                        0x1F02
+#define GL_EXTENSIONS                     0x1F03
+
+/* TextureMagFilter */
+#define GL_NEAREST                        0x2600
+#define GL_LINEAR                         0x2601
+
+/* TextureMinFilter */
+/*      GL_NEAREST */
+/*      GL_LINEAR */
+#define GL_NEAREST_MIPMAP_NEAREST         0x2700
+#define GL_LINEAR_MIPMAP_NEAREST          0x2701
+#define GL_NEAREST_MIPMAP_LINEAR          0x2702
+#define GL_LINEAR_MIPMAP_LINEAR           0x2703
+
+/* TextureParameterName */
+#define GL_TEXTURE_MAG_FILTER             0x2800
+#define GL_TEXTURE_MIN_FILTER             0x2801
+#define GL_TEXTURE_WRAP_S                 0x2802
+#define GL_TEXTURE_WRAP_T                 0x2803
+
+/* TextureTarget */
+/*      GL_TEXTURE_2D */
+#define GL_TEXTURE                        0x1702
+
+#define GL_TEXTURE_CUBE_MAP               0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP       0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X    0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X    0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y    0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y    0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z    0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z    0x851A
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE      0x851C
+
+/* TextureUnit */
+#define GL_TEXTURE0                       0x84C0
+#define GL_TEXTURE1                       0x84C1
+#define GL_TEXTURE2                       0x84C2
+#define GL_TEXTURE3                       0x84C3
+#define GL_TEXTURE4                       0x84C4
+#define GL_TEXTURE5                       0x84C5
+#define GL_TEXTURE6                       0x84C6
+#define GL_TEXTURE7                       0x84C7
+#define GL_TEXTURE8                       0x84C8
+#define GL_TEXTURE9                       0x84C9
+#define GL_TEXTURE10                      0x84CA
+#define GL_TEXTURE11                      0x84CB
+#define GL_TEXTURE12                      0x84CC
+#define GL_TEXTURE13                      0x84CD
+#define GL_TEXTURE14                      0x84CE
+#define GL_TEXTURE15                      0x84CF
+#define GL_TEXTURE16                      0x84D0
+#define GL_TEXTURE17                      0x84D1
+#define GL_TEXTURE18                      0x84D2
+#define GL_TEXTURE19                      0x84D3
+#define GL_TEXTURE20                      0x84D4
+#define GL_TEXTURE21                      0x84D5
+#define GL_TEXTURE22                      0x84D6
+#define GL_TEXTURE23                      0x84D7
+#define GL_TEXTURE24                      0x84D8
+#define GL_TEXTURE25                      0x84D9
+#define GL_TEXTURE26                      0x84DA
+#define GL_TEXTURE27                      0x84DB
+#define GL_TEXTURE28                      0x84DC
+#define GL_TEXTURE29                      0x84DD
+#define GL_TEXTURE30                      0x84DE
+#define GL_TEXTURE31                      0x84DF
+#define GL_ACTIVE_TEXTURE                 0x84E0
+
+/* TextureWrapMode */
+#define GL_REPEAT                         0x2901
+#define GL_CLAMP_TO_EDGE                  0x812F
+#define GL_MIRRORED_REPEAT                0x8370
+
+/* Uniform Types */
+#define GL_FLOAT_VEC2                     0x8B50
+#define GL_FLOAT_VEC3                     0x8B51
+#define GL_FLOAT_VEC4                     0x8B52
+#define GL_INT_VEC2                       0x8B53
+#define GL_INT_VEC3                       0x8B54
+#define GL_INT_VEC4                       0x8B55
+#define GL_BOOL                           0x8B56
+#define GL_BOOL_VEC2                      0x8B57
+#define GL_BOOL_VEC3                      0x8B58
+#define GL_BOOL_VEC4                      0x8B59
+#define GL_FLOAT_MAT2                     0x8B5A
+#define GL_FLOAT_MAT3                     0x8B5B
+#define GL_FLOAT_MAT4                     0x8B5C
+#define GL_SAMPLER_2D                     0x8B5E
+#define GL_SAMPLER_CUBE                   0x8B60
+
+/* Vertex Arrays */
+#define GL_VERTEX_ATTRIB_ARRAY_ENABLED        0x8622
+#define GL_VERTEX_ATTRIB_ARRAY_SIZE           0x8623
+#define GL_VERTEX_ATTRIB_ARRAY_STRIDE         0x8624
+#define GL_VERTEX_ATTRIB_ARRAY_TYPE           0x8625
+#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED     0x886A
+#define GL_VERTEX_ATTRIB_ARRAY_POINTER        0x8645
+#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F
+
+/* Read Format */
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE   0x8B9A
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
+
+/* Shader Source */
+#define GL_COMPILE_STATUS                 0x8B81
+#define GL_INFO_LOG_LENGTH                0x8B84
+#define GL_SHADER_SOURCE_LENGTH           0x8B88
+#define GL_SHADER_COMPILER                0x8DFA
+
+/* Shader Binary */
+#define GL_SHADER_BINARY_FORMATS          0x8DF8
+#define GL_NUM_SHADER_BINARY_FORMATS      0x8DF9
+
+/* Shader Precision-Specified Types */
+#define GL_LOW_FLOAT                      0x8DF0
+#define GL_MEDIUM_FLOAT                   0x8DF1
+#define GL_HIGH_FLOAT                     0x8DF2
+#define GL_LOW_INT                        0x8DF3
+#define GL_MEDIUM_INT                     0x8DF4
+#define GL_HIGH_INT                       0x8DF5
+
+/* Framebuffer Object. */
+#define GL_FRAMEBUFFER                    0x8D40
+#define GL_RENDERBUFFER                   0x8D41
+
+#define GL_RGBA4                          0x8056
+#define GL_RGB5_A1                        0x8057
+#define GL_RGB565                         0x8D62
+#define GL_DEPTH_COMPONENT16              0x81A5
+#define GL_STENCIL_INDEX                  0x1901
+#define GL_STENCIL_INDEX8                 0x8D48
+
+#define GL_RENDERBUFFER_WIDTH             0x8D42
+#define GL_RENDERBUFFER_HEIGHT            0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT   0x8D44
+#define GL_RENDERBUFFER_RED_SIZE          0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE        0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE         0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE        0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE        0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE      0x8D55
+
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE           0x8CD0
+#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME           0x8CD1
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL         0x8CD2
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3
+
+#define GL_COLOR_ATTACHMENT0              0x8CE0
+#define GL_DEPTH_ATTACHMENT               0x8D00
+#define GL_STENCIL_ATTACHMENT             0x8D20
+
+#define GL_NONE                           0
+
+#define GL_FRAMEBUFFER_COMPLETE                      0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT         0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS         0x8CD9
+#define GL_FRAMEBUFFER_UNSUPPORTED                   0x8CDD
+
+#define GL_FRAMEBUFFER_BINDING            0x8CA6
+#define GL_RENDERBUFFER_BINDING           0x8CA7
+#define GL_MAX_RENDERBUFFER_SIZE          0x84E8
+
+#define GL_INVALID_FRAMEBUFFER_OPERATION  0x0506
+
+/*-------------------------------------------------------------------------
+ * GL core functions.
+ *-----------------------------------------------------------------------*/
+
+GL_APICALL void         GL_APIENTRY glActiveTexture (GLenum texture);
+GL_APICALL void         GL_APIENTRY glAttachShader (GLuint program, GLuint shader);
+GL_APICALL void         GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const GLchar* name);
+GL_APICALL void         GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer);
+GL_APICALL void         GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer);
+GL_APICALL void         GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer);
+GL_APICALL void         GL_APIENTRY glBindTexture (GLenum target, GLuint texture);
+GL_APICALL void         GL_APIENTRY glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_APICALL void         GL_APIENTRY glBlendEquation ( GLenum mode );
+GL_APICALL void         GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha);
+GL_APICALL void         GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor);
+GL_APICALL void         GL_APIENTRY glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+GL_APICALL void         GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const GLvoid* data, GLenum usage);
+GL_APICALL void         GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid* data);
+GL_APICALL GLenum       GL_APIENTRY glCheckFramebufferStatus (GLenum target);
+GL_APICALL void         GL_APIENTRY glClear (GLbitfield mask);
+GL_APICALL void         GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+GL_APICALL void         GL_APIENTRY glClearDepthf (GLclampf depth);
+GL_APICALL void         GL_APIENTRY glClearStencil (GLint s);
+GL_APICALL void         GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+GL_APICALL void         GL_APIENTRY glCompileShader (GLuint shader);
+GL_APICALL void         GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void         GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void         GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border);
+GL_APICALL void         GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL GLuint       GL_APIENTRY glCreateProgram (void);
+GL_APICALL GLuint       GL_APIENTRY glCreateShader (GLenum type);
+GL_APICALL void         GL_APIENTRY glCullFace (GLenum mode);
+GL_APICALL void         GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint* buffers);
+GL_APICALL void         GL_APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint* framebuffers);
+GL_APICALL void         GL_APIENTRY glDeleteProgram (GLuint program);
+GL_APICALL void         GL_APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint* renderbuffers);
+GL_APICALL void         GL_APIENTRY glDeleteShader (GLuint shader);
+GL_APICALL void         GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint* textures);
+GL_APICALL void         GL_APIENTRY glDepthFunc (GLenum func);
+GL_APICALL void         GL_APIENTRY glDepthMask (GLboolean flag);
+GL_APICALL void         GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar);
+GL_APICALL void         GL_APIENTRY glDetachShader (GLuint program, GLuint shader);
+GL_APICALL void         GL_APIENTRY glDisable (GLenum cap);
+GL_APICALL void         GL_APIENTRY glDisableVertexAttribArray (GLuint index);
+GL_APICALL void         GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count);
+GL_APICALL void         GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const GLvoid* indices);
+GL_APICALL void         GL_APIENTRY glEnable (GLenum cap);
+GL_APICALL void         GL_APIENTRY glEnableVertexAttribArray (GLuint index);
+GL_APICALL void         GL_APIENTRY glFinish (void);
+GL_APICALL void         GL_APIENTRY glFlush (void);
+GL_APICALL void         GL_APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
+GL_APICALL void         GL_APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
+GL_APICALL void         GL_APIENTRY glFrontFace (GLenum mode);
+GL_APICALL void         GL_APIENTRY glGenBuffers (GLsizei n, GLuint* buffers);
+GL_APICALL void         GL_APIENTRY glGenerateMipmap (GLenum target);
+GL_APICALL void         GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint* framebuffers);
+GL_APICALL void         GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint* renderbuffers);
+GL_APICALL void         GL_APIENTRY glGenTextures (GLsizei n, GLuint* textures);
+GL_APICALL void         GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+GL_APICALL void         GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, GLchar* name);
+GL_APICALL void         GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders);
+GL_APICALL int          GL_APIENTRY glGetAttribLocation (GLuint program, const GLchar* name);
+GL_APICALL void         GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean* params);
+GL_APICALL void         GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL GLenum       GL_APIENTRY glGetError (void);
+GL_APICALL void         GL_APIENTRY glGetFloatv (GLenum pname, GLfloat* params);
+GL_APICALL void         GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params);
+GL_APICALL void         GL_APIENTRY glGetIntegerv (GLenum pname, GLint* params);
+GL_APICALL void         GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint* params);
+GL_APICALL void         GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog);
+GL_APICALL void         GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void         GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint* params);
+GL_APICALL void         GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog);
+GL_APICALL void         GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision);
+GL_APICALL void         GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* source);
+GL_APICALL const GLubyte* GL_APIENTRY glGetString (GLenum name);
+GL_APICALL void         GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params);
+GL_APICALL void         GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint* params);
+GL_APICALL void         GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat* params);
+GL_APICALL void         GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint* params);
+GL_APICALL int          GL_APIENTRY glGetUniformLocation (GLuint program, const GLchar* name);
+GL_APICALL void         GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params);
+GL_APICALL void         GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params);
+GL_APICALL void         GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, GLvoid** pointer);
+GL_APICALL void         GL_APIENTRY glHint (GLenum target, GLenum mode);
+GL_APICALL GLboolean    GL_APIENTRY glIsBuffer (GLuint buffer);
+GL_APICALL GLboolean    GL_APIENTRY glIsEnabled (GLenum cap);
+GL_APICALL GLboolean    GL_APIENTRY glIsFramebuffer (GLuint framebuffer);
+GL_APICALL GLboolean    GL_APIENTRY glIsProgram (GLuint program);
+GL_APICALL GLboolean    GL_APIENTRY glIsRenderbuffer (GLuint renderbuffer);
+GL_APICALL GLboolean    GL_APIENTRY glIsShader (GLuint shader);
+GL_APICALL GLboolean    GL_APIENTRY glIsTexture (GLuint texture);
+GL_APICALL void         GL_APIENTRY glLineWidth (GLfloat width);
+GL_APICALL void         GL_APIENTRY glLinkProgram (GLuint program);
+GL_APICALL void         GL_APIENTRY glPixelStorei (GLenum pname, GLint param);
+GL_APICALL void         GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units);
+GL_APICALL void         GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid* pixels);
+GL_APICALL void         GL_APIENTRY glReleaseShaderCompiler (void);
+GL_APICALL void         GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
+GL_APICALL void         GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert);
+GL_APICALL void         GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void         GL_APIENTRY glShaderBinary (GLsizei n, const GLuint* shaders, GLenum binaryformat, const GLvoid* binary, GLsizei length);
+GL_APICALL void         GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const GLchar** string, const GLint* length);
+GL_APICALL void         GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask);
+GL_APICALL void         GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask);
+GL_APICALL void         GL_APIENTRY glStencilMask (GLuint mask);
+GL_APICALL void         GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask);
+GL_APICALL void         GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass);
+GL_APICALL void         GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass);
+GL_APICALL void         GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void         GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param);
+GL_APICALL void         GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat* params);
+GL_APICALL void         GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param);
+GL_APICALL void         GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint* params);
+GL_APICALL void         GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void         GL_APIENTRY glUniform1f (GLint location, GLfloat x);
+GL_APICALL void         GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void         GL_APIENTRY glUniform1i (GLint location, GLint x);
+GL_APICALL void         GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void         GL_APIENTRY glUniform2f (GLint location, GLfloat x, GLfloat y);
+GL_APICALL void         GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void         GL_APIENTRY glUniform2i (GLint location, GLint x, GLint y);
+GL_APICALL void         GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void         GL_APIENTRY glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void         GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void         GL_APIENTRY glUniform3i (GLint location, GLint x, GLint y, GLint z);
+GL_APICALL void         GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void         GL_APIENTRY glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void         GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat* v);
+GL_APICALL void         GL_APIENTRY glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w);
+GL_APICALL void         GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint* v);
+GL_APICALL void         GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void         GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void         GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value);
+GL_APICALL void         GL_APIENTRY glUseProgram (GLuint program);
+GL_APICALL void         GL_APIENTRY glValidateProgram (GLuint program);
+GL_APICALL void         GL_APIENTRY glVertexAttrib1f (GLuint indx, GLfloat x);
+GL_APICALL void         GL_APIENTRY glVertexAttrib1fv (GLuint indx, const GLfloat* values);
+GL_APICALL void         GL_APIENTRY glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y);
+GL_APICALL void         GL_APIENTRY glVertexAttrib2fv (GLuint indx, const GLfloat* values);
+GL_APICALL void         GL_APIENTRY glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z);
+GL_APICALL void         GL_APIENTRY glVertexAttrib3fv (GLuint indx, const GLfloat* values);
+GL_APICALL void         GL_APIENTRY glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w);
+GL_APICALL void         GL_APIENTRY glVertexAttrib4fv (GLuint indx, const GLfloat* values);
+GL_APICALL void         GL_APIENTRY glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const GLvoid* ptr);
+GL_APICALL void         GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl2_h_ */
diff --git a/interface/khronos/include/GLES2/gl2ext.h b/interface/khronos/include/GLES2/gl2ext.h
new file mode 100755 (executable)
index 0000000..4eacf7f
--- /dev/null
@@ -0,0 +1,1218 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef __gl2ext_h_
+#define __gl2ext_h_
+
+/* $Revision: 15049 $ on $Date:: 2011-07-07 01:28:16 +0100 #$ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* We want this */
+#ifndef GL_GLEXT_PROTOTYPES
+#define GL_GLEXT_PROTOTYPES
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+#ifndef GL_APIENTRYP
+#   define GL_APIENTRYP GL_APIENTRY*
+#endif
+
+/*------------------------------------------------------------------------*
+ * OES extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_ETC1_RGB8_OES                                        0x8D64
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_PALETTE4_RGB8_OES                                    0x8B90
+#define GL_PALETTE4_RGBA8_OES                                   0x8B91
+#define GL_PALETTE4_R5_G6_B5_OES                                0x8B92
+#define GL_PALETTE4_RGBA4_OES                                   0x8B93
+#define GL_PALETTE4_RGB5_A1_OES                                 0x8B94
+#define GL_PALETTE8_RGB8_OES                                    0x8B95
+#define GL_PALETTE8_RGBA8_OES                                   0x8B96
+#define GL_PALETTE8_R5_G6_B5_OES                                0x8B97
+#define GL_PALETTE8_RGBA4_OES                                   0x8B98
+#define GL_PALETTE8_RGB5_A1_OES                                 0x8B99
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_DEPTH_COMPONENT24_OES                                0x81A6
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_DEPTH_COMPONENT32_OES                                0x81A7
+#endif
+
+/* GL_OES_depth_texture */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+typedef void* GLeglImageOES;
+#endif
+
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
+/* GLeglImageOES defined in GL_OES_EGL_image already. */
+#define GL_TEXTURE_EXTERNAL_OES                                 0x8D65
+#define GL_SAMPLER_EXTERNAL_OES                                 0x8D66
+#define GL_TEXTURE_BINDING_EXTERNAL_OES                         0x8D67
+#define GL_REQUIRED_TEXTURE_IMAGE_UNITS_OES                     0x8D68
+#endif
+
+/* GL_OES_element_index_uint */
+#ifndef GL_OES_element_index_uint
+#define GL_UNSIGNED_INT                                         0x1405
+#endif
+
+/* GL_OES_get_program_binary */
+#ifndef GL_OES_get_program_binary
+#define GL_PROGRAM_BINARY_LENGTH_OES                            0x8741
+#define GL_NUM_PROGRAM_BINARY_FORMATS_OES                       0x87FE
+#define GL_PROGRAM_BINARY_FORMATS_OES                           0x87FF
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_WRITE_ONLY_OES                                       0x88B9
+#define GL_BUFFER_ACCESS_OES                                    0x88BB
+#define GL_BUFFER_MAPPED_OES                                    0x88BC
+#define GL_BUFFER_MAP_POINTER_OES                               0x88BD
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_DEPTH_STENCIL_OES                                    0x84F9
+#define GL_UNSIGNED_INT_24_8_OES                                0x84FA
+#define GL_DEPTH24_STENCIL8_OES                                 0x88F0
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_RGB8_OES                                             0x8051
+#define GL_RGBA8_OES                                            0x8058
+#endif
+
+/* GL_OES_standard_derivatives */
+#ifndef GL_OES_standard_derivatives
+#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES                  0x8B8B
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_STENCIL_INDEX1_OES                                   0x8D46
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_STENCIL_INDEX4_OES                                   0x8D47
+#endif
+
+/* GL_OES_texture_3D */
+#ifndef GL_OES_texture_3D
+#define GL_TEXTURE_WRAP_R_OES                                   0x8072
+#define GL_TEXTURE_3D_OES                                       0x806F
+#define GL_TEXTURE_BINDING_3D_OES                               0x806A
+#define GL_MAX_3D_TEXTURE_SIZE_OES                              0x8073
+#define GL_SAMPLER_3D_OES                                       0x8B5F
+#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES        0x8CD4
+#endif
+
+/* GL_OES_texture_float */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_texture_float_linear */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_texture_half_float */
+#ifndef GL_OES_texture_half_float
+#define GL_HALF_FLOAT_OES                                       0x8D61
+#endif
+
+/* GL_OES_texture_half_float_linear */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_texture_npot */
+/* No new tokens introduced by this extension. */
+
+/* GL_OES_vertex_array_object */
+#ifndef GL_OES_vertex_array_object
+#define GL_VERTEX_ARRAY_BINDING_OES                             0x85B5
+#endif
+
+/* GL_OES_vertex_half_float */
+/* GL_HALF_FLOAT_OES defined in GL_OES_texture_half_float already. */
+
+/* GL_OES_vertex_type_10_10_10_2 */
+#ifndef GL_OES_vertex_type_10_10_10_2
+#define GL_UNSIGNED_INT_10_10_10_2_OES                          0x8DF6
+#define GL_INT_10_10_10_2_OES                                   0x8DF7
+#endif
+
+/*------------------------------------------------------------------------*
+ * AMD extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_3DC_X_AMD                                            0x87F9
+#define GL_3DC_XY_AMD                                           0x87FA
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_ATC_RGB_AMD                                          0x8C92
+#define GL_ATC_RGBA_EXPLICIT_ALPHA_AMD                          0x8C93
+#define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD                      0x87EE
+#endif
+
+/* GL_AMD_performance_monitor */
+#ifndef GL_AMD_performance_monitor
+#define GL_COUNTER_TYPE_AMD                                     0x8BC0
+#define GL_COUNTER_RANGE_AMD                                    0x8BC1
+#define GL_UNSIGNED_INT64_AMD                                   0x8BC2
+#define GL_PERCENTAGE_AMD                                       0x8BC3
+#define GL_PERFMON_RESULT_AVAILABLE_AMD                         0x8BC4
+#define GL_PERFMON_RESULT_SIZE_AMD                              0x8BC5
+#define GL_PERFMON_RESULT_AMD                                   0x8BC6
+#endif
+
+/* GL_AMD_program_binary_Z400 */
+#ifndef GL_AMD_program_binary_Z400
+#define GL_Z400_BINARY_AMD                                      0x8740
+#endif
+
+/*------------------------------------------------------------------------*
+ * ANGLE extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_ANGLE_framebuffer_blit */
+#ifndef GL_ANGLE_framebuffer_blit
+#define GL_READ_FRAMEBUFFER_ANGLE                               0x8CA8
+#define GL_DRAW_FRAMEBUFFER_ANGLE                               0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_ANGLE                       0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_ANGLE                       0x8CAA
+#endif
+
+/* GL_ANGLE_framebuffer_multisample */
+#ifndef GL_ANGLE_framebuffer_multisample
+#define GL_RENDERBUFFER_SAMPLES_ANGLE                           0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_ANGLE             0x8D56
+#define GL_MAX_SAMPLES_ANGLE                                    0x8D57
+#endif
+
+/*------------------------------------------------------------------------*
+ * APPLE extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_APPLE_rgb_422 */
+#ifndef GL_APPLE_rgb_422
+#define GL_RGB_422_APPLE                                        0x8A1F
+#define GL_UNSIGNED_SHORT_8_8_APPLE                             0x85BA
+#define GL_UNSIGNED_SHORT_8_8_REV_APPLE                         0x85BB
+#endif
+
+/* GL_APPLE_framebuffer_multisample */
+#ifndef GL_APPLE_framebuffer_multisample
+#define GL_RENDERBUFFER_SAMPLES_APPLE                           0x8CAB
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_APPLE             0x8D56
+#define GL_MAX_SAMPLES_APPLE                                    0x8D57
+#define GL_READ_FRAMEBUFFER_APPLE                               0x8CA8
+#define GL_DRAW_FRAMEBUFFER_APPLE                               0x8CA9
+#define GL_DRAW_FRAMEBUFFER_BINDING_APPLE                       0x8CA6
+#define GL_READ_FRAMEBUFFER_BINDING_APPLE                       0x8CAA
+#endif
+
+/* GL_APPLE_texture_format_BGRA8888 */
+#ifndef GL_APPLE_texture_format_BGRA8888
+#define GL_BGRA_EXT                                             0x80E1
+#endif
+
+/* GL_APPLE_texture_max_level */
+#ifndef GL_APPLE_texture_max_level
+#define GL_TEXTURE_MAX_LEVEL_APPLE                              0x813D
+#endif
+
+/*------------------------------------------------------------------------*
+ * ARM extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_ARM_mali_shader_binary */
+#ifndef GL_ARM_mali_shader_binary
+#define GL_MALI_SHADER_BINARY_ARM                               0x8F60
+#endif
+
+/* GL_ARM_rgba8 */
+/* No new tokens introduced by this extension. */
+
+/*------------------------------------------------------------------------*
+ * EXT extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_blend_minmax */
+#ifndef GL_EXT_blend_minmax
+#define GL_MIN_EXT                                              0x8007
+#define GL_MAX_EXT                                              0x8008
+#endif
+
+/* GL_EXT_discard_framebuffer */
+#ifndef GL_EXT_discard_framebuffer
+#define GL_COLOR_EXT                                            0x1800
+#define GL_DEPTH_EXT                                            0x1801
+#define GL_STENCIL_EXT                                          0x1802
+#endif
+
+/* GL_EXT_multi_draw_arrays */
+/* No new tokens introduced by this extension. */
+
+/* GL_EXT_read_format_bgra */
+#ifndef GL_EXT_read_format_bgra
+#define GL_BGRA_EXT                                             0x80E1
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV_EXT                       0x8365
+#define GL_UNSIGNED_SHORT_1_5_5_5_REV_EXT                       0x8366
+#endif
+
+/* GL_EXT_shader_texture_lod */
+/* No new tokens introduced by this extension. */
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_TEXTURE_MAX_ANISOTROPY_EXT                           0x84FE
+#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT                       0x84FF
+#endif
+
+/* GL_EXT_texture_format_BGRA8888 */
+#ifndef GL_EXT_texture_format_BGRA8888
+#define GL_BGRA_EXT                                             0x80E1
+#endif
+
+#ifndef GL_texture_format_RGBX8888_BRCM
+#define GL_RGBX_BRCM                                            0x80EE
+#endif
+
+/* GL_EXT_texture_type_2_10_10_10_REV */
+#ifndef GL_EXT_texture_type_2_10_10_10_REV
+#define GL_UNSIGNED_INT_2_10_10_10_REV_EXT                      0x8368
+#endif
+
+/* GL_EXT_texture_compression_dxt1 */
+#ifndef GL_EXT_texture_compression_dxt1
+#define GL_COMPRESSED_RGB_S3TC_DXT1_EXT                         0x83F0
+#define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT                        0x83F1
+#endif
+
+/* GL_EXT_unpack_subimage */
+#ifndef GL_EXT_unpack_subimage
+#define GL_UNPACK_ROW_LENGTH                                    0x0CF2
+#define GL_UNPACK_SKIP_ROWS                                     0x0CF3
+#define GL_UNPACK_SKIP_PIXELS                                   0x0CF4
+#endif
+
+/*------------------------------------------------------------------------*
+ * DMP extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_DMP_shader_binary */
+#ifndef GL_DMP_shader_binary
+#define GL_SHADER_BINARY_DMP                                    0x9250
+#endif
+
+/*------------------------------------------------------------------------*
+ * IMG extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_IMG_program_binary */
+#ifndef GL_IMG_program_binary
+#define GL_SGX_PROGRAM_BINARY_IMG                               0x9130
+#endif
+
+/* GL_IMG_read_format */
+#ifndef GL_IMG_read_format
+#define GL_BGRA_IMG                                             0x80E1
+#define GL_UNSIGNED_SHORT_4_4_4_4_REV_IMG                       0x8365
+#endif
+
+/* GL_IMG_shader_binary */
+#ifndef GL_IMG_shader_binary
+#define GL_SGX_BINARY_IMG                                       0x8C0A
+#endif
+
+/* GL_IMG_texture_compression_pvrtc */
+#ifndef GL_IMG_texture_compression_pvrtc
+#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG                      0x8C00
+#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG                      0x8C01
+#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG                     0x8C02
+#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG                     0x8C03
+#endif
+
+/* GL_IMG_multisampled_render_to_texture */
+#ifndef GL_IMG_multisampled_render_to_texture
+#define GL_RENDERBUFFER_SAMPLES_IMG                             0x9133
+#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_IMG               0x9134
+#define GL_MAX_SAMPLES_IMG                                      0x9135
+#define GL_TEXTURE_SAMPLES_IMG                                  0x9136
+#endif
+
+/*------------------------------------------------------------------------*
+ * NV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_NV_coverage_sample */
+#ifndef GL_NV_coverage_sample
+#define GL_COVERAGE_COMPONENT_NV                                0x8ED0
+#define GL_COVERAGE_COMPONENT4_NV                               0x8ED1
+#define GL_COVERAGE_ATTACHMENT_NV                               0x8ED2
+#define GL_COVERAGE_BUFFERS_NV                                  0x8ED3
+#define GL_COVERAGE_SAMPLES_NV                                  0x8ED4
+#define GL_COVERAGE_ALL_FRAGMENTS_NV                            0x8ED5
+#define GL_COVERAGE_EDGE_FRAGMENTS_NV                           0x8ED6
+#define GL_COVERAGE_AUTOMATIC_NV                                0x8ED7
+#define GL_COVERAGE_BUFFER_BIT_NV                               0x8000
+#endif
+
+/* GL_NV_depth_nonlinear */
+#ifndef GL_NV_depth_nonlinear
+#define GL_DEPTH_COMPONENT16_NONLINEAR_NV                       0x8E2C
+#endif
+
+/* GL_NV_draw_buffers */
+#ifndef GL_NV_draw_buffers
+#define GL_MAX_DRAW_BUFFERS_NV                                  0x8824
+#define GL_DRAW_BUFFER0_NV                                      0x8825
+#define GL_DRAW_BUFFER1_NV                                      0x8826
+#define GL_DRAW_BUFFER2_NV                                      0x8827
+#define GL_DRAW_BUFFER3_NV                                      0x8828
+#define GL_DRAW_BUFFER4_NV                                      0x8829
+#define GL_DRAW_BUFFER5_NV                                      0x882A
+#define GL_DRAW_BUFFER6_NV                                      0x882B
+#define GL_DRAW_BUFFER7_NV                                      0x882C
+#define GL_DRAW_BUFFER8_NV                                      0x882D
+#define GL_DRAW_BUFFER9_NV                                      0x882E
+#define GL_DRAW_BUFFER10_NV                                     0x882F
+#define GL_DRAW_BUFFER11_NV                                     0x8830
+#define GL_DRAW_BUFFER12_NV                                     0x8831
+#define GL_DRAW_BUFFER13_NV                                     0x8832
+#define GL_DRAW_BUFFER14_NV                                     0x8833
+#define GL_DRAW_BUFFER15_NV                                     0x8834
+#define GL_COLOR_ATTACHMENT0_NV                                 0x8CE0
+#define GL_COLOR_ATTACHMENT1_NV                                 0x8CE1
+#define GL_COLOR_ATTACHMENT2_NV                                 0x8CE2
+#define GL_COLOR_ATTACHMENT3_NV                                 0x8CE3
+#define GL_COLOR_ATTACHMENT4_NV                                 0x8CE4
+#define GL_COLOR_ATTACHMENT5_NV                                 0x8CE5
+#define GL_COLOR_ATTACHMENT6_NV                                 0x8CE6
+#define GL_COLOR_ATTACHMENT7_NV                                 0x8CE7
+#define GL_COLOR_ATTACHMENT8_NV                                 0x8CE8
+#define GL_COLOR_ATTACHMENT9_NV                                 0x8CE9
+#define GL_COLOR_ATTACHMENT10_NV                                0x8CEA
+#define GL_COLOR_ATTACHMENT11_NV                                0x8CEB
+#define GL_COLOR_ATTACHMENT12_NV                                0x8CEC
+#define GL_COLOR_ATTACHMENT13_NV                                0x8CED
+#define GL_COLOR_ATTACHMENT14_NV                                0x8CEE
+#define GL_COLOR_ATTACHMENT15_NV                                0x8CEF
+#endif
+
+/* GL_NV_fbo_color_attachments */
+#ifndef GL_NV_fbo_color_attachments
+#define GL_MAX_COLOR_ATTACHMENTS_NV                             0x8CDF
+/* GL_COLOR_ATTACHMENT{0-15}_NV defined in GL_NV_draw_buffers already. */
+#endif
+
+/* GL_NV_fence */
+#ifndef GL_NV_fence
+#define GL_ALL_COMPLETED_NV                                     0x84F2
+#define GL_FENCE_STATUS_NV                                      0x84F3
+#define GL_FENCE_CONDITION_NV                                   0x84F4
+#endif
+
+/* GL_NV_read_buffer */
+#ifndef GL_NV_read_buffer
+#define GL_READ_BUFFER_NV                                       0x0C02
+#endif
+
+/* GL_NV_read_buffer_front */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_read_depth */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_read_depth_stencil */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_read_stencil */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_texture_compression_s3tc_update */
+/* No new tokens introduced by this extension. */
+
+/* GL_NV_texture_npot_2D_mipmap */
+/* No new tokens introduced by this extension. */
+
+/*------------------------------------------------------------------------*
+ * QCOM extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_QCOM_alpha_test */
+#ifndef GL_QCOM_alpha_test
+#define GL_ALPHA_TEST_QCOM                                      0x0BC0
+#define GL_ALPHA_TEST_FUNC_QCOM                                 0x0BC1
+#define GL_ALPHA_TEST_REF_QCOM                                  0x0BC2
+#endif
+
+/* GL_QCOM_driver_control */
+/* No new tokens introduced by this extension. */
+
+/* GL_QCOM_extended_get */
+#ifndef GL_QCOM_extended_get
+#define GL_TEXTURE_WIDTH_QCOM                                   0x8BD2
+#define GL_TEXTURE_HEIGHT_QCOM                                  0x8BD3
+#define GL_TEXTURE_DEPTH_QCOM                                   0x8BD4
+#define GL_TEXTURE_INTERNAL_FORMAT_QCOM                         0x8BD5
+#define GL_TEXTURE_FORMAT_QCOM                                  0x8BD6
+#define GL_TEXTURE_TYPE_QCOM                                    0x8BD7
+#define GL_TEXTURE_IMAGE_VALID_QCOM                             0x8BD8
+#define GL_TEXTURE_NUM_LEVELS_QCOM                              0x8BD9
+#define GL_TEXTURE_TARGET_QCOM                                  0x8BDA
+#define GL_TEXTURE_OBJECT_VALID_QCOM                            0x8BDB
+#define GL_STATE_RESTORE                                        0x8BDC
+#endif
+
+/* GL_QCOM_extended_get2 */
+/* No new tokens introduced by this extension. */
+
+/* GL_QCOM_perfmon_global_mode */
+#ifndef GL_QCOM_perfmon_global_mode
+#define GL_PERFMON_GLOBAL_MODE_QCOM                             0x8FA0
+#endif
+
+/* GL_QCOM_writeonly_rendering */
+#ifndef GL_QCOM_writeonly_rendering
+#define GL_WRITEONLY_RENDERING_QCOM                             0x8823
+#endif
+
+/* GL_QCOM_tiled_rendering */
+#ifndef GL_QCOM_tiled_rendering
+#define GL_COLOR_BUFFER_BIT0_QCOM                               0x00000001
+#define GL_COLOR_BUFFER_BIT1_QCOM                               0x00000002
+#define GL_COLOR_BUFFER_BIT2_QCOM                               0x00000004
+#define GL_COLOR_BUFFER_BIT3_QCOM                               0x00000008
+#define GL_COLOR_BUFFER_BIT4_QCOM                               0x00000010
+#define GL_COLOR_BUFFER_BIT5_QCOM                               0x00000020
+#define GL_COLOR_BUFFER_BIT6_QCOM                               0x00000040
+#define GL_COLOR_BUFFER_BIT7_QCOM                               0x00000080
+#define GL_DEPTH_BUFFER_BIT0_QCOM                               0x00000100
+#define GL_DEPTH_BUFFER_BIT1_QCOM                               0x00000200
+#define GL_DEPTH_BUFFER_BIT2_QCOM                               0x00000400
+#define GL_DEPTH_BUFFER_BIT3_QCOM                               0x00000800
+#define GL_DEPTH_BUFFER_BIT4_QCOM                               0x00001000
+#define GL_DEPTH_BUFFER_BIT5_QCOM                               0x00002000
+#define GL_DEPTH_BUFFER_BIT6_QCOM                               0x00004000
+#define GL_DEPTH_BUFFER_BIT7_QCOM                               0x00008000
+#define GL_STENCIL_BUFFER_BIT0_QCOM                             0x00010000
+#define GL_STENCIL_BUFFER_BIT1_QCOM                             0x00020000
+#define GL_STENCIL_BUFFER_BIT2_QCOM                             0x00040000
+#define GL_STENCIL_BUFFER_BIT3_QCOM                             0x00080000
+#define GL_STENCIL_BUFFER_BIT4_QCOM                             0x00100000
+#define GL_STENCIL_BUFFER_BIT5_QCOM                             0x00200000
+#define GL_STENCIL_BUFFER_BIT6_QCOM                             0x00400000
+#define GL_STENCIL_BUFFER_BIT7_QCOM                             0x00800000
+#define GL_MULTISAMPLE_BUFFER_BIT0_QCOM                         0x01000000
+#define GL_MULTISAMPLE_BUFFER_BIT1_QCOM                         0x02000000
+#define GL_MULTISAMPLE_BUFFER_BIT2_QCOM                         0x04000000
+#define GL_MULTISAMPLE_BUFFER_BIT3_QCOM                         0x08000000
+#define GL_MULTISAMPLE_BUFFER_BIT4_QCOM                         0x10000000
+#define GL_MULTISAMPLE_BUFFER_BIT5_QCOM                         0x20000000
+#define GL_MULTISAMPLE_BUFFER_BIT6_QCOM                         0x40000000
+#define GL_MULTISAMPLE_BUFFER_BIT7_QCOM                         0x80000000
+#endif
+
+/*------------------------------------------------------------------------*
+ * VIV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_VIV_shader_binary */
+#ifndef GL_VIV_shader_binary
+#define GL_SHADER_BINARY_VIV                                    0x8FC4
+#endif
+
+/*------------------------------------------------------------------------*
+ * BRCM extension tokens
+ * TODO: these aren't official yet
+ *------------------------------------------------------------------------*/
+#ifndef GL_BRCM_side_by_side_stero_hint
+#define GL_SIDE_BY_SIDE_STEREO_HINT_BRCM                        0x8193         /* GET AN OFFICIAL ENUM */
+#endif
+
+/*------------------------------------------------------------------------*
+ * End of extension tokens, start of corresponding extension functions
+ *------------------------------------------------------------------------*/
+
+/*------------------------------------------------------------------------*
+ * OES extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_OES_compressed_ETC1_RGB8_texture */
+#ifndef GL_OES_compressed_ETC1_RGB8_texture
+#define GL_OES_compressed_ETC1_RGB8_texture 1
+#endif
+
+/* GL_OES_compressed_paletted_texture */
+#ifndef GL_OES_compressed_paletted_texture
+#define GL_OES_compressed_paletted_texture 1
+#endif
+
+/* GL_OES_depth24 */
+#ifndef GL_OES_depth24
+#define GL_OES_depth24 1
+#endif
+
+/* GL_OES_depth32 */
+#ifndef GL_OES_depth32
+#define GL_OES_depth32 0
+#endif
+
+/* GL_OES_depth_texture */
+#ifndef GL_OES_depth_texture
+#define GL_OES_depth_texture 0
+#endif
+
+/* GL_OES_EGL_image */
+#ifndef GL_OES_EGL_image
+#define GL_OES_EGL_image 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image);
+GL_APICALL void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image);
+#endif
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image);
+typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image);
+#endif
+
+/* GL_OES_EGL_image_external */
+#ifndef GL_OES_EGL_image_external
+#define GL_OES_EGL_image_external 1
+/* glEGLImageTargetTexture2DOES defined in GL_OES_EGL_image already. */
+#endif
+
+/* GL_OES_element_index_uint */
+#ifndef GL_OES_element_index_uint
+#define GL_OES_element_index_uint 0
+#endif
+
+/* GL_OES_fbo_render_mipmap */
+#ifndef GL_OES_fbo_render_mipmap
+#define GL_OES_fbo_render_mipmap 0
+#endif
+
+/* GL_OES_fragment_precision_high */
+#ifndef GL_OES_fragment_precision_high
+#define GL_OES_fragment_precision_high 0
+#endif
+
+/* GL_OES_get_program_binary */
+#ifndef GL_OES_get_program_binary
+#define GL_OES_get_program_binary 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetProgramBinaryOES (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary);
+GL_APICALL void GL_APIENTRY glProgramBinaryOES (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, GLvoid *binary);
+typedef void (GL_APIENTRYP PFNGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const GLvoid *binary, GLint length);
+#endif
+
+/* GL_OES_mapbuffer */
+#ifndef GL_OES_mapbuffer
+#define GL_OES_mapbuffer 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void* GL_APIENTRY glMapBufferOES (GLenum target, GLenum access);
+GL_APICALL GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target);
+GL_APICALL void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, GLvoid** params);
+#endif
+typedef void* (GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access);
+typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFEROESPROC) (GLenum target);
+typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, GLvoid** params);
+#endif
+
+/* GL_OES_packed_depth_stencil */
+#ifndef GL_OES_packed_depth_stencil
+#define GL_OES_packed_depth_stencil 0
+#endif
+
+/* GL_OES_rgb8_rgba8 */
+#ifndef GL_OES_rgb8_rgba8
+#define GL_OES_rgb8_rgba8 0
+#endif
+
+/* GL_OES_standard_derivatives */
+#ifndef GL_OES_standard_derivatives
+#define GL_OES_standard_derivatives 0
+#endif
+
+/* GL_OES_stencil1 */
+#ifndef GL_OES_stencil1
+#define GL_OES_stencil1 0
+#endif
+
+/* GL_OES_stencil4 */
+#ifndef GL_OES_stencil4
+#define GL_OES_stencil4 0
+#endif
+
+/* GL_OES_texture_3D */
+#ifndef GL_OES_texture_3D
+#define GL_OES_texture_3D 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels);
+GL_APICALL void GL_APIENTRY glCopyTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glCompressedTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glCompressedTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data);
+GL_APICALL void GL_APIENTRY glFramebufferTexture3DOES (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+#endif
+typedef void (GL_APIENTRYP PFNGLTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels);
+typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* pixels);
+typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const GLvoid* data);
+typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const GLvoid* data);
+typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DOES) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset);
+#endif
+
+/* GL_OES_texture_float */
+#ifndef GL_OES_texture_float
+#define GL_OES_texture_float 0
+#endif
+
+/* GL_OES_texture_float_linear */
+#ifndef GL_OES_texture_float_linear
+#define GL_OES_texture_float_linear 0
+#endif
+
+/* GL_OES_texture_half_float */
+#ifndef GL_OES_texture_half_float
+#define GL_OES_texture_half_float 0
+#endif
+
+/* GL_OES_texture_half_float_linear */
+#ifndef GL_OES_texture_half_float_linear
+#define GL_OES_texture_half_float_linear 0
+#endif
+
+/* GL_OES_texture_npot */
+#ifndef GL_OES_texture_npot
+#define GL_OES_texture_npot 1
+#endif
+
+/* GL_OES_vertex_array_object */
+#ifndef GL_OES_vertex_array_object
+#define GL_OES_vertex_array_object 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glBindVertexArrayOES (GLuint array);
+GL_APICALL void GL_APIENTRY glDeleteVertexArraysOES (GLsizei n, const GLuint *arrays);
+GL_APICALL void GL_APIENTRY glGenVertexArraysOES (GLsizei n, GLuint *arrays);
+GL_APICALL GLboolean GL_APIENTRY glIsVertexArrayOES (GLuint array);
+#endif
+typedef void (GL_APIENTRYP PFNGLBINDVERTEXARRAYOESPROC) (GLuint array);
+typedef void (GL_APIENTRYP PFNGLDELETEVERTEXARRAYSOESPROC) (GLsizei n, const GLuint *arrays);
+typedef void (GL_APIENTRYP PFNGLGENVERTEXARRAYSOESPROC) (GLsizei n, GLuint *arrays);
+typedef GLboolean (GL_APIENTRYP PFNGLISVERTEXARRAYOESPROC) (GLuint array);
+#endif
+
+/* GL_OES_vertex_half_float */
+#ifndef GL_OES_vertex_half_float
+#define GL_OES_vertex_half_float 1
+#endif
+
+/* GL_OES_vertex_type_10_10_10_2 */
+#ifndef GL_OES_vertex_type_10_10_10_2
+#define GL_OES_vertex_type_10_10_10_2 0
+#endif
+
+/*------------------------------------------------------------------------*
+ * AMD extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_AMD_compressed_3DC_texture */
+#ifndef GL_AMD_compressed_3DC_texture
+#define GL_AMD_compressed_3DC_texture 0
+#endif
+
+/* GL_AMD_compressed_ATC_texture */
+#ifndef GL_AMD_compressed_ATC_texture
+#define GL_AMD_compressed_ATC_texture 0
+#endif
+
+/* AMD_performance_monitor */
+#ifndef GL_AMD_performance_monitor
+#define GL_AMD_performance_monitor 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, GLvoid *data);
+GL_APICALL void GL_APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors);
+GL_APICALL void GL_APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors);
+GL_APICALL void GL_APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList);
+GL_APICALL void GL_APIENTRY glBeginPerfMonitorAMD (GLuint monitor);
+GL_APICALL void GL_APIENTRY glEndPerfMonitorAMD (GLuint monitor);
+GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, GLchar *groupString);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, GLchar *counterString);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, GLvoid *data);
+typedef void (GL_APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
+typedef void (GL_APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors);
+typedef void (GL_APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList);
+typedef void (GL_APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor);
+typedef void (GL_APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor);
+typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten);
+#endif
+
+/* GL_AMD_program_binary_Z400 */
+#ifndef GL_AMD_program_binary_Z400
+#define GL_AMD_program_binary_Z400 0
+#endif
+
+/*------------------------------------------------------------------------*
+ * ANGLE extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_ANGLE_framebuffer_blit */
+#ifndef GL_ANGLE_framebuffer_blit
+#define GL_ANGLE_framebuffer_blit 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glBlitFramebufferANGLE (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+typedef void (GL_APIENTRYP PFNGLBLITFRAMEBUFFERANGLEPROC) (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
+#endif
+
+/* GL_ANGLE_framebuffer_multisample */
+#ifndef GL_ANGLE_framebuffer_multisample
+#define GL_ANGLE_framebuffer_multisample 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleANGLE (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEANGLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+#endif
+
+/*------------------------------------------------------------------------*
+ * APPLE extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_APPLE_rgb_422 */
+#ifndef GL_APPLE_rgb_422
+#define GL_APPLE_rgb_422 0
+#endif
+
+/* GL_APPLE_framebuffer_multisample */
+#ifndef GL_APPLE_framebuffer_multisample
+#define GL_APPLE_framebuffer_multisample 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleAPPLE (GLenum, GLsizei, GLenum, GLsizei, GLsizei);
+GL_APICALL void GL_APIENTRY glResolveMultisampleFramebufferAPPLE (void);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEAPPLEPROC) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLRESOLVEMULTISAMPLEFRAMEBUFFERAPPLEPROC) (void);
+#endif
+
+/* GL_APPLE_texture_format_BGRA8888 */
+#ifndef GL_APPLE_texture_format_BGRA8888
+#define GL_APPLE_texture_format_BGRA8888 0
+#endif
+
+/* GL_APPLE_texture_max_level */
+#ifndef GL_APPLE_texture_max_level
+#define GL_APPLE_texture_max_level 0
+#endif
+
+/*------------------------------------------------------------------------*
+ * ARM extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_ARM_mali_shader_binary */
+#ifndef GL_ARM_mali_shader_binary
+#define GL_ARM_mali_shader_binary 0
+#endif
+
+/* GL_ARM_rgba8 */
+#ifndef GL_ARM_rgba8
+#define GL_ARM_rgba8 0
+#endif
+
+/*------------------------------------------------------------------------*
+ * APPLE extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_APPLE_rgb_422 */
+#ifndef GL_APPLE_rgb_422
+#define GL_APPLE_rgb_422 1
+#define GL_RGB_422_APPLE                                        0x8A1F
+#define GL_UNSIGNED_SHORT_8_8_APPLE                             0x85BA
+#define GL_UNSIGNED_SHORT_8_8_REV_APPLE                         0x85BB
+#endif
+
+/*------------------------------------------------------------------------*
+ * EXT extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_EXT_blend_minmax */
+#ifndef GL_EXT_blend_minmax
+#define GL_EXT_blend_minmax 0
+#endif
+
+/* GL_EXT_discard_framebuffer */
+#ifndef GL_EXT_discard_framebuffer
+#define GL_EXT_discard_framebuffer 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDiscardFramebufferEXT (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+#endif
+typedef void (GL_APIENTRYP PFNGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments);
+#endif
+
+/* GL_EXT_debug_marker */
+#ifndef GL_EXT_debug_marker
+#define GL_EXT_debug_marker 1
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glInsertEventMarkerEXT (GLsizei length, const GLchar *marker);
+GL_APICALL void GL_APIENTRY glPushGroupMarkerEXT (GLsizei length, const GLchar *marker);
+GL_APICALL void GL_APIENTRY glPopGroupMarkerEXT (void);
+#endif
+typedef void (GL_APIENTRYP PFNGLINSERTEVENTMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (GL_APIENTRYP PFNGLPUSHGROUPMARKEREXTPROC) (GLsizei length, const GLchar *marker);
+typedef void (GL_APIENTRYP PFNGLPOPGROUPMARKEREXTPROC) (void);
+#endif
+
+#ifndef GL_EXT_multi_draw_arrays
+#define GL_EXT_multi_draw_arrays 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glMultiDrawArraysEXT (GLenum, GLint *, GLsizei *, GLsizei);
+GL_APICALL void GL_APIENTRY glMultiDrawElementsEXT (GLenum, const GLsizei *, GLenum, const GLvoid* *, GLsizei);
+#endif /* GL_GLEXT_PROTOTYPES */
+typedef void (GL_APIENTRYP PFNGLMULTIDRAWARRAYSEXTPROC) (GLenum mode, GLint *first, GLsizei *count, GLsizei primcount);
+typedef void (GL_APIENTRYP PFNGLMULTIDRAWELEMENTSEXTPROC) (GLenum mode, const GLsizei *count, GLenum type, const GLvoid* *indices, GLsizei primcount);
+#endif
+
+/* GL_EXT_read_format_bgra */
+#ifndef GL_EXT_read_format_bgra
+#define GL_EXT_read_format_bgra 0
+#endif
+
+/* GL_EXT_shader_texture_lod */
+#ifndef GL_EXT_shader_texture_lod
+#define GL_EXT_shader_texture_lod 0
+#endif
+
+/* GL_EXT_texture_filter_anisotropic */
+#ifndef GL_EXT_texture_filter_anisotropic
+#define GL_EXT_texture_filter_anisotropic 0
+#endif
+
+/* GL_EXT_texture_format_BGRA8888 */
+#ifndef GL_EXT_texture_format_BGRA8888
+#define GL_EXT_texture_format_BGRA8888 1
+#endif
+
+#ifndef GL_texture_format_RGBX8888_BRCM
+#define GL_texture_format_RGBX8888_BRCM 1
+#endif
+
+/* GL_EXT_texture_type_2_10_10_10_REV */
+#ifndef GL_EXT_texture_type_2_10_10_10_REV
+#define GL_EXT_texture_type_2_10_10_10_REV 0
+#endif
+
+/* GL_EXT_texture_compression_dxt1 */
+#ifndef GL_EXT_texture_compression_dxt1
+#define GL_EXT_texture_compression_dxt1 0
+#endif
+
+/* GL_EXT_unpack_subimage */
+#ifndef GL_EXT_unpack_subimage
+#define GL_EXT_unpack_subimage 0
+#endif
+
+/*------------------------------------------------------------------------*
+ * DMP extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_DMP_shader_binary */
+#ifndef GL_DMP_shader_binary
+#define GL_DMP_shader_binary 0
+#endif
+
+/*------------------------------------------------------------------------*
+ * IMG extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_IMG_program_binary */
+#ifndef GL_IMG_program_binary
+#define GL_IMG_program_binary 0
+#endif
+
+/* GL_IMG_read_format */
+#ifndef GL_IMG_read_format
+#define GL_IMG_read_format 0
+#endif
+
+/* GL_IMG_shader_binary */
+#ifndef GL_IMG_shader_binary
+#define GL_IMG_shader_binary 0
+#endif
+
+/* GL_IMG_texture_compression_pvrtc */
+#ifndef GL_IMG_texture_compression_pvrtc
+#define GL_IMG_texture_compression_pvrtc 0
+#endif
+
+/* GL_IMG_multisampled_render_to_texture */
+#ifndef GL_IMG_multisampled_render_to_texture
+#define GL_IMG_multisampled_render_to_texture 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleIMG (GLenum, GLsizei, GLenum, GLsizei, GLsizei);
+GL_APICALL void GL_APIENTRY glFramebufferTexture2DMultisampleIMG (GLenum, GLenum, GLenum, GLuint, GLint, GLsizei);
+#endif
+typedef void (GL_APIENTRYP PFNGLRENDERBUFFERSTORAGEMULTISAMPLEIMG) (GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GL_APIENTRYP PFNGLCLIPPLANEXIMG) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLsizei samples);
+#endif
+
+/*------------------------------------------------------------------------*
+ * NV extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_NV_coverage_sample */
+#ifndef GL_NV_coverage_sample
+#define GL_NV_coverage_sample 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glCoverageMaskNV (GLboolean mask);
+GL_APICALL void GL_APIENTRY glCoverageOperationNV (GLenum operation);
+#endif
+typedef void (GL_APIENTRYP PFNGLCOVERAGEMASKNVPROC) (GLboolean mask);
+typedef void (GL_APIENTRYP PFNGLCOVERAGEOPERATIONNVPROC) (GLenum operation);
+#endif
+
+/* GL_NV_depth_nonlinear */
+#ifndef GL_NV_depth_nonlinear
+#define GL_NV_depth_nonlinear 0
+#endif
+
+/* GL_NV_draw_buffers */
+#ifndef GL_NV_draw_buffers
+#define GL_NV_draw_buffers 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDrawBuffersNV (GLsizei n, const GLenum *bufs);
+#endif
+typedef void (GL_APIENTRYP PFNGLDRAWBUFFERSNVPROC) (GLsizei n, const GLenum *bufs);
+#endif
+
+/* GL_NV_fbo_color_attachments */
+#ifndef GL_NV_fbo_color_attachments
+#define GL_NV_fbo_color_attachments 0
+#endif
+
+/* GL_NV_fence */
+#ifndef GL_NV_fence
+#define GL_NV_fence 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glDeleteFencesNV (GLsizei, const GLuint *);
+GL_APICALL void GL_APIENTRY glGenFencesNV (GLsizei, GLuint *);
+GL_APICALL GLboolean GL_APIENTRY glIsFenceNV (GLuint);
+GL_APICALL GLboolean GL_APIENTRY glTestFenceNV (GLuint);
+GL_APICALL void GL_APIENTRY glGetFenceivNV (GLuint, GLenum, GLint *);
+GL_APICALL void GL_APIENTRY glFinishFenceNV (GLuint);
+GL_APICALL void GL_APIENTRY glSetFenceNV (GLuint, GLenum);
+#endif
+typedef void (GL_APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences);
+typedef void (GL_APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences);
+typedef GLboolean (GL_APIENTRYP PFNGLISFENCENVPROC) (GLuint fence);
+typedef GLboolean (GL_APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence);
+typedef void (GL_APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence);
+typedef void (GL_APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition);
+#endif
+
+/* GL_NV_read_buffer */
+#ifndef GL_NV_read_buffer
+#define GL_NV_read_buffer 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glReadBufferNV (GLenum mode);
+#endif
+typedef void (GL_APIENTRYP PFNGLREADBUFFERNVPROC) (GLenum mode);
+#endif
+
+/* GL_NV_read_buffer_front */
+#ifndef GL_NV_read_buffer_front
+#define GL_NV_read_buffer_front 0
+#endif
+
+/* GL_NV_read_depth */
+#ifndef GL_NV_read_depth
+#define GL_NV_read_depth 0
+#endif
+
+/* GL_NV_read_depth_stencil */
+#ifndef GL_NV_read_depth_stencil
+#define GL_NV_read_depth_stencil 0
+#endif
+
+/* GL_NV_read_stencil */
+#ifndef GL_NV_read_stencil
+#define GL_NV_read_stencil 0
+#endif
+
+/* GL_NV_texture_compression_s3tc_update */
+#ifndef GL_NV_texture_compression_s3tc_update
+#define GL_NV_texture_compression_s3tc_update 0
+#endif
+
+/* GL_NV_texture_npot_2D_mipmap */
+#ifndef GL_NV_texture_npot_2D_mipmap
+#define GL_NV_texture_npot_2D_mipmap 0
+#endif
+
+/*------------------------------------------------------------------------*
+ * QCOM extension functions
+ *------------------------------------------------------------------------*/
+
+/* GL_QCOM_alpha_test */
+#ifndef GL_QCOM_alpha_test
+#define GL_QCOM_alpha_test 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glAlphaFuncQCOM (GLenum func, GLclampf ref);
+#endif
+typedef void (GL_APIENTRYP PFNGLALPHAFUNCQCOMPROC) (GLenum func, GLclampf ref);
+#endif
+
+/* GL_QCOM_driver_control */
+#ifndef GL_QCOM_driver_control
+#define GL_QCOM_driver_control 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glGetDriverControlsQCOM (GLint *num, GLsizei size, GLuint *driverControls);
+GL_APICALL void GL_APIENTRY glGetDriverControlStringQCOM (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);
+GL_APICALL void GL_APIENTRY glEnableDriverControlQCOM (GLuint driverControl);
+GL_APICALL void GL_APIENTRY glDisableDriverControlQCOM (GLuint driverControl);
+#endif
+typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSQCOMPROC) (GLint *num, GLsizei size, GLuint *driverControls);
+typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSTRINGQCOMPROC) (GLuint driverControl, GLsizei bufSize, GLsizei *length, GLchar *driverControlString);
+typedef void (GL_APIENTRYP PFNGLENABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
+typedef void (GL_APIENTRYP PFNGLDISABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl);
+#endif
+
+/* GL_QCOM_extended_get */
+#ifndef GL_QCOM_extended_get
+#define GL_QCOM_extended_get 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glExtGetTexturesQCOM (GLuint *textures, GLint maxTextures, GLint *numTextures);
+GL_APICALL void GL_APIENTRY glExtGetBuffersQCOM (GLuint *buffers, GLint maxBuffers, GLint *numBuffers);
+GL_APICALL void GL_APIENTRY glExtGetRenderbuffersQCOM (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers);
+GL_APICALL void GL_APIENTRY glExtGetFramebuffersQCOM (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers);
+GL_APICALL void GL_APIENTRY glExtGetTexLevelParameterivQCOM (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params);
+GL_APICALL void GL_APIENTRY glExtTexObjectStateOverrideiQCOM (GLenum target, GLenum pname, GLint param);
+GL_APICALL void GL_APIENTRY glExtGetTexSubImageQCOM (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels);
+GL_APICALL void GL_APIENTRY glExtGetBufferPointervQCOM (GLenum target, GLvoid **params);
+#endif
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXTURESQCOMPROC) (GLuint *textures, GLint maxTextures, GLint *numTextures);
+typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERSQCOMPROC) (GLuint *buffers, GLint maxBuffers, GLint *numBuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETRENDERBUFFERSQCOMPROC) (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETFRAMEBUFFERSQCOMPROC) (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers);
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXLEVELPARAMETERIVQCOMPROC) (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params);
+typedef void (GL_APIENTRYP PFNGLEXTTEXOBJECTSTATEOVERRIDEIQCOMPROC) (GLenum target, GLenum pname, GLint param);
+typedef void (GL_APIENTRYP PFNGLEXTGETTEXSUBIMAGEQCOMPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, GLvoid *texels);
+typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERPOINTERVQCOMPROC) (GLenum target, GLvoid **params);
+#endif
+
+/* GL_QCOM_extended_get2 */
+#ifndef GL_QCOM_extended_get2
+#define GL_QCOM_extended_get2 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glExtGetShadersQCOM (GLuint *shaders, GLint maxShaders, GLint *numShaders);
+GL_APICALL void GL_APIENTRY glExtGetProgramsQCOM (GLuint *programs, GLint maxPrograms, GLint *numPrograms);
+GL_APICALL GLboolean GL_APIENTRY glExtIsProgramBinaryQCOM (GLuint program);
+GL_APICALL void GL_APIENTRY glExtGetProgramBinarySourceQCOM (GLuint program, GLenum shadertype, GLchar *source, GLint *length);
+#endif
+typedef void (GL_APIENTRYP PFNGLEXTGETSHADERSQCOMPROC) (GLuint *shaders, GLint maxShaders, GLint *numShaders);
+typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMSQCOMPROC) (GLuint *programs, GLint maxPrograms, GLint *numPrograms);
+typedef GLboolean (GL_APIENTRYP PFNGLEXTISPROGRAMBINARYQCOMPROC) (GLuint program);
+typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMBINARYSOURCEQCOMPROC) (GLuint program, GLenum shadertype, GLchar *source, GLint *length);
+#endif
+
+/* GL_QCOM_perfmon_global_mode */
+#ifndef GL_QCOM_perfmon_global_mode
+#define GL_QCOM_perfmon_global_mode 0
+#endif
+
+/* GL_QCOM_writeonly_rendering */
+#ifndef GL_QCOM_writeonly_rendering
+#define GL_QCOM_writeonly_rendering 0
+#endif
+
+/* GL_QCOM_tiled_rendering */
+#ifndef GL_QCOM_tiled_rendering
+#define GL_QCOM_tiled_rendering 0
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY glStartTilingQCOM (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask);
+GL_APICALL void GL_APIENTRY glEndTilingQCOM (GLbitfield preserveMask);
+#endif
+typedef void (GL_APIENTRYP PFNGLSTARTTILINGQCOMPROC) (GLuint x, GLuint y, GLuint width, GLuint height, GLbitfield preserveMask);
+typedef void (GL_APIENTRYP PFNGLENDTILINGQCOMPROC) (GLbitfield preserveMask);
+#endif
+
+/*------------------------------------------------------------------------*
+ * VIV extension tokens
+ *------------------------------------------------------------------------*/
+
+/* GL_VIV_shader_binary */
+#ifndef GL_VIV_shader_binary
+#define GL_VIV_shader_binary 0
+#endif
+
+/*------------------------------------------------------------------------*
+ * BRCM extension functions
+ * TODO: these aren't official yet
+ *------------------------------------------------------------------------*/
+#ifndef GL_BRCM_side_by_side_stero_hint
+#define GL_BRCM_side_by_side_stero_hint 1
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl2ext_h_ */
diff --git a/interface/khronos/include/GLES2/gl2platform.h b/interface/khronos/include/GLES2/gl2platform.h
new file mode 100755 (executable)
index 0000000..b4fe904
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef __gl2platform_h_
+#define __gl2platform_h_
+
+/* $Revision: 10602 $ on $Date:: 2010-03-04 22:35:34 -0800 #$ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This document is licensed under the SGI Free Software B License Version
+ * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ .
+ */
+
+/* Platform-specific types and definitions for OpenGL ES 2.X  gl2.h
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file.  Please submit changes
+ * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
+ * by filing a bug against product "OpenGL-ES" component "Registry".
+ */
+
+#include "../KHR/khrplatform.h"
+
+#ifndef GL_APICALL
+#define GL_APICALL  KHRONOS_APICALL
+#endif
+
+#ifndef GL_APIENTRY
+#define GL_APIENTRY KHRONOS_APIENTRY
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __gl2platform_h_ */
diff --git a/interface/khronos/include/KHR/khrplatform.h b/interface/khronos/include/KHR/khrplatform.h
new file mode 100755 (executable)
index 0000000..ecb5199
--- /dev/null
@@ -0,0 +1,295 @@
+#ifndef __khrplatform_h_
+#define __khrplatform_h_
+
+/*
+** Copyright (c) 2008-2009 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are furnished to do so, subject to
+** the following conditions:
+**
+** The above copyright notice and this permission notice shall be included
+** in all copies or substantial portions of the Materials.
+**
+** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+/* Khronos platform-specific types and definitions.
+ *
+ * $Revision: 23298 $ on $Date: 2013-09-30 17:07:13 -0700 (Mon, 30 Sep 2013) $
+ *
+ * Adopters may modify this file to suit their platform. Adopters are
+ * encouraged to submit platform specific modifications to the Khronos
+ * group so that they can be included in future versions of this file.
+ * Please submit changes by sending them to the public Khronos Bugzilla
+ * (http://khronos.org/bugzilla) by filing a bug against product
+ * "Khronos (general)" component "Registry".
+ *
+ * A predefined template which fills in some of the bug fields can be
+ * reached using http://tinyurl.com/khrplatform-h-bugreport, but you
+ * must create a Bugzilla login first.
+ *
+ *
+ * See the Implementer's Guidelines for information about where this file
+ * should be located on your system and for more details of its use:
+ *    http://www.khronos.org/registry/implementers_guide.pdf
+ *
+ * This file should be included as
+ *        #include <KHR/khrplatform.h>
+ * by Khronos client API header files that use its types and defines.
+ *
+ * The types in khrplatform.h should only be used to define API-specific types.
+ *
+ * Types defined in khrplatform.h:
+ *    khronos_int8_t              signed   8  bit
+ *    khronos_uint8_t             unsigned 8  bit
+ *    khronos_int16_t             signed   16 bit
+ *    khronos_uint16_t            unsigned 16 bit
+ *    khronos_int32_t             signed   32 bit
+ *    khronos_uint32_t            unsigned 32 bit
+ *    khronos_int64_t             signed   64 bit
+ *    khronos_uint64_t            unsigned 64 bit
+ *    khronos_intptr_t            signed   same number of bits as a pointer
+ *    khronos_uintptr_t           unsigned same number of bits as a pointer
+ *    khronos_ssize_t             signed   size
+ *    khronos_usize_t             unsigned size
+ *    khronos_float_t             signed   32 bit floating point
+ *    khronos_time_ns_t           unsigned 64 bit time in nanoseconds
+ *    khronos_utime_nanoseconds_t unsigned time interval or absolute time in
+ *                                         nanoseconds
+ *    khronos_stime_nanoseconds_t signed time interval in nanoseconds
+ *    khronos_boolean_enum_t      enumerated boolean type. This should
+ *      only be used as a base type when a client API's boolean type is
+ *      an enum. Client APIs which use an integer or other type for
+ *      booleans cannot use this as the base type for their boolean.
+ *
+ * Tokens defined in khrplatform.h:
+ *
+ *    KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
+ *
+ *    KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
+ *    KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
+ *
+ * Calling convention macros defined in this file:
+ *    KHRONOS_APICALL
+ *    KHRONOS_APIENTRY
+ *    KHRONOS_APIATTRIBUTES
+ *
+ * These may be used in function prototypes as:
+ *
+ *      KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
+ *                                  int arg1,
+ *                                  int arg2) KHRONOS_APIATTRIBUTES;
+ */
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APICALL
+ *-------------------------------------------------------------------------
+ * This precedes the return type of the function in the function prototype.
+ */
+#if defined(_WIN32) && !defined(__SCITECH_SNAP__)
+#   define KHRONOS_APICALL __declspec(dllimport)
+#elif defined (__SYMBIAN32__)
+#   define KHRONOS_APICALL IMPORT_C
+#else
+#   define KHRONOS_APICALL
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIENTRY
+ *-------------------------------------------------------------------------
+ * This follows the return type of the function  and precedes the function
+ * name in the function prototype.
+ */
+#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
+    /* Win32 but not WinCE */
+#   define KHRONOS_APIENTRY __stdcall
+#else
+#   define KHRONOS_APIENTRY
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIATTRIBUTES
+ *-------------------------------------------------------------------------
+ * This follows the closing parenthesis of the function prototype arguments.
+ */
+#if defined (__ARMCC_2__)
+#define KHRONOS_APIATTRIBUTES __softfp
+#else
+#define KHRONOS_APIATTRIBUTES
+#endif
+
+/*-------------------------------------------------------------------------
+ * basic type definitions
+ *-----------------------------------------------------------------------*/
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
+
+
+/*
+ * Using <stdint.h>
+ */
+#include <stdint.h>
+typedef int32_t                 khronos_int32_t;
+typedef uint32_t                khronos_uint32_t;
+typedef int64_t                 khronos_int64_t;
+typedef uint64_t                khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64   1
+#define KHRONOS_SUPPORT_FLOAT   1
+
+#elif defined(__VMS ) || defined(__sgi)
+
+/*
+ * Using <inttypes.h>
+ */
+#include <inttypes.h>
+typedef int32_t                 khronos_int32_t;
+typedef uint32_t                khronos_uint32_t;
+typedef int64_t                 khronos_int64_t;
+typedef uint64_t                khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64   1
+#define KHRONOS_SUPPORT_FLOAT   1
+
+#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
+
+/*
+ * Win32
+ */
+typedef __int32                 khronos_int32_t;
+typedef unsigned __int32        khronos_uint32_t;
+typedef __int64                 khronos_int64_t;
+typedef unsigned __int64        khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64   1
+#define KHRONOS_SUPPORT_FLOAT   1
+
+#elif defined(__sun__) || defined(__digital__)
+
+/*
+ * Sun or Digital
+ */
+typedef int                     khronos_int32_t;
+typedef unsigned int            khronos_uint32_t;
+#if defined(__arch64__) || defined(_LP64)
+typedef long int                khronos_int64_t;
+typedef unsigned long int       khronos_uint64_t;
+#else
+typedef long long int           khronos_int64_t;
+typedef unsigned long long int  khronos_uint64_t;
+#endif /* __arch64__ */
+#define KHRONOS_SUPPORT_INT64   1
+#define KHRONOS_SUPPORT_FLOAT   1
+
+#elif defined(_VIDEOCORE)
+
+/*
+ * VideoCore with Metaware compiler
+ */
+#include <vcinclude/common.h>
+typedef int32_t                 khronos_int32_t;
+typedef uint32_t                khronos_uint32_t;
+typedef int64_t                 khronos_int64_t;
+typedef uint64_t                khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64   1
+#define KHRONOS_SUPPORT_FLOAT   1
+
+#elif 0
+
+/*
+ * Hypothetical platform with no float or int64 support
+ */
+typedef int                     khronos_int32_t;
+typedef unsigned int            khronos_uint32_t;
+#define KHRONOS_SUPPORT_INT64   0
+#define KHRONOS_SUPPORT_FLOAT   0
+
+#else
+
+/*
+ * Generic fallback
+ */
+#include <stdint.h>
+typedef int32_t                 khronos_int32_t;
+typedef uint32_t                khronos_uint32_t;
+typedef int64_t                 khronos_int64_t;
+typedef uint64_t                khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64   1
+#define KHRONOS_SUPPORT_FLOAT   1
+
+#endif
+
+
+/*
+ * Types that are (so far) the same on all platforms
+ */
+typedef signed   char          khronos_int8_t;
+typedef unsigned char          khronos_uint8_t;
+typedef signed   short int     khronos_int16_t;
+typedef unsigned short int     khronos_uint16_t;
+
+/*
+ * Types that differ between LLP64 and LP64 architectures - in LLP64, 
+ * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
+ * to be the only LLP64 architecture in current use.
+ */
+#ifdef _WIN64
+typedef signed   long long int khronos_intptr_t;
+typedef unsigned long long int khronos_uintptr_t;
+typedef signed   long long int khronos_ssize_t;
+typedef unsigned long long int khronos_usize_t;
+#else
+typedef signed   long  int     khronos_intptr_t;
+typedef unsigned long  int     khronos_uintptr_t;
+typedef signed   long  int     khronos_ssize_t;
+typedef unsigned long  int     khronos_usize_t;
+#endif
+
+#if KHRONOS_SUPPORT_FLOAT
+/*
+ * Float type
+ */
+typedef          float         khronos_float_t;
+#endif
+
+#if KHRONOS_SUPPORT_INT64
+/* Time types
+ *
+ * These types can be used to represent a time interval in nanoseconds or
+ * an absolute Unadjusted System Time.  Unadjusted System Time is the number
+ * of nanoseconds since some arbitrary system event (e.g. since the last
+ * time the system booted).  The Unadjusted System Time is an unsigned
+ * 64 bit value that wraps back to 0 every 584 years.  Time intervals
+ * may be either signed or unsigned.
+ */
+typedef khronos_uint64_t       khronos_utime_nanoseconds_t;
+typedef khronos_int64_t        khronos_stime_nanoseconds_t;
+#endif
+
+/*
+ * Dummy value used to pad enum types to 32 bits.
+ */
+#ifndef KHRONOS_MAX_ENUM
+#define KHRONOS_MAX_ENUM 0x7FFFFFFF
+#endif
+
+/*
+ * Enumerated boolean type
+ *
+ * Values other than zero should be considered to be true.  Therefore
+ * comparisons should not be made against KHRONOS_TRUE.
+ */
+typedef enum {
+    KHRONOS_FALSE = 0,
+    KHRONOS_TRUE  = 1,
+    KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
+} khronos_boolean_enum_t;
+
+#endif /* __khrplatform_h_ */
diff --git a/interface/khronos/include/VG/openvg.h b/interface/khronos/include/VG/openvg.h
new file mode 100755 (executable)
index 0000000..c5cb3e4
--- /dev/null
@@ -0,0 +1,745 @@
+/* $Revision: 6838 $ on $Date:: 2008-11-04 11:46:08 +0000 #$ */
+
+/*------------------------------------------------------------------------
+ *
+ * OpenVG 1.1 Reference Implementation
+ * -------------------------------------
+ *
+ * Copyright (c) 2008 The Khronos Group Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and /or associated documentation files
+ * (the "Materials "), to deal in the Materials without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Materials,
+ * and to permit persons to whom the Materials are furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR
+ * THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//**
+ * \file
+ * \brief      OpenVG 1.1 API.
+ *//*-------------------------------------------------------------------*/
+
+#ifndef _OPENVG_H
+#define _OPENVG_H
+
+#include "vgplatform.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define OPENVG_VERSION_1_0             1
+#define OPENVG_VERSION_1_0_1   1
+#define OPENVG_VERSION_1_1             2
+
+#ifndef VG_MAXSHORT
+#define VG_MAXSHORT 0x7FFF
+#endif
+
+#ifndef VG_MAXINT
+#define VG_MAXINT 0x7FFFFFFF
+#endif
+
+#ifndef VG_MAX_ENUM
+#define VG_MAX_ENUM 0x7FFFFFFF
+#endif
+
+typedef VGuint VGHandle;
+
+typedef VGHandle VGPath;
+typedef VGHandle VGImage;
+typedef VGHandle VGMaskLayer;
+typedef VGHandle VGFont;
+typedef VGHandle VGPaint;
+
+#define VG_INVALID_HANDLE ((VGHandle)0)
+
+typedef VGuint VGboolean;
+#define VG_FALSE 0
+#define VG_TRUE  1
+
+typedef enum {
+  VG_NO_ERROR                                 = 0,
+  VG_BAD_HANDLE_ERROR                         = 0x1000,
+  VG_ILLEGAL_ARGUMENT_ERROR                   = 0x1001,
+  VG_OUT_OF_MEMORY_ERROR                      = 0x1002,
+  VG_PATH_CAPABILITY_ERROR                    = 0x1003,
+  VG_UNSUPPORTED_IMAGE_FORMAT_ERROR           = 0x1004,
+  VG_UNSUPPORTED_PATH_FORMAT_ERROR            = 0x1005,
+  VG_IMAGE_IN_USE_ERROR                       = 0x1006,
+  VG_NO_CONTEXT_ERROR                         = 0x1007,
+
+  VG_ERROR_CODE_FORCE_SIZE                    = VG_MAX_ENUM
+} VGErrorCode;
+
+typedef enum {
+  /* Mode settings */
+  VG_MATRIX_MODE                              = 0x1100,
+  VG_FILL_RULE                                = 0x1101,
+  VG_IMAGE_QUALITY                            = 0x1102,
+  VG_RENDERING_QUALITY                        = 0x1103,
+  VG_BLEND_MODE                               = 0x1104,
+  VG_IMAGE_MODE                               = 0x1105,
+
+  /* Scissoring rectangles */
+  VG_SCISSOR_RECTS                            = 0x1106,
+
+  /* Color Transformation */
+  VG_COLOR_TRANSFORM                          = 0x1170,
+  VG_COLOR_TRANSFORM_VALUES                   = 0x1171,
+
+  /* Stroke parameters */
+  VG_STROKE_LINE_WIDTH                        = 0x1110,
+  VG_STROKE_CAP_STYLE                         = 0x1111,
+  VG_STROKE_JOIN_STYLE                        = 0x1112,
+  VG_STROKE_MITER_LIMIT                       = 0x1113,
+  VG_STROKE_DASH_PATTERN                      = 0x1114,
+  VG_STROKE_DASH_PHASE                        = 0x1115,
+  VG_STROKE_DASH_PHASE_RESET                  = 0x1116,
+
+  /* Edge fill color for VG_TILE_FILL tiling mode */
+  VG_TILE_FILL_COLOR                          = 0x1120,
+
+  /* Color for vgClear */
+  VG_CLEAR_COLOR                              = 0x1121,
+
+  /* Glyph origin */
+  VG_GLYPH_ORIGIN                             = 0x1122,
+
+  /* Enable/disable alpha masking and scissoring */
+  VG_MASKING                                  = 0x1130,
+  VG_SCISSORING                               = 0x1131,
+
+  /* Pixel layout information */
+  VG_PIXEL_LAYOUT                             = 0x1140,
+  VG_SCREEN_LAYOUT                            = 0x1141,
+
+  /* Source format selection for image filters */
+  VG_FILTER_FORMAT_LINEAR                     = 0x1150,
+  VG_FILTER_FORMAT_PREMULTIPLIED              = 0x1151,
+
+  /* Destination write enable mask for image filters */
+  VG_FILTER_CHANNEL_MASK                      = 0x1152,
+
+  /* Implementation limits (read-only) */
+  VG_MAX_SCISSOR_RECTS                        = 0x1160,
+  VG_MAX_DASH_COUNT                           = 0x1161,
+  VG_MAX_KERNEL_SIZE                          = 0x1162,
+  VG_MAX_SEPARABLE_KERNEL_SIZE                = 0x1163,
+  VG_MAX_COLOR_RAMP_STOPS                     = 0x1164,
+  VG_MAX_IMAGE_WIDTH                          = 0x1165,
+  VG_MAX_IMAGE_HEIGHT                         = 0x1166,
+  VG_MAX_IMAGE_PIXELS                         = 0x1167,
+  VG_MAX_IMAGE_BYTES                          = 0x1168,
+  VG_MAX_FLOAT                                = 0x1169,
+  VG_MAX_GAUSSIAN_STD_DEVIATION               = 0x116A,
+
+  VG_PARAM_TYPE_FORCE_SIZE                    = VG_MAX_ENUM
+} VGParamType;
+
+typedef enum {
+  VG_RENDERING_QUALITY_NONANTIALIASED         = 0x1200,
+  VG_RENDERING_QUALITY_FASTER                 = 0x1201,
+  VG_RENDERING_QUALITY_BETTER                 = 0x1202, /* Default */
+
+  VG_RENDERING_QUALITY_FORCE_SIZE             = VG_MAX_ENUM
+} VGRenderingQuality;
+
+typedef enum {
+  VG_PIXEL_LAYOUT_UNKNOWN                     = 0x1300,
+  VG_PIXEL_LAYOUT_RGB_VERTICAL                = 0x1301,
+  VG_PIXEL_LAYOUT_BGR_VERTICAL                = 0x1302,
+  VG_PIXEL_LAYOUT_RGB_HORIZONTAL              = 0x1303,
+  VG_PIXEL_LAYOUT_BGR_HORIZONTAL              = 0x1304,
+
+  VG_PIXEL_LAYOUT_FORCE_SIZE                  = VG_MAX_ENUM
+} VGPixelLayout;
+
+typedef enum {
+  VG_MATRIX_PATH_USER_TO_SURFACE              = 0x1400,
+  VG_MATRIX_IMAGE_USER_TO_SURFACE             = 0x1401,
+  VG_MATRIX_FILL_PAINT_TO_USER                = 0x1402,
+  VG_MATRIX_STROKE_PAINT_TO_USER              = 0x1403,
+  VG_MATRIX_GLYPH_USER_TO_SURFACE             = 0x1404,
+
+  VG_MATRIX_MODE_FORCE_SIZE                   = VG_MAX_ENUM
+} VGMatrixMode;
+
+typedef enum {
+  VG_CLEAR_MASK                               = 0x1500,
+  VG_FILL_MASK                                = 0x1501,
+  VG_SET_MASK                                 = 0x1502,
+  VG_UNION_MASK                               = 0x1503,
+  VG_INTERSECT_MASK                           = 0x1504,
+  VG_SUBTRACT_MASK                            = 0x1505,
+
+  VG_MASK_OPERATION_FORCE_SIZE                = VG_MAX_ENUM
+} VGMaskOperation;
+
+#define VG_PATH_FORMAT_STANDARD 0
+
+typedef enum {
+  VG_PATH_DATATYPE_S_8                        =  0,
+  VG_PATH_DATATYPE_S_16                       =  1,
+  VG_PATH_DATATYPE_S_32                       =  2,
+  VG_PATH_DATATYPE_F                          =  3,
+
+  VG_PATH_DATATYPE_FORCE_SIZE                 = VG_MAX_ENUM
+} VGPathDatatype;
+
+typedef enum {
+  VG_ABSOLUTE                                 = 0,
+  VG_RELATIVE                                 = 1,
+
+  VG_PATH_ABS_REL_FORCE_SIZE                  = VG_MAX_ENUM
+} VGPathAbsRel;
+
+typedef enum {
+  VG_CLOSE_PATH                               = ( 0 << 1),
+  VG_MOVE_TO                                  = ( 1 << 1),
+  VG_LINE_TO                                  = ( 2 << 1),
+  VG_HLINE_TO                                 = ( 3 << 1),
+  VG_VLINE_TO                                 = ( 4 << 1),
+  VG_QUAD_TO                                  = ( 5 << 1),
+  VG_CUBIC_TO                                 = ( 6 << 1),
+  VG_SQUAD_TO                                 = ( 7 << 1),
+  VG_SCUBIC_TO                                = ( 8 << 1),
+  VG_SCCWARC_TO                               = ( 9 << 1),
+  VG_SCWARC_TO                                = (10 << 1),
+  VG_LCCWARC_TO                               = (11 << 1),
+  VG_LCWARC_TO                                = (12 << 1),
+
+  VG_SEGMENT_MASK                             = 0xf << 1,
+
+  VG_PATH_SEGMENT_FORCE_SIZE                  = VG_MAX_ENUM
+} VGPathSegment;
+
+typedef enum {
+  VG_MOVE_TO_ABS                              = VG_MOVE_TO    | VG_ABSOLUTE,
+  VG_MOVE_TO_REL                              = VG_MOVE_TO    | VG_RELATIVE,
+  VG_LINE_TO_ABS                              = VG_LINE_TO    | VG_ABSOLUTE,
+  VG_LINE_TO_REL                              = VG_LINE_TO    | VG_RELATIVE,
+  VG_HLINE_TO_ABS                             = VG_HLINE_TO   | VG_ABSOLUTE,
+  VG_HLINE_TO_REL                             = VG_HLINE_TO   | VG_RELATIVE,
+  VG_VLINE_TO_ABS                             = VG_VLINE_TO   | VG_ABSOLUTE,
+  VG_VLINE_TO_REL                             = VG_VLINE_TO   | VG_RELATIVE,
+  VG_QUAD_TO_ABS                              = VG_QUAD_TO    | VG_ABSOLUTE,
+  VG_QUAD_TO_REL                              = VG_QUAD_TO    | VG_RELATIVE,
+  VG_CUBIC_TO_ABS                             = VG_CUBIC_TO   | VG_ABSOLUTE,
+  VG_CUBIC_TO_REL                             = VG_CUBIC_TO   | VG_RELATIVE,
+  VG_SQUAD_TO_ABS                             = VG_SQUAD_TO   | VG_ABSOLUTE,
+  VG_SQUAD_TO_REL                             = VG_SQUAD_TO   | VG_RELATIVE,
+  VG_SCUBIC_TO_ABS                            = VG_SCUBIC_TO  | VG_ABSOLUTE,
+  VG_SCUBIC_TO_REL                            = VG_SCUBIC_TO  | VG_RELATIVE,
+  VG_SCCWARC_TO_ABS                           = VG_SCCWARC_TO | VG_ABSOLUTE,
+  VG_SCCWARC_TO_REL                           = VG_SCCWARC_TO | VG_RELATIVE,
+  VG_SCWARC_TO_ABS                            = VG_SCWARC_TO  | VG_ABSOLUTE,
+  VG_SCWARC_TO_REL                            = VG_SCWARC_TO  | VG_RELATIVE,
+  VG_LCCWARC_TO_ABS                           = VG_LCCWARC_TO | VG_ABSOLUTE,
+  VG_LCCWARC_TO_REL                           = VG_LCCWARC_TO | VG_RELATIVE,
+  VG_LCWARC_TO_ABS                            = VG_LCWARC_TO  | VG_ABSOLUTE,
+  VG_LCWARC_TO_REL                            = VG_LCWARC_TO  | VG_RELATIVE,
+
+  VG_PATH_COMMAND_FORCE_SIZE                  = VG_MAX_ENUM
+} VGPathCommand;
+
+typedef enum {
+  VG_PATH_CAPABILITY_APPEND_FROM              = (1 <<  0),
+  VG_PATH_CAPABILITY_APPEND_TO                = (1 <<  1),
+  VG_PATH_CAPABILITY_MODIFY                   = (1 <<  2),
+  VG_PATH_CAPABILITY_TRANSFORM_FROM           = (1 <<  3),
+  VG_PATH_CAPABILITY_TRANSFORM_TO             = (1 <<  4),
+  VG_PATH_CAPABILITY_INTERPOLATE_FROM         = (1 <<  5),
+  VG_PATH_CAPABILITY_INTERPOLATE_TO           = (1 <<  6),
+  VG_PATH_CAPABILITY_PATH_LENGTH              = (1 <<  7),
+  VG_PATH_CAPABILITY_POINT_ALONG_PATH         = (1 <<  8),
+  VG_PATH_CAPABILITY_TANGENT_ALONG_PATH       = (1 <<  9),
+  VG_PATH_CAPABILITY_PATH_BOUNDS              = (1 << 10),
+  VG_PATH_CAPABILITY_PATH_TRANSFORMED_BOUNDS  = (1 << 11),
+  VG_PATH_CAPABILITY_ALL                      = (1 << 12) - 1,
+
+  VG_PATH_CAPABILITIES_FORCE_SIZE             = VG_MAX_ENUM
+} VGPathCapabilities;
+
+typedef enum {
+  VG_PATH_FORMAT                              = 0x1600,
+  VG_PATH_DATATYPE                            = 0x1601,
+  VG_PATH_SCALE                               = 0x1602,
+  VG_PATH_BIAS                                = 0x1603,
+  VG_PATH_NUM_SEGMENTS                        = 0x1604,
+  VG_PATH_NUM_COORDS                          = 0x1605,
+
+  VG_PATH_PARAM_TYPE_FORCE_SIZE               = VG_MAX_ENUM
+} VGPathParamType;
+
+typedef enum {
+  VG_CAP_BUTT                                 = 0x1700,
+  VG_CAP_ROUND                                = 0x1701,
+  VG_CAP_SQUARE                               = 0x1702,
+
+  VG_CAP_STYLE_FORCE_SIZE                     = VG_MAX_ENUM
+} VGCapStyle;
+
+typedef enum {
+  VG_JOIN_MITER                               = 0x1800,
+  VG_JOIN_ROUND                               = 0x1801,
+  VG_JOIN_BEVEL                               = 0x1802,
+
+  VG_JOIN_STYLE_FORCE_SIZE                    = VG_MAX_ENUM
+} VGJoinStyle;
+
+typedef enum {
+  VG_EVEN_ODD                                 = 0x1900,
+  VG_NON_ZERO                                 = 0x1901,
+
+  VG_FILL_RULE_FORCE_SIZE                     = VG_MAX_ENUM
+} VGFillRule;
+
+typedef enum {
+  VG_STROKE_PATH                              = (1 << 0),
+  VG_FILL_PATH                                = (1 << 1),
+
+  VG_PAINT_MODE_FORCE_SIZE                    = VG_MAX_ENUM
+} VGPaintMode;
+
+typedef enum {
+  /* Color paint parameters */
+  VG_PAINT_TYPE                               = 0x1A00,
+  VG_PAINT_COLOR                              = 0x1A01,
+  VG_PAINT_COLOR_RAMP_SPREAD_MODE             = 0x1A02,
+  VG_PAINT_COLOR_RAMP_PREMULTIPLIED           = 0x1A07,
+  VG_PAINT_COLOR_RAMP_STOPS                   = 0x1A03,
+
+  /* Linear gradient paint parameters */
+  VG_PAINT_LINEAR_GRADIENT                    = 0x1A04,
+
+  /* Radial gradient paint parameters */
+  VG_PAINT_RADIAL_GRADIENT                    = 0x1A05,
+
+  /* Pattern paint parameters */
+  VG_PAINT_PATTERN_TILING_MODE                = 0x1A06,
+
+  VG_PAINT_PARAM_TYPE_FORCE_SIZE              = VG_MAX_ENUM
+} VGPaintParamType;
+
+typedef enum {
+  VG_PAINT_TYPE_COLOR                         = 0x1B00,
+  VG_PAINT_TYPE_LINEAR_GRADIENT               = 0x1B01,
+  VG_PAINT_TYPE_RADIAL_GRADIENT               = 0x1B02,
+  VG_PAINT_TYPE_PATTERN                       = 0x1B03,
+
+  VG_PAINT_TYPE_FORCE_SIZE                    = VG_MAX_ENUM
+} VGPaintType;
+
+typedef enum {
+  VG_COLOR_RAMP_SPREAD_PAD                    = 0x1C00,
+  VG_COLOR_RAMP_SPREAD_REPEAT                 = 0x1C01,
+  VG_COLOR_RAMP_SPREAD_REFLECT                = 0x1C02,
+
+  VG_COLOR_RAMP_SPREAD_MODE_FORCE_SIZE        = VG_MAX_ENUM
+} VGColorRampSpreadMode;
+
+typedef enum {
+  VG_TILE_FILL                                = 0x1D00,
+  VG_TILE_PAD                                 = 0x1D01,
+  VG_TILE_REPEAT                              = 0x1D02,
+  VG_TILE_REFLECT                             = 0x1D03,
+
+  VG_TILING_MODE_FORCE_SIZE                   = VG_MAX_ENUM
+} VGTilingMode;
+
+typedef enum {
+  /* RGB{A,X} channel ordering */
+  VG_sRGBX_8888                               =  0,
+  VG_sRGBA_8888                               =  1,
+  VG_sRGBA_8888_PRE                           =  2,
+  VG_sRGB_565                                 =  3,
+  VG_sRGBA_5551                               =  4,
+  VG_sRGBA_4444                               =  5,
+  VG_sL_8                                     =  6,
+  VG_lRGBX_8888                               =  7,
+  VG_lRGBA_8888                               =  8,
+  VG_lRGBA_8888_PRE                           =  9,
+  VG_lL_8                                     = 10,
+  VG_A_8                                      = 11,
+  VG_BW_1                                     = 12,
+  VG_A_1                                      = 13,
+  VG_A_4                                      = 14,
+
+  /* {A,X}RGB channel ordering */
+  VG_sXRGB_8888                               =  0 | (1 << 6),
+  VG_sARGB_8888                               =  1 | (1 << 6),
+  VG_sARGB_8888_PRE                           =  2 | (1 << 6),
+  VG_sARGB_1555                               =  4 | (1 << 6),
+  VG_sARGB_4444                               =  5 | (1 << 6),
+  VG_lXRGB_8888                               =  7 | (1 << 6),
+  VG_lARGB_8888                               =  8 | (1 << 6),
+  VG_lARGB_8888_PRE                           =  9 | (1 << 6),
+
+  /* BGR{A,X} channel ordering */
+  VG_sBGRX_8888                               =  0 | (1 << 7),
+  VG_sBGRA_8888                               =  1 | (1 << 7),
+  VG_sBGRA_8888_PRE                           =  2 | (1 << 7),
+  VG_sBGR_565                                 =  3 | (1 << 7),
+  VG_sBGRA_5551                               =  4 | (1 << 7),
+  VG_sBGRA_4444                               =  5 | (1 << 7),
+  VG_lBGRX_8888                               =  7 | (1 << 7),
+  VG_lBGRA_8888                               =  8 | (1 << 7),
+  VG_lBGRA_8888_PRE                           =  9 | (1 << 7),
+
+  /* {A,X}BGR channel ordering */
+  VG_sXBGR_8888                               =  0 | (1 << 6) | (1 << 7),
+  VG_sABGR_8888                               =  1 | (1 << 6) | (1 << 7),
+  VG_sABGR_8888_PRE                           =  2 | (1 << 6) | (1 << 7),
+  VG_sABGR_1555                               =  4 | (1 << 6) | (1 << 7),
+  VG_sABGR_4444                               =  5 | (1 << 6) | (1 << 7),
+  VG_lXBGR_8888                               =  7 | (1 << 6) | (1 << 7),
+  VG_lABGR_8888                               =  8 | (1 << 6) | (1 << 7),
+  VG_lABGR_8888_PRE                           =  9 | (1 << 6) | (1 << 7),
+
+  VG_IMAGE_FORMAT_FORCE_SIZE                  = VG_MAX_ENUM
+} VGImageFormat;
+
+typedef enum {
+  VG_IMAGE_QUALITY_NONANTIALIASED             = (1 << 0),
+  VG_IMAGE_QUALITY_FASTER                     = (1 << 1),
+  VG_IMAGE_QUALITY_BETTER                     = (1 << 2),
+
+  VG_IMAGE_QUALITY_FORCE_SIZE                 = VG_MAX_ENUM
+} VGImageQuality;
+
+typedef enum {
+  VG_IMAGE_FORMAT                             = 0x1E00,
+  VG_IMAGE_WIDTH                              = 0x1E01,
+  VG_IMAGE_HEIGHT                             = 0x1E02,
+
+  VG_IMAGE_PARAM_TYPE_FORCE_SIZE              = VG_MAX_ENUM
+} VGImageParamType;
+
+typedef enum {
+  VG_DRAW_IMAGE_NORMAL                        = 0x1F00,
+  VG_DRAW_IMAGE_MULTIPLY                      = 0x1F01,
+  VG_DRAW_IMAGE_STENCIL                       = 0x1F02,
+
+  VG_IMAGE_MODE_FORCE_SIZE                    = VG_MAX_ENUM
+} VGImageMode;
+
+typedef enum {
+  VG_RED                                      = (1 << 3),
+  VG_GREEN                                    = (1 << 2),
+  VG_BLUE                                     = (1 << 1),
+  VG_ALPHA                                    = (1 << 0),
+
+  VG_IMAGE_CHANNEL_FORCE_SIZE                 = VG_MAX_ENUM
+} VGImageChannel;
+
+typedef enum {
+  VG_BLEND_SRC                                = 0x2000,
+  VG_BLEND_SRC_OVER                           = 0x2001,
+  VG_BLEND_DST_OVER                           = 0x2002,
+  VG_BLEND_SRC_IN                             = 0x2003,
+  VG_BLEND_DST_IN                             = 0x2004,
+  VG_BLEND_MULTIPLY                           = 0x2005,
+  VG_BLEND_SCREEN                             = 0x2006,
+  VG_BLEND_DARKEN                             = 0x2007,
+  VG_BLEND_LIGHTEN                            = 0x2008,
+  VG_BLEND_ADDITIVE                           = 0x2009,
+
+  VG_BLEND_MODE_FORCE_SIZE                    = VG_MAX_ENUM
+} VGBlendMode;
+
+typedef enum {
+  VG_FONT_NUM_GLYPHS                          = 0x2F00,
+
+  VG_FONT_PARAM_TYPE_FORCE_SIZE               = VG_MAX_ENUM
+} VGFontParamType;
+
+typedef enum {
+  VG_IMAGE_FORMAT_QUERY                       = 0x2100,
+  VG_PATH_DATATYPE_QUERY                      = 0x2101,
+
+  VG_HARDWARE_QUERY_TYPE_FORCE_SIZE           = VG_MAX_ENUM
+} VGHardwareQueryType;
+
+typedef enum {
+  VG_HARDWARE_ACCELERATED                     = 0x2200,
+  VG_HARDWARE_UNACCELERATED                   = 0x2201,
+
+  VG_HARDWARE_QUERY_RESULT_FORCE_SIZE         = VG_MAX_ENUM
+} VGHardwareQueryResult;
+
+typedef enum {
+  VG_VENDOR                                   = 0x2300,
+  VG_RENDERER                                 = 0x2301,
+  VG_VERSION                                  = 0x2302,
+  VG_EXTENSIONS                               = 0x2303,
+
+  VG_STRING_ID_FORCE_SIZE                     = VG_MAX_ENUM
+} VGStringID;
+
+/* Function Prototypes */
+
+#ifndef VG_API_CALL
+#      error VG_API_CALL must be defined
+#endif
+
+#ifndef VG_API_ENTRY
+#   error VG_API_ENTRY must be defined
+#endif
+
+#ifndef VG_API_EXIT
+#   error VG_API_EXIT must be defined
+#endif
+
+VG_API_CALL VGErrorCode VG_API_ENTRY vgGetError(void) VG_API_EXIT;
+
+VG_API_CALL void VG_API_ENTRY vgFlush(void) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgFinish(void) VG_API_EXIT;
+
+/* Getters and Setters */
+VG_API_CALL void VG_API_ENTRY vgSetf (VGParamType type, VGfloat value) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgSeti (VGParamType type, VGint value) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgSetfv(VGParamType type, VGint count,
+                         const VGfloat * values) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgSetiv(VGParamType type, VGint count,
+                         const VGint * values) VG_API_EXIT;
+
+VG_API_CALL VGfloat VG_API_ENTRY vgGetf(VGParamType type) VG_API_EXIT;
+VG_API_CALL VGint VG_API_ENTRY vgGeti(VGParamType type) VG_API_EXIT;
+VG_API_CALL VGint VG_API_ENTRY vgGetVectorSize(VGParamType type) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgGetfv(VGParamType type, VGint count, VGfloat * values) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgGetiv(VGParamType type, VGint count, VGint * values) VG_API_EXIT;
+
+VG_API_CALL void VG_API_ENTRY vgSetParameterf(VGHandle object,
+                                 VGint paramType,
+                                 VGfloat value) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgSetParameteri(VGHandle object,
+                                 VGint paramType,
+                                 VGint value) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgSetParameterfv(VGHandle object,
+                                  VGint paramType,
+                                  VGint count, const VGfloat * values) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgSetParameteriv(VGHandle object,
+                                  VGint paramType,
+                                  VGint count, const VGint * values) VG_API_EXIT;
+
+VG_API_CALL VGfloat VG_API_ENTRY vgGetParameterf(VGHandle object,
+                                    VGint paramType) VG_API_EXIT;
+VG_API_CALL VGint VG_API_ENTRY vgGetParameteri(VGHandle object,
+                                  VGint paramType);
+VG_API_CALL VGint VG_API_ENTRY vgGetParameterVectorSize(VGHandle object,
+                                           VGint paramType) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgGetParameterfv(VGHandle object,
+                                  VGint paramType,
+                                  VGint count, VGfloat * values) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgGetParameteriv(VGHandle object,
+                                  VGint paramType,
+                                  VGint count, VGint * values) VG_API_EXIT;
+
+/* Matrix Manipulation */
+VG_API_CALL void VG_API_ENTRY vgLoadIdentity(void) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgLoadMatrix(const VGfloat * m) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgGetMatrix(VGfloat * m) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgMultMatrix(const VGfloat * m) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgTranslate(VGfloat tx, VGfloat ty) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgScale(VGfloat sx, VGfloat sy) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgShear(VGfloat shx, VGfloat shy) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgRotate(VGfloat angle) VG_API_EXIT;
+
+/* Masking and Clearing */
+VG_API_CALL void VG_API_ENTRY vgMask(VGHandle mask, VGMaskOperation operation,
+                                     VGint x, VGint y,
+                                     VGint width, VGint height) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgRenderToMask(VGPath path,
+                                            VGbitfield paintModes,
+                                            VGMaskOperation operation) VG_API_EXIT;
+VG_API_CALL VGMaskLayer VG_API_ENTRY vgCreateMaskLayer(VGint width, VGint height) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgDestroyMaskLayer(VGMaskLayer maskLayer) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgFillMaskLayer(VGMaskLayer maskLayer,
+                                             VGint x, VGint y,
+                                             VGint width, VGint height,
+                                             VGfloat value) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgCopyMask(VGMaskLayer maskLayer,
+                                        VGint dx, VGint dy,
+                                        VGint sx, VGint sy,
+                                        VGint width, VGint height) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgClear(VGint x, VGint y, VGint width, VGint height) VG_API_EXIT;
+
+/* Paths */
+VG_API_CALL VGPath VG_API_ENTRY vgCreatePath(VGint pathFormat,
+                                VGPathDatatype datatype,
+                                VGfloat scale, VGfloat bias,
+                                VGint segmentCapacityHint,
+                                VGint coordCapacityHint,
+                                VGbitfield capabilities) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgClearPath(VGPath path, VGbitfield capabilities) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgDestroyPath(VGPath path) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgRemovePathCapabilities(VGPath path,
+                                          VGbitfield capabilities) VG_API_EXIT;
+VG_API_CALL VGbitfield VG_API_ENTRY vgGetPathCapabilities(VGPath path) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgAppendPath(VGPath dstPath, VGPath srcPath) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgAppendPathData(VGPath dstPath,
+                                  VGint numSegments,
+                                  const VGubyte * pathSegments,
+                                  const void * pathData) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgModifyPathCoords(VGPath dstPath, VGint startIndex,
+                                    VGint numSegments,
+                                    const void * pathData) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgTransformPath(VGPath dstPath, VGPath srcPath) VG_API_EXIT;
+VG_API_CALL VGboolean VG_API_ENTRY vgInterpolatePath(VGPath dstPath,
+                                        VGPath startPath,
+                                        VGPath endPath,
+                                        VGfloat amount) VG_API_EXIT;
+VG_API_CALL VGfloat VG_API_ENTRY vgPathLength(VGPath path,
+                                 VGint startSegment, VGint numSegments) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgPointAlongPath(VGPath path,
+                                  VGint startSegment, VGint numSegments,
+                                  VGfloat distance,
+                                  VGfloat * x, VGfloat * y,
+                                  VGfloat * tangentX, VGfloat * tangentY) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgPathBounds(VGPath path,
+                              VGfloat * minX, VGfloat * minY,
+                              VGfloat * width, VGfloat * height) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgPathTransformedBounds(VGPath path,
+                                         VGfloat * minX, VGfloat * minY,
+                                         VGfloat * width, VGfloat * height) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgDrawPath(VGPath path, VGbitfield paintModes) VG_API_EXIT;
+
+/* Paint */
+VG_API_CALL VGPaint VG_API_ENTRY vgCreatePaint(void) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgDestroyPaint(VGPaint paint) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgSetPaint(VGPaint paint, VGbitfield paintModes) VG_API_EXIT;
+VG_API_CALL VGPaint VG_API_ENTRY vgGetPaint(VGPaintMode paintMode) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgSetColor(VGPaint paint, VGuint rgba) VG_API_EXIT;
+VG_API_CALL VGuint VG_API_ENTRY vgGetColor(VGPaint paint) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgPaintPattern(VGPaint paint, VGImage pattern) VG_API_EXIT;
+
+/* Images */
+VG_API_CALL VGImage VG_API_ENTRY vgCreateImage(VGImageFormat format,
+                                  VGint width, VGint height,
+                                  VGbitfield allowedQuality) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgDestroyImage(VGImage image) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgClearImage(VGImage image,
+                              VGint x, VGint y, VGint width, VGint height) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgImageSubData(VGImage image,
+                                const void * data, VGint dataStride,
+                                VGImageFormat dataFormat,
+                                VGint x, VGint y, VGint width, VGint height) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgGetImageSubData(VGImage image,
+                                   void * data, VGint dataStride,
+                                   VGImageFormat dataFormat,
+                                   VGint x, VGint y,
+                                   VGint width, VGint height) VG_API_EXIT;
+VG_API_CALL VGImage VG_API_ENTRY vgChildImage(VGImage parent,
+                                 VGint x, VGint y, VGint width, VGint height) VG_API_EXIT;
+VG_API_CALL VGImage VG_API_ENTRY vgGetParent(VGImage image) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgCopyImage(VGImage dst, VGint dx, VGint dy,
+                             VGImage src, VGint sx, VGint sy,
+                             VGint width, VGint height,
+                             VGboolean dither) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgDrawImage(VGImage image) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgSetPixels(VGint dx, VGint dy,
+                             VGImage src, VGint sx, VGint sy,
+                             VGint width, VGint height) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgWritePixels(const void * data, VGint dataStride,
+                               VGImageFormat dataFormat,
+                               VGint dx, VGint dy,
+                               VGint width, VGint height) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgGetPixels(VGImage dst, VGint dx, VGint dy,
+                             VGint sx, VGint sy,
+                             VGint width, VGint height) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgReadPixels(void * data, VGint dataStride,
+                              VGImageFormat dataFormat,
+                              VGint sx, VGint sy,
+                              VGint width, VGint height) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgCopyPixels(VGint dx, VGint dy,
+                              VGint sx, VGint sy,
+                              VGint width, VGint height) VG_API_EXIT;
+
+/* Text */
+VG_API_CALL VGFont VG_API_ENTRY vgCreateFont(VGint glyphCapacityHint) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgDestroyFont(VGFont font) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgSetGlyphToPath(VGFont font,
+                                              VGuint glyphIndex,
+                                              VGPath path,
+                                              VGboolean isHinted,
+                                              VGfloat glyphOrigin [2],
+                                              VGfloat escapement[2]) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgSetGlyphToImage(VGFont font,
+                                               VGuint glyphIndex,
+                                               VGImage image,
+                                               VGfloat glyphOrigin [2],
+                                               VGfloat escapement[2]) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgClearGlyph(VGFont font,VGuint glyphIndex) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgDrawGlyph(VGFont font,
+                                         VGuint glyphIndex,
+                                         VGbitfield paintModes,
+                                         VGboolean allowAutoHinting) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgDrawGlyphs(VGFont font,
+                                          VGint glyphCount,
+                                          const VGuint *glyphIndices,
+                                          const VGfloat *adjustments_x,
+                                          const VGfloat *adjustments_y,
+                                          VGbitfield paintModes,
+                                          VGboolean allowAutoHinting) VG_API_EXIT;
+
+/* Image Filters */
+VG_API_CALL void VG_API_ENTRY vgColorMatrix(VGImage dst, VGImage src,
+                               const VGfloat * matrix) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgConvolve(VGImage dst, VGImage src,
+                            VGint kernelWidth, VGint kernelHeight,
+                            VGint shiftX, VGint shiftY,
+                            const VGshort * kernel,
+                            VGfloat scale,
+                            VGfloat bias,
+                            VGTilingMode tilingMode) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgSeparableConvolve(VGImage dst, VGImage src,
+                                     VGint kernelWidth,
+                                     VGint kernelHeight,
+                                     VGint shiftX, VGint shiftY,
+                                     const VGshort * kernelX,
+                                     const VGshort * kernelY,
+                                     VGfloat scale,
+                                     VGfloat bias,
+                                     VGTilingMode tilingMode) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgGaussianBlur(VGImage dst, VGImage src,
+                                VGfloat stdDeviationX,
+                                VGfloat stdDeviationY,
+                                VGTilingMode tilingMode) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgLookup(VGImage dst, VGImage src,
+                          const VGubyte * redLUT,
+                          const VGubyte * greenLUT,
+                          const VGubyte * blueLUT,
+                          const VGubyte * alphaLUT,
+                          VGboolean outputLinear,
+                          VGboolean outputPremultiplied) VG_API_EXIT;
+VG_API_CALL void VG_API_ENTRY vgLookupSingle(VGImage dst, VGImage src,
+                                const VGuint * lookupTable,
+                                VGImageChannel sourceChannel,
+                                VGboolean outputLinear,
+                                VGboolean outputPremultiplied) VG_API_EXIT;
+
+/* Hardware Queries */
+VG_API_CALL VGHardwareQueryResult VG_API_ENTRY vgHardwareQuery(VGHardwareQueryType key,
+                                                  VGint setting) VG_API_EXIT;
+
+/* Renderer and Extension Information */
+VG_API_CALL const VGubyte * VG_API_ENTRY vgGetString(VGStringID name) VG_API_EXIT;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* _OPENVG_H */
diff --git a/interface/khronos/include/VG/vgext.h b/interface/khronos/include/VG/vgext.h
new file mode 100755 (executable)
index 0000000..f718a35
--- /dev/null
@@ -0,0 +1,233 @@
+/* $Revision: 6810 $ on $Date:: 2008-10-29 14:31:37 +0000 #$ */
+
+/*------------------------------------------------------------------------
+ *
+ * VG extensions Reference Implementation
+ * -------------------------------------
+ *
+ * Copyright (c) 2008 The Khronos Group Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and /or associated documentation files
+ * (the "Materials "), to deal in the Materials without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Materials,
+ * and to permit persons to whom the Materials are furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR
+ * THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//**
+ * \file
+ * \brief      VG extensions
+ *//*-------------------------------------------------------------------*/
+
+
+
+#ifndef _VGEXT_H
+#define _VGEXT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "openvg.h"
+#include "vgu.h"
+
+#ifndef VG_API_ENTRYP
+#   define VG_API_ENTRYP VG_API_ENTRY*
+#endif
+
+#ifndef VGU_API_ENTRYP
+#   define VGU_API_ENTRYP VGU_API_ENTRY*
+#endif
+
+/*-------------------------------------------------------------------------------
+ * KHR extensions
+ *------------------------------------------------------------------------------*/
+
+typedef enum  {
+
+#ifndef VG_KHR_iterative_average_blur
+  VG_MAX_AVERAGE_BLUR_DIMENSION_KHR        = 0x116B,
+  VG_AVERAGE_BLUR_DIMENSION_RESOLUTION_KHR = 0x116C,
+  VG_MAX_AVERAGE_BLUR_ITERATIONS_KHR       = 0x116D,
+#endif
+
+  VG_PARAM_TYPE_KHR_FORCE_SIZE             = VG_MAX_ENUM
+} VGParamTypeKHR;
+
+#ifndef VG_KHR_EGL_image
+#define VG_KHR_EGL_image 1
+/* VGEGLImageKHR is an opaque handle to an EGLImage */
+typedef void* VGeglImageKHR;
+
+#ifdef VG_VGEXT_PROTOTYPES
+VG_API_CALL VGImage VG_API_ENTRY vgCreateEGLImageTargetKHR(VGeglImageKHR image);
+#endif
+typedef VGImage (VG_API_ENTRYP PFNVGCREATEEGLIMAGETARGETKHRPROC) (VGeglImageKHR image);
+
+#endif
+
+
+#ifndef VG_KHR_iterative_average_blur
+#define VG_KHR_iterative_average_blur 1
+
+#ifdef VG_VGEXT_PROTOTYPES
+VG_API_CALL void vgIterativeAverageBlurKHR(VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGTilingMode tilingMode);
+#endif
+typedef void (VG_API_ENTRYP PFNVGITERATIVEAVERAGEBLURKHRPROC) (VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGTilingMode tilingMode);
+
+#endif
+
+
+#ifndef VG_KHR_advanced_blending
+#define VG_KHR_advanced_blending 1
+
+typedef enum {
+  VG_BLEND_OVERLAY_KHR        = 0x2010,
+  VG_BLEND_HARDLIGHT_KHR      = 0x2011,
+  VG_BLEND_SOFTLIGHT_SVG_KHR  = 0x2012,
+  VG_BLEND_SOFTLIGHT_KHR      = 0x2013,
+  VG_BLEND_COLORDODGE_KHR     = 0x2014,
+  VG_BLEND_COLORBURN_KHR      = 0x2015,
+  VG_BLEND_DIFFERENCE_KHR     = 0x2016,
+  VG_BLEND_SUBTRACT_KHR       = 0x2017,
+  VG_BLEND_INVERT_KHR         = 0x2018,
+  VG_BLEND_EXCLUSION_KHR      = 0x2019,
+  VG_BLEND_LINEARDODGE_KHR    = 0x201a,
+  VG_BLEND_LINEARBURN_KHR     = 0x201b,
+  VG_BLEND_VIVIDLIGHT_KHR     = 0x201c,
+  VG_BLEND_LINEARLIGHT_KHR    = 0x201d,
+  VG_BLEND_PINLIGHT_KHR       = 0x201e,
+  VG_BLEND_HARDMIX_KHR        = 0x201f,
+  VG_BLEND_CLEAR_KHR          = 0x2020,
+  VG_BLEND_DST_KHR            = 0x2021,
+  VG_BLEND_SRC_OUT_KHR        = 0x2022,
+  VG_BLEND_DST_OUT_KHR        = 0x2023,
+  VG_BLEND_SRC_ATOP_KHR       = 0x2024,
+  VG_BLEND_DST_ATOP_KHR       = 0x2025,
+  VG_BLEND_XOR_KHR            = 0x2026,
+
+  VG_BLEND_MODE_KHR_FORCE_SIZE= VG_MAX_ENUM
+} VGBlendModeKHR;
+#endif
+
+#ifndef VG_KHR_parametric_filter
+#define VG_KHR_parametric_filter 1
+
+typedef enum {
+  VG_PF_OBJECT_VISIBLE_FLAG_KHR = (1 << 0),
+  VG_PF_KNOCKOUT_FLAG_KHR       = (1 << 1),
+  VG_PF_OUTER_FLAG_KHR          = (1 << 2),
+  VG_PF_INNER_FLAG_KHR          = (1 << 3),
+
+  VG_PF_TYPE_KHR_FORCE_SIZE     = VG_MAX_ENUM
+} VGPfTypeKHR;
+
+typedef enum {
+  VGU_IMAGE_IN_USE_ERROR           = 0xF010,
+
+  VGU_ERROR_CODE_KHR_FORCE_SIZE    = VG_MAX_ENUM
+} VGUErrorCodeKHR;
+
+#ifdef VG_VGEXT_PROTOTYPES
+VG_API_CALL void VG_API_ENTRY vgParametricFilterKHR(VGImage dst,VGImage src,VGImage blur,VGfloat strength,VGfloat offsetX,VGfloat offsetY,VGbitfield filterFlags,VGPaint highlightPaint,VGPaint shadowPaint);
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguDropShadowKHR(VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGfloat strength,VGfloat distance,VGfloat angle,VGbitfield filterFlags,VGbitfield allowedQuality,VGuint shadowColorRGBA);
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguGlowKHR(VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGfloat strength,VGbitfield filterFlags,VGbitfield allowedQuality,VGuint glowColorRGBA) ;
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguBevelKHR(VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGfloat strength,VGfloat distance,VGfloat angle,VGbitfield filterFlags,VGbitfield allowedQuality,VGuint highlightColorRGBA,VGuint shadowColorRGBA);
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguGradientGlowKHR(VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGfloat strength,VGfloat distance,VGfloat angle,VGbitfield filterFlags,VGbitfield allowedQuality,VGuint stopsCount,const VGfloat* glowColorRampStops);
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguGradientBevelKHR(VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGfloat strength,VGfloat distance,VGfloat angle,VGbitfield filterFlags,VGbitfield allowedQuality,VGuint stopsCount,const VGfloat* bevelColorRampStops);
+#endif
+typedef void (VG_API_ENTRYP PFNVGPARAMETRICFILTERKHRPROC) (VGImage dst,VGImage src,VGImage blur,VGfloat strength,VGfloat offsetX,VGfloat offsetY,VGbitfield filterFlags,VGPaint highlightPaint,VGPaint shadowPaint);
+typedef VGUErrorCode (VGU_API_ENTRYP PFNVGUDROPSHADOWKHRPROC) (VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGfloat strength,VGfloat distance,VGfloat angle,VGbitfield filterFlags,VGbitfield allowedQuality,VGuint shadowColorRGBA);
+typedef VGUErrorCode (VGU_API_ENTRYP PFNVGUGLOWKHRPROC) (VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGfloat strength,VGbitfield filterFlags,VGbitfield allowedQuality,VGuint glowColorRGBA);
+typedef VGUErrorCode (VGU_API_ENTRYP PFNVGUBEVELKHRPROC) (VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGfloat strength,VGfloat distance,VGfloat angle,VGbitfield filterFlags,VGbitfield allowedQuality,VGuint highlightColorRGBA,VGuint shadowColorRGBA);
+typedef VGUErrorCode (VGU_API_ENTRYP PFNVGUGRADIENTGLOWKHRPROC) (VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGfloat strength,VGfloat distance,VGfloat angle,VGbitfield filterFlags,VGbitfield allowedQuality,VGuint stopsCount,const VGfloat* glowColorRampStops);
+typedef VGUErrorCode (VGU_API_ENTRYP PFNVGUGRADIENTBEVELKHRPROC) (VGImage dst,VGImage src,VGfloat dimX,VGfloat dimY,VGuint iterative,VGfloat strength,VGfloat distance,VGfloat angle,VGbitfield filterFlags,VGbitfield allowedQuality,VGuint stopsCount,const VGfloat* bevelColorRampStops);
+
+#endif
+
+
+/*-------------------------------------------------------------------------------
+ * NDS extensions
+ *------------------------------------------------------------------------------*/
+
+#ifndef VG_NDS_paint_generation
+#define VG_NDS_paint_generation 1
+
+typedef enum {
+  VG_PAINT_COLOR_RAMP_LINEAR_NDS            = 0x1A10,
+  VG_COLOR_MATRIX_NDS                       = 0x1A11,
+  VG_PAINT_COLOR_TRANSFORM_LINEAR_NDS       = 0x1A12,
+
+  VG_PAINT_PARAM_TYPE_NDS_FORCE_SIZE        = VG_MAX_ENUM
+} VGPaintParamTypeNds;
+
+typedef enum {
+  VG_DRAW_IMAGE_COLOR_MATRIX_NDS            = 0x1F10,
+
+  VG_IMAGE_MODE_NDS_FORCE_SIZE              = VG_MAX_ENUM
+} VGImageModeNds;
+#endif
+
+
+#ifndef VG_NDS_projective_geometry
+#define VG_NDS_projective_geometry 1
+
+typedef enum {
+  VG_CLIP_MODE_NDS                          = 0x1180,
+  VG_CLIP_LINES_NDS                         = 0x1181,
+  VG_MAX_CLIP_LINES_NDS                     = 0x1182,
+
+  VG_PARAM_TYPE_NDS_FORCE_SIZE        = VG_MAX_ENUM
+} VGParamTypeNds;
+
+typedef enum {
+  VG_CLIPMODE_NONE_NDS                      = 0x3000,
+  VG_CLIPMODE_CLIP_CLOSED_NDS               = 0x3001,
+  VG_CLIPMODE_CLIP_OPEN_NDS                 = 0x3002,
+  VG_CLIPMODE_CULL_NDS                      = 0x3003,
+
+  VG_CLIPMODE_NDS_FORCE_SIZE = VG_MAX_ENUM
+} VGClipModeNds;
+
+typedef enum {
+  VG_RQUAD_TO_NDS              = ( 13 << 1 ),
+  VG_RCUBIC_TO_NDS             = ( 14 << 1 ),
+
+  VG_PATH_SEGMENT_NDS_FORCE_SIZE = VG_MAX_ENUM
+} VGPathSegmentNds;
+
+typedef enum {
+  VG_RQUAD_TO_ABS_NDS            = (VG_RQUAD_TO_NDS  | VG_ABSOLUTE),
+  VG_RQUAD_TO_REL_NDS            = (VG_RQUAD_TO_NDS  | VG_RELATIVE),
+  VG_RCUBIC_TO_ABS_NDS           = (VG_RCUBIC_TO_NDS | VG_ABSOLUTE),
+  VG_RCUBIC_TO_REL_NDS           = (VG_RCUBIC_TO_NDS | VG_RELATIVE),
+
+  VG_PATH_COMMAND_NDS_FORCE_SIZE = VG_MAX_ENUM
+} VGPathCommandNds;
+
+#ifdef VG_VGEXT_PROTOTYPES
+VG_API_CALL void VG_API_ENTRY vgProjectiveMatrixNDS(VGboolean enable) ;
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguTransformClipLineNDS(const VGfloat Ain,const VGfloat Bin,const VGfloat Cin,const VGfloat* matrix,const VGboolean inverse,VGfloat* Aout,VGfloat* Bout,VGfloat* Cout);
+#endif
+typedef void (VG_API_ENTRYP PFNVGPROJECTIVEMATRIXNDSPROC) (VGboolean enable) ;
+typedef VGUErrorCode (VGU_API_ENTRYP PFNVGUTRANSFORMCLIPLINENDSPROC) (const VGfloat Ain,const VGfloat Bin,const VGfloat Cin,const VGfloat* matrix,const VGboolean inverse,VGfloat* Aout,VGfloat* Bout,VGfloat* Cout);
+
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* _VGEXT_H */
diff --git a/interface/khronos/include/VG/vgplatform.h b/interface/khronos/include/VG/vgplatform.h
new file mode 100755 (executable)
index 0000000..636779b
--- /dev/null
@@ -0,0 +1,86 @@
+/* $Revision: 6810 $ on $Date:: 2008-10-29 14:31:37 +0000 #$ */
+
+/*------------------------------------------------------------------------
+ *
+ * VG platform specific header Reference Implementation
+ * ----------------------------------------------------
+ *
+ * Copyright (c) 2008 The Khronos Group Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and /or associated documentation files
+ * (the "Materials "), to deal in the Materials without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Materials,
+ * and to permit persons to whom the Materials are furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR
+ * THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//**
+ * \file
+ * \brief VG platform specific header
+ *//*-------------------------------------------------------------------*/
+
+#ifndef _VGPLATFORM_H
+#define _VGPLATFORM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef VG_API_CALL
+   #ifdef KHAPI
+      #define VG_API_CALL KHAPI
+   #else
+      #define VG_API_CALL extern
+   #endif
+#endif
+
+#ifndef VGU_API_CALL
+   #define VGU_API_CALL VG_API_CALL
+#endif
+
+#ifndef VG_API_ENTRY
+#define VG_API_ENTRY
+#endif
+
+#ifndef VG_API_EXIT
+#define VG_API_EXIT
+#endif
+
+#ifndef VGU_API_ENTRY
+#define VGU_API_ENTRY
+#endif
+
+#ifndef VGU_API_EXIT
+#define VGU_API_EXIT
+#endif
+
+#include "../KHR/khrplatform.h"
+typedef khronos_float_t  VGfloat;
+typedef khronos_int8_t   VGbyte;
+typedef khronos_uint8_t  VGubyte;
+typedef khronos_int16_t  VGshort;
+typedef khronos_int32_t  VGint;
+typedef khronos_uint32_t VGuint;
+typedef khronos_uint32_t VGbitfield;
+
+#ifndef VG_VGEXT_PROTOTYPES
+#define VG_VGEXT_PROTOTYPES
+#endif
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* _VGPLATFORM_H */
diff --git a/interface/khronos/include/VG/vgu.h b/interface/khronos/include/VG/vgu.h
new file mode 100755 (executable)
index 0000000..b49aee2
--- /dev/null
@@ -0,0 +1,131 @@
+/* $Revision: 6810 $ on $Date:: 2008-10-29 14:31:37 +0000 #$ */
+
+/*------------------------------------------------------------------------
+ *
+ * VGU 1.1 Reference Implementation
+ * -------------------------------------
+ *
+ * Copyright (c) 2008 The Khronos Group Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and /or associated documentation files
+ * (the "Materials "), to deal in the Materials without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Materials,
+ * and to permit persons to whom the Materials are furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Materials.
+ *
+ * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR
+ * THE USE OR OTHER DEALINGS IN THE MATERIALS.
+ *
+ *//**
+ * \file
+ * \brief      VGU 1.1 API.
+ *//*-------------------------------------------------------------------*/
+
+#ifndef _VGU_H
+#define _VGU_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "openvg.h"
+
+#define VGU_VERSION_1_0 1
+#define VGU_VERSION_1_1 2
+
+#ifndef VGU_API_CALL
+#      error VGU_API_CALL must be defined
+#endif
+
+#ifndef VGU_API_ENTRY
+#   error VGU_API_ENTRY must be defined
+#endif
+
+#ifndef VGU_API_EXIT
+#   error VGU_API_EXIT must be defined
+#endif
+
+
+typedef enum {
+  VGU_NO_ERROR                                 = 0,
+  VGU_BAD_HANDLE_ERROR                         = 0xF000,
+  VGU_ILLEGAL_ARGUMENT_ERROR                   = 0xF001,
+  VGU_OUT_OF_MEMORY_ERROR                      = 0xF002,
+  VGU_PATH_CAPABILITY_ERROR                    = 0xF003,
+  VGU_BAD_WARP_ERROR                           = 0xF004,
+
+  VGU_ERROR_CODE_FORCE_SIZE                    = VG_MAX_ENUM
+} VGUErrorCode;
+
+typedef enum {
+  VGU_ARC_OPEN                                 = 0xF100,
+  VGU_ARC_CHORD                                = 0xF101,
+  VGU_ARC_PIE                                  = 0xF102,
+
+  VGU_ARC_TYPE_FORCE_SIZE                      = VG_MAX_ENUM
+} VGUArcType;
+
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguLine(VGPath path,
+                                  VGfloat x0, VGfloat y0,
+                                  VGfloat x1, VGfloat y1) VGU_API_EXIT;
+
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguPolygon(VGPath path,
+                                     const VGfloat * points, VGint count,
+                                     VGboolean closed) VGU_API_EXIT;
+
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguRect(VGPath path,
+                                  VGfloat x, VGfloat y,
+                                  VGfloat width, VGfloat height) VGU_API_EXIT;
+
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguRoundRect(VGPath path,
+                                       VGfloat x, VGfloat y,
+                                       VGfloat width, VGfloat height,
+                                       VGfloat arcWidth, VGfloat arcHeight) VGU_API_EXIT;
+
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguEllipse(VGPath path,
+                                     VGfloat cx, VGfloat cy,
+                                     VGfloat width, VGfloat height) VGU_API_EXIT;
+
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguArc(VGPath path,
+                                 VGfloat x, VGfloat y,
+                                 VGfloat width, VGfloat height,
+                                 VGfloat startAngle, VGfloat angleExtent,
+                                 VGUArcType arcType) VGU_API_EXIT;
+
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguComputeWarpQuadToSquare(VGfloat sx0, VGfloat sy0,
+                                                     VGfloat sx1, VGfloat sy1,
+                                                     VGfloat sx2, VGfloat sy2,
+                                                     VGfloat sx3, VGfloat sy3,
+                                                     VGfloat * matrix) VGU_API_EXIT;
+
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguComputeWarpSquareToQuad(VGfloat dx0, VGfloat dy0,
+                                                     VGfloat dx1, VGfloat dy1,
+                                                     VGfloat dx2, VGfloat dy2,
+                                                     VGfloat dx3, VGfloat dy3,
+                                                     VGfloat * matrix) VGU_API_EXIT;
+
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguComputeWarpQuadToQuad(VGfloat dx0, VGfloat dy0,
+                                                   VGfloat dx1, VGfloat dy1,
+                                                   VGfloat dx2, VGfloat dy2,
+                                                   VGfloat dx3, VGfloat dy3,
+                                                   VGfloat sx0, VGfloat sy0,
+                                                   VGfloat sx1, VGfloat sy1,
+                                                   VGfloat sx2, VGfloat sy2,
+                                                   VGfloat sx3, VGfloat sy3,
+                                                   VGfloat * matrix) VGU_API_EXIT;
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* #ifndef _VGU_H */
diff --git a/interface/khronos/include/WF/wfc.h b/interface/khronos/include/WF/wfc.h
new file mode 100755 (executable)
index 0000000..a684dc0
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _WFC_H_
+#define _WFC_H_
+
+#include "wfcplatform.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define OPENWFC_VERSION_1_0       (1)
+
+#define WFC_NONE                  (0)
+
+#define WFC_INVALID_HANDLE        ((WFCHandle)0)
+
+#define WFC_DEFAULT_DEVICE_ID     (0)
+
+#define WFC_MAX_INT               ((WFCint)16777216)
+#define WFC_MAX_FLOAT             ((WFCfloat)16777216)
+
+typedef WFCHandle WFCDevice;
+typedef WFCHandle WFCContext;
+typedef WFCHandle WFCSource;
+typedef WFCHandle WFCMask;
+typedef WFCHandle WFCElement;
+
+typedef enum {
+    WFC_ERROR_NONE                          = 0,
+    WFC_ERROR_OUT_OF_MEMORY                 = 0x7001,
+    WFC_ERROR_ILLEGAL_ARGUMENT              = 0x7002,
+    WFC_ERROR_UNSUPPORTED                   = 0x7003,
+    WFC_ERROR_BAD_ATTRIBUTE                 = 0x7004,
+    WFC_ERROR_IN_USE                        = 0x7005,
+    WFC_ERROR_BUSY                          = 0x7006,
+    WFC_ERROR_BAD_DEVICE                    = 0x7007,
+    WFC_ERROR_BAD_HANDLE                    = 0x7008,
+    WFC_ERROR_INCONSISTENCY                 = 0x7009,
+    WFC_ERROR_FORCE_32BIT                   = 0x7FFFFFFF
+} WFCErrorCode;
+
+typedef enum {
+    WFC_DEVICE_FILTER_SCREEN_NUMBER         = 0x7020,
+    WFC_DEVICE_FILTER_FORCE_32BIT           = 0x7FFFFFFF
+} WFCDeviceFilter;
+
+typedef enum {
+    /* Read-only */
+    WFC_DEVICE_CLASS                        = 0x7030,
+    WFC_DEVICE_ID                           = 0x7031,
+    WFC_DEVICE_FORCE_32BIT                  = 0x7FFFFFFF
+} WFCDeviceAttrib;
+
+typedef enum {
+    WFC_DEVICE_CLASS_FULLY_CAPABLE          = 0x7040,
+    WFC_DEVICE_CLASS_OFF_SCREEN_ONLY        = 0x7041,
+    WFC_DEVICE_CLASS_FORCE_32BIT            = 0x7FFFFFFF
+} WFCDeviceClass;
+
+typedef enum {
+    /* Read-only */
+    WFC_CONTEXT_TYPE                        = 0x7051,
+    WFC_CONTEXT_TARGET_HEIGHT               = 0x7052,
+    WFC_CONTEXT_TARGET_WIDTH                = 0x7053,
+    WFC_CONTEXT_LOWEST_ELEMENT              = 0x7054,
+
+    /* Read-write */
+    WFC_CONTEXT_ROTATION                    = 0x7061,
+    WFC_CONTEXT_BG_COLOR                    = 0x7062,
+    WFC_CONTEXT_FORCE_32BIT                 = 0x7FFFFFFF
+} WFCContextAttrib;
+
+typedef enum {
+    WFC_CONTEXT_TYPE_ON_SCREEN              = 0x7071,
+    WFC_CONTEXT_TYPE_OFF_SCREEN             = 0x7072,
+    WFC_CONTEXT_TYPE_FORCE_32BIT            = 0x7FFFFFFF
+} WFCContextType;
+
+typedef enum {
+    /* Clockwise rotation */
+    WFC_ROTATION_0                          = 0x7081,  /* default */
+    WFC_ROTATION_90                         = 0x7082,
+    WFC_ROTATION_180                        = 0x7083,
+    WFC_ROTATION_270                        = 0x7084,
+    WFC_ROTATION_FORCE_32BIT                = 0x7FFFFFFF
+} WFCRotation;
+
+typedef enum {
+    WFC_ELEMENT_DESTINATION_RECTANGLE       = 0x7101,
+    WFC_ELEMENT_SOURCE                      = 0x7102,
+    WFC_ELEMENT_SOURCE_RECTANGLE            = 0x7103,
+    WFC_ELEMENT_SOURCE_FLIP                 = 0x7104,
+    WFC_ELEMENT_SOURCE_ROTATION             = 0x7105,
+    WFC_ELEMENT_SOURCE_SCALE_FILTER         = 0x7106,
+    WFC_ELEMENT_TRANSPARENCY_TYPES          = 0x7107,
+    WFC_ELEMENT_GLOBAL_ALPHA                = 0x7108,
+    WFC_ELEMENT_MASK                        = 0x7109,
+    WFC_ELEMENT_FORCE_32BIT                 = 0x7FFFFFFF
+} WFCElementAttrib;
+
+typedef enum {
+    WFC_SCALE_FILTER_NONE                   = 0x7151,  /* default */
+    WFC_SCALE_FILTER_FASTER                 = 0x7152,
+    WFC_SCALE_FILTER_BETTER                 = 0x7153,
+    WFC_SCALE_FILTER_FORCE_32BIT            = 0x7FFFFFFF
+} WFCScaleFilter;
+
+typedef enum {
+    WFC_TRANSPARENCY_NONE                   = 0,       /* default */
+    WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA   = (1 << 0),
+    WFC_TRANSPARENCY_SOURCE                 = (1 << 1),
+    WFC_TRANSPARENCY_MASK                   = (1 << 2),
+    WFC_TRANSPARENCY_FORCE_32BIT            = 0x7FFFFFFF
+} WFCTransparencyType;
+
+typedef enum {
+    WFC_VENDOR                              = 0x7200,
+    WFC_RENDERER                            = 0x7201,
+    WFC_VERSION                             = 0x7202,
+    WFC_EXTENSIONS                          = 0x7203,
+    WFC_STRINGID_FORCE_32BIT                = 0x7FFFFFFF
+} WFCStringID;
+
+
+/* Function Prototypes */
+
+/* Device */
+WFC_API_CALL WFCint WFC_APIENTRY
+    wfcEnumerateDevices(WFCint *deviceIds, WFCint deviceIdsCount,
+        const WFCint *filterList) WFC_APIEXIT;
+WFC_API_CALL WFCDevice WFC_APIENTRY
+    wfcCreateDevice(WFCint deviceId, const WFCint *attribList) WFC_APIEXIT;
+WFC_API_CALL WFCErrorCode WFC_APIENTRY
+    wfcGetError(WFCDevice dev) WFC_APIEXIT;
+WFC_API_CALL WFCint WFC_APIENTRY
+    wfcGetDeviceAttribi(WFCDevice dev, WFCDeviceAttrib attrib) WFC_APIEXIT;
+WFC_API_CALL WFCErrorCode WFC_APIENTRY
+    wfcDestroyDevice(WFCDevice dev) WFC_APIEXIT;
+
+/* Context */
+WFC_API_CALL WFCContext WFC_APIENTRY
+    wfcCreateOnScreenContext(WFCDevice dev,
+        WFCint screenNumber,
+        const WFCint *attribList) WFC_APIEXIT;
+WFC_API_CALL WFCContext WFC_APIENTRY
+    wfcCreateOffScreenContext(WFCDevice dev,
+        WFCNativeStreamType stream,
+        const WFCint *attribList) WFC_APIEXIT;
+WFC_API_CALL void WFC_APIENTRY
+    wfcCommit(WFCDevice dev, WFCContext ctx, WFCboolean wait) WFC_APIEXIT;
+WFC_API_CALL WFCint WFC_APIENTRY
+    wfcGetContextAttribi(WFCDevice dev, WFCContext ctx,
+        WFCContextAttrib attrib) WFC_APIEXIT;
+WFC_API_CALL void WFC_APIENTRY
+    wfcGetContextAttribfv(WFCDevice dev, WFCContext ctx,
+        WFCContextAttrib attrib, WFCint count, WFCfloat *values) WFC_APIEXIT;
+WFC_API_CALL void WFC_APIENTRY
+    wfcSetContextAttribi(WFCDevice dev, WFCContext ctx,
+        WFCContextAttrib attrib, WFCint value) WFC_APIEXIT;
+WFC_API_CALL void WFC_APIENTRY
+    wfcSetContextAttribfv(WFCDevice dev, WFCContext ctx,
+        WFCContextAttrib attrib,
+        WFCint count, const WFCfloat *values) WFC_APIEXIT;
+WFC_API_CALL void WFC_APIENTRY
+    wfcDestroyContext(WFCDevice dev, WFCContext ctx) WFC_APIEXIT;
+
+/* Source */
+WFC_API_CALL WFCSource WFC_APIENTRY
+    wfcCreateSourceFromStream(WFCDevice dev, WFCContext ctx,
+        WFCNativeStreamType stream,
+        const WFCint *attribList) WFC_APIEXIT;
+WFC_API_CALL void WFC_APIENTRY
+    wfcDestroySource(WFCDevice dev, WFCSource src) WFC_APIEXIT;
+
+/* Mask */
+WFC_API_CALL WFCMask WFC_APIENTRY
+    wfcCreateMaskFromStream(WFCDevice dev, WFCContext ctx,
+        WFCNativeStreamType stream,
+        const WFCint *attribList) WFC_APIEXIT;
+WFC_API_CALL void WFC_APIENTRY
+    wfcDestroyMask(WFCDevice dev, WFCMask mask) WFC_APIEXIT;
+
+/* Element */
+WFC_API_CALL WFCElement WFC_APIENTRY
+    wfcCreateElement(WFCDevice dev, WFCContext ctx,
+        const WFCint *attribList) WFC_APIEXIT;
+WFC_API_CALL WFCint WFC_APIENTRY
+    wfcGetElementAttribi(WFCDevice dev, WFCElement element,
+        WFCElementAttrib attrib) WFC_APIEXIT;
+WFC_API_CALL WFCfloat WFC_APIENTRY
+    wfcGetElementAttribf(WFCDevice dev, WFCElement element,
+        WFCElementAttrib attrib) WFC_APIEXIT;
+WFC_API_CALL void WFC_APIENTRY
+    wfcGetElementAttribiv(WFCDevice dev, WFCElement element,
+        WFCElementAttrib attrib, WFCint count, WFCint *values) WFC_APIEXIT;
+WFC_API_CALL void WFC_APIENTRY
+    wfcGetElementAttribfv(WFCDevice dev, WFCElement element,
+        WFCElementAttrib attrib, WFCint count, WFCfloat *values) WFC_APIEXIT;
+WFC_API_CALL void WFC_APIENTRY
+    wfcSetElementAttribi(WFCDevice dev, WFCElement element,
+        WFCElementAttrib attrib, WFCint value) WFC_APIEXIT;
+WFC_API_CALL void WFC_APIENTRY
+    wfcSetElementAttribf(WFCDevice dev, WFCElement element,
+        WFCElementAttrib attrib, WFCfloat value) WFC_APIEXIT;
+WFC_API_CALL void WFC_APIENTRY
+    wfcSetElementAttribiv(WFCDevice dev, WFCElement element,
+        WFCElementAttrib attrib,
+        WFCint count, const WFCint *values) WFC_APIEXIT;
+WFC_API_CALL void WFC_APIENTRY
+    wfcSetElementAttribfv(WFCDevice dev, WFCElement element,
+        WFCElementAttrib attrib,
+        WFCint count, const WFCfloat *values) WFC_APIEXIT;
+WFC_API_CALL void WFC_APIENTRY
+    wfcInsertElement(WFCDevice dev, WFCElement element,
+        WFCElement subordinate) WFC_APIEXIT;
+WFC_API_CALL void WFC_APIENTRY
+    wfcRemoveElement(WFCDevice dev, WFCElement element) WFC_APIEXIT;
+WFC_API_CALL WFCElement WFC_APIENTRY
+    wfcGetElementAbove(WFCDevice dev, WFCElement element) WFC_APIEXIT;
+WFC_API_CALL WFCElement WFC_APIENTRY
+    wfcGetElementBelow(WFCDevice dev, WFCElement element) WFC_APIEXIT;
+WFC_API_CALL void WFC_APIENTRY
+    wfcDestroyElement(WFCDevice dev, WFCElement element) WFC_APIEXIT;
+
+/* Rendering */
+WFC_API_CALL void WFC_APIENTRY
+    wfcActivate(WFCDevice dev, WFCContext ctx) WFC_APIEXIT;
+WFC_API_CALL void WFC_APIENTRY
+    wfcDeactivate(WFCDevice dev, WFCContext ctx) WFC_APIEXIT;
+WFC_API_CALL void WFC_APIENTRY
+    wfcCompose(WFCDevice dev, WFCContext ctx, WFCboolean wait) WFC_APIEXIT;
+WFC_API_CALL void WFC_APIENTRY
+    wfcFence(WFCDevice dev, WFCContext ctx, WFCEGLDisplay dpy,
+        WFCEGLSync sync) WFC_APIEXIT;
+
+/* Renderer and extension information */
+WFC_API_CALL WFCint WFC_APIENTRY
+    wfcGetStrings(WFCDevice dev,
+        WFCStringID name,
+        const char **strings,
+        WFCint stringsCount) WFC_APIEXIT;
+WFC_API_CALL WFCboolean WFC_APIENTRY
+    wfcIsExtensionSupported(WFCDevice dev, const char *string) WFC_APIEXIT;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _WFC_H_ */
diff --git a/interface/khronos/include/WF/wfcplatform.h b/interface/khronos/include/WF/wfcplatform.h
new file mode 100755 (executable)
index 0000000..da47232
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _WFCPLATFORM_H_
+#define _WFCPLATFORM_H_
+
+#include "../KHR/khrplatform.h"
+#include "../EGL/egl.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef WFC_API_CALL
+#define WFC_API_CALL KHRONOS_APICALL
+#endif
+#ifndef WFC_APIENTRY
+#define WFC_APIENTRY KHRONOS_APIENTRY
+#endif
+#ifndef WFC_APIEXIT
+#define WFC_APIEXIT KHRONOS_APIATTRIBUTES
+#endif
+
+#ifndef WFC_DEFAULT_SCREEN_NUMBER
+#define WFC_DEFAULT_SCREEN_NUMBER (0)
+#endif
+
+typedef enum {
+    WFC_FALSE               = 0,
+    WFC_TRUE                = 1,
+    WFC_BOOLEAN_FORCE_32BIT = 0x7FFFFFFF
+} WFCboolean;
+
+typedef khronos_int32_t   WFCint;
+typedef khronos_float_t   WFCfloat;
+typedef khronos_uint32_t  WFCbitfield;
+typedef khronos_uint32_t  WFCHandle;
+
+typedef EGLDisplay   WFCEGLDisplay;
+typedef void         *WFCEGLSync;   /* An opaque handle to an EGLSyncKHR */
+typedef WFCHandle    WFCNativeStreamType;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _WFCPLATFORM_H_ */
diff --git a/interface/khronos/vg/vg_client.c b/interface/khronos/vg/vg_client.c
new file mode 100755 (executable)
index 0000000..e10070c
--- /dev/null
@@ -0,0 +1,5666 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+Copyright (c) 2008 Broadcom Europe Limited.
+All rights reserved.
+
+Project  :  khronos
+Module   :  VG client
+
+FILE DESCRIPTION
+VG client-side function definitions. Dispatches VG calls via RPC or direct
+call. Some functions require support for control messages just over 1kB in
+length, 2kB should be fine for all functions.
+=============================================================================*/
+
+/*
+   Potential spec bugs:
+
+   vgImageSubData, vgGetImageSubData, vgWritePixels, and vgReadPixels require
+      the data pointer to be aligned, but do not require the stride to be
+      aligned. This seems a little useless, so we require that both the pointer
+      and stride are aligned (unless height is 1, in which case we just require
+      that the pointer is aligned)
+*/
+
+#define VG_VGEXT_PROTOTYPES /* we want the prototypes so the compiler will check that the signatures match */
+
+#include "interface/khronos/common/khrn_client_mangle.h"
+#include "interface/khronos/common/khrn_int_common.h"
+
+#include "interface/khronos/common/khrn_client_platform.h"
+#include "interface/khronos/common/khrn_client_rpc.h"
+#include "interface/khronos/vg/vg_client.h"
+
+#include "interface/khronos/egl/egl_client_config.h"
+
+#include "interface/khronos/common/khrn_int_color.h"
+#include "interface/khronos/common/khrn_int_math.h"
+#include "interface/khronos/common/khrn_int_util.h"
+
+#include "interface/khronos/include/VG/openvg.h"
+#include "interface/khronos/include/VG/vgext.h"
+#include "interface/khronos/include/VG/vgu.h"
+
+#include "interface/khronos/vg/vg_int_config.h"
+#include "interface/khronos/vg/vg_int_mat3x3.h"
+#ifdef RPC_DIRECT
+   #include "interface/khronos/vg/vg_int_impl.h" /* for _impl function calls */
+#endif
+#if defined(WIN32) || defined(__mips__)
+#include "interface/khronos/common/khrn_int_misc_impl.h"
+#endif
+
+#include "interface/khronos/vg/vg_int_util.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/******************************************************************************
+shared state
+******************************************************************************/
+
+VG_CLIENT_SHARED_STATE_T *vg_client_shared_state_alloc(void)
+{
+   VG_CLIENT_SHARED_STATE_T *shared_state;
+   KHR_STATUS_T status;
+
+   shared_state = (VG_CLIENT_SHARED_STATE_T *)khrn_platform_malloc(sizeof(VG_CLIENT_SHARED_STATE_T), "VG_CLIENT_SHARED_STATE_T");
+   if (!shared_state) {
+      return NULL;
+   }
+
+   status = platform_mutex_create(&shared_state->mutex);
+   if (status != KHR_SUCCESS) {
+      khrn_platform_free(shared_state);
+      return NULL;
+   }
+
+   if (!khrn_pointer_map_init(&shared_state->objects, 128)) {
+      platform_mutex_destroy(&shared_state->mutex);
+      khrn_platform_free(shared_state);
+      return NULL;
+   }
+
+   shared_state->ref_count = 1;
+   shared_state->stems_count = 0;
+
+   return shared_state;
+}
+
+static void object_free(void *object);
+
+static void object_free_callback(KHRN_POINTER_MAP_T *pointer_map, uint32_t key, void *object, void *data)
+{
+   UNUSED(pointer_map);
+   UNUSED(key);
+   UNUSED(data);
+
+   object_free(object);
+}
+
+void vg_client_shared_state_free(VG_CLIENT_SHARED_STATE_T *shared_state)
+{
+   vcos_assert(shared_state->ref_count == 0);
+   khrn_pointer_map_iterate(&shared_state->objects, object_free_callback, NULL);
+   khrn_pointer_map_term(&shared_state->objects);
+   platform_mutex_destroy(&shared_state->mutex);
+   khrn_platform_free(shared_state);
+}
+
+/******************************************************************************
+state
+******************************************************************************/
+
+VG_CLIENT_STATE_T *vg_client_state_alloc(VG_CLIENT_SHARED_STATE_T *shared_state)
+{
+   VGuint i;
+
+   VG_CLIENT_STATE_T *state = (VG_CLIENT_STATE_T *)khrn_platform_malloc(sizeof(VG_CLIENT_STATE_T), "VG_CLIENT_STATE_T");
+   if (!state) {
+      return NULL;
+   }
+
+   vg_client_shared_state_acquire(shared_state);
+   state->shared_state = shared_state;
+
+   state->render_callback = NULL;
+   state->flush_callback = NULL;
+
+   state->matrix_mode = VG_MATRIX_PATH_USER_TO_SURFACE;
+   for (i = 0; i != ARR_COUNT(state->matrices); ++i) {
+      vg_mat3x3_set_identity(&state->matrices[i].client);
+      vg_mat3x3_set_identity(&state->matrices[i].server);
+   }
+
+   state->fill_rule = VG_EVEN_ODD;
+   state->stroke_line_width = 1.0f;
+   state->stroke_cap_style = VG_CAP_BUTT;
+   state->stroke_join_style = VG_JOIN_MITER;
+   state->stroke_miter_limit = 4.0f;
+   state->stroke_dash_pattern_count = 0;
+   state->stroke_dash_phase = 0.0f;
+   state->stroke_dash_phase_reset = false;
+   state->image_quality = VG_IMAGE_QUALITY_FASTER;
+   state->image_mode = VG_DRAW_IMAGE_NORMAL;
+
+   state->scissoring = false;
+   state->scissor_rects_count = 0;
+
+   state->rendering_quality = VG_RENDERING_QUALITY_BETTER;
+
+   state->fill_paint = VG_INVALID_HANDLE;
+   state->stroke_paint = VG_INVALID_HANDLE;
+   state->tile_fill_color[0] = 0.0f;
+   state->tile_fill_color[1] = 0.0f;
+   state->tile_fill_color[2] = 0.0f;
+   state->tile_fill_color[3] = 0.0f;
+   state->clear_color[0] = 0.0f;
+   state->clear_color[1] = 0.0f;
+   state->clear_color[2] = 0.0f;
+   state->clear_color[3] = 0.0f;
+
+   state->color_transform = false;
+   state->color_transform_values[0] = 1.0f;
+   state->color_transform_values[1] = 1.0f;
+   state->color_transform_values[2] = 1.0f;
+   state->color_transform_values[3] = 1.0f;
+   state->color_transform_values[4] = 0.0f;
+   state->color_transform_values[5] = 0.0f;
+   state->color_transform_values[6] = 0.0f;
+   state->color_transform_values[7] = 0.0f;
+
+   state->blend_mode = VG_BLEND_SRC_OVER;
+   state->masking = false;
+
+   state->filter_format_linear = false;
+   state->filter_format_pre = false;
+   state->filter_channel_mask = VG_RED | VG_GREEN | VG_BLUE | VG_ALPHA;
+
+   state->pixel_layout = VG_PIXEL_LAYOUT_UNKNOWN;
+
+   return state;
+}
+
+void vg_client_state_free(VG_CLIENT_STATE_T *state)
+{
+   vg_client_shared_state_release(state->shared_state);
+   khrn_platform_free(state);
+}
+
+/******************************************************************************
+helpers
+******************************************************************************/
+
+static void clear_error(void)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   RPC_CALL0(vgClearError_impl,
+             thread,
+             VGCLEARERROR_ID);
+}
+
+static void set_error(VGErrorCode error)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   RPC_CALL1(vgSetError_impl,
+             thread,
+             VGSETERROR_ID,
+             RPC_ENUM(error));
+}
+
+static VGErrorCode get_error(void)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   return (VGErrorCode)RPC_ENUM_RES(RPC_CALL0_RES(vgGetError_impl,
+                                                  thread,
+                                                  VGGETERROR_ID));
+}
+
+static INLINE bool is_aligned(const void *p, VGuint alignment)
+{
+   vcos_assert(is_power_of_2(alignment));
+   return ((uintptr_t)p & (alignment - 1)) == 0;
+}
+
+static INLINE bool is_aligned_float(const VGfloat *p)
+{
+   return is_aligned(p, alignof(VGfloat));
+}
+
+static INLINE bool is_aligned_short(const VGshort *p)
+{
+   return is_aligned(p, alignof(VGshort));
+}
+
+static INLINE bool is_aligned_int(const VGint *p)
+{
+   return is_aligned(p, alignof(VGint));
+}
+
+static INLINE bool is_aligned_uint(const VGuint *p)
+{
+   return is_aligned(p, alignof(VGuint));
+}
+
+static bool is_aligned_path_datatype(const void *p, VGPathDatatype path_datatype)
+{
+   switch (path_datatype) {
+   case VG_PATH_DATATYPE_S_8:  return true;
+   case VG_PATH_DATATYPE_S_16: return is_aligned_short((const VGshort *)p);
+   case VG_PATH_DATATYPE_S_32: return is_aligned_int((const VGint *)p);
+   case VG_PATH_DATATYPE_F:    return is_aligned_float((const VGfloat *)p);
+   default:                    UNREACHABLE(); return false;
+   }
+}
+
+static bool is_aligned_image_format(const void *p, VGImageFormat image_format)
+{
+   switch (image_format) {
+   case VG_sRGBX_8888:
+   case VG_sRGBA_8888:
+   case VG_sRGBA_8888_PRE:
+   case VG_lRGBX_8888:
+   case VG_lRGBA_8888:
+   case VG_lRGBA_8888_PRE:
+   case VG_sXRGB_8888:
+   case VG_sARGB_8888:
+   case VG_sARGB_8888_PRE:
+   case VG_lXRGB_8888:
+   case VG_lARGB_8888:
+   case VG_lARGB_8888_PRE:
+   case VG_sBGRX_8888:
+   case VG_sBGRA_8888:
+   case VG_sBGRA_8888_PRE:
+   case VG_lBGRX_8888:
+   case VG_lBGRA_8888:
+   case VG_lBGRA_8888_PRE:
+   case VG_sXBGR_8888:
+   case VG_sABGR_8888:
+   case VG_sABGR_8888_PRE:
+   case VG_lXBGR_8888:
+   case VG_lABGR_8888:
+   case VG_lABGR_8888_PRE:
+      return is_aligned_uint((const VGuint *)p);
+   case VG_sRGB_565:
+   case VG_sRGBA_5551:
+   case VG_sRGBA_4444:
+   case VG_sARGB_1555:
+   case VG_sARGB_4444:
+   case VG_sBGR_565:
+   case VG_sBGRA_5551:
+   case VG_sBGRA_4444:
+   case VG_sABGR_1555:
+   case VG_sABGR_4444:
+      return is_aligned_short((const VGshort *)p);
+   case VG_sL_8:
+   case VG_lL_8:
+   case VG_A_8:
+   case VG_BW_1:
+   case VG_A_1:
+   case VG_A_4:
+      return true;
+   default:
+      UNREACHABLE();
+      return false;
+   }
+}
+
+static bool contains_illegal_segment(const VGubyte *segments, VGint segments_count)
+{
+   for (; segments_count != 0; ++segments, --segments_count) {
+      switch (*segments & ~VG_RELATIVE) {
+      case VG_CLOSE_PATH: break;
+      case VG_MOVE_TO:    break;
+      case VG_LINE_TO:    break;
+      case VG_HLINE_TO:   break;
+      case VG_VLINE_TO:   break;
+      case VG_QUAD_TO:    break;
+      case VG_CUBIC_TO:   break;
+      case VG_SQUAD_TO:   break;
+      case VG_SCUBIC_TO:  break;
+      case VG_SCCWARC_TO: break;
+      case VG_SCWARC_TO:  break;
+      case VG_LCCWARC_TO: break;
+      case VG_LCWARC_TO:  break;
+      default:            return true;
+      }
+   }
+   return false;
+}
+
+static VGuint get_coords_count(const VGubyte *segments, VGint segments_count)
+{
+   VGuint coords_count = 0;
+   for (; segments_count != 0; ++segments, --segments_count) {
+      coords_count += get_segment_coords_count(*segments & ~VG_RELATIVE);
+   }
+   return coords_count;
+}
+
+static VGuint normalise_segment(VGuint segment)
+{
+   switch (segment) {
+   case VG_CLOSE_PATH: return VG_CLOSE_PATH;
+   case VG_MOVE_TO:    return VG_MOVE_TO;
+   case VG_LINE_TO:    return VG_LINE_TO;
+   case VG_HLINE_TO:   return VG_LINE_TO;
+   case VG_VLINE_TO:   return VG_LINE_TO;
+   case VG_QUAD_TO:    return VG_CUBIC_TO;
+   case VG_CUBIC_TO:   return VG_CUBIC_TO;
+   case VG_SQUAD_TO:   return VG_CUBIC_TO;
+   case VG_SCUBIC_TO:  return VG_CUBIC_TO;
+
+   /*
+      on the client-side, we don't care about the different arc types, just
+      normalise them all to the same type
+   */
+
+   case VG_SCCWARC_TO: return VG_SCCWARC_TO;
+   case VG_SCWARC_TO:  return VG_SCCWARC_TO;
+   case VG_LCCWARC_TO: return VG_SCCWARC_TO;
+   case VG_LCWARC_TO:  return VG_SCCWARC_TO;
+   default:            UNREACHABLE(); return 0;
+   }
+}
+
+static bool interpolate_segments_compatible(const VGubyte *begin_segments, const VGubyte *end_segments, VGuint segments_count)
+{
+   for (; segments_count != 0; ++begin_segments, ++end_segments, --segments_count) {
+      if (normalise_segment(*begin_segments & ~VG_RELATIVE) != normalise_segment(*end_segments & ~VG_RELATIVE)) {
+         return false;
+      }
+   }
+   return true;
+}
+
+#ifndef RPC_DIRECT
+
+static VGuint get_log2_image_format_bpp(VGImageFormat image_format)
+{
+   switch (image_format) {
+   case VG_sRGBX_8888:
+   case VG_sRGBA_8888:
+   case VG_sRGBA_8888_PRE:
+   case VG_lRGBX_8888:
+   case VG_lRGBA_8888:
+   case VG_lRGBA_8888_PRE:
+   case VG_sXRGB_8888:
+   case VG_sARGB_8888:
+   case VG_sARGB_8888_PRE:
+   case VG_lXRGB_8888:
+   case VG_lARGB_8888:
+   case VG_lARGB_8888_PRE:
+   case VG_sBGRX_8888:
+   case VG_sBGRA_8888:
+   case VG_sBGRA_8888_PRE:
+   case VG_lBGRX_8888:
+   case VG_lBGRA_8888:
+   case VG_lBGRA_8888_PRE:
+   case VG_sXBGR_8888:
+   case VG_sABGR_8888:
+   case VG_sABGR_8888_PRE:
+   case VG_lXBGR_8888:
+   case VG_lABGR_8888:
+   case VG_lABGR_8888_PRE:
+      return 5;
+   case VG_sRGB_565:
+   case VG_sRGBA_5551:
+   case VG_sRGBA_4444:
+   case VG_sARGB_1555:
+   case VG_sARGB_4444:
+   case VG_sBGR_565:
+   case VG_sBGRA_5551:
+   case VG_sBGRA_4444:
+   case VG_sABGR_1555:
+   case VG_sABGR_4444:
+      return 4;
+   case VG_sL_8:
+   case VG_lL_8:
+   case VG_A_8:
+      return 3;
+   case VG_A_4:
+      return 2;
+   case VG_BW_1:
+   case VG_A_1:
+      return 0;
+   default:
+      UNREACHABLE();
+      return 0;
+   }
+}
+
+#endif
+
+static VGint param_to_int(
+   bool are_floats,
+   const void *values,
+   VGuint i)
+{
+   vcos_assert(values);
+   return are_floats ?
+      float_to_int_floor(clean_float(((const VGfloat *)values)[i])) :
+      ((const VGint *)values)[i];
+}
+
+static bool params_to_ints(
+   VGint *ints,
+   bool are_floats,
+   const void *values,
+   VGuint count)
+{
+   bool changed = false;
+   VGuint i;
+   for (i = 0; i != count; ++i) {
+      VGint x = param_to_int(are_floats, values, i);
+      if (ints[i] != x) {
+         changed = true;
+         ints[i] = x;
+      }
+   }
+   return changed;
+}
+
+static VGfloat param_to_float(
+   bool are_floats,
+   const void *values,
+   VGuint i)
+{
+   vcos_assert(values);
+   return are_floats ?
+      ((const VGfloat *)values)[i] :
+      (VGfloat)((const VGint *)values)[i];
+}
+
+static bool params_to_floats(
+   VGfloat *floats,
+   bool are_floats,
+   const void *values,
+   VGuint count)
+{
+   bool changed = false;
+   VGuint i;
+   for (i = 0; i != count; ++i) {
+      VGfloat x = param_to_float(are_floats, values, i);
+      if (!floats_identical(floats[i], x)) {
+         changed = true;
+         floats[i] = x;
+      }
+   }
+   return changed;
+}
+
+static void int_to_param(
+   bool are_floats,
+   void *values,
+   VGuint i,
+   VGint value)
+{
+   if (are_floats) {
+      ((VGfloat *)values)[i] = (VGfloat)value;
+   } else {
+      ((VGint *)values)[i] = value;
+   }
+}
+
+static void ints_to_params(
+   bool are_floats,
+   void *values,
+   VGuint count,
+   const VGint *ints)
+{
+   VGuint i;
+   for (i = 0; i != count; ++i) {
+      int_to_param(are_floats, values, i, ints[i]);
+   }
+}
+
+static void float_to_param(
+   bool are_floats,
+   void *values,
+   VGuint i,
+   VGfloat value)
+{
+   if (are_floats) {
+      ((VGfloat *)values)[i] = value;
+   } else {
+      ((VGint *)values)[i] = float_to_int_floor(clean_float(value));
+   }
+}
+
+static void floats_to_params(
+   bool are_floats,
+   void *values,
+   VGuint count,
+   const VGfloat *floats)
+{
+   VGuint i;
+   for (i = 0; i != count; ++i) {
+      float_to_param(are_floats, values, i, floats[i]);
+   }
+}
+
+static VGHandle get_stem(VG_CLIENT_STATE_T *state)
+{
+   VGHandle vg_handle;
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+
+   if (state->shared_state->stems_count == 0) {
+      CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+      RPC_HIGH_PRIORITY_BEGIN(thread);
+      state->shared_state->stems_count = RPC_UINT_RES(RPC_CALL2_OUT_CTRL_RES(vgCreateStems_impl,
+                                                                             thread,
+                                                                             VGCREATESTEMS_ID,
+                                                                             VG_CLIENT_STEMS_COUNT_MAX,
+                                                                             state->shared_state->stems));
+      RPC_HIGH_PRIORITY_END(thread);
+   }
+   vg_handle = (state->shared_state->stems_count == 0) ? VG_INVALID_HANDLE : state->shared_state->stems[--state->shared_state->stems_count];
+
+   platform_mutex_release(&state->shared_state->mutex);
+
+   return vg_handle;
+}
+
+static void destroy_stem(VGHandle vg_handle)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   RPC_CALL1(vgDestroyStem_impl,
+             thread,
+             VGDESTROYSTEM_ID,
+             RPC_HANDLE(vg_handle));
+}
+
+static VG_CLIENT_FONT_T *font_alloc(void)
+{
+   VG_CLIENT_FONT_T *font = (VG_CLIENT_FONT_T *)khrn_platform_malloc(sizeof(VG_CLIENT_FONT_T), "VG_CLIENT_FONT_T");
+   if (!font) {
+      return NULL;
+   }
+
+   font->object_type = VG_CLIENT_OBJECT_TYPE_FONT;
+#if EGL_BRCM_global_image && EGL_KHR_image
+   if (!khrn_global_image_map_init(&font->glyph_global_images, 8)) {
+      khrn_platform_free(font);
+      return NULL;
+   }
+#endif
+
+   return font;
+}
+
+static void font_free(VG_CLIENT_FONT_T *font)
+{
+#if EGL_BRCM_global_image && EGL_KHR_image
+   khrn_global_image_map_term(&font->glyph_global_images);
+#endif
+   khrn_platform_free(font);
+}
+
+static VG_CLIENT_IMAGE_T *image_alloc(VGImageFormat format, VGint width, VGint height
+#if EGL_BRCM_global_image && EGL_KHR_image
+   , VGuint global_image_id_0, VGuint global_image_id_1
+#endif
+   )
+{
+   VG_CLIENT_IMAGE_T *image = (VG_CLIENT_IMAGE_T *)khrn_platform_malloc(sizeof(VG_CLIENT_IMAGE_T), "VG_CLIENT_IMAGE_T");
+   if (!image) {
+      return NULL;
+   }
+
+   image->object_type = VG_CLIENT_OBJECT_TYPE_IMAGE;
+   image->format = format;
+   image->width = width;
+   image->height = height;
+#if EGL_BRCM_global_image && EGL_KHR_image
+   if (global_image_id_0 || global_image_id_1) {
+      platform_acquire_global_image(global_image_id_0, global_image_id_1);
+   }
+   image->global_image_id[0] = global_image_id_0;
+   image->global_image_id[1] = global_image_id_1;
+#endif
+
+   return image;
+}
+
+static void image_free(VG_CLIENT_IMAGE_T *image)
+{
+#if EGL_BRCM_global_image && EGL_KHR_image
+   if (image->global_image_id[0] || image->global_image_id[1]) {
+      platform_release_global_image(image->global_image_id[0], image->global_image_id[1]);
+   }
+#endif
+   khrn_platform_free(image);
+}
+
+static VG_CLIENT_MASK_LAYER_T *mask_layer_alloc(VGint width, VGint height)
+{
+   VG_CLIENT_MASK_LAYER_T *mask_layer = (VG_CLIENT_MASK_LAYER_T *)khrn_platform_malloc(sizeof(VG_CLIENT_MASK_LAYER_T), "VG_CLIENT_MASK_LAYER_T");
+   if (!mask_layer) {
+      return NULL;
+   }
+
+   mask_layer->object_type = VG_CLIENT_OBJECT_TYPE_MASK_LAYER;
+   mask_layer->width = width;
+   mask_layer->height = height;
+
+   return mask_layer;
+}
+
+static void mask_layer_free(VG_CLIENT_MASK_LAYER_T *mask_layer)
+{
+   khrn_platform_free(mask_layer);
+}
+
+static bool need_paint_gradient(VGint param_type)
+{
+   return (param_type == VG_PAINT_COLOR_RAMP_SPREAD_MODE) ||
+          (param_type == VG_PAINT_COLOR_RAMP_PREMULTIPLIED) ||
+          (param_type == VG_PAINT_COLOR_RAMP_STOPS) ||
+          (param_type == VG_PAINT_LINEAR_GRADIENT) ||
+          (param_type == VG_PAINT_RADIAL_GRADIENT);
+}
+
+static VG_CLIENT_PAINT_T *paint_alloc(void)
+{
+   VG_CLIENT_PAINT_T *paint = (VG_CLIENT_PAINT_T *)khrn_platform_malloc(sizeof(VG_CLIENT_PAINT_T), "VG_CLIENT_PAINT_T");
+   if (!paint) {
+      return NULL;
+   }
+
+   paint->object_type = VG_CLIENT_OBJECT_TYPE_PAINT;
+   paint->type = VG_PAINT_TYPE_COLOR;
+   paint->color[0] = 0.0f;
+   paint->color[1] = 0.0f;
+   paint->color[2] = 0.0f;
+   paint->color[3] = 1.0f;
+   paint->gradient = NULL; /* will be allocated when required */
+   paint->pattern_tiling_mode = VG_TILE_FILL;
+   paint->pattern = VG_INVALID_HANDLE;
+#if EGL_BRCM_global_image && EGL_KHR_image
+   paint->pattern_global_image_id[0] = 0;
+   paint->pattern_global_image_id[1] = 0;
+#endif
+
+   return paint;
+}
+
+static bool paint_alloc_gradient(VG_CLIENT_PAINT_T *paint)
+{
+   VG_CLIENT_PAINT_GRADIENT_T *gradient;
+
+   vcos_assert(!paint->gradient);
+
+   gradient = (VG_CLIENT_PAINT_GRADIENT_T *)khrn_platform_malloc(sizeof(VG_CLIENT_PAINT_GRADIENT_T), "VG_CLIENT_PAINT_GRADIENT_T");
+   if (!gradient) {
+      return false;
+   }
+
+   gradient->linear[0] = 0.0f;
+   gradient->linear[1] = 0.0f;
+   gradient->linear[2] = 1.0f;
+   gradient->linear[3] = 0.0f;
+   gradient->radial[0] = 0.0f;
+   gradient->radial[1] = 0.0f;
+   gradient->radial[2] = 0.0f;
+   gradient->radial[3] = 0.0f;
+   gradient->radial[4] = 1.0f;
+   gradient->ramp_spread_mode = VG_COLOR_RAMP_SPREAD_PAD;
+   gradient->ramp_pre = true;
+   gradient->ramp_stops = NULL;
+   gradient->ramp_stops_count = 0;
+
+   paint->gradient = gradient;
+
+   return true;
+}
+
+static void paint_free(VG_CLIENT_PAINT_T *paint)
+{
+#if EGL_BRCM_global_image && EGL_KHR_image
+   if (paint->pattern_global_image_id[0] || paint->pattern_global_image_id[1]) {
+      platform_release_global_image(paint->pattern_global_image_id[0], paint->pattern_global_image_id[1]);
+   }
+#endif
+   if (paint->gradient) {
+      if (paint->gradient->ramp_stops) {
+         khrn_platform_free(paint->gradient->ramp_stops);
+      }
+      khrn_platform_free(paint->gradient);
+   }
+   khrn_platform_free(paint);
+}
+
+static bool need_path_segments(VGbitfield caps)
+{
+   /*
+      need segments for vgModifyPath and interpolating from, but also need for
+      appending from incase the path being appended to needs segments (we don't
+      want to have to go to the server to get them)
+   */
+
+   return !!(caps & (VG_PATH_CAPABILITY_APPEND_FROM |
+                     VG_PATH_CAPABILITY_MODIFY |
+                     VG_PATH_CAPABILITY_TRANSFORM_FROM |
+                     VG_PATH_CAPABILITY_INTERPOLATE_FROM));
+}
+
+static VG_CLIENT_PATH_T *path_alloc(VGint format, VGPathDatatype datatype, VGfloat scale, VGfloat bias, VGbitfield caps, VGint segments_capacity)
+{
+   VG_CLIENT_PATH_T *path = (VG_CLIENT_PATH_T *)khrn_platform_malloc(sizeof(VG_CLIENT_PATH_T), "VG_CLIENT_PATH_T");
+   if (!path) {
+      return NULL;
+   }
+
+   path->object_type = VG_CLIENT_OBJECT_TYPE_PATH;
+   path->format = format;
+   path->datatype = datatype;
+   path->scale = scale;
+   path->bias = bias;
+   path->caps = caps;
+   if (need_path_segments(caps)) {
+      khrn_vector_init(&path->segments, clampi(segments_capacity, 0, 1024));
+   }
+
+   return path;
+}
+
+static void path_update_caps(VG_CLIENT_PATH_T *path, VGbitfield caps)
+{
+   if (!need_path_segments(path->caps) && need_path_segments(caps)) {
+      khrn_vector_init(&path->segments, 0);
+   }
+   if (need_path_segments(path->caps) && !need_path_segments(caps)) {
+      khrn_vector_term(&path->segments);
+   }
+   path->caps = caps;
+}
+
+static void path_free(VG_CLIENT_PATH_T *path)
+{
+   if (need_path_segments(path->caps)) {
+      khrn_vector_term(&path->segments);
+   }
+   khrn_platform_free(path);
+}
+
+static void object_free(void *object)
+{
+   switch (*(VG_CLIENT_OBJECT_TYPE_T *)object) {
+   case VG_CLIENT_OBJECT_TYPE_FONT:       font_free((VG_CLIENT_FONT_T *)object); break;
+   case VG_CLIENT_OBJECT_TYPE_IMAGE:      image_free((VG_CLIENT_IMAGE_T *)object); break;
+   case VG_CLIENT_OBJECT_TYPE_MASK_LAYER: mask_layer_free((VG_CLIENT_MASK_LAYER_T *)object); break;
+   case VG_CLIENT_OBJECT_TYPE_PAINT:      paint_free((VG_CLIENT_PAINT_T *)object); break;
+   case VG_CLIENT_OBJECT_TYPE_PATH:       path_free((VG_CLIENT_PATH_T *)object); break;
+   default:                               UNREACHABLE();
+   }
+}
+
+/*
+   see nice_handle in middleware/khronos/vg/vg_set.c
+*/
+
+static INLINE uint32_t nice_handle(VGHandle vg_handle)
+{
+   return _ror((uint32_t)vg_handle, 31);
+}
+
+static bool insert_object(VG_CLIENT_STATE_T *state, VGHandle vg_handle, void *object)
+{
+   void *prev_object = khrn_pointer_map_lookup(&state->shared_state->objects, nice_handle(vg_handle));
+   if (prev_object) {
+      object_free(prev_object);
+   }
+   return khrn_pointer_map_insert(&state->shared_state->objects, nice_handle(vg_handle), object);
+}
+
+static void delete_object(VG_CLIENT_STATE_T *state, VGHandle vg_handle, VG_CLIENT_OBJECT_TYPE_T type)
+{
+   void *object = khrn_pointer_map_lookup(&state->shared_state->objects, nice_handle(vg_handle));
+   if (object && (*(VG_CLIENT_OBJECT_TYPE_T *)object == type)) {
+      object_free(object);
+      khrn_pointer_map_delete(&state->shared_state->objects, nice_handle(vg_handle));
+   }
+}
+
+static INLINE void *lookup_object(VG_CLIENT_STATE_T *state, VGHandle vg_handle, VG_CLIENT_OBJECT_TYPE_T type)
+{
+   void *object = khrn_pointer_map_lookup(&state->shared_state->objects, nice_handle(vg_handle));
+   return (object && (*(VG_CLIENT_OBJECT_TYPE_T *)object == type)) ? object : NULL;
+}
+
+static INLINE VG_MAT3X3_SYNC_T *get_matrix_sync(VG_CLIENT_STATE_T *state, VGMatrixMode matrix_mode)
+{
+   vcos_assert(
+      (matrix_mode >= VG_MATRIX_PATH_USER_TO_SURFACE) &&
+      (matrix_mode < (VG_MATRIX_PATH_USER_TO_SURFACE + ARR_COUNT(state->matrices))));
+   return state->matrices + (matrix_mode - VG_MATRIX_PATH_USER_TO_SURFACE);
+}
+
+static INLINE bool is_matrix_affine(VGMatrixMode matrix_mode)
+{
+   return matrix_mode != VG_MATRIX_IMAGE_USER_TO_SURFACE;
+}
+
+static void sync_matrix(VG_CLIENT_STATE_T *state, VGMatrixMode matrix_mode)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_MAT3X3_SYNC_T *matrix_sync = get_matrix_sync(state, matrix_mode);
+   if (!vg_mat3x3_identical(&matrix_sync->server, &matrix_sync->client)) {
+      RPC_CALL2_IN_CTRL(vgLoadMatrix_impl,
+                        thread,
+                        VGLOADMATRIX_ID,
+                        RPC_ENUM(matrix_mode),
+                        &matrix_sync->client,
+                        sizeof(VG_MAT3X3_T));
+      matrix_sync->server = matrix_sync->client;
+   }
+}
+
+/******************************************************************************
+api misc
+******************************************************************************/
+
+VG_API_CALL VGErrorCode VG_API_ENTRY vgGetError(void) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return VG_NO_CONTEXT_ERROR;
+   }
+
+   return get_error();
+}
+
+VG_API_CALL void VG_API_ENTRY vgFlush(void) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   RPC_CALL0(vgFlush_impl,
+             thread,
+             VGFLUSH_ID);
+   RPC_FLUSH(thread);
+
+#ifdef KHRN_COMMAND_MODE_DISPLAY
+   {
+      //Check for single buffered windows surface in which case call surface updater
+      EGL_SURFACE_T *surface = CLIENT_GET_THREAD_STATE()->openvg.draw;
+      if (surface->type == WINDOW && surface->buffers==1) {
+         platform_surface_update(surface->internal_handle);
+      }
+   }
+#endif
+
+   if (state->flush_callback)
+      state->flush_callback(false);
+}
+
+VG_API_CALL void VG_API_ENTRY vgFinish(void) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   (void)RPC_UINT_RES(RPC_CALL0_RES(vgFinish_impl,
+                                    thread,
+                                    VGFINISH_ID)); /* return value ignored -- read performed to ensure blocking */
+
+#ifdef KHRN_COMMAND_MODE_DISPLAY
+   {
+   //Check for single buffered windows surface in which case call surface updater
+      EGL_SURFACE_T *surface = CLIENT_GET_THREAD_STATE()->openvg.draw;
+      if (surface->type == WINDOW && surface->buffers==1) {
+         platform_surface_update(surface->internal_handle);
+      }
+   }
+#endif
+
+   if (state->flush_callback)
+      state->flush_callback(true);
+}
+
+/******************************************************************************
+api get/set
+******************************************************************************/
+
+static void set_iv_server(
+   VGParamType param_type,
+   VGint count,
+   const VGint *values)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   RPC_CALL3_IN_CTRL(vgSetiv_impl,
+                     thread,
+                     VGSETIV_ID,
+                     RPC_ENUM(param_type),
+                     RPC_INT(count),
+                     values,
+                     count * sizeof(VGint));
+}
+
+static void set_fv_server(
+   VGParamType param_type,
+   VGint count,
+   const VGfloat *values)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   RPC_CALL3_IN_CTRL(vgSetfv_impl,
+                     thread,
+                     VGSETFV_ID,
+                     RPC_ENUM(param_type),
+                     RPC_INT(count),
+                     values,
+                     count * sizeof(VGfloat));
+}
+
+static void get_fv_server(
+   VGParamType param_type,
+   VGint count,
+   VGfloat *values)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   RPC_CALL3_OUT_CTRL(vgGetfv_impl,
+                      thread,
+                      VGGETFV_ID,
+                      RPC_ENUM(param_type),
+                      RPC_INT(count),
+                      values);
+}
+
+static void set_parameter_iv_server(
+   VGHandle vg_handle,
+   VG_CLIENT_OBJECT_TYPE_T object_type,
+   VGint param_type,
+   VGint count,
+   const VGint *values)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   RPC_CALL5_IN_CTRL(vgSetParameteriv_impl,
+                     thread,
+                     VGSETPARAMETERIV_ID,
+                     RPC_HANDLE(vg_handle),
+                     RPC_ENUM(object_type),
+                     RPC_INT(param_type),
+                     RPC_INT(count),
+                     values,
+                     count * sizeof(VGint));
+}
+
+static void set_parameter_fv_server(
+   VGHandle vg_handle,
+   VG_CLIENT_OBJECT_TYPE_T object_type,
+   VGint param_type,
+   VGint count,
+   const VGfloat *values)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   RPC_CALL5_IN_CTRL(vgSetParameterfv_impl,
+                     thread,
+                     VGSETPARAMETERFV_ID,
+                     RPC_HANDLE(vg_handle),
+                     RPC_ENUM(object_type),
+                     RPC_INT(param_type),
+                     RPC_INT(count),
+                     values,
+                     count * sizeof(VGfloat));
+}
+
+static bool get_parameter_iv_server(
+   VGHandle vg_handle,
+   VG_CLIENT_OBJECT_TYPE_T object_type,
+   VGint param_type,
+   VGint count,
+   VGint *values)
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   return RPC_BOOLEAN_RES(RPC_CALL5_OUT_CTRL_RES(vgGetParameteriv_impl,
+                                                 thread,
+                                                 VGGETPARAMETERIV_ID,
+                                                 RPC_HANDLE(vg_handle),
+                                                 RPC_ENUM(object_type),
+                                                 RPC_INT(param_type),
+                                                 RPC_INT(count),
+                                                 values));
+}
+
+static void set_ifv(
+   CLIENT_THREAD_STATE_T *thread,
+   VG_CLIENT_STATE_T *state,
+   VGParamType param_type,
+   VGint count,
+   bool are_floats,
+   const void *values)
+{
+   /*
+    * If 'count' is greater than zero, then our caller must have verified
+    * that 'values' is non-NULL.
+    * If 'count' is zero, then 'values' *must not* be dereferenced.
+    * Note that params_to_floats() and params_to_ints() handle a zero 'count'
+    * argument correctly and do not dereference 'values' in this case.
+    * Other functions, e.g. param_to_int() and param_to_float(), require a
+    * check before calling.
+    */
+   VGint value_i = (count == 1) ? param_to_int(are_floats, values, 0) : 0;
+   VGfloat value_f = (count == 1) ? param_to_float(are_floats, values, 0) : 0.0f;
+
+   switch (param_type) {
+   /*
+      settable scalar param types
+   */
+
+   #define CASE(PARAM_TYPE, OK, DO) \
+      case PARAM_TYPE: \
+      { \
+         if ((count != 1) || !(OK)) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; } \
+         DO; \
+         break; \
+      }
+   #define CASE_I_SERVER(PARAM_TYPE, OK, VALUE, FN) CASE(PARAM_TYPE, OK, if (VALUE != FN(value_i)) { VALUE = FN(value_i); set_iv_server(PARAM_TYPE, 1, &value_i); })
+   #define CASE_F_SERVER(PARAM_TYPE, OK, VALUE) CASE(PARAM_TYPE, OK, if (!floats_identical(VALUE, value_f)) { VALUE = value_f; set_fv_server(PARAM_TYPE, 1, &value_f); })
+   CASE(VG_MATRIX_MODE, is_matrix_mode((VGMatrixMode)value_i), state->matrix_mode = (VGMatrixMode)value_i)
+   CASE_I_SERVER(VG_FILL_RULE, is_fill_rule((VGFillRule)value_i), state->fill_rule, (VGFillRule))
+   CASE_I_SERVER(VG_IMAGE_QUALITY, is_image_quality((VGImageQuality)value_i), state->image_quality, (VGImageQuality))
+   CASE_I_SERVER(VG_RENDERING_QUALITY, is_rendering_quality((VGRenderingQuality)value_i), state->rendering_quality, (VGRenderingQuality))
+   CASE_I_SERVER(VG_BLEND_MODE, is_blend_mode((VGBlendMode)value_i), state->blend_mode, (VGBlendMode))
+   CASE_I_SERVER(VG_IMAGE_MODE, is_image_mode((VGImageMode)value_i), state->image_mode, (VGImageMode))
+   CASE_I_SERVER(VG_COLOR_TRANSFORM, true, state->color_transform, clean_boolean)
+   CASE_F_SERVER(VG_STROKE_LINE_WIDTH, true, state->stroke_line_width)
+   CASE_I_SERVER(VG_STROKE_CAP_STYLE, is_cap_style((VGCapStyle)value_i), state->stroke_cap_style, (VGCapStyle))
+   CASE_I_SERVER(VG_STROKE_JOIN_STYLE, is_join_style((VGJoinStyle)value_i), state->stroke_join_style, (VGJoinStyle))
+   CASE_F_SERVER(VG_STROKE_MITER_LIMIT, true, state->stroke_miter_limit)
+   CASE_F_SERVER(VG_STROKE_DASH_PHASE, true, state->stroke_dash_phase)
+   CASE_I_SERVER(VG_STROKE_DASH_PHASE_RESET, true, state->stroke_dash_phase_reset, clean_boolean)
+   CASE_I_SERVER(VG_MASKING, true, state->masking, clean_boolean)
+   CASE_I_SERVER(VG_SCISSORING, true, state->scissoring, clean_boolean)
+   CASE(VG_PIXEL_LAYOUT, is_pixel_layout((VGPixelLayout)value_i), state->pixel_layout = (VGPixelLayout)value_i)
+   CASE_I_SERVER(VG_FILTER_FORMAT_LINEAR, true, state->filter_format_linear, clean_boolean)
+   CASE_I_SERVER(VG_FILTER_FORMAT_PREMULTIPLIED, true, state->filter_format_pre, clean_boolean)
+   CASE_I_SERVER(VG_FILTER_CHANNEL_MASK, true, state->filter_channel_mask, )
+   #undef CASE_F_SERVER
+   #undef CASE_I_SERVER
+   #undef CASE
+
+   /*
+      read-only scalar param types
+   */
+
+   case VG_SCREEN_LAYOUT:
+   case VG_MAX_SCISSOR_RECTS:
+   case VG_MAX_DASH_COUNT:
+   case VG_MAX_KERNEL_SIZE:
+   case VG_MAX_SEPARABLE_KERNEL_SIZE:
+   case VG_MAX_COLOR_RAMP_STOPS:
+   case VG_MAX_IMAGE_WIDTH:
+   case VG_MAX_IMAGE_HEIGHT:
+   case VG_MAX_IMAGE_PIXELS:
+   case VG_MAX_IMAGE_BYTES:
+   case VG_MAX_FLOAT:
+   case VG_MAX_GAUSSIAN_STD_DEVIATION:
+   {
+      if (count != 1) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); }
+      break;
+   }
+
+   /*
+      vector param types
+   */
+
+   case VG_SCISSOR_RECTS:
+   {
+      if (count & 0x3) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
+      count = _min(count, VG_CONFIG_MAX_SCISSOR_RECTS * 4);
+      if (params_to_ints(
+         state->scissor_rects,
+         are_floats, values, count) ||
+         (state->scissor_rects_count != count)) {
+         state->scissor_rects_count = count;
+         set_iv_server(VG_SCISSOR_RECTS, count, state->scissor_rects);
+      }
+      break;
+   }
+   case VG_COLOR_TRANSFORM_VALUES:
+   {
+      if (count != 8) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
+      if (params_to_floats(
+         state->color_transform_values,
+         are_floats, values, count)) {
+         set_fv_server(VG_COLOR_TRANSFORM_VALUES, 8, state->color_transform_values);
+      }
+      break;
+   }
+   case VG_STROKE_DASH_PATTERN:
+   {
+      count = _min(count, VG_CONFIG_MAX_DASH_COUNT);
+      if (params_to_floats(
+         state->stroke_dash_pattern,
+         are_floats, values, count) ||
+         (state->stroke_dash_pattern_count != count)) {
+         state->stroke_dash_pattern_count = count;
+         set_fv_server(VG_STROKE_DASH_PATTERN, count, state->stroke_dash_pattern);
+      }
+      break;
+   }
+   case VG_TILE_FILL_COLOR:
+   case VG_CLEAR_COLOR:
+   {
+      VGfloat *color;
+      if (count != 4) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
+      color = (param_type == VG_TILE_FILL_COLOR) ? state->tile_fill_color : state->clear_color;
+      if (params_to_floats(
+         color,
+         are_floats, values, count)) {
+         VGint rgba = color_floats_to_rgba_clean(color);
+         set_iv_server(param_type, 1, &rgba);
+      }
+      break;
+   }
+   case VG_GLYPH_ORIGIN:
+   {
+      /*
+         don't store on client as it can change
+      */
+
+      VGfloat glyph_origin[2];
+      if (count != 2) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
+      (void)params_to_floats(
+         glyph_origin,
+         are_floats, values, count); /* ignore return -- it doesn't mean anything in this case */
+      set_fv_server(VG_GLYPH_ORIGIN, 2, glyph_origin);
+      break;
+   }
+
+   /*
+      invalid param type
+   */
+
+   default:
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+   }
+}
+
+static void get_ifv(
+   CLIENT_THREAD_STATE_T *thread,
+   VG_CLIENT_STATE_T *state,
+   VGParamType param_type,
+   VGint count,
+   bool are_floats,
+   void *values)
+{
+   switch (param_type) {
+   /*
+      scalar param types
+   */
+
+   #define CASE(PARAM_TYPE, FN, VALUE) \
+      case PARAM_TYPE: \
+      { \
+         if (count > 1) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; } \
+         FN(are_floats, values, 0, VALUE); \
+         break; \
+      }
+   #define CASE_I(PARAM_TYPE, VALUE) CASE(PARAM_TYPE, int_to_param, VALUE)
+   #define CASE_F(PARAM_TYPE, VALUE) CASE(PARAM_TYPE, float_to_param, VALUE)
+   CASE_I(VG_MATRIX_MODE, state->matrix_mode)
+   CASE_I(VG_FILL_RULE, state->fill_rule)
+   CASE_I(VG_IMAGE_QUALITY, state->image_quality)
+   CASE_I(VG_RENDERING_QUALITY, state->rendering_quality)
+   CASE_I(VG_BLEND_MODE, state->blend_mode)
+   CASE_I(VG_IMAGE_MODE, state->image_mode)
+   CASE_I(VG_COLOR_TRANSFORM, state->color_transform)
+   CASE_F(VG_STROKE_LINE_WIDTH, state->stroke_line_width)
+   CASE_I(VG_STROKE_CAP_STYLE, state->stroke_cap_style)
+   CASE_I(VG_STROKE_JOIN_STYLE, state->stroke_join_style)
+   CASE_F(VG_STROKE_MITER_LIMIT, state->stroke_miter_limit)
+   CASE_F(VG_STROKE_DASH_PHASE, state->stroke_dash_phase)
+   CASE_I(VG_STROKE_DASH_PHASE_RESET, state->stroke_dash_phase_reset)
+   CASE_I(VG_MASKING, state->masking)
+   CASE_I(VG_SCISSORING, state->scissoring)
+   CASE_I(VG_PIXEL_LAYOUT, state->pixel_layout)
+   CASE_I(VG_SCREEN_LAYOUT, VG_CONFIG_SCREEN_LAYOUT)
+   CASE_I(VG_FILTER_FORMAT_LINEAR, state->filter_format_linear)
+   CASE_I(VG_FILTER_FORMAT_PREMULTIPLIED, state->filter_format_pre)
+   CASE_I(VG_FILTER_CHANNEL_MASK, state->filter_channel_mask)
+   CASE_I(VG_MAX_SCISSOR_RECTS, VG_CONFIG_MAX_SCISSOR_RECTS)
+   CASE_I(VG_MAX_DASH_COUNT, VG_CONFIG_MAX_DASH_COUNT)
+   CASE_I(VG_MAX_KERNEL_SIZE, VG_CONFIG_MAX_KERNEL_SIZE)
+   CASE_I(VG_MAX_SEPARABLE_KERNEL_SIZE, VG_CONFIG_MAX_SEPARABLE_KERNEL_SIZE)
+   CASE_I(VG_MAX_COLOR_RAMP_STOPS, VG_CONFIG_MAX_COLOR_RAMP_STOPS)
+   CASE_I(VG_MAX_IMAGE_WIDTH, VG_CONFIG_MAX_IMAGE_WIDTH)
+   CASE_I(VG_MAX_IMAGE_HEIGHT, VG_CONFIG_MAX_IMAGE_HEIGHT)
+   CASE_I(VG_MAX_IMAGE_PIXELS, VG_CONFIG_MAX_IMAGE_PIXELS)
+   CASE_I(VG_MAX_IMAGE_BYTES, VG_CONFIG_MAX_IMAGE_BYTES)
+   CASE_F(VG_MAX_FLOAT, VG_CONFIG_MAX_FLOAT)
+   CASE_F(VG_MAX_GAUSSIAN_STD_DEVIATION, VG_CONFIG_MAX_GAUSSIAN_STD_DEVIATION)
+   #undef CASE_F
+   #undef CASE_I
+   #undef CASE
+
+   /*
+      vector param types
+   */
+
+   case VG_SCISSOR_RECTS:
+   {
+      if ((VGuint)count > state->scissor_rects_count) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
+      ints_to_params(
+         are_floats, values, count,
+         state->scissor_rects);
+      break;
+   }
+   case VG_COLOR_TRANSFORM_VALUES:
+   {
+      if (count > 8) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
+      floats_to_params(
+         are_floats, values, count,
+         state->color_transform_values);
+      break;
+   }
+   case VG_STROKE_DASH_PATTERN:
+   {
+      if ((VGuint)count > state->stroke_dash_pattern_count) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
+      floats_to_params(
+         are_floats, values, count,
+         state->stroke_dash_pattern);
+      break;
+   }
+   case VG_TILE_FILL_COLOR:
+   case VG_CLEAR_COLOR:
+   {
+      if (count > 4) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
+      floats_to_params(
+         are_floats, values, count,
+         (param_type == VG_TILE_FILL_COLOR) ? state->tile_fill_color : state->clear_color);
+      break;
+   }
+   case VG_GLYPH_ORIGIN:
+   {
+      VGfloat glyph_origin[2];
+      if (count > 2) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
+      get_fv_server(VG_GLYPH_ORIGIN, 2, glyph_origin);
+      floats_to_params(
+         are_floats, values, count,
+         glyph_origin);
+      break;
+   }
+
+   /*
+      invalid param type
+   */
+
+   default:
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+   }
+}
+
+static void set_parameter_ifv(
+   CLIENT_THREAD_STATE_T *thread,
+   VG_CLIENT_STATE_T *state,
+   VGHandle vg_handle,
+   VGint param_type,
+   VGint count,
+   bool are_floats,
+   const void *values)
+{
+   /*
+    * If 'count' is greater than zero, then our caller must have verified
+    * that 'values' is non-NULL.
+    * If 'count' is zero, then 'values' *must not* be dereferenced.
+    * Note that params_to_floats() and params_to_ints() handle a zero 'count'
+    * argument correctly and do not dereference 'values' in this case.
+    * Other functions, e.g. param_to_int() and param_to_float(), require a
+    * check before calling.
+    */
+   void *object;
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+
+   object = khrn_pointer_map_lookup(&state->shared_state->objects, nice_handle(vg_handle));
+   if (!object) {
+      set_error(VG_BAD_HANDLE_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      return;
+   }
+
+   switch (*(VG_CLIENT_OBJECT_TYPE_T *)object) {
+   case VG_CLIENT_OBJECT_TYPE_PATH:
+   {
+      switch (param_type) {
+      /*
+         read-only scalar param types
+      */
+
+      case VG_PATH_FORMAT:
+      case VG_PATH_DATATYPE:
+      case VG_PATH_SCALE:
+      case VG_PATH_BIAS:
+      case VG_PATH_NUM_SEGMENTS:
+      case VG_PATH_NUM_COORDS:
+      {
+         if (count != 1) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); }
+         break;
+      }
+
+      /*
+         invalid param type
+      */
+
+      default:
+         set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      }
+
+      break;
+   }
+   case VG_CLIENT_OBJECT_TYPE_PAINT:
+   {
+      VG_CLIENT_PAINT_T *paint = (VG_CLIENT_PAINT_T *)object;
+      VGint value_i;
+
+      if (!paint->gradient &&
+         need_paint_gradient(param_type) &&
+         !paint_alloc_gradient(paint)) {
+         set_error(VG_OUT_OF_MEMORY_ERROR);
+         break;
+      }
+
+      value_i = (count == 1) ? param_to_int(are_floats, values, 0) : 0;
+
+      switch (param_type) {
+      /*
+         settable scalar param types
+      */
+
+      #define CASE_I_SERVER(PARAM_TYPE, OK, VALUE, FN) \
+         case PARAM_TYPE: \
+         { \
+            if ((count != 1) || !(OK)) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; } \
+            if (VALUE != FN(value_i)) { \
+               VALUE = FN(value_i); \
+               set_parameter_iv_server(vg_handle, VG_CLIENT_OBJECT_TYPE_PAINT, PARAM_TYPE, 1, &value_i); \
+            } \
+            break; \
+         }
+      CASE_I_SERVER(VG_PAINT_TYPE, is_paint_type((VGPaintType)value_i), paint->type, (VGPaintType))
+      CASE_I_SERVER(VG_PAINT_COLOR_RAMP_SPREAD_MODE, is_color_ramp_spread_mode((VGColorRampSpreadMode)value_i), paint->gradient->ramp_spread_mode, (VGColorRampSpreadMode))
+      CASE_I_SERVER(VG_PAINT_COLOR_RAMP_PREMULTIPLIED, true, paint->gradient->ramp_pre, clean_boolean)
+      CASE_I_SERVER(VG_PAINT_PATTERN_TILING_MODE, is_tiling_mode((VGTilingMode)value_i), paint->pattern_tiling_mode, (VGTilingMode))
+      #undef CASE_I_SERVER
+
+      /*
+         vector param types
+      */
+
+      case VG_PAINT_COLOR:
+      {
+         if (count != 4) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
+         if (params_to_floats(
+            paint->color,
+            are_floats, values, count)) {
+            VGint rgba = color_floats_to_rgba_clean(paint->color);
+            set_parameter_iv_server(vg_handle, VG_CLIENT_OBJECT_TYPE_PAINT, VG_PAINT_COLOR, 1, &rgba);
+         }
+         break;
+      }
+      case VG_PAINT_COLOR_RAMP_STOPS:
+      {
+         if ((count % 5) != 0) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
+         count = _min(count, VG_CONFIG_MAX_COLOR_RAMP_STOPS * 5);
+         if (paint->gradient->ramp_stops_count != count) {
+            VGfloat *ramp_stops = NULL;
+            if (count != 0) {
+               ramp_stops = (VGfloat *)khrn_platform_malloc(count * sizeof(VGfloat), "VG_CLIENT_PAINT_GRADIENT_T.ramp_stops");
+               if (!ramp_stops) {
+                  set_error(VG_OUT_OF_MEMORY_ERROR);
+                  break;
+               }
+            }
+            if (paint->gradient->ramp_stops) {
+               khrn_platform_free(paint->gradient->ramp_stops);
+            }
+            paint->gradient->ramp_stops = ramp_stops;
+         }
+         if (params_to_floats(
+            paint->gradient->ramp_stops,
+            are_floats, values, count) ||
+            (paint->gradient->ramp_stops_count != count)) {
+            paint->gradient->ramp_stops_count = count;
+            set_parameter_fv_server(vg_handle, VG_CLIENT_OBJECT_TYPE_PAINT, VG_PAINT_COLOR_RAMP_STOPS, count, paint->gradient->ramp_stops);
+         }
+         break;
+      }
+      case VG_PAINT_LINEAR_GRADIENT:
+      {
+         if (count != 4) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
+         if (params_to_floats(
+            paint->gradient->linear,
+            are_floats, values, count)) {
+            set_parameter_fv_server(vg_handle, VG_CLIENT_OBJECT_TYPE_PAINT, VG_PAINT_LINEAR_GRADIENT, 4, paint->gradient->linear);
+         }
+         break;
+      }
+      case VG_PAINT_RADIAL_GRADIENT:
+      {
+         if (count != 5) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
+         if (params_to_floats(
+            paint->gradient->radial,
+            are_floats, values, count)) {
+            set_parameter_fv_server(vg_handle, VG_CLIENT_OBJECT_TYPE_PAINT, VG_PAINT_RADIAL_GRADIENT, 5, paint->gradient->radial);
+         }
+         break;
+      }
+
+      /*
+         invalid param type
+      */
+
+      default:
+         set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      }
+
+      break;
+   }
+   case VG_CLIENT_OBJECT_TYPE_IMAGE:
+   {
+      switch (param_type) {
+      /*
+         read-only scalar param types
+      */
+
+      case VG_IMAGE_FORMAT:
+      case VG_IMAGE_WIDTH:
+      case VG_IMAGE_HEIGHT:
+      {
+         if (count != 1) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); }
+         break;
+      }
+
+      /*
+         invalid param type
+      */
+
+      default:
+         set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      }
+
+      break;
+   }
+   case VG_CLIENT_OBJECT_TYPE_MASK_LAYER:
+   {
+      switch (param_type) {
+      /*
+         read-only scalar param types
+      */
+
+      case VG_IMAGE_WIDTH:
+      case VG_IMAGE_HEIGHT:
+      {
+         if (count != 1) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); }
+         break;
+      }
+
+      /*
+         invalid param type
+      */
+
+      default:
+         set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      }
+
+      break;
+   }
+   case VG_CLIENT_OBJECT_TYPE_FONT:
+   {
+      switch (param_type) {
+      /*
+         read-only scalar param types
+      */
+
+      case VG_FONT_NUM_GLYPHS:
+      {
+         if (count != 1) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); }
+         break;
+      }
+
+      /*
+         invalid param type
+      */
+
+      default:
+         set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      }
+
+      break;
+   }
+   default:
+   {
+      UNREACHABLE();
+   }
+   }
+
+   platform_mutex_release(&state->shared_state->mutex);
+}
+
+static void get_parameter_ifv(
+   CLIENT_THREAD_STATE_T *thread,
+   VG_CLIENT_STATE_T *state,
+   VGHandle vg_handle,
+   VGint param_type,
+   VGint count,
+   bool are_floats,
+   void *values)
+{
+   void *object;
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+
+   object = khrn_pointer_map_lookup(&state->shared_state->objects, nice_handle(vg_handle));
+   if (!object) {
+      set_error(VG_BAD_HANDLE_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      return;
+   }
+
+   #define CASE(PARAM_TYPE, FN, VALUE) \
+      case PARAM_TYPE: \
+      { \
+         if (count > 1) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; } \
+         FN(are_floats, values, 0, VALUE); \
+         break; \
+      }
+   #define CASE_I(PARAM_TYPE, VALUE) CASE(PARAM_TYPE, int_to_param, VALUE)
+   #define CASE_F(PARAM_TYPE, VALUE) CASE(PARAM_TYPE, float_to_param, VALUE)
+
+   switch (*(VG_CLIENT_OBJECT_TYPE_T *)object) {
+   case VG_CLIENT_OBJECT_TYPE_PATH:
+   {
+      VG_CLIENT_PATH_T *path = (VG_CLIENT_PATH_T *)object;
+
+      switch (param_type) {
+      /*
+         scalar param types
+      */
+
+      CASE_I(VG_PATH_FORMAT, path->format)
+      CASE_I(VG_PATH_DATATYPE, path->datatype)
+      CASE_F(VG_PATH_SCALE, path->scale)
+      CASE_F(VG_PATH_BIAS, path->bias)
+      case VG_PATH_NUM_SEGMENTS:
+      case VG_PATH_NUM_COORDS:
+      {
+         if (count > 1) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
+         if (need_path_segments(path->caps)) {
+            int_to_param(are_floats, values, 0, (param_type == VG_PATH_NUM_SEGMENTS) ?
+               path->segments.size :
+               get_coords_count((const VGubyte *)path->segments.data, path->segments.size));
+         } else {
+            VGint value;
+            if (get_parameter_iv_server(vg_handle, VG_CLIENT_OBJECT_TYPE_PATH, param_type, 1, &value)) {
+               int_to_param(are_floats, values, 0, value);
+            }
+         }
+         break;
+      }
+
+      /*
+         invalid param type
+      */
+
+      default:
+         set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      }
+
+      break;
+   }
+   case VG_CLIENT_OBJECT_TYPE_PAINT:
+   {
+      VG_CLIENT_PAINT_T *paint = (VG_CLIENT_PAINT_T *)object;
+
+      if (!paint->gradient &&
+         need_paint_gradient(param_type) &&
+         !paint_alloc_gradient(paint)) {
+         set_error(VG_OUT_OF_MEMORY_ERROR);
+         break;
+      }
+
+      switch (param_type) {
+      /*
+         scalar param types
+      */
+
+      CASE_I(VG_PAINT_TYPE, paint->type)
+      CASE_I(VG_PAINT_COLOR_RAMP_SPREAD_MODE, paint->gradient->ramp_spread_mode)
+      CASE_I(VG_PAINT_COLOR_RAMP_PREMULTIPLIED, paint->gradient->ramp_pre)
+      CASE_I(VG_PAINT_PATTERN_TILING_MODE, paint->pattern_tiling_mode)
+
+      /*
+         vector param types
+      */
+
+      case VG_PAINT_COLOR:
+      {
+         if (count > 4) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
+         floats_to_params(
+            are_floats, values, count,
+            paint->color);
+         break;
+      }
+      case VG_PAINT_COLOR_RAMP_STOPS:
+      {
+         if ((VGuint)count > paint->gradient->ramp_stops_count) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
+         floats_to_params(
+            are_floats, values, count,
+            paint->gradient->ramp_stops);
+         break;
+      }
+      case VG_PAINT_LINEAR_GRADIENT:
+      {
+         if (count > 4) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
+         floats_to_params(
+            are_floats, values, count,
+            paint->gradient->linear);
+         break;
+      }
+      case VG_PAINT_RADIAL_GRADIENT:
+      {
+         if (count > 5) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
+         floats_to_params(
+            are_floats, values, count,
+            paint->gradient->radial);
+         break;
+      }
+
+      /*
+         invalid param type
+      */
+
+      default:
+         set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      }
+
+      break;
+   }
+   case VG_CLIENT_OBJECT_TYPE_IMAGE:
+   {
+      VG_CLIENT_IMAGE_T *image = (VG_CLIENT_IMAGE_T *)object;
+
+      switch (param_type) {
+      /*
+         scalar param types
+      */
+
+      CASE_I(VG_IMAGE_FORMAT, image->format)
+      CASE_I(VG_IMAGE_WIDTH, image->width)
+      CASE_I(VG_IMAGE_HEIGHT, image->height)
+
+      /*
+         invalid param type
+      */
+
+      default:
+         set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      }
+
+      break;
+   }
+   case VG_CLIENT_OBJECT_TYPE_MASK_LAYER:
+   {
+      VG_CLIENT_MASK_LAYER_T *mask_layer = (VG_CLIENT_MASK_LAYER_T *)object;
+
+      switch (param_type) {
+      /*
+         scalar param types
+      */
+
+      CASE_I(VG_IMAGE_WIDTH, mask_layer->width)
+      CASE_I(VG_IMAGE_HEIGHT, mask_layer->height)
+
+      /*
+         invalid param type
+      */
+
+      default:
+         set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      }
+
+      break;
+   }
+   case VG_CLIENT_OBJECT_TYPE_FONT:
+   {
+      switch (param_type) {
+      /*
+         scalar param types
+      */
+
+      case VG_FONT_NUM_GLYPHS:
+      {
+         VGint glyphs_count;
+         if (count > 1) { set_error(VG_ILLEGAL_ARGUMENT_ERROR); break; }
+         if (get_parameter_iv_server(vg_handle, VG_CLIENT_OBJECT_TYPE_FONT, VG_FONT_NUM_GLYPHS, 1, &glyphs_count)) {
+            int_to_param(are_floats, values, 0, glyphs_count);
+         }
+         break;
+      }
+
+      /*
+         invalid param type
+      */
+
+      default:
+         set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      }
+
+      break;
+   }
+   default:
+   {
+      UNREACHABLE();
+   }
+   }
+
+   #undef CASE_F
+   #undef CASE_I
+   #undef CASE
+
+   platform_mutex_release(&state->shared_state->mutex);
+}
+
+VG_API_CALL void VG_API_ENTRY vgSetf(
+   VGParamType param_type,
+   VGfloat value) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   if (is_vector_param_type(param_type)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   set_ifv(thread, state, param_type, 1, true, &value);
+}
+
+VG_API_CALL void VG_API_ENTRY vgSeti(
+   VGParamType param_type,
+   VGint value) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   if (is_vector_param_type(param_type)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   set_ifv(thread, state, param_type, 1, false, &value);
+}
+
+VG_API_CALL void VG_API_ENTRY vgSetfv(
+   VGParamType param_type,
+   VGint count,
+   const VGfloat *values) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   /*
+    * Verify the arguments, and report an error if any of the following holds:
+    *   - 'count' is negative
+    *   - 'count' is greater than zero and 'values' is NULL
+    *   - 'values' is non-NULL but not aligned on an float boundary
+    *
+    * If 'count' is zero, then 'values' will not (and must not) be dereferenced
+    * in this function or any of it's descendents.  The OpenVG Specification
+    * Version 1.1, section 5.2 Setting and Querying Context Parameter Values
+    * states:
+    *
+    *   "If the count parameter is 0, the pointer argument is not dereferenced.
+    *    For example, the call vgSet(VG_STROKE_DASH_PATTERN, 0, (void *) 0)
+    *    sets the dash pattern to a zero-length array (which has the effect of
+    *    disabling dashing) without dereferencing the third parameter."
+    *
+    * Automatic checking tools such as Coverity may flag this case ('values'
+    * not verified non-NULL when 'count' is zero) as a potential NULL pointer
+    * dereference. In this case it is not.
+    */
+   if ((count < 0) || ((count > 0) && !values) || (values && !is_aligned_float(values))) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   set_ifv(thread, state, param_type, count, true, values);
+}
+
+VG_API_CALL void VG_API_ENTRY vgSetiv(
+   VGParamType param_type,
+   VGint count,
+   const VGint *values) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   /*
+    * Verify the arguments, and report an error if any of the following holds:
+    *   - 'count' is negative
+    *   - 'count' is greater than zero and 'values' is NULL
+    *   - 'values' is non-NULL but not aligned on an integer boundary
+    *
+    * If 'count' is zero, then 'values' will not (and must not) be dereferenced
+    * in this function or any of it's descendents.  See the comment in vgSetfv()
+    * above for more detail.
+    *
+    * Automatic checking tools such as Coverity may flag this case ('values'
+    * not verified non-NULL when 'count' is zero) as a potential NULL pointer
+    * dereference. In this case it is not.
+    */
+   if ((count < 0) || ((count > 0) && !values) || (values && !is_aligned_int(values))) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   set_ifv(thread, state, param_type, count, false, values);
+}
+
+VG_API_CALL VGfloat VG_API_ENTRY vgGetf(
+   VGParamType param_type) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VGfloat value = 0.0f;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return 0.0f;
+   }
+
+   if (is_vector_param_type(param_type)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return 0.0f;
+   }
+
+   get_ifv(thread, state, param_type, 1, true, &value);
+   return value;
+}
+
+VG_API_CALL VGint VG_API_ENTRY vgGeti(
+   VGParamType param_type) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VGint value = 0;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return 0;
+   }
+
+   if (is_vector_param_type(param_type)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return 0;
+   }
+
+   get_ifv(thread, state, param_type, 1, false, &value);
+   return value;
+}
+
+VG_API_CALL VGint VG_API_ENTRY vgGetVectorSize(
+   VGParamType param_type) VG_API_EXIT
+{
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(CLIENT_GET_THREAD_STATE());
+   if (!state) {
+      return 0;
+   }
+
+   switch (param_type) {
+   /*
+      scalar param types
+   */
+
+   case VG_MATRIX_MODE:
+   case VG_FILL_RULE:
+   case VG_IMAGE_QUALITY:
+   case VG_RENDERING_QUALITY:
+   case VG_BLEND_MODE:
+   case VG_IMAGE_MODE:
+   case VG_COLOR_TRANSFORM:
+   case VG_STROKE_LINE_WIDTH:
+   case VG_STROKE_CAP_STYLE:
+   case VG_STROKE_JOIN_STYLE:
+   case VG_STROKE_MITER_LIMIT:
+   case VG_STROKE_DASH_PHASE:
+   case VG_STROKE_DASH_PHASE_RESET:
+   case VG_MASKING:
+   case VG_SCISSORING:
+   case VG_PIXEL_LAYOUT:
+   case VG_SCREEN_LAYOUT:
+   case VG_FILTER_FORMAT_LINEAR:
+   case VG_FILTER_FORMAT_PREMULTIPLIED:
+   case VG_FILTER_CHANNEL_MASK:
+   case VG_MAX_SCISSOR_RECTS:
+   case VG_MAX_DASH_COUNT:
+   case VG_MAX_KERNEL_SIZE:
+   case VG_MAX_SEPARABLE_KERNEL_SIZE:
+   case VG_MAX_COLOR_RAMP_STOPS:
+   case VG_MAX_IMAGE_WIDTH:
+   case VG_MAX_IMAGE_HEIGHT:
+   case VG_MAX_IMAGE_PIXELS:
+   case VG_MAX_IMAGE_BYTES:
+   case VG_MAX_FLOAT:
+   case VG_MAX_GAUSSIAN_STD_DEVIATION: return 1;
+
+   /*
+      vector param types
+   */
+
+   case VG_SCISSOR_RECTS:          return state->scissor_rects_count;
+   case VG_COLOR_TRANSFORM_VALUES: return 8;
+   case VG_STROKE_DASH_PATTERN:    return state->stroke_dash_pattern_count;
+   case VG_TILE_FILL_COLOR:
+   case VG_CLEAR_COLOR:            return 4;
+   case VG_GLYPH_ORIGIN:           return 2;
+
+   /*
+      invalid param type
+   */
+
+   default: set_error(VG_ILLEGAL_ARGUMENT_ERROR); return 0;
+   }
+}
+
+VG_API_CALL void VG_API_ENTRY vgGetfv(
+   VGParamType param_type,
+   VGint count,
+   VGfloat *values) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   if ((count <= 0) || !values || !is_aligned_float(values)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   get_ifv(thread, state, param_type, count, true, values);
+}
+
+VG_API_CALL void VG_API_ENTRY vgGetiv(
+   VGParamType param_type,
+   VGint count,
+   VGint *values) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   if ((count <= 0) || !values || !is_aligned_int(values)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   get_ifv(thread, state, param_type, count, false, values);
+}
+
+VG_API_CALL void VG_API_ENTRY vgSetParameterf(
+   VGHandle vg_handle,
+   VGint param_type,
+   VGfloat value) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   if (is_vector_object_param_type(param_type)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   set_parameter_ifv(thread, state, vg_handle, param_type, 1, true, &value);
+}
+
+VG_API_CALL void VG_API_ENTRY vgSetParameteri(
+   VGHandle vg_handle,
+   VGint param_type,
+   VGint value) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   if (is_vector_object_param_type(param_type)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   set_parameter_ifv(thread, state, vg_handle, param_type, 1, false, &value);
+}
+
+VG_API_CALL void VG_API_ENTRY vgSetParameterfv(
+   VGHandle vg_handle,
+   VGint param_type,
+   VGint count,
+   const VGfloat *values) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   /*
+    * Verify the arguments, and report an error if any of the following holds:
+    *   - 'count' is negative
+    *   - 'count' is greater than zero and 'values' is NULL
+    *   - 'values' is non-NULL but not aligned on an float boundary
+    *
+    * If 'count' is zero, then 'values' will not (and must not) be dereferenced
+    * in this function or any of it's descendents.  See the comment in vgSetfv()
+    * above for more detail.
+    *
+    * Automatic checking tools such as Coverity may flag this case ('values'
+    * not verified non-NULL when 'count' is zero) as a potential NULL pointer
+    * dereference. In this case it is not.
+    */
+   if ((count < 0) || ((count > 0) && !values) || (values && !is_aligned_float(values))) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   set_parameter_ifv(thread, state, vg_handle, param_type, count, true, values);
+}
+
+VG_API_CALL void VG_API_ENTRY vgSetParameteriv(
+   VGHandle vg_handle,
+   VGint param_type,
+   VGint count,
+   const VGint *values) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   /*
+    * Verify the arguments, and report an error if any of the following holds:
+    *   - 'count' is negative
+    *   - 'count' is greater than zero and 'values' is NULL
+    *   - 'values' is non-NULL but not aligned on an integer boundary
+    *
+    * If 'count' is zero, then 'values' will not (and must not) be dereferenced
+    * in this function or any of it's descendents.  See the comment in vgSetfv()
+    * above for more detail.
+    *
+    * Automatic checking tools such as Coverity may flag this case ('values'
+    * not verified non-NULL when 'count' is zero) as a potential NULL pointer
+    * dereference. In this case it is not.
+    */
+   if ((count < 0) || ((count > 0) && !values) || (values && !is_aligned_int(values))) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   set_parameter_ifv(thread, state, vg_handle, param_type, count, false, values);
+}
+
+VG_API_CALL VGfloat VG_API_ENTRY vgGetParameterf(
+   VGHandle vg_handle,
+   VGint param_type) VG_API_EXIT
+{
+   VGfloat value = 0.0f;
+
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return 0.0f;
+   }
+
+   if (is_vector_object_param_type(param_type)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return 0.0f;
+   }
+
+   get_parameter_ifv(thread, state, vg_handle, param_type, 1, true, &value);
+   return value;
+}
+
+VG_API_CALL VGint VG_API_ENTRY vgGetParameteri(
+   VGHandle vg_handle,
+   VGint param_type) VG_API_EXIT
+{
+   VGint value = 0;
+
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return 0;
+   }
+
+   if (is_vector_object_param_type(param_type)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return 0;
+   }
+
+   get_parameter_ifv(thread, state, vg_handle, param_type, 1, false, &value);
+   return value;
+}
+
+VG_API_CALL VGint VG_API_ENTRY vgGetParameterVectorSize(
+   VGHandle vg_handle,
+   VGint param_type) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   void *object;
+   VGint count = 0;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return 0;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+
+   object = khrn_pointer_map_lookup(&state->shared_state->objects, nice_handle(vg_handle));
+   if (!object) {
+      set_error(VG_BAD_HANDLE_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      return 0;
+   }
+
+   switch (*(VG_CLIENT_OBJECT_TYPE_T *)object) {
+   case VG_CLIENT_OBJECT_TYPE_PATH:
+   {
+      switch (param_type) {
+      /*
+         scalar param types
+      */
+
+      case VG_PATH_FORMAT:
+      case VG_PATH_DATATYPE:
+      case VG_PATH_SCALE:
+      case VG_PATH_BIAS:
+      case VG_PATH_NUM_SEGMENTS:
+      case VG_PATH_NUM_COORDS:
+      {
+         count = 1;
+         break;
+      }
+
+      /*
+         invalid param type
+      */
+
+      default:
+         set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      }
+
+      break;
+   }
+   case VG_CLIENT_OBJECT_TYPE_PAINT:
+   {
+      switch (param_type) {
+      /*
+         scalar param types
+      */
+
+      case VG_PAINT_TYPE:
+      case VG_PAINT_COLOR_RAMP_SPREAD_MODE:
+      case VG_PAINT_COLOR_RAMP_PREMULTIPLIED:
+      case VG_PAINT_PATTERN_TILING_MODE:
+      {
+         count = 1;
+         break;
+      }
+
+      /*
+         vector param types
+      */
+
+      case VG_PAINT_COLOR:
+      {
+         count = 4;
+         break;
+      }
+      case VG_PAINT_COLOR_RAMP_STOPS:
+      {
+         VG_CLIENT_PAINT_T *paint = (VG_CLIENT_PAINT_T *)object;
+         count = paint->gradient ? paint->gradient->ramp_stops_count : 0;
+         break;
+      }
+      case VG_PAINT_LINEAR_GRADIENT:
+      {
+         count = 4;
+         break;
+      }
+      case VG_PAINT_RADIAL_GRADIENT:
+      {
+         count = 5;
+         break;
+      }
+
+      /*
+         invalid param type
+      */
+
+      default:
+         set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      }
+
+      break;
+   }
+   case VG_CLIENT_OBJECT_TYPE_IMAGE:
+   {
+      switch (param_type) {
+      /*
+         scalar param types
+      */
+
+      case VG_IMAGE_FORMAT:
+      case VG_IMAGE_WIDTH:
+      case VG_IMAGE_HEIGHT:
+      {
+         count = 1;
+         break;
+      }
+
+      /*
+         invalid param type
+      */
+
+      default:
+         set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      }
+
+      break;
+   }
+   case VG_CLIENT_OBJECT_TYPE_MASK_LAYER:
+   {
+      switch (param_type) {
+      /*
+         scalar param types
+      */
+
+      case VG_IMAGE_WIDTH:
+      case VG_IMAGE_HEIGHT:
+      {
+         count = 1;
+         break;
+      }
+
+      /*
+         invalid param type
+      */
+
+      default:
+         set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      }
+
+      break;
+   }
+   case VG_CLIENT_OBJECT_TYPE_FONT:
+   {
+      switch (param_type) {
+      /*
+         scalar param types
+      */
+
+      case VG_FONT_NUM_GLYPHS:
+      {
+         count = 1;
+         break;
+      }
+
+      /*
+         invalid param type
+      */
+
+      default:
+         set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      }
+
+      break;
+   }
+   default:
+   {
+      UNREACHABLE();
+   }
+   }
+
+   platform_mutex_release(&state->shared_state->mutex);
+   return count;
+}
+
+VG_API_CALL void VG_API_ENTRY vgGetParameterfv(
+   VGHandle vg_handle,
+   VGint param_type,
+   VGint count,
+   VGfloat *values) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   if ((count <= 0) || !values || !is_aligned_float(values)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   get_parameter_ifv(thread, state, vg_handle, param_type, count, true, values);
+}
+
+VG_API_CALL void VG_API_ENTRY vgGetParameteriv(
+   VGHandle vg_handle,
+   VGint param_type,
+   VGint count,
+   VGint *values) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   if ((count <= 0) || !values || !is_aligned_int(values)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   get_parameter_ifv(thread, state, vg_handle, param_type, count, false, values);
+}
+
+/******************************************************************************
+api matrices
+******************************************************************************/
+
+VG_API_CALL void VG_API_ENTRY vgLoadIdentity(void) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_MAT3X3_SYNC_T *matrix_sync;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   matrix_sync = get_matrix_sync(state, state->matrix_mode);
+   vg_mat3x3_set_identity(&matrix_sync->client);
+}
+
+VG_API_CALL void VG_API_ENTRY vgLoadMatrix(const VGfloat *matrix) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_MAT3X3_SYNC_T *matrix_sync;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   if (!matrix || !is_aligned_float(matrix)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   matrix_sync = get_matrix_sync(state, state->matrix_mode);
+   vg_mat3x3_set_clean(&matrix_sync->client, matrix, is_matrix_affine(state->matrix_mode));
+}
+
+VG_API_CALL void VG_API_ENTRY vgGetMatrix(VGfloat *matrix) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   if (!matrix || !is_aligned_float(matrix)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   vg_mat3x3_get(&get_matrix_sync(state, state->matrix_mode)->client, matrix);
+}
+
+VG_API_CALL void VG_API_ENTRY vgMultMatrix(const VGfloat *matrix) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_MAT3X3_T a;
+   VG_MAT3X3_SYNC_T *matrix_sync;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   if (!matrix || !is_aligned_float(matrix)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   vg_mat3x3_set_clean(&a, matrix, is_matrix_affine(state->matrix_mode));
+
+   matrix_sync = get_matrix_sync(state, state->matrix_mode);
+   vg_mat3x3_postmul(&matrix_sync->client, &a);
+}
+
+VG_API_CALL void VG_API_ENTRY vgTranslate(VGfloat x, VGfloat y) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state;
+   VG_MAT3X3_SYNC_T *matrix_sync;
+
+   x = clean_float(x);
+   y = clean_float(y);
+
+   state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   matrix_sync = get_matrix_sync(state, state->matrix_mode);
+   vg_mat3x3_postmul_translate(&matrix_sync->client, x, y);
+}
+
+VG_API_CALL void VG_API_ENTRY vgScale(VGfloat x, VGfloat y) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state;
+   VG_MAT3X3_SYNC_T *matrix_sync;
+
+   x = clean_float(x);
+   y = clean_float(y);
+
+   state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   matrix_sync = get_matrix_sync(state, state->matrix_mode);
+   vg_mat3x3_postmul_scale(&matrix_sync->client, x, y);
+}
+
+VG_API_CALL void VG_API_ENTRY vgShear(VGfloat x, VGfloat y) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state;
+   VG_MAT3X3_SYNC_T *matrix_sync;
+
+   x = clean_float(x);
+   y = clean_float(y);
+
+   state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   matrix_sync = get_matrix_sync(state, state->matrix_mode);
+   vg_mat3x3_postmul_shear(&matrix_sync->client, x, y);
+}
+
+VG_API_CALL void VG_API_ENTRY vgRotate(VGfloat angle) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state;
+   VG_MAT3X3_SYNC_T *matrix_sync;
+
+   angle = clean_float(angle);
+
+   state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   matrix_sync = get_matrix_sync(state, state->matrix_mode);
+   vg_mat3x3_postmul_rotate(&matrix_sync->client, angle * (PI / 180.0f));
+}
+
+/******************************************************************************
+api mask/clear
+******************************************************************************/
+
+VG_API_CALL void VG_API_ENTRY vgMask(
+   VGHandle vg_handle, /* theoretically image under vg 1.0 */
+   VGMaskOperation operation,
+   VGint dst_x, VGint dst_y,
+   VGint width, VGint height) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return;
+   }
+
+   RPC_CALL6(vgMask_impl,
+             thread,
+             VGMASK_ID,
+             RPC_HANDLE(vg_handle),
+             RPC_ENUM(operation),
+             RPC_INT(dst_x),
+             RPC_INT(dst_y),
+             RPC_INT(width),
+             RPC_INT(height));
+}
+
+VG_API_CALL void VG_API_ENTRY vgRenderToMask(
+   VGPath vg_handle,
+   VGbitfield paint_modes,
+   VGMaskOperation operation) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state;
+
+#ifdef VG_NO_STROKING
+   paint_modes &= ~VG_STROKE_PATH;
+   if (!paint_modes) { return; }
+#endif
+
+   state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   sync_matrix(state, VG_MATRIX_PATH_USER_TO_SURFACE);
+
+   RPC_CALL3(vgRenderToMask_impl,
+             thread,
+             VGRENDERTOMASK_ID,
+             RPC_HANDLE(vg_handle),
+             RPC_BITFIELD(paint_modes),
+             RPC_ENUM(operation));
+}
+
+VG_API_CALL VGMaskLayer VG_API_ENTRY vgCreateMaskLayer(
+   VGint width, VGint height) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VGHandle vg_handle;
+   VG_CLIENT_MASK_LAYER_T *mask_layer;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return VG_INVALID_HANDLE;
+   }
+
+   if ((width <= 0) || (height <= 0) ||
+      (width > VG_CONFIG_MAX_IMAGE_WIDTH) || (height > VG_CONFIG_MAX_IMAGE_HEIGHT) ||
+      ((width * height) > VG_CONFIG_MAX_IMAGE_PIXELS)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+
+   if (egl_config_get_mask_format(egl_config_to_id(
+      CLIENT_GET_THREAD_STATE()->openvg.draw->config)) == IMAGE_FORMAT_INVALID) {
+      return VG_INVALID_HANDLE;
+   }
+
+   vg_handle = get_stem(state);
+   if (vg_handle == VG_INVALID_HANDLE) {
+      set_error(VG_OUT_OF_MEMORY_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+
+   mask_layer = mask_layer_alloc(width, height);
+   if (!mask_layer) {
+      set_error(VG_OUT_OF_MEMORY_ERROR);
+      destroy_stem(vg_handle);
+      return VG_INVALID_HANDLE;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   if (!insert_object(state, vg_handle, mask_layer)) {
+      set_error(VG_OUT_OF_MEMORY_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      mask_layer_free(mask_layer);
+      destroy_stem(vg_handle);
+      return VG_INVALID_HANDLE;
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+
+   RPC_CALL3(vgCreateMaskLayer_impl,
+             thread,
+             VGCREATEMASKLAYER_ID,
+             RPC_HANDLE(vg_handle),
+             RPC_INT(width),
+             RPC_INT(height));
+
+   return vg_handle;
+}
+
+VG_API_CALL void VG_API_ENTRY vgDestroyMaskLayer(
+   VGMaskLayer vg_handle) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   delete_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_MASK_LAYER);
+   platform_mutex_release(&state->shared_state->mutex);
+
+   RPC_CALL1(vgDestroyMaskLayer_impl,
+             thread,
+             VGDESTROYMASKLAYER_ID,
+             RPC_HANDLE(vg_handle));
+}
+
+VG_API_CALL void VG_API_ENTRY vgFillMaskLayer(
+   VGMaskLayer vg_handle,
+   VGint x, VGint y,
+   VGint width, VGint height,
+   VGfloat value) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   value = clean_float(value);
+
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return;
+   }
+
+   RPC_CALL6(vgFillMaskLayer_impl,
+             thread,
+             VGFILLMASKLAYER_ID,
+             RPC_HANDLE(vg_handle),
+             RPC_INT(x), RPC_INT(y),
+             RPC_INT(width), RPC_INT(height),
+             RPC_FLOAT(value));
+}
+
+VG_API_CALL void VG_API_ENTRY vgCopyMask(
+   VGMaskLayer dst_vg_handle,
+   VGint dst_x, VGint dst_y,
+   VGint src_x, VGint src_y,
+   VGint width, VGint height) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return;
+   }
+
+   RPC_CALL7(vgCopyMask_impl,
+             thread,
+             VGCOPYMASK_ID,
+             RPC_HANDLE(dst_vg_handle),
+             RPC_INT(dst_x), RPC_INT(dst_y),
+             RPC_INT(src_x), RPC_INT(src_y),
+             RPC_INT(width), RPC_INT(height));
+}
+
+VG_API_CALL void VG_API_ENTRY vgClear(
+   VGint x, VGint y,
+   VGint width, VGint height) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   //TODO: pixmap behaviour can be better optimized to handle clears
+   if (state->render_callback)
+      state->render_callback();
+
+   RPC_CALL4(vgClear_impl,
+             thread,
+             VGCLEAR_ID,
+             RPC_INT(x),
+             RPC_INT(y),
+             RPC_INT(width),
+             RPC_INT(height));
+}
+
+/******************************************************************************
+api path
+******************************************************************************/
+
+VG_API_CALL VGPath VG_API_ENTRY vgCreatePath(
+   VGint format,
+   VGPathDatatype datatype,
+   VGfloat scale, VGfloat bias,
+   VGint segments_capacity,
+   VGint coords_capacity,
+   VGbitfield caps) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state;
+   VGHandle vg_handle;
+   VG_CLIENT_PATH_T *path;
+
+   scale = clean_float(scale);
+   bias = clean_float(bias);
+   caps &= VG_PATH_CAPABILITY_ALL;
+
+   state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return VG_INVALID_HANDLE;
+   }
+
+   if (!is_path_format(format)) {
+      set_error(VG_UNSUPPORTED_PATH_FORMAT_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+   if (!is_path_datatype(datatype) || is_zero(scale)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+
+   vg_handle = get_stem(state);
+   if (vg_handle == VG_INVALID_HANDLE) {
+      set_error(VG_OUT_OF_MEMORY_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+
+   path = path_alloc(format, datatype, scale, bias, caps, segments_capacity);
+   if (!path) {
+      set_error(VG_OUT_OF_MEMORY_ERROR);
+      destroy_stem(vg_handle);
+      return VG_INVALID_HANDLE;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   if (!insert_object(state, vg_handle, path)) {
+      set_error(VG_OUT_OF_MEMORY_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      path_free(path);
+      destroy_stem(vg_handle);
+      return VG_INVALID_HANDLE;
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+
+   RPC_CALL8(vgCreatePath_impl,
+             thread,
+             VGCREATEPATH_ID,
+             RPC_HANDLE(vg_handle),
+             RPC_INT(format),
+             RPC_ENUM(datatype),
+             RPC_FLOAT(scale), RPC_FLOAT(bias),
+             RPC_INT(segments_capacity),
+             RPC_INT(coords_capacity),
+             RPC_BITFIELD(caps));
+
+   return vg_handle;
+}
+
+VG_API_CALL void VG_API_ENTRY vgClearPath(
+   VGPath vg_handle,
+   VGbitfield caps) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state;
+   VG_CLIENT_PATH_T *path;
+
+   caps &= VG_PATH_CAPABILITY_ALL;
+
+   state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   path = (VG_CLIENT_PATH_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
+   if (path) {
+      if (need_path_segments(path->caps) && need_path_segments(caps)) {
+         khrn_vector_clear(&path->segments);
+      }
+      path_update_caps(path, caps);
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+
+   RPC_CALL2(vgClearPath_impl,
+             thread,
+             VGCLEARPATH_ID,
+             RPC_HANDLE(vg_handle),
+             RPC_BITFIELD(caps));
+}
+
+VG_API_CALL void VG_API_ENTRY vgDestroyPath(
+   VGPath vg_handle) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   delete_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
+   platform_mutex_release(&state->shared_state->mutex);
+
+   RPC_CALL1(vgDestroyPath_impl,
+             thread,
+             VGDESTROYPATH_ID,
+             RPC_HANDLE(vg_handle));
+}
+
+VG_API_CALL void VG_API_ENTRY vgRemovePathCapabilities(
+   VGPath vg_handle,
+   VGbitfield caps) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_PATH_T *path;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   path = (VG_CLIENT_PATH_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
+   if (path) {
+      path_update_caps(path, path->caps & ~caps);
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+
+   RPC_CALL2(vgRemovePathCapabilities_impl,
+             thread,
+             VGREMOVEPATHCAPABILITIES_ID,
+             RPC_HANDLE(vg_handle),
+             RPC_BITFIELD(caps));
+}
+
+VG_API_CALL VGbitfield VG_API_ENTRY vgGetPathCapabilities(
+   VGPath vg_handle) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VGbitfield caps = 0;
+   VG_CLIENT_PATH_T *path;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return 0;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   path = (VG_CLIENT_PATH_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
+   if (path) {
+      caps = path->caps;
+   } else {
+      set_error(VG_BAD_HANDLE_ERROR);
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+
+   return caps;
+}
+
+VG_API_CALL void VG_API_ENTRY vgAppendPath(
+   VGPath dst_vg_handle,
+   VGPath src_vg_handle) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_PATH_T *dst;
+   VG_CLIENT_PATH_T *src;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   dst = (VG_CLIENT_PATH_T *)lookup_object(state, dst_vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
+   src = (VG_CLIENT_PATH_T *)lookup_object(state, src_vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
+   if (dst && src &&
+      (dst->caps & VG_PATH_CAPABILITY_APPEND_TO) && (src->caps & VG_PATH_CAPABILITY_APPEND_FROM) &&
+      need_path_segments(dst->caps)) {
+      VGuint segments_count = src->segments.size;
+      if (!khrn_vector_extend(&dst->segments, segments_count)) {
+         set_error(VG_OUT_OF_MEMORY_ERROR);
+         platform_mutex_release(&state->shared_state->mutex);
+         return;
+      }
+      memcpy((VGubyte *)dst->segments.data + (dst->segments.size - segments_count), src->segments.data, segments_count);
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+
+   RPC_CALL2(vgAppendPath_impl,
+             thread,
+             VGAPPENDPATH_ID,
+             RPC_HANDLE(dst_vg_handle),
+             RPC_HANDLE(src_vg_handle));
+}
+
+VG_API_CALL void VG_API_ENTRY vgAppendPathData(
+   VGPath vg_handle,
+   VGint segments_count, const VGubyte *segments,
+   const void *coords) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_PATH_T *path;
+   VGPathDatatype datatype;
+   VGuint datatype_size;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+
+   path = (VG_CLIENT_PATH_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
+   if (!path) {
+      set_error(VG_BAD_HANDLE_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      return;
+   }
+
+   datatype = path->datatype;
+
+   if ((segments_count <= 0) || !segments ||
+      contains_illegal_segment(segments, segments_count) ||
+      !coords || !is_aligned_path_datatype(coords, datatype)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      return;
+   }
+
+   if (!(path->caps & VG_PATH_CAPABILITY_APPEND_TO)) {
+      set_error(VG_PATH_CAPABILITY_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      return;
+   }
+
+   if (need_path_segments(path->caps)) {
+      if (!khrn_vector_extend(&path->segments, segments_count)) {
+         set_error(VG_OUT_OF_MEMORY_ERROR);
+         platform_mutex_release(&state->shared_state->mutex);
+         return;
+      }
+      memcpy((VGubyte *)path->segments.data + (path->segments.size - segments_count), segments, segments_count);
+   }
+
+   platform_mutex_release(&state->shared_state->mutex);
+
+   datatype_size = get_path_datatype_size(datatype);
+
+   #ifdef RPC_DIRECT
+      {
+         VGuint coords_count = 0;
+         VGuint i;
+         for (i = 0; i != segments_count; ++i) {
+            coords_count += get_segment_coords_count(segments[i] & ~VG_RELATIVE);
+         }
+
+         RPC_CALL6(vgAppendPathData_impl, thread, no_id, 
+            vg_handle,
+            datatype,
+            segments_count, segments,
+            coords_count * datatype_size, coords);
+      }
+   #else
+      /*
+         split into multiple calls if necessary to avoid overflowing control buffer
+      */
+
+      while (segments_count != 0) {
+         #define MESSAGE_SIZE 20
+
+         VGuint size_max = rpc_send_ctrl_longest(thread, MESSAGE_SIZE + rpc_pad_ctrl(1) + rpc_pad_ctrl(6 * datatype_size)) - MESSAGE_SIZE; /* fit at least one segment */
+         VGint chunk_segments_count = 0;
+         VGuint chunk_coords_size = 0;
+         for (; chunk_segments_count != segments_count; ++chunk_segments_count) {
+            VGuint segment_coords_size = get_segment_coords_count(segments[chunk_segments_count] & ~VG_RELATIVE) * datatype_size;
+            if ((rpc_pad_ctrl(chunk_segments_count + 1) +
+               rpc_pad_ctrl(chunk_coords_size + segment_coords_size)) > size_max) {
+               /*
+                  can't fit this segment in
+               */
+
+               break;
+            }
+            chunk_coords_size += segment_coords_size;
+         }
+
+         {
+            uint32_t message[] = {
+               VGAPPENDPATHDATA_ID,
+               RPC_HANDLE(vg_handle),
+               RPC_ENUM(datatype),
+               RPC_INT(chunk_segments_count),
+               RPC_UINT(chunk_coords_size) };
+            vcos_static_assert(sizeof(message) == MESSAGE_SIZE);
+
+            #undef MESSAGE_SIZE
+            CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+
+            rpc_send_ctrl_begin(thread, sizeof(message) + rpc_pad_ctrl(chunk_segments_count) + rpc_pad_ctrl(chunk_coords_size));
+            rpc_send_ctrl_write(thread, message, sizeof(message));
+            rpc_send_ctrl_write(thread, (uint32_t *)segments, chunk_segments_count);
+            rpc_send_ctrl_write(thread, (uint32_t *)coords, chunk_coords_size);
+            rpc_send_ctrl_end(thread);
+         }
+
+         segments_count -= chunk_segments_count;
+         segments += chunk_segments_count;
+         coords = (const uint8_t *)coords + chunk_coords_size;
+      }
+   #endif
+}
+
+VG_API_CALL void VG_API_ENTRY vgModifyPathCoords(
+   VGPath vg_handle,
+   VGint segments_i, VGint segments_count,
+   const void *coords) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_PATH_T *path;
+   VGPathDatatype datatype;
+   VGuint datatype_size;
+   VGuint coords_offset;
+   VGuint coords_size;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+
+   path = (VG_CLIENT_PATH_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
+   if (!path) {
+      set_error(VG_BAD_HANDLE_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      return;
+   }
+
+   if (!(path->caps & VG_PATH_CAPABILITY_MODIFY)) {
+      set_error(VG_PATH_CAPABILITY_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      return;
+   }
+
+   datatype = path->datatype;
+
+   if ((segments_i < 0) || (segments_count <= 0) ||
+      /* will fit in VGuint (may not fit in VGint) */
+      (((VGuint)(segments_i + segments_count)) > path->segments.size) ||
+      !coords || !is_aligned_path_datatype(coords, datatype)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      return;
+   }
+
+   datatype_size = get_path_datatype_size(path->datatype);
+   coords_offset = get_coords_count((const VGubyte *)path->segments.data, segments_i) * datatype_size;
+   coords_size = get_coords_count((const VGubyte *)path->segments.data + segments_i, segments_count) * datatype_size;
+
+   platform_mutex_release(&state->shared_state->mutex);
+
+   #ifdef RPC_DIRECT
+      RPC_CALL5(vgModifyPathCoords_impl, thread, no_id, 
+         vg_handle,
+         datatype,
+         coords_offset, coords_size, coords);
+   #else
+      /*
+         split into multiple calls if necessary to avoid overflowing control buffer
+      */
+
+      while (coords_size != 0) {
+         #define MESSAGE_SIZE 20
+
+         VGuint chunk_coords_size = _min(coords_size, rpc_send_ctrl_longest(thread, MESSAGE_SIZE + rpc_pad_ctrl(4)) - MESSAGE_SIZE); /* fit at least one coordinate */
+
+         uint32_t message[] = {
+            VGMODIFYPATHCOORDS_ID,
+            RPC_HANDLE(vg_handle),
+            RPC_ENUM(datatype),
+            RPC_UINT(coords_offset),
+            RPC_UINT(chunk_coords_size) };
+         vcos_static_assert(sizeof(message) == MESSAGE_SIZE);
+
+         #undef MESSAGE_SIZE
+
+         rpc_send_ctrl_begin(thread, sizeof(message) + rpc_pad_ctrl(chunk_coords_size));
+         rpc_send_ctrl_write(thread, message, sizeof(message));
+         rpc_send_ctrl_write(thread, (uint32_t *)coords, chunk_coords_size);
+         rpc_send_ctrl_end(thread);
+
+         coords_size -= chunk_coords_size;
+         coords_offset += chunk_coords_size;
+         coords = (const uint8_t *)coords + chunk_coords_size;
+      }
+   #endif
+}
+
+VG_API_CALL void VG_API_ENTRY vgTransformPath(
+   VGPath dst_vg_handle,
+   VGPath src_vg_handle) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_PATH_T *dst;
+   VG_CLIENT_PATH_T *src;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   dst = (VG_CLIENT_PATH_T *)lookup_object(state, dst_vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
+   src = (VG_CLIENT_PATH_T *)lookup_object(state, src_vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
+   if (dst && src &&
+      (dst->caps & VG_PATH_CAPABILITY_TRANSFORM_TO) && (src->caps & VG_PATH_CAPABILITY_TRANSFORM_FROM) &&
+      need_path_segments(dst->caps)) {
+      VGuint segments_count = src->segments.size;
+      if (!khrn_vector_extend(&dst->segments, segments_count)) {
+         set_error(VG_OUT_OF_MEMORY_ERROR);
+         platform_mutex_release(&state->shared_state->mutex);
+         return;
+      }
+      {
+         VGubyte *dst_segments = (VGubyte *)dst->segments.data + (dst->segments.size - segments_count);
+         const VGubyte *src_segments = (const VGubyte *)src->segments.data;
+         for (; segments_count != 0; ++dst_segments, ++src_segments, --segments_count) {
+            VGuint segment = *src_segments;
+            if (((segment & ~VG_RELATIVE) == VG_HLINE_TO) || ((segment & ~VG_RELATIVE) == VG_VLINE_TO)) {
+               segment = VG_LINE_TO | (segment & VG_RELATIVE);
+            }
+
+            /*
+               on the server, we also flip arc types if the determinant of the path
+               user to surface matrix is negative, but we don't actually care about
+               the particular arc type on the client
+            */
+
+            *dst_segments = (VGubyte)segment;
+         }
+      }
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+
+   sync_matrix(state, VG_MATRIX_PATH_USER_TO_SURFACE);
+
+   RPC_CALL2(vgTransformPath_impl,
+             thread,
+             VGTRANSFORMPATH_ID,
+             RPC_HANDLE(dst_vg_handle),
+             RPC_HANDLE(src_vg_handle));
+}
+
+VG_API_CALL VGboolean VG_API_ENTRY vgInterpolatePath(
+   VGPath dst_vg_handle,
+   VGPath begin_vg_handle,
+   VGPath end_vg_handle,
+   VGfloat t) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state;
+   VG_CLIENT_PATH_T *dst;
+   VG_CLIENT_PATH_T *begin;
+   VG_CLIENT_PATH_T *end;
+
+   t = clean_float(t);
+
+   state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return VG_FALSE;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   dst = (VG_CLIENT_PATH_T *)lookup_object(state, dst_vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
+   begin = (VG_CLIENT_PATH_T *)lookup_object(state, begin_vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
+   end = (VG_CLIENT_PATH_T *)lookup_object(state, end_vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
+   if (dst && begin && end &&
+      (dst->caps & VG_PATH_CAPABILITY_INTERPOLATE_TO) && (begin->caps & VG_PATH_CAPABILITY_INTERPOLATE_FROM) && (end->caps & VG_PATH_CAPABILITY_INTERPOLATE_FROM)) {
+      if ((begin->segments.size != end->segments.size) ||
+         !interpolate_segments_compatible((const VGubyte *)begin->segments.data, (const VGubyte *)end->segments.data, begin->segments.size)) {
+         /*
+            incompatible paths. no error -- just return false
+         */
+
+         platform_mutex_release(&state->shared_state->mutex);
+         return VG_FALSE;
+      }
+      if (need_path_segments(dst->caps)) {
+         VGuint segments_count = begin->segments.size;
+         if (!khrn_vector_extend(&dst->segments, segments_count)) {
+            set_error(VG_OUT_OF_MEMORY_ERROR);
+            platform_mutex_release(&state->shared_state->mutex);
+            return VG_FALSE;
+         }
+         {
+            VGubyte *dst_segments = (VGubyte *)dst->segments.data + (dst->segments.size - segments_count);
+            const VGubyte *begin_segments = (const VGubyte *)begin->segments.data;
+            for (; segments_count != 0; ++dst_segments, ++begin_segments, --segments_count) {
+               *dst_segments = (VGubyte)normalise_segment(*begin_segments & ~VG_RELATIVE);
+            }
+         }
+      }
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+
+   RPC_CALL4(vgInterpolatePath_impl,
+             thread,
+             VGINTERPOLATEPATH_ID,
+             RPC_HANDLE(dst_vg_handle),
+             RPC_HANDLE(begin_vg_handle),
+             RPC_HANDLE(end_vg_handle),
+             RPC_FLOAT(t));
+
+   return VG_TRUE;
+}
+
+VG_API_CALL VGfloat VG_API_ENTRY vgPathLength(
+   VGPath vg_handle,
+   VGint segments_i, VGint segments_count) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return 0.0f;
+   }
+
+   return RPC_FLOAT_RES(RPC_CALL3_RES(vgPathLength_impl,
+                                      thread,
+                                      VGPATHLENGTH_ID,
+                                      RPC_HANDLE(vg_handle),
+                                      RPC_INT(segments_i), RPC_INT(segments_count)));
+}
+
+VG_API_CALL void VG_API_ENTRY vgPointAlongPath(
+   VGPath vg_handle,
+   VGint segments_i, VGint segments_count,
+   VGfloat distance,
+   VGfloat *x, VGfloat *y,
+   VGfloat *tangent_x, VGfloat *tangent_y) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VGfloat values[4];
+
+   distance = clean_float(distance);
+
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return;
+   }
+
+   if ((x && !is_aligned_float(x)) || (y && !is_aligned_float(y)) ||
+      (tangent_x && !is_aligned_float(tangent_x)) || (tangent_y && !is_aligned_float(tangent_y))) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   if (RPC_BOOLEAN_RES(RPC_CALL6_OUT_CTRL_RES(vgPointAlongPath_impl,
+                                              thread,
+                                              VGPOINTALONGPATH_ID,
+                                              RPC_HANDLE(vg_handle),
+                                              RPC_INT(segments_i), RPC_INT(segments_count),
+                                              RPC_FLOAT(distance),
+                                              RPC_BITFIELD(((x && y) << 0) | ((tangent_x && tangent_y) << 1)),
+                                              values))) {
+      /*
+         no error occurred on the server side
+      */
+
+      if (x && y) {
+         *x = values[0];
+         *y = values[1];
+      }
+      if (tangent_x && tangent_y) {
+         *tangent_x = values[2];
+         *tangent_y = values[3];
+      }
+   }
+}
+
+VG_API_CALL void VG_API_ENTRY vgPathBounds(
+   VGPath vg_handle,
+   VGfloat *min_x, VGfloat *min_y,
+   VGfloat *width, VGfloat *height) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VGfloat values[4];
+
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return;
+   }
+
+   if (!min_x || !is_aligned_float(min_x) || !min_y || !is_aligned_float(min_y) ||
+      !width || !is_aligned_float(width) || !height || !is_aligned_float(height)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   if (RPC_BOOLEAN_RES(RPC_CALL2_OUT_CTRL_RES(vgPathBounds_impl,
+                                              thread,
+                                              VGPATHBOUNDS_ID,
+                                              RPC_HANDLE(vg_handle),
+                                              values))) {
+      /*
+         no error occurred on the server side
+      */
+
+      *min_x = values[0];
+      *min_y = values[1];
+      *width = values[2];
+      *height = values[3];
+   }
+}
+
+VG_API_CALL void VG_API_ENTRY vgPathTransformedBounds(
+   VGPath vg_handle,
+   VGfloat *min_x, VGfloat *min_y,
+   VGfloat *width, VGfloat *height) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VGfloat values[4];
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   if (!min_x || !is_aligned_float(min_x) || !min_y || !is_aligned_float(min_y) ||
+      !width || !is_aligned_float(width) || !height || !is_aligned_float(height)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   sync_matrix(state, VG_MATRIX_PATH_USER_TO_SURFACE);
+
+   if (RPC_BOOLEAN_RES(RPC_CALL2_OUT_CTRL_RES(vgPathTransformedBounds_impl,
+                                              thread,
+                                              VGPATHTRANSFORMEDBOUNDS_ID,
+                                              RPC_HANDLE(vg_handle),
+                                              values))) {
+      /*
+         no error occurred on the server side
+      */
+
+      *min_x = values[0];
+      *min_y = values[1];
+      *width = values[2];
+      *height = values[3];
+   }
+}
+
+VG_API_CALL void VG_API_ENTRY vgDrawPath(
+   VGPath vg_handle,
+   VGbitfield paint_modes) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state;
+
+#ifdef VG_NO_STROKING
+   paint_modes &= ~VG_STROKE_PATH;
+   if (!paint_modes) { return; }
+#endif
+
+   state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   sync_matrix(state, VG_MATRIX_PATH_USER_TO_SURFACE);
+   if (paint_modes & VG_FILL_PATH) {
+      sync_matrix(state, VG_MATRIX_FILL_PAINT_TO_USER);
+   }
+   if (paint_modes & VG_STROKE_PATH) {
+      sync_matrix(state, VG_MATRIX_STROKE_PAINT_TO_USER);
+   }
+
+   if (state->render_callback)
+      state->render_callback();
+
+   RPC_CALL2(vgDrawPath_impl,
+             thread,
+             VGDRAWPATH_ID,
+             RPC_HANDLE(vg_handle),
+             RPC_BITFIELD(paint_modes));
+}
+
+/******************************************************************************
+api paint
+******************************************************************************/
+
+VG_API_CALL VGPaint VG_API_ENTRY vgCreatePaint(void) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VGHandle vg_handle;
+   VG_CLIENT_PAINT_T *paint;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return VG_INVALID_HANDLE;
+   }
+
+   vg_handle = get_stem(state);
+   if (vg_handle == VG_INVALID_HANDLE) {
+      set_error(VG_OUT_OF_MEMORY_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+
+   paint = paint_alloc();
+   if (!paint) {
+      set_error(VG_OUT_OF_MEMORY_ERROR);
+      destroy_stem(vg_handle);
+      return VG_INVALID_HANDLE;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   if (!insert_object(state, vg_handle, paint)) {
+      set_error(VG_OUT_OF_MEMORY_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      paint_free(paint);
+      destroy_stem(vg_handle);
+      return VG_INVALID_HANDLE;
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+
+   RPC_CALL1(vgCreatePaint_impl,
+             thread,
+             VGCREATEPAINT_ID,
+             RPC_HANDLE(vg_handle));
+
+   return vg_handle;
+}
+
+VG_API_CALL void VG_API_ENTRY vgDestroyPaint(
+   VGPaint vg_handle) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   delete_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PAINT);
+   platform_mutex_release(&state->shared_state->mutex);
+
+   RPC_CALL1(vgDestroyPaint_impl,
+             thread,
+             VGDESTROYPAINT_ID,
+             RPC_HANDLE(vg_handle));
+}
+
+VG_API_CALL void VG_API_ENTRY vgSetPaint(
+   VGPaint vg_handle,
+   VGbitfield paint_modes) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   if (!is_paint_modes(paint_modes)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   if ((vg_handle != VG_INVALID_HANDLE) &&
+      !lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PAINT)) {
+      set_error(VG_BAD_HANDLE_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      return;
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+
+   if (((paint_modes & VG_FILL_PATH) && (state->fill_paint != vg_handle)) ||
+      ((paint_modes & VG_STROKE_PATH) && (state->stroke_paint != vg_handle))) {
+      if (paint_modes & VG_FILL_PATH) {
+         state->fill_paint = vg_handle;
+      }
+      if (paint_modes & VG_STROKE_PATH) {
+         state->stroke_paint = vg_handle;
+      }
+      RPC_CALL2(vgSetPaint_impl,
+                thread,
+                VGSETPAINT_ID,
+                RPC_HANDLE(vg_handle),
+                RPC_BITFIELD(paint_modes));
+   }
+}
+
+VG_API_CALL VGPaint VG_API_ENTRY vgGetPaint(
+   VGPaintMode paint_mode) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return VG_INVALID_HANDLE;
+   }
+
+   if (!is_paint_mode(paint_mode)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+
+   return (paint_mode == VG_FILL_PATH) ? state->fill_paint : state->stroke_paint;
+}
+
+VG_API_CALL void VG_API_ENTRY vgSetColor(
+   VGPaint vg_handle,
+   VGuint rgba) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state;
+   VG_CLIENT_PAINT_T *paint;
+
+   rgba = khrn_color_rgba_flip(rgba);
+
+   state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   paint = (VG_CLIENT_PAINT_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PAINT);
+   if (!paint) {
+      set_error(VG_BAD_HANDLE_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      return;
+   }
+   if (color_floats_to_rgba_clean(paint->color) != rgba) {
+      set_parameter_iv_server(vg_handle, VG_CLIENT_OBJECT_TYPE_PAINT, VG_PAINT_COLOR, 1, (const VGint *)&rgba);
+   }
+   khrn_color_rgba_to_floats(paint->color, rgba);
+   platform_mutex_release(&state->shared_state->mutex);
+}
+
+VG_API_CALL VGuint VG_API_ENTRY vgGetColor(
+   VGPaint vg_handle) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_PAINT_T *paint;
+   VGuint rgba;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return 0;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   paint = (VG_CLIENT_PAINT_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PAINT);
+   if (!paint) {
+      set_error(VG_BAD_HANDLE_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      return 0;
+   }
+   rgba = color_floats_to_rgba_clean(paint->color);
+   platform_mutex_release(&state->shared_state->mutex);
+   return khrn_color_rgba_flip(rgba);
+}
+
+VG_API_CALL void VG_API_ENTRY vgPaintPattern(
+   VGPaint vg_handle,
+   VGImage pattern_vg_handle) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_PAINT_T *paint;
+   VG_CLIENT_IMAGE_T *pattern;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   paint = (VG_CLIENT_PAINT_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PAINT);
+   pattern = (pattern_vg_handle == VG_INVALID_HANDLE) ? NULL : (VG_CLIENT_IMAGE_T *)lookup_object(state, pattern_vg_handle, VG_CLIENT_OBJECT_TYPE_IMAGE);
+   if (!paint || ((pattern_vg_handle != VG_INVALID_HANDLE) && !pattern)) {
+      set_error(VG_BAD_HANDLE_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      return;
+   }
+   if (paint->pattern != pattern_vg_handle) {
+      paint->pattern = pattern_vg_handle;
+#if EGL_BRCM_global_image && EGL_KHR_image
+      if (pattern && (pattern->global_image_id[0] || pattern->global_image_id[1])) {
+         platform_acquire_global_image(pattern->global_image_id[0], pattern->global_image_id[1]);
+      }
+      if (paint->pattern_global_image_id[0] || paint->pattern_global_image_id[1]) {
+         platform_release_global_image(paint->pattern_global_image_id[0], paint->pattern_global_image_id[1]);
+      }
+      paint->pattern_global_image_id[0] = pattern ? pattern->global_image_id[0] : 0;
+      paint->pattern_global_image_id[1] = pattern ? pattern->global_image_id[1] : 0;
+#endif
+      RPC_CALL2(vgPaintPattern_impl,
+                thread,
+                VGPAINTPATTERN_ID,
+                RPC_HANDLE(vg_handle),
+                RPC_HANDLE(pattern_vg_handle));
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+}
+
+/******************************************************************************
+api image
+******************************************************************************/
+
+VG_API_CALL VGImage VG_API_ENTRY vgCreateImage(
+   VGImageFormat format,
+   VGint width, VGint height,
+   VGbitfield allowed_quality) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VGHandle vg_handle;
+   VG_CLIENT_IMAGE_T *image;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return VG_INVALID_HANDLE;
+   }
+
+   if (!is_allowed_quality(allowed_quality) ||
+      (width <= 0) || (height <= 0) ||
+      (width > VG_CONFIG_MAX_IMAGE_WIDTH) || (height > VG_CONFIG_MAX_IMAGE_HEIGHT) ||
+      ((width * height) > VG_CONFIG_MAX_IMAGE_PIXELS)) { /* todo: VG_CONFIG_MAX_IMAGE_BYTES */
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+   if (!is_image_format(format)) {
+      set_error(VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+
+   vg_handle = get_stem(state);
+   if (vg_handle == VG_INVALID_HANDLE) {
+      set_error(VG_OUT_OF_MEMORY_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+
+   image = image_alloc(format, width, height
+#if EGL_BRCM_global_image && EGL_KHR_image
+      , 0, 0
+#endif
+      );
+   if (!image) {
+      set_error(VG_OUT_OF_MEMORY_ERROR);
+      destroy_stem(vg_handle);
+      return VG_INVALID_HANDLE;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   if (!insert_object(state, vg_handle, image)) {
+      set_error(VG_OUT_OF_MEMORY_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      image_free(image);
+      destroy_stem(vg_handle);
+      return VG_INVALID_HANDLE;
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+
+   RPC_CALL5(vgCreateImage_impl,
+             thread,
+             VGCREATEIMAGE_ID,
+             RPC_HANDLE(vg_handle),
+             RPC_ENUM(format),
+             RPC_INT(width), RPC_INT(height),
+             RPC_BITFIELD(allowed_quality));
+
+   return vg_handle;
+}
+
+VG_API_CALL void VG_API_ENTRY vgDestroyImage(
+   VGImage vg_handle) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   delete_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_IMAGE);
+   platform_mutex_release(&state->shared_state->mutex);
+
+   RPC_CALL1(vgDestroyImage_impl,
+             thread,
+             VGDESTROYIMAGE_ID,
+             RPC_HANDLE(vg_handle));
+}
+
+VG_API_CALL void VG_API_ENTRY vgClearImage(
+   VGImage vg_handle,
+   VGint x, VGint y,
+   VGint width, VGint height) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return;
+   }
+
+   RPC_CALL5(vgClearImage_impl,
+             thread,
+             VGCLEARIMAGE_ID,
+             RPC_HANDLE(vg_handle),
+             RPC_INT(x), RPC_INT(y),
+             RPC_INT(width), RPC_INT(height));
+}
+
+VG_API_CALL void VG_API_ENTRY vgImageSubData(
+   VGImage vg_handle,
+   const void *data, VGint data_stride,
+   VGImageFormat data_format,
+   VGint dst_x, VGint dst_y,
+   VGint width, VGint height) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_IMAGE_T *dst;
+   VGint dst_width;
+   VGint dst_height;
+   VGint src_x = 0, src_y = 0;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   if (!is_image_format(data_format)) {
+      set_error(VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
+      return;
+   }
+
+   if (!data || !is_aligned_image_format(data, data_format) ||
+      ((height != 1) && !is_aligned_image_format((void *)(uintptr_t)data_stride, data_format)) ||
+      (width <= 0) || (height <= 0)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+
+   dst = (VG_CLIENT_IMAGE_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_IMAGE);
+   if (!dst) {
+      set_error(VG_BAD_HANDLE_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      return;
+   }
+
+   dst_width = dst->width;
+   dst_height = dst->height;
+
+   platform_mutex_release(&state->shared_state->mutex);
+
+   khrn_clip_rect2(
+      &dst_x, &dst_y, &src_x, &src_y, &width, &height,
+      0, 0, dst_width, dst_height,
+      0, 0, width, height);
+
+   if (width <= 0 || height <= 0) {
+      return;
+   }
+   
+   data = (const VGubyte *)data + (src_y * data_stride);
+
+   #ifdef RPC_DIRECT
+      RPC_CALL11(vgImageSubData_impl, thread, no_id, 
+         vg_handle,
+         dst_width, dst_height,
+         data, data_stride,
+         data_format,
+         src_x,
+         dst_x, dst_y,
+         width, height);
+   #else
+      {
+         VGuint log2_bpp = get_log2_image_format_bpp(data_format);
+         VGuint line_size;
+         VGuint chunk_height_max;
+
+         data = (const VGubyte *)data + ((src_x << log2_bpp) >> 3);
+         src_x = ((src_x << log2_bpp) & 0x7) >> log2_bpp;
+
+         line_size = (((src_x + width) << log2_bpp) + 0x7) >> 3;
+
+         /*
+            split into KHDISPATCH_WORKSPACE_SIZE chunks (or thereabouts)
+         */
+
+         chunk_height_max = (line_size == 0) ? height : (KHDISPATCH_WORKSPACE_SIZE / line_size);
+         vcos_assert((height == 0) || (chunk_height_max != 0));
+
+         while (height != 0) {
+            VGint chunk_height = _min(height, chunk_height_max);
+
+            uint32_t message[] = {
+               VGIMAGESUBDATA_ID,
+               RPC_HANDLE(vg_handle),
+               RPC_INT(dst_width), RPC_INT(dst_height),
+               RPC_UINT(line_size),
+               RPC_ENUM(data_format),
+               RPC_INT(src_x),
+               RPC_INT(dst_x), RPC_INT(dst_y),
+               RPC_INT(width), RPC_INT(chunk_height) };
+
+            rpc_begin(thread);
+            rpc_send_ctrl_begin(thread, sizeof(message));
+            rpc_send_ctrl_write(thread, message, sizeof(message));
+            rpc_send_ctrl_end(thread);
+            rpc_send_bulk_gather(thread, data, line_size, data_stride, chunk_height);
+            data = (const VGubyte *)data + (chunk_height * data_stride);
+            rpc_end(thread);
+
+            height -= chunk_height;
+            dst_y += chunk_height;
+         }
+      }
+   #endif
+}
+
+VG_API_CALL void VG_API_ENTRY vgGetImageSubData(
+   VGImage vg_handle,
+   void *data, VGint data_stride,
+   VGImageFormat data_format,
+   VGint src_x, VGint src_y,
+   VGint width, VGint height) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_IMAGE_T *src;
+   VGint src_width;
+   VGint src_height;
+   VGint dst_x = 0, dst_y = 0;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   if (!is_image_format(data_format)) {
+      set_error(VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
+      return;
+   }
+
+   if (!data || !is_aligned_image_format(data, data_format) ||
+      ((height != 1) && !is_aligned_image_format((void *)(uintptr_t)data_stride, data_format)) ||
+      (width <= 0) || (height <= 0)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+
+   src = (VG_CLIENT_IMAGE_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_IMAGE);
+   if (!src) {
+      set_error(VG_BAD_HANDLE_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      return;
+   }
+
+   src_width = src->width;
+   src_height = src->height;
+
+   platform_mutex_release(&state->shared_state->mutex);
+
+   khrn_clip_rect2(
+      &dst_x, &dst_y, &src_x, &src_y, &width, &height,
+      0, 0, width, height,
+      0, 0, src_width, src_height);
+
+   if (width <= 0 || height <= 0) {
+      return;
+   }
+   
+   data = (VGubyte *)data + (dst_y * data_stride);
+
+   #ifdef RPC_DIRECT
+      RPC_CALL11(vgGetImageSubData_impl, thread, no_id, 
+         vg_handle,
+         src_width, src_height,
+         data, data_stride,
+         data_format,
+         dst_x,
+         src_x, src_y,
+         width, height);
+   #else
+      {
+         VGuint log2_bpp = get_log2_image_format_bpp(data_format);
+         VGuint line_size;
+         VGuint first_mask;
+         VGuint last_mask;
+         VGuint chunk_height_max;
+
+         data = (VGubyte *)data + ((dst_x << log2_bpp) >> 3);
+         dst_x = ((dst_x << log2_bpp) & 0x7) >> log2_bpp;
+
+         line_size = (((dst_x + width) << log2_bpp) + 0x7) >> 3;
+         first_mask = (1 << (dst_x << log2_bpp)) - 1;
+         last_mask = ~((2 << ((((dst_x + width) << log2_bpp) - 1) & 0x7)) - 1) & 0xff;
+
+         /*
+            split into KHDISPATCH_WORKSPACE_SIZE chunks (or thereabouts)
+         */
+
+         chunk_height_max = (line_size == 0) ? height : (KHDISPATCH_WORKSPACE_SIZE / line_size);
+         vcos_assert((height == 0) || (chunk_height_max != 0));
+
+         while (height != 0) {
+            VGint chunk_height = _min(height, chunk_height_max);
+
+            uint32_t message[] = {
+               VGGETIMAGESUBDATA_ID,
+               RPC_HANDLE(vg_handle),
+               RPC_INT(src_width), RPC_INT(src_height),
+               RPC_UINT(line_size),
+               RPC_ENUM(data_format),
+               RPC_INT(dst_x),
+               RPC_INT(src_x), RPC_INT(src_y),
+               RPC_INT(width), RPC_INT(chunk_height) };
+
+            rpc_begin(thread);
+            rpc_send_ctrl_begin(thread, sizeof(message));
+            rpc_send_ctrl_write(thread, message, sizeof(message));
+            rpc_send_ctrl_end(thread);
+            {
+               uint32_t len[] = { 0, data_stride, chunk_height, first_mask, last_mask };
+               rpc_recv(thread, data, len, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_BULK_SCATTER | RPC_RECV_FLAG_LEN));
+               data = (VGubyte *)data + (chunk_height * data_stride);
+               if (len[0] == 0) {  //The command has failed so no data sent back
+                  rpc_end(thread);
+                  break;
+               }
+               vcos_assert(len[0] == line_size);
+            }
+            rpc_end(thread);
+            height -= chunk_height;
+            src_y += chunk_height;
+         }
+      }
+   #endif
+}
+
+VG_API_CALL VGImage VG_API_ENTRY vgChildImage(
+   VGImage parent_vg_handle,
+   VGint x, VGint y,
+   VGint width, VGint height) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_IMAGE_T *parent;
+   VGImageFormat format;
+   VGint parent_width;
+   VGint parent_height;
+#if EGL_BRCM_global_image && EGL_KHR_image
+   VGuint parent_global_image_id_0, parent_global_image_id_1;
+#endif
+   VGHandle vg_handle;
+   VG_CLIENT_IMAGE_T *image;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return VG_INVALID_HANDLE;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+
+   parent = (VG_CLIENT_IMAGE_T *)lookup_object(state, parent_vg_handle, VG_CLIENT_OBJECT_TYPE_IMAGE);
+   if (!parent) {
+      set_error(VG_BAD_HANDLE_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      return VG_INVALID_HANDLE;
+   }
+
+   format = parent->format;
+   parent_width = parent->width;
+   parent_height = parent->height;
+#if EGL_BRCM_global_image && EGL_KHR_image
+   parent_global_image_id_0 = parent->global_image_id[0];
+   parent_global_image_id_1 = parent->global_image_id[1];
+#endif
+
+   platform_mutex_release(&state->shared_state->mutex); /* mustn't hold this mutex when calling get_stem, so release now and acquire again later */
+
+   if ((x < 0) || (y < 0) || (width <= 0) || (height <= 0) ||
+      /* x + width / y + height will fit in VGuint (may not fit in VGint) */
+      (((VGuint)(x + width)) > (VGuint)parent_width) ||
+      (((VGuint)(y + height)) > (VGuint)parent_height)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+
+   vg_handle = get_stem(state);
+   if (vg_handle == VG_INVALID_HANDLE) {
+      set_error(VG_OUT_OF_MEMORY_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+
+   image = image_alloc(format, width, height
+#if EGL_BRCM_global_image && EGL_KHR_image
+      , parent_global_image_id_0, parent_global_image_id_1
+#endif
+      );
+   if (!image) {
+      set_error(VG_OUT_OF_MEMORY_ERROR);
+      destroy_stem(vg_handle);
+      return VG_INVALID_HANDLE;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   if (!insert_object(state, vg_handle, image)) {
+      set_error(VG_OUT_OF_MEMORY_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      image_free(image);
+      destroy_stem(vg_handle);
+      return VG_INVALID_HANDLE;
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+
+   RPC_CALL8(vgChildImage_impl,
+             thread,
+             VGCHILDIMAGE_ID,
+             RPC_HANDLE(vg_handle),
+             RPC_HANDLE(parent_vg_handle),
+             RPC_INT(parent_width), RPC_INT(parent_height),
+             RPC_INT(x), RPC_INT(y),
+             RPC_INT(width), RPC_INT(height));
+
+   return vg_handle;
+}
+
+VG_API_CALL VGImage VG_API_ENTRY vgGetParent(
+   VGImage vg_handle) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return VG_INVALID_HANDLE;
+   }
+
+   return RPC_HANDLE_RES(RPC_CALL1_RES(vgGetParent_impl,
+                                       thread,
+                                       VGGETPARENT_ID,
+                                       RPC_HANDLE(vg_handle)));
+}
+
+VG_API_CALL void VG_API_ENTRY vgCopyImage(
+   VGImage dst_vg_handle, VGint dst_x, VGint dst_y,
+   VGImage src_vg_handle, VGint src_x, VGint src_y,
+   VGint width, VGint height,
+   VGboolean dither) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return;
+   }
+
+   RPC_CALL9(vgCopyImage_impl,
+             thread,
+             VGCOPYIMAGE_ID,
+             RPC_HANDLE(dst_vg_handle), RPC_INT(dst_x), RPC_INT(dst_y),
+             RPC_HANDLE(src_vg_handle), RPC_INT(src_x), RPC_INT(src_y),
+             RPC_INT(width), RPC_INT(height),
+             RPC_BOOLEAN(clean_boolean(dither)));
+}
+
+VG_API_CALL void VG_API_ENTRY vgDrawImage(
+   VGImage vg_handle) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   sync_matrix(state, VG_MATRIX_IMAGE_USER_TO_SURFACE);
+   sync_matrix(state, VG_MATRIX_FILL_PAINT_TO_USER);
+
+   if (state->render_callback)
+      state->render_callback();
+
+   RPC_CALL1(vgDrawImage_impl,
+             thread,
+             VGDRAWIMAGE_ID,
+             RPC_HANDLE(vg_handle));
+}
+
+/******************************************************************************
+api framebuffer
+******************************************************************************/
+
+VG_API_CALL void VG_API_ENTRY vgSetPixels(
+   VGint dst_x, VGint dst_y,
+   VGImage src_vg_handle, VGint src_x, VGint src_y,
+   VGint width, VGint height) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   if (state->render_callback)
+      state->render_callback();
+
+   RPC_CALL7(vgSetPixels_impl,
+             thread,
+             VGSETPIXELS_ID,
+             RPC_INT(dst_x), RPC_INT(dst_y),
+             RPC_HANDLE(src_vg_handle), RPC_INT(src_x), RPC_INT(src_y),
+             RPC_INT(width), RPC_INT(height));
+}
+
+VG_API_CALL void VG_API_ENTRY vgWritePixels(
+   const void *data, VGint data_stride,
+   VGImageFormat data_format,
+   VGint dst_x, VGint dst_y,
+   VGint width, VGint height) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   EGL_SURFACE_T *frame;
+   VGint src_x = 0, src_y = 0;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   if (!is_image_format(data_format)) {
+      set_error(VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
+      return;
+   }
+
+   if (!data || !is_aligned_image_format(data, data_format) ||
+      ((height != 1) && !is_aligned_image_format((void *)(uintptr_t)data_stride, data_format)) ||
+      (width <= 0) || (height <= 0)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   frame = CLIENT_GET_THREAD_STATE()->openvg.draw;
+
+   khrn_clip_rect2(
+      &dst_x, &dst_y, &src_x, &src_y, &width, &height,
+      0, 0, frame->width, frame->height,
+      0, 0, width, height);
+
+   if (width <= 0 || height <= 0) {
+      return;
+   }
+   
+   data = (const VGubyte *)data + (src_y * data_stride);
+
+   if (state->render_callback)
+      state->render_callback();
+
+   #ifdef RPC_DIRECT
+      RPC_CALL8(vgWritePixels_impl, thread, no_id, 
+         data, data_stride,
+         data_format,
+         src_x,
+         dst_x, dst_y,
+         width, height);
+   #else
+      {
+         VGuint log2_bpp = get_log2_image_format_bpp(data_format);
+         VGuint line_size;
+         VGuint chunk_height_max;
+
+         data = (const VGubyte *)data + ((src_x << log2_bpp) >> 3);
+         src_x = ((src_x << log2_bpp) & 0x7) >> log2_bpp;
+
+         line_size = (((src_x + width) << log2_bpp) + 0x7) >> 3;
+
+         /*
+            split into KHDISPATCH_WORKSPACE_SIZE chunks (or thereabouts)
+         */
+
+         chunk_height_max = (line_size == 0) ? height : (KHDISPATCH_WORKSPACE_SIZE / line_size);
+         vcos_assert((height == 0) || (chunk_height_max != 0));
+
+         while (height != 0) {
+            VGint chunk_height = _min(height, chunk_height_max);
+
+            uint32_t message[] = {
+               VGWRITEPIXELS_ID,
+               RPC_UINT(line_size),
+               RPC_ENUM(data_format),
+               RPC_INT(src_x),
+               RPC_INT(dst_x), RPC_INT(dst_y),
+               RPC_INT(width), RPC_INT(chunk_height) };
+
+            rpc_begin(thread);
+            rpc_send_ctrl_begin(thread, sizeof(message));
+            rpc_send_ctrl_write(thread, message, sizeof(message));
+            rpc_send_ctrl_end(thread);
+            rpc_send_bulk_gather(thread, data, line_size, data_stride, chunk_height);
+            data = (const VGubyte *)data + (chunk_height * data_stride);
+            rpc_end(thread);
+
+            height -= chunk_height;
+            dst_y += chunk_height;
+         }
+      }
+   #endif
+}
+
+VG_API_CALL void VG_API_ENTRY vgGetPixels(
+   VGImage dst_vg_handle, VGint dst_x, VGint dst_y,
+   VGint src_x, VGint src_y,
+   VGint width, VGint height) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return;
+   }
+
+   RPC_CALL7(vgGetPixels_impl,
+             thread,
+             VGGETPIXELS_ID,
+             RPC_HANDLE(dst_vg_handle), RPC_INT(dst_x), RPC_INT(dst_y),
+             RPC_INT(src_x), RPC_INT(src_y),
+             RPC_INT(width), RPC_INT(height));
+}
+
+VG_API_CALL void VG_API_ENTRY vgReadPixels(
+   void *data, VGint data_stride,
+   VGImageFormat data_format,
+   VGint src_x, VGint src_y,
+   VGint width, VGint height) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   EGL_SURFACE_T *frame;
+   VGint dst_x = 0, dst_y = 0;
+
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return;
+   }
+
+   if (!is_image_format(data_format)) {
+      set_error(VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
+      return;
+   }
+
+   if (!data || !is_aligned_image_format(data, data_format) ||
+      ((height != 1) && !is_aligned_image_format((void *)(uintptr_t)data_stride, data_format)) ||
+      (width <= 0) || (height <= 0)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   frame = CLIENT_GET_THREAD_STATE()->openvg.draw;
+
+   khrn_clip_rect2(
+      &dst_x, &dst_y, &src_x, &src_y, &width, &height,
+      0, 0, width, height,
+      0, 0, frame->width, frame->height);
+
+   if (width <= 0 || height <= 0) {
+      return;
+   }
+   
+   data = (VGubyte *)data + (dst_y * data_stride);
+
+   #ifdef RPC_DIRECT
+      RPC_CALL8(vgReadPixels_impl, thread, no_id, 
+         data, data_stride,
+         data_format,
+         dst_x,
+         src_x, src_y,
+         width, height);
+   #else
+      {
+         VGuint log2_bpp = get_log2_image_format_bpp(data_format);
+         VGuint line_size;
+         VGuint first_mask;
+         VGuint last_mask;
+         VGuint chunk_height_max;
+
+         data = (VGubyte *)data + ((dst_x << log2_bpp) >> 3);
+         dst_x = ((dst_x << log2_bpp) & 0x7) >> log2_bpp;
+
+         line_size = (((dst_x + width) << log2_bpp) + 0x7) >> 3;
+         first_mask = (1 << (dst_x << log2_bpp)) - 1;
+         last_mask = ~((2 << ((((dst_x + width) << log2_bpp) - 1) & 0x7)) - 1) & 0xff;
+
+         /*
+            split into KHDISPATCH_WORKSPACE_SIZE chunks (or thereabouts)
+         */
+
+         chunk_height_max = (line_size == 0) ? height : (KHDISPATCH_WORKSPACE_SIZE / line_size);
+         vcos_assert((height == 0) || (chunk_height_max != 0));
+
+         while (height != 0) {
+            VGint chunk_height = _min(height, chunk_height_max);
+
+            uint32_t message[] = {
+               VGREADPIXELS_ID,
+               RPC_UINT(line_size),
+               RPC_ENUM(data_format),
+               RPC_INT(dst_x),
+               RPC_INT(src_x), RPC_INT(src_y),
+               RPC_INT(width), RPC_INT(chunk_height) };
+
+#ifndef __SYMBIAN32__
+            rpc_begin(thread);
+#endif
+            rpc_send_ctrl_begin(thread, sizeof(message));
+            rpc_send_ctrl_write(thread, message, sizeof(message));
+            rpc_send_ctrl_end(thread);
+            {
+               uint32_t len[] = { line_size, data_stride, chunk_height, first_mask, last_mask };
+               rpc_recv(thread, data, len, (RPC_RECV_FLAG_T)(RPC_RECV_FLAG_BULK | RPC_RECV_FLAG_BULK_SCATTER));
+               data = (VGubyte *)data + (chunk_height * data_stride);
+            }
+#ifndef __SYMBIAN32__
+            rpc_end(thread);
+#endif
+            height -= chunk_height;
+            src_y += chunk_height;
+         }
+      }
+   #endif
+}
+
+VG_API_CALL void VG_API_ENTRY vgCopyPixels(
+   VGint dst_x, VGint dst_y,
+   VGint src_x, VGint src_y,
+   VGint width, VGint height) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   if (state->render_callback)
+      state->render_callback();
+
+   RPC_CALL6(vgCopyPixels_impl,
+             thread,
+             VGCOPYPIXELS_ID,
+             RPC_INT(dst_x), RPC_INT(dst_y),
+             RPC_INT(src_x), RPC_INT(src_y),
+             RPC_INT(width), RPC_INT(height));
+}
+
+/******************************************************************************
+api fonts
+******************************************************************************/
+
+VG_API_CALL VGFont VG_API_ENTRY vgCreateFont(
+   VGint glyphs_capacity) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VGHandle vg_handle;
+   VG_CLIENT_FONT_T *font;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return VG_INVALID_HANDLE;
+   }
+
+   if (glyphs_capacity < 0) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+
+   vg_handle = get_stem(state);
+   if (vg_handle == VG_INVALID_HANDLE) {
+      set_error(VG_OUT_OF_MEMORY_ERROR);
+      return VG_INVALID_HANDLE;
+   }
+
+   font = font_alloc();
+   if (!font) {
+      set_error(VG_OUT_OF_MEMORY_ERROR);
+      destroy_stem(vg_handle);
+      return VG_INVALID_HANDLE;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   if (!insert_object(state, vg_handle, font)) {
+      set_error(VG_OUT_OF_MEMORY_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      font_free(font);
+      destroy_stem(vg_handle);
+      return VG_INVALID_HANDLE;
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+
+   RPC_CALL2(vgCreateFont_impl,
+             thread,
+             VGCREATEFONT_ID,
+             RPC_HANDLE(vg_handle),
+             RPC_INT(glyphs_capacity));
+
+   return vg_handle;
+}
+
+VG_API_CALL void VG_API_ENTRY vgDestroyFont(
+   VGFont vg_handle) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   delete_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_FONT);
+   platform_mutex_release(&state->shared_state->mutex);
+
+   RPC_CALL1(vgDestroyFont_impl,
+             thread,
+             VGDESTROYFONT_ID,
+             RPC_HANDLE(vg_handle));
+}
+
+VG_API_CALL void VG_API_ENTRY vgSetGlyphToPath(
+   VGFont vg_handle,
+   VGuint glyph_id,
+   VGPath path_vg_handle,
+   VGboolean is_hinted,
+   VGfloat glyph_origin[2],
+   VGfloat escapement[2]) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+#if EGL_BRCM_global_image && EGL_KHR_image
+   VG_CLIENT_FONT_T *font;
+#endif
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   if (!glyph_origin || !is_aligned_float(glyph_origin) ||
+      !escapement || !is_aligned_float(escapement)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+#if EGL_BRCM_global_image && EGL_KHR_image
+   platform_mutex_acquire(&state->shared_state->mutex);
+   font = (VG_CLIENT_FONT_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_FONT);
+   if (font && ((path_vg_handle == VG_INVALID_HANDLE) || lookup_object(state, path_vg_handle, VG_CLIENT_OBJECT_TYPE_PATH))) {
+      khrn_global_image_map_delete(&font->glyph_global_images, glyph_id);
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+#endif
+
+   RPC_CALL8(vgSetGlyphToPath_impl,
+             thread,
+             VGSETGLYPHTOPATH_ID,
+             RPC_HANDLE(vg_handle),
+             RPC_UINT(glyph_id),
+             RPC_HANDLE(path_vg_handle),
+             RPC_BOOLEAN(clean_boolean(is_hinted)),
+             RPC_FLOAT(clean_float(glyph_origin[0])), RPC_FLOAT(clean_float(glyph_origin[1])),
+             RPC_FLOAT(clean_float(escapement[0])), RPC_FLOAT(clean_float(escapement[1])));
+}
+
+VG_API_CALL void VG_API_ENTRY vgSetGlyphToImage(
+   VGFont vg_handle,
+   VGuint glyph_id,
+   VGImage image_vg_handle,
+   VGfloat glyph_origin[2],
+   VGfloat escapement[2]) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+#if EGL_BRCM_global_image && EGL_KHR_image
+   VG_CLIENT_FONT_T *font;
+   VG_CLIENT_IMAGE_T *image;
+#endif
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   if (!glyph_origin || !is_aligned_float(glyph_origin) ||
+      !escapement || !is_aligned_float(escapement)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+#if EGL_BRCM_global_image && EGL_KHR_image
+   platform_mutex_acquire(&state->shared_state->mutex);
+   font = (VG_CLIENT_FONT_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_FONT);
+   image = (image_vg_handle == VG_INVALID_HANDLE) ? NULL : (VG_CLIENT_IMAGE_T *)lookup_object(state, image_vg_handle, VG_CLIENT_OBJECT_TYPE_IMAGE);
+   if (font && ((image_vg_handle == VG_INVALID_HANDLE) || image)) {
+      if (image && (image->global_image_id[0] || image->global_image_id[1])) {
+         if (!khrn_global_image_map_insert(&font->glyph_global_images, glyph_id,
+            image->global_image_id[0] | ((uint64_t)image->global_image_id[1] << 32))) {
+            set_error(VG_OUT_OF_MEMORY_ERROR);
+            platform_mutex_release(&state->shared_state->mutex);
+            return;
+         }
+      } else {
+         khrn_global_image_map_delete(&font->glyph_global_images, glyph_id);
+      }
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+#endif
+
+   RPC_CALL7(vgSetGlyphToImage_impl,
+             thread,
+             VGSETGLYPHTOIMAGE_ID,
+             RPC_HANDLE(vg_handle),
+             RPC_UINT(glyph_id),
+             RPC_HANDLE(image_vg_handle),
+             RPC_FLOAT(clean_float(glyph_origin[0])), RPC_FLOAT(clean_float(glyph_origin[1])),
+             RPC_FLOAT(clean_float(escapement[0])), RPC_FLOAT(clean_float(escapement[1])));
+}
+
+VG_API_CALL void VG_API_ENTRY vgClearGlyph(
+   VGFont vg_handle,
+   VGuint glyph_id) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+#if EGL_BRCM_global_image && EGL_KHR_image
+   VG_CLIENT_FONT_T *font;
+#endif
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+#if EGL_BRCM_global_image && EGL_KHR_image
+   platform_mutex_acquire(&state->shared_state->mutex);
+   font = (VG_CLIENT_FONT_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_FONT);
+   if (font) {
+      khrn_global_image_map_delete(&font->glyph_global_images, glyph_id);
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+#endif
+
+   RPC_CALL2(vgClearGlyph_impl,
+             thread,
+             VGCLEARGLYPH_ID,
+             RPC_HANDLE(vg_handle),
+             RPC_UINT(glyph_id));
+}
+
+VG_API_CALL void VG_API_ENTRY vgDrawGlyph(
+   VGFont vg_handle,
+   VGuint glyph_id,
+   VGbitfield paint_modes,
+   VGboolean allow_autohinting) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state;
+
+#ifdef VG_NO_STROKING
+   paint_modes &= ~VG_STROKE_PATH;
+   if (!paint_modes) { return; }
+#endif
+
+   state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   sync_matrix(state, VG_MATRIX_GLYPH_USER_TO_SURFACE);
+   sync_matrix(state, VG_MATRIX_FILL_PAINT_TO_USER); /* image glyphs will use, so have to send even if paint_modes doesn't have VG_FILL_PATH */
+   if (paint_modes & VG_STROKE_PATH) {
+      sync_matrix(state, VG_MATRIX_STROKE_PAINT_TO_USER);
+   }
+
+   if (state->render_callback)
+      state->render_callback();
+
+   RPC_CALL4(vgDrawGlyph_impl,
+             thread,
+             VGDRAWGLYPH_ID,
+             RPC_HANDLE(vg_handle),
+             RPC_UINT(glyph_id),
+             RPC_BITFIELD(paint_modes),
+             RPC_BOOLEAN(clean_boolean(allow_autohinting)));
+}
+
+VG_API_CALL void VG_API_ENTRY vgDrawGlyphs(
+   VGFont vg_handle,
+   VGint glyphs_count,
+   const VGuint *glyph_ids,
+   const VGfloat *adjustments_x,
+   const VGfloat *adjustments_y,
+   VGbitfield paint_modes,
+   VGboolean allow_autohinting) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state;
+
+#ifdef VG_NO_STROKING
+   paint_modes &= ~VG_STROKE_PATH;
+   if (!paint_modes) { return; }
+#endif
+
+   state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return;
+   }
+
+   if ((glyphs_count <= 0) || !glyph_ids || !is_aligned_uint(glyph_ids) ||
+      (adjustments_x && !is_aligned_float(adjustments_x)) ||
+      (adjustments_y && !is_aligned_float(adjustments_y))) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   sync_matrix(state, VG_MATRIX_GLYPH_USER_TO_SURFACE);
+   sync_matrix(state, VG_MATRIX_FILL_PAINT_TO_USER); /* image glyphs will use, so have to send even if paint_modes doesn't have VG_FILL_PATH */
+   if (paint_modes & VG_STROKE_PATH) {
+      sync_matrix(state, VG_MATRIX_STROKE_PAINT_TO_USER);
+   }
+
+   if (state->render_callback)
+      state->render_callback();
+
+   #ifdef RPC_DIRECT
+      RPC_CALL7(vgDrawGlyphs_impl, thread, no_id, 
+         vg_handle,
+         glyphs_count, glyph_ids,
+         adjustments_x, adjustments_y,
+         paint_modes,
+         clean_boolean(allow_autohinting));
+   #else
+      {
+         /*
+            split into multiple calls if necessary to avoid overflowing control buffer
+
+            todo: if there's an invalid glyph, we're not supposed to draw anything
+            at all. currently, this works on a per-chunk level (ie we will try to
+            draw the glyphs in a chunk iff there are no invalid glyphs in the chunk)
+         */
+
+         VGuint glyph_size = sizeof(VGuint) +
+            (adjustments_x ? sizeof(VGfloat) : 0) +
+            (adjustments_y ? sizeof(VGfloat) : 0);
+
+         while (glyphs_count != 0) {
+            #define MESSAGE_SIZE 24
+
+            /* at least 8 glyphs. this is a hack for the cts -- it checks that we don't draw anything if there's an invalid glyph (see above) */
+            VGint chunk_glyphs_count = _min(glyphs_count, (rpc_send_ctrl_longest(thread, MESSAGE_SIZE + (8 * glyph_size)) - MESSAGE_SIZE) / glyph_size);
+
+            uint32_t message[] = {
+               VGDRAWGLYPHS_ID,
+               RPC_HANDLE(vg_handle),
+               RPC_INT(chunk_glyphs_count),
+               RPC_BITFIELD((!!adjustments_x << 0) | (!!adjustments_y << 1)),
+               RPC_BITFIELD(paint_modes),
+               RPC_BOOLEAN(clean_boolean(allow_autohinting)) };
+            vcos_static_assert(sizeof(message) == MESSAGE_SIZE);
+
+            #undef MESSAGE_SIZE
+
+            rpc_send_ctrl_begin(thread, sizeof(message) + (chunk_glyphs_count * glyph_size));
+            rpc_send_ctrl_write(thread, message, sizeof(message));
+            rpc_send_ctrl_write(thread, (uint32_t *)glyph_ids, chunk_glyphs_count * sizeof(VGuint));
+            if (adjustments_x) { rpc_send_ctrl_write(thread, (uint32_t *)adjustments_x, chunk_glyphs_count * sizeof(VGfloat)); }
+            if (adjustments_y) { rpc_send_ctrl_write(thread, (uint32_t *)adjustments_y, chunk_glyphs_count * sizeof(VGfloat)); }
+            rpc_send_ctrl_end(thread);
+
+            glyphs_count -= chunk_glyphs_count;
+            glyph_ids += chunk_glyphs_count;
+            if (adjustments_x) { adjustments_x += chunk_glyphs_count; }
+            if (adjustments_y) { adjustments_y += chunk_glyphs_count; }
+         }
+      }
+   #endif
+}
+
+/******************************************************************************
+api filters
+******************************************************************************/
+
+VG_API_CALL void VG_API_ENTRY vgColorMatrix(
+   VGImage dst_vg_handle, VGImage src_vg_handle,
+   const VGfloat *matrix) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return;
+   }
+
+   if (!matrix || !is_aligned_float(matrix)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   RPC_CALL3_IN_CTRL(vgColorMatrix_impl,
+                     thread,
+                     VGCOLORMATRIX_ID,
+                     RPC_HANDLE(dst_vg_handle),
+                     RPC_HANDLE(src_vg_handle),
+                     matrix,
+                     20 * sizeof(VGfloat));
+}
+
+VG_API_CALL void VG_API_ENTRY vgConvolve(
+   VGImage dst_vg_handle, VGImage src_vg_handle,
+   VGint kernel_width, VGint kernel_height,
+   VGint shift_x, VGint shift_y,
+   const VGshort *kernel,
+   VGfloat scale, VGfloat bias,
+   VGTilingMode tiling_mode) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   scale = clean_float(scale);
+   bias = clean_float(bias);
+
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return;
+   }
+
+   if ((kernel_width <= 0) || (kernel_height <= 0) ||
+      (kernel_width > VG_CONFIG_MAX_KERNEL_SIZE) || (kernel_height > VG_CONFIG_MAX_KERNEL_SIZE) ||
+      !kernel || !is_aligned_short(kernel)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   RPC_CALL10_IN_CTRL(vgConvolve_impl,
+                      thread,
+                      VGCONVOLVE_ID,
+                      RPC_HANDLE(dst_vg_handle), RPC_HANDLE(src_vg_handle),
+                      RPC_INT(kernel_width), RPC_INT(kernel_height),
+                      RPC_INT(shift_x), RPC_INT(shift_y),
+                      RPC_FLOAT(scale), RPC_FLOAT(bias),
+                      RPC_ENUM(tiling_mode),
+                      kernel,
+                      kernel_width * kernel_height * sizeof(VGshort));
+}
+
+VG_API_CALL void VG_API_ENTRY vgSeparableConvolve(
+   VGImage dst_vg_handle, VGImage src_vg_handle,
+   VGint kernel_width, VGint kernel_height,
+   VGint shift_x, VGint shift_y,
+   const VGshort *kernel_x,
+   const VGshort *kernel_y,
+   VGfloat scale, VGfloat bias,
+   VGTilingMode tiling_mode) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   scale = clean_float(scale);
+   bias = clean_float(bias);
+
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return;
+   }
+
+   if ((kernel_width <= 0) || (kernel_height <= 0) ||
+      (kernel_width > VG_CONFIG_MAX_SEPARABLE_KERNEL_SIZE) || (kernel_height > VG_CONFIG_MAX_SEPARABLE_KERNEL_SIZE) ||
+      !kernel_x || !is_aligned_short(kernel_x) || !kernel_y || !is_aligned_short(kernel_y)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   #ifdef RPC_DIRECT
+      RPC_CALL11(vgSeparableConvolve_impl, thread, no_id, 
+         dst_vg_handle, src_vg_handle,
+         kernel_width, kernel_height,
+         shift_x, shift_y,
+         kernel_x, kernel_y,
+         scale, bias,
+         tiling_mode);
+   #else
+      {
+         uint32_t message[] = {
+            VGSEPARABLECONVOLVE_ID,
+            RPC_HANDLE(dst_vg_handle), RPC_HANDLE(src_vg_handle),
+            RPC_INT(kernel_width), RPC_INT(kernel_height),
+            RPC_INT(shift_x), RPC_INT(shift_y),
+            RPC_FLOAT(scale), RPC_FLOAT(bias),
+            RPC_ENUM(tiling_mode) };
+
+         VGuint kernel_x_size = kernel_width * sizeof(VGshort);
+         VGuint kernel_y_size = kernel_height * sizeof(VGshort);
+
+         rpc_send_ctrl_begin(thread, sizeof(message) + rpc_pad_ctrl(kernel_x_size) + rpc_pad_ctrl(kernel_y_size));
+         rpc_send_ctrl_write(thread, message, sizeof(message));
+         rpc_send_ctrl_write(thread, (uint32_t *)kernel_x, kernel_x_size);
+         rpc_send_ctrl_write(thread, (uint32_t *)kernel_y, kernel_y_size);
+         rpc_send_ctrl_end(thread);
+      }
+   #endif
+}
+
+VG_API_CALL void VG_API_ENTRY vgGaussianBlur(
+   VGImage dst_vg_handle, VGImage src_vg_handle,
+   VGfloat std_dev_x, VGfloat std_dev_y,
+   VGTilingMode tiling_mode) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   std_dev_x = clean_float(std_dev_x);
+   std_dev_y = clean_float(std_dev_y);
+
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return;
+   }
+
+   RPC_CALL5(vgGaussianBlur_impl,
+             thread,
+             VGGAUSSIANBLUR_ID,
+             RPC_HANDLE(dst_vg_handle), RPC_HANDLE(src_vg_handle),
+             RPC_FLOAT(std_dev_x), RPC_FLOAT(std_dev_y),
+             RPC_ENUM(tiling_mode));
+}
+
+VG_API_CALL void VG_API_ENTRY vgLookup(
+   VGImage dst_vg_handle, VGImage src_vg_handle,
+   const VGubyte *red_lut,
+   const VGubyte *green_lut,
+   const VGubyte *blue_lut,
+   const VGubyte *alpha_lut,
+   VGboolean output_linear,
+   VGboolean output_pre) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return;
+   }
+
+   if (!red_lut || !green_lut || !blue_lut || !alpha_lut) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   #ifdef RPC_DIRECT
+      RPC_CALL8(vgLookup_impl, thread, no_id, 
+         dst_vg_handle, src_vg_handle,
+         red_lut, green_lut, blue_lut, alpha_lut,
+         clean_boolean(output_linear),
+         clean_boolean(output_pre));
+   #else
+      {
+         uint32_t message[] = {
+            VGLOOKUP_ID,
+            RPC_HANDLE(dst_vg_handle), RPC_HANDLE(src_vg_handle),
+            RPC_BOOLEAN(clean_boolean(output_linear)),
+            RPC_BOOLEAN(clean_boolean(output_pre)) };
+
+         rpc_send_ctrl_begin(thread, sizeof(message) + 1024);
+         rpc_send_ctrl_write(thread, message, sizeof(message));
+         rpc_send_ctrl_write(thread, (uint32_t *)red_lut, 256);
+         rpc_send_ctrl_write(thread, (uint32_t *)green_lut, 256);
+         rpc_send_ctrl_write(thread, (uint32_t *)blue_lut, 256);
+         rpc_send_ctrl_write(thread, (uint32_t *)alpha_lut, 256);
+         rpc_send_ctrl_end(thread);
+      }
+   #endif
+}
+
+VG_API_CALL void VG_API_ENTRY vgLookupSingle(
+   VGImage dst_vg_handle, VGImage src_vg_handle,
+   const VGuint *lut,
+   VGImageChannel source_channel,
+   VGboolean output_linear,
+   VGboolean output_pre) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return;
+   }
+
+   if (!lut || !is_aligned_uint(lut)) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return;
+   }
+
+   RPC_CALL6_IN_CTRL(vgLookupSingle_impl,
+                     thread,
+                     VGLOOKUPSINGLE_ID,
+                     RPC_HANDLE(dst_vg_handle), RPC_HANDLE(src_vg_handle),
+                     RPC_ENUM(source_channel),
+                     RPC_BOOLEAN(clean_boolean(output_linear)),
+                     RPC_BOOLEAN(clean_boolean(output_pre)),
+                     lut,
+                     256 * sizeof(VGuint));
+}
+
+/******************************************************************************
+api client-side stuff
+******************************************************************************/
+
+VG_API_CALL VGHardwareQueryResult VG_API_ENTRY vgHardwareQuery(
+   VGHardwareQueryType hardware_query_type,
+   VGint setting) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return (VGHardwareQueryResult)0;
+   }
+
+   if (!is_hardware_query_type(hardware_query_type) ||
+      ((hardware_query_type == VG_IMAGE_FORMAT_QUERY) && !is_image_format((VGImageFormat)setting)) ||
+      ((hardware_query_type == VG_PATH_DATATYPE_QUERY) && !is_path_datatype((VGPathDatatype)setting))) {
+      set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+      return (VGHardwareQueryResult)0;
+   }
+
+   return VG_HARDWARE_ACCELERATED;
+}
+
+VG_API_CALL const VGubyte * VG_API_ENTRY vgGetString(VGStringID name) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return NULL;
+   }
+
+   switch (name) {
+   case VG_VENDOR:     return (const VGubyte *)VG_CONFIG_VENDOR;
+   case VG_RENDERER:   return (const VGubyte *)VG_CONFIG_RENDERER;
+   case VG_VERSION:    return (const VGubyte *)"1.1";
+   case VG_EXTENSIONS: return (const VGubyte *)VG_CONFIG_EXTENSIONS;
+   default:            return NULL;
+   }
+}
+
+/******************************************************************************
+api vgu
+******************************************************************************/
+
+static VGUErrorCode get_vgu_error(void)
+{
+   switch (get_error()) {
+   case VG_NO_ERROR:               return VGU_NO_ERROR;
+   case VG_BAD_HANDLE_ERROR:       return VGU_BAD_HANDLE_ERROR;
+   case VG_ILLEGAL_ARGUMENT_ERROR: return VGU_ILLEGAL_ARGUMENT_ERROR;
+   case VG_OUT_OF_MEMORY_ERROR:    return VGU_OUT_OF_MEMORY_ERROR;
+   case VG_PATH_CAPABILITY_ERROR:  return VGU_PATH_CAPABILITY_ERROR;
+   default:                        UNREACHABLE(); return (VGUErrorCode)0;
+   }
+}
+
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguLine(
+   VGPath vg_handle,
+   VGfloat p0_x, VGfloat p0_y,
+   VGfloat p1_x, VGfloat p1_y) VGU_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state;
+   VG_CLIENT_PATH_T *path;
+
+   p0_x = clean_float(p0_x);
+   p0_y = clean_float(p0_y);
+   p1_x = clean_float(p1_x);
+   p1_y = clean_float(p1_y);
+
+   state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return VGU_NO_ERROR;
+   }
+
+   clear_error();
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   path = (VG_CLIENT_PATH_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
+   if (path &&
+      (path->caps & VG_PATH_CAPABILITY_APPEND_TO) &&
+      need_path_segments(path->caps)) {
+      VGubyte *segments;
+      if (!khrn_vector_extend(&path->segments, 2)) {
+         platform_mutex_release(&state->shared_state->mutex);
+         return VGU_OUT_OF_MEMORY_ERROR;
+      }
+      segments = (VGubyte *)path->segments.data + (path->segments.size - 2);
+      segments[0] = VG_MOVE_TO_ABS;
+      segments[1] = VG_LINE_TO_ABS;
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+
+   RPC_CALL5(vguLine_impl,
+             thread,
+             VGULINE_ID,
+             RPC_HANDLE(vg_handle),
+             RPC_FLOAT(p0_x), RPC_FLOAT(p0_y),
+             RPC_FLOAT(p1_x), RPC_FLOAT(p1_y));
+
+   return get_vgu_error();
+}
+
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguPolygon(
+   VGPath vg_handle,
+   const VGfloat *ps, VGint ps_count,
+   VGboolean close) VGU_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_PATH_T *path;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return VGU_NO_ERROR;
+   }
+
+   clear_error();
+
+   if ((ps_count <= 0) || !ps || !is_aligned_float(ps)) {
+      return VGU_ILLEGAL_ARGUMENT_ERROR;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   path = (VG_CLIENT_PATH_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
+   if (path &&
+      (path->caps & VG_PATH_CAPABILITY_APPEND_TO) &&
+      need_path_segments(path->caps)) {
+      VGubyte *segments;
+      VGuint segments_count = ps_count + (close ? 1 : 0);
+      if (!khrn_vector_extend(&path->segments, segments_count)) {
+         platform_mutex_release(&state->shared_state->mutex);
+         return VGU_OUT_OF_MEMORY_ERROR;
+      }
+      segments = (VGubyte *)path->segments.data + (path->segments.size - segments_count);
+      memset(segments, VG_LINE_TO_ABS, segments_count);
+      segments[0] = VG_MOVE_TO_ABS;
+      if (close) { segments[segments_count - 1] = VG_CLOSE_PATH; }
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+
+   #ifdef RPC_DIRECT
+      RPC_CALL5(vguPolygon_impl, thread, no_id, 
+         vg_handle,
+         ps, ps_count,
+         true, clean_boolean(close));
+   #else
+      {
+         /*
+            split into multiple calls if necessary to avoid overflowing control buffer
+         */
+
+         bool first = true;
+         while (ps_count != 0) {
+            #define MESSAGE_SIZE 20
+
+            VGint chunk_ps_count = _min(ps_count, (rpc_send_ctrl_longest(thread, MESSAGE_SIZE + (2 * sizeof(VGfloat))) - MESSAGE_SIZE) / (2 * sizeof(VGfloat))); /* at least one p */
+            bool last = chunk_ps_count == ps_count;
+
+            uint32_t message[] = {
+               VGUPOLYGON_ID,
+               RPC_HANDLE(vg_handle),
+               RPC_INT(chunk_ps_count),
+               RPC_BOOLEAN(first), RPC_BOOLEAN(last && close) };
+            vcos_static_assert(sizeof(message) == MESSAGE_SIZE);
+
+            #undef MESSAGE_SIZE
+
+            rpc_send_ctrl_begin(thread, 
+               sizeof(message) +
+               (chunk_ps_count * 2 * sizeof(VGfloat)));
+            rpc_send_ctrl_write(thread, message, sizeof(message));
+            rpc_send_ctrl_write(thread, (uint32_t *)ps, chunk_ps_count * 2 * sizeof(VGfloat));
+            rpc_send_ctrl_end(thread);
+
+            ps_count -= chunk_ps_count;
+            ps += 2 * chunk_ps_count;
+            first = false;
+         }
+      }
+   #endif
+
+   return get_vgu_error();
+}
+
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguRect(
+   VGPath vg_handle,
+   VGfloat x, VGfloat y,
+   VGfloat width, VGfloat height) VGU_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state;
+   VG_CLIENT_PATH_T *path;
+
+   x = clean_float(x);
+   y = clean_float(y);
+   width = clean_float(width);
+   height = clean_float(height);
+
+   state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return VGU_NO_ERROR;
+   }
+
+   clear_error();
+
+   if (is_le_zero(width) || is_le_zero(height)) {
+      return VGU_ILLEGAL_ARGUMENT_ERROR;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   path = (VG_CLIENT_PATH_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
+   if (path &&
+      (path->caps & VG_PATH_CAPABILITY_APPEND_TO) &&
+      need_path_segments(path->caps)) {
+      VGubyte *segments;
+      if (!khrn_vector_extend(&path->segments, 5)) {
+         platform_mutex_release(&state->shared_state->mutex);
+         return VGU_OUT_OF_MEMORY_ERROR;
+      }
+      segments = (VGubyte *)path->segments.data + (path->segments.size - 5);
+      segments[0] = VG_MOVE_TO_ABS;
+      segments[1] = VG_HLINE_TO_REL;
+      segments[2] = VG_VLINE_TO_REL;
+      segments[3] = VG_HLINE_TO_REL;
+      segments[4] = VG_CLOSE_PATH;
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+
+   RPC_CALL5(vguRect_impl,
+             thread,
+             VGURECT_ID,
+             RPC_HANDLE(vg_handle),
+             RPC_FLOAT(x), RPC_FLOAT(y),
+             RPC_FLOAT(width), RPC_FLOAT(height));
+
+   return get_vgu_error();
+}
+
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguRoundRect(
+   VGPath vg_handle,
+   VGfloat x, VGfloat y,
+   VGfloat width, VGfloat height,
+   VGfloat arc_width, VGfloat arc_height) VGU_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state;
+   VG_CLIENT_PATH_T *path;
+
+   x = clean_float(x);
+   y = clean_float(y);
+   width = clean_float(width);
+   height = clean_float(height);
+   arc_width = clean_float(arc_width);
+   arc_height = clean_float(arc_height);
+
+   state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return VGU_NO_ERROR;
+   }
+
+   clear_error();
+
+   if (is_le_zero(width) || is_le_zero(height)) {
+      return VGU_ILLEGAL_ARGUMENT_ERROR;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   path = (VG_CLIENT_PATH_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
+   if (path &&
+      (path->caps & VG_PATH_CAPABILITY_APPEND_TO) &&
+      need_path_segments(path->caps)) {
+      VGubyte *segments;
+      if (!khrn_vector_extend(&path->segments, 10)) {
+         platform_mutex_release(&state->shared_state->mutex);
+         return VGU_OUT_OF_MEMORY_ERROR;
+      }
+      segments = (VGubyte *)path->segments.data + (path->segments.size - 10);
+      segments[0] = VG_MOVE_TO_ABS;
+      segments[1] = VG_HLINE_TO_REL;
+      segments[2] = VG_SCCWARC_TO_REL;
+      segments[3] = VG_VLINE_TO_REL;
+      segments[4] = VG_SCCWARC_TO_REL;
+      segments[5] = VG_HLINE_TO_REL;
+      segments[6] = VG_SCCWARC_TO_REL;
+      segments[7] = VG_VLINE_TO_REL;
+      segments[8] = VG_SCCWARC_TO_REL;
+      segments[9] = VG_CLOSE_PATH;
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+
+   RPC_CALL7(vguRoundRect_impl,
+             thread,
+             VGUROUNDRECT_ID,
+             RPC_HANDLE(vg_handle),
+             RPC_FLOAT(x), RPC_FLOAT(y),
+             RPC_FLOAT(width), RPC_FLOAT(height),
+             RPC_FLOAT(arc_width), RPC_FLOAT(arc_height));
+
+   return get_vgu_error();
+}
+
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguEllipse(
+   VGPath vg_handle,
+   VGfloat x, VGfloat y,
+   VGfloat width, VGfloat height) VGU_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state;
+   VG_CLIENT_PATH_T *path;
+
+   x = clean_float(x);
+   y = clean_float(y);
+   width = clean_float(width);
+   height = clean_float(height);
+
+   state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return VGU_NO_ERROR;
+   }
+
+   clear_error();
+
+   if (is_le_zero(width) || is_le_zero(height)) {
+      return VGU_ILLEGAL_ARGUMENT_ERROR;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   path = (VG_CLIENT_PATH_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
+   if (path &&
+      (path->caps & VG_PATH_CAPABILITY_APPEND_TO) &&
+      need_path_segments(path->caps)) {
+      VGubyte *segments;
+      if (!khrn_vector_extend(&path->segments, 4)) {
+         platform_mutex_release(&state->shared_state->mutex);
+         return VGU_OUT_OF_MEMORY_ERROR;
+      }
+      segments = (VGubyte *)path->segments.data + (path->segments.size - 4);
+      segments[0] = VG_MOVE_TO_ABS;
+      segments[1] = VG_SCCWARC_TO_REL;
+      segments[2] = VG_SCCWARC_TO_REL;
+      segments[3] = VG_CLOSE_PATH;
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+
+   RPC_CALL5(vguEllipse_impl,
+             thread,
+             VGUELLIPSE_ID,
+             RPC_HANDLE(vg_handle),
+             RPC_FLOAT(x), RPC_FLOAT(y),
+             RPC_FLOAT(width), RPC_FLOAT(height));
+
+   return get_vgu_error();
+}
+
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguArc(
+   VGPath vg_handle,
+   VGfloat x, VGfloat y,
+   VGfloat width, VGfloat height,
+   VGfloat start_angle, VGfloat angle_extent,
+   VGUArcType arc_type) VGU_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_CLIENT_STATE_T *state;
+   VGuint angle_o180;
+   VG_CLIENT_PATH_T *path;
+
+   x = clean_float(x);
+   y = clean_float(y);
+   width = clean_float(width);
+   height = clean_float(height);
+   start_angle = clean_float(start_angle);
+   angle_extent = clean_float(angle_extent);
+
+   state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return VGU_NO_ERROR;
+   }
+
+   clear_error();
+
+   if (is_le_zero(width) || is_le_zero(height) || !is_arc_type(arc_type)) {
+      return VGU_ILLEGAL_ARGUMENT_ERROR;
+   }
+
+   angle_o180 = float_to_int_zero(absf_(angle_extent) * (1.0f / 180.0f));
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   path = (VG_CLIENT_PATH_T *)lookup_object(state, vg_handle, VG_CLIENT_OBJECT_TYPE_PATH);
+   if (path &&
+      (path->caps & VG_PATH_CAPABILITY_APPEND_TO) &&
+      need_path_segments(path->caps)) {
+      VGubyte *segments;
+      VGuint segments_count = 2 + angle_o180;
+      switch (arc_type) {
+      case VGU_ARC_OPEN:  break;
+      case VGU_ARC_CHORD: segments_count += 1; break;
+      case VGU_ARC_PIE:   segments_count += 2; break;
+      default:            UNREACHABLE();
+      }
+      if (!khrn_vector_extend(&path->segments, segments_count)) {
+         platform_mutex_release(&state->shared_state->mutex);
+         return VGU_OUT_OF_MEMORY_ERROR;
+      }
+      segments = (VGubyte *)path->segments.data + (path->segments.size - segments_count);
+      segments[0] = VG_MOVE_TO_ABS;
+      memset(segments + 1, VG_SCCWARC_TO_ABS, segments_count - 1); /* don't care about actual arc type on client */
+      if (arc_type == VGU_ARC_PIE) { segments[segments_count - 2] = VG_LINE_TO_ABS; }
+      if ((arc_type == VGU_ARC_CHORD) || (arc_type == VGU_ARC_PIE)) { segments[segments_count - 1] = VG_CLOSE_PATH; }
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+
+   RPC_CALL9(vguArc_impl,
+             thread,
+             VGUARC_ID,
+             RPC_HANDLE(vg_handle),
+             RPC_FLOAT(x), RPC_FLOAT(y),
+             RPC_FLOAT(width), RPC_FLOAT(height),
+             RPC_FLOAT(start_angle), RPC_FLOAT(angle_extent), RPC_UINT(angle_o180),
+             RPC_ENUM(arc_type));
+
+   return get_vgu_error();
+}
+
+/*
+   based on "Fundamentals of Texture Mapping and Image Warping" by Paul S Heckbert
+*/
+
+static bool warp_square_to_quad(VG_MAT3X3_T *a,
+   VGfloat p0_x, VGfloat p0_y,
+   VGfloat p1_x, VGfloat p1_y,
+   VGfloat p2_x, VGfloat p2_y,
+   VGfloat p3_x, VGfloat p3_y)
+{
+   VGfloat d1_x = p1_x - p3_x;
+   VGfloat d1_y = p1_y - p3_y;
+   VGfloat d2_x = p2_x - p3_x;
+   VGfloat d2_y = p2_y - p3_y;
+
+   VGfloat d = (d1_x * d2_y) - (d1_y * d2_x);
+
+   VGfloat oo_d;
+   VGfloat sum_x;
+   VGfloat sum_y;
+   VGfloat g;
+   VGfloat h;
+
+   if (absf_(d) < EPS) {
+      return false;
+   }
+   oo_d = recip_(d);
+
+   sum_x = (p0_x + p3_x) - (p1_x + p2_x);
+   sum_y = (p0_y + p3_y) - (p1_y + p2_y);
+
+   g = ((sum_x * d2_y) - (sum_y * d2_x)) * oo_d;
+   h = ((d1_x * sum_y) - (d1_y * sum_x)) * oo_d;
+
+   a->m[0][0] = (p1_x - p0_x) + (g * p1_x);
+   a->m[0][1] = (p2_x - p0_x) + (h * p2_x);
+   a->m[0][2] = p0_x;
+
+   a->m[1][0] = (p1_y - p0_y) + (g * p1_y);
+   a->m[1][1] = (p2_y - p0_y) + (h * p2_y);
+   a->m[1][2] = p0_y;
+
+   a->m[2][0] = g;
+   a->m[2][1] = h;
+   a->m[2][2] = 1.0f;
+
+   return true;
+}
+
+static bool warp_quad_to_square(VG_MAT3X3_T *a,
+   VGfloat p0_x, VGfloat p0_y,
+   VGfloat p1_x, VGfloat p1_y,
+   VGfloat p2_x, VGfloat p2_y,
+   VGfloat p3_x, VGfloat p3_y)
+{
+   if (!warp_square_to_quad(a, p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y) ||
+      !vg_mat3x3_is_invertible(a)) {
+      return false;
+   }
+   vg_mat3x3_invert(a);
+   return true;
+}
+
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguComputeWarpQuadToSquare(
+   VGfloat p0_x, VGfloat p0_y,
+   VGfloat p1_x, VGfloat p1_y,
+   VGfloat p2_x, VGfloat p2_y,
+   VGfloat p3_x, VGfloat p3_y,
+   VGfloat *matrix) VGU_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_MAT3X3_T a;
+
+   p0_x = clean_float(p0_x);
+   p0_y = clean_float(p0_y);
+   p1_x = clean_float(p1_x);
+   p1_y = clean_float(p1_y);
+   p2_x = clean_float(p2_x);
+   p2_y = clean_float(p2_y);
+   p3_x = clean_float(p3_x);
+   p3_y = clean_float(p3_y);
+
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return VGU_NO_ERROR;
+   }
+
+   if (!matrix || !is_aligned_float(matrix)) {
+      return VGU_ILLEGAL_ARGUMENT_ERROR;
+   }
+
+   if (!warp_quad_to_square(&a, p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y)) {
+      return VGU_BAD_WARP_ERROR;
+   }
+   vg_mat3x3_get(&a, matrix);
+   return VGU_NO_ERROR;
+}
+
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguComputeWarpSquareToQuad(
+   VGfloat p0_x, VGfloat p0_y,
+   VGfloat p1_x, VGfloat p1_y,
+   VGfloat p2_x, VGfloat p2_y,
+   VGfloat p3_x, VGfloat p3_y,
+   VGfloat *matrix) VGU_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_MAT3X3_T a;
+
+   p0_x = clean_float(p0_x);
+   p0_y = clean_float(p0_y);
+   p1_x = clean_float(p1_x);
+   p1_y = clean_float(p1_y);
+   p2_x = clean_float(p2_x);
+   p2_y = clean_float(p2_y);
+   p3_x = clean_float(p3_x);
+   p3_y = clean_float(p3_y);
+
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return VGU_NO_ERROR;
+   }
+
+   if (!matrix || !is_aligned_float(matrix)) {
+      return VGU_ILLEGAL_ARGUMENT_ERROR;
+   }
+
+   if (!warp_square_to_quad(&a, p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y)) {
+      return VGU_BAD_WARP_ERROR;
+   }
+   vg_mat3x3_get(&a, matrix);
+   return VGU_NO_ERROR;
+}
+
+VGU_API_CALL VGUErrorCode VGU_API_ENTRY vguComputeWarpQuadToQuad(
+   VGfloat p0_x, VGfloat p0_y,
+   VGfloat p1_x, VGfloat p1_y,
+   VGfloat p2_x, VGfloat p2_y,
+   VGfloat p3_x, VGfloat p3_y,
+   VGfloat q0_x, VGfloat q0_y,
+   VGfloat q1_x, VGfloat q1_y,
+   VGfloat q2_x, VGfloat q2_y,
+   VGfloat q3_x, VGfloat q3_y,
+   VGfloat *matrix) VGU_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+   VG_MAT3X3_T a, b;
+
+   p0_x = clean_float(p0_x);
+   p0_y = clean_float(p0_y);
+   p1_x = clean_float(p1_x);
+   p1_y = clean_float(p1_y);
+   p2_x = clean_float(p2_x);
+   p2_y = clean_float(p2_y);
+   p3_x = clean_float(p3_x);
+   p3_y = clean_float(p3_y);
+   q0_x = clean_float(q0_x);
+   q0_y = clean_float(q0_y);
+   q1_x = clean_float(q1_x);
+   q1_y = clean_float(q1_y);
+   q2_x = clean_float(q2_x);
+   q2_y = clean_float(q2_y);
+   q3_x = clean_float(q3_x);
+   q3_y = clean_float(q3_y);
+
+   if (!VG_GET_CLIENT_STATE(thread)) {
+      return VGU_NO_ERROR;
+   }
+
+   if (!matrix || !is_aligned_float(matrix)) {
+      return VGU_ILLEGAL_ARGUMENT_ERROR;
+   }
+
+   if (!warp_square_to_quad(&a, p0_x, p0_y, p1_x, p1_y, p2_x, p2_y, p3_x, p3_y) ||
+      !warp_quad_to_square(&b, q0_x, q0_y, q1_x, q1_y, q2_x, q2_y, q3_x, q3_y)) {
+      return VGU_BAD_WARP_ERROR;
+   }
+   vg_mat3x3_postmul(&a, &b);
+   vg_mat3x3_get(&a, matrix);
+   return VGU_NO_ERROR;
+}
+
+/******************************************************************************
+VG_KHR_EGL_image
+******************************************************************************/
+
+#if VG_KHR_EGL_image
+
+VG_API_CALL VGImage VG_API_ENTRY vgCreateEGLImageTargetKHR(
+   VGeglImageKHR src_egl_handle) VG_API_EXIT
+{
+   CLIENT_THREAD_STATE_T *thread = CLIENT_GET_THREAD_STATE();
+#if EGL_BRCM_global_image
+   VGuint global_image_id[2];
+#endif
+   VGuint format_width_height[3];
+   VGImage vg_handle;
+   VG_CLIENT_IMAGE_T *image;
+
+   VG_CLIENT_STATE_T *state = VG_GET_CLIENT_STATE(thread);
+   if (!state) {
+      return VG_INVALID_HANDLE;
+   }
+
+#if EGL_BRCM_global_image
+   if ((uintptr_t)src_egl_handle & (1 << 31)) {
+      CLIENT_PROCESS_STATE_T *process = CLIENT_GET_PROCESS_STATE();
+      uint64_t id;
+
+      CLIENT_LOCK();
+      id = process->inited ? khrn_global_image_map_lookup(&process->global_image_egl_images, (uint32_t)(uintptr_t)src_egl_handle) : 0;
+      CLIENT_UNLOCK();
+      if (!id) {
+         set_error(VG_ILLEGAL_ARGUMENT_ERROR);
+         return VG_INVALID_HANDLE;
+      }
+      global_image_id[0] = (VGuint)id;
+      global_image_id[1] = (VGuint)(id >> 32);
+
+      platform_get_global_image_info(global_image_id[0], global_image_id[1],
+         format_width_height + 0, format_width_height + 1, format_width_height + 2);
+
+      if (!(format_width_height[0] & EGL_PIXEL_FORMAT_VG_IMAGE_BRCM) ||
+         (format_width_height[1] == 0) || (format_width_height[2] == 0) ||
+         (format_width_height[1] > VG_CONFIG_MAX_IMAGE_WIDTH) || (format_width_height[2] > VG_CONFIG_MAX_IMAGE_HEIGHT)) {
+         set_error(VG_UNSUPPORTED_IMAGE_FORMAT_ERROR);
+         return VG_INVALID_HANDLE;
+      }
+
+      switch (format_width_height[0] & ~EGL_PIXEL_FORMAT_USAGE_MASK_BRCM) {
+      case EGL_PIXEL_FORMAT_ARGB_8888_PRE_BRCM: format_width_height[0] = VG_sARGB_8888_PRE; break;
+      case EGL_PIXEL_FORMAT_ARGB_8888_BRCM:     format_width_height[0] = VG_sARGB_8888; break;
+      case EGL_PIXEL_FORMAT_XRGB_8888_BRCM:     format_width_height[0] = VG_sXRGB_8888; break;
+      case EGL_PIXEL_FORMAT_RGB_565_BRCM:       format_width_height[0] = VG_sRGB_565; break;
+      case EGL_PIXEL_FORMAT_A_8_BRCM:           format_width_height[0] = VG_A_8; break;
+      default:                                  UNREACHABLE();
+      }
+
+      vg_handle = get_stem(state);
+      if (vg_handle == VG_INVALID_HANDLE) {
+         set_error(VG_OUT_OF_MEMORY_ERROR);
+         return VG_INVALID_HANDLE;
+      }
+
+      RPC_CALL3(vgCreateImageFromGlobalImage_impl,
+                thread,
+                VGCREATEIMAGEFROMGLOBALIMAGE_ID,
+                RPC_HANDLE(vg_handle),
+                RPC_UINT(global_image_id[0]),
+                RPC_UINT(global_image_id[1]));
+   } else {
+      global_image_id[0] = 0;
+      global_image_id[1] = 0;
+#endif
+      vg_handle = RPC_HANDLE_RES(RPC_CALL2_OUT_CTRL_RES(vgCreateEGLImageTargetKHR_impl,
+                                                        thread,
+                                                        VGCREATEEGLIMAGETARGETKHR_ID,
+                                                        RPC_EGLID(src_egl_handle),
+                                                        format_width_height));
+      if (vg_handle == VG_INVALID_HANDLE) {
+         return VG_INVALID_HANDLE;
+      }
+#if EGL_BRCM_global_image
+   }
+#endif
+
+   image = image_alloc((VGImageFormat)format_width_height[0], format_width_height[1], format_width_height[2]
+#if EGL_BRCM_global_image
+      , global_image_id[0], global_image_id[1]
+#endif
+      );
+   if (!image) {
+      set_error(VG_OUT_OF_MEMORY_ERROR);
+      RPC_CALL1(vgDestroyImage_impl,
+                thread,
+                VGDESTROYIMAGE_ID,
+                RPC_HANDLE(vg_handle));
+      return VG_INVALID_HANDLE;
+   }
+
+   platform_mutex_acquire(&state->shared_state->mutex);
+   if (!insert_object(state, vg_handle, image)) {
+      set_error(VG_OUT_OF_MEMORY_ERROR);
+      platform_mutex_release(&state->shared_state->mutex);
+      image_free(image);
+      RPC_CALL1(vgDestroyImage_impl,
+                thread,
+                VGDESTROYIMAGE_ID,
+                RPC_HANDLE(vg_handle));
+      return VG_INVALID_HANDLE;
+   }
+   platform_mutex_release(&state->shared_state->mutex);
+
+   return vg_handle;
+}
+
+#endif
diff --git a/interface/khronos/vg/vg_client.h b/interface/khronos/vg/vg_client.h
new file mode 100755 (executable)
index 0000000..4d580ae
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VG_CLIENT_H
+#define VG_CLIENT_H
+
+#include "interface/khronos/common/khrn_client.h"
+#include "interface/khronos/common/khrn_client_platform.h"
+#include "interface/khronos/common/khrn_client_pointermap.h"
+#include "interface/khronos/common/khrn_client_vector.h"
+
+#include "interface/khronos/egl/egl_client_context.h"
+
+#include "interface/khronos/include/EGL/egl.h"
+#include "interface/khronos/include/EGL/eglext.h"
+#include "interface/khronos/include/VG/openvg.h"
+
+#include "interface/khronos/vg/vg_int_config.h"
+#include "interface/khronos/vg/vg_int.h"
+#include "interface/khronos/vg/vg_int_mat3x3.h"
+
+/* should be after EGL/eglext.h */
+#if EGL_BRCM_global_image && EGL_KHR_image
+   #include "interface/khronos/common/khrn_client_global_image_map.h"
+#endif
+
+/******************************************************************************
+shared state
+******************************************************************************/
+
+#define VG_CLIENT_STEMS_COUNT_MAX 64
+
+typedef struct {
+   VG_CLIENT_OBJECT_TYPE_T object_type;
+#if EGL_BRCM_global_image && EGL_KHR_image
+   KHRN_GLOBAL_IMAGE_MAP_T glyph_global_images;
+#endif
+} VG_CLIENT_FONT_T;
+
+typedef struct {
+   VG_CLIENT_OBJECT_TYPE_T object_type;
+   VGImageFormat format;
+   VGint width;
+   VGint height;
+#if EGL_BRCM_global_image && EGL_KHR_image
+   VGuint global_image_id[2];
+#endif
+} VG_CLIENT_IMAGE_T;
+
+typedef struct {
+   VG_CLIENT_OBJECT_TYPE_T object_type;
+   VGint width;
+   VGint height;
+} VG_CLIENT_MASK_LAYER_T;
+
+typedef struct {
+   VGfloat linear[4];
+   VGfloat radial[5];
+   VGColorRampSpreadMode ramp_spread_mode;
+   bool ramp_pre;
+   VGfloat *ramp_stops; /* NULL when count is 0 */
+   VGuint ramp_stops_count;
+} VG_CLIENT_PAINT_GRADIENT_T;
+
+typedef struct {
+   VG_CLIENT_OBJECT_TYPE_T object_type;
+   VGPaintType type;
+   VGfloat color[4];
+   VG_CLIENT_PAINT_GRADIENT_T *gradient; /* allocated when required */
+   VGTilingMode pattern_tiling_mode;
+   VGImage pattern;
+#if EGL_BRCM_global_image && EGL_KHR_image
+   VGuint pattern_global_image_id[2];
+#endif
+} VG_CLIENT_PAINT_T;
+
+typedef struct {
+   VG_CLIENT_OBJECT_TYPE_T object_type;
+   VGint format;
+   VGPathDatatype datatype;
+   VGfloat scale;
+   VGfloat bias;
+   VGbitfield caps;
+   KHRN_VECTOR_T segments;
+} VG_CLIENT_PATH_T;
+
+typedef struct {
+   VGuint ref_count; /* we only read/write this when holding the client mutex */
+
+   PLATFORM_MUTEX_T mutex; /* just one mutex for everything else in here */
+
+   VGuint stems_count;
+   VGHandle stems[VG_CLIENT_STEMS_COUNT_MAX];
+
+   KHRN_POINTER_MAP_T objects;
+} VG_CLIENT_SHARED_STATE_T;
+
+extern VG_CLIENT_SHARED_STATE_T *vg_client_shared_state_alloc(void);
+extern void vg_client_shared_state_free(VG_CLIENT_SHARED_STATE_T *shared_state);
+
+static INLINE void vg_client_shared_state_acquire(VG_CLIENT_SHARED_STATE_T *shared_state)
+{
+   ++shared_state->ref_count;
+}
+
+static INLINE void vg_client_shared_state_release(VG_CLIENT_SHARED_STATE_T *shared_state)
+{
+   if (--shared_state->ref_count == 0) {
+      vg_client_shared_state_free(shared_state);
+   }
+}
+
+/******************************************************************************
+state
+******************************************************************************/
+
+/*
+   Called just before a rendering command (i.e. anything which could modify
+   the draw surface) is executed
+ */
+typedef void (*VG_RENDER_CALLBACK_T)(void);
+
+/*
+   Called just after rendering has been compeleted (i.e. flush or finish).
+   wait should be true for finish-like behaviour, false for flush-like
+   behaviour
+*/
+typedef void (*VG_FLUSH_CALLBACK_T)(bool wait);
+
+typedef struct {
+   VG_MAT3X3_T client;
+   VG_MAT3X3_T server;
+} VG_MAT3X3_SYNC_T;
+
+typedef struct {
+   VG_CLIENT_SHARED_STATE_T *shared_state;
+
+   VG_RENDER_CALLBACK_T render_callback;
+   VG_FLUSH_CALLBACK_T flush_callback;
+
+   /*
+      matrices stored on client
+      updates sent to server as necessary
+   */
+
+   VGMatrixMode matrix_mode;
+   VG_MAT3X3_SYNC_T matrices[5];
+
+   /*
+      state cached on client-side to allow dropping of redundant calls
+   */
+
+   VGFillRule fill_rule;
+   VGfloat stroke_line_width;
+   VGCapStyle stroke_cap_style;
+   VGJoinStyle stroke_join_style;
+   VGfloat stroke_miter_limit;
+   VGfloat stroke_dash_pattern[VG_CONFIG_MAX_DASH_COUNT];
+   VGuint stroke_dash_pattern_count;
+   VGfloat stroke_dash_phase;
+   bool stroke_dash_phase_reset;
+   VGImageQuality image_quality;
+   VGImageMode image_mode;
+
+   bool scissoring;
+   VGint scissor_rects[VG_CONFIG_MAX_SCISSOR_RECTS * 4];
+   VGuint scissor_rects_count;
+
+   VGRenderingQuality rendering_quality;
+
+   VGPaint fill_paint;
+   VGPaint stroke_paint;
+   VGfloat tile_fill_color[4];
+   VGfloat clear_color[4];
+
+   bool color_transform;
+   VGfloat color_transform_values[8];
+
+   VGBlendMode blend_mode;
+   bool masking;
+
+   bool filter_format_linear;
+   bool filter_format_pre;
+   VGuint filter_channel_mask;
+
+   VGPixelLayout pixel_layout;
+} VG_CLIENT_STATE_T;
+
+extern VG_CLIENT_STATE_T *vg_client_state_alloc(VG_CLIENT_SHARED_STATE_T *shared_state);
+extern void vg_client_state_free(VG_CLIENT_STATE_T *state);
+
+static INLINE VG_CLIENT_STATE_T *vg_get_client_state(CLIENT_THREAD_STATE_T *thread)
+{
+   EGL_CONTEXT_T *context = thread->openvg.context;
+   if (context) {
+      vcos_assert(context->type == OPENVG);
+      return (VG_CLIENT_STATE_T *)context->state;
+   } else {
+      return NULL;
+   }
+}
+
+#define VG_GET_CLIENT_STATE(thread) vg_get_client_state(thread)
+
+#endif
diff --git a/interface/khronos/vg/vg_int.h b/interface/khronos/vg/vg_int.h
new file mode 100755 (executable)
index 0000000..4ddbb6a
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VG_INT_H
+#define VG_INT_H
+
+/*
+   object types as used on the client
+
+   the server has a separate notion of object types, defined in
+   middleware/khronos/vg/vg_server.c, which includes partially constructed
+   objects ("blueprints") and a distinction between images and child images
+*/
+
+typedef enum {
+   VG_CLIENT_OBJECT_TYPE_FONT       = 0,
+   VG_CLIENT_OBJECT_TYPE_IMAGE      = 1,
+   VG_CLIENT_OBJECT_TYPE_MASK_LAYER = 2,
+   VG_CLIENT_OBJECT_TYPE_PAINT      = 3,
+   VG_CLIENT_OBJECT_TYPE_PATH       = 4
+} VG_CLIENT_OBJECT_TYPE_T;
+
+#endif
diff --git a/interface/khronos/vg/vg_int_config.h b/interface/khronos/vg/vg_int_config.h
new file mode 100755 (executable)
index 0000000..eded185
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VG_INT_CONFIG_H
+#define VG_INT_CONFIG_H
+
+#include "interface/khronos/include/VG/vgext.h"
+#include "middleware/khronos/vg/2708/vg_config_filler_4.h" /* should #define VG_CONFIG_RENDERER */
+
+#define VG_CONFIG_VENDOR "Broadcom"
+/* VG_CONFIG_RENDERER is platform-specific */
+#if VG_KHR_EGL_image
+   #define VG_CONFIG_EXTENSIONS_KHR_EGL_IMAGE "VG_KHR_EGL_image "
+#else
+   #define VG_CONFIG_EXTENSIONS_KHR_EGL_IMAGE ""
+#endif
+#define VG_CONFIG_EXTENSIONS \
+   VG_CONFIG_EXTENSIONS_KHR_EGL_IMAGE
+
+#define VG_CONFIG_SCREEN_LAYOUT              VG_PIXEL_LAYOUT_UNKNOWN
+#define VG_CONFIG_MAX_SCISSOR_RECTS                               32 /* must be >= 32 */
+#define VG_CONFIG_MAX_DASH_COUNT                                  16 /* must be >= 16 */
+#define VG_CONFIG_MAX_KERNEL_SIZE                                 15 /* must be >= 7 */
+#define VG_CONFIG_MAX_SEPARABLE_KERNEL_SIZE                       33 /* must be >= 15 */
+#define VG_CONFIG_MAX_COLOR_RAMP_STOPS                            32 /* must be >= 32 */
+#define VG_CONFIG_MAX_IMAGE_WIDTH                               2048 /* must be >= 256 */
+#define VG_CONFIG_MAX_IMAGE_HEIGHT                              2048 /* must be >= 256 */
+#define VG_CONFIG_MAX_IMAGE_PIXELS                           4194304 /* must be >= 65536 */
+#define VG_CONFIG_MAX_IMAGE_BYTES                           16777216 /* must be >= 65536 */
+#define VG_CONFIG_MAX_FLOAT                            3.4028234e38f /* must be >= 10.0e10f */
+#define VG_CONFIG_MAX_GAUSSIAN_STD_DEVIATION                   16.0f /* must be >= 16.0f */
+
+#endif
diff --git a/interface/khronos/vg/vg_int_impl.h b/interface/khronos/vg/vg_int_impl.h
new file mode 100755 (executable)
index 0000000..82cd5f7
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if defined(KHRN_IMPL_STRUCT)
+#define FN(type, name, args) type (*name) args;
+#elif defined(KHRN_IMPL_STRUCT_INIT)
+#define FN(type, name, args) name,
+#else
+#define FN(type, name, args) extern type name args;
+#endif
+
+FN(void, vgClearError_impl, (void))
+FN(void, vgSetError_impl, (VGErrorCode error))
+FN(VGErrorCode, vgGetError_impl, (void))
+FN(void, vgFlush_impl, (void))
+FN(VGuint, vgFinish_impl, (void))
+FN(VGuint, vgCreateStems_impl, (VGuint count, VGHandle *vg_handles))
+FN(void, vgDestroyStem_impl, (VGHandle vg_handle))
+FN(void, vgSetiv_impl, (VGParamType param_type, VGint count, const VGint *values))
+FN(void, vgSetfv_impl, (VGParamType param_type, VGint count, const VGfloat *values))
+FN(void, vgGetfv_impl, (VGParamType param_type, VGint count, VGfloat *values))
+FN(void, vgSetParameteriv_impl, (VGHandle vg_handle, VG_CLIENT_OBJECT_TYPE_T client_object_type, VGint param_type, VGint count, const VGint *values))
+FN(void, vgSetParameterfv_impl, (VGHandle vg_handle, VG_CLIENT_OBJECT_TYPE_T client_object_type, VGint param_type, VGint count, const VGfloat *values))
+FN(bool, vgGetParameteriv_impl, (VGHandle vg_handle, VG_CLIENT_OBJECT_TYPE_T client_object_type, VGint param_type, VGint count, VGint *values))
+FN(void, vgLoadMatrix_impl, (VGMatrixMode matrix_mode, const VG_MAT3X3_T *matrix))
+FN(void, vgMask_impl, (VGImage vg_handle, VGMaskOperation operation, VGint dst_x, VGint dst_y, VGint width, VGint height))
+FN(void, vgRenderToMask_impl, (VGPath vg_handle, VGbitfield paint_modes, VGMaskOperation operation))
+FN(void, vgCreateMaskLayer_impl, (VGHandle vg_handle, VGint width, VGint height))
+FN(void, vgDestroyMaskLayer_impl, (VGMaskLayer vg_handle))
+FN(void, vgFillMaskLayer_impl, (VGMaskLayer vg_handle, VGint x, VGint y, VGint width, VGint height, VGfloat value))
+FN(void, vgCopyMask_impl, (VGMaskLayer dst_vg_handle, VGint dst_x, VGint dst_y, VGint src_x, VGint src_y, VGint width, VGint height))
+FN(void, vgClear_impl, (VGint x, VGint y, VGint width, VGint height))
+FN(void, vgCreatePath_impl, (VGHandle vg_handle, VGint format, VGPathDatatype datatype, VGfloat scale, VGfloat bias, VGint segments_capacity, VGint coords_capacity, VGbitfield caps))
+FN(void, vgClearPath_impl, (VGPath vg_handle, VGbitfield caps))
+FN(void, vgDestroyPath_impl, (VGPath vg_handle))
+FN(void, vgRemovePathCapabilities_impl, (VGPath vg_handle, VGbitfield caps))
+FN(void, vgAppendPath_impl, (VGPath dst_vg_handle, VGPath src_vg_handle))
+FN(void, vgAppendPathData_impl, (VGPath vg_handle, VGPathDatatype datatype, VGint segments_count, const VGubyte *segments, VGuint coords_size, const void *coords))
+FN(void, vgModifyPathCoords_impl, (VGPath vg_handle, VGPathDatatype datatype, VGuint coords_offset, VGuint coords_size, const void *coords))
+FN(void, vgTransformPath_impl, (VGPath dst_vg_handle, VGPath src_vg_handle))
+FN(void, vgInterpolatePath_impl, (VGPath dst_vg_handle, VGPath begin_vg_handle, VGPath end_vg_handle, VGfloat t))
+FN(VGfloat, vgPathLength_impl, (VGPath vg_handle, VGint segments_i, VGint segments_count))
+FN(bool, vgPointAlongPath_impl, (VGPath vg_handle, VGint segments_i, VGint segments_count, VGfloat distance, VGbitfield mask, VGfloat *values))
+FN(bool, vgPathBounds_impl, (VGPath vg_handle, VGfloat *values))
+FN(bool, vgPathTransformedBounds_impl, (VGPath vg_handle, VGfloat *values))
+FN(void, vgDrawPath_impl, (VGPath vg_handle, VGbitfield paint_modes))
+FN(void, vgCreatePaint_impl, (VGHandle vg_handle))
+FN(void, vgDestroyPaint_impl, (VGPaint vg_handle))
+FN(void, vgSetPaint_impl, (VGPaint vg_handle, VGbitfield paint_modes))
+FN(void, vgPaintPattern_impl, (VGPaint vg_handle, VGImage pattern_vg_handle))
+FN(void, vgCreateImage_impl, (VGHandle vg_handle, VGImageFormat format, VGint width, VGint height, VGbitfield allowed_quality))
+FN(void, vgDestroyImage_impl, (VGImage vg_handle))
+FN(void, vgClearImage_impl, (VGImage vg_handle, VGint x, VGint y, VGint width, VGint height))
+FN(void, vgImageSubData_impl, (VGImage vg_handle, VGint dst_width, VGint dst_height, const void *data, VGint data_stride, VGImageFormat data_format, VGint src_x, VGint dst_x, VGint dst_y, VGint width, VGint height))
+FN(bool, vgGetImageSubData_impl, (VGImage vg_handle, VGint src_width, VGint src_height, void *data, VGint data_stride, VGImageFormat data_format, VGint dst_x, VGint src_x, VGint src_y, VGint width, VGint height))
+FN(void, vgChildImage_impl, (VGHandle vg_handle, VGImage parent_vg_handle, VGint parent_width, VGint parent_height, VGint x, VGint y, VGint width, VGint height))
+FN(VGImage, vgGetParent_impl, (VGImage vg_handle))
+FN(void, vgCopyImage_impl, (VGImage dst_vg_handle, VGint dst_x, VGint dst_y, VGImage src_vg_handle, VGint src_x, VGint src_y, VGint width, VGint height, bool dither))
+FN(void, vgDrawImage_impl, (VGImage vg_handle))
+FN(void, vgSetPixels_impl, (VGint dst_x, VGint dst_y, VGImage src_vg_handle, VGint src_x, VGint src_y, VGint width, VGint height))
+FN(void, vgWritePixels_impl, (const void *data, VGint data_stride, VGImageFormat data_format, VGint src_x, VGint dst_x, VGint dst_y, VGint width, VGint height))
+FN(void, vgGetPixels_impl, (VGImage dst_vg_handle, VGint dst_x, VGint dst_y, VGint src_x, VGint src_y, VGint width, VGint height))
+FN(void, vgReadPixels_impl, (void *data, VGint data_stride, VGImageFormat data_format, VGint dst_x, VGint src_x, VGint src_y, VGint width, VGint height))
+FN(void, vgCopyPixels_impl, (VGint dst_x, VGint dst_y, VGint src_x, VGint src_y, VGint width, VGint height))
+FN(void, vgCreateFont_impl, (VGHandle vg_handle, VGint glyphs_capacity))
+FN(void, vgDestroyFont_impl, (VGFont vg_handle))
+FN(void, vgSetGlyphToPath_impl, (VGFont vg_handle, VGuint glyph_id, VGPath path_vg_handle, bool is_hinted, VGfloat glyph_origin_x, VGfloat glyph_origin_y, VGfloat escapement_x, VGfloat escapement_y))
+FN(void, vgSetGlyphToImage_impl, (VGFont vg_handle, VGuint glyph_id, VGImage image_vg_handle, VGfloat glyph_origin_x, VGfloat glyph_origin_y, VGfloat escapement_x, VGfloat escapement_y))
+FN(void, vgClearGlyph_impl, (VGFont vg_handle, VGuint glyph_id))
+FN(void, vgDrawGlyph_impl, (VGFont vg_handle, VGuint glyph_id, VGbitfield paint_modes, bool allow_autohinting))
+FN(void, vgDrawGlyphs_impl, (VGFont vg_handle, VGint glyphs_count, const VGuint *glyph_ids, const VGfloat *adjustments_x, const VGfloat *adjustments_y, VGbitfield paint_modes, bool allow_autohinting))
+FN(void, vgColorMatrix_impl, (VGImage dst_vg_handle, VGImage src_vg_handle, const VGfloat *matrix))
+FN(void, vgConvolve_impl, (VGImage dst_vg_handle, VGImage src_vg_handle, VGint kernel_width, VGint kernel_height, VGint shift_x, VGint shift_y, VGfloat scale, VGfloat bias, VGTilingMode tiling_mode, const VGshort *kernel))
+FN(void, vgSeparableConvolve_impl, (VGImage dst_vg_handle, VGImage src_vg_handle, VGint kernel_width, VGint kernel_height, VGint shift_x, VGint shift_y, const VGshort *kernel_x, const VGshort *kernel_y, VGfloat scale, VGfloat bias, VGTilingMode tiling_mode))
+FN(void, vgGaussianBlur_impl, (VGImage dst_vg_handle, VGImage src_vg_handle, VGfloat std_dev_x, VGfloat std_dev_y, VGTilingMode tiling_mode))
+FN(void, vgLookup_impl, (VGImage dst_vg_handle, VGImage src_vg_handle, const VGubyte *red_lut, const VGubyte *green_lut, const VGubyte *blue_lut, const VGubyte *alpha_lut, bool output_linear, bool output_pre))
+FN(void, vgLookupSingle_impl, (VGImage dst_vg_handle, VGImage src_vg_handle, VGImageChannel source_channel, bool output_linear, bool output_pre, const VGuint *lut))
+FN(void, vguLine_impl, (VGPath vg_handle, VGfloat p0_x, VGfloat p0_y, VGfloat p1_x, VGfloat p1_y))
+FN(void, vguPolygon_impl, (VGPath vg_handle, const VGfloat *ps, VGint ps_count, bool first, bool close))
+FN(void, vguRect_impl, (VGPath vg_handle, VGfloat x, VGfloat y, VGfloat width, VGfloat height))
+FN(void, vguRoundRect_impl, (VGPath vg_handle, VGfloat x, VGfloat y, VGfloat width, VGfloat height, VGfloat arc_width, VGfloat arc_height))
+FN(void, vguEllipse_impl, (VGPath vg_handle, VGfloat x, VGfloat y, VGfloat width, VGfloat height))
+FN(void, vguArc_impl, (VGPath vg_handle, VGfloat x, VGfloat y, VGfloat width, VGfloat height, VGfloat start_angle, VGfloat angle_extent, VGuint angle_o180, VGUArcType arc_type))
+#if VG_KHR_EGL_image
+FN(VGImage, vgCreateEGLImageTargetKHR_impl, (VGeglImageKHR src_egl_handle, VGuint *format_width_height))
+#if EGL_BRCM_global_image
+FN(void, vgCreateImageFromGlobalImage_impl, (VGHandle vg_handle, VGuint id_0, VGuint id_1))
+#endif
+#endif
+
+#undef FN
diff --git a/interface/khronos/vg/vg_int_mat3x3.c b/interface/khronos/vg/vg_int_mat3x3.c
new file mode 100755 (executable)
index 0000000..47e14ae
--- /dev/null
@@ -0,0 +1,646 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/khronos/common/khrn_int_common.h"
+#include "interface/khronos/vg/vg_int_mat3x3.h"
+#include "interface/khronos/common/khrn_int_math.h"
+#include "interface/khronos/common/khrn_int_util.h"
+
+/*
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   a is the identity matrix.
+*/
+
+void vg_mat3x3_set_identity(VG_MAT3X3_T *a)
+{
+   a->m[0][0] = 1.0f;  a->m[0][1] = 0.0f;  a->m[0][2] = 0.0f;
+   a->m[1][0] = 0.0f;  a->m[1][1] = 1.0f;  a->m[1][2] = 0.0f;
+   a->m[2][0] = 0.0f;  a->m[2][1] = 0.0f;  a->m[2][2] = 1.0f;
+}
+
+/*
+   copies matrix (column-major) into a, "cleaning" the elements (see
+   clean_float). forces the bottom row of a to (0, 0, 1) if force_affine is
+   true.
+
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   no elements of a are nan or infinity.
+   if force_affine is true, a is affine.
+*/
+
+void vg_mat3x3_set_clean(VG_MAT3X3_T *a, const float *matrix, bool force_affine)
+{
+   a->m[0][0] = clean_float(matrix[0]);
+   a->m[0][1] = clean_float(matrix[3]);
+   a->m[0][2] = clean_float(matrix[6]);
+
+   a->m[1][0] = clean_float(matrix[1]);
+   a->m[1][1] = clean_float(matrix[4]);
+   a->m[1][2] = clean_float(matrix[7]);
+
+   if (force_affine) {
+      a->m[2][0] = 0.0f;
+      a->m[2][1] = 0.0f;
+      a->m[2][2] = 1.0f;
+   } else {
+      a->m[2][0] = clean_float(matrix[2]);
+      a->m[2][1] = clean_float(matrix[5]);
+      a->m[2][2] = clean_float(matrix[8]);
+   }
+}
+
+/*
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   matrix (column-major) is set to a.
+*/
+
+void vg_mat3x3_get(const VG_MAT3X3_T *a, float *matrix)
+{
+   matrix[0] = a->m[0][0];
+   matrix[3] = a->m[0][1];
+   matrix[6] = a->m[0][2];
+
+   matrix[1] = a->m[1][0];
+   matrix[4] = a->m[1][1];
+   matrix[7] = a->m[1][2];
+
+   matrix[2] = a->m[2][0];
+   matrix[5] = a->m[2][1];
+   matrix[8] = a->m[2][2];
+}
+
+/*
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   returns true iff a and b are bitwise identical.
+*/
+
+bool vg_mat3x3_identical(const VG_MAT3X3_T *a, const VG_MAT3X3_T *b)
+{
+   return floats_identical(a->m[0][0], b->m[0][0]) && floats_identical(a->m[0][1], b->m[0][1]) && floats_identical(a->m[0][2], b->m[0][2]) &&
+          floats_identical(a->m[1][0], b->m[1][0]) && floats_identical(a->m[1][1], b->m[1][1]) && floats_identical(a->m[1][2], b->m[1][2]) &&
+          floats_identical(a->m[2][0], b->m[2][0]) && floats_identical(a->m[2][1], b->m[2][1]) && floats_identical(a->m[2][2], b->m[2][2]);
+}
+
+/*
+   Preconditions:
+
+   a does not point to the same matrix as b or c.
+
+   Postconditions:
+
+   a is set to b * c.
+*/
+
+void vg_mat3x3_mul(VG_MAT3X3_T *a, const VG_MAT3X3_T *b, const VG_MAT3X3_T *c)
+{
+   uint32_t j, i;
+   for (j = 0; j != 3; ++j) {
+      for (i = 0; i != 3; ++i) {
+         a->m[j][i] =
+            (b->m[j][0] * c->m[0][i]) +
+            (b->m[j][1] * c->m[1][i]) +
+            (b->m[j][2] * c->m[2][i]);
+      }
+   }
+}
+
+/*
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   a is set to a * translation_matrix(x, y).
+*/
+
+void vg_mat3x3_postmul_translate(VG_MAT3X3_T *a, float x, float y)
+{
+   a->m[0][2] += (a->m[0][0] * x) + (a->m[0][1] * y);
+   a->m[1][2] += (a->m[1][0] * x) + (a->m[1][1] * y);
+   a->m[2][2] += (a->m[2][0] * x) + (a->m[2][1] * y);
+}
+
+/*
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   a is set to a * scale_matrix(x, y).
+*/
+
+void vg_mat3x3_postmul_scale(VG_MAT3X3_T *a, float x, float y)
+{
+   a->m[0][0] *= x;
+   a->m[0][1] *= y;
+
+   a->m[1][0] *= x;
+   a->m[1][1] *= y;
+
+   a->m[2][0] *= x;
+   a->m[2][1] *= y;
+}
+
+/*
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   a is set to a * shear_matrix(x, y).
+*/
+
+void vg_mat3x3_postmul_shear(VG_MAT3X3_T *a, float x, float y)
+{
+   float m00 = a->m[0][0], m10 = a->m[1][0], m20 = a->m[2][0];
+
+   a->m[0][0] += a->m[0][1] * y;
+   a->m[0][1] += m00 * x;
+
+   a->m[1][0] += a->m[1][1] * y;
+   a->m[1][1] += m10 * x;
+
+   a->m[2][0] += a->m[2][1] * y;
+   a->m[2][1] += m20 * x;
+}
+
+/*
+   Preconditions:
+
+   angle is in radians.
+
+   Postconditions:
+
+   a is set to a * rotation_matrix(angle).
+*/
+
+void vg_mat3x3_postmul_rotate(VG_MAT3X3_T *a, float angle)
+{
+   float s, c;
+   sin_cos_(&s, &c, angle);
+   vg_mat3x3_postmul_rotate_sc(a, s, c);
+}
+
+/*
+   Preconditions:
+
+   there is some angle such that:
+   s = sin(angle)
+   c = cos(angle)
+
+   Postconditions:
+
+   a is set to a * rotation_matrix(angle).
+*/
+
+void vg_mat3x3_postmul_rotate_sc(VG_MAT3X3_T *a, float s, float c)
+{
+   float m00 = a->m[0][0], m10 = a->m[1][0], m20 = a->m[2][0];
+
+   a->m[0][0] = (m00 * c) + (a->m[0][1] * s);
+   a->m[0][1] = (a->m[0][1] * c) - (m00 * s);
+
+   a->m[1][0] = (m10 * c) + (a->m[1][1] * s);
+   a->m[1][1] = (a->m[1][1] * c) - (m10 * s);
+
+   a->m[2][0] = (m20 * c) + (a->m[2][1] * s);
+   a->m[2][1] = (a->m[2][1] * c) - (m20 * s);
+}
+
+/*
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   a is set to translation_matrix(x, y) * a.
+*/
+
+void vg_mat3x3_premul_translate(VG_MAT3X3_T *a, float x, float y)
+{
+   a->m[0][0] += a->m[2][0] * x;
+   a->m[0][1] += a->m[2][1] * x;
+   a->m[0][2] += a->m[2][2] * x;
+
+   a->m[1][0] += a->m[2][0] * y;
+   a->m[1][1] += a->m[2][1] * y;
+   a->m[1][2] += a->m[2][2] * y;
+}
+
+/*
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   a is set to scale_matrix(x, y) * a.
+*/
+
+void vg_mat3x3_premul_scale(VG_MAT3X3_T *a, float x, float y)
+{
+   a->m[0][0] *= x;
+   a->m[0][1] *= x;
+   a->m[0][2] *= x;
+
+   a->m[1][0] *= y;
+   a->m[1][1] *= y;
+   a->m[1][2] *= y;
+}
+
+/*
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   a is set to shear_matrix(x, y) * a.
+*/
+
+void vg_mat3x3_premul_shear(VG_MAT3X3_T *a, float x, float y)
+{
+   float m00 = a->m[0][0], m01 = a->m[0][1], m02 = a->m[0][2];
+
+   a->m[0][0] += a->m[1][0] * x;
+   a->m[0][1] += a->m[1][1] * x;
+   a->m[0][2] += a->m[1][2] * x;
+
+   a->m[1][0] += m00 * y;
+   a->m[1][1] += m01 * y;
+   a->m[1][2] += m02 * y;
+}
+
+/*
+   Preconditions:
+
+   angle is in radians.
+
+   Postconditions:
+
+   a is set to rotation_matrix(angle) * a.
+*/
+
+void vg_mat3x3_premul_rotate(VG_MAT3X3_T *a, float angle)
+{
+   float s, c;
+   sin_cos_(&s, &c, angle);
+   vg_mat3x3_premul_rotate_sc(a, s, c);
+}
+
+/*
+   Preconditions:
+
+   there is some angle such that:
+   s = sin(angle)
+   c = cos(angle)
+
+   Postconditions:
+
+   a is set to rotation_matrix(angle) * a.
+*/
+
+void vg_mat3x3_premul_rotate_sc(VG_MAT3X3_T *a, float s, float c)
+{
+   float m00 = a->m[0][0], m01 = a->m[0][1], m02 = a->m[0][2];
+
+   a->m[0][0] = (m00 * c) - (a->m[1][0] * s);
+   a->m[0][1] = (m01 * c) - (a->m[1][1] * s);
+   a->m[0][2] = (m02 * c) - (a->m[1][2] * s);
+
+   a->m[1][0] = (m00 * s) + (a->m[1][0] * c);
+   a->m[1][1] = (m01 * s) + (a->m[1][1] * c);
+   a->m[1][2] = (m02 * s) + (a->m[1][2] * c);
+}
+
+/*
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   returns true iff a is affine.
+*/
+
+bool vg_mat3x3_is_affine(const VG_MAT3X3_T *a)
+{
+   return (a->m[2][0] == 0.0f) && (a->m[2][1] == 0.0f) && (a->m[2][2] == 1.0f);
+}
+
+/*
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   returns true iff a is affine or has nans in the bad elements.
+*/
+
+bool vg_mat3x3_is_affine_or_nans(const VG_MAT3X3_T *a)
+{
+   return !nan_ne_(a->m[2][0], 0.0f) && !nan_ne_(a->m[2][1], 0.0f) && !nan_ne_(a->m[2][2], 1.0f);
+}
+
+/*
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   returns the determinant of a.
+*/
+
+float vg_mat3x3_det(const VG_MAT3X3_T *a)
+{
+   return (a->m[0][0] * ((a->m[2][2] * a->m[1][1]) - (a->m[2][1] * a->m[1][2]))) +
+          (a->m[1][0] * ((a->m[0][2] * a->m[2][1]) - (a->m[0][1] * a->m[2][2]))) +
+          (a->m[2][0] * ((a->m[1][2] * a->m[0][1]) - (a->m[1][1] * a->m[0][2])));
+}
+
+/*
+   Preconditions:
+
+   a must be affine (or have nans in the bad elements).
+
+   Postconditions:
+
+   returns the determinant of a.
+*/
+
+float vg_mat3x3_affine_det(const VG_MAT3X3_T *a)
+{
+   vcos_assert(vg_mat3x3_is_affine_or_nans(a));
+   return (a->m[0][0] * a->m[1][1]) - (a->m[1][0] * a->m[0][1]);
+}
+
+/*
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   returns false iff a is not invertible (or very close to not being
+   invertible).
+*/
+
+bool vg_mat3x3_is_invertible(const VG_MAT3X3_T *a)
+{
+   return absf_(vg_mat3x3_det(a)) >= EPS;
+}
+
+/*
+   Preconditions:
+
+   a must be affine (or have nans in the bad elements).
+
+   Postconditions:
+
+   returns false iff a is not invertible (or very close to not being
+   invertible).
+*/
+
+bool vg_mat3x3_affine_is_invertible(const VG_MAT3X3_T *a)
+{
+   return absf_(vg_mat3x3_affine_det(a)) >= EPS;
+}
+
+/*
+   Preconditions:
+
+   a must be invertible, according to vg_mat3x3_is_invertible.
+
+   Postconditions:
+
+   a is inverted.
+*/
+
+void vg_mat3x3_invert(VG_MAT3X3_T *a)
+{
+   float oo_det;
+   VG_MAT3X3_T b;
+
+   vcos_assert(vg_mat3x3_is_invertible(a));
+
+   oo_det = recip_(vg_mat3x3_det(a));
+
+   b.m[0][0] = ((a->m[2][2] * a->m[1][1]) - (a->m[2][1] * a->m[1][2])) * oo_det;
+   b.m[0][1] = ((a->m[0][2] * a->m[2][1]) - (a->m[0][1] * a->m[2][2])) * oo_det;
+   b.m[0][2] = ((a->m[1][2] * a->m[0][1]) - (a->m[1][1] * a->m[0][2])) * oo_det;
+
+   b.m[1][0] = ((a->m[2][0] * a->m[1][2]) - (a->m[2][2] * a->m[1][0])) * oo_det;
+   b.m[1][1] = ((a->m[0][0] * a->m[2][2]) - (a->m[0][2] * a->m[2][0])) * oo_det;
+   b.m[1][2] = ((a->m[1][0] * a->m[0][2]) - (a->m[1][2] * a->m[0][0])) * oo_det;
+
+   b.m[2][0] = ((a->m[2][1] * a->m[1][0]) - (a->m[2][0] * a->m[1][1])) * oo_det;
+   b.m[2][1] = ((a->m[0][1] * a->m[2][0]) - (a->m[0][0] * a->m[2][1])) * oo_det;
+   b.m[2][2] = ((a->m[1][1] * a->m[0][0]) - (a->m[1][0] * a->m[0][1])) * oo_det;
+
+   *a = b;
+}
+
+/*
+   Preconditions:
+
+   a must be affine (or have nans in the bad elements).
+   a must be invertible, according to vg_mat3x3_affine_is_invertible.
+
+   Postconditions:
+
+   a is inverted.
+*/
+
+void vg_mat3x3_affine_invert(VG_MAT3X3_T *a)
+{
+   float oo_det;
+   float m00, m01, m02, m10;
+
+   vcos_assert(vg_mat3x3_affine_is_invertible(a));
+
+   oo_det = recip_(vg_mat3x3_affine_det(a));
+   m00 = a->m[0][0];
+   m01 = a->m[0][1];
+   m02 = a->m[0][2];
+   m10 = a->m[1][0];
+
+   a->m[0][0] = a->m[1][1] * oo_det;
+   a->m[0][1] = -m01 * oo_det;
+   a->m[0][2] = ((a->m[1][2] * m01) - (a->m[1][1] * m02)) * oo_det;
+
+   a->m[1][0] = -m10 * oo_det;
+   a->m[1][1] = m00 * oo_det;
+   a->m[1][2] = ((m10 * m02) - (a->m[1][2] * m00)) * oo_det;
+
+   a->m[2][0] = 0.0f;
+   a->m[2][1] = 0.0f;
+   a->m[2][2] = 1.0f;
+}
+
+/*
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   (x, y, -) is set to a * (x, y, 1).
+*/
+
+void vg_mat3x3_affine_transform(const VG_MAT3X3_T *a, float *x_io, float *y_io)
+{
+   float x = (a->m[0][0] * *x_io) + (a->m[0][1] * *y_io) + a->m[0][2];
+   float y = (a->m[1][0] * *x_io) + (a->m[1][1] * *y_io) + a->m[1][2];
+   *x_io = x;
+   *y_io = y;
+}
+
+/*
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   (x, y, -) is set to a * (x, y, 0).
+*/
+
+void vg_mat3x3_affine_transform_t(const VG_MAT3X3_T *a, float *x_io, float *y_io)
+{
+   float x = (a->m[0][0] * *x_io) + (a->m[0][1] * *y_io);
+   float y = (a->m[1][0] * *x_io) + (a->m[1][1] * *y_io);
+   *x_io = x;
+   *y_io = y;
+}
+
+/*
+   the top-left 2x2 submatrix of a is decomposed into (R * S * Q), where R is a
+   rotation matrix, S is a scale matrix, and Q is a rotation/flip matrix. note
+   that this decomposition is not unique.
+
+   Preconditions:
+
+   r may be NULL.
+   s0 may be NULL.
+   s1 may be NULL.
+
+   Postconditions:
+
+   if r is non-NULL, it is set to the angle of R (so R = rotation_matrix(r)) in
+   radians.
+   if s0 is non-NULL, it is set to S[0][0].
+   if s1 is non-NULL, it is set to S[1][1].
+   so if we set both, S = scale_matrix(s0, s1).
+*/
+
+void vg_mat3x3_rsq(const VG_MAT3X3_T *a,
+   float *r, float *s0, float *s1)
+{
+   /*
+      a = R * S * Q (svd, R is rotation, S is scale, Q is rotation/flip)
+      a^T = Q^T * S * R^T
+      a * a^T = R * S * Q * Q^T * S * R^T = R * S^2 * R^T
+
+      eigenvalues of a * a^T will give S^2
+      eigenvectors of a * a^T will give R
+   */
+
+   /*
+      ( b c ) = a * a^T
+      ( d e )
+   */
+
+   float b = (a->m[0][0] * a->m[0][0]) + (a->m[0][1] * a->m[0][1]);
+   float c = (a->m[0][0] * a->m[1][0]) + (a->m[0][1] * a->m[1][1]);
+   /* d = c */
+   float e = (a->m[1][0] * a->m[1][0]) + (a->m[1][1] * a->m[1][1]);
+
+   float bpe = b + e;
+   float bme = b - e;
+
+   /*
+      solve:
+
+      bx + cy = sx
+      dx + ey = sy
+
+      cy * dx = (s - b)x * (s - e)y
+      c^2 = (s - b) * (s - e)
+      s^2 - (b + e)s + (be - c^2) = 0
+      s = (b + e +/- sqrt((b + e)^2 - 4(be - c^2))) / 2
+      s = (b + e +/- sqrt(b^2 + e^2 - 2be + 4c^2)) / 2
+      s = (b + e +/- sqrt((b - e)^2 + 4c^2)) / 2
+   */
+
+   float t = sqrt_((bme * bme) + (4.0f * c * c));
+   float v = (bpe + t) * 0.5f; /* first eigenvalue */
+   if (s0) {
+      *s0 = sqrt_(v);
+   }
+   if (s1) {
+      *s1 = sqrt_(
+         /* second eigenvalue */
+         _maxf(bpe - t, 0.0f) * 0.5f);
+   }
+
+   /*
+      angle of eigenvector corresponds to r
+   */
+
+   if (r) {
+      /* first eigenvector is (c, v - b) / (v - e, c) */
+      float x = (v - e) + c;
+      float y = (v - b) + c;
+      *r = ((absf_(x) < EPS) && (absf_(y) < EPS)) ? 0.0f : atan2_(y, x);
+   }
+}
diff --git a/interface/khronos/vg/vg_int_mat3x3.h b/interface/khronos/vg/vg_int_mat3x3.h
new file mode 100755 (executable)
index 0000000..536be3f
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VG_INT_MAT3X3_H
+#define VG_INT_MAT3X3_H
+
+typedef struct {
+   float m[3][3]; /* [y][x] */
+} VG_MAT3X3_T;
+
+extern void vg_mat3x3_set_identity(VG_MAT3X3_T *a);
+extern void vg_mat3x3_set_clean(VG_MAT3X3_T *a, const float *matrix, bool force_affine);
+extern void vg_mat3x3_get(const VG_MAT3X3_T *a, float *matrix);
+extern bool vg_mat3x3_identical(const VG_MAT3X3_T *a, const VG_MAT3X3_T *b);
+
+extern void vg_mat3x3_mul(VG_MAT3X3_T *a, const VG_MAT3X3_T *b, const VG_MAT3X3_T *c);
+
+/*
+   Preconditions:
+
+   a and b may point to the same matrix.
+
+   Postconditions:
+
+   a is set to a * b.
+*/
+
+static INLINE void vg_mat3x3_postmul(VG_MAT3X3_T *a, const VG_MAT3X3_T *b)
+{
+   VG_MAT3X3_T c;
+   vg_mat3x3_mul(&c, a, b);
+   *a = c;
+}
+
+extern void vg_mat3x3_postmul_translate(VG_MAT3X3_T *a, float x, float y);
+extern void vg_mat3x3_postmul_scale(VG_MAT3X3_T *a, float x, float y);
+extern void vg_mat3x3_postmul_shear(VG_MAT3X3_T *a, float x, float y);
+extern void vg_mat3x3_postmul_rotate(VG_MAT3X3_T *a, float angle);
+extern void vg_mat3x3_postmul_rotate_sc(VG_MAT3X3_T *a, float s, float c);
+
+/*
+   Preconditions:
+
+   a and b may point to the same matrix.
+
+   Postconditions:
+
+   a is set to b * a.
+*/
+
+static INLINE void vg_mat3x3_premul(VG_MAT3X3_T *a, const VG_MAT3X3_T *b)
+{
+   VG_MAT3X3_T c;
+   vg_mat3x3_mul(&c, b, a);
+   *a = c;
+}
+
+extern void vg_mat3x3_premul_translate(VG_MAT3X3_T *a, float x, float y);
+extern void vg_mat3x3_premul_scale(VG_MAT3X3_T *a, float x, float y);
+extern void vg_mat3x3_premul_shear(VG_MAT3X3_T *a, float x, float y);
+extern void vg_mat3x3_premul_rotate(VG_MAT3X3_T *a, float angle);
+extern void vg_mat3x3_premul_rotate_sc(VG_MAT3X3_T *a, float s, float c);
+
+extern bool vg_mat3x3_is_affine(const VG_MAT3X3_T *a);
+
+/* it is possible to start with an affine matrix, apply only affine-preserving
+ * transformations, and then end up with a matrix where vg_mat3x3_is_affine
+ * returns false. this is because the bottom row of the matrix can end up
+ * containing nans if infinities or nans crop up in the calculations
+ *
+ * this is why i vcos_assert(vg_mat3x3_is_affine_or_nans) rather than just
+ * vcos_assert(vg_mat3x3_is_affine) in various places. todo: i think this could
+ * be fixed by having special affine versions of the various multiply functions
+ * that don't touch the bottom row at all, but is it worth it? */
+extern bool vg_mat3x3_is_affine_or_nans(const VG_MAT3X3_T *a);
+
+extern float vg_mat3x3_det(const VG_MAT3X3_T *a);
+extern float vg_mat3x3_affine_det(const VG_MAT3X3_T *a);
+
+extern bool vg_mat3x3_is_invertible(const VG_MAT3X3_T *a);
+extern bool vg_mat3x3_affine_is_invertible(const VG_MAT3X3_T *a);
+
+extern void vg_mat3x3_invert(VG_MAT3X3_T *a);
+extern void vg_mat3x3_affine_invert(VG_MAT3X3_T *a);
+
+/*
+   Preconditions:
+
+   -
+
+   Postconditions:
+
+   if a is invertible, according to vg_mat3x3_is_invertible, true is returned
+   and a is inverted. otherwise, false is returned and a is untouched.
+*/
+
+static INLINE bool vg_mat3x3_try_invert(VG_MAT3X3_T *a)
+{
+   if (!vg_mat3x3_is_invertible(a)) {
+      return false;
+   }
+   vg_mat3x3_invert(a);
+   return true;
+}
+
+/*
+   Preconditions:
+
+   a must be affine (or have nans in the bad elements).
+
+   Postconditions:
+
+   if a is invertible, according to vg_mat3x3_affine_is_invertible, true is
+   returned and a is inverted. otherwise, false is returned and a is untouched.
+*/
+
+static INLINE bool vg_mat3x3_affine_try_invert(VG_MAT3X3_T *a)
+{
+   if (!vg_mat3x3_affine_is_invertible(a)) {
+      return false;
+   }
+   vg_mat3x3_affine_invert(a);
+   return true;
+}
+
+extern void vg_mat3x3_affine_transform(const VG_MAT3X3_T *a, float *x, float *y);
+extern void vg_mat3x3_affine_transform_t(const VG_MAT3X3_T *a, float *x, float *y);
+
+extern void vg_mat3x3_rsq(const VG_MAT3X3_T *a, /* only top-left 2x2 matrix used */
+   float *r, float *s0, float *s1); /* don't need q for anything atm, so not calculated */
+
+#endif
diff --git a/interface/khronos/vg/vg_int_util.h b/interface/khronos/vg/vg_int_util.h
new file mode 100755 (executable)
index 0000000..a8ea2cd
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VG_INT_UTIL_H
+#define VG_INT_UTIL_H
+
+#include "interface/khronos/common/khrn_int_util.h"
+#include "interface/khronos/include/VG/openvg.h"
+#include "interface/khronos/include/VG/vgu.h"
+
+static INLINE bool is_matrix_mode(VGMatrixMode matrix_mode)
+{
+   return (matrix_mode >= VG_MATRIX_PATH_USER_TO_SURFACE) &&
+          (matrix_mode <= VG_MATRIX_GLYPH_USER_TO_SURFACE);
+}
+
+static INLINE bool is_fill_rule(VGFillRule fill_rule)
+{
+   return (fill_rule == VG_EVEN_ODD) ||
+          (fill_rule == VG_NON_ZERO);
+}
+
+static INLINE bool is_image_quality(VGImageQuality image_quality)
+{
+   return (image_quality == VG_IMAGE_QUALITY_NONANTIALIASED) ||
+          (image_quality == VG_IMAGE_QUALITY_FASTER) ||
+          (image_quality == VG_IMAGE_QUALITY_BETTER);
+}
+
+static INLINE bool is_rendering_quality(VGRenderingQuality rendering_quality)
+{
+   return (rendering_quality >= VG_RENDERING_QUALITY_NONANTIALIASED) &&
+          (rendering_quality <= VG_RENDERING_QUALITY_BETTER);
+}
+
+static INLINE bool is_blend_mode(VGBlendMode blend_mode)
+{
+   return (blend_mode >= VG_BLEND_SRC) &&
+          (blend_mode <= VG_BLEND_ADDITIVE);
+}
+
+static INLINE bool is_image_mode(VGImageMode image_mode)
+{
+   return (image_mode >= VG_DRAW_IMAGE_NORMAL) &&
+          (image_mode <= VG_DRAW_IMAGE_STENCIL);
+}
+
+static INLINE bool is_cap_style(VGCapStyle cap_style)
+{
+   return (cap_style >= VG_CAP_BUTT) &&
+          (cap_style <= VG_CAP_SQUARE);
+}
+
+static INLINE bool is_join_style(VGJoinStyle join_style)
+{
+   return (join_style >= VG_JOIN_MITER) &&
+          (join_style <= VG_JOIN_BEVEL);
+}
+
+static INLINE bool is_pixel_layout(VGPixelLayout pixel_layout)
+{
+   return (pixel_layout >= VG_PIXEL_LAYOUT_UNKNOWN) &&
+          (pixel_layout <= VG_PIXEL_LAYOUT_BGR_HORIZONTAL);
+}
+
+static INLINE bool is_paint_type(VGPaintType paint_type)
+{
+   return (paint_type >= VG_PAINT_TYPE_COLOR) &&
+          (paint_type <= VG_PAINT_TYPE_PATTERN);
+}
+
+static INLINE bool is_color_ramp_spread_mode(VGColorRampSpreadMode color_ramp_spread_mode)
+{
+   return (color_ramp_spread_mode >= VG_COLOR_RAMP_SPREAD_PAD) &&
+          (color_ramp_spread_mode <= VG_COLOR_RAMP_SPREAD_REFLECT);
+}
+
+static INLINE bool is_tiling_mode(VGTilingMode tiling_mode)
+{
+   return (tiling_mode >= VG_TILE_FILL) &&
+          (tiling_mode <= VG_TILE_REFLECT);
+}
+
+static INLINE bool is_vector_param_type(VGParamType param_type)
+{
+   return (param_type == VG_SCISSOR_RECTS) ||
+          (param_type == VG_COLOR_TRANSFORM_VALUES) ||
+          (param_type == VG_STROKE_DASH_PATTERN) ||
+          (param_type == VG_TILE_FILL_COLOR) ||
+          (param_type == VG_CLEAR_COLOR) ||
+          (param_type == VG_GLYPH_ORIGIN);
+}
+
+static INLINE bool is_vector_object_param_type(int32_t param_type)
+{
+   return (param_type == VG_PAINT_COLOR) ||
+          (param_type == VG_PAINT_COLOR_RAMP_STOPS) ||
+          (param_type == VG_PAINT_LINEAR_GRADIENT) ||
+          (param_type == VG_PAINT_RADIAL_GRADIENT);
+}
+
+static INLINE bool is_path_format(int32_t path_format)
+{
+   return path_format == VG_PATH_FORMAT_STANDARD;
+}
+
+static INLINE bool is_path_datatype(VGPathDatatype path_datatype)
+{
+#ifdef __HIGHC__
+   #pragma Offwarn(428) /* unsigned compare with 0 always true */
+#endif
+   return (path_datatype >= VG_PATH_DATATYPE_S_8) &&
+          (path_datatype <= VG_PATH_DATATYPE_F);
+#ifdef __HIGHC__
+   #pragma Popwarn
+#endif
+}
+
+static INLINE uint32_t get_path_datatype_size(VGPathDatatype path_datatype)
+{
+   switch (path_datatype) {
+   case VG_PATH_DATATYPE_S_8:  return 1;
+   case VG_PATH_DATATYPE_S_16: return sizeof(int16_t);
+   case VG_PATH_DATATYPE_S_32: return sizeof(int32_t);
+   case VG_PATH_DATATYPE_F:    return sizeof(float);
+   default:                    UNREACHABLE(); return 0;
+   }
+}
+
+static INLINE uint32_t get_segment_coords_count(uint32_t segment)
+{
+   switch (segment) {
+   case VG_CLOSE_PATH: return 0;
+   case VG_MOVE_TO:    return 2;
+   case VG_LINE_TO:    return 2;
+   case VG_HLINE_TO:   return 1;
+   case VG_VLINE_TO:   return 1;
+   case VG_QUAD_TO:    return 4;
+   case VG_CUBIC_TO:   return 6;
+   case VG_SQUAD_TO:   return 2;
+   case VG_SCUBIC_TO:  return 4;
+   case VG_SCCWARC_TO: return 5;
+   case VG_SCWARC_TO:  return 5;
+   case VG_LCCWARC_TO: return 5;
+   case VG_LCWARC_TO:  return 5;
+   default:            UNREACHABLE(); return 0;
+   }
+}
+
+static INLINE float get_coord(
+   VGPathDatatype datatype, float scale, float bias,
+   const void **coords)
+{
+   switch (datatype) {
+   case VG_PATH_DATATYPE_S_8:  return bias + (scale * *((*(const int8_t **)coords)++));
+   case VG_PATH_DATATYPE_S_16: return bias + (scale * *((*(const int16_t **)coords)++));
+   case VG_PATH_DATATYPE_S_32: return bias + (scale * *((*(const int32_t **)coords)++));
+   case VG_PATH_DATATYPE_F:    return bias + (scale * *((*(const float **)coords)++));
+   default:                    UNREACHABLE(); return 0.0f;
+   }
+}
+
+static INLINE void put_coord(
+   VGPathDatatype datatype, float oo_scale, float bias,
+   void **coords, float x)
+{
+   x = oo_scale * (x - bias);
+   switch (datatype) {
+   case VG_PATH_DATATYPE_S_8:  *((*(int8_t **)coords)++) = (int8_t)clampi(float_to_int(x), -0x80, 0x7f); break;
+   case VG_PATH_DATATYPE_S_16: *((*(int16_t **)coords)++) = (int16_t)clampi(float_to_int(x), -0x8000, 0x7fff); break;
+   case VG_PATH_DATATYPE_S_32: *((*(int32_t **)coords)++) = float_to_int(x); break;
+   case VG_PATH_DATATYPE_F:    *((*(float **)coords)++) = x; break;
+   default:                    UNREACHABLE();
+   }
+}
+
+static INLINE bool is_paint_modes(uint32_t paint_modes)
+{
+   return paint_modes && !(paint_modes & ~(VG_STROKE_PATH | VG_FILL_PATH));
+}
+
+static INLINE bool is_paint_mode(VGPaintMode paint_mode)
+{
+   return (paint_mode == VG_STROKE_PATH) ||
+          (paint_mode == VG_FILL_PATH);
+}
+
+static INLINE bool is_allowed_quality(uint32_t allowed_quality)
+{
+   return allowed_quality && !(allowed_quality & ~(VG_IMAGE_QUALITY_NONANTIALIASED | VG_IMAGE_QUALITY_FASTER | VG_IMAGE_QUALITY_BETTER));
+}
+
+static INLINE bool is_hardware_query_type(VGHardwareQueryType hardware_query_type)
+{
+   return (hardware_query_type == VG_IMAGE_FORMAT_QUERY) ||
+          (hardware_query_type == VG_PATH_DATATYPE_QUERY);
+}
+
+static INLINE bool is_image_format(VGImageFormat image_format)
+{
+#ifdef __HIGHC__
+   #pragma Offwarn(428) /* unsigned compare with 0 always true */
+#endif
+   return ((image_format >= VG_sRGBX_8888) &&
+          (image_format <= VG_A_4)) ||
+          (image_format == VG_sXRGB_8888) ||
+          (image_format == VG_sARGB_8888) ||
+          (image_format == VG_sARGB_8888_PRE) ||
+          (image_format == VG_sARGB_1555) ||
+          (image_format == VG_sARGB_4444) ||
+          (image_format == VG_lXRGB_8888) ||
+          (image_format == VG_lARGB_8888) ||
+          (image_format == VG_lARGB_8888_PRE) ||
+          (image_format == VG_sBGRX_8888) ||
+          (image_format == VG_sBGRA_8888) ||
+          (image_format == VG_sBGRA_8888_PRE) ||
+          (image_format == VG_sBGR_565) ||
+          (image_format == VG_sBGRA_5551) ||
+          (image_format == VG_sBGRA_4444) ||
+          (image_format == VG_lBGRX_8888) ||
+          (image_format == VG_lBGRA_8888) ||
+          (image_format == VG_lBGRA_8888_PRE) ||
+          (image_format == VG_sXBGR_8888) ||
+          (image_format == VG_sABGR_8888) ||
+          (image_format == VG_sABGR_8888_PRE) ||
+          (image_format == VG_sABGR_1555) ||
+          (image_format == VG_sABGR_4444) ||
+          (image_format == VG_lXBGR_8888) ||
+          (image_format == VG_lABGR_8888) ||
+          (image_format == VG_lABGR_8888_PRE);
+#ifdef __HIGHC__
+   #pragma Popwarn
+#endif
+}
+
+static INLINE bool is_arc_type(VGUArcType arc_type)
+{
+   return (arc_type >= VGU_ARC_OPEN) &&
+          (arc_type <= VGU_ARC_PIE);
+}
+
+static INLINE bool is_mask_operation(VGMaskOperation mask_operation)
+{
+   return (mask_operation >= VG_CLEAR_MASK) &&
+          (mask_operation <= VG_SUBTRACT_MASK);
+}
+
+static INLINE bool is_image_channel(VGImageChannel image_channel)
+{
+   return (image_channel == VG_RED) ||
+          (image_channel == VG_GREEN) ||
+          (image_channel == VG_BLUE) ||
+          (image_channel == VG_ALPHA);
+}
+
+#endif
diff --git a/interface/khronos/wf/wfc_client.c b/interface/khronos/wf/wfc_client.c
new file mode 100755 (executable)
index 0000000..6409242
--- /dev/null
@@ -0,0 +1,2597 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#define VCOS_VERIFY_BKPTS 1
+
+#define VCOS_LOG_CATEGORY (&log_cat)
+
+#include <stdlib.h>
+#include <stddef.h>
+
+#include "interface/khronos/include/WF/wfc.h"
+
+#include "interface/khronos/wf/wfc_client_stream.h"
+#include "interface/khronos/wf/wfc_server_api.h"
+
+//#define WFC_FULL_LOGGING
+#ifdef WFC_FULL_LOGGING
+#define WFC_LOG_LEVEL VCOS_LOG_TRACE
+#else
+#define WFC_LOG_LEVEL VCOS_LOG_WARN
+#endif
+
+//==============================================================================
+
+//!@name
+//! Values used in wfcEnumerateDevices().
+//!@{
+#define WFC_NUM_OF_DEVICES 1
+#define WFC_OUR_DEVICE_ID  1
+//!@}
+
+//!@name
+//! Global mutex
+//!@{
+#define WFC_LOCK()      do {vcos_mutex_lock(&wfc_client_state.mutex);} while (0)
+#define WFC_UNLOCK()    do {vcos_mutex_unlock(&wfc_client_state.mutex);} while (0)
+//!@}
+
+//!@name
+//! Values for wfc_source_or_mask_create()
+//!@{
+#define WFC_IS_SOURCE   1
+#define WFC_IS_MASK     0
+//!@}
+
+//==============================================================================
+
+//! Simple doubly-linked list.
+typedef struct _WFC_LINK
+{
+   struct _WFC_LINK *prev;
+   struct _WFC_LINK *next;
+} WFC_LINK_T;
+
+//! Function pointer type, used when iterating through the linked list in wfc_link_iterate().
+typedef void (*WFC_LINK_CALLBACK_T)(WFC_LINK_T *link, void *arg);
+
+//------------------------------------------------------------------------------
+
+//! WF-C device
+typedef struct
+{
+   WFCErrorCode error;  //!< Error code returned by wfcGetError().
+
+   WFC_LINK_T contexts; //!< Contexts belonging to this device.
+} WFC_DEVICE_T;
+
+#define DEVICE_POOL_COUNT  4
+#define DEVICE_POOL_MAX_SUBPOOLS 4
+
+//! WFCDevice handle modifier
+#define WFC_DEVICE_MOD  0xD0000000
+
+//! WF-C context
+typedef struct
+{
+   WFC_LINK_T link;           //!< Handle of this context within the contexts list.
+
+   WFC_DEVICE_T *device_ptr;  //!< Parent device
+   WFC_LINK_T sources;        //!< List of sources belonging to this context
+   WFC_LINK_T masks;          //!< List of masks belonging to this context
+   WFCNativeStreamType output_stream; //!< For off-screen contexts only, stream to compose into.
+
+   WFC_LINK_T elements_not_in_scene;   //!< List of elements belonging to this context, but not on screen.
+   WFC_LINK_T elements_in_scene;       //!< List of elements belonging to this context and on screen.
+   bool active;                        //!< True if this context has had autonomous composition enabled with wfcActivate().
+
+   WFC_CONTEXT_STATIC_ATTRIB_T static_attributes;  //!< Attributes associated with the context which are fixed on creation.
+   WFC_CONTEXT_DYNAMIC_ATTRIB_T dynamic_attributes;//!< Attributes associated with the context which may change.
+
+   uint32_t commit_count;           //!< Count of commits made
+   WFC_SCENE_T committed_scene;     //!< Last committed scene
+} WFC_CONTEXT_T;
+
+#define CONTEXT_POOL_COUNT 4
+#define CONTEXT_POOL_MAX_SUBPOOLS 4
+
+//! WFCContext handle modifier
+#define WFC_CONTEXT_MOD 0xC0000000
+
+//! WF-C image provider (source or mask)
+typedef struct
+{
+   WFC_LINK_T link;              //!< Handle of this source/mask within the source/mask list.
+   bool is_source;               //!< Indicates if this is a source or a mask.
+
+   WFC_CONTEXT_T *context_ptr;   //!< Parent context
+
+   //!@brief Number of elements using this source/mask.
+   //! Required to ensure that it won't be destroyed while it's still in use.
+   uint32_t refcount;
+
+   WFCNativeStreamType stream;   //!< Stream associated with this source/mask.
+
+   //!@brief Destruction requested.
+   //! Indicates that the source/mask will be destroyed at the earliest opportunity.
+   bool destroy_pending;
+} WFC_SOURCE_OR_MASK_T;
+
+#define SOURCE_POOL_COUNT 16
+#define SOURCE_POOL_MAX_SUBPOOLS 8
+
+//! WFCSource handle modifier
+#define WFC_SOURCE_MOD  0x50000000
+
+//! WF-C element
+typedef struct
+{
+   WFC_LINK_T link;                    //!< Handle of this element within the element list.
+   WFC_CONTEXT_T *context_ptr;         //!< Parent context.
+
+   WFC_SOURCE_OR_MASK_T *source_ptr;   //!< Source associated with this element.
+   WFC_SOURCE_OR_MASK_T *mask_ptr;     //!< Mask associated with this element.
+
+   bool is_in_scene;                   //!< Indicates if this element is within the scene.
+
+   WFC_ELEMENT_ATTRIB_T attributes;    //!< Element attributes.
+} WFC_ELEMENT_T;
+
+#define ELEMENT_POOL_COUNT 16
+#define ELEMENT_POOL_MAX_SUBPOOLS 8
+
+//! WFCElement handle modifier
+#define WFC_ELEMENT_MOD 0xE0000000
+
+//! Global state
+typedef struct
+{
+   bool is_initialised; //!< Set the first time wfcCreateDevice() is called.
+   VCOS_MUTEX_T mutex;  //!< Global mutex.
+   VCOS_UNSIGNED handle_mod;           //!< Process specific handle modifier
+   VCOS_BLOCKPOOL_T device_pool;       //!< Devices allocated by this process
+   VCOS_BLOCKPOOL_T context_pool;      //!< Contexts allocated by this process
+   VCOS_BLOCKPOOL_T element_pool;      //!< Elements allocated by this process
+   VCOS_BLOCKPOOL_T source_pool;       //!< Sources allocated by this process
+} WFC_CLIENT_STATE_T;
+
+//! Blockpool information for initialisation
+typedef struct WFC_BLOCKPOOL_INFO_tag
+{
+   VCOS_BLOCKPOOL_T *pool;
+   VCOS_UNSIGNED size;
+   VCOS_UNSIGNED count;
+   VCOS_UNSIGNED max_subpools;
+   const char *name;
+} WFC_BLOCKPOOL_INFO_T;
+
+//==============================================================================
+
+static VCOS_ONCE_T wfc_client_once;          //!< For initialisation
+static WFC_CLIENT_STATE_T wfc_client_state;  //!< Global state
+
+//! Initialisation data for the client blockpools
+static const WFC_BLOCKPOOL_INFO_T wfc_client_blockpool_info[] = {
+   { &wfc_client_state.device_pool,  sizeof(WFC_DEVICE_T),         DEVICE_POOL_COUNT,  DEVICE_POOL_MAX_SUBPOOLS,  "WFC device pool"  },
+   { &wfc_client_state.context_pool, sizeof(WFC_CONTEXT_T),        CONTEXT_POOL_COUNT, CONTEXT_POOL_MAX_SUBPOOLS, "WFC context pool" },
+   { &wfc_client_state.element_pool, sizeof(WFC_ELEMENT_T),        ELEMENT_POOL_COUNT, ELEMENT_POOL_MAX_SUBPOOLS, "WFC element pool" },
+   { &wfc_client_state.source_pool,  sizeof(WFC_SOURCE_OR_MASK_T), SOURCE_POOL_COUNT,  SOURCE_POOL_MAX_SUBPOOLS,  "WFC source pool"  },
+};
+
+static VCOS_LOG_CAT_T log_cat = VCOS_LOG_INIT("wfc_client_func", WFC_LOG_LEVEL);
+
+//==============================================================================
+//!@name Static functions
+//!@{
+
+static void wfc_initialise_client_state(void);
+static WFC_DEVICE_T *wfc_device_from_handle(WFCDevice dev);
+static WFCDevice wfc_device_to_handle(WFC_DEVICE_T *device_ptr);
+static WFC_CONTEXT_T *wfc_context_from_handle(WFCContext ctx);
+static WFCContext wfc_context_to_handle(WFC_CONTEXT_T *context_ptr);
+static WFC_ELEMENT_T *wfc_element_from_handle(WFCElement element);
+static WFCElement wfc_element_to_handle(WFC_ELEMENT_T *element_ptr);
+static WFCElement wfc_element_link_to_handle(WFC_LINK_T *element_link_ptr);
+static WFC_SOURCE_OR_MASK_T *wfc_source_or_mask_from_handle(WFCHandle source_or_mask);
+static WFCHandle wfc_source_or_mask_to_handle(WFC_SOURCE_OR_MASK_T *source_or_mask_ptr);
+
+static WFC_CONTEXT_T *wfc_context_create
+   (WFC_DEVICE_T *device_ptr, WFCContextType context_type,
+      uint32_t screen_or_stream_num, WFCErrorCode *error);
+static void wfc_context_destroy(WFC_CONTEXT_T *context_ptr);
+
+static WFCHandle wfc_source_or_mask_create(bool is_source, WFCDevice dev, WFCContext ctx,
+      WFCNativeStreamType stream, const WFCint *attribList);
+static void wfc_source_or_mask_destroy(WFCDevice dev, WFCHandle source_or_mask);
+static void wfc_source_or_mask_acquire(WFC_SOURCE_OR_MASK_T *source_or_mask_ptr);
+static void wfc_source_or_mask_release(WFC_SOURCE_OR_MASK_T *source_or_mask_ptr);
+
+static void wfc_element_destroy(WFC_ELEMENT_T *element_ptr, void *unused);
+
+static void wfc_commit_iterator(WFC_ELEMENT_T *element_ptr, WFC_SCENE_T *scene);
+
+static void wfc_set_error_with_location(WFC_DEVICE_T *device, WFCErrorCode error, const char *func, int line);
+
+static bool wfc_check_no_attribs(const WFCint *attribList);
+static bool wfc_is_rotation(WFCint value);
+static bool wfc_is_scale_filter(WFCint value);
+static bool wfc_are_transparency_types(WFCint value);
+
+static int32_t wfc_round(float f);
+
+static void wfc_link_detach(WFC_LINK_T *link);
+static void wfc_link_attach(WFC_LINK_T *link, WFC_LINK_T *prev);
+static void wfc_link_init_null(WFC_LINK_T *link);
+static void wfc_link_init_empty(WFC_LINK_T *link);
+static void wfc_link_iterate(WFC_LINK_T *link, WFC_LINK_CALLBACK_T func, void *arg);
+
+static void wfc_source_or_mask_destroy_actual
+   (WFC_SOURCE_OR_MASK_T *source_or_mask_ptr, void *unused);
+
+static void wfc_client_scene_taken_cb(void *cb_data);
+static void wfc_client_wait_for_scene_taken(VCOS_SEMAPHORE_T *wait_sem, WFCContext ctx,
+      const char *calling_function);
+
+#define wfc_set_error(D, E) wfc_set_error_with_location(D, E, __FILE__, __LINE__)
+
+//!@} // (Static functions)
+
+//!@name OpenWF-C API functions
+//! Refer to the <a href="http://www.khronos.org/registry/wf/">OpenWF-C specification</a> for details.
+//!@{
+//==============================================================================
+// Device functions
+
+WFC_API_CALL WFCint WFC_APIENTRY
+    wfcEnumerateDevices(WFCint *deviceIds, WFCint deviceIdsCount,
+        const WFCint *filterList) WFC_APIEXIT
+{
+   bool filters_valid = true;
+
+   // Check for valid filter list. Somewhat redundant, as there is only one device,
+   // and it supports all screens.
+   if(filterList != NULL)
+   {
+      filters_valid &= (*filterList == WFC_DEVICE_FILTER_SCREEN_NUMBER);
+      filterList++;
+      filters_valid &= ((*filterList >= 0) && (*filterList <= WFC_ID_MAX_SCREENS));
+      filterList++;
+      filters_valid &= (*filterList == WFC_NONE);
+   } // if
+
+   if(vcos_verify(filters_valid))
+   {
+      if(deviceIds != NULL)
+      {
+         if(deviceIdsCount > 0)
+         {
+            *deviceIds = WFC_OUR_DEVICE_ID;
+            return WFC_NUM_OF_DEVICES;
+         } // if
+         else
+            {return 0;}
+      } // if
+      else
+         {return WFC_NUM_OF_DEVICES;}
+   } // if
+
+   return 0;
+} // wfcEnumerateDevices()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL WFCDevice WFC_APIENTRY
+    wfcCreateDevice(WFCint deviceId, const WFCint *attribList) WFC_APIEXIT
+{
+   WFCDevice result = WFC_INVALID_HANDLE;
+
+   // This function will be called before anything else can be created, so is
+   // a good place to initialise the state.
+   vcos_once(&wfc_client_once, wfc_initialise_client_state);
+
+   if (!wfc_client_state.is_initialised)
+      return WFC_INVALID_HANDLE;
+
+   WFC_LOCK();
+
+   if ((deviceId == WFC_DEFAULT_DEVICE_ID || deviceId == WFC_OUR_DEVICE_ID)
+      && wfc_check_no_attribs(attribList))
+   {
+      WFC_DEVICE_T *device = vcos_blockpool_calloc(&wfc_client_state.device_pool);
+
+      if(vcos_verify(device != NULL))
+      {
+         if (wfc_server_connect() != VCOS_SUCCESS)
+         {
+            vcos_blockpool_free(device);
+            vcos_log_error("%s: failed to connect to server", VCOS_FUNCTION);
+         }
+         else
+         {
+            device->error = WFC_ERROR_NONE;
+            wfc_link_init_empty(&device->contexts);
+            result = wfc_device_to_handle(device);
+         }
+      } // if
+   } // if
+
+   WFC_UNLOCK();
+
+   return result;
+} // wfcCreateDevice()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL WFCErrorCode WFC_APIENTRY
+    wfcGetError(WFCDevice dev) WFC_APIEXIT
+{
+   WFCErrorCode result;
+
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+
+   if(vcos_verify(device_ptr != NULL))
+   {
+      result = device_ptr->error;
+      device_ptr->error = WFC_ERROR_NONE;
+   } // if
+   else
+      {result = WFC_ERROR_BAD_DEVICE;}
+
+   WFC_UNLOCK();
+
+   return result;
+} // wfcGetError()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL WFCint WFC_APIENTRY
+    wfcGetDeviceAttribi(WFCDevice dev, WFCDeviceAttrib attrib) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      // Behaviour is unspecified if dev is null, so do something sensible.
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return 0;
+   }
+
+   WFCint result = 0;
+
+   switch (attrib)
+   {
+      case WFC_DEVICE_CLASS:
+         result = WFC_DEVICE_CLASS_FULLY_CAPABLE;
+         break;
+      case WFC_DEVICE_ID:
+         result = WFC_OUR_DEVICE_ID;
+         break;
+      default:
+         wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
+   } // switch
+
+   WFC_UNLOCK();
+
+   return result;
+} // wfcGetDeviceAttribi()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL WFCErrorCode WFC_APIENTRY
+    wfcDestroyDevice(WFCDevice dev) WFC_APIEXIT
+{
+   WFCErrorCode result;
+
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+
+   if(vcos_verify(device_ptr != NULL))
+   {
+      // Destroy all of the contexts associated with the device. This will in turn
+      // destroy all of the sources, masks and elements associated with each context.
+      wfc_link_iterate(&device_ptr->contexts, (WFC_LINK_CALLBACK_T) wfc_context_destroy, NULL);
+
+      vcos_blockpool_free(device_ptr);
+
+      wfc_server_disconnect();
+
+      result = WFC_ERROR_NONE;
+   } // if
+   else
+      {result = WFC_ERROR_BAD_DEVICE;}
+
+   WFC_UNLOCK();
+
+   return result;
+} // wfcDestroyDevice()
+
+//==============================================================================
+// Context functions
+
+WFC_API_CALL WFCContext WFC_APIENTRY
+    wfcCreateOnScreenContext(WFCDevice dev,
+        WFCint screenNumber,
+        const WFCint *attribList) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return WFC_INVALID_HANDLE;
+   }
+
+   WFCContext context = WFC_INVALID_HANDLE;
+
+   if (screenNumber < 0 || screenNumber >= WFC_ID_MAX_SCREENS)
+      {wfc_set_error(device_ptr, WFC_ERROR_UNSUPPORTED);}
+   else if (!wfc_check_no_attribs(attribList))
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);}
+   else
+   {
+      WFC_CONTEXT_T *context_ptr;
+
+      WFCErrorCode error;
+
+      // Create on-screen context_ptr
+      context_ptr = wfc_context_create
+         (device_ptr, WFC_CONTEXT_TYPE_ON_SCREEN, screenNumber, &error);
+
+      // Insert new context_ptr into list of contexts
+      if(context_ptr)
+      {
+         wfc_link_attach(&context_ptr->link, &device_ptr->contexts);
+
+         context = wfc_context_to_handle(context_ptr);
+      } // if
+      else
+         {wfc_set_error(device_ptr, error);}
+   } // else
+
+   WFC_UNLOCK();
+
+   return context;
+} // wfcCreateOnScreenContext()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL WFCContext WFC_APIENTRY
+    wfcCreateOffScreenContext(WFCDevice dev,
+        WFCNativeStreamType stream,
+        const WFCint *attribList) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return WFC_INVALID_HANDLE;
+   }
+
+   WFCContext context = WFC_INVALID_HANDLE;
+
+   if(stream == WFC_INVALID_HANDLE)
+      {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
+   else if(wfc_stream_used_for_off_screen(stream))
+      {wfc_set_error(device_ptr, WFC_ERROR_IN_USE);}
+   else if (!wfc_check_no_attribs(attribList))
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);}
+   else
+   {
+      WFC_CONTEXT_T *context_ptr;
+
+      WFCErrorCode error;
+
+      // Create on-screen context_ptr
+      context_ptr = wfc_context_create
+         (device_ptr, WFC_CONTEXT_TYPE_OFF_SCREEN, stream, &error);
+
+      // Insert new context_ptr into list of contexts
+      if(context_ptr)
+      {
+         wfc_link_attach(&context_ptr->link, &device_ptr->contexts);
+
+         context = wfc_context_to_handle(context_ptr);
+
+         wfc_stream_register_off_screen(stream, true);
+      } // if
+      else
+         {wfc_set_error(device_ptr, error);}
+   } // else
+
+   WFC_UNLOCK();
+
+   return context;
+} // wfcCreateOffScreenContext()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL void WFC_APIENTRY
+    wfcCommit(WFCDevice dev, WFCContext ctx, WFCboolean wait) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
+   VCOS_STATUS_T status = VCOS_ENOSYS;
+   VCOS_SEMAPHORE_T wait_sem;
+   WFCboolean wait_for_sem = WFC_FALSE;
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return;
+   }
+
+   // Send data for all elements
+   if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
+   {
+      WFC_SCENE_T *scene = &context_ptr->committed_scene;
+
+      memset(scene, 0, sizeof(*scene));
+      // Store scene in committed_scene structure
+      memcpy(&scene->context, &context_ptr->dynamic_attributes, sizeof(WFC_CONTEXT_DYNAMIC_ATTRIB_T));
+      scene->element_count = 0;
+      scene->commit_count = context_ptr->commit_count++;
+      wfc_link_iterate(&context_ptr->elements_in_scene,
+         (WFC_LINK_CALLBACK_T) wfc_commit_iterator, scene);
+
+      vcos_log_info("%s: dev 0x%X, ctx 0x%X commit %u", VCOS_FUNCTION, dev, ctx, context_ptr->committed_scene.commit_count);
+
+      if (context_ptr->active)
+      {
+         uint32_t commit_flags = WFC_SERVER_COMMIT_COMPOSE;
+
+         if (wait)
+         {
+            commit_flags |= WFC_SERVER_COMMIT_WAIT;
+
+            // Long running operation, so keep VC alive until it completes.
+            wfc_server_use_keep_alive();
+
+            status = vcos_semaphore_create(&wait_sem, "WFC commit", 0);
+            vcos_assert(status == VCOS_SUCCESS);   // On platforms we care about.
+            wait_for_sem = WFC_TRUE;
+
+            do
+            {
+               status = wfc_server_commit_scene(ctx, &context_ptr->committed_scene,
+                     commit_flags, wfc_client_scene_taken_cb, &wait_sem);
+
+               if (status == VCOS_EAGAIN)
+               {
+                  // Another thread is competing for access to the context, so
+                  // wait a little and try again.
+                  vcos_sleep(1);
+               }
+            }
+            while (status == VCOS_EAGAIN);
+
+            if (status != VCOS_SUCCESS)
+            {
+               wait_for_sem = WFC_FALSE;
+               wfc_server_release_keep_alive();
+               vcos_semaphore_delete(&wait_sem);
+            }
+         }
+         else
+         {
+            status = wfc_server_commit_scene(ctx, &context_ptr->committed_scene,
+                  commit_flags, NULL, NULL);
+         }
+
+         if (status != VCOS_SUCCESS)
+         {
+            vcos_log_info("%s: failed to compose scene: %d", VCOS_FUNCTION, status);
+            wfc_set_error(device_ptr, WFC_ERROR_BUSY);
+         }
+      }
+   } // if
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+
+   // Wait for the scene to be taken outside the lock
+   if (wait_for_sem)
+   {
+      wfc_client_wait_for_scene_taken(&wait_sem, ctx, VCOS_FUNCTION);
+   }
+
+   vcos_log_trace("%s: complete", VCOS_FUNCTION);
+} // wfcCommit()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL WFCint WFC_APIENTRY
+    wfcGetContextAttribi(WFCDevice dev, WFCContext ctx,
+        WFCContextAttrib attrib) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
+   WFCint result = 0;
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return result;
+   }
+
+   if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
+   {
+      switch (attrib)
+      {
+         case WFC_CONTEXT_TYPE:
+            result = context_ptr->static_attributes.type;
+            break;
+         case WFC_CONTEXT_TARGET_WIDTH:
+            result = context_ptr->static_attributes.width;
+            break;
+         case WFC_CONTEXT_TARGET_HEIGHT:
+            result = context_ptr->static_attributes.height;
+            break;
+         case WFC_CONTEXT_LOWEST_ELEMENT:
+         {
+            WFC_LINK_T *first = &context_ptr->elements_in_scene;
+            WFC_LINK_T *current = first;
+
+            if(first->next == first)
+            {
+               // List is empty.
+               result = WFC_INVALID_HANDLE;
+            } // if
+            else
+            {
+               // First element in list is the lowest.
+               result = (WFCint) wfc_element_link_to_handle(current->next);
+            } // else
+            break;
+         }
+         case WFC_CONTEXT_ROTATION:
+            result = context_ptr->dynamic_attributes.rotation;
+            break;
+         case WFC_CONTEXT_BG_COLOR:
+            result = (WFCint) (context_ptr->dynamic_attributes.background_clr[WFC_BG_CLR_RED]    * 255.0f) << 24 |
+                     (WFCint) (context_ptr->dynamic_attributes.background_clr[WFC_BG_CLR_GREEN]  * 255.0f) << 16 |
+                     (WFCint) (context_ptr->dynamic_attributes.background_clr[WFC_BG_CLR_BLUE]   * 255.0f) << 8  |
+                     (WFCint) (context_ptr->dynamic_attributes.background_clr[WFC_BG_CLR_ALPHA]  * 255.0f);
+            break;
+         default:
+            wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
+            break;
+      } // switch
+   } // if
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+
+   return result;
+} // wfcGetContextAttribi()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL void WFC_APIENTRY
+    wfcGetContextAttribfv(WFCDevice dev, WFCContext ctx,
+        WFCContextAttrib attrib, WFCint count, WFCfloat *values) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return;
+   }
+
+   if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
+   {
+      uint32_t i;
+
+      switch (attrib)
+      {
+         case WFC_CONTEXT_BG_COLOR:
+            if(vcos_verify(values != NULL) &&
+               vcos_verify(((uint32_t) values & 0x3) == 0) &&
+               vcos_verify(count == WFC_BG_CLR_SIZE))
+            {
+               for (i = 0; i < WFC_BG_CLR_SIZE; i++)
+                  {values[i] = context_ptr->dynamic_attributes.background_clr[i];}
+            } // if
+            else
+               {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
+            break;
+         default:
+            wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
+            break;
+      } // switch
+   }
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+} // wfcGetContextAttribfv()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL void WFC_APIENTRY
+    wfcSetContextAttribi(WFCDevice dev, WFCContext ctx,
+        WFCContextAttrib attrib, WFCint value) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return;
+   }
+
+   if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
+   {
+      switch(attrib)
+      {
+         case WFC_CONTEXT_ROTATION:
+            if(wfc_is_rotation(value))
+               {context_ptr->dynamic_attributes.rotation = value;}
+            else
+               {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
+            break;
+         case WFC_CONTEXT_BG_COLOR:
+         {
+            int32_t i;
+            for(i = WFC_BG_CLR_SIZE - 1; i >= 0; i--)
+            {
+               context_ptr->dynamic_attributes.background_clr[i]
+                  = ((float) (value & 0xff)) / 255.0f;
+               value >>= 8;
+            } // for
+            break;
+         }
+         default:
+            wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
+            break;
+      } // switch
+   } // if
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+} // wfcSetContextAttribi()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL void WFC_APIENTRY
+    wfcSetContextAttribfv(WFCDevice dev, WFCContext ctx,
+        WFCContextAttrib attrib,
+        WFCint count, const WFCfloat *values) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return;
+   }
+
+   if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
+   {
+      int i;
+
+      switch (attrib)
+      {
+         case WFC_CONTEXT_BG_COLOR:
+            if(vcos_verify((values != NULL) && (((uint32_t) values & 0x3) == 0)
+               && (count == WFC_BG_CLR_SIZE)))
+            {
+               for (i = 0; i < WFC_BG_CLR_SIZE; i++)
+                  {context_ptr->dynamic_attributes.background_clr[i] = values[i];}
+            } // if
+            else
+               {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
+            break;
+         default:
+            wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
+            break;
+      } // switch
+   } // if
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+} // wfcSetContextAttribfv()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL void WFC_APIENTRY
+    wfcDestroyContext(WFCDevice dev, WFCContext ctx) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
+
+   vcos_log_trace("%s: context = 0x%X", VCOS_FUNCTION, ctx);
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return;
+   }
+
+   if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
+   {
+      wfc_context_destroy(context_ptr);
+   }
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+} // wfcDestroyContext()
+
+//==============================================================================
+// Source functions
+
+WFC_API_CALL WFCSource WFC_APIENTRY wfcCreateSourceFromStream(WFCDevice dev, WFCContext ctx,
+        WFCNativeStreamType stream,
+        const WFCint *attribList) WFC_APIEXIT
+{
+   WFCSource source;
+
+   WFC_LOCK();
+
+   source = (WFCSource) wfc_source_or_mask_create(WFC_IS_SOURCE, dev, ctx, stream, attribList);
+
+   WFC_UNLOCK();
+
+   return source;
+} // wfcCreateSourceFromStream()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL void WFC_APIENTRY
+    wfcDestroySource(WFCDevice dev, WFCSource src) WFC_APIEXIT
+{
+   vcos_log_trace("%s: source = 0x%X", VCOS_FUNCTION, src);
+
+   WFC_LOCK();
+   wfc_source_or_mask_destroy(dev, (WFCHandle) src);
+   WFC_UNLOCK();
+} // wfcDestroySource()
+
+//==============================================================================
+// Mask functions
+
+WFC_API_CALL WFCMask WFC_APIENTRY
+    wfcCreateMaskFromStream(WFCDevice dev, WFCContext ctx,
+        WFCNativeStreamType stream,
+        const WFCint *attribList) WFC_APIEXIT
+{
+   WFCMask mask;
+
+   WFC_LOCK();
+
+   mask = (WFCMask) wfc_source_or_mask_create(WFC_IS_MASK, dev, ctx, stream, attribList);
+
+   WFC_UNLOCK();
+
+   return mask;
+} // wfcCreateMaskFromStream()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL void WFC_APIENTRY
+    wfcDestroyMask(WFCDevice dev, WFCMask msk) WFC_APIEXIT
+{
+   WFC_LOCK();
+   wfc_source_or_mask_destroy(dev, (WFCHandle) msk);
+   WFC_UNLOCK();
+} // wfcDestroyMask()
+
+//==============================================================================
+// Element functions
+
+WFC_API_CALL WFCElement WFC_APIENTRY
+    wfcCreateElement(WFCDevice dev, WFCContext ctx,
+        const WFCint *attribList) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
+
+   WFCElement element = WFC_INVALID_HANDLE;
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return WFC_INVALID_HANDLE;
+   }
+
+   if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
+   {
+      if(wfc_check_no_attribs(attribList))
+      {
+         WFC_ELEMENT_T *element_ptr = vcos_blockpool_calloc(&wfc_client_state.element_pool);
+         const WFC_ELEMENT_ATTRIB_T element_attrib_default = WFC_ELEMENT_ATTRIB_DEFAULT;
+
+         if(element_ptr != NULL)
+         {
+            wfc_link_init_null(&element_ptr->link);
+            element_ptr->context_ptr = context_ptr;
+            element_ptr->attributes = element_attrib_default;
+
+            wfc_link_attach(&element_ptr->link, &context_ptr->elements_not_in_scene);
+
+            element = wfc_element_to_handle(element_ptr);
+         } // if
+         else
+            {wfc_set_error(device_ptr, WFC_ERROR_OUT_OF_MEMORY);}
+      } // if
+      else
+         {wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);}
+   } // if
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+
+   return element;
+} // wfcCreateElement()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL WFCint WFC_APIENTRY
+    wfcGetElementAttribi(WFCDevice dev, WFCElement elm,
+        WFCElementAttrib attrib) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
+
+   WFCint result = 0;
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return result;
+   }
+
+   if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
+      && (element_ptr->context_ptr->device_ptr == device_ptr)))
+   {
+      switch (attrib)
+      {
+         case WFC_ELEMENT_SOURCE:
+            result = (WFCint)wfc_source_or_mask_to_handle(element_ptr->source_ptr);
+            break;
+         case WFC_ELEMENT_SOURCE_FLIP:
+            result = element_ptr->attributes.flip;
+            break;
+         case WFC_ELEMENT_SOURCE_ROTATION:
+            result = element_ptr->attributes.rotation;
+            break;
+         case WFC_ELEMENT_SOURCE_SCALE_FILTER:
+            result = element_ptr->attributes.scale_filter;
+            break;
+         case WFC_ELEMENT_TRANSPARENCY_TYPES:
+            result = element_ptr->attributes.transparency_types;
+            break;
+         case WFC_ELEMENT_GLOBAL_ALPHA:
+            result = wfc_round(element_ptr->attributes.global_alpha * 255.0f);
+            break;
+         case WFC_ELEMENT_MASK:
+            result = (WFCint)wfc_source_or_mask_to_handle(element_ptr->mask_ptr);
+            break;
+         default:
+            wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
+            break;
+      } // switch
+   } // if
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+
+   return result;
+} // wfcGetElementAttribi()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL WFCfloat WFC_APIENTRY
+    wfcGetElementAttribf(WFCDevice dev, WFCElement elm,
+        WFCElementAttrib attrib) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
+
+   WFCfloat result = 0;
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return result;
+   }
+
+   if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
+      && (element_ptr->context_ptr->device_ptr == device_ptr)))
+   {
+      switch (attrib) {
+      case WFC_ELEMENT_GLOBAL_ALPHA:
+         result = element_ptr->attributes.global_alpha;
+         break;
+      default:
+         wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
+         break;
+      }
+   }
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+
+   return result;
+} // wfcGetElementAttribf()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL void WFC_APIENTRY
+    wfcGetElementAttribiv(WFCDevice dev, WFCElement elm,
+        WFCElementAttrib attrib, WFCint count, WFCint *values) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return;
+   }
+
+   if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
+      && (element_ptr->context_ptr->device_ptr == device_ptr)))
+   {
+      int i;
+
+      switch (attrib) {
+      case WFC_ELEMENT_DESTINATION_RECTANGLE:
+         if (values && count == WFC_RECT_SIZE)
+            for (i = 0; i < WFC_RECT_SIZE; i++)
+               values[i] = element_ptr->attributes.dest_rect[i];
+         else
+            wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
+         break;
+      case WFC_ELEMENT_SOURCE_RECTANGLE:
+         if (values && !((size_t)values & 3) && count == WFC_RECT_SIZE)
+         {
+            for (i = 0; i < WFC_RECT_SIZE; i++)
+               values[i] = (WFCint) element_ptr->attributes.src_rect[i];
+         } // if
+         else
+            wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
+         break;
+      default:
+         wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
+         break;
+      }
+   }
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+} // wfcGetElementAttribiv()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL void WFC_APIENTRY
+    wfcGetElementAttribfv(WFCDevice dev, WFCElement elm,
+        WFCElementAttrib attrib, WFCint count, WFCfloat *values) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return;
+   }
+
+   if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
+      && (element_ptr->context_ptr->device_ptr == device_ptr)))
+   {
+      uint32_t i;
+
+      switch(attrib)
+      {
+         case WFC_ELEMENT_DESTINATION_RECTANGLE:
+            if(values && !((size_t)values & 3) && (count == WFC_RECT_SIZE))
+            {
+               for (i = 0; i < WFC_RECT_SIZE; i++)
+                  {values[i] = (WFCfloat) element_ptr->attributes.dest_rect[i];}
+            } // if
+            else
+               {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
+            break;
+         case WFC_ELEMENT_SOURCE_RECTANGLE:
+            if(values && !((size_t)values & 3) && (count == WFC_RECT_SIZE))
+            {
+               for (i = 0; i < WFC_RECT_SIZE; i++)
+                  {values[i] = element_ptr->attributes.src_rect[i];}
+            } // if
+            else
+               {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
+            break;
+         default:
+            wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
+            break;
+      } // switch
+   } // if
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+} // wfcGetElementAttribfv()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL void WFC_APIENTRY
+    wfcSetElementAttribi(WFCDevice dev, WFCElement elm,
+        WFCElementAttrib attrib, WFCint value) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return;
+   }
+
+   if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
+      && (element_ptr->context_ptr->device_ptr == device_ptr)))
+   {
+      switch (attrib)
+      {
+         case WFC_ELEMENT_SOURCE:
+         {
+            WFC_SOURCE_OR_MASK_T *new_source_ptr = wfc_source_or_mask_from_handle(value);
+
+            if
+            (
+               ((new_source_ptr != NULL) && (element_ptr->context_ptr == new_source_ptr->context_ptr))
+               || (new_source_ptr == NULL)
+            )
+            {
+               wfc_source_or_mask_acquire(new_source_ptr);
+               wfc_source_or_mask_release(element_ptr->source_ptr);
+               element_ptr->source_ptr = new_source_ptr;
+
+               element_ptr->attributes.source_stream =
+                  element_ptr->source_ptr ? element_ptr->source_ptr->stream : WFC_INVALID_HANDLE;
+            } // if
+            else
+               {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
+            break;
+         }
+         case WFC_ELEMENT_SOURCE_FLIP:
+         {
+            if (value == WFC_FALSE || value == WFC_TRUE)
+               element_ptr->attributes.flip = value;
+            else
+               wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
+
+            break;
+         }
+         case WFC_ELEMENT_SOURCE_ROTATION:
+         {
+            if (wfc_is_rotation(value))
+               element_ptr->attributes.rotation = value;
+            else
+               wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
+
+            break;
+         }
+         case WFC_ELEMENT_SOURCE_SCALE_FILTER:
+         {
+            if (wfc_is_scale_filter(value))
+               element_ptr->attributes.scale_filter = value;
+            else
+               wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
+
+            break;
+         }
+         case WFC_ELEMENT_TRANSPARENCY_TYPES:
+         {
+            if (wfc_are_transparency_types(value))
+               element_ptr->attributes.transparency_types = value;
+            else
+               wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
+
+            break;
+         }
+         case WFC_ELEMENT_GLOBAL_ALPHA:
+         {
+            if (value >= 0 && value <= 255)
+               element_ptr->attributes.global_alpha = (float)value / 255.0f;
+            else
+               wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
+
+            break;
+         }
+         case WFC_ELEMENT_MASK:
+         {
+            WFC_SOURCE_OR_MASK_T *new_mask_ptr = wfc_source_or_mask_from_handle(value);
+
+            if
+            (
+               ((new_mask_ptr != NULL) && (element_ptr->context_ptr == new_mask_ptr->context_ptr))
+               || (new_mask_ptr == NULL)
+            )
+            {
+               wfc_source_or_mask_release(element_ptr->mask_ptr);
+               element_ptr->mask_ptr = new_mask_ptr;
+               wfc_source_or_mask_acquire(element_ptr->mask_ptr);
+
+               element_ptr->attributes.mask_stream =
+                  element_ptr->mask_ptr ? element_ptr->mask_ptr->stream : WFC_INVALID_HANDLE;
+            } // if
+            else
+               {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
+            break;
+         }
+         default:
+            wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
+            break;
+      } // switch
+   } // if
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+} // wfcSetElementAttribi()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL void WFC_APIENTRY
+    wfcSetElementAttribf(WFCDevice dev, WFCElement elm,
+        WFCElementAttrib attrib, WFCfloat value) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return;
+   }
+
+   if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
+      && (element_ptr->context_ptr->device_ptr == device_ptr)))
+   {
+      switch(attrib)
+      {
+         case WFC_ELEMENT_GLOBAL_ALPHA:
+            if (value >= 0.0f && value <= 1.0f)
+               element_ptr->attributes.global_alpha = value;
+            else
+               wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
+            break;
+         default:
+            wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
+            break;
+      } // switch
+   } // if
+   else
+      wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);
+
+   WFC_UNLOCK();
+} // wfcSetElementAttribf()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL void WFC_APIENTRY
+    wfcSetElementAttribiv(WFCDevice dev, WFCElement elm,
+        WFCElementAttrib attrib,
+        WFCint count, const WFCint *values) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return;
+   }
+
+   if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
+      && (element_ptr->context_ptr->device_ptr == device_ptr)))
+   {
+      uint32_t i;
+
+      switch (attrib) {
+      case WFC_ELEMENT_DESTINATION_RECTANGLE:
+         if (values && !((size_t)values & 3) && count == WFC_RECT_SIZE)
+         {
+            for (i = 0; i < WFC_RECT_SIZE; i++)
+               {element_ptr->attributes.dest_rect[i] = values[i];}
+         } // if
+         else
+            {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
+         break;
+      case WFC_ELEMENT_SOURCE_RECTANGLE:
+         if (values && !((size_t)values & 3) && count == WFC_RECT_SIZE)
+         {
+            // TODO verify that source rectangle is within the source image.
+            for (i = 0; i < WFC_RECT_SIZE; i++)
+               {element_ptr->attributes.src_rect[i] = (float)values[i];}
+         } // if
+         else
+            {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
+         break;
+      default:
+         wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
+         break;
+      } // switch
+   } // if
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+} // wfcSetElementAttribiv()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL void WFC_APIENTRY
+    wfcSetElementAttribfv(WFCDevice dev, WFCElement elm,
+        WFCElementAttrib attrib,
+        WFCint count, const WFCfloat *values) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return;
+   }
+
+   if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
+      && (element_ptr->context_ptr->device_ptr == device_ptr)))
+   {
+      uint32_t i;
+
+      switch (attrib)
+      {
+         case WFC_ELEMENT_DESTINATION_RECTANGLE:
+            if (values && !((size_t)values & 3) && count == WFC_RECT_SIZE)
+            {
+               for (i = 0; i < WFC_RECT_SIZE; i++)
+                  {element_ptr->attributes.dest_rect[i] = (int)values[i];}
+            } // if
+            else
+               {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
+            break;
+         case WFC_ELEMENT_SOURCE_RECTANGLE:
+            if (values && !((size_t)values & 3) && count == WFC_RECT_SIZE)
+            {
+               // TODO verify that source rectangle is within the source image.
+               // Note that these are floats, so check if difference is < 0.00001,
+               // as per spec, p37 (PDF p42)
+               for (i = 0; i < WFC_RECT_SIZE; i++)
+                  {element_ptr->attributes.src_rect[i] = values[i];}
+            } // if
+            else
+               {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
+            break;
+         default:
+            wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
+            break;
+      } // switch
+   } // if
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+} // wfcSetElementAttribfv()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL void WFC_APIENTRY
+    wfcInsertElement(WFCDevice dev, WFCElement elm, WFCElement subordinate) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
+   WFC_ELEMENT_T *subordinate_ptr = wfc_element_from_handle(subordinate);
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return;
+   }
+
+   if(vcos_verify
+   (
+      (element_ptr != NULL) && (element_ptr->context_ptr != NULL)
+         && (element_ptr->context_ptr->device_ptr == device_ptr)
+      &&
+      (
+         (subordinate_ptr == NULL)
+         || ((subordinate_ptr->context_ptr != NULL)
+            && (subordinate_ptr->context_ptr->device_ptr == device_ptr))
+      )
+   ))
+   {
+      if(subordinate_ptr != NULL)
+      {
+         // Insert element after subordinate.
+         if((element_ptr->context_ptr == subordinate_ptr->context_ptr) && subordinate_ptr->is_in_scene)
+         {
+            // Insert element in front of itself has no effect.
+            if (elm != subordinate)
+            {
+               wfc_link_attach(&element_ptr->link, &subordinate_ptr->link);
+               element_ptr->is_in_scene = true;
+            }
+         }
+         else
+            {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
+      } // if
+      else
+      {
+         // Insert at the "bottom of the scene" - which is the end of the list.
+         wfc_link_attach(&element_ptr->link, &element_ptr->context_ptr->elements_in_scene);
+         element_ptr->is_in_scene = true;
+      } // else
+   }
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+} // wfcInsertElement()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL void WFC_APIENTRY
+    wfcRemoveElement(WFCDevice dev, WFCElement elm) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return;
+   }
+
+   if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
+      && (element_ptr->context_ptr->device_ptr == device_ptr)))
+   {
+      wfc_link_attach(&element_ptr->link, &element_ptr->context_ptr->elements_not_in_scene);
+      element_ptr->is_in_scene = false;
+   }
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+} // wfcRemoveElement()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL WFCElement WFC_APIENTRY
+    wfcGetElementAbove(WFCDevice dev, WFCElement elm) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
+
+   WFCElement result = WFC_INVALID_HANDLE;
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return result;
+   }
+
+   if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
+      && (element_ptr->context_ptr->device_ptr == device_ptr)))
+   {
+      if (element_ptr->is_in_scene)
+      {
+         if (element_ptr->link.next != &element_ptr->context_ptr->elements_in_scene)
+            {result = wfc_element_link_to_handle(element_ptr->link.next);}
+      }
+      else
+         {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
+   }
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+
+   return result;
+} // wfcGetElementAbove()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL WFCElement WFC_APIENTRY
+    wfcGetElementBelow(WFCDevice dev, WFCElement elm) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
+
+   WFCElement result = WFC_INVALID_HANDLE;
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return result;
+   }
+
+   if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
+      && (element_ptr->context_ptr->device_ptr == device_ptr)))
+   {
+      if (element_ptr->is_in_scene)
+      {
+         if (element_ptr->link.prev != &element_ptr->context_ptr->elements_in_scene)
+            {result = wfc_element_link_to_handle(element_ptr->link.prev);}
+      }
+      else
+         {wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);}
+   }
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+
+   return result;
+} // wfcGetElementBelow()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL void WFC_APIENTRY
+    wfcDestroyElement(WFCDevice dev, WFCElement elm) WFC_APIEXIT
+{
+   vcos_log_trace("%s: element = 0x%X", VCOS_FUNCTION, elm);
+
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_ELEMENT_T *element_ptr = wfc_element_from_handle(elm);
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return;
+   }
+
+   if(vcos_verify((element_ptr != NULL) && (element_ptr->context_ptr != NULL)
+      && (element_ptr->context_ptr->device_ptr == device_ptr)))
+      {wfc_element_destroy(element_ptr, NULL);}
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+} // wfcDestroyElement()
+
+//==============================================================================
+// Rendering
+
+WFC_API_CALL void WFC_APIENTRY
+    wfcActivate(WFCDevice dev, WFCContext ctx) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
+   VCOS_STATUS_T status = VCOS_ENOSYS;
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return;
+   }
+
+   if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
+   {
+      wfc_server_activate(ctx);
+
+      context_ptr->active = true;
+
+      do
+      {
+         vcos_log_info("%s: dev 0x%X, ctx 0x%X commit %u", VCOS_FUNCTION, dev, ctx, context_ptr->committed_scene.commit_count);
+
+         status = wfc_server_commit_scene(ctx, &context_ptr->committed_scene,
+               0, NULL, NULL);
+
+         if (status == VCOS_EAGAIN)
+         {
+            // Another thread is competing for access to the context, so
+            // wait a little and try again.
+            vcos_sleep(1);
+         }
+      }
+      while (status == VCOS_EAGAIN);
+
+      if (status != VCOS_SUCCESS)
+      {
+         wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);
+      }
+   } //if
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+} // wfcActivate()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL void WFC_APIENTRY
+    wfcDeactivate(WFCDevice dev, WFCContext ctx) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return;
+   }
+
+   if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
+   {
+      wfc_server_deactivate(ctx);
+
+      context_ptr->active = false;
+   } else
+      wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);
+
+   WFC_UNLOCK();
+} // wfcDeactivate()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL void WFC_APIENTRY
+    wfcCompose(WFCDevice dev, WFCContext ctx, WFCboolean wait) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
+   VCOS_STATUS_T status = VCOS_ENOSYS;
+   VCOS_SEMAPHORE_T wait_sem;
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return;
+   }
+
+   if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
+   {
+      // Only tell the server to compose if the context is not active, since it will
+      // be automatically composed on commit when active
+      if(!context_ptr->active)
+      {
+         uint32_t commit_flags = WFC_SERVER_COMMIT_COMPOSE;
+
+         vcos_log_info("%s: dev 0x%X, ctx 0x%X commit %u", VCOS_FUNCTION, dev, ctx, context_ptr->committed_scene.commit_count);
+
+         if (wait)
+         {
+            commit_flags |= WFC_SERVER_COMMIT_WAIT;
+
+            // Long running operation, so keep VC alive until it completes.
+            wfc_server_use_keep_alive();
+
+            status = vcos_semaphore_create(&wait_sem, "WFC compose", 0);
+            vcos_assert(status == VCOS_SUCCESS);   // On platforms we care about.
+
+            do
+            {
+               status = wfc_server_commit_scene(ctx, &context_ptr->committed_scene,
+                     commit_flags, wfc_client_scene_taken_cb, &wait_sem);
+
+               if (status == VCOS_EAGAIN)
+               {
+                  // Another thread is competing for access to the context, so
+                  // wait a little and try again.
+                  vcos_sleep(1);
+               }
+            }
+            while (status == VCOS_EAGAIN);
+
+            if (status != VCOS_SUCCESS)
+            {
+               vcos_semaphore_delete(&wait_sem);
+               wfc_server_release_keep_alive();
+            }
+         }
+         else
+         {
+            status = wfc_server_commit_scene(ctx, &context_ptr->committed_scene,
+                  commit_flags, NULL, NULL);
+         }
+
+         if (status != VCOS_SUCCESS)
+         {
+            vcos_log_info("%s: failed to compose scene: %d", VCOS_FUNCTION, status);
+            wfc_set_error(device_ptr, WFC_ERROR_BUSY);
+         }
+      } // if
+      else
+         {wfc_set_error(device_ptr, WFC_ERROR_UNSUPPORTED);}
+   }
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+
+   // Wait for the scene to be taken outside the lock
+   if (wait && status == VCOS_SUCCESS)
+   {
+      wfc_client_wait_for_scene_taken(&wait_sem, ctx, VCOS_FUNCTION);
+   }
+} // wfcCompose()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL void WFC_APIENTRY
+    wfcFence(WFCDevice dev, WFCContext ctx, WFCEGLDisplay dpy,
+        WFCEGLSync sync) WFC_APIEXIT
+{
+   vcos_unused(dpy);
+   vcos_unused(sync);
+
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return;
+   }
+
+   // TODO wfcFence()
+   vcos_assert(0);
+
+   if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
+   {
+      /* Set error as WFC_ERROR_ILLEGAL_ARGUMENT
+         - if dpy is not a valid EGLDisplay
+         - if sync is not a valid sync object
+         - if sync\92s EGL_SYNC_TYPE_KHR is not EGL_SYNC_REUSABLE_KHR
+       */
+   } // if
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+} // wfcFence()
+
+//==============================================================================
+// Renderer and extension information
+
+WFC_API_CALL WFCint WFC_APIENTRY
+    wfcGetStrings(WFCDevice dev,
+        WFCStringID name,
+        const char **strings,
+        WFCint stringsCount) WFC_APIEXIT
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   const char *name_string = NULL;
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return 0;
+   }
+
+   switch(name)
+   {
+      case WFC_VENDOR:
+         name_string = "Broadcom";
+         break;
+      case WFC_RENDERER:
+         name_string = "VideoCore IV HW";
+         break;
+      case WFC_VERSION:
+         name_string = "1.0";
+         break;
+      case WFC_EXTENSIONS:
+         name_string = "";
+         break;
+      default:
+         wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
+         WFC_UNLOCK();
+         return 0;
+   } // switch
+
+   WFCint num_of_strings = 0;
+
+   if(stringsCount >= 0)
+   {
+      num_of_strings = 1;
+      if((strings != NULL) && (stringsCount > 0))
+      {
+         *strings = name_string;
+      } // if
+   } // if
+   else
+   {
+      wfc_set_error(device_ptr, WFC_ERROR_ILLEGAL_ARGUMENT);
+   } // else
+
+   WFC_UNLOCK();
+
+   return num_of_strings;
+} // wfcGetStrings()
+
+//------------------------------------------------------------------------------
+
+WFC_API_CALL WFCboolean WFC_APIENTRY
+    wfcIsExtensionSupported(WFCDevice dev, const char *string) WFC_APIEXIT
+{
+   vcos_unused(string);
+
+   // TODO wfcIsExtensionSupported()
+   vcos_assert(0);
+
+   if(!vcos_verify(dev != WFC_INVALID_HANDLE))
+      {return WFC_FALSE;}
+
+   return WFC_FALSE;
+}
+
+//!@} // (OpenWF-C API functions)
+//==============================================================================
+
+static void wfc_initialise_client_state(void)
+{
+   size_t pool_index;
+   const WFC_BLOCKPOOL_INFO_T *pool_info = wfc_client_blockpool_info;
+   uint64_t pid = vcos_process_id_current();
+
+   // Logging
+   vcos_log_set_level(&log_cat, WFC_LOG_LEVEL);
+   vcos_log_register("wfc_client_func", &log_cat);
+
+   vcos_log_error("%s: entered", VCOS_FUNCTION);
+
+   // Allocate all the pools
+   for (pool_index = 0; pool_index < countof(wfc_client_blockpool_info); pool_index++, pool_info++)
+   {
+      if (vcos_blockpool_create_on_heap(pool_info->pool, pool_info->count, pool_info->size,
+            VCOS_BLOCKPOOL_ALIGN_DEFAULT, 0, pool_info->name) != VCOS_SUCCESS)
+         goto fail;
+
+      vcos_blockpool_extend(pool_info->pool, pool_info->max_subpools - 1, pool_info->count);
+   }
+
+   vcos_mutex_create(&wfc_client_state.mutex, NULL);
+
+   // Set up a handle modifier that is generally process specific. The shifting
+   // around should put the ID on Linux in an otherwise fairly unused bit of the
+   // handle, which makes debugging easier.
+   wfc_client_state.handle_mod = (VCOS_UNSIGNED)((pid << 16) ^ (pid >> 16) ^ (pid >> 48));
+
+   wfc_client_state.is_initialised = true;
+
+   vcos_log_error("%s: success", VCOS_FUNCTION);
+   // Success
+   return;
+
+fail:
+   vcos_log_error("%s: failed to allocate memory pools", VCOS_FUNCTION);
+
+   // pool_index and pool_info refer to the one that failed to allocate. Free
+   // any pools already allocated.
+   while (pool_index-- > 0)
+   {
+      pool_info--;
+      vcos_blockpool_delete(pool_info->pool);
+   }
+}
+
+//------------------------------------------------------------------------------
+
+static WFC_DEVICE_T *wfc_device_from_handle(WFCDevice dev)
+{
+   VCOS_UNSIGNED handle_mod = WFC_DEVICE_MOD ^ wfc_client_state.handle_mod;
+
+   if (dev == WFC_INVALID_HANDLE)
+      return NULL;
+   return vcos_blockpool_elem_from_handle(&wfc_client_state.device_pool, dev ^ handle_mod);
+}
+
+//------------------------------------------------------------------------------
+
+static WFCDevice wfc_device_to_handle(WFC_DEVICE_T *device_ptr)
+{
+   VCOS_UNSIGNED handle_mod = WFC_DEVICE_MOD ^ wfc_client_state.handle_mod;
+   VCOS_UNSIGNED handle = vcos_blockpool_elem_to_handle(device_ptr);
+
+   if (handle == VCOS_BLOCKPOOL_INVALID_HANDLE)
+      return WFC_INVALID_HANDLE;
+
+   return (WFCDevice)(handle ^ handle_mod);
+}
+
+//------------------------------------------------------------------------------
+
+static WFC_CONTEXT_T *wfc_context_from_handle(WFCContext ctx)
+{
+   VCOS_UNSIGNED handle_mod = WFC_CONTEXT_MOD ^ wfc_client_state.handle_mod;
+
+   if (ctx == WFC_INVALID_HANDLE)
+      return NULL;
+
+   return vcos_blockpool_elem_from_handle(&wfc_client_state.context_pool, ctx ^ handle_mod);
+}
+
+//------------------------------------------------------------------------------
+
+static WFCContext wfc_context_to_handle(WFC_CONTEXT_T *context_ptr)
+{
+   VCOS_UNSIGNED handle_mod = WFC_CONTEXT_MOD ^ wfc_client_state.handle_mod;
+   VCOS_UNSIGNED handle = vcos_blockpool_elem_to_handle(context_ptr);
+
+   if (handle == VCOS_BLOCKPOOL_INVALID_HANDLE)
+      return WFC_INVALID_HANDLE;
+
+   return (WFCContext)(handle ^ handle_mod);
+}
+
+//------------------------------------------------------------------------------
+
+static WFC_ELEMENT_T *wfc_element_from_handle(WFCElement element)
+{
+   VCOS_UNSIGNED handle_mod = WFC_ELEMENT_MOD ^ wfc_client_state.handle_mod;
+
+   if (element == WFC_INVALID_HANDLE)
+      return NULL;
+
+   return vcos_blockpool_elem_from_handle(&wfc_client_state.element_pool, element ^ handle_mod);
+}
+
+//------------------------------------------------------------------------------
+
+static WFCElement wfc_element_to_handle(WFC_ELEMENT_T *element_ptr)
+{
+   VCOS_UNSIGNED handle_mod = WFC_ELEMENT_MOD ^ wfc_client_state.handle_mod;
+   VCOS_UNSIGNED handle = vcos_blockpool_elem_to_handle(element_ptr);
+
+   if (handle == VCOS_BLOCKPOOL_INVALID_HANDLE)
+      return WFC_INVALID_HANDLE;
+
+   return (WFCElement)(handle ^ handle_mod);
+}
+
+//------------------------------------------------------------------------------
+
+static WFCElement wfc_element_link_to_handle(WFC_LINK_T *element_link_ptr)
+{
+   return wfc_element_to_handle((WFC_ELEMENT_T *)((char *)element_link_ptr - offsetof(WFC_ELEMENT_T, link)));
+}
+
+//------------------------------------------------------------------------------
+
+static WFC_SOURCE_OR_MASK_T *wfc_source_or_mask_from_handle(WFCHandle source_or_mask)
+{
+   VCOS_UNSIGNED handle_mod = WFC_SOURCE_MOD ^ wfc_client_state.handle_mod;
+
+   if (source_or_mask == WFC_INVALID_HANDLE)
+      return NULL;
+
+   return vcos_blockpool_elem_from_handle(&wfc_client_state.source_pool, source_or_mask ^ handle_mod);
+}
+
+//------------------------------------------------------------------------------
+
+static WFCHandle wfc_source_or_mask_to_handle(WFC_SOURCE_OR_MASK_T *source_or_mask_ptr)
+{
+   VCOS_UNSIGNED handle_mod = WFC_SOURCE_MOD ^ wfc_client_state.handle_mod;
+   VCOS_UNSIGNED handle = vcos_blockpool_elem_to_handle(source_or_mask_ptr);
+
+   if (handle == VCOS_BLOCKPOOL_INVALID_HANDLE)
+      return WFC_INVALID_HANDLE;
+
+   return (WFCHandle)(handle ^ handle_mod);
+}
+
+//------------------------------------------------------------------------------
+
+//!@name
+//! Macros used in wfc_context_create() to extract data returned from wfc_server_create_context().
+//!@{
+#define WFC_CONTEXT_WIDTH(data)  ((data) >> 16)
+#define WFC_CONTEXT_HEIGHT_OR_ERR(data) ((data) & 0xFFFF)
+//!@}
+
+static WFC_CONTEXT_T *wfc_context_create
+   (WFC_DEVICE_T *device_ptr, WFCContextType context_type,
+      uint32_t screen_or_stream_num, WFCErrorCode *error)
+{
+   WFC_CONTEXT_T *context_ptr = vcos_blockpool_calloc(&wfc_client_state.context_pool);
+   const WFC_CONTEXT_DYNAMIC_ATTRIB_T ctx_dyn_attrib_default = WFC_CONTEXT_DYNAMIC_ATTRIB_DEFAULT;
+
+   if(context_ptr != NULL)
+   {
+      uint64_t pid = vcos_process_id_current();
+      uint32_t pid_lo = (uint32_t) pid;
+      uint32_t pid_hi = (uint32_t) (pid >> 32);
+
+      uint32_t response = wfc_server_create_context(wfc_context_to_handle(context_ptr),
+            context_type, screen_or_stream_num, pid_lo, pid_hi);
+
+      uint32_t height_or_err = WFC_CONTEXT_HEIGHT_OR_ERR(response);
+      uint32_t width = WFC_CONTEXT_WIDTH(response);
+
+      if(width != 0)
+      {
+         wfc_link_init_null(&context_ptr->link);
+
+         context_ptr->device_ptr = device_ptr;
+         wfc_link_init_empty(&context_ptr->sources);
+         wfc_link_init_empty(&context_ptr->masks);
+
+         wfc_link_init_empty(&context_ptr->elements_not_in_scene);
+         wfc_link_init_empty(&context_ptr->elements_in_scene);
+         context_ptr->active = false;
+
+         context_ptr->dynamic_attributes = ctx_dyn_attrib_default;
+         context_ptr->static_attributes.type = context_type;
+         context_ptr->static_attributes.height = height_or_err;
+         context_ptr->static_attributes.width = width;
+
+         if(context_type == WFC_CONTEXT_TYPE_OFF_SCREEN)
+         {
+            context_ptr->output_stream = screen_or_stream_num;
+         }
+      }
+      else
+      {
+         vcos_blockpool_free(context_ptr);
+         context_ptr = NULL;
+         *error = (WFCErrorCode) response;
+      }
+   } // if
+   else
+      {*error = WFC_ERROR_OUT_OF_MEMORY;}
+
+   return context_ptr;
+} // wfc_context_create()
+
+//------------------------------------------------------------------------------
+
+static void wfc_context_destroy(WFC_CONTEXT_T *context_ptr)
+{
+   // Detach output stream for off-screen contexts.
+   wfc_stream_register_off_screen(context_ptr->output_stream, false);
+
+   // Remove from parent device's list of contexts.
+   wfc_link_detach(&context_ptr->link);
+
+   // Destroy all components
+   wfc_link_iterate(&context_ptr->elements_in_scene, (WFC_LINK_CALLBACK_T) wfc_element_destroy, NULL);
+   wfc_link_iterate(&context_ptr->elements_not_in_scene, (WFC_LINK_CALLBACK_T) wfc_element_destroy, NULL);
+   wfc_link_iterate(&context_ptr->sources, (WFC_LINK_CALLBACK_T) wfc_source_or_mask_destroy_actual, NULL);
+   wfc_link_iterate(&context_ptr->masks, (WFC_LINK_CALLBACK_T) wfc_source_or_mask_destroy_actual, NULL);
+
+   wfc_server_destroy_context(wfc_context_to_handle(context_ptr));
+
+   vcos_blockpool_free(context_ptr);
+} // wfc_context_destroy()
+
+//==============================================================================
+
+static WFCHandle wfc_source_or_mask_create(
+      bool is_source, WFCDevice dev, WFCContext ctx,
+      WFCNativeStreamType stream, const WFCint *attribList)
+//!@brief Create a new image provider and associate it with a stream.
+//!
+//! wfcCreateSourceFromStream() and wfcCreateMaskFromStream() are essentially
+//! wrappers for this function.
+{
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
+
+   WFCHandle handle = WFC_INVALID_HANDLE;
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      return handle;
+   }
+
+   if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
+   {
+      if(!wfc_check_no_attribs(attribList))
+      {
+         wfc_set_error(device_ptr, WFC_ERROR_BAD_ATTRIBUTE);
+      }
+      else if(context_ptr->output_stream == stream)
+      {
+         // Verify that context isn't an input for this stream
+         wfc_set_error(device_ptr, WFC_ERROR_IN_USE);
+      }
+      else if (!wfc_stream_register_source_or_mask(stream, true))
+      {
+         vcos_log_error("%s: failed to register stream 0x%x", VCOS_FUNCTION, stream);
+         wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);
+      }
+      else
+      {
+         WFC_SOURCE_OR_MASK_T *source_or_mask_ptr = vcos_blockpool_calloc(&wfc_client_state.source_pool);
+
+         if(source_or_mask_ptr != NULL)
+         {
+            // Note that refcount is initialised to zero here, as a source or mask is
+            // only in use when it is linked to an element.
+
+            wfc_link_init_null(&source_or_mask_ptr->link);
+
+            source_or_mask_ptr->is_source = is_source;
+            source_or_mask_ptr->context_ptr = context_ptr;
+            source_or_mask_ptr->stream = stream;
+
+            if(is_source)
+            {
+               wfc_link_attach(&source_or_mask_ptr->link, &context_ptr->sources);
+            }
+            else
+            {
+               wfc_link_attach(&source_or_mask_ptr->link, &context_ptr->masks);
+            }
+            handle = wfc_source_or_mask_to_handle(source_or_mask_ptr);
+         }
+         else
+         {
+            wfc_stream_register_source_or_mask(stream, false);
+            vcos_log_error("%s: failed to allocate source/mask info for stream 0x%x", VCOS_FUNCTION, stream);
+            wfc_set_error(device_ptr, WFC_ERROR_OUT_OF_MEMORY);
+         }
+      }
+   }
+   else
+   {
+      wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);
+   }
+
+   return handle;
+}
+
+//------------------------------------------------------------------------------
+
+static void wfc_source_or_mask_destroy(WFCDevice dev, WFCHandle source_or_mask)
+//!@brief Destroy an image provider and dissociate its stream.
+//!
+//! wfcDestroySource() and wfcDestroyMask() are essentially wrappers for this function.
+{
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_SOURCE_OR_MASK_T *source_or_mask_ptr = wfc_source_or_mask_from_handle(source_or_mask);
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      return;
+   }
+
+   if((source_or_mask_ptr != NULL) && (source_or_mask_ptr->context_ptr != NULL)
+      && (source_or_mask_ptr->context_ptr->device_ptr == device_ptr))
+   {
+      wfc_source_or_mask_destroy_actual(source_or_mask_ptr, NULL);
+   }
+   else
+   {
+      wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);
+   }
+}
+
+//------------------------------------------------------------------------------
+
+static void wfc_source_or_mask_acquire(WFC_SOURCE_OR_MASK_T *source_or_mask_ptr)
+//! Indicate that the image provider is now linked to an element.
+{
+   vcos_log_trace("%s: %p refcount %d", VCOS_FUNCTION, source_or_mask_ptr,
+         source_or_mask_ptr ? source_or_mask_ptr->refcount : 0);
+   if(source_or_mask_ptr != NULL)
+      {source_or_mask_ptr->refcount++;}
+} // wfc_source_or_mask_acquire()
+
+//------------------------------------------------------------------------------
+
+static void wfc_source_or_mask_release(WFC_SOURCE_OR_MASK_T *source_or_mask_ptr)
+//! Indicate the the image provider is no longer linked to an element; destroy if previously requested.
+{
+   vcos_log_trace("%s: %p refcount %d", VCOS_FUNCTION, source_or_mask_ptr,
+         source_or_mask_ptr ? source_or_mask_ptr->refcount : 0);
+   if(source_or_mask_ptr != NULL)
+   {
+      if(source_or_mask_ptr->refcount > 0)
+      {
+         source_or_mask_ptr->refcount--;
+      }
+
+      // If no-one is using this source or mask, and a request has previously
+      // been made to destroy it, do so now.
+      if((source_or_mask_ptr->refcount == 0) && source_or_mask_ptr->destroy_pending)
+      {
+         wfc_source_or_mask_destroy_actual(source_or_mask_ptr, NULL);
+      }
+   }
+}
+
+//------------------------------------------------------------------------------
+
+static void wfc_source_or_mask_destroy_actual(WFC_SOURCE_OR_MASK_T *source_or_mask_ptr, void *unused)
+{
+   source_or_mask_ptr->destroy_pending = true;
+
+   if(source_or_mask_ptr->refcount == 0)
+   {
+      vcos_log_trace("%s: %p source 0x%x stream 0x%x", VCOS_FUNCTION, source_or_mask_ptr,
+            wfc_source_or_mask_to_handle(source_or_mask_ptr), source_or_mask_ptr->stream);
+
+      wfc_stream_register_source_or_mask(source_or_mask_ptr->stream, false);
+
+      // Remove from parent context's list of sources or masks.
+      wfc_link_detach(&source_or_mask_ptr->link);
+
+      // Destroy.
+      vcos_blockpool_free(source_or_mask_ptr);
+   }
+   else
+   {
+      vcos_log_trace("%s: pending: %p refcount: %d", VCOS_FUNCTION, source_or_mask_ptr, source_or_mask_ptr->refcount);
+   }
+}
+
+//==============================================================================
+
+static void wfc_element_destroy(WFC_ELEMENT_T *element_ptr, void *unused)
+{
+   vcos_log_trace("%s: %p", VCOS_FUNCTION, element_ptr);
+
+   // Release source and mask (if present); destroy if previously requested.
+   wfc_source_or_mask_release(element_ptr->source_ptr);
+   wfc_source_or_mask_release(element_ptr->mask_ptr);
+
+   element_ptr->source_ptr = NULL;
+   element_ptr->mask_ptr = NULL;
+
+   wfc_link_detach(&element_ptr->link);
+
+   vcos_blockpool_free(element_ptr);
+} // wfc_element_destroy()
+
+//==============================================================================
+
+static void wfc_commit_iterator(WFC_ELEMENT_T *element_ptr, WFC_SCENE_T *scene)
+{
+   // Elements with source or destination rectangles having zero width or height
+   // must not displayed
+   if
+   (
+      (element_ptr->attributes.dest_rect[WFC_RECT_WIDTH] == 0)
+      || (element_ptr->attributes.dest_rect[WFC_RECT_HEIGHT] == 0)
+      || (element_ptr->attributes.src_rect[WFC_RECT_WIDTH] < 0.00001)
+      || (element_ptr->attributes.src_rect[WFC_RECT_HEIGHT] < 0.00001)
+   )
+   {return;}
+
+   // Elements with a (near-)zero global alpha are transparent, so ignore them
+   if
+   (
+      (element_ptr->attributes.transparency_types & WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA)
+      && (element_ptr->attributes.global_alpha < 0.001)
+   )
+   {return;}
+
+   // Copy element attributes into scene and increment count
+   memcpy(&scene->elements[scene->element_count++], &element_ptr->attributes, sizeof(WFC_ELEMENT_ATTRIB_T));
+} // wfc_commit_iterator()
+
+//==============================================================================
+
+static void wfc_set_error_with_location(WFC_DEVICE_T *device, WFCErrorCode error, const char *func, int line)
+//! Update device's error code (but only if previously cleared).
+{
+   vcos_log_error("%s: device %p error 0x%x at line %d", func, device, error, line);
+   if((device != NULL) && (device->error == WFC_ERROR_NONE))
+      {device->error = error;}
+} // wfc_set_error()
+
+//==============================================================================
+
+static bool wfc_check_no_attribs(const WFCint *attribList)
+//! Returns true if the attribute list is empty.
+{
+   return !attribList || (*attribList == WFC_NONE);
+}
+
+//------------------------------------------------------------------------------
+
+static bool wfc_is_rotation(WFCint value)
+{
+   return value == WFC_ROTATION_0   ||
+          value == WFC_ROTATION_90  ||
+          value == WFC_ROTATION_180 ||
+          value == WFC_ROTATION_270;
+}
+
+//------------------------------------------------------------------------------
+
+static bool wfc_is_scale_filter(WFCint value)
+{
+   return value == WFC_SCALE_FILTER_NONE   ||
+          value == WFC_SCALE_FILTER_FASTER ||
+          value == WFC_SCALE_FILTER_BETTER;
+}
+
+//------------------------------------------------------------------------------
+
+static bool wfc_are_transparency_types(WFCint value)
+{
+   return value == WFC_TRANSPARENCY_NONE ||
+          value == WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA ||
+          value == WFC_TRANSPARENCY_SOURCE ||
+          value == WFC_TRANSPARENCY_SOURCE_VC_NON_PRE_MULT ||
+          value == WFC_TRANSPARENCY_MASK ||
+          value == (WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA | WFC_TRANSPARENCY_SOURCE) ||
+          value == (WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA | WFC_TRANSPARENCY_SOURCE_VC_NON_PRE_MULT) ||
+          value == (WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA | WFC_TRANSPARENCY_MASK);
+}
+
+//------------------------------------------------------------------------------
+
+static int32_t wfc_round(float f)
+{
+   int result = (int)f;
+   if (f>=0)
+      if ((f-result)>=0.5) return ++result; else return result;
+   else
+      if ((f-result)<=-0.5) return --result; else return result;
+}
+
+//==============================================================================
+
+static void wfc_link_detach(WFC_LINK_T *link)
+{
+   vcos_assert(link != NULL);
+   if (link->next) {
+      /*
+         never unlink a base link
+      */
+
+      vcos_assert(link->next != link);
+      vcos_assert(link->prev != link);
+
+      link->next->prev = link->prev;
+      link->prev->next = link->next;
+
+      link->prev = NULL;
+      link->next = NULL;
+   }
+}
+
+//------------------------------------------------------------------------------
+
+static void wfc_link_attach(WFC_LINK_T *link, WFC_LINK_T *prev)
+{
+   wfc_link_detach(link);
+
+   link->prev = prev;
+   link->next = prev->next;
+
+   link->prev->next = link;
+   link->next->prev = link;
+}
+
+//------------------------------------------------------------------------------
+
+static void wfc_link_init_null(WFC_LINK_T *link)
+//!@brief Initialise a link when the link will be used to keep track of structures
+//! of the kind which contain the link.
+{
+   link->prev = NULL;
+   link->next = NULL;
+}
+
+//------------------------------------------------------------------------------
+
+static void wfc_link_init_empty(WFC_LINK_T *link)
+//!@brief Initialise a link which will contain structures which are children of the
+//! structure containing the link.
+{
+   link->prev = link;
+   link->next = link;
+}
+
+//------------------------------------------------------------------------------
+
+static void wfc_link_iterate(WFC_LINK_T *link, WFC_LINK_CALLBACK_T func, void *arg)
+{
+   WFC_LINK_T *curr = link;
+   WFC_LINK_T *next = curr->next;
+
+   while (next != link) {
+      curr = next;
+      next = curr->next;
+
+      func(curr, arg);
+   }
+}
+
+//------------------------------------------------------------------------------
+
+void wfc_set_deferral_stream(WFCDevice dev, WFCContext ctx, WFCNativeStreamType stream)
+{
+   WFC_LOCK();
+
+   WFC_DEVICE_T *device_ptr = wfc_device_from_handle(dev);
+   WFC_CONTEXT_T *context_ptr = wfc_context_from_handle(ctx);
+
+   if (!vcos_verify(device_ptr != NULL))
+   {
+      vcos_log_error("%s: invalid device handle 0x%x", VCOS_FUNCTION, dev);
+      WFC_UNLOCK();
+      return;
+   }
+
+   if(vcos_verify((context_ptr != NULL) && (context_ptr->device_ptr == device_ptr)))
+   {
+      wfc_server_set_deferral_stream(ctx, stream);
+   } //if
+   else
+      {wfc_set_error(device_ptr, WFC_ERROR_BAD_HANDLE);}
+
+   WFC_UNLOCK();
+}
+
+//------------------------------------------------------------------------------
+
+/** Called when a scene for composition has been taken
+ *
+ * @param cb_data Callback data
+ */
+static void wfc_client_scene_taken_cb(void *cb_data)
+{
+   VCOS_SEMAPHORE_T *wait_sem = (VCOS_SEMAPHORE_T *)cb_data;
+
+   vcos_assert(wait_sem != NULL);
+   vcos_semaphore_post(wait_sem);
+}
+
+//------------------------------------------------------------------------------
+
+/** Wait for the scene taken callback to have been called. Deletes the semaphore
+ * and releases the VideoCore keep alive.
+ *
+ * @param wait_sem The wait semaphore.
+ * @param ctx The handle for the context receiving the scene, used in logging.
+ * @param calling_function The calling function name, used in logging.
+ */
+static void wfc_client_wait_for_scene_taken(VCOS_SEMAPHORE_T *wait_sem, WFCContext ctx,
+      const char *calling_function)
+{
+   VCOS_STATUS_T status;
+
+#if defined(VCOS_LOGGING_ENABLED)
+   uint64_t pid = vcos_process_id_current();
+
+   vcos_log_trace("%s: wait for compositor to take scene, context 0x%x pid 0x%x%08x",
+         calling_function, ctx, (uint32_t)(pid >> 32), (uint32_t)pid);
+#else
+   vcos_unused(ctx);
+   vcos_unused(calling_function);
+#endif
+
+   status = vcos_semaphore_wait(wait_sem);
+   vcos_assert(status == VCOS_SUCCESS);
+   vcos_unused(status);
+
+   vcos_semaphore_delete(wait_sem);
+   wfc_server_release_keep_alive();
+
+   vcos_log_trace("%s: wait completed", calling_function);
+}
+
+//==============================================================================
diff --git a/interface/khronos/wf/wfc_client_ipc.c b/interface/khronos/wf/wfc_client_ipc.c
new file mode 100755 (executable)
index 0000000..126903b
--- /dev/null
@@ -0,0 +1,521 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/khronos/wf/wfc_client_ipc.h"
+#include "interface/khronos/wf/wfc_ipc.h"
+#include "interface/vcos/vcos.h"
+#include "interface/vchiq_arm/vchiq.h"
+
+#define VCOS_LOG_CATEGORY (&wfc_client_ipc_log_category)
+
+//#define WFC_FULL_LOGGING
+#ifdef WFC_FULL_LOGGING
+#define WFC_CLIENT_IPC_LOGLEVEL VCOS_LOG_TRACE
+#else
+#define WFC_CLIENT_IPC_LOGLEVEL VCOS_LOG_WARN
+#endif
+
+#define WFC_CLIENT_IPC_MAX_WAITERS 16
+static VCOS_ONCE_T wfc_client_ipc_once = VCOS_ONCE_INIT;
+static VCHIQ_INSTANCE_T wfc_client_ipc_vchiq_instance;
+static VCOS_LOG_CAT_T wfc_client_ipc_log_category;
+
+/** Client threads use one of these to wait for
+ * a reply from VideoCore.
+ */
+typedef struct WFC_WAITER_T
+{
+   VCOS_SEMAPHORE_T sem;
+   unsigned inuse;
+   void *dest;                   /**< Where to write reply */
+   size_t destlen;               /**< Max length for reply */
+} WFC_WAITER_T;
+
+/** We have an array of waiters and allocate them to waiting
+  * threads. They can be released back to the pool in any order.
+  * If there are none free, the calling thread will block until
+  * one becomes available.
+  */
+typedef struct
+{
+   WFC_WAITER_T waiters[WFC_CLIENT_IPC_MAX_WAITERS];
+   VCOS_SEMAPHORE_T sem;
+} WFC_WAITPOOL_T;
+
+struct WFC_CLIENT_IPC_T
+{
+   int refcount;
+   int keep_alive_count;
+   VCOS_MUTEX_T lock;
+   VCHIQ_SERVICE_HANDLE_T service;
+   WFC_WAITPOOL_T waitpool;
+};
+typedef struct WFC_CLIENT_IPC_T WFC_CLIENT_IPC_T;
+
+/* One client per process/VC connection. Multiple threads may
+ * be using a single client.
+ */
+static WFC_CLIENT_IPC_T wfc_client_ipc;
+
+static void init_once(void)
+{
+   vcos_mutex_create(&wfc_client_ipc.lock, VCOS_FUNCTION);
+}
+
+/** Create a pool of wait-structures.
+  */
+static VCOS_STATUS_T wfc_client_ipc_create_waitpool(WFC_WAITPOOL_T *waitpool)
+{
+   VCOS_STATUS_T status;
+   int i;
+
+   status = vcos_semaphore_create(&waitpool->sem, VCOS_FUNCTION,
+                                  WFC_CLIENT_IPC_MAX_WAITERS);
+   if (status != VCOS_SUCCESS)
+      return status;
+
+   for (i = 0; i < WFC_CLIENT_IPC_MAX_WAITERS; i++)
+   {
+      waitpool->waiters[i].inuse = 0;
+      status = vcos_semaphore_create(&waitpool->waiters[i].sem,
+                                     "wfc ipc waiter", 0);
+      if (status != VCOS_SUCCESS)
+         break;
+   }
+
+   if (status != VCOS_SUCCESS)
+   {
+      /* clean up */
+      i--;
+      while (i >= 0)
+      {
+         vcos_semaphore_delete(&waitpool->waiters[i].sem);
+         i--;
+      }
+      vcos_semaphore_delete(&waitpool->sem);
+   }
+   return status;
+}
+
+static void wfc_client_ipc_destroy_waitpool(WFC_WAITPOOL_T *waitpool)
+{
+   int i;
+
+   for (i = 0; i < WFC_CLIENT_IPC_MAX_WAITERS; i++)
+      vcos_semaphore_delete(&waitpool->waiters[i].sem);
+
+   vcos_semaphore_delete(&waitpool->sem);
+}
+
+/** Grab a waiter from the pool. Return immediately if one already
+  * available, or wait for one to become available.
+  */
+static WFC_WAITER_T *wfc_client_ipc_get_waiter(WFC_CLIENT_IPC_T *client)
+{
+   int i;
+   WFC_WAITER_T *waiter = NULL;
+
+   vcos_semaphore_wait(&client->waitpool.sem);
+   vcos_mutex_lock(&client->lock);
+
+   for (i = 0; i < WFC_CLIENT_IPC_MAX_WAITERS; i++)
+   {
+      if (client->waitpool.waiters[i].inuse == 0)
+         break;
+   }
+
+   /* If this fails, the semaphore isn't working */
+   if (vcos_verify(i != WFC_CLIENT_IPC_MAX_WAITERS))
+   {
+      waiter = client->waitpool.waiters + i;
+      waiter->inuse = 1;
+   }
+   vcos_mutex_unlock(&client->lock);
+
+   return waiter;
+}
+
+/** Return a waiter to the pool.
+  */
+static void wfc_client_ipc_release_waiter(WFC_CLIENT_IPC_T *client, WFC_WAITER_T *waiter)
+{
+   vcos_log_trace("%s: at %p", VCOS_FUNCTION, waiter);
+
+   vcos_assert(waiter);
+   vcos_assert(waiter->inuse);
+
+   waiter->inuse = 0;
+   vcos_semaphore_post(&client->waitpool.sem);
+}
+
+/** Callback invoked by VCHIQ
+  */
+static VCHIQ_STATUS_T wfc_client_ipc_vchiq_callback(VCHIQ_REASON_T reason,
+                                                VCHIQ_HEADER_T *vchiq_header,
+                                                VCHIQ_SERVICE_HANDLE_T service,
+                                                void *context)
+{
+   vcos_log_trace("%s: reason %d", VCOS_FUNCTION, reason);
+
+   switch (reason)
+   {
+   case VCHIQ_MESSAGE_AVAILABLE:
+      {
+         WFC_IPC_MSG_HEADER_T *response = (WFC_IPC_MSG_HEADER_T *)vchiq_header->data;
+
+         vcos_assert(vchiq_header->size >= sizeof(*response));
+         vcos_assert(response->magic == WFC_IPC_MSG_MAGIC);
+
+         if (response->type == WFC_IPC_MSG_CALLBACK)
+         {
+            WFC_IPC_MSG_CALLBACK_T *callback_msg = (WFC_IPC_MSG_CALLBACK_T *)response;
+            WFC_CALLBACK_T cb_func = callback_msg->callback_fn.ptr;
+
+            vcos_assert(vchiq_header->size == sizeof(*callback_msg));
+            if (vcos_verify(cb_func != NULL))
+            {
+               /* Call the client function */
+               (*cb_func)(callback_msg->callback_data.ptr);
+            }
+            vchiq_release_message(service, vchiq_header);
+         }
+         else
+         {
+            WFC_WAITER_T *waiter = response->waiter.ptr;
+            int len;
+
+            vcos_assert(waiter != NULL);
+
+            vcos_log_trace("%s: waking up waiter at %p", VCOS_FUNCTION, waiter);
+            vcos_assert(waiter->inuse);
+
+            /* Limit response data length */
+            len = vcos_min(waiter->destlen, vchiq_header->size - sizeof(*response));
+            waiter->destlen = len;
+
+            vcos_log_trace("%s: copying %d bytes from %p to %p first word 0x%x",
+                  VCOS_FUNCTION, len, response + 1, waiter->dest, *(uint32_t *)(response + 1));
+            memcpy(waiter->dest, response + 1, len);
+
+            vchiq_release_message(service, vchiq_header);
+            vcos_semaphore_post(&waiter->sem);
+         }
+      }
+      break;
+   case VCHIQ_BULK_TRANSMIT_DONE:
+   case VCHIQ_BULK_RECEIVE_DONE:
+   case VCHIQ_BULK_RECEIVE_ABORTED:
+   case VCHIQ_BULK_TRANSMIT_ABORTED:
+      {
+         vcos_assert_msg(0, "bulk messages not used");
+         vchiq_release_message(service, vchiq_header);
+      }
+      break;
+   case VCHIQ_SERVICE_OPENED:
+      vcos_log_trace("%s: service %x opened", VCOS_FUNCTION, service);
+      break;
+   case VCHIQ_SERVICE_CLOSED:
+      vcos_log_trace("%s: service %x closed", VCOS_FUNCTION, service);
+      break;
+   default:
+      vcos_assert_msg(0, "unexpected message reason");
+      break;
+   }
+   return VCHIQ_SUCCESS;
+}
+
+static VCOS_STATUS_T wfc_client_ipc_send_client_pid(void)
+{
+   WFC_IPC_MSG_SET_CLIENT_PID_T msg;
+   uint64_t pid = vcos_process_id_current();
+   uint32_t pid_lo = (uint32_t) pid;
+   uint32_t pid_hi = (uint32_t) (pid >> 32);
+
+   msg.header.type = WFC_IPC_MSG_SET_CLIENT_PID;
+   msg.pid_lo = pid_lo;
+   msg.pid_hi = pid_hi;
+
+   vcos_log_trace("%s: setting client pid to 0x%x%08x", VCOS_FUNCTION, pid_hi, pid_lo);
+
+   return wfc_client_ipc_send(&msg.header, sizeof(msg));
+}
+
+VCOS_STATUS_T wfc_client_ipc_sendwait(WFC_IPC_MSG_HEADER_T *msg,
+                                       size_t size,
+                                       void *dest,
+                                       size_t *destlen)
+{
+   VCOS_STATUS_T ret = VCOS_SUCCESS;
+   WFC_WAITER_T *waiter;
+   VCHIQ_STATUS_T vst;
+   VCHIQ_ELEMENT_T elems[] = {{msg, size}};
+
+   vcos_assert(size >= sizeof(*msg));
+   vcos_assert(dest);
+
+   if (!vcos_verify(wfc_client_ipc.refcount))
+   {
+      VCOS_ALERT("%s: client uninitialised", VCOS_FUNCTION);
+      /* Client has not been initialised */
+      return VCOS_EINVAL;
+   }
+
+   msg->magic = WFC_IPC_MSG_MAGIC;
+
+   waiter = wfc_client_ipc_get_waiter(&wfc_client_ipc);
+   waiter->dest = dest;
+   waiter->destlen = *destlen;
+   msg->waiter.ptr = waiter;
+
+   wfc_client_ipc_use_keep_alive();
+
+   vcos_log_trace("%s: wait %p, reply to %p", VCOS_FUNCTION, waiter, dest);
+   vst = vchiq_queue_message(wfc_client_ipc.service, elems, 1);
+
+   if (vst != VCHIQ_SUCCESS)
+   {
+      vcos_log_error("%s: failed to queue, 0x%x", VCOS_FUNCTION, vst);
+      ret = VCOS_ENXIO;
+      goto completed;
+   }
+
+   /* now wait for the reply...
+    *
+    * FIXME: we could do with a timeout here. Need to be careful to cancel
+    * the semaphore on a timeout.
+    */
+   vcos_semaphore_wait(&waiter->sem);
+   vcos_log_trace("%s: got reply (len %i/%i)", VCOS_FUNCTION, (int)*destlen, (int)waiter->destlen);
+   *destlen = waiter->destlen;
+
+   /* Drop through completion code */
+
+completed:
+   wfc_client_ipc_release_waiter(&wfc_client_ipc, waiter);
+   wfc_client_ipc_release_keep_alive();
+
+   return ret;
+}
+
+VCOS_STATUS_T wfc_client_ipc_send(WFC_IPC_MSG_HEADER_T *msg,
+                                    size_t size)
+{
+   VCHIQ_STATUS_T vst;
+   VCHIQ_ELEMENT_T elems[] = {{msg, size}};
+
+   vcos_log_trace("%s: type %d, len %d", VCOS_FUNCTION, msg->type, size);
+
+   vcos_assert(size >= sizeof(*msg));
+
+   if (!vcos_verify(wfc_client_ipc.refcount))
+   {
+      VCOS_ALERT("%s: client uninitialised", VCOS_FUNCTION);
+      /* Client has not been initialised */
+      return VCOS_EINVAL;
+   }
+
+   msg->magic  = WFC_IPC_MSG_MAGIC;
+   msg->waiter.ptr = NULL;
+
+   wfc_client_ipc_use_keep_alive();
+
+   vst = vchiq_queue_message(wfc_client_ipc.service, elems, 1);
+
+   wfc_client_ipc_release_keep_alive();
+
+   if (vst != VCHIQ_SUCCESS)
+   {
+      vcos_log_error("%s: failed to queue, 0x%x", VCOS_FUNCTION, vst);
+      return VCOS_ENXIO;
+   }
+
+   return VCOS_SUCCESS;
+}
+
+VCOS_STATUS_T wfc_client_ipc_init(void)
+{
+   VCHIQ_SERVICE_PARAMS_T vchiq_params;
+   bool vchiq_initialised = false, waitpool_initialised = false;
+   bool service_initialised = false;
+   VCOS_STATUS_T status = VCOS_ENXIO;
+   VCHIQ_STATUS_T vchiq_status;
+
+   vcos_once(&wfc_client_ipc_once, init_once);
+
+   vcos_mutex_lock(&wfc_client_ipc.lock);
+
+   if (wfc_client_ipc.refcount++ > 0)
+   {
+      /* Already initialised so nothing to do */
+      vcos_mutex_unlock(&wfc_client_ipc.lock);
+      return VCOS_SUCCESS;
+   }
+
+   vcos_log_set_level(VCOS_LOG_CATEGORY, WFC_CLIENT_IPC_LOGLEVEL);
+   vcos_log_register("wfcipc", VCOS_LOG_CATEGORY);
+
+   vcos_log_trace("%s: starting initialisation", VCOS_FUNCTION);
+
+   /* Initialise a VCHIQ instance */
+   vchiq_status = vchiq_initialise(&wfc_client_ipc_vchiq_instance);
+   if (vchiq_status != VCHIQ_SUCCESS)
+   {
+      vcos_log_error("%s: failed to initialise vchiq: %d", VCOS_FUNCTION, vchiq_status);
+      goto error;
+   }
+   vchiq_initialised = true;
+
+   vchiq_status = vchiq_connect(wfc_client_ipc_vchiq_instance);
+   if (vchiq_status != VCHIQ_SUCCESS)
+   {
+      vcos_log_error("%s: failed to connect to vchiq: %d", VCOS_FUNCTION, vchiq_status);
+      goto error;
+   }
+
+   memset(&vchiq_params, 0, sizeof(vchiq_params));
+   vchiq_params.fourcc = WFC_IPC_CONTROL_FOURCC();
+   vchiq_params.callback = wfc_client_ipc_vchiq_callback;
+   vchiq_params.userdata = &wfc_client_ipc;
+   vchiq_params.version = WFC_IPC_VER_CURRENT;
+   vchiq_params.version_min = WFC_IPC_VER_MINIMUM;
+
+   vchiq_status = vchiq_open_service(wfc_client_ipc_vchiq_instance, &vchiq_params, &wfc_client_ipc.service);
+   if (vchiq_status != VCHIQ_SUCCESS)
+   {
+      vcos_log_error("%s: could not open vchiq service: %d", VCOS_FUNCTION, vchiq_status);
+      goto error;
+   }
+   service_initialised = true;
+
+   status = wfc_client_ipc_create_waitpool(&wfc_client_ipc.waitpool);
+   if (status != VCOS_SUCCESS)
+   {
+      vcos_log_error("%s: could not create wait pool: %d", VCOS_FUNCTION, status);
+      goto error;
+   }
+   waitpool_initialised = true;
+
+   /* Allow videocore to suspend, drops count to zero. */
+   vchiq_release_service(wfc_client_ipc.service);
+
+   vcos_mutex_unlock(&wfc_client_ipc.lock);
+
+   status = wfc_client_ipc_send_client_pid();
+   if (status != VCOS_SUCCESS)
+   {
+      vcos_log_error("%s: could not send client pid: %d", VCOS_FUNCTION, status);
+      vcos_mutex_lock(&wfc_client_ipc.lock);
+      goto error;
+   }
+
+   return VCOS_SUCCESS;
+
+error:
+   if (waitpool_initialised)
+      wfc_client_ipc_destroy_waitpool(&wfc_client_ipc.waitpool);
+   if (service_initialised)
+      vchiq_remove_service(wfc_client_ipc.service);
+   if (vchiq_initialised)
+      vchiq_shutdown(wfc_client_ipc_vchiq_instance);
+   vcos_log_unregister(VCOS_LOG_CATEGORY);
+   wfc_client_ipc.refcount--;
+
+   vcos_mutex_unlock(&wfc_client_ipc.lock);
+   return status;
+}
+
+bool wfc_client_ipc_deinit(void)
+{
+   bool service_destroyed = false;
+
+   vcos_once(&wfc_client_ipc_once, init_once);
+
+   vcos_mutex_lock(&wfc_client_ipc.lock);
+
+   if (!wfc_client_ipc.refcount)
+   {
+      /* Never initialised */
+      goto completed;
+   }
+
+   if (--wfc_client_ipc.refcount != 0)
+   {
+      /* Still in use so don't do anything */
+      goto completed;
+   }
+
+   vcos_log_trace("%s: starting deinitialisation", VCOS_FUNCTION);
+
+   /* Last reference dropped, tear down service */
+   wfc_client_ipc_destroy_waitpool(&wfc_client_ipc.waitpool);
+   vchiq_remove_service(wfc_client_ipc.service);
+   vchiq_shutdown(wfc_client_ipc_vchiq_instance);
+   vcos_log_unregister(VCOS_LOG_CATEGORY);
+
+   wfc_client_ipc.service = 0;
+
+   service_destroyed = true;
+
+completed:
+   vcos_mutex_unlock(&wfc_client_ipc.lock);
+
+   return service_destroyed;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void wfc_client_ipc_use_keep_alive(void)
+{
+   vcos_mutex_lock(&wfc_client_ipc.lock);
+
+   if (!wfc_client_ipc.keep_alive_count++)
+      vchiq_use_service(wfc_client_ipc.service);
+
+   vcos_mutex_unlock(&wfc_client_ipc.lock);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void wfc_client_ipc_release_keep_alive(void)
+{
+   vcos_mutex_lock(&wfc_client_ipc.lock);
+
+   if (vcos_verify(wfc_client_ipc.keep_alive_count > 0))
+   {
+      if (!--wfc_client_ipc.keep_alive_count)
+         vchiq_release_service(wfc_client_ipc.service);
+   }
+
+   vcos_mutex_unlock(&wfc_client_ipc.lock);
+}
+
+/* ------------------------------------------------------------------------- */
+
+WFC_CLIENT_IPC_T *wfc_client_ipc_get_client(void)
+{
+   return &wfc_client_ipc;
+}
diff --git a/interface/khronos/wf/wfc_client_ipc.h b/interface/khronos/wf/wfc_client_ipc.h
new file mode 100755 (executable)
index 0000000..48f3b95
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined(WFC_CLIENT_IPC_H)
+#define WFC_CLIENT_IPC_H
+
+#include "interface/vcos/vcos.h"
+#include "interface/khronos/wf/wfc_ipc.h"
+
+/** Send a message and wait for a reply.
+ *
+ * @param msg       message to send
+ * @param size      length of message, including header
+ * @param dest      destination for reply data, or NULL
+ * @param destlen   size of destination, updated with actual length
+ * @return Success or the error code for failure.
+ */
+VCOS_STATUS_T wfc_client_ipc_sendwait(WFC_IPC_MSG_HEADER_T *msg,
+                                       size_t size,
+                                       void *dest,
+                                       size_t *destlen);
+
+/** Send a message and do not wait for a reply.
+ *
+ * @param msg_header   message header to send
+ * @param size         length of message, including header
+ * @param msgid        message id
+ * @return Success or the error code for failure.
+ */
+VCOS_STATUS_T wfc_client_ipc_send(WFC_IPC_MSG_HEADER_T *msg,
+                                    size_t size);
+
+/** Initialise the OpenWF-C client IPC. If successful, this must be balanced by
+ * a call to wfc_client_ipc_deinit(). This must be called at least once before
+ * sending a message.
+ *
+ * @return Success or the error code for failure.
+ */
+VCOS_STATUS_T wfc_client_ipc_init(void);
+
+/** Deinitialise the OpenWF-C client IPC.
+ *
+ * @return True if the service has been destroyed, false if there are other
+ *    users still active.
+ */
+bool wfc_client_ipc_deinit(void);
+
+/** Increase the keep alive count by one. If it rises from zero, the VideoCore
+ * will be prevented from being suspended.
+ */
+void wfc_client_ipc_use_keep_alive(void);
+
+/** Drop the keep alive count by one. If it reaches zero, the VideoCore may be
+ * suspended.
+ */
+void wfc_client_ipc_release_keep_alive(void);
+
+#endif   /* WFC_IPC_H */
diff --git a/interface/khronos/wf/wfc_client_server_api.c b/interface/khronos/wf/wfc_client_server_api.c
new file mode 100755 (executable)
index 0000000..a5773d8
--- /dev/null
@@ -0,0 +1,673 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/khronos/wf/wfc_server_api.h"
+#include "interface/khronos/wf/wfc_client_ipc.h"
+#include "interface/khronos/wf/wfc_ipc.h"
+#include "interface/vcos/vcos.h"
+#include "interface/khronos/include/WF/wfc.h"
+#include "interface/khronos/wf/wfc_int.h"
+#include "interface/khronos/include/EGL/eglext.h"
+
+#define VCOS_LOG_CATEGORY (&wfc_client_server_api_log_category)
+
+//#define WFC_FULL_LOGGING
+#ifdef WFC_FULL_LOGGING
+#define WFC_CLIENT_SERVER_API_LOGLEVEL VCOS_LOG_TRACE
+#else
+#define WFC_CLIENT_SERVER_API_LOGLEVEL VCOS_LOG_WARN
+#endif
+
+static VCOS_LOG_CAT_T wfc_client_server_api_log_category;
+
+/** Implement "void foo(WFCContext context)" */
+static VCOS_STATUS_T wfc_client_server_api_send_context(WFC_IPC_MSG_TYPE msg_type, WFCContext context)
+{
+   WFC_IPC_MSG_CONTEXT_T msg;
+
+   msg.header.type = msg_type;
+   msg.context = context;
+
+   return wfc_client_ipc_send(&msg.header, sizeof(msg));
+}
+
+/** Implement "void foo(WFCNativeStreamType stream)" */
+static VCOS_STATUS_T wfc_client_server_api_send_stream(WFC_IPC_MSG_TYPE msg_type, WFCNativeStreamType stream)
+{
+   WFC_IPC_MSG_STREAM_T msg;
+
+   msg.header.type = msg_type;
+   msg.stream = stream;
+
+   return wfc_client_ipc_send(&msg.header, sizeof(msg));
+}
+
+/** Implement "foo(WFCNativeStreamType stream)" where a result is returned.
+ * This may either be as a return value, or via a pointer parameter.
+ */
+static VCOS_STATUS_T wfc_client_server_api_sendwait_stream(WFC_IPC_MSG_TYPE msg_type, WFCNativeStreamType stream,
+      void *result, size_t *result_len)
+{
+   WFC_IPC_MSG_STREAM_T msg;
+
+   msg.header.type = msg_type;
+   msg.stream = stream;
+
+   return wfc_client_ipc_sendwait(&msg.header, sizeof(msg), result, result_len);
+}
+
+/* ========================================================================= */
+
+VCOS_STATUS_T wfc_server_connect(void)
+{
+   VCOS_STATUS_T status;
+
+   vcos_log_set_level(VCOS_LOG_CATEGORY, WFC_CLIENT_SERVER_API_LOGLEVEL);
+   vcos_log_register("wfccsapi", VCOS_LOG_CATEGORY);
+
+   status = wfc_client_ipc_init();
+
+   vcos_log_trace("%s: result %d", VCOS_FUNCTION, status);
+
+   if (status != VCOS_SUCCESS)
+   {
+      vcos_log_unregister(VCOS_LOG_CATEGORY);
+   }
+
+   return status;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void wfc_server_disconnect(void)
+{
+   vcos_log_trace("%s: called", VCOS_FUNCTION);
+
+   if (wfc_client_ipc_deinit())
+   {
+      vcos_log_unregister(VCOS_LOG_CATEGORY);
+   }
+}
+
+/* ------------------------------------------------------------------------- */
+
+void wfc_server_use_keep_alive(void)
+{
+   wfc_client_ipc_use_keep_alive();
+}
+
+/* ------------------------------------------------------------------------- */
+
+void wfc_server_release_keep_alive(void)
+{
+   wfc_client_ipc_release_keep_alive();
+}
+
+/* ------------------------------------------------------------------------- */
+
+uint32_t wfc_server_create_context(WFCContext context, uint32_t context_type,
+   uint32_t screen_or_stream_num, uint32_t pid_lo, uint32_t pid_hi)
+{
+   WFC_IPC_MSG_CREATE_CONTEXT_T msg;
+   VCOS_STATUS_T status;
+   uint32_t result = -1;
+   size_t result_len = sizeof(result);
+
+   vcos_log_trace("%s: context 0x%x type 0x%x num 0x%x pid 0x%x%08x", VCOS_FUNCTION,
+         context, context_type, screen_or_stream_num, pid_hi, pid_lo);
+
+   msg.header.type = WFC_IPC_MSG_CREATE_CONTEXT;
+   msg.context = context;
+   msg.context_type = context_type;
+   msg.screen_or_stream_num = screen_or_stream_num;
+   msg.pid_lo = pid_lo;
+   msg.pid_hi = pid_hi;
+
+   status = wfc_client_ipc_sendwait(&msg.header, sizeof(msg), &result, &result_len);
+
+   vcos_log_trace("%s: status 0x%x, result 0x%x", VCOS_FUNCTION, status, result);
+
+   if (status != VCOS_SUCCESS)
+      result = -1;
+
+   return result;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void wfc_server_destroy_context(WFCContext context)
+{
+   VCOS_STATUS_T status;
+
+   vcos_log_trace("%s: context 0x%x", VCOS_FUNCTION, context);
+
+   status = wfc_client_server_api_send_context(WFC_IPC_MSG_DESTROY_CONTEXT, context);
+
+   vcos_assert(status == VCOS_SUCCESS);
+}
+
+/* ------------------------------------------------------------------------- */
+
+uint32_t wfc_server_commit_scene(WFCContext context, const WFC_SCENE_T *scene,
+      uint32_t flags, WFC_CALLBACK_T scene_taken_cb, void *scene_taken_data)
+{
+   WFC_IPC_MSG_COMMIT_SCENE_T msg;
+   VCOS_STATUS_T status = VCOS_SUCCESS;
+   uint32_t result = VCOS_ENOSYS;
+   size_t result_len = sizeof(result);
+   uint32_t i;
+
+   vcos_log_trace("%s: context 0x%x commit %u elements %u flags 0x%x",
+         VCOS_FUNCTION, context, scene->commit_count, scene->element_count, flags);
+   for (i = 0; i < scene->element_count; i++)
+   {
+      vcos_log_trace("%s: element[%u] stream 0x%x", VCOS_FUNCTION, i, scene->elements[i].source_stream);
+   }
+
+   msg.header.type = WFC_IPC_MSG_COMMIT_SCENE;
+   msg.context = context;
+   msg.flags = flags;
+   msg.scene_taken_cb.ptr = scene_taken_cb;
+   msg.scene_taken_data.ptr = scene_taken_data;
+   memcpy(&msg.scene, scene, sizeof(*scene));
+
+   if (flags & WFC_SERVER_COMMIT_WAIT)
+   {
+      /* Caller will wait for callback, call cannot fail */
+      vcos_assert(scene_taken_cb != NULL);
+      vcos_assert(scene_taken_data != NULL);
+   }
+   else
+   {
+      /* Caller will not wait for callback, so need to at least wait for result. */
+      vcos_assert(scene_taken_cb == NULL);
+      vcos_assert(scene_taken_data == NULL);
+   }
+
+   status = wfc_client_ipc_sendwait(&msg.header, sizeof(msg), &result, &result_len);
+
+   /* Override the result if the status was an error */
+   if (status != VCOS_SUCCESS)
+      result = status;
+
+   return result;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void wfc_server_activate(WFCContext context)
+{
+   VCOS_STATUS_T status;
+
+   vcos_log_trace("%s: context 0x%x", VCOS_FUNCTION, context);
+
+   status = wfc_client_server_api_send_context(WFC_IPC_MSG_ACTIVATE, context);
+
+   vcos_assert(status == VCOS_SUCCESS);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void wfc_server_deactivate(WFCContext context)
+{
+   VCOS_STATUS_T status;
+
+   vcos_log_trace("%s: context 0x%x", VCOS_FUNCTION, context);
+
+   status = wfc_client_server_api_send_context(WFC_IPC_MSG_DEACTIVATE, context);
+
+   vcos_assert(status == VCOS_SUCCESS);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void wfc_server_set_deferral_stream(WFCContext context, WFCNativeStreamType stream)
+{
+   WFC_IPC_MSG_SET_DEFERRAL_STREAM_T msg;
+   VCOS_STATUS_T status;
+
+   vcos_log_trace("%s: context 0x%x stream 0x%x", VCOS_FUNCTION, context, stream);
+
+   msg.header.type = WFC_IPC_MSG_SET_DEFERRAL_STREAM;
+   msg.context = context;
+   msg.stream = stream;
+
+   status = wfc_client_ipc_send(&msg.header, sizeof(msg));
+
+   vcos_assert(status == VCOS_SUCCESS);
+}
+
+/* ------------------------------------------------------------------------- */
+
+WFCNativeStreamType wfc_server_stream_create(WFCNativeStreamType stream, uint32_t flags, uint32_t pid_lo, uint32_t pid_hi)
+{
+   WFC_IPC_MSG_SS_CREATE_INFO_T msg;
+   VCOS_STATUS_T status;
+   WFCNativeStreamType result = WFC_INVALID_HANDLE;
+   size_t result_len = sizeof(result);
+
+   vcos_log_trace("%s: stream 0x%x flags 0x%x pid 0x%x%08x", VCOS_FUNCTION, stream, flags, pid_hi, pid_lo);
+
+   msg.header.type = WFC_IPC_MSG_SS_CREATE_INFO;
+   msg.stream = stream;
+   memset(&msg.info, 0, sizeof(msg.info));
+   msg.info.size = sizeof(msg.info);
+   msg.info.flags = flags;
+   msg.pid_lo = pid_lo;
+   msg.pid_hi = pid_hi;
+
+   status = wfc_client_ipc_sendwait(&msg.header, sizeof(msg), &result, &result_len);
+
+   vcos_log_trace("%s: status 0x%x, result 0x%x", VCOS_FUNCTION, status, result);
+
+   if (status != VCOS_SUCCESS)
+      result = WFC_INVALID_HANDLE;
+
+   return result;
+}
+
+/* ------------------------------------------------------------------------- */
+
+WFCNativeStreamType wfc_server_stream_create_info(WFCNativeStreamType stream, const WFC_STREAM_INFO_T *info, uint32_t pid_lo, uint32_t pid_hi)
+{
+   WFC_IPC_MSG_SS_CREATE_INFO_T msg;
+   uint32_t copy_size;
+   VCOS_STATUS_T status;
+   WFCNativeStreamType result = WFC_INVALID_HANDLE;
+   size_t result_len = sizeof(result);
+
+   if (!info)
+   {
+      vcos_log_error("%s: NULL info pointer passed", VCOS_FUNCTION);
+      return WFC_INVALID_HANDLE;
+   }
+
+   if (info->size < sizeof(uint32_t))
+   {
+      vcos_log_error("%s: invalid info pointer passed (size:%u)", VCOS_FUNCTION, info->size);
+      return WFC_INVALID_HANDLE;
+   }
+
+   vcos_log_trace("%s: stream 0x%x flags 0x%x pid 0x%x%08x", VCOS_FUNCTION, stream, info->flags, pid_hi, pid_lo);
+
+   msg.header.type = WFC_IPC_MSG_SS_CREATE_INFO;
+   msg.stream = stream;
+   copy_size = vcos_min(info->size, sizeof(msg.info));
+   memcpy(&msg.info, info, copy_size);
+   msg.info.size = copy_size;
+   msg.pid_lo = pid_lo;
+   msg.pid_hi = pid_hi;
+
+   status = wfc_client_ipc_sendwait(&msg.header, sizeof(msg), &result, &result_len);
+
+   vcos_log_trace("%s: status 0x%x, result 0x%x", VCOS_FUNCTION, status, result);
+
+   if (status != VCOS_SUCCESS)
+      result = WFC_INVALID_HANDLE;
+
+   return result;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void wfc_server_stream_destroy(WFCNativeStreamType stream, uint32_t pid_lo, uint32_t pid_hi)
+{
+   WFC_IPC_MSG_SS_DESTROY_T msg;
+   VCOS_STATUS_T status;
+
+   vcos_log_trace("%s: stream 0x%x", VCOS_FUNCTION, stream);
+
+   msg.header.type = WFC_IPC_MSG_SS_DESTROY;
+   msg.stream = stream;
+   msg.pid_lo = pid_lo;
+   msg.pid_hi = pid_hi;
+
+   status = wfc_client_ipc_send(&msg.header, sizeof(msg));
+
+   vcos_assert(status == VCOS_SUCCESS);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void wfc_server_stream_on_rects_change(WFCNativeStreamType stream, WFC_CALLBACK_T rects_change_cb, void *rects_change_data)
+{
+   WFC_IPC_MSG_SS_ON_RECTS_CHANGE_T msg;
+   VCOS_STATUS_T status;
+
+   vcos_log_trace("%s: stream 0x%x cb %p data %p", VCOS_FUNCTION, stream, rects_change_cb, rects_change_data);
+
+   msg.header.type = WFC_IPC_MSG_SS_ON_RECTS_CHANGE;
+   msg.stream = stream;
+   msg.rects_change_cb.ptr = rects_change_cb;
+   msg.rects_change_data.ptr = rects_change_data;
+
+   status = wfc_client_ipc_send(&msg.header, sizeof(msg));
+
+   if (!vcos_verify(status == VCOS_SUCCESS))
+   {
+      (*rects_change_cb)(rects_change_data);
+   }
+}
+
+/* ------------------------------------------------------------------------- */
+
+uint32_t wfc_server_stream_get_rects(WFCNativeStreamType stream, int32_t rects[WFC_SERVER_STREAM_RECTS_SIZE])
+{
+   uint32_t result;
+   VCOS_STATUS_T status;
+   WFC_IPC_MSG_SS_GET_RECTS_T reply;
+   size_t rects_len = sizeof(reply) - sizeof(WFC_IPC_MSG_HEADER_T);
+
+   vcos_log_trace("%s: stream 0x%x", VCOS_FUNCTION, stream);
+   memset(&reply, 0, sizeof(reply));
+   status = wfc_client_server_api_sendwait_stream(WFC_IPC_MSG_SS_GET_RECTS, stream, &reply.result, &rects_len);
+
+   if (status == VCOS_SUCCESS)
+   {
+      result = reply.result;
+
+      if (result == VCOS_SUCCESS)
+      {
+         memcpy(rects, reply.rects, WFC_SERVER_STREAM_RECTS_SIZE * sizeof(*rects));
+         vcos_log_trace("%s: rects (%d,%d,%d,%d) (%d,%d,%d,%d)", VCOS_FUNCTION,
+               rects[0], rects[1], rects[2], rects[3], rects[4], rects[5], rects[6], rects[7]);
+      }
+      else
+      {
+         vcos_log_error("%s: result %d", VCOS_FUNCTION, result);
+      }
+   }
+   else
+   {
+      vcos_log_error("%s: send msg status %d", VCOS_FUNCTION, status);
+      result = status;
+   }
+
+   return result;
+}
+
+/* ------------------------------------------------------------------------- */
+
+bool wfc_server_stream_is_in_use(WFCNativeStreamType stream)
+{
+   VCOS_STATUS_T status;
+   uint32_t result = 0;
+   size_t result_len = sizeof(result);
+
+   vcos_log_trace("%s: stream 0x%x", VCOS_FUNCTION, stream);
+
+   status = wfc_client_server_api_sendwait_stream(WFC_IPC_MSG_SS_IS_IN_USE, stream, &result, &result_len);
+
+   vcos_log_trace("%s: status 0x%x, result %u", VCOS_FUNCTION, status, result);
+
+   if (status != VCOS_SUCCESS)
+      result = 0;
+
+   return result != 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+bool wfc_server_stream_allocate_images(WFCNativeStreamType stream, uint32_t width, uint32_t height, uint32_t nbufs)
+{
+   WFC_IPC_MSG_SS_ALLOCATE_IMAGES_T msg;
+   VCOS_STATUS_T status;
+   uint32_t result = 0;
+   size_t result_len = sizeof(result);
+
+   vcos_log_trace("%s: stream 0x%x width %u height %u nbufs %u", VCOS_FUNCTION, stream, width, height, nbufs);
+
+   msg.header.type = WFC_IPC_MSG_SS_ALLOCATE_IMAGES;
+   msg.stream = stream;
+   msg.width = width;
+   msg.height = height;
+   msg.nbufs = nbufs;
+
+   status = wfc_client_ipc_sendwait(&msg.header, sizeof(msg), &result, &result_len);
+
+   vcos_log_trace("%s: status 0x%x result %u", VCOS_FUNCTION, status, result);
+
+   if (status != VCOS_SUCCESS)
+      result = 0;
+
+   return result;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void wfc_server_stream_signal_eglimage_data(WFCNativeStreamType stream,
+      uint32_t ustorage, uint32_t width, uint32_t height, uint32_t stride,
+      uint32_t offset, uint32_t format, uint32_t flags, bool flip)
+{
+   WFC_IPC_MSG_SS_SIGNAL_EGLIMAGE_DATA_T msg;
+   VCOS_STATUS_T status;
+
+   memset(&msg, 0, sizeof msg);
+   msg.header.type = WFC_IPC_MSG_SS_SIGNAL_EGLIMAGE_DATA;
+   msg.stream = stream;
+   msg.ustorage = ustorage;
+   msg.width = width;
+   msg.height = height;
+   msg.stride = stride;
+   msg.offset = offset;
+   msg.format = format;
+   msg.flags = flags;
+   msg.flip = flip;
+
+   vcos_log_trace("%s: stream 0x%x image storage 0x%x",
+         VCOS_FUNCTION, stream, ustorage);
+
+   status = wfc_client_ipc_send(&msg.header, sizeof(msg));
+
+   vcos_assert(status == VCOS_SUCCESS);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void wfc_server_stream_signal_mm_image_data(WFCNativeStreamType stream, uint32_t image_handle)
+{
+   WFC_IPC_MSG_SS_SIGNAL_MM_IMAGE_DATA_T msg;
+   VCOS_STATUS_T status;
+
+   vcos_log_trace("%s: stream 0x%x image 0x%x", VCOS_FUNCTION, stream, image_handle);
+
+   msg.header.type = WFC_IPC_MSG_SS_SIGNAL_MM_IMAGE_DATA;
+   msg.stream = stream;
+   msg.image_handle = image_handle;
+
+   status = wfc_client_ipc_send(&msg.header, sizeof(msg));
+
+   vcos_assert(status == VCOS_SUCCESS);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void wfc_server_stream_signal_raw_pixels(WFCNativeStreamType stream,
+      uint32_t handle, uint32_t format, uint32_t width, uint32_t height,
+      uint32_t pitch, uint32_t vpitch)
+{
+   WFC_IPC_MSG_SS_SIGNAL_RAW_PIXELS_T msg;
+   VCOS_STATUS_T status;
+
+   vcos_log_trace("%s: stream 0x%x image 0x%x format 0x%x width %u height %u"
+         " pitch %u vpitch %u",
+         VCOS_FUNCTION, stream, handle, format, width, height, pitch, vpitch);
+
+   msg.header.type = WFC_IPC_MSG_SS_SIGNAL_RAW_PIXELS;
+   msg.stream = stream;
+   msg.handle = handle;
+   msg.format = format;
+   msg.width = width;
+   msg.height = height;
+   msg.pitch = pitch;
+   msg.vpitch = vpitch;
+
+   status = wfc_client_ipc_send(&msg.header, sizeof(msg));
+   vcos_assert(status == VCOS_SUCCESS);
+}
+
+/* ------------------------------------------------------------------------- */
+void wfc_server_stream_signal_image(WFCNativeStreamType stream,
+      const WFC_STREAM_IMAGE_T *image)
+{
+   WFC_IPC_MSG_SS_SIGNAL_IMAGE_T msg;
+   VCOS_STATUS_T status;
+
+   vcos_log_trace("%s: stream 0x%x type 0x%x handle 0x%x "
+         " format 0x%x protection 0x%x width %u height %u "
+         " pitch %u vpitch %u",
+         VCOS_FUNCTION, stream, image->type, image->handle,
+         image->format, image->protection, image->width, image->height,
+         image->pitch, image->vpitch);
+
+   msg.header.type = WFC_IPC_MSG_SS_SIGNAL_IMAGE;
+   msg.stream = stream;
+   if vcos_verify(image->length <= sizeof(msg.image))
+   {
+      msg.image = *image;
+   }
+   else
+   {
+      /* Client is newer than VC ? */
+      memcpy(&msg.image, image, sizeof(msg.image));
+      msg.image.length = sizeof(msg.image);
+   }
+
+   status = wfc_client_ipc_send(&msg.header, sizeof(msg));
+
+   vcos_assert(status == VCOS_SUCCESS);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void wfc_server_stream_register(WFCNativeStreamType stream, uint32_t pid_lo, uint32_t pid_hi)
+{
+   WFC_IPC_MSG_SS_REGISTER_T msg;
+   VCOS_STATUS_T status;
+
+   vcos_log_trace("%s: stream 0x%x pid 0x%x%08x", VCOS_FUNCTION, stream, pid_hi, pid_lo);
+
+   msg.header.type = WFC_IPC_MSG_SS_REGISTER;
+   msg.stream = stream;
+   msg.pid_lo = pid_lo;
+   msg.pid_hi = pid_hi;
+
+   status = wfc_client_ipc_send(&msg.header, sizeof(msg));
+
+   vcos_assert(status == VCOS_SUCCESS);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void wfc_server_stream_unregister(WFCNativeStreamType stream, uint32_t pid_lo, uint32_t pid_hi)
+{
+   WFC_IPC_MSG_SS_UNREGISTER_T msg;
+   VCOS_STATUS_T status;
+
+   vcos_log_trace("%s: stream 0x%x pid 0x%x%08x", VCOS_FUNCTION, stream, pid_hi, pid_lo);
+
+   msg.header.type = WFC_IPC_MSG_SS_UNREGISTER;
+   msg.stream = stream;
+   msg.pid_lo = pid_lo;
+   msg.pid_hi = pid_hi;
+
+   status = wfc_client_ipc_send(&msg.header, sizeof(msg));
+
+   vcos_assert(status == VCOS_SUCCESS);
+}
+
+/* ------------------------------------------------------------------------- */
+
+uint32_t wfc_server_stream_get_info(WFCNativeStreamType stream, WFC_STREAM_INFO_T *info)
+{
+   uint32_t result;
+   VCOS_STATUS_T status;
+   WFC_IPC_MSG_SS_GET_INFO_T reply;
+   size_t info_len = sizeof(reply) - sizeof(WFC_IPC_MSG_HEADER_T);
+
+   if (!info)
+   {
+      vcos_log_error("%s: NULL info pointer passed", VCOS_FUNCTION);
+      return WFC_INVALID_HANDLE;
+   }
+
+   if (info->size < sizeof(uint32_t))
+   {
+      vcos_log_error("%s: invalid info pointer passed (size:%u)", VCOS_FUNCTION, info->size);
+      return WFC_INVALID_HANDLE;
+   }
+
+   vcos_log_trace("%s: stream 0x%x", VCOS_FUNCTION, stream);
+   memset(&reply, 0, sizeof(reply));
+   status = wfc_client_server_api_sendwait_stream(WFC_IPC_MSG_SS_GET_INFO, stream, &reply.result, &info_len);
+
+   if (status == VCOS_SUCCESS)
+   {
+      result = reply.result;
+
+      if (result == VCOS_SUCCESS)
+      {
+         uint32_t copy_size = vcos_min(info->size, reply.info.size);
+         memcpy(info, &reply.info, copy_size);
+         info->size = copy_size;
+         vcos_log_trace("%s: copied %u bytes", VCOS_FUNCTION, copy_size);
+      }
+      else
+      {
+         vcos_log_error("%s: result %d", VCOS_FUNCTION, result);
+      }
+   }
+   else
+   {
+      vcos_log_error("%s: send msg status %d", VCOS_FUNCTION, status);
+      result = status;
+   }
+
+   return result;
+}
+
+/* ------------------------------------------------------------------------- */
+
+void wfc_server_stream_on_image_available(WFCNativeStreamType stream, WFC_CALLBACK_T image_available_cb, void *image_available_data)
+{
+   WFC_IPC_MSG_SS_ON_IMAGE_AVAILABLE_T msg;
+   VCOS_STATUS_T status;
+
+   vcos_log_trace("%s: stream 0x%x cb %p data %p", VCOS_FUNCTION, stream, image_available_cb, image_available_data);
+
+   msg.header.type = WFC_IPC_MSG_SS_ON_IMAGE_AVAILABLE;
+   msg.stream = stream;
+   msg.image_available_cb.ptr = image_available_cb;
+   msg.image_available_data.ptr = image_available_data;
+
+   status = wfc_client_ipc_send(&msg.header, sizeof(msg));
+
+   if (!vcos_verify(status == VCOS_SUCCESS))
+   {
+      (*image_available_cb)(image_available_data);
+   }
+}
diff --git a/interface/khronos/wf/wfc_client_stream.c b/interface/khronos/wf/wfc_client_stream.c
new file mode 100755 (executable)
index 0000000..77ae927
--- /dev/null
@@ -0,0 +1,1043 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define VCOS_VERIFY_BKPTS 1 // TODO remove
+#define VCOS_LOG_CATEGORY (&log_cat)
+
+#include "interface/khronos/common/khrn_client.h"
+#include "interface/vcos/vcos.h"
+#ifdef KHRN_FRUIT_DIRECT
+#include "middleware/khronos/egl/egl_server.h"
+#include "middleware/khronos/ext/egl_khr_image.h"
+#include "middleware/khronos/common/khrn_umem.h"
+#endif
+
+#include "interface/khronos/wf/wfc_client_stream.h"
+#include "interface/khronos/wf/wfc_server_api.h"
+
+//#define WFC_FULL_LOGGING
+#ifdef WFC_FULL_LOGGING
+#define WFC_LOG_LEVEL VCOS_LOG_TRACE
+#else
+#define WFC_LOG_LEVEL VCOS_LOG_WARN
+#endif
+
+//==============================================================================
+
+//!@name Stream data block pool sizes
+//!@{
+#define WFC_STREAM_BLOCK_SIZE          (WFC_MAX_STREAMS_PER_CLIENT / 8)
+#define WFC_STREAM_MAX_EXTENSIONS      7
+#define WFC_STREAM_MAX_STREAMS         (WFC_STREAM_BLOCK_SIZE * (WFC_STREAM_MAX_EXTENSIONS + 1))
+//!@}
+
+//!@name Global lock to protect global data (stream data list, next stream ID)
+//!@{
+#define GLOBAL_LOCK()      do {vcos_once(&wfc_stream_initialise_once, wfc_stream_initialise); vcos_mutex_lock(&wfc_stream_global_lock);} while (0)
+#define GLOBAL_UNLOCK()    do {vcos_mutex_unlock(&wfc_stream_global_lock);} while (0)
+//!@}
+
+//!@name Stream-specific mutex. Global lock must already be held when acquiring this lock.
+//!@{
+#define STREAM_LOCK(stream_ptr)        do {vcos_mutex_lock(&stream_ptr->mutex);} while (0)
+#define STREAM_UNLOCK(stream_ptr)      do {vcos_mutex_unlock(&stream_ptr->mutex);} while (0)
+//!@}
+
+//! Period in milliseconds to wait for an existing stream handle to be released
+//! when creating a new one.
+#define WFC_STREAM_RETRY_DELAY_MS      1
+//! Number of attempts allowed to create a stream with a given handle.
+#define WFC_STREAM_RETRIES             50
+
+//==============================================================================
+
+//! Top-level stream type
+typedef struct WFC_STREAM_tag
+{
+   //! Handle; may be assigned by window manager.
+   WFCNativeStreamType handle;
+
+   //! Number of times this stream has been registered in the process. Creation implies registration
+   uint32_t registrations;
+
+   //! Flag to indicate entry is no longer in use and imminently due for destruction.
+   bool to_be_deleted;
+
+   //! Mutex, for thread safety.
+   VCOS_MUTEX_T mutex;
+
+   //! Configuration info.
+   WFC_STREAM_INFO_T info;
+
+   //!@brief Image providers to which this stream sends data; recorded so we do
+   //! not destroy this stream if it is still associated with a source or mask.
+   uint32_t num_of_sources_or_masks;
+   //! Record if this stream holds the output from an off-screen context.
+   bool used_for_off_screen;
+
+   //! Thread for handling server-side request to change source and/or destination rectangles
+   VCOS_THREAD_T rect_req_thread_data;
+   //! Flag for when thread must terminate
+   bool rect_req_terminate;
+   //! Callback function notifying calling module
+   WFC_STREAM_REQ_RECT_CALLBACK_T req_rect_callback;
+   //! Argument to callback function
+   void *req_rect_cb_args;
+
+   //! Pointer to next stream
+   struct WFC_STREAM_tag *next;
+   //! Pointer to previous stream
+   struct WFC_STREAM_tag *prev;
+} WFC_STREAM_T;
+
+//==============================================================================
+
+//! Blockpool containing all created streams.
+static VCOS_BLOCKPOOL_T wfc_stream_blockpool;
+//! Next stream handle, allocated by wfc_stream_get_next().
+static WFCNativeStreamType wfc_stream_next_handle = (1 << 31);
+
+static VCOS_LOG_CAT_T log_cat = VCOS_LOG_INIT("wfc_client_stream", WFC_LOG_LEVEL);
+
+//! Ensure lock and blockpool are only initialised once
+static VCOS_ONCE_T wfc_stream_initialise_once;
+//! The global (process-wide) lock
+static VCOS_MUTEX_T wfc_stream_global_lock;
+//! Pointer to the first stream data block
+static WFC_STREAM_T *wfc_stream_head;
+
+//==============================================================================
+//!@name Static functions
+//!@{
+static void wfc_stream_initialise(void);
+static WFC_STREAM_T *wfc_stream_global_lock_and_find_stream_ptr(WFCNativeStreamType stream);
+static WFC_STREAM_T *wfc_stream_create_stream_ptr(WFCNativeStreamType stream, bool allow_duplicate);
+static WFC_STREAM_T *wfc_stream_find_stream_ptr(WFCNativeStreamType stream);
+static void wfc_stream_destroy_if_ready(WFC_STREAM_T *stream_ptr);
+static void *wfc_stream_rect_req_thread(void *arg);
+static void wfc_client_stream_post_sem(void *cb_data);
+//!@}
+//==============================================================================
+//!@name Public functions
+//!@{
+
+WFCNativeStreamType wfc_stream_get_next(void)
+// In cases where the caller doesn't want to assign a stream number, provide
+// one for it.
+{
+   GLOBAL_LOCK();
+
+   WFCNativeStreamType next_stream = wfc_stream_next_handle;
+   wfc_stream_next_handle++;
+
+   GLOBAL_UNLOCK();
+
+   return next_stream;
+}
+
+//------------------------------------------------------------------------------
+
+uint32_t wfc_stream_create(WFCNativeStreamType stream, uint32_t flags)
+// Create a stream, using the given stream handle (typically assigned by the
+// window manager). Return zero if OK.
+{
+   WFC_STREAM_T *stream_ptr;
+   uint32_t result = 0;
+
+   vcos_log_info("%s: stream 0x%x flags 0x%x", VCOS_FUNCTION, stream, flags);
+
+   // Create stream
+   stream_ptr = wfc_stream_create_stream_ptr(stream, false);
+   if(stream_ptr == NULL)
+   {
+      vcos_log_error("%s: unable to create data block for stream 0x%x", VCOS_FUNCTION, stream);
+      return VCOS_ENOMEM;
+   }
+
+   uint64_t pid = vcos_process_id_current();
+   uint32_t pid_lo = (uint32_t) pid;
+   uint32_t pid_hi = (uint32_t) (pid >> 32);
+   int stream_in_use_retries = WFC_STREAM_RETRIES;
+   WFC_STREAM_INFO_T info;
+
+   memset(&info, 0, sizeof(info));
+   info.size = sizeof(info);
+   info.flags = flags;
+
+   do
+   {
+      stream_ptr->handle = wfc_server_stream_create_info(stream, &info, pid_lo, pid_hi);
+      vcos_log_trace("%s: server create returned 0x%x", VCOS_FUNCTION, stream_ptr->handle);
+
+      // If a handle is re-used rapidly, it may still be in use in the server temporarily
+      // Retry after a short delay
+      if (stream_ptr->handle == WFC_INVALID_HANDLE)
+         vcos_sleep(WFC_STREAM_RETRY_DELAY_MS);
+   }
+   while (stream_ptr->handle == WFC_INVALID_HANDLE && stream_in_use_retries-- > 0);
+
+   if (stream_ptr->handle == WFC_INVALID_HANDLE)
+   {
+      // Even after the retries, stream handle was still in use. Fail.
+      vcos_log_error("%s: stream 0x%x already exists in server", VCOS_FUNCTION, stream);
+      result = VCOS_EEXIST;
+      wfc_stream_destroy_if_ready(stream_ptr);
+   }
+   else
+   {
+      vcos_assert(stream_ptr->handle == stream);
+
+      stream_ptr->registrations++;
+      stream_ptr->info.flags = flags;
+      STREAM_UNLOCK(stream_ptr);
+   }
+
+   return result;
+}
+
+//------------------------------------------------------------------------------
+
+WFCNativeStreamType wfc_stream_create_assign_id(uint32_t flags)
+// Create a stream, and automatically assign it a new stream number, which is returned
+{
+   WFCNativeStreamType stream = wfc_stream_get_next();
+   uint32_t failure = wfc_stream_create(stream, flags);
+
+   if (failure == VCOS_EEXIST)
+   {
+      // If a duplicate stream exists, give it one more go with a new ID
+      stream = wfc_stream_get_next();
+      failure = wfc_stream_create(stream, flags);
+   }
+
+   if(failure) {return WFC_INVALID_HANDLE;}
+   else {return stream;}
+}
+
+//------------------------------------------------------------------------------
+
+uint32_t wfc_stream_create_req_rect
+   (WFCNativeStreamType stream, uint32_t flags,
+      WFC_STREAM_REQ_RECT_CALLBACK_T callback, void *cb_args)
+// Create a stream, using the given stream handle, which will notify the calling
+// module when the server requests a change in source and/or destination rectangle,
+// using the supplied callback. Return zero if OK.
+{
+   vcos_log_info("wfc_stream_create_req_rect: stream %X", stream);
+
+   uint32_t failure;
+
+   failure = wfc_stream_create(stream, flags | WFC_STREAM_FLAGS_REQ_RECT);
+   if (failure)
+      return failure;
+
+   WFC_STREAM_T *stream_ptr = wfc_stream_find_stream_ptr(stream);
+   // Stream just created, so ought to be found
+   vcos_assert(stream_ptr);
+
+   // There's no point creating this type of stream if you don't supply a callback
+   // to update the src/dest rects via WF-C.
+   vcos_assert(callback != NULL);
+
+   stream_ptr->req_rect_callback = callback;
+   stream_ptr->req_rect_cb_args = cb_args;
+
+   // Create thread for handling server-side request to change source
+   // and/or destination rectangles. One per stream (if enabled).
+   VCOS_STATUS_T status = vcos_thread_create(&stream_ptr->rect_req_thread_data, "wfc_stream_rect_req_thread",
+      NULL, wfc_stream_rect_req_thread, (void *) stream);
+   vcos_demand(status == VCOS_SUCCESS);
+
+   STREAM_UNLOCK(stream_ptr);
+
+   return 0;
+}
+
+//------------------------------------------------------------------------------
+
+bool wfc_stream_register_source_or_mask(WFCNativeStreamType stream, bool add_source_or_mask)
+// Indicate that a source or mask is now associated with this stream, or should
+// now be removed from such an association.
+{
+   WFC_STREAM_T *stream_ptr = wfc_stream_find_stream_ptr(stream);
+
+   if (!stream_ptr)
+      return false;
+
+   vcos_log_trace("%s: stream 0x%x %d->%d", VCOS_FUNCTION, stream,
+         stream_ptr->num_of_sources_or_masks,
+         add_source_or_mask ? stream_ptr->num_of_sources_or_masks + 1 : stream_ptr->num_of_sources_or_masks - 1);
+
+   if(add_source_or_mask)
+   {
+      stream_ptr->num_of_sources_or_masks++;
+      STREAM_UNLOCK(stream_ptr);
+   }
+   else
+   {
+      if(vcos_verify(stream_ptr->num_of_sources_or_masks > 0))
+         {stream_ptr->num_of_sources_or_masks--;}
+
+      // Stream is unlocked by destroy_if_ready
+      wfc_stream_destroy_if_ready(stream_ptr);
+   }
+
+   return true;
+}
+
+//------------------------------------------------------------------------------
+
+void wfc_stream_await_buffer(WFCNativeStreamType stream)
+// Suspend until buffer is available on the server.
+{
+   vcos_log_trace("%s: stream 0x%x", VCOS_FUNCTION, stream);
+
+   WFC_STREAM_T *stream_ptr = wfc_stream_find_stream_ptr(stream);
+   if (!stream_ptr)
+      return;
+
+   if(vcos_verify(stream_ptr->info.flags & WFC_STREAM_FLAGS_BUF_AVAIL))
+   {
+      VCOS_SEMAPHORE_T image_available_sem;
+      VCOS_STATUS_T status;
+
+      // Long running operation, so keep VC alive until it completes.
+      wfc_server_use_keep_alive();
+
+      status = vcos_semaphore_create(&image_available_sem, "WFC image available", 0);
+      vcos_assert(status == VCOS_SUCCESS);      // For all relevant platforms
+      vcos_unused(status);
+
+      wfc_server_stream_on_image_available(stream, wfc_client_stream_post_sem, &image_available_sem);
+
+      vcos_log_trace("%s: pre async sem wait: stream: %X", VCOS_FUNCTION, stream);
+      vcos_semaphore_wait(&image_available_sem);
+      vcos_log_trace("%s: post async sem wait: stream: %X", VCOS_FUNCTION, stream);
+
+      vcos_semaphore_delete(&image_available_sem);
+      wfc_server_release_keep_alive();
+   }
+
+   STREAM_UNLOCK(stream_ptr);
+
+}
+
+//------------------------------------------------------------------------------
+
+void wfc_stream_destroy(WFCNativeStreamType stream)
+// Destroy a stream - unless it is still in use, in which case, mark it for
+// destruction once all users have finished with it.
+{
+   vcos_log_info("%s: stream: %X", VCOS_FUNCTION, stream);
+
+   WFC_STREAM_T *stream_ptr = wfc_stream_find_stream_ptr(stream);
+
+   if (stream_ptr)
+   {
+      /* If stream is still in use (e.g. it's attached to at least one source/mask
+       * which is associated with at least one element) then destruction is delayed
+       * until it's no longer in use. */
+      if (stream_ptr->registrations> 0)
+      {
+         stream_ptr->registrations--;
+         vcos_log_trace("%s: stream: %X ready to destroy?", VCOS_FUNCTION, stream);
+      }
+      else
+      {
+         vcos_log_error("%s: stream: %X destroyed when unregistered", VCOS_FUNCTION, stream);
+      }
+
+      // Stream is unlocked by destroy_if_ready
+      wfc_stream_destroy_if_ready(stream_ptr);
+   }
+   else
+   {
+      vcos_log_warn("%s: stream %X doesn't exist", VCOS_FUNCTION, stream);
+   }
+
+}
+
+//------------------------------------------------------------------------------
+//!@name
+//! Off-screen composition functions
+//!@{
+//------------------------------------------------------------------------------
+
+uint32_t wfc_stream_create_for_context
+   (WFCNativeStreamType stream, uint32_t width, uint32_t height)
+// Create a stream for an off-screen context to output to, with the default number of buffers.
+{
+   return wfc_stream_create_for_context_nbufs(stream, width, height, 0);
+}
+
+uint32_t wfc_stream_create_for_context_nbufs
+   (WFCNativeStreamType stream, uint32_t width, uint32_t height, uint32_t nbufs)
+// Create a stream for an off-screen context to output to, with a specific number of buffers.
+{
+   WFC_STREAM_T *stream_ptr;
+   bool stream_created = false;
+
+   if(!vcos_verify(stream != WFC_INVALID_HANDLE))
+      {return 1;}
+
+   stream_ptr = wfc_stream_find_stream_ptr(stream);
+   if (stream_ptr)
+   {
+      uint32_t flags = stream_ptr->info.flags;
+
+      // Stream already exists, check flags match expected
+      STREAM_UNLOCK(stream_ptr);
+
+      if (flags != WFC_STREAM_FLAGS_NONE)
+      {
+         vcos_log_error("%s: stream flags mismatch (expected 0x%x, got 0x%x)", VCOS_FUNCTION, WFC_STREAM_FLAGS_NONE, flags);
+         return 1;
+      }
+   }
+   else
+   {
+      // Create stream
+      if (wfc_stream_create(stream, WFC_STREAM_FLAGS_NONE) != 0)
+         return 1;
+      stream_created = true;
+   }
+
+   // Allocate buffers on the server.
+   if (!wfc_server_stream_allocate_images(stream, width, height, nbufs))
+   {
+      // Failed to allocate buffers
+      vcos_log_warn("%s: failed to allocate %u buffers for stream %X size %ux%u", VCOS_FUNCTION, nbufs, stream, width, height);
+      if (stream_created)
+         wfc_stream_destroy(stream);
+      return 1;
+   }
+
+   return 0;
+}
+
+//------------------------------------------------------------------------------
+
+bool wfc_stream_used_for_off_screen(WFCNativeStreamType stream)
+// Returns true if this stream exists, and is in use as the output of an
+// off-screen context.
+{
+   bool used_for_off_screen;
+
+   vcos_log_trace("%s: stream 0x%x", VCOS_FUNCTION, stream);
+
+   WFC_STREAM_T *stream_ptr = wfc_stream_find_stream_ptr(stream);
+   if (!stream_ptr)
+      return false;
+
+   used_for_off_screen = stream_ptr->used_for_off_screen;
+
+   STREAM_UNLOCK(stream_ptr);
+
+   return used_for_off_screen;
+
+}
+
+//------------------------------------------------------------------------------
+
+void wfc_stream_register_off_screen(WFCNativeStreamType stream, bool used_for_off_screen)
+// Called on behalf of an off-screen context, to either set or clear the stream's
+// flag indicating that it's being used as output for that context.
+{
+   if(stream == WFC_INVALID_HANDLE)
+      {return;}
+
+   vcos_log_trace("%s: stream 0x%x", VCOS_FUNCTION, stream);
+
+   WFC_STREAM_T *stream_ptr = wfc_stream_find_stream_ptr(stream);
+   if (!stream_ptr)
+      return;
+
+   stream_ptr->used_for_off_screen = used_for_off_screen;
+
+   if (used_for_off_screen)
+      STREAM_UNLOCK(stream_ptr);
+   else
+   {
+      // Stream is unlocked by destroy_if_ready
+      wfc_stream_destroy_if_ready(stream_ptr);
+   }
+}
+
+//!@} // Off-screen composition functions
+//!@} // Public functions
+//==============================================================================
+
+/** Initialise logging and global mutex */
+static void wfc_stream_initialise(void)
+{
+   VCOS_STATUS_T status;
+
+   vcos_log_set_level(&log_cat, WFC_LOG_LEVEL);
+   vcos_log_register("wfc_client_stream", &log_cat);
+
+   vcos_log_trace("%s", VCOS_FUNCTION);
+
+   status = vcos_mutex_create(&wfc_stream_global_lock, "WFC stream global lock");
+   vcos_assert(status == VCOS_SUCCESS);
+
+   status = vcos_blockpool_create_on_heap(&wfc_stream_blockpool,
+         WFC_STREAM_BLOCK_SIZE, sizeof(WFC_STREAM_T),
+         VCOS_BLOCKPOOL_ALIGN_DEFAULT, VCOS_BLOCKPOOL_FLAG_NONE,
+         "wfc stream pool");
+   vcos_assert(status == VCOS_SUCCESS);
+
+   status = vcos_blockpool_extend(&wfc_stream_blockpool,
+         WFC_STREAM_MAX_EXTENSIONS, WFC_STREAM_BLOCK_SIZE);
+   vcos_assert(status == VCOS_SUCCESS);
+}
+
+//------------------------------------------------------------------------------
+
+/** Take the global lock and then search for the stream data for a given handle.
+ * The global lock is not released on return and the stream is not locked.
+ *
+ * @param stream The stream handle.
+ * @return The pointer to the stream structure, or NULL if not found.
+ */
+static WFC_STREAM_T *wfc_stream_global_lock_and_find_stream_ptr(WFCNativeStreamType stream)
+{
+   WFC_STREAM_T *stream_ptr;
+
+   GLOBAL_LOCK();
+
+   stream_ptr = wfc_stream_head;
+   while (stream_ptr && stream_ptr->handle != stream)
+      stream_ptr = stream_ptr->next;
+
+   return stream_ptr;
+}
+
+//------------------------------------------------------------------------------
+
+/** Create a stream structure corresponding to the specified stream handle. If
+ * the stream structure already exists or there is an error allocating it, the
+ * function returns NULL. On success, the stream pointer is left locked.
+ *
+ * @param stream The stream handle.
+ * @param allow_duplicate True to allow an existing entry
+ * @return The pointer to the new stream structure, or NULL on error.
+ */
+static WFC_STREAM_T *wfc_stream_create_stream_ptr(WFCNativeStreamType stream, bool allow_duplicate)
+{
+   WFC_STREAM_T *stream_ptr = wfc_stream_global_lock_and_find_stream_ptr(stream);
+
+   vcos_log_trace("%s: stream handle 0x%x", VCOS_FUNCTION, stream);
+
+   if (stream_ptr && !stream_ptr->to_be_deleted)
+   {
+      if (!allow_duplicate)
+      {
+         vcos_log_error("%s: attempt to create duplicate of stream handle 0x%x", VCOS_FUNCTION, stream);
+         // Stream already exists, return NULL
+         stream_ptr = NULL;
+      }
+      else
+      {
+         vcos_log_trace("%s: duplicate of stream handle 0x%x created", VCOS_FUNCTION, stream);
+
+         STREAM_LOCK(stream_ptr);
+      }
+   }
+   else
+   {
+      if (stream_ptr)
+      {
+         vcos_log_trace("%s: recycling data block for stream handle 0x%x", VCOS_FUNCTION, stream);
+
+         // Recycle existing entry
+         stream_ptr->to_be_deleted = false;
+
+         STREAM_LOCK(stream_ptr);
+      }
+      else
+      {
+         vcos_log_trace("%s: allocating block for stream handle 0x%x", VCOS_FUNCTION, stream);
+
+         // Create new block and insert it into the list
+         stream_ptr = vcos_blockpool_calloc(&wfc_stream_blockpool);
+
+         if (stream_ptr)
+         {
+            VCOS_STATUS_T status;
+
+            status = vcos_mutex_create(&stream_ptr->mutex, "WFC_STREAM_T mutex");
+            if (vcos_verify(status == VCOS_SUCCESS))
+            {
+               STREAM_LOCK(stream_ptr);
+
+               // First stream in this process, connect
+               if (!wfc_stream_head)
+                  wfc_server_connect();
+
+               stream_ptr->handle = stream;
+               stream_ptr->info.size = sizeof(stream_ptr->info);
+
+               // Insert data into list
+               stream_ptr->next = wfc_stream_head;
+               if (wfc_stream_head)
+                  wfc_stream_head->prev = stream_ptr;
+               wfc_stream_head = stream_ptr;
+            }
+            else
+            {
+               vcos_log_error("%s: unable to create mutex for stream handle 0x%x", VCOS_FUNCTION, stream);
+               vcos_blockpool_free(stream_ptr);
+               stream_ptr = NULL;
+            }
+         }
+         else
+         {
+            vcos_log_error("%s: unable to allocate data for stream handle 0x%x", VCOS_FUNCTION, stream);
+         }
+      }
+   }
+
+   GLOBAL_UNLOCK();
+
+   return stream_ptr;
+}
+
+//------------------------------------------------------------------------------
+
+/** Destroys a stream structure identified by stream handle. If the stream is not
+ * found or the stream has not been marked for deletion, the operation has no
+ * effect.
+ *
+ * @param stream The stream handle.
+ */
+static void wfc_stream_destroy_stream_ptr(WFCNativeStreamType stream)
+{
+   WFC_STREAM_T *stream_ptr = wfc_stream_global_lock_and_find_stream_ptr(stream);
+
+   vcos_log_trace("%s: stream handle 0x%x", VCOS_FUNCTION, stream);
+
+   if (stream_ptr)
+   {
+      if (stream_ptr->to_be_deleted)
+      {
+         STREAM_LOCK(stream_ptr);
+
+         vcos_log_trace("%s: unlinking from list", VCOS_FUNCTION);
+
+         if (stream_ptr->next)
+            stream_ptr->next->prev = stream_ptr->prev;
+         if (stream_ptr->prev)
+            stream_ptr->prev->next = stream_ptr->next;
+         else
+            wfc_stream_head = stream_ptr->next;
+
+         // No streams left in this process, disconnect
+         if (wfc_stream_head == NULL)
+            wfc_server_disconnect();
+      }
+      else
+      {
+         vcos_log_trace("%s: stream 0x%x recycled before destruction", VCOS_FUNCTION, stream);
+         stream_ptr = NULL;
+      }
+   }
+   else
+   {
+      vcos_log_error("%s: stream 0x%x not found", VCOS_FUNCTION, stream);
+   }
+
+   GLOBAL_UNLOCK();
+
+   if (stream_ptr)
+   {
+      // Stream data block no longer in list, can safely destroy it
+      STREAM_UNLOCK(stream_ptr);
+
+      // Wait for rectangle request thread to complete
+      if(stream_ptr->info.flags & WFC_STREAM_FLAGS_REQ_RECT)
+         vcos_thread_join(&stream_ptr->rect_req_thread_data, NULL);
+
+      // Destroy mutex
+      vcos_mutex_delete(&stream_ptr->mutex);
+
+      // Delete
+      vcos_blockpool_free(stream_ptr);
+   }
+}
+
+//------------------------------------------------------------------------------
+
+/** Return a pointer to the stream structure corresponding to the specified stream
+ * handle. On success, the stream pointer is locked.
+ *
+ * @param stream The stream handle.
+ * @return The pointer to the stream structure, or NULL on error.
+ */
+static WFC_STREAM_T *wfc_stream_find_stream_ptr(WFCNativeStreamType stream)
+{
+   WFC_STREAM_T *stream_ptr = wfc_stream_global_lock_and_find_stream_ptr(stream);
+
+   if (stream_ptr && !stream_ptr->to_be_deleted)
+      STREAM_LOCK(stream_ptr);
+
+   GLOBAL_UNLOCK();
+
+   return stream_ptr;
+}
+
+//------------------------------------------------------------------------------
+
+/** Destroy the stream if it is no longer in use. The stream must be locked on
+ * entry and shall be unlocked (or destroyed along with the rest of the stream)
+ * on exit.
+ *
+ * @param stream_ptr The locked stream data pointer.
+ */
+static void wfc_stream_destroy_if_ready(WFC_STREAM_T *stream_ptr)
+{
+   WFCNativeStreamType stream;
+   uint64_t pid = vcos_process_id_current();
+   uint32_t pid_lo = (uint32_t)pid;
+   uint32_t pid_hi = (uint32_t)(pid >> 32);
+
+   if (stream_ptr == NULL)
+   {
+      vcos_log_error("%s: stream_ptr is NULL", VCOS_FUNCTION);
+      return;
+   }
+
+   if(stream_ptr->num_of_sources_or_masks > 0
+      || stream_ptr->used_for_off_screen
+      || stream_ptr->registrations > 0)
+   {
+      vcos_log_trace("%s: stream: %X not ready: reg:%u srcs:%u o/s:%d", VCOS_FUNCTION,
+            stream_ptr->handle, stream_ptr->registrations,
+            stream_ptr->num_of_sources_or_masks, stream_ptr->used_for_off_screen);
+      STREAM_UNLOCK(stream_ptr);
+      return;
+   }
+
+   stream = stream_ptr->handle;
+
+   vcos_log_info("%s: stream: %X to be destroyed", VCOS_FUNCTION, stream);
+
+   // Prevent stream from being found, although it can be recycled.
+   stream_ptr->to_be_deleted = true;
+
+   // Delete server-side stream
+   wfc_server_stream_destroy(stream, pid_lo, pid_hi);
+
+   STREAM_UNLOCK(stream_ptr);
+
+   wfc_stream_destroy_stream_ptr(stream);
+}
+
+//------------------------------------------------------------------------------
+
+//! Convert from dispmanx source rectangle type (int * 2^16) to WF-C type (float).
+#define WFC_DISPMANX_TO_SRC_VAL(value) (((WFCfloat) (value)) / 65536.0)
+
+static void *wfc_stream_rect_req_thread(void *arg)
+//!@brief Thread for handling server-side request to change source and/or destination
+//! rectangles. One per stream (if enabled).
+{
+   WFCNativeStreamType stream = (WFCNativeStreamType) arg;
+
+   WFC_STREAM_REQ_RECT_CALLBACK_T callback;
+   void *cb_args;
+   VCOS_SEMAPHORE_T rect_req_sem;
+   VCOS_STATUS_T status;
+
+   int32_t  vc_rects[8];
+   WFCint   dest_rect[WFC_RECT_SIZE];
+   WFCfloat src_rect[WFC_RECT_SIZE];
+
+   vcos_log_info("wfc_stream_rect_req_thread: START: stream: %X", stream);
+
+   WFC_STREAM_T *stream_ptr = wfc_stream_find_stream_ptr(stream);
+   if (!stream_ptr)
+      return NULL;
+
+   // Get local pointers to stream parameters
+   callback = stream_ptr->req_rect_callback;
+   cb_args = stream_ptr->req_rect_cb_args;
+
+   STREAM_UNLOCK(stream_ptr);
+
+   status = vcos_semaphore_create(&rect_req_sem, "WFC rect req", 0);
+   vcos_assert(status == VCOS_SUCCESS);      // On all relevant platforms
+
+   while (status == VCOS_SUCCESS)
+   {
+      wfc_server_stream_on_rects_change(stream, wfc_client_stream_post_sem, &rect_req_sem);
+
+      // Await new values from server
+      vcos_semaphore_wait(&rect_req_sem);
+
+      status = wfc_server_stream_get_rects(stream, vc_rects);
+      if (status == VCOS_SUCCESS)
+      {
+         // Convert from VC/dispmanx to WF-C types.
+         vcos_static_assert(sizeof(dest_rect) == (4 * sizeof(int32_t)));
+         memcpy(dest_rect, vc_rects, sizeof(dest_rect)); // Types are equivalent
+
+         src_rect[WFC_RECT_X] = WFC_DISPMANX_TO_SRC_VAL(vc_rects[4]);
+         src_rect[WFC_RECT_Y] = WFC_DISPMANX_TO_SRC_VAL(vc_rects[5]);
+         src_rect[WFC_RECT_WIDTH] = WFC_DISPMANX_TO_SRC_VAL(vc_rects[6]);
+         src_rect[WFC_RECT_HEIGHT] = WFC_DISPMANX_TO_SRC_VAL(vc_rects[7]);
+
+         callback(cb_args, dest_rect, src_rect);
+      }
+   }
+
+   vcos_semaphore_delete(&rect_req_sem);
+
+   vcos_log_info("wfc_stream_rect_req_thread: END: stream: %X", stream);
+
+   return NULL;
+}
+
+//------------------------------------------------------------------------------
+
+static void wfc_client_stream_post_sem(void *cb_data)
+{
+   VCOS_SEMAPHORE_T *sem = (VCOS_SEMAPHORE_T *)cb_data;
+
+   vcos_log_trace("%s: sem %p", VCOS_FUNCTION, sem);
+   vcos_assert(sem != NULL);
+   vcos_semaphore_post(sem);
+}
+
+//==============================================================================
+#ifdef KHRN_FRUIT_DIRECT
+static KHRN_UMEM_HANDLE_T get_ustorage(EGLImageKHR im, KHRN_DEPS_T *deps)
+{
+   KHRN_UMEM_HANDLE_T ret = KHRN_UMEM_HANDLE_INVALID;
+   EGL_SERVER_STATE_T *state = EGL_GET_SERVER_STATE();
+   EGL_IMAGE_T *eglimage_;
+   KHRN_IMAGE_T *image;
+
+   KHRN_MEM_HANDLE_T eglimage =
+      khrn_map_lookup(&state->eglimages, (uint32_t) im);
+
+   if (eglimage == KHRN_MEM_HANDLE_INVALID) {
+      vcos_log_error("Bad image %p", im);
+      goto end;
+   }
+
+   eglimage_ = khrn_mem_lock(eglimage);
+   vcos_assert(eglimage_->external.src != KHRN_UMEM_HANDLE_INVALID);
+   image = khrn_mem_lock(eglimage_->external.src);
+
+   /* FIXME: We probably don't need this. It doesn't make any sense */
+   khrn_deps_quick_write(deps, &image->interlock);
+
+   ret = image->ustorage;
+
+   khrn_mem_unlock(eglimage_->external.src);
+   khrn_mem_unlock(eglimage);
+
+end:
+   return ret;
+}
+
+void wfc_stream_signal_eglimage_data(WFCNativeStreamType stream, EGLImageKHR im)
+{
+   wfc_stream_signal_eglimage_data_protected(stream, im, 0);
+}
+
+#ifdef ANDROID
+void wfc_stream_signal_eglimage_data_protected(WFCNativeStreamType stream, EGLImageKHR im, uint32_t is_protected)
+{
+   EGL_SERVER_STATE_T *state = EGL_GET_SERVER_STATE();
+   KHRN_DEPS_T deps;
+   KHRN_MEM_HANDLE_T eglimage;
+   EGL_IMAGE_T *eglimage_;
+   KHRN_IMAGE_T *image_;
+
+   CLIENT_LOCK();
+
+   khrn_deps_init(&deps);
+
+   eglimage = khrn_map_lookup(&state->eglimages, (uint32_t)im);
+   eglimage_ = khrn_mem_lock(eglimage);
+   image_ = khrn_mem_lock(eglimage_->external.src);
+
+   vcos_assert(image_->ustorage != KHRN_UMEM_HANDLE_INVALID);
+   khrn_umem_acquire(&deps, image_->ustorage);
+
+   image_->flags &= ~IMAGE_FLAG_PROTECTED;
+   if (is_protected)
+      image_->flags |= IMAGE_FLAG_PROTECTED;
+
+   khrn_signal_image_data((uint32_t)stream, image_->ustorage, image_->width, image_->height, image_->stride, image_->offset,
+      image_->format, image_->flags, eglimage_->flip_y ? true : false);
+
+   khrn_mem_unlock(eglimage_->external.src);
+   khrn_mem_unlock(eglimage);
+
+   CLIENT_UNLOCK();
+}
+#else
+void wfc_stream_signal_eglimage_data_protected(WFCNativeStreamType stream, EGLImageKHR im, uint32_t is_protected)
+{
+   EGL_SERVER_STATE_T *state = EGL_GET_SERVER_STATE();
+   KHRN_DEPS_T deps;
+   KHRN_MEM_HANDLE_T eglimage;
+   EGL_IMAGE_T *eglimage_;
+   KHRN_IMAGE_T *image_;
+   WFC_STREAM_IMAGE_T stream_image;
+
+   CLIENT_LOCK();
+
+   khrn_deps_init(&deps);
+
+   eglimage = khrn_map_lookup(&state->eglimages, (uint32_t)im);
+   eglimage_ = khrn_mem_lock(eglimage);
+   image_ = khrn_mem_lock(eglimage_->external.src);
+
+   vcos_assert(image_->ustorage != KHRN_UMEM_HANDLE_INVALID);
+   khrn_umem_acquire(&deps, image_->ustorage);
+
+   /* The EGL protection flag is passed through the KHRN_IMAGE_T flags field */
+   image_->flags &= ~IMAGE_FLAG_PROTECTED;
+   if (is_protected)
+      image_->flags |= IMAGE_FLAG_PROTECTED;
+
+   memset(&stream_image, 0, sizeof(stream_image));
+   stream_image.length = sizeof(stream_image);
+   stream_image.type = WFC_STREAM_IMAGE_TYPE_EGL;
+
+   stream_image.handle = image_->ustorage;
+   stream_image.width = image_->width;
+   stream_image.height = image_->height;
+   stream_image.format = image_->format;
+   stream_image.pitch = image_->stride;
+   stream_image.offset = image_->offset;
+   stream_image.flags = image_->flags;
+   stream_image.flip = eglimage_->flip_y ? WFC_STREAM_IMAGE_FLIP_VERT : WFC_STREAM_IMAGE_FLIP_NONE;
+
+   khrn_mem_unlock(eglimage_->external.src);
+   khrn_mem_unlock(eglimage);
+
+   CLIENT_UNLOCK();
+
+   wfc_server_stream_signal_image(stream, &stream_image);
+}
+#endif
+
+void wfc_stream_release_eglimage_data(WFCNativeStreamType stream,
+      EGLImageKHR im)
+{
+   KHRN_DEPS_T deps;
+   KHRN_UMEM_HANDLE_T ustorage;
+
+   CLIENT_LOCK();
+   ustorage = get_ustorage(im, &deps);
+   khrn_umem_release(&deps, ustorage);
+   CLIENT_UNLOCK();
+}
+#endif
+
+void wfc_stream_signal_mm_image_data(WFCNativeStreamType stream, uint32_t im)
+{
+   wfc_server_stream_signal_mm_image_data(stream, im);
+}
+
+void wfc_stream_signal_raw_pixels(WFCNativeStreamType stream, uint32_t handle,
+      uint32_t format, uint32_t w, uint32_t h, uint32_t pitch, uint32_t vpitch)
+{
+   wfc_server_stream_signal_raw_pixels(stream, handle, format, w, h, pitch, vpitch);
+}
+
+void wfc_stream_signal_image(WFCNativeStreamType stream,
+      const WFC_STREAM_IMAGE_T *image)
+{
+   wfc_server_stream_signal_image(stream, image);
+}
+
+void wfc_stream_register(WFCNativeStreamType stream) {
+   uint64_t pid = vcos_process_id_current();
+   uint32_t pid_lo = (uint32_t)pid;
+   uint32_t pid_hi = (uint32_t)(pid >> 32);
+
+   if (wfc_server_connect() == VCOS_SUCCESS)
+   {
+      WFC_STREAM_INFO_T info;
+      uint32_t status;
+
+      info.size = sizeof(info);
+      status = wfc_server_stream_get_info(stream, &info);
+
+      if (status == VCOS_SUCCESS)
+      {
+         WFC_STREAM_T *stream_ptr = wfc_stream_create_stream_ptr(stream, true);
+
+         if (stream_ptr)
+         {
+            stream_ptr->registrations++;
+            memcpy(&stream_ptr->info, &info, info.size);
+            STREAM_UNLOCK(stream_ptr);
+         }
+
+         wfc_server_stream_register(stream, pid_lo, pid_hi);
+      }
+      else
+      {
+         vcos_log_error("%s: get stream info failed: %u", VCOS_FUNCTION, status);
+      }
+   }
+}
+
+void wfc_stream_unregister(WFCNativeStreamType stream) {
+   uint64_t pid = vcos_process_id_current();
+   uint32_t pid_lo = (uint32_t)pid;
+   uint32_t pid_hi = (uint32_t)(pid >> 32);
+   WFC_STREAM_T *stream_ptr = wfc_stream_find_stream_ptr(stream);
+
+   if (vcos_verify(stream_ptr != NULL))
+   {
+      wfc_server_stream_unregister(stream, pid_lo, pid_hi);
+
+      if (stream_ptr->registrations > 0)
+      {
+         stream_ptr->registrations--;
+         vcos_log_trace("%s: stream %X", VCOS_FUNCTION, stream);
+      }
+      else
+      {
+         vcos_log_error("%s: stream %X already fully unregistered", VCOS_FUNCTION, stream);
+      }
+
+      wfc_stream_destroy_if_ready(stream_ptr);
+   }
+
+   wfc_server_disconnect();
+}
+
+//==============================================================================
+
diff --git a/interface/khronos/wf/wfc_client_stream.h b/interface/khronos/wf/wfc_client_stream.h
new file mode 100755 (executable)
index 0000000..9ff5f0a
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef WFC_CLIENT_STREAM_H
+#define WFC_CLIENT_STREAM_H
+
+#include "interface/vctypes/vc_image_types.h"
+#include "interface/khronos/common/khrn_int_common.h"
+#include "interface/khronos/include/WF/wfc.h"
+#include "interface/khronos/wf/wfc_int.h"
+#include "interface/khronos/include/EGL/eglext.h"
+
+//==============================================================================
+//!@name Flags
+//!@{
+
+#define WFC_STREAM_FLAGS_NONE       0
+//!@brief Allow the server to indicate to the host when a buffer is available; for use
+//! with wfc_stream_await_buffer().
+#define WFC_STREAM_FLAGS_BUF_AVAIL  (1 << 0)
+//! GNL - Hack up a new semaphore thing to make Android rendering wait
+#define WFC_STREAM_FLAGS_ANDROID_GL_STREAM (1 << 2)
+//! So the reference to the vc image in the pool can be released
+#define WFC_STREAM_FLAGS_ANDROID_MM_STREAM (1 << 3)
+
+//! Flags needed to work with EGL
+#define WFC_STREAM_FLAGS_EGL  (WFC_STREAM_FLAGS_BUF_AVAIL)
+
+//!@}
+//!@name Internal flags; do not use directly.
+//!@{
+
+//!@brief Allow the server to indicate to the host that a change to the source and/or
+//! destination rectangles has been requested by the server.
+#define WFC_STREAM_FLAGS_REQ_RECT   (1 << 31)
+
+//!@}
+//==============================================================================
+
+//! Type for callback from wfc_stream_create_req_rect().
+typedef void (*WFC_STREAM_REQ_RECT_CALLBACK_T)
+   (void *args, const WFCint dest_rect[WFC_RECT_SIZE], const WFCfloat src_rect[WFC_RECT_SIZE]);
+
+//==============================================================================
+
+//! In cases where the caller doesn't want to assign a stream number, provide one for it.
+WFCNativeStreamType wfc_stream_get_next(void);
+
+//!@brief Create a stream, using the given stream handle (typically assigned by the
+//! window manager). Return zero if OK.
+uint32_t wfc_stream_create(WFCNativeStreamType stream, uint32_t flags);
+
+//! Create a stream, and automatically assign it a new stream number, which is returned
+WFCNativeStreamType wfc_stream_create_assign_id(uint32_t flags);
+
+//!@brief Create a stream, using the given stream handle, which will notify the calling
+//! module when the server requests a change in source and/or destination rectangle,
+//! using the supplied callback. Return zero if OK.
+uint32_t wfc_stream_create_req_rect
+   (WFCNativeStreamType stream, uint32_t flags,
+      WFC_STREAM_REQ_RECT_CALLBACK_T callback, void *cb_args);
+
+//!@brief Indicate that a source or mask is now associated with this stream, or should
+//! now be removed from such an association.
+//!
+//!@return True if successful, false if not (invalid handle).
+bool wfc_stream_register_source_or_mask(WFCNativeStreamType stream, bool add_source_or_mask);
+
+//!@brief Suspend until buffer is available on the server (requires
+//! WFC_STREAM_FLAGS_ASYNC_SEM to have been specified on creation).
+void wfc_stream_await_buffer(WFCNativeStreamType stream);
+
+//! Destroy a stream.
+void wfc_stream_destroy(WFCNativeStreamType stream);
+
+//------------------------------------------------------------------------------
+//!@name Off-screen composition functions
+//!@{
+
+//! Create a stream for an off-screen context to output to, with the default number of buffers.
+uint32_t wfc_stream_create_for_context
+   (WFCNativeStreamType stream, uint32_t width, uint32_t height);
+
+//! Create a stream for an off-screen context to output to, with a specific number of buffers.
+uint32_t wfc_stream_create_for_context_nbufs
+   (WFCNativeStreamType stream, uint32_t width, uint32_t height, uint32_t nbufs);
+
+//! Returns true if this stream exists, and is in use as the output of an off-screen context.
+bool wfc_stream_used_for_off_screen(WFCNativeStreamType stream);
+
+//!@brief Called on behalf of an off-screen context, to either set or clear the stream's
+//! flag indicating that it's being used as output for that context.
+void wfc_stream_register_off_screen(WFCNativeStreamType stream, bool used_for_off_screen);
+
+//!@}
+//------------------------------------------------------------------------------
+
+void wfc_stream_signal_eglimage_data(WFCNativeStreamType stream, EGLImageKHR im);
+void wfc_stream_signal_eglimage_data_protected(WFCNativeStreamType stream, EGLImageKHR im, uint32_t is_protected);
+void wfc_stream_release_eglimage_data(WFCNativeStreamType stream, EGLImageKHR im);
+void wfc_stream_signal_mm_image_data(WFCNativeStreamType stream, uint32_t im);
+
+void wfc_stream_signal_raw_pixels(WFCNativeStreamType stream, uint32_t handle,
+      uint32_t format, uint32_t w, uint32_t h, uint32_t pitch, uint32_t vpitch);
+void wfc_stream_signal_image(WFCNativeStreamType stream,
+      const WFC_STREAM_IMAGE_T *image);
+void wfc_stream_register(WFCNativeStreamType stream);
+void wfc_stream_unregister(WFCNativeStreamType stream);
+
+//==============================================================================
+#endif /* WF_INT_STREAM_H_ */
diff --git a/interface/khronos/wf/wfc_int.h b/interface/khronos/wf/wfc_int.h
new file mode 100755 (executable)
index 0000000..f780e27
--- /dev/null
@@ -0,0 +1,253 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef WFC_INT_H
+#define WFC_INT_H
+
+#include "interface/khronos/include/WF/wfc.h"
+
+//!@file wfc.h
+//!@brief Standard OpenWF-C header file. Available from the
+//! <a href="http://www.khronos.org/registry/wf/">Khronos OpenWF API Registry</a>.
+
+//==============================================================================
+
+//! Only valid value for attribute list (as of WF-C v1.0)
+#define NO_ATTRIBUTES   NULL
+
+//!@name
+//! Values for rectangle types
+//!@{
+#define WFC_RECT_X      0
+#define WFC_RECT_Y      1
+#define WFC_RECT_WIDTH  2
+#define WFC_RECT_HEIGHT 3
+
+#define WFC_RECT_SIZE   4
+//!@}
+
+//!@name
+//! Values for context background colour
+//!@{
+#define WFC_BG_CLR_RED     0
+#define WFC_BG_CLR_GREEN   1
+#define WFC_BG_CLR_BLUE    2
+#define WFC_BG_CLR_ALPHA   3
+
+#define WFC_BG_CLR_SIZE    4
+//!@}
+
+//==============================================================================
+
+//! Attributes associated with each element
+typedef struct
+{
+   WFCint         dest_rect[WFC_RECT_SIZE];//< The destination region of the element in the context
+   WFCfloat       src_rect[WFC_RECT_SIZE];//< The region of the source to be mapped to the destination
+   WFCboolean     flip;                   //< If WFC_TRUE, the source is flipped about a horizontal axis through its centre
+   WFCRotation    rotation;               //< The rotation of the source, see WFCRotation
+   WFCScaleFilter scale_filter;           //< The scaling filter, see WFCScaleFilter
+   WFCbitfield    transparency_types;     //< A combination of transparency types, see WFCTransparencyType
+   WFCfloat       global_alpha;           //< The global alpha for the element, if WFC_TRANSPARENCY_ELEMENT_GLOBAL_ALPHA is set
+   WFCNativeStreamType source_stream;     //< The source stream handle or WFC_INVALID_HANDLE
+   WFCNativeStreamType mask_stream;       //< The mask stream handle or WFC_INVALID_HANDLE
+} WFC_ELEMENT_ATTRIB_T;
+
+//! Default values for elements
+#define WFC_ELEMENT_ATTRIB_DEFAULT \
+{ \
+   {0, 0, 0, 0}, \
+   {0.0, 0.0, 0.0, 0.0}, \
+   WFC_FALSE, \
+   WFC_ROTATION_0, \
+   WFC_SCALE_FILTER_NONE, \
+   WFC_TRANSPARENCY_NONE, \
+   1.0, \
+   WFC_INVALID_HANDLE, \
+   WFC_INVALID_HANDLE \
+}
+
+//! Attributes associated with a context which are fixed on creation
+typedef struct
+{
+   WFCContextType type;                   //!< The context type, either on- or off-screen
+   WFCint         width;                  //!< The width of the context
+   WFCint         height;                 //!< The height of the context
+} WFC_CONTEXT_STATIC_ATTRIB_T;
+
+//! Default static values for contexts
+#define WFC_CONTEXT_STATIC_ATTRIB_DEFAULT \
+{ \
+   WFC_CONTEXT_TYPE_ON_SCREEN, \
+   0, 0, \
+}
+
+// Attributes associated with a context that may change
+typedef struct
+{
+   WFCRotation    rotation;               //< The rotation to be applied to the whole context
+   WFCfloat       background_clr[WFC_BG_CLR_SIZE]; //< The background colour of the context, in order RGBA, scaled from 0 to 1
+} WFC_CONTEXT_DYNAMIC_ATTRIB_T;
+
+//! Default dynamic values for contexts
+#define WFC_CONTEXT_DYNAMIC_ATTRIB_DEFAULT \
+{ \
+   WFC_ROTATION_0, \
+   {0.0, 0.0, 0.0, 1.0} \
+}
+
+//! Arbitrary maximum number of elements per scene
+#define WFC_MAX_ELEMENTS_IN_SCENE 8
+
+//! Arbitrary maximum number of WFC stream ids per client
+#define WFC_MAX_STREAMS_PER_CLIENT     128
+
+//! Data for a "scene" (i.e. context and element data associated with a commit).
+typedef struct
+{
+    WFC_CONTEXT_DYNAMIC_ATTRIB_T context;    //!< Dynamic attributes for this scene's context
+    uint32_t commit_count;                   //!< Count of the scenes committed for this context
+    uint32_t element_count;                  //!< Number of elements to be committed
+    WFC_ELEMENT_ATTRIB_T elements[WFC_MAX_ELEMENTS_IN_SCENE];  //!< Attributes of committed elements
+} WFC_SCENE_T;
+
+//definitions moved from wfc_server_stream.h so can be included on client
+
+typedef enum
+{
+   WFC_IMAGE_NO_FLAGS         = 0,
+   WFC_IMAGE_FLIP_VERT        = (1 << 0), //< Vertically flip image
+   WFC_IMAGE_DISP_NOTHING     = (1 << 1), //< Display nothing on screen
+   WFC_IMAGE_CB_ON_NO_CHANGE  = (1 << 2), //< Callback, even if the image is the same
+   WFC_IMAGE_CB_ON_COMPOSE    = (1 << 3), //< Callback on composition, instead of when not in use
+   WFC_IMAGE_PROTECTION_HDCP  = (1 << 4), //< HDCP required if output to HDMI display
+   WFC_IMAGE_FLIP_HORZ        = (1 << 5), //< Horizontally flip image
+   WFC_IMAGE_SENTINEL         = 0x7FFFFFFF
+} WFC_IMAGE_FLAGS_T;
+
+//! Define the type of generic WFC image
+typedef enum
+{
+   WFC_STREAM_IMAGE_TYPE_OPAQUE = 0,    //< Handle to a multimedia opaque image
+   WFC_STREAM_IMAGE_TYPE_RAW,           //< Handle to a raw pixel buffer in shared memory
+   WFC_STREAM_IMAGE_TYPE_EGL,           //< Handle to an EGL storage
+
+   WFC_STREAM_IMAGE_TYPE_SENTINEL = 0x7FFFFFFF
+} WFC_STREAM_IMAGE_TYPE_T;
+
+//! DRM protection attributes for an image. Currently tis just maps to
+//! WFC_IMAGE_PROTECTION_HDCP and DISPMANX_PROTECTION_HDCP but in future
+//! could contain other options e.g. to down-sample output.
+typedef enum
+{
+   WFC_PROTECTION_NONE = 0,         //< Image is unprotected
+   WFC_PROTECTION_HDCP = (1 << 0),  //< HDCP required if output to HDMI display
+
+   WFC_PROTECTION_SENTINEL = 0x7FFFFFFF
+} WFC_PROTECTION_FLAGS_T;
+
+//! Horizontal and vertical flip combinations
+typedef enum
+{
+   WFC_STREAM_IMAGE_FLIP_NONE = 0,     //< No flip
+   WFC_STREAM_IMAGE_FLIP_VERT,         //< Vertical flip only
+   WFC_STREAM_IMAGE_FLIP_HORZ,         //< Horizontal flip only
+   WFC_STREAM_IMAGE_FLIP_BOTH,         //< Horizontal and vertical flip (180 degree rotation)
+
+   WFC_STREAM_IMAGE_FLIP_SENTINEL = 0x7FFFFFFF
+} WFC_STREAM_IMAGE_FLIP_T;
+
+//! Describes a generic buffer on the reloctable heap.
+typedef struct
+{
+   uint32_t length;                    //< The size of the structure passed in the message. Used for versioning.
+   WFC_STREAM_IMAGE_TYPE_T type;       //< The type of the image buffer e.g. opaque.
+   uint32_t handle;                    //< The relocatable heap handle for the buffer
+   uint32_t width;                     //< Width of the image in pixels
+   uint32_t height;                    //< Height of the image in pixels
+   uint32_t format;                    //< The pixel format. Specific to type.
+   uint32_t pitch;                     //< The horizontal pitch of the image in bytes
+   uint32_t vpitch;                    //< The vertical pitch of the image in rows. Zero implies vpitch == height
+   WFC_PROTECTION_FLAGS_T protection;  //< DRM protection
+   uint32_t offset;                    //< The starting offset within the heap handle for the buffer
+   uint32_t flags;                     //< Type-specific flags associated with the buffer
+   WFC_STREAM_IMAGE_FLIP_T flip;       //< Flips to apply to the buffer for display
+} WFC_STREAM_IMAGE_T;
+
+
+//==============================================================================
+// VideoCore-specific definitions
+//==============================================================================
+
+//!@name
+//! VideoCore standard display identifiers (c.f. vc_dispmanx_types.h).
+//!@{
+#define WFC_ID_MAIN_LCD    0
+#define WFC_ID_AUX_LCD     1
+#define WFC_ID_HDMI        2
+#define WFC_ID_SDTV        3
+
+#define WFC_ID_MAX_SCREENS 3
+//!@}
+
+//------------------------------------------------------------------------------
+// Non-standard definitions
+
+//!@brief WF-C assumes that images are pre-multiplied prior to blending. However, we
+//! need to handle non-pre-multiplied ones.
+#define WFC_TRANSPARENCY_SOURCE_VC_NON_PRE_MULT    (1 << 31)
+
+//!@brief Raw pixel formats supported by the server
+typedef enum
+{
+   WFC_PIXEL_FORMAT_NONE,
+   WFC_PIXEL_FORMAT_YVU420PLANAR,
+   WFC_PIXEL_FORMAT_YUV420PLANAR,
+   WFC_PIXEL_FORMAT_FORCE_32BIT   = 0x7FFFFFFF
+} WFC_PIXEL_FORMAT_T;
+
+
+
+//------------------------------------------------------------------------------
+// Non-standard functions
+
+void wfc_set_deferral_stream(WFCDevice dev, WFCContext ctx, WFCNativeStreamType stream);
+
+//==============================================================================
+
+// Callback function types.
+
+/** Called when the buffer of a stream is no longer in use.
+ *
+ * @param The client stream handle.
+ * @param The value passed in when the buffer was set as the front buffer.
+ */
+typedef void (*WFC_SERVER_STREAM_CALLBACK_T)(WFCNativeStreamType stream, void *cb_data);
+
+//==============================================================================
+
+#endif /* WFC_INT_H */
diff --git a/interface/khronos/wf/wfc_ipc.h b/interface/khronos/wf/wfc_ipc.h
new file mode 100755 (executable)
index 0000000..63220f5
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined(WFC_IPC_H)
+#define WFC_IPC_H
+
+#include "interface/vcos/vcos.h"
+#include "interface/khronos/include/WF/wfc.h"
+#include "interface/khronos/wf/wfc_int.h"
+#include "interface/khronos/wf/wfc_server_api.h"
+#include "interface/khronos/include/EGL/eglext.h"
+
+#define WFC_IPC_CONTROL_FOURCC()   VCHIQ_MAKE_FOURCC('W','F','C','I')
+
+/* Define the current version number of the IPC API that the host library of VC
+ * server is built against.
+ */
+/* The current IPC version number */
+#define WFC_IPC_VER_CURRENT     8
+
+/* The minimum version number for backwards compatibility */
+#ifndef WFC_IPC_VER_MINIMUM
+#define WFC_IPC_VER_MINIMUM     5
+#endif
+
+/** Definitions of messages used for implementing the WFC API on the server.
+ *
+ * These are passed to the server thread via VCHIQ.
+ */
+
+typedef enum {
+   WFC_IPC_MSG_SET_CLIENT_PID,
+   WFC_IPC_MSG_GET_VERSION,            /**< Returns major, minor and minimum values */
+   WFC_IPC_MSG_CREATE_CONTEXT,         /**< Returns uint32_t */
+   WFC_IPC_MSG_DESTROY_CONTEXT,
+   WFC_IPC_MSG_COMMIT_SCENE,
+   WFC_IPC_MSG_ACTIVATE,
+   WFC_IPC_MSG_DEACTIVATE,
+   WFC_IPC_MSG_SET_DEFERRAL_STREAM,
+   WFC_IPC_MSG_SS_CREATE,              /**< Returns WFCNativeStreamType */
+   WFC_IPC_MSG_SS_DESTROY,
+   WFC_IPC_MSG_SS_ON_RECTS_CHANGE,
+   WFC_IPC_MSG_SS_GET_RECTS,
+   WFC_IPC_MSG_SS_IS_IN_USE,           /**< Returns uint32_t */
+   WFC_IPC_MSG_SS_ALLOCATE_IMAGES,     /**< Returns uint32_t */
+   WFC_IPC_MSG_SS_SIGNAL_EGLIMAGE_DATA,
+   WFC_IPC_MSG_SS_SIGNAL_MM_IMAGE_DATA,
+   WFC_IPC_MSG_SS_SIGNAL_RAW_PIXELS,
+   WFC_IPC_MSG_SS_REGISTER,
+   WFC_IPC_MSG_SS_UNREGISTER,
+   WFC_IPC_MSG_SS_ON_IMAGE_AVAILABLE,
+   WFC_IPC_MSG_SS_SIGNAL_IMAGE,        /**< Signal to update the front buffer of a generic image stream */
+   WFC_IPC_MSG_SS_CREATE_INFO,         /**< Returns WFCNativeStreamType */
+   WFC_IPC_MSG_SS_GET_INFO,            /**< Get stream configuration information */
+
+   WFC_IPC_MSG_COUNT,                  /**< Always immediately after last client message type */
+
+   WFC_IPC_MSG_CALLBACK,               /**< Sent from server to complete callback */
+
+
+   WFC_IPC_MSG_MAX = 0x7FFFFFFF        /**< Force type to be 32-bit */
+} WFC_IPC_MSG_TYPE;
+
+/** Padded pointer type, for when client and server have different size pointers.
+ * Set the padding field type to be big enough on both to hold a pointer.
+ */
+#define WFC_IPC_PTR_T(T)  union { uint32_t padding; T ptr; }
+typedef WFC_IPC_PTR_T(WFC_CALLBACK_T)  WFC_IPC_CALLBACK_T;
+typedef WFC_IPC_PTR_T(void *)          WFC_IPC_VOID_PTR_T;
+
+/** The message header. All messages must start with this structure. */
+typedef struct
+{
+   uint32_t magic;                     /**< Sentinel value to perform simple validation */
+   WFC_IPC_MSG_TYPE type;              /**< The type of the message */
+
+   /** Opaque client pointer, passed back in a reply */
+   WFC_IPC_PTR_T(struct WFC_WAITER_T *) waiter;
+} WFC_IPC_MSG_HEADER_T;
+
+/** General purpose message, for passing just a uint32_t. */
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   uint32_t value;
+} WFC_IPC_MSG_UINT32_T;
+
+/** General purpose message, for passing just a context. */
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   WFCContext context;
+} WFC_IPC_MSG_CONTEXT_T;
+
+/** General purpose message, for passing just a stream. */
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   WFCNativeStreamType stream;
+} WFC_IPC_MSG_STREAM_T;
+
+/** General purpose message, for calling a client provided callback. */
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   WFC_IPC_CALLBACK_T callback_fn;     /**< Opaque client function pointer */
+   WFC_IPC_VOID_PTR_T callback_data;   /**< Opaque client data */
+} WFC_IPC_MSG_CALLBACK_T;
+
+/** Set client process identifier message */
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   uint32_t pid_lo;
+   uint32_t pid_hi;
+} WFC_IPC_MSG_SET_CLIENT_PID_T;
+
+/** Get version reply message */
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   uint32_t major;
+   uint32_t minor;
+   uint32_t minimum;
+} WFC_IPC_MSG_GET_VERSION_T;
+
+/** Create context message */
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   WFCContext context;
+   uint32_t context_type;
+   uint32_t screen_or_stream_num;
+   uint32_t pid_lo;
+   uint32_t pid_hi;
+} WFC_IPC_MSG_CREATE_CONTEXT_T;
+
+/** Compose scene message */
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   WFC_IPC_CALLBACK_T scene_taken_cb;     /**< Opaque client function pointer */
+   WFC_IPC_VOID_PTR_T scene_taken_data;   /**< Opaque client data */
+   WFCContext context;
+   uint32_t flags;
+   WFC_SCENE_T scene;
+} WFC_IPC_MSG_COMMIT_SCENE_T;
+
+/** Set deferral stream message */
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   WFCContext context;
+   WFCNativeStreamType stream;
+} WFC_IPC_MSG_SET_DEFERRAL_STREAM_T;
+
+/** Create stream message */
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   WFCNativeStreamType stream;
+   uint32_t flags;
+   uint32_t pid_lo;
+   uint32_t pid_hi;
+} WFC_IPC_MSG_SS_CREATE_T;
+
+/** Create stream using info block message */
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   WFCNativeStreamType stream;
+   WFC_STREAM_INFO_T info;
+   uint32_t pid_lo;
+   uint32_t pid_hi;
+} WFC_IPC_MSG_SS_CREATE_INFO_T;
+
+/** Destroy stream message */
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   WFCNativeStreamType stream;
+   uint32_t pid_lo;
+   uint32_t pid_hi;
+} WFC_IPC_MSG_SS_DESTROY_T;
+
+/** Set stream rectangle update callback message */
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   WFCNativeStreamType stream;
+   WFC_IPC_CALLBACK_T rects_change_cb;    /**< Opaque client function pointer */
+   WFC_IPC_VOID_PTR_T rects_change_data;  /**< Opaque client data */
+} WFC_IPC_MSG_SS_ON_RECTS_CHANGE_T;
+
+/** Get rectangles reply message */
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   uint32_t result;
+   int32_t rects[WFC_SERVER_STREAM_RECTS_SIZE];
+} WFC_IPC_MSG_SS_GET_RECTS_T;
+
+/** Allocate stream target images message */
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   WFCNativeStreamType stream;
+   uint32_t width;
+   uint32_t height;
+   uint32_t nbufs;
+} WFC_IPC_MSG_SS_ALLOCATE_IMAGES_T;
+
+/** Signal new EGLImage image message */
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   WFCNativeStreamType stream;
+   uint32_t ustorage;
+   uint32_t width;
+   uint32_t height;
+   uint32_t stride;
+   uint32_t offset;
+   uint32_t format;
+   uint32_t flags;
+   bool flip;
+} WFC_IPC_MSG_SS_SIGNAL_EGLIMAGE_DATA_T;
+
+/** Signal new multimedia image message */
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   WFCNativeStreamType stream;
+   uint32_t image_handle;
+} WFC_IPC_MSG_SS_SIGNAL_MM_IMAGE_DATA_T;
+
+/** Signal new raw pixel image message */
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   WFCNativeStreamType stream;
+   uint32_t handle;
+   uint32_t format;
+   uint32_t width;
+   uint32_t height;
+   uint32_t pitch;
+   uint32_t vpitch;
+} WFC_IPC_MSG_SS_SIGNAL_RAW_PIXELS_T;
+
+/** Signals a new image buffer */
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+   WFCNativeStreamType stream;
+
+   /**< Descibes the image buffer.
+    * image.length initialised to sizeof(WFC_STREAM_IMAGE_T) */
+   WFC_STREAM_IMAGE_T image;
+
+} WFC_IPC_MSG_SS_SIGNAL_IMAGE_T;
+
+/** Register stream as owned by process message */
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   WFCNativeStreamType stream;
+   uint32_t pid_lo;
+   uint32_t pid_hi;
+} WFC_IPC_MSG_SS_REGISTER_T;
+
+/** Unregister stream as owned by process message */
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   WFCNativeStreamType stream;
+   uint32_t pid_lo;
+   uint32_t pid_hi;
+} WFC_IPC_MSG_SS_UNREGISTER_T;
+
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   uint32_t result;
+   WFC_STREAM_INFO_T info;
+} WFC_IPC_MSG_SS_GET_INFO_T;
+
+/** Set stream image available callback message */
+typedef struct {
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   WFCNativeStreamType stream;
+   WFC_IPC_CALLBACK_T image_available_cb;    /**< Opaque client function pointer */
+   WFC_IPC_VOID_PTR_T image_available_data;  /**< Opaque client data */
+} WFC_IPC_MSG_SS_ON_IMAGE_AVAILABLE_T;
+
+
+/** All messages sent between the client and server must be represented in
+ * this union.
+ */
+typedef union
+{
+   WFC_IPC_MSG_HEADER_T header;  /**< All messages start with a header */
+
+   WFC_IPC_MSG_UINT32_T u32_msg;
+   WFC_IPC_MSG_CONTEXT_T context;
+   WFC_IPC_MSG_STREAM_T stream;
+   WFC_IPC_MSG_CREATE_CONTEXT_T create_context;
+   WFC_IPC_MSG_COMMIT_SCENE_T commit_scene;
+   WFC_IPC_MSG_SET_DEFERRAL_STREAM_T set_deferral_stream;
+   WFC_IPC_MSG_SS_CREATE_T ss_create;
+   WFC_IPC_MSG_SS_CREATE_INFO_T ss_create_info;
+   WFC_IPC_MSG_SS_DESTROY_T ss_destroy;
+   WFC_IPC_MSG_SS_ON_RECTS_CHANGE_T ss_on_rects_change;
+   WFC_IPC_MSG_SS_ALLOCATE_IMAGES_T ss_allocate_images;
+   WFC_IPC_MSG_SS_SIGNAL_EGLIMAGE_DATA_T ss_signal_eglimage_data;
+   WFC_IPC_MSG_SS_SIGNAL_MM_IMAGE_DATA_T ss_signal_mm_image_data;
+   WFC_IPC_MSG_SS_SIGNAL_RAW_PIXELS_T ss_signal_raw_image_data;
+   WFC_IPC_MSG_SS_REGISTER_T ss_register;
+   WFC_IPC_MSG_SS_UNREGISTER_T ss_unregister;
+   WFC_IPC_MSG_SS_ON_IMAGE_AVAILABLE_T ss_on_image_available;
+   WFC_IPC_MSG_GET_VERSION_T get_version;
+   WFC_IPC_MSG_SS_GET_RECTS_T ss_get_rects;
+   WFC_IPC_MSG_SS_SIGNAL_IMAGE_T ss_signal_image;
+} WFC_IPC_MSG_T;
+
+#define WFC_IPC_MSG_MAGIC       VCHIQ_MAKE_FOURCC('W', 'F', 'C', 'm')
+
+#endif   /* WFC_IPC_H */
diff --git a/interface/khronos/wf/wfc_server_api.h b/interface/khronos/wf/wfc_server_api.h
new file mode 100755 (executable)
index 0000000..a0f653d
--- /dev/null
@@ -0,0 +1,302 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined(WFC_SERVER_API_H)
+#define WFC_SERVER_API_H
+
+#include "interface/vcos/vcos.h"
+#include "interface/vcos/vcos_stdbool.h"
+#include "interface/khronos/include/WF/wfc.h"
+#include "interface/khronos/wf/wfc_int.h"
+#include "interface/khronos/include/EGL/eglext.h"
+
+/** Defining WFC_FULL_LOGGING will enable trace level logging across all WFC
+ * components.
+#define WFC_FULL_LOGGING
+ */
+
+/** General purpose callback function.
+ * Note: callbacks are often made on a thread other than the original function's.
+ *
+ * @param cb_data Callback additional data.
+ */
+typedef void (*WFC_CALLBACK_T)(void *cb_data);
+
+/** Extensible stream information block, supplied during creation and
+ * retrievable using wfc_server_stream_get_info. */
+typedef struct WFC_STREAM_INFO_T
+{
+   uint32_t size;    /**< Size of the strucuture, for versioning. */
+   uint32_t flags;   /**< Stream flags. */
+} WFC_STREAM_INFO_T;
+
+/** Create a connection to the server, as necessary. If this fails, no other
+ * server functions should be called. If it succeeds, there must be one call to
+ * wfc_server_disconnect() when use of the server has ended.
+ *
+ * @return VCOS_SUCCESS or a failure code.
+ */
+VCOS_STATUS_T wfc_server_connect(void);
+
+/** Destroy a connection to the server. This must be called once and only once
+ * for each successful call to wfc_server_connect().
+ */
+void wfc_server_disconnect(void);
+
+/** Increase the keep alive count by one. If it rises from zero, the VideoCore
+ * will be prevented from being suspended.
+ */
+void wfc_server_use_keep_alive(void);
+
+/** Drop the keep alive count by one. If it reaches zero, the VideoCore may be
+ * suspended.
+ */
+void wfc_server_release_keep_alive(void);
+
+/** Create a new on- or off-screen context for composition. The type of the context
+ * is either WFC_CONTEXT_TYPE_ON_SCREEN or WFC_CONTEXT_TYPE_OFF_SCREEN.
+ *
+ * @param context The client context identifier.
+ * @param context_type The type of the context.
+ * @param screen_or_stream_num The screen number for and on-screen context, or the
+ *    target client stream identifier for an off-screen context.
+ * @param pid_lo The low 32-bits of the owning client process identifier.
+ * @param pid_hi The high 32-bits of the owning client process identifier.
+ * @return Zero on failure, or the width and height of the context in pixels,
+ *    packed in the top and bottom 16 bits, respectively.
+ */
+uint32_t wfc_server_create_context(WFCContext context, uint32_t context_type,
+   uint32_t screen_or_stream_num, uint32_t pid_lo, uint32_t pid_hi);
+
+/** Destroy a context.
+ *
+ * @param context The client context identifier.
+ */
+void wfc_server_destroy_context(WFCContext ctx);
+
+/** Flags to be passed to wfc_server_commit_scene. A bitwise combination of
+ * flags may be passed in to control behaviour.
+ */
+typedef enum
+{
+   WFC_SERVER_COMMIT_WAIT     = 1,  /**< Wait for scene to be committed. */
+   WFC_SERVER_COMMIT_COMPOSE  = 2,  /**< Trigger composition */
+} WFC_SERVER_COMMIT_FLAGS_T;
+
+/** Commit a scene in the context. If the WAIT flag is set, a callback
+ * must be given and shall be called once a new scene can be given. If the
+ * COMPOSE flag is set, the newly committed scene shall be composed
+ * as soon as possible (subject to presence of a deferral stream).
+ *
+ * @param context The client context identifier.
+ * @param scene The scene to be composed.
+ * @param flags Combination of WFC_SERVER_COMMIT_FLAGS_T values, or 0.
+ * @param scene_taken_cb Called when scene has been taken, generally on a
+ *    different thread, or zero for no callback.
+ * @param scene_taken_data Passed to scene_taken_cb.
+ * @return VCOS_SUCCESS if successful, VCOS_EAGAIN if the scene cannot be
+ *    taken immediately and the wait flag is false.
+ */
+uint32_t wfc_server_commit_scene(WFCContext ctx, const WFC_SCENE_T *scene,
+      uint32_t flags, WFC_CALLBACK_T scene_taken_cb, void *scene_taken_data);
+
+/** Activate a context. While a context is active, it will be automatically
+ * composed when any of the streams in its current scene are updated.
+ *
+ * @param context The client context identifier.
+ */
+void wfc_server_activate(WFCContext ctx);
+
+/** Deactivate a context.
+ *
+ * @param context The client context identifier.
+ */
+void wfc_server_deactivate(WFCContext ctx);
+
+/** Set the deferral stream for a context. When a deferral stream is set on a
+ * context and a new scene is given for that context, composition is deferred
+ * until the stream is updated.
+ *
+ * @param context The client context identifier.
+ * @param stream The deferral stream, or WFC_INVALID_HANDLE for none.
+ */
+void wfc_server_set_deferral_stream(WFCContext ctx, WFCNativeStreamType stream);
+
+/** Create a stream and its buffers, for supplying pixel data to one or more
+ * elements, and optionally for storing the output of off-screen composition.
+ *
+ * @param stream The client stream identifier.
+ * @param flags Stream flags.
+ * @param pid_lo The low 32-bits of the owning client process identifier.
+ * @param pid_hi The high 32-bits of the owning client process identifier.
+ * @return The client stream identifier on success, or WFC_INVALID_HANDLE on error.
+ */
+WFCNativeStreamType wfc_server_stream_create(
+   WFCNativeStreamType stream, uint32_t flags, uint32_t pid_lo, uint32_t pid_hi);
+
+/** Create a stream and its buffers, for supplying pixel data to one or more
+ * elements, and optionally for storing the output of off-screen composition.
+ *
+ * @param stream The client stream identifier.
+ * @param info Stream configuration.
+ * @param pid_lo The low 32-bits of the owning client process identifier.
+ * @param pid_hi The high 32-bits of the owning client process identifier.
+ * @return The client stream identifier on success, or WFC_INVALID_HANDLE on error.
+ */
+WFCNativeStreamType wfc_server_stream_create_info(
+   WFCNativeStreamType stream, const WFC_STREAM_INFO_T *info, uint32_t pid_lo, uint32_t pid_hi);
+
+/** Destroy a stream.
+ *
+ * @param stream The client stream identifier.
+ * @param pid_lo The low 32-bits of the owning client process identifier.
+ * @param pid_hi The high 32-bits of the owning client process identifier.
+ */
+void wfc_server_stream_destroy(WFCNativeStreamType stream, uint32_t pid_lo, uint32_t pid_hi);
+
+/** Set callback for when src/dest rectangles are updated.
+ *
+ * @param stream The client stream identifier.
+ * @param rects_change_cb Called when either src or dest rectangles have been
+ *    updated.
+ * @param rects_change_data Passed to the callback.
+ * @return VCOS_SUCCESS if successful, or an error code if not.
+ */
+void wfc_server_stream_on_rects_change(WFCNativeStreamType stream,
+      WFC_CALLBACK_T rects_change_cb, void *rects_change_data);
+
+/** Get destination and source rectangles, following request from server
+ *
+ * @param stream The client stream identifier.
+ * @param rects The rectangle data is written here.
+ * @return VCOS_SUCCESS if successful, or an error code if not.
+ */
+#define WFC_SERVER_STREAM_RECTS_SIZE   8
+uint32_t wfc_server_stream_get_rects(WFCNativeStreamType stream, int32_t rects[WFC_SERVER_STREAM_RECTS_SIZE]);
+
+/** Returns true if given stream number is currently in use.
+ *
+ * @param stream The client stream identifier.
+ * @return True if the client stream identifier is already in use, false if not.
+ */
+bool wfc_server_stream_is_in_use(WFCNativeStreamType stream);
+
+/** Allocate images in the stream into which an off-screen context can write
+ * composited output.
+ *
+ * @param stream The client stream identifier.
+ * @param width The width of the images, in pixels.
+ * @param height The height of the images, in pixels.
+ * @param nbufs The number of images to allocate in the stream.
+ * @return True on success, false on failure.
+ */
+bool wfc_server_stream_allocate_images(WFCNativeStreamType stream, uint32_t width, uint32_t height, uint32_t nbufs);
+
+/** Signal that the given EGLImageKHR is the new front image for the stream.
+ * @param stream     The client stream identifier.
+ * @param ustorage   The innards of KHRN_IMAGE_T
+ * @param width      etc..
+ * @param height     etc...
+ * @param stride
+ * @param offset
+ * @param format
+ * @param flags
+ * @param flip
+ */
+void wfc_server_stream_signal_eglimage_data(WFCNativeStreamType stream,
+      uint32_t ustorage, uint32_t width, uint32_t height, uint32_t stride,
+      uint32_t offset, uint32_t format, uint32_t flags, bool flip);
+
+/** Signal that the given multimedia image handle is the new front image for
+ * the stream.
+ *
+ * @param stream The client stream identifier.
+ * @param image_handle The new front image for the stream.
+ */
+void wfc_server_stream_signal_mm_image_data(WFCNativeStreamType stream, uint32_t image_handle);
+
+/** Signal that a raw image memhandle is the new front image for the stream.
+ *
+ * @param stream The client stream identifier.
+ * @param handle The new front image memhandle for the stream.
+ * @param format The image format. See WFC_PIXEL_FORMAT_T for supported formats.
+ * @param width  The image width, in pixels.
+ * @param height The image height, in pixels.
+ * @param pitch  The image pitch, in bytes.
+ * @param vpitch The image vertical pitch, in pixels.
+ */
+void wfc_server_stream_signal_raw_pixels(WFCNativeStreamType stream,
+      uint32_t handle, uint32_t format, uint32_t width, uint32_t height,
+      uint32_t pitch, uint32_t vpitch);
+
+/** Signal that the given image is the new front image for the stream.
+ *
+ * The type of each image the stream must be the same e.g. it is not permitted
+ * to mix opaque and raw pixel multimedia images within the same stream.
+ *
+ * @param stream  The client stream identifier.
+ * @param image  Structure describing the image.
+ */
+void wfc_server_stream_signal_image(WFCNativeStreamType stream,
+      const WFC_STREAM_IMAGE_T *image);
+
+/** Register a stream as in use by a given process.
+ *
+ * @param stream The client stream identifier.
+ * @param pid_lo The low 32-bits of the process ID.
+ * @param pid_hi The high 32-bits of the process ID.
+ */
+void wfc_server_stream_register(WFCNativeStreamType stream, uint32_t pid_lo, uint32_t pid_hi);
+
+/** Unregister a stream as in use by a given process.
+ *
+ * @param stream The client stream identifier.
+ * @param pid_lo The low 32-bits of the process ID.
+ * @param pid_hi The high 32-bits of the process ID.
+ */
+void wfc_server_stream_unregister(WFCNativeStreamType stream, uint32_t pid_lo, uint32_t pid_hi);
+
+/** Retrieve the stream configuration information, if available.
+ *
+ * @param stream The client stream identifier.
+ * @param info Address of block to receive the information on success.
+ * @return VCOS_SUCCESS if successful, or an error code if not.
+ */
+uint32_t wfc_server_stream_get_info(WFCNativeStreamType stream, WFC_STREAM_INFO_T *info);
+
+/** Set callback for when there is an image available. The stream must have
+ * been created with either the WFC_STREAM_FLAGS_EGL or WFC_STREAM_FLAGS_BUF_AVAIL
+ * flags set.
+ *
+ * @param stream The client stream identifier.
+ * @param image_available_cb Called when there is an image available.
+ * @param image_available_data Passed to the callback.
+ */
+void wfc_server_stream_on_image_available(WFCNativeStreamType stream,
+      WFC_CALLBACK_T image_available_cb, void *image_available_data);
+
+#endif   /* WFC_SERVER_API_H */
diff --git a/interface/mmal/CMakeLists.txt b/interface/mmal/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..37ae757
--- /dev/null
@@ -0,0 +1,46 @@
+# We support building both static and shared libraries
+if (NOT DEFINED LIBRARY_TYPE)
+set(LIBRARY_TYPE SHARED)
+endif (NOT DEFINED LIBRARY_TYPE)
+
+add_definitions(-Wall -Werror)
+
+add_library(mmal SHARED util/mmal_util.c)
+
+add_subdirectory(core)
+add_subdirectory(util)
+add_subdirectory(vc)
+add_subdirectory(components)
+add_subdirectory(openmaxil)
+add_subdirectory(client)
+
+target_link_libraries(mmal mmal_core mmal_util mmal_vc_client vcos mmal_components)
+
+install(TARGETS mmal DESTINATION lib)
+install(FILES
+   mmal.h
+   mmal_buffer.h
+   mmal_clock.h
+   mmal_common.h
+   mmal_component.h
+   mmal_encodings.h
+   mmal_events.h
+   mmal_format.h
+   mmal_logging.h
+   mmal_metadata.h
+   mmal_parameters.h
+   mmal_parameters_audio.h
+   mmal_parameters_camera.h
+   mmal_parameters_clock.h
+   mmal_parameters_common.h
+   mmal_parameters_video.h
+   mmal_pool.h mmal_port.h
+   mmal_queue.h
+   mmal_types.h
+   DESTINATION include/interface/mmal
+)
+
+# Test apps
+if(BUILD_MMAL_APPS)
+add_subdirectory(test)
+endif(BUILD_MMAL_APPS)
diff --git a/interface/mmal/client/CMakeLists.txt b/interface/mmal/client/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..58bdaed
--- /dev/null
@@ -0,0 +1 @@
+add_subdirectory(brcmjpeg)
diff --git a/interface/mmal/client/brcmjpeg/CMakeLists.txt b/interface/mmal/client/brcmjpeg/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..342a182
--- /dev/null
@@ -0,0 +1,6 @@
+add_library(brcmjpeg SHARED brcmjpeg.c)
+target_link_libraries(brcmjpeg mmal_core mmal_util mmal_vc_client)
+
+include_directories(../../../../host_applications/linux/libs/sm)
+add_executable(brcmjpeg_test brcmjpeg_test.c)
+target_link_libraries(brcmjpeg_test brcmjpeg vcsm vcos)
diff --git a/interface/mmal/client/brcmjpeg/brcmjpeg.c b/interface/mmal/client/brcmjpeg/brcmjpeg.c
new file mode 100755 (executable)
index 0000000..1fc4220
--- /dev/null
@@ -0,0 +1,914 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file
+ *  Jpeg encoder and decoder library using the hardware jpeg codec
+ */
+
+#include "mmal.h"
+#include "util/mmal_component_wrapper.h"
+#include "util/mmal_util_params.h"
+#include "mmal_logging.h"
+#include "brcmjpeg.h"
+
+/*******************************************************************************
+* Defines
+*******************************************************************************/
+#define MMAL_COMPONENT_IMAGE_DECODE "vc.aggregator.pipeline:ril.image_decode:video_convert"
+#define MMAL_COMPONENT_IMAGE_ENCODE "vc.ril.image_encode"
+
+#define ENABLE_SLICE_MODE 0
+
+#define CHECK_MMAL_STATUS(status, jerr, msg, ...) \
+   if (status != MMAL_SUCCESS) {LOG_ERROR(msg, ## __VA_ARGS__); \
+   err = BRCMJPEG_ERROR_##jerr; goto error;}
+
+/*******************************************************************************
+* Type definitions
+*******************************************************************************/
+struct BRCMJPEG_T
+{
+   BRCMJPEG_TYPE_T type;
+   unsigned int ref_count;
+   unsigned int init;
+
+   MMAL_WRAPPER_T *mmal;
+   unsigned int slice_height;
+
+   VCOS_MUTEX_T lock;
+   VCOS_MUTEX_T process_lock;
+   VCOS_SEMAPHORE_T sema;
+};
+
+/*******************************************************************************
+* Local prototypes
+*******************************************************************************/
+static BRCMJPEG_STATUS_T brcmjpeg_init_encoder(BRCMJPEG_T *);
+static BRCMJPEG_STATUS_T brcmjpeg_init_decoder(BRCMJPEG_T *);
+static BRCMJPEG_STATUS_T brcmjpeg_configure_encoder(BRCMJPEG_T *, BRCMJPEG_REQUEST_T *);
+static BRCMJPEG_STATUS_T brcmjpeg_configure_decoder(BRCMJPEG_T *, BRCMJPEG_REQUEST_T *);
+static BRCMJPEG_STATUS_T brcmjpeg_encode(BRCMJPEG_T *, BRCMJPEG_REQUEST_T *);
+static BRCMJPEG_STATUS_T brcmjpeg_decode(BRCMJPEG_T *, BRCMJPEG_REQUEST_T *);
+static void brcmjpeg_destroy(BRCMJPEG_T *);
+
+static MMAL_FOURCC_T brcmjpeg_pixfmt_to_encoding(BRCMJPEG_PIXEL_FORMAT_T);
+static unsigned int brcmjpeg_copy_pixels(uint8_t *out, unsigned int out_size,
+   const uint8_t *in, unsigned int in_size, BRCMJPEG_PIXEL_FORMAT_T fmt,
+   unsigned int out_width, unsigned int out_height,
+   unsigned int in_width, unsigned int in_height,
+   unsigned int line_offset, unsigned int convert_from);
+
+static BRCMJPEG_T *brcmjpeg_encoder = NULL;
+static BRCMJPEG_T *brcmjpeg_decoder = NULL;
+
+/*******************************************************************************
+* Platform specific code
+*******************************************************************************/
+static VCOS_ONCE_T once = VCOS_ONCE_INIT;
+static VCOS_MUTEX_T brcmjpeg_lock;
+
+static void brcmjpeg_init_once(void)
+{
+   vcos_mutex_create(&brcmjpeg_lock, VCOS_FUNCTION);
+}
+
+#define LOCK() vcos_mutex_lock(&brcmjpeg_lock)
+#define UNLOCK() vcos_mutex_unlock(&brcmjpeg_lock)
+#define LOCK_COMP(ctx) vcos_mutex_lock(&(ctx)->lock)
+#define UNLOCK_COMP(ctx) vcos_mutex_unlock(&(ctx)->lock)
+#define LOCK_PROCESS(ctx) vcos_mutex_lock(&(ctx)->process_lock)
+#define UNLOCK_PROCESS(ctx) vcos_mutex_unlock(&(ctx)->process_lock)
+#define WAIT(ctx) vcos_semaphore_wait(&(ctx)->sema)
+#define SIGNAL(ctx) vcos_semaphore_post(&(ctx)->sema)
+
+/*******************************************************************************
+* Implementation
+*******************************************************************************/
+
+BRCMJPEG_STATUS_T brcmjpeg_create(BRCMJPEG_TYPE_T type, BRCMJPEG_T **ctx)
+{
+   BRCMJPEG_STATUS_T status = BRCMJPEG_SUCCESS;
+   BRCMJPEG_T **comp;
+
+   if (type == BRCMJPEG_TYPE_ENCODER)
+      comp = &brcmjpeg_encoder;
+   else
+      comp = &brcmjpeg_decoder;
+
+   vcos_once(&once, brcmjpeg_init_once);
+   LOCK();
+   if (!*comp)
+   {
+      int init1, init2, init3;
+      *comp = calloc(sizeof(BRCMJPEG_T), 1);
+      if (!*comp)
+      {
+         UNLOCK();
+         return BRCMJPEG_ERROR_NOMEM;
+      }
+      (*comp)->type = type;
+      init1 = vcos_mutex_create(&(*comp)->lock, "brcmjpeg lock") != VCOS_SUCCESS;
+      init2 = vcos_mutex_create(&(*comp)->process_lock, "brcmjpeg process lock") != VCOS_SUCCESS;
+      init3 = vcos_semaphore_create(&(*comp)->sema, "brcmjpeg sema", 0) != VCOS_SUCCESS;
+      if (init1 | init2 | init3)
+      {
+         if (init1) vcos_mutex_delete(&(*comp)->lock);
+         if (init2) vcos_mutex_delete(&(*comp)->process_lock);
+         if (init3) vcos_semaphore_delete(&(*comp)->sema);
+         free(comp);
+         UNLOCK();
+         return BRCMJPEG_ERROR_NOMEM;
+      }
+   }
+   (*comp)->ref_count++;
+   UNLOCK();
+
+   LOCK_COMP(*comp);
+   if (!(*comp)->init)
+   {
+      if (type == BRCMJPEG_TYPE_ENCODER)
+         status = brcmjpeg_init_encoder(*comp);
+      else
+         status = brcmjpeg_init_decoder(*comp);
+
+      (*comp)->init = status == BRCMJPEG_SUCCESS;
+   }
+   UNLOCK_COMP(*comp);
+
+   if (status != BRCMJPEG_SUCCESS)
+      brcmjpeg_release(*comp);
+
+   *ctx = *comp;
+   return status;
+}
+
+void brcmjpeg_acquire(BRCMJPEG_T *ctx)
+{
+   LOCK_COMP(ctx);
+   ctx->ref_count++;
+   UNLOCK_COMP(ctx);
+}
+
+void brcmjpeg_release(BRCMJPEG_T *ctx)
+{
+   LOCK_COMP(ctx);
+   if (--ctx->ref_count)
+   {
+      UNLOCK_COMP(ctx);
+      return;
+   }
+
+   LOCK();
+   if (ctx->type == BRCMJPEG_TYPE_ENCODER)
+      brcmjpeg_encoder = NULL;
+   else
+      brcmjpeg_decoder = NULL;
+   UNLOCK();
+   UNLOCK_COMP(ctx);
+
+   brcmjpeg_destroy(ctx);
+   return;
+}
+
+BRCMJPEG_STATUS_T brcmjpeg_process(BRCMJPEG_T *ctx, BRCMJPEG_REQUEST_T *req)
+{
+   BRCMJPEG_STATUS_T status;
+
+   /* Sanity check */
+   if ((req->input && req->input_handle) ||
+       (req->output && req->output_handle))
+   {
+      LOG_ERROR("buffer pointer and handle both set (%p/%u %p/%u)",
+            req->input, req->input_handle, req->output, req->output_handle);
+      return BRCMJPEG_ERROR_REQUEST;
+   }
+
+   LOCK_PROCESS(ctx);
+   if (ctx->type == BRCMJPEG_TYPE_ENCODER)
+      status = brcmjpeg_encode(ctx, req);
+   else
+      status = brcmjpeg_decode(ctx, req);
+   UNLOCK_PROCESS(ctx);
+
+   return status;
+}
+
+static void brcmjpeg_destroy(BRCMJPEG_T *ctx)
+{
+   if (ctx->mmal)
+      mmal_wrapper_destroy(ctx->mmal);
+   vcos_mutex_delete(&ctx->lock);
+   vcos_mutex_delete(&ctx->process_lock);
+   vcos_semaphore_delete(&ctx->sema);
+   free(ctx);
+}
+
+static void brcmjpeg_mmal_cb(MMAL_WRAPPER_T *wrapper)
+{
+   BRCMJPEG_T *ctx = wrapper->user_data;
+   SIGNAL(ctx);
+}
+
+static BRCMJPEG_STATUS_T brcmjpeg_init_encoder(BRCMJPEG_T *ctx)
+{
+   MMAL_STATUS_T status;
+   BRCMJPEG_STATUS_T err = BRCMJPEG_SUCCESS;
+
+   /* Create encoder component */
+   status = mmal_wrapper_create(&ctx->mmal, MMAL_COMPONENT_IMAGE_ENCODE);
+   CHECK_MMAL_STATUS(status, INIT, "failed to create encoder");
+   ctx->mmal->user_data = ctx;
+   ctx->mmal->callback = brcmjpeg_mmal_cb;
+
+   /* Configure things that won't change from encode to encode */
+   mmal_port_parameter_set_boolean(ctx->mmal->control,
+      MMAL_PARAMETER_EXIF_DISABLE, MMAL_TRUE);
+
+   ctx->mmal->output[0]->format->encoding = MMAL_ENCODING_JPEG;
+   status = mmal_port_format_commit(ctx->mmal->output[0]);
+   CHECK_MMAL_STATUS(status, INIT, "failed to commit output port format");
+
+   ctx->mmal->output[0]->buffer_size = ctx->mmal->output[0]->buffer_size_min;
+   ctx->mmal->output[0]->buffer_num = 3;
+   status = mmal_wrapper_port_enable(ctx->mmal->output[0], 0);
+   CHECK_MMAL_STATUS(status, INIT, "failed to enable output port");
+
+   LOG_DEBUG("encoder initialised (output chunk size %i)",
+      ctx->mmal->output[0]->buffer_size);
+   return BRCMJPEG_SUCCESS;
+
+ error:
+   return err;
+}
+
+static BRCMJPEG_STATUS_T brcmjpeg_init_decoder(BRCMJPEG_T *ctx)
+{
+   MMAL_STATUS_T status;
+   BRCMJPEG_STATUS_T err = BRCMJPEG_SUCCESS;
+
+   /* Create decoder component */
+   status = mmal_wrapper_create(&ctx->mmal, MMAL_COMPONENT_IMAGE_DECODE);
+   CHECK_MMAL_STATUS(status, INIT, "failed to create decoder");
+   ctx->mmal->user_data = ctx;
+   ctx->mmal->callback = brcmjpeg_mmal_cb;
+
+   /* Configure things that won't change from decode to decode */
+   ctx->mmal->input[0]->format->encoding = MMAL_ENCODING_JPEG;
+   status = mmal_port_format_commit(ctx->mmal->input[0]);
+   CHECK_MMAL_STATUS(status, INIT, "failed to commit input port format");
+
+   ctx->mmal->input[0]->buffer_size = ctx->mmal->input[0]->buffer_size_min;
+   ctx->mmal->input[0]->buffer_num = 3;
+   status = mmal_wrapper_port_enable(ctx->mmal->input[0], 0);
+   CHECK_MMAL_STATUS(status, INIT, "failed to enable input port");
+
+   LOG_DEBUG("decoder initialised (input chunk size %i)",
+      ctx->mmal->input[0]->buffer_size);
+   return BRCMJPEG_SUCCESS;
+
+ error:
+   return BRCMJPEG_ERROR_INIT;
+}
+
+/* Configuration which needs to be done on a per encode basis */
+static BRCMJPEG_STATUS_T brcmjpeg_configure_encoder(BRCMJPEG_T *ctx,
+   BRCMJPEG_REQUEST_T *req)
+{
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   MMAL_FOURCC_T encoding = brcmjpeg_pixfmt_to_encoding(req->pixel_format);
+   MMAL_PORT_T *port_in;
+   BRCMJPEG_STATUS_T err = BRCMJPEG_SUCCESS;
+   MMAL_BOOL_T slice_mode = MMAL_FALSE;
+
+   if (encoding == MMAL_ENCODING_UNKNOWN)
+      status = MMAL_EINVAL;
+   CHECK_MMAL_STATUS(status, INPUT_FORMAT, "format not supported (%i)",
+      req->pixel_format);
+
+   if (!req->buffer_width)
+      req->buffer_width = req->width;
+   if (!req->buffer_height)
+      req->buffer_height = req->height;
+   if (req->buffer_width < req->width || req->buffer_height < req->height)
+      status = MMAL_EINVAL;
+   CHECK_MMAL_STATUS(status, INPUT_FORMAT, "invalid buffer width/height "
+      "(%i<=%i %i<=%i)", req->buffer_width, req->width, req->buffer_height,
+      req->height);
+
+   ctx->slice_height = 0;
+   ctx->mmal->status = MMAL_SUCCESS;
+   port_in = ctx->mmal->input[0];
+
+   /* The input port needs to be re-configured to take into account
+    * the properties of the new frame to encode */
+   if (port_in->is_enabled)
+   {
+      status = mmal_wrapper_port_disable(port_in);
+      CHECK_MMAL_STATUS(status, EXECUTE, "failed to disable input port");
+   }
+
+   port_in->format->encoding = encoding;
+   port_in->format->es->video.width =
+      port_in->format->es->video.crop.width = req->width;
+   port_in->format->es->video.height =
+      port_in->format->es->video.crop.height = req->height;
+   port_in->buffer_num = 1;
+
+   if (!req->input_handle &&
+         (port_in->format->encoding == MMAL_ENCODING_I420 ||
+          port_in->format->encoding == MMAL_ENCODING_I422))
+   {
+      if (port_in->format->encoding == MMAL_ENCODING_I420)
+         port_in->format->encoding = MMAL_ENCODING_I420_SLICE;
+      else if (port_in->format->encoding == MMAL_ENCODING_I422)
+         port_in->format->encoding = MMAL_ENCODING_I422_SLICE;
+      slice_mode = MMAL_TRUE;
+      port_in->buffer_num = 3;
+   }
+
+   status = mmal_port_format_commit(port_in);
+   CHECK_MMAL_STATUS(status, INPUT_FORMAT, "failed to commit input port format");
+
+   ctx->slice_height = slice_mode ? 16 : port_in->format->es->video.height;
+   port_in->buffer_size = port_in->buffer_size_min;
+
+   if (req->input_handle)
+      status = mmal_wrapper_port_enable(port_in, MMAL_WRAPPER_FLAG_PAYLOAD_USE_SHARED_MEMORY);
+   else
+      status = mmal_wrapper_port_enable(port_in, MMAL_WRAPPER_FLAG_PAYLOAD_ALLOCATE);
+   CHECK_MMAL_STATUS(status, EXECUTE, "failed to enable input port");
+
+   mmal_port_parameter_set_uint32(ctx->mmal->output[0],
+      MMAL_PARAMETER_JPEG_Q_FACTOR, req->quality);
+
+   if (!ctx->mmal->output[0]->is_enabled)
+   {
+      status = mmal_wrapper_port_enable(ctx->mmal->output[0], 0);
+      CHECK_MMAL_STATUS(status, EXECUTE, "failed to enable output port");
+   }
+
+   LOG_DEBUG("encoder configured (%4.4s:%ux%u|%ux%u slice: %u)",
+      (char *)&port_in->format->encoding,
+      port_in->format->es->video.crop.width, port_in->format->es->video.crop.height,
+      port_in->format->es->video.width, port_in->format->es->video.height,
+      ctx->slice_height);
+   return BRCMJPEG_SUCCESS;
+
+ error:
+   return err;
+}
+
+/* Configuration which needs to be done on a per decode basis */
+static BRCMJPEG_STATUS_T brcmjpeg_configure_decoder(BRCMJPEG_T *ctx,
+   BRCMJPEG_REQUEST_T *req)
+{
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   MMAL_FOURCC_T encoding = brcmjpeg_pixfmt_to_encoding(req->pixel_format);
+   MMAL_PORT_T *port_out;
+   BRCMJPEG_STATUS_T err = BRCMJPEG_SUCCESS;
+
+   if (encoding != MMAL_ENCODING_I420 &&
+       encoding != MMAL_ENCODING_I422 &&
+       encoding != MMAL_ENCODING_RGBA)
+      status = MMAL_EINVAL;
+   CHECK_MMAL_STATUS(status, OUTPUT_FORMAT, "format not supported");
+
+   ctx->slice_height = 0;
+   ctx->mmal->status = MMAL_SUCCESS;
+   port_out = ctx->mmal->output[0];
+
+   /* The input port needs to be re-configured to take into account
+    * the properties of the new frame to decode */
+   if (port_out->is_enabled)
+   {
+       status = mmal_wrapper_port_disable(port_out);
+       CHECK_MMAL_STATUS(status, EXECUTE, "failed to disable output port");
+   }
+
+   /* We assume that we do not know the format of the new jpeg to be decoded
+    * and configure the input port for autodetecting the new format */
+   port_out->format->encoding = encoding;
+   port_out->format->es->video.width =
+      port_out->format->es->video.crop.width = 0;
+   port_out->format->es->video.height =
+      port_out->format->es->video.crop.height = 0;
+   status = mmal_port_format_commit(port_out);
+   CHECK_MMAL_STATUS(status, OUTPUT_FORMAT, "failed to commit output port format");
+
+   port_out->buffer_num = 1;
+   if (req->output_handle)
+      status = mmal_wrapper_port_enable(port_out, MMAL_WRAPPER_FLAG_PAYLOAD_USE_SHARED_MEMORY);
+   else
+      status = mmal_wrapper_port_enable(port_out, MMAL_WRAPPER_FLAG_PAYLOAD_ALLOCATE);
+   CHECK_MMAL_STATUS(status, EXECUTE, "failed to enable output port");
+
+   LOG_DEBUG("decoder configured (%4.4s:%ux%u|%ux%u)", (char *)&port_out->format->encoding,
+         port_out->format->es->video.crop.width, port_out->format->es->video.crop.height,
+         port_out->format->es->video.width, port_out->format->es->video.height);
+   return BRCMJPEG_SUCCESS;
+
+ error:
+   return err;
+}
+
+static BRCMJPEG_STATUS_T brcmjpeg_encode(BRCMJPEG_T *ctx,
+   BRCMJPEG_REQUEST_T *je)
+{
+   BRCMJPEG_STATUS_T err;
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   MMAL_BUFFER_HEADER_T *in, *out;
+   MMAL_BOOL_T eos = MMAL_FALSE;
+   const uint8_t *outBuf = je->output;
+   unsigned int loop = 0, slices = 0, outBufSize = je->output_alloc_size;
+   MMAL_PORT_T *port_in = ctx->mmal->input[0];
+   MMAL_PORT_T *port_out = ctx->mmal->output[0];
+
+   je->output_size = 0;
+   err = brcmjpeg_configure_encoder(ctx, je);
+   if (err != BRCMJPEG_SUCCESS)
+      return err;
+
+   /* Then we read the encoded data back from the encoder */
+
+   while (!eos && status == MMAL_SUCCESS)
+   {
+      /* send buffers to be filled */
+      while (mmal_wrapper_buffer_get_empty(port_out, &out, 0) == MMAL_SUCCESS)
+      {
+         out->data = (uint8_t *)outBuf;
+         out->alloc_size = MMAL_MIN(port_out->buffer_size, outBufSize);
+         outBufSize -= out->alloc_size;
+         outBuf += out->alloc_size;
+         status = mmal_port_send_buffer(port_out, out);
+         CHECK_MMAL_STATUS(status, EXECUTE, "failed to send buffer");
+      }
+
+      /* Send slices to be encoded */
+      if (slices * ctx->slice_height < port_in->format->es->video.height &&
+          mmal_wrapper_buffer_get_empty(port_in, &in, 0) == MMAL_SUCCESS)
+      {
+         if (je->input_handle)
+         {
+            in->data = (uint8_t *)je->input_handle;
+            in->length = in->alloc_size = je->input_size;
+         }
+         else
+         {
+            in->length = brcmjpeg_copy_pixels(in->data, in->alloc_size,
+               je->input, je->input_size, je->pixel_format,
+               port_in->format->es->video.width,
+               ctx->slice_height, je->buffer_width, je->buffer_height,
+               slices * ctx->slice_height, 1);
+            if (!in->length)
+               status = MMAL_EINVAL;
+            CHECK_MMAL_STATUS(status, INPUT_BUFFER, "input buffer too small");
+         }
+
+         slices++;
+         if (slices * ctx->slice_height >= port_in->format->es->video.height)
+             in->flags = MMAL_BUFFER_HEADER_FLAG_EOS;
+         status = mmal_port_send_buffer(port_in, in);
+         CHECK_MMAL_STATUS(status, EXECUTE, "failed to send buffer");
+      }
+
+      status = mmal_wrapper_buffer_get_full(port_out, &out, 0);
+      if (status == MMAL_EAGAIN)
+      {
+         status = MMAL_SUCCESS;
+         WAIT(ctx);
+         continue;
+      }
+      CHECK_MMAL_STATUS(status, EXECUTE, "failed to get full buffer");
+
+      LOG_DEBUG("received %i bytes", out->length);
+      je->output_size += out->length;
+      eos = out->flags & MMAL_BUFFER_HEADER_FLAG_EOS;
+
+      /* Detect when the encoder is running out of space for its output */
+      if (++loop >= port_out->buffer_num && !eos && !out->length)
+      {
+         LOG_ERROR("no more output space for encoder");
+         status = MMAL_EINVAL;
+      }
+
+      mmal_buffer_header_release(out);
+   }
+
+   /* Check if buffer was too small */
+   CHECK_MMAL_STATUS(status, OUTPUT_BUFFER, "output buffer too small");
+
+   LOG_DEBUG("encoded W:%ixH:%i:%i (%i bytes) in %i slices",
+         je->width, je->height, je->pixel_format, je->output_size, slices);
+   mmal_port_flush(port_out);
+   return BRCMJPEG_SUCCESS;
+
+ error:
+   mmal_wrapper_port_disable(port_in);
+   mmal_wrapper_port_disable(port_out);
+   return err;
+}
+
+static BRCMJPEG_STATUS_T brcmjpeg_decode(BRCMJPEG_T *ctx,
+   BRCMJPEG_REQUEST_T *jd)
+{
+   BRCMJPEG_STATUS_T err;
+   MMAL_STATUS_T status;
+   MMAL_BUFFER_HEADER_T *in, *out;
+   MMAL_BOOL_T eos = MMAL_FALSE;
+   const uint8_t *inBuf = jd->input;
+   unsigned int slices = 0, inBufSize = jd->input_size;
+   MMAL_PORT_T *port_in = ctx->mmal->input[0];
+   MMAL_PORT_T *port_out = ctx->mmal->output[0];
+   LOG_DEBUG("decode %i bytes", jd->input_size);
+
+   jd->output_size = 0;
+   err = brcmjpeg_configure_decoder(ctx, jd);
+   if (err != BRCMJPEG_SUCCESS)
+      return err;
+
+   while (!eos)
+   {
+      /* Send as many chunks of data to decode as we can */
+      while (inBufSize)
+      {
+         status = mmal_wrapper_buffer_get_empty(port_in, &in, 0);
+         if (status == MMAL_EAGAIN)
+            break;
+         CHECK_MMAL_STATUS(status, EXECUTE, "failed to get empty buffer (%i)", status);
+
+         in->data = (uint8_t *)inBuf;
+         in->length = MMAL_MIN(port_in->buffer_size, inBufSize);
+         in->alloc_size = in->length;
+         inBufSize -= in->length;
+         inBuf += in->length;
+         in->flags = inBufSize ? 0 : MMAL_BUFFER_HEADER_FLAG_EOS;
+         LOG_DEBUG("send decode in (%i bytes)", in->length);
+         status = mmal_port_send_buffer(port_in, in);
+         CHECK_MMAL_STATUS(status, EXECUTE, "failed to send input buffer");
+      }
+
+      /* Check for decoded data */
+      status = mmal_wrapper_buffer_get_full(port_out, &out, 0);
+      if (status == MMAL_EAGAIN)
+      {
+         WAIT(ctx);
+         continue;
+      }
+      CHECK_MMAL_STATUS(status, EXECUTE, "error decoding");
+
+      /* Check if a new format has been auto-detected by the decoder */
+      if (out->cmd == MMAL_EVENT_FORMAT_CHANGED)
+      {
+         MMAL_EVENT_FORMAT_CHANGED_T *event = mmal_event_format_changed_get(out);
+
+         if (event)
+            mmal_format_copy(port_out->format, event->format);
+         mmal_buffer_header_release(out);
+
+         if (!event)
+            status = MMAL_EINVAL;
+         CHECK_MMAL_STATUS(status, EXECUTE, "invalid format change event");
+
+         LOG_DEBUG("new format (%4.4s:%ux%u|%ux%u)", (char *)&event->format->encoding,
+            event->format->es->video.crop.width, event->format->es->video.crop.height,
+            event->format->es->video.width, event->format->es->video.height);
+
+         /* re-setup the output port for the new format */
+         status = mmal_wrapper_port_disable(port_out);
+         CHECK_MMAL_STATUS(status, EXECUTE, "failed to disable output port");
+
+         ctx->slice_height = event->format->es->video.height;
+         if (ENABLE_SLICE_MODE && !jd->output_handle)
+         {
+            /* setup slice mode */
+            if (port_out->format->encoding == MMAL_ENCODING_I420 ||
+               port_out->format->encoding == MMAL_ENCODING_I422)
+            {
+               if (port_out->format->encoding == MMAL_ENCODING_I420)
+                  port_out->format->encoding = MMAL_ENCODING_I420_SLICE;
+               if (port_out->format->encoding == MMAL_ENCODING_I422)
+                  port_out->format->encoding = MMAL_ENCODING_I422_SLICE;
+               ctx->slice_height = 16;
+               port_out->buffer_num = 3;
+            }
+         }
+
+         LOG_DEBUG("using slice size %u", ctx->slice_height);
+         status = mmal_port_format_commit(port_out);
+         CHECK_MMAL_STATUS(status, EXECUTE, "invalid format change event");
+         port_out->buffer_size = port_out->buffer_size_min;
+         if (jd->output_handle)
+            status = mmal_wrapper_port_enable(port_out, MMAL_WRAPPER_FLAG_PAYLOAD_USE_SHARED_MEMORY);
+         else
+            status = mmal_wrapper_port_enable(port_out, MMAL_WRAPPER_FLAG_PAYLOAD_ALLOCATE);
+         CHECK_MMAL_STATUS(status, EXECUTE, "failed to enable output port");
+
+         /* send all our output buffers to the decoder */
+         while (mmal_wrapper_buffer_get_empty(port_out, &out, 0) == MMAL_SUCCESS)
+         {
+            if (jd->output_handle)
+            {
+               out->data = (uint8_t*)jd->output_handle;
+               out->alloc_size = jd->output_alloc_size;
+            }
+            status = mmal_port_send_buffer(port_out, out);
+            CHECK_MMAL_STATUS(status, EXECUTE, "failed to send output buffer");
+         }
+
+         continue;
+      }
+
+      /* We have part of our output frame */
+      jd->width = port_out->format->es->video.crop.width;
+      if (!jd->width)
+         jd->width = port_out->format->es->video.width;
+      if (jd->output_handle)
+         jd->buffer_width = port_out->format->es->video.width;
+      if (!jd->buffer_width)
+         jd->buffer_width = jd->width;
+      jd->height = port_out->format->es->video.crop.height;
+      if (!jd->height)
+         jd->height = port_out->format->es->video.height;
+      if (jd->output_handle)
+         jd->buffer_height = port_out->format->es->video.height;
+      if (!jd->buffer_height)
+         jd->buffer_height = jd->height;
+
+      if (jd->output_handle)
+      {
+         jd->output_size += out->length;
+      }
+      else
+      {
+         jd->output_size = brcmjpeg_copy_pixels(jd->output, jd->output_alloc_size,
+            out->data, out->length, jd->pixel_format,
+            jd->buffer_width, jd->buffer_height,
+            port_out->format->es->video.width,
+            ctx->slice_height, slices * ctx->slice_height, 0);
+         slices++;
+      }
+
+      eos = out->flags & MMAL_BUFFER_HEADER_FLAG_EOS;
+      out->length = 0;
+      if (eos)
+      {
+         mmal_buffer_header_release(out);
+      }
+      else
+      {
+         status = mmal_port_send_buffer(port_out, out);
+         CHECK_MMAL_STATUS(status, EXECUTE, "failed to send output buffer");
+      }
+
+      if (!jd->output_size)
+         status = MMAL_EINVAL;
+      CHECK_MMAL_STATUS(status, OUTPUT_BUFFER, "invalid output buffer");
+   }
+
+   LOG_DEBUG("decoded W:%ixH%i:(W%ixH%i):%i in %i slices",
+      jd->width, jd->height, jd->buffer_width, jd->buffer_height,
+      jd->pixel_format, slices);
+   mmal_port_flush(port_in);
+   return BRCMJPEG_SUCCESS;
+
+ error:
+   mmal_port_flush(port_in);
+   return err;
+}
+
+/*****************************************************************************/
+static struct {
+    BRCMJPEG_PIXEL_FORMAT_T pixel_format;
+    MMAL_FOURCC_T encoding;
+} mmal_raw_conversion[] = {
+    {PIXEL_FORMAT_I420, MMAL_ENCODING_I420},
+    {PIXEL_FORMAT_YV12, MMAL_ENCODING_I420},
+    {PIXEL_FORMAT_I422, MMAL_ENCODING_I422},
+    {PIXEL_FORMAT_YV16, MMAL_ENCODING_I422},
+    {PIXEL_FORMAT_YUYV, MMAL_ENCODING_I422},
+    {PIXEL_FORMAT_RGBA, MMAL_ENCODING_RGBA},
+    {PIXEL_FORMAT_UNKNOWN, MMAL_ENCODING_UNKNOWN} };
+
+static MMAL_FOURCC_T brcmjpeg_pixfmt_to_encoding(BRCMJPEG_PIXEL_FORMAT_T pixel_format)
+{
+   unsigned int i;
+   for (i = 0; mmal_raw_conversion[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
+      if (mmal_raw_conversion[i].pixel_format == pixel_format)
+         break;
+   return mmal_raw_conversion[i].encoding;
+}
+
+// Copy a raw frame from 1 buffer to another, taking care of
+// stride / height differences between the input and output buffers.
+static unsigned int brcmjpeg_copy_pixels(uint8_t *out, unsigned int out_size,
+    const uint8_t *in, unsigned int in_size, BRCMJPEG_PIXEL_FORMAT_T fmt,
+    unsigned int out_width, unsigned int out_height,
+    unsigned int in_width, unsigned int in_height,
+    unsigned int line_offset, unsigned int convert_from)
+{
+    struct {
+        uint8_t *data;
+        unsigned int pitch;
+        unsigned int height;
+    } planes[2][3];
+    unsigned int num_planes = 0;
+    unsigned int i, size = 0;
+    unsigned int in_height_full = in_height;
+    unsigned int out_height_full = out_height;
+    unsigned int k = convert_from ? 1 : 0;
+
+    // Sanity check line_offset
+    if (line_offset >= (convert_from ? in_height : out_height))
+        return 0;
+
+    if (convert_from)
+       in_height -= line_offset;
+    else
+       out_height -= line_offset;
+
+    if (fmt == PIXEL_FORMAT_I420 ||
+        fmt == PIXEL_FORMAT_YV12)
+    {
+       planes[0][0].data = out;
+       planes[0][0].pitch = out_width;
+       planes[0][0].height = out_height;
+
+       planes[1][0].data = (uint8_t *)in;
+       planes[1][0].pitch = in_width;
+       planes[1][0].height = in_height;
+
+       planes[0][1].pitch = planes[0][2].pitch = out_width / 2;
+       planes[0][1].height = planes[0][2].height = out_height / 2;
+       planes[0][1].data = planes[0][0].data + out_width * out_height_full;
+       planes[0][2].data = planes[0][1].data + out_width * out_height_full / 4;
+
+       planes[1][1].pitch = planes[1][2].pitch = in_width / 2;
+       planes[1][1].height = planes[1][2].height = in_height / 2;
+       planes[1][1].data = planes[1][0].data + in_width * in_height_full;
+       planes[1][2].data = planes[1][1].data + in_width * in_height_full / 4;
+
+       if (fmt == PIXEL_FORMAT_YV12)
+       {
+          // We need to swap U and V
+          uint8_t *tmp = planes[1][2].data;
+          planes[1][2].data = planes[1][1].data;
+          planes[1][1].data = tmp;
+       }
+
+       // Add the line offset
+       planes[k][0].data += planes[k][0].pitch * line_offset;
+       planes[k][1].data += planes[k][1].pitch * line_offset/2;
+       planes[k][2].data += planes[k][2].pitch * line_offset/2;
+
+       num_planes = 3;
+       size = out_width * out_height_full * 3 / 2;
+
+       if (in_size < in_width * in_height * 3 / 2)
+          return 0;
+
+   } else if (fmt == PIXEL_FORMAT_I422 ||
+              fmt == PIXEL_FORMAT_YV16 ||
+              fmt == PIXEL_FORMAT_YUYV)
+   {
+      planes[0][0].data = out;
+      planes[0][0].pitch = out_width;
+      planes[0][0].height = out_height;
+
+      planes[1][0].data = (uint8_t *)in;
+      planes[1][0].pitch = in_width;
+      planes[1][0].height = in_height;
+
+      planes[0][1].pitch = planes[0][2].pitch = out_width / 2;
+      planes[0][1].height = planes[0][2].height = out_height;
+      planes[0][1].data = planes[0][0].data + out_width * out_height_full;
+      planes[0][2].data = planes[0][1].data + out_width * out_height_full / 2;
+
+      planes[1][1].pitch = planes[1][2].pitch = in_width / 2;
+      planes[1][1].height = planes[1][2].height = in_height;
+      planes[1][1].data = planes[1][0].data + in_width * in_height_full;
+      planes[1][2].data = planes[1][1].data + in_width * in_height_full / 2;
+
+      // Add the line offset
+      planes[k][0].data += planes[k][0].pitch * line_offset;
+      planes[k][1].data += planes[k][1].pitch * line_offset;
+      planes[k][2].data += planes[k][2].pitch * line_offset;
+      if (fmt == PIXEL_FORMAT_YUYV)
+         planes[k][0].data += planes[k][0].pitch * line_offset;
+
+      if (fmt == PIXEL_FORMAT_YV16)
+      {
+         // We need to swap U and V
+         uint8_t *tmp = planes[1][2].data;
+         planes[1][2].data = planes[1][1].data;
+         planes[1][1].data = tmp;
+      }
+
+      num_planes = 3;
+      size = out_width * out_height_full * 2;
+
+      if (in_size < in_width * in_height * 2)
+         return 0;
+   } else if (fmt == PIXEL_FORMAT_RGBA)
+   {
+       planes[0][0].data = out;
+       planes[0][0].pitch = out_width * 4;
+       planes[0][0].height = out_height;
+
+       planes[1][0].data = (uint8_t *)in;
+       planes[1][0].pitch = in_width * 4;
+       planes[1][0].height = in_height;
+
+       // Add the line offset
+       planes[k][0].data += planes[k][0].pitch * line_offset;
+
+       num_planes = 1;
+       size = out_width * out_height_full * 4;
+
+       if (in_size < in_width * in_height * 4)
+          return 0;
+   }
+
+   if (out_size < size)
+      return 0;
+
+   // Special case for YUYV where don't just copy but convert to/from I422
+   if (fmt == PIXEL_FORMAT_YUYV)
+   {
+      unsigned int width = in_width > out_width ? out_width : in_width;
+      unsigned int height = in_height > out_height ? out_height : in_height;
+      uint8_t *y = planes[convert_from ? 0 : 1][0].data;
+      uint8_t *u = planes[convert_from ? 0 : 1][1].data;
+      uint8_t *v = planes[convert_from ? 0 : 1][2].data;
+      uint8_t *yuyv = planes[convert_from ? 1 : 0][0].data;
+      unsigned int y_diff = (convert_from ? out_width : in_width) - width;
+      unsigned int yuyv_diff = ((convert_from ? in_width : out_width) - width) * 2;
+
+      while (height--)
+      {
+         if (convert_from)
+            for (i = width / 2; i; i--)
+            {
+                *y++ = *yuyv++;
+                *u++ = *yuyv++;
+                *y++ = *yuyv++;
+                *v++ = *yuyv++;
+            }
+         else
+            for (i = width / 2; i; i--)
+            {
+                *yuyv++ = *y++;
+                *yuyv++ = *u++;
+                *yuyv++ = *y++;
+                *yuyv++ = *v++;
+            }
+
+         yuyv += yuyv_diff;
+         y += y_diff;
+         u += y_diff >> 1;
+         v += y_diff >> 1;
+      }
+
+      return size;
+   }
+
+   for (i = 0; i < num_planes; i++)
+   {
+      unsigned int width = MMAL_MIN(planes[0][i].pitch, planes[1][i].pitch);
+      unsigned int height = MMAL_MIN(planes[0][i].height, planes[1][i].height);
+      uint8_t *data_out = planes[0][i].data;
+      uint8_t *data_in = planes[1][i].data;
+
+      while (height--)
+      {
+         memcpy(data_out, data_in, width);
+         data_out += planes[0][i].pitch;
+         data_in += planes[1][i].pitch;
+      }
+   }
+
+   return size;
+}
diff --git a/interface/mmal/client/brcmjpeg/brcmjpeg.h b/interface/mmal/client/brcmjpeg/brcmjpeg.h
new file mode 100755 (executable)
index 0000000..d787e99
--- /dev/null
@@ -0,0 +1,152 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file
+ *  Jpeg encoder and decoder library using the hardware jpeg codec
+ */
+
+#ifndef BRCM_JPEG_H
+#define BRCM_JPEG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Status return codes from the API */
+typedef enum
+{
+   BRCMJPEG_SUCCESS = 0,
+   BRCMJPEG_ERROR_NOMEM,
+   BRCMJPEG_ERROR_INIT,
+   BRCMJPEG_ERROR_INPUT_FORMAT,
+   BRCMJPEG_ERROR_OUTPUT_FORMAT,
+   BRCMJPEG_ERROR_INPUT_BUFFER,
+   BRCMJPEG_ERROR_OUTPUT_BUFFER,
+   BRCMJPEG_ERROR_EXECUTE,
+   BRCMJPEG_ERROR_REQUEST,
+} BRCMJPEG_STATUS_T;
+
+/** Type of the codec instance to create */
+typedef enum
+{
+   BRCMJPEG_TYPE_ENCODER = 0,
+   BRCMJPEG_TYPE_DECODER
+} BRCMJPEG_TYPE_T;
+
+/** Pixel formats supported by the codec */
+typedef enum
+{
+   PIXEL_FORMAT_UNKNOWN = 0,
+   PIXEL_FORMAT_I420, /* planar YUV 4:2:0 */
+   PIXEL_FORMAT_YV12, /* planar YVU 4:2:0 */
+   PIXEL_FORMAT_I422, /* planar YUV 4:2:2 */
+   PIXEL_FORMAT_YV16, /* planar YVU 4:2:2 */
+   PIXEL_FORMAT_YUYV, /* interleaved YUV 4:2:2 */
+   PIXEL_FORMAT_RGBA, /* interleaved RGBA */
+} BRCMJPEG_PIXEL_FORMAT_T;
+
+/** Definition of a codec request  */
+typedef struct
+{
+   /** Pointer to the buffer containing the input data
+    * A client should set input OR input_handle, but not both. */
+   const unsigned char *input;
+   /** Actual size of the input data */
+   unsigned int input_size;
+   /** Handle to input buffer containing input data */
+   unsigned int input_handle;
+
+   /** Pointer to the buffer used for the output data
+     * A client should set output OR output_handle, but not both. */
+   unsigned char *output;
+   /** Total size of the output buffer */
+   unsigned int output_alloc_size;
+   /** Actual size of the output data (this is an output parameter) */
+   unsigned int output_size;
+   /** Handle to the buffer used for the output data */
+   unsigned int output_handle;
+
+   /** Width of the raw frame (this is an input parameter for encode) */
+   unsigned int width;
+   /** Height of the raw frame (this is an input parameter for encode) */
+   unsigned int height;
+   /** Pixel format of the raw frame (this is an input parameter) */
+   BRCMJPEG_PIXEL_FORMAT_T pixel_format;
+
+   /** Width of the buffer containing the raw frame (input parameter).
+     * This is optional but if set, is used to specify the actual width
+     * of the buffer containing the raw frame */
+   unsigned int buffer_width;
+   /** Height of the buffer containing the raw frame (input parameter).
+     * This is optional but if set, is used to specify the actual height
+     * of the buffer containing the raw frame */
+   unsigned int buffer_height;
+
+   /** Encode quality - 0 to 100 */
+   unsigned int quality;
+} BRCMJPEG_REQUEST_T;
+
+/** Type of the codec instance */
+typedef struct BRCMJPEG_T BRCMJPEG_T;
+
+/** Create an instance of the jpeg codec
+ * This will actually re-use an existing instance if one is
+ * available.
+ *
+ * @param type type of codec instance required
+ * @param ctx will point to the newly created instance
+ * @return BRCMJPEG_SUCCESS on success
+ */
+BRCMJPEG_STATUS_T brcmjpeg_create(BRCMJPEG_TYPE_T type, BRCMJPEG_T **ctx);
+
+/** Acquire a new reference on a codec instance
+ *
+ * @param ctx instance to acquire a reference on
+ */
+void brcmjpeg_acquire(BRCMJPEG_T *ctx);
+
+/** Release an instance of the jpeg codec
+ * This will only trigger the destruction of the codec instance when
+ * the last reference to it is being released.
+ *
+ * @param ctx instance to release
+ */
+void brcmjpeg_release(BRCMJPEG_T *ctx);
+
+/** Process a jpeg codec request
+ *
+ * @param ctx instance of codec to use
+ * @param request codec request to execute
+ * @return BRCMJPEG_SUCCESS on success
+ */
+BRCMJPEG_STATUS_T brcmjpeg_process(BRCMJPEG_T *ctx, BRCMJPEG_REQUEST_T *request);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* BRCM_JPEG_H */
diff --git a/interface/mmal/client/brcmjpeg/brcmjpeg_test.c b/interface/mmal/client/brcmjpeg/brcmjpeg_test.c
new file mode 100755 (executable)
index 0000000..9e249b6
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "brcmjpeg.h"
+#include <sys/time.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <user-vcsm.h>
+
+#define MAX_WIDTH   5000
+#define MAX_HEIGHT  5000
+#define MAX_ENCODED (15*1024*1024)
+#define MAX_DECODED (MAX_WIDTH*MAX_HEIGHT*2)
+
+static uint8_t encodedInBuf[MAX_ENCODED];
+static uint8_t encodedOutBuf[MAX_ENCODED];
+static uint8_t decodedBuf[MAX_DECODED];
+static char outFileName[2048];
+
+int64_t get_time_microsec(void)
+{
+    struct timeval now;
+    gettimeofday(&now, NULL);
+    return now.tv_sec * 1000000LL + now.tv_usec;
+}
+
+int main(int argc, char **argv)
+{
+    BRCMJPEG_STATUS_T status;
+    BRCMJPEG_REQUEST_T enc_request, dec_request;
+    BRCMJPEG_T *enc = 0, *dec = 0;
+    int64_t start, stop, time_dec = 0, time_enc = 0;
+    unsigned int count = 1, format = PIXEL_FORMAT_YUYV;
+    unsigned int use_vcsm = 0, handle = 0, vc_handle = 0;
+    int i, arg = 1, help = 0;
+
+    // Parse command line arguments
+    while (arg < argc && argv[arg][0] == '-')
+    {
+        if (!strcmp(argv[arg], "-n"))
+        {
+            if (++arg >= argc || sscanf(argv[arg++], "%u", &count) != 1)
+                arg = argc;
+        }
+        else if (!strcmp(argv[arg], "-f"))
+        {
+            if (++arg >= argc || sscanf(argv[arg++], "%u", &format) != 1)
+                arg = argc;
+        }
+        else if (!strcmp(argv[arg], "-s"))
+        {
+            use_vcsm = 1;
+            arg++;
+        }
+        else if (!strcmp(argv[arg], "-h"))
+        {
+            help = 1;
+            break;
+        }
+        else
+        {
+            arg = argc;
+        }
+    }
+
+    if (arg == argc || help)
+    {
+        if (!help) fprintf(stderr, "invalid arguments\n");
+        fprintf(stderr, "usage: %s [options] file1 ... fileN\n", argv[0]);
+        fprintf(stderr, "options list:\n");
+        fprintf(stderr, " -h     : help\n");
+        fprintf(stderr, " -n <N> : process each file N times\n");
+        fprintf(stderr, " -f <N> : force color format\n");
+        fprintf(stderr, " -s     : use shared-memory for intermediate buffer\n");
+        return !help;
+    }
+
+    if (use_vcsm)
+    {
+        if (vcsm_init() < 0)
+        {
+            fprintf(stderr, "failed to initialise vcsm\n");
+            return 1;
+        }
+
+        handle = vcsm_malloc_cache(MAX_DECODED, VCSM_CACHE_TYPE_HOST, "brcmjpeg-test");
+        if (!handle)
+        {
+            fprintf(stderr, "failed to alloc vcsm buffer\n");
+            vcsm_exit();
+            return 1;
+        }
+
+        vc_handle = vcsm_vc_hdl_from_hdl(handle);
+
+        fprintf(stderr, "decodedBuf handle %u vc_handle %u\n", handle, vc_handle);
+    }
+
+    // Setup of the dec / enc requests
+    memset(&enc_request, 0, sizeof(enc_request));
+    memset(&dec_request, 0, sizeof(dec_request));
+    dec_request.input = encodedInBuf;
+    dec_request.output = use_vcsm ? NULL : decodedBuf;
+    dec_request.output_handle = use_vcsm ? vc_handle : 0;
+    dec_request.output_alloc_size = MAX_DECODED;
+    enc_request.input = dec_request.output;
+    enc_request.input_handle = dec_request.output_handle;
+    enc_request.output = encodedOutBuf;
+    enc_request.output_alloc_size = sizeof(encodedOutBuf);
+    enc_request.quality = 75;
+    enc_request.pixel_format = dec_request.pixel_format = format;
+
+    status = brcmjpeg_create(BRCMJPEG_TYPE_ENCODER, &enc);
+    if (status != BRCMJPEG_SUCCESS)
+    {
+        fprintf(stderr, "could not create encoder\n");
+        return 1;
+    }
+    status = brcmjpeg_create(BRCMJPEG_TYPE_DECODER, &dec);
+    if (status != BRCMJPEG_SUCCESS)
+    {
+        fprintf(stderr, "could not create decoder\n");
+        brcmjpeg_release(enc);
+        return 1;
+    }
+
+    for (i = arg; i < argc; i++)
+    {
+        unsigned int j;
+        fprintf(stderr, "processing %s\n", argv[i]);
+
+        FILE *file_in = fopen(argv[i], "rb");
+        if (!file_in) {
+            fprintf(stderr, "could not open file %s\n", argv[i]);
+            continue;
+        }
+        snprintf(outFileName, sizeof(outFileName), "%s.out", argv[i]);
+        FILE *file_out = fopen(outFileName, "wb+");
+        if (!file_out) {
+            fprintf(stderr, "could not open file %s\n", outFileName);
+            fclose(file_in);
+            continue;
+        }
+        dec_request.input_size = fread(encodedInBuf, 1, sizeof(encodedInBuf), file_in);
+
+        for (j = 0; j < count; j++)
+        {
+            dec_request.buffer_width = 0;
+            dec_request.buffer_height = 0;
+
+            start = get_time_microsec();
+            status = brcmjpeg_process(dec, &dec_request);
+            stop = get_time_microsec();
+            if (status != BRCMJPEG_SUCCESS) {
+                fprintf(stderr, "could not decode %s\n", argv[i]);
+                break;
+            }
+
+            fprintf(stderr, "decoded %ix%i(%ix%i), %i bytes in %lldus\n",
+                    dec_request.width, dec_request.height,
+                    dec_request.buffer_width, dec_request.buffer_height,
+                    dec_request.input_size, stop - start);
+            time_dec += stop - start;
+
+            enc_request.input_size = dec_request.output_size;
+            enc_request.width = dec_request.width;
+            enc_request.height = dec_request.height;
+            enc_request.buffer_width = dec_request.buffer_width;
+            enc_request.buffer_height = dec_request.buffer_height;
+
+            start = get_time_microsec();
+            status = brcmjpeg_process(enc, &enc_request);
+            stop = get_time_microsec();
+            if (status != BRCMJPEG_SUCCESS) {
+                fprintf(stderr, "could not encode %s\n", outFileName);
+                break;
+            }
+
+            fprintf(stderr, "encoded %ix%i(%ix%i), %i bytes in %lldus\n",
+                    enc_request.width, enc_request.height,
+                    enc_request.buffer_width, enc_request.buffer_height,
+                    enc_request.output_size, stop - start);
+            time_enc += stop - start;
+        }
+
+        if (status != BRCMJPEG_SUCCESS)
+            continue;
+
+        fwrite(enc_request.output, 1, enc_request.output_size, file_out);
+        fclose(file_out);
+        fclose(file_in);
+
+        fprintf(stderr, "decode times %lldus (%lldus per run)\n",
+                time_dec, time_dec / count);
+        fprintf(stderr, "encode times %lldus (%lldus per run)\n",
+                time_enc, time_enc / count);
+    }
+
+    brcmjpeg_release(dec);
+    brcmjpeg_release(enc);
+
+    if (use_vcsm)
+    {
+       vcsm_free(handle);
+       vcsm_exit();
+    }
+
+    return 0;
+}
diff --git a/interface/mmal/components/CMakeLists.txt b/interface/mmal/components/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..d65fa37
--- /dev/null
@@ -0,0 +1,34 @@
+add_library(mmal_components ${LIBRARY_TYPE}
+           container_reader.c
+           null_sink.c
+           passthrough.c
+           scheduler.c
+           splitter.c
+           copy.c
+           artificial_camera.c
+           aggregator.c
+           clock.c
+           spdif.c
+          )
+
+set(extra_components_SRCS avcodec_video_decoder.c avcodec_audio_decoder.c
+    sdl_video_render.c sdl_audio_render.c aaf_audio_render.cpp android_media_codec.cpp)
+
+#target_link_libraries(mmal_components avcodec avutil)
+#target_link_libraries(mmal_components SDL)
+#if (WIN32)
+#target_link_libraries(mmal_components avcore avutil z) # For avcodec
+#target_link_libraries(mmal_components gdi32 winmm) # For SDL
+#endif (WIN32)
+
+add_custom_target(mmal_components_extra ALL
+    COMMAND touch ${extra_components_SRCS}
+    WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/interface/mmal/components)
+
+set(container_libs ${container_libs} containers)
+
+target_link_libraries(mmal_components ${container_libs} mmal_util)
+target_link_libraries(mmal_components mmal_core)
+
+install(TARGETS mmal_components DESTINATION lib)
+
diff --git a/interface/mmal/components/aaf_audio_render.cpp b/interface/mmal/components/aaf_audio_render.cpp
new file mode 100755 (executable)
index 0000000..32b5d6d
--- /dev/null
@@ -0,0 +1,504 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "mmal_logging.h"
+#include "core/mmal_component_private.h"
+#include "core/mmal_port_private.h"
+#include "core/mmal_clock_private.h"
+
+#include <media/AudioTrack.h>
+#include <utils/Mutex.h>
+
+using namespace android;
+
+/* Buffering requirements */
+#define INPUT_MIN_BUFFER_NUM 4
+#define INPUT_RECOMMENDED_BUFFER_NUM 8
+
+#define SPDIF_AC3_FRAME_SIZE 6144
+
+/*****************************************************************************/
+enum TRACK_STATE_T {
+   TRACK_STATE_STOPPED,
+   TRACK_STATE_RUNNING,
+   TRACK_STATE_PAUSED
+};
+
+typedef struct MMAL_COMPONENT_MODULE_T
+{
+   MMAL_STATUS_T status;
+   MMAL_QUEUE_T *queue;
+
+   android::sp<android::AudioTrack> track;
+
+   Mutex *lock;
+   uint32_t bytes_queued;
+
+   MMAL_BOOL_T is_enabled;
+   TRACK_STATE_T state;
+
+   MMAL_ES_FORMAT_T *format; /**< format currently configured */
+
+} MMAL_COMPONENT_MODULE_T;
+
+/*****************************************************************************/
+
+static void aaf_track_callback(int event, void *user, void *info);
+
+static struct encoding_table_t {
+   MMAL_FOURCC_T encoding;
+   audio_format_t format;
+} encoding_list[] =
+{ {MMAL_ENCODING_PCM_SIGNED, AUDIO_FORMAT_PCM_16_BIT},
+#ifdef ANDROID_SUPPORTS_AC3
+  {MMAL_ENCODING_AC3, AUDIO_FORMAT_AC3_SPDIF},
+  {MMAL_ENCODING_EAC3, AUDIO_FORMAT_EAC3_SPDIF},
+#endif
+  {0, AUDIO_FORMAT_INVALID}
+};
+
+static audio_format_t encoding_to_audio_format(MMAL_FOURCC_T encoding)
+{
+   struct encoding_table_t *entry = encoding_list;
+
+   for (entry = encoding_list; entry->encoding; entry++)
+      if (entry->encoding == encoding)
+         break;
+
+   return entry->format;
+}
+
+static void aaf_track_destroy(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+
+   if (module->track != NULL)
+   {
+      module->track->stop();
+      module->track = NULL;
+   }
+}
+
+static MMAL_STATUS_T aaf_track_create(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_PORT_T *port = component->input[0];
+   audio_channel_mask_t channels_mask;
+   int frame_count = 256;
+
+   /* Reset track on format change.  Can do better than that? */
+   if (module->track != NULL)
+      aaf_track_destroy(component);
+
+   channels_mask = audio_channel_out_mask_from_count(port->format->es->audio.channels);
+   LOG_INFO("%s(%p) %4.4s, %i Hz, mask %x, chan %i", port->name, port,
+            (char *)&port->format->encoding,
+            (int)port->format->es->audio.sample_rate, channels_mask,
+            (int)port->format->es->audio.channels);
+
+   AudioTrack::getMinFrameCount(&frame_count);
+   if (port->format->encoding == MMAL_ENCODING_AC3)
+      frame_count = SPDIF_AC3_FRAME_SIZE;
+   else if (port->format->encoding == MMAL_ENCODING_EAC3)
+      frame_count = SPDIF_AC3_FRAME_SIZE * 4;
+   frame_count *= 2; /* Twice the minimum should be enough */
+
+   module->track = new AudioTrack(AUDIO_STREAM_MUSIC,
+      port->format->es->audio.sample_rate,
+      encoding_to_audio_format(port->format->encoding), channels_mask,
+      frame_count, port->format->encoding == MMAL_ENCODING_PCM_SIGNED ?
+         AUDIO_OUTPUT_FLAG_NONE : AUDIO_OUTPUT_FLAG_DIRECT,
+      &aaf_track_callback, port, 0);
+
+   if (module->track == NULL || module->track->initCheck() != OK)
+   {
+      LOG_ERROR("%s(%p): track creation failed", port->name, port);
+      module->track = NULL;
+      return MMAL_ENOSYS;
+   }
+
+   return MMAL_SUCCESS;
+}
+
+static void aaf_track_callback(int event, void *user, void *info)
+{
+   MMAL_PORT_T *port = (MMAL_PORT_T *)user;
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_BUFFER_HEADER_T *buffer;
+   AudioTrack::Buffer *trackbuf = NULL;
+   unsigned int bytes, space;
+   uint8_t *dest;
+
+   if (event == AudioTrack::EVENT_UNDERRUN)
+      LOG_ERROR("underrun");
+
+   if (event != AudioTrack::EVENT_MORE_DATA)
+      return;
+
+   trackbuf = (AudioTrack::Buffer *)info;
+   space = trackbuf->size;
+   dest = (uint8_t *)trackbuf->raw;
+   trackbuf->size = 0;
+
+   if (!mmal_queue_length(module->queue))
+   {
+      LOG_ERROR("no buffers queued");
+      return;
+   }
+
+   while (space > 0)
+   {
+      buffer = mmal_queue_get(module->queue);
+      if (!buffer)
+         break;
+
+      bytes = MMAL_MIN(buffer->length, space);
+      memcpy(dest, buffer->data + buffer->offset, bytes);
+      buffer->offset += bytes;
+      buffer->length -= bytes;
+      dest += bytes;
+      space -= bytes;
+      trackbuf->size += bytes;
+
+      if (buffer->length)
+      {
+         /* Re-queue */
+         mmal_queue_put_back(module->queue, buffer);
+         continue;
+      }
+
+      /* Handle the EOS */
+      if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_EOS)
+         mmal_event_eos_send(port);
+
+      buffer->offset = 0;
+      mmal_port_buffer_header_callback(port, buffer);
+   }
+
+   module->lock->lock();
+   module->bytes_queued -= trackbuf->size;
+   module->lock->unlock();
+}
+
+static MMAL_STATUS_T aaf_track_state_update(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   TRACK_STATE_T new_state = TRACK_STATE_STOPPED;
+
+   if (module->track == NULL)
+      return MMAL_SUCCESS;
+
+   if (module->is_enabled)
+   {
+      MMAL_RATIONAL_T scale = mmal_port_clock_scale_get(component->clock[0]);
+      new_state = TRACK_STATE_PAUSED;
+      if (scale.den && scale.den == scale.num)
+         new_state = TRACK_STATE_RUNNING;
+   }
+
+   if (new_state == module->state)
+      return MMAL_SUCCESS; /* Nothing to do */
+
+   if (module->state == TRACK_STATE_STOPPED && new_state == TRACK_STATE_RUNNING)
+   {
+      module->track->start();
+   }
+   else if (module->state == TRACK_STATE_RUNNING)
+   {
+      if (new_state == TRACK_STATE_STOPPED)
+         module->track->stop();
+      else if (new_state == TRACK_STATE_PAUSED)
+         module->track->pause();
+   }
+   else if (module->state == TRACK_STATE_PAUSED)
+   {
+      if (new_state == TRACK_STATE_STOPPED)
+         module->track->stop();
+      else if (new_state == TRACK_STATE_RUNNING)
+         module->track->start();
+   }
+
+   module->state = new_state;
+   return MMAL_SUCCESS;
+}
+
+/** Destroy a previously created component */
+static MMAL_STATUS_T aaf_component_destroy(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+
+   aaf_track_destroy(component);
+
+   if(component->input_num)
+      mmal_ports_free(component->input, component->input_num);
+   if(component->clock_num)
+      mmal_ports_clock_free(component->clock, component->clock_num);
+   if(module->format)
+      mmal_format_free(module->format);
+   if(module->queue)
+      mmal_queue_destroy(module->queue);
+   delete module->lock;
+   vcos_free(module);
+   return MMAL_SUCCESS;
+}
+
+/** Set format on a port */
+static MMAL_STATUS_T aaf_port_set_format(MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+
+   if (!mmal_format_compare(port->format, component->priv->module->format))
+      return MMAL_SUCCESS;
+
+   /* Check the format is supported */
+   if (encoding_to_audio_format(port->format->encoding) == AUDIO_FORMAT_INVALID)
+   {
+      LOG_ERROR("port does not support '%4.4s'", (char *)&port->format->encoding);
+      return MMAL_EINVAL;
+   }
+
+   /* Specific checks for PCM */
+   if (port->format->encoding == MMAL_ENCODING_PCM_SIGNED)
+   {
+
+      if (port->format->es->audio.bits_per_sample != 16 &&
+          port->format->es->audio.bits_per_sample != 32)
+      {
+         LOG_ERROR("port does not support '%4.4s' at %ibps",
+                   (char *)&port->format->encoding,
+                   port->format->es->audio.bits_per_sample);
+         return MMAL_EINVAL;
+      }
+
+      if (!audio_channel_out_mask_from_count(port->format->es->audio.channels))
+      {
+         LOG_ERROR("%s invalid channels mask from %i", port->name,
+            (int)port->format->es->audio.channels);
+         return MMAL_ENOSYS;
+      }
+   }
+
+   mmal_format_copy(component->priv->module->format, port->format);
+
+   return aaf_track_create(component);
+}
+
+/** Enable processing on a port */
+static MMAL_STATUS_T aaf_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   MMAL_PARAM_UNUSED(cb);
+
+   if (module->track == NULL)
+      status = aaf_port_set_format(port);
+   if (status != MMAL_SUCCESS)
+      return status;
+
+   module->is_enabled = MMAL_TRUE;
+   aaf_track_state_update(component);
+   return MMAL_SUCCESS;
+}
+
+/** Flush a port */
+static MMAL_STATUS_T aaf_port_flush(MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_BUFFER_HEADER_T *buffer;
+
+   while((buffer = mmal_queue_get(module->queue)))
+      mmal_port_buffer_header_callback(port, buffer);
+
+   module->lock->lock();
+   module->bytes_queued = 0;
+   module->lock->unlock();
+
+   if (module->track == NULL)
+      return MMAL_SUCCESS;
+
+   module->track->stop();
+   module->track->flush();
+   module->state = TRACK_STATE_STOPPED;
+   aaf_track_state_update(component);
+   return MMAL_SUCCESS;
+}
+
+/** Disable processing on a port */
+static MMAL_STATUS_T aaf_port_disable(MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+
+   module->is_enabled = MMAL_FALSE;
+   aaf_track_state_update(component);
+
+   return aaf_port_flush(port);
+}
+
+static MMAL_STATUS_T aaf_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   unsigned int bits_per_sample, channels, sample_rate;
+   uint32_t aaf_bytes_queued = 0;
+   int64_t latency, ts;
+
+   /* Handle event buffers */
+   if (buffer->cmd)
+   {
+      LOG_ERROR("discarding event %i on port %p", (int)buffer->cmd, port);
+      buffer->length = 0;
+      mmal_port_buffer_header_callback(port, buffer);
+      return MMAL_SUCCESS;
+   }
+
+   if (module->status != MMAL_SUCCESS)
+      return module->status;
+
+   bits_per_sample = port->format->es->audio.bits_per_sample;
+   channels = port->format->es->audio.channels;
+   sample_rate = port->format->es->audio.sample_rate;
+
+   if (port->format->encoding == MMAL_ENCODING_AC3 ||
+       port->format->encoding == MMAL_ENCODING_EAC3)
+   {
+      uint32_t aaf_latency = 0;
+      AudioSystem::getOutputLatency(&aaf_latency, AUDIO_STREAM_MUSIC);
+      latency = aaf_latency * 1000LL;
+
+      bits_per_sample = 16;
+      channels = 2;
+      if (port->format->encoding == MMAL_ENCODING_EAC3 &&
+          sample_rate <= 48000)
+         sample_rate *= 4;
+      aaf_bytes_queued = module->track->frameCount();
+   }
+   else
+   {
+      latency = module->track->latency() * 1000LL;
+   }
+
+   /* Keep aaf_track_callback from sending more samples */
+   module->lock->lock();
+
+   module->bytes_queued += buffer->length;
+   latency += (module->bytes_queued + aaf_bytes_queued) / channels /
+      (bits_per_sample / 8) * 1000000LL / sample_rate;
+   ts = buffer->pts - latency;
+
+   module->lock->unlock();
+
+   mmal_port_clock_media_time_set(component->clock[0], ts);
+
+   mmal_queue_put(module->queue, buffer);
+
+   return MMAL_SUCCESS;
+}
+
+void aaf_clock_event(MMAL_PORT_T *port, const MMAL_CLOCK_EVENT_T *event)
+{
+   MMAL_COMPONENT_T *component = port->component;
+
+   switch (event->id)
+   {
+   case MMAL_CLOCK_EVENT_SCALE:
+      aaf_track_state_update(component);
+      break;
+   case MMAL_CLOCK_EVENT_TIME:
+   case MMAL_CLOCK_EVENT_REFERENCE:
+   case MMAL_CLOCK_EVENT_ACTIVE:
+      /* nothing to do */
+      break;
+   default:
+      LOG_DEBUG("unknown event id %4.4s", (char*)&event->id);
+      break;
+   }
+}
+
+/** Create an instance of a component  */
+static MMAL_STATUS_T mmal_component_create_aaf(const char *name, MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module;
+
+   /* Check we're the requested component */
+   if(strcmp(name, "aaf." MMAL_AUDIO_RENDER))
+      return MMAL_ENOENT;
+
+   /* Allocate our module context */
+   component->priv->module = module = (MMAL_COMPONENT_MODULE_T *)vcos_calloc(1, sizeof(*module), "mmal module");
+   if(!module)
+      return MMAL_ENOMEM;
+   module->lock = new Mutex();
+   if (!module->lock)
+      goto error;
+
+   /* Allocate the ports for this component */
+   component->input = mmal_ports_alloc(component, 1, MMAL_PORT_TYPE_INPUT, 0);
+   if(!component->input)
+      goto error;
+   component->input_num = 1;
+
+   /* Create the clock port (clock ports are managed by the framework) */
+   component->clock = mmal_ports_clock_alloc(component, 1, 0, aaf_clock_event);
+   if (!component->clock)
+      goto error;
+   component->clock_num = 1;
+
+   module->queue = mmal_queue_create();
+   if(!module->queue)
+      goto error;
+
+   module->format = mmal_format_alloc();
+   if(!module->format)
+      goto error;
+
+   component->input[0]->priv->pf_set_format = aaf_port_set_format;
+   component->input[0]->priv->pf_enable = aaf_port_enable;
+   component->input[0]->priv->pf_disable = aaf_port_disable;
+   component->input[0]->priv->pf_flush = aaf_port_flush;
+   component->input[0]->priv->pf_send = aaf_port_send;
+   component->input[0]->buffer_num_min = INPUT_MIN_BUFFER_NUM;
+   component->input[0]->buffer_num_recommended = INPUT_RECOMMENDED_BUFFER_NUM;
+   component->input[0]->format->type = MMAL_ES_TYPE_AUDIO;
+
+   component->priv->pf_destroy = aaf_component_destroy;
+   return MMAL_SUCCESS;
+
+ error:
+   aaf_component_destroy(component);
+   return MMAL_ENOMEM;
+}
+
+MMAL_CONSTRUCTOR(mmal_register_component_aaf_audio);
+void mmal_register_component_aaf_audio(void)
+{
+   mmal_component_supplier_register("aaf", mmal_component_create_aaf);
+}
diff --git a/interface/mmal/components/aggregator.c b/interface/mmal/components/aggregator.c
new file mode 100755 (executable)
index 0000000..fac4596
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "core/mmal_component_private.h"
+#include "core/mmal_port_private.h"
+#include "util/mmal_graph.h"
+#include "mmal_logging.h"
+
+#define AGGREGATOR_PREFIX "aggregator"
+#define AGGREGATOR_PIPELINE_PREFIX "pipeline"
+
+typedef struct MMAL_GRAPH_USERDATA_T {
+    int dummy;
+} MMAL_GRAPH_USERDATA_T;
+
+static MMAL_STATUS_T aggregator_parameter_set(MMAL_GRAPH_T *graph,
+   MMAL_PORT_T *port, const MMAL_PARAMETER_HEADER_T *param)
+{
+   MMAL_PARAM_UNUSED(graph);
+   MMAL_PARAM_UNUSED(port);
+   MMAL_PARAM_UNUSED(param);
+   LOG_TRACE("graph %p, port %p, param %p", graph, port, param);
+   return MMAL_ENOSYS;
+}
+
+static MMAL_STATUS_T aggregator_parameter_get(MMAL_GRAPH_T *graph,
+      MMAL_PORT_T *port, MMAL_PARAMETER_HEADER_T *param)
+{
+   MMAL_PARAM_UNUSED(graph);
+   MMAL_PARAM_UNUSED(port);
+   MMAL_PARAM_UNUSED(param);
+   LOG_TRACE("graph %p, port %p, param %p", graph, port, param);
+   return MMAL_ENOSYS;
+}
+
+/** Create an instance of a component  */
+static MMAL_STATUS_T mmal_component_create_aggregator_pipeline(const char *full_name,
+   const char *component_names, MMAL_COMPONENT_T *component)
+{
+   MMAL_GRAPH_T *graph = 0;
+   MMAL_COMPONENT_T *subcomponent[2] = {0};
+   MMAL_STATUS_T status = MMAL_ENOMEM;
+   unsigned int length;
+   char *orig, *names;
+
+   length = strlen(component_names);
+   names = orig = vcos_calloc(1, length + 1, "mmal aggregator");
+   if (!names)
+      goto error;
+   memcpy(names, component_names, length);
+
+   /* We'll build the aggregator using a graph */
+   status = mmal_graph_create(&graph, sizeof(MMAL_GRAPH_USERDATA_T));
+   if (status != MMAL_SUCCESS)
+      goto error;
+   graph->pf_parameter_get = aggregator_parameter_get;
+   graph->pf_parameter_set = aggregator_parameter_set;
+
+   /* Iterate through all the specified components */
+   while (*names)
+   {
+      MMAL_CONNECTION_T *connection;
+      const char *name;
+
+      /* Switch to a new connection */
+      if (subcomponent[0])
+         mmal_component_destroy(subcomponent[0]);
+      subcomponent[0] = subcomponent[1];
+      subcomponent[1] = 0;
+
+      /* Extract the name of the next component */
+      for (name = names; *names && *names != ':'; names++);
+
+      /* Replace the separator */
+      if (*names)
+         *(names++) = 0;
+
+      /* Skip empty strings */
+      if (!*name)
+         continue;
+
+      status = mmal_component_create(name, &subcomponent[1]);
+      if (status != MMAL_SUCCESS)
+         goto error;
+
+      status = mmal_graph_add_component(graph, subcomponent[1]);
+      if (status != MMAL_SUCCESS)
+         goto error;
+
+      /* Special case for dealing with the first component in the chain */
+      if (!subcomponent[0])
+      {
+         /* Add first input port if any */
+         if (subcomponent[1]->input_num)
+         {
+            status = mmal_graph_add_port(graph, subcomponent[1]->input[0]);
+            if (status != MMAL_SUCCESS)
+               goto error;
+         }
+         continue;
+      }
+
+      /* Create connection between the 2 ports */
+      if (subcomponent[0]->output_num < 1 || subcomponent[1]->input_num < 1)
+         goto error;
+      status = mmal_connection_create(&connection, subcomponent[0]->output[0],
+         subcomponent[1]->input[0], 0);
+      if (status != MMAL_SUCCESS)
+         goto error;
+
+      status = mmal_graph_add_connection(graph, connection);
+      /* Now the connection is added to the graph we don't care about it anymore */
+      mmal_connection_destroy(connection);
+      if (status != MMAL_SUCCESS)
+         goto error;
+   }
+
+   /* Add last output port if any */
+   if (subcomponent[1] && subcomponent[1]->output_num && subcomponent[1]->output[0])
+   {
+      status = mmal_graph_add_port(graph, subcomponent[1]->output[0]);
+      if (status != MMAL_SUCCESS)
+         goto error;
+   }
+
+   /* Build the graph */
+   component->priv->module = (struct MMAL_COMPONENT_MODULE_T *)graph;
+   status = mmal_graph_component_constructor(full_name, component);
+   if (status != MMAL_SUCCESS)
+      goto error;
+
+ end:
+   if (subcomponent[0])
+      mmal_component_destroy(subcomponent[0]);
+   if (subcomponent[1])
+      mmal_component_destroy(subcomponent[1]);
+   vcos_free(orig);
+   return status;
+
+ error:
+   if (graph)
+      mmal_graph_destroy(graph);
+   goto end;
+}
+
+/** Create an instance of a component  */
+static MMAL_STATUS_T mmal_component_create_aggregator(const char *name, MMAL_COMPONENT_T *component)
+{
+   const char *stripped = name + sizeof(AGGREGATOR_PREFIX);
+
+   /* Select the requested aggregator */
+   if (!strncmp(stripped, AGGREGATOR_PIPELINE_PREFIX ":", sizeof(AGGREGATOR_PIPELINE_PREFIX)))
+      return mmal_component_create_aggregator_pipeline(name,
+         stripped + sizeof(AGGREGATOR_PIPELINE_PREFIX), component);
+
+   return MMAL_ENOSYS;
+}
+
+MMAL_CONSTRUCTOR(mmal_register_component_aggregator);
+void mmal_register_component_aggregator(void)
+{
+   mmal_component_supplier_register(AGGREGATOR_PREFIX, mmal_component_create_aggregator);
+}
diff --git a/interface/mmal/components/android_media_codec.cpp b/interface/mmal/components/android_media_codec.cpp
new file mode 100755 (executable)
index 0000000..8877a52
--- /dev/null
@@ -0,0 +1,861 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "core/mmal_component_private.h"
+#include "core/mmal_port_private.h"
+#include "mmal_logging.h"
+
+#include <media/stagefright/MediaCodec.h>
+#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/ICrypto.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+#include <binder/ProcessState.h>
+
+using namespace android;
+
+/* List of variants supported by this component */
+#define AMC_VARIANT_UNKNOWN 0
+#define AMC_VARIANT_AUDIO_DECODE 1
+#define AMC_VARIANT_AUDIO_DECODE_NAME "audio_decode"
+
+/*****************************************************************************/
+struct AmcHandler :  public AHandler
+{
+   AmcHandler(MMAL_COMPONENT_T *component) :
+      mComponent(component), mNotificationRequested(false) {}
+
+   void requestNotification(sp<MediaCodec> &codec)
+   {
+      if (mActivityNotify == NULL)
+         mActivityNotify = new AMessage(0, id());
+
+      if (!mNotificationRequested)
+      {
+         mNotificationRequested = true;
+         codec->requestActivityNotification(mActivityNotify->dup());
+      }
+   }
+
+   void reset()
+   {
+      mNotificationRequested = false;
+   }
+
+protected:
+   virtual void onMessageReceived(const sp<AMessage> &msg)
+   {
+      (void)msg;
+      mNotificationRequested = false;
+      mmal_component_action_trigger(mComponent);
+   }
+
+private:
+   MMAL_COMPONENT_T *mComponent;
+   sp<AMessage> mActivityNotify;
+   bool mNotificationRequested;
+};
+
+typedef struct MMAL_COMPONENT_MODULE_T
+{
+   MMAL_STATUS_T status; /**< current status of the component */
+
+   sp<MediaCodec> codec;
+   sp<AmcHandler> ahandler;
+   sp<ALooper> alooper;
+   Vector<sp<ABuffer> > input_buffers; /**< list of buffers exported by mediacodec */
+   Vector<sp<ABuffer> > output_buffers; /**< list of buffers exported by mediacodec */
+
+} MMAL_COMPONENT_MODULE_T;
+
+typedef struct MMAL_PORT_MODULE_T
+{
+   MMAL_ES_FORMAT_T *format; /**< format currently configured */
+   MMAL_QUEUE_T *queue; /**< queue for the buffers sent to the ports */
+   MMAL_BOOL_T needs_configuring; /**< port is waiting for a format commit */
+
+   List<size_t> *dequeued; /* buffers already dequeued from the codec */
+
+   const char *mime;
+   unsigned int actual_channels;
+
+} MMAL_PORT_MODULE_T;
+
+static struct encoding_table_t {
+   const char *mime;
+   MMAL_FOURCC_T encoding;
+   MMAL_ES_TYPE_T type;
+   MMAL_FOURCC_T encoding_variant;
+} encoding_list[] =
+{  {"audio/3gpp", MMAL_ENCODING_AMRNB, MMAL_ES_TYPE_AUDIO, 0},
+  {"audio/amr-wb", MMAL_ENCODING_AMRWB, MMAL_ES_TYPE_AUDIO, 0},
+  {"audio/mpeg", MMAL_ENCODING_MPGA, MMAL_ES_TYPE_AUDIO, 0},
+  {"audio/mp4a-latm", MMAL_ENCODING_MP4A, MMAL_ES_TYPE_AUDIO, 0},
+  {"audio/mp4a-latm", MMAL_ENCODING_MP4A, MMAL_ES_TYPE_AUDIO, MMAL_ENCODING_VARIANT_MP4A_ADTS},
+  {"audio/vorbis", MMAL_ENCODING_VORBIS, MMAL_ES_TYPE_AUDIO, 0},
+  {"audio/g711-alaw", MMAL_ENCODING_ALAW, MMAL_ES_TYPE_AUDIO, 0},
+  {"audio/g711-ulaw", MMAL_ENCODING_MULAW, MMAL_ES_TYPE_AUDIO, 0},
+  {"audio/ac3", MMAL_ENCODING_AC3, MMAL_ES_TYPE_AUDIO, 0},
+  {"audio/ec3", MMAL_ENCODING_EAC3, MMAL_ES_TYPE_AUDIO, 0},
+  {"audio/eac3", MMAL_ENCODING_EAC3, MMAL_ES_TYPE_AUDIO, 0},
+  {"audio/raw", MMAL_ENCODING_PCM_SIGNED, MMAL_ES_TYPE_AUDIO, 0},
+  {"", MMAL_ENCODING_PCM_SIGNED, MMAL_ES_TYPE_AUDIO, 0},
+  { 0, 0, MMAL_ES_TYPE_UNKNOWN, 0}
+};
+
+static const char *encoding_to_mime(MMAL_ES_TYPE_T type, MMAL_FOURCC_T encoding,
+   MMAL_FOURCC_T encoding_variant)
+{
+   struct encoding_table_t *entry = encoding_list;
+
+   for (entry = encoding_list; entry->mime; entry++)
+      if (entry->encoding == encoding && entry->type == type &&
+          entry->encoding_variant == encoding_variant)
+         break;
+
+   return entry->mime;
+}
+
+static void mime_to_encoding(const char *mime,
+   MMAL_ES_TYPE_T *type, MMAL_FOURCC_T *encoding, MMAL_FOURCC_T *encoding_variant)
+{
+   struct encoding_table_t *entry = encoding_list;
+
+   for (entry = encoding_list; entry->mime; entry++)
+      if (!strcmp(mime, entry->mime))
+         break;
+
+   *encoding = entry->encoding;
+   *type = entry->type;
+   *encoding_variant = entry->encoding_variant;
+}
+
+/*****************************************************************************/
+
+/** Actual processing functions */
+static MMAL_BOOL_T amc_do_input_processing(MMAL_COMPONENT_T *component,
+   MMAL_BOOL_T *notification)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_PORT_T *port = component->input[0];
+   MMAL_PORT_MODULE_T *port_module = port->priv->module;
+   MMAL_BUFFER_HEADER_T *in;
+   status_t astatus;
+   size_t size, index;
+   uint32_t flags = 0;
+
+   in = mmal_queue_get(port_module->queue);
+
+   /* Get an input buffer from the codec. We dequeue input buffers even
+    * if we do not any data to process to make sure that we do not get
+    * flooded with notifications from the codec that buffers are
+    * available. */
+   if (port_module->dequeued->empty() || !in)
+   {
+      astatus = module->codec->dequeueInputBuffer(&index, 0ll);
+      if (astatus == OK)
+      {
+         LOG_TRACE("dequeueInputBuffer %i", index);
+         port_module->dequeued->push_back(index);
+      }
+      else if (astatus != -EAGAIN)
+      {
+         LOG_TRACE("dequeueInputBuffer failed (%i)", astatus);
+      }
+   }
+
+   /* Check whether we can process data */
+   if (!in)
+   {
+      return 0;
+   }
+   else if (port_module->dequeued->empty())
+   {
+      mmal_queue_put_back(port_module->queue, in);
+
+      /* We have data we want to process so request to be notified as soon
+       * as the codec is available to process it */
+      *notification |= MMAL_TRUE;
+
+      return 0;
+   }
+
+   /* We have some processing to do */
+
+   index = *port_module->dequeued->begin();
+   sp<ABuffer> inBuf = module->input_buffers.itemAt(index);
+   if (inBuf->capacity() < in->length)
+      LOG_ERROR("MediaCodec input buffer too small (%i/%i)",
+         (int)inBuf->capacity(), (int)in->length);
+   size = MMAL_MIN(inBuf->capacity(), in->length);
+
+   if (in->length)
+      memcpy(inBuf->data(), in->data + in->offset, size);
+   if (in->flags & MMAL_BUFFER_HEADER_FLAG_EOS)
+      flags |= MediaCodec::BUFFER_FLAG_EOS;
+   if (in->flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
+      flags |= MediaCodec::BUFFER_FLAG_SYNCFRAME;
+   if (in->flags & MMAL_BUFFER_HEADER_FLAG_CONFIG)
+      flags |= MediaCodec::BUFFER_FLAG_CODECCONFIG;
+
+   LOG_TRACE("queueInputBuffer %i %ibytes, %lldus", index, in->length, in->pts);
+   astatus = module->codec->queueInputBuffer(index, 0, size, in->pts, flags);
+   if (astatus != OK)
+   {
+      LOG_ERROR("queueInputBuffer failed (%i)", astatus);
+      mmal_event_error_send(component, MMAL_EIO);
+      module->status = MMAL_EIO;
+   }
+
+   /* Send buffers back */
+   in->length = 0;
+   mmal_port_buffer_header_callback(port, in);
+   port_module->dequeued->erase(port_module->dequeued->begin());
+
+   return 1;
+}
+
+static void amc_output_format_changed(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_PORT_T *port = component->output[0];
+   MMAL_EVENT_FORMAT_CHANGED_T *event;
+   MMAL_BUFFER_HEADER_T *buffer;
+   MMAL_STATUS_T status;
+   int32_t value;
+
+   sp<AMessage> format = new AMessage;
+   status_t astatus = module->codec->getOutputFormat(&format);
+   LOG_DEBUG("INFO_FORMAT_CHANGED (%i): %s", astatus,
+      format->debugString().c_str());
+
+   /* Get an event buffer */
+   status = mmal_port_event_get(port, &buffer, MMAL_EVENT_FORMAT_CHANGED);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("unable to get an event buffer");
+      return;
+   }
+   event = mmal_event_format_changed_get(buffer);
+
+   AString amime;
+   format->findString("mime", &amime);
+   mime_to_encoding(amime.c_str(),
+      &event->format->type, &event->format->encoding,
+      &event->format->encoding_variant);
+
+   switch (port->format->type)
+   {
+   case MMAL_ES_TYPE_VIDEO:
+      if (format->findInt32("width", &value))
+         event->format->es->video.width = value;
+      if (format->findInt32("height", &value))
+         event->format->es->video.height = value;
+      break;
+   case MMAL_ES_TYPE_AUDIO:
+      if (format->findInt32("channel-count", &value))
+         event->format->es->audio.channels = value;
+      if (format->findInt32("sample-rate", &value))
+         event->format->es->audio.sample_rate = value;
+      if (format->findInt32("bitrate", &value))
+         event->format->bitrate = value;
+      if (event->format->encoding == MMAL_ENCODING_PCM_SIGNED)
+         event->format->es->audio.bits_per_sample = 16;
+      break;
+   default:
+      break;
+   }
+
+   /* Work-around for the ril audio_render component which only supports
+    * power of 2 arrangements */
+   if (event->format->type == MMAL_ES_TYPE_AUDIO &&
+       event->format->encoding == MMAL_ENCODING_PCM_SIGNED)
+   {
+      port->priv->module->actual_channels = event->format->es->audio.channels;
+      if (event->format->es->audio.channels == 6)
+         event->format->es->audio.channels = 8;
+   }
+
+   /* Update current format */
+   mmal_format_copy(port->priv->module->format, event->format);
+
+   /* Pass on the buffer requirements */
+   event->buffer_num_min = port->buffer_num_min;
+   event->buffer_size_min = port->buffer_size_min;
+   event->buffer_size_recommended = port->buffer_size_recommended;
+   event->buffer_num_recommended = port->buffer_num_recommended;
+
+   mmal_port_event_send(port, buffer);
+}
+
+static MMAL_BOOL_T amc_do_output_processing(MMAL_COMPONENT_T *component,
+   MMAL_BOOL_T *notification)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_PORT_T *port_out = component->output[0];
+   MMAL_BUFFER_HEADER_T *out;
+   status_t astatus;
+   size_t size, offset, index;
+   int64_t pts;
+   uint32_t flags;
+
+   if (port_out->priv->module->needs_configuring)
+      return 0;
+
+   out = mmal_queue_get(port_out->priv->module->queue);
+   if (!out)
+   {
+      /* We do not want notifications in that case. We've already filled
+       * our output buffers so we should really wait to receive more
+       * output buffers before resuming the processing */
+      *notification = MMAL_FALSE;
+      return 0;
+   }
+   out->flags = 0;
+
+   astatus = module->codec->dequeueOutputBuffer(&index, &offset, &size, &pts, &flags, 0ll);
+   if (astatus != OK)
+   {
+      MMAL_BOOL_T do_more = 0;
+
+      switch (astatus)
+      {
+      case INFO_OUTPUT_BUFFERS_CHANGED:
+         LOG_DEBUG("INFO_OUTPUT_BUFFERS_CHANGED");
+         astatus = module->codec->getOutputBuffers(&module->output_buffers);
+         do_more = MMAL_TRUE;
+         break;
+      case INFO_FORMAT_CHANGED:
+         amc_output_format_changed(component);
+         port_out->priv->module->needs_configuring = 1;
+         do_more = MMAL_TRUE;
+         break;
+      case -EAGAIN:
+         /* We have data we want to process so request to be notified as soon
+          * as the codec is available to process it */
+         *notification |= MMAL_TRUE;
+         break;
+      default:
+         LOG_ERROR("dequeueOutputBuffer failed (%i)", astatus);
+      }
+
+      mmal_queue_put_back(port_out->priv->module->queue, out);
+      return do_more;
+   }
+
+   LOG_TRACE("dequeueOutputBuffer %i, %ibytes, %lldus, flags %x",
+      index, size, pts, flags);
+   sp<ABuffer> outBuf = module->output_buffers.itemAt(index);
+
+   out->flags = 0;
+   out->offset = 0;
+   out->pts = pts;
+   out->dts = 0;
+
+   if (flags & MediaCodec::BUFFER_FLAG_EOS)
+      out->flags |= MMAL_BUFFER_HEADER_FLAG_EOS;
+   if (flags & MediaCodec::BUFFER_FLAG_SYNCFRAME)
+      out->flags |= MMAL_BUFFER_HEADER_FLAG_KEYFRAME;
+   if (flags & MediaCodec::BUFFER_FLAG_CODECCONFIG)
+      out->flags |= MMAL_BUFFER_HEADER_FLAG_CONFIG;
+
+   if (out->alloc_size < size)
+      LOG_ERROR("MediaCodec output buffer too big (%i/%i)",
+         (int)out->alloc_size, (int)size);
+   size = MMAL_MIN(out->alloc_size, size);
+
+   /* Audio render only accepts power of 2 channel configurations */
+   if (port_out->format->type == MMAL_ES_TYPE_AUDIO &&
+       port_out->format->encoding == MMAL_ENCODING_PCM_SIGNED &&
+       port_out->priv->module->actual_channels !=
+          port_out->format->es->audio.channels)
+   {
+      unsigned int valid = port_out->priv->module->actual_channels * 2;
+      unsigned int pitch = port_out->format->es->audio.channels * 2;
+      uint8_t *src = outBuf->data() + offset;
+      uint8_t *dst = out->data;
+      unsigned int i;
+
+      size = size * port_out->format->es->audio.channels /
+         port_out->priv->module->actual_channels;
+      size = MMAL_MIN(out->alloc_size, size);
+      memset(dst, 0, size);
+      for (i = size / pitch; i; i--, src += valid, dst += pitch)
+         memcpy(dst, src, valid);
+   }
+   else if (size)
+      memcpy(out->data, outBuf->data() + offset, size);
+   out->length = size;
+
+   /* Send buffers back */
+   module->codec->releaseOutputBuffer(index);
+   mmal_port_buffer_header_callback(port_out, out);
+
+   return 1;
+}
+
+static MMAL_BOOL_T amc_do_processing(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_BOOL_T do_more, request_notification = MMAL_FALSE;
+
+   if (module->codec == NULL)
+      return 0;
+
+   /* Don't do anything if we've already seen an error */
+   if (module->status != MMAL_SUCCESS)
+      return 0;
+
+   do_more = amc_do_input_processing(component, &request_notification);
+   do_more |= amc_do_output_processing(component, &request_notification);
+
+   if (request_notification)
+      module->ahandler->requestNotification(module->codec);
+
+   return do_more;
+}
+
+/*****************************************************************************/
+static void amc_do_processing_loop(MMAL_COMPONENT_T *component)
+{
+   while (amc_do_processing(component));
+}
+
+/** Destroy a previously created component */
+static MMAL_STATUS_T amc_component_destroy(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   unsigned int i;
+
+   for(i = 0; i < component->input_num; i++)
+   {
+      if(component->input[i]->priv->module->queue)
+         mmal_queue_destroy(component->input[i]->priv->module->queue);
+      if(component->input[i]->priv->module->format)
+         mmal_format_free(component->input[i]->priv->module->format);
+      if(component->input[i]->priv->module->dequeued)
+         delete component->input[i]->priv->module->dequeued;
+   }
+   if(component->input_num)
+      mmal_ports_free(component->input, component->input_num);
+
+   for(i = 0; i < component->output_num; i++)
+   {
+      if(component->output[i]->priv->module->queue)
+         mmal_queue_destroy(component->output[i]->priv->module->queue);
+      if(component->output[i]->priv->module->format)
+         mmal_format_free(component->output[i]->priv->module->format);
+   }
+   if(component->output_num)
+      mmal_ports_free(component->output, component->output_num);
+
+   if (module->codec != NULL)
+   {
+      module->codec->stop();
+      module->codec->release();
+   }
+
+   module->alooper->unregisterHandler(module->ahandler->id());
+   module->alooper->stop();
+   delete module;
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T amc_codec_start(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_PORT_T *in = component->input[0];
+   sp<AMessage> format = new AMessage;
+   status_t astatus;
+   const char *mime;
+
+   mime = encoding_to_mime(in->format->type, in->format->encoding,
+      in->format->encoding_variant);
+   if (!mime)
+   {
+      LOG_ERROR("cannot match codec %4.4s(%4.4s) with a mime type",
+         (char *)&in->format->encoding, (char *)&in->format->encoding_variant);
+      return MMAL_EINVAL;
+   }
+
+   /* We need to restart MediaCodec when the codec type changes */
+   if (module->codec == NULL || mime != in->priv->module->mime)
+   {
+      LOG_DEBUG("creating codec for %s", mime);
+
+      /* Start by releasing any instance we've previously created */
+      if (module->codec != NULL)
+      {
+         module->codec->stop();
+         module->codec->release();
+      }
+
+      module->codec = MediaCodec::CreateByType(module->alooper, mime, false);
+      if (module->codec == NULL)
+      {
+         LOG_ERROR("cannot instantiate MediaCodec for mime: %s", mime);
+         return MMAL_EINVAL;
+      }
+
+      in->priv->module->mime = mime;
+      module->ahandler->reset();
+      LOG_TRACE("creation done");
+   }
+   /* When reusing an existing instance, we just need to stop it */
+   else
+   {
+      module->codec->stop();
+   }
+
+   /* Configure MediaCodec */
+   switch (in->format->type)
+   {
+   case MMAL_ES_TYPE_VIDEO:
+      format->setInt32("width", in->format->es->video.width);
+      format->setInt32("height", in->format->es->video.height);
+      if (in->format->es->video.frame_rate.num && in->format->es->video.frame_rate.den)
+         format->setFloat("frame-rate", in->format->es->video.frame_rate.num /
+                          (float)in->format->es->video.frame_rate.den);
+      break;
+   case MMAL_ES_TYPE_AUDIO:
+      format->setInt32("channel-count", in->format->es->audio.channels);
+      format->setInt32("sample-rate", in->format->es->audio.sample_rate);
+      format->setInt32("bitrate", in->format->bitrate);
+      break;
+   default:
+      break;
+   }
+
+   format->setString("mime", mime);
+
+   /* Handle the codec specific data */
+   if (in->format->extradata_size)
+   {
+      sp<ABuffer> csd = new ABuffer(in->format->extradata,
+         in->format->extradata_size);
+      csd->meta()->setInt32("csd", true);
+      csd->meta()->setInt64("timeUs", 0);
+      format->setBuffer("csd-0", csd);
+   }
+
+   /* Propagate the buffer size setting of the input port to the
+    * codec */
+   format->setInt32("max-input-size", in->buffer_size);
+
+   LOG_TRACE("configuring: %s", format->debugString().c_str());
+   astatus = module->codec->configure(format, NULL, NULL, 0);
+   if (astatus)
+   {
+      LOG_ERROR("configure failed (%i)", astatus);
+      return MMAL_EINVAL;
+   }
+
+   LOG_TRACE("starting");
+   astatus = module->codec->start();
+   if (astatus != OK)
+   {
+      LOG_ERROR("failed to start codec (%i)", astatus);
+      return MMAL_EINVAL;
+   }
+   LOG_TRACE("started");
+
+   return MMAL_SUCCESS;
+}
+
+/** Enable processing on a port */
+static MMAL_STATUS_T amc_input_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_STATUS_T status;
+   status_t astatus;
+   MMAL_PARAM_UNUSED(cb);
+
+   /* Make sure the format as been committed */
+   status = port->priv->pf_set_format(port);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("cannot commit port format (%i)", status);
+      return status;
+   }
+
+   status = amc_codec_start(component);
+   if (status != MMAL_SUCCESS)
+      return status;
+
+   astatus = module->codec->getInputBuffers(&module->input_buffers);
+   if (astatus != OK)
+   {
+      LOG_ERROR("failed to get codec input buffers (%i)", astatus);
+      return MMAL_EINVAL;
+   }
+
+   if (module->input_buffers.size())
+      LOG_TRACE("%i input buffers of size %i", module->input_buffers.size(),
+         module->input_buffers.itemAt(0)->capacity());
+
+   astatus = module->codec->getOutputBuffers(&module->output_buffers);
+   if (astatus != OK)
+   {
+      LOG_ERROR("failed to get codec output buffers (%i)", astatus);
+      return MMAL_EINVAL;
+   }
+
+   if (module->output_buffers.size())
+      LOG_TRACE("%i output buffers of size %i", module->output_buffers.size(),
+         module->output_buffers.itemAt(0)->capacity());
+
+   module->status = MMAL_SUCCESS;
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T amc_output_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
+{
+   MMAL_PARAM_UNUSED(port);
+   MMAL_PARAM_UNUSED(cb);
+   return MMAL_SUCCESS;
+}
+
+/** Flush a port */
+static MMAL_STATUS_T amc_port_flush(MMAL_PORT_T *port)
+{
+   MMAL_PORT_MODULE_T *port_module = port->priv->module;
+   MMAL_BUFFER_HEADER_T *buffer;
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   status_t astatus;
+
+   /* Flush buffers that our component is holding on to */
+   buffer = mmal_queue_get(port_module->queue);
+   while(buffer)
+   {
+      mmal_port_buffer_header_callback(port, buffer);
+      buffer = mmal_queue_get(port_module->queue);
+   }
+
+   if (port_module->dequeued)
+      port_module->dequeued->clear();
+
+   /* Flush codec itself */
+   if (port->type == MMAL_PORT_TYPE_INPUT && module->codec != NULL)
+   {
+      astatus = module->codec->flush();
+      if (astatus != OK)
+         LOG_ERROR("failed to flush codec (%i)", astatus);
+   }
+
+   return MMAL_SUCCESS;
+}
+
+/** Disable processing on a port */
+static MMAL_STATUS_T amc_port_disable(MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   status_t astatus;
+
+   if (port->type == MMAL_PORT_TYPE_INPUT)
+   {
+      astatus = module->codec->stop();
+      if (astatus != OK)
+         LOG_ERROR("failed to stop codec (%i)", astatus);
+      module->codec->release();
+      module->codec = NULL;
+   }
+
+   /* We just need to flush our internal queue */
+   return amc_port_flush(port);
+}
+
+/** Send a buffer header to a port */
+static MMAL_STATUS_T amc_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   mmal_queue_put(port->priv->module->queue, buffer);
+   mmal_component_action_trigger(port->component);
+   return MMAL_SUCCESS;
+}
+
+/** Set format on input port */
+static MMAL_STATUS_T amc_input_port_format_commit(MMAL_PORT_T *in)
+{
+   MMAL_STATUS_T status;
+   const char *mime;
+
+   if (in->is_enabled)
+      return MMAL_EINVAL;
+
+   if (!mmal_format_compare(in->format, in->priv->module->format))
+      return MMAL_SUCCESS;
+
+   mime = encoding_to_mime(in->format->type, in->format->encoding,
+      in->format->encoding_variant);
+   if (!mime)
+   {
+      LOG_ERROR("cannot match codec %4.4s(%4.4s) with a mime type",
+         (char *)&in->format->encoding, (char *)&in->format->encoding_variant);
+      return MMAL_EINVAL;
+   }
+
+   /* Note that the MediaCodec object is only created when the input
+    * port is enabled to avoid deadlocking when we're running inside an
+    * Android OMX component (you can't create an OMX odec instance while
+    * you're already instantiating one) */
+
+   status = mmal_format_full_copy(in->priv->module->format, in->format);
+   if (status != MMAL_SUCCESS)
+      return status;
+
+   /* No need to propagate anything to the output port since
+    * we'll generate a format change event for it later on */
+
+   return status;
+}
+
+/** Set format on output port */
+static MMAL_STATUS_T amc_output_port_format_commit(MMAL_PORT_T *out)
+{
+   /* The format of the output port needs to match the output of
+    * MediaCodec */
+   if (mmal_format_compare(out->format, out->priv->module->format))
+      return MMAL_EINVAL;
+
+   out->priv->module->needs_configuring = 0;
+   mmal_component_action_trigger(out->component);
+   return MMAL_SUCCESS;
+}
+
+/** Create an instance of a component  */
+static MMAL_STATUS_T mmal_component_create_android_media_codec(const char *name, MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module;
+   MMAL_STATUS_T status = MMAL_ENOMEM;
+   const char *variant_name = name + sizeof("amc");
+   unsigned int variant = AMC_VARIANT_UNKNOWN;
+
+   if (!strcmp(variant_name, AMC_VARIANT_AUDIO_DECODE_NAME))
+      variant = AMC_VARIANT_AUDIO_DECODE;
+
+   if (variant == AMC_VARIANT_UNKNOWN)
+   {
+      LOG_ERROR("unsupported variant %s", variant_name);
+      return MMAL_ENOENT;
+   }
+
+   /* Allocate the context for our module */
+   component->priv->module = module = new MMAL_COMPONENT_MODULE_T;
+   if (!module)
+      return MMAL_ENOMEM;
+
+   component->priv->pf_destroy = amc_component_destroy;
+   module->status = MMAL_SUCCESS;
+   ProcessState::self()->startThreadPool();
+   module->ahandler = new AmcHandler(component);
+   module->alooper = new ALooper;
+   module->alooper->setName("amc_looper");
+   module->alooper->registerHandler(module->ahandler);
+   module->alooper->start(false);
+
+   /* Allocate and initialise all the ports for this component */
+   component->input = mmal_ports_alloc(component, 1, MMAL_PORT_TYPE_INPUT, sizeof(MMAL_PORT_MODULE_T));
+   if(!component->input)
+      goto error;
+   component->input_num = 1;
+   component->input[0]->priv->pf_enable = amc_input_port_enable;
+   component->input[0]->priv->pf_disable = amc_port_disable;
+   component->input[0]->priv->pf_flush = amc_port_flush;
+   component->input[0]->priv->pf_send = amc_port_send;
+   component->input[0]->priv->pf_set_format = amc_input_port_format_commit;
+   component->input[0]->buffer_num_min = 1;
+   component->input[0]->buffer_num_recommended = 3;
+   component->input[0]->priv->module->queue = mmal_queue_create();
+   if(!component->input[0]->priv->module->queue)
+      goto error;
+   component->input[0]->priv->module->format = mmal_format_alloc();
+   if(!component->input[0]->priv->module->format)
+      goto error;
+   component->input[0]->priv->module->dequeued = new List<size_t>;
+   if(!component->input[0]->priv->module->dequeued)
+      goto error;
+
+   component->output = mmal_ports_alloc(component, 1, MMAL_PORT_TYPE_OUTPUT, sizeof(MMAL_PORT_MODULE_T));
+   if(!component->output)
+      goto error;
+   component->output_num = 1;
+   component->output[0]->priv->pf_enable = amc_output_port_enable;
+   component->output[0]->priv->pf_disable = amc_port_disable;
+   component->output[0]->priv->pf_flush = amc_port_flush;
+   component->output[0]->priv->pf_send = amc_port_send;
+   component->output[0]->priv->pf_set_format = amc_output_port_format_commit;
+   component->output[0]->buffer_num_min = 1;
+   component->output[0]->buffer_num_recommended = 3;
+   component->output[0]->priv->module->queue = mmal_queue_create();
+   if(!component->output[0]->priv->module->queue)
+      goto error;
+   component->output[0]->priv->module->format = mmal_format_alloc();
+   if(!component->output[0]->priv->module->format)
+      goto error;
+
+   status = mmal_component_action_register(component, amc_do_processing_loop);
+   if (status != MMAL_SUCCESS)
+      goto error;
+
+   /* Setup ports according to selected variant */
+   if (variant == AMC_VARIANT_AUDIO_DECODE)
+   {
+      component->input[0]->format->type = MMAL_ES_TYPE_AUDIO;
+      component->input[0]->format->encoding = MMAL_ENCODING_EAC3;
+      component->input[0]->format->es->audio.sample_rate = 48000;
+      component->input[0]->format->es->audio.channels = 2;
+      component->input[0]->buffer_size_min = 4 * 1024;
+
+      component->output[0]->format->type = MMAL_ES_TYPE_AUDIO;
+      component->output[0]->format->encoding = MMAL_ENCODING_PCM_SIGNED;
+      component->output[0]->format->es->audio.sample_rate = 48000;
+      component->output[0]->format->es->audio.channels = 2;
+      component->output[0]->format->es->audio.bits_per_sample = 16;
+      component->output[0]->buffer_size_min = 32 * 1024;
+   }
+
+   /* Update our current view of the output format */
+   mmal_format_copy(component->output[0]->priv->module->format,
+      component->output[0]->format);
+
+   return MMAL_SUCCESS;
+
+ error:
+   amc_component_destroy(component);
+   return status;
+}
+
+MMAL_CONSTRUCTOR(mmal_register_component_android_media_codec);
+void mmal_register_component_android_media_codec(void)
+{
+   mmal_component_supplier_register("amc", mmal_component_create_android_media_codec);
+}
diff --git a/interface/mmal/components/artificial_camera.c b/interface/mmal/components/artificial_camera.c
new file mode 100755 (executable)
index 0000000..e883f53
--- /dev/null
@@ -0,0 +1,287 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "core/mmal_component_private.h"
+#include "core/mmal_port_private.h"
+#include "mmal_logging.h"
+
+#define ARTIFICIAL_CAMERA_PORTS_NUM 3
+
+/* Buffering requirements */
+#define OUTPUT_MIN_BUFFER_NUM 1
+#define OUTPUT_RECOMMENDED_BUFFER_NUM 4
+
+#define DEFAULT_WIDTH 320
+#define DEFAULT_HEIGHT 240
+
+/*****************************************************************************/
+typedef struct MMAL_PORT_MODULE_T
+{
+   MMAL_BUFFER_HEADER_VIDEO_SPECIFIC_T frame;
+   unsigned int frame_size;
+   int count;
+
+   MMAL_QUEUE_T *queue;
+
+} MMAL_PORT_MODULE_T;
+
+typedef struct MMAL_COMPONENT_MODULE_T
+{
+   MMAL_STATUS_T status;
+
+} MMAL_COMPONENT_MODULE_T;
+
+/*****************************************************************************/
+static void artificial_camera_do_processing(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_BUFFER_HEADER_T *buffer;
+   unsigned int i;
+
+   if (module->status != MMAL_SUCCESS)
+      return;
+
+   /* Loop through all the ports */
+   for (i = 0; i < component->output_num; i++)
+   {
+      MMAL_PORT_T *port = component->output[i];
+
+      buffer = mmal_queue_get(port->priv->module->queue);
+      if (!buffer)
+         continue;
+
+      /* Sanity check the buffer size */
+      if (buffer->alloc_size < port->priv->module->frame_size)
+      {
+         LOG_ERROR("buffer too small (%i/%i)",
+                   buffer->alloc_size, port->priv->module->frame_size);
+         module->status = MMAL_EINVAL;
+         mmal_queue_put_back(port->priv->module->queue, buffer);
+         mmal_event_error_send(component, module->status);
+         return;
+      }
+      module->status = mmal_buffer_header_mem_lock(buffer);
+      if (module->status != MMAL_SUCCESS)
+      {
+         LOG_ERROR("invalid buffer (%p, %p)", buffer, buffer->data);
+         mmal_queue_put_back(port->priv->module->queue, buffer);
+         mmal_event_error_send(component, module->status);
+         return;
+      }
+
+      buffer->offset = 0;
+      buffer->length = port->priv->module->frame_size;
+      buffer->type->video = port->priv->module->frame;
+
+      memset(buffer->data, 0xff, buffer->length);
+      if (buffer->type->video.planes > 1)
+         memset(buffer->data + buffer->type->video.offset[1],
+                0x7f - port->priv->module->count++,
+                buffer->length - buffer->type->video.offset[1]);
+
+      mmal_buffer_header_mem_unlock(buffer);
+      mmal_port_buffer_header_callback(port, buffer);
+   }
+
+   vcos_sleep(10); /* Make sure we don't peg all the resources */
+}
+
+/** Destroy a previously created component */
+static MMAL_STATUS_T artificial_camera_component_destroy(MMAL_COMPONENT_T *component)
+{
+   unsigned int i;
+
+   for (i = 0; i < component->output_num; i++)
+      if (component->output[i]->priv->module->queue)
+         mmal_queue_destroy(component->output[i]->priv->module->queue);
+
+   if(component->output_num)
+      mmal_ports_free(component->output, component->output_num);
+
+   vcos_free(component->priv->module);
+   return MMAL_SUCCESS;
+}
+
+/** Enable processing on a port */
+static MMAL_STATUS_T artificial_camera_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
+{
+   MMAL_PARAM_UNUSED(port);
+   MMAL_PARAM_UNUSED(cb);
+   return MMAL_SUCCESS;
+}
+
+/** Flush a port */
+static MMAL_STATUS_T artificial_camera_port_flush(MMAL_PORT_T *port)
+{
+   MMAL_PARAM_UNUSED(port);
+   return MMAL_SUCCESS;
+}
+
+/** Disable processing on a port */
+static MMAL_STATUS_T artificial_camera_port_disable(MMAL_PORT_T *port)
+{
+   MMAL_PARAM_UNUSED(port);
+   return MMAL_SUCCESS;
+}
+
+/** Send a buffer header to a port */
+static MMAL_STATUS_T artificial_camera_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   /* Just queue the buffer */
+   mmal_queue_put(port->priv->module->queue, buffer);
+   mmal_component_action_trigger(port->component);
+   return MMAL_SUCCESS;
+}
+
+/** Set format on a port */
+static MMAL_STATUS_T artificial_camera_port_format_commit(MMAL_PORT_T *port)
+{
+   MMAL_PORT_MODULE_T *port_module = port->priv->module;
+   unsigned int width = port->format->es->video.width;
+   unsigned int height = port->format->es->video.height;
+   width = (width + 31) & ~31;
+   height = (height + 15) & ~15;
+
+   /* We only support a few formats */
+   switch(port->format->encoding)
+   {
+   case MMAL_ENCODING_I420:
+      port_module->frame_size = width * height * 3 / 2;
+      port_module->frame.planes = 3;
+      port_module->frame.pitch[0] = width;
+      port_module->frame.offset[1] = port_module->frame.pitch[0] * height;
+      port_module->frame.pitch[1] = width / 2;
+      port_module->frame.offset[2] = port_module->frame.offset[1] + port_module->frame.pitch[1] * height / 2;
+      port_module->frame.pitch[2] = width / 2;
+      break;
+   case MMAL_ENCODING_NV21:
+      port_module->frame_size = width * height * 3 / 2;
+      port_module->frame.planes = 2;
+      port_module->frame.pitch[0] = width;
+      port_module->frame.offset[1] = port_module->frame.pitch[0] * height;
+      port_module->frame.pitch[1] = width;
+      break;
+   case MMAL_ENCODING_I422:
+      port_module->frame_size = width * height * 2;
+      port_module->frame.planes = 3;
+      port_module->frame.pitch[0] = width;
+      port_module->frame.offset[1] = port_module->frame.pitch[0] * height;
+      port_module->frame.pitch[1] = width / 2;
+      port_module->frame.offset[2] = port_module->frame.offset[1] + port_module->frame.pitch[1] * height;
+      port_module->frame.pitch[2] = width / 2;
+      break;
+   default:
+      return MMAL_ENOSYS;
+   }
+
+   port->buffer_size_min = port->buffer_size_recommended = port_module->frame_size;
+   return MMAL_SUCCESS;
+}
+
+/** Set parameter on a port */
+static MMAL_STATUS_T artificial_port_parameter_set(MMAL_PORT_T *port, const MMAL_PARAMETER_HEADER_T *param)
+{
+   MMAL_PARAM_UNUSED(port);
+   switch (param->id)
+   {
+   default:
+      return MMAL_ENOSYS;
+   }
+}
+
+/** Get parameter on a port */
+static MMAL_STATUS_T artificial_port_parameter_get(MMAL_PORT_T *port, MMAL_PARAMETER_HEADER_T *param)
+{
+   MMAL_PARAM_UNUSED(port);
+   switch (param->id)
+   {
+   default:
+      return MMAL_ENOSYS;
+   }
+}
+
+/** Create an instance of a component  */
+static MMAL_STATUS_T mmal_component_create_artificial_camera(const char *name, MMAL_COMPONENT_T *component)
+{
+   MMAL_STATUS_T status = MMAL_ENOMEM;
+   unsigned int i;
+   MMAL_PARAM_UNUSED(name);
+
+   /* Allocate our module context */
+   component->priv->module = vcos_calloc(1, sizeof(*component->priv->module), "mmal module");
+   if (!component->priv->module)
+      return MMAL_ENOMEM;
+
+   component->priv->pf_destroy = artificial_camera_component_destroy;
+
+   /* Allocate all the ports for this component */
+   component->output = mmal_ports_alloc(component, ARTIFICIAL_CAMERA_PORTS_NUM, MMAL_PORT_TYPE_OUTPUT,
+                                        sizeof(MMAL_PORT_MODULE_T));
+   if(!component->output)
+      goto error;
+   component->output_num = ARTIFICIAL_CAMERA_PORTS_NUM;
+
+   for (i = 0; i < component->output_num; i++)
+   {
+      component->output[i]->priv->pf_enable = artificial_camera_port_enable;
+      component->output[i]->priv->pf_disable = artificial_camera_port_disable;
+      component->output[i]->priv->pf_flush = artificial_camera_port_flush;
+      component->output[i]->priv->pf_send = artificial_camera_port_send;
+      component->output[i]->priv->pf_send = artificial_camera_port_send;
+      component->output[i]->priv->pf_set_format = artificial_camera_port_format_commit;
+      component->output[i]->priv->pf_parameter_set = artificial_port_parameter_set;
+      component->output[i]->priv->pf_parameter_get = artificial_port_parameter_get;
+      component->output[i]->format->type = MMAL_ES_TYPE_VIDEO;
+      component->output[i]->format->encoding = MMAL_ENCODING_I420;
+      component->output[i]->format->es->video.width = DEFAULT_WIDTH;
+      component->output[i]->format->es->video.height = DEFAULT_HEIGHT;
+      component->output[i]->buffer_num_min = OUTPUT_MIN_BUFFER_NUM;
+      component->output[i]->buffer_num_recommended = OUTPUT_RECOMMENDED_BUFFER_NUM;
+      artificial_camera_port_format_commit(component->output[i]);
+
+      component->output[i]->priv->module->queue = mmal_queue_create();
+      if (!component->output[i]->priv->module->queue)
+         goto error;
+   }
+
+   status = mmal_component_action_register(component, artificial_camera_do_processing);
+   if (status != MMAL_SUCCESS)
+      goto error;
+
+   return MMAL_SUCCESS;
+
+ error:
+   artificial_camera_component_destroy(component);
+   return status;
+}
+
+MMAL_CONSTRUCTOR(mmal_register_component_artificial_camera);
+void mmal_register_component_artificial_camera(void)
+{
+   mmal_component_supplier_register("artificial_camera", mmal_component_create_artificial_camera);
+}
diff --git a/interface/mmal/components/avcodec_audio_decoder.c b/interface/mmal/components/avcodec_audio_decoder.c
new file mode 100755 (executable)
index 0000000..20f6192
--- /dev/null
@@ -0,0 +1,607 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "core/mmal_component_private.h"
+#include "core/mmal_port_private.h"
+#include "mmal_logging.h"
+
+#include "libavcodec/avcodec.h"
+#include "libavutil/mathematics.h"
+#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT( 52, 23, 0 )
+# include "libavformat/avformat.h"
+ static AVPacket null_packet = {AV_NOPTS_VALUE, AV_NOPTS_VALUE};
+# define av_init_packet(a) *(a) = null_packet
+#endif
+
+#if LIBAVCODEC_VERSION_MAJOR < 53
+# define avcodec_decode_audio3(a,b,c,d) avcodec_decode_audio2(a,b,c,(d)->data,(d)->size)
+#endif
+
+#if LIBAVCODEC_VERSION_MAJOR < 54
+#define AVSampleFormat      SampleFormat
+#define AV_SAMPLE_FMT_NONE  SAMPLE_FMT_NONE
+#define AV_SAMPLE_FMT_U8    SAMPLE_FMT_U8
+#define AV_SAMPLE_FMT_S16   SAMPLE_FMT_S16
+#define AV_SAMPLE_FMT_S32   SAMPLE_FMT_S32
+#define AV_SAMPLE_FMT_FLT   SAMPLE_FMT_FLT
+#define AV_SAMPLE_FMT_DBL   SAMPLE_FMT_DBL
+#endif
+
+/* Buffering requirements */
+#define INPUT_MIN_BUFFER_SIZE (4*1024)
+#define INPUT_MIN_BUFFER_NUM 1
+#define INPUT_RECOMMENDED_BUFFER_SIZE INPUT_MIN_BUFFER_SIZE
+#define INPUT_RECOMMENDED_BUFFER_NUM 10
+#define OUTPUT_MIN_BUFFER_NUM 1
+#define OUTPUT_RECOMMENDED_BUFFER_NUM 4
+#define OUTPUT_MIN_BUFFER_SIZE 512
+#define OUTPUT_RECOMMENDED_BUFFER_SIZE 4096
+
+static uint32_t encoding_to_codecid(uint32_t encoding);
+static uint32_t samplefmt_to_encoding(enum AVSampleFormat);
+static unsigned int samplefmt_to_sample_size(enum AVSampleFormat samplefmt);
+
+/****************************/
+typedef struct MMAL_COMPONENT_MODULE_T
+{
+   MMAL_STATUS_T status;
+
+   MMAL_QUEUE_T *queue_in;
+   MMAL_QUEUE_T *queue_out;
+
+   int64_t pts;
+
+   int64_t last_pts;
+   int64_t samples_since_last_pts;
+
+   int output_buffer_size;
+   uint8_t *output_buffer;
+
+   uint8_t *output;
+   int output_size;
+   AVCodecContext *codec_context;
+   AVCodec *codec;
+
+   enum AVSampleFormat sample_fmt;
+   int channels;
+   int sample_rate;
+   int bits_per_sample;
+
+   MMAL_BOOL_T output_needs_configuring;
+
+} MMAL_COMPONENT_MODULE_T;
+
+/** Destroy a previously created component */
+static MMAL_STATUS_T avcodec_component_destroy(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+
+   if (module->codec_context)
+   {
+      if (module->codec_context->extradata)
+         vcos_free(module->codec_context->extradata);
+      if (module->codec_context->codec)
+         avcodec_close(module->codec_context);
+      av_free(module->codec_context);
+   }
+   if (module->output_buffer)
+      av_free(module->output_buffer);
+
+   if (module->queue_in)
+      mmal_queue_destroy(module->queue_in);
+   if (module->queue_out)
+      mmal_queue_destroy(module->queue_out);
+   vcos_free(module);
+   if (component->input_num)
+      mmal_ports_free(component->input, 1);
+   if (component->output_num)
+      mmal_ports_free(component->output, 1);
+   return MMAL_SUCCESS;
+}
+
+/** Set format on a port */
+static MMAL_STATUS_T avcodec_input_port_set_format(MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   enum CodecID codec_id;
+   AVCodec *codec;
+
+   codec_id = encoding_to_codecid(port->format->encoding);
+   if (codec_id == CODEC_ID_NONE ||
+       !(codec = avcodec_find_decoder(codec_id)))
+   {
+      LOG_ERROR("ffmpeg codec id %d (for %4.4s) not recognized",
+                codec_id, (char *)&port->format->encoding);
+      return MMAL_ENXIO;
+   }
+
+   module->output_buffer_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
+   if (module->output_buffer)
+      av_free(module->output_buffer);
+   module->output_buffer = av_malloc(module->output_buffer_size);
+
+   module->codec_context->sample_rate  = port->format->es->audio.sample_rate;
+   module->codec_context->channels  = port->format->es->audio.channels;
+   module->codec_context->block_align = port->format->es->audio.block_align;
+   module->codec_context->bit_rate = port->format->bitrate;
+   module->codec_context->bits_per_coded_sample = port->format->es->audio.bits_per_sample;
+   module->codec_context->extradata_size  = port->format->extradata_size;
+   module->codec_context->extradata =
+      vcos_calloc(1, port->format->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE,
+                  "avcodec extradata");
+   if (module->codec_context->extradata)
+      memcpy(module->codec_context->extradata, port->format->extradata,
+             port->format->extradata_size);
+
+   if (codec->capabilities & CODEC_CAP_TRUNCATED)
+      module->codec_context->flags |= CODEC_FLAG_TRUNCATED;
+
+   if (avcodec_open(module->codec_context, codec) < 0)
+   {
+      LOG_ERROR("could not open codec");
+      return MMAL_EIO;
+   }
+
+   /* Set a default format */
+   if (module->codec_context->sample_fmt == AV_SAMPLE_FMT_NONE)
+      module->codec_context->sample_fmt = AV_SAMPLE_FMT_S16;
+
+   /* Copy format to output */
+   mmal_format_copy(component->output[0]->format, port->format);
+   LOG_DEBUG("avcodec output format %i", module->codec_context->sample_fmt);
+   component->output[0]->format->encoding = samplefmt_to_encoding(module->codec_context->sample_fmt);
+   component->output[0]->format->es->audio.bits_per_sample =
+      samplefmt_to_sample_size(module->codec_context->sample_fmt);
+
+   component->output[0]->priv->pf_set_format(component->output[0]);
+   return MMAL_SUCCESS;
+}
+
+/** Set format on a port */
+static MMAL_STATUS_T avcodec_output_port_set_format(MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+
+   /* Format can only be set to what is output by the codec */
+   if (samplefmt_to_encoding(module->codec_context->sample_fmt) != port->format->encoding ||
+       samplefmt_to_sample_size(module->codec_context->sample_fmt) != port->format->es->audio.bits_per_sample)
+      return MMAL_EINVAL;
+
+   if (!port->format->es->audio.sample_rate || !port->format->es->audio.channels)
+      return MMAL_EINVAL;
+
+   module->sample_fmt = module->codec_context->sample_fmt;
+   module->sample_rate = port->format->es->audio.sample_rate;
+   module->channels = port->format->es->audio.channels;
+   module->bits_per_sample = port->format->es->audio.bits_per_sample;
+
+   port->component->priv->module->output_needs_configuring = 0;
+   mmal_component_action_trigger(port->component);
+
+   return MMAL_SUCCESS;
+}
+
+/** Enable processing on a port */
+static MMAL_STATUS_T avcodec_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
+{
+   MMAL_PARAM_UNUSED(port);
+   MMAL_PARAM_UNUSED(cb);
+   return MMAL_SUCCESS;
+}
+
+/** Flush a port */
+static MMAL_STATUS_T avcodec_port_flush(MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_BUFFER_HEADER_T *buffer;
+   MMAL_QUEUE_T *queue;
+
+   if(port->type == MMAL_PORT_TYPE_OUTPUT)
+      queue = module->queue_out;
+   else if(port->type == MMAL_PORT_TYPE_INPUT)
+      queue = module->queue_in;
+   else
+      return MMAL_EINVAL;
+
+   /* Flush buffers that our component is holding on to.
+    * If the reading thread is holding onto a buffer it will send it back ASAP as well
+    * so no need to care about that.  */
+   while((buffer = mmal_queue_get(queue)))
+      mmal_port_buffer_header_callback(port, buffer);
+
+   return MMAL_SUCCESS;
+}
+
+/** Disable processing on a port */
+static MMAL_STATUS_T avcodec_port_disable(MMAL_PORT_T *port)
+{
+   MMAL_STATUS_T status;
+
+   /* Actions are prevented from running at that point so a flush
+    * will return all buffers. */
+   status = avcodec_port_flush(port);
+   if(status != MMAL_SUCCESS)
+      return status;
+
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+static void avcodec_send_event_format_changed(MMAL_COMPONENT_T *component, MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_BUFFER_HEADER_T *buffer = NULL;
+   MMAL_EVENT_FORMAT_CHANGED_T *event;
+
+   /* Get an event buffer */
+   module->status = mmal_port_event_get(port, &buffer, MMAL_EVENT_FORMAT_CHANGED);
+   if (module->status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("unable to get an event buffer");
+      return;
+   }
+   event = mmal_event_format_changed_get(buffer);
+
+   /* Fill in the new format */
+   mmal_format_copy(event->format, port->format);
+   event->format->es->audio.sample_rate = module->codec_context->sample_rate;
+   event->format->es->audio.channels = module->codec_context->channels;
+   event->format->encoding = samplefmt_to_encoding(module->codec_context->sample_fmt);
+   event->format->es->audio.bits_per_sample = samplefmt_to_sample_size(module->codec_context->sample_fmt);
+
+   /* Pass on the buffer requirements */
+   event->buffer_num_min = port->buffer_num_min;
+   event->buffer_size_min = port->buffer_size_min;
+   event->buffer_size_recommended = event->buffer_size_min;
+   event->buffer_num_recommended = port->buffer_num_recommended;
+
+   module->output_needs_configuring = 1;
+   mmal_port_event_send(port, buffer);
+}
+
+/*****************************************************************************/
+static MMAL_STATUS_T avcodec_send_eos(MMAL_COMPONENT_T *component, MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_BUFFER_HEADER_T *out = mmal_queue_get(module->queue_out);
+
+   if (!out)
+      return MMAL_EAGAIN;
+
+   out->length = 0;
+   out->flags = MMAL_BUFFER_HEADER_FLAG_EOS;
+   mmal_port_buffer_header_callback(port, out);
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+static MMAL_STATUS_T avcodec_send_frame(MMAL_COMPONENT_T *component, MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_BUFFER_HEADER_T *out;
+   int size, samples;
+
+   /* Detect format changes */
+   if (module->codec_context->channels != module->channels ||
+       module->codec_context->sample_rate != module->sample_rate ||
+       module->codec_context->sample_fmt != module->sample_fmt)
+   {
+      avcodec_send_event_format_changed(component, port);
+      return MMAL_EAGAIN;
+   }
+
+   out = mmal_queue_get(module->queue_out);
+   if (!out)
+      return MMAL_EAGAIN;
+
+   size = module->output_size;
+   if (size > (int)out->alloc_size)
+      size = out->alloc_size;
+
+   samples = size / module->channels * 8 / module->bits_per_sample;
+   size = samples * module->channels * module->bits_per_sample / 8;
+   out->length = size;
+   out->pts    = module->pts;
+   out->flags  = 0;
+   memcpy(out->data, module->output, size);
+   module->output_size -= size;
+   module->output += size;
+
+   if (module->pts != MMAL_TIME_UNKNOWN)
+   {
+      module->last_pts = module->pts;
+      module->samples_since_last_pts = 0;
+   }
+   module->pts = MMAL_TIME_UNKNOWN;
+   module->samples_since_last_pts += samples;
+
+   if (out->pts == MMAL_TIME_UNKNOWN)
+      out->pts = module->last_pts + module->samples_since_last_pts * 1000000 / module->sample_rate;
+
+   out->dts = out->pts;
+   mmal_port_buffer_header_callback(port, out);
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+static MMAL_BOOL_T avaudio_do_processing(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_PORT_T *port_in = component->input[0];
+   MMAL_PORT_T *port_out = component->output[0];
+   MMAL_BUFFER_HEADER_T *in;
+   AVPacket avpkt;
+   int used = 0;
+
+   if (module->output_needs_configuring)
+      return 0;
+
+   if (module->output_size &&
+       avcodec_send_frame(component, port_out) != MMAL_SUCCESS)
+      return 0;
+   if (module->output_size)
+      return 1;
+
+   /* Get input buffer to decode */
+   in = mmal_queue_get(module->queue_in);
+   if (!in)
+      return 0;
+
+   /* Discard empty buffers. EOS buffers are not discarded since they will be used
+    * to flush the codec. */
+   if (!in->length && !(in->flags & MMAL_BUFFER_HEADER_FLAG_EOS))
+      goto end;
+
+   /* Avcodec expects padded input data */
+   if (in->length && !in->offset)
+   {
+      if(in->length + FF_INPUT_BUFFER_PADDING_SIZE <= in->alloc_size)
+         memset(in->data + in->length, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+      else
+         LOG_WARN("could not pad buffer"); // Try to decode the data anyway
+   }
+
+   /* The actual decoding */
+   av_init_packet(&avpkt);
+   avpkt.data = in->length ? in->data + in->offset : 0;
+   avpkt.size = in->length;
+   module->output_size = module->output_buffer_size;
+   module->output = module->output_buffer;
+   used = avcodec_decode_audio3(module->codec_context, (int16_t*)module->output,
+                                &module->output_size, &avpkt);
+
+   /* Check for errors */
+   if (used < 0 || used > (int)in->length)
+   {
+      LOG_ERROR("decoding failed (%i), discarding buffer", used);
+      used = in->length;
+   }
+
+   module->pts = in->dts;
+   if (module->pts == MMAL_TIME_UNKNOWN)
+      module->pts = in->pts;
+
+ end:
+   in->offset += used;
+   in->length -= used;
+
+   if (in->length)
+   {
+      mmal_queue_put_back(module->queue_in, in);
+      return 1;
+   }
+
+   /* We want to keep the EOS buffer until all the frames have been flushed */
+   if ((in->flags & MMAL_BUFFER_HEADER_FLAG_EOS) &&
+       module->output_size)
+   {
+      mmal_queue_put_back(module->queue_in, in);
+      return 1;
+   }
+
+   /* Send EOS */
+   if ((in->flags & MMAL_BUFFER_HEADER_FLAG_EOS) &&
+       avcodec_send_eos(component, port_out) != MMAL_SUCCESS)
+   {
+      mmal_queue_put_back(module->queue_in, in);
+      return 0;
+   }
+
+   in->offset = 0;
+   mmal_port_buffer_header_callback(port_in, in);
+   return 1;
+}
+
+/*****************************************************************************/
+static void avcodec_do_processing_loop(MMAL_COMPONENT_T *component)
+{
+   while (avaudio_do_processing(component));
+}
+
+/** Buffer sending */
+static MMAL_STATUS_T avcodec_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+
+   if(port->type == MMAL_PORT_TYPE_OUTPUT) mmal_queue_put(module->queue_out, buffer);
+   if(port->type == MMAL_PORT_TYPE_INPUT) mmal_queue_put(module->queue_in, buffer);
+   mmal_component_action_trigger(port->component);
+
+   return MMAL_SUCCESS;
+}
+
+/** Create an instance of a component  */
+static MMAL_STATUS_T mmal_component_create_avcodec(const char *name, MMAL_COMPONENT_T *component)
+{
+   MMAL_STATUS_T status = MMAL_ENOMEM;
+   MMAL_COMPONENT_MODULE_T *module;
+
+   /* Check we're the requested component */
+   if(strcmp(name, "avcodec." MMAL_AUDIO_DECODE))
+      return MMAL_ENOENT;
+
+   /* Allocate our module context */
+   component->priv->module = module = vcos_calloc(1, sizeof(*module), "mmal module");
+   if(!module)
+      return MMAL_ENOENT;
+
+   /* Allocate the ports for this component */
+   component->input = mmal_ports_alloc(component, 1, MMAL_PORT_TYPE_INPUT, 0);
+   if(!component->input) goto error;
+   component->input_num = 1;
+   component->output = mmal_ports_alloc(component, 1, MMAL_PORT_TYPE_OUTPUT, 0);
+   if(!component->output) goto error;
+   component->output_num = 1;
+
+   module->queue_in = mmal_queue_create();
+   if(!module->queue_in) goto error;
+   module->queue_out = mmal_queue_create();
+   if(!module->queue_out) goto error;
+
+   module->codec_context = avcodec_alloc_context();
+   if(!module->codec_context) goto error;
+
+   component->input[0]->priv->pf_set_format = avcodec_input_port_set_format;
+   component->input[0]->priv->pf_enable = avcodec_port_enable;
+   component->input[0]->priv->pf_disable = avcodec_port_disable;
+   component->input[0]->priv->pf_flush = avcodec_port_flush;
+   component->input[0]->priv->pf_send = avcodec_port_send;
+   component->input[0]->buffer_num_min = INPUT_MIN_BUFFER_NUM;
+   component->input[0]->buffer_num_recommended = INPUT_RECOMMENDED_BUFFER_NUM;
+   component->input[0]->buffer_size_min = INPUT_MIN_BUFFER_SIZE;
+   component->input[0]->buffer_size_recommended = INPUT_RECOMMENDED_BUFFER_SIZE;
+
+   component->output[0]->priv->pf_set_format = avcodec_output_port_set_format;
+   component->output[0]->priv->pf_enable = avcodec_port_enable;
+   component->output[0]->priv->pf_disable = avcodec_port_disable;
+   component->output[0]->priv->pf_disable = avcodec_port_flush;
+   component->output[0]->priv->pf_send = avcodec_port_send;
+   component->output[0]->buffer_num_min = OUTPUT_MIN_BUFFER_NUM;
+   component->output[0]->buffer_num_recommended = OUTPUT_RECOMMENDED_BUFFER_NUM;
+   component->output[0]->buffer_size_min = OUTPUT_MIN_BUFFER_SIZE;
+   component->output[0]->buffer_size_recommended = OUTPUT_RECOMMENDED_BUFFER_SIZE;
+
+   component->output[0]->format->type = MMAL_ES_TYPE_AUDIO;
+   component->output[0]->format->encoding = MMAL_ENCODING_PCM_SIGNED_LE;
+
+   component->priv->pf_destroy = avcodec_component_destroy;
+
+   status = mmal_component_action_register(component, avcodec_do_processing_loop);
+   if (status != MMAL_SUCCESS)
+      goto error;
+
+   return MMAL_SUCCESS;
+
+ error:
+   avcodec_component_destroy(component);
+   return status;
+}
+
+static struct {
+   uint32_t encoding;
+   int codecid;
+} codec_to_encoding_table[] =
+{
+   {MMAL_ENCODING_MP4A,            CODEC_ID_AAC},
+   {MMAL_ENCODING_MPGA,            CODEC_ID_MP3},
+   {MMAL_ENCODING_ALAW,            CODEC_ID_PCM_ALAW},
+   {MMAL_ENCODING_MULAW,           CODEC_ID_PCM_MULAW},
+   {MMAL_ENCODING_ADPCM_MS,        CODEC_ID_ADPCM_MS},
+   {MMAL_ENCODING_ADPCM_IMA_MS,    CODEC_ID_ADPCM_IMA_WAV},
+   {MMAL_ENCODING_ADPCM_SWF,       CODEC_ID_ADPCM_SWF},
+   {MMAL_ENCODING_WMA1,            CODEC_ID_WMAV1},
+   {MMAL_ENCODING_WMA2,            CODEC_ID_WMAV2},
+   {MMAL_ENCODING_WMAP,            CODEC_ID_WMAPRO},
+   {MMAL_ENCODING_WMAL,            CODEC_ID_NONE},
+   {MMAL_ENCODING_WMAV,            CODEC_ID_WMAVOICE},
+   {MMAL_ENCODING_AMRNB,           CODEC_ID_AMR_NB},
+   {MMAL_ENCODING_AMRWB,           CODEC_ID_AMR_WB},
+   {MMAL_ENCODING_AMRWBP,          CODEC_ID_NONE},
+   {MMAL_ENCODING_AC3,             CODEC_ID_AC3},
+   {MMAL_ENCODING_EAC3,            CODEC_ID_EAC3},
+   {MMAL_ENCODING_DTS,             CODEC_ID_DTS},
+   {MMAL_ENCODING_MLP,             CODEC_ID_MLP},
+   {MMAL_ENCODING_FLAC,            CODEC_ID_FLAC},
+   {MMAL_ENCODING_VORBIS,          CODEC_ID_VORBIS},
+   {MMAL_ENCODING_SPEEX,           CODEC_ID_SPEEX},
+   {MMAL_ENCODING_NELLYMOSER,      CODEC_ID_NELLYMOSER},
+   {MMAL_ENCODING_QCELP,           CODEC_ID_QCELP},
+
+   {MMAL_ENCODING_UNKNOWN, CODEC_ID_NONE}
+};
+
+static uint32_t encoding_to_codecid(uint32_t encoding)
+{
+   unsigned int i;
+   for(i = 0; codec_to_encoding_table[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
+      if(codec_to_encoding_table[i].encoding == encoding) break;
+   return codec_to_encoding_table[i].codecid;
+}
+
+static struct {
+   uint32_t encoding;
+   enum AVSampleFormat samplefmt;
+   unsigned int sample_size;
+} samplefmt_to_encoding_table[] =
+{
+   {MMAL_ENCODING_PCM_UNSIGNED, AV_SAMPLE_FMT_U8, 8},
+   {MMAL_ENCODING_PCM_SIGNED,   AV_SAMPLE_FMT_S16, 16},
+   {MMAL_ENCODING_PCM_SIGNED,   AV_SAMPLE_FMT_S32, 32},
+   {MMAL_ENCODING_PCM_FLOAT,    AV_SAMPLE_FMT_FLT, 32},
+   {MMAL_ENCODING_PCM_FLOAT,    AV_SAMPLE_FMT_DBL, 64},
+   {MMAL_ENCODING_UNKNOWN,      AV_SAMPLE_FMT_NONE, 1}
+};
+
+static uint32_t samplefmt_to_encoding(enum AVSampleFormat samplefmt)
+{
+   unsigned int i;
+   for(i = 0; samplefmt_to_encoding_table[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
+      if(samplefmt_to_encoding_table[i].samplefmt == samplefmt) break;
+   return samplefmt_to_encoding_table[i].encoding;
+}
+
+static unsigned int samplefmt_to_sample_size(enum AVSampleFormat samplefmt)
+{
+   unsigned int i;
+   for(i = 0; samplefmt_to_encoding_table[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
+      if(samplefmt_to_encoding_table[i].samplefmt == samplefmt) break;
+   return samplefmt_to_encoding_table[i].sample_size;
+}
+
+MMAL_CONSTRUCTOR(mmal_register_component_avcodec_audio);
+void mmal_register_component_avcodec_audio(void)
+{
+   avcodec_init();
+   avcodec_register_all();
+
+   mmal_component_supplier_register("avcodec", mmal_component_create_avcodec);
+}
diff --git a/interface/mmal/components/avcodec_video_decoder.c b/interface/mmal/components/avcodec_video_decoder.c
new file mode 100755 (executable)
index 0000000..356c429
--- /dev/null
@@ -0,0 +1,586 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "core/mmal_component_private.h"
+#include "core/mmal_port_private.h"
+#include "mmal_logging.h"
+
+#define attribute_deprecated
+#include "libavcodec/avcodec.h"
+#include "libavutil/mathematics.h"
+#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT( 52, 23, 0 )
+# include "libavformat/avformat.h"
+ static AVPacket null_packet = {AV_NOPTS_VALUE, AV_NOPTS_VALUE};
+# define av_init_packet(a) *(a) = null_packet
+#endif
+
+#if LIBAVCODEC_VERSION_MAJOR < 53
+# define avcodec_decode_video2(a,b,c,d) avcodec_decode_video(a,b,c,(d)->data,(d)->size)
+#endif
+
+/* Buffering requirements */
+#define INPUT_MIN_BUFFER_SIZE (800*1024)
+#define INPUT_MIN_BUFFER_NUM 1
+#define INPUT_RECOMMENDED_BUFFER_SIZE INPUT_MIN_BUFFER_SIZE
+#define INPUT_RECOMMENDED_BUFFER_NUM 10
+#define OUTPUT_MIN_BUFFER_NUM 1
+#define OUTPUT_RECOMMENDED_BUFFER_NUM 4
+
+#define DEFAULT_WIDTH 320
+#define DEFAULT_HEIGHT 240
+
+static uint32_t encoding_to_codecid(uint32_t encoding);
+static uint32_t pixfmt_to_encoding(enum PixelFormat);
+
+/****************************/
+typedef struct MMAL_COMPONENT_MODULE_T
+{
+   MMAL_STATUS_T status;
+
+   MMAL_QUEUE_T *queue_in;
+   MMAL_QUEUE_T *queue_out;
+
+   int picture_available;
+   int64_t pts;
+   int64_t dts;
+
+   AVFrame *picture;
+   AVCodecContext *codec_context;
+   AVCodec *codec;
+
+   int width;
+   int height;
+   enum PixelFormat pix_fmt;
+   AVPicture layout;
+   unsigned int planes;
+
+   int frame_size;
+   MMAL_BOOL_T output_needs_configuring;
+
+} MMAL_COMPONENT_MODULE_T;
+
+/** Destroy a previously created component */
+static MMAL_STATUS_T avcodec_component_destroy(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+
+   if (module->picture)
+      av_free(module->picture);
+   if (module->codec_context)
+   {
+      if(module->codec_context->extradata) vcos_free(module->codec_context->extradata);
+      if(module->codec_context->codec) avcodec_close(module->codec_context);
+      av_free(module->codec_context);
+   }
+
+   if(module->queue_in) mmal_queue_destroy(module->queue_in);
+   if(module->queue_out) mmal_queue_destroy(module->queue_out);
+   vcos_free(module);
+   if(component->input_num) mmal_ports_free(component->input, 1);
+   if(component->output_num) mmal_ports_free(component->output, 1);
+   return MMAL_SUCCESS;
+}
+
+/** Set format on a port */
+static MMAL_STATUS_T avcodec_input_port_set_format(MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   enum CodecID codec_id;
+   AVCodec *codec;
+
+   codec_id = encoding_to_codecid(port->format->encoding);
+   if(codec_id == CODEC_ID_NONE ||
+      !(codec = avcodec_find_decoder(codec_id)))
+   {
+      LOG_ERROR("ffmpeg codec id %d (for %4.4s) not recognized",
+                codec_id, (char *)&port->format->encoding);
+      return MMAL_ENXIO;
+   }
+
+   module->picture = avcodec_alloc_frame();
+
+   module->codec_context->width  = port->format->es->video.width;
+   module->codec_context->height  = port->format->es->video.height;
+   module->codec_context->extradata_size  = port->format->extradata_size;
+   module->codec_context->extradata =
+      vcos_calloc(1, port->format->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE,
+                  "avcodec extradata");
+   if(module->codec_context->extradata)
+      memcpy(module->codec_context->extradata, port->format->extradata,
+             port->format->extradata_size);
+
+   if (codec->capabilities & CODEC_CAP_TRUNCATED)
+      module->codec_context->flags |= CODEC_FLAG_TRUNCATED;
+
+   if (avcodec_open(module->codec_context, codec) < 0)
+   {
+      LOG_ERROR("could not open codec");
+      return MMAL_EIO;
+   }
+
+   /* Set a default format */
+   if (module->codec_context->pix_fmt == PIX_FMT_NONE)
+      module->codec_context->pix_fmt = PIX_FMT_YUV420P;
+
+   /* Copy format to output */
+   LOG_DEBUG("avcodec output format %i (%ix%i)", module->codec_context->pix_fmt,
+             module->codec_context->width, module->codec_context->height);
+   port->format->es->video.width = module->codec_context->width;
+   port->format->es->video.height = module->codec_context->height;
+   mmal_format_copy(component->output[0]->format, port->format);
+   component->output[0]->format->encoding = pixfmt_to_encoding(module->codec_context->pix_fmt);
+   if (!component->output[0]->format->es->video.width)
+      component->output[0]->format->es->video.width = DEFAULT_WIDTH;
+   if (!component->output[0]->format->es->video.height)
+      component->output[0]->format->es->video.height = DEFAULT_HEIGHT;
+
+   component->output[0]->priv->pf_set_format(component->output[0]);
+
+   return MMAL_SUCCESS;
+}
+
+/** Set format on a port */
+static MMAL_STATUS_T avcodec_output_port_set_format(MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+
+   /* Format can only be set to what is output by the codec */
+   if (pixfmt_to_encoding(module->codec_context->pix_fmt) != port->format->encoding)
+      return MMAL_EINVAL;
+
+   module->pix_fmt = module->codec_context->pix_fmt;
+   module->width = port->format->es->video.width;
+   module->height = port->format->es->video.height;
+
+   module->frame_size =
+      avpicture_fill(&module->layout, 0, module->pix_fmt, module->width, module->height);
+   if (module->frame_size < 0)
+      return MMAL_EINVAL;
+
+   /* Calculate the number of planes for this format */
+   for (module->planes = 0; module->planes < 4; )
+      if (!module->layout.data[module->planes++])
+         break;
+
+   port->buffer_size_min = module->frame_size;
+   port->component->priv->module->output_needs_configuring = 0;
+   mmal_component_action_trigger(port->component);
+
+   return MMAL_SUCCESS;
+}
+
+/** Enable processing on a port */
+static MMAL_STATUS_T avcodec_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
+{
+   MMAL_PARAM_UNUSED(port);
+   MMAL_PARAM_UNUSED(cb);
+   return MMAL_SUCCESS;
+}
+
+/** Flush a port */
+static MMAL_STATUS_T avcodec_port_flush(MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_BUFFER_HEADER_T *buffer;
+   MMAL_QUEUE_T *queue;
+
+   if(port->type == MMAL_PORT_TYPE_OUTPUT)
+      queue = module->queue_out;
+   else if(port->type == MMAL_PORT_TYPE_INPUT)
+      queue = module->queue_in;
+   else
+      return MMAL_EINVAL;
+
+   /* Flush buffers that our component is holding on to.
+    * If the reading thread is holding onto a buffer it will send it back ASAP as well
+    * so no need to care about that.  */
+   while((buffer = mmal_queue_get(queue)))
+      mmal_port_buffer_header_callback(port, buffer);
+
+   return MMAL_SUCCESS;
+}
+
+/** Disable processing on a port */
+static MMAL_STATUS_T avcodec_port_disable(MMAL_PORT_T *port)
+{
+   MMAL_STATUS_T status;
+
+   /* Actions are prevented from running at that point so a flush
+    * will return all buffers. */
+   status = avcodec_port_flush(port);
+   if(status != MMAL_SUCCESS)
+      return status;
+
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+static void avcodec_send_event_format_changed(MMAL_COMPONENT_T *component, MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_BUFFER_HEADER_T *buffer = NULL;
+   MMAL_EVENT_FORMAT_CHANGED_T *event;
+
+   /* Get an event buffer */
+   module->status = mmal_port_event_get(port, &buffer, MMAL_EVENT_FORMAT_CHANGED);
+   if (module->status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("unable to get an event buffer");
+      return;
+   }
+   event = mmal_event_format_changed_get(buffer);
+
+   /* Fill in the new format */
+   mmal_format_copy(event->format, port->format);
+   event->format->es->video.width = module->codec_context->width;
+   event->format->es->video.height = module->codec_context->height;
+   event->format->encoding = pixfmt_to_encoding(module->codec_context->pix_fmt);
+
+   /* Pass on the buffer requirements */
+   event->buffer_num_min = port->buffer_num_min;
+   event->buffer_size_min = module->codec_context->width * module->codec_context->height * 2;
+   event->buffer_size_recommended = event->buffer_size_min;
+   event->buffer_num_recommended = port->buffer_num_recommended;
+
+   module->output_needs_configuring = 1;
+   mmal_port_event_send(port, buffer);
+}
+
+/*****************************************************************************/
+static MMAL_STATUS_T avcodec_send_eos(MMAL_COMPONENT_T *component, MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_BUFFER_HEADER_T *out = mmal_queue_get(module->queue_out);
+
+   if (!out)
+      return MMAL_EAGAIN;
+
+   out->length = 0;
+   out->flags = MMAL_BUFFER_HEADER_FLAG_EOS;
+   mmal_port_buffer_header_callback(port, out);
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+static MMAL_STATUS_T avcodec_send_picture(MMAL_COMPONENT_T *component, MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_BUFFER_HEADER_T *out;
+   int i, size;
+
+   /* Detect format changes */
+   if (module->codec_context->width != module->width ||
+       module->codec_context->height != module->height ||
+       module->codec_context->pix_fmt != module->pix_fmt)
+   {
+      avcodec_send_event_format_changed(component, port);
+      return MMAL_EAGAIN;
+   }
+
+   out = mmal_queue_get(module->queue_out);
+   if (!out)
+      return MMAL_EAGAIN;
+
+   size = avpicture_layout((AVPicture *)module->picture, module->pix_fmt,
+                           module->width, module->height, out->data, out->alloc_size);
+   if (size < 0)
+   {
+      mmal_queue_put_back(module->queue_out, out);
+      LOG_ERROR("avpicture_layout failed: %i, %i, %i, %i",module->pix_fmt,
+                module->width, module->height, out->alloc_size );
+      mmal_event_error_send(component, MMAL_EINVAL);
+      return MMAL_EINVAL;
+   }
+
+   out->length = size;
+   out->pts    = module->pts;
+   out->flags  = 0;
+
+   out->type->video.planes = module->planes;
+   for (i = 0; i < 3; i++)
+   {
+      out->type->video.offset[i] = (uint64_t)module->layout.data[i];
+      out->type->video.pitch[i] = module->layout.linesize[i];
+   }
+
+   mmal_port_buffer_header_callback(port, out);
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+static MMAL_BOOL_T avcodec_do_processing(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_PORT_T *port_in = component->input[0];
+   MMAL_PORT_T *port_out = component->output[0];
+   MMAL_BUFFER_HEADER_T *in;
+   AVPacket avpkt;
+   int used = 0;
+
+   if (module->output_needs_configuring)
+      return 0;
+
+   if (module->picture_available &&
+       avcodec_send_picture(component, port_out) != MMAL_SUCCESS)
+      return 0;
+
+   module->picture_available = 0;
+
+   /* Get input buffer to decode */
+   in = mmal_queue_get(module->queue_in);
+   if (!in)
+      return 0;
+
+   /* Discard empty buffers. EOS buffers are not discarded since they will be used
+    * to flush the codec. */
+   if (!in->length && !(in->flags & MMAL_BUFFER_HEADER_FLAG_EOS))
+      goto end;
+
+   /* Avcodec expects padded input data */
+   if (in->length && !in->offset)
+   {
+      if(in->length + FF_INPUT_BUFFER_PADDING_SIZE <= in->alloc_size)
+         memset(in->data + in->length, 0, FF_INPUT_BUFFER_PADDING_SIZE);
+      else
+         LOG_WARN("could not pad buffer"); // Try to decode the data anyway
+   }
+
+   /* The actual decoding */
+   module->codec_context->reordered_opaque = in->pts;
+   av_init_packet(&avpkt);
+   avpkt.data = in->length ? in->data + in->offset : 0;
+   avpkt.size = in->length;
+   used = avcodec_decode_video2(module->codec_context, module->picture,
+                                &module->picture_available, &avpkt);
+
+   /* Check for errors */
+   if (used < 0 || used > (int)in->length)
+   {
+      LOG_ERROR("decoding failed (%i), discarding buffer", used);
+      used = in->length;
+   }
+
+   if (module->picture_available)
+   {
+      module->pts = module->picture->reordered_opaque;
+      if (module->pts == MMAL_TIME_UNKNOWN)
+         module->pts = in->dts;
+   }
+
+ end:
+   in->offset += used;
+   in->length -= used;
+
+   if (in->length)
+   {
+      mmal_queue_put_back(module->queue_in, in);
+      return 1;
+   }
+
+   /* We want to keep the EOS buffer until all the frames have been flushed */
+   if ((in->flags & MMAL_BUFFER_HEADER_FLAG_EOS) &&
+       module->picture_available)
+   {
+      mmal_queue_put_back(module->queue_in, in);
+      return 1;
+   }
+
+   /* Send EOS */
+   if ((in->flags & MMAL_BUFFER_HEADER_FLAG_EOS) &&
+       avcodec_send_eos(component, port_out) != MMAL_SUCCESS)
+   {
+      mmal_queue_put_back(module->queue_in, in);
+      return 0;
+   }
+
+   in->offset = 0;
+   mmal_port_buffer_header_callback(port_in, in);
+   return 1;
+}
+
+/*****************************************************************************/
+static void avcodec_do_processing_loop(MMAL_COMPONENT_T *component)
+{
+   while (avcodec_do_processing(component));
+}
+
+/** Buffer sending */
+static MMAL_STATUS_T avcodec_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+
+   if(port->type == MMAL_PORT_TYPE_OUTPUT) mmal_queue_put(module->queue_out, buffer);
+   if(port->type == MMAL_PORT_TYPE_INPUT) mmal_queue_put(module->queue_in, buffer);
+   mmal_component_action_trigger(port->component);
+
+   return MMAL_SUCCESS;
+}
+
+/** Create an instance of a component  */
+static MMAL_STATUS_T mmal_component_create_avcodec(const char *name, MMAL_COMPONENT_T *component)
+{
+   MMAL_STATUS_T status = MMAL_ENOMEM;
+   MMAL_COMPONENT_MODULE_T *module;
+
+   /* Check we're the requested component */
+   if(strcmp(name, "avcodec." MMAL_VIDEO_DECODE))
+      return MMAL_ENOENT;
+
+   /* Allocate our module context */
+   component->priv->module = module = vcos_malloc(sizeof(*module), "mmal module");
+   memset(module, 0, sizeof(*module));
+
+   /* Allocate the ports for this component */
+   component->input = mmal_ports_alloc(component, 1, MMAL_PORT_TYPE_INPUT, 0);
+   if(!component->input) goto error;
+   component->input_num = 1;
+   component->output = mmal_ports_alloc(component, 1, MMAL_PORT_TYPE_OUTPUT, 0);
+   if(!component->output) goto error;
+   component->output_num = 1;
+
+   module->queue_in = mmal_queue_create();
+   if(!module->queue_in) goto error;
+   module->queue_out = mmal_queue_create();
+   if(!module->queue_out) goto error;
+
+   module->codec_context = avcodec_alloc_context();
+   if(!module->codec_context) goto error;
+
+   component->input[0]->priv->pf_set_format = avcodec_input_port_set_format;
+   component->input[0]->priv->pf_enable = avcodec_port_enable;
+   component->input[0]->priv->pf_disable = avcodec_port_disable;
+   component->input[0]->priv->pf_flush = avcodec_port_flush;
+   component->input[0]->priv->pf_send = avcodec_port_send;
+   component->input[0]->buffer_num_min = INPUT_MIN_BUFFER_NUM;
+   component->input[0]->buffer_num_recommended = INPUT_RECOMMENDED_BUFFER_NUM;
+   component->input[0]->buffer_size_min = INPUT_MIN_BUFFER_SIZE;
+   component->input[0]->buffer_size_recommended = INPUT_RECOMMENDED_BUFFER_SIZE;
+
+   component->output[0]->priv->pf_set_format = avcodec_output_port_set_format;
+   component->output[0]->priv->pf_enable = avcodec_port_enable;
+   component->output[0]->priv->pf_disable = avcodec_port_disable;
+   component->output[0]->priv->pf_flush = avcodec_port_flush;
+   component->output[0]->priv->pf_send = avcodec_port_send;
+   component->output[0]->buffer_num_min = OUTPUT_MIN_BUFFER_NUM;
+   component->output[0]->buffer_num_recommended = OUTPUT_RECOMMENDED_BUFFER_NUM;
+
+   component->output[0]->format->type = MMAL_ES_TYPE_VIDEO;
+   component->output[0]->format->encoding = MMAL_ENCODING_I420;
+   component->output[0]->format->es->video.width = DEFAULT_WIDTH;
+   component->output[0]->format->es->video.height = DEFAULT_HEIGHT;
+
+   component->priv->pf_destroy = avcodec_component_destroy;
+
+   status = mmal_component_action_register(component, avcodec_do_processing_loop);
+   if (status != MMAL_SUCCESS)
+      goto error;
+
+   return MMAL_SUCCESS;
+
+ error:
+   avcodec_component_destroy(component);
+   return status;
+}
+
+static struct {
+   uint32_t encoding;
+   int codecid;
+} codec_to_encoding_table[] =
+{
+   {MMAL_ENCODING_H263,    CODEC_ID_H263},
+   {MMAL_ENCODING_H264,    CODEC_ID_H264},
+   {MMAL_ENCODING_MP4V,    CODEC_ID_MPEG4},
+   {MMAL_ENCODING_MP2V,    CODEC_ID_MPEG2VIDEO},
+   {MMAL_ENCODING_MP1V,    CODEC_ID_MPEG1VIDEO},
+   {MMAL_ENCODING_WMV3,    CODEC_ID_WMV3},
+   {MMAL_ENCODING_WMV2,    CODEC_ID_WMV2},
+   {MMAL_ENCODING_WMV1,    CODEC_ID_WMV1},
+   {MMAL_ENCODING_WVC1,    CODEC_ID_VC1},
+   {MMAL_ENCODING_VP6,     CODEC_ID_VP6},
+#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT( 52, 68, 2 )
+   {MMAL_ENCODING_VP8,     CODEC_ID_VP8},
+#endif
+   {MMAL_ENCODING_THEORA,  CODEC_ID_THEORA},
+
+   {MMAL_ENCODING_GIF,  CODEC_ID_GIF},
+   {MMAL_ENCODING_PNG,  CODEC_ID_PNG},
+   {MMAL_ENCODING_PPM,  CODEC_ID_PPM},
+   {MMAL_ENCODING_BMP,  CODEC_ID_BMP},
+   {MMAL_ENCODING_JPEG, CODEC_ID_MJPEG},
+
+   {MMAL_ENCODING_UNKNOWN, CODEC_ID_NONE}
+};
+
+static uint32_t encoding_to_codecid(uint32_t encoding)
+{
+   unsigned int i;
+   for(i = 0; codec_to_encoding_table[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
+      if(codec_to_encoding_table[i].encoding == encoding) break;
+   return codec_to_encoding_table[i].codecid;
+}
+
+static struct {
+   uint32_t encoding;
+   enum PixelFormat pixfmt;
+} pixfmt_to_encoding_table[] =
+{
+   {MMAL_ENCODING_I420,    PIX_FMT_YUV420P},
+   {MMAL_ENCODING_I422,    PIX_FMT_YUV422P},
+   {MMAL_ENCODING_I420,    PIX_FMT_YUVJ420P}, // FIXME
+   {MMAL_ENCODING_I422,    PIX_FMT_YUVJ422P}, // FIXME
+   {MMAL_ENCODING_RGB16,   PIX_FMT_RGB565},
+   {MMAL_ENCODING_BGR16,   PIX_FMT_BGR565},
+   {MMAL_ENCODING_RGB24,   PIX_FMT_RGB24},
+   {MMAL_ENCODING_BGR24,   PIX_FMT_BGR24},
+   {MMAL_ENCODING_ARGB,    PIX_FMT_ARGB},
+   {MMAL_ENCODING_RGBA,    PIX_FMT_RGBA},
+   {MMAL_ENCODING_ABGR,    PIX_FMT_ABGR},
+   {MMAL_ENCODING_BGRA,    PIX_FMT_BGRA},
+   {MMAL_ENCODING_UNKNOWN, PIX_FMT_NONE}
+};
+
+static uint32_t pixfmt_to_encoding(enum PixelFormat pixfmt)
+{
+   unsigned int i;
+   for(i = 0; pixfmt_to_encoding_table[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
+      if(pixfmt_to_encoding_table[i].pixfmt == pixfmt) break;
+   return pixfmt_to_encoding_table[i].encoding;
+}
+
+MMAL_CONSTRUCTOR(mmal_register_component_avcodec);
+void mmal_register_component_avcodec(void)
+{
+   avcodec_init();
+   avcodec_register_all();
+
+   mmal_component_supplier_register("avcodec", mmal_component_create_avcodec);
+}
diff --git a/interface/mmal/components/clock.c b/interface/mmal/components/clock.c
new file mode 100755 (executable)
index 0000000..d59f4e4
--- /dev/null
@@ -0,0 +1,900 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "core/mmal_component_private.h"
+#include "core/mmal_port_private.h"
+#include "util/mmal_util_rational.h"
+#include "util/mmal_list.h"
+#include "mmal_logging.h"
+
+
+#define CLOCK_PORTS_NUM         5
+
+#define MAX_CLOCK_EVENT_SLOTS   16
+
+#define DEFAULT_FRAME_RATE      30             /* frames per second */
+#define DEFAULT_CLOCK_LATENCY   60000          /* microseconds */
+
+#define FILTER_DURATION         2              /* seconds */
+#define MAX_FILTER_LENGTH       180            /* samples */
+
+#define MAX_TIME                (~(1LL << 63)) /* microseconds */
+#define MIN_TIME                (1LL << 63)    /* microseconds */
+
+#define ABS(a)                  ((a) <  0  ? -(a) : (a))
+#define MIN(a,b)                ((a) < (b) ?  (a) : (b))
+#define MAX(a,b)                ((a) > (b) ?  (a) : (b))
+
+/** Set to 1 to enable additional stream timing log
+ * messages used for debugging the clock algorithm */
+#define ENABLE_ADDITIONAL_LOGGING   0
+static int clock_additional_logging = ENABLE_ADDITIONAL_LOGGING;
+
+/*****************************************************************************/
+typedef int64_t TIME_T;
+
+typedef struct FILTER_T
+{
+   uint32_t first;              /**< index to the oldest sample */
+   uint32_t last;               /**< index to the most recent sample*/
+   uint32_t count;              /**< total number of samples in the filter */
+   uint32_t length;             /**< maximum number of samples */
+   TIME_T sum;                  /**< sum of all samples currently in the filter */
+   TIME_T h[MAX_FILTER_LENGTH]; /**< filter history */
+} FILTER_T;
+
+/** Frame statistics for a stream */
+typedef struct CLOCK_STREAM_T
+{
+   uint32_t id;                 /**< for debug purposes */
+
+   MMAL_BOOL_T started;         /**< TRUE at least one frame has been received */
+
+   TIME_T pts;                  /**< most recent time-stamp seen */
+   TIME_T stc;                  /**< most recent wall-time seen */
+
+   TIME_T mt_off;               /**< offset of the current time stamp from the
+                                     arrival time, i.e. PTS - STC */
+   TIME_T mt_off_avg;           /**< rolling average of the media time offset */
+   TIME_T mt_off_std;           /**< approximate standard deviation of the media
+                                     time offset */
+
+   FILTER_T avg_filter;         /**< moving average filter */
+   FILTER_T std_filter;         /**< (approximate) standard deviation filter */
+} CLOCK_STREAM_T;
+
+/** Clock stream events */
+typedef enum CLOCK_STREAM_EVENT_T
+{
+   CLOCK_STREAM_EVENT_NONE,
+   CLOCK_STREAM_EVENT_STARTED,        /**< first data received */
+   CLOCK_STREAM_EVENT_DISCONT,        /**< discontinuity detected */
+   CLOCK_STREAM_EVENT_FRAME_COMPLETE, /**< complete frame received */
+} CLOCK_STREAM_EVENT_T;
+
+/** Clock port event */
+typedef struct CLOCK_PORT_EVENT_T
+{
+   MMAL_LIST_ELEMENT_T link;   /**< must be first */
+   MMAL_PORT_T *port;          /**< clock port where the event occurred */
+   MMAL_CLOCK_EVENT_T event;   /**< event data */
+} CLOCK_PORT_EVENT_T;
+
+/** Clock component context */
+typedef struct MMAL_COMPONENT_MODULE_T
+{
+   MMAL_STATUS_T status;       /**< current status of the component */
+
+   MMAL_BOOL_T clock_discont;  /**< TRUE -> clock discontinuity detected */
+
+   uint32_t stream_min_id;     /**< id of selected minimum stream (debugging only) */
+   uint32_t stream_max_id;     /**< if of selected maximum stream (debugging only) */
+
+   TIME_T mt_off_target;       /**< target clock media time offset */
+   TIME_T mt_off_clk;          /**< current clock media time offset */
+
+   TIME_T adj_p;               /**< proportional clock adjustment */
+   TIME_T adj_m;               /**< clock adjustment factor (between 1 and 0) */
+   TIME_T adj;                 /**< final clock adjustment */
+
+   TIME_T stc_at_update;       /**< the value of the STC the last time the clocks
+                                    were updated */
+
+   TIME_T frame_duration;      /**< one frame period (microseconds) */
+   MMAL_RATIONAL_T frame_rate; /**< frame rate set by the client */
+   uint32_t frame_rate_log2;   /**< frame rate expressed as a power of two */
+
+   MMAL_RATIONAL_T scale;      /**< current clock scale factor */
+   MMAL_BOOL_T pending_scale;  /**< TRUE -> scale change is pending */
+
+   MMAL_CLOCK_LATENCY_T           latency;
+   MMAL_CLOCK_UPDATE_THRESHOLD_T  update_threshold;
+   MMAL_CLOCK_DISCONT_THRESHOLD_T discont_threshold;
+   MMAL_CLOCK_REQUEST_THRESHOLD_T request_threshold;
+
+   /** Clock port events */
+   struct
+   {
+      MMAL_LIST_T* queue;      /**< pending events */
+      MMAL_LIST_T* free;       /**< available event slots */
+      CLOCK_PORT_EVENT_T pool[MAX_CLOCK_EVENT_SLOTS];
+   } events;
+} MMAL_COMPONENT_MODULE_T;
+
+/** Clock port context */
+typedef struct MMAL_PORT_MODULE_T
+{
+   CLOCK_STREAM_T *stream;     /**< stream associated with this clock port */
+} MMAL_PORT_MODULE_T;
+
+
+/*****************************************************************************/
+/** Round x up to the next power of two */
+static uint32_t next_pow2(uint32_t x)
+{
+   x--;
+   x = (x >> 1)  | x;
+   x = (x >> 2)  | x;
+   x = (x >> 4)  | x;
+   x = (x >> 8)  | x;
+   x = (x >> 16) | x;
+   return ++x;
+}
+
+/** Given a power of 2 value, return the number of bit shifts */
+static uint32_t pow2_shift(uint32_t x)
+{
+   static const uint32_t BIT_POSITIONS[32] =
+   {
+      0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8,
+      31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9
+   };
+
+   return BIT_POSITIONS[((x & -x) * 0x077CB531U) >> 27];
+}
+
+/** Add 2 values with saturation */
+static inline TIME_T saturate_add(TIME_T a, TIME_T b)
+{
+   TIME_T sum = a + b;
+   if (a > 0 && b > 0 && sum < 0)
+      sum = MAX_TIME;
+   else if (a < 0 && b < 0 && sum > 0)
+      sum = MIN_TIME;
+   return sum;
+}
+
+/*****************************************************************************/
+/** Filter reset */
+static void filter_init(FILTER_T *filter, uint32_t length)
+{
+   memset(filter, 0, sizeof(*filter));
+   filter->last = length - 1;
+   filter->length = length;
+};
+
+/** Increment filter index modulo the length */
+static inline uint32_t filter_index_wrap(uint32_t index, uint32_t length)
+{
+   return (++index < length) ? index : 0;
+}
+
+/** Remove the oldest sample from the filter */
+static void filter_drop(FILTER_T *filter)
+{
+   if (!filter->count)
+      return;
+
+   filter->sum -= filter->h[filter->first];
+   filter->first = filter_index_wrap(filter->first, filter->length);
+   filter->count--;
+}
+
+/** Add a new sample (and drop the oldest when full) */
+static void filter_insert(FILTER_T *filter, TIME_T sample)
+{
+   if (filter->count == filter->length)
+      filter_drop(filter);
+
+   filter->last = filter_index_wrap(filter->last, filter->length);
+   filter->h[filter->last] = sample;
+   filter->sum = saturate_add(filter->sum, sample);
+   filter->count++;
+}
+
+/*****************************************************************************/
+/** Create and initialise a clock stream */
+static MMAL_BOOL_T clock_create_stream(CLOCK_STREAM_T **stream, uint32_t id, uint32_t filter_length)
+{
+   CLOCK_STREAM_T *s = vcos_calloc(1, sizeof(CLOCK_STREAM_T), "clock stream");
+   if (!s)
+   {
+      LOG_ERROR("failed to allocate stream");
+      return MMAL_FALSE;
+   }
+
+   s->id = id;
+
+   filter_init(&s->avg_filter, filter_length);
+   filter_init(&s->std_filter, filter_length);
+
+   *stream = s;
+   return MMAL_TRUE;
+}
+
+/** Flag this stream as started */
+static void clock_start_stream(CLOCK_STREAM_T *stream, TIME_T stc, TIME_T pts)
+{
+   stream->started = MMAL_TRUE;
+   stream->pts = pts;
+   stream->stc = stc;
+}
+
+/** Reset the internal state of a stream */
+static void clock_reset_stream(CLOCK_STREAM_T *stream)
+{
+   if (!stream)
+      return;
+
+   stream->pts = 0;
+   stream->stc = 0;
+   stream->mt_off = 0;
+   stream->mt_off_avg = 0;
+   stream->mt_off_std = 0;
+   stream->started = MMAL_FALSE;
+
+   filter_init(&stream->avg_filter, stream->avg_filter.length);
+   filter_init(&stream->std_filter, stream->std_filter.length);
+}
+
+/** Update the internal state of a stream */
+static CLOCK_STREAM_EVENT_T clock_update_stream(CLOCK_STREAM_T *stream, TIME_T stc, TIME_T pts,
+                                                TIME_T discont_threshold)
+{
+   CLOCK_STREAM_EVENT_T event = CLOCK_STREAM_EVENT_NONE;
+   TIME_T pts_delta, stc_delta;
+
+   if (pts == MMAL_TIME_UNKNOWN)
+   {
+      LOG_TRACE("ignoring invalid timestamp received at %"PRIi64, stc);
+      return CLOCK_STREAM_EVENT_NONE;
+   }
+
+   if (!stream->started)
+   {
+      LOG_TRACE("stream %d started %"PRIi64" %"PRIi64, stream->id, stc, pts);
+      clock_start_stream(stream, stc, pts);
+      return CLOCK_STREAM_EVENT_STARTED;
+   }
+
+   /* XXX: This should really use the buffer flags to determine if a complete
+    * frame has been received.  However, not all clients set MMAL buffer flags
+    * correctly (if at all). */
+   pts_delta = pts - stream->pts;
+   stc_delta = stc - stream->stc;
+
+   /* Check for discontinuities. */
+   if ((ABS(pts_delta) > discont_threshold) || (ABS(stc_delta) > discont_threshold))
+   {
+      LOG_ERROR("discontinuity detected on stream %d %"PRIi64" %"PRIi64" %"PRIi64,
+                stream->id, pts_delta, stc_delta, discont_threshold);
+      return CLOCK_STREAM_EVENT_DISCONT;
+   }
+
+   if (pts_delta)
+   {
+      /* A complete frame has now been received, so update the stream's notion of media time */
+      stream->mt_off = stream->pts - stream->stc;
+
+      filter_insert(&stream->avg_filter, stream->mt_off);
+      stream->mt_off_avg = stream->avg_filter.sum / stream->avg_filter.count;
+
+      filter_insert(&stream->std_filter, ABS(stream->mt_off - stream->mt_off_avg));
+      stream->mt_off_std = stream->std_filter.sum / stream->std_filter.count;
+
+      LOG_TRACE("stream %d %"PRIi64" %"PRIi64" %"PRIi64" %"PRIi64,
+                stream->id, stream->stc, stream->pts, stream->mt_off_avg, stream->mt_off);
+
+      event = CLOCK_STREAM_EVENT_FRAME_COMPLETE;
+   }
+
+   stream->pts = pts;
+   stream->stc = stc;
+
+   return event;
+}
+
+/*****************************************************************************/
+/** Start all enabled clock ports, making sure all use the same thresholds */
+static void clock_start_clocks(MMAL_COMPONENT_T *component, TIME_T media_time)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   unsigned i;
+
+   for (i = 0; i < component->clock_num; ++i)
+   {
+      MMAL_PORT_T *port = component->clock[i];
+      if (port->is_enabled)
+      {
+         LOG_TRACE("starting clock %d with time %"PRIi64, port->index, media_time);
+         mmal_port_clock_reference_set(port, MMAL_TRUE);
+         mmal_port_clock_media_time_set(port, media_time);
+         mmal_port_clock_update_threshold_set(port, &module->update_threshold);
+         mmal_port_clock_discont_threshold_set(port, &module->discont_threshold);
+         mmal_port_clock_request_threshold_set(port, &module->request_threshold);
+         mmal_port_clock_active_set(port, MMAL_TRUE);
+      }
+   }
+}
+
+/** Stop (and flush) all enabled clock ports */
+static void clock_stop_clocks(MMAL_COMPONENT_T *component)
+{
+   unsigned i;
+
+   for (i = 0; i < component->clock_num; ++i)
+   {
+      MMAL_PORT_T *port = component->clock[i];
+      if (port->is_enabled)
+      {
+         LOG_TRACE("stopping clock %d", port->index);
+         mmal_port_clock_request_flush(port);
+         mmal_port_clock_active_set(port, MMAL_FALSE);
+      }
+   }
+}
+
+/** Reset the internal state of all streams in order to rebase clock
+ * adjustment calculations */
+static void clock_reset_clocks(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   unsigned i;
+
+   for (i = 0; i < component->clock_num; ++i)
+      clock_reset_stream(component->clock[i]->priv->module->stream);
+
+   module->clock_discont = MMAL_TRUE;
+}
+
+/** Change the media-time for all enabled clock ports */
+static void clock_set_media_time(MMAL_COMPONENT_T *component, TIME_T media_time)
+{
+   unsigned i;
+
+   for (i = 0; i < component->clock_num; ++i)
+   {
+      MMAL_PORT_T *port = component->clock[i];
+      if (port->is_enabled)
+         mmal_port_clock_media_time_set(port, media_time);
+   }
+}
+
+/** Change the scale for all clock ports */
+static void clock_set_scale(MMAL_COMPONENT_T *component, MMAL_RATIONAL_T scale)
+{
+   unsigned i;
+
+   for (i = 0; i < component->clock_num; ++i)
+      mmal_port_clock_scale_set(component->clock[i], scale);
+
+   component->priv->module->pending_scale = 0;
+}
+
+/** Update the average and standard deviation calculations for all streams
+ * (dropping samples where necessary) and return the minimum and maximum
+ * streams */
+static MMAL_BOOL_T clock_get_mt_off_avg(MMAL_COMPONENT_T *component, TIME_T stc,
+                                        CLOCK_STREAM_T **minimum, CLOCK_STREAM_T **maximum)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   TIME_T drop_threshold = 6 * module->frame_duration;
+   TIME_T reset_threshold = module->latency.target << 1;
+   TIME_T avg_min = MAX_TIME;
+   TIME_T avg_max = MIN_TIME;
+   TIME_T avg_bias;
+   TIME_T stc_delta;
+   unsigned i;
+
+   *minimum = 0;
+   *maximum = 0;
+
+   for (i = 0; i < component->clock_num; ++i)
+   {
+      CLOCK_STREAM_T *stream = component->clock[i]->priv->module->stream;
+      if (stream)
+      {
+         stc_delta = stc - stream->stc;
+
+         /* Drop samples from the moving average and standard deviation filters */
+         if (stc_delta > reset_threshold)
+         {
+            filter_init(&stream->avg_filter, stream->avg_filter.length);
+            filter_init(&stream->std_filter, stream->std_filter.length);
+            LOG_TRACE("reset stream %d filters due to stc_delta %"PRIi64, stream->id, stc_delta);
+         }
+         else if (stc_delta > drop_threshold)
+         {
+            filter_drop(&stream->avg_filter);
+            filter_drop(&stream->std_filter);
+            LOG_TRACE("drop stream %d filter samples due to stc_delta %"PRIi64, stream->id, stc_delta);
+         }
+
+         /* No point in continuing if filters are empty */
+         if (!stream->avg_filter.count)
+            continue;
+
+         /* Calculate new average and standard deviation for the stream */
+         stream->mt_off_avg = stream->avg_filter.sum / stream->avg_filter.count;
+         stream->mt_off_std = stream->std_filter.sum / stream->std_filter.count;
+
+         /* Select the minimum and maximum average between all active streams */
+         avg_bias = (stream->avg_filter.length - stream->avg_filter.count) * ABS(stream->mt_off_avg) / stream->avg_filter.length;
+         if ((stream->mt_off_avg + avg_bias) < avg_min)
+         {
+            avg_min = stream->mt_off_avg;
+            *minimum = stream;
+            LOG_TRACE("found min on %d mt_off_avg %"PRIi64" mt_off_std %"PRIi64" avg_bias %"PRIi64" count %d",
+                      stream->id, stream->mt_off_avg, stream->mt_off_std, avg_bias, stream->avg_filter.count);
+         }
+         if ((stream->mt_off_avg - avg_bias) > avg_max)
+         {
+            avg_max = stream->mt_off_avg;
+            *maximum = stream;
+            LOG_TRACE("found max on %d mt_off_avg %"PRIi64" mt_off_std %"PRIi64" avg_bias %"PRIi64" count %d",
+                      stream->id, stream->mt_off_avg, stream->mt_off_std, avg_bias, stream->avg_filter.count);
+         }
+      }
+   }
+
+   return (*minimum) && (*maximum);
+}
+
+/** Adjust the media-time of the playback clocks based on current timing statistics */
+static void clock_adjust_clocks(MMAL_COMPONENT_T *component, TIME_T stc)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   CLOCK_STREAM_T *stream_min;
+   CLOCK_STREAM_T *stream_max;
+   TIME_T mt_off_clk;
+   TIME_T stc_prev;
+
+   if (!clock_get_mt_off_avg(component, stc, &stream_min, &stream_max))
+      return;
+
+   module->stream_min_id = stream_min->id;
+   module->stream_max_id = stream_max->id;
+
+   /* Calculate the actual media-time offset seen by the clock */
+   mt_off_clk = mmal_port_clock_media_time_get(component->clock[0]) - stc;
+
+   stc_prev = module->stc_at_update;
+   module->stc_at_update = stc;
+
+   /* If there has been a discontinuity, restart the clock,
+    * else use the clock control loop to apply a clock adjustment */
+   if (module->clock_discont)
+   {
+      module->clock_discont = MMAL_FALSE;
+
+      module->mt_off_clk = stream_min->mt_off_avg - module->latency.target;
+      module->mt_off_target = module->mt_off_clk;
+
+      clock_stop_clocks(component);
+      clock_start_clocks(component, module->mt_off_clk + stc);
+   }
+   else
+   {
+      /* Determine the new clock target */
+      TIME_T mt_off_target_max = stream_max->mt_off_avg - module->latency.target;
+      TIME_T mt_off_target_min = stream_min->mt_off_avg - module->frame_duration;
+      module->mt_off_target = MIN(mt_off_target_max, mt_off_target_min);
+
+      /* Calculate the proportional adjustment, capped by the attack rate
+       * set by the client */
+      TIME_T stc_delta = (stc > stc_prev) ? (stc - stc_prev) : 0;
+      TIME_T adj_p_max = stc_delta * module->latency.attack_rate / module->latency.attack_period;
+
+      module->adj_p = module->mt_off_target - module->mt_off_clk;
+      if (module->adj_p < -adj_p_max)
+         module->adj_p = -adj_p_max;
+      else if (module->adj_p > adj_p_max)
+         module->adj_p = adj_p_max;
+
+      /* Calculate the confidence of the adjustment using the approximate
+       * standard deviation for the selected stream:
+       *
+       * adj_m = 1.0 - STD * FPS / 4
+       *
+       * The adjustment factor is scaled up by 2^20 which is an approximation
+       * of 1000000 (microseconds per second) and the frame rate is assumed
+       * to be either 32 or 64 which are approximations for 24/25/30 and 60
+       * fps to avoid divisions.  This has a lower limit of 0. */
+      module->adj_m =
+         MAX((1 << 20) - ((stream_min->mt_off_std << module->frame_rate_log2) >> 2), 0);
+
+      /* Modulate the proportional adjustment by the sample confidence
+       * and apply the adjustment to the current clock */
+      module->adj = (module->adj_p * module->adj_m) >> 20;
+      module->adj = (module->adj * (stream_min->avg_filter.count << 8) / stream_min->avg_filter.length) >> 8;
+      module->mt_off_clk += module->adj;
+
+      clock_set_media_time(component, module->mt_off_clk + stc);
+   }
+
+   /* Any pending clock scale changes can now be applied */
+   if (component->priv->module->pending_scale)
+      clock_set_scale(component, component->priv->module->scale);
+}
+
+/*****************************************************************************/
+static void clock_process_stream_event(MMAL_COMPONENT_T *component, CLOCK_STREAM_T *stream,
+                                       CLOCK_STREAM_EVENT_T event, TIME_T stc)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+
+   switch (event)
+   {
+   case CLOCK_STREAM_EVENT_FRAME_COMPLETE:
+      clock_adjust_clocks(component, stc);
+      if (clock_additional_logging)
+      {
+         VCOS_ALERT("STRM_%d %"PRIi64" %"PRIi64" %"PRIi64" %"PRIi64" %"PRIi64" %"PRIi64" %d %"
+                    PRIi64" %"PRIi64" %"PRIi64" %"PRIi64" %"PRIi64" %u %u",
+                    stream->id, stream->stc, stream->pts, stream->mt_off_avg, stream->mt_off,
+                    stream->mt_off_std, ABS(stream->mt_off - stream->mt_off_avg), stream->avg_filter.count,
+                    module->mt_off_clk, module->mt_off_target, module->adj_p, module->adj_m, module->adj,
+                    module->stream_min_id, module->stream_max_id);
+      }
+      break;
+   case CLOCK_STREAM_EVENT_DISCONT:
+      clock_reset_clocks(component);
+      break;
+   default:
+      /* ignore all other events */
+      break;
+   }
+}
+
+/** Handler for input buffer events */
+static void clock_process_input_buffer_info_event(MMAL_COMPONENT_T *component, MMAL_PORT_T *port,
+                                                  const MMAL_CLOCK_BUFFER_INFO_T *info)
+{
+   CLOCK_STREAM_EVENT_T stream_event = CLOCK_STREAM_EVENT_NONE;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_PORT_MODULE_T *port_module = port->priv->module;
+   TIME_T stc = (TIME_T)((uint64_t)info->arrival_time);
+   TIME_T pts = info->time_stamp;
+
+   LOG_TRACE("port %d %"PRIi64" %"PRIi64, port->index, stc, pts);
+
+   if (!port_module->stream)
+   {
+      /* First data received for this stream */
+      uint32_t filter_length = module->frame_rate.num * FILTER_DURATION /
+                               module->frame_rate.den;
+      if (!clock_create_stream(&port_module->stream, port->index, filter_length))
+         return;
+   }
+
+   stream_event = clock_update_stream(port_module->stream, stc, pts, module->discont_threshold.threshold);
+
+   clock_process_stream_event(component, port_module->stream, stream_event, stc);
+}
+
+/** Handler for clock scale events */
+static void clock_process_scale_event(MMAL_COMPONENT_T *component, MMAL_RATIONAL_T scale)
+{
+   /* When pausing the clock (i.e. scale = 0.0), apply the scale change
+    * immediately.  However, when resuming the clock (i.e. scale = 1.0),
+    * the scale change can only be applied the next time new buffer timing
+    * information is received.  This ensures that clocks resume with the
+    * correct media-time. */
+   if (scale.num == 0)
+   {
+      component->priv->module->scale = scale;
+      clock_set_scale(component, scale);
+   }
+   else
+   {
+      /* Only support scale == 1.0 */
+      if (!mmal_rational_equal(component->priv->module->scale, scale) &&
+          (scale.num == scale.den))
+      {
+         component->priv->module->scale = scale;
+         component->priv->module->pending_scale = 1;
+         clock_reset_clocks(component);
+      }
+   }
+}
+
+/** Handler for update threshold events */
+static void clock_process_update_threshold_event(MMAL_COMPONENT_T *component, const MMAL_CLOCK_UPDATE_THRESHOLD_T *threshold)
+{
+   unsigned i;
+
+   component->priv->module->update_threshold = *threshold;
+
+   for (i = 0; i < component->clock_num; ++i)
+      mmal_port_clock_update_threshold_set(component->clock[i], threshold);
+}
+
+/** Handler for discontinuity threshold events */
+static void clock_process_discont_threshold_event(MMAL_COMPONENT_T *component, const MMAL_CLOCK_DISCONT_THRESHOLD_T *threshold)
+{
+   unsigned i;
+
+   component->priv->module->discont_threshold = *threshold;
+
+   for (i = 0; i < component->clock_num; ++i)
+      mmal_port_clock_discont_threshold_set(component->clock[i], threshold);
+}
+
+/** Handler for request threshold events */
+static void clock_process_request_threshold_event(MMAL_COMPONENT_T *component, const MMAL_CLOCK_REQUEST_THRESHOLD_T *threshold)
+{
+   unsigned i;
+
+   component->priv->module->request_threshold = *threshold;
+
+   for (i = 0; i < component->clock_num; ++i)
+      mmal_port_clock_request_threshold_set(component->clock[i], threshold);
+}
+
+/** Handler for latency events */
+static void clock_process_latency_event(MMAL_COMPONENT_T *component, const MMAL_CLOCK_LATENCY_T *latency)
+{
+   component->priv->module->latency = *latency;
+
+   clock_reset_clocks(component);
+}
+
+/** Add a clock port event to the queue and trigger the action thread */
+static MMAL_STATUS_T clock_event_queue(MMAL_COMPONENT_T *component, MMAL_PORT_T *port, const MMAL_CLOCK_EVENT_T *event)
+{
+   CLOCK_PORT_EVENT_T *slot = (CLOCK_PORT_EVENT_T*)mmal_list_pop_front(component->priv->module->events.free);
+   if (!slot)
+   {
+      LOG_ERROR("no event slots available");
+      return MMAL_ENOSPC;
+   }
+
+   slot->port = port;
+   slot->event = *event;
+   mmal_list_push_back(component->priv->module->events.queue, &slot->link);
+
+   return mmal_component_action_trigger(component);
+}
+
+/** Get the next clock port event in the queue */
+static MMAL_STATUS_T clock_event_dequeue(MMAL_COMPONENT_T *component, CLOCK_PORT_EVENT_T *port_event)
+{
+   CLOCK_PORT_EVENT_T *slot = (CLOCK_PORT_EVENT_T*)mmal_list_pop_front(component->priv->module->events.queue);
+   if (!slot)
+      return MMAL_EINVAL;
+
+   port_event->port = slot->port;
+   port_event->event = slot->event;
+   mmal_list_push_back(component->priv->module->events.free, &slot->link);
+
+   if (port_event->event.buffer)
+   {
+      port_event->event.buffer->length = 0;
+      mmal_port_buffer_header_callback(port_event->port, port_event->event.buffer);
+   }
+
+   return MMAL_SUCCESS;
+}
+
+/** Event callback from a clock port */
+static void clock_event_cb(MMAL_PORT_T *port, const MMAL_CLOCK_EVENT_T *event)
+{
+   clock_event_queue(port->component, port, event);
+}
+
+
+/*****************************************************************************/
+/** Actual processing function */
+static MMAL_BOOL_T clock_do_processing(MMAL_COMPONENT_T *component)
+{
+   CLOCK_PORT_EVENT_T port_event;
+
+   if (clock_event_dequeue(component, &port_event) != MMAL_SUCCESS)
+      return MMAL_FALSE; /* No more external events to process */
+
+   /* Process external events (coming from clock ports) */
+   switch (port_event.event.id)
+   {
+   case MMAL_CLOCK_EVENT_SCALE:
+      clock_process_scale_event(component, port_event.event.data.scale);
+      break;
+   case MMAL_CLOCK_EVENT_UPDATE_THRESHOLD:
+      clock_process_update_threshold_event(component, &port_event.event.data.update_threshold);
+      break;
+   case MMAL_CLOCK_EVENT_DISCONT_THRESHOLD:
+      clock_process_discont_threshold_event(component, &port_event.event.data.discont_threshold);
+      break;
+   case MMAL_CLOCK_EVENT_REQUEST_THRESHOLD:
+      clock_process_request_threshold_event(component, &port_event.event.data.request_threshold);
+      break;
+   case MMAL_CLOCK_EVENT_LATENCY:
+      clock_process_latency_event(component, &port_event.event.data.latency);
+      break;
+   case MMAL_CLOCK_EVENT_INPUT_BUFFER_INFO:
+      clock_process_input_buffer_info_event(component, port_event.port, &port_event.event.data.buffer);
+      break;
+   default:
+      break;
+   }
+
+   return MMAL_TRUE;
+}
+
+/** Component action thread */
+static void clock_do_processing_loop(MMAL_COMPONENT_T *component)
+{
+   while (clock_do_processing(component));
+}
+
+
+/*****************************************************************************/
+/** Set a parameter on the clock component's control port */
+static MMAL_STATUS_T clock_control_parameter_set(MMAL_PORT_T *port, const MMAL_PARAMETER_HEADER_T *param)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+
+   switch (param->id)
+   {
+      case MMAL_PARAMETER_CLOCK_FRAME_RATE:
+      {
+         const MMAL_PARAMETER_FRAME_RATE_T *p = (const MMAL_PARAMETER_FRAME_RATE_T *)param;
+         module->frame_rate = p->frame_rate;
+         /* XXX: take frame_rate.den into account */
+         module->frame_rate_log2 = pow2_shift(next_pow2(module->frame_rate.num));
+         module->frame_duration = p->frame_rate.den * 1000000 / p->frame_rate.num;
+         LOG_TRACE("frame rate %d/%d (%u) duration %"PRIi64,
+                   module->frame_rate.num, module->frame_rate.den,
+                   module->frame_rate_log2, module->frame_duration);
+      }
+      break;
+      case MMAL_PARAMETER_CLOCK_LATENCY:
+      {
+         /* Changing the latency setting requires a reset of the clock algorithm, but
+          * that can only be safely done from within the component's worker thread.
+          * So, queue the new latency setting as a clock event. */
+         const MMAL_PARAMETER_CLOCK_LATENCY_T *p = (const MMAL_PARAMETER_CLOCK_LATENCY_T *)param;
+         MMAL_CLOCK_EVENT_T event = { MMAL_CLOCK_EVENT_LATENCY, MMAL_CLOCK_EVENT_MAGIC };
+
+         LOG_TRACE("latency target %"PRIi64" attack %"PRIi64"/%"PRIi64,
+                   p->value.target, p->value.attack_rate, p->value.attack_period);
+
+         event.data.latency = p->value;
+         status = clock_event_queue(port->component, port, &event);
+      }
+      break;
+      default:
+         LOG_ERROR("parameter not supported (0x%x)", param->id);
+         status = MMAL_ENOSYS;
+         break;
+   }
+   return status;
+}
+
+/** Destroy a previously created component */
+static MMAL_STATUS_T clock_component_destroy(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   unsigned int i;
+
+   if (module->events.free)
+      mmal_list_destroy(module->events.free);
+
+   if (module->events.queue)
+      mmal_list_destroy(module->events.queue);
+
+   if (component->clock_num)
+   {
+      for (i = 0; i < component->clock_num; ++i)
+         vcos_free(component->clock[i]->priv->module->stream);
+
+      mmal_ports_clock_free(component->clock, component->clock_num);
+   }
+
+   vcos_free(module);
+
+   return MMAL_SUCCESS;
+}
+
+/** Create an instance of a clock component  */
+static MMAL_STATUS_T mmal_component_create_clock(const char *name, MMAL_COMPONENT_T *component)
+{
+   int i;
+   MMAL_COMPONENT_MODULE_T *module;
+   MMAL_STATUS_T status = MMAL_ENOMEM;
+   MMAL_PARAM_UNUSED(name);
+
+   /* Allocate the context for our module */
+   component->priv->module = module = vcos_malloc(sizeof(*module), "mmal module");
+   if (!module)
+      return MMAL_ENOMEM;
+   memset(module, 0, sizeof(*module));
+
+   component->priv->pf_destroy = clock_component_destroy;
+
+   /* Create the clock ports (clock ports are managed by the framework) */
+   component->clock = mmal_ports_clock_alloc(component, CLOCK_PORTS_NUM,
+                                             sizeof(MMAL_PORT_MODULE_T), clock_event_cb);
+   if (!component->clock)
+      goto error;
+   component->clock_num = CLOCK_PORTS_NUM;
+
+   component->control->priv->pf_parameter_set = clock_control_parameter_set;
+
+   /* Setup event slots */
+   module->events.free = mmal_list_create();
+   module->events.queue = mmal_list_create();
+   if (!module->events.free || !module->events.queue)
+   {
+      LOG_ERROR("failed to create list %p %p", module->events.free, module->events.queue);
+      goto error;
+   }
+   for (i = 0; i < MAX_CLOCK_EVENT_SLOTS; ++i)
+      mmal_list_push_back(module->events.free, &module->events.pool[i].link);
+
+   component->priv->priority = VCOS_THREAD_PRI_REALTIME;
+   status = mmal_component_action_register(component, clock_do_processing_loop);
+
+   module->clock_discont = MMAL_TRUE;
+   module->frame_rate.num = DEFAULT_FRAME_RATE;
+   module->frame_rate.den = 1;
+
+   module->scale = mmal_port_clock_scale_get(component->clock[0]);
+
+   memset(&module->latency, 0, sizeof(module->latency));
+   module->latency.target = DEFAULT_CLOCK_LATENCY;
+
+   mmal_port_clock_update_threshold_get(component->clock[0], &module->update_threshold);
+   mmal_port_clock_discont_threshold_get(component->clock[0], &module->discont_threshold);
+   mmal_port_clock_request_threshold_get(component->clock[0], &module->request_threshold);
+
+   return status;
+
+ error:
+   clock_component_destroy(component);
+   return status;
+}
+
+
+/*****************************************************************************/
+MMAL_CONSTRUCTOR(mmal_register_component_clock);
+void mmal_register_component_clock(void)
+{
+   mmal_component_supplier_register("clock", mmal_component_create_clock);
+}
diff --git a/interface/mmal/components/container_reader.c b/interface/mmal/components/container_reader.c
new file mode 100755 (executable)
index 0000000..b4e77da
--- /dev/null
@@ -0,0 +1,1000 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "core/mmal_component_private.h"
+#include "core/mmal_port_private.h"
+#include "mmal_logging.h"
+
+#include "containers/containers.h"
+#include "containers/containers_codecs.h"
+#include "containers/core/containers_utils.h"
+
+#define READER_MAX_URI_LENGTH 1024
+
+#define WRITER_PORTS_NUM 3 /**< 3 ports should be enough for video + audio + subpicture */
+
+/* Buffering requirements */
+#define READER_MIN_BUFFER_SIZE (2*1024)
+#define READER_MIN_BUFFER_NUM 1
+#define READER_RECOMMENDED_BUFFER_SIZE (32*1024)
+#define READER_RECOMMENDED_BUFFER_NUM 10
+
+/*****************************************************************************/
+
+/** Private context for this component */
+typedef struct MMAL_COMPONENT_MODULE_T
+{
+   VC_CONTAINER_T *container;
+   char uri[READER_MAX_URI_LENGTH+1];
+   unsigned int ports;
+
+   MMAL_BOOL_T writer;
+   MMAL_BOOL_T error;
+
+   /* Reader specific */
+   MMAL_BOOL_T packet_logged;
+
+   /* Writer specific */
+   unsigned int port_last_used;
+   unsigned int port_writing_frame;
+
+} MMAL_COMPONENT_MODULE_T;
+
+typedef struct MMAL_PORT_MODULE_T
+{
+   unsigned int track;
+   MMAL_QUEUE_T *queue;
+
+   MMAL_BOOL_T flush;
+   MMAL_BOOL_T eos;
+
+   VC_CONTAINER_ES_FORMAT_T *format; /**< Format description for the elementary stream */
+
+} MMAL_PORT_MODULE_T;
+
+/*****************************************************************************/
+static struct {
+   VC_CONTAINER_FOURCC_T codec;
+   MMAL_FOURCC_T encoding;
+   VC_CONTAINER_FOURCC_T codec_variant;
+   MMAL_FOURCC_T encoding_variant;
+} encoding_table[] =
+{
+   {VC_CONTAINER_CODEC_H263,           MMAL_ENCODING_H263, 0, 0},
+   {VC_CONTAINER_CODEC_H264,           MMAL_ENCODING_H264, 0, 0},
+   {VC_CONTAINER_CODEC_H264,           MMAL_ENCODING_H264,
+      VC_CONTAINER_VARIANT_H264_AVC1,           MMAL_ENCODING_VARIANT_H264_AVC1},
+   {VC_CONTAINER_CODEC_H264,           MMAL_ENCODING_H264,
+      VC_CONTAINER_VARIANT_H264_RAW,            MMAL_ENCODING_VARIANT_H264_RAW},
+   {VC_CONTAINER_CODEC_MP4V,           MMAL_ENCODING_MP4V, 0, 0},
+   {VC_CONTAINER_CODEC_MP2V,           MMAL_ENCODING_MP2V, 0, 0},
+   {VC_CONTAINER_CODEC_MP1V,           MMAL_ENCODING_MP1V, 0, 0},
+   {VC_CONTAINER_CODEC_WMV3,           MMAL_ENCODING_WMV3, 0, 0},
+   {VC_CONTAINER_CODEC_WMV2,           MMAL_ENCODING_WMV2, 0, 0},
+   {VC_CONTAINER_CODEC_WMV1,           MMAL_ENCODING_WMV1, 0, 0},
+   {VC_CONTAINER_CODEC_WVC1,           MMAL_ENCODING_WVC1, 0, 0},
+   {VC_CONTAINER_CODEC_VP6,            MMAL_ENCODING_VP6, 0, 0},
+   {VC_CONTAINER_CODEC_VP7,            MMAL_ENCODING_VP7, 0, 0},
+   {VC_CONTAINER_CODEC_VP8,            MMAL_ENCODING_VP8, 0, 0},
+   {VC_CONTAINER_CODEC_THEORA,         MMAL_ENCODING_THEORA, 0, 0},
+   {VC_CONTAINER_CODEC_SPARK,          MMAL_ENCODING_SPARK, 0, 0},
+
+   {VC_CONTAINER_CODEC_GIF,            MMAL_ENCODING_GIF, 0, 0},
+   {VC_CONTAINER_CODEC_JPEG,           MMAL_ENCODING_JPEG, 0, 0},
+   {VC_CONTAINER_CODEC_PNG,            MMAL_ENCODING_PNG, 0, 0},
+   {VC_CONTAINER_CODEC_PPM,            MMAL_ENCODING_PPM, 0, 0},
+   {VC_CONTAINER_CODEC_TGA,            MMAL_ENCODING_TGA, 0, 0},
+   {VC_CONTAINER_CODEC_BMP,            MMAL_ENCODING_BMP, 0, 0},
+
+   {VC_CONTAINER_CODEC_PCM_SIGNED_BE,  MMAL_ENCODING_PCM_SIGNED_BE, 0, 0},
+   {VC_CONTAINER_CODEC_PCM_UNSIGNED_BE,MMAL_ENCODING_PCM_UNSIGNED_BE, 0, 0},
+   {VC_CONTAINER_CODEC_PCM_SIGNED_LE,  MMAL_ENCODING_PCM_SIGNED_LE, 0, 0},
+   {VC_CONTAINER_CODEC_PCM_UNSIGNED_LE,MMAL_ENCODING_PCM_UNSIGNED_LE, 0, 0},
+   {VC_CONTAINER_CODEC_PCM_FLOAT_BE,   MMAL_ENCODING_PCM_FLOAT_BE, 0, 0},
+   {VC_CONTAINER_CODEC_PCM_FLOAT_LE,   MMAL_ENCODING_PCM_FLOAT_LE, 0, 0},
+
+   {VC_CONTAINER_CODEC_MPGA,           MMAL_ENCODING_MPGA, 0, 0},
+   {VC_CONTAINER_CODEC_MP4A,           MMAL_ENCODING_MP4A, 0, 0},
+   {VC_CONTAINER_CODEC_ALAW,           MMAL_ENCODING_ALAW, 0, 0},
+   {VC_CONTAINER_CODEC_MULAW,          MMAL_ENCODING_MULAW, 0, 0},
+   {VC_CONTAINER_CODEC_ADPCM_MS,       MMAL_ENCODING_ADPCM_MS, 0, 0},
+   {VC_CONTAINER_CODEC_ADPCM_IMA_MS,   MMAL_ENCODING_ADPCM_IMA_MS, 0, 0},
+   {VC_CONTAINER_CODEC_ADPCM_SWF,      MMAL_ENCODING_ADPCM_SWF, 0, 0},
+   {VC_CONTAINER_CODEC_WMA1,           MMAL_ENCODING_WMA1, 0, 0},
+   {VC_CONTAINER_CODEC_WMA2,           MMAL_ENCODING_WMA2, 0, 0},
+   {VC_CONTAINER_CODEC_WMAP,           MMAL_ENCODING_WMAP, 0, 0},
+   {VC_CONTAINER_CODEC_WMAL,           MMAL_ENCODING_WMAL, 0, 0},
+   {VC_CONTAINER_CODEC_WMAV,           MMAL_ENCODING_WMAV, 0, 0},
+   {VC_CONTAINER_CODEC_AMRNB,          MMAL_ENCODING_AMRNB, 0, 0},
+   {VC_CONTAINER_CODEC_AMRWB,          MMAL_ENCODING_AMRWB, 0, 0},
+   {VC_CONTAINER_CODEC_AMRWBP,         MMAL_ENCODING_AMRWBP, 0, 0},
+   {VC_CONTAINER_CODEC_AC3,            MMAL_ENCODING_AC3, 0, 0},
+   {VC_CONTAINER_CODEC_EAC3,           MMAL_ENCODING_EAC3, 0, 0},
+   {VC_CONTAINER_CODEC_DTS,            MMAL_ENCODING_DTS, 0, 0},
+   {VC_CONTAINER_CODEC_MLP,            MMAL_ENCODING_MLP, 0, 0},
+   {VC_CONTAINER_CODEC_FLAC,           MMAL_ENCODING_FLAC, 0, 0},
+   {VC_CONTAINER_CODEC_VORBIS,         MMAL_ENCODING_VORBIS, 0, 0},
+   {VC_CONTAINER_CODEC_SPEEX,          MMAL_ENCODING_SPEEX, 0, 0},
+   {VC_CONTAINER_CODEC_ATRAC3,         MMAL_ENCODING_ATRAC3, 0, 0},
+   {VC_CONTAINER_CODEC_ATRACX,         MMAL_ENCODING_ATRACX, 0, 0},
+   {VC_CONTAINER_CODEC_ATRACL,         MMAL_ENCODING_ATRACL, 0, 0},
+   {VC_CONTAINER_CODEC_MIDI,           MMAL_ENCODING_MIDI, 0, 0},
+   {VC_CONTAINER_CODEC_EVRC,           MMAL_ENCODING_EVRC, 0, 0},
+   {VC_CONTAINER_CODEC_NELLYMOSER,     MMAL_ENCODING_NELLYMOSER, 0, 0},
+   {VC_CONTAINER_CODEC_QCELP,          MMAL_ENCODING_QCELP, 0, 0},
+
+   {VC_CONTAINER_CODEC_UNKNOWN,        MMAL_ENCODING_UNKNOWN, 0, 0}
+};
+
+static MMAL_FOURCC_T container_to_mmal_encoding(VC_CONTAINER_FOURCC_T codec)
+{
+   unsigned int i;
+   for(i = 0; encoding_table[i].codec != VC_CONTAINER_CODEC_UNKNOWN; i++)
+      if(encoding_table[i].codec == codec)
+         break;
+   return encoding_table[i].encoding;
+}
+
+static VC_CONTAINER_FOURCC_T mmal_to_container_encoding(uint32_t encoding)
+{
+   unsigned int i;
+   for(i = 0; encoding_table[i].codec != VC_CONTAINER_CODEC_UNKNOWN; i++)
+      if(encoding_table[i].encoding == encoding)
+         break;
+   return encoding_table[i].codec;
+}
+
+static MMAL_FOURCC_T container_to_mmal_variant(VC_CONTAINER_FOURCC_T codec,
+   VC_CONTAINER_FOURCC_T codec_variant)
+{
+   unsigned int i;
+   for(i = 0; encoding_table[i].codec != VC_CONTAINER_CODEC_UNKNOWN; i++)
+      if(encoding_table[i].codec == codec &&
+         encoding_table[i].codec_variant == codec_variant)
+         break;
+   return encoding_table[i].encoding_variant;
+}
+
+static VC_CONTAINER_FOURCC_T mmal_to_container_variant(MMAL_FOURCC_T encoding,
+   MMAL_FOURCC_T encoding_variant)
+{
+   unsigned int i;
+   for(i = 0; encoding_table[i].codec != VC_CONTAINER_CODEC_UNKNOWN; i++)
+      if(encoding_table[i].encoding == encoding &&
+         encoding_table[i].encoding_variant == encoding_variant)
+         break;
+   return encoding_table[i].codec_variant;
+}
+
+/*****************************************************************************/
+static struct {
+   VC_CONTAINER_ES_TYPE_T container_type;
+   MMAL_ES_TYPE_T type;
+} es_type_table[] =
+{
+   {VC_CONTAINER_ES_TYPE_VIDEO,          MMAL_ES_TYPE_VIDEO},
+   {VC_CONTAINER_ES_TYPE_AUDIO,          MMAL_ES_TYPE_AUDIO},
+   {VC_CONTAINER_ES_TYPE_SUBPICTURE,     MMAL_ES_TYPE_SUBPICTURE},
+   {VC_CONTAINER_ES_TYPE_UNKNOWN,        MMAL_ES_TYPE_UNKNOWN}
+};
+
+static MMAL_ES_TYPE_T container_to_mmal_es_type(VC_CONTAINER_ES_TYPE_T type)
+{
+   unsigned int i;
+   for(i = 0; es_type_table[i].container_type != VC_CONTAINER_ES_TYPE_UNKNOWN; i++)
+      if(es_type_table[i].container_type == type)
+         break;
+   return es_type_table[i].type;
+}
+
+static VC_CONTAINER_ES_TYPE_T mmal_to_container_es_type(MMAL_ES_TYPE_T type)
+{
+   unsigned int i;
+   for(i = 0; es_type_table[i].container_type != VC_CONTAINER_ES_TYPE_UNKNOWN; i++)
+      if(es_type_table[i].type == type)
+         break;
+   return es_type_table[i].container_type;
+}
+
+static MMAL_STATUS_T container_map_to_mmal_status(VC_CONTAINER_STATUS_T cstatus)
+{
+   switch (cstatus)
+   {
+      case VC_CONTAINER_SUCCESS: return MMAL_SUCCESS;
+      case VC_CONTAINER_ERROR_CORRUPTED: return MMAL_ECORRUPT;
+      case VC_CONTAINER_ERROR_OUT_OF_MEMORY: return MMAL_ENOMEM;
+      case VC_CONTAINER_ERROR_OUT_OF_RESOURCES: return MMAL_ENOSPC;
+      case VC_CONTAINER_ERROR_NOT_READY: return MMAL_ENOTREADY;
+      case VC_CONTAINER_ERROR_NOT_FOUND: return MMAL_ENOENT;
+      case VC_CONTAINER_ERROR_URI_NOT_FOUND: return MMAL_ENOENT;
+      default: return MMAL_EINVAL;
+   }
+}
+
+static MMAL_STATUS_T container_to_mmal_format(MMAL_ES_FORMAT_T *format,
+   VC_CONTAINER_ES_FORMAT_T *container_format)
+{
+   format->type = container_to_mmal_es_type(container_format->es_type);
+   if(format->type == MMAL_ES_TYPE_UNKNOWN)
+      return MMAL_EINVAL;
+
+   format->encoding = container_to_mmal_encoding(container_format->codec);
+   format->encoding_variant = container_to_mmal_variant(container_format->codec, container_format->codec_variant);
+   format->bitrate = container_format->bitrate;
+   format->flags = (container_format->flags & VC_CONTAINER_ES_FORMAT_FLAG_FRAMED) ?
+      MMAL_ES_FORMAT_FLAG_FRAMED : 0;
+   memset(format->es, 0, sizeof(*format->es));
+
+   switch(format->type)
+   {
+   case MMAL_ES_TYPE_VIDEO:
+      format->es->video.width = container_format->type->video.width;
+      format->es->video.height = container_format->type->video.height;
+      format->es->video.crop.width = container_format->type->video.visible_width;
+      format->es->video.crop.height = container_format->type->video.visible_height;
+      format->es->video.frame_rate.num = container_format->type->video.frame_rate_num;
+      format->es->video.frame_rate.den = container_format->type->video.frame_rate_den;
+      format->es->video.par.num = container_format->type->video.par_num;
+      format->es->video.par.den = container_format->type->video.par_den;
+      break;
+   case MMAL_ES_TYPE_AUDIO:
+      format->es->audio.channels = container_format->type->audio.channels;
+      format->es->audio.sample_rate = container_format->type->audio.sample_rate;
+      format->es->audio.bits_per_sample = container_format->type->audio.bits_per_sample;
+      format->es->audio.block_align = container_format->type->audio.block_align;
+      break;
+   default:
+      LOG_ERROR("format es type not handled (%i)", (int)format->type);
+      break;
+   }
+
+   if(container_format->extradata_size)
+   {
+      MMAL_STATUS_T status = mmal_format_extradata_alloc(format, container_format->extradata_size);
+      if(status != MMAL_SUCCESS)
+      {
+         LOG_ERROR("couldn't allocate extradata");
+         return status;
+      }
+      format->extradata_size = container_format->extradata_size;
+      memcpy(format->extradata, container_format->extradata, format->extradata_size);
+   }
+
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T mmal_to_container_format(VC_CONTAINER_ES_FORMAT_T *container_format,
+   MMAL_ES_FORMAT_T *format)
+{
+   container_format->es_type = mmal_to_container_es_type(format->type);
+   if(container_format->es_type == VC_CONTAINER_ES_TYPE_UNKNOWN)
+      return MMAL_EINVAL;
+
+   container_format->codec = mmal_to_container_encoding(format->encoding);
+   container_format->codec_variant = mmal_to_container_variant(format->encoding, format->encoding_variant);
+   container_format->bitrate = format->bitrate;
+   container_format->flags = 0;
+   if(format->flags & MMAL_ES_FORMAT_FLAG_FRAMED)
+      container_format->flags |= VC_CONTAINER_ES_FORMAT_FLAG_FRAMED;
+   memset(container_format->type, 0, sizeof(*container_format->type));
+
+   /* Auto-detect H264 AVC1 variant */
+   if(format->encoding == MMAL_ENCODING_H264 && !format->encoding_variant &&
+      format->extradata_size >= 5 && *format->extradata == 1)
+      container_format->codec_variant = VC_CONTAINER_VARIANT_H264_AVC1;
+
+   switch(format->type)
+   {
+   case MMAL_ES_TYPE_VIDEO:
+      container_format->type->video.width = format->es->video.width;
+      container_format->type->video.height = format->es->video.height;
+      container_format->type->video.frame_rate_num = format->es->video.frame_rate.num;
+      container_format->type->video.frame_rate_den = format->es->video.frame_rate.den;
+      container_format->type->video.par_num = format->es->video.par.num;
+      container_format->type->video.par_den = format->es->video.par.den;
+      break;
+   case MMAL_ES_TYPE_AUDIO:
+      container_format->type->audio.channels = format->es->audio.channels;
+      container_format->type->audio.sample_rate = format->es->audio.sample_rate;
+      container_format->type->audio.bits_per_sample = format->es->audio.bits_per_sample;
+      container_format->type->audio.block_align = format->es->audio.block_align;
+      break;
+   default:
+      LOG_ERROR("format es type not handled (%i)", (int)format->type);
+      break;
+   }
+
+   container_format->extradata_size = format->extradata_size;
+   container_format->extradata = format->extradata;
+
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+static void reader_do_processing(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_BUFFER_HEADER_T *buffer;
+   VC_CONTAINER_STATUS_T cstatus;
+   VC_CONTAINER_PACKET_T packet;
+   MMAL_STATUS_T status;
+   unsigned int i;
+
+   memset(&packet, 0, sizeof(packet));
+
+   while(1)
+   {
+      cstatus = vc_container_read(module->container, &packet, VC_CONTAINER_READ_FLAG_INFO);
+      if(cstatus == VC_CONTAINER_ERROR_CONTINUE)
+         continue;
+      if(cstatus != VC_CONTAINER_SUCCESS)
+      {
+         LOG_DEBUG("READ EOF (%i)", cstatus);
+         break;
+      }
+
+      if (!module->packet_logged)
+         LOG_DEBUG("packet info: track %i, size %i/%i, pts %"PRId64"%s, dts %"PRId64"%s, flags %x%s",
+                   packet.track, packet.size, packet.frame_size,
+                   packet.pts == VC_CONTAINER_TIME_UNKNOWN ? 0 : packet.pts,
+                   packet.pts == VC_CONTAINER_TIME_UNKNOWN ? ":unknown" : "",
+                   packet.dts == VC_CONTAINER_TIME_UNKNOWN ? 0 : packet.dts,
+                   packet.dts == VC_CONTAINER_TIME_UNKNOWN ? ":unknown" : "",
+                   packet.flags, (packet.flags & VC_CONTAINER_PACKET_FLAG_KEYFRAME) ? " (keyframe)" : "");
+
+      /* Find the port corresponding to that track */
+      for(i = 0; i < module->ports; i++)
+         if(component->output[i]->priv->module->track == packet.track)
+            break;
+      if(i == module->ports)
+      {
+         vc_container_read(module->container, 0, VC_CONTAINER_READ_FLAG_SKIP);
+         continue;
+      }
+
+      /* Get a buffer from this port */
+      buffer = mmal_queue_get(component->output[i]->priv->module->queue);
+      if(!buffer)
+      {
+         module->packet_logged = 1;
+         break; /* Try again next time */
+      }
+      module->packet_logged = 0;
+
+      if(component->output[i]->priv->module->flush)
+      {
+         buffer->length = 0;
+         component->output[i]->priv->module->flush = MMAL_FALSE;
+      }
+
+      mmal_buffer_header_mem_lock(buffer);
+      packet.data = buffer->data + buffer->length;
+      packet.buffer_size = buffer->alloc_size - buffer->length;
+      packet.size = 0;
+      cstatus = vc_container_read(module->container, &packet, 0);
+      mmal_buffer_header_mem_unlock(buffer);
+      if(cstatus != VC_CONTAINER_SUCCESS)
+      {
+         LOG_DEBUG("TEST read status: %i", cstatus);
+         mmal_queue_put_back(component->output[i]->priv->module->queue, buffer);
+         break;
+      }
+
+      if(!buffer->length)
+      {
+         buffer->pts = packet.pts == VC_CONTAINER_TIME_UNKNOWN ? MMAL_TIME_UNKNOWN : packet.pts;
+         buffer->dts = packet.dts == VC_CONTAINER_TIME_UNKNOWN ? MMAL_TIME_UNKNOWN : packet.dts;
+         buffer->flags = 0;
+         if(packet.flags & VC_CONTAINER_PACKET_FLAG_KEYFRAME)
+            buffer->flags |= MMAL_BUFFER_HEADER_FLAG_KEYFRAME;
+         if(packet.flags & VC_CONTAINER_PACKET_FLAG_FRAME_START)
+            buffer->flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_START;
+      }
+      if(packet.flags & VC_CONTAINER_PACKET_FLAG_FRAME_END)
+         buffer->flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END;
+#ifdef VC_CONTAINER_PACKET_FLAG_CONFIG
+      if(packet.flags & VC_CONTAINER_PACKET_FLAG_CONFIG)
+         buffer->flags |= MMAL_BUFFER_HEADER_FLAG_CONFIG;
+#endif
+
+      buffer->length += packet.size;
+
+      if((component->output[i]->format->flags & MMAL_ES_FORMAT_FLAG_FRAMED) &&
+         buffer->length != buffer->alloc_size &&
+         !(buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END))
+      {
+         mmal_queue_put_back(component->output[i]->priv->module->queue, buffer);
+         continue;
+      }
+
+      /* Send buffer back */
+      mmal_port_buffer_header_callback(component->output[i], buffer);
+   }
+
+   if(cstatus == VC_CONTAINER_ERROR_EOS)
+   {
+      /* Send an empty EOS buffer for each port */
+      for(i = 0; i < component->output_num; i++)
+      {
+         MMAL_PORT_T *port = component->output[i];
+         if(!port->is_enabled)
+            continue;
+         if(port->priv->module->eos)
+            continue;
+         /* Get a buffer from this port */
+         buffer = mmal_queue_get(port->priv->module->queue);
+         if(!buffer)
+            continue; /* Try again next time */
+         buffer->length = 0;
+         buffer->pts = buffer->dts = MMAL_TIME_UNKNOWN;
+         buffer->flags = MMAL_BUFFER_HEADER_FLAG_EOS;
+         /* Send buffer back */
+         port->priv->module->eos = 1;
+         mmal_port_buffer_header_callback(port, buffer);
+      }
+   }
+   else if(cstatus != VC_CONTAINER_SUCCESS && !module->error)
+   {
+      status = mmal_event_error_send(component, container_map_to_mmal_status(cstatus));
+      if (status != MMAL_SUCCESS)
+      {
+         LOG_ERROR("unable to send an error event buffer (%i)", (int)status);
+         return;
+      }
+      module->error = 1;
+   }
+
+   return;
+}
+
+/*****************************************************************************/
+static void writer_do_processing(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   VC_CONTAINER_STATUS_T cstatus;
+   MMAL_PORT_MODULE_T *port_module;
+   MMAL_PORT_T *port;
+   MMAL_STATUS_T status;
+   MMAL_BOOL_T eos;
+   int64_t timestamp, timestamp_current;
+   MMAL_BUFFER_HEADER_T *buffer;
+   VC_CONTAINER_PACKET_T packet;
+   unsigned int i, index;
+
+   if(module->error)
+      return;
+
+   /* Select the next port to read from based on earliest timestamp. Buffers without
+    * timestamps will end-up being prioritised. */
+   for(i = 0, index = module->port_last_used, port = 0, timestamp = INT64_C(0);
+       i < component->input_num; i++, index++)
+   {
+      if(index == component->input_num)
+         index = 0;
+
+      if(!component->input[index]->is_enabled)
+         continue;
+
+      buffer = mmal_queue_get(component->input[index]->priv->module->queue);
+      if(!buffer)
+         continue;
+
+      timestamp_current = buffer->dts;
+      if (timestamp_current == MMAL_TIME_UNKNOWN)
+         timestamp_current = buffer->pts;
+      if(!port)
+         timestamp = timestamp_current;
+
+      if(timestamp_current <= timestamp)
+      {
+         port = component->input[index];
+         timestamp = timestamp_current;
+         module->port_last_used = index;
+      }
+      mmal_queue_put_back(component->input[index]->priv->module->queue, buffer);
+   }
+
+   /* If a port is currently writing a frame then we override the decision to avoid
+    * splitting frames */
+   if(module->port_writing_frame && module->port_writing_frame - 1 < component->input_num &&
+      component->input[module->port_writing_frame-1]->is_enabled)
+      port = component->input[module->port_writing_frame-1];
+
+   if(!port)
+      return; /* nothing to write */
+
+   port_module = port->priv->module;
+
+   /* Get a buffer from this port */
+   buffer = mmal_queue_get(port_module->queue);
+   if(!buffer)
+      return; /* nothing to write */
+
+   mmal_buffer_header_mem_lock(buffer);
+   memset(&packet, 0, sizeof(packet));
+   packet.track = port_module->track;
+   packet.size = buffer->length;
+   packet.data = buffer->data + buffer->offset;
+   packet.pts = buffer->pts == MMAL_TIME_UNKNOWN ? VC_CONTAINER_TIME_UNKNOWN : buffer->pts;
+   packet.dts = buffer->dts == MMAL_TIME_UNKNOWN ? VC_CONTAINER_TIME_UNKNOWN  : buffer->dts;
+   if(buffer->flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
+      packet.flags |= VC_CONTAINER_PACKET_FLAG_KEYFRAME;
+   if(buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_START)
+      packet.flags |= VC_CONTAINER_PACKET_FLAG_FRAME_START;
+   if(buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END)
+      packet.flags |= VC_CONTAINER_PACKET_FLAG_FRAME_END;
+   eos = buffer->flags & MMAL_BUFFER_HEADER_FLAG_EOS;
+
+   if ((packet.flags & VC_CONTAINER_PACKET_FLAG_FRAME) == VC_CONTAINER_PACKET_FLAG_FRAME)
+      packet.frame_size = packet.size;
+   else
+      packet.frame_size = 0;
+
+   module->port_writing_frame = port->index + 1;
+   if((buffer->flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END) ||
+      !(port->format->flags & MMAL_ES_FORMAT_FLAG_FRAMED))
+      module->port_writing_frame = 0;
+
+   LOG_DEBUG("packet info: track %i, size %i/%i, pts %"PRId64", flags %x%s",
+             packet.track, packet.size, packet.frame_size, packet.pts,
+             packet.flags, (packet.flags & VC_CONTAINER_PACKET_FLAG_KEYFRAME) ? " (keyframe)" : "");
+
+   cstatus = vc_container_write(module->container, &packet);
+   mmal_buffer_header_mem_unlock(buffer);
+
+   /* Send buffer back */
+   buffer->length = 0;
+   mmal_port_buffer_header_callback(port, buffer);
+
+   /* Check for errors */
+   if(cstatus != VC_CONTAINER_SUCCESS)
+   {
+      LOG_ERROR("write failed (%i)", (int)cstatus);
+      status = mmal_event_error_send(component, container_map_to_mmal_status(cstatus));
+      if (status != MMAL_SUCCESS)
+      {
+         LOG_ERROR("unable to send an error event buffer (%i)", (int)status);
+         return;
+      }
+      module->error = 1;
+      return;
+   }
+
+   /* Generate EOS events */
+   if(eos)
+   {
+      MMAL_EVENT_END_OF_STREAM_T *event;
+      status = mmal_port_event_get(component->control, &buffer, MMAL_EVENT_EOS);
+      if (status != MMAL_SUCCESS)
+      {
+         LOG_ERROR("unable to get an event buffer");
+         return;
+      }
+
+      buffer->length = sizeof(*event);
+      event = (MMAL_EVENT_END_OF_STREAM_T *)buffer->data;
+      event->port_type = port->type;
+      event->port_index = port->index;
+      mmal_port_event_send(component->control, buffer);
+   }
+}
+
+/** Destroy a previously created component */
+static MMAL_STATUS_T container_component_destroy(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   unsigned int i;
+
+   if(module->container)
+      vc_container_close(module->container);
+
+   for(i = 0; i < component->input_num; i++)
+   {
+      if(component->input[i]->priv->module->queue)
+         mmal_queue_destroy(component->input[i]->priv->module->queue);
+      if(component->input[i]->priv->module->format)
+         vc_container_format_delete(component->input[i]->priv->module->format);
+   }
+   if(component->input_num)
+      mmal_ports_free(component->input, component->input_num);
+
+   for(i = 0; i < component->output_num; i++)
+      if(component->output[i]->priv->module->queue)
+         mmal_queue_destroy(component->output[i]->priv->module->queue);
+   if(component->output_num)
+      mmal_ports_free(component->output, component->output_num);
+
+   vcos_free(module);
+   return MMAL_SUCCESS;
+}
+
+/** Enable processing on a port */
+static MMAL_STATUS_T container_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_PORT_MODULE_T *port_module = port->priv->module;
+   MMAL_PARAM_UNUSED(cb);
+
+   if(!module->container)
+      return MMAL_EINVAL;
+
+   if(module->writer)
+   {
+      VC_CONTAINER_STATUS_T cstatus;
+      port_module->track = module->container->tracks_num;
+      cstatus = vc_container_control(module->container, VC_CONTAINER_CONTROL_TRACK_ADD,
+                                     port_module->format);
+      if(cstatus != VC_CONTAINER_SUCCESS)
+      {
+         LOG_ERROR("error adding track %4.4s (%i)", (char *)&port->format->encoding, (int)cstatus);
+         return container_map_to_mmal_status(cstatus);
+      }
+   }
+
+   if(port_module->track >= module->container->tracks_num)
+      {
+      LOG_ERROR("error 1 adding track %4.4s (%i/%i)", (char *)&port->format->encoding, port_module->track, module->container->tracks_num);
+      return MMAL_EINVAL;
+      }
+   module->container->tracks[port_module->track]->is_enabled = 1;
+   return MMAL_SUCCESS;
+}
+
+/** Flush a port */
+static MMAL_STATUS_T container_port_flush(MMAL_PORT_T *port)
+{
+   MMAL_PORT_MODULE_T *port_module = port->priv->module;
+   MMAL_BUFFER_HEADER_T *buffer;
+
+   /* Flush buffers that our component is holding on to.
+    * If the reading thread is holding onto a buffer it will send it back ASAP as well
+    * so no need to care about that.  */
+   buffer = mmal_queue_get(port_module->queue);
+   while(buffer)
+   {
+      buffer->length = 0;
+      mmal_port_buffer_header_callback(port, buffer);
+      buffer = mmal_queue_get(port_module->queue);
+   }
+
+   return MMAL_SUCCESS;
+}
+
+/** Disable processing on a port */
+static MMAL_STATUS_T container_port_disable(MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   unsigned int track = port->priv->module->track;
+   MMAL_STATUS_T status;
+
+   if(!module->container || track >= module->container->tracks_num)
+      return MMAL_EINVAL;
+
+   /* Actions are prevented from running at that point so a flush
+    * will return all buffers. */
+   status = container_port_flush(port);
+   if(status != MMAL_SUCCESS)
+      return status;
+
+   module->container->tracks[track]->is_enabled = 0;
+   return MMAL_SUCCESS;
+}
+
+/** Send a buffer header to a port */
+static MMAL_STATUS_T container_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   mmal_queue_put(port->priv->module->queue, buffer);
+   mmal_component_action_trigger(port->component);
+   return MMAL_SUCCESS;
+}
+
+/** Set format on a port */
+static MMAL_STATUS_T container_port_set_format(MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_STATUS_T status;
+
+   if(!module->writer)
+      return MMAL_EINVAL;
+
+   /* Set format of the track */
+   status = mmal_to_container_format(port->priv->module->format, port->format);
+   if (status != MMAL_SUCCESS)
+      return status;
+
+   port->buffer_num_min = READER_MIN_BUFFER_NUM;
+   port->buffer_num_recommended = READER_RECOMMENDED_BUFFER_NUM;
+   port->buffer_size_min = READER_MIN_BUFFER_SIZE;
+   port->buffer_size_recommended = READER_RECOMMENDED_BUFFER_SIZE;
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T reader_container_open(MMAL_COMPONENT_T *component, const char *uri)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   VC_CONTAINER_STATUS_T cstatus;
+   VC_CONTAINER_T *container;
+   unsigned int i, port, track;
+
+   /* Open container */
+   module->container = container =
+      vc_container_open_reader(uri, &cstatus, 0, 0);
+   if(!container)
+   {
+     LOG_ERROR("error opening file %s (%i)", uri, cstatus);
+     return container_map_to_mmal_status(cstatus);
+   }
+
+   /* Disable all tracks */
+   for(track = 0; track < container->tracks_num; track++)
+      container->tracks[track]->is_enabled = 0;
+
+   /* Fill-in the ports */
+   for(i = 0, port = 0; i < component->output_num; i++)
+   {
+      VC_CONTAINER_ES_TYPE_T type = VC_CONTAINER_ES_TYPE_VIDEO;
+      if(i == 1) type = VC_CONTAINER_ES_TYPE_AUDIO;
+      if(i == 2) type = VC_CONTAINER_ES_TYPE_SUBPICTURE;
+
+      /* Look for the first track with the specified type */
+      for(track = 0; track < container->tracks_num; track++)
+         if(container->tracks[track]->format->es_type == type)
+            break;
+      if(track == container->tracks_num)
+         continue;
+
+      if(container_to_mmal_encoding(container->tracks[track]->format->codec) == MMAL_ENCODING_UNKNOWN)
+         continue;
+
+      /* Set format of the port */
+      if(container_to_mmal_format(component->output[port]->format,
+                                  container->tracks[track]->format) != MMAL_SUCCESS)
+         continue;
+
+      component->output[port]->buffer_num_min = READER_MIN_BUFFER_NUM;
+      component->output[port]->buffer_num_recommended = READER_RECOMMENDED_BUFFER_NUM;
+      component->output[port]->buffer_size_min = READER_MIN_BUFFER_SIZE;
+      component->output[port]->buffer_size_recommended = READER_RECOMMENDED_BUFFER_SIZE;
+      component->output[port]->priv->module->track = track;
+
+      /* We're done with this port */
+      port++;
+   }
+   module->ports = port;
+
+   /* Reset the left over ports */
+   for(i = port; i < component->output_num; i++)
+   {
+      component->output[i]->format->type = MMAL_ES_TYPE_UNKNOWN;
+      component->output[i]->format->encoding = MMAL_ENCODING_UNKNOWN;
+   }
+
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T reader_container_seek(MMAL_COMPONENT_T *component, const MMAL_PARAMETER_SEEK_T *seek)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   VC_CONTAINER_SEEK_FLAGS_T flags = 0;
+   int64_t offset = seek->offset;
+   VC_CONTAINER_STATUS_T cstatus;
+   unsigned int i;
+
+   if(seek->flags & MMAL_PARAM_SEEK_FLAG_PRECISE)
+      flags |= VC_CONTAINER_SEEK_FLAG_PRECISE;
+   if(seek->flags & MMAL_PARAM_SEEK_FLAG_FORWARD)
+      flags |= VC_CONTAINER_SEEK_FLAG_FORWARD;
+
+   mmal_component_action_lock(component);
+   for(i = 0; i < component->output_num; i++)
+   {
+      component->output[i]->priv->module->eos = MMAL_FALSE;
+      component->output[i]->priv->module->flush = MMAL_TRUE;
+   }
+   cstatus = vc_container_seek( module->container, &offset, VC_CONTAINER_SEEK_MODE_TIME, flags);
+   mmal_component_action_unlock(component);
+   return container_map_to_mmal_status(cstatus);
+}
+
+static MMAL_STATUS_T reader_parameter_set(MMAL_PORT_T *port, const MMAL_PARAMETER_HEADER_T *param)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+
+   switch(param->id)
+   {
+   case MMAL_PARAMETER_URI:
+      if(module->container)
+         return MMAL_EINVAL;
+
+      memset(module->uri, 0, sizeof(module->uri));
+      strncpy(module->uri, ((const MMAL_PARAMETER_STRING_T *)param)->str, sizeof(module->uri)-1 );
+      return reader_container_open(component, module->uri);
+
+   case MMAL_PARAMETER_SEEK:
+      if(!module->container || param->size < sizeof(MMAL_PARAMETER_SEEK_T))
+         return MMAL_EINVAL;
+
+      return reader_container_seek(component, (const MMAL_PARAMETER_SEEK_T *)param);
+
+   default:
+      return MMAL_ENOSYS;
+   }
+
+   return MMAL_SUCCESS;
+}
+
+/** Create an instance of a component  */
+static MMAL_STATUS_T mmal_component_create_reader(const char *name, MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module;
+   unsigned int outputs_num, i;
+   MMAL_STATUS_T status = MMAL_ENOMEM;
+   MMAL_PARAM_UNUSED(name);
+
+   /* Allocate the context for our module */
+   component->priv->module = module = vcos_malloc(sizeof(*module), "mmal module");
+   if (!module)
+      return MMAL_ENOMEM;
+   memset(module, 0, sizeof(*module));
+
+   component->priv->pf_destroy = container_component_destroy;
+
+   /* Create 3 tracks for now (audio/video/subpicture).
+    * FIXME: ideally we should create 1 track per elementary stream. */
+   outputs_num = 3;
+
+   /* Now the component on reader has been created, we can allocate
+    * the ports for this component */
+   component->output = mmal_ports_alloc(component, outputs_num, MMAL_PORT_TYPE_OUTPUT,
+                                        sizeof(MMAL_PORT_MODULE_T));
+   if(!component->output)
+      goto error;
+   component->output_num = outputs_num;
+
+   for(i = 0; i < outputs_num; i++)
+   {
+      component->output[i]->priv->pf_enable = container_port_enable;
+      component->output[i]->priv->pf_disable = container_port_disable;
+      component->output[i]->priv->pf_flush = container_port_flush;
+      component->output[i]->priv->pf_send = container_port_send;
+      component->output[i]->priv->module->queue = mmal_queue_create();
+      if(!component->output[i]->priv->module->queue)
+         goto error;
+   }
+   component->control->priv->pf_parameter_set = reader_parameter_set;
+
+   status = mmal_component_action_register(component, reader_do_processing);
+   if (status != MMAL_SUCCESS)
+      goto error;
+
+   return MMAL_SUCCESS;
+
+ error:
+   container_component_destroy(component);
+   return status;
+}
+
+static MMAL_STATUS_T writer_parameter_set(MMAL_PORT_T *port, const MMAL_PARAMETER_HEADER_T *param)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   VC_CONTAINER_STATUS_T cstatus;
+
+   switch(param->id)
+   {
+   case MMAL_PARAMETER_URI:
+      if(module->container)
+         return MMAL_EINVAL;
+
+      memset(module->uri, 0, sizeof(module->uri));
+      strncpy(module->uri, ((const MMAL_PARAMETER_URI_T *)param)->uri, sizeof(module->uri)-1 );
+
+      /* Open container */
+      module->container = vc_container_open_writer(module->uri, &cstatus, 0, 0);
+      if(!module->container)
+      {
+         LOG_ERROR("error opening file %s (%i)", module->uri, cstatus);
+         return container_map_to_mmal_status(cstatus);
+      }
+      return MMAL_SUCCESS;
+
+   default:
+      return MMAL_ENOSYS;
+   }
+
+   return MMAL_SUCCESS;
+}
+
+/** Create an instance of a component  */
+static MMAL_STATUS_T mmal_component_create_writer(const char *name, MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module;
+   MMAL_STATUS_T status = MMAL_ENOMEM;
+   unsigned int i;
+   MMAL_PARAM_UNUSED(name);
+
+   /* Allocate the context for our module */
+   component->priv->module = module = vcos_malloc(sizeof(*module), "mmal module");
+   if (!module)
+      return MMAL_ENOMEM;
+   memset(module, 0, sizeof(*module));
+   module->writer = 1;
+
+   component->priv->pf_destroy = container_component_destroy;
+
+   /* Now the component on reader has been created, we can allocate
+    * the ports for this component */
+   component->input = mmal_ports_alloc(component, WRITER_PORTS_NUM, MMAL_PORT_TYPE_INPUT,
+                                        sizeof(MMAL_PORT_MODULE_T));
+   if(!component->input)
+      goto error;
+   component->input_num = WRITER_PORTS_NUM;
+
+   for(i = 0; i < component->input_num; i++)
+   {
+      component->input[i]->priv->pf_enable = container_port_enable;
+      component->input[i]->priv->pf_disable = container_port_disable;
+      component->input[i]->priv->pf_flush = container_port_flush;
+      component->input[i]->priv->pf_send = container_port_send;
+      component->input[i]->priv->pf_set_format = container_port_set_format;
+
+      component->input[i]->priv->module->queue = mmal_queue_create();
+      if(!component->input[i]->priv->module->queue)
+         goto error;
+      component->input[i]->priv->module->format = vc_container_format_create(0);
+      if(!component->input[i]->priv->module->format)
+         goto error;
+   }
+   component->control->priv->pf_parameter_set = writer_parameter_set;
+
+   status = mmal_component_action_register(component, writer_do_processing);
+   if (status != MMAL_SUCCESS)
+      goto error;
+
+   return MMAL_SUCCESS;
+
+ error:
+   container_component_destroy(component);
+   return status;
+}
+
+MMAL_CONSTRUCTOR(mmal_register_component_container_reader);
+void mmal_register_component_container_reader(void)
+{
+   mmal_component_supplier_register("container_reader", mmal_component_create_reader);
+}
+
+MMAL_CONSTRUCTOR(mmal_register_component_container_writer);
+void mmal_register_component_container_writer(void)
+{
+   mmal_component_supplier_register("container_writer", mmal_component_create_writer);
+}
diff --git a/interface/mmal/components/copy.c b/interface/mmal/components/copy.c
new file mode 100755 (executable)
index 0000000..1bbd952
--- /dev/null
@@ -0,0 +1,327 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "core/mmal_component_private.h"
+#include "core/mmal_port_private.h"
+#include "mmal_logging.h"
+
+/*****************************************************************************/
+typedef struct MMAL_COMPONENT_MODULE_T
+{
+   MMAL_STATUS_T status; /**< current status of the component */
+
+} MMAL_COMPONENT_MODULE_T;
+
+typedef struct MMAL_PORT_MODULE_T
+{
+   MMAL_QUEUE_T *queue; /**< queue for the buffers sent to the ports */
+   MMAL_BOOL_T needs_configuring; /**< port is waiting for a format commit */
+
+} MMAL_PORT_MODULE_T;
+
+/*****************************************************************************/
+
+/** Actual processing function */
+static MMAL_BOOL_T copy_do_processing(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_PORT_T *port_in = component->input[0];
+   MMAL_PORT_T *port_out = component->output[0];
+   MMAL_BUFFER_HEADER_T *in, *out;
+
+   if (port_out->priv->module->needs_configuring)
+      return 0;
+
+   in = mmal_queue_get(port_in->priv->module->queue);
+   if (!in)
+      return 0;
+
+   /* Handle event buffers */
+   if (in->cmd)
+   {
+      MMAL_EVENT_FORMAT_CHANGED_T *event = mmal_event_format_changed_get(in);
+      if (event)
+      {
+         module->status = mmal_format_full_copy(port_in->format, event->format);
+         if (module->status == MMAL_SUCCESS)
+            module->status = port_in->priv->pf_set_format(port_in);
+         if (module->status != MMAL_SUCCESS)
+         {
+            LOG_ERROR("format not set on port %s %p (%i)", port_in->name, port_in, module->status);
+            if (mmal_event_error_send(component, module->status) != MMAL_SUCCESS)
+               LOG_ERROR("unable to send an error event buffer");
+         }
+      }
+      else
+      {
+         LOG_ERROR("discarding event %i on port %s %p", (int)in->cmd, port_in->name, port_in);
+      }
+
+      in->length = 0;
+      mmal_port_buffer_header_callback(port_in, in);
+      return 1;
+   }
+
+   /* Don't do anything if we've already seen an error */
+   if (module->status != MMAL_SUCCESS)
+   {
+      mmal_queue_put_back(port_in->priv->module->queue, in);
+      return 0;
+   }
+
+   out = mmal_queue_get(port_out->priv->module->queue);
+   if (!out)
+   {
+      mmal_queue_put_back(port_in->priv->module->queue, in);
+      return 0;
+   }
+
+   /* Sanity check the output buffer is big enough */
+   if (out->alloc_size < in->length)
+   {
+      module->status = MMAL_EINVAL;
+      if (mmal_event_error_send(component, module->status) != MMAL_SUCCESS)
+         LOG_ERROR("unable to send an error event buffer");
+      return 0;
+   }
+
+   mmal_buffer_header_mem_lock(out);
+   mmal_buffer_header_mem_lock(in);
+   memcpy(out->data, in->data + in->offset, in->length);
+   mmal_buffer_header_mem_unlock(in);
+   mmal_buffer_header_mem_unlock(out);
+   out->length     = in->length;
+   out->offset     = 0;
+   out->flags      = in->flags;
+   out->pts        = in->pts;
+   out->dts        = in->dts;
+   *out->type      = *in->type;
+
+   /* Send buffers back */
+   in->length = 0;
+   mmal_port_buffer_header_callback(port_in, in);
+   mmal_port_buffer_header_callback(port_out, out);
+   return 1;
+}
+
+/*****************************************************************************/
+static void copy_do_processing_loop(MMAL_COMPONENT_T *component)
+{
+   while (copy_do_processing(component));
+}
+
+/** Destroy a previously created component */
+static MMAL_STATUS_T copy_component_destroy(MMAL_COMPONENT_T *component)
+{
+   unsigned int i;
+
+   for(i = 0; i < component->input_num; i++)
+      if(component->input[i]->priv->module->queue)
+         mmal_queue_destroy(component->input[i]->priv->module->queue);
+   if(component->input_num)
+      mmal_ports_free(component->input, component->input_num);
+
+   for(i = 0; i < component->output_num; i++)
+      if(component->output[i]->priv->module->queue)
+         mmal_queue_destroy(component->output[i]->priv->module->queue);
+   if(component->output_num)
+      mmal_ports_free(component->output, component->output_num);
+
+   vcos_free(component->priv->module);
+   return MMAL_SUCCESS;
+}
+
+/** Enable processing on a port */
+static MMAL_STATUS_T copy_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
+{
+   MMAL_PARAM_UNUSED(cb);
+
+   /* We need to propagate the buffer requirements when the input port is
+    * enabled */
+   if (port->type == MMAL_PORT_TYPE_INPUT)
+      return port->priv->pf_set_format(port);
+
+   return MMAL_SUCCESS;
+}
+
+/** Flush a port */
+static MMAL_STATUS_T copy_port_flush(MMAL_PORT_T *port)
+{
+   MMAL_PORT_MODULE_T *port_module = port->priv->module;
+   MMAL_BUFFER_HEADER_T *buffer;
+
+   /* Flush buffers that our component is holding on to */
+   buffer = mmal_queue_get(port_module->queue);
+   while(buffer)
+   {
+      mmal_port_buffer_header_callback(port, buffer);
+      buffer = mmal_queue_get(port_module->queue);
+   }
+
+   return MMAL_SUCCESS;
+}
+
+/** Disable processing on a port */
+static MMAL_STATUS_T copy_port_disable(MMAL_PORT_T *port)
+{
+   /* We just need to flush our internal queue */
+   return copy_port_flush(port);
+}
+
+/** Send a buffer header to a port */
+static MMAL_STATUS_T copy_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   mmal_queue_put(port->priv->module->queue, buffer);
+   mmal_component_action_trigger(port->component);
+   return MMAL_SUCCESS;
+}
+
+/** Set format on input port */
+static MMAL_STATUS_T copy_input_port_format_commit(MMAL_PORT_T *in)
+{
+   MMAL_COMPONENT_T *component = in->component;
+   MMAL_PORT_T *out = component->output[0];
+   MMAL_EVENT_FORMAT_CHANGED_T *event;
+   MMAL_BUFFER_HEADER_T *buffer;
+   MMAL_STATUS_T status;
+
+   /* Check if there's anything to propagate to the output port */
+   /* The format of the output port needs to match the input port */
+   if (!mmal_format_compare(in->format, out->format) &&
+       out->buffer_size_min == out->buffer_size_recommended &&
+       out->buffer_size_min == MMAL_MAX(in->buffer_size_min, in->buffer_size))
+      return MMAL_SUCCESS;
+
+   /* If the output port is not enabled we just need to update its format.
+    * Otherwise we'll have to trigger a format changed event for it. */
+   if (!out->is_enabled)
+   {
+      out->buffer_size_min = out->buffer_size_recommended =
+         MMAL_MAX(in->buffer_size, in->buffer_size_min);
+      return mmal_format_full_copy(out->format, in->format);
+   }
+
+   /* Send an event on the output port */
+   status = mmal_port_event_get(out, &buffer, MMAL_EVENT_FORMAT_CHANGED);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("unable to get an event buffer");
+      return status;
+   }
+
+   event = mmal_event_format_changed_get(buffer);
+   mmal_format_copy(event->format, in->format); /* FIXME: can full copy be done ? */
+
+   /* Pass on the buffer requirements */
+   event->buffer_num_min = out->buffer_num_min;
+   event->buffer_num_recommended = out->buffer_num_recommended;
+   event->buffer_size_min = event->buffer_size_recommended =
+      MMAL_MAX(in->buffer_size_min, in->buffer_size);
+
+   out->priv->module->needs_configuring = 1;
+   mmal_port_event_send(out, buffer);
+   return status;
+}
+
+/** Set format on output port */
+static MMAL_STATUS_T copy_output_port_format_commit(MMAL_PORT_T *out)
+{
+   MMAL_COMPONENT_T *component = out->component;
+   MMAL_PORT_T *in = component->input[0];
+
+   /* The format of the output port needs to match the input port */
+   if (mmal_format_compare(out->format, in->format))
+      return MMAL_EINVAL;
+
+   out->priv->module->needs_configuring = 0;
+   mmal_component_action_trigger(out->component);
+   return MMAL_SUCCESS;
+}
+
+/** Create an instance of a component  */
+static MMAL_STATUS_T mmal_component_create_copy(const char *name, MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module;
+   MMAL_STATUS_T status = MMAL_ENOMEM;
+   MMAL_PARAM_UNUSED(name);
+
+   /* Allocate the context for our module */
+   component->priv->module = module = vcos_malloc(sizeof(*module), "mmal module");
+   if (!module)
+      return MMAL_ENOMEM;
+   memset(module, 0, sizeof(*module));
+
+   component->priv->pf_destroy = copy_component_destroy;
+
+   /* Allocate and initialise all the ports for this component */
+   component->input = mmal_ports_alloc(component, 1, MMAL_PORT_TYPE_INPUT, sizeof(MMAL_PORT_MODULE_T));
+   if(!component->input)
+      goto error;
+   component->input_num = 1;
+   component->input[0]->priv->pf_enable = copy_port_enable;
+   component->input[0]->priv->pf_disable = copy_port_disable;
+   component->input[0]->priv->pf_flush = copy_port_flush;
+   component->input[0]->priv->pf_send = copy_port_send;
+   component->input[0]->priv->pf_set_format = copy_input_port_format_commit;
+   component->input[0]->buffer_num_min = 1;
+   component->input[0]->buffer_num_recommended = 0;
+   component->input[0]->priv->module->queue = mmal_queue_create();
+   if(!component->input[0]->priv->module->queue)
+      goto error;
+
+   component->output = mmal_ports_alloc(component, 1, MMAL_PORT_TYPE_OUTPUT, sizeof(MMAL_PORT_MODULE_T));
+   if(!component->output)
+      goto error;
+   component->output_num = 1;
+   component->output[0]->priv->pf_enable = copy_port_enable;
+   component->output[0]->priv->pf_disable = copy_port_disable;
+   component->output[0]->priv->pf_flush = copy_port_flush;
+   component->output[0]->priv->pf_send = copy_port_send;
+   component->output[0]->priv->pf_set_format = copy_output_port_format_commit;
+   component->output[0]->buffer_num_min = 1;
+   component->output[0]->buffer_num_recommended = 0;
+   component->output[0]->priv->module->queue = mmal_queue_create();
+   if(!component->output[0]->priv->module->queue)
+      goto error;
+
+   status = mmal_component_action_register(component, copy_do_processing_loop);
+   if (status != MMAL_SUCCESS)
+      goto error;
+
+   return MMAL_SUCCESS;
+
+ error:
+   copy_component_destroy(component);
+   return status;
+}
+
+MMAL_CONSTRUCTOR(mmal_register_component_copy);
+void mmal_register_component_copy(void)
+{
+   mmal_component_supplier_register("copy", mmal_component_create_copy);
+}
diff --git a/interface/mmal/components/null_sink.c b/interface/mmal/components/null_sink.c
new file mode 100755 (executable)
index 0000000..78c7144
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "core/mmal_component_private.h"
+#include "core/mmal_port_private.h"
+#include "mmal_logging.h"
+
+#define NULLSINK_PORTS_NUM 1
+
+/** Destroy a previously created component */
+static MMAL_STATUS_T null_sink_component_destroy(MMAL_COMPONENT_T *component)
+{
+   if(component->input_num)
+      mmal_ports_free(component->input, component->input_num);
+   return MMAL_SUCCESS;
+}
+
+/** Enable processing on a port */
+static MMAL_STATUS_T null_sink_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
+{
+   MMAL_PARAM_UNUSED(port);
+   MMAL_PARAM_UNUSED(cb);
+   return MMAL_SUCCESS;
+}
+
+/** Flush a port */
+static MMAL_STATUS_T null_sink_port_flush(MMAL_PORT_T *port)
+{
+   MMAL_PARAM_UNUSED(port);
+   return MMAL_SUCCESS;
+}
+
+/** Disable processing on a port */
+static MMAL_STATUS_T null_sink_port_disable(MMAL_PORT_T *port)
+{
+   MMAL_PARAM_UNUSED(port);
+   return MMAL_SUCCESS;
+}
+
+/** Send a buffer header to a port */
+static MMAL_STATUS_T null_sink_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_BOOL_T eos = buffer->flags & MMAL_BUFFER_HEADER_FLAG_EOS;
+
+   /* Send buffer back */
+   buffer->length = 0;
+   mmal_port_buffer_header_callback(port, buffer);
+
+   /* Generate EOS events */
+   if(eos)
+      return mmal_event_eos_send(port);
+
+   return MMAL_SUCCESS;
+}
+
+/** Set format on a port */
+static MMAL_STATUS_T null_sink_port_format_commit(MMAL_PORT_T *port)
+{
+   MMAL_PARAM_UNUSED(port);
+   return MMAL_SUCCESS;
+}
+
+/** Create an instance of a component  */
+static MMAL_STATUS_T mmal_component_create_null_sink(const char *name, MMAL_COMPONENT_T *component)
+{
+   MMAL_STATUS_T status = MMAL_ENOMEM;
+   unsigned int i;
+   MMAL_PARAM_UNUSED(name);
+
+   component->priv->pf_destroy = null_sink_component_destroy;
+
+   /* Allocate all the ports for this component */
+   component->input = mmal_ports_alloc(component, NULLSINK_PORTS_NUM, MMAL_PORT_TYPE_INPUT, 0);
+   if(!component->input)
+      goto error;
+   component->input_num = NULLSINK_PORTS_NUM;
+
+   for(i = 0; i < component->input_num; i++)
+   {
+      component->input[i]->priv->pf_enable = null_sink_port_enable;
+      component->input[i]->priv->pf_disable = null_sink_port_disable;
+      component->input[i]->priv->pf_flush = null_sink_port_flush;
+      component->input[i]->priv->pf_send = null_sink_port_send;
+      component->input[i]->priv->pf_set_format = null_sink_port_format_commit;
+      component->input[i]->buffer_num_min = 1;
+      component->input[i]->buffer_num_recommended = 1;
+   }
+
+   return MMAL_SUCCESS;
+
+ error:
+   null_sink_component_destroy(component);
+   return status;
+}
+
+MMAL_CONSTRUCTOR(mmal_register_component_null_sink);
+void mmal_register_component_null_sink(void)
+{
+   mmal_component_supplier_register("null_sink", mmal_component_create_null_sink);
+}
diff --git a/interface/mmal/components/passthrough.c b/interface/mmal/components/passthrough.c
new file mode 100755 (executable)
index 0000000..e51277d
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "core/mmal_component_private.h"
+#include "core/mmal_port_private.h"
+#include "mmal_logging.h"
+
+#define PASSTHROUGH_PORTS_NUM 1
+
+/*****************************************************************************/
+typedef struct MMAL_COMPONENT_MODULE_T
+{
+   MMAL_BOOL_T error;      /**< Error state */
+
+} MMAL_COMPONENT_MODULE_T;
+
+typedef struct MMAL_PORT_MODULE_T
+{
+   MMAL_QUEUE_T *queue; /**< queue for the buffers sent to the ports */
+
+} MMAL_PORT_MODULE_T;
+
+/*****************************************************************************/
+
+/** Destroy a previously created component */
+static MMAL_STATUS_T passthrough_component_destroy(MMAL_COMPONENT_T *component)
+{
+   unsigned int i;
+
+   for(i = 0; i < component->input_num; i++)
+      if(component->input[i]->priv->module->queue)
+         mmal_queue_destroy(component->input[i]->priv->module->queue);
+   if(component->input_num)
+      mmal_ports_free(component->input, component->input_num);
+
+   for(i = 0; i < component->output_num; i++)
+      if(component->output[i]->priv->module->queue)
+         mmal_queue_destroy(component->output[i]->priv->module->queue);
+   if(component->output_num)
+      mmal_ports_free(component->output, component->output_num);
+
+   vcos_free(component->priv->module);
+   return MMAL_SUCCESS;
+}
+
+/** Enable processing on a port */
+static MMAL_STATUS_T passthrough_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
+{
+   MMAL_PARAM_UNUSED(port);
+   MMAL_PARAM_UNUSED(cb);
+   return MMAL_SUCCESS;
+}
+
+/** Flush a port */
+static MMAL_STATUS_T passthrough_port_flush(MMAL_PORT_T *port)
+{
+   MMAL_PORT_MODULE_T *port_module = port->priv->module;
+   MMAL_BUFFER_HEADER_T *buffer;
+
+   /* Flush buffers that our component is holding on to */
+   buffer = mmal_queue_get(port_module->queue);
+   while(buffer)
+   {
+      mmal_port_buffer_header_callback(port, buffer);
+      buffer = mmal_queue_get(port_module->queue);
+   }
+
+   return MMAL_SUCCESS;
+}
+
+/** Disable processing on a port */
+static MMAL_STATUS_T passthrough_port_disable(MMAL_PORT_T *port)
+{
+   /* We just need to flush our internal queue */
+   return passthrough_port_flush(port);
+}
+
+/** Send a buffer header to a port */
+static MMAL_STATUS_T passthrough_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_PORT_T **other_port, *in_port, *out_port;
+   MMAL_BUFFER_HEADER_T **other_buffer, *in = 0, *out = 0;
+   MMAL_STATUS_T status;
+
+   if (module->error)
+   {
+      mmal_queue_put(port->priv->module->queue, buffer);
+      return MMAL_SUCCESS; /* Just do nothing */
+   }
+
+   in_port = port->component->input[port->index];
+   out_port = port->component->output[port->index];
+
+   if (port->type == MMAL_PORT_TYPE_INPUT)
+   {
+      other_port = &out_port;
+      other_buffer = &out;
+      in = buffer;
+   }
+   else
+   {
+      other_port = &in_port;
+      other_buffer = &in;
+      out = buffer;
+   }
+
+   /* Get a buffer header from the matching port */
+   *other_buffer = mmal_queue_get((*other_port)->priv->module->queue);
+   if (!*other_buffer)
+   {
+      /* None available. Just queue the buffer header for now. */
+      mmal_queue_put(port->priv->module->queue, buffer);
+      return MMAL_SUCCESS;
+   }
+
+   /* Copy our input buffer header */
+   status = mmal_buffer_header_replicate(out, in);
+   if (status != MMAL_SUCCESS)
+      goto error;
+
+   /* Consume the input buffer */
+   in->length = 0;
+
+   /* Send buffers back */
+   mmal_port_buffer_header_callback(in_port, in);
+   mmal_port_buffer_header_callback(out_port, out);
+
+   return MMAL_SUCCESS;
+
+ error:
+   mmal_queue_put(in_port->priv->module->queue, in);
+   mmal_queue_put(out_port->priv->module->queue, out);
+   status = mmal_event_error_send(port->component, status);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("unable to send an error event buffer (%i)", (int)status);
+      return MMAL_SUCCESS;
+   }
+   module->error = 1;
+   return MMAL_SUCCESS;
+}
+
+/** Set format on a port */
+static MMAL_STATUS_T passthrough_port_format_commit(MMAL_PORT_T *port)
+{
+   /* Sanity check */
+   if (port->type == MMAL_PORT_TYPE_OUTPUT)
+   {
+      LOG_ERROR("output port is read-only");
+      return MMAL_EINVAL;
+   }
+
+   return mmal_format_full_copy(port->component->output[port->index]->format, port->format);
+}
+
+static MMAL_STATUS_T passthrough_port_parameter_set(MMAL_PORT_T *port, const MMAL_PARAMETER_HEADER_T *param)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_PORT_T *in = component->input[port->index], *out = component->input[port->index];
+
+   switch (param->id)
+   {
+   case MMAL_PARAMETER_BUFFER_REQUIREMENTS:
+      {
+         /* Propagate the requirements to the matching input and output the ports */
+         const MMAL_PARAMETER_BUFFER_REQUIREMENTS_T *req = (const MMAL_PARAMETER_BUFFER_REQUIREMENTS_T *)param;
+         uint32_t buffer_num_min = MMAL_MAX(port->buffer_num_min, req->buffer_num_min);
+         uint32_t buffer_num_recommended = MMAL_MAX(port->buffer_num_recommended, req->buffer_num_recommended);
+         uint32_t buffer_size_min = MMAL_MAX(port->buffer_size_min, req->buffer_size_min);
+         uint32_t buffer_size_recommended = MMAL_MAX(port->buffer_size_recommended, req->buffer_size_recommended);
+
+         in->buffer_num_min = buffer_num_min;
+         in->buffer_num_recommended = buffer_num_recommended;
+         in->buffer_size_min = buffer_size_min;
+         in->buffer_size_recommended = buffer_size_recommended;
+         out->buffer_num_min = buffer_num_min;
+         out->buffer_num_recommended = buffer_num_recommended;
+         out->buffer_size_min = buffer_size_min;
+         out->buffer_size_recommended = buffer_size_recommended;
+      }
+      return MMAL_SUCCESS;
+
+   default:
+      return MMAL_ENOSYS;
+   }
+}
+
+/** Create an instance of a component  */
+static MMAL_STATUS_T mmal_component_create_passthrough(const char *name, MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module;
+   MMAL_STATUS_T status = MMAL_ENOMEM;
+   unsigned int i;
+   MMAL_PARAM_UNUSED(name);
+
+   /* Allocate the context for our module */
+   component->priv->module = module = vcos_malloc(sizeof(*module), "mmal module");
+   if (!module)
+      return MMAL_ENOMEM;
+   memset(module, 0, sizeof(*module));
+
+   component->priv->pf_destroy = passthrough_component_destroy;
+
+   /* Allocate and initialise all the ports for this component */
+   component->input = mmal_ports_alloc(component, PASSTHROUGH_PORTS_NUM,
+                                       MMAL_PORT_TYPE_INPUT, sizeof(MMAL_PORT_MODULE_T));
+   if(!component->input)
+      goto error;
+   component->input_num = PASSTHROUGH_PORTS_NUM;
+   for(i = 0; i < component->input_num; i++)
+   {
+      component->input[i]->priv->pf_enable = passthrough_port_enable;
+      component->input[i]->priv->pf_disable = passthrough_port_disable;
+      component->input[i]->priv->pf_flush = passthrough_port_flush;
+      component->input[i]->priv->pf_send = passthrough_port_send;
+      component->input[i]->priv->pf_set_format = passthrough_port_format_commit;
+      component->input[i]->priv->pf_parameter_set = passthrough_port_parameter_set;
+      component->input[i]->buffer_num_min = 1;
+      component->input[i]->buffer_num_recommended = 0;
+      component->input[i]->priv->module->queue = mmal_queue_create();
+      if(!component->input[i]->priv->module->queue)
+         goto error;
+   }
+
+   component->output = mmal_ports_alloc(component, PASSTHROUGH_PORTS_NUM,
+                                        MMAL_PORT_TYPE_OUTPUT, sizeof(MMAL_PORT_MODULE_T));
+   if(!component->output)
+      goto error;
+   component->output_num = PASSTHROUGH_PORTS_NUM;
+   for(i = 0; i < component->output_num; i++)
+   {
+      component->output[i]->priv->pf_enable = passthrough_port_enable;
+      component->output[i]->priv->pf_disable = passthrough_port_disable;
+      component->output[i]->priv->pf_flush = passthrough_port_flush;
+      component->output[i]->priv->pf_send = passthrough_port_send;
+      component->output[i]->priv->pf_set_format = passthrough_port_format_commit;
+      component->output[i]->priv->pf_parameter_set = passthrough_port_parameter_set;
+      component->output[i]->buffer_num_min = 1;
+      component->output[i]->buffer_num_recommended = 0;
+      component->output[i]->capabilities = MMAL_PORT_CAPABILITY_PASSTHROUGH;
+      component->output[i]->priv->module->queue = mmal_queue_create();
+      if(!component->output[i]->priv->module->queue)
+         goto error;
+   }
+
+   return MMAL_SUCCESS;
+
+ error:
+   passthrough_component_destroy(component);
+   return status;
+}
+
+MMAL_CONSTRUCTOR(mmal_register_component_passthrough);
+void mmal_register_component_passthrough(void)
+{
+   mmal_component_supplier_register("passthrough", mmal_component_create_passthrough);
+}
diff --git a/interface/mmal/components/scheduler.c b/interface/mmal/components/scheduler.c
new file mode 100755 (executable)
index 0000000..753b46a
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "mmal_logging.h"
+#include "core/mmal_port_private.h"
+#include "core/mmal_component_private.h"
+#include "core/mmal_clock_private.h"
+
+#define SCHEDULER_CLOCK_PORTS_NUM  1
+#define SCHEDULER_INPUT_PORTS_NUM  1
+#define SCHEDULER_OUTPUT_PORTS_NUM 1
+
+#define SCHEDULER_REQUEST_SLOTS 16
+
+/*****************************************************************************/
+typedef struct MMAL_COMPONENT_MODULE_T
+{
+   MMAL_STATUS_T status;     /**< current status of the component */
+} MMAL_COMPONENT_MODULE_T;
+
+
+typedef struct MMAL_PORT_MODULE_T
+{
+   MMAL_QUEUE_T *queue;      /**< queue for the buffers sent to the port */
+   int64_t last_ts;          /***< Last timestamp seen on the input port */
+} MMAL_PORT_MODULE_T;
+
+
+/*****************************************************************************/
+/** Process an event buffer */
+static MMAL_STATUS_T scheduler_event_process(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_STATUS_T status = MMAL_EINVAL;
+
+   if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED)
+   {
+      MMAL_EVENT_FORMAT_CHANGED_T *event =
+         mmal_event_format_changed_get(buffer);
+      if (!event)
+         goto end;
+
+      status = mmal_format_full_copy(port->format, event->format);
+      if (status == MMAL_SUCCESS)
+         status = mmal_port_format_commit(port);
+      if (status != MMAL_SUCCESS)
+      {
+         LOG_ERROR("format commit failed on port %s (%i)",
+                   port->name, status);
+         goto end;
+      }
+
+      status = MMAL_SUCCESS;
+   }
+   /* Forward any other event as is to the next component */
+   else
+   {
+      LOG_DEBUG("forwarding unknown event %4.4s", (char *)&buffer->cmd);
+      status = mmal_event_forward(buffer, port->component->output[port->index]);
+      if (status != MMAL_SUCCESS)
+      {
+         LOG_ERROR("unable to forward event %4.4s", (char *)&buffer->cmd);
+         goto end;
+      }
+   }
+
+ end:
+   buffer->length = 0;
+   mmal_port_buffer_header_callback(port, buffer);
+   return status;
+}
+
+/** Invoked when a clock request has been serviced */
+static void scheduler_component_clock_port_request_cb(MMAL_PORT_T *port, int64_t media_time, void *cb_data)
+{
+   MMAL_COMPONENT_T *component = port->component;;
+   MMAL_PORT_T *port_in = component->input[0];
+   MMAL_PORT_T *port_out = component->output[0];
+   MMAL_BUFFER_HEADER_T *buffer = (MMAL_BUFFER_HEADER_T*)cb_data;
+
+   LOG_TRACE("media-time %"PRIi64" pts %"PRIi64" delta %"PRIi64,
+         media_time, buffer->pts, media_time - buffer->pts);
+
+   if (buffer->cmd)
+      scheduler_event_process(port_in, buffer);
+   else
+      /* Forward the buffer to the next component */
+      mmal_port_buffer_header_callback(port_out, buffer);
+}
+
+/** Process buffers on the input and output ports */
+static MMAL_BOOL_T scheduler_component_process_buffers(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_PORT_T *port_in = component->input[0];
+   MMAL_PORT_T *port_out = component->output[0];
+   MMAL_QUEUE_T *queue_in = port_in->priv->module->queue;
+   MMAL_QUEUE_T *queue_out = port_out->priv->module->queue;
+   MMAL_BUFFER_HEADER_T *in, *out;
+   MMAL_STATUS_T cb_status = MMAL_EINVAL;
+
+   /* Don't do anything if we've already seen an error */
+   if (module->status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("module failure");
+      return MMAL_FALSE;
+   }
+
+   in = mmal_queue_get(queue_in);
+
+   /* Special case for dealing with event buffers */
+   if (in && in->cmd)
+   {
+      /* We normally schedule cmds so they come out in the right order,
+       * except when we don't know when to schedule them, which will only
+       * happen at the start of the stream.
+       * The fudge factor added to the last timestamp here is because the
+       * cmd really applies to the next buffer so we want to make sure
+       * we leave enough time to the next component to process the previous
+       * buffer before forwarding the event. */
+      in->pts = port_in->priv->module->last_ts + 1000;
+      if (in->pts != MMAL_TIME_UNKNOWN)
+         cb_status = mmal_port_clock_request_add(component->clock[0],
+            in->pts, scheduler_component_clock_port_request_cb, in);
+      if (cb_status != MMAL_SUCCESS)
+      {
+         if (in->pts != MMAL_TIME_UNKNOWN)
+            LOG_ERROR("failed to add request for cmd");
+         scheduler_event_process(port_in, in);
+      }
+      return MMAL_TRUE;
+   }
+
+   /* Need both an input and output buffer to be able to go any further */
+   out = mmal_queue_get(queue_out);
+   if (!in || !out)
+      goto end;
+
+   if (port_out->capabilities & MMAL_PORT_CAPABILITY_PASSTHROUGH)
+   {
+      /* Just need to keep a reference to the input buffer */
+      module->status = mmal_buffer_header_replicate(out, in);
+   }
+   else
+   {
+      /* Make a full copy of the input payload */
+      if (out->alloc_size < in->length)
+      {
+         LOG_ERROR("output buffer too small");
+
+         module->status = MMAL_EINVAL;
+         if (mmal_event_error_send(component, module->status) != MMAL_SUCCESS)
+            LOG_ERROR("unable to send an error event buffer");
+         goto end;
+      }
+      mmal_buffer_header_mem_lock(out);
+      mmal_buffer_header_mem_lock(in);
+      memcpy(out->data, in->data + in->offset, in->length);
+      mmal_buffer_header_mem_unlock(in);
+      mmal_buffer_header_mem_unlock(out);
+      out->length     = in->length;
+      out->offset     = 0;
+      out->flags      = in->flags;
+      out->pts        = in->pts;
+      out->dts        = in->dts;
+      *out->type      = *in->type;
+   }
+
+   /* Finished with the input buffer, so return it */
+   in->length = 0;
+   mmal_port_buffer_header_callback(port_in, in);
+   in = 0;
+
+   if (module->status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("failed to replicate buffer");
+      goto end;
+   }
+
+   /* Request a clock callback when media-time >= pts */
+   LOG_TRACE("requesting callback at %"PRIi64,out->pts);
+   port_in->priv->module->last_ts = out->pts;
+
+   cb_status = mmal_port_clock_request_add(component->clock[0], out->pts,
+      scheduler_component_clock_port_request_cb, out);
+   if (cb_status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("failed to add request");
+      out->length = 0;
+      mmal_port_buffer_header_callback(port_out, out);
+      if (cb_status != MMAL_ECORRUPT)
+         module->status = cb_status;
+   }
+   out = 0;
+
+ end:
+   if (in)
+      mmal_queue_put_back(queue_in, in);
+   if (out)
+      mmal_queue_put_back(queue_out, out);
+
+   return mmal_queue_length(queue_in) && mmal_queue_length(queue_out);
+}
+
+/** Main processing action */
+static void scheduler_component_action(MMAL_COMPONENT_T *component)
+{
+   /* Send requests to the clock */
+   while (scheduler_component_process_buffers(component));
+}
+
+/** Destroy a scheduler component */
+static MMAL_STATUS_T scheduler_component_destroy(MMAL_COMPONENT_T *component)
+{
+   unsigned int i;
+
+   for (i = 0; i < component->input_num; i++)
+      if (component->input[i]->priv->module->queue)
+         mmal_queue_destroy(component->input[i]->priv->module->queue);
+   if (component->input_num)
+      mmal_ports_free(component->input, component->input_num);
+
+   for (i = 0; i < component->output_num; i++)
+      if (component->output[i]->priv->module->queue)
+         mmal_queue_destroy(component->output[i]->priv->module->queue);
+   if (component->output_num)
+      mmal_ports_free(component->output, component->output_num);
+
+   if (component->clock_num)
+      mmal_ports_clock_free(component->clock, component->clock_num);
+
+   vcos_free(component->priv->module);
+   return MMAL_SUCCESS;
+}
+
+/** Enable processing on a port */
+static MMAL_STATUS_T scheduler_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
+{
+   MMAL_PARAM_UNUSED(port);
+   MMAL_PARAM_UNUSED(cb);
+   return MMAL_SUCCESS;
+}
+
+/** Flush a port */
+static MMAL_STATUS_T scheduler_port_flush(MMAL_PORT_T *port)
+{
+   MMAL_PORT_MODULE_T *port_module = port->priv->module;
+   MMAL_BUFFER_HEADER_T *buffer;
+
+   /* Flush buffers associated with pending clock requests */
+   mmal_port_clock_request_flush(port->component->clock[0]);
+
+   /* Flush buffers that our component is holding on to */
+   buffer = mmal_queue_get(port_module->queue);
+   while (buffer)
+   {
+      mmal_port_buffer_header_callback(port, buffer);
+      buffer = mmal_queue_get(port_module->queue);
+   }
+
+   port->priv->module->last_ts = MMAL_TIME_UNKNOWN;
+   return MMAL_SUCCESS;
+}
+
+/** Disable processing on a port */
+static MMAL_STATUS_T scheduler_port_disable(MMAL_PORT_T *port)
+{
+   /* We just need to flush our internal queue */
+   return scheduler_port_flush(port);
+}
+
+/** Send a buffer header to a port */
+static MMAL_STATUS_T scheduler_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_COMPONENT_T *component = port->component;
+
+   /* notify the clock port */
+   if (port->type == MMAL_PORT_TYPE_INPUT && !buffer->cmd)
+   {
+      MMAL_CLOCK_BUFFER_INFO_T info = { buffer->pts, vcos_getmicrosecs() };
+      mmal_port_clock_input_buffer_info(port->component->clock[0], &info);
+   }
+
+   mmal_queue_put(port->priv->module->queue, buffer);
+   return mmal_component_action_trigger(component);
+}
+
+/** Set format on an input port */
+static MMAL_STATUS_T scheduler_input_port_format_commit(MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_EVENT_FORMAT_CHANGED_T *event;
+   MMAL_PORT_T *output = component->output[0];
+   MMAL_BUFFER_HEADER_T *buffer;
+   MMAL_STATUS_T status;
+
+   /* If the output port is not enabled we just need to update its format.
+    * Otherwise we'll have to trigger a format changed event for it. */
+   if (!output->is_enabled)
+   {
+      status = mmal_format_full_copy(output->format, port->format);
+      return status;
+   }
+
+   /* Send an event on the output port */
+   status = mmal_port_event_get(output, &buffer, MMAL_EVENT_FORMAT_CHANGED);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("unable to get an event buffer");
+      return status;
+   }
+   event = mmal_event_format_changed_get(buffer);
+   if (!event)
+   {
+      mmal_buffer_header_release(buffer);
+      LOG_ERROR("failed to set format");
+      return MMAL_EINVAL;
+   }
+   mmal_format_copy(event->format, port->format);
+
+   /* Pass on the buffer requirements */
+   event->buffer_num_min = port->buffer_num_min;
+   event->buffer_size_min = port->buffer_size_min;
+   event->buffer_num_recommended = port->buffer_num_recommended;
+   event->buffer_size_recommended = port->buffer_size_recommended;
+
+   mmal_port_event_send(component->output[port->index], buffer);
+   return status;
+}
+
+/** Set format on an output port */
+static MMAL_STATUS_T scheduler_output_port_format_commit(MMAL_PORT_T *port)
+{
+   /* The format of the output port needs to match the input port */
+   if (mmal_format_compare(port->format, port->component->input[port->index]->format))
+      LOG_DEBUG("output port format different from input port");
+
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T scheduler_port_parameter_set(MMAL_PORT_T *port, const MMAL_PARAMETER_HEADER_T *param)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_PORT_T *in = component->input[port->index], *out = component->input[port->index];
+
+   switch (param->id)
+   {
+   case MMAL_PARAMETER_BUFFER_REQUIREMENTS:
+      {
+         /* Propagate the requirements to the matching input and output the ports */
+         const MMAL_PARAMETER_BUFFER_REQUIREMENTS_T *req = (const MMAL_PARAMETER_BUFFER_REQUIREMENTS_T *)param;
+         uint32_t buffer_num_min = MMAL_MAX(port->buffer_num_min, req->buffer_num_min);
+         uint32_t buffer_num_recommended = MMAL_MAX(port->buffer_num_recommended, req->buffer_num_recommended);
+         uint32_t buffer_size_min = MMAL_MAX(port->buffer_size_min, req->buffer_size_min);
+         uint32_t buffer_size_recommended = MMAL_MAX(port->buffer_size_recommended, req->buffer_size_recommended);
+
+         in->buffer_num_min = buffer_num_min;
+         in->buffer_num_recommended = buffer_num_recommended;
+         in->buffer_size_min = buffer_size_min;
+         in->buffer_size_recommended = buffer_size_recommended;
+         out->buffer_num_min = buffer_num_min;
+         out->buffer_num_recommended = buffer_num_recommended;
+         out->buffer_size_min = buffer_size_min;
+         out->buffer_size_recommended = buffer_size_recommended;
+      }
+      return MMAL_SUCCESS;
+
+   default:
+      return MMAL_ENOSYS;
+   }
+}
+
+/** Create an instance of a component  */
+static MMAL_STATUS_T mmal_component_create_scheduler(const char *name, MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module;
+   MMAL_STATUS_T status = MMAL_ENOMEM;
+   int disable_passthrough = 0;
+   unsigned int i;
+
+   /* Allocate the context for our module */
+   component->priv->module = module = vcos_calloc(1, sizeof(*module), "mmal module");
+   if (!module)
+      return MMAL_ENOMEM;
+
+   component->priv->pf_destroy = scheduler_component_destroy;
+
+   /* Allocate and initialise all the ports for this component */
+   component->input = mmal_ports_alloc(component, SCHEDULER_INPUT_PORTS_NUM,
+                                       MMAL_PORT_TYPE_INPUT, sizeof(MMAL_PORT_MODULE_T));
+   if (!component->input)
+      goto error;
+   component->input_num = SCHEDULER_INPUT_PORTS_NUM;
+   for (i = 0; i < component->input_num; i++)
+   {
+      component->input[i]->priv->pf_enable = scheduler_port_enable;
+      component->input[i]->priv->pf_disable = scheduler_port_disable;
+      component->input[i]->priv->pf_flush = scheduler_port_flush;
+      component->input[i]->priv->pf_send = scheduler_port_send;
+      component->input[i]->priv->pf_set_format = scheduler_input_port_format_commit;
+      component->input[i]->priv->pf_parameter_set = scheduler_port_parameter_set;
+      component->input[i]->buffer_num_min = 1;
+      component->input[i]->buffer_num_recommended = 0;
+      component->input[i]->capabilities = MMAL_PORT_CAPABILITY_SUPPORTS_EVENT_FORMAT_CHANGE;
+      component->input[i]->priv->module->queue = mmal_queue_create();
+      if (!component->input[i]->priv->module->queue)
+         goto error;
+      component->input[i]->priv->module->last_ts = MMAL_TIME_UNKNOWN;
+   }
+
+   /* Override passthrough behaviour */
+   if (strstr(name, ".copy"))
+   {
+      LOG_TRACE("disable passthrough on output ports");
+      disable_passthrough = 1;
+   }
+
+   component->output = mmal_ports_alloc(component, SCHEDULER_OUTPUT_PORTS_NUM,
+                                        MMAL_PORT_TYPE_OUTPUT, sizeof(MMAL_PORT_MODULE_T));
+   if (!component->output)
+      goto error;
+   component->output_num = SCHEDULER_OUTPUT_PORTS_NUM;
+   for (i = 0; i < component->output_num; i++)
+   {
+      component->output[i]->priv->pf_enable = scheduler_port_enable;
+      component->output[i]->priv->pf_disable = scheduler_port_disable;
+      component->output[i]->priv->pf_flush = scheduler_port_flush;
+      component->output[i]->priv->pf_send = scheduler_port_send;
+      component->output[i]->priv->pf_set_format = scheduler_output_port_format_commit;
+      component->output[i]->priv->pf_parameter_set = scheduler_port_parameter_set;
+      component->output[i]->buffer_num_min = 1;
+      component->output[i]->buffer_num_recommended = 0;
+      component->output[i]->capabilities = disable_passthrough ? 0 : MMAL_PORT_CAPABILITY_PASSTHROUGH;
+      component->output[i]->priv->module->queue = mmal_queue_create();
+      if (!component->output[i]->priv->module->queue)
+         goto error;
+   }
+
+   /* Create the clock port (clock ports are managed by the framework) */
+   component->clock = mmal_ports_clock_alloc(component, SCHEDULER_CLOCK_PORTS_NUM, 0, NULL);
+   if (!component->clock)
+      goto error;
+   component->clock_num = SCHEDULER_CLOCK_PORTS_NUM;
+
+   status = mmal_component_action_register(component, scheduler_component_action);
+   if (status != MMAL_SUCCESS)
+      goto error;
+
+   return MMAL_SUCCESS;
+
+error:
+   scheduler_component_destroy(component);
+   return status;
+}
+
+MMAL_CONSTRUCTOR(mmal_register_component_scheduler);
+void mmal_register_component_scheduler(void)
+{
+   mmal_component_supplier_register("scheduler", mmal_component_create_scheduler);
+}
+
diff --git a/interface/mmal/components/sdl_audio_render.c b/interface/mmal/components/sdl_audio_render.c
new file mode 100755 (executable)
index 0000000..43c2ff2
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "mmal_logging.h"
+#include "core/mmal_component_private.h"
+#include "core/mmal_port_private.h"
+
+#include <SDL/SDL.h>
+
+#define FRAME_LENGTH 2048
+
+/* Buffering requirements */
+#define INPUT_MIN_BUFFER_NUM 4
+#define INPUT_RECOMMENDED_BUFFER_NUM 8
+
+/****************************/
+typedef struct MMAL_COMPONENT_MODULE_T
+{
+   MMAL_STATUS_T status;
+   MMAL_QUEUE_T *queue;
+   MMAL_BOOL_T audio_opened;
+
+} MMAL_COMPONENT_MODULE_T;
+
+/** Destroy a previously created component */
+static MMAL_STATUS_T sdl_component_destroy(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+
+   if (module->audio_opened)
+      SDL_CloseAudio();
+   SDL_QuitSubSystem(SDL_INIT_AUDIO);
+
+   if(component->input_num) mmal_ports_free(component->input, 1);
+   if(module->queue) mmal_queue_destroy(module->queue);
+   vcos_free(module);
+   return MMAL_SUCCESS;
+}
+
+static void sdl_callback( void *ctx, uint8_t *stream, int size )
+{
+   MMAL_PORT_T *port = (MMAL_PORT_T *)ctx;
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_BUFFER_HEADER_T *buffer;
+   unsigned int i, bytes;
+
+   while (size > 0)
+   {
+      buffer = mmal_queue_get(module->queue);
+      if (!buffer)
+      {
+         LOG_ERROR("audio underrun");
+         return;
+      }
+
+      if (port->format->encoding == MMAL_ENCODING_PCM_SIGNED &&
+          port->format->es->audio.bits_per_sample == 16)
+      {
+         bytes = buffer->length;
+         if (bytes > (unsigned int)size) bytes = size;
+         memcpy(stream, buffer->data + buffer->offset, bytes);
+         buffer->offset += bytes;
+         buffer->length -= bytes;
+         stream += bytes;
+         size -= bytes;
+      }
+      else if (port->format->es->audio.bits_per_sample == 32)
+      {
+         bytes = buffer->length;
+         if (bytes > 2 * (unsigned int)size) bytes = 2 * size;
+         vcos_assert(!(bytes&0x3));
+
+         if (port->format->encoding == MMAL_ENCODING_PCM_FLOAT)
+         {
+            float *in = (float *)(buffer->data + buffer->offset);
+            int16_t *out = (int16_t *)stream;
+            for (i = 0; i < bytes / 4; i++)
+            {
+               if (*in >= 1.0) *out = 32767;
+               else if (*in < -1.0) *out = -32768;
+               else *out = *in * 32768.0;
+               in++; out++;
+            }
+         }
+         else if (port->format->encoding == MMAL_ENCODING_PCM_SIGNED)
+         {
+            int32_t *in = (int32_t *)(buffer->data + buffer->offset);
+            int16_t *out = (int16_t *)stream;
+            for (i = 0; i < bytes / 4; i++)
+               *out++ = (*in++) >> 16;
+         }
+         buffer->offset += bytes;
+         buffer->length -= bytes;
+         stream += bytes / 2;
+         size -= bytes / 2;
+      }
+
+      if (buffer->length)
+      {
+         /* We still have some data left for next time */
+         mmal_queue_put_back(module->queue, buffer);
+         continue;
+      }
+
+      /* Handle the EOS */
+      if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_EOS)
+         mmal_event_eos_send(port);
+
+      buffer->offset = 0;
+      mmal_port_buffer_header_callback(port, buffer);
+   }
+}
+
+/** Set format on a port */
+static MMAL_STATUS_T sdl_port_set_format(MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   SDL_AudioSpec desired, obtained;
+
+   if (port->format->encoding != MMAL_ENCODING_PCM_SIGNED &&
+       port->format->encoding != MMAL_ENCODING_PCM_FLOAT &&
+       port->format->es->audio.bits_per_sample != 16 &&
+      port->format->es->audio.bits_per_sample != 32)
+   {
+      LOG_ERROR("port does not support '%4.4s' at %ibps",
+                (char *)&port->format->encoding, port->format->es->audio.bits_per_sample);
+      return MMAL_EINVAL;
+   }
+
+   if (module->audio_opened)
+      SDL_CloseAudio();
+   module->audio_opened = MMAL_FALSE;
+
+   desired.freq       = port->format->es->audio.sample_rate;
+   desired.format     = AUDIO_S16SYS;
+   desired.channels   = port->format->es->audio.channels;
+   desired.callback   = sdl_callback;
+   desired.userdata   = port;
+   desired.samples    = FRAME_LENGTH;
+
+   /* Open the sound device. */
+   if (SDL_OpenAudio( &desired, &obtained ) < 0)
+       return MMAL_ENOSYS;
+   module->audio_opened = MMAL_TRUE;
+
+   /* Now have a look at what we got. */
+   if (obtained.format != AUDIO_S16SYS)
+      return MMAL_ENOSYS;
+
+   port->format->es->audio.sample_rate = obtained.freq;
+   port->format->es->audio.channels = obtained.channels;
+   port->buffer_size_min = obtained.samples * port->format->es->audio.channels * 2;
+
+   return MMAL_SUCCESS;
+}
+
+/** Enable processing on a port */
+static MMAL_STATUS_T sdl_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
+{
+   MMAL_PARAM_UNUSED(port);
+   MMAL_PARAM_UNUSED(cb);
+   SDL_PauseAudio( 0 );
+   return MMAL_SUCCESS;
+}
+
+/** Disable processing on a port */
+static MMAL_STATUS_T sdl_port_disable(MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_BUFFER_HEADER_T *buffer;
+
+   SDL_PauseAudio( 1 );
+
+   while((buffer = mmal_queue_get(module->queue)))
+      mmal_port_buffer_header_callback(port, buffer);
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T sdl_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+
+   /* Handle event buffers */
+   if (buffer->cmd)
+   {
+      LOG_ERROR("discarding event %i on port %p", (int)buffer->cmd, port);
+      buffer->length = 0;
+      mmal_port_buffer_header_callback(port, buffer);
+      return MMAL_SUCCESS;
+   }
+
+   if (module->status != MMAL_SUCCESS)
+      return module->status;
+
+   mmal_queue_put(module->queue, buffer);
+
+   return MMAL_SUCCESS;
+}
+
+/** Create an instance of a component  */
+static MMAL_STATUS_T mmal_component_create_sdl(const char *name, MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module;
+
+   /* Check we're the requested component */
+   if(strcmp(name, "sdl." MMAL_AUDIO_RENDER))
+      return MMAL_ENOENT;
+
+   if( SDL_WasInit(SDL_INIT_AUDIO) )
+      return MMAL_ENXIO;
+
+   /* Allocate our module context */
+   component->priv->module = module = vcos_calloc(1, sizeof(*module), "mmal module");
+   if(!module)
+      return MMAL_ENOMEM;
+
+   if(SDL_Init(SDL_INIT_AUDIO|SDL_INIT_NOPARACHUTE) < 0)
+      return MMAL_ENXIO;
+
+   /* Allocate the ports for this component */
+   component->input = mmal_ports_alloc(component, 1, MMAL_PORT_TYPE_INPUT, 0);
+   if(!component->input)
+      goto error;
+   component->input_num = 1;
+
+   module->queue = mmal_queue_create();
+   if(!module->queue)
+      goto error;
+
+   component->input[0]->priv->pf_set_format = sdl_port_set_format;
+   component->input[0]->priv->pf_enable = sdl_port_enable;
+   component->input[0]->priv->pf_disable = sdl_port_disable;
+   component->input[0]->priv->pf_send = sdl_port_send;
+   component->input[0]->buffer_num_min = INPUT_MIN_BUFFER_NUM;
+   component->input[0]->buffer_num_recommended = INPUT_RECOMMENDED_BUFFER_NUM;
+
+   component->priv->pf_destroy = sdl_component_destroy;
+   return MMAL_SUCCESS;
+
+ error:
+   sdl_component_destroy(component);
+   return MMAL_ENOMEM;
+}
+
+MMAL_CONSTRUCTOR(mmal_register_component_sdl_audio);
+void mmal_register_component_sdl_audio(void)
+{
+   mmal_component_supplier_register("sdl", mmal_component_create_sdl);
+}
diff --git a/interface/mmal/components/sdl_video_render.c b/interface/mmal/components/sdl_video_render.c
new file mode 100755 (executable)
index 0000000..6f95d96
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "mmal_logging.h"
+#include "core/mmal_component_private.h"
+#include "core/mmal_port_private.h"
+
+#include <SDL/SDL.h>
+
+#define NUM_PORTS_INPUT 1
+#define SDL_WIDTH 800
+#define SDL_HEIGHT 600
+
+/* Buffering requirements */
+#define INPUT_MIN_BUFFER_NUM 1
+#define INPUT_RECOMMENDED_BUFFER_NUM 4
+
+/****************************/
+typedef struct MMAL_COMPONENT_MODULE_T
+{
+   SDL_Overlay *sdl_overlay;
+   SDL_Surface *sdl_surface;
+   unsigned int width;
+   unsigned int height;
+   MMAL_STATUS_T status;
+   MMAL_RECT_T display_region;
+
+   MMAL_QUEUE_T *queue;
+
+   SDL_Thread *thread;
+   MMAL_BOOL_T quit;
+} MMAL_COMPONENT_MODULE_T;
+
+static MMAL_STATUS_T sdl_port_parameter_set(MMAL_PORT_T *port, const MMAL_PARAMETER_HEADER_T *param)
+{
+   MMAL_STATUS_T status = MMAL_ENOSYS;
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+
+   switch (param->id)
+   {
+   case MMAL_PARAMETER_DISPLAYREGION:
+      {
+         /* We only support setting the destination rectangle */
+         const MMAL_DISPLAYREGION_T *display = (const MMAL_DISPLAYREGION_T *)param;
+         if (display->set & MMAL_DISPLAY_SET_DEST_RECT)
+            module->display_region = display->dest_rect;
+         status = MMAL_SUCCESS;
+      }
+      break;
+   default:
+      break;
+   }
+   return status;
+}
+
+/** Destroy a previously created component */
+static MMAL_STATUS_T sdl_component_destroy(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   SDL_Event event = {SDL_QUIT};
+
+   module->quit = MMAL_TRUE;
+   SDL_PushEvent(&event);
+   if(module->thread)
+      SDL_WaitThread(module->thread, NULL);
+   if(module->sdl_overlay)
+      SDL_FreeYUVOverlay(module->sdl_overlay);
+   if(module->sdl_surface)
+      SDL_FreeSurface(module->sdl_surface);
+   SDL_QuitSubSystem(SDL_INIT_VIDEO);
+
+   if(component->input_num) mmal_ports_free(component->input, 1);
+   if(module->queue) mmal_queue_destroy(module->queue);
+   vcos_free(module);
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T mmal_sdl_create_surface(MMAL_COMPONENT_MODULE_T *module)
+{
+   uint32_t flags;
+   int bpp;
+   int w = module->display_region.width;
+   int h = module->display_region.height;
+
+   flags = SDL_ANYFORMAT | SDL_HWPALETTE | SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_RESIZABLE;
+   bpp = SDL_VideoModeOK(w, h, 16, flags);
+   if(!bpp)
+   {
+      LOG_ERROR("no SDL video mode available");
+      return MMAL_ENOSYS;
+   }
+   module->sdl_surface = SDL_SetVideoMode(w, h, bpp, flags); 
+   if(!module->sdl_surface)
+   {
+      LOG_ERROR("cannot create SDL surface");
+      return MMAL_ENOMEM;
+   }
+   return MMAL_SUCCESS;
+}
+
+
+/** Set format on a port */
+static MMAL_STATUS_T sdl_port_set_format(MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_STATUS_T status;
+
+   if ((status=mmal_sdl_create_surface(module)) != MMAL_SUCCESS)
+      return status;
+
+   /* We only support I420 */
+   if (port->format->encoding != MMAL_ENCODING_I420)
+      return MMAL_ENOSYS;
+
+   /* Check if we need to re-create an overlay */
+   if (module->sdl_overlay &&
+       module->width == port->format->es->video.width &&
+       module->height == port->format->es->video.height)
+      return MMAL_SUCCESS; /* Nothing to do */
+
+   if (module->sdl_overlay)
+      SDL_FreeYUVOverlay(module->sdl_overlay);
+
+   /* Create overlay */
+   module->sdl_overlay =
+      SDL_CreateYUVOverlay(port->format->es->video.width,
+                           port->format->es->video.height,
+                           SDL_YV12_OVERLAY, module->sdl_surface);
+   if (!module->sdl_overlay)
+   {
+      LOG_ERROR("cannot create SDL overlay");
+      return MMAL_ENOSPC;
+   }
+   module->width = port->format->es->video.width;
+   module->height = port->format->es->video.height;
+
+   port->buffer_size_min = module->width * module->height * 3 / 2;
+   return MMAL_SUCCESS;
+}
+
+/** Enable processing on a port */
+static MMAL_STATUS_T sdl_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
+{
+   MMAL_PARAM_UNUSED(port);
+   MMAL_PARAM_UNUSED(cb);
+   return MMAL_SUCCESS;
+}
+
+/** Disable processing on a port */
+static MMAL_STATUS_T sdl_port_disable(MMAL_PORT_T *port)
+{
+   MMAL_PARAM_UNUSED(port);
+   return MMAL_SUCCESS;
+}
+
+/** Flush a port */
+static MMAL_STATUS_T sdl_port_flush(MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_BUFFER_HEADER_T *buffer;
+
+   /* Flush buffers that our component is holding on to.
+    * If the reading thread is holding onto a buffer it will send it back ASAP as well
+    * so no need to care about that.  */
+   while((buffer = mmal_queue_get(module->queue)))
+      mmal_port_buffer_header_callback(port, buffer);
+
+   return MMAL_SUCCESS;
+}
+
+static MMAL_BOOL_T sdl_do_processing(MMAL_COMPONENT_T *component)
+{
+   MMAL_PORT_T *port = component->input[0];
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   unsigned int width = port->format->es->video.width;
+   unsigned int height = port->format->es->video.height;
+   MMAL_BUFFER_HEADER_T *buffer;
+   uint8_t *src_plane[3];
+   uint32_t *src_pitch;
+   unsigned int i, line;
+   MMAL_BOOL_T eos;
+   SDL_Rect rect;
+
+   buffer = mmal_queue_get(module->queue);
+   if (!buffer)
+          return 0;
+
+   eos = buffer->flags & MMAL_BUFFER_HEADER_FLAG_EOS;
+
+   /* Handle event buffers */
+   if (buffer->cmd)
+   {
+      MMAL_EVENT_FORMAT_CHANGED_T *event = mmal_event_format_changed_get(buffer);
+      if (event)
+      {
+         mmal_format_copy(port->format, event->format);
+         module->status = port->priv->pf_set_format(port);
+         if (module->status != MMAL_SUCCESS)
+         {
+            LOG_ERROR("format not set on port %p", port);
+            if (mmal_event_error_send(port->component, module->status) != MMAL_SUCCESS)
+               LOG_ERROR("unable to send an error event buffer");
+         }
+      }
+      else
+      {
+         LOG_ERROR("discarding event %i on port %p", (int)buffer->cmd, port);
+      }
+
+      buffer->length = 0;
+      mmal_port_buffer_header_callback(port, buffer);
+      return 1;
+   }
+
+   if (module->status != MMAL_SUCCESS)
+      return 1;
+
+   /* Ignore empty buffers */
+   if (!buffer->length)
+      goto end;
+
+   // FIXME: sanity check the size of the buffer
+
+   /* Blit the buffer onto the overlay. */
+   src_pitch = buffer->type->video.pitch;
+   src_plane[0] = buffer->data + buffer->type->video.offset[0];
+   src_plane[1] = buffer->data + buffer->type->video.offset[2];
+   src_plane[2] = buffer->data + buffer->type->video.offset[1];
+
+   SDL_LockYUVOverlay(module->sdl_overlay);
+   for (i=0; i<3; i++)
+   {
+      uint8_t *src = src_plane[i];
+      uint8_t *dst = module->sdl_overlay->pixels[i];
+
+      if(i == 1) {width /= 2; height /= 2;}
+      for(line = 0; line < height; line++)
+      {
+         memcpy(dst, src, width);
+         src += src_pitch[i];
+         dst += module->sdl_overlay->pitches[i];
+      }
+   }
+   SDL_UnlockYUVOverlay(module->sdl_overlay);
+
+   width = port->format->es->video.width;
+   height = port->format->es->video.height;
+   rect.x = module->display_region.x;
+   rect.w = module->display_region.width;
+   height = rect.w * height / width;
+   rect.y = module->display_region.y + (module->display_region.height - height) / 2;
+   rect.h = height;
+
+   SDL_DisplayYUVOverlay(module->sdl_overlay, &rect);
+
+ end:
+   buffer->offset = buffer->length = 0;
+   mmal_port_buffer_header_callback(port, buffer);
+
+   /* Generate EOS events */
+   if (eos)
+      mmal_event_eos_send(port);
+
+   return 1;
+}
+
+/*****************************************************************************/
+static void sdl_do_processing_loop(MMAL_COMPONENT_T *component)
+{
+   while (sdl_do_processing(component));
+}
+
+/** Buffer sending */
+static MMAL_STATUS_T sdl_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+
+   mmal_queue_put(module->queue, buffer);
+   mmal_component_action_trigger(port->component);
+
+   return MMAL_SUCCESS;
+}
+
+/** SDL event thread */
+static int sdl_event_thread(void *arg)
+{
+   MMAL_COMPONENT_T *component = (MMAL_COMPONENT_T *)arg;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   SDL_Event event;
+
+   while (SDL_WaitEvent(&event))
+   {
+      switch (event.type)
+      {
+      case SDL_QUIT:
+         if (!module->quit)
+            mmal_event_error_send(component, MMAL_SUCCESS);
+         return 0;
+      default:
+         break;
+      }
+   }
+
+   return 0;
+}
+
+/** Create an instance of a component  */
+static MMAL_STATUS_T mmal_component_create_sdl(const char *name, MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module;
+   MMAL_STATUS_T status = MMAL_ENOMEM;
+
+   /* Check we're the requested component */
+   if(strcmp(name, "sdl." MMAL_VIDEO_RENDER))
+      return MMAL_ENOENT;
+
+   if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_EVENTTHREAD|SDL_INIT_NOPARACHUTE) < 0)
+      return MMAL_ENXIO;
+
+   /* Allocate our module context */
+   component->priv->module = module = vcos_calloc(1, sizeof(*module), "mmal module");
+   if(!module) return MMAL_ENOMEM;
+
+   module->queue = mmal_queue_create();
+   if(!module->queue) goto error;
+
+   /* Allocate the ports for this component */
+   component->input = mmal_ports_alloc(component, 1, MMAL_PORT_TYPE_INPUT, 0);
+   if(!component->input) goto error;
+   component->input_num = 1;
+   module->display_region.width = SDL_WIDTH;
+   module->display_region.height = SDL_HEIGHT;
+
+   /************/
+
+   component->input[0]->priv->pf_set_format = sdl_port_set_format;
+   component->input[0]->priv->pf_enable = sdl_port_enable;
+   component->input[0]->priv->pf_disable = sdl_port_disable;
+   component->input[0]->priv->pf_flush = sdl_port_flush;
+   component->input[0]->priv->pf_send = sdl_port_send;
+   component->input[0]->priv->pf_parameter_set = sdl_port_parameter_set;
+   component->input[0]->buffer_num_min = INPUT_MIN_BUFFER_NUM;
+   component->input[0]->buffer_num_recommended = INPUT_RECOMMENDED_BUFFER_NUM;
+
+   component->priv->pf_destroy = sdl_component_destroy;
+
+   /* Create a thread to monitor SDL events */
+   module->thread = SDL_CreateThread(sdl_event_thread, component);
+
+   status = mmal_component_action_register(component, sdl_do_processing_loop);
+   if (status != MMAL_SUCCESS)
+      goto error;
+
+   return MMAL_SUCCESS;
+
+ error:
+   sdl_component_destroy(component);
+   return status;
+}
+
+MMAL_CONSTRUCTOR(mmal_register_component_sdl);
+void mmal_register_component_sdl(void)
+{
+   mmal_component_supplier_register("sdl", mmal_component_create_sdl);
+}
diff --git a/interface/mmal/components/spdif.c b/interface/mmal/components/spdif.c
new file mode 100755 (executable)
index 0000000..d5747ee
--- /dev/null
@@ -0,0 +1,496 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "core/mmal_component_private.h"
+#include "core/mmal_port_private.h"
+#include "mmal_logging.h"
+
+#define SPDIF_AC3_FRAME_SIZE 6144
+#define SPDIF_EAC3_FRAME_SIZE (6144*4)
+#define SPDIF_FRAME_SIZE SPDIF_EAC3_FRAME_SIZE
+
+/* Buffering requirements */
+#define INPUT_MIN_BUFFER_SIZE SPDIF_FRAME_SIZE
+#define INPUT_MIN_BUFFER_NUM 2
+#define OUTPUT_MIN_BUFFER_SIZE SPDIF_FRAME_SIZE
+#define OUTPUT_MIN_BUFFER_NUM 2
+
+/*****************************************************************************/
+typedef struct MMAL_COMPONENT_MODULE_T
+{
+   MMAL_STATUS_T status; /**< current status of the component */
+
+} MMAL_COMPONENT_MODULE_T;
+
+typedef struct MMAL_PORT_MODULE_T
+{
+   MMAL_QUEUE_T *queue; /**< queue for the buffers sent to the ports */
+   MMAL_BOOL_T needs_configuring; /**< port is waiting for a format commit */
+
+} MMAL_PORT_MODULE_T;
+
+/*****************************************************************************/
+
+/*****************************************************************************/
+
+static MMAL_STATUS_T spdif_send_event_format_changed(MMAL_COMPONENT_T *component, MMAL_PORT_T *port,
+   MMAL_ES_FORMAT_T *format)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_BUFFER_HEADER_T *buffer = NULL;
+   MMAL_EVENT_FORMAT_CHANGED_T *event;
+
+   /* Get an event buffer */
+   module->status = mmal_port_event_get(port, &buffer, MMAL_EVENT_FORMAT_CHANGED);
+   if (module->status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("unable to get an event buffer");
+      return module->status;
+   }
+   /* coverity[returned_null] Can't return null or call above would have failed */
+   event = mmal_event_format_changed_get(buffer);
+
+   /* Fill in the new format */
+   if (port->format->encoding == MMAL_ENCODING_PCM_SIGNED)
+      mmal_format_copy(event->format, port->format);
+   else
+      mmal_format_copy(event->format, format);
+
+   event->format->es->audio.sample_rate = format->es->audio.sample_rate;
+
+   /* Pass on the buffer requirements */
+   event->buffer_num_min = port->buffer_num_min;
+   event->buffer_size_min = port->buffer_size_min;
+   event->buffer_size_recommended = event->buffer_size_min;
+   event->buffer_num_recommended = port->buffer_num_recommended;
+
+   port->priv->module->needs_configuring = 1;
+   mmal_port_event_send(port, buffer);
+   return MMAL_SUCCESS;
+}
+
+/** Actual processing function */
+static MMAL_BOOL_T spdif_do_processing(MMAL_COMPONENT_T *component)
+{
+   static const uint8_t ac3_spdif_header[6] = {0x72,0xF8,0x1F,0x4E,0x1, 0};
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_PORT_T *port_in = component->input[0];
+   MMAL_PORT_T *port_out = component->output[0];
+   MMAL_BUFFER_HEADER_T *in, *out;
+   unsigned int i, sample_rate, frame_size, spdif_frame_size;
+   uint8_t *in_data;
+
+   if (port_out->priv->module->needs_configuring)
+      return 0;
+
+   in = mmal_queue_get(port_in->priv->module->queue);
+   if (!in)
+      return 0;
+
+   /* Handle event buffers */
+   if (in->cmd)
+   {
+      MMAL_EVENT_FORMAT_CHANGED_T *event = mmal_event_format_changed_get(in);
+      if (event)
+      {
+         module->status = mmal_format_full_copy(port_in->format, event->format);
+         if (module->status == MMAL_SUCCESS)
+            module->status = port_in->priv->pf_set_format(port_in);
+         if (module->status != MMAL_SUCCESS)
+         {
+            LOG_ERROR("format not set on port %s %p (%i)", port_in->name, port_in, module->status);
+            if (mmal_event_error_send(component, module->status) != MMAL_SUCCESS)
+               LOG_ERROR("unable to send an error event buffer");
+         }
+      }
+      else
+      {
+         LOG_ERROR("discarding event %i on port %s %p", (int)in->cmd, port_in->name, port_in);
+      }
+
+      in->length = 0;
+      mmal_port_buffer_header_callback(port_in, in);
+      return 1;
+   }
+
+   /* Don't do anything if we've already seen an error */
+   if (module->status != MMAL_SUCCESS)
+   {
+      mmal_queue_put_back(port_in->priv->module->queue, in);
+      return 0;
+   }
+
+   /* Discard empty buffers */
+   if (!in->length && !in->flags)
+   {
+      mmal_port_buffer_header_callback(port_in, in);
+      return 1;
+   }
+   /* Discard codec config data as it's not needed */
+   if (in->flags & MMAL_BUFFER_HEADER_FLAG_CONFIG)
+   {
+      LOG_DEBUG("config buffer %ibytes", in->length);
+      in->length = 0;
+      mmal_port_buffer_header_callback(port_in, in);
+      return 1;
+   }
+
+   out = mmal_queue_get(port_out->priv->module->queue);
+   if (!out)
+   {
+      mmal_queue_put_back(port_in->priv->module->queue, in);
+      return 0;
+   }
+
+   spdif_frame_size = SPDIF_AC3_FRAME_SIZE;
+   if (port_out->format->encoding == MMAL_ENCODING_EAC3)
+      spdif_frame_size = SPDIF_EAC3_FRAME_SIZE;
+
+   /* Sanity check the output buffer is big enough */
+   if (out->alloc_size < spdif_frame_size)
+   {
+      module->status = MMAL_EINVAL;
+      if (mmal_event_error_send(component, module->status) != MMAL_SUCCESS)
+         LOG_ERROR("unable to send an error event buffer");
+      mmal_queue_put_back(port_in->priv->module->queue, in);
+      mmal_queue_put_back(port_out->priv->module->queue, out);
+      return 0;
+   }
+
+   /* Special case for empty buffers carrying a flag */
+   if (!in->length && in->flags)
+   {
+      out->length = 0;
+      goto end;
+   }
+
+   LOG_DEBUG("frame: %lld, size %i", in->pts, in->length);
+   mmal_buffer_header_mem_lock(out);
+   mmal_buffer_header_mem_lock(in);
+   in_data = in->data + in->offset;
+
+   /* Sanity check we're dealing with an AC3 frame */
+   if (in->length < 5)
+   {
+      LOG_ERROR("invalid data size (%i bytes)", in->length);
+      goto discard;
+   }
+
+   if (!(in_data[0] == 0x0B || in_data[1] == 0x77) &&
+       !(in_data[0] == 0x77 || in_data[1] == 0x0B))
+   {
+      LOG_ERROR("invalid data (%i bytes): %2.2x,%2.2x,%2.2x,%2.2x",
+         in->length, in_data[0], in_data[1], in_data[2], in_data[3]);
+      goto discard;
+   }
+
+   /* We need to make sure we use the right sample rate
+    * to be able to play this at the right rate */
+   if ((in_data[4] & 0xC0) == 0x40) sample_rate = 44100;
+   else if ((in_data[4] & 0xC0) == 0x80) sample_rate = 32000;
+   else sample_rate = 48000;
+
+   /* If the sample rate changes, stop everything we're doing
+    * and signal the format change. */
+   if (sample_rate != port_out->format->es->audio.sample_rate)
+   {
+      LOG_INFO("format change: %i->%i",
+         port_out->format->es->audio.sample_rate, sample_rate);
+      port_in->format->es->audio.sample_rate = sample_rate;
+      spdif_send_event_format_changed(component, port_out, port_in->format);
+      mmal_buffer_header_mem_unlock(in);
+      mmal_buffer_header_mem_unlock(out);
+      mmal_queue_put_back(port_in->priv->module->queue, in);
+      mmal_queue_put_back(port_out->priv->module->queue, out);
+      return 0;
+   }
+
+   /* Build our S/PDIF frame. We assume that we need to send
+    * little endian S/PDIF data. */
+   if (in->length > spdif_frame_size - 8)
+      LOG_ERROR("frame too big, truncating (%i/%i bytes)",
+         in->length, spdif_frame_size - 8);
+   frame_size = MMAL_MIN(in->length, spdif_frame_size - 8) / 2;
+   memcpy(out->data, ac3_spdif_header, sizeof(ac3_spdif_header));
+   out->data[5] = in_data[5] & 0x7; /* bsmod */
+   out->data[6] = frame_size & 0xFF;
+   out->data[7] = frame_size >> 8;
+
+   /* Copy the AC3 data, reverting the endianness if required */
+   if (in_data[0] == 0x0B)
+   {
+      for (i = 0; i < frame_size; i++)
+      {
+         out->data[8+i*2] = in_data[in->offset+i*2+1];
+         out->data[8+i*2+1] = in_data[in->offset+i*2];
+      }
+   }
+   else
+      memcpy(out->data + 8, in_data, in->length);
+
+   /* The S/PDIF frame needs to be padded */
+   memset(out->data + 8 + frame_size * 2, 0,
+      spdif_frame_size - frame_size * 2 - 8);
+   mmal_buffer_header_mem_unlock(in);
+   mmal_buffer_header_mem_unlock(out);
+   out->length     = spdif_frame_size;
+ end:
+   out->offset     = 0;
+   out->flags      = in->flags;
+   out->pts        = in->pts;
+   out->dts        = in->dts;
+
+   /* Send buffers back */
+   in->length = 0;
+   mmal_port_buffer_header_callback(port_in, in);
+   mmal_port_buffer_header_callback(port_out, out);
+   return 1;
+
+ discard:
+   mmal_buffer_header_mem_unlock(in);
+   mmal_buffer_header_mem_unlock(out);
+   in->length = 0;
+   mmal_queue_put_back(port_out->priv->module->queue, out);
+   mmal_port_buffer_header_callback(port_in, in);
+   return 1;
+}
+
+/*****************************************************************************/
+static void spdif_do_processing_loop(MMAL_COMPONENT_T *component)
+{
+   while (spdif_do_processing(component));
+}
+
+/** Destroy a previously created component */
+static MMAL_STATUS_T spdif_component_destroy(MMAL_COMPONENT_T *component)
+{
+   unsigned int i;
+
+   for(i = 0; i < component->input_num; i++)
+      if(component->input[i]->priv->module->queue)
+         mmal_queue_destroy(component->input[i]->priv->module->queue);
+   if(component->input_num)
+      mmal_ports_free(component->input, component->input_num);
+
+   for(i = 0; i < component->output_num; i++)
+      if(component->output[i]->priv->module->queue)
+         mmal_queue_destroy(component->output[i]->priv->module->queue);
+   if(component->output_num)
+      mmal_ports_free(component->output, component->output_num);
+
+   vcos_free(component->priv->module);
+   return MMAL_SUCCESS;
+}
+
+/** Enable processing on a port */
+static MMAL_STATUS_T spdif_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
+{
+   MMAL_PARAM_UNUSED(cb);
+
+   /* We need to propagate the buffer requirements when the input port is
+    * enabled */
+   if (port->type == MMAL_PORT_TYPE_INPUT)
+      return port->priv->pf_set_format(port);
+
+   return MMAL_SUCCESS;
+}
+
+/** Flush a port */
+static MMAL_STATUS_T spdif_port_flush(MMAL_PORT_T *port)
+{
+   MMAL_PORT_MODULE_T *port_module = port->priv->module;
+   MMAL_BUFFER_HEADER_T *buffer;
+
+   /* Flush buffers that our component is holding on to */
+   buffer = mmal_queue_get(port_module->queue);
+   while(buffer)
+   {
+      mmal_port_buffer_header_callback(port, buffer);
+      buffer = mmal_queue_get(port_module->queue);
+   }
+
+   return MMAL_SUCCESS;
+}
+
+/** Disable processing on a port */
+static MMAL_STATUS_T spdif_port_disable(MMAL_PORT_T *port)
+{
+   /* We just need to flush our internal queue */
+   return spdif_port_flush(port);
+}
+
+/** Send a buffer header to a port */
+static MMAL_STATUS_T spdif_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   mmal_queue_put(port->priv->module->queue, buffer);
+   mmal_component_action_trigger(port->component);
+   return MMAL_SUCCESS;
+}
+
+/** Set format on input port */
+static MMAL_STATUS_T spdif_input_port_format_commit(MMAL_PORT_T *in)
+{
+   MMAL_COMPONENT_T *component = in->component;
+   MMAL_PORT_T *out = component->output[0];
+
+   /* Sanity check we cope with this format */
+   if (in->format->encoding != MMAL_ENCODING_AC3 &&
+       in->format->encoding != MMAL_ENCODING_EAC3)
+      return MMAL_ENXIO;
+
+   LOG_INFO("%4.4s, %iHz, %ichan, %ibps", (char *)&in->format->encoding,
+      in->format->es->audio.sample_rate, in->format->es->audio.channels,
+      in->format->bitrate);
+
+   /* TODO: should we check the bitrate to see if that fits in an S/PDIF
+    * frame? */
+
+   /* Check if there's anything to propagate to the output port */
+   if (!mmal_format_compare(in->format, out->format))
+      return MMAL_SUCCESS;
+   if (out->format->encoding == MMAL_ENCODING_PCM_SIGNED &&
+       in->format->es->audio.sample_rate ==
+          out->format->es->audio.sample_rate)
+      return MMAL_SUCCESS;
+
+   /* If the output port is not enabled we just need to update its format.
+    * Otherwise we'll have to trigger a format changed event for it. */
+   if (!out->is_enabled)
+   {
+      if (out->format->encoding != MMAL_ENCODING_PCM_SIGNED)
+         mmal_format_copy(out->format, in->format);
+      out->format->es->audio.sample_rate = in->format->es->audio.sample_rate;
+      return MMAL_SUCCESS;
+   }
+
+   /* Send an event on the output port */
+   return spdif_send_event_format_changed(component, out, in->format);
+}
+
+/** Set format on output port */
+static MMAL_STATUS_T spdif_output_port_format_commit(MMAL_PORT_T *out)
+{
+   int supported = 0;
+
+   if (out->format->type == MMAL_ES_TYPE_AUDIO &&
+       out->format->encoding == MMAL_ENCODING_PCM_SIGNED &&
+       out->format->es->audio.channels == 2 &&
+       out->format->es->audio.bits_per_sample == 16)
+      supported = 1;
+   if (out->format->type == MMAL_ES_TYPE_AUDIO &&
+       (out->format->encoding == MMAL_ENCODING_AC3 ||
+        out->format->encoding == MMAL_ENCODING_EAC3))
+      supported = 1;
+
+   if (!supported)
+   {
+      LOG_ERROR("invalid format %4.4s, %ichan, %ibps",
+         (char *)&out->format->encoding, out->format->es->audio.channels,
+         out->format->es->audio.bits_per_sample);
+      return MMAL_EINVAL;
+   }
+
+   out->priv->module->needs_configuring = 0;
+   mmal_component_action_trigger(out->component);
+   return MMAL_SUCCESS;
+}
+
+/** Create an instance of a component  */
+static MMAL_STATUS_T mmal_component_create_spdif(const char *name, MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module;
+   MMAL_STATUS_T status = MMAL_ENOMEM;
+   MMAL_PARAM_UNUSED(name);
+
+   /* Allocate the context for our module */
+   component->priv->module = module = vcos_malloc(sizeof(*module), "mmal module");
+   if (!module)
+      return MMAL_ENOMEM;
+   memset(module, 0, sizeof(*module));
+
+   component->priv->pf_destroy = spdif_component_destroy;
+
+   /* Allocate and initialise all the ports for this component */
+   component->input = mmal_ports_alloc(component, 1, MMAL_PORT_TYPE_INPUT, sizeof(MMAL_PORT_MODULE_T));
+   if(!component->input)
+      goto error;
+   component->input_num = 1;
+   component->input[0]->priv->pf_enable = spdif_port_enable;
+   component->input[0]->priv->pf_disable = spdif_port_disable;
+   component->input[0]->priv->pf_flush = spdif_port_flush;
+   component->input[0]->priv->pf_send = spdif_port_send;
+   component->input[0]->priv->pf_set_format = spdif_input_port_format_commit;
+   component->input[0]->priv->module->queue = mmal_queue_create();
+   if(!component->input[0]->priv->module->queue)
+      goto error;
+
+   component->output = mmal_ports_alloc(component, 1, MMAL_PORT_TYPE_OUTPUT, sizeof(MMAL_PORT_MODULE_T));
+   if(!component->output)
+      goto error;
+   component->output_num = 1;
+   component->output[0]->priv->pf_enable = spdif_port_enable;
+   component->output[0]->priv->pf_disable = spdif_port_disable;
+   component->output[0]->priv->pf_flush = spdif_port_flush;
+   component->output[0]->priv->pf_send = spdif_port_send;
+   component->output[0]->priv->pf_set_format = spdif_output_port_format_commit;
+   component->output[0]->priv->module->queue = mmal_queue_create();
+   if(!component->output[0]->priv->module->queue)
+      goto error;
+
+   status = mmal_component_action_register(component, spdif_do_processing_loop);
+   if (status != MMAL_SUCCESS)
+      goto error;
+
+   component->input[0]->format->type = MMAL_ES_TYPE_AUDIO;
+   component->input[0]->format->encoding = MMAL_ENCODING_AC3;
+   component->input[0]->buffer_size_min =
+      component->input[0]->buffer_size_recommended = INPUT_MIN_BUFFER_SIZE;
+   component->input[0]->buffer_num_min =
+      component->input[0]->buffer_num_recommended = INPUT_MIN_BUFFER_NUM;
+
+   component->output[0]->format->type = MMAL_ES_TYPE_AUDIO;
+   component->output[0]->format->encoding = MMAL_ENCODING_AC3;
+   component->output[0]->format->es->audio.channels = 2;
+   component->output[0]->format->es->audio.bits_per_sample = 16;
+   component->output[0]->buffer_size_min =
+      component->output[0]->buffer_size_recommended = OUTPUT_MIN_BUFFER_SIZE;
+   component->output[0]->buffer_num_min =
+      component->output[0]->buffer_num_recommended = OUTPUT_MIN_BUFFER_NUM;
+
+   return MMAL_SUCCESS;
+
+ error:
+   spdif_component_destroy(component);
+   return status;
+}
+
+MMAL_CONSTRUCTOR(mmal_register_component_spdif);
+void mmal_register_component_spdif(void)
+{
+   mmal_component_supplier_register("spdif", mmal_component_create_spdif);
+}
diff --git a/interface/mmal/components/splitter.c b/interface/mmal/components/splitter.c
new file mode 100755 (executable)
index 0000000..7753a16
--- /dev/null
@@ -0,0 +1,345 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "core/mmal_component_private.h"
+#include "core/mmal_port_private.h"
+#include "mmal_logging.h"
+
+#define SPLITTER_OUTPUT_PORTS_NUM 4 /* 4 should do for now */
+
+/*****************************************************************************/
+typedef struct MMAL_COMPONENT_MODULE_T
+{
+   uint32_t enabled_flags; /**< Flags indicating which output port is enabled */
+   uint32_t sent_flags;    /**< Flags indicating which output port we've already sent data to */
+   MMAL_BOOL_T error;      /**< Error state */
+
+} MMAL_COMPONENT_MODULE_T;
+
+typedef struct MMAL_PORT_MODULE_T
+{
+   MMAL_QUEUE_T *queue; /**< queue for the buffers sent to the ports */
+
+} MMAL_PORT_MODULE_T;
+
+/*****************************************************************************/
+
+/** Destroy a previously created component */
+static MMAL_STATUS_T splitter_component_destroy(MMAL_COMPONENT_T *component)
+{
+   unsigned int i;
+
+   for(i = 0; i < component->input_num; i++)
+      if(component->input[i]->priv->module->queue)
+         mmal_queue_destroy(component->input[i]->priv->module->queue);
+   if(component->input_num)
+      mmal_ports_free(component->input, component->input_num);
+
+   for(i = 0; i < component->output_num; i++)
+      if(component->output[i]->priv->module->queue)
+         mmal_queue_destroy(component->output[i]->priv->module->queue);
+   if(component->output_num)
+      mmal_ports_free(component->output, component->output_num);
+
+   vcos_free(component->priv->module);
+   return MMAL_SUCCESS;
+}
+
+/** Enable processing on a port */
+static MMAL_STATUS_T splitter_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
+{
+#if 0
+   MMAL_COMPONENT_T *component = port->component;
+   uint32_t buffer_num, buffer_size;
+   unsigned int i;
+
+   /* Find the max and apply that to all ports */
+   buffer_num = component->input[0]->buffer_num;
+   buffer_size = component->input[0]->buffer_size;
+   for (i = 0; i < component->output_num; i++)
+   {
+      buffer_num = MMAL_MAX(buffer_num, component->output[i]->buffer_num);
+      buffer_size = MMAL_MAX(buffer_num, component->output[i]->buffer_size);
+   }
+   component->input[0]->buffer_num = buffer_num;
+   component->input[0]->buffer_size = buffer_size;
+   for (i = 0; i < component->output_num; i++)
+   {
+      component->output[i]->buffer_num = buffer_num;
+      component->output[i]->buffer_size = buffer_num;
+   }
+#endif
+
+   MMAL_PARAM_UNUSED(cb);
+   if (port->buffer_size)
+   if (port->type == MMAL_PORT_TYPE_OUTPUT)
+      port->component->priv->module->enabled_flags |= (1<<port->index);
+   return MMAL_SUCCESS;
+}
+
+/** Flush a port */
+static MMAL_STATUS_T splitter_port_flush(MMAL_PORT_T *port)
+{
+   MMAL_PORT_MODULE_T *port_module = port->priv->module;
+   MMAL_BUFFER_HEADER_T *buffer;
+
+   /* Flush buffers that our component is holding on to */
+   buffer = mmal_queue_get(port_module->queue);
+   while(buffer)
+   {
+      mmal_port_buffer_header_callback(port, buffer);
+      buffer = mmal_queue_get(port_module->queue);
+   }
+
+   if (port->type == MMAL_PORT_TYPE_INPUT)
+      port->component->priv->module->sent_flags = 0;
+
+   return MMAL_SUCCESS;
+}
+
+/** Disable processing on a port */
+static MMAL_STATUS_T splitter_port_disable(MMAL_PORT_T *port)
+{
+   if (port->type == MMAL_PORT_TYPE_OUTPUT)
+      port->component->priv->module->enabled_flags &= ~(1<<port->index);
+
+   /* We just need to flush our internal queue */
+   return splitter_port_flush(port);
+}
+
+/** Send a buffer header to a port */
+static MMAL_STATUS_T splitter_send_output(MMAL_BUFFER_HEADER_T *buffer, MMAL_PORT_T *out_port)
+{
+   MMAL_BUFFER_HEADER_T *out;
+   MMAL_STATUS_T status;
+
+   /* Get a buffer header from output port */
+   out = mmal_queue_get(out_port->priv->module->queue);
+   if (!out)
+      return MMAL_EAGAIN;
+
+   /* Copy our input buffer header */
+   status = mmal_buffer_header_replicate(out, buffer);
+   if (status != MMAL_SUCCESS)
+      goto error;
+
+   /* Send buffer back */
+   mmal_port_buffer_header_callback(out_port, out);
+   return MMAL_SUCCESS;
+
+ error:
+   mmal_queue_put_back(out_port->priv->module->queue, out);
+   return status;
+}
+
+/** Send a buffer header to a port */
+static MMAL_STATUS_T splitter_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_PORT_T *in_port, *out_port;
+   MMAL_BUFFER_HEADER_T *in;
+   MMAL_STATUS_T status;
+   unsigned int i;
+
+   mmal_queue_put(port->priv->module->queue, buffer);
+
+   if (module->error)
+      return MMAL_SUCCESS; /* Just do nothing */
+
+   /* Get input buffer header */
+   in_port = component->input[0];
+   in = mmal_queue_get(in_port->priv->module->queue);
+   if (!in)
+      return MMAL_SUCCESS; /* Nothing to do */
+
+   for (i = 0; i < component->output_num; i++)
+   {
+      out_port = component->output[i];
+      status = splitter_send_output(in, out_port);
+
+      if (status != MMAL_SUCCESS && status != MMAL_EAGAIN)
+         goto error;
+
+      if (status == MMAL_SUCCESS)
+         module->sent_flags |= (1<<i);
+   }
+
+   /* Check if we're done with the input buffer */
+   if ((module->sent_flags & module->enabled_flags) == module->enabled_flags)
+   {
+      in->length = 0; /* Consume the input buffer */
+      mmal_port_buffer_header_callback(in_port, in);
+      module->sent_flags = 0;
+      return MMAL_SUCCESS;
+   }
+
+   /* We're not done yet so put the buffer back in the queue */
+   mmal_queue_put(in_port->priv->module->queue, in);
+   return MMAL_SUCCESS;
+
+ error:
+   mmal_queue_put(in_port->priv->module->queue, in);
+
+   status = mmal_event_error_send(port->component, status);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("unable to send an error event buffer (%i)", (int)status);
+      return MMAL_SUCCESS;
+   }
+   module->error = 1;
+   return MMAL_SUCCESS;
+}
+
+/** Set format on a port */
+static MMAL_STATUS_T splitter_port_format_commit(MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_STATUS_T status;
+   unsigned int i;
+
+   /* Sanity check */
+   if (port->type == MMAL_PORT_TYPE_OUTPUT)
+   {
+      LOG_ERROR("output port is read-only");
+      return MMAL_EINVAL;
+   }
+
+   /* Commit the format on all output ports */
+   for (i = 0; i < component->output_num; i++)
+   {
+      status = mmal_format_full_copy(component->output[i]->format, port->format);
+      if (status != MMAL_SUCCESS)
+         return status;
+   }
+
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T splitter_port_parameter_set(MMAL_PORT_T *port, const MMAL_PARAMETER_HEADER_T *param)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   unsigned int i;
+
+   switch (param->id)
+   {
+   case MMAL_PARAMETER_BUFFER_REQUIREMENTS:
+      {
+         /* Propagate the requirements to all the ports */
+         const MMAL_PARAMETER_BUFFER_REQUIREMENTS_T *req = (const MMAL_PARAMETER_BUFFER_REQUIREMENTS_T *)param;
+         uint32_t buffer_num_min = MMAL_MAX(port->buffer_num_min, req->buffer_num_min);
+         uint32_t buffer_num_recommended = MMAL_MAX(port->buffer_num_recommended, req->buffer_num_recommended);
+         uint32_t buffer_size_min = MMAL_MAX(port->buffer_size_min, req->buffer_size_min);
+         uint32_t buffer_size_recommended = MMAL_MAX(port->buffer_size_recommended, req->buffer_size_recommended);
+
+         component->input[0]->buffer_num_min = buffer_num_min;
+         component->input[0]->buffer_num_recommended = buffer_num_recommended;
+         component->input[0]->buffer_size_min = buffer_size_min;
+         component->input[0]->buffer_size_recommended = buffer_size_recommended;
+         for (i = 0; i < component->output_num; i++)
+         {
+            component->output[i]->buffer_num_min = buffer_num_min;
+            component->output[i]->buffer_num_recommended = buffer_num_recommended;
+            component->output[i]->buffer_size_min = buffer_size_min;
+            component->output[i]->buffer_size_recommended = buffer_size_recommended;
+         }
+
+      }
+      return MMAL_SUCCESS;
+
+   default:
+      return MMAL_ENOSYS;
+   }
+}
+
+/** Create an instance of a component  */
+static MMAL_STATUS_T mmal_component_create_splitter(const char *name, MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module;
+   MMAL_STATUS_T status = MMAL_ENOMEM;
+   unsigned int i;
+   MMAL_PARAM_UNUSED(name);
+
+   /* Allocate the context for our module */
+   component->priv->module = module = vcos_malloc(sizeof(*module), "mmal module");
+   if (!module)
+      return MMAL_ENOMEM;
+   memset(module, 0, sizeof(*module));
+
+   component->priv->pf_destroy = splitter_component_destroy;
+
+   /* Allocate and initialise all the ports for this component */
+   component->input = mmal_ports_alloc(component, 1, MMAL_PORT_TYPE_INPUT, sizeof(MMAL_PORT_MODULE_T));
+   if(!component->input)
+      goto error;
+   component->input_num = 1;
+   component->input[0]->priv->pf_enable = splitter_port_enable;
+   component->input[0]->priv->pf_disable = splitter_port_disable;
+   component->input[0]->priv->pf_flush = splitter_port_flush;
+   component->input[0]->priv->pf_send = splitter_port_send;
+   component->input[0]->priv->pf_set_format = splitter_port_format_commit;
+   component->input[0]->priv->pf_parameter_set = splitter_port_parameter_set;
+   component->input[0]->buffer_num_min = 1;
+   component->input[0]->buffer_num_recommended = 0;
+   component->input[0]->priv->module->queue = mmal_queue_create();
+   if(!component->input[0]->priv->module->queue)
+      goto error;
+
+   component->output = mmal_ports_alloc(component, SPLITTER_OUTPUT_PORTS_NUM,
+                                        MMAL_PORT_TYPE_OUTPUT, sizeof(MMAL_PORT_MODULE_T));
+   if(!component->output)
+      goto error;
+   component->output_num = SPLITTER_OUTPUT_PORTS_NUM;
+   for(i = 0; i < component->output_num; i++)
+   {
+      component->output[i]->priv->pf_enable = splitter_port_enable;
+      component->output[i]->priv->pf_disable = splitter_port_disable;
+      component->output[i]->priv->pf_flush = splitter_port_flush;
+      component->output[i]->priv->pf_send = splitter_port_send;
+      component->output[i]->priv->pf_set_format = splitter_port_format_commit;
+      component->output[i]->priv->pf_parameter_set = splitter_port_parameter_set;
+      component->output[i]->buffer_num_min = 1;
+      component->output[i]->buffer_num_recommended = 0;
+      component->output[i]->capabilities = MMAL_PORT_CAPABILITY_PASSTHROUGH;
+      component->output[i]->priv->module->queue = mmal_queue_create();
+      if(!component->output[i]->priv->module->queue)
+         goto error;
+   }
+
+   return MMAL_SUCCESS;
+
+ error:
+   splitter_component_destroy(component);
+   return status;
+}
+
+MMAL_CONSTRUCTOR(mmal_register_component_splitter);
+void mmal_register_component_splitter(void)
+{
+   mmal_component_supplier_register("splitter", mmal_component_create_splitter);
+}
diff --git a/interface/mmal/core/CMakeLists.txt b/interface/mmal/core/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..de0bcb2
--- /dev/null
@@ -0,0 +1,25 @@
+add_library (mmal_core ${LIBRARY_TYPE}
+   mmal_format.c
+   mmal_port.c
+   mmal_port_clock.c
+   mmal_component.c
+   mmal_buffer.c
+   mmal_queue.c
+   mmal_pool.c
+   mmal_events.c
+   mmal_logging.c
+   mmal_clock.c
+)
+
+target_link_libraries (mmal_core vcos)
+
+install(TARGETS mmal_core DESTINATION lib)
+install(FILES
+   mmal_buffer_private.h
+   mmal_clock_private.h
+   mmal_component_private.h
+   mmal_core_private.h
+   mmal_port_private.h
+   mmal_events_private.h
+   DESTINATION include/interface/mmal/core
+)
diff --git a/interface/mmal/core/mmal_buffer.c b/interface/mmal/core/mmal_buffer.c
new file mode 100755 (executable)
index 0000000..3f83063
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "mmal_buffer.h"
+#include "core/mmal_buffer_private.h"
+#include "mmal_logging.h"
+
+#define ROUND_UP(s,align) ((((unsigned long)(s)) & ~((align)-1)) + (align))
+#define DEFAULT_COMMAND_SIZE 256 /**< 256 bytes of space for commands */
+#define ALIGN  8
+
+/** Acquire a buffer header */
+void mmal_buffer_header_acquire(MMAL_BUFFER_HEADER_T *header)
+{
+#ifdef ENABLE_MMAL_EXTRA_LOGGING
+   LOG_TRACE("%p (%i)", header, (int)header->priv->refcount+1);
+#endif
+   header->priv->refcount++;
+}
+
+/** Reset a buffer header */
+void mmal_buffer_header_reset(MMAL_BUFFER_HEADER_T *header)
+{
+   header->length = 0;
+   header->offset = 0;
+   header->flags = 0;
+   header->pts = MMAL_TIME_UNKNOWN;
+   header->dts = MMAL_TIME_UNKNOWN;
+}
+
+/** Release a buffer header */
+void mmal_buffer_header_release(MMAL_BUFFER_HEADER_T *header)
+{
+#ifdef ENABLE_MMAL_EXTRA_LOGGING
+   LOG_TRACE("%p (%i)", header, (int)header->priv->refcount-1);
+#endif
+
+   if(--header->priv->refcount != 0)
+      return;
+
+   if (header->priv->pf_pre_release)
+   {
+      if (header->priv->pf_pre_release(header, header->priv->pre_release_userdata))
+         return; /* delay releasing the buffer */
+   }
+   mmal_buffer_header_release_continue(header);
+}
+
+/** Finalise buffer release following a pre-release event */
+void mmal_buffer_header_release_continue(MMAL_BUFFER_HEADER_T *header)
+{
+   mmal_buffer_header_reset(header);
+   if (header->priv->reference)
+      mmal_buffer_header_release(header->priv->reference);
+   header->priv->reference = 0;
+   header->priv->pf_release(header);
+}
+
+/** Replicate a buffer header */
+MMAL_STATUS_T mmal_buffer_header_replicate(MMAL_BUFFER_HEADER_T *dest,
+   MMAL_BUFFER_HEADER_T *src)
+{
+#ifdef ENABLE_MMAL_EXTRA_LOGGING
+   LOG_TRACE("dest: %p src: %p", dest, src);
+#endif
+
+   if (!dest || !src || dest->priv->reference)
+      return MMAL_EINVAL;
+
+   mmal_buffer_header_acquire(src);
+   dest->priv->reference = src;
+
+   /* Copy all the relevant fields */
+   dest->cmd        = src->cmd;
+   dest->alloc_size = src->alloc_size;
+   dest->data       = src->data;
+   dest->offset     = src->offset;
+   dest->length     = src->length;
+   dest->flags      = src->flags;
+   dest->pts        = src->pts;
+   dest->dts        = src->dts;
+   *dest->type      = *src->type;
+   return MMAL_SUCCESS;
+}
+
+/** Get the size in bytes of a fully initialised MMAL_BUFFER_HEADER_T */
+unsigned int mmal_buffer_header_size(MMAL_BUFFER_HEADER_T *header)
+{
+   unsigned int header_size;
+
+   header_size = ROUND_UP(sizeof(*header), ALIGN);
+   header_size += ROUND_UP(sizeof(*header->type), ALIGN);
+   header_size += ROUND_UP(DEFAULT_COMMAND_SIZE, ALIGN);
+   header_size += ROUND_UP(sizeof(*header->priv), ALIGN);
+   return header_size;
+}
+
+/** Initialise a MMAL_BUFFER_HEADER_T */
+MMAL_BUFFER_HEADER_T *mmal_buffer_header_initialise(void *mem, unsigned int length)
+{
+   MMAL_BUFFER_HEADER_T *header;
+   unsigned int header_size = mmal_buffer_header_size(0);
+
+   if(length < header_size)
+      return 0;
+
+   memset(mem, 0, header_size);
+
+   header = (MMAL_BUFFER_HEADER_T *)mem;
+   header->type = (void *)&header[1];
+   header->priv = (MMAL_BUFFER_HEADER_PRIVATE_T *)&header->type[1];
+   return header;
+}
+
+/** Return a pointer to the area reserved for the driver */
+MMAL_DRIVER_BUFFER_T *mmal_buffer_header_driver_data(MMAL_BUFFER_HEADER_T *header)
+{
+   return (MMAL_DRIVER_BUFFER_T *)header->priv->driver_area;
+}
+
+/** Return a pointer to a referenced buffer header */
+MMAL_BUFFER_HEADER_T *mmal_buffer_header_reference(MMAL_BUFFER_HEADER_T *header)
+{
+   return header->priv->reference;
+}
+
+#ifdef __VIDEOCORE__
+# include "vcfw/rtos/common/rtos_common_mem.h"
+#endif
+
+/** Lock the data buffer contained in the buffer header */
+MMAL_STATUS_T mmal_buffer_header_mem_lock(MMAL_BUFFER_HEADER_T *header)
+{
+#ifdef __VIDEOCORE__
+   uint8_t *data = mem_lock((MEM_HANDLE_T)header->data);
+   if (!data)
+      return MMAL_EINVAL;
+   header->priv->payload_handle = (void *)header->data;
+   header->data = data;
+#else
+   MMAL_PARAM_UNUSED(header);
+#endif
+
+   return MMAL_SUCCESS;
+}
+
+/** Unlock the data buffer contained in the buffer header */
+void mmal_buffer_header_mem_unlock(MMAL_BUFFER_HEADER_T *header)
+{
+#ifdef __VIDEOCORE__
+   mem_unlock((MEM_HANDLE_T)header->priv->payload_handle);
+   header->data = header->priv->payload_handle;
+#else
+   MMAL_PARAM_UNUSED(header);
+#endif
+}
+
+/** Set a pre-release callback for a buffer header */
+void mmal_buffer_header_pre_release_cb_set(MMAL_BUFFER_HEADER_T *header, MMAL_BH_PRE_RELEASE_CB_T cb, void *userdata)
+{
+   header->priv->pf_pre_release = cb;
+   header->priv->pre_release_userdata = userdata;
+}
diff --git a/interface/mmal/core/mmal_buffer_private.h b/interface/mmal/core/mmal_buffer_private.h
new file mode 100755 (executable)
index 0000000..d24be20
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_BUFFER_PRIVATE_H
+#define MMAL_BUFFER_PRIVATE_H
+
+/** Typedef for the private area the framework reserves for the driver / communication layer */
+typedef struct MMAL_DRIVER_BUFFER_T MMAL_DRIVER_BUFFER_T;
+
+/** Size of the private area the framework reserves for the driver / communication layer */
+#define MMAL_DRIVER_BUFFER_SIZE 32
+
+/** Typedef for the framework's private area in the buffer header */
+typedef struct MMAL_BUFFER_HEADER_PRIVATE_T
+{
+   /** Callback invoked just prior to actually releasing the buffer header. Returns TRUE if
+    * release should be delayed. */
+   MMAL_BH_PRE_RELEASE_CB_T pf_pre_release;
+   void *pre_release_userdata;
+
+   /** Callback used to release / recycle the buffer header. This needs to be set by
+    * whoever allocates the buffer header. */
+   void (*pf_release)(struct MMAL_BUFFER_HEADER_T *header);
+   void *owner;               /**< Context set by the allocator of the buffer header and passed
+                                   during the release callback */
+
+   int32_t refcount;          /**< Reference count of the buffer header. When it reaches 0,
+                                   the release callback will be called. */
+
+   MMAL_BUFFER_HEADER_T *reference; /**< Reference to another acquired buffer header. */
+
+   /** Callback used to free the payload associated with this buffer header. This is only
+    * used if the buffer header was created by MMAL with a payload associated with it. */
+   void   (*pf_payload_free)(void *payload_context, void *payload);
+   void    *payload;          /**< Pointer / handle to the allocated payload buffer */
+   void    *payload_context;  /**< Pointer to the context of the payload allocator */
+   uint32_t payload_size;     /**< Allocated size in bytes of payload buffer */
+
+   void *component_data;      /**< Field reserved for use by the component */
+   void *payload_handle;      /**< Field reserved for mmal_buffer_header_mem_lock */
+
+   uint8_t driver_area[MMAL_DRIVER_BUFFER_SIZE];
+
+} MMAL_BUFFER_HEADER_PRIVATE_T;
+
+/** Get the size in bytes of a fully initialised MMAL_BUFFER_HEADER_T */
+unsigned int mmal_buffer_header_size(MMAL_BUFFER_HEADER_T *header);
+
+/** Initialise a MMAL_BUFFER_HEADER_T */
+MMAL_BUFFER_HEADER_T *mmal_buffer_header_initialise(void *mem, unsigned int length);
+
+/** Return a pointer to the area reserved for the driver.
+  */
+MMAL_DRIVER_BUFFER_T *mmal_buffer_header_driver_data(MMAL_BUFFER_HEADER_T *);
+
+/** Return a pointer to a referenced buffer header.
+ * It is the caller's responsibility to ensure that the reference is still
+ * valid when using it.
+ */
+MMAL_BUFFER_HEADER_T *mmal_buffer_header_reference(MMAL_BUFFER_HEADER_T *header);
+
+#endif /* MMAL_BUFFER_PRIVATE_H */
diff --git a/interface/mmal/core/mmal_clock.c b/interface/mmal/core/mmal_clock.c
new file mode 100755 (executable)
index 0000000..23f3043
--- /dev/null
@@ -0,0 +1,892 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/vcos/vcos.h"
+#include "interface/mmal/mmal_logging.h"
+#include "interface/mmal/util/mmal_list.h"
+#include "interface/mmal/util/mmal_util_rational.h"
+#include "interface/mmal/core/mmal_clock_private.h"
+
+#ifdef __VIDEOCORE__
+/* Use RTOS timer for improved accuracy */
+# include "vcfw/rtos/rtos.h"
+# define USE_RTOS_TIMER
+#endif
+
+
+/*****************************************************************************/
+#ifdef USE_RTOS_TIMER
+# define MIN_TIMER_DELAY  1     /* microseconds */
+#else
+# define MIN_TIMER_DELAY  10000 /* microseconds */
+#endif
+
+/* 1.0 in Q16 format */
+#define Q16_ONE  (1 << 16)
+
+/* Maximum number of pending requests */
+#define CLOCK_REQUEST_SLOTS  32
+
+/* Number of microseconds the clock tries to service requests early
+ * to account for processing overhead */
+#define CLOCK_TARGET_OFFSET  20
+
+/* Default wait time (in microseconds) when the clock is paused. */
+#define CLOCK_WAIT_TIME  200000LL
+
+/* In order to prevent unnecessary clock jitter when updating the local media-time of the
+ * clock, an upper and lower threshold is used. If the difference between the reference
+ * media-time and local media-time is greater than the upper threshold, local media-time
+ * is set to the reference time. Below this threshold, a weighted moving average is applied
+ * to the difference. If this is greater than the lower threshold, the local media-time is
+ * adjusted by the average. Anything below the lower threshold is ignored. */
+#define CLOCK_UPDATE_THRESHOLD_LOWER  8000   /* microseconds */
+#define CLOCK_UPDATE_THRESHOLD_UPPER  50000  /* microseconds */
+
+/* Default threshold after which backward jumps in media time are treated as a discontinuity. */
+#define CLOCK_DISCONT_THRESHOLD  1000000  /* microseconds */
+
+/* Default duration for which a discontinuity applies. Used for wall time duration for which
+ * a discontinuity continues to cause affected requests to fire immediately, and as the media
+ * time span for detecting discontinuous requests. */
+#define CLOCK_DISCONT_DURATION   1000000  /* microseconds */
+
+/* Absolute value macro */
+#define ABS_VALUE(v)  (((v) < 0) ? -(v) : (v))
+
+/* Macros used to make clock access thread-safe */
+#define LOCK(p)    vcos_mutex_lock(&(p)->lock);
+#define UNLOCK(p)  vcos_mutex_unlock(&(p)->lock);
+
+
+/*****************************************************************************/
+#ifdef USE_RTOS_TIMER
+typedef RTOS_TIMER_T MMAL_TIMER_T;
+#else
+typedef VCOS_TIMER_T MMAL_TIMER_T;
+#endif
+
+typedef struct MMAL_CLOCK_REQUEST_T
+{
+   MMAL_LIST_ELEMENT_T link; /**< must be first */
+   MMAL_CLOCK_VOID_FP priv;  /**< client-supplied function pointer */
+   MMAL_CLOCK_REQUEST_CB cb; /**< client-supplied callback to invoke */
+   void *cb_data;            /**< client-supplied callback data */
+   int64_t media_time;       /**< media-time requested by the client (microseconds) */
+   int64_t media_time_adj;   /**< adjusted media-time at which the request will
+                                  be serviced in microseconds (this takes
+                                  CLOCK_TARGET_OFFSET into account) */
+} MMAL_CLOCK_REQUEST_T;
+
+typedef struct MMAL_CLOCK_PRIVATE_T
+{
+   MMAL_CLOCK_T clock;        /**< must be first */
+
+   MMAL_BOOL_T is_active;     /**< TRUE -> media-time is advancing */
+
+   MMAL_BOOL_T scheduling;    /**< TRUE -> client request scheduling is enabled */
+   MMAL_BOOL_T stop_thread;
+   VCOS_SEMAPHORE_T event;
+   VCOS_THREAD_T thread;      /**< processing thread for client requests */
+   MMAL_TIMER_T timer;        /**< used for scheduling client requests */
+
+   VCOS_MUTEX_T lock;         /**< lock access to the request lists */
+
+   int32_t scale;             /**< media-time scale factor (Q16 format) */
+   int32_t scale_inv;         /**< 1/scale (Q16 format) */
+   MMAL_RATIONAL_T scale_rational;
+                              /**< clock scale as a rational number; keep a copy since
+                                   converting from Q16 will result in precision errors */
+
+   int64_t  average_ref_diff; /**< media-time moving average adjustment */
+   int64_t  media_time;       /**< current local media-time in microseconds */
+   uint32_t media_time_frac;  /**< media-time fraction in microseconds (Q24 format) */
+   int64_t  wall_time;        /**< current local wall-time (microseconds) */
+   uint32_t rtc_at_update;    /**< real-time clock value at local time update (microseconds) */
+   int64_t  media_time_at_timer;
+                              /**< media-time when the timer was last set */
+
+   int64_t  discont_expiry;   /**< wall-time when discontinuity expires; 0 = no discontinuity
+                                   in effect */
+   int64_t  discont_start;    /**< media-time at start of discontinuity
+                                   (n/a if discont_expiry = 0) */
+   int64_t  discont_end;      /**< media-time at end of discontinuity
+                                   (n/a if discont_expiry = 0) */
+   int64_t  discont_threshold;/**< Threshold after which backward jumps in media time are treated
+                                   as a discontinuity  (microseconds) */
+   int64_t  discont_duration; /**< Duration (wall-time) for which a discontinuity applies */
+
+   int64_t  request_threshold;/**< Threshold after which frames exceeding the media-time are
+                                   dropped (microseconds) */
+   MMAL_BOOL_T request_threshold_enable;/**< Enable the request threshold */
+   int64_t  update_threshold_lower;
+                              /**< Time differences below this threshold are ignored */
+   int64_t  update_threshold_upper;
+                              /**< Time differences above this threshold reset media time */
+
+   /* Client requests */
+   struct
+   {
+      MMAL_LIST_T* list_free;
+      MMAL_LIST_T* list_pending;
+      MMAL_CLOCK_REQUEST_T pool[CLOCK_REQUEST_SLOTS];
+   } request;
+
+} MMAL_CLOCK_PRIVATE_T;
+
+
+/*****************************************************************************/
+static void mmal_clock_wake_thread(MMAL_CLOCK_PRIVATE_T *private);
+
+/*****************************************************************************
+ * Timer-specific functions
+ *****************************************************************************/
+/* Callback invoked when timer expires */
+#ifdef USE_RTOS_TIMER
+static void mmal_clock_timer_cb(MMAL_TIMER_T *timer, void *ctx)
+{
+   MMAL_PARAM_UNUSED(timer);
+   /* Notify the worker thread */
+   mmal_clock_wake_thread((MMAL_CLOCK_PRIVATE_T*)ctx);
+}
+#else
+static void mmal_clock_timer_cb(void *ctx)
+{
+   /* Notify the worker thread */
+   mmal_clock_wake_thread((MMAL_CLOCK_PRIVATE_T*)ctx);
+}
+#endif
+
+/* Create a timer */
+static inline MMAL_BOOL_T mmal_clock_timer_create(MMAL_TIMER_T *timer, void *ctx)
+{
+#ifdef USE_RTOS_TIMER
+   return (rtos_timer_init(timer, mmal_clock_timer_cb, ctx) == 0);
+#else
+   return (vcos_timer_create(timer, "mmal-clock timer", mmal_clock_timer_cb, ctx) == VCOS_SUCCESS);
+#endif
+}
+
+/* Destroy a timer */
+static inline void mmal_clock_timer_destroy(MMAL_TIMER_T *timer)
+{
+#ifdef USE_RTOS_TIMER
+   /* Nothing to do */
+#else
+   vcos_timer_delete(timer);
+#endif
+}
+
+/* Set the timer. Delay is in microseconds. */
+static inline void mmal_clock_timer_set(MMAL_TIMER_T *timer, int64_t delay_us)
+{
+#ifdef USE_RTOS_TIMER
+   rtos_timer_set(timer, (RTOS_TIMER_TIME_T)delay_us);
+#else
+   /* VCOS timer only provides millisecond accuracy */
+   vcos_timer_set(timer, (VCOS_UNSIGNED)(delay_us / 1000));
+#endif
+}
+
+/* Stop the timer. */
+static inline void mmal_clock_timer_cancel(MMAL_TIMER_T *timer)
+{
+#ifdef USE_RTOS_TIMER
+   rtos_timer_cancel(timer);
+#else
+   vcos_timer_cancel(timer);
+#endif
+}
+
+
+/*****************************************************************************
+ * Clock module private functions
+ *****************************************************************************/
+/* Update the internal wall-time and media-time */
+static void mmal_clock_update_local_time_locked(MMAL_CLOCK_PRIVATE_T *private)
+{
+   uint32_t time_now = vcos_getmicrosecs();
+   uint32_t time_diff = (time_now > private->rtc_at_update) ? (time_now - private->rtc_at_update) : 0;
+
+   private->wall_time += time_diff;
+
+   /* For small clock scale values (i.e. slow motion), the media-time increment
+    * could potentially be rounded down when doing lots of updates, so also keep
+    * track of the fractional increment. */
+   int64_t media_diff = ((int64_t)time_diff) * (int64_t)(private->scale << 8) + private->media_time_frac;
+
+   private->media_time += media_diff >> 24;
+   private->media_time_frac = media_diff & ((1<<24)-1);
+
+   private->rtc_at_update = time_now;
+}
+
+/* Return the current local media-time */
+static int64_t mmal_clock_media_time_get_locked(MMAL_CLOCK_PRIVATE_T *private)
+{
+   mmal_clock_update_local_time_locked(private);
+   return private->media_time;
+}
+
+/* Comparison function used for inserting a request into
+ * the list of pending requests when clock scale is positive. */
+static int mmal_clock_request_compare_pos(MMAL_LIST_ELEMENT_T *lhs, MMAL_LIST_ELEMENT_T *rhs)
+{
+   return ((MMAL_CLOCK_REQUEST_T*)lhs)->media_time_adj < ((MMAL_CLOCK_REQUEST_T*)rhs)->media_time_adj;
+}
+
+/* Comparison function used for inserting a request into
+ * the list of pending requests when clock scale is negative. */
+static int mmal_clock_request_compare_neg(MMAL_LIST_ELEMENT_T *lhs, MMAL_LIST_ELEMENT_T *rhs)
+{
+   return ((MMAL_CLOCK_REQUEST_T*)lhs)->media_time_adj > ((MMAL_CLOCK_REQUEST_T*)rhs)->media_time_adj;
+}
+
+/* Insert a new request into the list of pending requests */
+static MMAL_BOOL_T mmal_clock_request_insert(MMAL_CLOCK_PRIVATE_T *private, MMAL_CLOCK_REQUEST_T *request)
+{
+   MMAL_LIST_T *list = private->request.list_pending;
+   MMAL_CLOCK_REQUEST_T *pending;
+
+   if (private->stop_thread)
+      return MMAL_FALSE; /* the clock is being destroyed */
+
+   if (list->length == 0)
+   {
+      mmal_list_push_front(list, &request->link);
+      return MMAL_TRUE;
+   }
+
+   /* It is more likely for requests to be received in sequence,
+    * so try adding to the back of the list first before doing
+    * a more expensive list insert. */
+   pending = (MMAL_CLOCK_REQUEST_T*)list->last;
+   if ((private->scale >= 0 && (request->media_time_adj >= pending->media_time_adj)) ||
+       (private->scale <  0 && (request->media_time_adj <= pending->media_time_adj)))
+   {
+      mmal_list_push_back(list, &request->link);
+   }
+   else
+   {
+      mmal_list_insert(list, &request->link,
+            (private->scale >= 0) ? mmal_clock_request_compare_pos : mmal_clock_request_compare_neg);
+   }
+   return MMAL_TRUE;
+}
+
+/* Flush all pending requests */
+static MMAL_STATUS_T mmal_clock_request_flush_locked(MMAL_CLOCK_PRIVATE_T *private,
+                                                     int64_t media_time)
+{
+   MMAL_LIST_T *pending = private->request.list_pending;
+   MMAL_LIST_T *list_free = private->request.list_free;
+   MMAL_CLOCK_REQUEST_T *request;
+
+   while ((request = (MMAL_CLOCK_REQUEST_T *)mmal_list_pop_front(pending)) != NULL)
+   {
+      /* Inform the client */
+      request->cb(&private->clock, media_time, request->cb_data, request->priv);
+      /* Recycle request slot */
+      mmal_list_push_back(list_free, &request->link);
+   }
+
+   private->media_time_at_timer = 0;
+
+   return MMAL_SUCCESS;
+}
+
+/* Process all pending requests */
+static void mmal_clock_process_requests(MMAL_CLOCK_PRIVATE_T *private)
+{
+   int64_t media_time_now;
+   MMAL_LIST_T* free = private->request.list_free;
+   MMAL_LIST_T* pending = private->request.list_pending;
+   MMAL_CLOCK_REQUEST_T *next;
+
+   if (pending->length == 0 || !private->is_active)
+      return;
+
+   LOCK(private);
+
+   /* Detect discontinuity */
+   if (private->media_time_at_timer != 0)
+   {
+      media_time_now = mmal_clock_media_time_get_locked(private);
+      /* Currently only applied to forward speeds */
+      if (private->scale > 0 &&
+          media_time_now + private->discont_threshold < private->media_time_at_timer)
+      {
+         LOG_INFO("discontinuity: was=%" PRIi64 " now=%" PRIi64 " pending=%d",
+                  private->media_time_at_timer, media_time_now, pending->length);
+
+         /* It's likely that packets from before the discontinuity will continue to arrive for
+          * a short time. Ensure these are detected and the requests fired immediately. */
+         private->discont_start = private->media_time_at_timer;
+         private->discont_end = private->discont_start + private->discont_duration;
+         private->discont_expiry = private->wall_time + private->discont_duration;
+
+         /* Fire all pending requests */
+         mmal_clock_request_flush_locked(private, media_time_now);
+      }
+   }
+
+   /* Earliest request is always at the front */
+   next = (MMAL_CLOCK_REQUEST_T*)mmal_list_pop_front(pending);
+   while (next)
+   {
+      media_time_now = mmal_clock_media_time_get_locked(private);
+
+      if (private->discont_expiry != 0 && private->wall_time > private->discont_expiry)
+         private->discont_expiry = 0;
+
+      /* Fire the request if it matches the pending discontinuity or if its requested media time
+       * has been reached. */
+      if ((private->discont_expiry != 0 &&
+           next->media_time_adj >= private->discont_start &&
+           next->media_time_adj < private->discont_end) ||
+          (private->scale > 0 && ((media_time_now + MIN_TIMER_DELAY) >= next->media_time_adj)) ||
+          (private->scale < 0 && ((media_time_now - MIN_TIMER_DELAY) <= next->media_time_adj)))
+      {
+         LOG_TRACE("servicing request: next %"PRIi64" now %"PRIi64, next->media_time_adj, media_time_now);
+         /* Inform the client */
+         next->cb(&private->clock, media_time_now, next->cb_data, next->priv);
+         /* Recycle the request slot */
+         mmal_list_push_back(free, &next->link);
+         /* Move onto next pending request */
+         next = (MMAL_CLOCK_REQUEST_T*)mmal_list_pop_front(pending);
+      }
+      else
+      {
+         /* The next request is in the future, so re-schedule the
+          * timer based on the current clock scale and media-time diff */
+         int64_t media_time_delay = ABS_VALUE(media_time_now - next->media_time_adj);
+         int64_t wall_time_delay = ABS_VALUE(((int64_t)private->scale_inv * media_time_delay) >> 16);
+
+         if (private->scale == 0)
+            wall_time_delay = CLOCK_WAIT_TIME; /* Clock is paused */
+
+         /* Put next request back into pending list */
+         mmal_list_push_front(pending, &next->link);
+         next = NULL;
+
+         /* Set the timer */
+         private->media_time_at_timer = media_time_now;
+         mmal_clock_timer_set(&private->timer, wall_time_delay);
+
+         LOG_TRACE("re-schedule timer: now %"PRIi64" delay %"PRIi64, media_time_now, wall_time_delay);
+      }
+   }
+
+   UNLOCK(private);
+}
+
+/* Trigger the worker thread (if present) */
+static void mmal_clock_wake_thread(MMAL_CLOCK_PRIVATE_T *private)
+{
+   if (private->scheduling)
+      vcos_semaphore_post(&private->event);
+}
+
+/* Stop the worker thread */
+static void mmal_clock_stop_thread(MMAL_CLOCK_PRIVATE_T *private)
+{
+   private->stop_thread = MMAL_TRUE;
+   mmal_clock_wake_thread(private);
+   vcos_thread_join(&private->thread, NULL);
+}
+
+/* Main processing thread */
+static void* mmal_clock_worker_thread(void *ctx)
+{
+   MMAL_CLOCK_PRIVATE_T *private = (MMAL_CLOCK_PRIVATE_T*)ctx;
+
+   while (1)
+   {
+      vcos_semaphore_wait(&private->event);
+
+      /* Either the timer has expired or a new request is pending */
+      mmal_clock_timer_cancel(&private->timer);
+
+      if (private->stop_thread)
+         break;
+
+      mmal_clock_process_requests(private);
+   }
+   return NULL;
+}
+
+/* Create scheduling resources */
+static MMAL_STATUS_T mmal_clock_create_scheduling(MMAL_CLOCK_PRIVATE_T *private)
+{
+   unsigned int i;
+   MMAL_BOOL_T timer_status = MMAL_FALSE;
+   VCOS_STATUS_T event_status = VCOS_EINVAL;
+   VCOS_UNSIGNED priority;
+
+   timer_status = mmal_clock_timer_create(&private->timer, private);
+   if (!timer_status)
+   {
+      LOG_ERROR("failed to create timer %p", private);
+      goto error;
+   }
+
+   event_status = vcos_semaphore_create(&private->event, "mmal-clock sema", 0);
+   if (event_status != VCOS_SUCCESS)
+   {
+      LOG_ERROR("failed to create event semaphore %d", event_status);
+      goto error;
+   }
+
+   private->request.list_free = mmal_list_create();
+   private->request.list_pending = mmal_list_create();
+   if (!private->request.list_free || !private->request.list_pending)
+   {
+      LOG_ERROR("failed to create list %p %p", private->request.list_free, private->request.list_pending);
+      goto error;
+   }
+
+   /* Populate the list of available request slots */
+   for (i = 0; i < CLOCK_REQUEST_SLOTS; ++i)
+      mmal_list_push_back(private->request.list_free, &private->request.pool[i].link);
+
+   if (vcos_thread_create(&private->thread, "mmal-clock thread", NULL,
+                          mmal_clock_worker_thread, private) != VCOS_SUCCESS)
+   {
+      LOG_ERROR("failed to create worker thread");
+      goto error;
+   }
+   priority = vcos_thread_get_priority(&private->thread);
+   vcos_thread_set_priority(&private->thread, 1 | (priority & VCOS_AFFINITY_MASK));
+
+   private->scheduling = MMAL_TRUE;
+
+   return MMAL_SUCCESS;
+
+error:
+   if (event_status == VCOS_SUCCESS) vcos_semaphore_delete(&private->event);
+   if (timer_status) mmal_clock_timer_destroy(&private->timer);
+   if (private->request.list_free) mmal_list_destroy(private->request.list_free);
+   if (private->request.list_pending) mmal_list_destroy(private->request.list_pending);
+   return MMAL_ENOSPC;
+}
+
+/* Destroy all scheduling resources */
+static void mmal_clock_destroy_scheduling(MMAL_CLOCK_PRIVATE_T *private)
+{
+   mmal_clock_stop_thread(private);
+
+   mmal_clock_request_flush(&private->clock);
+
+   mmal_list_destroy(private->request.list_free);
+   mmal_list_destroy(private->request.list_pending);
+
+   vcos_semaphore_delete(&private->event);
+
+   mmal_clock_timer_destroy(&private->timer);
+}
+
+/* Start the media-time */
+static void mmal_clock_start(MMAL_CLOCK_T *clock)
+{
+   MMAL_CLOCK_PRIVATE_T *private = (MMAL_CLOCK_PRIVATE_T*)clock;
+
+   private->is_active = MMAL_TRUE;
+
+   mmal_clock_wake_thread(private);
+}
+
+/* Stop the media-time */
+static void mmal_clock_stop(MMAL_CLOCK_T *clock)
+{
+   MMAL_CLOCK_PRIVATE_T *private = (MMAL_CLOCK_PRIVATE_T*)clock;
+
+   private->is_active = MMAL_FALSE;
+
+   mmal_clock_wake_thread(private);
+}
+
+static int mmal_clock_is_paused(MMAL_CLOCK_T *clock)
+{
+   MMAL_CLOCK_PRIVATE_T *private = (MMAL_CLOCK_PRIVATE_T*)clock;
+   return private->scale == 0;
+}
+
+/*****************************************************************************
+ * Clock module public functions
+ *****************************************************************************/
+/* Create new clock instance */
+MMAL_STATUS_T mmal_clock_create(MMAL_CLOCK_T **clock)
+{
+   unsigned int size = sizeof(MMAL_CLOCK_PRIVATE_T);
+   MMAL_RATIONAL_T scale = { 1, 1 };
+   MMAL_CLOCK_PRIVATE_T *private;
+
+   /* Sanity checking */
+   if (clock == NULL)
+      return MMAL_EINVAL;
+
+   private = vcos_calloc(1, size, "mmal-clock");
+   if (!private)
+   {
+      LOG_ERROR("failed to allocate memory");
+      return MMAL_ENOMEM;
+   }
+
+   if (vcos_mutex_create(&private->lock, "mmal-clock lock") != VCOS_SUCCESS)
+   {
+      LOG_ERROR("failed to create lock mutex");
+      vcos_free(private);
+      return MMAL_ENOSPC;
+   }
+
+   /* Set the default threshold values */
+   private->update_threshold_lower = CLOCK_UPDATE_THRESHOLD_LOWER;
+   private->update_threshold_upper = CLOCK_UPDATE_THRESHOLD_UPPER;
+   private->discont_threshold      = CLOCK_DISCONT_THRESHOLD;
+   private->discont_duration       = CLOCK_DISCONT_DURATION;
+   private->request_threshold      = 0;
+   private->request_threshold_enable = MMAL_FALSE;
+
+   /* Default scale = 1.0, i.e. normal playback speed */
+   mmal_clock_scale_set(&private->clock, scale);
+
+   *clock = &private->clock;
+   return MMAL_SUCCESS;
+}
+
+/* Destroy a clock instance */
+MMAL_STATUS_T mmal_clock_destroy(MMAL_CLOCK_T *clock)
+{
+   MMAL_CLOCK_PRIVATE_T *private = (MMAL_CLOCK_PRIVATE_T*)clock;
+
+   if (private->scheduling)
+      mmal_clock_destroy_scheduling(private);
+
+   vcos_mutex_delete(&private->lock);
+
+   vcos_free(private);
+
+   return MMAL_SUCCESS;
+}
+
+/* Add new client request to list of pending requests */
+MMAL_STATUS_T mmal_clock_request_add(MMAL_CLOCK_T *clock, int64_t media_time,
+      MMAL_CLOCK_REQUEST_CB cb, void *cb_data, MMAL_CLOCK_VOID_FP priv)
+{
+   MMAL_CLOCK_PRIVATE_T *private = (MMAL_CLOCK_PRIVATE_T*)clock;
+   MMAL_CLOCK_REQUEST_T *request;
+   MMAL_BOOL_T wake_thread = MMAL_FALSE;
+   int64_t media_time_now;
+
+   LOG_TRACE("media time %"PRIi64, media_time);
+
+   LOCK(private);
+
+   media_time_now = mmal_clock_media_time_get_locked(private);
+
+   /* Drop the request if request_threshold_enable and the frame exceeds the request threshold */
+   if (private->request_threshold_enable && (media_time > (media_time_now + private->request_threshold)))
+   {
+      LOG_TRACE("dropping request: media time %"PRIi64" now %"PRIi64, media_time, media_time_now);
+      UNLOCK(private);
+      return MMAL_ECORRUPT;
+   }
+
+   /* The clock module is usually only used for time-keeping, so all the
+    * objects needed to process client requests are not allocated by default
+    * and need to be created on the first client request received */
+   if (!private->scheduling)
+   {
+      if (mmal_clock_create_scheduling(private) != MMAL_SUCCESS)
+      {
+         LOG_ERROR("failed to create scheduling objects");
+         UNLOCK(private);
+         return MMAL_ENOSPC;
+      }
+   }
+
+   request = (MMAL_CLOCK_REQUEST_T*)mmal_list_pop_front(private->request.list_free);
+   if (request == NULL)
+   {
+      LOG_ERROR("no more free clock request slots");
+      UNLOCK(private);
+      return MMAL_ENOSPC;
+   }
+
+   request->cb = cb;
+   request->cb_data = cb_data;
+   request->priv = priv;
+   request->media_time = media_time;
+   request->media_time_adj = media_time - (int64_t)(private->scale * CLOCK_TARGET_OFFSET >> 16);
+
+   if (mmal_clock_request_insert(private, request))
+      wake_thread = private->is_active;
+
+   UNLOCK(private);
+
+   /* Notify the worker thread */
+   if (wake_thread)
+      mmal_clock_wake_thread(private);
+
+   return MMAL_SUCCESS;
+}
+
+/* Flush all pending requests */
+MMAL_STATUS_T mmal_clock_request_flush(MMAL_CLOCK_T *clock)
+{
+   MMAL_CLOCK_PRIVATE_T *private = (MMAL_CLOCK_PRIVATE_T*)clock;
+
+   LOCK(private);
+   if (private->scheduling)
+      mmal_clock_request_flush_locked(private, MMAL_TIME_UNKNOWN);
+   UNLOCK(private);
+
+   return MMAL_SUCCESS;
+}
+
+/* Update the local media-time with the given reference */
+MMAL_STATUS_T mmal_clock_media_time_set(MMAL_CLOCK_T *clock, int64_t media_time)
+{
+   MMAL_CLOCK_PRIVATE_T *private = (MMAL_CLOCK_PRIVATE_T*)clock;
+   MMAL_BOOL_T wake_thread = MMAL_TRUE;
+   int64_t time_diff;
+
+   LOCK(private);
+
+   if (!private->is_active)
+   {
+      uint32_t time_now = vcos_getmicrosecs();
+      private->wall_time = time_now;
+      private->media_time = media_time;
+      private->media_time_frac = 0;
+      private->rtc_at_update = time_now;
+
+      UNLOCK(private);
+      return MMAL_SUCCESS;
+   }
+
+   if (mmal_clock_is_paused(clock))
+   {
+      LOG_TRACE("clock is paused; ignoring update");
+      UNLOCK(private);
+      return MMAL_SUCCESS;
+   }
+
+   /* Reset the local media-time with the given time reference */
+   mmal_clock_update_local_time_locked(private);
+
+   time_diff = private->media_time - media_time;
+   if (time_diff >  private->update_threshold_upper ||
+       time_diff < -private->update_threshold_upper)
+   {
+      LOG_TRACE("cur:%"PRIi64" new:%"PRIi64" diff:%"PRIi64, private->media_time, media_time, time_diff);
+      private->media_time = media_time;
+      private->average_ref_diff = 0;
+   }
+   else
+   {
+      private->average_ref_diff = ((private->average_ref_diff << 6) - private->average_ref_diff + time_diff) >> 6;
+      if(private->average_ref_diff >  private->update_threshold_lower ||
+         private->average_ref_diff < -private->update_threshold_lower)
+      {
+         LOG_TRACE("cur:%"PRIi64" new:%"PRIi64" ave:%"PRIi64, private->media_time,
+               private->media_time - private->average_ref_diff, private->average_ref_diff);
+         private->media_time -= private->average_ref_diff;
+         private->average_ref_diff = 0;
+      }
+      else
+      {
+         /* Don't update the media-time */
+         wake_thread = MMAL_FALSE;
+         LOG_TRACE("cur:%"PRIi64" new:%"PRIi64" diff:%"PRIi64" ave:%"PRIi64" ignored", private->media_time,
+               media_time, private->media_time - media_time, private->average_ref_diff);
+      }
+   }
+
+   UNLOCK(private);
+
+   if (wake_thread)
+      mmal_clock_wake_thread(private);
+
+   return MMAL_SUCCESS;
+}
+
+/* Change the clock scale */
+MMAL_STATUS_T mmal_clock_scale_set(MMAL_CLOCK_T *clock, MMAL_RATIONAL_T scale)
+{
+   MMAL_CLOCK_PRIVATE_T *private = (MMAL_CLOCK_PRIVATE_T*)clock;
+
+   LOG_TRACE("new scale %d/%d", scale.num, scale.den);
+
+   LOCK(private);
+
+   mmal_clock_update_local_time_locked(private);
+
+   private->scale_rational = scale;
+   private->scale = mmal_rational_to_fixed_16_16(scale);
+
+   if (private->scale)
+      private->scale_inv = (int32_t)((1LL << 32) / (int64_t)private->scale);
+   else
+      private->scale_inv = Q16_ONE; /* clock is paused */
+
+   UNLOCK(private);
+
+   mmal_clock_wake_thread(private);
+
+   return MMAL_SUCCESS;
+}
+
+/* Set the clock state */
+MMAL_STATUS_T mmal_clock_active_set(MMAL_CLOCK_T *clock, MMAL_BOOL_T active)
+{
+   if (active)
+      mmal_clock_start(clock);
+   else
+      mmal_clock_stop(clock);
+
+   return MMAL_SUCCESS;
+}
+
+/* Get the clock's scale */
+MMAL_RATIONAL_T mmal_clock_scale_get(MMAL_CLOCK_T *clock)
+{
+   MMAL_CLOCK_PRIVATE_T *private = (MMAL_CLOCK_PRIVATE_T*)clock;
+   MMAL_RATIONAL_T scale;
+
+   LOCK(private);
+   scale = private->scale_rational;
+   UNLOCK(private);
+
+   return scale;
+}
+
+/* Return the current local media-time */
+int64_t mmal_clock_media_time_get(MMAL_CLOCK_T *clock)
+{
+   int64_t media_time;
+   MMAL_CLOCK_PRIVATE_T *private = (MMAL_CLOCK_PRIVATE_T*)clock;
+
+   LOCK(private);
+   media_time = mmal_clock_media_time_get_locked(private);
+   UNLOCK(private);
+
+   return media_time;
+}
+
+/* Get the clock's state */
+MMAL_BOOL_T mmal_clock_is_active(MMAL_CLOCK_T *clock)
+{
+   return ((MMAL_CLOCK_PRIVATE_T*)clock)->is_active;
+}
+
+/* Get the clock's media-time update threshold values */
+MMAL_STATUS_T mmal_clock_update_threshold_get(MMAL_CLOCK_T *clock, MMAL_CLOCK_UPDATE_THRESHOLD_T *update_threshold)
+{
+   MMAL_CLOCK_PRIVATE_T *private = (MMAL_CLOCK_PRIVATE_T *)clock;
+
+   LOCK(private);
+   update_threshold->threshold_lower = private->update_threshold_lower;
+   update_threshold->threshold_upper = private->update_threshold_upper;
+   UNLOCK(private);
+
+   return MMAL_SUCCESS;
+}
+
+/* Set the clock's media-time update threshold values */
+MMAL_STATUS_T mmal_clock_update_threshold_set(MMAL_CLOCK_T *clock, const MMAL_CLOCK_UPDATE_THRESHOLD_T *update_threshold)
+{
+   MMAL_CLOCK_PRIVATE_T *private = (MMAL_CLOCK_PRIVATE_T *)clock;
+
+   LOG_TRACE("new clock update thresholds: upper %"PRIi64", lower %"PRIi64,
+         update_threshold->threshold_lower, update_threshold->threshold_upper);
+
+   LOCK(private);
+   private->update_threshold_lower = update_threshold->threshold_lower;
+   private->update_threshold_upper = update_threshold->threshold_upper;
+   UNLOCK(private);
+
+   return MMAL_SUCCESS;
+}
+
+/* Get the clock's discontinuity threshold values */
+MMAL_STATUS_T mmal_clock_discont_threshold_get(MMAL_CLOCK_T *clock, MMAL_CLOCK_DISCONT_THRESHOLD_T *discont)
+{
+   MMAL_CLOCK_PRIVATE_T *private = (MMAL_CLOCK_PRIVATE_T *)clock;
+
+   LOCK(private);
+   discont->threshold = private->discont_threshold;
+   discont->duration  = private->discont_duration;
+   UNLOCK(private);
+
+   return MMAL_SUCCESS;
+}
+
+/* Set the clock's discontinuity threshold values */
+MMAL_STATUS_T mmal_clock_discont_threshold_set(MMAL_CLOCK_T *clock, const MMAL_CLOCK_DISCONT_THRESHOLD_T *discont)
+{
+   MMAL_CLOCK_PRIVATE_T *private = (MMAL_CLOCK_PRIVATE_T *)clock;
+
+   LOG_TRACE("new clock discontinuity values: threshold %"PRIi64", duration %"PRIi64,
+         discont->threshold, discont->duration);
+
+   LOCK(private);
+   private->discont_threshold = discont->threshold;
+   private->discont_duration  = discont->duration;
+   UNLOCK(private);
+
+   return MMAL_SUCCESS;
+}
+
+/* Get the clock's request threshold values */
+MMAL_STATUS_T mmal_clock_request_threshold_get(MMAL_CLOCK_T *clock, MMAL_CLOCK_REQUEST_THRESHOLD_T *req)
+{
+   MMAL_CLOCK_PRIVATE_T *private = (MMAL_CLOCK_PRIVATE_T *)clock;
+
+   LOCK(private);
+   req->threshold = private->request_threshold;
+   req->threshold_enable = private->request_threshold_enable;
+   UNLOCK(private);
+
+   return MMAL_SUCCESS;
+}
+
+/* Set the clock's request threshold values */
+MMAL_STATUS_T mmal_clock_request_threshold_set(MMAL_CLOCK_T *clock, const MMAL_CLOCK_REQUEST_THRESHOLD_T *req)
+{
+   MMAL_CLOCK_PRIVATE_T *private = (MMAL_CLOCK_PRIVATE_T *)clock;
+
+   LOG_TRACE("new clock request values: threshold %"PRIi64,
+         req->threshold);
+
+   LOCK(private);
+   private->request_threshold = req->threshold;
+   private->request_threshold_enable = req->threshold_enable;
+   UNLOCK(private);
+
+   return MMAL_SUCCESS;
+}
diff --git a/interface/mmal/core/mmal_clock_private.h b/interface/mmal/core/mmal_clock_private.h
new file mode 100755 (executable)
index 0000000..25ebc87
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_CLOCK_PRIVATE_H
+#define MMAL_CLOCK_PRIVATE_H
+
+#include "interface/mmal/mmal.h"
+#include "interface/mmal/mmal_clock.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/** Handle to a clock. */
+typedef struct MMAL_CLOCK_T
+{
+   void *user_data;   /**< Client-supplied data (not used by the clock). */
+} MMAL_CLOCK_T;
+
+/** Create a new instance of a clock.
+ *
+ * @param clock Returned clock
+ *
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_clock_create(MMAL_CLOCK_T **clock);
+
+/** Destroy a previously created clock.
+ *
+ * @param clock The clock to destroy
+ *
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_clock_destroy(MMAL_CLOCK_T *clock);
+
+/** Definition of a clock request callback.
+ * This is invoked when the media-time requested by the client is reached.
+ *
+ * @param clock      The clock which serviced the request
+ * @param media_time The current media-time
+ * @param cb_data    Client-supplied data
+ * @param priv       Function pointer used by the framework
+ */
+typedef void (*MMAL_CLOCK_VOID_FP)(void);
+typedef void (*MMAL_CLOCK_REQUEST_CB)(MMAL_CLOCK_T *clock, int64_t media_time, void *cb_data, MMAL_CLOCK_VOID_FP priv);
+
+/** Register a request with the clock.
+ * When the specified media-time is reached, the clock will invoke the supplied callback.
+ *
+ * @param clock      The clock
+ * @param media_time The media-time at which the callback should be invoked (microseconds)
+ * @param cb         Callback to invoke
+ * @param cb_data    Client-supplied callback data
+ * @param priv       Function pointer used by the framework
+ *
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_clock_request_add(MMAL_CLOCK_T *clock, int64_t media_time,
+                                     MMAL_CLOCK_REQUEST_CB cb, void *cb_data, MMAL_CLOCK_VOID_FP priv);
+
+/** Remove all previously registered clock requests.
+ *
+ * @param clock      The clock
+ *
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_clock_request_flush(MMAL_CLOCK_T *clock);
+
+/** Update the clock's media-time.
+ *
+ * @param clock      The clock to update
+ * @param media_time New media-time to be applied (microseconds)
+ *
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_clock_media_time_set(MMAL_CLOCK_T *clock, int64_t media_time);
+
+/** Set the clock's scale.
+ *
+ * @param clock      The clock
+ * @param scale      Scale factor
+ *
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_clock_scale_set(MMAL_CLOCK_T *clock, MMAL_RATIONAL_T scale);
+
+/** Set the clock state.
+ *
+ * @param clock      The clock
+ * @param active     TRUE -> clock is active and media-time is advancing
+ *
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_clock_active_set(MMAL_CLOCK_T *clock, MMAL_BOOL_T active);
+
+/** Get the clock's scale.
+ *
+ * @param clock      The clock
+ *
+ * @return Current clock scale
+ */
+MMAL_RATIONAL_T mmal_clock_scale_get(MMAL_CLOCK_T *clock);
+
+/** Get the clock's current media-time.
+ * This takes the clock scale and media-time offset into account.
+ *
+ * @param clock      The clock to query
+ *
+ * @return Current media-time in microseconds
+ */
+int64_t mmal_clock_media_time_get(MMAL_CLOCK_T *clock);
+
+/** Get the clock's state.
+ *
+ * @param clock      The clock to query
+ *
+ * @return TRUE if clock is running (i.e. local media-time is advancing)
+ */
+MMAL_BOOL_T mmal_clock_is_active(MMAL_CLOCK_T *clock);
+
+/** Get the clock's media-time update threshold values.
+ *
+ * @param clock             The clock
+ * @param update_threshold  Pointer to clock update threshold values to fill
+ *
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_clock_update_threshold_get(MMAL_CLOCK_T *clock, MMAL_CLOCK_UPDATE_THRESHOLD_T *update_threshold);
+
+/** Set the clock's media-time update threshold values.
+ *
+ * @param clock             The clock
+ * @param update_threshold  Pointer to new clock update threshold values
+ *
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_clock_update_threshold_set(MMAL_CLOCK_T *clock, const MMAL_CLOCK_UPDATE_THRESHOLD_T *update_threshold);
+
+/** Get the clock's discontinuity threshold values.
+ *
+ * @param clock      The clock
+ * @param discont    Pointer to clock discontinuity threshold values to fill
+ *
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_clock_discont_threshold_get(MMAL_CLOCK_T *clock, MMAL_CLOCK_DISCONT_THRESHOLD_T *discont);
+
+/** Set the clock's discontinuity threshold values.
+ *
+ * @param clock      The clock
+ * @param discont    Pointer to new clock discontinuity threshold values
+ *
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_clock_discont_threshold_set(MMAL_CLOCK_T *clock, const MMAL_CLOCK_DISCONT_THRESHOLD_T *discont);
+
+/** Get the clock's request threshold values.
+ *
+ * @param clock      The clock
+ * @param future     Pointer to clock request threshold values to fill
+ *
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_clock_request_threshold_get(MMAL_CLOCK_T *clock, MMAL_CLOCK_REQUEST_THRESHOLD_T *req);
+
+/** Set the clock's request threshold values.
+ *
+ * @param clock      The clock
+ * @param discont    Pointer to new clock request threshold values
+ *
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_clock_request_threshold_set(MMAL_CLOCK_T *clock, const MMAL_CLOCK_REQUEST_THRESHOLD_T *req);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MMAL_CLOCK_PRIVATE_H */
diff --git a/interface/mmal/core/mmal_component.c b/interface/mmal/core/mmal_component.c
new file mode 100755 (executable)
index 0000000..c621ca8
--- /dev/null
@@ -0,0 +1,780 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "core/mmal_component_private.h"
+#include "core/mmal_port_private.h"
+#include "core/mmal_core_private.h"
+#include "mmal_logging.h"
+
+/* Minimum number of buffers that will be available on the control port */
+#define MMAL_CONTROL_PORT_BUFFERS_MIN 4
+
+/** Definition of the core private context. */
+typedef struct
+{
+   MMAL_COMPONENT_PRIVATE_T private;
+
+   /** Action registered by component and run when buffers are received by any of the ports */
+   void (*pf_action)(MMAL_COMPONENT_T *component);
+
+   /** Action thread */
+   VCOS_THREAD_T action_thread;
+   VCOS_EVENT_T action_event;
+   VCOS_MUTEX_T action_mutex;
+   MMAL_BOOL_T action_quit;
+
+   VCOS_MUTEX_T lock; /**< Used to lock access to the component */
+   MMAL_BOOL_T destruction_pending;
+
+} MMAL_COMPONENT_CORE_PRIVATE_T;
+
+/*****************************************************************************/
+static void mmal_core_init(void);
+static void mmal_core_deinit(void);
+
+static MMAL_STATUS_T mmal_component_supplier_create(const char *name, MMAL_COMPONENT_T *component);
+static void mmal_component_init_control_port(MMAL_PORT_T *port);
+
+static MMAL_STATUS_T mmal_component_destroy_internal(MMAL_COMPONENT_T *component);
+static MMAL_STATUS_T mmal_component_release_internal(MMAL_COMPONENT_T *component);
+
+/*****************************************************************************/
+static VCOS_MUTEX_T mmal_core_lock;
+/** Used to generate a unique id for each MMAL component in this context.    */
+static unsigned int mmal_core_instance_count;
+static unsigned int mmal_core_refcount;
+/*****************************************************************************/
+
+/** Create an instance of a component */
+static MMAL_STATUS_T mmal_component_create_core(const char *name,
+   MMAL_STATUS_T (*constructor)(const char *name, MMAL_COMPONENT_T *),
+   struct MMAL_COMPONENT_MODULE_T *constructor_private,
+   MMAL_COMPONENT_T **component)
+{
+   MMAL_COMPONENT_CORE_PRIVATE_T *private;
+   MMAL_STATUS_T status = MMAL_ENOMEM;
+   unsigned int size = sizeof(MMAL_COMPONENT_T) + sizeof(MMAL_COMPONENT_CORE_PRIVATE_T);
+   unsigned int i, name_length = strlen(name) + 1;
+   unsigned int port_index;
+   char *component_name;
+
+   if(!component)
+      return MMAL_EINVAL;
+
+   mmal_core_init();
+
+   *component = vcos_calloc(1, size + name_length, "mmal component");
+   if(!*component)
+      return MMAL_ENOMEM;
+
+   private = (MMAL_COMPONENT_CORE_PRIVATE_T *)&(*component)[1];
+   (*component)->priv = (MMAL_COMPONENT_PRIVATE_T *)private;
+   (*component)->name = component_name= (char *)&((MMAL_COMPONENT_CORE_PRIVATE_T *)(*component)->priv)[1];
+   memcpy(component_name, name, name_length);
+   /* coverity[missing_lock] Component and mutex have just been created. No need to lock yet */
+   (*component)->priv->refcount = 1;
+   (*component)->priv->priority = VCOS_THREAD_PRI_NORMAL;
+
+   if(vcos_mutex_create(&private->lock, "mmal component lock") != VCOS_SUCCESS)
+   {
+      vcos_free(*component);
+      return MMAL_ENOMEM;
+   }
+
+   vcos_mutex_lock(&mmal_core_lock);
+   (*component)->id=mmal_core_instance_count++;
+   vcos_mutex_unlock(&mmal_core_lock);
+
+   /* Create the control port */
+   (*component)->control = mmal_port_alloc(*component, MMAL_PORT_TYPE_CONTROL, 0);
+   if(!(*component)->control)
+      goto error;
+   mmal_component_init_control_port((*component)->control);
+
+   /* Create the actual component */
+   (*component)->priv->module = constructor_private;
+   if (!constructor)
+      constructor = mmal_component_supplier_create;
+   status = constructor(name, *component);
+   if (status != MMAL_SUCCESS)
+   {
+      if (status == MMAL_ENOSYS)
+         LOG_ERROR("could not find component '%s'", name);
+      else
+         LOG_ERROR("could not create component '%s' (%i)", name, status);
+      goto error;
+   }
+
+   /* Make sure we have enough space for at least a MMAL_EVENT_FORMAT_CHANGED */
+   if ((*component)->control->buffer_size_min <
+       sizeof(MMAL_ES_FORMAT_T) + sizeof(MMAL_ES_SPECIFIC_FORMAT_T) + sizeof(MMAL_EVENT_FORMAT_CHANGED_T))
+      (*component)->control->buffer_size_min = sizeof(MMAL_ES_FORMAT_T) +
+         sizeof(MMAL_ES_SPECIFIC_FORMAT_T) + sizeof(MMAL_EVENT_FORMAT_CHANGED_T);
+   /* Make sure we have enough events */
+   if ((*component)->control->buffer_num_min < MMAL_CONTROL_PORT_BUFFERS_MIN)
+      (*component)->control->buffer_num_min = MMAL_CONTROL_PORT_BUFFERS_MIN;
+
+   /* Create the event pool */
+   (*component)->priv->event_pool = mmal_pool_create((*component)->control->buffer_num_min,
+         (*component)->control->buffer_size_min);
+   if (!(*component)->priv->event_pool)
+   {
+      status = MMAL_ENOMEM;
+      LOG_ERROR("could not create event pool (%d, %d)", (*component)->control->buffer_num_min,
+            (*component)->control->buffer_size_min);
+      goto error;
+   }
+
+   /* Build the list of all the ports */
+   (*component)->port_num = (*component)->input_num + (*component)->output_num + (*component)->clock_num + 1;
+   (*component)->port = vcos_malloc((*component)->port_num * sizeof(MMAL_PORT_T *), "mmal ports");
+   if (!(*component)->port)
+   {
+      status = MMAL_ENOMEM;
+      LOG_ERROR("could not create list of ports");
+      goto error;
+   }
+   port_index = 0;
+   (*component)->port[port_index++] = (*component)->control;
+   for (i = 0; i < (*component)->input_num; i++)
+      (*component)->port[port_index++] = (*component)->input[i];
+   for (i = 0; i < (*component)->output_num; i++)
+      (*component)->port[port_index++] = (*component)->output[i];
+   for (i = 0; i < (*component)->clock_num; i++)
+      (*component)->port[port_index++] = (*component)->clock[i];
+   for (i = 0; i < (*component)->port_num; i++)
+      (*component)->port[i]->index_all = i;
+
+   LOG_INFO("created '%s' %d %p", name, (*component)->id, *component);
+
+   /* Make sure the port types, indexes and buffer sizes are set correctly */
+   (*component)->control->type = MMAL_PORT_TYPE_CONTROL;
+   (*component)->control->index = 0;
+   for (i = 0; i < (*component)->input_num; i++)
+   {
+      MMAL_PORT_T *port = (*component)->input[i];
+      port->type = MMAL_PORT_TYPE_INPUT;
+      port->index = i;
+   }
+   for (i = 0; i < (*component)->output_num; i++)
+   {
+      MMAL_PORT_T *port = (*component)->output[i];
+      port->type = MMAL_PORT_TYPE_OUTPUT;
+      port->index = i;
+   }
+   for (i = 0; i < (*component)->clock_num; i++)
+   {
+      MMAL_PORT_T *port = (*component)->clock[i];
+      port->type = MMAL_PORT_TYPE_CLOCK;
+      port->index = i;
+   }
+   for (i = 0; i < (*component)->port_num; i++)
+   {
+      MMAL_PORT_T *port = (*component)->port[i];
+      if (port->buffer_size < port->buffer_size_min)
+         port->buffer_size = port->buffer_size_min;
+      if (port->buffer_num < port->buffer_num_min)
+         port->buffer_num = port->buffer_num_min;
+   }
+
+   return MMAL_SUCCESS;
+
+ error:
+   mmal_component_destroy_internal(*component);
+   *component = 0;
+   return status;
+}
+
+/** Create an instance of a component */
+MMAL_STATUS_T mmal_component_create(const char *name,
+   MMAL_COMPONENT_T **component)
+{
+   LOG_TRACE("%s", name);
+   return mmal_component_create_core(name, 0, 0, component);
+}
+
+/** Create an instance of a component */
+MMAL_STATUS_T mmal_component_create_with_constructor(const char *name,
+   MMAL_STATUS_T (*constructor)(const char *name, MMAL_COMPONENT_T *),
+   struct MMAL_COMPONENT_MODULE_T *constructor_private,
+   MMAL_COMPONENT_T **component)
+{
+   LOG_TRACE("%s", name);
+   return mmal_component_create_core(name, constructor, constructor_private, component);
+}
+
+/** Destroy a previously created component */
+static MMAL_STATUS_T mmal_component_destroy_internal(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_CORE_PRIVATE_T *private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
+   MMAL_STATUS_T status;
+
+   LOG_TRACE("%s %d", component->name, component->id);
+
+   mmal_component_action_deregister(component);
+
+   /* Should pf_destroy be allowed to fail ?
+    * If so, what do we do if it fails ?
+    */
+   if (component->priv->pf_destroy)
+   {
+      status = component->priv->pf_destroy(component);
+      if(!vcos_verify(status == MMAL_SUCCESS))
+         return status;
+   }
+
+   if (component->priv->event_pool)
+      mmal_pool_destroy(component->priv->event_pool);
+
+   if (component->control)
+      mmal_port_free(component->control);
+
+   if (component->port)
+      vcos_free(component->port);
+
+   vcos_mutex_delete(&private->lock);
+   vcos_free(component);
+   mmal_core_deinit();
+   return MMAL_SUCCESS;
+}
+
+/** Release a reference to a component */
+static MMAL_STATUS_T mmal_component_release_internal(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_CORE_PRIVATE_T *private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
+   unsigned int i;
+
+   if (!vcos_verify(component->priv->refcount > 0))
+      return MMAL_EINVAL;
+
+   vcos_mutex_lock(&private->lock);
+   if (--component->priv->refcount)
+   {
+      vcos_mutex_unlock(&private->lock);
+      return MMAL_SUCCESS;
+   }
+   private->destruction_pending = 1;
+   vcos_mutex_unlock(&private->lock);
+
+   LOG_TRACE("%s %d preparing for destruction", component->name, component->id);
+
+   /* Make sure the ports are all disabled */
+   for(i = 0; i < component->input_num; i++)
+      if(component->input[i]->is_enabled)
+         mmal_port_disable(component->input[i]);
+   for(i = 0; i < component->output_num; i++)
+      if(component->output[i]->is_enabled)
+         mmal_port_disable(component->output[i]);
+   for(i = 0; i < component->clock_num; i++)
+      if(component->clock[i]->is_enabled)
+         mmal_port_disable(component->clock[i]);
+   if(component->control->is_enabled)
+      mmal_port_disable(component->control);
+
+   /* Make sure all the ports are disconnected. This is necessary to prevent
+    * connected ports from referencing destroyed components */
+   for(i = 0; i < component->input_num; i++)
+      mmal_port_disconnect(component->input[i]);
+   for(i = 0; i < component->output_num; i++)
+      mmal_port_disconnect(component->output[i]);
+   for(i = 0; i < component->clock_num; i++)
+      mmal_port_disconnect(component->clock[i]);
+
+   /* If there is any reference pending on the ports we will delay the actual destruction */
+   vcos_mutex_lock(&private->lock);
+   if (component->priv->refcount_ports)
+   {
+      private->destruction_pending = 0;
+      vcos_mutex_unlock(&private->lock);
+      LOG_TRACE("%s %d delaying destruction", component->name, component->id);
+      return MMAL_SUCCESS;
+   }
+   vcos_mutex_unlock(&private->lock);
+
+   return mmal_component_destroy_internal(component);
+}
+
+/** Destroy a component */
+MMAL_STATUS_T mmal_component_destroy(MMAL_COMPONENT_T *component)
+{
+   if(!component)
+      return MMAL_EINVAL;
+
+   LOG_TRACE("%s %d", component->name, component->id);
+
+   return mmal_component_release_internal(component);
+}
+
+/** Acquire a reference to a component */
+void mmal_component_acquire(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_CORE_PRIVATE_T *private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
+
+   LOG_TRACE("component %s(%d), refcount %i", component->name, component->id,
+             component->priv->refcount);
+
+   vcos_mutex_lock(&private->lock);
+   component->priv->refcount++;
+   vcos_mutex_unlock(&private->lock);
+}
+
+/** Release a reference to a component */
+MMAL_STATUS_T mmal_component_release(MMAL_COMPONENT_T *component)
+{
+   if(!component)
+      return MMAL_EINVAL;
+
+   LOG_TRACE("component %s(%d), refcount %i", component->name, component->id,
+             component->priv->refcount);
+
+   return mmal_component_release_internal(component);
+}
+
+/** Enable processing on a component */
+MMAL_STATUS_T mmal_component_enable(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_CORE_PRIVATE_T *private;
+   MMAL_STATUS_T status = MMAL_ENOSYS;
+   unsigned int i;
+
+   if(!component)
+      return MMAL_EINVAL;
+
+   private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
+
+   LOG_TRACE("%s %d", component->name, component->id);
+
+   vcos_mutex_lock(&private->lock);
+
+   /* Check we have anything to do */
+   if (component->is_enabled)
+   {
+      vcos_mutex_unlock(&private->lock);
+      return MMAL_SUCCESS;
+   }
+
+   if (component->priv->pf_enable)
+      status = component->priv->pf_enable(component);
+
+   /* If the component does not support enable/disable, we handle that
+    * in the core itself */
+   if (status == MMAL_ENOSYS)
+   {
+      status = MMAL_SUCCESS;
+
+      /* Resume all input / output ports */
+      for (i = 0; status == MMAL_SUCCESS && i < component->input_num; i++)
+         status = mmal_port_pause(component->input[i], MMAL_FALSE);
+      for (i = 0; status == MMAL_SUCCESS && i < component->output_num; i++)
+         status = mmal_port_pause(component->output[i], MMAL_FALSE);
+   }
+
+   if (status == MMAL_SUCCESS)
+      component->is_enabled = 1;
+
+   vcos_mutex_unlock(&private->lock);
+
+   return status;
+}
+
+/** Disable processing on a component */
+MMAL_STATUS_T mmal_component_disable(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_CORE_PRIVATE_T *private;
+   MMAL_STATUS_T status = MMAL_ENOSYS;
+   unsigned int i;
+
+   if (!component)
+      return MMAL_EINVAL;
+
+   private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
+
+   LOG_TRACE("%s %d", component->name, component->id);
+
+   vcos_mutex_lock(&private->lock);
+
+   /* Check we have anything to do */
+   if (!component->is_enabled)
+   {
+      vcos_mutex_unlock(&private->lock);
+      return MMAL_SUCCESS;
+   }
+
+   if (component->priv->pf_disable)
+      status = component->priv->pf_disable(component);
+
+   /* If the component does not support enable/disable, we handle that
+    * in the core itself */
+   if (status == MMAL_ENOSYS)
+   {
+      status = MMAL_SUCCESS;
+
+      /* Pause all input / output ports */
+      for (i = 0; status == MMAL_SUCCESS && i < component->input_num; i++)
+         status = mmal_port_pause(component->input[i], MMAL_TRUE);
+      for (i = 0; status == MMAL_SUCCESS && i < component->output_num; i++)
+         status = mmal_port_pause(component->output[i], MMAL_TRUE);
+   }
+
+   if (status == MMAL_SUCCESS)
+      component->is_enabled = 0;
+
+   vcos_mutex_unlock(&private->lock);
+
+   return status;
+}
+
+static MMAL_STATUS_T mmal_component_enable_control_port(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
+{
+   (void)port;
+   (void)cb;
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T mmal_component_disable_control_port(MMAL_PORT_T *port)
+{
+   (void)port;
+   return MMAL_SUCCESS;
+}
+
+MMAL_STATUS_T mmal_component_parameter_set(MMAL_PORT_T *control_port,
+                                           const MMAL_PARAMETER_HEADER_T *param)
+{
+   (void)control_port;
+   (void)param;
+   /* No generic component control parameters */
+   LOG_ERROR("parameter id 0x%08x not supported", param->id);
+   return MMAL_ENOSYS;
+}
+
+MMAL_STATUS_T mmal_component_parameter_get(MMAL_PORT_T *control_port,
+                                           MMAL_PARAMETER_HEADER_T *param)
+{
+   (void)control_port;
+   (void)param;
+   /* No generic component control parameters */
+   LOG_ERROR("parameter id 0x%08x not supported", param->id);
+   return MMAL_ENOSYS;
+}
+
+static void mmal_component_init_control_port(MMAL_PORT_T *port)
+{
+   port->format->type = MMAL_ES_TYPE_CONTROL;
+   port->buffer_num_min = MMAL_CONTROL_PORT_BUFFERS_MIN;
+   port->buffer_num = port->buffer_num_min;
+   port->buffer_size_min = sizeof(MMAL_ES_FORMAT_T) + sizeof(MMAL_ES_SPECIFIC_FORMAT_T);
+   port->buffer_size = port->buffer_size_min;
+
+   /* Default to generic handling */
+   port->priv->pf_enable = mmal_component_enable_control_port;
+   port->priv->pf_disable = mmal_component_disable_control_port;
+   port->priv->pf_parameter_set = mmal_component_parameter_set;
+   port->priv->pf_parameter_get = mmal_component_parameter_get;
+   /* No pf_set_format - format of control port cannot be changed */
+   /* No pf_send - buffers cannot be sent to control port */
+}
+
+/** Acquire a reference on a port */
+void mmal_port_acquire(MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_CORE_PRIVATE_T *private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
+
+   LOG_TRACE("port %s(%p), refcount %i", port->name, port,
+             component->priv->refcount_ports);
+
+   vcos_mutex_lock(&private->lock);
+   component->priv->refcount_ports++;
+   vcos_mutex_unlock(&private->lock);
+}
+
+/** Release a reference on a port */
+MMAL_STATUS_T mmal_port_release(MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_CORE_PRIVATE_T *private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
+
+   LOG_TRACE("port %s(%p), refcount %i", port->name, port,
+             component->priv->refcount_ports);
+
+   /* Sanity check the refcount */
+   if (!vcos_verify(component->priv->refcount_ports > 0))
+      return MMAL_EINVAL;
+
+   vcos_mutex_lock(&private->lock);
+   if (--component->priv->refcount_ports ||
+       component->priv->refcount || private->destruction_pending)
+   {
+      vcos_mutex_unlock(&private->lock);
+      return MMAL_SUCCESS;
+   }
+   vcos_mutex_unlock(&private->lock);
+
+   return mmal_component_destroy_internal(component);
+}
+
+/*****************************************************************************
+ * Actions support
+ *****************************************************************************/
+
+/** Registers an action with the core */
+static void *mmal_component_action_thread_func(void *arg)
+{
+   MMAL_COMPONENT_T *component = (MMAL_COMPONENT_T *)arg;
+   MMAL_COMPONENT_CORE_PRIVATE_T *private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
+   VCOS_STATUS_T status;
+
+   while (1)
+   {
+      status = vcos_event_wait(&private->action_event);
+
+      if (status == VCOS_EAGAIN)
+         continue;
+      if (private->action_quit)
+         break;
+      if (!vcos_verify(status == VCOS_SUCCESS))
+         break;
+
+      vcos_mutex_lock(&private->action_mutex);
+      private->pf_action(component);
+      vcos_mutex_unlock(&private->action_mutex);
+   }
+   return 0;
+}
+
+/** Registers an action with the core */
+MMAL_STATUS_T mmal_component_action_register(MMAL_COMPONENT_T *component,
+                                             void (*pf_action)(MMAL_COMPONENT_T *) )
+{
+   MMAL_COMPONENT_CORE_PRIVATE_T *private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
+   VCOS_THREAD_ATTR_T attrs;
+   VCOS_STATUS_T status;
+
+   if (private->pf_action)
+      return MMAL_EINVAL;
+
+   status = vcos_event_create(&private->action_event, component->name);
+   if (status != VCOS_SUCCESS)
+      return MMAL_ENOMEM;
+
+   status = vcos_mutex_create(&private->action_mutex, component->name);
+   if (status != VCOS_SUCCESS)
+   {
+      vcos_event_delete(&private->action_event);
+      return MMAL_ENOMEM;
+   }
+
+   vcos_thread_attr_init(&attrs);
+   vcos_thread_attr_setpriority(&attrs,
+                                private->private.priority);
+   status = vcos_thread_create(&private->action_thread, component->name, &attrs,
+                               mmal_component_action_thread_func, component);
+   if (status != VCOS_SUCCESS)
+   {
+      vcos_mutex_delete(&private->action_mutex);
+      vcos_event_delete(&private->action_event);
+      return MMAL_ENOMEM;
+   }
+
+   private->pf_action = pf_action;
+   return MMAL_SUCCESS;
+}
+
+/** De-registers the current action with the core */
+MMAL_STATUS_T mmal_component_action_deregister(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_CORE_PRIVATE_T *private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
+
+   if (!private->pf_action)
+      return MMAL_EINVAL;
+
+   private->action_quit = 1;
+   vcos_event_signal(&private->action_event);
+   vcos_thread_join(&private->action_thread, NULL);
+   vcos_event_delete(&private->action_event);
+   vcos_mutex_delete(&private->action_mutex);
+   private->pf_action = NULL;
+   private->action_quit = 0;
+   return MMAL_SUCCESS;
+}
+
+/** Triggers a registered action */
+MMAL_STATUS_T mmal_component_action_trigger(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_CORE_PRIVATE_T *private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
+
+   if (!private->pf_action)
+      return MMAL_EINVAL;
+
+   vcos_event_signal(&private->action_event);
+   return MMAL_SUCCESS;
+}
+
+/** Lock an action to prevent it from running */
+MMAL_STATUS_T mmal_component_action_lock(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_CORE_PRIVATE_T *private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
+
+   if (!private->pf_action)
+      return MMAL_EINVAL;
+
+   vcos_mutex_lock(&private->action_mutex);
+   return MMAL_SUCCESS;
+}
+
+/** Unlock an action to allow it to run again */
+MMAL_STATUS_T mmal_component_action_unlock(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_CORE_PRIVATE_T *private = (MMAL_COMPONENT_CORE_PRIVATE_T *)component->priv;
+
+   if (!private->pf_action)
+      return MMAL_EINVAL;
+
+   vcos_mutex_unlock(&private->action_mutex);
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************
+ * Initialisation / Deinitialisation of the MMAL core
+ *****************************************************************************/
+static void mmal_core_init_once(void)
+{
+   vcos_mutex_create(&mmal_core_lock, VCOS_FUNCTION);
+}
+
+static void mmal_core_init(void)
+{
+   static VCOS_ONCE_T once = VCOS_ONCE_INIT;
+   vcos_init();
+   vcos_once(&once, mmal_core_init_once);
+
+   vcos_mutex_lock(&mmal_core_lock);
+   if (mmal_core_refcount++)
+   {
+      vcos_mutex_unlock(&mmal_core_lock);
+      return;
+   }
+
+   mmal_logging_init();
+   vcos_mutex_unlock(&mmal_core_lock);
+}
+
+static void mmal_core_deinit(void)
+{
+   vcos_mutex_lock(&mmal_core_lock);
+   if (!mmal_core_refcount || --mmal_core_refcount)
+   {
+      vcos_mutex_unlock(&mmal_core_lock);
+      return;
+   }
+
+   mmal_logging_deinit();
+   vcos_mutex_unlock(&mmal_core_lock);
+   vcos_deinit();
+}
+
+/*****************************************************************************
+ * Supplier support
+ *****************************************************************************/
+
+/** a component supplier gets passed a string and returns a
+  * component (if it can) based on that string.
+  */
+
+#define SUPPLIER_PREFIX_LEN 32
+typedef struct MMAL_COMPONENT_SUPPLIER_T
+{
+   struct MMAL_COMPONENT_SUPPLIER_T *next;
+   MMAL_COMPONENT_SUPPLIER_FUNCTION_T create;
+   char prefix[SUPPLIER_PREFIX_LEN];
+} MMAL_COMPONENT_SUPPLIER_T;
+
+/** List of component suppliers.
+  *
+  * Does not need to be thread-safe if we assume that suppliers
+  * can never be removed.
+  */
+static MMAL_COMPONENT_SUPPLIER_T *suppliers;
+
+/** Create an instance of a component  */
+static MMAL_STATUS_T mmal_component_supplier_create(const char *name, MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_SUPPLIER_T *supplier = suppliers;
+   MMAL_STATUS_T status = MMAL_ENOSYS;
+   const char *dot = strchr(name, '.');
+   size_t dot_size = dot ? dot - name : (int)strlen(name);
+
+   /* walk list of suppliers to see if any can create this component */
+   while (supplier)
+   {
+      if (strlen(supplier->prefix) == dot_size && !memcmp(supplier->prefix, name, dot_size))
+      {
+         status = supplier->create(name, component);
+         if (status == MMAL_SUCCESS)
+            break;
+      }
+      supplier = supplier->next;
+   }
+   return status;
+}
+
+void mmal_component_supplier_register(const char *prefix,
+   MMAL_COMPONENT_SUPPLIER_FUNCTION_T create_fn)
+{
+   MMAL_COMPONENT_SUPPLIER_T *supplier = vcos_calloc(1,sizeof(*supplier),NULL);
+
+   LOG_TRACE("prefix %s fn %p", (prefix ? prefix : "NULL"), create_fn);
+
+   if (vcos_verify(supplier))
+   {
+      supplier->create = create_fn;
+      strncpy(supplier->prefix, prefix, SUPPLIER_PREFIX_LEN);
+      supplier->prefix[SUPPLIER_PREFIX_LEN-1] = '\0';
+
+      supplier->next = suppliers;
+      suppliers = supplier;
+   }
+   else
+   {
+      LOG_ERROR("no memory for supplier registry entry");
+   }
+}
+
+MMAL_DESTRUCTOR(mmal_component_supplier_destructor);
+void mmal_component_supplier_destructor(void)
+{
+   MMAL_COMPONENT_SUPPLIER_T *supplier = suppliers;
+
+   /* walk list of suppliers and free associated memory */
+   while (supplier)
+   {
+      MMAL_COMPONENT_SUPPLIER_T *current = supplier;
+      supplier = supplier->next;
+      vcos_free(current);
+   }
+}
diff --git a/interface/mmal/core/mmal_component_private.h b/interface/mmal/core/mmal_component_private.h
new file mode 100755 (executable)
index 0000000..26c7a7e
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_COMPONENT_PRIVATE_H
+#define MMAL_COMPONENT_PRIVATE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MMAL_VIDEO_DECODE  "video_decode"
+#define MMAL_VIDEO_ENCODE  "video_encode"
+#define MMAL_VIDEO_RENDER  "video_render"
+#define MMAL_AUDIO_DECODE  "audio_decode"
+#define MMAL_AUDIO_ENCODE  "audio_encode"
+#define MMAL_AUDIO_RENDER  "audio_render"
+#define MMAL_CAMERA        "camera"
+
+#if defined(__GNUC__) && (__GNUC__ > 2)
+# define MMAL_CONSTRUCTOR(func) void __attribute__((constructor,used)) func(void)
+# define MMAL_DESTRUCTOR(func) void __attribute__((destructor,used)) func(void)
+#else
+# define MMAL_CONSTRUCTOR(func) void func(void)
+# define MMAL_DESTRUCTOR(func) void func(void)
+#endif
+
+#include "mmal.h"
+#include "mmal_component.h"
+
+/** Definition of a component. */
+struct MMAL_COMPONENT_PRIVATE_T
+{
+   /** Pointer to the private data of the component module in use */
+   struct MMAL_COMPONENT_MODULE_T *module;
+
+   MMAL_STATUS_T (*pf_enable)(MMAL_COMPONENT_T *component);
+   MMAL_STATUS_T (*pf_disable)(MMAL_COMPONENT_T *component);
+   MMAL_STATUS_T (*pf_destroy)(MMAL_COMPONENT_T *component);
+
+   /** Pool of event buffer headers, for sending events from component to client. */
+   MMAL_POOL_T *event_pool;
+
+   /** Reference counting of the component */
+   int refcount;
+   /** Reference counting of the ports. Component won't be destroyed until this
+    * goes to 0 */
+   int refcount_ports;
+
+   /** Priority associated with the 'action thread' for this component, when
+    * such action thread is applicable. */
+   int priority;
+};
+
+/** Set a generic component control parameter.
+  *
+  * @param control_port control port of component on which to set the parameter.
+  * @param param        parameter to be set.
+  * @return MMAL_SUCCESS or another status on error.
+  */
+MMAL_STATUS_T mmal_component_parameter_set(MMAL_PORT_T *control_port,
+                                           const MMAL_PARAMETER_HEADER_T *param);
+
+/** Get a generic component control parameter.
+  *
+  * @param contorl_port control port of component from which to get the parameter.
+  * @param param        parameter to be retrieved.
+  * @return MMAL_SUCCESS or another status on error.
+  */
+MMAL_STATUS_T mmal_component_parameter_get(MMAL_PORT_T *control_port,
+                                           MMAL_PARAMETER_HEADER_T *param);
+
+/** Registers an action with the core.
+  * The MMAL core allows components to register an action which will be run
+  * from a separate thread context when the action is explicitly triggered by
+  * the component.
+  *
+  * @param component    component registering the action.
+  * @param action       action to register.
+  * @return MMAL_SUCCESS or another status on error.
+  */
+MMAL_STATUS_T mmal_component_action_register(MMAL_COMPONENT_T *component,
+                                             void (*pf_action)(MMAL_COMPONENT_T *));
+
+/** De-registers the current action registered with the core.
+  *
+  * @param component    component de-registering the action.
+  * @return MMAL_SUCCESS or another status on error.
+  */
+MMAL_STATUS_T mmal_component_action_deregister(MMAL_COMPONENT_T *component);
+
+/** Triggers a registered action.
+  * Explicitly triggers an action registered by a component.
+  *
+  * @param component    component on which to trigger the action.
+  * @return MMAL_SUCCESS or another status on error.
+  */
+MMAL_STATUS_T mmal_component_action_trigger(MMAL_COMPONENT_T *component);
+
+/** Lock an action to prevent it from running.
+  * Allows a component to make sure no action is running while the lock is taken.
+  *
+  * @param component    component.
+  * @return MMAL_SUCCESS or another status on error.
+  */
+MMAL_STATUS_T mmal_component_action_lock(MMAL_COMPONENT_T *component);
+
+/** Unlock an action to allow it to run again.
+  *
+  * @param component    component.
+  * @return MMAL_SUCCESS or another status on error.
+  */
+MMAL_STATUS_T mmal_component_action_unlock(MMAL_COMPONENT_T *component);
+
+/** Prototype used by components to register themselves to the supplier. */
+typedef MMAL_STATUS_T (*MMAL_COMPONENT_SUPPLIER_FUNCTION_T)(const char *name,
+                                                            MMAL_COMPONENT_T *component);
+
+/** Create an instance of a component given a constructor for the component.
+ * This allows the creation of client-side components which haven't been registered with the core.
+ * See \ref mmal_component_create for the public interface used to create components.
+ *
+ * @param name name assigned to the component by the client
+ * @param constructor constructor function for the component
+ * @param constructor_private private data for the constructor
+ * @param component returned component
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_component_create_with_constructor(const char *name,
+   MMAL_STATUS_T (*constructor)(const char *name, MMAL_COMPONENT_T *),
+   struct MMAL_COMPONENT_MODULE_T *constructor_private,
+   MMAL_COMPONENT_T **component);
+
+/** Register a component with the mmal component supplier.
+  *
+  * @param prefix     prefix for this supplier, e.g. "VC"
+  * @param create_fn  function which will instantiate a component given a name.
+  */
+void mmal_component_supplier_register(const char *prefix,
+                                      MMAL_COMPONENT_SUPPLIER_FUNCTION_T create_fn);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MMAL_COMPONENT_PRIVATE_H */
diff --git a/interface/mmal/core/mmal_core_private.h b/interface/mmal/core/mmal_core_private.h
new file mode 100755 (executable)
index 0000000..8dc6cba
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_CORE_PRIVATE_H
+#define MMAL_CORE_PRIVATE_H
+
+/** Initialise the logging system.
+  */
+void mmal_logging_init(void);
+
+/** Deinitialise the logging system.
+  */
+void mmal_logging_deinit(void);
+
+#endif /* MMAL_CORE_PRIVATE_H */
+
diff --git a/interface/mmal/core/mmal_events.c b/interface/mmal/core/mmal_events.c
new file mode 100755 (executable)
index 0000000..80607f7
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "mmal_port_private.h"
+#include "mmal_buffer.h"
+#include "mmal_logging.h"
+
+MMAL_EVENT_FORMAT_CHANGED_T *mmal_event_format_changed_get(MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_EVENT_FORMAT_CHANGED_T *event;
+   MMAL_ES_FORMAT_T *format;
+   uint32_t size;
+
+   size = sizeof(MMAL_EVENT_FORMAT_CHANGED_T);
+   size += sizeof(MMAL_ES_FORMAT_T) + sizeof(MMAL_ES_SPECIFIC_FORMAT_T);
+
+   if (!buffer || buffer->cmd != MMAL_EVENT_FORMAT_CHANGED || buffer->length < size)
+      return 0;
+
+   event = (MMAL_EVENT_FORMAT_CHANGED_T *)buffer->data;
+   format = event->format = (MMAL_ES_FORMAT_T *)&event[1];
+   format->es = (MMAL_ES_SPECIFIC_FORMAT_T *)&format[1];
+   format->extradata = (uint8_t *)&format->es[1];
+   format->extradata_size = buffer->length - size;
+   return event;
+}
+
+MMAL_STATUS_T mmal_event_error_send(MMAL_COMPONENT_T *component, MMAL_STATUS_T error_status)
+{
+   MMAL_BUFFER_HEADER_T* event;
+   MMAL_STATUS_T status;
+
+   if(!component)
+   {
+      LOG_ERROR("invalid component");
+      return MMAL_EINVAL;
+   }
+
+   status = mmal_port_event_get(component->control, &event, MMAL_EVENT_ERROR);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("event not available for component %s %p, result %d", component->name, component, status);
+      return status;
+   }
+
+   event->length = sizeof(MMAL_STATUS_T);
+   *(MMAL_STATUS_T *)event->data = error_status;
+   mmal_port_event_send(component->control, event);
+
+   return MMAL_SUCCESS;
+}
+
+MMAL_STATUS_T mmal_event_eos_send(MMAL_PORT_T *port)
+{
+   MMAL_EVENT_END_OF_STREAM_T *event;
+   MMAL_BUFFER_HEADER_T *buffer;
+   MMAL_STATUS_T status;
+
+   if(!port)
+   {
+      LOG_ERROR("invalid port");
+      return MMAL_EINVAL;
+   }
+
+   status = mmal_port_event_get(port->component->control, &buffer, MMAL_EVENT_EOS);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("event not available for port %s %p, result %d", port->name, port, status);
+      return status;
+   }
+
+   buffer->length = sizeof(*event);
+   event = (MMAL_EVENT_END_OF_STREAM_T *)buffer->data;
+   event->port_type = port->type;
+   event->port_index = port->index;
+   mmal_port_event_send(port->component->control, buffer);
+
+   return MMAL_SUCCESS;
+}
+
+MMAL_STATUS_T mmal_event_forward(MMAL_BUFFER_HEADER_T *event, MMAL_PORT_T *port)
+{
+   MMAL_BUFFER_HEADER_T *buffer;
+   MMAL_STATUS_T status;
+
+   if(!port || port->type != MMAL_PORT_TYPE_OUTPUT)
+   {
+      LOG_ERROR("invalid port");
+      return MMAL_EINVAL;
+   }
+
+   status = mmal_port_event_get(port->component->control, &buffer, event->cmd);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("event not available for port %s %p, result %d", port->name, port, status);
+      return status;
+   }
+
+   if (buffer->alloc_size < event->length)
+   {
+      LOG_ERROR("event buffer too small (%i/%i)", buffer->alloc_size, event->length);
+      mmal_buffer_header_release(buffer);
+      return MMAL_ENOSPC;
+   }
+
+   memcpy(buffer->data, event->data, event->length);
+   buffer->length = event->length;
+   buffer->offset = event->offset;
+   buffer->flags = event->flags;
+   buffer->pts = event->pts;
+   mmal_port_event_send(port->component->control, buffer);
+   return MMAL_SUCCESS;
+}
diff --git a/interface/mmal/core/mmal_events_private.h b/interface/mmal/core/mmal_events_private.h
new file mode 100755 (executable)
index 0000000..00d7307
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_EVENTS_PRIVATE_H
+#define MMAL_EVENTS_PRIVATE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mmal_events.h"
+
+/** Send an error event through the component's control port.
+ * The error event data will be the MMAL_STATUS_T passed in.
+ *
+ * @param component component to receive the error event.
+ * @param status the error status to be sent.
+ * @return MMAL_SUCCESS or an error if the event could not be sent.
+ */
+MMAL_STATUS_T mmal_event_error_send(MMAL_COMPONENT_T *component, MMAL_STATUS_T status);
+
+/** Send an eos event through a specific port.
+ *
+ * @param port port to receive the error event.
+ * @return MMAL_SUCCESS or an error if the event could not be sent.
+ */
+MMAL_STATUS_T mmal_event_eos_send(MMAL_PORT_T *port);
+
+/** Forward an event onto an output port.
+ * This will allocate a new event buffer on the output port, make a copy
+ * of the event buffer which will then be forwarded.
+ *
+ * @event event to forward.
+ * @param port port to forward event to.
+ * @return MMAL_SUCCESS or an error if the event could not be forwarded.
+ */
+MMAL_STATUS_T mmal_event_forward(MMAL_BUFFER_HEADER_T *event, MMAL_PORT_T *port);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MMAL_EVENTS_PRIVATE_H */
diff --git a/interface/mmal/core/mmal_format.c b/interface/mmal/core/mmal_format.c
new file mode 100755 (executable)
index 0000000..7b8e25e
--- /dev/null
@@ -0,0 +1,183 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal_types.h"
+#include "mmal_format.h"
+#include "util/mmal_util_rational.h"
+
+#define MMAL_ES_FORMAT_MAGIC MMAL_FOURCC('m','a','g','f')
+#define EXTRADATA_SIZE_DEFAULT 32
+#define EXTRADATA_SIZE_MAX (10*1024)
+
+typedef struct MMAL_ES_FORMAT_PRIVATE_T
+{
+   MMAL_ES_FORMAT_T format;
+   MMAL_ES_SPECIFIC_FORMAT_T es;
+
+   uint32_t magic;
+
+   unsigned int extradata_size;
+   uint8_t *extradata;
+
+   uint8_t buffer[EXTRADATA_SIZE_DEFAULT];
+
+} MMAL_ES_FORMAT_PRIVATE_T;
+
+/** Allocate a format structure */
+MMAL_ES_FORMAT_T *mmal_format_alloc(void)
+{
+   MMAL_ES_FORMAT_PRIVATE_T *private;
+
+   private = vcos_malloc(sizeof(*private), "mmal format");
+   if(!private) return 0;
+   memset(private, 0, sizeof(*private));
+
+   private->magic = MMAL_ES_FORMAT_MAGIC;
+   private->format.es = (void *)&private->es;
+   private->extradata_size = EXTRADATA_SIZE_DEFAULT;
+
+   return &private->format;
+}
+
+/** Free a format structure */
+void mmal_format_free(MMAL_ES_FORMAT_T *format)
+{
+   MMAL_ES_FORMAT_PRIVATE_T *private = (MMAL_ES_FORMAT_PRIVATE_T *)format;
+   vcos_assert(private->magic == MMAL_ES_FORMAT_MAGIC);
+   if(private->extradata) vcos_free(private->extradata);
+   vcos_free(private);
+}
+
+/** Copy a format structure */
+void mmal_format_copy(MMAL_ES_FORMAT_T *fmt_dst, MMAL_ES_FORMAT_T *fmt_src)
+{
+   void *backup = fmt_dst->es;
+   *fmt_dst->es = *fmt_src->es;
+   *fmt_dst = *fmt_src;
+   fmt_dst->es = backup;
+   fmt_dst->extradata = 0;
+   fmt_dst->extradata_size = 0;
+}
+
+/** Full copy of a format structure (including extradata) */
+MMAL_STATUS_T mmal_format_full_copy(MMAL_ES_FORMAT_T *fmt_dst, MMAL_ES_FORMAT_T *fmt_src)
+{
+   mmal_format_copy(fmt_dst, fmt_src);
+
+   if (fmt_src->extradata_size)
+   {
+      MMAL_STATUS_T status = mmal_format_extradata_alloc(fmt_dst, fmt_src->extradata_size);
+      if (status != MMAL_SUCCESS)
+         return status;
+      fmt_dst->extradata_size = fmt_src->extradata_size;
+      memcpy(fmt_dst->extradata, fmt_src->extradata, fmt_src->extradata_size);
+   }
+   return MMAL_SUCCESS;
+}
+
+/** Compare 2 format structures */
+uint32_t mmal_format_compare(MMAL_ES_FORMAT_T *fmt1, MMAL_ES_FORMAT_T *fmt2)
+{
+   MMAL_VIDEO_FORMAT_T *video1, *video2;
+   uint32_t result = 0;
+
+   if (fmt1->type != fmt2->type)
+      return MMAL_ES_FORMAT_COMPARE_FLAG_TYPE;
+
+   if (fmt1->encoding != fmt2->encoding)
+      result |= MMAL_ES_FORMAT_COMPARE_FLAG_ENCODING;
+   if (fmt1->bitrate != fmt2->bitrate)
+      result |= MMAL_ES_FORMAT_COMPARE_FLAG_BITRATE;
+   if (fmt1->flags != fmt2->flags)
+      result |= MMAL_ES_FORMAT_COMPARE_FLAG_FLAGS;
+   if (fmt1->extradata_size != fmt2->extradata_size ||
+       (fmt1->extradata_size && (!fmt1->extradata || !fmt2->extradata)) ||
+       memcmp(fmt1->extradata, fmt2->extradata, fmt1->extradata_size))
+      result |= MMAL_ES_FORMAT_COMPARE_FLAG_EXTRADATA;
+
+   /* Compare the ES specific information */
+   switch (fmt1->type)
+   {
+   case MMAL_ES_TYPE_VIDEO:
+      video1 = &fmt1->es->video;
+      video2 = &fmt2->es->video;
+      if (video1->width != video2->width || video1->height != video2->height)
+         result |= MMAL_ES_FORMAT_COMPARE_FLAG_VIDEO_RESOLUTION;
+      if (memcmp(&video1->crop, &video2->crop, sizeof(video1->crop)))
+         result |= MMAL_ES_FORMAT_COMPARE_FLAG_VIDEO_CROPPING;
+      if (!mmal_rational_equal(video1->par, video2->par))
+         result |= MMAL_ES_FORMAT_COMPARE_FLAG_VIDEO_ASPECT_RATIO;
+      if (!mmal_rational_equal(video1->frame_rate, video2->frame_rate))
+         result |= MMAL_ES_FORMAT_COMPARE_FLAG_VIDEO_FRAME_RATE;
+      if (video1->color_space != video2->color_space)
+         result |= MMAL_ES_FORMAT_COMPARE_FLAG_VIDEO_COLOR_SPACE;
+      /* coverity[overrun-buffer-arg] We're comparing the rest of the video format structure */
+      if (memcmp(((char*)&video1->color_space) + sizeof(video1->color_space),
+                 ((char*)&video2->color_space) + sizeof(video2->color_space),
+                 sizeof(*video1) - offsetof(MMAL_VIDEO_FORMAT_T, color_space) - sizeof(video1->color_space)))
+         result |= MMAL_ES_FORMAT_COMPARE_FLAG_ES_OTHER;
+      break;
+   case MMAL_ES_TYPE_AUDIO:
+      if (memcmp(fmt1->es, fmt2->es, sizeof(MMAL_AUDIO_FORMAT_T)))
+         result |= MMAL_ES_FORMAT_COMPARE_FLAG_ES_OTHER;
+      break;
+   case MMAL_ES_TYPE_SUBPICTURE:
+      if (memcmp(fmt1->es, fmt2->es, sizeof(MMAL_SUBPICTURE_FORMAT_T)))
+         result |= MMAL_ES_FORMAT_COMPARE_FLAG_ES_OTHER;
+      break;
+   default:
+      break;
+   }
+
+   return result;
+}
+
+/** */
+MMAL_STATUS_T mmal_format_extradata_alloc(MMAL_ES_FORMAT_T *format, unsigned int size)
+{
+   MMAL_ES_FORMAT_PRIVATE_T *private = (MMAL_ES_FORMAT_PRIVATE_T *)format;
+
+   /* Sanity check the size requested */
+   if(size > EXTRADATA_SIZE_MAX)
+      return MMAL_EINVAL;
+
+   /* Allocate memory if needed */
+   if(private->extradata_size < size)
+   {
+      if(private->extradata) vcos_free(private->extradata);
+      private->extradata = vcos_malloc(size, "mmal format extradata");
+      if(!private->extradata)
+         return MMAL_ENOMEM;
+      private->extradata_size = size;
+   }
+
+   /* Set the fields in the actual format structure */
+   if(private->extradata) private->format.extradata = private->extradata;
+   else private->format.extradata = private->buffer;
+
+   return MMAL_SUCCESS;
+}
diff --git a/interface/mmal/core/mmal_logging.c b/interface/mmal/core/mmal_logging.c
new file mode 100755 (executable)
index 0000000..e05bc92
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "mmal_logging.h"
+#include "core/mmal_core_private.h"
+
+VCOS_LOG_CAT_T mmal_log_category;
+static VCOS_LOG_LEVEL_T mmal_log_level = VCOS_LOG_ERROR;
+
+void mmal_logging_init(void)
+{
+   vcos_log_set_level(VCOS_LOG_CATEGORY, mmal_log_level);
+   vcos_log_register("mmal", VCOS_LOG_CATEGORY);
+}
+
+void mmal_logging_deinit(void)
+{
+   mmal_log_level = mmal_log_category.level;
+   vcos_log_unregister(VCOS_LOG_CATEGORY);
+}
diff --git a/interface/mmal/core/mmal_pool.c b/interface/mmal/core/mmal_pool.c
new file mode 100755 (executable)
index 0000000..1eac85f
--- /dev/null
@@ -0,0 +1,303 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "mmal_pool.h"
+#include "core/mmal_buffer_private.h"
+#include "mmal_logging.h"
+
+/** Definition of a pool */
+typedef struct MMAL_POOL_PRIVATE_T
+{
+   MMAL_POOL_T pool; /**< Actual pool */
+
+   MMAL_POOL_BH_CB_T cb; /**< Buffer header release callback */
+   void *userdata;       /**< User provided data to pass with callback */
+
+   mmal_pool_allocator_alloc_t allocator_alloc; /**< Allocator for the payload buffers */
+   mmal_pool_allocator_free_t allocator_free;   /**< Allocator for the payload buffers */
+   void *allocator_context;                     /**< Context for the allocator */
+
+   unsigned int header_size; /**< Size of an initialised buffer header structure */
+   unsigned int payload_size;
+
+   unsigned int headers_alloc_num; /**< Number of buffer headers allocated as part of the private structure */
+
+} MMAL_POOL_PRIVATE_T;
+
+#define ROUND_UP(s,align) ((((unsigned long)(s)) & ~((align)-1)) + (align))
+#define ALIGN  8
+
+static void mmal_pool_buffer_header_release(MMAL_BUFFER_HEADER_T *header);
+
+static void *mmal_pool_allocator_default_alloc(void *context, uint32_t size)
+{
+   MMAL_PARAM_UNUSED(context);
+   return vcos_malloc(size, "mmal_pool payload");
+}
+
+static void mmal_pool_allocator_default_free(void *context, void *mem)
+{
+   MMAL_PARAM_UNUSED(context);
+   vcos_free(mem);
+}
+
+static MMAL_STATUS_T mmal_pool_initialise_buffer_headers(MMAL_POOL_T *pool, unsigned int headers,
+                                                         MMAL_BOOL_T reinitialise)
+{
+   MMAL_POOL_PRIVATE_T *private = (MMAL_POOL_PRIVATE_T *)pool;
+   MMAL_BUFFER_HEADER_T *header;
+   uint8_t *payload = NULL;
+   unsigned int i;
+
+   header = (MMAL_BUFFER_HEADER_T *)((uint8_t *)pool->header + ROUND_UP(sizeof(void *)*headers,ALIGN));
+
+   for (i = 0; i < headers; i++)
+   {
+      if (reinitialise)
+         header = mmal_buffer_header_initialise(header, private->header_size);
+
+      if (private->payload_size && private->allocator_alloc)
+      {
+         LOG_TRACE("allocating %u bytes for payload %u/%u", private->payload_size, i, headers);
+         payload = (uint8_t*)private->allocator_alloc(private->allocator_context, private->payload_size);
+         if (! payload)
+         {
+            LOG_ERROR("failed to allocate payload %u/%u", i, headers);
+            return MMAL_ENOMEM;
+         }
+      }
+      else
+      {
+         if (header->priv->pf_payload_free && header->priv->payload && header->priv->payload_size)
+         {
+            LOG_TRACE("freeing %u bytes for payload %u/%u", header->priv->payload_size, i, headers);
+            header->priv->pf_payload_free(header->priv->payload_context, header->priv->payload);
+         }
+      }
+      header->data = payload;
+      header->alloc_size = private->payload_size;
+      header->priv->pf_release = mmal_pool_buffer_header_release;
+      header->priv->owner = (void *)pool;
+      header->priv->refcount = 1;
+      header->priv->payload = payload;
+      header->priv->payload_context = private->allocator_context;
+      header->priv->pf_payload_free = private->allocator_free;
+      header->priv->payload_size = private->payload_size;
+      pool->header[i] = header;
+      pool->headers_num = i+1;
+      header = (MMAL_BUFFER_HEADER_T *)((uint8_t*)header + private->header_size);
+   }
+
+   return MMAL_SUCCESS;
+}
+
+/** Create a pool of MMAL_BUFFER_HEADER_T */
+MMAL_POOL_T *mmal_pool_create(unsigned int headers, uint32_t payload_size)
+{
+   return mmal_pool_create_with_allocator(headers, payload_size, NULL,
+             mmal_pool_allocator_default_alloc, mmal_pool_allocator_default_free);
+}
+
+/** Create a pool of MMAL_BUFFER_HEADER_T */
+MMAL_POOL_T *mmal_pool_create_with_allocator(unsigned int headers, uint32_t payload_size,
+                              void *allocator_context, mmal_pool_allocator_alloc_t allocator_alloc,
+                              mmal_pool_allocator_free_t allocator_free)
+{
+   unsigned int i, headers_array_size, header_size, pool_size;
+   MMAL_POOL_PRIVATE_T *private;
+   MMAL_BUFFER_HEADER_T **array;
+   MMAL_POOL_T *pool;
+   MMAL_QUEUE_T *queue;
+
+   queue = mmal_queue_create();
+   if (!queue)
+   {
+      LOG_ERROR("failed to create queue");
+      return NULL;
+   }
+
+   /* Calculate how much memory we need */
+   pool_size = ROUND_UP(sizeof(MMAL_POOL_PRIVATE_T),ALIGN);
+   headers_array_size = ROUND_UP(sizeof(void *)*headers,ALIGN);
+   header_size = ROUND_UP(mmal_buffer_header_size(0),ALIGN);
+
+   LOG_TRACE("allocating %u + %u + %u * %u bytes for pool",
+             pool_size, headers_array_size, header_size, headers);
+   private = vcos_calloc(pool_size, 1, "MMAL pool");
+   array = vcos_calloc(headers_array_size + header_size * headers, 1, "MMAL buffer headers");
+   if (!private || !array)
+   {
+      LOG_ERROR("failed to allocate pool");
+      if (private) vcos_free(private);
+      if (array) vcos_free(array);
+      mmal_queue_destroy(queue);
+      return NULL;
+   }
+   pool = &private->pool;
+   pool->queue = queue;
+   pool->header = (MMAL_BUFFER_HEADER_T **)array;
+   private->header_size = header_size;
+   private->payload_size = payload_size;
+   private->headers_alloc_num = headers;
+
+   /* Use default allocators if none has been specified by client */
+   if (!allocator_alloc || !allocator_free)
+   {
+      allocator_alloc = mmal_pool_allocator_default_alloc;
+      allocator_free = mmal_pool_allocator_default_free;
+      allocator_context = NULL;
+   }
+
+   /* Keep reference to the allocator to allow resizing the payloads at a later point */
+   private->allocator_alloc = allocator_alloc;
+   private->allocator_free = allocator_free;
+   private->allocator_context = allocator_context;
+
+   if (mmal_pool_initialise_buffer_headers(pool, headers, 1) != MMAL_SUCCESS)
+   {
+      mmal_pool_destroy(pool);
+      return NULL;
+   }
+
+   /* Add all the headers to the queue */
+   for (i = 0; i < pool->headers_num; i++)
+      mmal_queue_put(queue, pool->header[i]);
+
+   return pool;
+}
+
+/** Destroy a pool of MMAL_BUFFER_HEADER_T */
+void mmal_pool_destroy(MMAL_POOL_T *pool)
+{
+   unsigned int i;
+
+   if (!pool)
+      return;
+
+   /* If the payload_size is non-zero then the buffer header payload
+    * must be freed. Otherwise it is the caller's responsibility. */
+   for (i = 0; i < pool->headers_num; ++i)
+   {
+      MMAL_BUFFER_HEADER_PRIVATE_T* priv = pool->header[i]->priv;
+
+      if (priv->pf_payload_free && priv->payload && priv->payload_size)
+         priv->pf_payload_free(priv->payload_context, priv->payload);
+   }
+
+   if (pool->header)
+      vcos_free(pool->header);
+
+   if(pool->queue) mmal_queue_destroy(pool->queue);
+   vcos_free(pool);
+}
+
+/** Resize a pool of MMAL_BUFFER_HEADER_T */
+MMAL_STATUS_T mmal_pool_resize(MMAL_POOL_T *pool, unsigned int headers, uint32_t payload_size)
+{
+   MMAL_POOL_PRIVATE_T *private = (MMAL_POOL_PRIVATE_T *)pool;
+   unsigned int i;
+
+   if (!private || !headers)
+      return MMAL_EINVAL;
+
+   /* Check if anything needs to be done */
+   if (headers == pool->headers_num && payload_size == private->payload_size)
+      return MMAL_SUCCESS;
+
+   /* Remove all the headers from the queue */
+   for (i = 0; i < pool->headers_num; i++)
+      mmal_queue_get(pool->queue);
+
+   /* Start by freeing the current payloads */
+   private->payload_size = 0;
+   mmal_pool_initialise_buffer_headers(pool, pool->headers_num, 0);
+   pool->headers_num = 0;
+
+   /* Check if we need to reallocate the buffer headers themselves */
+   if (headers > private->headers_alloc_num)
+   {
+      private->headers_alloc_num = 0;
+      if (pool->header)
+         vcos_free(pool->header);
+      pool->header =
+         vcos_calloc(private->header_size * headers + ROUND_UP(sizeof(void *)*headers,ALIGN),
+                     1, "MMAL buffer headers");
+      if (!pool->header)
+         return MMAL_ENOMEM;
+      private->headers_alloc_num = headers;
+   }
+
+   /* Allocate the new payloads */
+   private->payload_size = payload_size;
+   mmal_pool_initialise_buffer_headers(pool, headers, 1);
+
+   /* Add all the headers to the queue */
+   for (i = 0; i < pool->headers_num; i++)
+      mmal_queue_put(pool->queue, pool->header[i]);
+
+   return MMAL_SUCCESS;
+}
+
+/** Buffer header release callback.
+ * Call out to a further client callback and put the buffer back in the queue
+ * so it can be reused, unless the client callback prevents it. */
+static void mmal_pool_buffer_header_release(MMAL_BUFFER_HEADER_T *header)
+{
+   MMAL_POOL_T *pool = (MMAL_POOL_T *)header->priv->owner;
+   MMAL_POOL_PRIVATE_T *private = (MMAL_POOL_PRIVATE_T *)pool;
+   MMAL_BOOL_T queue_buffer = 1;
+
+   header->priv->refcount = 1;
+   if(private->cb)
+      queue_buffer = private->cb(pool, header, private->userdata);
+   if (queue_buffer)
+      mmal_queue_put(pool->queue, header);
+}
+
+/** Set a buffer header release callback to the pool */
+void mmal_pool_callback_set(MMAL_POOL_T *pool, MMAL_POOL_BH_CB_T cb, void *userdata)
+{
+   MMAL_POOL_PRIVATE_T *private = (MMAL_POOL_PRIVATE_T *)pool;
+   private->cb = cb;
+   private->userdata = userdata;
+}
+
+/* Set a pre-release callback for all buffer headers in the pool */
+void mmal_pool_pre_release_callback_set(MMAL_POOL_T *pool, MMAL_BH_PRE_RELEASE_CB_T cb, void *userdata)
+{
+   unsigned int i;
+   MMAL_POOL_PRIVATE_T *private = (MMAL_POOL_PRIVATE_T *)pool;
+   MMAL_BUFFER_HEADER_T *header =
+         (MMAL_BUFFER_HEADER_T*)((uint8_t*)pool->header + ROUND_UP(sizeof(void*)*pool->headers_num,ALIGN));
+
+   for (i = 0; i < pool->headers_num; ++i)
+   {
+      mmal_buffer_header_pre_release_cb_set(header, cb, userdata);
+      header = (MMAL_BUFFER_HEADER_T *)((uint8_t*)header + private->header_size);
+   }
+}
diff --git a/interface/mmal/core/mmal_port.c b/interface/mmal/core/mmal_port.c
new file mode 100755 (executable)
index 0000000..d7b00c1
--- /dev/null
@@ -0,0 +1,1508 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "util/mmal_util.h"
+#include "core/mmal_component_private.h"
+#include "core/mmal_port_private.h"
+#include "interface/vcos/vcos.h"
+#include "mmal_logging.h"
+#include "interface/mmal/util/mmal_util.h"
+#include "interface/mmal/mmal_parameters.h"
+#include <stdio.h>
+
+#ifdef _VIDEOCORE
+#include "vcfw/rtos/common/rtos_common_mem.h" /* mem_alloc */
+#endif
+
+/** Only collect port stats if enabled in build. Performance could be
+ * affected on an ARM since gettimeofday() involves a system call.
+ */
+#if defined(MMAL_COLLECT_PORT_STATS)
+# define MMAL_COLLECT_PORT_STATS_ENABLED 1
+#else
+# define MMAL_COLLECT_PORT_STATS_ENABLED 0
+#endif
+
+static MMAL_STATUS_T mmal_port_private_parameter_get(MMAL_PORT_T *port,
+                                                     MMAL_PARAMETER_HEADER_T *param);
+
+static MMAL_STATUS_T mmal_port_private_parameter_set(MMAL_PORT_T *port,
+                                                     const MMAL_PARAMETER_HEADER_T *param);
+
+/* Define this if you want to log all buffer transfers */
+//#define ENABLE_MMAL_EXTRA_LOGGING
+
+/** Definition of the core's private structure for a port. */
+typedef struct MMAL_PORT_PRIVATE_CORE_T
+{
+   VCOS_MUTEX_T lock; /**< Used to lock access to the port */
+   VCOS_MUTEX_T send_lock; /**< Used to lock access while sending buffer to the port */
+   VCOS_MUTEX_T stats_lock; /**< Used to lock access to the stats */
+   VCOS_MUTEX_T connection_lock; /**< Used to lock access to a connection */
+
+   /** Callback set by client to call when buffer headers need to be returned */
+   MMAL_PORT_BH_CB_T buffer_header_callback;
+
+   /** Keeps track of the number of buffer headers currently in transit in this port */
+   int32_t transit_buffer_headers;
+   VCOS_MUTEX_T transit_lock;
+   VCOS_SEMAPHORE_T transit_sema;
+
+   /** Copy of the public port format pointer, to detect accidental overwrites */
+   MMAL_ES_FORMAT_T* format_ptr_copy;
+
+   /** Port to which this port is connected, or NULL if disconnected */
+   MMAL_PORT_T* connected_port;
+
+   MMAL_BOOL_T core_owns_connection; /**< Connection is handled by the core */
+
+   /** Pool of buffers used between connected ports - output port only */
+   MMAL_POOL_T* pool_for_connection;
+
+   /** Indicates whether the port is paused or not. Buffers received on
+    * a paused port will be queued instead of being sent to the component. */
+   MMAL_BOOL_T is_paused;
+   /** Queue for buffers received from the client when in paused state */
+   MMAL_BUFFER_HEADER_T* queue_first;
+   /** Queue for buffers received from the client when in paused state */
+   MMAL_BUFFER_HEADER_T** queue_last;
+
+   /** Per-port statistics collected directly by the MMAL core */
+   MMAL_CORE_PORT_STATISTICS_T stats;
+
+   char *name; /**< Port name */
+   unsigned int name_size; /** Size of the memory area reserved for the name string */
+} MMAL_PORT_PRIVATE_CORE_T;
+
+/*****************************************************************************
+ * Static declarations
+ *****************************************************************************/
+static MMAL_STATUS_T mmal_port_enable_internal(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb);
+static MMAL_STATUS_T mmal_port_disable_internal(MMAL_PORT_T *port);
+
+static MMAL_STATUS_T mmal_port_connection_enable(MMAL_PORT_T *port, MMAL_PORT_T *connected_port);
+static MMAL_STATUS_T mmal_port_connection_disable(MMAL_PORT_T *port, MMAL_PORT_T *connected_port);
+static MMAL_STATUS_T mmal_port_connection_start(MMAL_PORT_T *port, MMAL_PORT_T *connected_port);
+static MMAL_STATUS_T mmal_port_populate_from_pool(MMAL_PORT_T* port, MMAL_POOL_T* pool);
+static MMAL_STATUS_T mmal_port_populate_clock_ports(MMAL_PORT_T* output, MMAL_PORT_T* input, MMAL_POOL_T* pool);
+static MMAL_STATUS_T mmal_port_connect_default(MMAL_PORT_T *port, MMAL_PORT_T *other_port);
+static void mmal_port_connected_input_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
+static void mmal_port_connected_output_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
+static MMAL_BOOL_T mmal_port_connected_pool_cb(MMAL_POOL_T *pool, MMAL_BUFFER_HEADER_T *buffer, void *userdata);
+
+static void mmal_port_name_update(MMAL_PORT_T *port);
+static void mmal_port_update_port_stats(MMAL_PORT_T *port, MMAL_CORE_STATS_DIR direction);
+
+/*****************************************************************************/
+
+/* Macros used to make the port API thread safe */
+#define LOCK_PORT(a) vcos_mutex_lock(&(a)->priv->core->lock);
+#define UNLOCK_PORT(a) vcos_mutex_unlock(&(a)->priv->core->lock);
+
+/* Macros used to make the buffer sending / flushing thread safe */
+#define LOCK_SENDING(a) vcos_mutex_lock(&(a)->priv->core->send_lock);
+#define UNLOCK_SENDING(a) vcos_mutex_unlock(&(a)->priv->core->send_lock);
+
+/* Macros used to make the port connection API thread safe */
+#define LOCK_CONNECTION(a) vcos_mutex_lock(&(a)->priv->core->connection_lock);
+#define UNLOCK_CONNECTION(a) vcos_mutex_unlock(&(a)->priv->core->connection_lock);
+
+/* Macros used to make mmal_port_disable() blocking until all
+ * the buffers have been sent back to the client */
+#define IN_TRANSIT_INCREMENT(a) \
+   vcos_mutex_lock(&(a)->priv->core->transit_lock); \
+   if (!(a)->priv->core->transit_buffer_headers++) \
+      vcos_semaphore_wait(&(a)->priv->core->transit_sema); \
+   vcos_mutex_unlock(&(a)->priv->core->transit_lock)
+#define IN_TRANSIT_DECREMENT(a) \
+   vcos_mutex_lock(&(a)->priv->core->transit_lock); \
+   if (!--(a)->priv->core->transit_buffer_headers) \
+      vcos_semaphore_post(&(a)->priv->core->transit_sema); \
+   vcos_mutex_unlock(&(a)->priv->core->transit_lock)
+#define IN_TRANSIT_WAIT(a) \
+   vcos_semaphore_wait(&(a)->priv->core->transit_sema); \
+   vcos_semaphore_post(&(a)->priv->core->transit_sema)
+#define IN_TRANSIT_COUNT(a) \
+   (a)->priv->core->transit_buffer_headers
+
+#define PORT_NAME_FORMAT "%s:%.2222s:%i%c%4.4s)"
+
+/*****************************************************************************/
+
+/** Allocate a port structure */
+MMAL_PORT_T *mmal_port_alloc(MMAL_COMPONENT_T *component, MMAL_PORT_TYPE_T type, unsigned int extra_size)
+{
+   MMAL_PORT_T *port;
+   MMAL_PORT_PRIVATE_CORE_T *core;
+   unsigned int name_size = strlen(component->name) + sizeof(PORT_NAME_FORMAT);
+   unsigned int size = sizeof(*port) + sizeof(MMAL_PORT_PRIVATE_T) +
+      sizeof(MMAL_PORT_PRIVATE_CORE_T) + name_size + extra_size;
+   MMAL_BOOL_T lock = 0, lock_send = 0, lock_transit = 0, sema_transit = 0;
+   MMAL_BOOL_T lock_stats = 0, lock_connection = 0;
+
+   LOG_TRACE("component:%s type:%u extra:%u", component->name, type, extra_size);
+
+   port = vcos_calloc(1, size, "mmal port");
+   if (!port)
+   {
+      LOG_ERROR("failed to allocate port, size %u", size);
+      return 0;
+   }
+   port->type = type;
+
+   port->priv = (MMAL_PORT_PRIVATE_T *)(port+1);
+   port->priv->core = core = (MMAL_PORT_PRIVATE_CORE_T *)(port->priv+1);
+   if (extra_size)
+      port->priv->module = (struct MMAL_PORT_MODULE_T *)(port->priv->core+1);
+   port->component = component;
+   port->name = core->name = ((char *)(port->priv->core+1)) + extra_size;
+   core->name_size = name_size;
+   mmal_port_name_update(port);
+   core->queue_last = &core->queue_first;
+
+   port->priv->pf_connect = mmal_port_connect_default;
+
+   lock = vcos_mutex_create(&port->priv->core->lock, "mmal port lock") == VCOS_SUCCESS;
+   lock_send = vcos_mutex_create(&port->priv->core->send_lock, "mmal port send lock") == VCOS_SUCCESS;
+   lock_transit = vcos_mutex_create(&port->priv->core->transit_lock, "mmal port transit lock") == VCOS_SUCCESS;
+   sema_transit = vcos_semaphore_create(&port->priv->core->transit_sema, "mmal port transit sema", 1) == VCOS_SUCCESS;
+   lock_stats = vcos_mutex_create(&port->priv->core->stats_lock, "mmal stats lock") == VCOS_SUCCESS;
+   lock_connection = vcos_mutex_create(&port->priv->core->connection_lock, "mmal connection lock") == VCOS_SUCCESS;
+
+   if (!lock || !lock_send || !lock_transit || !sema_transit || !lock_stats || !lock_connection)
+   {
+      LOG_ERROR("%s: failed to create sync objects (%u,%u,%u,%u,%u,%u)",
+            port->name, lock, lock_send, lock_transit, sema_transit, lock_stats, lock_connection);
+      goto error;
+   }
+
+   port->format = mmal_format_alloc();
+   if (!port->format)
+   {
+      LOG_ERROR("%s: failed to allocate format object", port->name);
+      goto error;
+   }
+   port->priv->core->format_ptr_copy = port->format;
+
+   LOG_TRACE("%s: created at %p", port->name, port);
+   return port;
+
+ error:
+   if (lock) vcos_mutex_delete(&port->priv->core->lock);
+   if (lock_send) vcos_mutex_delete(&port->priv->core->send_lock);
+   if (lock_transit) vcos_mutex_delete(&port->priv->core->transit_lock);
+   if (sema_transit) vcos_semaphore_delete(&port->priv->core->transit_sema);
+   if (lock_stats) vcos_mutex_delete(&port->priv->core->stats_lock);
+   if (lock_connection) vcos_mutex_delete(&port->priv->core->connection_lock);
+   if (port->format) mmal_format_free(port->format);
+   vcos_free(port);
+   return 0;
+}
+
+/** Free a port structure */
+void mmal_port_free(MMAL_PORT_T *port)
+{
+   LOG_TRACE("%s at %p", port ? port->name : "<invalid>", port);
+
+   if (!port)
+      return;
+
+   vcos_assert(port->format == port->priv->core->format_ptr_copy);
+   mmal_format_free(port->priv->core->format_ptr_copy);
+   vcos_mutex_delete(&port->priv->core->connection_lock);
+   vcos_mutex_delete(&port->priv->core->stats_lock);
+   vcos_semaphore_delete(&port->priv->core->transit_sema);
+   vcos_mutex_delete(&port->priv->core->transit_lock);
+   vcos_mutex_delete(&port->priv->core->send_lock);
+   vcos_mutex_delete(&port->priv->core->lock);
+   vcos_free(port);
+}
+
+/** Allocate an array of ports */
+MMAL_PORT_T **mmal_ports_alloc(MMAL_COMPONENT_T *component, unsigned int ports_num,
+   MMAL_PORT_TYPE_T type, unsigned int extra_size)
+{
+   MMAL_PORT_T **ports;
+   unsigned int i;
+
+   ports = vcos_malloc(sizeof(MMAL_PORT_T *) * ports_num, "mmal ports");
+   if (!ports)
+      return 0;
+
+   for (i = 0; i < ports_num; i++)
+   {
+      ports[i] = mmal_port_alloc(component, type, extra_size);
+      if (!ports[i])
+         break;
+      ports[i]->index = i;
+      mmal_port_name_update(ports[i]);
+   }
+
+   if (i != ports_num)
+   {
+      for (ports_num = i, i = 0; i < ports_num; i++)
+         mmal_port_free(ports[i]);
+      vcos_free(ports);
+      return 0;
+   }
+
+   return ports;
+}
+
+/** Free an array of ports */
+void mmal_ports_free(MMAL_PORT_T **ports, unsigned int ports_num)
+{
+   unsigned int i;
+
+   for (i = 0; i < ports_num; i++)
+      mmal_port_free(ports[i]);
+   vcos_free(ports);
+}
+
+/** Set format of a port */
+MMAL_STATUS_T mmal_port_format_commit(MMAL_PORT_T *port)
+{
+   MMAL_STATUS_T status;
+   char encoding_string[16];
+
+   if (!port || !port->priv)
+   {
+      LOG_ERROR("invalid port (%p/%p)", port, port ? port->priv : NULL);
+      return MMAL_EINVAL;
+   }
+
+   if (port->format != port->priv->core->format_ptr_copy)
+   {
+      LOG_ERROR("%s: port format has been overwritten, resetting %p to %p",
+            port->name, port->format, port->priv->core->format_ptr_copy);
+      port->format = port->priv->core->format_ptr_copy;
+      return MMAL_EFAULT;
+   }
+
+   if (port->format->encoding == 0)
+      snprintf(encoding_string, sizeof(encoding_string), "<NO-FORMAT>");
+   else
+      snprintf(encoding_string, sizeof(encoding_string), "%4.4s", (char*)&port->format->encoding);
+
+   LOG_TRACE("%s(%i:%i) port %p format %i:%s",
+             port->component->name, (int)port->type, (int)port->index, port,
+             (int)port->format->type, encoding_string);
+
+   if (!port->priv->pf_set_format)
+   {
+      LOG_ERROR("%s: no component implementation", port->name);
+      return MMAL_ENOSYS;
+   }
+
+   LOCK_PORT(port);
+   status = port->priv->pf_set_format(port);
+   mmal_port_name_update(port);
+
+   /* Make sure the buffer size / num are sensible */
+   if (port->buffer_size < port->buffer_size_min)
+      port->buffer_size = port->buffer_size_min;
+   if (port->buffer_num < port->buffer_num_min)
+      port->buffer_num = port->buffer_num_min;
+   /* The output port settings might have changed */
+   if (port->type == MMAL_PORT_TYPE_INPUT)
+   {
+      MMAL_PORT_T **ports = port->component->output;
+      unsigned int i;
+
+      for (i = 0; i < port->component->output_num; i++)
+      {
+         if (ports[i]->buffer_size < ports[i]->buffer_size_min)
+            ports[i]->buffer_size = ports[i]->buffer_size_min;
+         if (ports[i]->buffer_num < ports[i]->buffer_num_min)
+            ports[i]->buffer_num = ports[i]->buffer_num_min;
+      }
+   }
+
+   UNLOCK_PORT(port);
+   return status;
+}
+
+/** Enable processing on a port */
+MMAL_STATUS_T mmal_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
+{
+   MMAL_STATUS_T status;
+   MMAL_PORT_T *connected_port;
+   MMAL_PORT_PRIVATE_CORE_T *core;
+
+   if (!port || !port->priv)
+      return MMAL_EINVAL;
+
+   LOG_TRACE("%s port %p, cb %p, buffers (%i/%i/%i,%i/%i/%i)",
+             port->name, port, cb,
+             (int)port->buffer_num, (int)port->buffer_num_recommended, (int)port->buffer_num_min,
+             (int)port->buffer_size, (int)port->buffer_size_recommended, (int)port->buffer_size_min);
+
+   if (!port->priv->pf_enable)
+      return MMAL_ENOSYS;
+
+   core = port->priv->core;
+   LOCK_CONNECTION(port);
+   connected_port = core->connected_port;
+
+   /* Sanity checking */
+   if (port->is_enabled)
+   {
+      UNLOCK_CONNECTION(port);
+      LOG_ERROR("%s(%p) already enabled", port->name, port);
+      return MMAL_EINVAL;
+   }
+   if (connected_port && cb) /* Callback must be NULL for connected ports */
+   {
+      UNLOCK_CONNECTION(port);
+      LOG_ERROR("callback (%p) not allowed for connected port (%s)%p",
+         cb, port->name, connected_port);
+      return MMAL_EINVAL;
+   }
+
+   /* Start by preparing the port connection so that everything is ready for when
+    * both ports are enabled */
+   if (connected_port)
+   {
+      LOCK_CONNECTION(connected_port);
+      status = mmal_port_connection_enable(port, connected_port);
+      if (status != MMAL_SUCCESS)
+      {
+         UNLOCK_CONNECTION(connected_port);
+         UNLOCK_CONNECTION(port);
+         return status;
+      }
+
+      cb = connected_port->type == MMAL_PORT_TYPE_INPUT ?
+         mmal_port_connected_output_cb : mmal_port_connected_input_cb;
+   }
+
+   /* Enable the input port of a connection first */
+   if (connected_port && connected_port->type == MMAL_PORT_TYPE_INPUT)
+   {
+      status = mmal_port_enable_internal(connected_port, mmal_port_connected_input_cb);
+      if (status != MMAL_SUCCESS)
+      {
+         LOG_ERROR("failed to enable connected port (%s)%p (%s)", connected_port->name,
+            connected_port, mmal_status_to_string(status));
+         goto error;
+      }
+   }
+
+   status = mmal_port_enable_internal(port, cb);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("failed to enable port %s(%p) (%s)", port->name, port,
+         mmal_status_to_string(status));
+      goto error;
+   }
+
+   /* Enable the output port of a connection last */
+   if (connected_port && connected_port->type != MMAL_PORT_TYPE_INPUT)
+   {
+      status = mmal_port_enable_internal(connected_port, mmal_port_connected_output_cb);
+      if (status != MMAL_SUCCESS)
+      {
+         LOG_ERROR("failed to enable connected port (%s)%p (%s)", connected_port->name,
+            connected_port, mmal_status_to_string(status));
+         goto error;
+      }
+   }
+
+   /* Kick off the connection */
+   if (connected_port && core->core_owns_connection)
+   {
+      status = mmal_port_connection_start(port, connected_port);
+      if (status != MMAL_SUCCESS)
+      {
+         LOG_ERROR("failed to start connection (%s)%p (%s)", port->name,
+            port, mmal_status_to_string(status));
+         goto error;
+      }
+   }
+
+   if (connected_port)
+      UNLOCK_CONNECTION(connected_port);
+   UNLOCK_CONNECTION(port);
+   return MMAL_SUCCESS;
+
+error:
+   if (connected_port && connected_port->is_enabled)
+      mmal_port_disable_internal(connected_port);
+   if (port->is_enabled)
+      mmal_port_disable_internal(port);
+   if (connected_port)
+      mmal_port_connection_disable(port, connected_port);
+
+   if (connected_port)
+      UNLOCK_CONNECTION(connected_port);
+   UNLOCK_CONNECTION(port);
+   return status;
+}
+
+static MMAL_STATUS_T mmal_port_enable_internal(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
+{
+   MMAL_PORT_PRIVATE_CORE_T* core = port->priv->core;
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+
+   LOCK_PORT(port);
+
+   if (port->is_enabled)
+      goto end;
+
+   /* Sanity check the buffer requirements */
+   if (port->buffer_num < port->buffer_num_min)
+   {
+      LOG_ERROR("buffer_num too small (%i/%i)", (int)port->buffer_num, (int)port->buffer_num_min);
+      status = MMAL_EINVAL;
+      goto end;
+   }
+   if (port->buffer_size < port->buffer_size_min)
+   {
+      LOG_ERROR("buffer_size too small (%i/%i)", (int)port->buffer_size, (int)port->buffer_size_min);
+      status = MMAL_EINVAL;
+      goto end;
+   }
+
+   core->buffer_header_callback = cb;
+   status = port->priv->pf_enable(port, cb);
+   if (status != MMAL_SUCCESS)
+      goto end;
+
+   LOCK_SENDING(port);
+   port->is_enabled = 1;
+   UNLOCK_SENDING(port);
+
+end:
+   UNLOCK_PORT(port);
+   return status;
+}
+
+static MMAL_STATUS_T mmal_port_connection_enable(MMAL_PORT_T *port, MMAL_PORT_T *connected_port)
+{
+   MMAL_PORT_T *output = port->type == MMAL_PORT_TYPE_OUTPUT ? port : connected_port;
+   MMAL_PORT_T *input = connected_port->type == MMAL_PORT_TYPE_INPUT ? connected_port : port;
+   MMAL_PORT_T *pool_port = (output->capabilities & MMAL_PORT_CAPABILITY_ALLOCATION) ? output : input;
+   MMAL_PORT_PRIVATE_CORE_T *pool_core = pool_port->priv->core;
+   uint32_t buffer_size, buffer_num;
+   MMAL_POOL_T *pool;
+
+   /* At this point both ports hold the connection lock */
+
+   /* Ensure that the buffer numbers and sizes used are the maxima between connected ports. */
+   buffer_num  = MMAL_MAX(port->buffer_num,  connected_port->buffer_num);
+   buffer_size = MMAL_MAX(port->buffer_size, connected_port->buffer_size);
+   port->buffer_num  = connected_port->buffer_num  = buffer_num;
+   port->buffer_size = connected_port->buffer_size = buffer_size;
+
+   if (output->capabilities & MMAL_PORT_CAPABILITY_PASSTHROUGH)
+      buffer_size = 0;
+
+   if (!port->priv->core->core_owns_connection)
+      return MMAL_SUCCESS;
+
+   pool = mmal_port_pool_create(pool_port, buffer_num, buffer_size);
+   if (!pool)
+   {
+      LOG_ERROR("failed to create pool for connection");
+      return MMAL_ENOMEM;
+   }
+
+   pool_core->pool_for_connection = pool;
+   mmal_pool_callback_set(pool, mmal_port_connected_pool_cb, output);
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T mmal_port_connection_disable(MMAL_PORT_T *port, MMAL_PORT_T *connected_port)
+{
+   MMAL_POOL_T *pool = port->priv->core->pool_for_connection ?
+      port->priv->core->pool_for_connection : connected_port->priv->core->pool_for_connection;
+
+   mmal_pool_destroy(pool);
+   port->priv->core->pool_for_connection =
+      connected_port->priv->core->pool_for_connection = NULL;
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T mmal_port_connection_start(MMAL_PORT_T *port, MMAL_PORT_T *connected_port)
+{
+   MMAL_PORT_T *output = port->type == MMAL_PORT_TYPE_OUTPUT ? port : connected_port;
+   MMAL_PORT_T *input = connected_port->type == MMAL_PORT_TYPE_INPUT ? connected_port : port;
+   MMAL_POOL_T *pool = port->priv->core->pool_for_connection ?
+      port->priv->core->pool_for_connection : connected_port->priv->core->pool_for_connection;
+   MMAL_STATUS_T status;
+
+   if (output->type == MMAL_PORT_TYPE_CLOCK && input->type == MMAL_PORT_TYPE_CLOCK)
+   {
+      /* Clock ports need buffers to send clock updates, so
+       * populate both clock ports */
+      status = mmal_port_populate_clock_ports(output, input, pool);
+   }
+   else
+   {
+      /* Put the buffers into the output port */
+      status = mmal_port_populate_from_pool(output, pool);
+   }
+
+   return status;
+}
+
+/** Disable processing on a port */
+MMAL_STATUS_T mmal_port_disable(MMAL_PORT_T *port)
+{
+   MMAL_STATUS_T status;
+   MMAL_PORT_T *connected_port;
+   MMAL_PORT_PRIVATE_CORE_T *core;
+
+   if (!port || !port->priv)
+      return MMAL_EINVAL;
+
+   LOG_TRACE("%s(%i:%i) port %p", port->component->name,
+             (int)port->type, (int)port->index, port);
+
+   if (!port->priv->pf_disable)
+      return MMAL_ENOSYS;
+
+   core = port->priv->core;
+   LOCK_CONNECTION(port);
+   connected_port = core->connected_port;
+
+   /* Sanity checking */
+   if (!port->is_enabled)
+   {
+      UNLOCK_CONNECTION(port);
+      LOG_ERROR("port %s(%p) is not enabled", port->name, port);
+      return MMAL_EINVAL;
+   }
+
+   if (connected_port)
+      LOCK_CONNECTION(connected_port);
+
+   /* Disable the output port of a connection first */
+   if (connected_port && connected_port->type != MMAL_PORT_TYPE_INPUT)
+   {
+      status = mmal_port_disable_internal(connected_port);
+      if (status != MMAL_SUCCESS)
+      {
+         LOG_ERROR("failed to disable connected port (%s)%p (%s)", connected_port->name,
+            connected_port, mmal_status_to_string(status));
+         goto end;
+      }
+   }
+
+   status = mmal_port_disable_internal(port);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("failed to disable port (%s)%p", port->name, port);
+      goto end;
+   }
+
+   /* Disable the input port of a connection last */
+   if (connected_port && connected_port->type == MMAL_PORT_TYPE_INPUT)
+   {
+      status = mmal_port_disable_internal(connected_port);
+      if (status != MMAL_SUCCESS)
+      {
+         LOG_ERROR("failed to disable connected port (%s)%p (%s)", connected_port->name,
+            connected_port, mmal_status_to_string(status));
+         goto end;
+      }
+   }
+
+   if (connected_port)
+   {
+      status = mmal_port_connection_disable(port, connected_port);
+      if (status != MMAL_SUCCESS)
+         LOG_ERROR("failed to disable connection (%s)%p (%s)", port->name,
+            port, mmal_status_to_string(status));
+   }
+
+end:
+   if (connected_port)
+      UNLOCK_CONNECTION(connected_port);
+   UNLOCK_CONNECTION(port);
+
+   return status;
+}
+
+static MMAL_STATUS_T mmal_port_disable_internal(MMAL_PORT_T *port)
+{
+   MMAL_PORT_PRIVATE_CORE_T* core = port->priv->core;
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   MMAL_BUFFER_HEADER_T *buffer;
+
+   LOCK_PORT(port);
+
+   if (!port->is_enabled)
+      goto end;
+
+   LOCK_SENDING(port);
+   port->is_enabled = 0;
+   UNLOCK_SENDING(port);
+
+   mmal_component_action_lock(port->component);
+
+   if (core->pool_for_connection)
+      mmal_pool_callback_set(core->pool_for_connection, NULL, NULL);
+
+   status = port->priv->pf_disable(port);
+
+   mmal_component_action_unlock(port->component);
+
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("port %p could not be disabled (%s)", port->name, mmal_status_to_string(status));
+      LOCK_SENDING(port);
+      port->is_enabled = 1;
+      UNLOCK_SENDING(port);
+      goto end;
+   }
+
+   /* Flush our internal queue */
+   buffer = port->priv->core->queue_first;
+   while (buffer)
+   {
+      MMAL_BUFFER_HEADER_T *next = buffer->next;
+      mmal_port_buffer_header_callback(port, buffer);
+      buffer = next;
+   }
+   port->priv->core->queue_first = 0;
+   port->priv->core->queue_last = &port->priv->core->queue_first;
+
+   /* Wait for all the buffers to have come back from the component */
+   LOG_DEBUG("%s waiting for %i buffers left in transit", port->name, (int)IN_TRANSIT_COUNT(port));
+   IN_TRANSIT_WAIT(port);
+   LOG_DEBUG("%s has no buffers left in transit", port->name);
+
+   port->priv->core->buffer_header_callback = NULL;
+
+ end:
+   UNLOCK_PORT(port);
+   return status;
+}
+
+/** Send a buffer header to a port */
+MMAL_STATUS_T mmal_port_send_buffer(MMAL_PORT_T *port,
+   MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+
+   if (!port || !port->priv)
+   {
+      LOG_ERROR("invalid port");
+      return MMAL_EINVAL;
+   }
+
+#ifdef ENABLE_MMAL_EXTRA_LOGGING
+   LOG_TRACE("%s(%i:%i) port %p, buffer %p (%p,%i,%i)",
+             port->component->name, (int)port->type, (int)port->index, port, buffer,
+             buffer ? buffer->data: 0, buffer ? (int)buffer->offset : 0,
+             buffer ? (int)buffer->length : 0);
+#endif
+
+   if (!buffer->data && !(port->capabilities & MMAL_PORT_CAPABILITY_PASSTHROUGH))
+   {
+      LOG_ERROR("%s(%p) received invalid buffer header", port->name, port);
+      return MMAL_EINVAL;
+   }
+
+   if (!port->priv->pf_send)
+      return MMAL_ENOSYS;
+
+   LOCK_SENDING(port);
+
+   if (!port->is_enabled)
+   {
+      UNLOCK_SENDING(port);
+      return MMAL_EINVAL;
+   }
+
+   if (port->type == MMAL_PORT_TYPE_OUTPUT && buffer->length)
+   {
+      LOG_DEBUG("given an output buffer with length != 0");
+      buffer->length = 0;
+   }
+
+   /* coverity[lock] transit_sema is used for signalling, and is not a lock */
+   /* coverity[lock_order] since transit_sema is not a lock, there is no ordering conflict */
+   IN_TRANSIT_INCREMENT(port);
+
+   if (port->priv->core->is_paused)
+   {
+      /* Add buffer to our internal queue */
+      buffer->next = NULL;
+      *port->priv->core->queue_last = buffer;
+      port->priv->core->queue_last = &buffer->next;
+   }
+   else
+   {
+      /* Send buffer to component */
+      status = port->priv->pf_send(port, buffer);
+   }
+
+   if (status != MMAL_SUCCESS)
+   {
+      IN_TRANSIT_DECREMENT(port);
+      LOG_ERROR("%s: send failed: %s", port->name, mmal_status_to_string(status));
+   }
+   else
+   {
+      mmal_port_update_port_stats(port, MMAL_CORE_STATS_RX);
+   }
+
+   UNLOCK_SENDING(port);
+   return status;
+}
+
+/** Flush a port */
+MMAL_STATUS_T mmal_port_flush(MMAL_PORT_T *port)
+{
+   MMAL_BUFFER_HEADER_T *buffer = 0;
+   MMAL_STATUS_T status;
+
+   if (!port || !port->priv)
+      return MMAL_EINVAL;
+
+   LOG_TRACE("%s(%i:%i) port %p", port->component->name,
+             (int)port->type, (int)port->index, port);
+
+   if (!port->priv->pf_flush)
+      return MMAL_ENOSYS;
+
+   /* N.B. must take action lock *before* sending lock */
+   mmal_component_action_lock(port->component);
+   LOCK_SENDING(port);
+
+   if (!port->is_enabled)
+   {
+      UNLOCK_SENDING(port);
+      mmal_component_action_unlock(port->component);
+      return MMAL_SUCCESS;
+   }
+
+   status = port->priv->pf_flush(port);
+   if (status == MMAL_SUCCESS)
+   {
+      /* Flush our internal queue */
+      buffer = port->priv->core->queue_first;
+      port->priv->core->queue_first = 0;
+      port->priv->core->queue_last = &port->priv->core->queue_first;
+   }
+
+   UNLOCK_SENDING(port);
+   mmal_component_action_unlock(port->component);
+
+   while (buffer)
+   {
+      MMAL_BUFFER_HEADER_T *next = buffer->next;
+      mmal_port_buffer_header_callback(port, buffer);
+      buffer = next;
+   }
+   return status;
+}
+
+/* Set a parameter on a port. */
+MMAL_STATUS_T mmal_port_parameter_set(MMAL_PORT_T *port,
+   const MMAL_PARAMETER_HEADER_T *param)
+{
+   MMAL_STATUS_T status = MMAL_ENOSYS;
+
+   if (!port)
+   {
+      LOG_ERROR("no port");
+      return MMAL_EINVAL;
+   }
+   if (!param)
+   {
+      LOG_ERROR("param not supplied");
+      return MMAL_EINVAL;
+   }
+   if (!port->priv)
+   {
+      LOG_ERROR("port not configured");
+      return MMAL_EINVAL;
+   }
+
+   LOG_TRACE("%s(%i:%i) port %p, param %p (%x,%i)", port->component->name,
+             (int)port->type, (int)port->index, port,
+             param, param ? param->id : 0, param ? (int)param->size : 0);
+
+   LOCK_PORT(port);
+   if (port->priv->pf_parameter_set)
+      status = port->priv->pf_parameter_set(port, param);
+   if (status == MMAL_ENOSYS)
+   {
+      /* is this a core parameter? */
+      status = mmal_port_private_parameter_set(port, param);
+   }
+   UNLOCK_PORT(port);
+   return status;
+}
+
+/* Get a port parameter */
+MMAL_STATUS_T mmal_port_parameter_get(MMAL_PORT_T *port,
+   MMAL_PARAMETER_HEADER_T *param)
+{
+   MMAL_STATUS_T status = MMAL_ENOSYS;
+
+   if (!port || !port->priv)
+      return MMAL_EINVAL;
+
+   LOG_TRACE("%s(%i:%i) port %p, param %p (%x,%i)", port->component->name,
+             (int)port->type, (int)port->index, port,
+             param, param ? param->id : 0, param ? (int)param->size : 0);
+
+   if (!param)
+      return MMAL_EINVAL;
+
+   LOCK_PORT(port);
+   if (port->priv->pf_parameter_get)
+      status = port->priv->pf_parameter_get(port, param);
+   if (status == MMAL_ENOSYS)
+   {
+      /* is this a core parameter? */
+      status = mmal_port_private_parameter_get(port, param);
+   }
+
+   UNLOCK_PORT(port);
+   return status;
+}
+
+/** Buffer header callback. */
+void mmal_port_buffer_header_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+#ifdef ENABLE_MMAL_EXTRA_LOGGING
+   LOG_TRACE("%s(%i:%i) port %p, buffer %p (%i,%p,%i,%i)",
+             port->component->name, (int)port->type, (int)port->index, port, buffer,
+             buffer ? (int)buffer->cmd : 0, buffer ? buffer->data : 0,
+             buffer ? (int)buffer->offset : 0, buffer ? (int)buffer->length : 0);
+#endif
+
+   if (!vcos_verify(IN_TRANSIT_COUNT(port) >= 0))
+      LOG_ERROR("%s: buffer headers in transit < 0 (%d)", port->name, (int)IN_TRANSIT_COUNT(port));
+
+   if (MMAL_COLLECT_PORT_STATS_ENABLED)
+   {
+      mmal_port_update_port_stats(port, MMAL_CORE_STATS_TX);
+   }
+
+   port->priv->core->buffer_header_callback(port, buffer);
+
+   IN_TRANSIT_DECREMENT(port);
+}
+
+/** Event callback */
+void mmal_port_event_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   if (port->priv->core->buffer_header_callback)
+   {
+      port->priv->core->buffer_header_callback(port, buffer);
+   }
+   else
+   {
+      LOG_ERROR("event lost on port %i,%i (buffer header callback not defined)",
+                (int)port->type, (int)port->index);
+      mmal_buffer_header_release(buffer);
+   }
+}
+
+/** Connect an output port to an input port. */
+MMAL_STATUS_T mmal_port_connect(MMAL_PORT_T *port, MMAL_PORT_T *other_port)
+{
+   MMAL_PORT_PRIVATE_CORE_T* core;
+   MMAL_PORT_PRIVATE_CORE_T* other_core;
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   MMAL_PORT_T* output_port = NULL;
+
+   if (!port || !port->priv || !other_port || !other_port->priv)
+   {
+      LOG_ERROR("invalid port");
+      return MMAL_EINVAL;
+   }
+
+   if ((port->type == MMAL_PORT_TYPE_CLOCK) && (port->type != other_port->type))
+   {
+      LOG_ERROR("invalid port connection");
+      return MMAL_EINVAL;
+   }
+
+   LOG_TRACE("connecting %s(%p) to %s(%p)", port->name, port, other_port->name, other_port);
+
+   if (!port->priv->pf_connect || !other_port->priv->pf_connect)
+   {
+      LOG_ERROR("at least one pf_connect is NULL");
+      return MMAL_ENOSYS;
+   }
+
+   core = port->priv->core;
+   other_core = other_port->priv->core;
+
+   LOCK_CONNECTION(port);
+   if (core->connected_port)
+   {
+      LOG_ERROR("port %p is already connected", port);
+      UNLOCK_CONNECTION(port);
+      return MMAL_EISCONN;
+   }
+   if (port->is_enabled)
+   {
+      LOG_ERROR("port %p should not be enabled", port);
+      UNLOCK_CONNECTION(port);
+      return MMAL_EINVAL;
+   }
+
+   LOCK_CONNECTION(other_port);
+   if (other_core->connected_port)
+   {
+      LOG_ERROR("port %p is already connected", other_port);
+      status = MMAL_EISCONN;
+      goto finish;
+   }
+   if (other_port->is_enabled)
+   {
+      LOG_ERROR("port %p should not be enabled", other_port);
+      status = MMAL_EINVAL;
+      goto finish;
+   }
+
+   core->connected_port = other_port;
+   other_core->connected_port = port;
+
+   core->core_owns_connection = 0;
+   other_core->core_owns_connection = 0;
+
+   /* Check to see if the port will manage the connection on its own. If not then the core
+    * will manage it. */
+   output_port = port->type == MMAL_PORT_TYPE_OUTPUT ? port : other_port;
+   if (output_port->priv->pf_connect(port, other_port) == MMAL_SUCCESS)
+      goto finish;
+
+   core->core_owns_connection = 1;
+   other_core->core_owns_connection = 1;
+
+
+finish:
+   UNLOCK_CONNECTION(other_port);
+   UNLOCK_CONNECTION(port);
+   return status;
+}
+
+/** Disconnect a connected port. */
+MMAL_STATUS_T mmal_port_disconnect(MMAL_PORT_T *port)
+{
+   MMAL_PORT_PRIVATE_CORE_T* core;
+   MMAL_PORT_T* other_port;
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+
+   if (!port || !port->priv)
+   {
+      LOG_ERROR("invalid port");
+      return MMAL_EINVAL;
+   }
+
+   LOG_TRACE("%s(%p)", port->name, port);
+
+   LOCK_CONNECTION(port);
+
+   core = port->priv->core;
+   other_port = core->connected_port;
+
+   if (!other_port)
+   {
+      UNLOCK_CONNECTION(port);
+      LOG_DEBUG("%s(%p) is not connected", port->name, port);
+      return MMAL_ENOTCONN;
+   }
+
+   LOCK_CONNECTION(other_port);
+
+   /* Make sure the connection is disabled first */
+   if (port->is_enabled)
+   {
+      MMAL_PORT_T *output = port->type == MMAL_PORT_TYPE_OUTPUT ? port : other_port;
+      MMAL_PORT_T *input = other_port->type == MMAL_PORT_TYPE_INPUT ? other_port : port;
+
+      status = mmal_port_disable_internal(output);
+      if (status != MMAL_SUCCESS)
+      {
+         LOG_ERROR("failed to disable port (%s)%p", port->name, port);
+         goto end;
+      }
+      status = mmal_port_disable_internal(input);
+      if (status != MMAL_SUCCESS)
+      {
+         LOG_ERROR("failed to disable port (%s)%p", port->name, port);
+         goto end;
+      }
+      status = mmal_port_connection_disable(port, other_port);
+   }
+
+   if (!core->core_owns_connection)
+   {
+      status = port->priv->pf_connect(port, NULL);
+      if (status != MMAL_SUCCESS)
+      {
+         LOG_ERROR("disconnection of %s(%p) failed (%i)", port->name, port, status);
+         goto end;
+      }
+   }
+
+   core->connected_port = NULL;
+   other_port->priv->core->connected_port = NULL;
+
+end:
+   UNLOCK_CONNECTION(other_port);
+   UNLOCK_CONNECTION(port);
+   return status;
+}
+
+/** Allocate a payload buffer */
+uint8_t *mmal_port_payload_alloc(MMAL_PORT_T *port, uint32_t payload_size)
+{
+   uint8_t *mem;
+
+   if (!port || !port->priv)
+      return NULL;
+
+   LOG_TRACE("%s(%i:%i) port %p, size %i", port->component->name,
+             (int)port->type, (int)port->index, port, (int)payload_size);
+
+   if (!payload_size)
+      return NULL;
+
+   /* TODO: keep track of the allocs so we can free them when the component is destroyed */
+
+   if (!port->priv->pf_payload_alloc)
+   {
+      /* Revert to using the heap */
+#ifdef _VIDEOCORE
+      mem = (void *)mem_alloc(payload_size, 32, MEM_FLAG_DIRECT, port->name);
+#else
+      mem = vcos_malloc(payload_size, "mmal payload");
+#endif
+      goto end;
+   }
+
+   LOCK_PORT(port);
+   mem = port->priv->pf_payload_alloc(port, payload_size);
+   UNLOCK_PORT(port);
+
+ end:
+   /* Acquire the port if the allocation was successful.
+    * This will ensure that the component is not destroyed until the payload has been freed. */
+   if (mem)
+      mmal_port_acquire(port);
+   return mem;
+}
+
+/** Free a payload buffer */
+void mmal_port_payload_free(MMAL_PORT_T *port, uint8_t *payload)
+{
+   if (!port || !port->priv)
+      return;
+
+   LOG_TRACE("%s(%i:%i) port %p, payload %p", port->component->name,
+             (int)port->type, (int)port->index, port, payload);
+
+   if (!port->priv->pf_payload_alloc)
+   {
+      /* Revert to using the heap */
+#ifdef _VIDEOCORE
+      mem_release((MEM_HANDLE_T)payload);
+#else
+      vcos_free(payload);
+#endif
+      mmal_port_release(port);
+      return;
+   }
+
+   LOCK_PORT(port);
+   port->priv->pf_payload_free(port, payload);
+   UNLOCK_PORT(port);
+   mmal_port_release(port);
+}
+
+MMAL_STATUS_T mmal_port_event_get(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T **buffer, uint32_t event)
+{
+   if (!port || !port->priv || !buffer)
+      return MMAL_EINVAL;
+
+   LOG_TRACE("%s(%i:%i) port %p, event %4.4s", port->component->name,
+             (int)port->type, (int)port->index, port, (char *)&event);
+
+   /* Get an event buffer from our event pool */
+   *buffer = mmal_queue_get(port->component->priv->event_pool->queue);
+   if (!*buffer)
+   {
+      LOG_ERROR("%s(%i:%i) port %p, no event buffer left for %4.4s", port->component->name,
+                (int)port->type, (int)port->index, port, (char *)&event);
+      return MMAL_ENOSPC;
+   }
+
+   (*buffer)->cmd = event;
+   (*buffer)->length = 0;
+
+   /* Special case for the FORMAT_CHANGED event. We need to properly initialise the event
+    * buffer so that it contains an initialised MMAL_ES_FORMAT_T structure. */
+   if (event == MMAL_EVENT_FORMAT_CHANGED)
+   {
+      uint32_t size = sizeof(MMAL_EVENT_FORMAT_CHANGED_T);
+      size += sizeof(MMAL_ES_FORMAT_T) + sizeof(MMAL_ES_SPECIFIC_FORMAT_T);
+
+      if ((*buffer)->alloc_size < size)
+      {
+         LOG_ERROR("%s(%i:%i) port %p, event buffer for %4.4s is too small (%i/%i)",
+                   port->component->name, (int)port->type, (int)port->index, port,
+                   (char *)&event, (int)(*buffer)->alloc_size, (int)size);
+         goto error;
+      }
+
+      memset((*buffer)->data, 0, size);
+      (*buffer)->length = size;
+   }
+
+   return MMAL_SUCCESS;
+
+error:
+   if (*buffer)
+      mmal_buffer_header_release(*buffer);
+   *buffer = NULL;
+   return MMAL_ENOSPC;
+}
+
+/** Populate clock ports from the given pool */
+static MMAL_STATUS_T mmal_port_populate_clock_ports(MMAL_PORT_T* output, MMAL_PORT_T* input, MMAL_POOL_T* pool)
+{
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   MMAL_BUFFER_HEADER_T *buffer;
+
+   if (!output->priv->pf_send || !input->priv->pf_send)
+      return MMAL_ENOSYS;
+
+   LOG_TRACE("output %s %p, input %s %p, pool: %p", output->name, output, input->name, input, pool);
+
+   buffer = mmal_queue_get(pool->queue);
+   while (buffer)
+   {
+      status = mmal_port_send_buffer(output, buffer);
+      if (status != MMAL_SUCCESS)
+      {
+         LOG_ERROR("failed to send buffer to clock port %s", output->name);
+         mmal_buffer_header_release(buffer);
+         break;
+      }
+
+      buffer = mmal_queue_get(pool->queue);
+      if (buffer)
+      {
+         status = mmal_port_send_buffer(input, buffer);
+         if (status != MMAL_SUCCESS)
+         {
+            LOG_ERROR("failed to send buffer to clock port %s", output->name);
+            mmal_buffer_header_release(buffer);
+            break;
+         }
+         buffer = mmal_queue_get(pool->queue);
+      }
+   }
+
+   return status;
+}
+
+/** Populate an output port with a pool of buffers */
+static MMAL_STATUS_T mmal_port_populate_from_pool(MMAL_PORT_T* port, MMAL_POOL_T* pool)
+{
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   uint32_t buffer_idx;
+   MMAL_BUFFER_HEADER_T *buffer;
+
+   if (!port->priv->pf_send)
+      return MMAL_ENOSYS;
+
+   LOG_TRACE("%s port %p, pool: %p", port->name, port, pool);
+
+   /* Populate port from pool */
+   for (buffer_idx = 0; buffer_idx < port->buffer_num; buffer_idx++)
+   {
+      buffer = mmal_queue_get(pool->queue);
+      if (!buffer)
+      {
+         LOG_ERROR("too few buffers in the pool");
+         status = MMAL_ENOMEM;
+         break;
+      }
+
+      status = mmal_port_send_buffer(port, buffer);
+      if (status != MMAL_SUCCESS)
+      {
+         LOG_ERROR("failed to send buffer to port");
+         mmal_buffer_header_release(buffer);
+         break;
+      }
+   }
+
+   return status;
+}
+
+/** Default behaviour when setting up or tearing down a connection to another port */
+static MMAL_STATUS_T mmal_port_connect_default(MMAL_PORT_T *port, MMAL_PORT_T *other_port)
+{
+   MMAL_PARAM_UNUSED(port);
+   MMAL_PARAM_UNUSED(other_port);
+
+   LOG_TRACE("port %p, other_port %p", port, other_port);
+   return MMAL_ENOSYS;
+}
+
+/** Connected input port buffer callback */
+static void mmal_port_connected_input_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   LOG_TRACE("buffer %p from connected input port %p: data %p, alloc_size %u, length %u",
+             buffer, port, buffer->data, buffer->alloc_size, buffer->length);
+
+   /* Clock ports are bi-directional and a buffer coming from an "input"
+    * clock port can potentially have valid payload data, in which case
+    * it should be sent directly to the connected port. */
+   if (port->type == MMAL_PORT_TYPE_CLOCK && buffer->length)
+   {
+      MMAL_PORT_T* connected_port = port->priv->core->connected_port;
+      mmal_port_send_buffer(connected_port, buffer);
+      return;
+   }
+
+   /* Simply release buffer back into pool for re-use */
+   mmal_buffer_header_release(buffer);
+}
+
+/** Connected output port buffer callback */
+static void mmal_port_connected_output_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_PORT_T* connected_port = port->priv->core->connected_port;
+   MMAL_STATUS_T status;
+
+   LOG_TRACE("buffer %p from connected output port %p: data %p, alloc_size %u, length %u",
+             buffer, port, buffer->data, buffer->alloc_size, buffer->length);
+
+   if (buffer->cmd)
+   {
+      MMAL_EVENT_FORMAT_CHANGED_T *event = mmal_event_format_changed_get(buffer);
+
+      /* Handle format changed events */
+      if (event)
+      {
+         /* Apply the change */
+         status = mmal_format_full_copy(port->format, event->format);
+         if (status == MMAL_SUCCESS)
+            status = mmal_port_format_commit(port);
+         if (status != MMAL_SUCCESS)
+            LOG_ERROR("format commit failed on port %s (%i)", port->name, status);
+
+         /* Forward to the connected port */
+         if (status == MMAL_SUCCESS)
+            status = mmal_port_send_buffer(connected_port, buffer);
+
+         if (status != MMAL_SUCCESS)
+         {
+            mmal_event_error_send(port->component, status);
+            mmal_buffer_header_release(buffer);
+         }
+         return; /* Event handled */
+      }
+
+      /* FIXME Release other event buffers for now, until we can deal with shared memory issues */
+      mmal_buffer_header_release(buffer);
+   }
+   else
+   {
+      if (port->is_enabled)
+      {
+         /* Forward data buffers to the connected input port */
+         status = mmal_port_send_buffer(connected_port, buffer);
+         if (status != MMAL_SUCCESS)
+         {
+            LOG_ERROR("%s could not send buffer on port %s (%s)",
+                      port->name, connected_port->name, mmal_status_to_string(status));
+            mmal_buffer_header_release(buffer);
+         }
+      }
+      else
+      {
+         /* This port is disabled. Buffer will be a flushed buffer, so
+          * return to the pool rather than delivering it.
+          */
+         mmal_buffer_header_release(buffer);
+      }
+   }
+}
+
+/** Callback for when a buffer from a connected input port is finally released */
+static MMAL_BOOL_T mmal_port_connected_pool_cb(MMAL_POOL_T *pool, MMAL_BUFFER_HEADER_T *buffer, void *userdata)
+{
+   MMAL_PORT_T* port = (MMAL_PORT_T*)userdata;
+   MMAL_STATUS_T status;
+   MMAL_PARAM_UNUSED(pool);
+
+   LOG_TRACE("released buffer %p, data %p alloc_size %u length %u",
+             buffer, buffer->data, buffer->alloc_size, buffer->length);
+
+   /* Pipe the buffer back to the output port */
+   status = mmal_port_send_buffer(port, buffer);
+
+   /* Put the buffer back in the pool if we were successful */
+   return status != MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+static void mmal_port_name_update(MMAL_PORT_T *port)
+{
+   MMAL_PORT_PRIVATE_CORE_T* core = port->priv->core;
+
+   vcos_snprintf(core->name, core->name_size - 1, PORT_NAME_FORMAT,
+            port->component->name, mmal_port_type_to_string(port->type), (int)port->index,
+            port->format && port->format->encoding ? '(' : '\0',
+            port->format && port->format->encoding ? (char *)&port->format->encoding : "");
+}
+
+static MMAL_STATUS_T mmal_port_get_core_stats(MMAL_PORT_T *port, MMAL_PARAMETER_HEADER_T *param)
+{
+   MMAL_PARAMETER_CORE_STATISTICS_T *stats_param = (MMAL_PARAMETER_CORE_STATISTICS_T*)param;
+   MMAL_CORE_STATISTICS_T *stats = &stats_param->stats;
+   MMAL_CORE_STATISTICS_T *src_stats;
+   MMAL_PORT_PRIVATE_CORE_T *core = port->priv->core;
+   vcos_mutex_lock(&core->stats_lock);
+   switch (stats_param->dir)
+   {
+   case MMAL_CORE_STATS_RX:
+      src_stats = &port->priv->core->stats.rx;
+      break;
+   default:
+      src_stats = &port->priv->core->stats.tx;
+      break;
+   }
+   *stats = *src_stats;
+   if (stats_param->reset)
+      memset(src_stats, 0, sizeof(*src_stats));
+   vcos_mutex_unlock(&core->stats_lock);
+   return MMAL_SUCCESS;
+}
+
+/** Update the port stats, called per buffer.
+ *
+ */
+static void mmal_port_update_port_stats(MMAL_PORT_T *port, MMAL_CORE_STATS_DIR direction)
+{
+   MMAL_PORT_PRIVATE_CORE_T *core = port->priv->core;
+   MMAL_CORE_STATISTICS_T *stats;
+   unsigned stc = vcos_getmicrosecs();
+
+   vcos_mutex_lock(&core->stats_lock);
+
+   stats = direction == MMAL_CORE_STATS_RX ? &core->stats.rx : &core->stats.tx;
+
+   stats->buffer_count++;
+
+   if (!stats->first_buffer_time)
+   {
+      stats->last_buffer_time = stats->first_buffer_time = stc;
+   }
+   else
+   {
+      stats->max_delay = vcos_max(stats->max_delay, stc-stats->last_buffer_time);
+      stats->last_buffer_time = stc;
+   }
+   vcos_mutex_unlock(&core->stats_lock);
+}
+
+static MMAL_STATUS_T mmal_port_private_parameter_get(MMAL_PORT_T *port,
+                                                     MMAL_PARAMETER_HEADER_T *param)
+{
+   switch (param->id)
+   {
+   case MMAL_PARAMETER_CORE_STATISTICS:
+      return mmal_port_get_core_stats(port, param);
+   default:
+      return MMAL_ENOSYS;
+   }
+}
+
+static MMAL_STATUS_T mmal_port_private_parameter_set(MMAL_PORT_T *port,
+                                                     const MMAL_PARAMETER_HEADER_T *param)
+{
+   (void)port;
+   switch (param->id)
+   {
+   default:
+      return MMAL_ENOSYS;
+   }
+}
+
+MMAL_STATUS_T mmal_port_pause(MMAL_PORT_T *port, MMAL_BOOL_T pause)
+{
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+
+   LOCK_SENDING(port);
+
+   /* When resuming from pause, we send all our queued buffers to the port */
+   if (!pause && port->is_enabled)
+   {
+      MMAL_BUFFER_HEADER_T *buffer = port->priv->core->queue_first;
+      while (buffer)
+      {
+         MMAL_BUFFER_HEADER_T *next = buffer->next;
+         status = port->priv->pf_send(port, buffer);
+         if (status != MMAL_SUCCESS)
+         {
+            buffer->next = next;
+            break;
+         }
+         buffer = next;
+      }
+
+      /* If for some reason we could not send one of the buffers, we just
+       * leave all the buffers in our internal queue and return an error. */
+      if (status != MMAL_SUCCESS)
+      {
+         port->priv->core->queue_first = buffer;
+      }
+      else
+      {
+         port->priv->core->queue_first = 0;
+         port->priv->core->queue_last = &port->priv->core->queue_first;
+      }
+   }
+
+   if (status == MMAL_SUCCESS)
+      port->priv->core->is_paused = pause;
+
+   UNLOCK_SENDING(port);
+   return status;
+}
+
+MMAL_BOOL_T mmal_port_is_connected(MMAL_PORT_T *port)
+{
+   return !!port->priv->core->connected_port;
+}
diff --git a/interface/mmal/core/mmal_port_clock.c b/interface/mmal/core/mmal_port_clock.c
new file mode 100755 (executable)
index 0000000..1eb7d10
--- /dev/null
@@ -0,0 +1,803 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal_clock.h"
+#include "mmal_logging.h"
+#include "core/mmal_clock_private.h"
+#include "core/mmal_port_private.h"
+#include "util/mmal_util.h"
+
+#ifdef __VIDEOCORE__
+# include "vcfw/rtos/common/rtos_common_mem.h"
+#endif
+
+/** Minimum number of buffers required on a clock port */
+#define MMAL_PORT_CLOCK_BUFFERS_MIN  16
+
+/** Private clock port context */
+typedef struct MMAL_PORT_CLOCK_T
+{
+   MMAL_PORT_CLOCK_EVENT_CB event_cb; /**< callback for notifying the component of clock events */
+   MMAL_QUEUE_T *queue;               /**< queue for empty buffers sent to the port */
+   MMAL_CLOCK_T *clock;               /**< clock module for scheduling requests */
+   MMAL_BOOL_T is_reference;          /**< TRUE -> clock port is a reference, therefore
+                                           will forward time updates */
+   MMAL_BOOL_T buffer_info_reporting; /**< controls buffer info reporting */
+} MMAL_PORT_CLOCK_T;
+
+/*****************************************************************************
+ * Private functions
+ *****************************************************************************/
+#ifdef __VIDEOCORE__
+/* FIXME: mmal_buffer_header_mem_lock() assumes that payload memory is on the
+ * relocatable heap when on VC. However that is not always the case. The MMAL
+ * framework will allocate memory from the normal heap when ports are connected.
+ * To work around this, override the default behaviour by providing a payload
+ * allocator for clock ports which always allocates from the relocatable heap. */
+static uint8_t* mmal_port_clock_payload_alloc(MMAL_PORT_T *port, uint32_t payload_size)
+{
+   int alignment = port->buffer_alignment_min;
+   uint8_t *mem;
+
+   if (!alignment)
+      alignment = 32;
+   vcos_assert((alignment & (alignment-1)) == 0);
+
+   mem = (uint8_t*)mem_alloc(payload_size, alignment, MEM_FLAG_DIRECT, port->name);
+   if (!mem)
+   {
+      LOG_ERROR("could not allocate %u bytes", payload_size);
+      return NULL;
+   }
+   return mem;
+}
+
+static void mmal_port_clock_payload_free(MMAL_PORT_T *port, uint8_t *payload)
+{
+   MMAL_PARAM_UNUSED(port);
+   mem_release((MEM_HANDLE_T)payload);
+}
+#endif
+
+
+/* Callback invoked by the clock module in response to a client request */
+static void mmal_port_clock_request_cb(MMAL_CLOCK_T* clock, int64_t media_time, void *cb_data, MMAL_CLOCK_VOID_FP cb)
+{
+   MMAL_PORT_CLOCK_REQUEST_CB cb_client = (MMAL_PORT_CLOCK_REQUEST_CB)cb;
+
+   /* Forward to the client */
+   cb_client((MMAL_PORT_T*)clock->user_data, media_time, cb_data);
+}
+
+/* Process buffers received from other clock ports */
+static MMAL_STATUS_T mmal_port_clock_process_buffer(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_PORT_CLOCK_T *priv_clock = port->priv->clock;
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   MMAL_CLOCK_EVENT_T event = MMAL_CLOCK_EVENT_INIT(MMAL_CLOCK_EVENT_INVALID);
+
+   if (buffer->length != sizeof(MMAL_CLOCK_EVENT_T))
+   {
+      LOG_ERROR("invalid buffer length %d expected %d",
+                buffer->length, sizeof(MMAL_CLOCK_EVENT_T));
+      return MMAL_EINVAL;
+   }
+
+   mmal_buffer_header_mem_lock(buffer);
+   memcpy(&event, buffer->data, sizeof(MMAL_CLOCK_EVENT_T));
+   mmal_buffer_header_mem_unlock(buffer);
+
+   if (event.magic != MMAL_CLOCK_EVENT_MAGIC)
+   {
+      LOG_ERROR("buffer corrupt (magic %4.4s)", (char*)&event.magic);
+      buffer->length = 0;
+      mmal_port_buffer_header_callback(port, buffer);
+      return MMAL_EINVAL;
+   }
+
+   LOG_TRACE("port %s id %4.4s", port->name, (char*)&event.id);
+
+   switch (event.id)
+   {
+   case MMAL_CLOCK_EVENT_ACTIVE:
+      status = mmal_clock_active_set(priv_clock->clock, event.data.enable);
+      break;
+   case MMAL_CLOCK_EVENT_TIME:
+      status = mmal_clock_media_time_set(priv_clock->clock, event.data.media_time);
+      break;
+   case MMAL_CLOCK_EVENT_SCALE:
+      status = mmal_clock_scale_set(priv_clock->clock, event.data.scale);
+      break;
+   case MMAL_CLOCK_EVENT_UPDATE_THRESHOLD:
+      status = mmal_clock_update_threshold_set(priv_clock->clock, &event.data.update_threshold);
+      break;
+   case MMAL_CLOCK_EVENT_DISCONT_THRESHOLD:
+      status = mmal_clock_discont_threshold_set(priv_clock->clock, &event.data.discont_threshold);
+      break;
+   case MMAL_CLOCK_EVENT_REQUEST_THRESHOLD:
+      status = mmal_clock_request_threshold_set(priv_clock->clock, &event.data.request_threshold);
+      break;
+   case MMAL_CLOCK_EVENT_INPUT_BUFFER_INFO:
+   case MMAL_CLOCK_EVENT_OUTPUT_BUFFER_INFO:
+      /* nothing to do - just forward to the client */
+      break;
+   default:
+      LOG_ERROR("invalid event %4.4s", (char*)&event.id);
+      status = MMAL_EINVAL;
+      break;
+   }
+
+   if (priv_clock->event_cb && status == MMAL_SUCCESS)
+   {
+      /* Notify the component, but don't return the buffer */
+      event.buffer = buffer;
+      priv_clock->event_cb(port, &event);
+   }
+   else
+   {
+      /* Finished with the buffer, so return it */
+      buffer->length = 0;
+      mmal_port_buffer_header_callback(port, buffer);
+   }
+
+   return status;
+}
+
+static MMAL_STATUS_T mmal_port_clock_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_PORT_CLOCK_T *priv_clock = port->priv->clock;
+
+   if (buffer->length)
+      return mmal_port_clock_process_buffer(port, buffer);
+
+   /* Queue empty buffers to be used later when forwarding clock updates */
+   mmal_queue_put(priv_clock->queue, buffer);
+
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T mmal_port_clock_flush(MMAL_PORT_T *port)
+{
+   MMAL_BUFFER_HEADER_T *buffer;
+
+   /* Flush empty buffers */
+   buffer = mmal_queue_get(port->priv->clock->queue);
+   while (buffer)
+   {
+      mmal_port_buffer_header_callback(port, buffer);
+      buffer = mmal_queue_get(port->priv->clock->queue);
+   }
+
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T mmal_port_clock_parameter_set(MMAL_PORT_T *port, const MMAL_PARAMETER_HEADER_T *param)
+{
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   MMAL_CLOCK_EVENT_T event = MMAL_CLOCK_EVENT_INIT(MMAL_CLOCK_EVENT_INVALID);
+
+   switch (param->id)
+   {
+      case MMAL_PARAMETER_CLOCK_REFERENCE:
+      {
+         const MMAL_PARAMETER_BOOLEAN_T *p = (const MMAL_PARAMETER_BOOLEAN_T*)param;
+         status = mmal_port_clock_reference_set(port, p->enable);
+         event.id = MMAL_CLOCK_EVENT_REFERENCE;
+         event.data.enable = p->enable;
+      }
+      break;
+      case MMAL_PARAMETER_CLOCK_ACTIVE:
+      {
+         const MMAL_PARAMETER_BOOLEAN_T *p = (const MMAL_PARAMETER_BOOLEAN_T*)param;
+         status = mmal_port_clock_active_set(port, p->enable);
+         event.id = MMAL_CLOCK_EVENT_ACTIVE;
+         event.data.enable = p->enable;
+      }
+      break;
+      case MMAL_PARAMETER_CLOCK_SCALE:
+      {
+         const MMAL_PARAMETER_RATIONAL_T *p = (const MMAL_PARAMETER_RATIONAL_T*)param;
+         status = mmal_port_clock_scale_set(port, p->value);
+         event.id = MMAL_CLOCK_EVENT_SCALE;
+         event.data.scale = p->value;
+      }
+      break;
+      case MMAL_PARAMETER_CLOCK_TIME:
+      {
+         const MMAL_PARAMETER_INT64_T *p = (const MMAL_PARAMETER_INT64_T*)param;
+         status = mmal_port_clock_media_time_set(port, p->value);
+         event.id = MMAL_CLOCK_EVENT_TIME;
+         event.data.media_time = p->value;
+      }
+      break;
+      case MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD:
+      {
+         const MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD_T *p = (const MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD_T *)param;
+         status = mmal_port_clock_update_threshold_set(port, &p->value);
+         event.id = MMAL_CLOCK_EVENT_UPDATE_THRESHOLD;
+         event.data.update_threshold = p->value;
+      }
+      break;
+      case MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD:
+      {
+         const MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD_T *p = (const MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD_T *)param;
+         status = mmal_port_clock_discont_threshold_set(port, &p->value);
+         event.id = MMAL_CLOCK_EVENT_DISCONT_THRESHOLD;
+         event.data.discont_threshold = p->value;
+      }
+      break;
+      case MMAL_PARAMETER_CLOCK_REQUEST_THRESHOLD:
+      {
+         const MMAL_PARAMETER_CLOCK_REQUEST_THRESHOLD_T *p = (const MMAL_PARAMETER_CLOCK_REQUEST_THRESHOLD_T *)param;
+         status = mmal_port_clock_request_threshold_set(port, &p->value);
+         event.id = MMAL_CLOCK_EVENT_REQUEST_THRESHOLD;
+         event.data.request_threshold = p->value;
+      }
+      break;
+      case MMAL_PARAMETER_CLOCK_ENABLE_BUFFER_INFO:
+      {
+         const MMAL_PARAMETER_BOOLEAN_T *p = (const MMAL_PARAMETER_BOOLEAN_T*)param;
+         port->priv->clock->buffer_info_reporting = p->enable;
+         return MMAL_SUCCESS;
+      }
+      default:
+         LOG_ERROR("unsupported clock parameter 0x%x", param->id);
+         return MMAL_ENOSYS;
+   }
+
+   /* Notify the component */
+   if (port->priv->clock->event_cb && status == MMAL_SUCCESS)
+      port->priv->clock->event_cb(port, &event);
+
+   return status;
+}
+
+static MMAL_STATUS_T mmal_port_clock_parameter_get(MMAL_PORT_T *port, MMAL_PARAMETER_HEADER_T *param)
+{
+   MMAL_PORT_CLOCK_T *priv_clock = port->priv->clock;
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+
+   switch (param->id)
+   {
+      case MMAL_PARAMETER_CLOCK_REFERENCE:
+      {
+         MMAL_PARAMETER_BOOLEAN_T *p = (MMAL_PARAMETER_BOOLEAN_T*)param;
+         p->enable = priv_clock->is_reference;
+      }
+      break;
+      case MMAL_PARAMETER_CLOCK_ACTIVE:
+      {
+         MMAL_PARAMETER_BOOLEAN_T *p = (MMAL_PARAMETER_BOOLEAN_T*)param;
+         p->enable = mmal_clock_is_active(priv_clock->clock);
+      }
+      break;
+      case MMAL_PARAMETER_CLOCK_SCALE:
+      {
+         MMAL_PARAMETER_RATIONAL_T *p = (MMAL_PARAMETER_RATIONAL_T*)param;
+         p->value = mmal_clock_scale_get(priv_clock->clock);
+      }
+      break;
+      case MMAL_PARAMETER_CLOCK_TIME:
+      {
+         MMAL_PARAMETER_INT64_T *p = (MMAL_PARAMETER_INT64_T*)param;
+         p->value = mmal_clock_media_time_get(priv_clock->clock);
+      }
+      break;
+      case MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD:
+      {
+         MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD_T *p = (MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD_T *)param;
+         status = mmal_clock_update_threshold_get(priv_clock->clock, &p->value);
+      }
+      break;
+      case MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD:
+      {
+         MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD_T *p = (MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD_T *)param;
+         status = mmal_clock_discont_threshold_get(priv_clock->clock, &p->value);
+      }
+      break;
+      case MMAL_PARAMETER_CLOCK_REQUEST_THRESHOLD:
+      {
+         MMAL_PARAMETER_CLOCK_REQUEST_THRESHOLD_T *p = (MMAL_PARAMETER_CLOCK_REQUEST_THRESHOLD_T *)param;
+         status = mmal_clock_request_threshold_get(priv_clock->clock, &p->value);
+      }
+      break;
+      case MMAL_PARAMETER_CLOCK_ENABLE_BUFFER_INFO:
+      {
+         MMAL_PARAMETER_BOOLEAN_T *p = (MMAL_PARAMETER_BOOLEAN_T*)param;
+         p->enable = priv_clock->buffer_info_reporting;
+      }
+      break;
+      default:
+         LOG_ERROR("unsupported clock parameter 0x%x", param->id);
+         return MMAL_ENOSYS;
+   }
+
+   return status;
+}
+
+static MMAL_STATUS_T mmal_port_clock_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
+{
+   MMAL_PARAM_UNUSED(port);
+   MMAL_PARAM_UNUSED(cb);
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T mmal_port_clock_disable(MMAL_PORT_T *port)
+{
+   MMAL_PORT_CLOCK_T *priv_clock = port->priv->clock;
+
+   if (mmal_clock_is_active(priv_clock->clock))
+      mmal_clock_active_set(priv_clock->clock, MMAL_FALSE);
+
+   mmal_port_clock_flush(port);
+
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T mmal_port_clock_set_format(MMAL_PORT_T *port)
+{
+   MMAL_PARAM_UNUSED(port);
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T mmal_port_clock_connect(MMAL_PORT_T *port, MMAL_PORT_T *other_port)
+{
+   MMAL_PARAM_UNUSED(port);
+   MMAL_PARAM_UNUSED(other_port);
+   return MMAL_ENOSYS;
+}
+
+/* Send an event buffer to a connected port */
+static MMAL_STATUS_T mmal_port_clock_forward_event(MMAL_PORT_T *port, const MMAL_CLOCK_EVENT_T *event)
+{
+   MMAL_STATUS_T status;
+   MMAL_BUFFER_HEADER_T *buffer;
+
+   buffer = mmal_queue_get(port->priv->clock->queue);
+   if (!buffer)
+   {
+      LOG_INFO("%s: no free event buffers available for event %4.4s", port->name, (const char*)&event->id);
+      return MMAL_ENOSPC;
+   }
+
+   status = mmal_buffer_header_mem_lock(buffer);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("failed to lock buffer %s", mmal_status_to_string(status));
+      mmal_queue_put_back(port->priv->clock->queue, buffer);
+      goto end;
+   }
+   buffer->length = sizeof(MMAL_CLOCK_EVENT_T);
+   memcpy(buffer->data, event, buffer->length);
+   mmal_buffer_header_mem_unlock(buffer);
+
+   mmal_port_buffer_header_callback(port, buffer);
+
+end:
+   return status;
+}
+
+/* Send a clock active state to a connected port */
+static MMAL_STATUS_T mmal_port_clock_forward_active_state(MMAL_PORT_T *port, MMAL_BOOL_T active)
+{
+   MMAL_CLOCK_EVENT_T event;
+
+   event.id = MMAL_CLOCK_EVENT_ACTIVE;
+   event.magic = MMAL_CLOCK_EVENT_MAGIC;
+   event.data.enable = active;
+
+   return mmal_port_clock_forward_event(port, &event);
+}
+
+/* Send a clock scale update to a connected port */
+static MMAL_STATUS_T mmal_port_clock_forward_scale(MMAL_PORT_T *port, MMAL_RATIONAL_T scale)
+{
+   MMAL_CLOCK_EVENT_T event;
+
+   event.id = MMAL_CLOCK_EVENT_SCALE;
+   event.magic = MMAL_CLOCK_EVENT_MAGIC;
+   event.data.scale = scale;
+
+   return mmal_port_clock_forward_event(port, &event);
+}
+
+/* Send a clock time update to a connected port */
+static MMAL_STATUS_T mmal_port_clock_forward_media_time(MMAL_PORT_T *port, int64_t media_time)
+{
+   MMAL_CLOCK_EVENT_T event;
+
+   event.id = MMAL_CLOCK_EVENT_TIME;
+   event.magic = MMAL_CLOCK_EVENT_MAGIC;
+   event.data.media_time = media_time;
+
+   return mmal_port_clock_forward_event(port, &event);
+}
+
+/* Send a clock update threshold to a connected port */
+static MMAL_STATUS_T mmal_port_clock_forward_update_threshold(MMAL_PORT_T *port,
+      const MMAL_CLOCK_UPDATE_THRESHOLD_T *threshold)
+{
+   MMAL_CLOCK_EVENT_T event;
+
+   event.id = MMAL_CLOCK_EVENT_UPDATE_THRESHOLD;
+   event.magic = MMAL_CLOCK_EVENT_MAGIC;
+   event.data.update_threshold = *threshold;
+
+   return mmal_port_clock_forward_event(port, &event);
+}
+
+/* Send a clock discontinuity threshold to a connected port */
+static MMAL_STATUS_T mmal_port_clock_forward_discont_threshold(MMAL_PORT_T *port,
+      const MMAL_CLOCK_DISCONT_THRESHOLD_T *threshold)
+{
+   MMAL_CLOCK_EVENT_T event;
+
+   event.id = MMAL_CLOCK_EVENT_DISCONT_THRESHOLD;
+   event.magic = MMAL_CLOCK_EVENT_MAGIC;
+   event.data.discont_threshold = *threshold;
+
+   return mmal_port_clock_forward_event(port, &event);
+}
+
+/* Send a clock request threshold to a connected port */
+static MMAL_STATUS_T mmal_port_clock_forward_request_threshold(MMAL_PORT_T *port,
+      const MMAL_CLOCK_REQUEST_THRESHOLD_T *threshold)
+{
+   MMAL_CLOCK_EVENT_T event;
+
+   event.id = MMAL_CLOCK_EVENT_REQUEST_THRESHOLD;
+   event.magic = MMAL_CLOCK_EVENT_MAGIC;
+   event.data.request_threshold = *threshold;
+
+   return mmal_port_clock_forward_event(port, &event);
+}
+
+/* Send information regarding an input buffer to connected port */
+static MMAL_STATUS_T mmal_port_clock_forward_input_buffer_info(MMAL_PORT_T *port, const MMAL_CLOCK_BUFFER_INFO_T *info)
+{
+   MMAL_CLOCK_EVENT_T event;
+
+   event.id = MMAL_CLOCK_EVENT_INPUT_BUFFER_INFO;
+   event.magic = MMAL_CLOCK_EVENT_MAGIC;
+   event.data.buffer = *info;
+
+   return mmal_port_clock_forward_event(port, &event);
+}
+
+/* Send information regarding an output buffer to connected port */
+static MMAL_STATUS_T mmal_port_clock_forward_output_buffer_info(MMAL_PORT_T *port, const MMAL_CLOCK_BUFFER_INFO_T *info)
+{
+   MMAL_CLOCK_EVENT_T event;
+
+   event.id = MMAL_CLOCK_EVENT_OUTPUT_BUFFER_INFO;
+   event.magic = MMAL_CLOCK_EVENT_MAGIC;
+   event.data.buffer = *info;
+
+   return mmal_port_clock_forward_event(port, &event);
+}
+
+/* Initialise all callbacks and setup internal resources */
+static MMAL_STATUS_T mmal_port_clock_setup(MMAL_PORT_T *port, unsigned int extra_size,
+                                           MMAL_PORT_CLOCK_EVENT_CB event_cb)
+{
+   MMAL_STATUS_T status;
+
+   port->priv->clock = (MMAL_PORT_CLOCK_T*)((char*)(port->priv->module) + extra_size);
+
+   status = mmal_clock_create(&port->priv->clock->clock);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("failed to create clock module on port %s (%s)",
+                port->name, mmal_status_to_string(status));
+      return status;
+   }
+   port->priv->clock->clock->user_data = port;
+
+   port->buffer_size = sizeof(MMAL_CLOCK_EVENT_T);
+   port->buffer_size_min = sizeof(MMAL_CLOCK_EVENT_T);
+   port->buffer_num_min = MMAL_PORT_CLOCK_BUFFERS_MIN;
+   port->buffer_num_recommended = MMAL_PORT_CLOCK_BUFFERS_MIN;
+
+   port->priv->clock->event_cb = event_cb;
+   port->priv->clock->queue = mmal_queue_create();
+   if (!port->priv->clock->queue)
+   {
+      mmal_clock_destroy(port->priv->clock->clock);
+      return MMAL_ENOMEM;
+   }
+
+   port->priv->pf_set_format = mmal_port_clock_set_format;
+   port->priv->pf_enable = mmal_port_clock_enable;
+   port->priv->pf_disable = mmal_port_clock_disable;
+   port->priv->pf_send = mmal_port_clock_send;
+   port->priv->pf_flush = mmal_port_clock_flush;
+   port->priv->pf_parameter_set = mmal_port_clock_parameter_set;
+   port->priv->pf_parameter_get = mmal_port_clock_parameter_get;
+   port->priv->pf_connect = mmal_port_clock_connect;
+#ifdef __VIDEOCORE__
+   port->priv->pf_payload_alloc = mmal_port_clock_payload_alloc;
+   port->priv->pf_payload_free = mmal_port_clock_payload_free;
+   port->capabilities = MMAL_PORT_CAPABILITY_ALLOCATION;
+#endif
+
+   return status;
+}
+
+/* Release all internal resources */
+static void mmal_port_clock_teardown(MMAL_PORT_T *port)
+{
+   if (!port)
+      return;
+   mmal_queue_destroy(port->priv->clock->queue);
+   mmal_clock_destroy(port->priv->clock->clock);
+}
+
+/*****************************************************************************
+ * Public functions
+ *****************************************************************************/
+/* Allocate a clock port */
+MMAL_PORT_T* mmal_port_clock_alloc(MMAL_COMPONENT_T *component, unsigned int extra_size,
+                                   MMAL_PORT_CLOCK_EVENT_CB event_cb)
+{
+   MMAL_PORT_T *port;
+
+   port = mmal_port_alloc(component, MMAL_PORT_TYPE_CLOCK,
+                          extra_size + sizeof(MMAL_PORT_CLOCK_T));
+   if (!port)
+      return NULL;
+
+   if (mmal_port_clock_setup(port, extra_size, event_cb) != MMAL_SUCCESS)
+   {
+      mmal_port_free(port);
+      return NULL;
+   }
+
+   return port;
+}
+
+/* Free a clock port */
+void mmal_port_clock_free(MMAL_PORT_T *port)
+{
+   mmal_port_clock_teardown(port);
+   mmal_port_free(port);
+}
+
+/* Allocate an array of clock ports */
+MMAL_PORT_T **mmal_ports_clock_alloc(MMAL_COMPONENT_T *component, unsigned int ports_num,
+                                     unsigned int extra_size, MMAL_PORT_CLOCK_EVENT_CB event_cb)
+{
+   unsigned int i;
+   MMAL_PORT_T **ports;
+
+   ports = mmal_ports_alloc(component, ports_num, MMAL_PORT_TYPE_CLOCK,
+                            extra_size + sizeof(MMAL_PORT_CLOCK_T));
+   if (!ports)
+      return NULL;
+
+   for (i = 0; i < ports_num; i++)
+   {
+      if (mmal_port_clock_setup(ports[i], extra_size, event_cb) != MMAL_SUCCESS)
+         break;
+   }
+
+   if (i != ports_num)
+   {
+      for (ports_num = i, i = 0; i < ports_num; i++)
+         mmal_port_clock_free(ports[i]);
+      vcos_free(ports);
+      return NULL;
+   }
+
+   return ports;
+}
+
+/* Free an array of clock ports */
+void mmal_ports_clock_free(MMAL_PORT_T **ports, unsigned int ports_num)
+{
+   unsigned int i;
+
+   for (i = 0; i < ports_num; i++)
+      mmal_port_clock_free(ports[i]);
+   vcos_free(ports);
+}
+
+/* Register a callback request */
+MMAL_STATUS_T mmal_port_clock_request_add(MMAL_PORT_T *port, int64_t media_time,
+      MMAL_PORT_CLOCK_REQUEST_CB cb, void *cb_data)
+{
+   return mmal_clock_request_add(port->priv->clock->clock, media_time,
+                                 mmal_port_clock_request_cb, cb_data, (MMAL_CLOCK_VOID_FP)cb);
+}
+
+/* Flush all pending clock requests */
+MMAL_STATUS_T mmal_port_clock_request_flush(MMAL_PORT_T *port)
+{
+   return mmal_clock_request_flush(port->priv->clock->clock);
+}
+
+/* Set the clock port's reference state */
+MMAL_STATUS_T mmal_port_clock_reference_set(MMAL_PORT_T *port, MMAL_BOOL_T reference)
+{
+   port->priv->clock->is_reference = reference;
+   return MMAL_SUCCESS;
+}
+
+/* Get the clock port's reference state */
+MMAL_BOOL_T mmal_port_clock_reference_get(MMAL_PORT_T *port)
+{
+   return port->priv->clock->is_reference;
+}
+
+/* Set the clock port's active state */
+MMAL_STATUS_T mmal_port_clock_active_set(MMAL_PORT_T *port, MMAL_BOOL_T active)
+{
+   MMAL_STATUS_T status;
+
+   status = mmal_clock_active_set(port->priv->clock->clock, active);
+   if (status != MMAL_SUCCESS)
+      return status;
+
+   if (port->priv->clock->is_reference)
+      status = mmal_port_clock_forward_active_state(port, active);
+
+   return status;
+}
+
+/* Get the clock port's active state */
+MMAL_BOOL_T mmal_port_clock_active_get(MMAL_PORT_T *port)
+{
+   return mmal_clock_is_active(port->priv->clock->clock);
+}
+
+/* Set the clock port's scale */
+MMAL_STATUS_T mmal_port_clock_scale_set(MMAL_PORT_T *port, MMAL_RATIONAL_T scale)
+{
+   MMAL_STATUS_T status;
+
+   status = mmal_clock_scale_set(port->priv->clock->clock, scale);
+   if (status != MMAL_SUCCESS)
+      return status;
+
+   if (port->priv->clock->is_reference)
+      status = mmal_port_clock_forward_scale(port, scale);
+
+   return status;
+}
+
+/* Get the clock port's scale */
+MMAL_RATIONAL_T mmal_port_clock_scale_get(MMAL_PORT_T *port)
+{
+   return mmal_clock_scale_get(port->priv->clock->clock);
+}
+
+/* Set the clock port's media-time */
+MMAL_STATUS_T mmal_port_clock_media_time_set(MMAL_PORT_T *port, int64_t media_time)
+{
+   MMAL_STATUS_T status;
+
+   status = mmal_clock_media_time_set(port->priv->clock->clock, media_time);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_DEBUG("clock media-time update ignored");
+      return status;
+   }
+
+   if (port->priv->clock->is_reference)
+      status = mmal_port_clock_forward_media_time(port, media_time);
+
+   return status;
+}
+
+/* Get the clock port's media-time */
+int64_t mmal_port_clock_media_time_get(MMAL_PORT_T *port)
+{
+   return mmal_clock_media_time_get(port->priv->clock->clock);
+}
+
+/* Set the clock port's update threshold */
+MMAL_STATUS_T mmal_port_clock_update_threshold_set(MMAL_PORT_T *port,
+                                                   const MMAL_CLOCK_UPDATE_THRESHOLD_T *threshold)
+{
+   MMAL_STATUS_T status;
+
+   status = mmal_clock_update_threshold_set(port->priv->clock->clock, threshold);
+   if (status != MMAL_SUCCESS)
+      return status;
+
+   if (port->priv->clock->is_reference)
+      status = mmal_port_clock_forward_update_threshold(port, threshold);
+
+   return status;
+}
+
+/* Get the clock port's update threshold */
+MMAL_STATUS_T mmal_port_clock_update_threshold_get(MMAL_PORT_T *port,
+                                          MMAL_CLOCK_UPDATE_THRESHOLD_T *threshold)
+{
+   return mmal_clock_update_threshold_get(port->priv->clock->clock, threshold);
+}
+
+/* Set the clock port's discontinuity threshold */
+MMAL_STATUS_T mmal_port_clock_discont_threshold_set(MMAL_PORT_T *port,
+                                                    const MMAL_CLOCK_DISCONT_THRESHOLD_T *threshold)
+{
+   MMAL_STATUS_T status;
+
+   status = mmal_clock_discont_threshold_set(port->priv->clock->clock, threshold);
+   if (status != MMAL_SUCCESS)
+      return status;
+
+   if (port->priv->clock->is_reference)
+      status = mmal_port_clock_forward_discont_threshold(port, threshold);
+
+   return status;
+}
+
+/* Get the clock port's discontinuity threshold */
+MMAL_STATUS_T mmal_port_clock_discont_threshold_get(MMAL_PORT_T *port,
+                                           MMAL_CLOCK_DISCONT_THRESHOLD_T *threshold)
+{
+   return mmal_clock_discont_threshold_get(port->priv->clock->clock, threshold);
+}
+
+/* Set the clock port's request threshold */
+MMAL_STATUS_T mmal_port_clock_request_threshold_set(MMAL_PORT_T *port,
+                                                    const MMAL_CLOCK_REQUEST_THRESHOLD_T *threshold)
+{
+   MMAL_STATUS_T status;
+
+   status = mmal_clock_request_threshold_set(port->priv->clock->clock, threshold);
+   if (status != MMAL_SUCCESS)
+      return status;
+
+   if (port->priv->clock->is_reference)
+      status = mmal_port_clock_forward_request_threshold(port, threshold);
+
+   return status;
+}
+
+/* Get the clock port's request threshold */
+MMAL_STATUS_T mmal_port_clock_request_threshold_get(MMAL_PORT_T *port,
+                                           MMAL_CLOCK_REQUEST_THRESHOLD_T *threshold)
+{
+   return mmal_clock_request_threshold_get(port->priv->clock->clock, threshold);
+}
+
+/* Provide input buffer information */
+void mmal_port_clock_input_buffer_info(MMAL_PORT_T *port, const MMAL_CLOCK_BUFFER_INFO_T *info)
+{
+   if (port->priv->clock->buffer_info_reporting)
+      mmal_port_clock_forward_input_buffer_info(port, info);
+}
+
+/* Provide output buffer information */
+void mmal_port_clock_output_buffer_info(MMAL_PORT_T *port, const MMAL_CLOCK_BUFFER_INFO_T *info)
+{
+   if (port->priv->clock->buffer_info_reporting)
+      mmal_port_clock_forward_output_buffer_info(port, info);
+}
+
diff --git a/interface/mmal/core/mmal_port_private.h b/interface/mmal/core/mmal_port_private.h
new file mode 100755 (executable)
index 0000000..1e538c5
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_PORT_PRIVATE_H
+#define MMAL_PORT_PRIVATE_H
+
+#include "interface/mmal/mmal.h"
+#include "interface/mmal/mmal_clock.h"
+#include "interface/mmal/core/mmal_events_private.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Definition of a port. */
+typedef struct MMAL_PORT_PRIVATE_T
+{
+   /** Pointer to the private data of the core */
+   struct MMAL_PORT_PRIVATE_CORE_T *core;
+   /** Pointer to the private data of the module in use */
+   struct MMAL_PORT_MODULE_T *module;
+   /** Pointer to the private data used by clock ports */
+   struct MMAL_PORT_CLOCK_T *clock;
+
+   MMAL_STATUS_T (*pf_set_format)(MMAL_PORT_T *port);
+   MMAL_STATUS_T (*pf_enable)(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T);
+   MMAL_STATUS_T (*pf_disable)(MMAL_PORT_T *port);
+   MMAL_STATUS_T (*pf_send)(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *);
+   MMAL_STATUS_T (*pf_flush)(MMAL_PORT_T *port);
+   MMAL_STATUS_T (*pf_parameter_set)(MMAL_PORT_T *port, const MMAL_PARAMETER_HEADER_T *param);
+   MMAL_STATUS_T (*pf_parameter_get)(MMAL_PORT_T *port, MMAL_PARAMETER_HEADER_T *param);
+   MMAL_STATUS_T (*pf_connect)(MMAL_PORT_T *port, MMAL_PORT_T *other_port);
+
+   uint8_t *(*pf_payload_alloc)(MMAL_PORT_T *port, uint32_t payload_size);
+   void     (*pf_payload_free)(MMAL_PORT_T *port, uint8_t *payload);
+
+} MMAL_PORT_PRIVATE_T;
+
+/** Callback called by components when a \ref MMAL_BUFFER_HEADER_T needs to be sent back to the
+ * user */
+void mmal_port_buffer_header_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
+
+/** Callback called by components when an event \ref MMAL_BUFFER_HEADER_T needs to be sent to the
+ * user. Events differ from ordinary buffer headers because they originate from the component
+ * and do not return data from the client to the component. */
+void mmal_port_event_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
+
+/** Allocate a port structure */
+MMAL_PORT_T *mmal_port_alloc(MMAL_COMPONENT_T *, MMAL_PORT_TYPE_T type, unsigned int extra_size);
+/** Free a port structure */
+void mmal_port_free(MMAL_PORT_T *port);
+/** Allocate an array of ports */
+MMAL_PORT_T **mmal_ports_alloc(MMAL_COMPONENT_T *, unsigned int ports_num, MMAL_PORT_TYPE_T type,
+                               unsigned int extra_size);
+/** Free an array of ports */
+void mmal_ports_free(MMAL_PORT_T **ports, unsigned int ports_num);
+
+/** Acquire a reference on a port */
+void mmal_port_acquire(MMAL_PORT_T *port);
+
+/** Release a reference on a port */
+MMAL_STATUS_T mmal_port_release(MMAL_PORT_T *port);
+
+/** Pause processing on a port */
+MMAL_STATUS_T mmal_port_pause(MMAL_PORT_T *port, MMAL_BOOL_T pause);
+
+/** Returns whether a port is connected or not */
+MMAL_BOOL_T mmal_port_is_connected(MMAL_PORT_T *port);
+
+/*****************************************************************************
+ * Clock Port API
+ *****************************************************************************/
+/** Definition of a clock port event callback.
+ * Used to inform the client of a clock event that has occurred.
+ *
+ * @param port       The clock port where the event occurred
+ * @param event      The event that has occurred
+ */
+typedef void (*MMAL_PORT_CLOCK_EVENT_CB)(MMAL_PORT_T *port, const MMAL_CLOCK_EVENT_T *event);
+
+/** Allocate a clock port.
+ *
+ * @param component  The component requesting the alloc
+ * @param extra_size Size of the port module
+ * @param event_cb   Clock event callback
+ *
+ * @return Pointer to new clock port or NULL on failure.
+ */
+MMAL_PORT_T* mmal_port_clock_alloc(MMAL_COMPONENT_T *component, unsigned int extra_size,
+                                   MMAL_PORT_CLOCK_EVENT_CB event_cb);
+
+/** Free a clock port.
+ *
+ * @param port       The clock port to free
+ */
+void mmal_port_clock_free(MMAL_PORT_T *port);
+
+/** Allocate an array of clock ports.
+ *
+ * @param component  The component requesting the alloc
+ * @param ports_num  Number of ports to allocate
+ * @param extra_size Size of the port module
+ * @param event_cb   Clock event callback
+ *
+ * @return Pointer to a new array of clock ports or NULL on failure.
+ */
+MMAL_PORT_T **mmal_ports_clock_alloc(MMAL_COMPONENT_T *component, unsigned int ports_num,
+                                     unsigned int extra_size, MMAL_PORT_CLOCK_EVENT_CB event_cb);
+
+/** Free an array of clock ports.
+ *
+ * @param ports      The clock ports to free
+ * @param ports_num  Number of ports to free
+ */
+void mmal_ports_clock_free(MMAL_PORT_T **ports, unsigned int ports_num);
+
+/** Definition of a clock port request callback.
+ * This is invoked when the media-time requested by the client is reached.
+ *
+ * @param port       The clock port which serviced the request
+ * @param media_time The current media-time
+ * @param cb_data    Client-supplied data
+ */
+typedef void (*MMAL_PORT_CLOCK_REQUEST_CB)(MMAL_PORT_T *port, int64_t media_time, void *cb_data);
+
+/** Register a request with the clock port.
+ * When the specified media-time is reached, the clock port will invoke the supplied callback.
+ *
+ * @param port       The clock port
+ * @param media_time The media-time at which the callback should be invoked (microseconds)
+ * @param cb         Callback to invoke
+ * @param cb_data    Client-supplied callback data
+ *
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_port_clock_request_add(MMAL_PORT_T *port, int64_t media_time,
+                                          MMAL_PORT_CLOCK_REQUEST_CB cb, void *cb_data);
+
+/** Remove all previously registered clock port requests.
+ *
+ * @param port       The clock port
+ *
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_port_clock_request_flush(MMAL_PORT_T *port);
+
+/** Get/set the clock port's reference state */
+MMAL_STATUS_T mmal_port_clock_reference_set(MMAL_PORT_T *port, MMAL_BOOL_T reference);
+MMAL_BOOL_T mmal_port_clock_reference_get(MMAL_PORT_T *port);
+
+/** Get/set the clock port's active state */
+MMAL_STATUS_T mmal_port_clock_active_set(MMAL_PORT_T *port, MMAL_BOOL_T active);
+MMAL_BOOL_T mmal_port_clock_active_get(MMAL_PORT_T *port);
+
+/** Get/set the clock port's scale */
+MMAL_STATUS_T mmal_port_clock_scale_set(MMAL_PORT_T *port, MMAL_RATIONAL_T scale);
+MMAL_RATIONAL_T mmal_port_clock_scale_get(MMAL_PORT_T *port);
+
+/** Get/set the clock port's media-time */
+MMAL_STATUS_T mmal_port_clock_media_time_set(MMAL_PORT_T *port, int64_t media_time);
+int64_t mmal_port_clock_media_time_get(MMAL_PORT_T *port);
+
+/** Get/set the clock port's update threshold */
+MMAL_STATUS_T mmal_port_clock_update_threshold_set(MMAL_PORT_T *port,
+                                                   const MMAL_CLOCK_UPDATE_THRESHOLD_T *threshold);
+MMAL_STATUS_T mmal_port_clock_update_threshold_get(MMAL_PORT_T *port,
+                                                   MMAL_CLOCK_UPDATE_THRESHOLD_T *threshold);
+
+/** Get/set the clock port's discontinuity threshold */
+MMAL_STATUS_T mmal_port_clock_discont_threshold_set(MMAL_PORT_T *port,
+                                                    const MMAL_CLOCK_DISCONT_THRESHOLD_T *threshold);
+MMAL_STATUS_T mmal_port_clock_discont_threshold_get(MMAL_PORT_T *port,
+                                                    MMAL_CLOCK_DISCONT_THRESHOLD_T *threshold);
+
+/** Get/set the clock port's request threshold */
+MMAL_STATUS_T mmal_port_clock_request_threshold_set(MMAL_PORT_T *port,
+                                                    const MMAL_CLOCK_REQUEST_THRESHOLD_T *threshold);
+MMAL_STATUS_T mmal_port_clock_request_threshold_get(MMAL_PORT_T *port,
+                                                    MMAL_CLOCK_REQUEST_THRESHOLD_T *threshold);
+
+/** Provide information regarding a buffer received on the component's input/output port */
+void mmal_port_clock_input_buffer_info(MMAL_PORT_T *port, const MMAL_CLOCK_BUFFER_INFO_T *info);
+void mmal_port_clock_output_buffer_info(MMAL_PORT_T *port, const MMAL_CLOCK_BUFFER_INFO_T *info);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MMAL_PORT_PRIVATE_H */
diff --git a/interface/mmal/core/mmal_queue.c b/interface/mmal/core/mmal_queue.c
new file mode 100755 (executable)
index 0000000..d58b28a
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "mmal_queue.h"
+
+/** Definition of the QUEUE */
+struct MMAL_QUEUE_T
+{
+   VCOS_MUTEX_T lock;
+   unsigned int length;
+   MMAL_BUFFER_HEADER_T *first;
+   MMAL_BUFFER_HEADER_T **last;
+   VCOS_SEMAPHORE_T semaphore;
+};
+
+// Only sanity check if asserts are enabled
+#if VCOS_ASSERT_ENABLED
+static void mmal_queue_sanity_check(MMAL_QUEUE_T *queue, MMAL_BUFFER_HEADER_T *buffer)
+{
+  MMAL_BUFFER_HEADER_T *q;
+  int len = 0;
+  for (q = queue->first; q && len<queue->length; q = q->next)
+  {
+    vcos_assert(buffer != q);
+    len++;
+  }
+  vcos_assert(len == queue->length && !q);
+}
+#else
+#define mmal_queue_sanity_check(q,b)
+#endif
+
+/** Create a QUEUE of MMAL_BUFFER_HEADER_T */
+MMAL_QUEUE_T *mmal_queue_create(void)
+{
+   MMAL_QUEUE_T *queue;
+
+   queue = vcos_malloc(sizeof(*queue), "MMAL queue");
+   if(!queue) return 0;
+
+   if(vcos_mutex_create(&queue->lock, "MMAL queue lock") != VCOS_SUCCESS )
+   {
+      vcos_free(queue);
+      return 0;
+   }
+
+   if(vcos_semaphore_create(&queue->semaphore, "MMAL queue sema", 0) != VCOS_SUCCESS )
+   {
+      vcos_mutex_delete(&queue->lock);
+      vcos_free(queue);
+      return 0;
+   }
+
+   /* gratuitous lock for coverity */ vcos_mutex_lock(&queue->lock);
+   queue->length = 0;
+   queue->first = 0;
+   queue->last = &queue->first;
+   mmal_queue_sanity_check(queue, NULL);
+   /* gratuitous unlock for coverity */ vcos_mutex_unlock(&queue->lock);
+
+   return queue;
+}
+
+/** Put a MMAL_BUFFER_HEADER_T into a QUEUE */
+void mmal_queue_put(MMAL_QUEUE_T *queue, MMAL_BUFFER_HEADER_T *buffer)
+{
+   vcos_assert(queue && buffer);
+   if(!queue || !buffer) return;
+
+   vcos_mutex_lock(&queue->lock);
+   mmal_queue_sanity_check(queue, buffer);
+   queue->length++;
+   *queue->last = buffer;
+   buffer->next = 0;
+   queue->last = &buffer->next;
+   // There is a possible advantage to putting the semaphore_post outside
+   // the lock as that would avoid the case where we set the semaphore, causing
+   // a task switch to a waiting get thread which then blocks because we still
+   // have the lock.  However this allows a race condition if we have (legit) code
+   // of the (simplified) form:
+   // if (mmal_queue_length(q) > 0) b = mmal_queue_get(q);
+   // where the _get should always succeed
+   // This has an easy fix if we have a fn that returns the count in a semaphore
+   // but by not all OSs support that (e.g. Win32)
+   vcos_semaphore_post(&queue->semaphore);
+   vcos_mutex_unlock(&queue->lock);
+}
+
+/** Put a MMAL_BUFFER_HEADER_T back at the start of a QUEUE. */
+void mmal_queue_put_back(MMAL_QUEUE_T *queue, MMAL_BUFFER_HEADER_T *buffer)
+{
+   if(!queue || !buffer) return;
+
+   vcos_mutex_lock(&queue->lock);
+   mmal_queue_sanity_check(queue, buffer);
+   queue->length++;
+   buffer->next = queue->first;
+   queue->first = buffer;
+   if(queue->last == &queue->first) queue->last = &buffer->next;
+   vcos_semaphore_post(&queue->semaphore);
+   vcos_mutex_unlock(&queue->lock);
+}
+
+
+/** Get a MMAL_BUFFER_HEADER_T from a QUEUE. Semaphore already claimed */
+static MMAL_BUFFER_HEADER_T *mmal_queue_get_core(MMAL_QUEUE_T *queue)
+{
+   MMAL_BUFFER_HEADER_T * buffer;
+
+   vcos_mutex_lock(&queue->lock);
+   mmal_queue_sanity_check(queue, NULL);
+   buffer = queue->first;
+   vcos_assert(buffer != NULL);
+
+   queue->first = buffer->next;
+   if(!queue->first) queue->last = &queue->first;
+
+   queue->length--;
+   vcos_mutex_unlock(&queue->lock);
+
+   return buffer;
+}
+
+/** Get a MMAL_BUFFER_HEADER_T from a QUEUE. */
+MMAL_BUFFER_HEADER_T *mmal_queue_get(MMAL_QUEUE_T *queue)
+{
+   vcos_assert(queue);
+   if(!queue) return 0;
+
+   if(vcos_semaphore_trywait(&queue->semaphore) != VCOS_SUCCESS)
+       return NULL;
+
+   return mmal_queue_get_core(queue);
+}
+
+/** Wait for a MMAL_BUFFER_HEADER_T from a QUEUE. */
+MMAL_BUFFER_HEADER_T *mmal_queue_wait(MMAL_QUEUE_T *queue)
+{
+       if(!queue) return 0;
+
+   if (vcos_semaphore_wait(&queue->semaphore) != VCOS_SUCCESS)
+       return NULL;
+
+   return mmal_queue_get_core(queue);
+}
+
+MMAL_BUFFER_HEADER_T *mmal_queue_timedwait(MMAL_QUEUE_T *queue, VCOS_UNSIGNED timeout)
+{
+    if (!queue)
+        return NULL;
+
+    if (vcos_semaphore_wait_timeout(&queue->semaphore, timeout) != VCOS_SUCCESS)
+        return NULL;
+
+    return mmal_queue_get_core(queue);
+}
+
+/** Get the number of MMAL_BUFFER_HEADER_T currently in a QUEUE */
+unsigned int mmal_queue_length(MMAL_QUEUE_T *queue)
+{
+       if(!queue) return 0;
+
+       return queue->length;
+}
+
+/** Destroy a queue of MMAL_BUFFER_HEADER_T */
+void mmal_queue_destroy(MMAL_QUEUE_T *queue)
+{
+   if(!queue) return;
+   vcos_mutex_delete(&queue->lock);
+   vcos_semaphore_delete(&queue->semaphore);
+   vcos_free(queue);
+}
diff --git a/interface/mmal/mmal.h b/interface/mmal/mmal.h
new file mode 100755 (executable)
index 0000000..d3dab07
--- /dev/null
@@ -0,0 +1,390 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file
+ * Multi-Media Abstraction Layer API
+ */
+
+#ifndef MMAL_H
+#define MMAL_H
+
+/**
+  *
+  * \mainpage Multi-Media Abstraction Layer (MMAL). Draft Version 0.1.
+  *
+  * \par Contents
+  * - \ref intro_sec
+  * - \ref features
+  * - \ref concepts
+  * - \ref comp
+  * - \ref create
+  * - \ref port
+  * - \ref buf
+  * - \ref metadata
+  * - \ref queue
+  * - \ref pool
+  * - \ref param
+  * - \ref events
+  * - \ref version
+  * - \ref example
+  *
+  * \section intro_sec Introduction
+  *
+  * MMAL (Multi-Media Abstraction Layer) is a framework which is used to provide a host-side,
+  * simple and relatively low-level interface to multimedia components running on VideoCore.
+  * It also provides a component interface so that new components can be easily created and
+  * integrated into the framework.
+  *
+  * There is no requirement that all the components be running on VideoCore as MMAL doesn't
+  * put any restriction on where components live. The current implementation for instance
+  * provides some components which can be run on both host-side or VideoCore (e.g. the splitter
+  * component).
+  *
+  * \section features Features
+  *
+  * The MMAL API has been designed to support all the following features:
+  * - Sufficiently generic to support different kinds of multimedia component.
+  * - Simple to use from client side (mostly synchronous except where it matters).
+  * - Straightforward API for designing components (e.g. avoids multiple data paths, as found in RIL).
+  * - Allows for fully-optimised implementation of components (e.g. zero-copy buffer passing).
+  * - Portability (API is self-contained).
+  * - Supports multiple instances (e.g. of VideoCore).
+  * - Extensible without breaking source or binary backward compatibility.
+  *
+  * \section concepts API concepts
+  *
+  * The MMAL API is based on the concept of components, ports and buffer headers.
+  * Clients create MMAL components which expose ports for each individual
+  * elementary stream of data they support (e.g. audio/video). Components expose
+  * input ports to receive data from the client, and expose output ports
+  * to return data to the client.
+  *
+  * Data sent to or received from the component needs to be attached to a buffer header.
+  * Buffer headers are necessary because they contain buffer specific ancillary data which is
+  * necessary for the component and client to do their processing (e.g timestamps).
+  *
+  * \section comp Components
+  *
+  * MMAL lets clients create multi-media components (video encoders,
+  * video decoders, camera, and so-on) using a common API. Clients exchange
+  * data with components using buffer headers. A buffer header
+  * has a pointer to the payload data and optional metadata.
+  * Buffer headers are sent to and received from ports that are provided by components.
+  *
+  * A typical decoder component would have a single input port and a
+  * single output port, but the same architecture could also be used
+  * for components with different layouts (e.g. a camera with a
+  * capture and preview port, or a debugging component with just an input port).
+  *
+  * \subsection create Component Creation
+  *
+  * Each component is identified by a unique name. To create a specific component
+  * the client needs to call \ref mmal_component_create with the desired component's
+  * name as an argument.
+  * This call will return a context (\ref MMAL_COMPONENT_T) to the component. This
+  * context will expose the input and output ports (\ref MMAL_PORT_T) supported
+  * by this specific component.
+  *
+  * \note All VideoCore components have a name starting with the "vc." prefix (this prefix
+  * is used to distinguish when a creation request needs to be forwarded to VideoCore).
+  *
+  * \section port Component Ports
+  *
+  * A port (\ref MMAL_PORT_T) is the entity which exposes an elementary stream
+  * (\ref MMAL_ES_FORMAT_T) on a component. It is also the entity to which buffer headers
+  * (\ref MMAL_BUFFER_HEADER_T) are sent or from which they are received.
+  *
+  * Clients do not need to create ports. They are created automatically by
+  * the component when this one is created but the format of a port might need to
+  * be set by the client depending on the type of component the client is using.
+  *
+  * For example, for a video decoding component, one input port and one output port
+  * will be available. The format of the input port must be set by the
+  * client (using \ref mmal_port_format_commit) while the format of the output port
+  * will be automatically set by the component once the component has enough information
+  * to find out what its format should be.
+  *
+  * If the input port format contains enough information for the component to determine
+  * the format of the output port straight away, then the output port will be set to the proper
+  * format when \ref mmal_port_format_commit returns. Otherwise the output format will be set to
+  * \ref MMAL_ENCODING_UNKNOWN until the component is fed enough data to determine the format
+  * of the output port.
+  * When this happens, the client will receive an event on the output port, signalling
+  * that its format has changed.
+  *
+  * \section buf Buffer Headers
+  *
+  * Buffer headers (\ref MMAL_BUFFER_HEADER_T) are used to exchange data with components.
+  * They do not contain the data directly but instead contain a pointer to the data being
+  * transferred.
+  *
+  * Separating the buffer headers from the payload means that the memory for the data can
+  * be allocated outside of MMAL (e.g. if it is supplied by an external library) while still
+  * providing a consistent way to exchange data between clients and components.
+  *
+  * Buffer headers are allocated from pools and are reference counted. The refcount
+  * will drop when \ref mmal_buffer_header_release is called and the buffer header
+  * will be recycled to its pool when it reaches zero.
+  * The client can be notified when the buffer header is recycled so that it can recycle the
+  * associated payload memory as well.
+  *
+  * A pool of buffer headers should be created after committing the format of the port. When
+  * the format is changed, the minimum and recommended size and number of buffers may change.
+  *
+  * \note The current number of buffers and their size (\ref MMAL_PORT_T::buffer_num and \ref
+  * MMAL_PORT_T::buffer_size) are not modified by MMAL, and must be updated by the client as
+  * required after changes to a port's format.
+  *
+  * \subsection metadata Buffer Metadata
+  *
+  * The API provides a way for clients or components to associate metadata with buffer headers.
+  * A camera component could for example store information like exposure time or focal length
+  * as metadata within the buffer header containing the frame just captured.
+  * \note This area needs more work
+  *
+  * \subsection queue Queues of Buffer Headers
+  *
+  * Queues (\ref MMAL_QUEUE_T) are a facility that allows thread-safe processing of buffer headers
+  * from the client. Callbacks triggered by a MMAL component when it sends a buffer header to the
+  * client can simply put the buffer in a queue and let the main processing thread of the client
+  * get its data from the queue.
+  *
+  * \subsection pool Pools of Buffer Headers
+  *
+  * Pools (\ref MMAL_POOL_T) let clients allocate a fixed number of buffer headers, and 
+  * a queue (\ref MMAL_QUEUE_T). They are used for buffer header allocation.
+  * Optionally a pool can also allocate the payload memory for the client.
+  *
+  * Pools can also be resized after creation, for example, if the port format is changed leading
+  * to a new number or size of buffers being required.
+  *
+  * \section param Port Parameters
+  *
+  * Components support setting and getting component specific parameters using
+  * \ref mmal_port_parameter_set and \ref mmal_port_parameter_get. Parameters
+  * are identified using an integer index; parameter data is binary. See the \ref MMAL_PARAMETER_IDS
+  * "Pre-defined MMAL parameter IDs" page for more information on the pre-defined parameters.
+  *
+  * \section events Port Events
+  *
+  * Components can generate events on their ports. Events are sent to clients
+  * as buffer headers and thus when the client receives a buffer header on one
+  * of the component's port it should check if the buffer header is an event
+  * and in which case process it and then release it (\ref mmal_buffer_header_release).
+  * The reason for transmitting events in-band with the actual data is that it
+  * is often very valuable to know exactly when the event happens relative to the
+  * the actual data (e.g. with a focus event, from which video frame are we in focus).\n
+  * Buffer headers used to transmit events are allocated internally by the framework
+  * so it is important to release the buffer headers with \ref mmal_buffer_header_release
+  * so the buffer headers make it back to their actual owner.
+  *
+  * Event buffer headers are allocated when the component is created, based on the
+  * minimum number and size of control port buffers set by the component. Component
+  * wide events (not port specific) are sent to the control port callback when that
+  * port is enabled. Port events are sent to the port callback, the same as data
+  * buffers, but the 'cmd' field is non-zero.
+  *
+  * \section version Versioning
+  *
+  * The API requires that the MMAL core be the same or more recent version
+  * as the components and clients. Clients and components can be older and
+  * the API will still work both at compile-time and run-time.
+  *
+  * \section example Example Code
+  *
+  * The following code is a simple example on how to do video decoding using MMAL. Note that
+  * the code is intended to be clear and illustrate how to use MMAL at its most fundamental
+  * level, not necessarily the most efficient way to achieve the same result. Use of opaque
+  * images, tunneling and zero-copy inter-processor buffers can all improve the performance
+  * or reduce the load.
+  *
+  * The \ref MmalConnectionUtility "Port Connection Utility" functions can also be used to
+  * replace much of the common "boilerplate" code, especially when a pipeline of several
+  * components needs to be processed.
+  *
+  * \code
+  * #include <mmal.h>
+  * ...
+  * static void input_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+  * {
+  *    // The decoder is done with the data, just recycle the buffer header into its pool
+  *    mmal_buffer_header_release(buffer);
+  * }
+  * static void output_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+  * {
+  *    MMAL_QUEUE_T *queue = (MMAL_QUEUE_T *)port->userdata;
+  *    mmal_queue_put(queue, buffer); // Queue the decoded video frame
+  * }
+  * ...
+  *
+  * MMAL_COMPONENT_T *decoder = 0;
+  * MMAL_STATUS_T status;
+  *
+  * // Create the video decoder component on VideoCore
+  * status = mmal_component_create("vc.ril.video_decoder", &decoder);
+  * ABORT_IF_ERROR(status);
+  *
+  * // Set format of video decoder input port
+  * MMAL_ES_FORMAT_T *format_in = decoder->input[0]->format;
+  * format_in->type = MMAL_ES_TYPE_VIDEO;
+  * format_in->encoding = MMAL_ENCODING_H264;
+  * format_in->es->video.width = 1280;
+  * format_in->es->video.height = 720;
+  * format_in->es->video.frame_rate.num = 30;
+  * format_in->es->video.frame_rate.den = 1;
+  * format_in->es->video.par.num = 1;
+  * format_in->es->video.par.den = 1;
+  * format_in->flags = MMAL_ES_FORMAT_FLAG_FRAMED;
+  * status = mmal_format_extradata_alloc(format_in, YOUR_H264_CODEC_HEADER_BYTES_SIZE);
+  * ABORT_IF_ERROR(status);
+  * format_in->extradata_size = YOUR_H264_CODEC_HEADER_BYTES_SIZE;
+  * memcpy(format_in->extradata, YOUR_H264_CODEC_HEADER_BYTES, format_in->extradata_size);
+  *
+  * status = mmal_port_format_commit(decoder->input[0]);
+  * ABORT_IF_ERROR(status);
+  *
+  * // Once the call to mmal_port_format_commit() on the input port returns, the decoder will
+  * // have set the format of the output port.
+  * // If the decoder still doesn t have enough information to determine the format of the
+  * // output port, the encoding will be set to unknown. As soon as the decoder receives
+  * // enough stream data to determine the format of the output port it will send an event
+  * // to the client to signal that the format of the port has changed.
+  * // However, for the sake of simplicity this example assumes that the decoder was given
+  * // all the necessary information right at the start (i.e. video format and codec header bytes)
+  * MMAL_FORMAT_T *format_out = decoder->output[0]->format;
+  * if (format_out->encoding == MMAL_ENCODING_UNKNOWN)
+  *    ABORT();
+  *
+  * // Now we know the format of both ports and the requirements of the decoder, we can create
+  * // our buffer headers and their associated memory buffers. We use the buffer pool API for this.
+  * decoder->input[0]->buffer_num = decoder->input[0]->buffer_num_min;
+  * decoder->input[0]->buffer_size = decoder->input[0]->buffer_size_min;
+  * MMAL_POOL_T *pool_in = mmal_pool_create(decoder->input[0]->buffer_num,
+  *                                         decoder->input[0]->buffer_size);
+  * decoder->output[0]->buffer_num = decoder->output[0]->buffer_num_min;
+  * decoder->output[0]->buffer_size = decoder->output[0]->buffer_size_min;
+  * MMAL_POOL_T *pool_out = mmal_pool_create(decoder->output[0]->buffer_num,
+  *                                          decoder->output[0]->buffer_size);
+  *
+  * // Create a queue to store our decoded video frames. The callback we will get when
+  * // a frame has been decoded will put the frame into this queue.
+  * MMAL_QUEUE_T *queue_decoded_frames = mmal_queue_create();
+  * decoder->output[0]->userdata = (void)queue_decoded_frames;
+  *
+  * // Enable all the input port and the output port.
+  * // The callback specified here is the function which will be called when the buffer header
+  * // we sent to the component has been processed.
+  * status = mmal_port_enable(decoder->input[0], input_callback);
+  * ABORT_IF_ERROR(status);
+  * status = mmal_port_enable(decoder->output[0], output_callback);
+  * ABORT_IF_ERROR(status);
+  *
+  * // Enable the component. Components will only process data when they are enabled.
+  * status = mmal_component_enable(decoder);
+  * ABORT_IF_ERROR(status);
+  *
+  * // Data processing loop
+  * while (1)
+  * {
+  *    MMAL_BUFFER_HEADER_T *buffer;
+  *
+  *    // The client needs to implement its own blocking code.
+  *    // (e.g. a semaphore which is posted when a buffer header is put in one of the queues)
+  *    WAIT_FOR_QUEUES_TO_HAVE_BUFFERS();
+  *
+  *    // Send empty buffers to the output port of the decoder to allow the decoder to start
+  *    // producing frames as soon as it gets input data
+  *    while ((buffer = mmal_queue_get(pool_out->queue)) != NULL)
+  *    {
+  *       status = mmal_port_send_buffer(decoder->output[0], buffer);
+  *       ABORT_IF_ERROR(status);
+  *    }
+  *
+  *    // Send data to decode to the input port of the video decoder
+  *    if ((buffer = mmal_queue_get(pool_in->queue)) != NULL)
+  *    {
+  *       READ_DATA_INTO_BUFFER(buffer);
+  *
+  *       status = mmal_port_send_buffer(decoder->input[0], buffer);
+  *       ABORT_IF_ERROR(status);
+  *    }
+  *
+  *    // Get our decoded frames. We also need to cope with events
+  *    // generated from the component here.
+  *    while ((buffer = mmal_queue_get(queue_decoded_frames)) != NULL)
+  *    {
+  *       if (buffer->cmd)
+  *       {
+  *          // This is an event. Do something with it and release the buffer.
+  *          mmal_buffer_header_release(buffer);
+  *          continue;
+  *       }
+  *
+  *       // We have a frame, do something with it (why not display it for instance?).
+  *       // Once we're done with it, we release it. It will magically go back
+  *       // to its original pool so it can be reused for a new video frame.
+  *       mmal_buffer_header_release(buffer);
+  *    }
+  * }
+  *
+  * // Cleanup everything
+  * mmal_component_destroy(decoder);
+  * mmal_pool_destroy(pool_in);
+  * mmal_pool_destroy(pool_out);
+  * mmal_queue_destroy(queue_decode_frames);
+  *
+  * \endcode
+  */
+
+#include "mmal_common.h"
+#include "mmal_types.h"
+#include "mmal_port.h"
+#include "mmal_component.h"
+#include "mmal_parameters.h"
+#include "mmal_metadata.h"
+#include "mmal_queue.h"
+#include "mmal_pool.h"
+#include "mmal_events.h"
+
+/**/
+/** \name API Version
+ * The following define the version number of the API */
+/* @{ */
+/** Major version number.
+ * This changes when the API breaks in a way which is not backward compatible. */
+#define MMAL_VERSION_MAJOR 0
+/** Minor version number.
+ * This changes each time the API is extended in a way which is still source and
+ * binary compatible. */
+#define MMAL_VERSION_MINOR 1
+
+#define MMAL_VERSION (MMAL_VERSION_MAJOR << 16 | MMAL_VERSION_MINOR)
+#define MMAL_VERSION_TO_MAJOR(a) (a >> 16)
+#define MMAL_VERSION_TO_MINOR(a) (a & 0xFFFF)
+/* @} */
+
+#endif /* MMAL_H */
diff --git a/interface/mmal/mmal_buffer.h b/interface/mmal/mmal_buffer.h
new file mode 100755 (executable)
index 0000000..923000f
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_BUFFER_H
+#define MMAL_BUFFER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup MmalBufferHeader Buffer headers
+ * Definition of a buffer header and its associated API.
+ * Buffer headers are the basic element used to pass data and information between different
+ * parts of the system. They are passed to components via ports and sent back to the client
+ * using a callback mechanism.
+ */
+/* @{ */
+
+/** Specific data associated with video frames */
+typedef struct {
+   uint32_t planes;     /**< Number of planes composing the video frame */
+   uint32_t offset[4];  /**< Offsets to the different planes. These must point within the
+                             payload buffer */
+   uint32_t pitch[4];   /**< Pitch (size in bytes of a line of a plane) of the different
+                             planes */
+   uint32_t flags;      /**< Flags describing video specific properties of a buffer header
+                             (see \ref videobufferheaderflags "Video buffer header flags") */
+   /* TBD stereoscopic support */
+} MMAL_BUFFER_HEADER_VIDEO_SPECIFIC_T;
+
+/** Type specific data that's associated with a payload buffer */
+typedef union
+{
+   /** Specific data associated with video frames */
+   MMAL_BUFFER_HEADER_VIDEO_SPECIFIC_T video;
+
+} MMAL_BUFFER_HEADER_TYPE_SPECIFIC_T;
+
+/** Definition of the buffer header structure.
+ * A buffer header does not directly carry the data to be passed to a component but instead
+ * it references the actual data using a pointer (and an associated length).
+ * It also contains an internal area which can be used to store command or metadata to be
+ * associated with the external data.
+ */
+typedef struct MMAL_BUFFER_HEADER_T
+{
+   struct MMAL_BUFFER_HEADER_T *next; /**< Used to link several buffer headers together */
+
+   struct MMAL_BUFFER_HEADER_PRIVATE_T *priv; /**< Data private to the framework */
+
+   uint32_t cmd;              /**< Defines what the buffer header contains. This is a FourCC
+                                   with 0 as a special value meaning stream data */
+
+   uint8_t  *data;            /**< Pointer to the start of the payload buffer (should not be
+                                   changed by component) */
+   uint32_t alloc_size;       /**< Allocated size in bytes of payload buffer */
+   uint32_t length;           /**< Number of bytes currently used in the payload buffer (starting
+                                   from offset) */
+   uint32_t offset;           /**< Offset in bytes to the start of valid data in the payload buffer */
+
+   uint32_t flags;            /**< Flags describing properties of a buffer header (see
+                                   \ref bufferheaderflags "Buffer header flags") */
+
+   int64_t  pts;              /**< Presentation timestamp in microseconds. \ref MMAL_TIME_UNKNOWN
+                                   is used when the pts is unknown. */
+   int64_t  dts;              /**< Decode timestamp in microseconds (dts = pts, except in the case
+                                   of video streams with B frames). \ref MMAL_TIME_UNKNOWN
+                                   is used when the dts is unknown. */
+
+   /** Type specific data that's associated with a payload buffer */
+   MMAL_BUFFER_HEADER_TYPE_SPECIFIC_T *type;
+
+   void *user_data;           /**< Field reserved for use by the client */
+
+} MMAL_BUFFER_HEADER_T;
+
+/** \name Buffer header flags
+ * \anchor bufferheaderflags
+ * The following flags describe properties of a buffer header */
+/* @{ */
+/** Signals that the current payload is the end of the stream of data */
+#define MMAL_BUFFER_HEADER_FLAG_EOS                    (1<<0)
+/** Signals that the start of the current payload starts a frame */
+#define MMAL_BUFFER_HEADER_FLAG_FRAME_START            (1<<1)
+/** Signals that the end of the current payload ends a frame */
+#define MMAL_BUFFER_HEADER_FLAG_FRAME_END              (1<<2)
+/** Signals that the current payload contains only complete frames (1 or more) */
+#define MMAL_BUFFER_HEADER_FLAG_FRAME                  (MMAL_BUFFER_HEADER_FLAG_FRAME_START|MMAL_BUFFER_HEADER_FLAG_FRAME_END)
+/** Signals that the current payload is a keyframe (i.e. self decodable) */
+#define MMAL_BUFFER_HEADER_FLAG_KEYFRAME               (1<<3)
+/** Signals a discontinuity in the stream of data (e.g. after a seek).
+ * Can be used for instance by a decoder to reset its state */
+#define MMAL_BUFFER_HEADER_FLAG_DISCONTINUITY          (1<<4)
+/** Signals a buffer containing some kind of config data for the component
+ * (e.g. codec config data) */
+#define MMAL_BUFFER_HEADER_FLAG_CONFIG                 (1<<5)
+/** Signals an encrypted payload */
+#define MMAL_BUFFER_HEADER_FLAG_ENCRYPTED              (1<<6)
+/** Signals a buffer containing side information */
+#define MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO          (1<<7)
+/** Signals a buffer which is the snapshot/postview image from a stills capture */
+#define MMAL_BUFFER_HEADER_FLAGS_SNAPSHOT              (1<<8)
+/** Signals a buffer which contains data known to be corrupted */
+#define MMAL_BUFFER_HEADER_FLAG_CORRUPTED              (1<<9)
+/** Signals that a buffer failed to be transmitted */
+#define MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED    (1<<10)
+/** Signals the output buffer won't be used, just update reference frames */
+#define MMAL_BUFFER_HEADER_FLAG_DECODEONLY             (1<<11)
+/** User flags - can be passed in and will get returned */
+#define MMAL_BUFFER_HEADER_FLAG_USER0                  (1<<28)
+#define MMAL_BUFFER_HEADER_FLAG_USER1                  (1<<29)
+#define MMAL_BUFFER_HEADER_FLAG_USER2                  (1<<30)
+#define MMAL_BUFFER_HEADER_FLAG_USER3                  (1<<31)
+/* @} */
+
+/** \name Video buffer header flags
+ * \anchor videobufferheaderflags
+ * The following flags describe properties of a video buffer header */
+#define MMAL_BUFFER_HEADER_FLAG_FORMAT_SPECIFIC_START (1<<16)
+/* @{ */
+/** Signals an interlaced video frame */
+#define MMAL_BUFFER_HEADER_VIDEO_FLAG_INTERLACED       (MMAL_BUFFER_HEADER_FLAG_FORMAT_SPECIFIC_START<<0)
+/** Signals that the top field of the current interlaced frame should be displayed first */
+#define MMAL_BUFFER_HEADER_VIDEO_FLAG_TOP_FIELD_FIRST  (MMAL_BUFFER_HEADER_FLAG_FORMAT_SPECIFIC_START<<1)
+/** Signals that the buffer should be displayed on external display if attached. */
+#define MMAL_BUFFER_HEADER_VIDEO_FLAG_DISPLAY_EXTERNAL (MMAL_BUFFER_HEADER_FLAG_FORMAT_SPECIFIC_START<<3)
+/** Signals that contents of the buffer requires copy protection. */
+#define MMAL_BUFFER_HEADER_VIDEO_FLAG_PROTECTED        (MMAL_BUFFER_HEADER_FLAG_FORMAT_SPECIFIC_START<<4)
+/* @} */
+
+/** Acquire a buffer header.
+ * Acquiring a buffer header increases a reference counter on it and makes sure that the
+ * buffer header won't be recycled until all the references to it are gone.
+ * This is useful for instance if a component needs to return a buffer header but still needs
+ * access to it for some internal processing (e.g. reference frames in video codecs).
+ *
+ * @param header buffer header to acquire
+ */
+void mmal_buffer_header_acquire(MMAL_BUFFER_HEADER_T *header);
+
+/** Reset a buffer header.
+ * Resets all header variables to default values.
+ *
+ * @param header buffer header to reset
+ */
+void mmal_buffer_header_reset(MMAL_BUFFER_HEADER_T *header);
+
+/** Release a buffer header.
+ * Releasing a buffer header will decrease its reference counter and when no more references
+ * are left, the buffer header will be recycled by calling its 'release' callback function.
+ *
+ * If a pre-release callback is set (\ref MMAL_BH_PRE_RELEASE_CB_T), this will be invoked
+ * before calling the buffer's release callback and potentially postpone buffer recycling.
+ * Once pre-release is complete the buffer header is recycled with
+ * \ref mmal_buffer_header_release_continue.
+ *
+ * @param header buffer header to release
+ */
+void mmal_buffer_header_release(MMAL_BUFFER_HEADER_T *header);
+
+/** Continue the buffer header release process.
+ * This should be called to complete buffer header recycling once all pre-release activity
+ * has been completed.
+ *
+ * @param header buffer header to release
+ */
+void mmal_buffer_header_release_continue(MMAL_BUFFER_HEADER_T *header);
+
+/** Buffer header pre-release callback.
+ * The callback is invoked just before a buffer is released back into a
+ * pool. This is used by clients who need to trigger additional actions
+ * before the buffer can finally be released (e.g. wait for a bulk transfer
+ * to complete).
+ *
+ * The callback should return TRUE if the buffer release need to be post-poned.
+ *
+ * @param header   buffer header about to be released
+ * @param userdata user-specific data
+ *
+ * @return TRUE if the buffer should not be released
+ */
+typedef MMAL_BOOL_T (*MMAL_BH_PRE_RELEASE_CB_T)(MMAL_BUFFER_HEADER_T *header, void *userdata);
+
+/** Set a buffer header pre-release callback.
+ * If the callback is NULL, the buffer will be released back into the pool
+ * immediately as usual.
+ *
+ * @param header   buffer header to associate callback with
+ * @param cb       pre-release callback to invoke
+ * @param userdata user-specific data
+ */
+void mmal_buffer_header_pre_release_cb_set(MMAL_BUFFER_HEADER_T *header, MMAL_BH_PRE_RELEASE_CB_T cb, void *userdata);
+
+/** Replicate a buffer header into another one.
+ * Replicating a buffer header will not only do an exact copy of all the public fields of the
+ * buffer header (including data and alloc_size), but it will also acquire a reference to the
+ * source buffer header which will only be released once the replicate has been released.
+ *
+ * @param dest buffer header into which to replicate
+ * @param src buffer header to use as the source for the replication
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_buffer_header_replicate(MMAL_BUFFER_HEADER_T *dest, MMAL_BUFFER_HEADER_T *src);
+
+/** Lock the data buffer contained in the buffer header in memory.
+ * This call does nothing on all platforms except VideoCore where it is needed to pin a
+ * buffer in memory before any access to it.
+ *
+ * @param header buffer header to lock
+ */
+MMAL_STATUS_T mmal_buffer_header_mem_lock(MMAL_BUFFER_HEADER_T *header);
+
+/** Unlock the data buffer contained in the buffer header.
+ * This call does nothing on all platforms except VideoCore where it is needed to un-pin a
+ * buffer in memory after any access to it.
+ *
+ * @param header buffer header to unlock
+ */
+void mmal_buffer_header_mem_unlock(MMAL_BUFFER_HEADER_T *header);
+
+/* @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MMAL_BUFFER_H */
diff --git a/interface/mmal/mmal_clock.h b/interface/mmal/mmal_clock.h
new file mode 100755 (executable)
index 0000000..37e017a
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#ifndef MMAL_CLOCK_H
+#define MMAL_CLOCK_H
+
+#include "interface/vcos/vcos.h"
+#include "mmal_types.h"
+#include "mmal_common.h"
+
+/** \defgroup MmalClock Clock Framework
+ * The MMAL clock framework provides scheduling facilities to the rest of
+ * MMAL.
+ *
+ * The framework consists mainly of clock ports and a clock module. Client
+ * applications and components interact directly with clock ports, while
+ * the clock module is only used internally by clock ports.
+ *
+ * Clock ports ensure that the local media-time for each component is
+ * synchronised across all components. This is done by passing buffers between
+ * clock ports which contain clock-specific data.
+ *
+ * One clock port will normally act as the reference clock for the rest of the
+ * system. This is usually chosen to be the clock port of the audio render
+ * component, but is configurable by the client and could potentially be any
+ * other clock port (or even the client application itself).
+ *
+ * Components that are responsible for timed delivery of frames, do so by
+ * registering callback requests for a particular time-stamp with the clock
+ * port. These requests are scheduled using the clock module which maintains
+ * an internal media-time.
+ *
+ * The clock framework also provides the ability to perform playback at different
+ * speeds. This is achieved with a clock scale factor which determines the speed
+ * at which the media-time advances relative to real-time, with:
+ *   scale = 1.0 -> normal playback speed
+ *   scale = 0   -> playback paused
+ *   scale > 1.0 -> fast-forward
+ *   scale < 1.0 -> slow motion
+ */
+
+/** Clock event magic */
+#define MMAL_CLOCK_EVENT_MAGIC               MMAL_FOURCC('C','K','L','M')
+
+/** Clock reference update */
+#define MMAL_CLOCK_EVENT_REFERENCE           MMAL_FOURCC('C','R','E','F')
+
+/** Clock state update */
+#define MMAL_CLOCK_EVENT_ACTIVE              MMAL_FOURCC('C','A','C','T')
+
+/** Clock scale update */
+#define MMAL_CLOCK_EVENT_SCALE               MMAL_FOURCC('C','S','C','A')
+
+/** Clock media-time update */
+#define MMAL_CLOCK_EVENT_TIME                MMAL_FOURCC('C','T','I','M')
+
+/** Clock update threshold */
+#define MMAL_CLOCK_EVENT_UPDATE_THRESHOLD    MMAL_FOURCC('C','U','T','H')
+
+/** Clock discontinuity threshold */
+#define MMAL_CLOCK_EVENT_DISCONT_THRESHOLD   MMAL_FOURCC('C','D','T','H')
+
+/** Clock request threshold */
+#define MMAL_CLOCK_EVENT_REQUEST_THRESHOLD   MMAL_FOURCC('C','R','T','H')
+
+/** Buffer statistics */
+#define MMAL_CLOCK_EVENT_INPUT_BUFFER_INFO   MMAL_FOURCC('C','I','B','I')
+#define MMAL_CLOCK_EVENT_OUTPUT_BUFFER_INFO  MMAL_FOURCC('C','O','B','I')
+
+/** Clock latency setting */
+#define MMAL_CLOCK_EVENT_LATENCY             MMAL_FOURCC('C','L','A','T')
+
+/** Clock event not valid */
+#define MMAL_CLOCK_EVENT_INVALID   0
+
+
+/** Thresholds used when updating a clock's media-time */
+typedef struct MMAL_CLOCK_UPDATE_THRESHOLD_T
+{
+   /** Time differences below this threshold are ignored (microseconds) */
+   int64_t threshold_lower;
+
+   /** Time differences above this threshold reset media-time (microseconds) */
+   int64_t threshold_upper;
+} MMAL_CLOCK_UPDATE_THRESHOLD_T;
+
+/** Threshold for detecting a discontinuity in media-time */
+typedef struct MMAL_CLOCK_DISCONT_THRESHOLD_T
+{
+   /** Threshold after which backward jumps in media-time are treated as a
+    * discontinuity (microseconds) */
+   int64_t threshold;
+
+   /** Duration in microseconds for which a discontinuity applies (wall-time) */
+   int64_t duration;
+} MMAL_CLOCK_DISCONT_THRESHOLD_T;
+
+/** Threshold applied to client callback requests */
+typedef struct MMAL_CLOCK_REQUEST_THRESHOLD_T
+{
+   /** Frames with a media-time difference (compared to current media-time)
+    * above this threshold are dropped (microseconds) */
+   int64_t threshold;
+
+   /** Enable/disable the request threshold */
+   MMAL_BOOL_T threshold_enable;
+} MMAL_CLOCK_REQUEST_THRESHOLD_T;
+
+/** Structure for passing buffer information to a clock port */
+typedef struct MMAL_CLOCK_BUFFER_INFO_T
+{
+   int64_t time_stamp;
+   uint32_t arrival_time;
+} MMAL_CLOCK_BUFFER_INFO_T;
+
+/** Clock latency settings used by the clock component */
+typedef struct MMAL_CLOCK_LATENCY_T
+{
+   int64_t target;            /**< target latency (microseconds) */
+   int64_t attack_period;     /**< duration of one attack period (microseconds) */
+   int64_t attack_rate;       /**< amount by which media-time will be adjusted
+                                   every attack_period (microseconds) */
+} MMAL_CLOCK_LATENCY_T;
+
+/** Clock event used to pass data between clock ports and a client. */
+typedef struct MMAL_CLOCK_EVENT_T
+{
+   /** 4cc event id */
+   uint32_t id;
+
+   /** 4cc event magic */
+   uint32_t magic;
+
+   /** buffer associated with this event (can be NULL) */
+   struct MMAL_BUFFER_HEADER_T *buffer;
+
+   /** pad to 64-bit boundary */
+   uint32_t padding0;
+
+   /** additional event data (type-specific) */
+   union
+   {
+      /** used either for clock reference or clock state */
+      MMAL_BOOL_T enable;
+
+      /** new clock scale */
+      MMAL_RATIONAL_T scale;
+
+      /** new media-time */
+      int64_t media_time;
+
+      /** media-time update threshold */
+      MMAL_CLOCK_UPDATE_THRESHOLD_T update_threshold;
+
+      /** media-time discontinuity threshold */
+      MMAL_CLOCK_DISCONT_THRESHOLD_T discont_threshold;
+
+      /** client callback request threshold */
+      MMAL_CLOCK_REQUEST_THRESHOLD_T request_threshold;
+
+      /** input/output buffer information */
+      MMAL_CLOCK_BUFFER_INFO_T buffer;
+
+      /** clock latency setting */
+      MMAL_CLOCK_LATENCY_T latency;
+   } data;
+
+   /** pad to 64-bit boundary */
+   uint64_t padding1;
+} MMAL_CLOCK_EVENT_T;
+
+/* Make sure MMAL_CLOCK_EVENT_T will preserve 64-bit alignment */
+vcos_static_assert(!(sizeof(MMAL_CLOCK_EVENT_T) & 0x7));
+
+#define MMAL_CLOCK_EVENT_INIT(id) { id, MMAL_CLOCK_EVENT_MAGIC, NULL, 0, {0}, 0 }
+
+#endif /* MMAL_CLOCK_H */
diff --git a/interface/mmal/mmal_common.h b/interface/mmal/mmal_common.h
new file mode 100755 (executable)
index 0000000..c1b186b
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file mmal_common.h
+ * Multi-Media Abstraction Layer - Common definitions
+ */
+
+#ifndef MMAL_COMMON_H
+#define MMAL_COMMON_H
+
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include <assert.h>
+
+#include <interface/vcos/vcos.h>
+
+/* C99 64bits integers */
+#ifndef INT64_C
+# define INT64_C(value) value##LL
+# define UINT64_C(value) value##ULL
+#endif
+
+#define MMAL_TSRING(s) #s
+#define MMAL_TO_STRING(s) MMAL_TSRING(s)
+
+#define MMAL_COUNTOF(x) (sizeof((x))/sizeof((x)[0]))
+#define MMAL_MIN(a,b) ((a)<(b)?(a):(b))
+#define MMAL_MAX(a,b) ((a)<(b)?(b):(a))
+
+/* FIXME: should be different for big endian */
+#define MMAL_FOURCC(a,b,c,d) ((a) | (b << 8) | (c << 16) | (d << 24))
+#define MMAL_PARAM_UNUSED(a) (void)(a)
+#define MMAL_MAGIC MMAL_FOURCC('m','m','a','l')
+
+typedef int32_t MMAL_BOOL_T;
+#define MMAL_FALSE   0
+#define MMAL_TRUE    1
+
+typedef struct MMAL_CORE_STATISTICS_T
+{
+   uint32_t buffer_count;        /**< Total buffer count on this port */
+   uint32_t first_buffer_time;   /**< Time (us) of first buffer seen on this port */
+   uint32_t last_buffer_time;    /**< Time (us) of most recently buffer on this port */
+   uint32_t max_delay;           /**< Max delay (us) between buffers, ignoring first few frames */
+} MMAL_CORE_STATISTICS_T;
+
+/** Statistics collected by the core on all ports, if enabled in the build.
+ */
+typedef struct MMAL_CORE_PORT_STATISTICS_T
+{
+   MMAL_CORE_STATISTICS_T rx;
+   MMAL_CORE_STATISTICS_T tx;
+} MMAL_CORE_PORT_STATISTICS_T;
+
+/** Unsigned 16.16 fixed point value, also known as Q16.16 */
+typedef uint32_t MMAL_FIXED_16_16_T;
+
+#endif /* MMAL_COMMON_H */
diff --git a/interface/mmal/mmal_component.h b/interface/mmal/mmal_component.h
new file mode 100755 (executable)
index 0000000..6c9d104
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_COMPONENT_H
+#define MMAL_COMPONENT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup MmalComponent Components
+ * Definition of a MMAL component and its associated API. A component will always expose ports
+ * which it uses to send and receive data in the form of buffer headers
+ * (\ref MMAL_BUFFER_HEADER_T) */
+/* @{ */
+
+#include "mmal_types.h"
+#include "mmal_port.h"
+
+struct MMAL_COMPONENT_PRIVATE_T;
+typedef struct MMAL_COMPONENT_PRIVATE_T MMAL_COMPONENT_PRIVATE_T;
+
+/** Definition of a component. */
+typedef struct MMAL_COMPONENT_T
+{
+   /** Pointer to the private data of the module in use */
+   struct MMAL_COMPONENT_PRIVATE_T *priv;
+
+   /** Pointer to private data of the client */
+   struct MMAL_COMPONENT_USERDATA_T *userdata;
+
+   /** Component name */
+   const char *name;
+
+   /** Specifies whether the component is enabled or not */
+   uint32_t is_enabled;
+
+   /** All components expose a control port.
+    * The control port is used by clients to set / get parameters that are global to the
+    * component. It is also used to receive events, which again are global to the component.
+    * To be able to receive events, the client needs to enable and register a callback on the
+    * control port. */
+   MMAL_PORT_T *control;
+
+   uint32_t    input_num;   /**< Number of input ports */
+   MMAL_PORT_T **input;     /**< Array of input ports */
+
+   uint32_t    output_num;  /**< Number of output ports */
+   MMAL_PORT_T **output;    /**< Array of output ports */
+
+   uint32_t    clock_num;   /**< Number of clock ports */
+   MMAL_PORT_T **clock;     /**< Array of clock ports */
+
+   uint32_t    port_num;    /**< Total number of ports */
+   MMAL_PORT_T **port;      /**< Array of all the ports (control/input/output/clock) */
+
+   /** Uniquely identifies the component's instance within the MMAL
+    * context / process. For debugging. */
+   uint32_t id;
+
+} MMAL_COMPONENT_T;
+
+/** Create an instance of a component.
+ * The newly created component will expose ports to the client. All the exposed ports are
+ * disabled by default.
+ * Note that components are reference counted and creating a component automatically
+ * acquires a reference to it (released when \ref mmal_component_destroy is called).
+ *
+ * @param name name of the component to create, e.g. "video_decode"
+ * @param component returned component
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_component_create(const char *name,
+                                    MMAL_COMPONENT_T **component);
+
+/** Acquire a reference on a component.
+ * Acquiring a reference on a component will prevent a component from being destroyed until
+ * the acquired reference is released (by a call to \ref mmal_component_destroy).
+ * References are internally counted so all acquired references need a matching call to
+ * release them.
+ *
+ * @param component component to acquire
+ */
+void mmal_component_acquire(MMAL_COMPONENT_T *component);
+
+/** Release a reference on a component
+ * Release an acquired reference on a component. Triggers the destruction of the component when
+ * the last reference is being released.
+ * \note This is in fact an alias of \ref mmal_component_destroy which is added to make client
+ * code clearer.
+ *
+ * @param component component to release
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_component_release(MMAL_COMPONENT_T *component);
+
+/** Destroy a previously created component
+ * Release an acquired reference on a component. Only actually destroys the component when
+ * the last reference is being released.
+ *
+ * @param component component to destroy
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_component_destroy(MMAL_COMPONENT_T *component);
+
+/** Enable processing on a component
+ * @param component component to enable
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_component_enable(MMAL_COMPONENT_T *component);
+
+/** Disable processing on a component
+ * @param component component to disable
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_component_disable(MMAL_COMPONENT_T *component);
+
+/* @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MMAL_COMPONENT_H */
diff --git a/interface/mmal/mmal_encodings.h b/interface/mmal/mmal_encodings.h
new file mode 100755 (executable)
index 0000000..ee642ab
--- /dev/null
@@ -0,0 +1,267 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_ENCODINGS_H
+#define MMAL_ENCODINGS_H
+
+#include "mmal_common.h"
+
+/** \defgroup MmalEncodings List of pre-defined encodings
+ * This defines a list of common encodings. This list isn't exhaustive and is only
+ * provided as a convenience to avoid clients having to use FourCC codes directly.
+ * However components are allowed to define and use their own FourCC codes. */
+/* @{ */
+
+/** \name Pre-defined video encodings */
+/* @{ */
+#define MMAL_ENCODING_H264             MMAL_FOURCC('H','2','6','4')
+#define MMAL_ENCODING_MVC              MMAL_FOURCC('M','V','C',' ')
+#define MMAL_ENCODING_H263             MMAL_FOURCC('H','2','6','3')
+#define MMAL_ENCODING_MP4V             MMAL_FOURCC('M','P','4','V')
+#define MMAL_ENCODING_MP2V             MMAL_FOURCC('M','P','2','V')
+#define MMAL_ENCODING_MP1V             MMAL_FOURCC('M','P','1','V')
+#define MMAL_ENCODING_WMV3             MMAL_FOURCC('W','M','V','3')
+#define MMAL_ENCODING_WMV2             MMAL_FOURCC('W','M','V','2')
+#define MMAL_ENCODING_WMV1             MMAL_FOURCC('W','M','V','1')
+#define MMAL_ENCODING_WVC1             MMAL_FOURCC('W','V','C','1')
+#define MMAL_ENCODING_VP8              MMAL_FOURCC('V','P','8',' ')
+#define MMAL_ENCODING_VP7              MMAL_FOURCC('V','P','7',' ')
+#define MMAL_ENCODING_VP6              MMAL_FOURCC('V','P','6',' ')
+#define MMAL_ENCODING_THEORA           MMAL_FOURCC('T','H','E','O')
+#define MMAL_ENCODING_SPARK            MMAL_FOURCC('S','P','R','K')
+#define MMAL_ENCODING_MJPEG            MMAL_FOURCC('M','J','P','G')
+
+#define MMAL_ENCODING_JPEG             MMAL_FOURCC('J','P','E','G')
+#define MMAL_ENCODING_GIF              MMAL_FOURCC('G','I','F',' ')
+#define MMAL_ENCODING_PNG              MMAL_FOURCC('P','N','G',' ')
+#define MMAL_ENCODING_PPM              MMAL_FOURCC('P','P','M',' ')
+#define MMAL_ENCODING_TGA              MMAL_FOURCC('T','G','A',' ')
+#define MMAL_ENCODING_BMP              MMAL_FOURCC('B','M','P',' ')
+
+#define MMAL_ENCODING_I420             MMAL_FOURCC('I','4','2','0')
+#define MMAL_ENCODING_I420_SLICE       MMAL_FOURCC('S','4','2','0')
+#define MMAL_ENCODING_YV12             MMAL_FOURCC('Y','V','1','2')
+#define MMAL_ENCODING_I422             MMAL_FOURCC('I','4','2','2')
+#define MMAL_ENCODING_I422_SLICE       MMAL_FOURCC('S','4','2','2')
+#define MMAL_ENCODING_YUYV             MMAL_FOURCC('Y','U','Y','V')
+#define MMAL_ENCODING_YVYU             MMAL_FOURCC('Y','V','Y','U')
+#define MMAL_ENCODING_UYVY             MMAL_FOURCC('U','Y','V','Y')
+#define MMAL_ENCODING_VYUY             MMAL_FOURCC('V','Y','U','Y')
+#define MMAL_ENCODING_NV12             MMAL_FOURCC('N','V','1','2')
+#define MMAL_ENCODING_NV21             MMAL_FOURCC('N','V','2','1')
+#define MMAL_ENCODING_ARGB             MMAL_FOURCC('A','R','G','B')
+#define MMAL_ENCODING_ARGB_SLICE       MMAL_FOURCC('a','r','g','b')
+#define MMAL_ENCODING_RGBA             MMAL_FOURCC('R','G','B','A')
+#define MMAL_ENCODING_RGBA_SLICE       MMAL_FOURCC('r','g','b','a')
+#define MMAL_ENCODING_ABGR             MMAL_FOURCC('A','B','G','R')
+#define MMAL_ENCODING_ABGR_SLICE       MMAL_FOURCC('a','b','g','r')
+#define MMAL_ENCODING_BGRA             MMAL_FOURCC('B','G','R','A')
+#define MMAL_ENCODING_BGRA_SLICE       MMAL_FOURCC('b','g','r','a')
+#define MMAL_ENCODING_RGB16            MMAL_FOURCC('R','G','B','2')
+#define MMAL_ENCODING_RGB16_SLICE      MMAL_FOURCC('r','g','b','2')
+#define MMAL_ENCODING_RGB24            MMAL_FOURCC('R','G','B','3')
+#define MMAL_ENCODING_RGB24_SLICE      MMAL_FOURCC('r','g','b','3')
+#define MMAL_ENCODING_RGB32            MMAL_FOURCC('R','G','B','4')
+#define MMAL_ENCODING_RGB32_SLICE      MMAL_FOURCC('r','g','b','4')
+#define MMAL_ENCODING_BGR16            MMAL_FOURCC('B','G','R','2')
+#define MMAL_ENCODING_BGR16_SLICE      MMAL_FOURCC('b','g','r','2')
+#define MMAL_ENCODING_BGR24            MMAL_FOURCC('B','G','R','3')
+#define MMAL_ENCODING_BGR24_SLICE      MMAL_FOURCC('b','g','r','3')
+#define MMAL_ENCODING_BGR32            MMAL_FOURCC('B','G','R','4')
+#define MMAL_ENCODING_BGR32_SLICE      MMAL_FOURCC('b','g','r','4')
+
+/** YUV 4:2:0 planar, 16bit/component.
+*/
+#define MMAL_ENCODING_I420_16          MMAL_FOURCC('i','4','2','0')
+/** YUV 4:2:0 planar, 10bit/component as least sig 10bits of 16 bit words.
+*/
+#define MMAL_ENCODING_I420_10          MMAL_FOURCC('i','4','1','0')
+
+//Bayer formats
+//FourCC values copied from V4L2 where defined.
+//10 bit per pixel packed Bayer formats.
+#define MMAL_ENCODING_BAYER_SBGGR10P   MMAL_FOURCC('p','B','A','A')  //BGGR
+#define MMAL_ENCODING_BAYER_SGRBG10P   MMAL_FOURCC('p','g','A','A')  //GRBG
+#define MMAL_ENCODING_BAYER_SGBRG10P   MMAL_FOURCC('p','G','A','A')  //GBRG
+#define MMAL_ENCODING_BAYER_SRGGB10P   MMAL_FOURCC('p','R','A','A')  //RGGB
+
+//8 bit per pixel Bayer formats.
+#define MMAL_ENCODING_BAYER_SBGGR8     MMAL_FOURCC('B','A','8','1')  //BGGR
+#define MMAL_ENCODING_BAYER_SGBRG8     MMAL_FOURCC('G','B','R','G')  //GBRG
+#define MMAL_ENCODING_BAYER_SGRBG8     MMAL_FOURCC('G','R','B','G')  //GRBG
+#define MMAL_ENCODING_BAYER_SRGGB8     MMAL_FOURCC('R','G','G','B')  //RGGB
+
+//12 bit per pixel Bayer formats - not defined in V4L2, only 12bit expanded to 16.
+//Copy 10bpp packed 4CC pattern
+#define MMAL_ENCODING_BAYER_SBGGR12P   MMAL_FOURCC('p','B','1','2')  //BGGR
+#define MMAL_ENCODING_BAYER_SGRBG12P   MMAL_FOURCC('p','g','1','2')  //GRBG
+#define MMAL_ENCODING_BAYER_SGBRG12P   MMAL_FOURCC('p','G','1','2')  //GBRG
+#define MMAL_ENCODING_BAYER_SRGGB12P   MMAL_FOURCC('p','R','1','2')  //RGGB
+
+//16 bit per pixel Bayer formats.
+#define MMAL_ENCODING_BAYER_SBGGR16    MMAL_FOURCC('R','G','1','6')  //BGGR
+#define MMAL_ENCODING_BAYER_SGBRG16    MMAL_FOURCC('G','B','1','6')  //GBRG
+#define MMAL_ENCODING_BAYER_SGRBG16    MMAL_FOURCC('G','R','1','6')  //GRBG
+#define MMAL_ENCODING_BAYER_SRGGB16    MMAL_FOURCC('R','G','1','6')  //RGGB
+
+//10 bit per pixel DPCM compressed to 8bits Bayer formats.
+#define MMAL_ENCODING_BAYER_SBGGR10DPCM8 MMAL_FOURCC('b','B','A','8')  //BGGR
+#define MMAL_ENCODING_BAYER_SGBRG10DPCM8 MMAL_FOURCC('b','G','A','8')  //GBRG
+#define MMAL_ENCODING_BAYER_SGRBG10DPCM8 MMAL_FOURCC('B','D','1','0')  //GRBG
+#define MMAL_ENCODING_BAYER_SRGGB10DPCM8 MMAL_FOURCC('b','R','A','8')  //RGGB
+
+/** SAND Video (YUVUV128) format, native format understood by VideoCore.
+ * This format is *not* opaque - if requested you will receive full frames
+ * of YUV_UV video.
+ */
+#define MMAL_ENCODING_YUVUV128         MMAL_FOURCC('S','A','N','D')
+/** 16 bit SAND Video (YUVUV64_16) format.
+ * This format is *not* opaque - if requested you will receive full frames
+ * of YUV_UV_16 video.
+ */
+#define MMAL_ENCODING_YUVUV64_16      MMAL_FOURCC('S','A','1','6')
+/** 10 bit SAND Video format, packed as least sig 10 bits of 16 bit words.
+ */
+#define MMAL_ENCODING_YUVUV64_10      MMAL_FOURCC('S','A','1','0')
+
+/** VideoCore opaque image format, image handles are returned to
+ * the host but not the actual image data.
+ */
+#define MMAL_ENCODING_OPAQUE           MMAL_FOURCC('O','P','Q','V')
+
+/** An EGL image handle
+ */
+#define MMAL_ENCODING_EGL_IMAGE        MMAL_FOURCC('E','G','L','I')
+
+/* }@ */
+
+/** \name Pre-defined audio encodings */
+/* @{ */
+#define MMAL_ENCODING_PCM_UNSIGNED_BE  MMAL_FOURCC('P','C','M','U')
+#define MMAL_ENCODING_PCM_UNSIGNED_LE  MMAL_FOURCC('p','c','m','u')
+#define MMAL_ENCODING_PCM_SIGNED_BE    MMAL_FOURCC('P','C','M','S')
+#define MMAL_ENCODING_PCM_SIGNED_LE    MMAL_FOURCC('p','c','m','s')
+#define MMAL_ENCODING_PCM_FLOAT_BE     MMAL_FOURCC('P','C','M','F')
+#define MMAL_ENCODING_PCM_FLOAT_LE     MMAL_FOURCC('p','c','m','f')
+/* Defines for native endianness */
+#ifdef MMAL_IS_BIG_ENDIAN
+#define MMAL_ENCODING_PCM_UNSIGNED     MMAL_ENCODING_PCM_UNSIGNED_BE
+#define MMAL_ENCODING_PCM_SIGNED       MMAL_ENCODING_PCM_SIGNED_BE
+#define MMAL_ENCODING_PCM_FLOAT        MMAL_ENCODING_PCM_FLOAT_BE
+#else
+#define MMAL_ENCODING_PCM_UNSIGNED     MMAL_ENCODING_PCM_UNSIGNED_LE
+#define MMAL_ENCODING_PCM_SIGNED       MMAL_ENCODING_PCM_SIGNED_LE
+#define MMAL_ENCODING_PCM_FLOAT        MMAL_ENCODING_PCM_FLOAT_LE
+#endif
+
+#define MMAL_ENCODING_MP4A             MMAL_FOURCC('M','P','4','A')
+#define MMAL_ENCODING_MPGA             MMAL_FOURCC('M','P','G','A')
+#define MMAL_ENCODING_ALAW             MMAL_FOURCC('A','L','A','W')
+#define MMAL_ENCODING_MULAW            MMAL_FOURCC('U','L','A','W')
+#define MMAL_ENCODING_ADPCM_MS         MMAL_FOURCC('M','S',0x0,0x2)
+#define MMAL_ENCODING_ADPCM_IMA_MS     MMAL_FOURCC('M','S',0x0,0x1)
+#define MMAL_ENCODING_ADPCM_SWF        MMAL_FOURCC('A','S','W','F')
+#define MMAL_ENCODING_WMA1             MMAL_FOURCC('W','M','A','1')
+#define MMAL_ENCODING_WMA2             MMAL_FOURCC('W','M','A','2')
+#define MMAL_ENCODING_WMAP             MMAL_FOURCC('W','M','A','P')
+#define MMAL_ENCODING_WMAL             MMAL_FOURCC('W','M','A','L')
+#define MMAL_ENCODING_WMAV             MMAL_FOURCC('W','M','A','V')
+#define MMAL_ENCODING_AMRNB            MMAL_FOURCC('A','M','R','N')
+#define MMAL_ENCODING_AMRWB            MMAL_FOURCC('A','M','R','W')
+#define MMAL_ENCODING_AMRWBP           MMAL_FOURCC('A','M','R','P')
+#define MMAL_ENCODING_AC3              MMAL_FOURCC('A','C','3',' ')
+#define MMAL_ENCODING_EAC3             MMAL_FOURCC('E','A','C','3')
+#define MMAL_ENCODING_DTS              MMAL_FOURCC('D','T','S',' ')
+#define MMAL_ENCODING_MLP              MMAL_FOURCC('M','L','P',' ')
+#define MMAL_ENCODING_FLAC             MMAL_FOURCC('F','L','A','C')
+#define MMAL_ENCODING_VORBIS           MMAL_FOURCC('V','O','R','B')
+#define MMAL_ENCODING_SPEEX            MMAL_FOURCC('S','P','X',' ')
+#define MMAL_ENCODING_ATRAC3           MMAL_FOURCC('A','T','R','3')
+#define MMAL_ENCODING_ATRACX           MMAL_FOURCC('A','T','R','X')
+#define MMAL_ENCODING_ATRACL           MMAL_FOURCC('A','T','R','L')
+#define MMAL_ENCODING_MIDI             MMAL_FOURCC('M','I','D','I')
+#define MMAL_ENCODING_EVRC             MMAL_FOURCC('E','V','R','C')
+#define MMAL_ENCODING_NELLYMOSER       MMAL_FOURCC('N','E','L','Y')
+#define MMAL_ENCODING_QCELP            MMAL_FOURCC('Q','C','E','L')
+#define MMAL_ENCODING_MP4V_DIVX_DRM    MMAL_FOURCC('M','4','V','D')
+/* @} */
+
+/* @} MmalEncodings List */
+
+/** \defgroup MmalEncodingVariants List of pre-defined encoding variants
+ * This defines a list of common encoding variants. This list isn't exhaustive and is only
+ * provided as a convenience to avoid clients having to use FourCC codes directly.
+ * However components are allowed to define and use their own FourCC codes. */
+/* @{ */
+
+/** \name Pre-defined H264 encoding variants */
+/* @{ */
+/** ISO 14496-10 Annex B byte stream format */
+#define MMAL_ENCODING_VARIANT_H264_DEFAULT   0
+/** ISO 14496-15 AVC stream format */
+#define MMAL_ENCODING_VARIANT_H264_AVC1      MMAL_FOURCC('A','V','C','1')
+/** Implicitly delineated NAL units without emulation prevention */
+#define MMAL_ENCODING_VARIANT_H264_RAW       MMAL_FOURCC('R','A','W',' ')
+/* @} */
+
+/** \name Pre-defined MPEG4 audio encoding variants */
+/* @{ */
+/** Raw stream format */
+#define MMAL_ENCODING_VARIANT_MP4A_DEFAULT   0
+/** ADTS stream format */
+#define MMAL_ENCODING_VARIANT_MP4A_ADTS      MMAL_FOURCC('A','D','T','S')
+/* @} */
+
+/* @} MmalEncodingVariants List */
+
+/** \defgroup MmalColorSpace List of pre-defined video color spaces
+ * This defines a list of common color spaces. This list isn't exhaustive and is only
+ * provided as a convenience to avoid clients having to use FourCC codes directly.
+ * However components are allowed to define and use their own FourCC codes. */
+/* @{ */
+
+/** Unknown color space */
+#define MMAL_COLOR_SPACE_UNKNOWN       0
+/** ITU-R BT.601-5 [SDTV] */
+#define MMAL_COLOR_SPACE_ITUR_BT601    MMAL_FOURCC('Y','6','0','1')
+/** ITU-R BT.709-3 [HDTV] */
+#define MMAL_COLOR_SPACE_ITUR_BT709    MMAL_FOURCC('Y','7','0','9')
+/** JPEG JFIF */
+#define MMAL_COLOR_SPACE_JPEG_JFIF     MMAL_FOURCC('Y','J','F','I')
+/** Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */
+#define MMAL_COLOR_SPACE_FCC           MMAL_FOURCC('Y','F','C','C')
+/** Society of Motion Picture and Television Engineers 240M (1999) */
+#define MMAL_COLOR_SPACE_SMPTE240M     MMAL_FOURCC('Y','2','4','0')
+/** ITU-R BT.470-2 System M */
+#define MMAL_COLOR_SPACE_BT470_2_M     MMAL_FOURCC('Y','_','_','M')
+/** ITU-R BT.470-2 System BG */
+#define MMAL_COLOR_SPACE_BT470_2_BG    MMAL_FOURCC('Y','_','B','G')
+/** JPEG JFIF, but with 16..255 luma */
+#define MMAL_COLOR_SPACE_JFIF_Y16_255  MMAL_FOURCC('Y','Y','1','6')
+/* @} MmalColorSpace List */
+
+#endif /* MMAL_ENCODINGS_H */
diff --git a/interface/mmal/mmal_events.h b/interface/mmal/mmal_events.h
new file mode 100755 (executable)
index 0000000..94ccd56
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_EVENTS_H
+#define MMAL_EVENTS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mmal_common.h"
+#include "mmal_parameters.h"
+#include "mmal_port.h"
+
+/** \defgroup MmalEvents List of pre-defined event types
+ * This defines a list of standard event types. Components can still define proprietary
+ * event types by using their own FourCC and defining their own event structures. */
+/* @{ */
+
+/** \name Pre-defined event FourCCs */
+/* @{ */
+
+/** Error event. Data contains a \ref MMAL_STATUS_T */
+#define MMAL_EVENT_ERROR                     MMAL_FOURCC('E','R','R','O')
+
+/** End-of-stream event. Data contains a \ref MMAL_EVENT_END_OF_STREAM_T */
+#define MMAL_EVENT_EOS                       MMAL_FOURCC('E','E','O','S')
+
+/** Format changed event. Data contains a \ref MMAL_EVENT_FORMAT_CHANGED_T */
+#define MMAL_EVENT_FORMAT_CHANGED            MMAL_FOURCC('E','F','C','H')
+
+/** Parameter changed event. Data contains the new parameter value, see
+ * \ref MMAL_EVENT_PARAMETER_CHANGED_T
+ */
+#define MMAL_EVENT_PARAMETER_CHANGED         MMAL_FOURCC('E','P','C','H')
+
+/* @} */
+
+
+/** End-of-stream event. */
+typedef struct MMAL_EVENT_END_OF_STREAM_T
+{
+   MMAL_PORT_TYPE_T port_type;   /**< Type of port that received the end of stream */
+   uint32_t port_index;          /**< Index of port that received the end of stream */
+} MMAL_EVENT_END_OF_STREAM_T;
+
+/** Format changed event data. */
+typedef struct MMAL_EVENT_FORMAT_CHANGED_T
+{
+   uint32_t buffer_size_min;         /**< Minimum size of buffers the port requires */
+   uint32_t buffer_num_min;          /**< Minimum number of buffers the port requires */
+   uint32_t buffer_size_recommended; /**< Size of buffers the port recommends for optimal performance.
+                                          A value of zero means no special recommendation. */
+   uint32_t buffer_num_recommended;  /**< Number of buffers the port recommends for optimal
+                                          performance. A value of zero means no special recommendation. */
+
+   MMAL_ES_FORMAT_T *format;         /**< New elementary stream format */
+} MMAL_EVENT_FORMAT_CHANGED_T;
+
+/** Parameter changed event data.
+ * This is a variable sized event. The full parameter is included in the event
+ * data, not just the header. Use the \ref MMAL_PARAMETER_HEADER_T::id field to determine how to
+ * cast the structure. The \ref MMAL_PARAMETER_HEADER_T::size field can be used to check validity.
+ */
+typedef struct MMAL_EVENT_PARAMETER_CHANGED_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+} MMAL_EVENT_PARAMETER_CHANGED_T;
+
+/** Get a pointer to the \ref MMAL_EVENT_FORMAT_CHANGED_T structure contained in the buffer header.
+ * Note that the pointer will point inside the data contained in the buffer header
+ * so doesn't need to be freed explicitly.
+ *
+ * @param buffer buffer header containing the MMAL_EVENT_FORMAT_CHANGED event.
+ * @return pointer to a MMAL_EVENT_FORMAT_CHANGED_T structure.
+ */
+MMAL_EVENT_FORMAT_CHANGED_T *mmal_event_format_changed_get(MMAL_BUFFER_HEADER_T *buffer);
+
+/* @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MMAL_EVENTS_H */
diff --git a/interface/mmal/mmal_format.h b/interface/mmal/mmal_format.h
new file mode 100755 (executable)
index 0000000..78c0844
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_FORMAT_H
+#define MMAL_FORMAT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup MmalFormat Elementary stream format
+ * Definition of an elementary stream format and its associated API */
+/* @{ */
+
+#include "mmal_types.h"
+#include "mmal_encodings.h"
+
+/** Enumeration of the different types of elementary streams.
+ * This divides elementary streams into 4 big categories, plus an invalid type. */
+typedef enum {
+   MMAL_ES_TYPE_UNKNOWN,     /**< Unknown elementary stream type */
+   MMAL_ES_TYPE_CONTROL,     /**< Elementary stream of control commands */
+   MMAL_ES_TYPE_AUDIO,       /**< Audio elementary stream */
+   MMAL_ES_TYPE_VIDEO,       /**< Video elementary stream */
+   MMAL_ES_TYPE_SUBPICTURE   /**< Sub-picture elementary stream (e.g. subtitles, overlays) */
+} MMAL_ES_TYPE_T;
+
+/** Definition of a video format.
+ * This describes the properties specific to a video stream */
+typedef struct
+{
+   uint32_t        width;        /**< Width of frame in pixels */
+   uint32_t        height;       /**< Height of frame in rows of pixels */
+   MMAL_RECT_T     crop;         /**< Visible region of the frame */
+   MMAL_RATIONAL_T frame_rate;   /**< Frame rate */
+   MMAL_RATIONAL_T par;          /**< Pixel aspect ratio */
+
+   MMAL_FOURCC_T   color_space;  /**< FourCC specifying the color space of the
+                                   * video stream. See the \ref MmalColorSpace
+                                   * "pre-defined color spaces" for some examples.
+                                   */
+
+} MMAL_VIDEO_FORMAT_T;
+
+/** Definition of an audio format.
+ * This describes the properties specific to an audio stream */
+typedef struct MMAL_AUDIO_FORMAT_T
+{
+   uint32_t channels;           /**< Number of audio channels */
+   uint32_t sample_rate;        /**< Sample rate */
+
+   uint32_t bits_per_sample;    /**< Bits per sample */
+   uint32_t block_align;        /**< Size of a block of data */
+
+   /** \todo add channel mapping, gapless and replay-gain support */
+
+} MMAL_AUDIO_FORMAT_T;
+
+/** Definition of a subpicture format.
+ * This describes the properties specific to a subpicture stream */
+typedef struct
+{
+   uint32_t x_offset;        /**< Width offset to the start of the subpicture */
+   uint32_t y_offset;        /**< Height offset to the start of the subpicture */
+
+   /** \todo surely more things are needed here */
+
+} MMAL_SUBPICTURE_FORMAT_T;
+
+/** Definition of the type specific format.
+ * This describes the type specific information of the elementary stream. */
+typedef union
+{
+   MMAL_AUDIO_FORMAT_T      audio;      /**< Audio specific information */
+   MMAL_VIDEO_FORMAT_T      video;      /**< Video specific information */
+   MMAL_SUBPICTURE_FORMAT_T subpicture; /**< Subpicture specific information */
+} MMAL_ES_SPECIFIC_FORMAT_T;
+
+/** \name Elementary stream flags
+ * \anchor elementarystreamflags
+ * The following flags describe properties of an elementary stream */
+/* @{ */
+#define MMAL_ES_FORMAT_FLAG_FRAMED       0x1 /**< The elementary stream will already be framed */
+/* @} */
+
+/** \name Undefined encoding value.
+ * This value indicates an unknown encoding
+ */
+/* @{ */
+#define MMAL_ENCODING_UNKNOWN            0
+/* @} */
+
+/** \name Default encoding variant value.
+ * This value indicates the default encoding variant is used
+ */
+/* @{ */
+#define MMAL_ENCODING_VARIANT_DEFAULT    0
+/* @} */
+
+/** Definition of an elementary stream format */
+typedef struct MMAL_ES_FORMAT_T
+{
+   MMAL_ES_TYPE_T type;           /**< Type of the elementary stream */
+
+   MMAL_FOURCC_T encoding;        /**< FourCC specifying the encoding of the elementary stream.
+                                    * See the \ref MmalEncodings "pre-defined encodings" for some
+                                    * examples.
+                                    */
+   MMAL_FOURCC_T encoding_variant;/**< FourCC specifying the specific encoding variant of
+                                    * the elementary stream. See the \ref MmalEncodingVariants
+                                    * "pre-defined encoding variants" for some examples.
+                                    */
+
+   MMAL_ES_SPECIFIC_FORMAT_T *es; /**< Type specific information for the elementary stream */
+
+   uint32_t bitrate;              /**< Bitrate in bits per second */
+   uint32_t flags;                /**< Flags describing properties of the elementary stream.
+                                    * See \ref elementarystreamflags "Elementary stream flags".
+                                    */
+
+   uint32_t extradata_size;       /**< Size of the codec specific data */
+   uint8_t  *extradata;           /**< Codec specific data */
+
+} MMAL_ES_FORMAT_T;
+
+/** Allocate and initialise a \ref MMAL_ES_FORMAT_T structure.
+ *
+ * @return a \ref MMAL_ES_FORMAT_T structure
+ */
+MMAL_ES_FORMAT_T *mmal_format_alloc(void);
+
+/** Free a \ref MMAL_ES_FORMAT_T structure allocated by \ref mmal_format_alloc.
+ *
+ * @param format the \ref MMAL_ES_FORMAT_T structure to free
+ */
+void mmal_format_free(MMAL_ES_FORMAT_T *format);
+
+/** Allocate the extradata buffer in \ref MMAL_ES_FORMAT_T.
+ * This buffer will be freed automatically when the format is destroyed or
+ * another allocation is done.
+ *
+ * @param format format structure for which the extradata buffer will be allocated
+ * @param size size of the extradata buffer to allocate
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_format_extradata_alloc(MMAL_ES_FORMAT_T *format, unsigned int size);
+
+/** Shallow copy a format structure.
+ * It is worth noting that the extradata buffer will not be copied in the new format.
+ *
+ * @param format_dest destination \ref MMAL_ES_FORMAT_T for the copy
+ * @param format_src source \ref MMAL_ES_FORMAT_T for the copy
+ */
+void mmal_format_copy(MMAL_ES_FORMAT_T *format_dest, MMAL_ES_FORMAT_T *format_src);
+
+/** Fully copy a format structure, including the extradata buffer.
+ *
+ * @param format_dest destination \ref MMAL_ES_FORMAT_T for the copy
+ * @param format_src source \ref MMAL_ES_FORMAT_T for the copy
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_format_full_copy(MMAL_ES_FORMAT_T *format_dest, MMAL_ES_FORMAT_T *format_src);
+
+/** \name Comparison flags
+ * \anchor comparisonflags
+ * The following flags describe the differences between 2 format structures */
+/* @{ */
+#define MMAL_ES_FORMAT_COMPARE_FLAG_TYPE              0x01 /**< The type is different */
+#define MMAL_ES_FORMAT_COMPARE_FLAG_ENCODING          0x02 /**< The encoding is different */
+#define MMAL_ES_FORMAT_COMPARE_FLAG_BITRATE           0x04 /**< The bitrate is different */
+#define MMAL_ES_FORMAT_COMPARE_FLAG_FLAGS             0x08 /**< The flags are different */
+#define MMAL_ES_FORMAT_COMPARE_FLAG_EXTRADATA         0x10 /**< The extradata is different */
+
+#define MMAL_ES_FORMAT_COMPARE_FLAG_VIDEO_RESOLUTION   0x0100 /**< The video resolution is different */
+#define MMAL_ES_FORMAT_COMPARE_FLAG_VIDEO_CROPPING     0x0200 /**< The video cropping is different */
+#define MMAL_ES_FORMAT_COMPARE_FLAG_VIDEO_FRAME_RATE   0x0400 /**< The video frame rate is different */
+#define MMAL_ES_FORMAT_COMPARE_FLAG_VIDEO_ASPECT_RATIO 0x0800 /**< The video aspect ratio is different */
+#define MMAL_ES_FORMAT_COMPARE_FLAG_VIDEO_COLOR_SPACE  0x1000 /**< The video color space is different */
+
+#define MMAL_ES_FORMAT_COMPARE_FLAG_ES_OTHER  0x10000000 /**< Other ES specific parameters are different */
+/* @} */
+
+/** Compare 2 format structures and returns a set of flags describing the differences.
+ * The result will be zero if the structures are the same, or a combination of
+ * one or more of the \ref comparisonflags "Comparison flags" if different.
+ *
+ * @param format_1 first \ref MMAL_ES_FORMAT_T to compare
+ * @param format_2 second \ref MMAL_ES_FORMAT_T to compare
+ * @return set of flags describing the differences
+ */
+uint32_t mmal_format_compare(MMAL_ES_FORMAT_T *format_1, MMAL_ES_FORMAT_T *format_2);
+
+/* @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MMAL_FORMAT_H */
diff --git a/interface/mmal/mmal_logging.h b/interface/mmal/mmal_logging.h
new file mode 100755 (executable)
index 0000000..2307ab3
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_LOGGING_H
+#define MMAL_LOGGING_H
+
+#include "mmal_common.h"
+#include "interface/vcos/vcos_logging.h"
+
+#ifndef VCOS_LOG_CATEGORY
+#define VCOS_LOG_CATEGORY (&mmal_log_category)
+extern VCOS_LOG_CAT_T mmal_log_category;
+#endif
+
+#if defined(__GNUC__) && (( __GNUC__ > 2 ) || (( __GNUC__ == 2 ) && ( __GNUC_MINOR__ >= 3 )))
+#define mmal_log_error(s, ...) vcos_log_error("%s: " s, VCOS_FUNCTION, ## __VA_ARGS__)
+#define mmal_log_info(s, ...) vcos_log_info("%s: " s, VCOS_FUNCTION, ## __VA_ARGS__)
+#define mmal_log_warn(s, ...) vcos_log_warn("%s: " s, VCOS_FUNCTION, ## __VA_ARGS__)
+#define mmal_log_debug(s, ...) vcos_log_info("%s: " s, VCOS_FUNCTION, ## __VA_ARGS__)
+#define mmal_log_trace(s, ...) vcos_log_trace("%s: " s, VCOS_FUNCTION, ## __VA_ARGS__)
+#elif defined(_MSC_VER)
+#define mmal_log_error(s, ...) vcos_log_error("%s: " s, VCOS_FUNCTION, __VA_ARGS__)
+#define mmal_log_info(s, ...) vcos_log_info("%s: " s, VCOS_FUNCTION, __VA_ARGS__)
+#define mmal_log_warn(s, ...) vcos_log_warn("%s: " s, VCOS_FUNCTION, __VA_ARGS__)
+#define mmal_log_debug(s, ...) vcos_log_info("%s: " s, VCOS_FUNCTION, __VA_ARGS__)
+#define mmal_log_trace(s, ...) vcos_log_trace("%s: " s, VCOS_FUNCTION, __VA_ARGS__)
+#else
+#define mmal_log_error_fun(s, ...) vcos_log_error("%s: " s, VCOS_FUNCTION, __VA_ARGS__)
+#define mmal_log_info_fun(s, ...) vcos_log_info("%s: " s, VCOS_FUNCTION, __VA_ARGS__)
+#define mmal_log_warn_fun(s, ...) vcos_log_warn("%s: " s, VCOS_FUNCTION, __VA_ARGS__)
+#define mmal_log_debug_fun(s, ...) vcos_log_info("%s: " s, VCOS_FUNCTION, __VA_ARGS__)
+#define mmal_log_trace_fun(s, ...) vcos_log_trace("%s: " s, VCOS_FUNCTION, __VA_ARGS__)
+
+#define mmal_log_error(s...) mmal_log_error_fun(s, 0)
+#define mmal_log_info(s...) mmal_log_info_fun(s, 0)
+#define mmal_log_warn(s...)  mmal_log_warn_fun(s, 0)
+#define mmal_log_debug(s...)  mmal_log_debug_fun(s, 0)
+#define mmal_log_trace(s...) mmal_log_trace_fun(s, 0)
+#endif
+
+#define LOG_ERROR mmal_log_error
+#define LOG_INFO mmal_log_info
+#define LOG_WARN mmal_log_warn
+#define LOG_DEBUG mmal_log_debug
+#define LOG_TRACE mmal_log_trace
+
+#endif /* MMAL_LOGGING_H */
diff --git a/interface/mmal/mmal_metadata.h b/interface/mmal/mmal_metadata.h
new file mode 100755 (executable)
index 0000000..5d21dd0
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_METADATA_H
+#define MMAL_METADATA_H
+
+#include "mmal_common.h"
+
+/** \defgroup MmalMetadata List of pre-defined metadata types
+ * This defines a list of standard metadata types. Components can still define proprietary
+ * metadata types by using their own FourCC and defining their own metadata structures. */
+/* @{ */
+
+/** \name Pre-defined metadata FourCCs */
+/* @{ */
+#define MMAL_METADATA_HELLO_WORLD             MMAL_FOURCC('H','E','L','O')
+/* @} */
+
+/** Generic metadata type. All metadata structures need to begin with these fields. */
+typedef struct MMAL_METATDATA_T
+{
+   uint32_t id;    /**< Metadata id. This is a FourCC */
+   uint32_t size;  /**< Size in bytes of the following metadata (not including id and size) */
+} MMAL_METADATA_T;
+
+/** Hello World metadata. */
+typedef struct MMAL_METATDATA_HELLO_WORLD_T
+{
+   uint32_t id;    /**< Metadata id. This is a FourCC */
+   uint32_t size;  /**< Size in bytes of the following metadata (not including id and size) */
+
+   uint32_t myvalue; /**< Metadata value */
+} MMAL_METADATA_HELLO_WORLD_T;
+
+/** Get metadata item from buffer header.
+ * This will search through all the metadata in the buffer header and return a pointer to the
+ * first instance of the requested metadata id.
+ *
+ * @param header buffer header containing the metadata
+ * @param id     requested metadata id
+ *
+ * @return Pointer to metadata requested or NULL if not found.
+ */
+MMAL_METADATA_T *mmal_metadata_get(MMAL_BUFFER_HEADER_T *header, uint32_t id);
+
+/** Set metadata item in buffer header.
+ * This will store the metadata item into the buffer header. This operation can fail if not
+ * enough memory is available in the data section of the buffer header.
+ *
+ * @param header   buffer header to store the metadata into
+ * @param metadata metadata item to store in buffer header
+ *
+ * @return MMAL_SUCCESS on success or MMAL_ENOMEM if not enough memory is available for storing
+ * the metadata
+ */
+MMAL_STATUS_T mmal_metadata_set(MMAL_BUFFER_HEADER_T *header, MMAL_METADATA_T *metadata);
+
+/* @} */
+
+#endif /* MMAL_METADATA_H */
diff --git a/interface/mmal/mmal_parameters.h b/interface/mmal/mmal_parameters.h
new file mode 100755 (executable)
index 0000000..67ffbda
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_PARAMETERS_H
+#define MMAL_PARAMETERS_H
+
+#include "mmal_common.h"
+#include "mmal_parameters_camera.h"
+#include "mmal_parameters_video.h"
+#include "mmal_parameters_audio.h"
+#include "mmal_parameters_clock.h"
+
+/** \defgroup MmalParameters List of pre-defined parameters
+ * This defines a list of standard parameters. Components can define proprietary
+ * parameters by creating a new group and defining their own structures. */
+/* @{ */
+
+/** Generic unsigned 64-bit integer parameter type. */
+typedef struct MMAL_PARAMETER_UINT64_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   uint64_t value; /**< Parameter value */
+} MMAL_PARAMETER_UINT64_T;
+
+/** Generic signed 64-bit integer parameter type. */
+typedef struct MMAL_PARAMETER_INT64_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   int64_t value; /**< Parameter value */
+} MMAL_PARAMETER_INT64_T;
+
+/** Generic unsigned 32-bit integer parameter type. */
+typedef struct MMAL_PARAMETER_UINT32_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   uint32_t value; /**< Parameter value */
+} MMAL_PARAMETER_UINT32_T;
+
+/** Generic signed 32-bit integer parameter type. */
+typedef struct MMAL_PARAMETER_INT32_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   int32_t value; /**< Parameter value */
+} MMAL_PARAMETER_INT32_T;
+
+/** Generic rational parameter type. */
+typedef struct MMAL_PARAMETER_RATIONAL_T {
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_RATIONAL_T value; /**< Parameter value */
+} MMAL_PARAMETER_RATIONAL_T;
+
+/** Generic boolean parameter type. */
+typedef struct MMAL_PARAMETER_BOOLEAN_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_BOOL_T enable; /**< Parameter value */
+} MMAL_PARAMETER_BOOLEAN_T;
+
+/** Generic string parameter type. */
+typedef struct MMAL_PARAMETER_STRING_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   char str[1];        /**< Null-terminated string */
+} MMAL_PARAMETER_STRING_T;
+
+/** Generic array of bytes parameter type. */
+typedef struct MMAL_PARAMETER_BYTES_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   uint8_t data[1];   /**< Array of bytes */
+} MMAL_PARAMETER_BYTES_T;
+
+/** The value 1 in 16.16 fixed point form */
+#define MMAL_FIXED_16_16_ONE  (1 << 16)
+
+/** Generic two-dimensional scaling factor type. */
+typedef struct MMAL_PARAMETER_SCALEFACTOR_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_FIXED_16_16_T scale_x;  /**< Scaling factor in X-axis */
+   MMAL_FIXED_16_16_T scale_y;  /**< Scaling factor in Y-axis */
+} MMAL_PARAMETER_SCALEFACTOR_T;
+
+/** Valid mirror modes */
+typedef enum MMAL_PARAM_MIRROR_T
+{
+   MMAL_PARAM_MIRROR_NONE,
+   MMAL_PARAM_MIRROR_VERTICAL,
+   MMAL_PARAM_MIRROR_HORIZONTAL,
+   MMAL_PARAM_MIRROR_BOTH,
+} MMAL_PARAM_MIRROR_T;
+
+/** Generic mirror parameter type */
+typedef struct MMAL_PARAMETER_MIRROR_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_PARAM_MIRROR_T value;   /**< Mirror mode */
+} MMAL_PARAMETER_MIRROR_T;
+
+/** URI parameter type.
+ * The parameter may hold an arbitrary length, nul-terminated string as long
+ * as the size is set appropriately.
+ */
+typedef struct MMAL_PARAMETER_URI_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   char uri[1];    /**< URI string (null-terminated) */
+} MMAL_PARAMETER_URI_T;
+
+/** Generic encoding parameter type.
+ * The parameter may hold more than one encoding by overriding the size to
+ * include a bigger array.
+ */
+typedef struct MMAL_PARAMETER_ENCODING_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   uint32_t encoding[1];   /**< Array of FourCC encodings, see \ref MmalEncodings */
+} MMAL_PARAMETER_ENCODING_T;
+
+/** Generic frame-rate parameter type.
+ * Frame rates are specified as a rational number, using a pair of integers.
+ * Since there can be many valid pairs for the same ratio, a frame-rate may
+ * not contain exactly the same pairs of values when read back as it was
+ * when set.
+ */
+typedef struct MMAL_PARAMETER_FRAME_RATE_T {
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_RATIONAL_T frame_rate;   /**< Frame-rate value */
+} MMAL_PARAMETER_FRAME_RATE_T;
+
+/** Generic configuration-file setup type.
+ * Configuration files are transferred in small chunks. The component can
+ * save all the chunks into a buffer, then process the entire file later.
+ * This parameter initialises a config file to have the given size.
+ */
+typedef struct MMAL_PARAMETER_CONFIGFILE_T {
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   uint32_t file_size;           /**< Size of complete file data */
+} MMAL_PARAMETER_CONFIGFILE_T;
+
+/** Generic configuration-file chunk data type.
+ * Once a config file has been initialised, this parameter can be used to
+ * write an arbitrary chunk of the file data (limited by the maximum MMAL
+ * message size).
+ */
+typedef struct MMAL_PARAMETER_CONFIGFILE_CHUNK_T {
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   uint32_t size;                /**< Number of bytes being transferred in this chunk */
+   uint32_t offset;              /**< Offset of this chunk in the file */
+   char data[1];                 /**< Chunk data */
+} MMAL_PARAMETER_CONFIGFILE_CHUNK_T;
+
+/* @} */
+
+#endif /* MMAL_PARAMETERS_H */
diff --git a/interface/mmal/mmal_parameters_audio.h b/interface/mmal/mmal_parameters_audio.h
new file mode 100755 (executable)
index 0000000..36625f6
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_PARAMETERS_AUDIO_H
+#define MMAL_PARAMETERS_AUDIO_H
+
+#include "mmal_parameters_common.h"
+
+/*************************************************
+ * ALWAYS ADD NEW ENUMS AT THE END OF THIS LIST! *
+ ************************************************/
+
+/** Audio-specific MMAL parameter IDs.
+ * @ingroup MMAL_PARAMETER_IDS
+ */
+enum
+{
+   MMAL_PARAMETER_AUDIO_DESTINATION      /**< Takes a MMAL_PARAMETER_STRING_T */
+         = MMAL_PARAMETER_GROUP_AUDIO,
+   MMAL_PARAMETER_AUDIO_LATENCY_TARGET,  /**< Takes a MMAL_PARAMETER_AUDIO_LATENCY_TARGET_T */
+   MMAL_PARAMETER_AUDIO_SOURCE,
+   MMAL_PARAMETER_AUDIO_PASSTHROUGH,     /**< Takes a MMAL_PARAMETER_BOOLEAN_T */
+};
+
+/** Audio latency target to maintain.
+ * These settings are used to adjust the clock speed in order
+ * to match the measured audio latency to a specified value. */
+typedef struct MMAL_PARAMETER_AUDIO_LATENCY_TARGET_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_BOOL_T enable;   /**< whether this mode is enabled */
+   uint32_t filter;      /**< number of latency samples to filter on, good value: 1 */
+   uint32_t target;      /**< target latency (microseconds) */
+   uint32_t shift;       /**< shift for storing latency values, good value: 7 */
+   int32_t speed_factor; /**< multiplier for speed changes, in 24.8 format, good value: 256-512 */
+   int32_t inter_factor; /**< divider for comparing latency versus gradiant, good value: 300 */
+   int32_t adj_cap;      /**< limit for speed change before nSpeedFactor is applied, good value: 100 */
+} MMAL_PARAMETER_AUDIO_LATENCY_TARGET_T;
+
+#endif /* MMAL_PARAMETERS_AUDIO_H */
+
diff --git a/interface/mmal/mmal_parameters_camera.h b/interface/mmal/mmal_parameters_camera.h
new file mode 100755 (executable)
index 0000000..8a88571
--- /dev/null
@@ -0,0 +1,967 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+Copyright (c) 2011 Broadcom Europe Limited.
+All rights reserved.
+=============================================================================*/
+/** \file
+ * Multi-Media Abstraction Layer - Definition of some standard parameters.
+ */
+
+#ifndef MMAL_PARAMETERS_CAMERA_H
+#define MMAL_PARAMETERS_CAMERA_H
+
+#include "mmal_parameters_common.h"
+
+/*************************************************
+ * ALWAYS ADD NEW ENUMS AT THE END OF THIS LIST! *
+ ************************************************/
+
+/** Camera-specific MMAL parameter IDs.
+ * @ingroup MMAL_PARAMETER_IDS
+ */
+enum {
+   /* 0 */
+   MMAL_PARAMETER_THUMBNAIL_CONFIGURATION    /**< Takes a @ref MMAL_PARAMETER_THUMBNAIL_CONFIG_T */
+         = MMAL_PARAMETER_GROUP_CAMERA,
+   MMAL_PARAMETER_CAPTURE_QUALITY,           /**< Unused? */
+   MMAL_PARAMETER_ROTATION,                  /**< Takes a @ref MMAL_PARAMETER_INT32_T */
+   MMAL_PARAMETER_EXIF_DISABLE,              /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_EXIF,                      /**< Takes a @ref MMAL_PARAMETER_EXIF_T */
+   MMAL_PARAMETER_AWB_MODE,                  /**< Takes a @ref MMAL_PARAM_AWBMODE_T */
+   MMAL_PARAMETER_IMAGE_EFFECT,              /**< Takes a @ref MMAL_PARAMETER_IMAGEFX_T */
+   MMAL_PARAMETER_COLOUR_EFFECT,             /**< Takes a @ref MMAL_PARAMETER_COLOURFX_T */
+   MMAL_PARAMETER_FLICKER_AVOID,             /**< Takes a @ref MMAL_PARAMETER_FLICKERAVOID_T */
+   MMAL_PARAMETER_FLASH,                     /**< Takes a @ref MMAL_PARAMETER_FLASH_T */
+   MMAL_PARAMETER_REDEYE,                    /**< Takes a @ref MMAL_PARAMETER_REDEYE_T */
+   MMAL_PARAMETER_FOCUS,                     /**< Takes a @ref MMAL_PARAMETER_FOCUS_T */
+   MMAL_PARAMETER_FOCAL_LENGTHS,             /**< Unused? */
+   MMAL_PARAMETER_EXPOSURE_COMP,             /**< Takes a @ref MMAL_PARAMETER_INT32_T or MMAL_PARAMETER_RATIONAL_T */
+   MMAL_PARAMETER_ZOOM,                      /**< Takes a @ref MMAL_PARAMETER_SCALEFACTOR_T */
+   MMAL_PARAMETER_MIRROR,                    /**< Takes a @ref MMAL_PARAMETER_MIRROR_T */
+
+   /* 0x10 */
+   MMAL_PARAMETER_CAMERA_NUM,                /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
+   MMAL_PARAMETER_CAPTURE,                   /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_EXPOSURE_MODE,             /**< Takes a @ref MMAL_PARAMETER_EXPOSUREMODE_T */
+   MMAL_PARAMETER_EXP_METERING_MODE,         /**< Takes a @ref MMAL_PARAMETER_EXPOSUREMETERINGMODE_T */
+   MMAL_PARAMETER_FOCUS_STATUS,              /**< Takes a @ref MMAL_PARAMETER_FOCUS_STATUS_T */
+   MMAL_PARAMETER_CAMERA_CONFIG,             /**< Takes a @ref MMAL_PARAMETER_CAMERA_CONFIG_T */
+   MMAL_PARAMETER_CAPTURE_STATUS,            /**< Takes a @ref MMAL_PARAMETER_CAPTURE_STATUS_T */
+   MMAL_PARAMETER_FACE_TRACK,                /**< Takes a @ref MMAL_PARAMETER_FACE_TRACK_T */
+   MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS,  /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_JPEG_Q_FACTOR,             /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
+   MMAL_PARAMETER_FRAME_RATE,                /**< Takes a @ref MMAL_PARAMETER_FRAME_RATE_T */
+   MMAL_PARAMETER_USE_STC,                   /**< Takes a @ref MMAL_PARAMETER_CAMERA_STC_MODE_T */
+   MMAL_PARAMETER_CAMERA_INFO,               /**< Takes a @ref MMAL_PARAMETER_CAMERA_INFO_T */
+   MMAL_PARAMETER_VIDEO_STABILISATION,       /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_FACE_TRACK_RESULTS,        /**< Takes a @ref MMAL_PARAMETER_FACE_TRACK_RESULTS_T */
+   MMAL_PARAMETER_ENABLE_RAW_CAPTURE,        /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+
+   /* 0x20 */
+   MMAL_PARAMETER_DPF_FILE,                  /**< Takes a @ref MMAL_PARAMETER_URI_T */
+   MMAL_PARAMETER_ENABLE_DPF_FILE,           /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_DPF_FAIL_IS_FATAL,         /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_CAPTURE_MODE,              /**< Takes a @ref MMAL_PARAMETER_CAPTUREMODE_T */
+   MMAL_PARAMETER_FOCUS_REGIONS,             /**< Takes a @ref MMAL_PARAMETER_FOCUS_REGIONS_T */
+   MMAL_PARAMETER_INPUT_CROP,                /**< Takes a @ref MMAL_PARAMETER_INPUT_CROP_T */
+   MMAL_PARAMETER_SENSOR_INFORMATION,        /**< Takes a @ref MMAL_PARAMETER_SENSOR_INFORMATION_T */
+   MMAL_PARAMETER_FLASH_SELECT,              /**< Takes a @ref MMAL_PARAMETER_FLASH_SELECT_T */
+   MMAL_PARAMETER_FIELD_OF_VIEW,             /**< Takes a @ref MMAL_PARAMETER_FIELD_OF_VIEW_T */
+   MMAL_PARAMETER_HIGH_DYNAMIC_RANGE,        /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION, /**< Takes a @ref MMAL_PARAMETER_DRC_T */
+   MMAL_PARAMETER_ALGORITHM_CONTROL,         /**< Takes a @ref MMAL_PARAMETER_ALGORITHM_CONTROL_T */
+   MMAL_PARAMETER_SHARPNESS,                 /**< Takes a @ref MMAL_PARAMETER_RATIONAL_T */
+   MMAL_PARAMETER_CONTRAST,                  /**< Takes a @ref MMAL_PARAMETER_RATIONAL_T */
+   MMAL_PARAMETER_BRIGHTNESS,                /**< Takes a @ref MMAL_PARAMETER_RATIONAL_T */
+   MMAL_PARAMETER_SATURATION,                /**< Takes a @ref MMAL_PARAMETER_RATIONAL_T */
+
+   /* 0x30 */
+   MMAL_PARAMETER_ISO,                       /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
+   MMAL_PARAMETER_ANTISHAKE,                 /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS,   /**< Takes a @ref MMAL_PARAMETER_IMAGEFX_PARAMETERS_T */
+   MMAL_PARAMETER_CAMERA_BURST_CAPTURE,      /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_CAMERA_MIN_ISO,            /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
+   MMAL_PARAMETER_CAMERA_USE_CASE,           /**< Takes a @ref MMAL_PARAMETER_CAMERA_USE_CASE_T */
+   MMAL_PARAMETER_CAPTURE_STATS_PASS,        /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG, /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
+   MMAL_PARAMETER_ENABLE_REGISTER_FILE,      /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_REGISTER_FAIL_IS_FATAL,    /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_CONFIGFILE_REGISTERS,      /**< Takes a @ref MMAL_PARAMETER_CONFIGFILE_T */
+   MMAL_PARAMETER_CONFIGFILE_CHUNK_REGISTERS,/**< Takes a @ref MMAL_PARAMETER_CONFIGFILE_CHUNK_T */
+   MMAL_PARAMETER_JPEG_ATTACH_LOG,           /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_ZERO_SHUTTER_LAG,          /**< Takes a @ref MMAL_PARAMETER_ZEROSHUTTERLAG_T */
+   MMAL_PARAMETER_FPS_RANGE,                 /**< Takes a @ref MMAL_PARAMETER_FPS_RANGE_T */
+   MMAL_PARAMETER_CAPTURE_EXPOSURE_COMP,     /**< Takes a @ref MMAL_PARAMETER_INT32_T */
+
+   /* 0x40 */
+   MMAL_PARAMETER_SW_SHARPEN_DISABLE,        /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_FLASH_REQUIRED,            /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_SW_SATURATION_DISABLE,     /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_SHUTTER_SPEED,             /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
+   MMAL_PARAMETER_CUSTOM_AWB_GAINS,          /**< Takes a @ref MMAL_PARAMETER_AWB_GAINS_T */
+   MMAL_PARAMETER_CAMERA_SETTINGS,           /**< Takes a @ref MMAL_PARAMETER_CAMERA_SETTINGS_T */
+   MMAL_PARAMETER_PRIVACY_INDICATOR,         /**< Takes a @ref MMAL_PARAMETER_PRIVACY_INDICATOR_T */
+   MMAL_PARAMETER_VIDEO_DENOISE,             /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_STILLS_DENOISE,            /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_ANNOTATE,                  /**< Takes a @ref MMAL_PARAMETER_CAMERA_ANNOTATE_T */
+   MMAL_PARAMETER_STEREOSCOPIC_MODE,         /**< Takes a @ref MMAL_PARAMETER_STEREOSCOPIC_MODE_T */
+   MMAL_PARAMETER_CAMERA_INTERFACE,          /**< Takes a @ref MMAL_PARAMETER_CAMERA_INTERFACE_T */
+   MMAL_PARAMETER_CAMERA_CLOCKING_MODE,      /**< Takes a @ref MMAL_PARAMETER_CAMERA_CLOCKING_MODE_T */
+   MMAL_PARAMETER_CAMERA_RX_CONFIG,          /**< Takes a @ref MMAL_PARAMETER_CAMERA_RX_CONFIG_T */
+   MMAL_PARAMETER_CAMERA_RX_TIMING,          /**< Takes a @ref MMAL_PARAMETER_CAMERA_RX_TIMING_T */
+   MMAL_PARAMETER_DPF_CONFIG,                /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
+
+   /* 0x50 */
+   MMAL_PARAMETER_JPEG_RESTART_INTERVAL,     /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
+   MMAL_PARAMETER_CAMERA_ISP_BLOCK_OVERRIDE, /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
+   MMAL_PARAMETER_LENS_SHADING_OVERRIDE,     /**< Takes a @ref MMAL_PARAMETER_LENS_SHADING_T */
+   MMAL_PARAMETER_BLACK_LEVEL,               /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
+   MMAL_PARAMETER_RESIZE_PARAMS,             /**< Takes a @ref MMAL_PARAMETER_RESIZE_T */
+   MMAL_PARAMETER_CROP,                      /**< Takes a @ref MMAL_PARAMETER_CROP_T */
+   MMAL_PARAMETER_OUTPUT_SHIFT,              /**< Takes a @ref MMAL_PARAMETER_INT32_T */
+   MMAL_PARAMETER_CCM_SHIFT,                 /**< Takes a @ref MMAL_PARAMETER_INT32_T */
+   MMAL_PARAMETER_CUSTOM_CCM,                /**< Takes a @ref MMAL_PARAMETER_CUSTOM_CCM_T */
+   MMAL_PARAMETER_ANALOG_GAIN,               /**< Takes a @ref MMAL_PARAMETER_RATIONAL_T */
+   MMAL_PARAMETER_DIGITAL_GAIN,              /**< Takes a @ref MMAL_PARAMETER_RATIONAL_T */
+};
+
+/** Thumbnail configuration parameter type */
+typedef struct MMAL_PARAMETER_THUMBNAIL_CONFIG_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   uint32_t enable;                  /**< Enable generation of thumbnails during still capture */
+   uint32_t width;                   /**< Desired width of the thumbnail */
+   uint32_t height;                  /**< Desired height of the thumbnail */
+   uint32_t quality;                 /**< Desired compression quality of the thumbnail */
+} MMAL_PARAMETER_THUMBNAIL_CONFIG_T;
+
+/** EXIF parameter type. */
+typedef struct MMAL_PARAMETER_EXIF_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   uint32_t keylen;                            /**< If 0, assume key is terminated by '=', otherwise length of key and treat data as binary */
+   uint32_t value_offset;                      /**< Offset within data buffer of the start of the value. If 0, look for a "key=value" string */
+   uint32_t valuelen;                          /**< If 0, assume value is null-terminated, otherwise length of value and treat data as binary */
+   uint8_t data[1];                            /**< EXIF key/value string. Variable length */
+} MMAL_PARAMETER_EXIF_T;
+
+/** Exposure modes. */
+typedef enum
+{
+   MMAL_PARAM_EXPOSUREMODE_OFF,
+   MMAL_PARAM_EXPOSUREMODE_AUTO,
+   MMAL_PARAM_EXPOSUREMODE_NIGHT,
+   MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW,
+   MMAL_PARAM_EXPOSUREMODE_BACKLIGHT,
+   MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT,
+   MMAL_PARAM_EXPOSUREMODE_SPORTS,
+   MMAL_PARAM_EXPOSUREMODE_SNOW,
+   MMAL_PARAM_EXPOSUREMODE_BEACH,
+   MMAL_PARAM_EXPOSUREMODE_VERYLONG,
+   MMAL_PARAM_EXPOSUREMODE_FIXEDFPS,
+   MMAL_PARAM_EXPOSUREMODE_ANTISHAKE,
+   MMAL_PARAM_EXPOSUREMODE_FIREWORKS,
+   MMAL_PARAM_EXPOSUREMODE_MAX = 0x7fffffff
+} MMAL_PARAM_EXPOSUREMODE_T;
+
+typedef struct MMAL_PARAMETER_EXPOSUREMODE_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_PARAM_EXPOSUREMODE_T value;   /**< exposure mode */
+} MMAL_PARAMETER_EXPOSUREMODE_T;
+
+typedef enum
+{
+   MMAL_PARAM_EXPOSUREMETERINGMODE_AVERAGE,
+   MMAL_PARAM_EXPOSUREMETERINGMODE_SPOT,
+   MMAL_PARAM_EXPOSUREMETERINGMODE_BACKLIT,
+   MMAL_PARAM_EXPOSUREMETERINGMODE_MATRIX,
+   MMAL_PARAM_EXPOSUREMETERINGMODE_MAX = 0x7fffffff
+} MMAL_PARAM_EXPOSUREMETERINGMODE_T;
+
+typedef struct MMAL_PARAMETER_EXPOSUREMETERINGMODE_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_PARAM_EXPOSUREMETERINGMODE_T value;   /**< metering mode */
+} MMAL_PARAMETER_EXPOSUREMETERINGMODE_T;
+
+/** AWB parameter modes. */
+typedef enum MMAL_PARAM_AWBMODE_T
+{
+   MMAL_PARAM_AWBMODE_OFF,
+   MMAL_PARAM_AWBMODE_AUTO,
+   MMAL_PARAM_AWBMODE_SUNLIGHT,
+   MMAL_PARAM_AWBMODE_CLOUDY,
+   MMAL_PARAM_AWBMODE_SHADE,
+   MMAL_PARAM_AWBMODE_TUNGSTEN,
+   MMAL_PARAM_AWBMODE_FLUORESCENT,
+   MMAL_PARAM_AWBMODE_INCANDESCENT,
+   MMAL_PARAM_AWBMODE_FLASH,
+   MMAL_PARAM_AWBMODE_HORIZON,
+   MMAL_PARAM_AWBMODE_MAX = 0x7fffffff
+} MMAL_PARAM_AWBMODE_T;
+
+/** AWB parameter type. */
+typedef struct MMAL_PARAMETER_AWBMODE_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_PARAM_AWBMODE_T value;   /**< AWB mode */
+} MMAL_PARAMETER_AWBMODE_T;
+
+/** Image effect */
+typedef enum MMAL_PARAM_IMAGEFX_T
+{
+   MMAL_PARAM_IMAGEFX_NONE,
+   MMAL_PARAM_IMAGEFX_NEGATIVE,
+   MMAL_PARAM_IMAGEFX_SOLARIZE,
+   MMAL_PARAM_IMAGEFX_POSTERIZE,
+   MMAL_PARAM_IMAGEFX_WHITEBOARD,
+   MMAL_PARAM_IMAGEFX_BLACKBOARD,
+   MMAL_PARAM_IMAGEFX_SKETCH,
+   MMAL_PARAM_IMAGEFX_DENOISE,
+   MMAL_PARAM_IMAGEFX_EMBOSS,
+   MMAL_PARAM_IMAGEFX_OILPAINT,
+   MMAL_PARAM_IMAGEFX_HATCH,
+   MMAL_PARAM_IMAGEFX_GPEN,
+   MMAL_PARAM_IMAGEFX_PASTEL,
+   MMAL_PARAM_IMAGEFX_WATERCOLOUR,
+   MMAL_PARAM_IMAGEFX_FILM,
+   MMAL_PARAM_IMAGEFX_BLUR,
+   MMAL_PARAM_IMAGEFX_SATURATION,
+   MMAL_PARAM_IMAGEFX_COLOURSWAP,
+   MMAL_PARAM_IMAGEFX_WASHEDOUT,
+   MMAL_PARAM_IMAGEFX_POSTERISE,
+   MMAL_PARAM_IMAGEFX_COLOURPOINT,
+   MMAL_PARAM_IMAGEFX_COLOURBALANCE,
+   MMAL_PARAM_IMAGEFX_CARTOON,
+   MMAL_PARAM_IMAGEFX_DEINTERLACE_DOUBLE,
+   MMAL_PARAM_IMAGEFX_DEINTERLACE_ADV,
+   MMAL_PARAM_IMAGEFX_DEINTERLACE_FAST,
+   MMAL_PARAM_IMAGEFX_MAX = 0x7fffffff
+} MMAL_PARAM_IMAGEFX_T;
+
+typedef struct MMAL_PARAMETER_IMAGEFX_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_PARAM_IMAGEFX_T value;   /**< Image effect mode */
+} MMAL_PARAMETER_IMAGEFX_T;
+
+#define MMAL_MAX_IMAGEFX_PARAMETERS 6  /* Image effects library currently uses a maximum of 5 parameters per effect */
+
+typedef struct MMAL_PARAMETER_IMAGEFX_PARAMETERS_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_PARAM_IMAGEFX_T effect;   /**< Image effect mode */
+   uint32_t num_effect_params;     /**< Number of used elements in */
+   uint32_t effect_parameter[MMAL_MAX_IMAGEFX_PARAMETERS]; /**< Array of parameters */
+} MMAL_PARAMETER_IMAGEFX_PARAMETERS_T;
+
+/** Colour effect parameter type*/
+typedef struct MMAL_PARAMETER_COLOURFX_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   int32_t enable;
+   uint32_t u;
+   uint32_t v;
+} MMAL_PARAMETER_COLOURFX_T;
+
+typedef enum MMAL_CAMERA_STC_MODE_T
+{
+   MMAL_PARAM_STC_MODE_OFF,         /**< Frames do not have STCs, as needed in OpenMAX/IL */
+   MMAL_PARAM_STC_MODE_RAW,         /**< Use raw clock STC, needed for true pause/resume support */
+   MMAL_PARAM_STC_MODE_COOKED,      /**< Start the STC from the start of capture, only for quick demo code */
+   MMAL_PARAM_STC_MODE_MAX = 0x7fffffff
+} MMAL_CAMERA_STC_MODE_T;
+
+typedef struct MMAL_PARAMETER_CAMERA_STC_MODE_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+   MMAL_CAMERA_STC_MODE_T value;
+} MMAL_PARAMETER_CAMERA_STC_MODE_T;
+
+typedef enum MMAL_PARAM_FLICKERAVOID_T
+{
+   MMAL_PARAM_FLICKERAVOID_OFF,
+   MMAL_PARAM_FLICKERAVOID_AUTO,
+   MMAL_PARAM_FLICKERAVOID_50HZ,
+   MMAL_PARAM_FLICKERAVOID_60HZ,
+   MMAL_PARAM_FLICKERAVOID_MAX = 0x7FFFFFFF
+} MMAL_PARAM_FLICKERAVOID_T;
+
+typedef struct MMAL_PARAMETER_FLICKERAVOID_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_PARAM_FLICKERAVOID_T value;   /**< Flicker avoidance mode */
+} MMAL_PARAMETER_FLICKERAVOID_T;
+
+typedef enum MMAL_PARAM_FLASH_T
+{
+   MMAL_PARAM_FLASH_OFF,
+   MMAL_PARAM_FLASH_AUTO,
+   MMAL_PARAM_FLASH_ON,
+   MMAL_PARAM_FLASH_REDEYE,
+   MMAL_PARAM_FLASH_FILLIN,
+   MMAL_PARAM_FLASH_TORCH,
+   MMAL_PARAM_FLASH_MAX = 0x7FFFFFFF
+} MMAL_PARAM_FLASH_T;
+
+typedef struct MMAL_PARAMETER_FLASH_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_PARAM_FLASH_T value;   /**< Flash mode */
+} MMAL_PARAMETER_FLASH_T;
+
+typedef enum MMAL_PARAM_REDEYE_T
+{
+   MMAL_PARAM_REDEYE_OFF,
+   MMAL_PARAM_REDEYE_ON,
+   MMAL_PARAM_REDEYE_SIMPLE,
+   MMAL_PARAM_REDEYE_MAX = 0x7FFFFFFF
+} MMAL_PARAM_REDEYE_T;
+
+typedef struct MMAL_PARAMETER_REDEYE_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_PARAM_REDEYE_T value;   /**< Red eye reduction mode */
+} MMAL_PARAMETER_REDEYE_T;
+
+typedef enum MMAL_PARAM_FOCUS_T
+{
+   MMAL_PARAM_FOCUS_AUTO,
+   MMAL_PARAM_FOCUS_AUTO_NEAR,
+   MMAL_PARAM_FOCUS_AUTO_MACRO,
+   MMAL_PARAM_FOCUS_CAF,
+   MMAL_PARAM_FOCUS_CAF_NEAR,
+   MMAL_PARAM_FOCUS_FIXED_INFINITY,
+   MMAL_PARAM_FOCUS_FIXED_HYPERFOCAL,
+   MMAL_PARAM_FOCUS_FIXED_NEAR,
+   MMAL_PARAM_FOCUS_FIXED_MACRO,
+   MMAL_PARAM_FOCUS_EDOF,
+   MMAL_PARAM_FOCUS_CAF_MACRO,
+   MMAL_PARAM_FOCUS_CAF_FAST,
+   MMAL_PARAM_FOCUS_CAF_NEAR_FAST,
+   MMAL_PARAM_FOCUS_CAF_MACRO_FAST,
+   MMAL_PARAM_FOCUS_FIXED_CURRENT,
+   MMAL_PARAM_FOCUS_MAX = 0x7FFFFFFF
+} MMAL_PARAM_FOCUS_T;
+
+typedef struct MMAL_PARAMETER_FOCUS_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_PARAM_FOCUS_T value;   /**< Focus mode */
+} MMAL_PARAMETER_FOCUS_T;
+
+typedef enum MMAL_PARAM_CAPTURE_STATUS_T
+{
+   MMAL_PARAM_CAPTURE_STATUS_NOT_CAPTURING,
+   MMAL_PARAM_CAPTURE_STATUS_CAPTURE_STARTED,
+   MMAL_PARAM_CAPTURE_STATUS_CAPTURE_ENDED,
+
+   MMAL_PARAM_CAPTURE_STATUS_MAX = 0x7FFFFFFF
+} MMAL_PARAM_CAPTURE_STATUS_T;
+
+typedef struct MMAL_PARAMETER_CAPTURE_STATUS_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_PARAM_CAPTURE_STATUS_T status;   /**< Capture status */
+} MMAL_PARAMETER_CAPTURE_STATUS_T;
+
+typedef enum MMAL_PARAM_FOCUS_STATUS_T
+{
+   MMAL_PARAM_FOCUS_STATUS_OFF,
+   MMAL_PARAM_FOCUS_STATUS_REQUEST,
+   MMAL_PARAM_FOCUS_STATUS_REACHED,
+   MMAL_PARAM_FOCUS_STATUS_UNABLE_TO_REACH,
+   MMAL_PARAM_FOCUS_STATUS_LOST,
+   MMAL_PARAM_FOCUS_STATUS_CAF_MOVING,
+   MMAL_PARAM_FOCUS_STATUS_CAF_SUCCESS,
+   MMAL_PARAM_FOCUS_STATUS_CAF_FAILED,
+   MMAL_PARAM_FOCUS_STATUS_MANUAL_MOVING,
+   MMAL_PARAM_FOCUS_STATUS_MANUAL_REACHED,
+   MMAL_PARAM_FOCUS_STATUS_CAF_WATCHING,
+   MMAL_PARAM_FOCUS_STATUS_CAF_SCENE_CHANGED,
+
+   MMAL_PARAM_FOCUS_STATUS_MAX = 0x7FFFFFFF
+} MMAL_PARAM_FOCUS_STATUS_T;
+
+typedef struct MMAL_PARAMETER_FOCUS_STATUS_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_PARAM_FOCUS_STATUS_T status;   /**< Focus status */
+} MMAL_PARAMETER_FOCUS_STATUS_T;
+
+typedef enum MMAL_PARAM_FACE_TRACK_MODE_T
+{
+   MMAL_PARAM_FACE_DETECT_NONE,                           /**< Disables face detection */
+   MMAL_PARAM_FACE_DETECT_ON,                             /**< Enables face detection */
+   MMAL_PARAM_FACE_DETECT_MAX = 0x7FFFFFFF
+} MMAL_PARAM_FACE_TRACK_MODE_T;
+
+typedef struct MMAL_PARAMETER_FACE_TRACK_T /* face tracking control */
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+   MMAL_PARAM_FACE_TRACK_MODE_T mode;
+   uint32_t maxRegions;
+   uint32_t frames;
+   uint32_t quality;
+} MMAL_PARAMETER_FACE_TRACK_T;
+
+typedef struct MMAL_PARAMETER_FACE_TRACK_FACE_T /* face tracking face information */
+{
+   int32_t     face_id;             /**< Face ID. Should remain the same whilst the face is detected to remain in the scene */
+   int32_t     score;               /**< Confidence of the face detection. Range 1-100 (1=unsure, 100=positive). */
+   MMAL_RECT_T face_rect;           /**< Rectangle around the whole face */
+
+   MMAL_RECT_T eye_rect[2];         /**< Rectangle around the eyes ([0] = left eye, [1] = right eye) */
+   MMAL_RECT_T mouth_rect;          /**< Rectangle around the mouth */
+} MMAL_PARAMETER_FACE_TRACK_FACE_T;
+
+typedef struct MMAL_PARAMETER_FACE_TRACK_RESULTS_T /* face tracking results */
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   uint32_t num_faces;        /**< Number of faces detected */
+   uint32_t frame_width;      /**< Width of the frame on which the faces were detected (allows scaling) */
+   uint32_t frame_height;     /**< Height of the frame on which the faces were detected (allows scaling) */
+
+   MMAL_PARAMETER_FACE_TRACK_FACE_T faces[1];   /**< Face information (variable length array */
+} MMAL_PARAMETER_FACE_TRACK_RESULTS_T;
+
+typedef enum MMAL_PARAMETER_CAMERA_CONFIG_TIMESTAMP_MODE_T
+{
+   MMAL_PARAM_TIMESTAMP_MODE_ZERO,           /**< Always timestamp frames as 0 */
+   MMAL_PARAM_TIMESTAMP_MODE_RAW_STC,        /**< Use the raw STC value for the frame timestamp */
+   MMAL_PARAM_TIMESTAMP_MODE_RESET_STC,      /**< Use the STC timestamp but subtract the timestamp
+                                              * of the first frame sent to give a zero based timestamp.
+                                              */
+   MMAL_PARAM_TIMESTAMP_MODE_MAX = 0x7FFFFFFF
+} MMAL_PARAMETER_CAMERA_CONFIG_TIMESTAMP_MODE_T;
+
+typedef struct MMAL_PARAMETER_CAMERA_CONFIG_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   /* Parameters for setting up the image pools */
+   uint32_t max_stills_w;        /**< Max size of stills capture */
+   uint32_t max_stills_h;
+   uint32_t stills_yuv422;       /**< Allow YUV422 stills capture */
+   uint32_t one_shot_stills;     /**< Continuous or one shot stills captures. */
+
+   uint32_t max_preview_video_w; /**< Max size of the preview or video capture frames */
+   uint32_t max_preview_video_h;
+   uint32_t num_preview_video_frames;
+
+   uint32_t stills_capture_circular_buffer_height; /**< Sets the height of the circular buffer for stills capture. */
+
+   uint32_t fast_preview_resume;    /**< Allows preview/encode to resume as fast as possible after the stills input frame
+                                     * has been received, and then processes the still frame in the background
+                                     * whilst preview/encode has resumed.
+                                     * Actual mode is controlled by MMAL_PARAMETER_CAPTURE_MODE.
+                                     */
+
+   MMAL_PARAMETER_CAMERA_CONFIG_TIMESTAMP_MODE_T use_stc_timestamp;
+                                    /**< Selects algorithm for timestamping frames if there is no clock component connected.
+                                      */
+
+
+} MMAL_PARAMETER_CAMERA_CONFIG_T;
+
+#define MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS 4
+#define MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES 2
+#define MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN 16
+
+typedef struct MMAL_PARAMETER_CAMERA_INFO_CAMERA_T
+{
+   uint32_t    port_id;
+   uint32_t    max_width;
+   uint32_t    max_height;
+   MMAL_BOOL_T lens_present;
+   char        camera_name[MMAL_PARAMETER_CAMERA_INFO_MAX_STR_LEN];
+} MMAL_PARAMETER_CAMERA_INFO_CAMERA_T;
+
+typedef enum MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_T
+{
+   MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_XENON = 0, /* Make values explicit */
+   MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_LED   = 1, /* to ensure they match */
+   MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_OTHER = 2, /* values in config ini */
+   MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_MAX = 0x7FFFFFFF
+} MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_T;
+
+typedef struct MMAL_PARAMETER_CAMERA_INFO_FLASH_T
+{
+   MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_T flash_type;
+} MMAL_PARAMETER_CAMERA_INFO_FLASH_T;
+
+typedef struct MMAL_PARAMETER_CAMERA_INFO_T
+{
+   MMAL_PARAMETER_HEADER_T             hdr;
+   uint32_t                            num_cameras;
+   uint32_t                            num_flashes;
+   MMAL_PARAMETER_CAMERA_INFO_CAMERA_T cameras[MMAL_PARAMETER_CAMERA_INFO_MAX_CAMERAS];
+   MMAL_PARAMETER_CAMERA_INFO_FLASH_T  flashes[MMAL_PARAMETER_CAMERA_INFO_MAX_FLASHES];
+} MMAL_PARAMETER_CAMERA_INFO_T;
+
+typedef enum MMAL_PARAMETER_CAPTUREMODE_MODE_T
+{
+   MMAL_PARAM_CAPTUREMODE_WAIT_FOR_END,            /**< Resumes preview once capture is completed. */
+   MMAL_PARAM_CAPTUREMODE_WAIT_FOR_END_AND_HOLD,   /**< Resumes preview once capture is completed, and hold the image for subsequent reprocessing. */
+   MMAL_PARAM_CAPTUREMODE_RESUME_VF_IMMEDIATELY,   /**< Resumes preview as soon as possible once capture frame is received from the sensor.
+                                                    *   Requires fast_preview_resume to be set via MMAL_PARAMETER_CAMERA_CONFIG.
+                                                    */
+} MMAL_PARAMETER_CAPTUREMODE_MODE_T;
+
+/** Stills capture mode control. */
+typedef struct MMAL_PARAMETER_CAPTUREMODE_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+   MMAL_PARAMETER_CAPTUREMODE_MODE_T mode;
+} MMAL_PARAMETER_CAPTUREMODE_T;
+
+typedef enum MMAL_PARAMETER_FOCUS_REGION_TYPE_T
+{
+   MMAL_PARAMETER_FOCUS_REGION_TYPE_NORMAL,     /**< Region defines a generic region */
+   MMAL_PARAMETER_FOCUS_REGION_TYPE_FACE,       /**< Region defines a face */
+   MMAL_PARAMETER_FOCUS_REGION_TYPE_MAX
+} MMAL_PARAMETER_FOCUS_REGION_TYPE_T;
+
+typedef struct MMAL_PARAMETER_FOCUS_REGION_T
+{
+   MMAL_RECT_T rect;    /**< Focus rectangle as 0P16 fixed point values. */
+   uint32_t weight;     /**< Region weighting. */
+   uint32_t mask;       /**< Mask for multi-stage regions */
+   MMAL_PARAMETER_FOCUS_REGION_TYPE_T type;  /**< Region type */
+} MMAL_PARAMETER_FOCUS_REGION_T;
+
+typedef struct MMAL_PARAMETER_FOCUS_REGIONS_T
+{
+   MMAL_PARAMETER_HEADER_T          hdr;
+   uint32_t                         num_regions;      /**< Number of regions defined */
+   MMAL_BOOL_T                      lock_to_faces;    /**< If region is within tolerance of a face, adopt face rect instead of defined region */
+   MMAL_PARAMETER_FOCUS_REGION_T    regions[1];       /**< Variable number of regions */
+} MMAL_PARAMETER_FOCUS_REGIONS_T;
+
+typedef struct MMAL_PARAMETER_INPUT_CROP_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+   MMAL_RECT_T             rect;    /**< Crop rectangle as 16P16 fixed point values */
+} MMAL_PARAMETER_INPUT_CROP_T;
+
+typedef struct MMAL_PARAMETER_SENSOR_INFORMATION_T
+{
+   MMAL_PARAMETER_HEADER_T          hdr;
+   MMAL_RATIONAL_T                  f_number;         /**< Lens f-number */
+   MMAL_RATIONAL_T                  focal_length;     /**< Lens focal length */
+   uint32_t                         model_id;         /**< Sensor reported model id */
+   uint32_t                         manufacturer_id;  /**< Sensor reported manufacturer id */
+   uint32_t                         revision;         /**< Sensor reported revision */
+} MMAL_PARAMETER_SENSOR_INFORMATION_T;
+
+typedef struct MMAL_PARAMETER_FLASH_SELECT_T
+{
+   MMAL_PARAMETER_HEADER_T          hdr;
+   MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_T flash_type;   /**< Flash type to use */
+} MMAL_PARAMETER_FLASH_SELECT_T;
+
+typedef struct MMAL_PARAMETER_FIELD_OF_VIEW_T
+{
+   MMAL_PARAMETER_HEADER_T          hdr;
+   MMAL_RATIONAL_T                  fov_h;         /**< Horizontal field of view */
+   MMAL_RATIONAL_T                  fov_v;         /**< Vertical field of view */
+} MMAL_PARAMETER_FIELD_OF_VIEW_T;
+
+typedef enum MMAL_PARAMETER_DRC_STRENGTH_T
+{
+   MMAL_PARAMETER_DRC_STRENGTH_OFF,
+   MMAL_PARAMETER_DRC_STRENGTH_LOW,
+   MMAL_PARAMETER_DRC_STRENGTH_MEDIUM,
+   MMAL_PARAMETER_DRC_STRENGTH_HIGH,
+   MMAL_PARAMETER_DRC_STRENGTH_MAX = 0x7fffffff
+} MMAL_PARAMETER_DRC_STRENGTH_T;
+
+typedef struct MMAL_PARAMETER_DRC_T
+{
+   MMAL_PARAMETER_HEADER_T          hdr;
+   MMAL_PARAMETER_DRC_STRENGTH_T    strength;      /**< DRC strength */
+} MMAL_PARAMETER_DRC_T;
+
+typedef enum MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_T
+{
+   MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_FACETRACKING,
+   MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_REDEYE_REDUCTION,
+   MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_VIDEO_STABILISATION,
+   MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_WRITE_RAW,
+   MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_VIDEO_DENOISE,
+   MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_STILLS_DENOISE,
+   MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_TEMPORAL_DENOISE,
+   MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_ANTISHAKE,
+   MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_IMAGE_EFFECTS,
+   MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_DYNAMIC_RANGE_COMPRESSION,
+   MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_FACE_RECOGNITION,
+   MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_FACE_BEAUTIFICATION,
+   MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_SCENE_DETECTION,
+   MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_HIGH_DYNAMIC_RANGE,
+   MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_MAX = 0x7fffffff
+} MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_T;
+
+typedef struct MMAL_PARAMETER_ALGORITHM_CONTROL_T
+{
+   MMAL_PARAMETER_HEADER_T          hdr;
+   MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_T algorithm;
+   MMAL_BOOL_T                      enabled;
+} MMAL_PARAMETER_ALGORITHM_CONTROL_T;
+
+
+typedef enum MMAL_PARAM_CAMERA_USE_CASE_T
+{
+   MMAL_PARAM_CAMERA_USE_CASE_UNKNOWN,             /**< Compromise on behaviour as use case totally unknown */
+   MMAL_PARAM_CAMERA_USE_CASE_STILLS_CAPTURE,      /**< Stills capture use case */
+   MMAL_PARAM_CAMERA_USE_CASE_VIDEO_CAPTURE,       /**< Video encode (camcorder) use case */
+
+   MMAL_PARAM_CAMERA_USE_CASE_MAX = 0x7fffffff
+} MMAL_PARAM_CAMERA_USE_CASE_T;
+
+typedef struct MMAL_PARAMETER_CAMERA_USE_CASE_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_PARAM_CAMERA_USE_CASE_T use_case;   /**< Use case */
+} MMAL_PARAMETER_CAMERA_USE_CASE_T;
+
+typedef struct MMAL_PARAMETER_FPS_RANGE_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_RATIONAL_T   fps_low;                /**< Low end of the permitted framerate range */
+   MMAL_RATIONAL_T   fps_high;               /**< High end of the permitted framerate range */
+} MMAL_PARAMETER_FPS_RANGE_T;
+
+typedef struct MMAL_PARAMETER_ZEROSHUTTERLAG_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_BOOL_T zero_shutter_lag_mode;        /**< Select zero shutter lag mode from sensor */
+   MMAL_BOOL_T concurrent_capture;           /**< Activate full zero shutter lag mode and
+                                              *  use the last preview raw image for the stills capture
+                                              */
+} MMAL_PARAMETER_ZEROSHUTTERLAG_T;
+
+typedef struct MMAL_PARAMETER_AWB_GAINS_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_RATIONAL_T r_gain;                   /**< Red gain */
+   MMAL_RATIONAL_T b_gain;                   /**< Blue gain */
+} MMAL_PARAMETER_AWB_GAINS_T;
+
+typedef struct MMAL_PARAMETER_CAMERA_SETTINGS_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   uint32_t exposure;
+   MMAL_RATIONAL_T analog_gain;
+   MMAL_RATIONAL_T digital_gain;
+   MMAL_RATIONAL_T awb_red_gain;
+   MMAL_RATIONAL_T awb_blue_gain;
+   uint32_t focus_position;
+} MMAL_PARAMETER_CAMERA_SETTINGS_T;
+
+typedef enum MMAL_PARAM_PRIVACY_INDICATOR_T
+{
+   MMAL_PARAMETER_PRIVACY_INDICATOR_OFF,        /**< Indicator will be off. */
+   MMAL_PARAMETER_PRIVACY_INDICATOR_ON,         /**< Indicator will come on just after a stills capture and
+                                                 *   and remain on for 2seconds, or will be on whilst output[1]
+                                                 *   is actively producing images.
+                                                 */
+   MMAL_PARAMETER_PRIVACY_INDICATOR_FORCE_ON,   /**< Turns indicator of for 2s independent of capture status.
+                                                 *   Set this mode repeatedly to keep the indicator on for a
+                                                 *   longer period.
+                                                 */
+   MMAL_PARAMETER_PRIVACY_INDICATOR_MAX = 0x7fffffff
+} MMAL_PARAM_PRIVACY_INDICATOR_T;
+
+typedef struct MMAL_PARAMETER_PRIVACY_INDICATOR_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_PARAM_PRIVACY_INDICATOR_T mode;
+} MMAL_PARAMETER_PRIVACY_INDICATOR_T;
+
+#define MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN 32
+typedef struct MMAL_PARAMETER_CAMERA_ANNOTATE_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_BOOL_T enable;
+   char text[MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN];
+   MMAL_BOOL_T show_shutter;
+   MMAL_BOOL_T show_analog_gain;
+   MMAL_BOOL_T show_lens;
+   MMAL_BOOL_T show_caf;
+   MMAL_BOOL_T show_motion;
+} MMAL_PARAMETER_CAMERA_ANNOTATE_T;
+
+#define MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V2 256
+typedef struct MMAL_PARAMETER_CAMERA_ANNOTATE_V2_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_BOOL_T enable;
+   MMAL_BOOL_T show_shutter;
+   MMAL_BOOL_T show_analog_gain;
+   MMAL_BOOL_T show_lens;
+   MMAL_BOOL_T show_caf;
+   MMAL_BOOL_T show_motion;
+   MMAL_BOOL_T show_frame_num;
+   MMAL_BOOL_T black_text_background;
+   char text[MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V2];
+} MMAL_PARAMETER_CAMERA_ANNOTATE_V2_T;
+
+#define MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3 256
+typedef struct MMAL_PARAMETER_CAMERA_ANNOTATE_V3_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_BOOL_T enable;
+   MMAL_BOOL_T show_shutter;
+   MMAL_BOOL_T show_analog_gain;
+   MMAL_BOOL_T show_lens;
+   MMAL_BOOL_T show_caf;
+   MMAL_BOOL_T show_motion;
+   MMAL_BOOL_T show_frame_num;
+   MMAL_BOOL_T enable_text_background;
+   MMAL_BOOL_T custom_background_colour;
+   uint8_t     custom_background_Y;
+   uint8_t     custom_background_U;
+   uint8_t     custom_background_V;
+   uint8_t     dummy1;
+   MMAL_BOOL_T custom_text_colour;
+   uint8_t     custom_text_Y;
+   uint8_t     custom_text_U;
+   uint8_t     custom_text_V;
+   uint8_t     text_size;
+   char text[MMAL_CAMERA_ANNOTATE_MAX_TEXT_LEN_V3];
+} MMAL_PARAMETER_CAMERA_ANNOTATE_V3_T;
+
+typedef enum MMAL_STEREOSCOPIC_MODE_T {
+   MMAL_STEREOSCOPIC_MODE_NONE = 0,
+   MMAL_STEREOSCOPIC_MODE_SIDE_BY_SIDE = 1,
+   MMAL_STEREOSCOPIC_MODE_TOP_BOTTOM = 2,
+   MMAL_STEREOSCOPIC_MODE_MAX = 0x7FFFFFFF,
+} MMAL_STEREOSCOPIC_MODE_T;
+
+typedef struct MMAL_PARAMETER_STEREOSCOPIC_MODE_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_STEREOSCOPIC_MODE_T mode;
+   MMAL_BOOL_T decimate;
+   MMAL_BOOL_T swap_eyes;
+} MMAL_PARAMETER_STEREOSCOPIC_MODE_T;
+
+typedef enum MMAL_CAMERA_INTERFACE_T {
+   MMAL_CAMERA_INTERFACE_CSI2 = 0,
+   MMAL_CAMERA_INTERFACE_CCP2 = 1,
+   MMAL_CAMERA_INTERFACE_CPI = 2,
+   MMAL_CAMERA_INTERFACE_MAX = 0x7FFFFFFF,
+} MMAL_CAMERA_INTERFACE_T;
+
+typedef struct MMAL_PARAMETER_CAMERA_INTERFACE_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_CAMERA_INTERFACE_T mode;
+} MMAL_PARAMETER_CAMERA_INTERFACE_T;
+
+typedef enum MMAL_CAMERA_CLOCKING_MODE_T {
+   MMAL_CAMERA_CLOCKING_MODE_STROBE = 0,
+   MMAL_CAMERA_CLOCKING_MODE_CLOCK = 1,
+   MMAL_CAMERA_CLOCKING_MODE_MAX = 0x7FFFFFFF,
+} MMAL_CAMERA_CLOCKING_MODE_T;
+
+typedef struct MMAL_PARAMETER_CAMERA_CLOCKING_MODE_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_CAMERA_CLOCKING_MODE_T mode;
+} MMAL_PARAMETER_CAMERA_CLOCKING_MODE_T;
+
+typedef enum MMAL_CAMERA_RX_CONFIG_DECODE {
+   MMAL_CAMERA_RX_CONFIG_DECODE_NONE = 0,
+   MMAL_CAMERA_RX_CONFIG_DECODE_DPCM8TO10 = 1,
+   MMAL_CAMERA_RX_CONFIG_DECODE_DPCM7TO10 = 2,
+   MMAL_CAMERA_RX_CONFIG_DECODE_DPCM6TO10 = 3,
+   MMAL_CAMERA_RX_CONFIG_DECODE_DPCM8TO12 = 4,
+   MMAL_CAMERA_RX_CONFIG_DECODE_DPCM7TO12 = 5,
+   MMAL_CAMERA_RX_CONFIG_DECODE_DPCM6TO12 = 6,
+   MMAL_CAMERA_RX_CONFIG_DECODE_DPCM10TO14 = 7,
+   MMAL_CAMERA_RX_CONFIG_DECODE_DPCM8TO14 = 8,
+   MMAL_CAMERA_RX_CONFIG_DECODE_DPCM12TO16 = 9,
+   MMAL_CAMERA_RX_CONFIG_DECODE_DPCM10TO16 = 10,
+   MMAL_CAMERA_RX_CONFIG_DECODE_DPCM8TO16 = 11,
+   MMAL_CAMERA_RX_CONFIG_DECODE_MAX = 0x7FFFFFFF
+} MMAL_CAMERA_RX_CONFIG_DECODE;
+
+typedef enum MMAL_CAMERA_RX_CONFIG_ENCODE {
+   MMAL_CAMERA_RX_CONFIG_ENCODE_NONE = 0,
+   MMAL_CAMERA_RX_CONFIG_ENCODE_DPCM10TO8 = 1,
+   MMAL_CAMERA_RX_CONFIG_ENCODE_DPCM12TO8 = 2,
+   MMAL_CAMERA_RX_CONFIG_ENCODE_DPCM14TO8 = 3,
+   MMAL_CAMERA_RX_CONFIG_ENCODE_MAX = 0x7FFFFFFF
+} MMAL_CAMERA_RX_CONFIG_ENCODE;
+
+typedef enum MMAL_CAMERA_RX_CONFIG_UNPACK {
+   MMAL_CAMERA_RX_CONFIG_UNPACK_NONE = 0,
+   MMAL_CAMERA_RX_CONFIG_UNPACK_6 = 1,
+   MMAL_CAMERA_RX_CONFIG_UNPACK_7 = 2,
+   MMAL_CAMERA_RX_CONFIG_UNPACK_8 = 3,
+   MMAL_CAMERA_RX_CONFIG_UNPACK_10 = 4,
+   MMAL_CAMERA_RX_CONFIG_UNPACK_12 = 5,
+   MMAL_CAMERA_RX_CONFIG_UNPACK_14 = 6,
+   MMAL_CAMERA_RX_CONFIG_UNPACK_16 = 7,
+   MMAL_CAMERA_RX_CONFIG_UNPACK_MAX = 0x7FFFFFFF
+} MMAL_CAMERA_RX_CONFIG_UNPACK;
+
+typedef enum MMAL_CAMERA_RX_CONFIG_PACK {
+   MMAL_CAMERA_RX_CONFIG_PACK_NONE = 0,
+   MMAL_CAMERA_RX_CONFIG_PACK_8 = 1,
+   MMAL_CAMERA_RX_CONFIG_PACK_10 = 2,
+   MMAL_CAMERA_RX_CONFIG_PACK_12 = 3,
+   MMAL_CAMERA_RX_CONFIG_PACK_14 = 4,
+   MMAL_CAMERA_RX_CONFIG_PACK_16 = 5,
+   MMAL_CAMERA_RX_CONFIG_PACK_RAW10 = 6,
+   MMAL_CAMERA_RX_CONFIG_PACK_RAW12 = 7,
+   MMAL_CAMERA_RX_CONFIG_PACK_MAX = 0x7FFFFFFF
+} MMAL_CAMERA_RX_CONFIG_PACK;
+
+typedef struct MMAL_PARAMETER_CAMERA_RX_CONFIG_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_CAMERA_RX_CONFIG_DECODE decode;
+   MMAL_CAMERA_RX_CONFIG_ENCODE encode;
+   MMAL_CAMERA_RX_CONFIG_UNPACK unpack;
+   MMAL_CAMERA_RX_CONFIG_PACK pack;
+   uint32_t data_lanes;
+   uint32_t encode_block_length;
+   uint32_t embedded_data_lines;
+   uint32_t image_id;
+} MMAL_PARAMETER_CAMERA_RX_CONFIG_T;
+
+typedef struct MMAL_PARAMETER_CAMERA_RX_TIMING_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   uint32_t timing1;
+   uint32_t timing2;
+   uint32_t timing3;
+   uint32_t timing4;
+   uint32_t timing5;
+   uint32_t term1;
+   uint32_t term2;
+   uint32_t cpi_timing1;
+   uint32_t cpi_timing2;
+} MMAL_PARAMETER_CAMERA_RX_TIMING_T;
+
+typedef struct MMAL_PARAMETER_LENS_SHADING_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_BOOL_T enabled;
+   uint32_t grid_cell_size;
+   uint32_t grid_width;
+   uint32_t grid_stride;
+   uint32_t grid_height;
+   uint32_t mem_handle_table;
+   uint32_t ref_transform;
+} MMAL_PARAMETER_LENS_SHADING_T;
+
+/*
+The mode determines the kind of resize.
+MMAL_RESIZE_BOX allow the max_width and max_height to set a bounding box into
+which the output must fit.
+MMAL_RESIZE_BYTES allows max_bytes to set the maximum number of bytes into which the
+full output frame must fit.  Two flags aid the setting of the output
+size. preserve_aspect_ratio sets whether the resize should
+preserve the aspect ratio of the incoming
+image. allow_upscaling sets whether the resize is allowed to
+increase the size of the output image compared to the size of the
+input image.
+*/
+typedef enum MMAL_RESIZEMODE_T {
+   MMAL_RESIZE_NONE,
+   MMAL_RESIZE_CROP,
+   MMAL_RESIZE_BOX,
+   MMAL_RESIZE_BYTES,
+   MMAL_RESIZE_DUMMY = 0x7FFFFFFF
+} MMAL_RESIZEMODE_T;
+
+typedef struct MMAL_PARAMETER_RESIZE_T {
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_RESIZEMODE_T mode;
+   uint32_t max_width;
+   uint32_t max_height;
+   uint32_t max_bytes;
+   MMAL_BOOL_T preserve_aspect_ratio;
+   MMAL_BOOL_T allow_upscaling;
+} MMAL_PARAMETER_RESIZE_T;
+
+typedef struct MMAL_PARAMETER_CROP_T {
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_RECT_T rect;
+} MMAL_PARAMETER_CROP_T;
+
+typedef struct MMAL_PARAMETER_CCM_T {
+   MMAL_RATIONAL_T ccm[3][3];
+   int32_t offsets[3];
+} MMAL_PARAMETER_CCM_T;
+
+typedef struct MMAL_PARAMETER_CUSTOM_CCM_T {
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_BOOL_T enable;           /**< Enable the custom CCM. */
+   MMAL_PARAMETER_CCM_T ccm;     /**< CCM to be used. */
+} MMAL_PARAMETER_CUSTOM_CCM_T;
+
+#endif  /* MMAL_PARAMETERS_CAMERA_H */
diff --git a/interface/mmal/mmal_parameters_clock.h b/interface/mmal/mmal_parameters_clock.h
new file mode 100755 (executable)
index 0000000..9f798a1
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_PARAMETERS_CLOCK_H
+#define MMAL_PARAMETERS_CLOCK_H
+
+#include "mmal_clock.h"
+#include "mmal_parameters_common.h"
+
+/*************************************************
+ * ALWAYS ADD NEW ENUMS AT THE END OF THIS LIST! *
+ ************************************************/
+
+/** Clock-specific MMAL parameter IDs.
+ * @ingroup MMAL_PARAMETER_IDS
+ */
+enum
+{
+   MMAL_PARAMETER_CLOCK_REFERENCE           /**< Takes a MMAL_PARAMETER_BOOLEAN_T */
+      = MMAL_PARAMETER_GROUP_CLOCK,
+   MMAL_PARAMETER_CLOCK_ACTIVE,             /**< Takes a MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_CLOCK_SCALE,              /**< Takes a MMAL_PARAMETER_RATIONAL_T */
+   MMAL_PARAMETER_CLOCK_TIME,               /**< Takes a MMAL_PARAMETER_INT64_T */
+   MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD,   /**< Takes a MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD_T */
+   MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD,  /**< Takes a MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD_T */
+   MMAL_PARAMETER_CLOCK_REQUEST_THRESHOLD,  /**< Takes a MMAL_PARAMETER_CLOCK_REQUEST_THRESHOLD_T */
+   MMAL_PARAMETER_CLOCK_ENABLE_BUFFER_INFO, /**< Takes a MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_CLOCK_FRAME_RATE,         /**< Takes a MMAL_PARAMETER_RATIONAL_T */
+   MMAL_PARAMETER_CLOCK_LATENCY,            /**< Takes a MMAL_PARAMETER_CLOCK_LATENCY_T */
+};
+
+/** Media-time update thresholds */
+typedef struct MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_CLOCK_UPDATE_THRESHOLD_T value;
+} MMAL_PARAMETER_CLOCK_UPDATE_THRESHOLD_T;
+
+/** Media-time discontinuity settings */
+typedef struct MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_CLOCK_DISCONT_THRESHOLD_T value;
+} MMAL_PARAMETER_CLOCK_DISCONT_THRESHOLD_T;
+
+/** Media-time future frame drop settings */
+typedef struct MMAL_PARAMETER_CLOCK_REQUEST_THRESHOLD_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_CLOCK_REQUEST_THRESHOLD_T value;
+} MMAL_PARAMETER_CLOCK_REQUEST_THRESHOLD_T;
+
+/** Clock latency parameter */
+typedef struct MMAL_PARAMETER_CLOCK_LATENCY_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_CLOCK_LATENCY_T value;
+} MMAL_PARAMETER_CLOCK_LATENCY_T;
+
+#endif /* MMAL_PARAMETERS_CLOCK_H */
diff --git a/interface/mmal/mmal_parameters_common.h b/interface/mmal/mmal_parameters_common.h
new file mode 100755 (executable)
index 0000000..28c3118
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_PARAMETERS_COMMON_H
+#define MMAL_PARAMETERS_COMMON_H
+
+/** @defgroup MMAL_PARAMETER_IDS Pre-defined MMAL parameter IDs
+ * @ingroup MmalParameters
+ * @{
+ */
+
+/** @name Parameter groups
+ * Parameters are divided into groups, and then allocated sequentially within
+ * a group using an enum.
+ * @{
+ */
+
+/** Common parameter ID group, used with many types of component. */
+#define MMAL_PARAMETER_GROUP_COMMON            (0<<16)
+/** Camera-specific parameter ID group. */
+#define MMAL_PARAMETER_GROUP_CAMERA            (1<<16)
+/** Video-specific parameter ID group. */
+#define MMAL_PARAMETER_GROUP_VIDEO             (2<<16)
+/** Audio-specific parameter ID group. */
+#define MMAL_PARAMETER_GROUP_AUDIO             (3<<16)
+/** Clock-specific parameter ID group. */
+#define MMAL_PARAMETER_GROUP_CLOCK             (4<<16)
+/** Miracast-specific parameter ID group. */
+#define MMAL_PARAMETER_GROUP_MIRACAST       (5<<16)
+
+
+/**@}*/
+
+/** Common MMAL parameter IDs.
+ */
+enum {
+   MMAL_PARAMETER_UNUSED                  /**< Never a valid parameter ID */
+         = MMAL_PARAMETER_GROUP_COMMON,
+   MMAL_PARAMETER_SUPPORTED_ENCODINGS,    /**< Takes a MMAL_PARAMETER_ENCODING_T */
+   MMAL_PARAMETER_URI,                    /**< Takes a MMAL_PARAMETER_URI_T */
+   MMAL_PARAMETER_CHANGE_EVENT_REQUEST,   /**< Takes a MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T */
+   MMAL_PARAMETER_ZERO_COPY,              /**< Takes a MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_BUFFER_REQUIREMENTS,    /**< Takes a MMAL_PARAMETER_BUFFER_REQUIREMENTS_T */
+   MMAL_PARAMETER_STATISTICS,             /**< Takes a MMAL_PARAMETER_STATISTICS_T */
+   MMAL_PARAMETER_CORE_STATISTICS,        /**< Takes a MMAL_PARAMETER_CORE_STATISTICS_T */
+   MMAL_PARAMETER_MEM_USAGE,              /**< Takes a MMAL_PARAMETER_MEM_USAGE_T */
+   MMAL_PARAMETER_BUFFER_FLAG_FILTER,     /**< Takes a MMAL_PARAMETER_UINT32_T */
+   MMAL_PARAMETER_SEEK,                   /**< Takes a MMAL_PARAMETER_SEEK_T */
+   MMAL_PARAMETER_POWERMON_ENABLE,        /**< Takes a MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_LOGGING,                /**< Takes a MMAL_PARAMETER_LOGGING_T */
+   MMAL_PARAMETER_SYSTEM_TIME,            /**< Takes a MMAL_PARAMETER_UINT64_T */
+   MMAL_PARAMETER_NO_IMAGE_PADDING,       /**< Takes a MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_LOCKSTEP_ENABLE         /**< Takes a MMAL_PARAMETER_BOOLEAN_T */
+};
+
+/**@}*/
+
+/** Parameter header type. All parameter structures need to begin with this type.
+ * The \ref id field must be set to a parameter ID, such as one of those listed on
+ * the \ref MMAL_PARAMETER_IDS "Pre-defined MMAL parameter IDs" page.
+ */
+typedef struct MMAL_PARAMETER_HEADER_T
+{
+   uint32_t id;      /**< Parameter ID. */
+   uint32_t size;    /**< Size in bytes of the parameter (including the header) */
+} MMAL_PARAMETER_HEADER_T;
+
+/** Change event request parameter type.
+ * This is used to control whether a \ref MMAL_EVENT_PARAMETER_CHANGED_T event
+ * is issued should a given parameter change.
+ */
+typedef struct MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   uint32_t change_id;  /**< ID of parameter that may change, see \ref MMAL_PARAMETER_IDS */
+   MMAL_BOOL_T enable;  /**< True if the event is enabled, false if disabled */
+} MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T;
+
+/** Buffer requirements parameter.
+ * This is mainly used to increase the requirements of a component. */
+typedef struct MMAL_PARAMETER_BUFFER_REQUIREMENTS_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   uint32_t buffer_num_min;          /**< Minimum number of buffers the port requires */
+   uint32_t buffer_size_min;         /**< Minimum size of buffers the port requires */
+   uint32_t buffer_alignment_min;    /**< Minimum alignment requirement for the buffers.
+                                          A value of zero means no special alignment requirements. */
+   uint32_t buffer_num_recommended;  /**< Number of buffers the port recommends for optimal performance.
+                                          A value of zero means no special recommendation. */
+   uint32_t buffer_size_recommended; /**< Size of buffers the port recommends for optimal performance.
+                                          A value of zero means no special recommendation. */
+} MMAL_PARAMETER_BUFFER_REQUIREMENTS_T;
+
+/** Seek request parameter type.
+ * This is used to issue a seek request to a source component.
+ */
+typedef struct MMAL_PARAMETER_SEEK_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   int64_t offset;  /**< Offset (in microseconds) to seek to */
+   uint32_t flags;  /**< Seeking flags */
+
+#define MMAL_PARAM_SEEK_FLAG_PRECISE 0x1 /**< Choose precise seeking even if slower */
+#define MMAL_PARAM_SEEK_FLAG_FORWARD 0x2 /**< Seek to the next keyframe following the specified offset */
+
+} MMAL_PARAMETER_SEEK_T;
+
+/** Port statistics for debugging/test purposes.
+ * Ports may support query of this parameter to return statistics for debugging or
+ * test purposes. Not all values may be relevant for a given port.
+ */
+typedef struct MMAL_PARAMETER_STATISTICS_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   uint32_t buffer_count;           /**< Total number of buffers processed */
+   uint32_t frame_count;            /**< Total number of frames processed */
+   uint32_t frames_skipped;         /**< Number of frames without expected PTS based on frame rate */
+   uint32_t frames_discarded;       /**< Number of frames discarded */
+   uint32_t eos_seen;               /**< Set if the end of stream has been reached */
+   uint32_t maximum_frame_bytes;    /**< Maximum frame size in bytes */
+   int64_t  total_bytes;            /**< Total number of bytes processed */
+   uint32_t corrupt_macroblocks;    /**< Number of corrupt macroblocks in the stream */
+} MMAL_PARAMETER_STATISTICS_T;
+
+typedef enum
+{
+   MMAL_CORE_STATS_RX,
+   MMAL_CORE_STATS_TX,
+   MMAL_CORE_STATS_MAX = 0x7fffffff /* Force 32 bit size for this enum */
+} MMAL_CORE_STATS_DIR;
+
+/** MMAL core statistics. These are collected by the core itself.
+ */
+typedef struct MMAL_PARAMETER_CORE_STATISTICS_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+   MMAL_CORE_STATS_DIR dir;
+   MMAL_BOOL_T reset;               /**< Reset to zero after reading */
+   MMAL_CORE_STATISTICS_T stats;    /**< The statistics */
+} MMAL_PARAMETER_CORE_STATISTICS_T;
+
+/**
+ * Component memory usage statistics.
+ */
+typedef struct MMAL_PARAMETER_MEM_USAGE_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+   /**< The amount of memory allocated in image pools by the component */
+   uint32_t pool_mem_alloc_size;
+} MMAL_PARAMETER_MEM_USAGE_T;
+
+/**
+ * Logging control.
+ */
+typedef struct MMAL_PARAMETER_LOGGING_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+   uint32_t set;     /**< Logging bits to set */
+   uint32_t clear;   /**< Logging bits to clear */
+} MMAL_PARAMETER_LOGGING_T;
+
+#endif /* MMAL_PARAMETERS_COMMON_H */
+
diff --git a/interface/mmal/mmal_parameters_video.h b/interface/mmal/mmal_parameters_video.h
new file mode 100755 (executable)
index 0000000..c4ef7f1
--- /dev/null
@@ -0,0 +1,512 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_PARAMETERS_VIDEO_H
+#define MMAL_PARAMETERS_VIDEO_H
+
+#include "mmal_parameters_common.h"
+
+/*************************************************
+ * ALWAYS ADD NEW ENUMS AT THE END OF THIS LIST! *
+ ************************************************/
+
+/** Video-specific MMAL parameter IDs.
+ * @ingroup MMAL_PARAMETER_IDS
+ */
+enum {
+   MMAL_PARAMETER_DISPLAYREGION           /**< Takes a @ref MMAL_DISPLAYREGION_T */
+         = MMAL_PARAMETER_GROUP_VIDEO,
+   MMAL_PARAMETER_SUPPORTED_PROFILES,     /**< Takes a @ref MMAL_PARAMETER_VIDEO_PROFILE_T */
+   MMAL_PARAMETER_PROFILE,                /**< Takes a @ref MMAL_PARAMETER_VIDEO_PROFILE_T */
+   MMAL_PARAMETER_INTRAPERIOD,            /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
+   MMAL_PARAMETER_RATECONTROL,            /**< Takes a @ref MMAL_PARAMETER_VIDEO_RATECONTROL_T */
+   MMAL_PARAMETER_NALUNITFORMAT,          /**< Takes a @ref MMAL_PARAMETER_VIDEO_NALUNITFORMAT_T */
+   MMAL_PARAMETER_MINIMISE_FRAGMENTATION, /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_MB_ROWS_PER_SLICE,      /**< Takes a @ref MMAL_PARAMETER_UINT32_T.
+                                           * Setting the value to zero resets to the default (one slice per frame). */
+   MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION,  /**< Takes a @ref MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION_T */
+   MMAL_PARAMETER_VIDEO_EEDE_ENABLE,      /**< Takes a @ref MMAL_PARAMETER_VIDEO_EEDE_ENABLE_T */
+   MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE,    /**< Takes a @ref MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE_T */
+   MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME,  /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T.
+                                           * Request an I-frame. */
+   MMAL_PARAMETER_VIDEO_INTRA_REFRESH,    /**< Takes a @ref MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T */
+   MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT,  /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T. */
+   MMAL_PARAMETER_VIDEO_BIT_RATE,         /**< Takes a @ref MMAL_PARAMETER_UINT32_T.
+                                           * Run-time bit rate control */
+   MMAL_PARAMETER_VIDEO_FRAME_RATE,       /**< Takes a @ref MMAL_PARAMETER_FRAME_RATE_T */
+   MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT, /**< Takes a @ref MMAL_PARAMETER_UINT32_T. */
+   MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT, /**< Takes a @ref MMAL_PARAMETER_UINT32_T. */
+   MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL,  /**< Takes a @ref MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL_T. */
+   MMAL_PARAMETER_EXTRA_BUFFERS,          /**< Takes a @ref MMAL_PARAMETER_UINT32_T. */
+   MMAL_PARAMETER_VIDEO_ALIGN_HORIZ,      /**< Takes a @ref MMAL_PARAMETER_UINT32_T.
+                                               Changing this paramater from the default can reduce frame rate
+                                               because image buffers need to be re-pitched.*/
+   MMAL_PARAMETER_VIDEO_ALIGN_VERT,        /**< Takes a @ref MMAL_PARAMETER_UINT32_T.
+                                               Changing this paramater from the default can reduce frame rate
+                                               because image buffers need to be re-pitched.*/
+   MMAL_PARAMETER_VIDEO_DROPPABLE_PFRAMES,      /**< Take a @ref MMAL_PARAMETER_BOOLEAN_T. */
+   MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT,   /**< Takes a @ref MMAL_PARAMETER_UINT32_T. */
+   MMAL_PARAMETER_VIDEO_ENCODE_QP_P,            /**< Takes a @ref MMAL_PARAMETER_UINT32_T. */
+   MMAL_PARAMETER_VIDEO_ENCODE_RC_SLICE_DQUANT, /**< Takes a @ref MMAL_PARAMETER_UINT32_T. */
+   MMAL_PARAMETER_VIDEO_ENCODE_FRAME_LIMIT_BITS,    /**< Takes a @ref MMAL_PARAMETER_UINT32_T */
+   MMAL_PARAMETER_VIDEO_ENCODE_PEAK_RATE,       /**< Takes a @ref MMAL_PARAMETER_UINT32_T. */       
+
+   /*H264 specific parameters*/
+   MMAL_PARAMETER_VIDEO_ENCODE_H264_DISABLE_CABAC,      /**< Take a @ref MMAL_PARAMETER_BOOLEAN_T. */
+   MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_LATENCY,        /**< Take a @ref MMAL_PARAMETER_BOOLEAN_T. */
+   MMAL_PARAMETER_VIDEO_ENCODE_H264_AU_DELIMITERS,      /**< Take a @ref MMAL_PARAMETER_BOOLEAN_T. */
+   MMAL_PARAMETER_VIDEO_ENCODE_H264_DEBLOCK_IDC,        /**< Takes a @ref MMAL_PARAMETER_UINT32_T. */
+   MMAL_PARAMETER_VIDEO_ENCODE_H264_MB_INTRA_MODE,      /**< Takes a @ref MMAL_PARAMETER_VIDEO_ENCODER_H264_MB_INTRA_MODES_T. */
+
+   MMAL_PARAMETER_VIDEO_ENCODE_HEADER_ON_OPEN,  /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_VIDEO_ENCODE_PRECODE_FOR_QP,  /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+
+   MMAL_PARAMETER_VIDEO_DRM_INIT_INFO,          /**< Takes a @ref MMAL_PARAMETER_VIDEO_DRM_INIT_INFO_T. */
+   MMAL_PARAMETER_VIDEO_TIMESTAMP_FIFO,         /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_VIDEO_DECODE_ERROR_CONCEALMENT,        /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER,              /**< Takes a @ref MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER_T. */
+
+   MMAL_PARAMETER_VIDEO_DECODE_CONFIG_VD3,       /**< Takes a @ref MMAL_PARAMETER_BYTES_T */
+   MMAL_PARAMETER_VIDEO_ENCODE_H264_VCL_HRD_PARAMETERS, /**< Take a @ref MMAL_PARAMETER_BOOLEAN_T. */
+   MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_DELAY_HRD_FLAG, /**< Take a @ref MMAL_PARAMETER_BOOLEAN_T. */
+   MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER,            /**< Take a @ref MMAL_PARAMETER_BOOLEAN_T. */
+   MMAL_PARAMETER_VIDEO_ENCODE_SEI_ENABLE,               /**< Take a @ref MMAL_PARAMETER_BOOLEAN_T. */
+   MMAL_PARAMETER_VIDEO_ENCODE_INLINE_VECTORS,           /**< Take a @ref MMAL_PARAMETER_BOOLEAN_T. */
+   MMAL_PARAMETER_VIDEO_RENDER_STATS,           /**< Take a @ref MMAL_PARAMETER_VIDEO_RENDER_STATS_T. */
+   MMAL_PARAMETER_VIDEO_INTERLACE_TYPE,           /**< Take a @ref MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T. */
+   MMAL_PARAMETER_VIDEO_INTERPOLATE_TIMESTAMPS,         /**< Takes a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_VIDEO_ENCODE_SPS_TIMING,         /**< Take a @ref MMAL_PARAMETER_BOOLEAN_T */
+   MMAL_PARAMETER_VIDEO_MAX_NUM_CALLBACKS,         /**< Take a @ref MMAL_PARAMETER_UINT32_T */
+   MMAL_PARAMETER_VIDEO_SOURCE_PATTERN,         /**< Take a @ref MMAL_PARAMETER_SOURCE_PATTERN_T */
+};
+
+/** Display transformations.
+ * Although an enumeration, the values correspond to combinations of:
+ * \li 1 Reflect in a vertical axis
+ * \li 2 180 degree rotation
+ * \li 4 Reflect in the leading diagonal
+ */
+typedef enum MMAL_DISPLAYTRANSFORM_T {
+   MMAL_DISPLAY_ROT0 = 0,
+   MMAL_DISPLAY_MIRROR_ROT0 = 1,
+   MMAL_DISPLAY_MIRROR_ROT180 = 2,
+   MMAL_DISPLAY_ROT180 = 3,
+   MMAL_DISPLAY_MIRROR_ROT90 = 4,
+   MMAL_DISPLAY_ROT270 = 5,
+   MMAL_DISPLAY_ROT90 = 6,
+   MMAL_DISPLAY_MIRROR_ROT270 = 7,
+   MMAL_DISPLAY_DUMMY = 0x7FFFFFFF
+} MMAL_DISPLAYTRANSFORM_T;
+
+/** Display modes. */
+typedef enum MMAL_DISPLAYMODE_T {
+   MMAL_DISPLAY_MODE_FILL = 0,
+   MMAL_DISPLAY_MODE_LETTERBOX = 1,
+   // these allow a left eye source->dest to be specified and the right eye mapping will be inferred by symmetry
+   MMAL_DISPLAY_MODE_STEREO_LEFT_TO_LEFT = 2,
+   MMAL_DISPLAY_MODE_STEREO_TOP_TO_TOP = 3,
+   MMAL_DISPLAY_MODE_STEREO_LEFT_TO_TOP = 4,
+   MMAL_DISPLAY_MODE_STEREO_TOP_TO_LEFT = 5,
+   MMAL_DISPLAY_MODE_DUMMY = 0x7FFFFFFF
+} MMAL_DISPLAYMODE_T;
+
+/** Values used to indicate which fields are used when setting the
+ * display configuration */
+typedef enum MMAL_DISPLAYSET_T {
+   MMAL_DISPLAY_SET_NONE = 0,
+   MMAL_DISPLAY_SET_NUM = 1,
+   MMAL_DISPLAY_SET_FULLSCREEN = 2,
+   MMAL_DISPLAY_SET_TRANSFORM = 4,
+   MMAL_DISPLAY_SET_DEST_RECT = 8,
+   MMAL_DISPLAY_SET_SRC_RECT = 0x10,
+   MMAL_DISPLAY_SET_MODE = 0x20,
+   MMAL_DISPLAY_SET_PIXEL = 0x40,
+   MMAL_DISPLAY_SET_NOASPECT = 0x80,
+   MMAL_DISPLAY_SET_LAYER = 0x100,
+   MMAL_DISPLAY_SET_COPYPROTECT = 0x200,
+   MMAL_DISPLAY_SET_ALPHA = 0x400,
+   MMAL_DISPLAY_SET_DUMMY = 0x7FFFFFFF
+} MMAL_DISPLAYSET_T;
+
+/**
+This config sets the output display device, as well as the region used
+on the output display, any display transformation, and some flags to
+indicate how to scale the image.
+*/
+
+typedef struct MMAL_DISPLAYREGION_T {
+   MMAL_PARAMETER_HEADER_T hdr;
+   /** Bitfield that indicates which fields are set and should be used. All
+    * other fields will maintain their current value.
+    * \ref MMAL_DISPLAYSET_T defines the bits that can be combined.
+    */
+   uint32_t set;
+   /** Describes the display output device, with 0 typically being a directly
+    * connected LCD display.  The actual values will depend on the hardware.
+    * Code using hard-wired numbers (e.g. 2) is certain to fail.
+    */
+   uint32_t display_num;
+   /** Indicates that we are using the full device screen area, rather than
+    * a window of the display.  If zero, then dest_rect is used to specify a
+    * region of the display to use.
+    */
+   MMAL_BOOL_T fullscreen;
+   /** Indicates any rotation or flipping used to map frames onto the natural
+    * display orientation.
+    */
+   MMAL_DISPLAYTRANSFORM_T transform;
+   /** Where to display the frame within the screen, if fullscreen is zero.
+    */
+   MMAL_RECT_T dest_rect;
+   /** Indicates which area of the frame to display. If all values are zero,
+    * the whole frame will be used.
+    */
+   MMAL_RECT_T src_rect;
+   /** If set to non-zero, indicates that any display scaling should disregard
+    * the aspect ratio of the frame region being displayed.
+    */
+   MMAL_BOOL_T noaspect;
+   /** Indicates how the image should be scaled to fit the display. \code
+    * MMAL_DISPLAY_MODE_FILL \endcode indicates that the image should fill the
+    * screen by potentially cropping the frames.  Setting \code mode \endcode
+    * to \code MMAL_DISPLAY_MODE_LETTERBOX \endcode indicates that all the source
+    * region should be displayed and black bars added if necessary.
+    */
+   MMAL_DISPLAYMODE_T mode;
+   /** If non-zero, defines the width of a source pixel relative to \code pixel_y
+    * \endcode.  If zero, then pixels default to being square.
+    */
+   uint32_t pixel_x;
+   /** If non-zero, defines the height of a source pixel relative to \code pixel_x
+    * \endcode.  If zero, then pixels default to being square.
+    */
+   uint32_t pixel_y;
+   /** Sets the relative depth of the images, with greater values being in front
+    * of smaller values.
+    */
+   int32_t layer;
+   /** Set to non-zero to ensure copy protection is used on output.
+    */
+   MMAL_BOOL_T copyprotect_required;
+   /** Level of opacity of the layer, where zero is fully transparent and
+    * 255 is fully opaque.
+    */
+   uint32_t alpha;
+} MMAL_DISPLAYREGION_T;
+
+/** Video profiles.
+ * Only certain combinations of profile and level will be valid.
+ * @ref MMAL_VIDEO_LEVEL_T
+ */
+typedef enum MMAL_VIDEO_PROFILE_T {
+    MMAL_VIDEO_PROFILE_H263_BASELINE,
+    MMAL_VIDEO_PROFILE_H263_H320CODING,
+    MMAL_VIDEO_PROFILE_H263_BACKWARDCOMPATIBLE,
+    MMAL_VIDEO_PROFILE_H263_ISWV2,
+    MMAL_VIDEO_PROFILE_H263_ISWV3,
+    MMAL_VIDEO_PROFILE_H263_HIGHCOMPRESSION,
+    MMAL_VIDEO_PROFILE_H263_INTERNET,
+    MMAL_VIDEO_PROFILE_H263_INTERLACE,
+    MMAL_VIDEO_PROFILE_H263_HIGHLATENCY,
+    MMAL_VIDEO_PROFILE_MP4V_SIMPLE,
+    MMAL_VIDEO_PROFILE_MP4V_SIMPLESCALABLE,
+    MMAL_VIDEO_PROFILE_MP4V_CORE,
+    MMAL_VIDEO_PROFILE_MP4V_MAIN,
+    MMAL_VIDEO_PROFILE_MP4V_NBIT,
+    MMAL_VIDEO_PROFILE_MP4V_SCALABLETEXTURE,
+    MMAL_VIDEO_PROFILE_MP4V_SIMPLEFACE,
+    MMAL_VIDEO_PROFILE_MP4V_SIMPLEFBA,
+    MMAL_VIDEO_PROFILE_MP4V_BASICANIMATED,
+    MMAL_VIDEO_PROFILE_MP4V_HYBRID,
+    MMAL_VIDEO_PROFILE_MP4V_ADVANCEDREALTIME,
+    MMAL_VIDEO_PROFILE_MP4V_CORESCALABLE,
+    MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCODING,
+    MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCORE,
+    MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSCALABLE,
+    MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSIMPLE,
+    MMAL_VIDEO_PROFILE_H264_BASELINE,
+    MMAL_VIDEO_PROFILE_H264_MAIN,
+    MMAL_VIDEO_PROFILE_H264_EXTENDED,
+    MMAL_VIDEO_PROFILE_H264_HIGH,
+    MMAL_VIDEO_PROFILE_H264_HIGH10,
+    MMAL_VIDEO_PROFILE_H264_HIGH422,
+    MMAL_VIDEO_PROFILE_H264_HIGH444,
+    MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE,
+    MMAL_VIDEO_PROFILE_DUMMY = 0x7FFFFFFF
+} MMAL_VIDEO_PROFILE_T;
+
+/** Video levels.
+ * Only certain combinations of profile and level will be valid.
+ * @ref MMAL_VIDEO_PROFILE_T
+ */
+typedef enum MMAL_VIDEO_LEVEL_T {
+    MMAL_VIDEO_LEVEL_H263_10,
+    MMAL_VIDEO_LEVEL_H263_20,
+    MMAL_VIDEO_LEVEL_H263_30,
+    MMAL_VIDEO_LEVEL_H263_40,
+    MMAL_VIDEO_LEVEL_H263_45,
+    MMAL_VIDEO_LEVEL_H263_50,
+    MMAL_VIDEO_LEVEL_H263_60,
+    MMAL_VIDEO_LEVEL_H263_70,
+    MMAL_VIDEO_LEVEL_MP4V_0,
+    MMAL_VIDEO_LEVEL_MP4V_0b,
+    MMAL_VIDEO_LEVEL_MP4V_1,
+    MMAL_VIDEO_LEVEL_MP4V_2,
+    MMAL_VIDEO_LEVEL_MP4V_3,
+    MMAL_VIDEO_LEVEL_MP4V_4,
+    MMAL_VIDEO_LEVEL_MP4V_4a,
+    MMAL_VIDEO_LEVEL_MP4V_5,
+    MMAL_VIDEO_LEVEL_MP4V_6,
+    MMAL_VIDEO_LEVEL_H264_1,
+    MMAL_VIDEO_LEVEL_H264_1b,
+    MMAL_VIDEO_LEVEL_H264_11,
+    MMAL_VIDEO_LEVEL_H264_12,
+    MMAL_VIDEO_LEVEL_H264_13,
+    MMAL_VIDEO_LEVEL_H264_2,
+    MMAL_VIDEO_LEVEL_H264_21,
+    MMAL_VIDEO_LEVEL_H264_22,
+    MMAL_VIDEO_LEVEL_H264_3,
+    MMAL_VIDEO_LEVEL_H264_31,
+    MMAL_VIDEO_LEVEL_H264_32,
+    MMAL_VIDEO_LEVEL_H264_4,
+    MMAL_VIDEO_LEVEL_H264_41,
+    MMAL_VIDEO_LEVEL_H264_42,
+    MMAL_VIDEO_LEVEL_H264_5,
+    MMAL_VIDEO_LEVEL_H264_51,
+    MMAL_VIDEO_LEVEL_DUMMY = 0x7FFFFFFF
+} MMAL_VIDEO_LEVEL_T;
+
+/** Video profile and level setting.
+ * This is a variable length structure when querying the supported profiles and
+ * levels. To get more than one, pass a structure with more profile/level pairs.
+ */
+typedef struct MMAL_PARAMETER_VIDEO_PROFILE_T
+{
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   struct
+   {
+      MMAL_VIDEO_PROFILE_T profile;
+      MMAL_VIDEO_LEVEL_T level;
+   } profile[1];
+} MMAL_PARAMETER_VIDEO_PROFILE_T;
+
+/** Manner of video rate control */
+typedef enum MMAL_VIDEO_RATECONTROL_T {
+    MMAL_VIDEO_RATECONTROL_DEFAULT,
+    MMAL_VIDEO_RATECONTROL_VARIABLE,
+    MMAL_VIDEO_RATECONTROL_CONSTANT,
+    MMAL_VIDEO_RATECONTROL_VARIABLE_SKIP_FRAMES,
+    MMAL_VIDEO_RATECONTROL_CONSTANT_SKIP_FRAMES,
+    MMAL_VIDEO_RATECONTROL_DUMMY = 0x7fffffff
+} MMAL_VIDEO_RATECONTROL_T;
+
+/** Intra refresh modes */
+typedef enum MMAL_VIDEO_INTRA_REFRESH_T {
+    MMAL_VIDEO_INTRA_REFRESH_CYCLIC,
+    MMAL_VIDEO_INTRA_REFRESH_ADAPTIVE,
+    MMAL_VIDEO_INTRA_REFRESH_BOTH,
+    MMAL_VIDEO_INTRA_REFRESH_KHRONOSEXTENSIONS = 0x6F000000,
+    MMAL_VIDEO_INTRA_REFRESH_VENDORSTARTUNUSED = 0x7F000000,
+    MMAL_VIDEO_INTRA_REFRESH_CYCLIC_MROWS,
+    MMAL_VIDEO_INTRA_REFRESH_PSEUDO_RAND,
+    MMAL_VIDEO_INTRA_REFRESH_MAX,
+    MMAL_VIDEO_INTRA_REFRESH_DUMMY         = 0x7FFFFFFF
+} MMAL_VIDEO_INTRA_REFRESH_T;
+
+/*Encode RC Models Supported*/
+typedef enum MMAL_VIDEO_ENCODE_RC_MODEL_T {
+    MMAL_VIDEO_ENCODER_RC_MODEL_DEFAULT    = 0,
+    MMAL_VIDEO_ENCODER_RC_MODEL_JVT = MMAL_VIDEO_ENCODER_RC_MODEL_DEFAULT,
+    MMAL_VIDEO_ENCODER_RC_MODEL_VOWIFI,
+    MMAL_VIDEO_ENCODER_RC_MODEL_CBR,
+    MMAL_VIDEO_ENCODER_RC_MODEL_LAST,
+    MMAL_VIDEO_ENCODER_RC_MODEL_DUMMY      = 0x7FFFFFFF
+} MMAL_VIDEO_ENCODE_RC_MODEL_T;
+
+typedef struct MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL_T {
+    MMAL_PARAMETER_HEADER_T hdr;
+    MMAL_VIDEO_ENCODE_RC_MODEL_T rc_model;
+}MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL_T;
+
+/** Video rate control setting */
+typedef struct MMAL_PARAMETER_VIDEO_RATECONTROL_T {
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_VIDEO_RATECONTROL_T control;
+} MMAL_PARAMETER_VIDEO_RATECONTROL_T;
+
+/*H264 INTRA MB MODES*/
+typedef enum MMAL_VIDEO_ENCODE_H264_MB_INTRA_MODES_T {
+    MMAL_VIDEO_ENCODER_H264_MB_4x4_INTRA = 1,
+    MMAL_VIDEO_ENCODER_H264_MB_8x8_INTRA = 2,
+    MMAL_VIDEO_ENCODER_H264_MB_16x16_INTRA = 4,
+    MMAL_VIDEO_ENCODER_H264_MB_INTRA_DUMMY = 0x7fffffff
+} MMAL_VIDEO_ENCODE_H264_MB_INTRA_MODES_T;
+
+typedef struct MMAL_PARAMETER_VIDEO_ENCODER_H264_MB_INTRA_MODES_T {
+    MMAL_PARAMETER_HEADER_T hdr;
+    MMAL_VIDEO_ENCODE_H264_MB_INTRA_MODES_T mb_mode;
+}MMAL_PARAMETER_VIDEO_ENCODER_H264_MB_INTRA_MODES_T;
+
+/** NAL unit formats */
+typedef enum MMAL_VIDEO_NALUNITFORMAT_T {
+    MMAL_VIDEO_NALUNITFORMAT_STARTCODES = 1,
+    MMAL_VIDEO_NALUNITFORMAT_NALUNITPERBUFFER = 2,
+    MMAL_VIDEO_NALUNITFORMAT_ONEBYTEINTERLEAVELENGTH = 4,
+    MMAL_VIDEO_NALUNITFORMAT_TWOBYTEINTERLEAVELENGTH = 8,
+    MMAL_VIDEO_NALUNITFORMAT_FOURBYTEINTERLEAVELENGTH = 16,
+    MMAL_VIDEO_NALUNITFORMAT_DUMMY = 0x7fffffff
+} MMAL_VIDEO_NALUNITFORMAT_T;
+
+/** NAL unit format setting */
+typedef struct MMAL_PARAMETER_VIDEO_NALUNITFORMAT_T {
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_VIDEO_NALUNITFORMAT_T format;
+} MMAL_PARAMETER_VIDEO_NALUNITFORMAT_T;
+
+/** H264 Only: Overrides for max macro-blocks per second, max framesize, 
+ * and max bitrates. This overrides the default maximums for the configured level.
+ */
+typedef struct MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION_T {
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   uint32_t custom_max_mbps;
+   uint32_t custom_max_fs;
+   uint32_t custom_max_br_and_cpb;
+} MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION_T;
+
+/** H264 Only: Overrides for max macro-blocks per second, max framesize,
+ * and max bitrates. This overrides the default maximums for the configured level.
+ */
+typedef struct MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T {
+   MMAL_PARAMETER_HEADER_T hdr;
+
+    MMAL_VIDEO_INTRA_REFRESH_T refresh_mode;
+    uint32_t air_mbs;
+    uint32_t air_ref;
+    uint32_t cir_mbs;
+    uint32_t pir_mbs;
+} MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T;
+
+/** Structure for enabling EEDE, we keep it like this for now, there could be extra fields in the future */
+typedef struct MMAL_PARAMETER_VIDEO_EEDE_ENABLE_T {
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   uint32_t enable;
+} MMAL_PARAMETER_VIDEO_EEDE_ENABLE_T;
+
+/** Structure for setting lossrate for EEDE, we keep it like this for now, there could be extra fields in the future */
+typedef struct MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE_T {
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   uint32_t loss_rate;
+} MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE_T;
+
+/** Structure for setting initial DRM parameters */
+typedef struct MMAL_PARAMETER_VIDEO_DRM_INIT_INFO_T {
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   uint32_t current_time;
+   uint32_t ticks_per_sec;
+   uint8_t  lhs[32];
+} MMAL_PARAMETER_VIDEO_DRM_INIT_INFO_T;
+
+/** Structure for requesting a hardware-protected memory buffer **/
+typedef struct MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER_T {
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   uint32_t size_wanted;     /**< Input. Zero size means internal video decoder buffer,
+                                 mem_handle and phys_addr not returned in this case */
+   uint32_t protect;         /**< Input. 1 = protect, 0 = unprotect */
+
+   uint32_t mem_handle;      /**< Output. Handle for protected buffer */
+   void *   phys_addr;       /**< Output. Physical memory address of protected buffer */
+
+} MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER_T;
+
+typedef struct MMAL_PARAMETER_VIDEO_RENDER_STATS_T {
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_BOOL_T valid;
+   uint32_t match;
+   uint32_t period;
+   uint32_t phase;
+   uint32_t pixel_clock_nominal;
+   uint32_t pixel_clock;
+   uint32_t hvs_status;
+   uint32_t dummy[2];
+} MMAL_PARAMETER_VIDEO_RENDER_STATS_T;
+
+typedef enum MMAL_INTERLACETYPE_T {
+   MMAL_InterlaceProgressive,                    /**< The data is not interlaced, it is progressive scan */
+   MMAL_InterlaceFieldSingleUpperFirst,          /**< The data is interlaced, fields sent
+                                                     separately in temporal order, with upper field first */
+   MMAL_InterlaceFieldSingleLowerFirst,          /**< The data is interlaced, fields sent
+                                                     separately in temporal order, with lower field first */
+   MMAL_InterlaceFieldsInterleavedUpperFirst,    /**< The data is interlaced, two fields sent together line
+                                                     interleaved, with the upper field temporally earlier */
+   MMAL_InterlaceFieldsInterleavedLowerFirst,    /**< The data is interlaced, two fields sent together line
+                                                     interleaved, with the lower field temporally earlier */
+   MMAL_InterlaceMixed,                          /**< The stream may contain a mixture of progressive
+                                                     and interlaced frames */
+   MMAL_InterlaceKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+   MMAL_InterlaceVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+   MMAL_InterlaceMax = 0x7FFFFFFF
+} MMAL_INTERLACETYPE_T;
+
+typedef struct MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T {
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_INTERLACETYPE_T eMode;       /**< The interlace type of the content */
+   MMAL_BOOL_T bRepeatFirstField;    /**< Whether to repeat the first field */
+} MMAL_PARAMETER_VIDEO_INTERLACE_TYPE_T;
+
+typedef enum MMAL_SOURCE_PATTERN_T {
+   MMAL_VIDEO_SOURCE_PATTERN_WHITE,
+   MMAL_VIDEO_SOURCE_PATTERN_BLACK,
+   MMAL_VIDEO_SOURCE_PATTERN_DIAGONAL,
+   MMAL_VIDEO_SOURCE_PATTERN_NOISE,
+   MMAL_VIDEO_SOURCE_PATTERN_RANDOM,
+   MMAL_VIDEO_SOURCE_PATTERN_COLOUR,
+   MMAL_VIDEO_SOURCE_PATTERN_BLOCKS,
+   MMAL_VIDEO_SOURCE_PATTERN_SWIRLY,
+   MMAL_VIDEO_SOURCE_PATTERN_DUMMY = 0x7fffffff
+} MMAL_SOURCE_PATTERN_T;
+
+typedef struct MMAL_PARAMETER_VIDEO_SOURCE_PATTERN_T {
+   MMAL_PARAMETER_HEADER_T hdr;
+
+   MMAL_SOURCE_PATTERN_T pattern;
+   uint32_t param;                              /**< Colour for PATTERN_COLOUR mode */
+   uint32_t framecount;                         /**< Number of frames to produce. 0 for continuous. */
+   MMAL_RATIONAL_T framerate;                   /**< Framerate used when determining buffer timestamps */
+} MMAL_PARAMETER_VIDEO_SOURCE_PATTERN_T;
+
+
+#endif
diff --git a/interface/mmal/mmal_pool.h b/interface/mmal/mmal_pool.h
new file mode 100755 (executable)
index 0000000..4df5853
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_POOL_H
+#define MMAL_POOL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup MmalPool Pools of buffer headers
+ * A pool of buffer headers is composed of a queue (\ref MMAL_QUEUE_T) and a user
+ * specified number of buffer headers (\ref MMAL_BUFFER_HEADER_T). */
+/* @{ */
+
+#include "mmal_queue.h"
+
+/** Definition of a pool */
+typedef struct MMAL_POOL_T
+{
+   MMAL_QUEUE_T *queue;             /**< Queue used by the pool */
+   uint32_t headers_num;            /**< Number of buffer headers in the pool */
+   MMAL_BUFFER_HEADER_T **header;   /**< Array of buffer headers belonging to the pool */
+} MMAL_POOL_T;
+
+/** Allocator alloc prototype
+ *
+ * @param context The context pointer passed in on pool creation.
+ * @param size    The size of the allocation required, in bytes.
+ * @return The pointer to the newly allocated memory, or NULL on failure.
+ */
+typedef void *(*mmal_pool_allocator_alloc_t)(void *context, uint32_t size);
+/** Allocator free prototype
+ *
+ * @param context The context pointer passed in on pool creation.
+ * @param mem     The pointer to the memory to be released.
+ */
+typedef void (*mmal_pool_allocator_free_t)(void *context, void *mem);
+
+/** Create a pool of MMAL_BUFFER_HEADER_T.
+ * After allocation, all allocated buffer headers will have been added to the queue.
+ *
+ * It is valid to create a pool with no buffer headers, or with zero size payload buffers.
+ * The mmal_pool_resize() function can be used to increase or decrease the number of buffer
+ * headers, or the size of the payload buffers, after creation of the pool.
+ *
+ * The payload buffers may also be allocated independently by the client, and assigned
+ * to the buffer headers, but it will be the responsibility of the client to deal with
+ * resizing and releasing the memory. It is recommended that mmal_pool_create_with_allocator()
+ * is used in this case, supplying allocator function pointers that will be used as
+ * necessary by MMAL.
+ *
+ * @param headers      Number of buffer headers to be allocated with the pool.
+ * @param payload_size Size of the payload buffer that will be allocated in 
+ *                     each of the buffer headers.
+ * @return Pointer to the newly created pool or NULL on failure.
+ */
+MMAL_POOL_T *mmal_pool_create(unsigned int headers, uint32_t payload_size);
+
+/** Create a pool of MMAL_BUFFER_HEADER_T.
+ * After allocation, all allocated buffer headers will have been added to the queue.
+ *
+ * It is valid to create a pool with no buffer headers, or with zero size payload buffers.
+ * The mmal_pool_resize() function can be used to increase or decrease the number of buffer
+ * headers, or the size of the payload buffers, after creation of the pool. The allocators
+ * passed during creation shall be used when resizing the payload buffers.
+ *
+ * @param headers      Number of buffer headers to be allocated with the pool.
+ * @param payload_size Size of the payload buffer that will be allocated in
+ *                     each of the buffer headers.
+ * @param allocator_context Pointer to the context of the allocator.
+ * @param allocator_alloc   Function pointer for the alloc call of the allocator.
+ * @param allocator_free    Function pointer for the free call of the allocator.
+ *
+ * @return Pointer to the newly created pool or NULL on failure.
+ */
+MMAL_POOL_T *mmal_pool_create_with_allocator(unsigned int headers, uint32_t payload_size,
+                              void *allocator_context, mmal_pool_allocator_alloc_t allocator_alloc,
+                              mmal_pool_allocator_free_t allocator_free);
+
+/** Destroy a pool of MMAL_BUFFER_HEADER_T.
+ * This will also deallocate all of the memory which was allocated when creating or
+ * resizing the pool.
+ *
+ * If payload buffers have been allocated independently by the client, they should be
+ * released prior to calling this function. If the client provided allocator functions,
+ * the allocator_free function shall be called for each payload buffer.
+ *
+ * @param pool  Pointer to a pool
+ */
+void mmal_pool_destroy(MMAL_POOL_T *pool);
+
+/** Resize a pool of MMAL_BUFFER_HEADER_T.
+ * This allows modifying either the number of allocated buffers, the payload size or both at the
+ * same time.
+ *
+ * @param pool         Pointer to the pool
+ * @param headers      New number of buffer headers to be allocated in the pool.
+ *                     It is not valid to pass zero for the number of buffers.
+ * @param payload_size Size of the payload buffer that will be allocated in
+ *                     each of the buffer headers.
+ *                     If this is set to 0, all payload buffers shall be released.
+ * @return MMAL_SUCCESS or an error on failure.
+ */
+MMAL_STATUS_T mmal_pool_resize(MMAL_POOL_T *pool, unsigned int headers, uint32_t payload_size);
+
+/** Definition of the callback used by a pool to signal back to the user that a buffer header
+ * has been released back to the pool.
+ *
+ * @param pool       Pointer to the pool
+ * @param buffer     Buffer header just released
+ * @param userdata   User specific data passed in when setting the callback
+ * @return True to have the buffer header put back in the pool's queue, false if the buffer
+ *          header has been taken within the callback.
+ */
+typedef MMAL_BOOL_T (*MMAL_POOL_BH_CB_T)(MMAL_POOL_T *pool, MMAL_BUFFER_HEADER_T *buffer, void *userdata);
+
+/** Set a buffer header release callback to the pool.
+ * Each time a buffer header is released to the pool, the callback will be triggered.
+ *
+ * @param pool     Pointer to a pool
+ * @param cb       Callback function
+ * @param userdata User specific data which will be passed with each callback
+ */
+void mmal_pool_callback_set(MMAL_POOL_T *pool, MMAL_POOL_BH_CB_T cb, void *userdata);
+
+/** Set a pre-release callback for all buffer headers in the pool.
+ * Each time a buffer header is about to be released to the pool, the callback
+ * will be triggered.
+ *
+ * @param pool     Pointer to the pool
+ * @param cb       Pre-release callback function
+ * @param userdata User-specific data passed back with each callback
+ */
+void mmal_pool_pre_release_callback_set(MMAL_POOL_T *pool, MMAL_BH_PRE_RELEASE_CB_T cb, void *userdata);
+
+/* @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MMAL_POOL_H */
diff --git a/interface/mmal/mmal_port.h b/interface/mmal/mmal_port.h
new file mode 100755 (executable)
index 0000000..982c45f
--- /dev/null
@@ -0,0 +1,286 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_PORT_H
+#define MMAL_PORT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup MmalPort Ports
+ * Definition of a MMAL port and its associated API */
+/* @{ */
+
+#include "mmal_types.h"
+#include "mmal_format.h"
+#include "mmal_buffer.h"
+#include "mmal_parameters.h"
+
+/** List of port types */
+typedef enum
+{
+   MMAL_PORT_TYPE_UNKNOWN = 0,          /**< Unknown port type */
+   MMAL_PORT_TYPE_CONTROL,              /**< Control port */
+   MMAL_PORT_TYPE_INPUT,                /**< Input port */
+   MMAL_PORT_TYPE_OUTPUT,               /**< Output port */
+   MMAL_PORT_TYPE_CLOCK,                /**< Clock port */
+   MMAL_PORT_TYPE_INVALID = 0xffffffff  /**< Dummy value to force 32bit enum */
+
+} MMAL_PORT_TYPE_T;
+
+/** \name Port capabilities
+ * \anchor portcapabilities
+ * The following flags describe the capabilities advertised by a port */
+/* @{ */
+/** The port is pass-through and doesn't need buffer headers allocated */
+#define MMAL_PORT_CAPABILITY_PASSTHROUGH                       0x01
+/** The port wants to allocate the buffer payloads. This signals a preference that
+ * payload allocation should be done on this port for efficiency reasons. */
+#define MMAL_PORT_CAPABILITY_ALLOCATION                        0x02
+/** The port supports format change events. This applies to input ports and is used
+ * to let the client know whether the port supports being reconfigured via a format
+ * change event (i.e. without having to disable the port). */
+#define MMAL_PORT_CAPABILITY_SUPPORTS_EVENT_FORMAT_CHANGE      0x04
+/* @} */
+
+/** Definition of a port.
+ * A port is the entity that is exposed by components to receive or transmit
+ * buffer headers (\ref MMAL_BUFFER_HEADER_T). A port is defined by its
+ * \ref MMAL_ES_FORMAT_T.
+ *
+ * It may be possible to override the buffer requirements of a port by using
+ * the MMAL_PARAMETER_BUFFER_REQUIREMENTS parameter.
+ */
+typedef struct MMAL_PORT_T
+{
+   struct MMAL_PORT_PRIVATE_T *priv; /**< Private member used by the framework */
+   const char *name;                 /**< Port name. Used for debugging purposes (Read Only) */
+
+   MMAL_PORT_TYPE_T type;            /**< Type of the port (Read Only) */
+   uint16_t index;                   /**< Index of the port in its type list (Read Only) */
+   uint16_t index_all;               /**< Index of the port in the list of all ports (Read Only) */
+
+   uint32_t is_enabled;              /**< Indicates whether the port is enabled or not (Read Only) */
+   MMAL_ES_FORMAT_T *format;         /**< Format of the elementary stream */
+
+   uint32_t buffer_num_min;          /**< Minimum number of buffers the port requires (Read Only).
+                                          This is set by the component. */
+   uint32_t buffer_size_min;         /**< Minimum size of buffers the port requires (Read Only).
+                                          This is set by the component. */
+   uint32_t buffer_alignment_min;    /**< Minimum alignment requirement for the buffers (Read Only).
+                                          A value of zero means no special alignment requirements.
+                                          This is set by the component. */
+   uint32_t buffer_num_recommended;  /**< Number of buffers the port recommends for optimal performance (Read Only).
+                                          A value of zero means no special recommendation.
+                                          This is set by the component. */
+   uint32_t buffer_size_recommended; /**< Size of buffers the port recommends for optimal performance (Read Only).
+                                          A value of zero means no special recommendation.
+                                          This is set by the component. */
+   uint32_t buffer_num;              /**< Actual number of buffers the port will use.
+                                          This is set by the client. */
+   uint32_t buffer_size;             /**< Actual maximum size of the buffers that will be sent
+                                          to the port. This is set by the client. */
+
+   struct MMAL_COMPONENT_T *component;    /**< Component this port belongs to (Read Only) */
+   struct MMAL_PORT_USERDATA_T *userdata; /**< Field reserved for use by the client */
+
+   uint32_t capabilities;            /**< Flags describing the capabilities of a port (Read Only).
+                                       * Bitwise combination of \ref portcapabilities "Port capabilities"
+                                       * values.
+                                       */
+
+} MMAL_PORT_T;
+
+/** Commit format changes on a port.
+ *
+ * @param port The port for which format changes are to be committed.
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_port_format_commit(MMAL_PORT_T *port);
+
+/** Definition of the callback used by a port to send a \ref MMAL_BUFFER_HEADER_T
+ * back to the user.
+ *
+ * @param port The port sending the buffer header.
+ * @param buffer The buffer header being sent.
+ */
+typedef void (*MMAL_PORT_BH_CB_T)(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
+
+/** Enable processing on a port
+ *
+ * If this port is connected to another, the given callback must be NULL, while for a
+ * disconnected port, the callback must be non-NULL.
+ *
+ * If this is a connected output port and is successfully enabled:
+ * <ul>
+ * <li>The port shall be populated with a pool of buffers, allocated as required, according
+ * to the buffer_num and buffer_size values.
+ * <li>The input port to which it is connected shall be set to the same buffer
+ * configuration and then be enabled. Should that fail, the original port shall be
+ * disabled.
+ * </ul>
+ *
+ * @param port port to enable
+ * @param cb callback use by the port to send a \ref MMAL_BUFFER_HEADER_T back
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb);
+
+/** Disable processing on a port
+ *
+ * Disabling a port will stop all processing on this port and return all (non-processed)
+ * buffer headers to the client.
+ *
+ * If this is a connected output port, the input port to which it is connected shall
+ * also be disabled. Any buffer pool shall be released.
+ *
+ * @param port port to disable
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_port_disable(MMAL_PORT_T *port);
+
+/** Ask a port to release all the buffer headers it currently has.
+ *
+ * Flushing a port will ask the port to send all the buffer headers it currently has
+ * to the client. Flushing is an asynchronous request and the flush call will
+ * return before all the buffer headers are returned to the client.
+ * It is up to the client to keep a count on the buffer headers to know when the
+ * flush operation has completed.
+ * It is also important to note that flushing will also reset the state of the port
+ * and any processing which was buffered by the port will be lost.
+ *
+ * \attention Flushing a connected port behaviour TBD.
+ *
+ * @param port The port to flush.
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_port_flush(MMAL_PORT_T *port);
+
+/** Set a parameter on a port.
+ *
+ * @param port The port to which the request is sent.
+ * @param param The pointer to the header of the parameter to set.
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_port_parameter_set(MMAL_PORT_T *port,
+   const MMAL_PARAMETER_HEADER_T *param);
+
+/** Get a parameter from a port.
+ * The size field must be set on input to the maximum size of the parameter
+ * (including the header) and will be set on output to the actual size of the
+ * parameter retrieved.
+ *
+ * \note If MMAL_ENOSPC is returned, the parameter is larger than the size
+ * given. The given parameter will have been filled up to its size and then
+ * the size field set to the full parameter's size. This can be used to
+ * resize the parameter buffer so that a second call should succeed.
+ *
+ * @param port The port to which the request is sent.
+ * @param param The pointer to the header of the parameter to get.
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_port_parameter_get(MMAL_PORT_T *port,
+   MMAL_PARAMETER_HEADER_T *param);
+
+/** Send a buffer header to a port.
+ *
+ * @param port The port to which the buffer header is to be sent.
+ * @param buffer The buffer header to send.
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_port_send_buffer(MMAL_PORT_T *port,
+   MMAL_BUFFER_HEADER_T *buffer);
+
+/** Connect an output port to an input port.
+ *
+ * When connected and enabled, buffers will automatically progress from the
+ * output port to the input port when they become available, and released back
+ * to the output port when no longer required by the input port.
+ *
+ * Ports can be given either way around, but one must be an output port and
+ * the other must be an input port. Neither can be connected or enabled
+ * already. The format of the output port will be applied to the input port
+ * on connection.
+ *
+ * @param port One of the ports to connect.
+ * @param other_port The other port to connect.
+ * @return MMAL_SUCCESS on success.
+ */
+MMAL_STATUS_T mmal_port_connect(MMAL_PORT_T *port, MMAL_PORT_T *other_port);
+
+/** Disconnect a connected port.
+ *
+ * If the port is not connected, an error will be returned. Otherwise, if the
+ * ports are enabled, they will be disabled and any buffer pool created will be
+ * freed.
+ *
+ * @param port The ports to disconnect.
+ * @return MMAL_SUCCESS on success.
+ */
+MMAL_STATUS_T mmal_port_disconnect(MMAL_PORT_T *port);
+
+/** Allocate a payload buffer.
+ * This allows a client to allocate memory for a payload buffer based on the preferences
+ * of a port. This for instance will allow the port to allocate memory which can be shared
+ * between the host processor and videocore.
+ *
+ * See \ref mmal_pool_create_with_allocator().
+ *
+ * @param port         Port responsible for allocating the memory.
+ * @param payload_size Size of the payload buffer which will be allocated.
+ *
+ * @return Pointer to the allocated memory.
+ */
+uint8_t *mmal_port_payload_alloc(MMAL_PORT_T *port, uint32_t payload_size);
+
+/** Free a payload buffer.
+ * This allows a client to free memory allocated by a previous call to \ref mmal_port_payload_alloc.
+ *
+ * See \ref mmal_pool_create_with_allocator().
+ *
+ * @param port         Port responsible for allocating the memory.
+ * @param payload      Pointer to the memory to free.
+ */
+void mmal_port_payload_free(MMAL_PORT_T *port, uint8_t *payload);
+
+/** Get an empty event buffer header from a port
+ *
+ * @param port The port from which to get the event buffer header.
+ * @param buffer The address of a buffer header pointer, which will be set on return.
+ * @param event The specific event FourCC required. See the \ref MmalEvents "pre-defined events".
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_port_event_get(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T **buffer, uint32_t event);
+
+/* @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MMAL_PORT_H */
diff --git a/interface/mmal/mmal_queue.h b/interface/mmal/mmal_queue.h
new file mode 100755 (executable)
index 0000000..ce53a26
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_QUEUE_H
+#define MMAL_QUEUE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup MmalQueue Queues of buffer headers
+ * This provides a thread-safe implementation of a queue of buffer headers
+ * (\ref MMAL_BUFFER_HEADER_T). The queue works in a first-in, first-out basis
+ * so the buffer headers will be dequeued in the order they have been queued. */
+/* @{ */
+
+#include "mmal_buffer.h"
+
+typedef struct MMAL_QUEUE_T MMAL_QUEUE_T;
+
+/** Create a queue of MMAL_BUFFER_HEADER_T
+ *
+ * @return Pointer to the newly created queue or NULL on failure.
+ */
+MMAL_QUEUE_T *mmal_queue_create(void);
+
+/** Put a MMAL_BUFFER_HEADER_T into a queue
+ *
+ * @param queue  Pointer to a queue
+ * @param buffer Pointer to the MMAL_BUFFER_HEADER_T to add to the queue
+ */
+void mmal_queue_put(MMAL_QUEUE_T *queue, MMAL_BUFFER_HEADER_T *buffer);
+
+/** Put a MMAL_BUFFER_HEADER_T back at the start of a queue.
+ * This is used when a buffer header was removed from the queue but not
+ * fully processed and needs to be put back where it was originally taken.
+ *
+ * @param queue  Pointer to a queue
+ * @param buffer Pointer to the MMAL_BUFFER_HEADER_T to add to the queue
+ */
+void mmal_queue_put_back(MMAL_QUEUE_T *queue, MMAL_BUFFER_HEADER_T *buffer);
+
+/** Get a MMAL_BUFFER_HEADER_T from a queue
+ *
+ * @param queue  Pointer to a queue
+ *
+ * @return pointer to the next MMAL_BUFFER_HEADER_T or NULL if the queue is empty.
+ */
+MMAL_BUFFER_HEADER_T *mmal_queue_get(MMAL_QUEUE_T *queue);
+
+/** Wait for a MMAL_BUFFER_HEADER_T from a queue.
+ * This is the same as a get except that this will block until a buffer header is
+ * available.
+ *
+ * @param queue  Pointer to a queue
+ *
+ * @return pointer to the next MMAL_BUFFER_HEADER_T.
+ */
+MMAL_BUFFER_HEADER_T *mmal_queue_wait(MMAL_QUEUE_T *queue);
+
+/** Wait for a MMAL_BUFFER_HEADER_T from a queue, up to a given timeout.
+ * This is the same as a wait, except that it will abort in case of timeout.
+ *
+ * @param queue  Pointer to a queue
+ * @param timeout Number of milliseconds to wait before
+ *                returning if the semaphore can't be acquired.
+ *
+ * @return pointer to the next MMAL_BUFFER_HEADER_T.
+ */
+MMAL_BUFFER_HEADER_T *mmal_queue_timedwait(MMAL_QUEUE_T *queue, VCOS_UNSIGNED timeout);
+
+/** Get the number of MMAL_BUFFER_HEADER_T currently in a queue.
+ *
+ * @param queue  Pointer to a queue
+ *
+ * @return length (in elements) of the queue.
+ */
+unsigned int mmal_queue_length(MMAL_QUEUE_T *queue);
+
+/** Destroy a queue of MMAL_BUFFER_HEADER_T.
+ *
+ * @param queue  Pointer to a queue
+ */
+void mmal_queue_destroy(MMAL_QUEUE_T *queue);
+
+/* @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MMAL_QUEUE_H */
diff --git a/interface/mmal/mmal_types.h b/interface/mmal/mmal_types.h
new file mode 100755 (executable)
index 0000000..741f742
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_TYPES_H
+#define MMAL_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup MmalTypes Common types
+ * Definition for common types */
+/* @{ */
+
+#include "mmal_common.h"
+
+/** Status return codes from the API.
+ *
+ * \internal Please try to keep this similar to the standard POSIX codes
+ * rather than making up new ones!
+ */
+typedef enum
+{
+   MMAL_SUCCESS = 0,                 /**< Success */
+   MMAL_ENOMEM,                      /**< Out of memory */
+   MMAL_ENOSPC,                      /**< Out of resources (other than memory) */
+   MMAL_EINVAL,                      /**< Argument is invalid */
+   MMAL_ENOSYS,                      /**< Function not implemented */
+   MMAL_ENOENT,                      /**< No such file or directory */
+   MMAL_ENXIO,                       /**< No such device or address */
+   MMAL_EIO,                         /**< I/O error */
+   MMAL_ESPIPE,                      /**< Illegal seek */
+   MMAL_ECORRUPT,                    /**< Data is corrupt \attention FIXME: not POSIX */
+   MMAL_ENOTREADY,                   /**< Component is not ready \attention FIXME: not POSIX */
+   MMAL_ECONFIG,                     /**< Component is not configured \attention FIXME: not POSIX */
+   MMAL_EISCONN,                     /**< Port is already connected */
+   MMAL_ENOTCONN,                    /**< Port is disconnected */
+   MMAL_EAGAIN,                      /**< Resource temporarily unavailable. Try again later*/
+   MMAL_EFAULT,                      /**< Bad address */
+   /* Do not add new codes here unless they match something from POSIX */
+   MMAL_STATUS_MAX = 0x7FFFFFFF      /**< Force to 32 bit */
+} MMAL_STATUS_T;
+
+/** Describes a rectangle */
+typedef struct
+{
+   int32_t x;      /**< x coordinate (from left) */
+   int32_t y;      /**< y coordinate (from top) */
+   int32_t width;  /**< width */
+   int32_t height; /**< height */
+} MMAL_RECT_T;
+
+/** Describes a rational number */
+typedef struct
+{
+   int32_t num;    /**< Numerator */
+   int32_t den;    /**< Denominator */
+} MMAL_RATIONAL_T;
+
+/** \name Special Unknown Time Value
+ * Timestamps in MMAL are defined as signed 64 bits integer values representing microseconds.
+ * However a pre-defined special value is used to signal that a timestamp is not known. */
+/* @{ */
+#define MMAL_TIME_UNKNOWN (INT64_C(1)<<63)  /**< Special value signalling that time is not known */
+/* @} */
+
+/** Four Character Code type */
+typedef uint32_t MMAL_FOURCC_T;
+
+/* @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MMAL_TYPES_H */
diff --git a/interface/mmal/openmaxil/CMakeLists.txt b/interface/mmal/openmaxil/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..68d9832
--- /dev/null
@@ -0,0 +1,20 @@
+add_library (mmal_omx ${LIBRARY_TYPE}
+   mmalomx_core.c
+   mmalomx_logging.c
+   mmalomx_commands.c
+   mmalomx_buffer.c
+   mmalomx_marks.c
+   mmalomx_roles.c
+   mmalomx_parameters.c
+   mmalomx_registry.c
+)
+
+add_library (mmal_omxutil ${LIBRARY_TYPE}
+   mmalomx_util_params.c
+   mmalomx_util_params_audio.c
+   mmalomx_util_params_video.c
+   mmalomx_util_params_camera.c
+   mmalomx_util_params_misc.c
+)
+
+target_link_libraries (mmal_omx mmal_omxutil mmal_core mmal_util vcos)
diff --git a/interface/mmal/openmaxil/mmalomx.h b/interface/mmal/openmaxil/mmalomx.h
new file mode 100755 (executable)
index 0000000..d58971a
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file
+ * OpenMAX IL adaptation layer for MMAL
+ */
+
+#include "interface/vmcs_host/khronos/IL/OMX_Core.h"
+#include "interface/vmcs_host/khronos/IL/OMX_Component.h"
+#include "interface/vmcs_host/khronos/IL/OMX_Video.h"
+#include "interface/vmcs_host/khronos/IL/OMX_Audio.h"
+#include <mmal.h>
+#include <util/mmal_il.h>
+
+/* Define this to 1 if you want to log all buffer transfers */
+#define ENABLE_MMAL_EXTRA_LOGGING 0
+
+#ifndef MMALOMX_EXPORT
+#  define MMALOMX_EXPORT(a) a
+#endif
+#ifndef MMALOMX_IMPORT
+#  define MMALOMX_IMPORT(a) a
+#endif
+
+#define MAX_MARKS_NUM 2
+#define MAX_ENCODINGS_NUM 20
+
+/** Per-port context data */
+typedef struct MMALOMX_PORT_T
+{
+   struct MMALOMX_COMPONENT_T *component;
+   MMAL_PORT_T *mmal;
+   OMX_DIRTYPE direction;
+   unsigned int index;
+   unsigned int buffers;
+   unsigned int buffers_in_transit;
+
+   MMAL_BOOL_T buffers_allocated:1;
+   MMAL_BOOL_T enabled:1;
+   MMAL_BOOL_T populated:1;
+   MMAL_BOOL_T zero_copy:1;
+   MMAL_BOOL_T no_cropping:1;
+   MMAL_BOOL_T format_changed:1;
+   MMAL_POOL_T *pool;
+
+   uint32_t actions;
+
+   OMX_MARKTYPE marks[MAX_MARKS_NUM];
+   unsigned int marks_first:8;
+   unsigned int marks_num:8;
+
+   OMX_FORMAT_PARAM_TYPE format_param;
+
+   MMAL_PARAMETER_HEADER_T encodings_header;
+   MMAL_FOURCC_T encodings[MAX_ENCODINGS_NUM];
+   unsigned int encodings_num;
+
+} MMALOMX_PORT_T;
+
+/** Component context data */
+typedef struct MMALOMX_COMPONENT_T {
+   OMX_COMPONENTTYPE omx;              /**< OMX component type structure */
+
+   unsigned int registry_id;
+   const char *name;
+   uint32_t role;
+   OMX_CALLBACKTYPE callbacks;
+   OMX_PTR callbacks_data;
+
+   struct MMAL_COMPONENT_T *mmal;
+   OMX_STATETYPE state;
+   unsigned int state_transition;
+
+   MMALOMX_PORT_T *ports;
+   unsigned int ports_num;
+   unsigned int ports_domain_num[4];
+
+   MMAL_BOOL_T actions_running;
+
+   OMX_U32 group_id;
+   OMX_U32 group_priority;
+
+   /* Support for command queues */
+   MMAL_POOL_T *cmd_pool;
+   MMAL_QUEUE_T *cmd_queue;
+   VCOS_THREAD_T cmd_thread;
+   MMAL_BOOL_T cmd_thread_used;
+   VCOS_SEMAPHORE_T cmd_sema;
+
+   VCOS_MUTEX_T lock; /**< Used to protect component state */
+   VCOS_MUTEX_T lock_port; /**< Used to protect port state */
+
+} MMALOMX_COMPONENT_T;
+
+OMX_ERRORTYPE mmalomx_callback_event_handler(
+   MMALOMX_COMPONENT_T *component,
+   OMX_EVENTTYPE eEvent,
+   OMX_U32 nData1,
+   OMX_U32 nData2,
+   OMX_PTR pEventData);
+
+#define MMALOMX_LOCK(a) vcos_mutex_lock(&a->lock)
+#define MMALOMX_UNLOCK(a) vcos_mutex_unlock(&a->lock)
+#define MMALOMX_LOCK_PORT(a,b) vcos_mutex_lock(&a->lock_port)
+#define MMALOMX_UNLOCK_PORT(a,b) vcos_mutex_unlock(&a->lock_port)
+
diff --git a/interface/mmal/openmaxil/mmalomx_buffer.c b/interface/mmal/openmaxil/mmalomx_buffer.c
new file mode 100755 (executable)
index 0000000..ef78baa
--- /dev/null
@@ -0,0 +1,235 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmalomx.h"
+#include "mmalomx_buffer.h"
+#include "mmalomx_commands.h"
+#include "mmalomx_marks.h"
+#include "mmalomx_logging.h"
+
+#include <util/mmal_util.h>
+
+/*****************************************************************************/
+OMX_ERRORTYPE mmalomx_buffer_send(
+   MMALOMX_COMPONENT_T *component,
+   OMX_BUFFERHEADERTYPE *omx_buffer,
+   OMX_DIRTYPE direction)
+{
+   OMX_ERRORTYPE status = OMX_ErrorNone;
+   MMAL_BUFFER_HEADER_T *mmal_buffer;
+   MMAL_STATUS_T mmal_status;
+   MMALOMX_PORT_T *port;
+   unsigned int index;
+
+   /* Sanity checks */
+   if (!component)
+      return OMX_ErrorInvalidComponent;
+   if (component->state == OMX_StateInvalid)
+      return OMX_ErrorInvalidState;
+
+   if (!omx_buffer || omx_buffer->nSize != sizeof(OMX_BUFFERHEADERTYPE) ||
+       omx_buffer->nOffset + omx_buffer->nFilledLen > omx_buffer->nAllocLen)
+      return OMX_ErrorBadParameter;
+
+   index = direction == OMX_DirInput ? omx_buffer->nInputPortIndex : omx_buffer->nOutputPortIndex;
+   if (index >= component->ports_num)
+      return OMX_ErrorBadPortIndex;
+
+   port = &component->ports[index];
+   if (port->direction != direction)
+      return OMX_ErrorBadPortIndex;
+
+   MMALOMX_LOCK_PORT(component, port);
+
+   if (component->state != OMX_StatePause && component->state != OMX_StateExecuting)
+      status = OMX_ErrorIncorrectStateOperation;
+   if (!port->enabled  /* FIXME: || flushing || pending idle */)
+      status = OMX_ErrorIncorrectStateOperation;
+   if (status != OMX_ErrorNone)
+      goto error;
+
+   mmal_buffer = mmal_queue_get( port->pool->queue );
+   if (!vcos_verify(mmal_buffer)) /* Should never happen */
+   {
+      status = OMX_ErrorUndefined;
+      goto error;
+   }
+
+   mmalomx_mark_process_incoming(component, port, omx_buffer);
+
+   mmal_buffer->user_data = (void *)omx_buffer;
+   mmalil_buffer_header_to_mmal(mmal_buffer, omx_buffer);
+
+   mmal_status = mmal_port_send_buffer(port->mmal, mmal_buffer);
+   if (!vcos_verify(mmal_status == MMAL_SUCCESS))
+   {
+      LOG_ERROR("failed to send buffer on %s", port->mmal->name);
+      mmal_queue_put_back( port->pool->queue, mmal_buffer );
+      status = mmalil_error_to_omx(mmal_status);
+   }
+   else
+   {
+      port->buffers_in_transit++;
+   }
+
+error:
+   MMALOMX_UNLOCK_PORT(component, port);
+   return status;
+}
+
+/*****************************************************************************/
+static void mmalomx_buffer_event(
+   MMALOMX_PORT_T *port,
+   MMAL_BUFFER_HEADER_T *mmal_buffer)
+{
+   MMALOMX_COMPONENT_T *component = port->component;
+   MMAL_EVENT_FORMAT_CHANGED_T *event;
+
+   LOG_TRACE("hComponent %p, port %i, event %4.4s", component, port->index,
+             (char *)&mmal_buffer->cmd);
+
+   if (mmal_buffer->cmd == MMAL_EVENT_ERROR )
+   {
+      mmalomx_callback_event_handler(component, OMX_EventError,
+         mmalil_error_to_omx(*(MMAL_STATUS_T *)mmal_buffer->data), 0, NULL);
+      return;
+   }
+
+   event = mmal_event_format_changed_get(mmal_buffer);
+   if (event && port->mmal->type == MMAL_PORT_TYPE_OUTPUT &&
+       port->mmal->format->type == MMAL_ES_TYPE_VIDEO)
+   {
+      uint32_t diff = mmal_format_compare(event->format, port->mmal->format);
+      MMAL_ES_FORMAT_T *format = port->mmal->format;
+      MMAL_VIDEO_FORMAT_T video = format->es->video;
+
+      /* Update the port settings with the new values */
+      mmal_format_copy(format, event->format);
+      port->mmal->buffer_num_min = event->buffer_num_min;
+      port->mmal->buffer_size_min = event->buffer_size_min;
+      port->format_changed = MMAL_TRUE;
+
+      if ((diff & MMAL_ES_FORMAT_COMPARE_FLAG_VIDEO_ASPECT_RATIO) &&
+          /* Do not report a change if going from unspecified to 1:1 */
+          !(format->es->video.par.num == format->es->video.par.den && !video.par.num))
+      {
+         LOG_DEBUG("aspect ratio change %ix%i->%ix%i", (int)video.par.num, (int)video.par.den,
+                   (int)format->es->video.par.num, (int)format->es->video.par.den);
+         mmalomx_callback_event_handler(component, OMX_EventPortSettingsChanged,
+                                        port->index, OMX_IndexParamBrcmPixelAspectRatio, NULL);
+      }
+
+      if (diff & (MMAL_ES_FORMAT_COMPARE_FLAG_ENCODING|
+                  MMAL_ES_FORMAT_COMPARE_FLAG_VIDEO_RESOLUTION|
+                  MMAL_ES_FORMAT_COMPARE_FLAG_VIDEO_CROPPING))
+      {
+         LOG_DEBUG("format change %ix%i(%ix%i) -> %ix%i(%ix%i)",
+                   (int)video.width, (int)video.height,
+                   (int)video.crop.width, (int)video.crop.height,
+                   (int)format->es->video.width, (int)format->es->video.height,
+                   (int)format->es->video.crop.width, (int)format->es->video.crop.height);
+         mmalomx_callback_event_handler(component, OMX_EventPortSettingsChanged,
+                                        port->index, 0, NULL);
+      }
+   }
+   else if (event && port->mmal->type == MMAL_PORT_TYPE_OUTPUT &&
+       port->mmal->format->type == MMAL_ES_TYPE_AUDIO)
+   {
+      uint32_t diff = mmal_format_compare(event->format, port->mmal->format);
+      MMAL_ES_FORMAT_T *format = port->mmal->format;
+      MMAL_AUDIO_FORMAT_T audio = format->es->audio;
+
+      /* Update the port settings with the new values */
+      mmal_format_copy(format, event->format);
+      port->mmal->buffer_num_min = event->buffer_num_min;
+      port->mmal->buffer_size_min = event->buffer_size_min;
+      port->format_changed = MMAL_TRUE;
+
+      if (diff)
+      {
+         LOG_DEBUG("format change %ich, %iHz, %ibps -> %ich, %iHz, %ibps",
+                   (int)audio.channels, (int)audio.sample_rate,
+                   (int)audio.bits_per_sample,
+                   (int)format->es->audio.channels,
+                   (int)format->es->audio.sample_rate,
+                   (int)format->es->audio.bits_per_sample);
+         mmalomx_callback_event_handler(component, OMX_EventPortSettingsChanged,
+                                        port->index, 0, NULL);
+      }
+   }
+}
+
+/*****************************************************************************/
+OMX_ERRORTYPE mmalomx_buffer_return(
+   MMALOMX_PORT_T *port,
+   MMAL_BUFFER_HEADER_T *mmal_buffer)
+{
+   MMALOMX_COMPONENT_T *component = port->component;
+   OMX_BUFFERHEADERTYPE *omx_buffer = (OMX_BUFFERHEADERTYPE *)mmal_buffer->user_data;
+   MMAL_BOOL_T signal;
+
+   if (mmal_buffer->cmd)
+   {
+      mmalomx_buffer_event(port, mmal_buffer);
+      mmal_buffer_header_release(mmal_buffer);
+      return OMX_ErrorNone;
+   }
+
+   if (ENABLE_MMAL_EXTRA_LOGGING)
+      LOG_TRACE("hComponent %p, port %i, pBuffer %p", component,
+                port->index, omx_buffer);
+
+   vcos_assert(omx_buffer->pBuffer == mmal_buffer->data);
+   mmalil_buffer_header_to_omx(omx_buffer, mmal_buffer);
+   mmal_buffer_header_release(mmal_buffer);
+
+   if ((omx_buffer->nFlags & OMX_BUFFERFLAG_EOS) && port->direction == OMX_DirOutput)
+   {
+      mmalomx_callback_event_handler(component, OMX_EventBufferFlag,
+                                     port->index, omx_buffer->nFlags, NULL);
+   }
+
+   mmalomx_mark_process_outgoing(component, port, omx_buffer);
+
+   if (port->direction == OMX_DirInput)
+      component->callbacks.EmptyBufferDone((OMX_HANDLETYPE)&component->omx,
+         component->callbacks_data, omx_buffer );
+   else
+      component->callbacks.FillBufferDone((OMX_HANDLETYPE)&component->omx,
+         component->callbacks_data, omx_buffer );
+
+   MMALOMX_LOCK_PORT(component, port);
+   signal = port->actions & MMALOMX_ACTION_CHECK_FLUSHED;
+   port->buffers_in_transit--;
+   MMALOMX_UNLOCK_PORT(component, port);
+
+   if (signal)
+      mmalomx_commands_actions_signal(component);
+
+   return OMX_ErrorNone;
+}
+
diff --git a/interface/mmal/openmaxil/mmalomx_buffer.h b/interface/mmal/openmaxil/mmalomx_buffer.h
new file mode 100755 (executable)
index 0000000..425f7ef
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file
+ * OpenMAX IL adaptation layer for MMAL - Buffer related functions
+ */
+
+OMX_ERRORTYPE mmalomx_buffer_send(
+   MMALOMX_COMPONENT_T *component,
+   OMX_BUFFERHEADERTYPE *omx_buffer,
+   OMX_DIRTYPE direction);
+
+OMX_ERRORTYPE mmalomx_buffer_return(
+   MMALOMX_PORT_T *port,
+   MMAL_BUFFER_HEADER_T *mmal_buffer);
diff --git a/interface/mmal/openmaxil/mmalomx_commands.c b/interface/mmal/openmaxil/mmalomx_commands.c
new file mode 100755 (executable)
index 0000000..dd395d4
--- /dev/null
@@ -0,0 +1,462 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmalomx.h"
+#include "mmalomx_commands.h"
+#include "mmalomx_buffer.h"
+#include "mmalomx_logging.h"
+
+typedef struct {
+   OMX_STATETYPE state;
+   OMX_STATETYPE request;
+   uint32_t actions;
+} MMALOMX_STATE_TRANSITION_T;
+
+MMALOMX_STATE_TRANSITION_T state_transition_table[] =
+{
+  {OMX_StateInvalid, OMX_StateInvalid, 0},
+  {OMX_StateLoaded, OMX_StateIdle, MMALOMX_ACTION_CHECK_ALLOCATED|MMALOMX_ACTION_ENABLE},
+  {OMX_StateLoaded, OMX_StateWaitForResources, 0},
+  {OMX_StateWaitForResources, OMX_StateLoaded, 0},
+  {OMX_StateWaitForResources, OMX_StateIdle, MMALOMX_ACTION_CHECK_ALLOCATED|MMALOMX_ACTION_ENABLE},
+  {OMX_StateIdle, OMX_StateLoaded, MMALOMX_ACTION_CHECK_DEALLOCATED|MMALOMX_ACTION_DISABLE},
+  {OMX_StateIdle, OMX_StateExecuting, 0},
+  {OMX_StateIdle, OMX_StatePause, 0},
+  {OMX_StateExecuting, OMX_StateIdle, MMALOMX_ACTION_FLUSH|MMALOMX_ACTION_CHECK_FLUSHED},
+  {OMX_StateExecuting, OMX_StatePause, 0},
+  {OMX_StatePause, OMX_StateIdle, 0},
+  {OMX_StatePause, OMX_StateExecuting, 0},
+  {OMX_StateMax, OMX_StateMax, 0}
+};
+
+/*****************************************************************************/
+static unsigned int mmalomx_state_transition_get(OMX_STATETYPE state, OMX_STATETYPE request)
+{
+   unsigned int i;
+
+   for (i = 0; state_transition_table[i].state != OMX_StateMax; i++)
+      if (state_transition_table[i].state == state &&
+          state_transition_table[i].request == request)
+         break;
+
+   return state_transition_table[i].state != OMX_StateMax ? i : 0;
+}
+
+/*****************************************************************************/
+static void mmalomx_buffer_cb_io(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   mmalomx_buffer_return((MMALOMX_PORT_T *)port->userdata, buffer);
+}
+
+/*****************************************************************************/
+static void mmalomx_commands_check_port_actions(MMALOMX_COMPONENT_T *component,
+   MMALOMX_PORT_T *port)
+{
+   uint32_t exec_actions = 0;
+   MMAL_STATUS_T status;
+
+   MMALOMX_LOCK_PORT(component, port);
+   if (!port->actions)
+   {
+      MMALOMX_UNLOCK_PORT(component, port);
+      return;
+   }
+
+   if (port->actions & MMALOMX_ACTION_FLUSH)
+   {
+      port->actions &= ~MMALOMX_ACTION_FLUSH;
+      port->actions |= MMALOMX_ACTION_PENDING_FLUSH;
+      exec_actions |= MMALOMX_ACTION_PENDING_FLUSH;
+   }
+   if ((port->actions & MMALOMX_ACTION_DISABLE) &&
+       (!port->buffers_in_transit ||
+        !(port->actions & MMALOMX_ACTION_CHECK_FLUSHED)))
+   {
+      port->actions &= ~MMALOMX_ACTION_DISABLE;
+      port->actions |= MMALOMX_ACTION_PENDING_DISABLE;
+      exec_actions |= MMALOMX_ACTION_PENDING_DISABLE;
+   }
+   if ((port->actions & MMALOMX_ACTION_ENABLE) &&
+       port->buffers)
+   {
+      /* We defer enabling the mmal port until the first buffer allocation
+       * has been done. Only at that point do we know for sure whether we
+       * are going to use shared memory or not.
+       * We might want to delay it to just before sending the event to the client ???
+       */
+      port->actions &= ~MMALOMX_ACTION_ENABLE;
+      port->actions |= MMALOMX_ACTION_PENDING_ENABLE;
+      exec_actions |= MMALOMX_ACTION_PENDING_ENABLE;
+   }
+   MMALOMX_UNLOCK_PORT(component, port);
+
+   if (exec_actions & MMALOMX_ACTION_PENDING_FLUSH)
+      mmal_port_flush(port->mmal);
+
+   if (exec_actions & MMALOMX_ACTION_PENDING_DISABLE)
+   {
+      mmal_port_disable(port->mmal);
+
+      /* If there was a port format changed event, we need to make sure
+       * the new format has been committed */
+      if (port->format_changed)
+      {
+         status = mmal_port_format_commit(port->mmal);
+         if (status != MMAL_SUCCESS)
+            LOG_WARN("could not commit new format (%i)", status);
+         port->format_changed = MMAL_FALSE;
+      }
+   }
+
+   if (exec_actions & MMALOMX_ACTION_PENDING_ENABLE)
+   {
+      status = mmal_port_enable(port->mmal, mmalomx_buffer_cb_io);
+      if (status == MMAL_SUCCESS)
+         status = mmal_pool_resize(port->pool, port->mmal->buffer_num, 0);
+      if (status != MMAL_SUCCESS)
+         mmalomx_callback_event_handler(component, OMX_EventError, mmalil_error_to_omx(status), 0, NULL);
+      /* FIXME: we're still going to generate a cmd complete. Not sure if that's an issue. */
+   }
+
+   MMALOMX_LOCK_PORT(component, port);
+
+   port->actions &= ~exec_actions;
+   if ((port->actions & MMALOMX_ACTION_CHECK_ALLOCATED) && port->populated)
+      port->actions &= ~MMALOMX_ACTION_CHECK_ALLOCATED;
+   if ((port->actions & MMALOMX_ACTION_CHECK_DEALLOCATED) && !port->buffers)
+      port->actions &= ~MMALOMX_ACTION_CHECK_DEALLOCATED;
+   if ((port->actions & MMALOMX_ACTION_CHECK_FLUSHED) && !port->buffers_in_transit)
+      port->actions &= ~MMALOMX_ACTION_CHECK_FLUSHED;
+   exec_actions = port->actions;
+
+   if (port->actions == MMALOMX_ACTION_NOTIFY_FLUSH ||
+       port->actions == MMALOMX_ACTION_NOTIFY_ENABLE ||
+       port->actions == MMALOMX_ACTION_NOTIFY_DISABLE)
+      port->actions = 0;  /* We're done */
+
+   MMALOMX_UNLOCK_PORT(component, port);
+
+   if (exec_actions == MMALOMX_ACTION_NOTIFY_FLUSH)
+      mmalomx_callback_event_handler(component, OMX_EventCmdComplete,
+         OMX_CommandFlush, port->index, NULL);
+   else if (exec_actions == MMALOMX_ACTION_NOTIFY_ENABLE)
+      mmalomx_callback_event_handler(component, OMX_EventCmdComplete,
+         OMX_CommandPortEnable, port->index, NULL);
+   else if (exec_actions == MMALOMX_ACTION_NOTIFY_DISABLE)
+      mmalomx_callback_event_handler(component, OMX_EventCmdComplete,
+         OMX_CommandPortDisable, port->index, NULL);
+}
+
+/*****************************************************************************/
+void mmalomx_commands_actions_check(MMALOMX_COMPONENT_T *component)
+{
+   uint32_t actions_left = 0;
+   unsigned int i;
+
+   for (i = 0; i < component->ports_num; i++)
+      mmalomx_commands_check_port_actions(component, &component->ports[i]);
+
+   MMALOMX_LOCK(component);
+   for (i = 0; i < component->ports_num; i++)
+      actions_left |= component->ports[i].actions;
+
+   if (!actions_left && component->state_transition)
+   {
+      component->state = state_transition_table[component->state_transition].request;
+      component->state_transition = 0;
+      actions_left = MMALOMX_ACTION_NOTIFY_STATE;
+   }
+   MMALOMX_UNLOCK(component);
+
+   if (actions_left == MMALOMX_ACTION_NOTIFY_STATE)
+   {
+      mmalomx_callback_event_handler(component, OMX_EventCmdComplete,
+         OMX_CommandStateSet, component->state, NULL);
+      actions_left = 0;
+   }
+
+   /* If we're not currently processing a command, we can start processing
+    * the next one. */
+   if (!actions_left)
+      mmalomx_commands_actions_next(component);
+}
+
+/*****************************************************************************/
+void mmalomx_commands_actions_signal(MMALOMX_COMPONENT_T *component)
+{
+   if (component->cmd_thread_used)
+      vcos_semaphore_post(&component->cmd_sema);
+   else
+      mmalomx_commands_actions_check(component);
+}
+
+/*****************************************************************************/
+OMX_ERRORTYPE mmalomx_command_state_set(
+   OMX_HANDLETYPE hComponent,
+   OMX_STATETYPE state)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+   unsigned int i, transition;
+
+   if (component->state == state)
+   {
+      mmalomx_callback_event_handler(component, OMX_EventError, OMX_ErrorSameState, 0, NULL);
+      return OMX_ErrorNone;
+   }
+
+   /* We're asked to transition to StateInvalid */
+   if (state == OMX_StateInvalid)
+   {
+      component->state = state;
+      mmalomx_callback_event_handler(component, OMX_EventError, OMX_ErrorInvalidState, 0, NULL);
+      return OMX_ErrorNone;
+   }
+
+   /* Commands are being queued so we should never get into that state */
+   vcos_assert(!component->state_transition);
+
+   /* Check the transition is valid */
+   transition = mmalomx_state_transition_get(component->state, state);
+   if (!transition)
+   {
+      mmalomx_callback_event_handler(component, OMX_EventError, OMX_ErrorIncorrectStateTransition, 0, NULL);
+      return OMX_ErrorNone;
+   }
+
+   /* Special case for transition in and out of Executing */
+   if (state == OMX_StateExecuting || component->state == OMX_StateExecuting)
+   {
+      MMAL_STATUS_T status;
+
+      if (state == OMX_StateExecuting)
+         status = mmal_component_enable(component->mmal);
+      else
+         status = mmal_component_disable(component->mmal);
+
+      if (status != MMAL_SUCCESS)
+      {
+         LOG_ERROR("could not %s %s", state == OMX_StateExecuting ? "enable" : "disable", component->name);
+         mmalomx_callback_event_handler(component, OMX_EventError, mmalil_error_to_omx(status), 0, NULL);
+         return OMX_ErrorNone;
+      }
+   }
+
+   MMALOMX_LOCK(component);
+   component->state_transition = transition;
+
+   for (i = 0; i < component->ports_num; i++)
+   {
+      if (!component->ports[i].enabled)
+         continue;
+
+      MMALOMX_LOCK_PORT(component, component->ports + i);
+      component->ports[i].actions = state_transition_table[transition].actions;
+
+      /* If we're transitionning from Idle to Loaded we'd rather do a flush first
+       * to avoid the cmd thread to block for too long (mmal_disable is a
+       * blocking call). */
+      if (state_transition_table[transition].state == OMX_StateIdle &&
+          state_transition_table[transition].request == OMX_StateLoaded &&
+          component->cmd_thread_used)
+         component->ports[i].actions |= MMALOMX_ACTION_FLUSH|MMALOMX_ACTION_CHECK_FLUSHED;
+      MMALOMX_UNLOCK_PORT(component, component->ports + i);
+   }
+   MMALOMX_UNLOCK(component);
+
+   mmalomx_commands_actions_check(component);
+   return OMX_ErrorNone;
+}
+
+/*****************************************************************************/
+OMX_ERRORTYPE mmalomx_command_port_mark(
+   OMX_HANDLETYPE hComponent,
+   OMX_U32 nPortIndex,
+   OMX_PTR *pCmdData)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+   OMX_MARKTYPE *mark = (OMX_MARKTYPE *)pCmdData;
+   MMALOMX_PORT_T *port;
+
+   if (nPortIndex >= component->ports_num)
+      return OMX_ErrorBadPortIndex;
+   port = &component->ports[nPortIndex];
+
+   if (port->marks_num == MAX_MARKS_NUM)
+      return OMX_ErrorInsufficientResources;
+
+   port->marks[(port->marks_first + port->marks_num) % MAX_MARKS_NUM] = *mark;
+   port->marks_num++;
+
+   return OMX_ErrorNone;
+}
+
+/*****************************************************************************/
+OMX_ERRORTYPE mmalomx_command_port_flush(
+   OMX_HANDLETYPE hComponent,
+   OMX_U32 nPortIndex)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+
+   MMALOMX_LOCK_PORT(component, &component->ports[nPortIndex]);
+   component->ports[nPortIndex].actions =
+      MMALOMX_ACTION_FLUSH|MMALOMX_ACTION_CHECK_FLUSHED|MMALOMX_ACTION_NOTIFY_FLUSH;
+   MMALOMX_UNLOCK_PORT(component, &component->ports[nPortIndex]);
+
+   mmalomx_commands_actions_check(component);
+
+   return OMX_ErrorNone;
+}
+
+/*****************************************************************************/
+OMX_ERRORTYPE mmalomx_command_port_enable(
+   OMX_HANDLETYPE hComponent,
+   OMX_U32 nPortIndex)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+   component->ports[nPortIndex].enabled = MMAL_TRUE;
+
+   if (component->state == OMX_StateLoaded ||
+       component->state == OMX_StateWaitForResources)
+   {
+      mmalomx_callback_event_handler(component, OMX_EventCmdComplete, OMX_CommandPortEnable, nPortIndex, NULL);
+      return OMX_ErrorNone;
+   }
+
+   MMALOMX_LOCK_PORT(component, &component->ports[nPortIndex]);
+   component->ports[nPortIndex].actions =
+      MMALOMX_ACTION_CHECK_ALLOCATED|MMALOMX_ACTION_ENABLE|MMALOMX_ACTION_NOTIFY_ENABLE;
+   MMALOMX_UNLOCK_PORT(component, &component->ports[nPortIndex]);
+
+   mmalomx_commands_actions_check(component);
+
+   return OMX_ErrorNone;
+}
+
+/*****************************************************************************/
+OMX_ERRORTYPE mmalomx_command_port_disable(
+   OMX_HANDLETYPE hComponent,
+   OMX_U32 nPortIndex)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+   component->ports[nPortIndex].enabled = MMAL_FALSE;
+
+   if (component->state == OMX_StateLoaded ||
+       component->state == OMX_StateWaitForResources)
+   {
+      mmalomx_callback_event_handler(component, OMX_EventCmdComplete, OMX_CommandPortDisable, nPortIndex, NULL);
+      return OMX_ErrorNone;
+   }
+
+   MMALOMX_LOCK_PORT(component, &component->ports[nPortIndex]);
+   component->ports[nPortIndex].actions =
+      MMALOMX_ACTION_DISABLE|MMALOMX_ACTION_CHECK_DEALLOCATED|MMALOMX_ACTION_NOTIFY_DISABLE;
+   if (component->cmd_thread_used)
+      component->ports[nPortIndex].actions |=
+         MMALOMX_ACTION_FLUSH|MMALOMX_ACTION_CHECK_FLUSHED;
+   MMALOMX_UNLOCK_PORT(component, &component->ports[nPortIndex]);
+
+   mmalomx_commands_actions_check(component);
+
+   return OMX_ErrorNone;
+}
+
+/*****************************************************************************/
+OMX_ERRORTYPE mmalomx_command_queue(
+   MMALOMX_COMPONENT_T *component, 
+   OMX_U32 arg1, OMX_U32 arg2)
+{
+   MMAL_BUFFER_HEADER_T *cmd = mmal_queue_get(component->cmd_pool->queue);
+
+   if (!vcos_verify(cmd))
+   {
+      LOG_ERROR("command queue too small");
+      return OMX_ErrorInsufficientResources;
+   }
+
+   cmd->cmd = arg1;
+   cmd->offset = arg2;
+   mmal_queue_put(component->cmd_queue, cmd);
+
+   mmalomx_commands_actions_signal(component);
+
+   return OMX_ErrorNone;
+}
+
+/*****************************************************************************/
+OMX_ERRORTYPE mmalomx_command_dequeue(
+   MMALOMX_COMPONENT_T *component,
+   OMX_U32 *arg1, OMX_U32 *arg2)
+{
+   MMAL_BUFFER_HEADER_T *cmd = mmal_queue_get(component->cmd_queue);
+   if (!cmd)
+      return OMX_ErrorNoMore;
+
+   *arg1 = cmd->cmd;
+   *arg2 = cmd->offset;
+   mmal_buffer_header_release(cmd);
+   return OMX_ErrorNone;
+}
+
+/*****************************************************************************/
+void mmalomx_commands_actions_next(MMALOMX_COMPONENT_T *component)
+{
+   OMX_ERRORTYPE status = OMX_ErrorNone;
+   OMX_COMMANDTYPE cmd;
+   OMX_U32 arg1, arg2, nParam1;
+   unsigned int i;
+
+   status = mmalomx_command_dequeue(component, &arg1, &arg2);
+   if (status != OMX_ErrorNone)
+      return;
+
+   cmd = (OMX_COMMANDTYPE)arg1;
+   nParam1 = arg2;
+
+   if (cmd == OMX_CommandStateSet)
+   {
+      mmalomx_command_state_set((OMX_HANDLETYPE)&component->omx, nParam1);
+   }
+   else if (cmd == OMX_CommandFlush)
+   {
+      for (i = 0; i < component->ports_num; i++)
+         if (i == nParam1 || nParam1 == OMX_ALL)
+            mmalomx_command_port_flush((OMX_HANDLETYPE)&component->omx, i);
+   }
+   else if (cmd == OMX_CommandPortEnable)
+   {
+      for (i = 0; i < component->ports_num; i++)
+         if (i == nParam1 || nParam1 == OMX_ALL)
+            mmalomx_command_port_enable((OMX_HANDLETYPE)&component->omx, i);
+   }
+   else if (cmd == OMX_CommandPortDisable)
+   {
+      for (i = 0; i < component->ports_num; i++)
+         if (i == nParam1 || nParam1 == OMX_ALL)
+            mmalomx_command_port_disable((OMX_HANDLETYPE)&component->omx, i);
+   }
+}
+
diff --git a/interface/mmal/openmaxil/mmalomx_commands.h b/interface/mmal/openmaxil/mmalomx_commands.h
new file mode 100755 (executable)
index 0000000..976b598
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file
+ * OpenMAX IL adaptation layer for MMAL - Commands related functions
+ */
+
+OMX_ERRORTYPE mmalomx_command_state_set(
+   OMX_HANDLETYPE hComponent,
+   OMX_STATETYPE state);
+
+OMX_ERRORTYPE mmalomx_command_port_mark(
+   OMX_HANDLETYPE hComponent,
+   OMX_U32 nPortIndex,
+   OMX_PTR *pCmdData);
+
+OMX_ERRORTYPE mmalomx_command_port_flush(
+   OMX_HANDLETYPE hComponent,
+   OMX_U32 nPortIndex);
+
+OMX_ERRORTYPE mmalomx_command_port_enable(
+   OMX_HANDLETYPE hComponent,
+   OMX_U32 nPortIndex);
+
+OMX_ERRORTYPE mmalomx_command_port_disable(
+   OMX_HANDLETYPE hComponent,
+   OMX_U32 nPortIndex);
+
+#define MMALOMX_ACTION_ENABLE                0x01
+#define MMALOMX_ACTION_DISABLE               0x02
+#define MMALOMX_ACTION_FLUSH                 0x04
+
+#define MMALOMX_ACTION_PENDING_ENABLE        0x010
+#define MMALOMX_ACTION_PENDING_DISABLE       0x020
+#define MMALOMX_ACTION_PENDING_FLUSH         0x040
+
+#define MMALOMX_ACTION_CHECK_ALLOCATED       0x0100
+#define MMALOMX_ACTION_CHECK_DEALLOCATED     0x0200
+#define MMALOMX_ACTION_CHECK_FLUSHED         0x0400
+
+#define MMALOMX_ACTION_NOTIFY_DISABLE        0x1000
+#define MMALOMX_ACTION_NOTIFY_ENABLE         0x2000
+#define MMALOMX_ACTION_NOTIFY_FLUSH          0x4000
+#define MMALOMX_ACTION_NOTIFY_STATE          0x8000
+
+#define MMALOMX_COMMAND_EXIT            0
+#define MMALOMX_COMMAND_STATE_SET       1
+#define MMALOMX_COMMAND_PORT_MARK       2
+#define MMALOMX_COMMAND_PORT_FLUSH      3
+#define MMALOMX_COMMAND_PORT_ENABLE     4
+#define MMALOMX_COMMAND_PORT_DISABLE    5
+
+OMX_ERRORTYPE mmalomx_command_queue(
+   MMALOMX_COMPONENT_T *component, OMX_U32 arg1, OMX_U32 arg2);
+OMX_ERRORTYPE mmalomx_command_dequeue(
+   MMALOMX_COMPONENT_T *component,  OMX_U32 *arg1, OMX_U32 *arg2);
+
+void mmalomx_commands_actions_check(MMALOMX_COMPONENT_T *component);
+void mmalomx_commands_actions_signal(MMALOMX_COMPONENT_T *component);
+void mmalomx_commands_actions_next(MMALOMX_COMPONENT_T *component);
+
diff --git a/interface/mmal/openmaxil/mmalomx_core.c b/interface/mmal/openmaxil/mmalomx_core.c
new file mode 100755 (executable)
index 0000000..20d4fc7
--- /dev/null
@@ -0,0 +1,1577 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/vmcs_host/khronos/IL/OMX_Broadcom.h"
+#include "mmalomx.h"
+#include "mmalomx_commands.h"
+#include "mmalomx_roles.h"
+#include "mmalomx_registry.h"
+#include "mmalomx_buffer.h"
+#include "mmalomx_parameters.h"
+#include "mmalomx_logging.h"
+
+#include <util/mmal_util.h>
+#include <util/mmal_util_params.h>
+#include <string.h>
+#include <stdio.h>
+
+#define MAX_CMD_BUFFERS 5
+
+#define PARAM_GET_PORT(port, component, index) \
+   if (index >= component->ports_num) return OMX_ErrorBadPortIndex; \
+   port = &component->ports[index]
+
+static void *mmalomx_cmd_thread_func(void *arg);
+#define MMALOMX_ZERO_COPY_THRESHOLD 256
+
+/*****************************************************************************/
+OMX_ERRORTYPE mmalomx_callback_event_handler(
+   MMALOMX_COMPONENT_T *component,
+   OMX_EVENTTYPE eEvent,
+   OMX_U32 nData1,
+   OMX_U32 nData2,
+   OMX_PTR pEventData)
+{
+   LOG_DEBUG("component %p, eEvent %i, nData1 %u, nData2 %u, pEventData %p",
+             component, (int)eEvent, (unsigned int)nData1, (unsigned int)nData2, pEventData);
+   return component->callbacks.EventHandler((OMX_HANDLETYPE)&component->omx,
+         component->callbacks_data, eEvent, nData1, nData2, pEventData);
+}
+
+/*****************************************************************************/
+static OMX_ERRORTYPE mmalomx_ComponentGetComponentVersion(
+   OMX_HANDLETYPE hComponent,
+   OMX_STRING pComponentName,
+   OMX_VERSIONTYPE* pComponentVersion,
+   OMX_VERSIONTYPE* pSpecVersion,
+   OMX_UUIDTYPE* pComponentUUID)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+   const char *short_name, *prefix;
+
+   LOG_TRACE("hComponent %p, componentName %p, componentVersion %p, "
+             "pSpecVersion %p, componentUUID %p",
+             hComponent, pComponentName, pComponentVersion, pSpecVersion,
+             pComponentUUID);
+
+   /* Sanity checks */
+   if (!hComponent)
+      return OMX_ErrorInvalidComponent;
+   if (component->state == OMX_StateInvalid)
+      return OMX_ErrorInvalidState;
+   if (!pComponentName || !pComponentVersion || !pSpecVersion || !pComponentUUID )
+      return OMX_ErrorBadParameter;
+
+   short_name = mmalomx_registry_component_name(component->registry_id, &prefix);
+
+   snprintf(pComponentName, OMX_MAX_STRINGNAME_SIZE, "%s%s", short_name, prefix);
+   pComponentVersion->nVersion = 0;
+   pSpecVersion->nVersion = OMX_VERSION;
+   snprintf((char *)(*pComponentUUID), sizeof(OMX_UUIDTYPE), "%s", pComponentName);
+
+   return OMX_ErrorNone;
+}
+
+/*****************************************************************************/
+static OMX_ERRORTYPE mmalomx_ComponentSendCommand(
+   OMX_HANDLETYPE hComponent,
+   OMX_COMMANDTYPE Cmd,
+   OMX_U32 nParam1,
+   OMX_PTR pCmdData)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+   OMX_ERRORTYPE status = OMX_ErrorNone;
+
+   LOG_TRACE("hComponent %p, Cmd %i (%s), nParam1 %i (%s), pCmdData %p",
+             hComponent, Cmd, mmalomx_cmd_to_string(Cmd), (int)nParam1,
+             Cmd == OMX_CommandStateSet ? mmalomx_state_to_string((OMX_STATETYPE)nParam1) : "",
+             pCmdData);
+
+   /* Sanity checks */
+   if (!hComponent)
+      return OMX_ErrorInvalidComponent;
+   if (component->state == OMX_StateInvalid)
+      return OMX_ErrorInvalidState;
+
+   /* Sanity check port index */
+   if (Cmd == OMX_CommandFlush || Cmd == OMX_CommandMarkBuffer ||
+       Cmd == OMX_CommandPortEnable || Cmd == OMX_CommandPortDisable)
+   {
+      if (nParam1 != OMX_ALL && nParam1 >= component->ports_num)
+         return OMX_ErrorBadPortIndex;
+   }
+
+   if (Cmd == OMX_CommandStateSet ||
+       Cmd == OMX_CommandFlush ||
+       Cmd == OMX_CommandPortEnable ||
+       Cmd == OMX_CommandPortDisable)
+   {
+      status = mmalomx_command_queue(component, Cmd, nParam1);
+   }
+   else if (Cmd == OMX_CommandMarkBuffer)
+   {
+      status = mmalomx_command_port_mark(hComponent, nParam1, pCmdData);
+   }
+   else
+   {
+      status = OMX_ErrorNotImplemented;
+   }
+
+   return status;
+}
+
+/*****************************************************************************/
+static MMAL_STATUS_T mmalomx_get_port_settings(MMALOMX_PORT_T *port, OMX_PARAM_PORTDEFINITIONTYPE *def)
+{
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   MMAL_PORT_T *mmal = port->mmal;
+
+   def->eDomain = mmalil_es_type_to_omx_domain(mmal->format->type);
+   def->eDir = OMX_DirInput;
+   if (mmal->type == MMAL_PORT_TYPE_OUTPUT)
+      def->eDir = OMX_DirOutput;
+
+   if (def->eDomain == OMX_PortDomainVideo)
+   {
+      def->format.video.eColorFormat = OMX_COLOR_FormatUnused;
+      def->format.video.eCompressionFormat = mmalil_encoding_to_omx_video_coding(mmal->format->encoding);
+      if (def->format.video.eCompressionFormat == OMX_VIDEO_CodingUnused)
+         def->format.video.eColorFormat = mmalil_encoding_to_omx_color_format(mmal->format->encoding);
+
+      def->format.video.nBitrate = mmal->format->bitrate;
+      def->format.video.nFrameWidth = mmal->format->es->video.width;
+      if (mmal->format->es->video.crop.width)
+         def->format.video.nFrameWidth = mmal->format->es->video.crop.width;
+      def->format.video.nStride = mmal->format->es->video.width;
+      if (port->no_cropping)
+         def->format.video.nFrameWidth = def->format.video.nStride;
+      def->format.video.nStride =
+         mmal_encoding_width_to_stride(mmal->format->encoding, def->format.video.nStride);
+      def->format.video.nFrameHeight = mmal->format->es->video.height;
+      if (mmal->format->es->video.crop.height)
+         def->format.video.nFrameHeight = mmal->format->es->video.crop.height;
+      def->format.video.nSliceHeight = mmal->format->es->video.height;
+      if (port->no_cropping)
+         def->format.video.nFrameHeight = def->format.video.nSliceHeight;
+      if (mmal->format->es->video.frame_rate.den)
+         def->format.video.xFramerate = (((int64_t)mmal->format->es->video.frame_rate.num) << 16) /
+            mmal->format->es->video.frame_rate.den;
+      else
+         def->format.video.xFramerate = 0;
+   }
+   else if (def->eDomain == OMX_PortDomainImage)
+   {
+      def->format.image.eColorFormat = OMX_COLOR_FormatUnused;
+      def->format.image.eCompressionFormat = mmalil_encoding_to_omx_image_coding(mmal->format->encoding);
+      if (def->format.image.eCompressionFormat == OMX_IMAGE_CodingUnused)
+         def->format.image.eColorFormat = mmalil_encoding_to_omx_color_format(mmal->format->encoding);
+      if (mmal->format->encoding == MMAL_ENCODING_UNKNOWN)
+         def->format.image.eCompressionFormat = OMX_IMAGE_CodingAutoDetect;
+      def->format.image.nFrameWidth = mmal->format->es->video.width;
+      if (mmal->format->es->video.crop.width)
+         def->format.image.nFrameWidth = mmal->format->es->video.crop.width;
+      def->format.image.nStride = mmal->format->es->video.width;
+      if (port->no_cropping)
+         def->format.image.nFrameWidth = def->format.image.nStride;
+      def->format.image.nStride =
+         mmal_encoding_width_to_stride(mmal->format->encoding, def->format.image.nStride);
+      def->format.image.nFrameHeight = mmal->format->es->video.height;
+      if (mmal->format->es->video.crop.height)
+         def->format.image.nFrameHeight = mmal->format->es->video.crop.height;
+      def->format.image.nSliceHeight = mmal->format->es->video.height;
+      if (port->no_cropping)
+         def->format.image.nFrameHeight = def->format.image.nSliceHeight;
+   }
+   else if(def->eDomain == OMX_PortDomainAudio)
+   {
+      def->format.audio.eEncoding = mmalil_encoding_to_omx_audio_coding(mmal->format->encoding);
+   }
+   else
+   {
+      LOG_ERROR("%s: unsupported domain (%u)", mmal->name, def->eDomain);
+      status = MMAL_EINVAL;
+      goto finish;
+   }
+
+   def->nBufferAlignment = mmal->buffer_alignment_min;
+   def->nBufferCountActual = mmal->buffer_num;
+   def->nBufferCountMin = mmal->buffer_num_min;
+   def->nBufferSize = mmal->buffer_size;
+   if (def->nBufferSize < mmal->buffer_size_min)
+      def->nBufferSize = mmal->buffer_size_min;
+   def->bEnabled = port->enabled;
+   def->bPopulated = port->populated;
+
+ finish:
+   return status;
+}
+
+/*****************************************************************************/
+static OMX_ERRORTYPE mmalomx_ComponentGetParameter(
+   OMX_HANDLETYPE hComponent,
+   OMX_INDEXTYPE nParamIndex,
+   OMX_PTR pParam)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+   MMALOMX_PORT_T *port = NULL;
+
+   LOG_TRACE("hComponent %p, nParamIndex 0x%x (%s), pParam %p",
+             hComponent, nParamIndex, mmalomx_param_to_string(nParamIndex), pParam);
+
+   /* Sanity checks */
+   if (!hComponent)
+      return OMX_ErrorInvalidComponent;
+   if (!pParam)
+      return OMX_ErrorBadParameter;
+   if (*(OMX_U32 *)pParam < sizeof(OMX_U32) + sizeof(OMX_VERSIONTYPE))
+      return OMX_ErrorBadParameter;
+   if (component->state == OMX_StateInvalid)
+      return OMX_ErrorInvalidState;
+
+   switch(nParamIndex)
+   {
+   case OMX_IndexParamAudioInit:
+   case OMX_IndexParamVideoInit:
+   case OMX_IndexParamImageInit:
+   case OMX_IndexParamOtherInit:
+      {
+         OMX_PORT_PARAM_TYPE *param = (OMX_PORT_PARAM_TYPE *)pParam;
+         param->nStartPortNumber = 0;
+         param->nPorts = component->ports_domain_num[OMX_PortDomainAudio];
+         if (nParamIndex == OMX_IndexParamAudioInit)
+            return OMX_ErrorNone;
+         param->nStartPortNumber += param->nPorts;
+         param->nPorts = component->ports_domain_num[OMX_PortDomainVideo];
+         if (nParamIndex == OMX_IndexParamVideoInit)
+            return OMX_ErrorNone;
+         param->nStartPortNumber += param->nPorts;
+         param->nPorts = component->ports_domain_num[OMX_PortDomainImage];
+         if (nParamIndex == OMX_IndexParamImageInit)
+            return OMX_ErrorNone;
+         param->nStartPortNumber += param->nPorts;
+         param->nPorts = component->ports_domain_num[OMX_PortDomainOther];
+      }
+      return OMX_ErrorNone;
+      break;
+   case OMX_IndexParamPortDefinition:
+      {
+         OMX_PARAM_PORTDEFINITIONTYPE *param = (OMX_PARAM_PORTDEFINITIONTYPE *)pParam;
+         PARAM_GET_PORT(port, component, param->nPortIndex);
+         return mmalil_error_to_omx(mmalomx_get_port_settings(port, param));
+      }
+      return OMX_ErrorNone;
+      break;
+   case OMX_IndexParamCompBufferSupplier:
+      {
+         OMX_PARAM_BUFFERSUPPLIERTYPE *param = (OMX_PARAM_BUFFERSUPPLIERTYPE *)pParam;
+         PARAM_GET_PORT(port, component, param->nPortIndex);
+         param->eBufferSupplier = OMX_BufferSupplyUnspecified;
+      }
+      return OMX_ErrorNone;
+      break;
+   case OMX_IndexParamPriorityMgmt:
+      {
+         OMX_PRIORITYMGMTTYPE *param = (OMX_PRIORITYMGMTTYPE *)pParam;
+         param->nGroupPriority = component->group_priority;
+         param->nGroupID = component->group_id;
+      }
+      return OMX_ErrorNone;
+      break;
+   case OMX_IndexParamVideoPortFormat:
+   case OMX_IndexParamAudioPortFormat:
+      {
+         OMX_VIDEO_PARAM_PORTFORMATTYPE *param = (OMX_VIDEO_PARAM_PORTFORMATTYPE *)pParam;
+         PARAM_GET_PORT(port, component, param->nPortIndex);
+
+         /* Populate our internal list of encodings the first time around */
+         if (!port->encodings_num)
+         {
+            port->encodings_header.id = MMAL_PARAMETER_SUPPORTED_ENCODINGS;
+            port->encodings_header.size = sizeof(port->encodings_header) + sizeof(port->encodings);
+            if (mmal_port_parameter_get(port->mmal, &port->encodings_header) == MMAL_SUCCESS)
+            {
+                port->encodings_num = (port->encodings_header.size - sizeof(port->encodings_header)) /
+                   sizeof(port->encodings[0]);
+            }
+            if (!port->encodings_num)
+            {
+               port->encodings_num = 1;
+               port->encodings[0] = port->mmal->format->encoding;
+            }
+         }
+
+         if (param->nIndex >= port->encodings_num)
+            return OMX_ErrorNoMore;
+
+         if (nParamIndex == OMX_IndexParamVideoPortFormat)
+         {
+            param->eColorFormat = OMX_COLOR_FormatUnused;
+            param->eCompressionFormat =
+               mmalil_encoding_to_omx_video_coding(port->encodings[param->nIndex]);
+            if (param->eCompressionFormat == OMX_VIDEO_CodingUnused)
+               param->eColorFormat =
+                  mmalil_encoding_to_omx_color_format(port->encodings[param->nIndex]);
+            param->xFramerate = 0;
+         }
+         else
+         {
+            OMX_AUDIO_PARAM_PORTFORMATTYPE *aparam =
+               (OMX_AUDIO_PARAM_PORTFORMATTYPE *)pParam;
+            aparam->eEncoding =
+               mmalil_encoding_to_omx_audio_coding(port->encodings[param->nIndex]);
+         }
+         return OMX_ErrorNone;
+      }
+      break;
+   case OMX_IndexParamImagePortFormat:
+   case OMX_IndexParamOtherPortFormat:
+      break;
+   case OMX_IndexParamStandardComponentRole:
+      {
+         OMX_PARAM_COMPONENTROLETYPE *param = (OMX_PARAM_COMPONENTROLETYPE *)pParam;
+         const char *role = mmalomx_role_to_name(component->role);
+         if (!role)
+            role = component->name;
+         snprintf((char *)param->cRole, sizeof(param->cRole), "%s", role);
+      }
+      return OMX_ErrorNone;
+   default:
+      return mmalomx_parameter_get(component, nParamIndex, pParam);
+   }
+
+   return OMX_ErrorNotImplemented;
+}
+
+/*****************************************************************************/
+static MMAL_STATUS_T mmalomx_set_port_settings(MMALOMX_PORT_T *mmalomx_port,
+   OMX_PARAM_PORTDEFINITIONTYPE *def)
+{
+   MMAL_PORT_T *port = mmalomx_port->mmal;
+   uint32_t buffer_size_min = port->buffer_size_min;
+   MMAL_STATUS_T status;
+
+   port->format->type = mmalil_omx_domain_to_es_type(def->eDomain);
+   port->format->encoding_variant = 0;
+
+   if(def->eDomain == OMX_PortDomainVideo)
+   {
+      if (def->format.video.eCompressionFormat != OMX_VIDEO_CodingUnused)
+         port->format->encoding = mmalil_omx_video_coding_to_encoding(def->format.video.eCompressionFormat);
+      else
+         port->format->encoding = mmalil_omx_color_format_to_encoding(def->format.video.eColorFormat);
+
+      port->format->bitrate = def->format.video.nBitrate;
+      port->format->es->video.width = def->format.video.nFrameWidth;
+      if (!mmalomx_port->no_cropping)
+         port->format->es->video.crop.width = port->format->es->video.width;
+      if (mmal_encoding_stride_to_width(port->format->encoding, def->format.video.nStride))
+         port->format->es->video.width =
+            mmal_encoding_stride_to_width(port->format->encoding, def->format.video.nStride);
+      port->format->es->video.height = def->format.video.nFrameHeight;
+      if (!mmalomx_port->no_cropping)
+         port->format->es->video.crop.height = port->format->es->video.height;
+      if (def->format.video.nSliceHeight > def->format.video.nFrameHeight)
+         port->format->es->video.height = def->format.video.nSliceHeight;
+      port->format->es->video.frame_rate.num = def->format.video.xFramerate;
+      port->format->es->video.frame_rate.den = (1<<16);
+   }
+   else if(def->eDomain == OMX_PortDomainImage)
+   {
+      if (def->format.image.eCompressionFormat != OMX_IMAGE_CodingUnused)
+         port->format->encoding = mmalil_omx_image_coding_to_encoding(def->format.image.eCompressionFormat);
+      else
+         port->format->encoding = mmalil_omx_color_format_to_encoding(def->format.image.eColorFormat);
+
+      port->format->es->video.width = def->format.image.nFrameWidth;
+      if (!mmalomx_port->no_cropping)
+         port->format->es->video.crop.width = port->format->es->video.width;
+      if (mmal_encoding_stride_to_width(port->format->encoding, def->format.image.nStride))
+         port->format->es->video.width =
+            mmal_encoding_stride_to_width(port->format->encoding, def->format.image.nStride);
+      port->format->es->video.height = def->format.image.nFrameHeight;
+      if (!mmalomx_port->no_cropping)
+         port->format->es->video.crop.height = port->format->es->video.height;
+      if (def->format.image.nSliceHeight > def->format.image.nFrameHeight)
+         port->format->es->video.height = def->format.image.nSliceHeight;
+   }
+   else if(def->eDomain == OMX_PortDomainAudio)
+   {
+      port->format->encoding = mmalil_omx_audio_coding_to_encoding(def->format.audio.eEncoding);
+   }
+   else
+   {
+      port->format->encoding = MMAL_ENCODING_UNKNOWN;
+   }
+
+   port->buffer_num = def->nBufferCountActual;
+   port->buffer_size = def->nBufferSize;
+   if (port->buffer_size < port->buffer_size_min)
+      port->buffer_size = port->buffer_size_min;
+
+   status = mmal_port_format_commit(port);
+   if (status != MMAL_SUCCESS)
+      return status;
+
+   /* Acknowledge any ongoing port format changed event */
+   mmalomx_port->format_changed = MMAL_FALSE;
+
+   /* The minimum buffer size only changes when the format significantly changes
+    * and in that case we want to advertise the new requirement to the client. */
+   if (port->buffer_size_min != buffer_size_min)
+      port->buffer_size = port->buffer_size_min;
+
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+static OMX_ERRORTYPE mmalomx_ComponentSetParameter(
+   OMX_HANDLETYPE hComponent,
+   OMX_INDEXTYPE nParamIndex,
+   OMX_PTR pParam)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+   MMALOMX_PORT_T *port = NULL;
+
+   LOG_TRACE("hComponent %p, nParamIndex 0x%x (%s), pParam %p",
+             hComponent, nParamIndex, mmalomx_param_to_string(nParamIndex), pParam);
+
+   /* Sanity checks */
+   if (!hComponent)
+      return OMX_ErrorInvalidComponent;
+   if (!pParam)
+      return OMX_ErrorBadParameter;
+   if (*(OMX_U32 *)pParam < sizeof(OMX_U32) + sizeof(OMX_VERSIONTYPE))
+      return OMX_ErrorBadParameter;
+   if (component->state == OMX_StateInvalid)
+      return OMX_ErrorInvalidState;
+
+   switch(nParamIndex)
+   {
+   case OMX_IndexParamPortDefinition:
+      {
+         OMX_PARAM_PORTDEFINITIONTYPE *param = (OMX_PARAM_PORTDEFINITIONTYPE *)pParam;
+         PARAM_GET_PORT(port, component, param->nPortIndex);
+         return mmalil_error_to_omx(mmalomx_set_port_settings(port, param));
+      }
+      return OMX_ErrorNone;
+      break;
+   case OMX_IndexParamCompBufferSupplier:
+      {
+         OMX_PARAM_BUFFERSUPPLIERTYPE *param = (OMX_PARAM_BUFFERSUPPLIERTYPE *)pParam;
+         PARAM_GET_PORT(port, component, param->nPortIndex);
+         //param->eBufferSupplier = OMX_BufferSupplyUnspecified;
+      }
+      return OMX_ErrorNone;
+      break;
+   case OMX_IndexParamPriorityMgmt:
+      {
+         OMX_PRIORITYMGMTTYPE *param = (OMX_PRIORITYMGMTTYPE *)pParam;
+
+         if (component->state != OMX_StateLoaded)
+         return OMX_ErrorIncorrectStateOperation;
+
+         component->group_priority = param->nGroupPriority;
+         component->group_id = param->nGroupID;
+      }
+      return OMX_ErrorNone;
+      break;
+   case OMX_IndexParamAudioPortFormat:
+      {
+         OMX_AUDIO_PARAM_PORTFORMATTYPE *param = (OMX_AUDIO_PARAM_PORTFORMATTYPE *)pParam;
+         PARAM_GET_PORT(port, component, param->nPortIndex);
+         port->mmal->format->encoding = mmalil_omx_audio_coding_to_encoding(param->eEncoding);
+         port->mmal->format->encoding_variant = 0;
+         if (mmal_port_format_commit(port->mmal) != MMAL_SUCCESS)
+            LOG_ERROR("OMX_IndexParamAudioPortFormat commit failed");
+         return OMX_ErrorNone;
+      }
+      break;
+   case OMX_IndexParamVideoPortFormat:
+      {
+         OMX_VIDEO_PARAM_PORTFORMATTYPE *param = (OMX_VIDEO_PARAM_PORTFORMATTYPE *)pParam;
+         PARAM_GET_PORT(port, component, param->nPortIndex);
+         if (param->eCompressionFormat != OMX_VIDEO_CodingUnused)
+            port->mmal->format->encoding = mmalil_omx_video_coding_to_encoding(param->eCompressionFormat);
+         else
+            port->mmal->format->encoding = mmalil_omx_color_format_to_encoding(param->eColorFormat);
+         port->mmal->format->encoding_variant = 0;
+
+         if (mmal_port_format_commit(port->mmal) != MMAL_SUCCESS)
+            LOG_ERROR("OMX_IndexParamAudioPortFormat commit failed");
+         return OMX_ErrorNone;
+      }
+      break;
+   case OMX_IndexParamImagePortFormat:
+   case OMX_IndexParamOtherPortFormat:
+      break;
+   case OMX_IndexParamStandardComponentRole:
+      {
+         OMX_PARAM_COMPONENTROLETYPE *param = (OMX_PARAM_COMPONENTROLETYPE *)pParam;
+         return mmalomx_role_set(component, (const char *)param->cRole);
+      }
+      break;
+   default:
+      {
+         OMX_ERRORTYPE status = mmalomx_parameter_set(component, nParamIndex, pParam);
+
+         /* Keep track of the zero-copy state */
+         if (status == OMX_ErrorNone && nParamIndex == OMX_IndexParamBrcmZeroCopy)
+         {
+            PARAM_GET_PORT(port, component, ((OMX_CONFIG_PORTBOOLEANTYPE *)pParam)->nPortIndex);
+            port->zero_copy = ((OMX_CONFIG_PORTBOOLEANTYPE *)pParam)->bEnabled;
+         }
+
+         return status;
+      }
+   }
+
+   return OMX_ErrorNotImplemented;
+}
+
+/*****************************************************************************/
+static OMX_ERRORTYPE mmalomx_ComponentGetConfig(
+   OMX_HANDLETYPE hComponent,
+   OMX_INDEXTYPE nParamIndex,
+   OMX_PTR pParam)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+
+   LOG_TRACE("hComponent %p, nParamIndex 0x%x (%s), pParam %p",
+             hComponent, nParamIndex, mmalomx_param_to_string(nParamIndex), pParam);
+
+   /* Sanity checks */
+   if (!hComponent)
+      return OMX_ErrorInvalidComponent;
+   if (!pParam)
+      return OMX_ErrorBadParameter;
+   if (*(OMX_U32 *)pParam < sizeof(OMX_U32) + sizeof(OMX_VERSIONTYPE))
+      return OMX_ErrorBadParameter;
+   if (component->state == OMX_StateInvalid)
+      return OMX_ErrorInvalidState;
+
+   return mmalomx_parameter_get(component, nParamIndex, pParam);
+}
+
+/*****************************************************************************/
+static OMX_ERRORTYPE mmalomx_ComponentSetConfig(
+   OMX_HANDLETYPE hComponent,
+   OMX_INDEXTYPE nParamIndex,
+   OMX_PTR pParam)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+
+   LOG_TRACE("hComponent %p, nParamIndex 0x%x (%s), pParam %p",
+             hComponent, nParamIndex, mmalomx_param_to_string(nParamIndex), pParam);
+
+   /* Sanity checks */
+   if (!hComponent)
+      return OMX_ErrorInvalidComponent;
+   if (!pParam)
+      return OMX_ErrorBadParameter;
+   if (*(OMX_U32 *)pParam < sizeof(OMX_U32) + sizeof(OMX_VERSIONTYPE))
+      return OMX_ErrorBadParameter;
+   if (component->state == OMX_StateInvalid)
+      return OMX_ErrorInvalidState;
+
+   return mmalomx_parameter_set(component, nParamIndex, pParam);
+}
+
+/*****************************************************************************/
+static OMX_ERRORTYPE mmalomx_ComponentGetExtensionIndex(
+   OMX_HANDLETYPE hComponent,
+   OMX_STRING cParameterName,
+   OMX_INDEXTYPE* pIndexType)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+
+   LOG_TRACE("hComponent %p, cParameterName %s, pIndexType %p",
+             hComponent, cParameterName, pIndexType);
+
+   /* Sanity checks */
+   if (!hComponent)
+      return OMX_ErrorInvalidComponent;
+   if (component->state == OMX_StateInvalid)
+      return OMX_ErrorInvalidState;
+
+   return mmalomx_parameter_extension_index_get(cParameterName, pIndexType);
+}
+
+/*****************************************************************************/
+static OMX_ERRORTYPE mmalomx_ComponentGetState(
+   OMX_HANDLETYPE hComponent,
+   OMX_STATETYPE* pState)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+   MMAL_PARAM_UNUSED(component);
+
+   LOG_TRACE("hComponent %p, pState, %p", hComponent, pState);
+
+   /* Sanity checks */
+   if (!hComponent)
+      return OMX_ErrorInvalidComponent;
+   if (!pState)
+      return OMX_ErrorBadParameter;
+
+   *pState = component->state;
+   return OMX_ErrorNone;
+}
+
+/*****************************************************************************/
+static OMX_ERRORTYPE mmalomx_ComponentTunnelRequest(
+   OMX_HANDLETYPE hComponent,
+   OMX_U32 nPort,
+   OMX_HANDLETYPE hTunneledComp,
+   OMX_U32 nTunneledPort,
+   OMX_TUNNELSETUPTYPE* pTunnelSetup)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+   MMAL_PARAM_UNUSED(component);
+
+   LOG_TRACE("hComponent %p, nPort %i, hTunneledComp %p, nTunneledPort %i, "
+             "pTunnelSetup %p", hComponent, (int)nPort, hTunneledComp,
+             (int)nTunneledPort, pTunnelSetup);
+
+   /* Sanity checks */
+   if (!hComponent)
+      return OMX_ErrorInvalidComponent;
+   if (component->state == OMX_StateInvalid)
+      return OMX_ErrorInvalidState;
+   if (nPort >= component->ports_num)
+      return OMX_ErrorBadPortIndex;
+   if (component->state != OMX_StateLoaded && component->ports[nPort].enabled)
+      return OMX_ErrorIncorrectStateOperation;
+   if (hTunneledComp && !pTunnelSetup)
+      return OMX_ErrorBadParameter;
+
+   if (!hTunneledComp)
+      return OMX_ErrorNone;
+   return OMX_ErrorNotImplemented;
+}
+
+/*****************************************************************************/
+static OMX_ERRORTYPE mmalomx_ComponentUseBuffer(
+   OMX_HANDLETYPE hComponent,
+   OMX_BUFFERHEADERTYPE** ppBuffer,
+   OMX_U32 nPortIndex,
+   OMX_PTR pAppPrivate,
+   OMX_U32 nSizeBytes,
+   OMX_U8* pBuffer)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+   OMX_ERRORTYPE status = OMX_ErrorNone;
+   MMAL_BOOL_T populated = MMAL_FALSE;
+   OMX_BUFFERHEADERTYPE *buffer;
+   MMALOMX_PORT_T *port;
+
+   LOG_TRACE("hComponent %p, ppBufferHdr %p, nPortIndex %i, pAppPrivate %p,"
+             " nSizeBytes %i, pBuffer %p", hComponent, ppBuffer,
+             (int)nPortIndex, pAppPrivate, (int)nSizeBytes, pBuffer);
+
+   /* Sanity checks */
+   if (!hComponent)
+      return OMX_ErrorInvalidComponent;
+   if (!ppBuffer)
+      return OMX_ErrorBadParameter;
+   if (component->state == OMX_StateInvalid)
+      return OMX_ErrorInvalidState;
+   if (nPortIndex >= component->ports_num)
+      return OMX_ErrorBadPortIndex;
+
+   /* Make sure any previous command has been processed.
+   * This is not ideal since done inline but in practice the actual
+   * notification to the client will not be done as part of this call. */
+   mmalomx_commands_actions_check(component);
+
+   port = &component->ports[nPortIndex];
+   MMALOMX_LOCK_PORT(component, port);
+
+   if (!(port->actions & MMALOMX_ACTION_CHECK_ALLOCATED))
+      status = OMX_ErrorIncorrectStateOperation;
+   if (port->populated)
+      status = OMX_ErrorIncorrectStateOperation;
+   if (status != OMX_ErrorNone)
+      goto error;
+
+   /* Check for mismatched calls to UseBuffer/AllocateBuffer */
+   if (port->buffers && port->buffers_allocated)
+   {
+      status = OMX_ErrorBadParameter;
+      goto error;
+   }
+
+   /* Sanity check buffer size */
+   if (nSizeBytes < port->mmal->buffer_size_min)
+   {
+      LOG_ERROR("buffer size too small (%i/%i)", (int)nSizeBytes,
+                (int)port->mmal->buffer_size_min);
+      status = OMX_ErrorBadParameter;
+      goto error;
+   }
+   if (!port->buffers)
+      port->mmal->buffer_size = nSizeBytes;
+   if (nSizeBytes > port->mmal->buffer_size)
+   {
+      LOG_ERROR("buffer size too big (%i/%i)", (int)nSizeBytes,
+                (int)port->mmal->buffer_size);
+      status = OMX_ErrorBadParameter;
+      goto error;
+   }
+
+   buffer = calloc( 1, sizeof(*buffer) );
+   if (!buffer)
+   {
+      status = OMX_ErrorInsufficientResources;
+      goto error;
+   }
+
+   buffer->nSize = sizeof(*buffer);
+   buffer->nVersion.nVersion = OMX_VERSION;
+   buffer->nAllocLen = nSizeBytes;
+   buffer->pBuffer = pBuffer;
+   buffer->pAppPrivate = pAppPrivate;
+   if (port->direction == OMX_DirInput)
+   {
+      buffer->nInputPortIndex = nPortIndex;
+      buffer->pOutputPortPrivate = pAppPrivate;
+   }
+   else
+   {
+      buffer->nOutputPortIndex = nPortIndex;
+      buffer->pInputPortPrivate = pAppPrivate;
+   }
+
+   *ppBuffer = buffer;
+   port->buffers++;
+   port->buffers_allocated = MMAL_FALSE;
+   port->populated = populated = port->buffers == port->mmal->buffer_num;
+
+   MMALOMX_UNLOCK_PORT(component, port);
+
+   LOG_DEBUG("allocated %i/%i buffers", port->buffers, port->mmal->buffer_num);
+
+   if (populated)
+      mmalomx_commands_actions_signal(component);
+
+   return OMX_ErrorNone;
+
+error:
+   MMALOMX_UNLOCK_PORT(component, port);
+   return status;
+}
+
+/*****************************************************************************/
+static OMX_ERRORTYPE mmalomx_ComponentAllocateBuffer(
+   OMX_HANDLETYPE hComponent,
+   OMX_BUFFERHEADERTYPE** ppBuffer,
+   OMX_U32 nPortIndex,
+   OMX_PTR pAppPrivate,
+   OMX_U32 nSizeBytes)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+   OMX_ERRORTYPE status = OMX_ErrorNone;
+   MMAL_BOOL_T populated = MMAL_FALSE;
+   OMX_BUFFERHEADERTYPE *buffer = 0;
+   MMALOMX_PORT_T *port;
+
+   LOG_TRACE("hComponent %p, ppBuffer %p, nPortIndex %i, pAppPrivate %p, "
+             "nSizeBytes %i", hComponent, ppBuffer, (int)nPortIndex,
+             pAppPrivate, (int)nSizeBytes);
+
+   /* Sanity checks */
+   if (!hComponent)
+      return OMX_ErrorInvalidComponent;
+   if (!ppBuffer)
+      return OMX_ErrorBadParameter;
+   if (component->state == OMX_StateInvalid)
+      return OMX_ErrorInvalidState;
+   if (nPortIndex >= component->ports_num)
+      return OMX_ErrorBadPortIndex;
+
+   /* Make sure any previous command has been processed.
+   * This is not ideal since done inline but in practice the actual
+   * notification to the client will not be done as part of this call. */
+   mmalomx_commands_actions_check(component);
+
+   port = &component->ports[nPortIndex];
+   MMALOMX_LOCK_PORT(component, port);
+
+   if (!(port->actions & MMALOMX_ACTION_CHECK_ALLOCATED))
+      status = OMX_ErrorIncorrectStateOperation;
+   if (port->populated)
+      status = OMX_ErrorIncorrectStateOperation;
+   if (status != OMX_ErrorNone)
+      goto error;
+
+   /* Check for mismatched calls to UseBuffer/AllocateBuffer */
+   if (!status && port->buffers && !port->buffers_allocated)
+   {
+      status = OMX_ErrorBadParameter;
+      goto error;
+   }
+
+   /* Sanity check buffer size */
+   if (nSizeBytes < port->mmal->buffer_size_min)
+   {
+      LOG_ERROR("buffer size too small (%i/%i)", (int)nSizeBytes,
+                (int)port->mmal->buffer_size_min);
+      status = OMX_ErrorBadParameter;
+      goto error;
+   }
+   if (!port->buffers)
+      port->mmal->buffer_size = nSizeBytes;
+   if (nSizeBytes > port->mmal->buffer_size)
+   {
+      LOG_ERROR("buffer size too big (%i/%i)", (int)nSizeBytes,
+                (int)port->mmal->buffer_size);
+      status = OMX_ErrorBadParameter;
+      goto error;
+   }
+
+   /* Set the zero-copy mode */
+   if (!port->buffers_allocated && nSizeBytes > MMALOMX_ZERO_COPY_THRESHOLD &&
+       !port->zero_copy)
+   {
+      MMAL_STATUS_T status = mmal_port_parameter_set_boolean(port->mmal,
+         MMAL_PARAMETER_ZERO_COPY, MMAL_TRUE);
+      if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
+         LOG_ERROR("failed to enable zero copy on %s", port->mmal->name);
+   }
+
+   buffer = calloc( 1, sizeof(*buffer) );
+   if (!buffer)
+   {
+      status = OMX_ErrorInsufficientResources;
+      goto error;
+   }
+
+   buffer->pBuffer = mmal_port_payload_alloc(port->mmal, nSizeBytes);
+   if (!buffer->pBuffer)
+   {
+      status = OMX_ErrorInsufficientResources;
+      goto error;
+   }
+
+   buffer->nSize = sizeof(*buffer);
+   buffer->nVersion.nVersion = OMX_VERSION;
+   buffer->nAllocLen = nSizeBytes;
+   buffer->pAppPrivate = pAppPrivate;
+   if (port->direction == OMX_DirInput)
+   {
+      buffer->nInputPortIndex = nPortIndex;
+      buffer->pOutputPortPrivate = pAppPrivate;
+   }
+   else
+   {
+      buffer->nOutputPortIndex = nPortIndex;
+      buffer->pInputPortPrivate = pAppPrivate;
+   }
+   /* Keep an unmodified copy of the pointer for when we come to free it */
+   buffer->pPlatformPrivate = (OMX_PTR)buffer->pBuffer;
+
+   *ppBuffer = buffer;
+   port->buffers++;
+   port->buffers_allocated = MMAL_TRUE;
+   port->populated = populated = port->buffers == port->mmal->buffer_num;
+
+   MMALOMX_UNLOCK_PORT(component, port);
+
+   LOG_DEBUG("allocated %i/%i buffers", port->buffers, port->mmal->buffer_num);
+
+   if (populated)
+      mmalomx_commands_actions_signal(component);
+
+   return OMX_ErrorNone;
+
+error:
+   if (!port->buffers_allocated && !port->zero_copy)
+      mmal_port_parameter_set_boolean(port->mmal, MMAL_PARAMETER_ZERO_COPY, MMAL_FALSE);
+
+   MMALOMX_UNLOCK_PORT(component, port);
+   LOG_ERROR("failed to allocate %i/%i buffers", port->buffers, port->mmal->buffer_num);
+   if (buffer)
+      free(buffer);
+   return status;
+}
+
+/*****************************************************************************/
+static OMX_ERRORTYPE mmalomx_ComponentFreeBuffer(
+   OMX_HANDLETYPE hComponent,
+   OMX_U32 nPortIndex,
+   OMX_BUFFERHEADERTYPE* pBuffer)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+   OMX_ERRORTYPE status = OMX_ErrorNone;
+   MMAL_BOOL_T unpopulated, allocated;
+   MMALOMX_PORT_T *port;
+   unsigned int buffers;
+
+   LOG_TRACE("hComponent %p, nPortIndex %i, pBuffer %p",
+             hComponent, (int)nPortIndex, pBuffer);
+
+   /* Sanity checks */
+   if (!hComponent)
+      return OMX_ErrorInvalidComponent;
+   if (!pBuffer)
+      return OMX_ErrorBadParameter;
+   if (nPortIndex >= component->ports_num)
+      return OMX_ErrorBadPortIndex;
+
+   /* Make sure any previous command has been processed.
+   * This is not ideal since done inline but in practice the actual
+   * notification to the client will not be done as part of this call. */
+   mmalomx_commands_actions_check(component);
+
+   port = &component->ports[nPortIndex];
+   MMALOMX_LOCK_PORT(component, port);
+
+   if (!port->buffers)
+   {
+      status = OMX_ErrorBadParameter;
+      goto error;
+   }
+
+   buffers = --port->buffers;
+   port->populated = MMAL_FALSE;
+   unpopulated = !(port->actions & MMALOMX_ACTION_CHECK_DEALLOCATED);
+   allocated = port->buffers_allocated;
+
+   MMALOMX_UNLOCK_PORT(component, port);
+
+   if (allocated) /* Free the unmodified pointer */
+      mmal_port_payload_free(port->mmal, pBuffer->pPlatformPrivate);
+   free(pBuffer);
+
+   if (allocated && !port->zero_copy) /* Reset the zero-copy status */
+      mmal_port_parameter_set_boolean(port->mmal, MMAL_PARAMETER_ZERO_COPY, MMAL_FALSE);
+
+   LOG_DEBUG("freed %i/%i buffers", port->mmal->buffer_num - port->buffers, port->mmal->buffer_num);
+
+   if (unpopulated)
+      mmalomx_callback_event_handler(component, OMX_EventError, OMX_ErrorPortUnpopulated, 0, NULL);
+
+   if (!buffers)
+      mmalomx_commands_actions_signal(component);
+
+   return OMX_ErrorNone;
+
+error:
+   MMALOMX_UNLOCK_PORT(component, port);
+   return status;
+}
+
+/*****************************************************************************/
+static OMX_ERRORTYPE mmalomx_ComponentEmptyThisBuffer(
+   OMX_HANDLETYPE hComponent,
+   OMX_BUFFERHEADERTYPE* pBuffer)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+
+   if (ENABLE_MMAL_EXTRA_LOGGING)
+      LOG_TRACE("hComponent %p, port %i, pBuffer %p", hComponent,
+                pBuffer ? (int)pBuffer->nInputPortIndex : -1, pBuffer);
+
+   return mmalomx_buffer_send(component, pBuffer, OMX_DirInput);
+}
+
+/*****************************************************************************/
+static OMX_ERRORTYPE mmalomx_ComponentFillThisBuffer(
+   OMX_HANDLETYPE hComponent,
+   OMX_BUFFERHEADERTYPE* pBuffer)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+
+   if (ENABLE_MMAL_EXTRA_LOGGING)
+      LOG_TRACE("hComponent %p, port %i, pBuffer %p", hComponent,
+                pBuffer ? (int)pBuffer->nOutputPortIndex : -1, pBuffer);
+
+  return mmalomx_buffer_send(component, pBuffer, OMX_DirOutput);
+}
+
+/*****************************************************************************/
+static OMX_ERRORTYPE mmalomx_ComponentSetCallbacks(
+   OMX_HANDLETYPE hComponent,
+   OMX_CALLBACKTYPE* pCallbacks,
+   OMX_PTR pAppData)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+   MMAL_PARAM_UNUSED(component);
+
+   LOG_TRACE("hComponent %p, pCallbacks %p, pAppData %p",
+              hComponent, pCallbacks, pAppData);
+
+   /* Sanity checks */
+   if (!hComponent)
+      return OMX_ErrorInvalidComponent;
+   if (!pCallbacks)
+      return OMX_ErrorBadParameter;
+   if (component->state == OMX_StateInvalid)
+      return OMX_ErrorInvalidState;
+
+   if (component->state != OMX_StateLoaded)
+      return OMX_ErrorInvalidState;
+
+   component->callbacks = *pCallbacks;
+   component->callbacks_data = pAppData;
+   return OMX_ErrorNone;
+}
+
+/*****************************************************************************/
+static OMX_ERRORTYPE mmalomx_ComponentDeInit(
+  OMX_HANDLETYPE hComponent)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+   MMAL_PARAM_UNUSED(component);
+
+   LOG_TRACE("hComponent %p", hComponent);
+
+   /* Sanity checks */
+   if (!hComponent)
+      return OMX_ErrorInvalidComponent;
+
+   return OMX_ErrorNone;
+}
+
+/*****************************************************************************/
+static OMX_ERRORTYPE mmalomx_ComponentUseEGLImage(
+   OMX_HANDLETYPE hComponent,
+   OMX_BUFFERHEADERTYPE** ppBufferHdr,
+   OMX_U32 nPortIndex,
+   OMX_PTR pAppPrivate,
+   void* eglImage)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+   MMAL_PARAM_UNUSED(component);
+
+   LOG_TRACE("hComponent %p, ppBufferHdr %p, nPortIndex %i, pAppPrivate %p,"
+             " eglImage %p", hComponent, ppBufferHdr, (int)nPortIndex,
+             pAppPrivate, eglImage);
+
+   /* Sanity checks */
+   if (!hComponent)
+      return OMX_ErrorInvalidComponent;
+   if (component->state == OMX_StateInvalid)
+      return OMX_ErrorInvalidState;
+
+   return OMX_ErrorNotImplemented;
+}
+
+/*****************************************************************************/
+static OMX_ERRORTYPE mmalomx_ComponentRoleEnum(
+   OMX_HANDLETYPE hComponent,
+   OMX_U8 *cRole,
+   OMX_U32 nIndex)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+   MMALOMX_ROLE_T role;
+
+   LOG_TRACE("hComponent %p, cRole %p, nIndex %i",
+             hComponent, cRole, (int)nIndex);
+
+   /* Sanity checks */
+   if (!hComponent)
+      return OMX_ErrorInvalidComponent;
+   if (component->state == OMX_StateInvalid)
+      return OMX_ErrorInvalidState;
+
+   role = mmalomx_registry_component_roles(component->registry_id, nIndex);
+   if (!role)
+      return OMX_ErrorNoMore;
+   if (!mmalomx_role_to_name(role))
+      return OMX_ErrorNoMore;
+
+   strcpy((char *)cRole, mmalomx_role_to_name(role));
+   return OMX_ErrorNone;
+}
+
+/*****************************************************************************/
+OMX_API OMX_ERRORTYPE OMX_APIENTRY MMALOMX_EXPORT(OMX_Init)(void)
+{
+   mmalomx_logging_init();
+   LOG_TRACE("Init");
+   return OMX_ErrorNone;
+}
+
+/*****************************************************************************/
+OMX_API OMX_ERRORTYPE OMX_APIENTRY MMALOMX_EXPORT(OMX_Deinit)(void)
+{
+   LOG_TRACE("Deinit");
+   mmalomx_logging_deinit();
+   return OMX_ErrorNone;
+}
+
+/*****************************************************************************/
+OMX_API OMX_ERRORTYPE OMX_APIENTRY MMALOMX_EXPORT(OMX_ComponentNameEnum)(
+   OMX_STRING cComponentName,
+   OMX_U32 nNameLength,
+   OMX_U32 nIndex)
+{
+   const char *prefix, *name;
+   name = mmalomx_registry_component_name(nIndex, &prefix);
+
+   LOG_TRACE("cComponentName %p, nNameLength %i, nIndex %i",
+             cComponentName, (int)nNameLength, (int)nIndex);
+
+   /* Sanity checking */
+   if (!cComponentName)
+      return OMX_ErrorBadParameter;
+   if (!name)
+      return OMX_ErrorNoMore;
+   if (nNameLength <= strlen(name) + strlen(prefix))
+      return OMX_ErrorBadParameter;
+
+   sprintf(cComponentName, "%s%s", prefix, name);
+   LOG_TRACE("cComponentName: %s", cComponentName);
+   return OMX_ErrorNone;
+}
+
+/*****************************************************************************/
+static void mmalomx_buffer_cb_control(
+   MMAL_PORT_T *port,
+   MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)port->userdata;
+
+   LOG_DEBUG("received event %4.4s on port %s", (char *)&buffer->cmd, port->name);
+
+   if (buffer->cmd == MMAL_EVENT_ERROR)
+   {
+      mmalomx_callback_event_handler(component, OMX_EventError,
+         mmalil_error_to_omx(*(MMAL_STATUS_T *)buffer->data), 0, NULL);
+   }
+   else if (buffer->cmd == MMAL_EVENT_EOS &&
+            buffer->length == sizeof(MMAL_EVENT_END_OF_STREAM_T))
+   {
+      MMAL_EVENT_END_OF_STREAM_T *eos = (MMAL_EVENT_END_OF_STREAM_T *)buffer->data;
+      if (eos->port_index < port->component->input_num)
+      {
+         MMALOMX_PORT_T *omx_port = (MMALOMX_PORT_T *)
+            port->component->input[eos->port_index]->userdata;
+         LOG_DEBUG("send EOS on %i", omx_port->index);
+         mmalomx_callback_event_handler(component, OMX_EventBufferFlag,
+            omx_port->index, OMX_BUFFERFLAG_EOS, NULL);
+      }
+   }
+
+   mmal_buffer_header_release(buffer);
+}
+
+/*****************************************************************************/
+OMX_API OMX_ERRORTYPE OMX_APIENTRY MMALOMX_EXPORT(OMX_GetHandle)(
+   OMX_HANDLETYPE* pHandle,
+   OMX_STRING cComponentName,
+   OMX_PTR pAppData,
+   OMX_CALLBACKTYPE* pCallBacks)
+{
+   OMX_ERRORTYPE status = OMX_ErrorInsufficientResources;
+   MMALOMX_COMPONENT_T *component = 0;
+   MMAL_COMPONENT_T *mmal_component = 0;
+   MMAL_STATUS_T mmal_status;
+   unsigned int i, ports_num;
+   OMX_PORTDOMAINTYPE domain;
+   const char *mmal_name;
+   int registry_id;
+
+   LOG_TRACE("pHandle %p, cComponentName %s, pAppData %p, pCallBacks %p",
+             pHandle, cComponentName, pAppData, pCallBacks);
+
+   /* Sanity check params */
+   if (!pHandle || !cComponentName || !pCallBacks)
+      return OMX_ErrorBadParameter;
+
+   /* Find component */
+   registry_id = mmalomx_registry_find_component(cComponentName);
+   if (registry_id < 0)
+      return OMX_ErrorComponentNotFound;
+
+   /* create and setup component */
+   mmal_name = mmalomx_registry_component_mmal(registry_id);
+   mmal_status = mmal_component_create(mmal_name, &mmal_component);
+   if (mmal_status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("could not create mmal component %s", mmal_name);
+      return mmalil_error_to_omx(mmal_status);
+   }
+   mmal_status = mmal_port_enable(mmal_component->control, mmalomx_buffer_cb_control);
+   if (mmal_status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("could not enable %s", mmal_component->control->name);
+      mmal_component_destroy(mmal_component);
+      return mmalil_error_to_omx(mmal_status);
+   }
+
+   ports_num = mmal_component->port_num - 1;
+
+   component = calloc(1, sizeof(*component) + ports_num * sizeof(*component->ports));
+   if (!component)
+   {
+      mmal_component_destroy(mmal_component);
+      return OMX_ErrorInsufficientResources;
+   }
+
+   if (vcos_mutex_create(&component->lock, "mmalomx lock") != VCOS_SUCCESS)
+   {
+      mmal_component_destroy(mmal_component);
+      free(component);
+      return OMX_ErrorInsufficientResources;
+   }
+   if (vcos_mutex_create(&component->lock_port, "mmalomx port lock") != VCOS_SUCCESS)
+   {
+      vcos_mutex_delete(&component->lock);
+      mmal_component_destroy(mmal_component);
+      free(component);
+      return OMX_ErrorInsufficientResources;
+   }
+
+   component->omx.nSize = sizeof(component->omx);
+   component->omx.nVersion.nVersion = OMX_VERSION;
+   component->mmal = mmal_component;
+   component->state = OMX_StateLoaded;
+   component->callbacks = *pCallBacks;
+   component->callbacks_data = pAppData;
+   component->ports = (MMALOMX_PORT_T *)&component[1];
+   component->registry_id = registry_id;
+   component->name = mmalomx_registry_component_name(registry_id, 0);
+   component->role = mmalomx_registry_component_roles(registry_id, 0);
+
+   // FIXME: make this configurable
+   component->cmd_thread_used = MMAL_TRUE;
+
+   /* Sort the ports into separate OMX domains */
+   for (domain = OMX_PortDomainAudio; domain < OMX_PortDomainOther; domain++)
+   {
+      for (i = 1; i < mmal_component->port_num; i++)
+      {
+         if (domain == mmalil_es_type_to_omx_domain(mmal_component->port[i]->format->type))
+         {
+            component->ports[component->ports_num].mmal = mmal_component->port[i];
+            component->ports_domain_num[domain]++;
+            component->ports_num++;
+         }
+      }
+   }
+   LOG_DEBUG("ports: %i audio, %i video",
+      component->ports_domain_num[OMX_PortDomainAudio],
+      component->ports_domain_num[OMX_PortDomainVideo]);
+
+   /* Setup our ports */
+   for (i = 0; i < component->ports_num; i++)
+   {
+      component->ports[i].component = component;
+      if (component->ports[i].mmal->type == MMAL_PORT_TYPE_OUTPUT)
+         component->ports[i].direction = OMX_DirOutput;
+      component->ports[i].index = i;
+      component->ports[i].enabled = MMAL_TRUE;
+      component->ports[i].pool =
+         mmal_port_pool_create(component->ports[i].mmal, 0, 0);
+      if (!component->ports[i].pool)
+         goto error;
+      component->ports[i].mmal->userdata = (struct MMAL_PORT_USERDATA_T *)&component->ports[i];
+   }
+   mmal_component->control->userdata = (struct MMAL_PORT_USERDATA_T *)component;
+
+   /* Create our OMX commands queue */
+   component->cmd_queue = mmal_queue_create();
+   if (!component->cmd_queue)
+      goto error;
+   component->cmd_pool = mmal_pool_create(MAX_CMD_BUFFERS, 0);
+   if (!component->cmd_pool)
+      goto error;
+
+   if (component->cmd_thread_used &&
+       vcos_semaphore_create(&component->cmd_sema,
+                             "mmalomx sema", 0) != VCOS_SUCCESS)
+   {
+      component->cmd_thread_used = MMAL_FALSE;
+      goto error;
+   }
+
+   if (component->cmd_thread_used &&
+       vcos_thread_create(&component->cmd_thread, component->name, NULL,
+                          mmalomx_cmd_thread_func, component) != VCOS_SUCCESS)
+   {
+      vcos_semaphore_delete(&component->cmd_sema);
+      component->cmd_thread_used = MMAL_FALSE;
+      goto error;
+   }
+
+   /* Set the function pointer for the component's interface */
+   component->omx.GetComponentVersion = mmalomx_ComponentGetComponentVersion;
+   component->omx.SendCommand = mmalomx_ComponentSendCommand;
+   component->omx.GetParameter = mmalomx_ComponentGetParameter;
+   component->omx.SetParameter = mmalomx_ComponentSetParameter;
+   component->omx.GetConfig = mmalomx_ComponentGetConfig;
+   component->omx.SetConfig = mmalomx_ComponentSetConfig;
+   component->omx.GetExtensionIndex = mmalomx_ComponentGetExtensionIndex;
+   component->omx.GetState = mmalomx_ComponentGetState;
+   component->omx.ComponentTunnelRequest = mmalomx_ComponentTunnelRequest;
+   component->omx.UseBuffer = mmalomx_ComponentUseBuffer;
+   component->omx.AllocateBuffer = mmalomx_ComponentAllocateBuffer;
+   component->omx.FreeBuffer = mmalomx_ComponentFreeBuffer;
+   component->omx.EmptyThisBuffer = mmalomx_ComponentEmptyThisBuffer;
+   component->omx.FillThisBuffer = mmalomx_ComponentFillThisBuffer;
+   component->omx.SetCallbacks = mmalomx_ComponentSetCallbacks;
+   component->omx.ComponentDeInit = mmalomx_ComponentDeInit;
+   component->omx.UseEGLImage = mmalomx_ComponentUseEGLImage;
+   component->omx.ComponentRoleEnum = mmalomx_ComponentRoleEnum;
+   *pHandle = (OMX_HANDLETYPE)&component->omx;
+
+   return OMX_ErrorNone;
+
+ error:
+   MMALOMX_IMPORT(OMX_FreeHandle)((OMX_HANDLETYPE)&component->omx);
+   return status;
+}
+
+/*****************************************************************************/
+OMX_API OMX_ERRORTYPE OMX_APIENTRY MMALOMX_EXPORT(OMX_FreeHandle)(
+   OMX_HANDLETYPE hComponent)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
+   OMX_ERRORTYPE status;
+   unsigned int i;
+
+   LOG_TRACE("hComponent %p", hComponent);
+
+   /* Sanity check */
+   if (!hComponent)
+      return OMX_ErrorInvalidComponent;
+
+   if (component->omx.ComponentDeInit)
+   {
+      status = component->omx.ComponentDeInit(hComponent);
+      if (status != OMX_ErrorNone)
+      {
+         LOG_ERROR("ComponentDeInit failed");
+         return status;
+      }
+   }
+
+   if (component->cmd_thread_used)
+   {
+      component->cmd_thread_used = MMAL_FALSE;
+      vcos_semaphore_post(&component->cmd_sema);
+      vcos_thread_join(&component->cmd_thread, NULL);
+   }
+
+   mmal_component_destroy(component->mmal);
+   for (i = 0; i < component->ports_num; i++)
+      if (component->ports[i].pool)
+         mmal_pool_destroy(component->ports[i].pool);
+
+   if (component->cmd_pool)
+      mmal_pool_destroy(component->cmd_pool);
+   if (component->cmd_queue)
+      mmal_queue_destroy(component->cmd_queue);
+   if (component->cmd_thread_used)
+      vcos_semaphore_delete(&component->cmd_sema);
+   vcos_mutex_delete(&component->lock_port);
+   vcos_mutex_delete(&component->lock);
+   free(component);
+   return OMX_ErrorNone;
+}
+
+/*****************************************************************************/
+OMX_API OMX_ERRORTYPE MMALOMX_EXPORT(OMX_GetRolesOfComponent)(
+   OMX_STRING compName,
+   OMX_U32 *pNumRoles,
+   OMX_U8 **roles)
+{
+   OMX_U32 i, num_roles;
+   MMALOMX_ROLE_T role;
+   int registry_id;
+
+   LOG_TRACE("compName %s, pNumRoles %p, roles %p", compName, pNumRoles, roles);
+
+   /* Sanity checks */
+   if (!compName || !pNumRoles)
+      return OMX_ErrorBadParameter;
+
+   if (!roles || *pNumRoles > MMALOMX_MAX_ROLES)
+      num_roles = MMALOMX_MAX_ROLES;
+   else
+      num_roles = *pNumRoles;
+   *pNumRoles = 0;
+
+   /* Find component */
+   registry_id = mmalomx_registry_find_component(compName);
+   if (registry_id < 0)
+      return OMX_ErrorComponentNotFound;
+
+   /* Enumerate Roles */
+   for (i = 0; i < num_roles; i++)
+   {
+      role = mmalomx_registry_component_roles(registry_id, i);
+      if (!role || !mmalomx_role_to_name(role))
+         break;
+
+      if(roles)
+      {
+         strncpy((char *)roles[i], mmalomx_role_to_name(role), OMX_MAX_STRINGNAME_SIZE);
+         LOG_DEBUG("found role: %s", roles[i]);
+      }
+   }
+   LOG_DEBUG("found %i roles", (int)i);
+   *pNumRoles = i;
+
+   return OMX_ErrorNone;
+}
+
+/*****************************************************************************/
+OMX_API OMX_ERRORTYPE MMALOMX_EXPORT(OMX_GetComponentsOfRole)(
+   OMX_STRING role,
+   OMX_U32 *pNumComps,
+   OMX_U8  **compNames)
+{
+   OMX_ERRORTYPE status;
+   OMX_HANDLETYPE handle;
+   OMX_COMPONENTTYPE *comp;
+   OMX_U8 name[OMX_MAX_STRINGNAME_SIZE], compRole[OMX_MAX_STRINGNAME_SIZE];
+   OMX_U32 nNameLength = OMX_MAX_STRINGNAME_SIZE, nIndex = 0;
+   OMX_U32 nRoles, nIndexRoles, nComps = 0;
+   OMX_CALLBACKTYPE callbacks = {0,0,0};
+
+   LOG_TRACE("role %s, pNumComps %p, compNames %p", role, pNumComps, compNames);
+
+   /* Sanity checks */
+   if (!role || !pNumComps)
+      return OMX_ErrorBadParameter;
+
+   /* Enumerates components */
+   while ((status = OMX_ComponentNameEnum((OMX_STRING)name, nNameLength,
+                                          nIndex++)) == OMX_ErrorNone)
+   {
+      /* Find component */
+      status = MMALOMX_IMPORT(OMX_GetHandle)(&handle, (OMX_STRING)name, 0, &callbacks);
+      if(status != OMX_ErrorNone) continue;
+      comp = (OMX_COMPONENTTYPE *)handle;
+
+      /* Enumerate Roles */
+      status = MMALOMX_IMPORT(OMX_GetRolesOfComponent)((OMX_STRING)name, &nRoles, 0);
+      if(status != OMX_ErrorNone) continue;
+
+      for (nIndexRoles = 0; nIndexRoles < nRoles; nIndexRoles++)
+      {
+         status = comp->ComponentRoleEnum(handle, compRole, nIndexRoles);
+         if(status != OMX_ErrorNone) break;
+
+         if(!strncmp((char *)role, (char *)compRole, OMX_MAX_STRINGNAME_SIZE))
+         {
+            /* Found one */
+            nComps++;
+
+            if(!compNames) break;
+
+            /* Check if enough space was provided for all the component names */
+            if(nComps > *pNumComps) return OMX_ErrorBadParameter;
+
+            strncpy((char *)compNames[nComps-1], (char *)name, OMX_MAX_STRINGNAME_SIZE);
+
+            LOG_DEBUG("found component: %s", name);
+         }
+      }
+
+      MMALOMX_IMPORT(OMX_FreeHandle)(handle);
+   }
+   LOG_DEBUG("found %i components", (int)nComps);
+   *pNumComps = nComps;
+
+   return OMX_ErrorNone;
+}
+
+/*****************************************************************************/
+OMX_API OMX_ERRORTYPE OMX_APIENTRY MMALOMX_EXPORT(OMX_SetupTunnel)(
+   OMX_HANDLETYPE hOutput,
+   OMX_U32 nPortOutput,
+   OMX_HANDLETYPE hInput,
+   OMX_U32 nPortInput)
+{
+   OMX_TUNNELSETUPTYPE tunnel_setup = {0, OMX_BufferSupplyUnspecified};
+   OMX_ERRORTYPE status = OMX_ErrorNone;
+
+   LOG_TRACE("hOutput %p, nPortOutput %d, hInput %p, nPortInput %d",
+             hOutput, (int)nPortOutput, hInput, (int)nPortInput);
+
+   /* Sanity checks */
+   if (!hOutput && !hInput)
+      return OMX_ErrorBadParameter;
+
+   if (hOutput)
+   {
+      status = ((OMX_COMPONENTTYPE *)hOutput)->ComponentTunnelRequest(
+         hOutput, nPortOutput, hInput, nPortInput, &tunnel_setup);
+      if (status != OMX_ErrorNone)
+         LOG_DEBUG("OMX_SetupTunnel failed on output port (%i)", status);
+   }
+
+   if (status == OMX_ErrorNone && hInput)
+   {
+      status = ((OMX_COMPONENTTYPE *)hInput)->ComponentTunnelRequest(
+         hInput, nPortInput, hOutput, nPortOutput, &tunnel_setup);
+      if (status != OMX_ErrorNone)
+      {
+         LOG_DEBUG("OMX_SetupTunnel failed on input port (%i)", status);
+         /* Cancel request on output port */
+         if (hOutput)
+            ((OMX_COMPONENTTYPE *)hOutput)->ComponentTunnelRequest(
+               hOutput, nPortOutput, NULL, 0, NULL);
+      }
+   }
+
+   return status;
+}
+
+OMX_API OMX_ERRORTYPE MMALOMX_EXPORT(OMX_GetContentPipe)(
+   OMX_HANDLETYPE *hPipe,
+   OMX_STRING szURI)
+{
+   MMAL_PARAM_UNUSED(hPipe);
+   MMAL_PARAM_UNUSED(szURI);
+
+   LOG_TRACE("hPipe %p, szURI %s", hPipe, szURI);
+
+   return OMX_ErrorNotImplemented;
+}
+
+/*****************************************************************************
+ * Processing thread
+ *****************************************************************************/
+static void *mmalomx_cmd_thread_func(void *arg)
+{
+   MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)arg;
+   VCOS_STATUS_T status;
+
+   while (component->cmd_thread_used)
+   {
+      status = vcos_semaphore_wait(&component->cmd_sema);
+      if (status == VCOS_EAGAIN)
+         continue;
+      mmalomx_commands_actions_check(component);
+   }
+
+   return 0;
+}
+
diff --git a/interface/mmal/openmaxil/mmalomx_logging.c b/interface/mmal/openmaxil/mmalomx_logging.c
new file mode 100755 (executable)
index 0000000..511e9c3
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/vmcs_host/khronos/IL/OMX_Core.h"
+#include "interface/vmcs_host/khronos/IL/OMX_Component.h"
+#include "interface/vmcs_host/khronos/IL/OMX_Video.h"
+#include "interface/vmcs_host/khronos/IL/OMX_Audio.h"
+#include "interface/vmcs_host/khronos/IL/OMX_Broadcom.h"
+#include "mmalomx_logging.h"
+#include "mmalomx.h"
+#include "mmalomx_util_params.h"
+#include "interface/vcos/vcos_types.h"
+
+VCOS_LOG_CAT_T mmalomx_log_category;
+static VCOS_LOG_LEVEL_T mmalomx_log_level = VCOS_LOG_ERROR;
+
+#define MMALOMX_SAT(a,b,c) ((a)<(b)?(a):(a)>(c)?(c):(a))
+
+void mmalomx_logging_init(void)
+{
+   vcos_log_set_level(VCOS_LOG_CATEGORY, mmalomx_log_level);
+   vcos_log_register("mmalomx", VCOS_LOG_CATEGORY);
+}
+
+void mmalomx_logging_deinit(void)
+{
+   mmalomx_log_level = mmalomx_log_category.level;
+   vcos_log_unregister(VCOS_LOG_CATEGORY);
+}
+
+const char *mmalomx_param_to_string(OMX_INDEXTYPE param)
+{
+  static const struct {
+    const char *string;
+    const OMX_INDEXTYPE param;
+  } param_to_names[] =
+  {
+    {"OMX_IndexParamPriorityMgmt", OMX_IndexParamPriorityMgmt},
+    {"OMX_IndexParamAudioInit", OMX_IndexParamAudioInit},
+    {"OMX_IndexParamImageInit", OMX_IndexParamImageInit},
+    {"OMX_IndexParamVideoInit", OMX_IndexParamVideoInit},
+    {"OMX_IndexParamOtherInit", OMX_IndexParamOtherInit},
+    {"OMX_IndexParamPortDefinition", OMX_IndexParamPortDefinition},
+    {"OMX_IndexParamCompBufferSupplier", OMX_IndexParamCompBufferSupplier},
+    {"OMX_IndexParamAudioPortFormat", OMX_IndexParamAudioPortFormat},
+    {"OMX_IndexParamVideoPortFormat", OMX_IndexParamVideoPortFormat},
+    {"OMX_IndexParamImagePortFormat", OMX_IndexParamImagePortFormat},
+    {"OMX_IndexParamOtherPortFormat", OMX_IndexParamOtherPortFormat},
+    {"OMX_IndexParamAudioPcm", OMX_IndexParamAudioPcm},
+    {"OMX_IndexParamAudioAac", OMX_IndexParamAudioAac},
+    {"OMX_IndexParamAudioMp3", OMX_IndexParamAudioMp3},
+    {"OMX_IndexParamVideoMpeg2", OMX_IndexParamVideoMpeg2},
+    {"OMX_IndexParamVideoMpeg4", OMX_IndexParamVideoMpeg4},
+    {"OMX_IndexParamVideoWmv", OMX_IndexParamVideoWmv},
+    {"OMX_IndexParamVideoRv", OMX_IndexParamVideoRv},
+    {"OMX_IndexParamVideoAvc", OMX_IndexParamVideoAvc},
+    {"OMX_IndexParamVideoH263", OMX_IndexParamVideoH263},
+    {"OMX_IndexParamStandardComponentRole", OMX_IndexParamStandardComponentRole},
+    {"OMX_IndexParamContentURI", OMX_IndexParamContentURI},
+    {"OMX_IndexParamCommonSensorMode", OMX_IndexParamCommonSensorMode},
+    {"OMX_IndexConfigCommonWhiteBalance", OMX_IndexConfigCommonWhiteBalance},
+    {"OMX_IndexConfigCommonDigitalZoom", OMX_IndexConfigCommonDigitalZoom},
+    {"OMX_IndexConfigCommonExposureValue", OMX_IndexConfigCommonExposureValue},
+    {"OMX_IndexConfigCapturing", OMX_IndexConfigCapturing},
+    {"OMX_IndexAutoPauseAfterCapture", OMX_IndexAutoPauseAfterCapture},
+    {"OMX_IndexConfigCommonRotate", OMX_IndexConfigCommonRotate},
+    {"OMX_IndexConfigCommonMirror", OMX_IndexConfigCommonMirror},
+    {"OMX_IndexConfigCommonScale", OMX_IndexConfigCommonScale},
+    {"OMX_IndexConfigCommonInputCrop", OMX_IndexConfigCommonInputCrop},
+    {"OMX_IndexConfigCommonOutputCrop", OMX_IndexConfigCommonOutputCrop},
+    {"OMX_IndexParamNumAvailableStreams", OMX_IndexParamNumAvailableStreams},
+    {"OMX_IndexParamActiveStream", OMX_IndexParamActiveStream},
+    {"OMX_IndexParamVideoBitrate", OMX_IndexParamVideoBitrate},
+    {"OMX_IndexParamVideoProfileLevelQuerySupported", OMX_IndexParamVideoProfileLevelQuerySupported},
+
+    {"OMX_IndexParam unknown", (OMX_INDEXTYPE)0}
+  };
+  const char *name = mmalomx_parameter_name_omx((uint32_t)param);
+  int i;
+
+  if (name)
+     return name;
+
+  for(i = 0; param_to_names[i].param &&
+      param_to_names[i].param != param; i++);
+
+  return param_to_names[i].string;
+}
+
+const char *mmalomx_cmd_to_string(OMX_COMMANDTYPE cmd)
+{
+  static const char *names[] = {
+    "OMX_CommandStateSet", "OMX_CommandFlush", "OMX_CommandPortDisable",
+    "OMX_CommandPortEnable", "OMX_CommandMarkBuffer", "OMX_Command unknown"
+  };
+
+  return names[MMALOMX_SAT((int)cmd, 0, (int)vcos_countof(names)-1)];
+}
+
+const char *mmalomx_state_to_string(OMX_STATETYPE state)
+{
+  static const char *names[] = {
+    "OMX_StateInvalid", "OMX_StateLoaded", "OMX_StateIdle",
+    "OMX_StateExecuting", "OMX_StatePause", "OMX_StateWaitForResources",
+    "OMX_State unknown"
+  };
+
+  return names[MMALOMX_SAT((int)state, 0, (int)vcos_countof(names)-1)];
+}
+
+const char *mmalomx_event_to_string(OMX_EVENTTYPE event)
+{
+  static const char *names[] = {
+    "OMX_EventCmdComplete", "OMX_EventError", "OMX_EventMark",
+    "OMX_EventPortSettingsChanged", "OMX_EventBufferFlag",
+    "OMX_EventResourcesAcquired", "OMX_EventComponentResumed",
+    "OMX_EventDynamicResourcesAvailable", "OMX_EventPortFormatDetected",
+    "OMX_Event unknown"
+  };
+
+  return names[MMALOMX_SAT((int)event, 0, (int)vcos_countof(names)-1)];
+}
+
+const char *mmalomx_error_to_string(OMX_ERRORTYPE error)
+{
+  static const char *names[] = {
+    "OMX_ErrorInsufficientResources", "OMX_ErrorUndefined",
+    "OMX_ErrorInvalidComponentName", "OMX_ErrorComponentNotFound",
+    "OMX_ErrorInvalidComponent", "OMX_ErrorBadParameter",
+    "OMX_ErrorNotImplemented", "OMX_ErrorUnderflow",
+    "OMX_ErrorOverflow", "OMX_ErrorHardware", "OMX_ErrorInvalidState",
+    "OMX_ErrorStreamCorrupt", "OMX_ErrorPortsNotCompatible",
+    "OMX_ErrorResourcesLost", "OMX_ErrorNoMore", "OMX_ErrorVersionMismatch",
+    "OMX_ErrorNotReady", "OMX_ErrorTimeout", "OMX_ErrorSameState",
+    "OMX_ErrorResourcesPreempted", "OMX_ErrorPortUnresponsiveDuringAllocation",
+    "OMX_ErrorPortUnresponsiveDuringDeallocation",
+    "OMX_ErrorPortUnresponsiveDuringStop", "OMX_ErrorIncorrectStateTransition",
+    "OMX_ErrorIncorrectStateOperation", "OMX_ErrorUnsupportedSetting",
+    "OMX_ErrorUnsupportedIndex", "OMX_ErrorBadPortIndex",
+    "OMX_ErrorPortUnpopulated", "OMX_ErrorComponentSuspended",
+    "OMX_ErrorDynamicResourcesUnavailable", "OMX_ErrorMbErrorsInFrame",
+    "OMX_ErrorFormatNotDetected", "OMX_ErrorContentPipeOpenFailed",
+    "OMX_ErrorContentPipeCreationFailed", "OMX_ErrorSeperateTablesUsed",
+    "OMX_ErrorTunnelingUnsupported",
+    "OMX_Error unknown"
+  };
+
+  if(error == OMX_ErrorNone) return "OMX_ErrorNone";
+
+  error -= OMX_ErrorInsufficientResources;
+  return names[MMALOMX_SAT((int)error, 0, (int)vcos_countof(names)-1)];
+}
diff --git a/interface/mmal/openmaxil/mmalomx_logging.h b/interface/mmal/openmaxil/mmalomx_logging.h
new file mode 100755 (executable)
index 0000000..eb583ab
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file
+ * OpenMAX IL adaptation layer for MMAL - Logging functions
+ */
+
+#include "mmal_common.h"
+#include "interface/vcos/vcos_logging.h"
+
+#define VCOS_LOG_CATEGORY (&mmalomx_log_category)
+extern VCOS_LOG_CAT_T mmalomx_log_category;
+#include <mmal_logging.h>
+
+void mmalomx_logging_init(void);
+void mmalomx_logging_deinit(void);
+
+const char *mmalomx_param_to_string(OMX_INDEXTYPE param);
+const char *mmalomx_cmd_to_string(OMX_COMMANDTYPE cmd);
+const char *mmalomx_state_to_string(OMX_STATETYPE state);
+const char *mmalomx_event_to_string(OMX_EVENTTYPE event);
+const char *mmalomx_error_to_string(OMX_ERRORTYPE error);
diff --git a/interface/mmal/openmaxil/mmalomx_marks.c b/interface/mmal/openmaxil/mmalomx_marks.c
new file mode 100755 (executable)
index 0000000..a645af6
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file
+ * OpenMAX IL adaptation layer for MMAL - Marking related functions
+ *
+ * Note that we do not support buffer marks properly other than for conformance
+ * testing. For input ports, we just move the mark over to the output port.
+ */
+
+#include "mmalomx.h"
+#include "mmalomx_buffer.h"
+#include "mmalomx_marks.h"
+#include "mmalomx_commands.h"
+#include "mmalomx_logging.h"
+
+#define MMALOMX_GET_MARK(port, mark) \
+   mark = &port->marks[port->marks_first]; \
+   port->marks_num--; \
+   port->marks_first = ++port->marks_first == MAX_MARKS_NUM ? 0 : port->marks_first
+#define MMALOMX_PUT_MARK(port, mark) \
+   port->marks[(port->marks_first + port->marks_num) % MAX_MARKS_NUM] = *mark; \
+   port->marks_num++;
+
+void mmalomx_mark_process_incoming(MMALOMX_COMPONENT_T *component,
+   MMALOMX_PORT_T *port, OMX_BUFFERHEADERTYPE *omx_buffer)
+{
+   /* Tag buffers with OMX marks */
+   if (!omx_buffer->hMarkTargetComponent && port->marks_num > 0 &&
+       port->direction == OMX_DirInput)
+   {
+      OMX_MARKTYPE *mark;
+      MMALOMX_GET_MARK(port, mark);
+      omx_buffer->hMarkTargetComponent = mark->hMarkTargetComponent;
+      omx_buffer->pMarkData = mark->pMarkData;
+
+      mmalomx_callback_event_handler(component, OMX_EventCmdComplete,
+         OMX_CommandMarkBuffer, port->index, NULL);
+   }
+   /* We do not support buffer marks properly other than for conformance testing.
+    * For input ports, we just move the mark over to the output port. */
+   if (port->direction == OMX_DirInput && omx_buffer->hMarkTargetComponent)
+   {
+      OMX_MARKTYPE mark = {omx_buffer->hMarkTargetComponent, omx_buffer->pMarkData};
+      unsigned int i;
+      for (i = 0; i < component->ports_num; i++)
+      {
+         if (component->ports[i].direction != OMX_DirOutput ||
+             component->ports[i].marks_num >= MAX_MARKS_NUM)
+            continue;
+
+         MMALOMX_PUT_MARK((&component->ports[i]), (&mark));
+      }
+   }
+}
+
+void mmalomx_mark_process_outgoing(MMALOMX_COMPONENT_T *component,
+   MMALOMX_PORT_T *port, OMX_BUFFERHEADERTYPE *omx_buffer)
+{
+   /* Tag buffers with OMX marks */
+   if (port->direction == OMX_DirOutput &&
+       !omx_buffer->hMarkTargetComponent && port->marks_num)
+   {
+         OMX_MARKTYPE *mark;
+         MMALOMX_GET_MARK(port, mark);
+         omx_buffer->hMarkTargetComponent = mark->hMarkTargetComponent;
+         omx_buffer->pMarkData = mark->pMarkData;
+   }
+   /* Check if we need to trigger a Mark event */
+   if (omx_buffer->hMarkTargetComponent &&
+       omx_buffer->hMarkTargetComponent == (OMX_HANDLETYPE)&component->omx)
+   {
+      mmalomx_callback_event_handler(component, OMX_EventMark, 0, 0, omx_buffer->pMarkData);
+      omx_buffer->hMarkTargetComponent = NULL;
+      omx_buffer->pMarkData = NULL;
+   }
+}
diff --git a/interface/mmal/openmaxil/mmalomx_marks.h b/interface/mmal/openmaxil/mmalomx_marks.h
new file mode 100755 (executable)
index 0000000..f543396
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file
+ * OpenMAX IL adaptation layer for MMAL - Marking related functions
+ */
+
+void mmalomx_mark_process_incoming(MMALOMX_COMPONENT_T *component,
+   MMALOMX_PORT_T *port, OMX_BUFFERHEADERTYPE *omx_buffer);
+void mmalomx_mark_process_outgoing(MMALOMX_COMPONENT_T *component,
+   MMALOMX_PORT_T *port, OMX_BUFFERHEADERTYPE *omx_buffer);
+
diff --git a/interface/mmal/openmaxil/mmalomx_parameters.c b/interface/mmal/openmaxil/mmalomx_parameters.c
new file mode 100755 (executable)
index 0000000..c4f97d4
--- /dev/null
@@ -0,0 +1,578 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/vmcs_host/khronos/IL/OMX_Broadcom.h"
+#include "mmalomx.h"
+#include "mmalomx_parameters.h"
+#include "mmalomx_util_params.h"
+#include "mmalomx_roles.h"
+#include "mmalomx_registry.h"
+#include "mmalomx_logging.h"
+#include <util/mmal_util.h>
+#include <util/mmal_util_params.h>
+#include <util/mmal_util_rational.h>
+
+#define PARAM_GET_PORT(port, component, index) \
+   if (index >= component->ports_num) return OMX_ErrorBadPortIndex; \
+   port = &component->ports[index]
+
+#define MMALOMX_PARAM_GENERIC_MAX    256
+
+/** A structure capable of holding any OMX parameter that contains a port */
+typedef struct MMALOMX_PARAM_OMX_GENERIC_T
+{
+   MMALOMX_PARAM_OMX_HEADER_T header;
+   uint8_t data[MMALOMX_PARAM_GENERIC_MAX];
+} MMALOMX_PARAM_OMX_GENERIC_T;
+
+/** A structure capable of holding any OMX parameter that doesn't contain a port */
+typedef struct MMALOMX_PARAM_OMX_GENERIC_PORTLESS_T
+{
+   MMALOMX_PARAM_OMX_HEADER_PORTLESS_T hdr;
+   uint8_t data[MMALOMX_PARAM_GENERIC_MAX];
+} MMALOMX_PARAM_OMX_GENERIC_PORTLESS_T;
+
+/** A structure capable of holding any MMAL parameter */
+typedef struct MMALOMX_PARAM_MMAL_GENERIC_T
+{
+   MMAL_PARAMETER_HEADER_T header;
+   uint8_t data[MMALOMX_PARAM_GENERIC_MAX];
+} MMALOMX_PARAM_MMAL_GENERIC_T;
+
+static OMX_ERRORTYPE mmalomx_parameter_set_xlat(MMALOMX_COMPONENT_T *component,
+   OMX_INDEXTYPE nParamIndex, OMX_PTR pParam)
+{
+   const MMALOMX_PARAM_TRANSLATION_T *xlat = mmalomx_find_parameter_from_omx_id(nParamIndex);
+   MMALOMX_PARAM_OMX_HEADER_T *omx_header = (MMALOMX_PARAM_OMX_HEADER_T *)pParam;
+   MMALOMX_PARAM_MMAL_GENERIC_T mmal_generic;
+   MMAL_PARAMETER_HEADER_T *mmal_header = &mmal_generic.header;
+   MMAL_PORT_T *mmal_port = component->mmal->control;
+   MMAL_STATUS_T status;
+
+   if (!xlat)
+   {
+      LOG_DEBUG("no translation for omx id 0x%08x", nParamIndex);
+      return OMX_ErrorNotImplemented;
+   }
+
+   if (!xlat->portless)
+   {
+      if (omx_header->nSize < sizeof(*omx_header))
+         return OMX_ErrorBadParameter;
+      if (omx_header->nPortIndex >= component->ports_num)
+         return OMX_ErrorBadPortIndex;
+      mmal_port = component->ports[omx_header->nPortIndex].mmal;
+   }
+
+   if (omx_header->nSize < xlat->omx_size)
+      return OMX_ErrorBadParameter;
+
+   /* Handle the direct case first */
+   if (xlat->type == MMALOMX_PARAM_TRANSLATION_TYPE_DIRECT)
+   {
+      mmal_header = (MMAL_PARAMETER_HEADER_T *)(((uint8_t *)pParam) + (xlat->portless ? 0 : 4));
+      mmal_generic.header = *mmal_header;
+      mmal_header->size = omx_header->nSize - (xlat->portless ? 0 : 4);
+      mmal_header->id = xlat->mmal_id;
+      status = mmal_port_parameter_set(mmal_port, mmal_header);
+      *mmal_header = mmal_generic.header;
+      return mmalil_error_to_omx(status);
+   }
+
+   if (!xlat->fn.generic && !xlat->fn.simple)
+   {
+      // FIXME
+      return OMX_ErrorNotImplemented;
+   }
+
+   // FIXME: check size of mmal_generic is sufficient
+   if (sizeof(mmal_generic) < xlat->mmal_size)
+      return OMX_ErrorBadParameter;
+
+   mmal_header->size = xlat->mmal_size;
+   mmal_header->id = xlat->mmal_id;
+   if (xlat->fn.generic)
+      status = xlat->fn.generic(MMALOMX_PARAM_MAPPING_TO_MMAL, xlat, mmal_header, pParam, mmal_port);
+   else
+      status = xlat->fn.simple(MMALOMX_PARAM_MAPPING_TO_MMAL, mmal_header, pParam);
+   if (status != MMAL_SUCCESS)
+      goto error;
+
+   status = mmal_port_parameter_set(mmal_port, mmal_header);
+
+ error:
+   return mmalil_error_to_omx(status);
+}
+
+static OMX_ERRORTYPE mmalomx_parameter_get_xlat(MMALOMX_COMPONENT_T *component,
+   OMX_INDEXTYPE nParamIndex, OMX_PTR pParam)
+{
+   const MMALOMX_PARAM_TRANSLATION_T *xlat = mmalomx_find_parameter_from_omx_id(nParamIndex);
+   MMALOMX_PARAM_OMX_HEADER_T *omx_header = (MMALOMX_PARAM_OMX_HEADER_T *)pParam;
+   MMALOMX_PARAM_MMAL_GENERIC_T mmal_generic;
+   MMAL_PARAMETER_HEADER_T *mmal_header = &mmal_generic.header;
+   MMAL_PORT_T *mmal_port = component->mmal->control;
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+
+   if (!xlat)
+      return OMX_ErrorNotImplemented;
+
+   if (!xlat->portless)
+   {
+      if (omx_header->nSize < sizeof(*omx_header))
+         return OMX_ErrorBadParameter;
+      if (omx_header->nPortIndex >= component->ports_num)
+         return OMX_ErrorBadPortIndex;
+      mmal_port = component->ports[omx_header->nPortIndex].mmal;
+   }
+
+   if (omx_header->nSize < xlat->omx_size)
+      return OMX_ErrorBadParameter;
+
+   /* Handle the direct case first */
+   if (xlat->type == MMALOMX_PARAM_TRANSLATION_TYPE_DIRECT)
+   {
+      OMX_U32 size;
+      mmal_header = (MMAL_PARAMETER_HEADER_T *)(((uint8_t *)pParam) + (xlat->portless ? 0 : 4));
+      mmal_generic.header = *mmal_header;
+      mmal_header->size = omx_header->nSize - (xlat->portless ? 0 : 4);
+      mmal_header->id = xlat->mmal_id;
+      status = mmal_port_parameter_get(mmal_port, mmal_header);
+      *mmal_header = mmal_generic.header;
+      size = mmal_header->size + (xlat->portless ? 0 : 4);
+      omx_header->nSize = size;
+      return mmalil_error_to_omx(status);
+   }
+
+   if (xlat->fn.custom)
+   {
+      return mmalil_error_to_omx(xlat->fn.custom(MMALOMX_PARAM_MAPPING_TO_OMX, xlat, mmal_header,
+         pParam, mmal_port));
+   }
+
+   if (xlat->fn.list)
+   {
+      OMX_U32 index, elements;
+      mmal_header = mmal_port_parameter_alloc_get(mmal_port, xlat->mmal_id,
+         10*xlat->mmal_size, &status);
+      if (!mmal_header)
+         return OMX_ErrorInsufficientResources;
+
+      /* Check we're not requesting too much */
+      index = *(OMX_U32 *)(((uint8_t *)pParam) + xlat->xlat_enum_num);
+      elements = (mmal_header->size - sizeof(MMAL_PARAMETER_HEADER_T)) /
+         (xlat->mmal_size - sizeof(MMAL_PARAMETER_HEADER_T));
+      if (index >= elements)
+      {
+         vcos_free(mmal_header);
+         return OMX_ErrorNoMore;
+      }
+      status = xlat->fn.list(MMALOMX_PARAM_MAPPING_TO_OMX, xlat, index, mmal_header, pParam, mmal_port);
+      vcos_free(mmal_header);
+      return mmalil_error_to_omx(status);
+   }
+
+   if (!xlat->fn.generic && !xlat->fn.simple)
+   {
+      // FIXME
+      return OMX_ErrorNotImplemented;
+   }
+
+   // FIXME: check size of mmal_generic is sufficient
+   if (sizeof(mmal_generic) < xlat->mmal_size)
+      return OMX_ErrorBadParameter;
+
+   mmal_header->size = xlat->mmal_size;
+   mmal_header->id = xlat->mmal_id;
+
+   if (xlat->double_translation)
+   {
+      if (xlat->fn.generic)
+         status = xlat->fn.generic(MMALOMX_PARAM_MAPPING_TO_MMAL, xlat, mmal_header, pParam, mmal_port);
+      else
+         status = xlat->fn.simple(MMALOMX_PARAM_MAPPING_TO_MMAL, mmal_header, pParam);
+   }
+   if (status != MMAL_SUCCESS)
+      goto error;
+
+   status = mmal_port_parameter_get(mmal_port, mmal_header);
+   if (status != MMAL_SUCCESS)
+      goto error;
+
+   if (xlat->fn.generic)
+      status = xlat->fn.generic(MMALOMX_PARAM_MAPPING_TO_OMX, xlat, mmal_header, pParam, mmal_port);
+   else
+      status = xlat->fn.simple(MMALOMX_PARAM_MAPPING_TO_OMX, mmal_header, pParam);
+
+ error:
+   return mmalil_error_to_omx(status);
+}
+
+OMX_ERRORTYPE mmalomx_parameter_extension_index_get(OMX_STRING cParameterName,
+   OMX_INDEXTYPE *pIndex)
+{
+   const MMALOMX_PARAM_TRANSLATION_T *xlat;
+   MMAL_BOOL_T config = MMAL_FALSE;
+   unsigned int i = 0;
+
+   /* Check we're dealing with our extensions */
+   if (!vcos_strncasecmp(cParameterName, MMALOMX_COMPONENT_PREFIX, sizeof(MMALOMX_COMPONENT_PREFIX)-1))
+      return OMX_ErrorNotImplemented;
+   cParameterName += sizeof(MMALOMX_COMPONENT_PREFIX)-1;
+
+   /* Check if we're dealing with a config or param */
+   if (!vcos_strncasecmp(cParameterName, "index.config.", sizeof("index.config.")-1))
+      config = MMAL_TRUE;
+   if (!config && vcos_strncasecmp(cParameterName, "index.param.", sizeof("index.param.")-1))
+      return OMX_ErrorNotImplemented;
+   if (config)
+      cParameterName += sizeof("index.config.")-1;
+   else
+      cParameterName += sizeof("index.param.")-1;
+
+   /* Loop through all the */
+   while ((xlat = mmalomx_find_parameter_enum(i++)) != NULL)
+   {
+      const char *name = xlat->omx_name;
+
+      /* We only report vendor extensions */
+      if (xlat->omx_id < OMX_IndexVendorStartUnused)
+         continue;
+
+      /* Strip out the standard prefix */
+      if (config)
+      {
+         if (!strncmp(name, "OMX_IndexConfigBrcm", sizeof("OMX_IndexConfigBrcm")-1))
+            name += sizeof("OMX_IndexConfigBrcm")-1;
+         else if (!strncmp(name, "OMX_IndexConfig", sizeof("OMX_IndexConfig")-1))
+            name += sizeof("OMX_IndexConfig")-1;
+         else continue;
+      }
+      else
+      {
+         if (!strncmp(name, "OMX_IndexParamBrcm", sizeof("OMX_IndexParamBrcm")-1))
+            name += sizeof("OMX_IndexParamBrcm")-1;
+         else if (!strncmp(name, "OMX_IndexParam", sizeof("OMX_IndexParam")-1))
+            name += sizeof("OMX_IndexParam")-1;
+         else continue;
+      }
+
+      /* Compare the last part of the name */
+      if (!vcos_strcasecmp(name, cParameterName))
+      {
+         *pIndex = xlat->omx_id;
+         return OMX_ErrorNone;
+      }
+   }
+
+   return OMX_ErrorNotImplemented;
+}
+
+/*****************************************************************************/
+static OMX_ERRORTYPE mmalomx_get_video_param(MMALOMX_PORT_T *port,
+   uint32_t *profile, uint32_t *level, uint32_t *intraperiod)
+{
+   MMAL_PARAMETER_VIDEO_PROFILE_T mmal_param = {{MMAL_PARAMETER_PROFILE, sizeof(mmal_param)},
+      {{(MMAL_VIDEO_PROFILE_T)0, (MMAL_VIDEO_LEVEL_T)0}}};
+
+   *profile = *level = *intraperiod = 0;
+
+   mmal_port_parameter_get_uint32(port->mmal, MMAL_PARAMETER_INTRAPERIOD, intraperiod);
+
+   if (mmal_port_parameter_get(port->mmal, &mmal_param.hdr) == MMAL_SUCCESS)
+   {
+      *profile = mmalil_video_profile_to_omx(mmal_param.profile[0].profile);
+      *level = mmalil_video_level_to_omx(mmal_param.profile[0].level);
+   }
+
+   return OMX_ErrorNone;
+}
+
+/*****************************************************************************/
+OMX_ERRORTYPE mmalomx_parameter_get(MMALOMX_COMPONENT_T *component,
+   OMX_INDEXTYPE nParamIndex, OMX_PTR pParam)
+{
+   MMALOMX_PORT_T *port = NULL;
+
+   switch(nParamIndex)
+   {
+   /* All OMX_IndexParamVideo parameters are only partially implemented
+    * and we try and use sensible hard-coded values for the rest. */
+   case OMX_IndexParamVideoAvc:
+      {
+         OMX_VIDEO_PARAM_AVCTYPE *param = (OMX_VIDEO_PARAM_AVCTYPE *)pParam;
+         uint32_t profile, level, intraperiod;
+         PARAM_GET_PORT(port, component, param->nPortIndex);
+         if (param->nSize < sizeof(*param))
+            return OMX_ErrorBadParameter;
+         memset(&param->nSliceHeaderSpacing, 0,
+            param->nSize - offsetof(OMX_VIDEO_PARAM_AVCTYPE, nSliceHeaderSpacing));
+
+         mmalomx_get_video_param(port, &profile, &level, &intraperiod);
+         param->eProfile = (OMX_VIDEO_AVCPROFILETYPE)profile;
+         param->eLevel = (OMX_VIDEO_AVCLEVELTYPE)level;
+         param->nPFrames = intraperiod - 1;
+         param->bUseHadamard = OMX_TRUE;
+         param->nRefFrames = 1;
+         param->nAllowedPictureTypes = OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
+         param->bFrameMBsOnly = OMX_TRUE;
+         if (param->eProfile != OMX_VIDEO_AVCProfileBaseline)
+            param->bEntropyCodingCABAC = OMX_TRUE;
+         param->eLoopFilterMode = OMX_VIDEO_AVCLoopFilterEnable;
+      }
+      return OMX_ErrorNone;
+   case OMX_IndexParamVideoMpeg4:
+      {
+         OMX_VIDEO_PARAM_MPEG4TYPE *param = (OMX_VIDEO_PARAM_MPEG4TYPE *)pParam;
+         uint32_t profile, level, intraperiod;
+         PARAM_GET_PORT(port, component, param->nPortIndex);
+         if (param->nSize < sizeof(*param))
+            return OMX_ErrorBadParameter;
+         memset(&param->nSliceHeaderSpacing, 0,
+            param->nSize - offsetof(OMX_VIDEO_PARAM_MPEG4TYPE, nSliceHeaderSpacing));
+
+         mmalomx_get_video_param(port, &profile, &level, &intraperiod);
+         param->eProfile = (OMX_VIDEO_MPEG4PROFILETYPE)profile;
+         param->eLevel = (OMX_VIDEO_MPEG4LEVELTYPE)level;
+         param->nPFrames = intraperiod - 1;
+         param->bACPred = OMX_TRUE;
+         param->nAllowedPictureTypes = OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
+      }
+      return OMX_ErrorNone;
+   case OMX_IndexParamVideoH263:
+      {
+         OMX_VIDEO_PARAM_H263TYPE *param = (OMX_VIDEO_PARAM_H263TYPE *)pParam;
+         uint32_t profile, level, intraperiod;
+         PARAM_GET_PORT(port, component, param->nPortIndex);
+         if (param->nSize < sizeof(*param))
+            return OMX_ErrorBadParameter;
+         memset(&param->nPFrames, 0,
+            param->nSize - offsetof(OMX_VIDEO_PARAM_H263TYPE, nPFrames));
+
+         mmalomx_get_video_param(port, &profile, &level, &intraperiod);
+         param->eProfile = (OMX_VIDEO_H263PROFILETYPE)profile;
+         param->eLevel = (OMX_VIDEO_H263LEVELTYPE)level;
+         param->nPFrames = intraperiod - 1;
+         param->nAllowedPictureTypes = OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP;
+      }
+      return OMX_ErrorNone;
+   case OMX_IndexParamVideoMpeg2:
+   case OMX_IndexParamVideoWmv:
+   case OMX_IndexParamVideoRv:
+      {
+         OMX_FORMAT_PARAM_TYPE *param = (OMX_FORMAT_PARAM_TYPE *)pParam;
+         PARAM_GET_PORT(port, component, param->common.nPortIndex);
+         OMX_U32 offset = offsetof(OMX_PARAM_U32TYPE, nU32);
+         if (param->common.nSize > sizeof(port->format_param) ||
+             param->common.nSize < offset)
+            return OMX_ErrorBadParameter;
+         memcpy(&param->common.nU32, &port->format_param.common.nU32,
+                param->common.nSize - offset);
+         return OMX_ErrorNone;
+      }
+   case OMX_IndexParamAudioPcm:
+   case OMX_IndexParamAudioAac:
+   case OMX_IndexParamAudioMp3:
+   case OMX_IndexParamAudioDdp:
+      {
+         OMX_FORMAT_PARAM_TYPE *param = (OMX_FORMAT_PARAM_TYPE *)pParam;
+         PARAM_GET_PORT(port, component, param->common.nPortIndex);
+         OMX_U32 offset = offsetof(OMX_PARAM_U32TYPE, nU32);
+         if (param->common.nSize > sizeof(port->format_param) ||
+             param->common.nSize < offset)
+            return OMX_ErrorBadParameter;
+         memcpy(&param->common.nU32, &port->format_param.common.nU32,
+                param->common.nSize - offset);
+         mmalil_format_to_omx_audio_param(param, NULL, port->mmal->format);
+         return OMX_ErrorNone;
+      }
+   case OMX_IndexParamBrcmPixelAspectRatio:
+      {
+         OMX_CONFIG_POINTTYPE *param = (OMX_CONFIG_POINTTYPE *)pParam;
+         PARAM_GET_PORT(port, component, param->nPortIndex);
+         param->nX = port->mmal->format->es->video.par.num;
+         param->nY = port->mmal->format->es->video.par.den;
+         return OMX_ErrorNone;
+      }
+   case OMX_IndexParamColorSpace:
+      {
+         OMX_PARAM_COLORSPACETYPE *param = (OMX_PARAM_COLORSPACETYPE *)pParam;
+         PARAM_GET_PORT(port, component, param->nPortIndex);
+         param->eColorSpace = mmalil_color_space_to_omx(port->mmal->format->es->video.color_space);
+         return OMX_ErrorNone;
+      }
+   case OMX_IndexConfigCommonOutputCrop:
+      {
+         OMX_CONFIG_RECTTYPE *param = (OMX_CONFIG_RECTTYPE *)pParam;
+         PARAM_GET_PORT(port, component, param->nPortIndex);
+         param->nLeft = port->mmal->format->es->video.crop.x;
+         param->nTop = port->mmal->format->es->video.crop.y;
+         param->nWidth = port->mmal->format->es->video.width;
+         if (port->mmal->format->es->video.crop.width)
+            param->nWidth = port->mmal->format->es->video.crop.width;
+         param->nHeight = port->mmal->format->es->video.height;
+         if (port->mmal->format->es->video.crop.height)
+            param->nHeight = port->mmal->format->es->video.crop.height;
+         return OMX_ErrorNone;
+      }
+   case OMX_IndexConfigCommonScale:
+      {
+         OMX_CONFIG_SCALEFACTORTYPE *param = (OMX_CONFIG_SCALEFACTORTYPE *)pParam;
+         PARAM_GET_PORT(port, component, param->nPortIndex);
+         param->xWidth = param->xHeight = 1<<16;
+         if (port->mmal->format->es->video.par.num &&
+             port->mmal->format->es->video.par.den)
+            param->xWidth = mmal_rational_to_fixed_16_16(port->mmal->format->es->video.par);
+         return OMX_ErrorNone;
+      }
+   default:
+      return mmalomx_parameter_get_xlat(component, nParamIndex, pParam);
+   }
+
+   return OMX_ErrorNotImplemented;
+}
+
+/*****************************************************************************/
+static OMX_ERRORTYPE mmalomx_set_video_param(MMALOMX_PORT_T *port,
+   uint32_t profile, uint32_t level, uint32_t intraperiod)
+{
+   MMAL_PARAMETER_VIDEO_PROFILE_T mmal_param = {{MMAL_PARAMETER_PROFILE, sizeof(mmal_param)},
+      {{(MMAL_VIDEO_PROFILE_T)0, (MMAL_VIDEO_LEVEL_T)0}}};
+   OMX_VIDEO_CODINGTYPE coding =
+      mmalil_encoding_to_omx_video_coding(port->mmal->format->encoding);
+
+   if (mmal_port_parameter_set_uint32(port->mmal, MMAL_PARAMETER_INTRAPERIOD,
+          intraperiod) != MMAL_SUCCESS)
+      return OMX_ErrorBadParameter;
+
+   mmal_param.profile[0].profile = (MMAL_VIDEO_PROFILE_T)
+      mmalil_omx_video_profile_to_mmal(profile, coding);
+   mmal_param.profile[0].level = (MMAL_VIDEO_LEVEL_T)
+      mmalil_omx_video_level_to_mmal(level, coding);
+   if (mmal_port_parameter_set(port->mmal, &mmal_param.hdr) != MMAL_SUCCESS)
+      return OMX_ErrorBadParameter;
+
+   return OMX_ErrorNone;
+}
+
+/*****************************************************************************/
+OMX_ERRORTYPE mmalomx_parameter_set(MMALOMX_COMPONENT_T *component,
+   OMX_INDEXTYPE nParamIndex, OMX_PTR pParam)
+{
+   MMALOMX_PORT_T *port = NULL;
+
+   switch(nParamIndex)
+   {
+   /* All OMX_IndexParamVideo parameters are only partially implemented */
+   case OMX_IndexParamVideoAvc:
+      {
+         OMX_VIDEO_PARAM_AVCTYPE *param = (OMX_VIDEO_PARAM_AVCTYPE *)pParam;
+         PARAM_GET_PORT(port, component, param->nPortIndex);
+         if (param->nSize < sizeof(*param))
+            return OMX_ErrorBadParameter;
+         return mmalomx_set_video_param(port, param->eProfile, param->eLevel,
+            param->nPFrames + 1);
+      }
+   case OMX_IndexParamVideoMpeg4:
+      {
+         OMX_VIDEO_PARAM_MPEG4TYPE *param = (OMX_VIDEO_PARAM_MPEG4TYPE *)pParam;
+         PARAM_GET_PORT(port, component, param->nPortIndex);
+         if (param->nSize < sizeof(*param))
+            return OMX_ErrorBadParameter;
+         return mmalomx_set_video_param(port, param->eProfile, param->eLevel,
+            param->nPFrames + 1);
+      }
+   case OMX_IndexParamVideoH263:
+      {
+         OMX_VIDEO_PARAM_H263TYPE *param = (OMX_VIDEO_PARAM_H263TYPE *)pParam;
+         PARAM_GET_PORT(port, component, param->nPortIndex);
+         if (param->nSize < sizeof(*param))
+            return OMX_ErrorBadParameter;
+         return mmalomx_set_video_param(port, param->eProfile, param->eLevel,
+            param->nPFrames + 1);
+      }
+   case OMX_IndexParamVideoMpeg2:
+   case OMX_IndexParamVideoWmv:
+   case OMX_IndexParamVideoRv:
+      {
+         OMX_FORMAT_PARAM_TYPE *param = (OMX_FORMAT_PARAM_TYPE *)pParam;
+         OMX_U32 offset = offsetof(OMX_PARAM_U32TYPE, nU32);
+         PARAM_GET_PORT(port, component, param->common.nPortIndex);
+         if (param->common.nSize > sizeof(port->format_param) ||
+             param->common.nSize < offset)
+            return OMX_ErrorBadParameter;
+         memcpy(&port->format_param.common.nU32, &param->common.nU32,
+                param->common.nSize - offset);
+         return OMX_ErrorNone;
+      }
+   case OMX_IndexParamAudioPcm:
+   case OMX_IndexParamAudioAac:
+   case OMX_IndexParamAudioMp3:
+   case OMX_IndexParamAudioDdp:
+      {
+         OMX_FORMAT_PARAM_TYPE *param = (OMX_FORMAT_PARAM_TYPE *)pParam;
+         OMX_U32 offset = offsetof(OMX_PARAM_U32TYPE, nU32);
+         PARAM_GET_PORT(port, component, param->common.nPortIndex);
+         if (param->common.nSize > sizeof(port->format_param) ||
+             param->common.nSize < offset)
+            return OMX_ErrorBadParameter;
+         memcpy(&port->format_param.common.nU32, &param->common.nU32,
+                param->common.nSize - offset);
+         mmalil_omx_audio_param_to_format(port->mmal->format,
+            mmalil_omx_audio_param_index_to_coding(nParamIndex), param);
+         mmal_port_format_commit(port->mmal);
+         return OMX_ErrorNone;
+      }
+   case OMX_IndexParamBrcmPixelAspectRatio:
+      {
+         OMX_CONFIG_POINTTYPE *param = (OMX_CONFIG_POINTTYPE *)pParam;
+         PARAM_GET_PORT(port, component, param->nPortIndex);
+         port->mmal->format->es->video.par.num = param->nX;
+         port->mmal->format->es->video.par.den = param->nY;
+         mmal_rational_simplify(&port->mmal->format->es->video.par);
+         return mmalil_error_to_omx(mmal_port_format_commit(port->mmal));
+      }
+   case OMX_IndexParamColorSpace:
+      {
+         OMX_PARAM_COLORSPACETYPE *param = (OMX_PARAM_COLORSPACETYPE *)pParam;
+         PARAM_GET_PORT(port, component, param->nPortIndex);
+         port->mmal->format->es->video.color_space = mmalil_omx_color_space_to_mmal(param->eColorSpace);
+         return mmalil_error_to_omx(mmal_port_format_commit(port->mmal));
+      }
+   case OMX_IndexParamBrcmVideoCroppingDisable:
+      {
+         OMX_CONFIG_PORTBOOLEANTYPE *param = (OMX_CONFIG_PORTBOOLEANTYPE *)pParam;
+         PARAM_GET_PORT(port, component, param->nPortIndex);
+         port->no_cropping = param->bEnabled;
+         return OMX_ErrorNone;
+      }
+   default:
+      return mmalomx_parameter_set_xlat(component, nParamIndex, pParam);
+   }
+
+   return OMX_ErrorNotImplemented;
+}
diff --git a/interface/mmal/openmaxil/mmalomx_parameters.h b/interface/mmal/openmaxil/mmalomx_parameters.h
new file mode 100755 (executable)
index 0000000..5c58c86
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file
+ * OpenMAX IL adaptation layer for MMAL - Parameters related functions
+ */
+
+OMX_ERRORTYPE mmalomx_parameter_get(MMALOMX_COMPONENT_T *component,
+   OMX_INDEXTYPE nParamIndex, OMX_PTR pParam);
+OMX_ERRORTYPE mmalomx_parameter_set(MMALOMX_COMPONENT_T *component,
+   OMX_INDEXTYPE nParamIndex, OMX_PTR pParam);
+OMX_ERRORTYPE mmalomx_parameter_extension_index_get(OMX_STRING cParameterName,
+   OMX_INDEXTYPE *pIndex);
diff --git a/interface/mmal/openmaxil/mmalomx_registry.c b/interface/mmal/openmaxil/mmalomx_registry.c
new file mode 100755 (executable)
index 0000000..059ed6b
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmalomx.h"
+#include "mmalomx_roles.h"
+#include "mmalomx_registry.h"
+#include "mmalomx_logging.h"
+#include <util/mmal_default_components.h>
+
+#ifndef ENABLE_MMALOMX_AUDIO_HW_DECODER
+# define ENABLE_MMALOMX_AUDIO_HW_DECODER 0
+#endif
+#ifndef ENABLE_MMALOMX_AUDIO_SPDIF
+# define ENABLE_MMALOMX_AUDIO_SPDIF 1
+#endif
+
+static const struct {
+   const char *omx;
+   const char *omx_prefix;
+   const char *mmal;
+   MMALOMX_ROLE_T roles[MMALOMX_ROLE_MAX];
+} mmalomx_components[] =
+{
+   {"video.hw.decoder", 0, MMAL_COMPONENT_DEFAULT_VIDEO_DECODER,
+      {MMALOMX_ROLE_VIDEO_DECODER_H263, MMALOMX_ROLE_VIDEO_DECODER_MPEG2,
+       MMALOMX_ROLE_VIDEO_DECODER_MPEG4, MMALOMX_ROLE_VIDEO_DECODER_AVC,
+       MMALOMX_ROLE_VIDEO_DECODER_WMV, MMALOMX_ROLE_VIDEO_DECODER_VPX,
+       MMALOMX_ROLE_UNDEFINED}},
+   {"video.hw.decoder.secure", 0, "drm_alloc.video_decode",
+      {MMALOMX_ROLE_VIDEO_DECODER_H263, MMALOMX_ROLE_VIDEO_DECODER_MPEG2,
+       MMALOMX_ROLE_VIDEO_DECODER_MPEG4, MMALOMX_ROLE_VIDEO_DECODER_AVC,
+       MMALOMX_ROLE_VIDEO_DECODER_WMV, MMALOMX_ROLE_VIDEO_DECODER_VPX,
+       MMALOMX_ROLE_UNDEFINED}},
+   {"video.hw.decoder.divx_drm", 0, "aggregator.pipeline:divx_drm:vc.video_decode",
+      {MMALOMX_ROLE_VIDEO_DECODER_MPEG4, MMALOMX_ROLE_UNDEFINED}},
+   {"video.vpx.decoder", 0, "libvpx",
+      {MMALOMX_ROLE_VIDEO_DECODER_VPX, MMALOMX_ROLE_UNDEFINED}},
+
+   {"video.hw.encoder", 0, MMAL_COMPONENT_DEFAULT_VIDEO_ENCODER,
+      {MMALOMX_ROLE_VIDEO_ENCODER_H263, MMALOMX_ROLE_VIDEO_ENCODER_MPEG4,
+       MMALOMX_ROLE_VIDEO_ENCODER_AVC, MMALOMX_ROLE_UNDEFINED}},
+
+   {"AIV.play", "", "aivplay",
+      {MMALOMX_ROLE_AIV_PLAY_101, MMALOMX_ROLE_AIV_PLAY_AVCDDP, MMALOMX_ROLE_UNDEFINED}},
+   {"AIV.play.avcddp", "", "aivplay.ddp",
+      {MMALOMX_ROLE_AIV_PLAY_AVCDDP, MMALOMX_ROLE_AIV_PLAY_101, MMALOMX_ROLE_UNDEFINED}},
+
+#if ENABLE_MMALOMX_AUDIO_HW_DECODER
+   {"audio.hw.decoder", 0, "vc.ril.audio_decode",
+      {MMALOMX_ROLE_AUDIO_DECODER_AAC, MMALOMX_ROLE_AUDIO_DECODER_MPGA_L1,
+       MMALOMX_ROLE_AUDIO_DECODER_MPGA_L2, MMALOMX_ROLE_AUDIO_DECODER_MPGA_L3,
+       MMALOMX_ROLE_AUDIO_DECODER_DDP, MMALOMX_ROLE_UNDEFINED}},
+#endif
+
+#if ENABLE_MMALOMX_AUDIO_SPDIF
+   {"audio.spdif", 0, "spdif",
+      {MMALOMX_ROLE_AUDIO_DECODER_DDP, MMALOMX_ROLE_UNDEFINED}},
+#endif
+
+   {0, 0, 0, {MMALOMX_ROLE_UNDEFINED}}
+};
+
+int mmalomx_registry_find_component(const char *name)
+{
+   int i, prefix_size;
+   const char *prefix;
+
+   for (i = 0; mmalomx_components[i].omx; i++)
+   {
+      /* Check the prefix first */
+      prefix = mmalomx_components[i].omx_prefix;
+      if (!prefix)
+         prefix = MMALOMX_COMPONENT_PREFIX;
+      prefix_size = strlen(prefix);
+      if (strncmp(name, prefix, prefix_size))
+         continue;
+
+      /* Check the rest of the name */
+      if (!strcmp(name + prefix_size, mmalomx_components[i].omx))
+         break;
+   }
+
+   return mmalomx_components[i].mmal ? i : -1;
+}
+
+const char *mmalomx_registry_component_mmal(int id)
+{
+   if (id >= (int)MMAL_COUNTOF(mmalomx_components) || id < 0)
+      id = MMAL_COUNTOF(mmalomx_components) - 1;
+
+   return mmalomx_components[id].mmal;
+}
+
+MMALOMX_ROLE_T mmalomx_registry_component_roles(int id, unsigned int index)
+{
+   unsigned int i;
+
+   if (id >= (int)MMAL_COUNTOF(mmalomx_components) || id < 0)
+      id = MMAL_COUNTOF(mmalomx_components) - 1;
+
+   for (i = 0; i < index; i++)
+      if (mmalomx_components[id].roles[i] == MMALOMX_ROLE_UNDEFINED)
+         break;
+
+   return mmalomx_components[id].roles[i];
+}
+
+MMAL_BOOL_T mmalomx_registry_component_supports_role(int id, MMALOMX_ROLE_T role)
+{
+   unsigned int i;
+
+   if (id >= (int)MMAL_COUNTOF(mmalomx_components) || id < 0)
+      id = MMAL_COUNTOF(mmalomx_components) - 1;
+
+   for (i = 0; mmalomx_components[id].roles[i] != MMALOMX_ROLE_UNDEFINED; i++)
+      if (mmalomx_components[id].roles[i] == role)
+         return MMAL_TRUE;
+
+   return MMAL_FALSE;
+}
+
+const char *mmalomx_registry_component_name(int id, const char **prefix)
+{
+   if (id >= (int)MMAL_COUNTOF(mmalomx_components) || id < 0)
+      id = MMAL_COUNTOF(mmalomx_components) - 1;
+
+   if (prefix)
+   {
+      *prefix = mmalomx_components[id].omx_prefix;
+      if (!*prefix)
+         *prefix = MMALOMX_COMPONENT_PREFIX;
+   }
+
+   return mmalomx_components[id].omx;
+}
diff --git a/interface/mmal/openmaxil/mmalomx_registry.h b/interface/mmal/openmaxil/mmalomx_registry.h
new file mode 100755 (executable)
index 0000000..3a7c7f5
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file
+ * OpenMAX IL adaptation layer for MMAL - Registry of components
+ */
+
+#define MMALOMX_COMPONENT_PREFIX "OMX.brcm."
+
+int mmalomx_registry_find_component(const char *name);
+
+const char *mmalomx_registry_component_mmal(int id);
+
+MMALOMX_ROLE_T mmalomx_registry_component_roles(int id, unsigned int index);
+MMAL_BOOL_T mmalomx_registry_component_supports_role(int id, MMALOMX_ROLE_T role);
+
+const char *mmalomx_registry_component_name(int index, const char **prefix);
diff --git a/interface/mmal/openmaxil/mmalomx_roles.c b/interface/mmal/openmaxil/mmalomx_roles.c
new file mode 100755 (executable)
index 0000000..17de66f
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmalomx.h"
+#include "mmalomx_roles.h"
+#include "mmalomx_registry.h"
+#include "mmalomx_logging.h"
+
+static const struct {
+   const char *name;
+   MMALOMX_ROLE_T role;
+} mmalomx_roles[] =
+{
+   {"video_decoder.h263",     MMALOMX_ROLE_VIDEO_DECODER_H263},
+   {"video_decoder.mpeg4",    MMALOMX_ROLE_VIDEO_DECODER_MPEG4},
+   {"video_decoder.avc",      MMALOMX_ROLE_VIDEO_DECODER_AVC},
+   {"video_decoder.mpeg2",    MMALOMX_ROLE_VIDEO_DECODER_MPEG2},
+   {"video_decoder.wmv",      MMALOMX_ROLE_VIDEO_DECODER_WMV},
+   {"video_decoder.vpx",      MMALOMX_ROLE_VIDEO_DECODER_VPX},
+
+   {"video_encoder.h263",     MMALOMX_ROLE_VIDEO_ENCODER_H263},
+   {"video_encoder.mpeg4",    MMALOMX_ROLE_VIDEO_ENCODER_MPEG4},
+   {"video_encoder.avc",      MMALOMX_ROLE_VIDEO_ENCODER_AVC},
+
+   {"audio_decoder.aac",      MMALOMX_ROLE_AUDIO_DECODER_AAC},
+   {"audio_decoder.mp1",      MMALOMX_ROLE_AUDIO_DECODER_MPGA_L1},
+   {"audio_decoder.mp2",      MMALOMX_ROLE_AUDIO_DECODER_MPGA_L2},
+   {"audio_decoder.mp3",      MMALOMX_ROLE_AUDIO_DECODER_MPGA_L3},
+   {"audio_decoder.ddp",      MMALOMX_ROLE_AUDIO_DECODER_DDP},
+
+   {"AIV.play.101",           MMALOMX_ROLE_AIV_PLAY_101},
+   {"play.avcddp",            MMALOMX_ROLE_AIV_PLAY_AVCDDP},
+
+   {0, 0}
+};
+
+const char *mmalomx_role_to_name(MMALOMX_ROLE_T role)
+{
+    unsigned int i;
+    for (i = 0; mmalomx_roles[i].name; i++)
+       if (mmalomx_roles[i].role == role)
+          break;
+    return mmalomx_roles[i].name;
+}
+
+MMALOMX_ROLE_T mmalomx_role_from_name(const char *name)
+{
+   unsigned int i;
+   for (i = 0; mmalomx_roles[i].name; i++)
+      if (!strcmp(mmalomx_roles[i].name, name))
+         break;
+   return mmalomx_roles[i].role;
+}
+
+static void mmalomx_format_encoding_from_role(MMALOMX_ROLE_T role,
+   MMAL_FOURCC_T *encoding, MMAL_ES_TYPE_T *es_type, unsigned int *port)
+{
+   switch (role)
+   {
+   case MMALOMX_ROLE_VIDEO_DECODER_MPEG4:
+   case MMALOMX_ROLE_VIDEO_ENCODER_MPEG4:
+      *encoding = MMAL_ENCODING_MP4V;
+      *es_type = MMAL_ES_TYPE_VIDEO;
+      break;
+   case MMALOMX_ROLE_VIDEO_DECODER_AVC:
+   case MMALOMX_ROLE_VIDEO_ENCODER_AVC:
+      *encoding = MMAL_ENCODING_H264;
+      *es_type = MMAL_ES_TYPE_VIDEO;
+      break;
+   case MMALOMX_ROLE_VIDEO_DECODER_MPEG2:
+      *encoding = MMAL_ENCODING_MP2V;
+      *es_type = MMAL_ES_TYPE_VIDEO;
+      break;
+   case MMALOMX_ROLE_VIDEO_DECODER_WMV:
+      *encoding = MMAL_ENCODING_WMV3;
+      *es_type = MMAL_ES_TYPE_VIDEO;
+      break;
+   case MMALOMX_ROLE_VIDEO_DECODER_VPX:
+      *encoding = MMAL_ENCODING_VP8;
+      *es_type = MMAL_ES_TYPE_VIDEO;
+      break;
+   case MMALOMX_ROLE_VIDEO_DECODER_H263:
+   case MMALOMX_ROLE_VIDEO_ENCODER_H263:
+      *encoding = MMAL_ENCODING_H263;
+      *es_type = MMAL_ES_TYPE_VIDEO;
+      break;
+   case MMALOMX_ROLE_AUDIO_DECODER_AAC:
+      *encoding = MMAL_ENCODING_MP4A;
+      *es_type = MMAL_ES_TYPE_AUDIO;
+      break;
+   case MMALOMX_ROLE_AUDIO_DECODER_MPGA_L1:
+   case MMALOMX_ROLE_AUDIO_DECODER_MPGA_L2:
+   case MMALOMX_ROLE_AUDIO_DECODER_MPGA_L3:
+      *encoding = MMAL_ENCODING_MPGA;
+      *es_type = MMAL_ES_TYPE_AUDIO;
+      break;
+
+   case MMALOMX_ROLE_AUDIO_DECODER_DDP:
+      *encoding = MMAL_ENCODING_AC3;
+      *es_type = MMAL_ES_TYPE_AUDIO;
+      break;
+
+   default:
+      *encoding = MMAL_ENCODING_UNKNOWN;
+      *es_type = MMAL_ES_TYPE_UNKNOWN;
+      break;
+   }
+
+   switch (role)
+   {
+   case MMALOMX_ROLE_VIDEO_ENCODER_H263:
+   case MMALOMX_ROLE_VIDEO_ENCODER_MPEG4:
+   case MMALOMX_ROLE_VIDEO_ENCODER_AVC:
+      *port = 1;
+      break;
+   default:
+      *port = 0;
+      break;
+   }
+}
+
+OMX_ERRORTYPE mmalomx_role_set(MMALOMX_COMPONENT_T *component, const char *name)
+{
+   const MMALOMX_ROLE_T role = mmalomx_role_from_name(name);
+   MMAL_FOURCC_T encoding = MMAL_ENCODING_UNKNOWN;
+   MMAL_ES_TYPE_T es_type = MMAL_ES_TYPE_UNKNOWN;
+   unsigned int port;
+   MMAL_ES_FORMAT_T *format;
+
+   if (!role || !mmalomx_registry_component_supports_role(component->registry_id, role))
+      return OMX_ErrorUnsupportedSetting;
+
+   component->role = role;
+
+   mmalomx_format_encoding_from_role(role, &encoding, &es_type, &port);
+   if (encoding == MMAL_ENCODING_UNKNOWN)
+      return OMX_ErrorNone;
+
+   format = component->ports[port].mmal->format;
+   format->type = es_type;
+   format->encoding = encoding;
+   format->bitrate = 64000;
+   switch (es_type)
+   {
+   case MMAL_ES_TYPE_VIDEO:
+      format->es->video.width = 176;
+      format->es->video.height = 144;
+      format->es->video.frame_rate.num = 15;
+      format->es->video.frame_rate.den = 1;
+      break;
+   default:
+      break;
+   }
+
+   switch (role)
+   {
+   case MMALOMX_ROLE_VIDEO_DECODER_H263:
+   case MMALOMX_ROLE_VIDEO_ENCODER_H263:
+      component->ports[port].format_param.h263.eProfile = OMX_VIDEO_H263ProfileBaseline;
+      component->ports[port].format_param.h263.eLevel = OMX_VIDEO_H263Level10;
+      component->ports[port].format_param.h263.bPLUSPTYPEAllowed = OMX_FALSE;
+      component->ports[port].format_param.h263.bForceRoundingTypeToZero = OMX_TRUE;
+      break;
+   case MMALOMX_ROLE_VIDEO_DECODER_MPEG4:
+   case MMALOMX_ROLE_VIDEO_ENCODER_MPEG4:
+      component->ports[port].format_param.mpeg4.eProfile = OMX_VIDEO_MPEG4ProfileSimple;
+      component->ports[port].format_param.mpeg4.eLevel = OMX_VIDEO_MPEG4Level1;
+      break;
+   case MMALOMX_ROLE_VIDEO_DECODER_AVC:
+   case MMALOMX_ROLE_VIDEO_ENCODER_AVC:
+      component->ports[port].format_param.avc.eProfile = OMX_VIDEO_AVCProfileBaseline;
+      component->ports[port].format_param.avc.eLevel = OMX_VIDEO_AVCLevel1;
+      break;
+   case MMALOMX_ROLE_VIDEO_DECODER_WMV:
+      component->ports[port].format_param.wmv.eFormat = OMX_VIDEO_WMVFormat9;
+      break;
+   default:
+      break;
+   }
+
+   if (mmal_port_format_commit(component->ports[port].mmal) != MMAL_SUCCESS)
+      LOG_ERROR("failed to commit format to %s for role %s",
+                component->ports[port].mmal->name, name);
+
+   return OMX_ErrorNone;
+}
diff --git a/interface/mmal/openmaxil/mmalomx_roles.h b/interface/mmal/openmaxil/mmalomx_roles.h
new file mode 100755 (executable)
index 0000000..cd4828d
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file
+ * OpenMAX IL adaptation layer for MMAL - Role specific functions
+ */
+
+#define MMALOMX_MAX_ROLES 16
+
+typedef enum MMALOMX_ROLE_T {
+   MMALOMX_ROLE_UNDEFINED = 0,
+   MMALOMX_ROLE_VIDEO_DECODER_H263,
+   MMALOMX_ROLE_VIDEO_DECODER_MPEG4,
+   MMALOMX_ROLE_VIDEO_DECODER_AVC,
+   MMALOMX_ROLE_VIDEO_DECODER_MPEG2,
+   MMALOMX_ROLE_VIDEO_DECODER_WMV,
+   MMALOMX_ROLE_VIDEO_DECODER_VPX,
+
+   MMALOMX_ROLE_VIDEO_ENCODER_H263,
+   MMALOMX_ROLE_VIDEO_ENCODER_MPEG4,
+   MMALOMX_ROLE_VIDEO_ENCODER_AVC,
+
+   MMALOMX_ROLE_AUDIO_DECODER_AAC,
+   MMALOMX_ROLE_AUDIO_DECODER_MPGA_L1,
+   MMALOMX_ROLE_AUDIO_DECODER_MPGA_L2,
+   MMALOMX_ROLE_AUDIO_DECODER_MPGA_L3,
+   MMALOMX_ROLE_AUDIO_DECODER_DDP,
+
+   MMALOMX_ROLE_AIV_PLAY_101,
+   MMALOMX_ROLE_AIV_PLAY_AVCDDP,
+
+   MMALOMX_ROLE_MAX
+} MMALOMX_ROLE_T;
+
+const char *mmalomx_role_to_name(MMALOMX_ROLE_T role);
+MMALOMX_ROLE_T mmalomx_role_from_name(const char *name);
+OMX_ERRORTYPE mmalomx_role_set(struct MMALOMX_COMPONENT_T *component, const char *name);
diff --git a/interface/mmal/openmaxil/mmalomx_util_params.c b/interface/mmal/openmaxil/mmalomx_util_params.c
new file mode 100755 (executable)
index 0000000..f03b43f
--- /dev/null
@@ -0,0 +1,193 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/vmcs_host/khronos/IL/OMX_Broadcom.h"
+#include "mmalomx.h"
+#include "mmalomx_util_params.h"
+#include "mmalomx_util_params_common.h"
+
+static const MMALOMX_PARAM_TRANSLATION_T *mmalomx_param_list[] = {
+   mmalomx_param_xlator_audio, mmalomx_param_xlator_video,
+   mmalomx_param_xlator_camera, mmalomx_param_xlator_misc};
+
+const MMALOMX_PARAM_TRANSLATION_T *mmalomx_find_parameter_enum(unsigned int index)
+{
+   unsigned int i, j;
+
+   for (i = 0; i < MMAL_COUNTOF(mmalomx_param_list); i++)
+   {
+      for (j = 0; mmalomx_param_list[i][j].mmal_id != MMAL_PARAMETER_UNUSED; j++)
+      {
+         if (!index--)
+            break;
+      }
+      if (mmalomx_param_list[i][j].mmal_id != MMAL_PARAMETER_UNUSED)
+         break;
+   }
+
+   return i < MMAL_COUNTOF(mmalomx_param_list) ? &mmalomx_param_list[i][j] : NULL;
+}
+
+const MMALOMX_PARAM_TRANSLATION_T *mmalomx_find_parameter_from_omx_id(uint32_t id)
+{
+   unsigned int i, j;
+
+   for (i = 0; i < MMAL_COUNTOF(mmalomx_param_list); i++)
+   {
+      for (j = 0; mmalomx_param_list[i][j].mmal_id != MMAL_PARAMETER_UNUSED; j++)
+      {
+         if (mmalomx_param_list[i][j].omx_id == id)
+            break;
+      }
+      if (mmalomx_param_list[i][j].mmal_id != MMAL_PARAMETER_UNUSED)
+         break;
+   }
+
+   return i < MMAL_COUNTOF(mmalomx_param_list) ? &mmalomx_param_list[i][j] : NULL;
+}
+
+const MMALOMX_PARAM_TRANSLATION_T *mmalomx_find_parameter_from_mmal_id(uint32_t id)
+{
+   unsigned int i, j;
+
+   for (i = 0; i < MMAL_COUNTOF(mmalomx_param_list); i++)
+   {
+      for (j = 0; mmalomx_param_list[i][j].mmal_id != MMAL_PARAMETER_UNUSED; j++)
+      {
+         if (mmalomx_param_list[i][j].mmal_id == id)
+            break;
+      }
+      if (mmalomx_param_list[i][j].mmal_id != MMAL_PARAMETER_UNUSED)
+         break;
+   }
+
+   return i < MMAL_COUNTOF(mmalomx_param_list) ? &mmalomx_param_list[i][j] : NULL;
+}
+
+const char *mmalomx_parameter_name_omx(uint32_t id)
+{
+   const MMALOMX_PARAM_TRANSLATION_T *xlat = mmalomx_find_parameter_from_omx_id(id);
+   return xlat ? xlat->omx_name : 0;
+}
+
+const char *mmalomx_parameter_name_mmal(uint32_t id)
+{
+   const MMALOMX_PARAM_TRANSLATION_T *xlat = mmalomx_find_parameter_from_mmal_id(id);
+   return xlat ? xlat->mmal_name : 0;
+}
+
+MMAL_STATUS_T mmalomx_param_mapping_generic(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   const MMALOMX_PARAM_TRANSLATION_T *xlat,
+   MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param, MMAL_PORT_T *mmal_port)
+{
+   MMALOMX_PARAM_OMX_HEADER_T *omx_header = (MMALOMX_PARAM_OMX_HEADER_T *)omx_param;
+   uint8_t *mmal_data = ((uint8_t *)mmal_param) + sizeof(MMAL_PARAMETER_HEADER_T);
+   uint8_t *omx_data = ((uint8_t *)omx_param) + sizeof(MMALOMX_PARAM_OMX_HEADER_T);
+   unsigned int size = mmal_param->size - sizeof(MMAL_PARAMETER_HEADER_T);
+   MMAL_PARAM_UNUSED(mmal_port);
+
+   if (xlat->portless)
+      omx_data -= sizeof(OMX_U32);
+
+   if (((uint8_t *)omx_param) + omx_header->nSize !=
+         omx_data + size)
+   {
+      VCOS_ALERT("mmalomx_param_mapping_generic: mismatch between mmal and omx parameters for (%u)",
+                 (unsigned int)mmal_param->id);
+      return MMAL_EINVAL;
+   }
+
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+      memcpy(mmal_data, omx_data, size);
+   else
+      memcpy(omx_data, mmal_data, size);
+
+   return MMAL_SUCCESS;
+}
+
+MMAL_STATUS_T mmalomx_param_enum_generic(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   const MMALOMX_PARAM_TRANSLATION_T *xlat,
+   MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param, MMAL_PORT_T *mmal_port)
+{
+   uint32_t *mmal = (uint32_t *)(((uint8_t *)mmal_param) + sizeof(MMAL_PARAMETER_HEADER_T));
+   uint32_t *omx = (uint32_t *)(((uint8_t *)omx_param) + sizeof(MMALOMX_PARAM_OMX_HEADER_T));
+   unsigned int i = 0;
+   MMAL_PARAM_UNUSED(mmal_port);
+
+   if (xlat->portless)
+      omx -= 1;
+
+   /* Find translation entry in lookup table */
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+      for (i = 0; i < xlat->xlat_enum_num && xlat->xlat_enum->omx != *omx; i++);
+   else
+      for (i = 0; i < xlat->xlat_enum_num && xlat->xlat_enum->mmal != *mmal; i++);
+
+   if (i == xlat->xlat_enum_num)
+   {
+      if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+         VCOS_ALERT("mmalomx_param_enum_generic: omx enum value %u not supported", (unsigned int)*omx);
+      else
+         VCOS_ALERT("mmalomx_param_enum_generic: mmal enum value %u not supported", (unsigned int)*mmal);
+      return MMAL_EINVAL;
+   }
+
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+      *mmal = xlat->xlat_enum[i].mmal;
+   else
+      *omx = xlat->xlat_enum[i].omx;
+
+   return MMAL_SUCCESS;
+}
+
+MMAL_STATUS_T mmalomx_param_rational_generic(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   const MMALOMX_PARAM_TRANSLATION_T *xlat,
+   MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param,  MMAL_PORT_T *mmal_port)
+{
+   MMAL_RATIONAL_T *mmal = (MMAL_RATIONAL_T *)(((uint8_t *)mmal_param) + sizeof(MMAL_PARAMETER_HEADER_T));
+   int32_t *omx = (int32_t *)(((uint8_t *)omx_param) + sizeof(MMALOMX_PARAM_OMX_HEADER_T));
+   MMAL_PARAM_UNUSED(mmal_port);
+
+   if (xlat->portless)
+      omx -= 1;
+
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+   {
+      mmal->num = *omx;
+      mmal->den = xlat->xlat_enum_num;
+      mmal_rational_simplify(mmal);
+   }
+   else
+   {
+      mmal_rational_simplify(mmal);
+      *omx = 0;
+      if (mmal->den)
+         *omx = mmal->num * xlat->xlat_enum_num / mmal->den;
+   }
+
+   return MMAL_SUCCESS;
+}
diff --git a/interface/mmal/openmaxil/mmalomx_util_params.h b/interface/mmal/openmaxil/mmalomx_util_params.h
new file mode 100755 (executable)
index 0000000..2520dfb
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file
+ * OpenMAX IL adaptation layer for MMAL - Parameters related functions
+ */
+
+#ifndef MMALOMX_UTIL_PARAMS_H
+#define MMALOMX_UTIL_PARAMS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** The structure that all OMX parameters containing a port start with */
+typedef struct MMALOMX_PARAM_OMX_HEADER_T
+{
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+} MMALOMX_PARAM_OMX_HEADER_T;
+
+/** The structure that all OMX parameters without a port start with */
+typedef struct MMALOMX_PARAM_OMX_HEADER_PORTLESS_T
+{
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+} MMALOMX_PARAM_OMX_HEADER_PORTLESS_T;
+
+typedef enum {
+   MMALOMX_PARAM_MAPPING_TO_MMAL,
+   MMALOMX_PARAM_MAPPING_TO_OMX
+} MMALOMX_PARAM_MAPPING_DIRECTION;
+
+typedef struct MMALOMX_PARAM_ENUM_TRANSLATE_T {
+   uint32_t mmal;
+   uint32_t omx;
+} MMALOMX_PARAM_ENUM_TRANSLATE_T;
+
+typedef enum MMALOMX_PARAM_TRANSLATION_TYPE_T {
+   MMALOMX_PARAM_TRANSLATION_TYPE_NONE = 0,
+   MMALOMX_PARAM_TRANSLATION_TYPE_SIMPLE,
+   MMALOMX_PARAM_TRANSLATION_TYPE_CUSTOM,
+   MMALOMX_PARAM_TRANSLATION_TYPE_DIRECT,
+} MMALOMX_PARAM_TRANSLATION_TYPE_T;
+
+/** MMAL <-> OMX parameter translation information */
+typedef struct MMALOMX_PARAM_TRANSLATION_T
+{
+   uint32_t mmal_id;               /**< MMAL parameter id */
+   uint32_t omx_id;                /**< OpenMAX IL parameter index */
+   unsigned int mmal_size:16;
+   unsigned int omx_size:16;
+   unsigned int portless:1;
+   unsigned int double_translation:1;
+   MMALOMX_PARAM_TRANSLATION_TYPE_T type:4;
+
+   struct {
+      MMAL_STATUS_T (*simple)(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+         MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param);
+      MMAL_STATUS_T (*generic)(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+         const struct MMALOMX_PARAM_TRANSLATION_T *xlat,
+         MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param, MMAL_PORT_T *mmal_port);
+      MMAL_STATUS_T (*list)(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+         const struct MMALOMX_PARAM_TRANSLATION_T *xlat, unsigned int index,
+         MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param, MMAL_PORT_T *mmal_port);
+      MMAL_STATUS_T (*custom)(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+         const struct MMALOMX_PARAM_TRANSLATION_T *xlat,
+         MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param, MMAL_PORT_T *mmal_port);
+   } fn;
+
+   const struct MMALOMX_PARAM_ENUM_TRANSLATE_T *xlat_enum;
+   unsigned int xlat_enum_num;
+
+   const char *mmal_name; /**< MMAL parameter name */
+   const char *omx_name;  /**< OMX parameter name */
+
+} MMALOMX_PARAM_TRANSLATION_T;
+
+const char *mmalomx_parameter_name_omx(uint32_t id);
+const char *mmalomx_parameter_name_mmal(uint32_t id);
+const MMALOMX_PARAM_TRANSLATION_T *mmalomx_find_parameter_from_omx_id(uint32_t id);
+const MMALOMX_PARAM_TRANSLATION_T *mmalomx_find_parameter_from_mmal_id(uint32_t id);
+const MMALOMX_PARAM_TRANSLATION_T *mmalomx_find_parameter_enum(unsigned int index);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MMALOMX_UTIL_PARAMS_H */
diff --git a/interface/mmal/openmaxil/mmalomx_util_params_audio.c b/interface/mmal/openmaxil/mmalomx_util_params_audio.c
new file mode 100755 (executable)
index 0000000..2fb81bb
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmalomx.h"
+#include "mmalomx_util_params_common.h"
+#include "mmalomx_logging.h"
+
+const MMALOMX_PARAM_TRANSLATION_T mmalomx_param_xlator_audio[] = {
+   MMALOMX_PARAM_TERMINATE()
+};
diff --git a/interface/mmal/openmaxil/mmalomx_util_params_camera.c b/interface/mmal/openmaxil/mmalomx_util_params_camera.c
new file mode 100755 (executable)
index 0000000..936eadc
--- /dev/null
@@ -0,0 +1,556 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmalomx.h"
+#include "mmalomx_util_params_common.h"
+#include "mmalomx_logging.h"
+
+static const MMALOMX_PARAM_ENUM_TRANSLATE_T mmalomx_param_enum_awb_mode[] = {
+   {MMAL_PARAM_AWBMODE_OFF,         OMX_WhiteBalControlOff},
+   {MMAL_PARAM_AWBMODE_AUTO,        OMX_WhiteBalControlAuto},
+   {MMAL_PARAM_AWBMODE_SUNLIGHT,    OMX_WhiteBalControlSunLight},
+   {MMAL_PARAM_AWBMODE_CLOUDY,      OMX_WhiteBalControlCloudy},
+   {MMAL_PARAM_AWBMODE_SHADE,       OMX_WhiteBalControlShade},
+   {MMAL_PARAM_AWBMODE_TUNGSTEN,    OMX_WhiteBalControlTungsten},
+   {MMAL_PARAM_AWBMODE_FLUORESCENT, OMX_WhiteBalControlFluorescent},
+   {MMAL_PARAM_AWBMODE_INCANDESCENT,OMX_WhiteBalControlIncandescent},
+   {MMAL_PARAM_AWBMODE_FLASH,       OMX_WhiteBalControlFlash},
+   {MMAL_PARAM_AWBMODE_HORIZON,     OMX_WhiteBalControlHorizon},
+};
+
+static const MMALOMX_PARAM_ENUM_TRANSLATE_T mmalomx_param_enum_image_effect[] = {
+   {MMAL_PARAM_IMAGEFX_NONE,        OMX_ImageFilterNone},
+   {MMAL_PARAM_IMAGEFX_NEGATIVE,    OMX_ImageFilterNegative},
+   {MMAL_PARAM_IMAGEFX_SOLARIZE,    OMX_ImageFilterSolarize},
+   {MMAL_PARAM_IMAGEFX_SKETCH,      OMX_ImageFilterSketch},
+   {MMAL_PARAM_IMAGEFX_DENOISE,     OMX_ImageFilterNoise},
+   {MMAL_PARAM_IMAGEFX_EMBOSS,      OMX_ImageFilterEmboss},
+   {MMAL_PARAM_IMAGEFX_OILPAINT,    OMX_ImageFilterOilPaint},
+   {MMAL_PARAM_IMAGEFX_HATCH,       OMX_ImageFilterHatch},
+   {MMAL_PARAM_IMAGEFX_GPEN,        OMX_ImageFilterGpen},
+   {MMAL_PARAM_IMAGEFX_PASTEL,      OMX_ImageFilterPastel},
+   {MMAL_PARAM_IMAGEFX_WATERCOLOUR, OMX_ImageFilterWatercolor},
+   {MMAL_PARAM_IMAGEFX_FILM,        OMX_ImageFilterFilm},
+   {MMAL_PARAM_IMAGEFX_BLUR,        OMX_ImageFilterBlur},
+   {MMAL_PARAM_IMAGEFX_SATURATION,  OMX_ImageFilterSaturation},
+   {MMAL_PARAM_IMAGEFX_COLOURSWAP,  OMX_ImageFilterColourSwap},
+   {MMAL_PARAM_IMAGEFX_WASHEDOUT,   OMX_ImageFilterWashedOut},
+   {MMAL_PARAM_IMAGEFX_POSTERISE,   OMX_ImageFilterPosterise},
+   {MMAL_PARAM_IMAGEFX_COLOURPOINT, OMX_ImageFilterColourPoint},
+   {MMAL_PARAM_IMAGEFX_COLOURBALANCE, OMX_ImageFilterColourBalance},
+   {MMAL_PARAM_IMAGEFX_CARTOON,     OMX_ImageFilterCartoon},
+};
+
+static MMAL_STATUS_T mmalomx_param_mapping_colour_effect(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param)
+{
+   OMX_CONFIG_COLORENHANCEMENTTYPE *omx = (OMX_CONFIG_COLORENHANCEMENTTYPE *)omx_param;
+   MMAL_PARAMETER_COLOURFX_T *mmal = (MMAL_PARAMETER_COLOURFX_T *)mmal_param;
+
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+   {
+      mmal->enable = omx->bColorEnhancement;
+      mmal->u = omx->nCustomizedU;
+      mmal->v = omx->nCustomizedV;
+   }
+   else
+   {
+      omx->bColorEnhancement = mmal->enable;
+      omx->nCustomizedU = mmal->u;
+      omx->nCustomizedV = mmal->v;
+   }
+
+   return MMAL_SUCCESS;
+}
+
+static const MMALOMX_PARAM_ENUM_TRANSLATE_T mmalomx_param_enum_flicker_avoid[] = {
+   {MMAL_PARAM_FLICKERAVOID_OFF,    OMX_COMMONFLICKERCANCEL_OFF},
+   {MMAL_PARAM_FLICKERAVOID_AUTO,   OMX_COMMONFLICKERCANCEL_AUTO},
+   {MMAL_PARAM_FLICKERAVOID_50HZ,   OMX_COMMONFLICKERCANCEL_50},
+   {MMAL_PARAM_FLICKERAVOID_60HZ,   OMX_COMMONFLICKERCANCEL_60},
+};
+
+static const MMALOMX_PARAM_ENUM_TRANSLATE_T mmalomx_param_enum_flash[] = {
+   {MMAL_PARAM_FLASH_OFF,     OMX_IMAGE_FlashControlOff},
+   {MMAL_PARAM_FLASH_AUTO,    OMX_IMAGE_FlashControlAuto},
+   {MMAL_PARAM_FLASH_ON,      OMX_IMAGE_FlashControlOn},
+   {MMAL_PARAM_FLASH_REDEYE,  OMX_IMAGE_FlashControlRedEyeReduction},
+   {MMAL_PARAM_FLASH_FILLIN,  OMX_IMAGE_FlashControlFillin},
+   {MMAL_PARAM_FLASH_TORCH,   OMX_IMAGE_FlashControlTorch},
+};
+
+static const MMALOMX_PARAM_ENUM_TRANSLATE_T mmalomx_param_enum_redeye[] = {
+   {MMAL_PARAM_REDEYE_OFF,    OMX_RedEyeRemovalNone},
+   {MMAL_PARAM_REDEYE_ON,     OMX_RedEyeRemovalOn},
+   {MMAL_PARAM_REDEYE_ON,     OMX_RedEyeRemovalAuto},
+   {MMAL_PARAM_REDEYE_SIMPLE, OMX_RedEyeRemovalSimple}
+};
+
+static MMAL_STATUS_T mmalomx_param_mapping_focus(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param)
+{
+   static const struct MMALOMX_PARAM_ENUM_TRANSLATE_T mmalomx_param_enum_focus[] = {
+      {MMAL_PARAM_FOCUS_AUTO,             OMX_IMAGE_FocusControlAutoLock},
+      {MMAL_PARAM_FOCUS_CAF,              OMX_IMAGE_FocusControlAuto},
+      {MMAL_PARAM_FOCUS_FIXED_INFINITY,   OMX_IMAGE_FocusControlInfinityFixed},
+      {MMAL_PARAM_FOCUS_FIXED_HYPERFOCAL, OMX_IMAGE_FocusControlHyperfocal},
+      {MMAL_PARAM_FOCUS_FIXED_NEAR,       OMX_IMAGE_FocusControlNearFixed},
+      {MMAL_PARAM_FOCUS_FIXED_MACRO,      OMX_IMAGE_FocusControlMacroFixed},
+      {MMAL_PARAM_FOCUS_AUTO_MACRO,       OMX_IMAGE_FocusControlAutoLockMacro},
+      {MMAL_PARAM_FOCUS_AUTO_NEAR,        OMX_IMAGE_FocusControlAutoLock},
+      {MMAL_PARAM_FOCUS_CAF_NEAR,         OMX_IMAGE_FocusControlAutoNear},
+      {MMAL_PARAM_FOCUS_CAF_MACRO,        OMX_IMAGE_FocusControlAutoMacro},
+      {MMAL_PARAM_FOCUS_CAF_FAST,         OMX_IMAGE_FocusControlAutoFast},
+      {MMAL_PARAM_FOCUS_CAF_MACRO_FAST,   OMX_IMAGE_FocusControlAutoMacroFast},
+      {MMAL_PARAM_FOCUS_CAF_NEAR_FAST,    OMX_IMAGE_FocusControlAutoNearFast},
+      /* {MMAL_PARAM_FOCUS_EDOF, ???}, */
+   };
+   OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE *omx = (OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE *)omx_param;
+   MMAL_PARAMETER_FOCUS_T *mmal = (MMAL_PARAMETER_FOCUS_T *)mmal_param;
+   MMALOMX_PARAM_ENUM_FIND(struct MMALOMX_PARAM_ENUM_TRANSLATE_T, xlat_enum, mmalomx_param_enum_focus,
+      dir, mmal->value, omx->eFocusControl);
+
+   if (!xlat_enum)
+      return MMAL_EINVAL;
+
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+   {
+      mmal->value = xlat_enum->mmal;
+   }
+   else
+   {
+      omx->eFocusControl = xlat_enum->omx;
+      omx->nFocusStepIndex = -1;
+   }
+
+   return MMAL_SUCCESS;
+}
+
+static const MMALOMX_PARAM_ENUM_TRANSLATE_T mmalomx_param_enum_mirror[] = {
+   {MMAL_PARAM_MIRROR_NONE,         OMX_MirrorNone},
+   {MMAL_PARAM_MIRROR_VERTICAL,     OMX_MirrorVertical},
+   {MMAL_PARAM_MIRROR_HORIZONTAL,   OMX_MirrorHorizontal},
+   {MMAL_PARAM_MIRROR_BOTH,         OMX_MirrorBoth}
+};
+
+static const MMALOMX_PARAM_ENUM_TRANSLATE_T mmalomx_param_enum_exposure_mode[] = {
+   {MMAL_PARAM_EXPOSUREMODE_OFF,           OMX_ExposureControlOff},
+   {MMAL_PARAM_EXPOSUREMODE_AUTO,          OMX_ExposureControlAuto},
+   {MMAL_PARAM_EXPOSUREMODE_NIGHT,         OMX_ExposureControlNight},
+   {MMAL_PARAM_EXPOSUREMODE_NIGHTPREVIEW,  OMX_ExposureControlNightWithPreview},
+   {MMAL_PARAM_EXPOSUREMODE_BACKLIGHT,     OMX_ExposureControlBackLight},
+   {MMAL_PARAM_EXPOSUREMODE_SPOTLIGHT,     OMX_ExposureControlSpotLight},
+   {MMAL_PARAM_EXPOSUREMODE_SPORTS,        OMX_ExposureControlSports},
+   {MMAL_PARAM_EXPOSUREMODE_SNOW,          OMX_ExposureControlSnow},
+   {MMAL_PARAM_EXPOSUREMODE_BEACH,         OMX_ExposureControlBeach},
+   {MMAL_PARAM_EXPOSUREMODE_VERYLONG,      OMX_ExposureControlVeryLong},
+   {MMAL_PARAM_EXPOSUREMODE_FIXEDFPS,      OMX_ExposureControlFixedFps},
+   {MMAL_PARAM_EXPOSUREMODE_ANTISHAKE,     OMX_ExposureControlAntishake},
+   {MMAL_PARAM_EXPOSUREMODE_FIREWORKS,     OMX_ExposureControlFireworks},
+};
+
+static const MMALOMX_PARAM_ENUM_TRANSLATE_T mmalomx_param_enum_capture_status[] = {
+   {MMAL_PARAM_CAPTURE_STATUS_NOT_CAPTURING,   OMX_NotCapturing},
+   {MMAL_PARAM_CAPTURE_STATUS_CAPTURE_STARTED, OMX_CaptureStarted},
+   {MMAL_PARAM_CAPTURE_STATUS_CAPTURE_ENDED,   OMX_CaptureComplete},
+};
+
+static MMAL_STATUS_T mmalomx_param_mapping_face_track(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param)
+{
+   static const MMALOMX_PARAM_ENUM_TRANSLATE_T mmalomx_param_enum_face_track[] = {
+      {MMAL_PARAM_FACE_DETECT_NONE,      OMX_FaceDetectionControlNone},
+      {MMAL_PARAM_FACE_DETECT_ON,        OMX_FaceDetectionControlOn},
+   };
+   OMX_CONFIG_FACEDETECTIONCONTROLTYPE *omx = (OMX_CONFIG_FACEDETECTIONCONTROLTYPE *)omx_param;
+   MMAL_PARAMETER_FACE_TRACK_T *mmal = (MMAL_PARAMETER_FACE_TRACK_T *)mmal_param;
+   MMALOMX_PARAM_ENUM_FIND(MMALOMX_PARAM_ENUM_TRANSLATE_T, xenum, mmalomx_param_enum_face_track,
+      dir, mmal->mode, omx->eMode);
+
+   if (!xenum)
+      return MMAL_EINVAL;
+
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+   {
+      mmal->mode = xenum->mmal;
+      mmal->maxRegions = omx->nMaxRegions;
+      mmal->frames = omx->nFrames;
+      mmal->quality = omx->nQuality;
+   }
+   else
+   {
+      omx->eMode = xenum->omx;
+      omx->nMaxRegions = mmal->maxRegions;
+      omx->nFrames = mmal->frames;
+      omx->nQuality = mmal->quality;
+   }
+
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T mmalomx_param_mapping_thumb_cfg(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param)
+{
+   OMX_PARAM_BRCMTHUMBNAILTYPE *omx = (OMX_PARAM_BRCMTHUMBNAILTYPE *)omx_param;
+   MMAL_PARAMETER_THUMBNAIL_CONFIG_T *mmal = (MMAL_PARAMETER_THUMBNAIL_CONFIG_T *)mmal_param;
+
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+   {
+      mmal->enable = !!omx->bEnable;
+      mmal->width = omx->nWidth;
+      mmal->height = omx->nHeight;
+      mmal->quality = 0;
+   }
+   else
+   {
+      omx->bEnable = mmal->enable ? OMX_TRUE : OMX_FALSE;
+      omx->bUsePreview = OMX_FALSE;
+      omx->nWidth = mmal->width;
+      omx->nHeight = mmal->height;
+      /* We don't have an API for setting the thumbnail quality */
+   }
+
+   return MMAL_SUCCESS;
+}
+
+static const MMALOMX_PARAM_ENUM_TRANSLATE_T mmalomx_param_enum_stc[] = {
+   {MMAL_PARAM_STC_MODE_OFF,        OMX_TimestampModeZero},
+   {MMAL_PARAM_STC_MODE_RAW,        OMX_TimestampModeRawStc},
+   {MMAL_PARAM_STC_MODE_COOKED,     OMX_TimestampModeResetStc},
+};
+
+static const MMALOMX_PARAM_ENUM_TRANSLATE_T mmalomx_param_enum_capture_mode[] = {
+   {MMAL_PARAM_CAPTUREMODE_WAIT_FOR_END,          OMX_CameraCaptureModeWaitForCaptureEnd},
+   {MMAL_PARAM_CAPTUREMODE_RESUME_VF_IMMEDIATELY, OMX_CameraCaptureModeResumeViewfinderImmediately},
+   /*{MMAL_PARAM_CAPTUREMODE_WAIT_FOR_END_AND_HOLD, OMX_CameraCaptureModeWaitForCaptureEndAndUsePreviousInputImage}, Don't enable for now as not working */
+};
+
+static MMAL_STATUS_T mmalomx_param_mapping_sensor_info(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param)
+{
+   OMX_CONFIG_CAMERAINFOTYPE *omx = (OMX_CONFIG_CAMERAINFOTYPE *)omx_param;
+   MMAL_PARAMETER_SENSOR_INFORMATION_T *mmal = (MMAL_PARAMETER_SENSOR_INFORMATION_T *)mmal_param;
+
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+   {
+      mmal->f_number = mmal_rational_from_fixed_16_16(omx->xFNumber);
+      mmal->focal_length = mmal_rational_from_fixed_16_16(omx->xFocalLength);
+      mmal->model_id = omx->nModelId;
+      mmal->manufacturer_id = omx->nManufacturerId;
+      mmal->revision = omx->nRevNum;
+   }
+   else
+   {
+      omx->xFNumber = mmal_rational_to_fixed_16_16(mmal->f_number);
+      omx->xFocalLength = mmal_rational_to_fixed_16_16(mmal->focal_length);
+      omx->nModelId = mmal->model_id;
+      omx->nManufacturerId = mmal->manufacturer_id;
+      omx->nRevNum = mmal->revision;
+   }
+
+   return MMAL_SUCCESS;
+}
+
+static const MMALOMX_PARAM_ENUM_TRANSLATE_T mmalomx_param_enum_flash_select[] = {
+   {MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_XENON,   OMX_CameraFlashXenon},
+   {MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_LED,     OMX_CameraFlashLED},
+   {MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_OTHER,   OMX_CameraFlashNone},
+};
+
+static MMAL_STATUS_T mmalomx_param_mapping_fov(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param)
+{
+   OMX_CONFIG_BRCMFOVTYPE *omx = (OMX_CONFIG_BRCMFOVTYPE *)omx_param;
+   MMAL_PARAMETER_FIELD_OF_VIEW_T *mmal = (MMAL_PARAMETER_FIELD_OF_VIEW_T *)mmal_param;
+
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+   {
+      mmal->fov_h = mmal_rational_from_fixed_16_16(omx->xFieldOfViewHorizontal);
+      mmal->fov_v = mmal_rational_from_fixed_16_16(omx->xFieldOfViewVertical);
+   }
+   else
+   {
+      omx->xFieldOfViewHorizontal = mmal_rational_to_fixed_16_16(mmal->fov_h);
+      omx->xFieldOfViewVertical = mmal_rational_to_fixed_16_16(mmal->fov_v);
+   }
+
+   return MMAL_SUCCESS;
+}
+
+static const MMALOMX_PARAM_ENUM_TRANSLATE_T mmalomx_param_enum_drc[] = {
+   {MMAL_PARAMETER_DRC_STRENGTH_OFF,      OMX_DynRangeExpOff},
+   {MMAL_PARAMETER_DRC_STRENGTH_LOW,      OMX_DynRangeExpLow},
+   {MMAL_PARAMETER_DRC_STRENGTH_MEDIUM,   OMX_DynRangeExpMedium},
+   {MMAL_PARAMETER_DRC_STRENGTH_HIGH,     OMX_DynRangeExpHigh},
+};
+
+static MMAL_STATUS_T mmalomx_param_mapping_algo_ctrl(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param)
+{
+   static const MMALOMX_PARAM_ENUM_TRANSLATE_T mmalomx_param_enum_algo_ctrl[] = {
+      { MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_FACETRACKING,             OMX_CameraDisableAlgorithmFacetracking},
+      { MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_REDEYE_REDUCTION,         OMX_CameraDisableAlgorithmRedEyeReduction},
+      { MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_VIDEO_STABILISATION,      OMX_CameraDisableAlgorithmVideoStabilisation},
+      { MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_WRITE_RAW,                OMX_CameraDisableAlgorithmWriteRaw},
+      { MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_VIDEO_DENOISE,            OMX_CameraDisableAlgorithmVideoDenoise},
+      { MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_STILLS_DENOISE,           OMX_CameraDisableAlgorithmStillsDenoise},
+      { MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_TEMPORAL_DENOISE,         OMX_CameraDisableAlgorithmMax},
+      { MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_ANTISHAKE,                OMX_CameraDisableAlgorithmAntiShake},
+      { MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_IMAGE_EFFECTS,            OMX_CameraDisableAlgorithmImageEffects},
+      { MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_DYNAMIC_RANGE_COMPRESSION,OMX_CameraDisableAlgorithmDynamicRangeExpansion},
+      { MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_FACE_RECOGNITION,         OMX_CameraDisableAlgorithmFaceRecognition},
+      { MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_FACE_BEAUTIFICATION,      OMX_CameraDisableAlgorithmFaceBeautification},
+      { MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_SCENE_DETECTION,          OMX_CameraDisableAlgorithmSceneDetection},
+      { MMAL_PARAMETER_ALGORITHM_CONTROL_ALGORITHMS_HIGH_DYNAMIC_RANGE,       OMX_CameraDisableAlgorithmHighDynamicRange},
+   };
+   OMX_PARAM_CAMERADISABLEALGORITHMTYPE *omx = (OMX_PARAM_CAMERADISABLEALGORITHMTYPE *)omx_param;
+   MMAL_PARAMETER_ALGORITHM_CONTROL_T *mmal = (MMAL_PARAMETER_ALGORITHM_CONTROL_T *)mmal_param;
+   MMALOMX_PARAM_ENUM_FIND(MMALOMX_PARAM_ENUM_TRANSLATE_T, xenum, mmalomx_param_enum_algo_ctrl,
+      dir, mmal->algorithm, omx->eAlgorithm);
+
+   if (!xenum)
+      return MMAL_EINVAL;
+
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+   {
+      mmal->algorithm = xenum->mmal;
+      mmal->enabled = !omx->bDisabled;
+   }
+   else
+   {
+      omx->eAlgorithm = xenum->omx;
+      omx->bDisabled = !mmal->enabled;
+   }
+
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T mmalomx_param_mapping_image_effect_params(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param)
+{
+   OMX_CONFIG_IMAGEFILTERPARAMSTYPE *omx = (OMX_CONFIG_IMAGEFILTERPARAMSTYPE *)omx_param;
+   MMAL_PARAMETER_IMAGEFX_PARAMETERS_T *mmal = (MMAL_PARAMETER_IMAGEFX_PARAMETERS_T *)mmal_param;
+   MMALOMX_PARAM_ENUM_FIND(MMALOMX_PARAM_ENUM_TRANSLATE_T, xenum, mmalomx_param_enum_image_effect,
+      dir, mmal->effect, omx->eImageFilter);
+
+   if (!xenum)
+      return MMAL_EINVAL;
+
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+   {
+      if (omx->nNumParams > MMAL_COUNTOF(mmal->effect_parameter))
+         return MMAL_EINVAL;
+      mmal->effect = xenum->mmal;
+      mmal->num_effect_params = omx->nNumParams;
+      memcpy(mmal->effect_parameter, omx->nParams, sizeof(uint32_t) * omx->nNumParams);
+   }
+   else
+   {
+      if (mmal->num_effect_params > MMAL_COUNTOF(omx->nParams))
+         return MMAL_EINVAL;
+      omx->eImageFilter = xenum->omx;
+      omx->nNumParams = mmal->num_effect_params;
+      memcpy(omx->nParams, mmal->effect_parameter, sizeof(uint32_t) * omx->nNumParams);
+   }
+
+   return MMAL_SUCCESS;
+}
+
+static const MMALOMX_PARAM_ENUM_TRANSLATE_T mmalomx_param_enum_use_case[] = {
+   {MMAL_PARAM_CAMERA_USE_CASE_UNKNOWN,         OMX_CameraUseCaseAuto},
+   {MMAL_PARAM_CAMERA_USE_CASE_STILLS_CAPTURE,  OMX_CameraUseCaseStills},
+   {MMAL_PARAM_CAMERA_USE_CASE_VIDEO_CAPTURE,   OMX_CameraUseCaseVideo},
+};
+
+static MMAL_STATUS_T mmalomx_param_mapping_fps_range(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param)
+{
+   OMX_PARAM_BRCMFRAMERATERANGETYPE *omx = (OMX_PARAM_BRCMFRAMERATERANGETYPE *)omx_param;
+   MMAL_PARAMETER_FPS_RANGE_T *mmal = (MMAL_PARAMETER_FPS_RANGE_T *)mmal_param;
+
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+   {
+      mmal->fps_low = mmal_rational_from_fixed_16_16(omx->xFramerateLow);
+      mmal->fps_high = mmal_rational_from_fixed_16_16(omx->xFramerateLow);
+   }
+   else
+   {
+      omx->xFramerateLow = mmal_rational_to_fixed_16_16(mmal->fps_low);
+      omx->xFramerateLow = mmal_rational_to_fixed_16_16(mmal->fps_high);
+   }
+
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T mmalomx_param_mapping_ev_comp(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param)
+{
+   OMX_PARAM_S32TYPE *omx = (OMX_PARAM_S32TYPE *)omx_param;
+   MMAL_PARAMETER_INT32_T *mmal = (MMAL_PARAMETER_INT32_T *)mmal_param;
+
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+      mmal->value = (omx->nS32 * 6) >> 16;
+   else
+      omx->nS32 = (mmal->value << 16) / 6;
+
+   return MMAL_SUCCESS;
+}
+
+const MMALOMX_PARAM_TRANSLATION_T mmalomx_param_xlator_camera[] = {
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_ROTATION, MMAL_PARAMETER_INT32_T,
+      OMX_IndexConfigCommonRotate, OMX_CONFIG_ROTATIONTYPE),
+   MMALOMX_PARAM_ENUM(MMAL_PARAMETER_AWB_MODE, MMAL_PARAM_AWBMODE_T,
+      OMX_IndexConfigCommonWhiteBalance, OMX_CONFIG_WHITEBALCONTROLTYPE, mmalomx_param_enum_awb_mode),
+   MMALOMX_PARAM_ENUM(MMAL_PARAMETER_IMAGE_EFFECT, MMAL_PARAMETER_IMAGEFX_T,
+      OMX_IndexConfigCommonImageFilter, OMX_CONFIG_IMAGEFILTERTYPE, mmalomx_param_enum_image_effect),
+   MMALOMX_PARAM_STRAIGHT_MAPPING(MMAL_PARAMETER_COLOUR_EFFECT, MMAL_PARAMETER_COLOURFX_T,
+      OMX_IndexConfigCommonColorEnhancement, OMX_CONFIG_COLORENHANCEMENTTYPE, mmalomx_param_mapping_colour_effect),
+   MMALOMX_PARAM_ENUM(MMAL_PARAMETER_FLICKER_AVOID, MMAL_PARAMETER_FLICKERAVOID_T,
+      OMX_IndexConfigCommonFlickerCancellation, OMX_CONFIG_FLICKERCANCELTYPE, mmalomx_param_enum_flicker_avoid),
+   MMALOMX_PARAM_ENUM(MMAL_PARAMETER_FLASH, MMAL_PARAMETER_FLASH_T,
+      OMX_IndexParamFlashControl, OMX_IMAGE_PARAM_FLASHCONTROLTYPE, mmalomx_param_enum_flash),
+   MMALOMX_PARAM_ENUM(MMAL_PARAMETER_REDEYE, MMAL_PARAMETER_REDEYE_T,
+      OMX_IndexConfigCommonRedEyeRemoval, OMX_CONFIG_REDEYEREMOVALTYPE, mmalomx_param_enum_redeye),
+   MMALOMX_PARAM_STRAIGHT_MAPPING(MMAL_PARAMETER_FOCUS, MMAL_PARAMETER_FOCUS_T,
+      OMX_IndexConfigFocusControl, OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE, mmalomx_param_mapping_focus),
+   MMALOMX_PARAM_ENUM(MMAL_PARAMETER_REDEYE, MMAL_PARAMETER_REDEYE_T,
+      OMX_IndexConfigCommonRedEyeRemoval, OMX_CONFIG_REDEYEREMOVALTYPE, mmalomx_param_enum_flash),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_ZOOM, MMAL_PARAMETER_SCALEFACTOR_T,
+      OMX_IndexConfigCommonDigitalZoom, OMX_CONFIG_SCALEFACTORTYPE),
+   MMALOMX_PARAM_ENUM(MMAL_PARAMETER_MIRROR, MMAL_PARAMETER_MIRROR_T,
+      OMX_IndexConfigCommonMirror, OMX_CONFIG_MIRRORTYPE, mmalomx_param_enum_mirror),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_CAMERA_NUM, MMAL_PARAMETER_UINT32_T,
+      OMX_IndexParamCameraDeviceNumber, OMX_PARAM_U32TYPE),
+   MMALOMX_PARAM_BOOLEAN(MMAL_PARAMETER_CAPTURE,
+      OMX_IndexConfigPortCapturing),
+   MMALOMX_PARAM_ENUM(MMAL_PARAMETER_EXPOSURE_MODE, MMAL_PARAMETER_EXPOSUREMODE_T,
+      OMX_IndexConfigCommonExposure, OMX_CONFIG_EXPOSURECONTROLTYPE, mmalomx_param_enum_exposure_mode),
+   MMALOMX_PARAM_ENUM_PORTLESS(MMAL_PARAMETER_CAPTURE_STATUS, MMAL_PARAMETER_CAPTURE_STATUS_T,
+      OMX_IndexParamCaptureStatus, OMX_PARAM_CAPTURESTATETYPE, mmalomx_param_enum_capture_status),
+   MMALOMX_PARAM_STRAIGHT_MAPPING(MMAL_PARAMETER_FACE_TRACK, MMAL_PARAMETER_FACE_TRACK_T,
+      OMX_IndexConfigCommonFaceDetectionControl, OMX_CONFIG_FACEDETECTIONCONTROLTYPE, mmalomx_param_mapping_face_track),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_DRAW_BOX_FACES_AND_FOCUS,
+      OMX_IndexConfigDrawBoxAroundFaces),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_JPEG_Q_FACTOR, MMAL_PARAMETER_UINT32_T,
+      OMX_IndexParamQFactor, OMX_IMAGE_PARAM_QFACTORTYPE),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_EXIF_DISABLE,
+      OMX_IndexParamBrcmDisableEXIF),
+   MMALOMX_PARAM_STRAIGHT_MAPPING_PORTLESS(MMAL_PARAMETER_THUMBNAIL_CONFIGURATION, MMAL_PARAMETER_THUMBNAIL_CONFIG_T,
+      OMX_IndexParamBrcmThumbnail, OMX_PARAM_BRCMTHUMBNAILTYPE, mmalomx_param_mapping_thumb_cfg),
+   MMALOMX_PARAM_ENUM(MMAL_PARAMETER_USE_STC, MMAL_PARAMETER_CAMERA_STC_MODE_T,
+      OMX_IndexParamCommonUseStcTimestamps, OMX_PARAM_TIMESTAMPMODETYPE, mmalomx_param_enum_stc),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_VIDEO_STABILISATION, MMAL_PARAMETER_BOOLEAN_T,
+      OMX_IndexConfigCommonFrameStabilisation, OMX_CONFIG_FRAMESTABTYPE),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_ENABLE_DPF_FILE,
+      OMX_IndexParamUseDynamicParameterFile),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_DPF_FAIL_IS_FATAL,
+      OMX_IndexParamDynamicParameterFileFailFatal),
+   MMALOMX_PARAM_ENUM(MMAL_PARAMETER_CAPTURE_MODE, MMAL_PARAMETER_CAPTUREMODE_T,
+      OMX_IndexParamCameraCaptureMode, OMX_PARAM_CAMERACAPTUREMODETYPE, mmalomx_param_enum_capture_mode),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_INPUT_CROP, MMAL_PARAMETER_INPUT_CROP_T,
+      OMX_IndexConfigInputCropPercentages, OMX_CONFIG_INPUTCROPTYPE),
+   MMALOMX_PARAM_STRAIGHT_MAPPING_PORTLESS(MMAL_PARAMETER_SENSOR_INFORMATION, MMAL_PARAMETER_SENSOR_INFORMATION_T,
+      OMX_IndexConfigCameraInfo, OMX_CONFIG_CAMERAINFOTYPE, mmalomx_param_mapping_sensor_info),
+   MMALOMX_PARAM_ENUM(MMAL_PARAMETER_FLASH_SELECT, MMAL_PARAMETER_FLASH_SELECT_T,
+      OMX_IndexParamCameraFlashType, OMX_PARAM_CAMERAFLASHTYPE, mmalomx_param_enum_flash_select),
+   MMALOMX_PARAM_STRAIGHT_MAPPING(MMAL_PARAMETER_FIELD_OF_VIEW, MMAL_PARAMETER_FIELD_OF_VIEW_T,
+      OMX_IndexConfigFieldOfView, OMX_CONFIG_BRCMFOVTYPE, mmalomx_param_mapping_fov),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_HIGH_DYNAMIC_RANGE,
+      OMX_IndexConfigBrcmHighDynamicRange),
+   MMALOMX_PARAM_ENUM_PORTLESS(MMAL_PARAMETER_DYNAMIC_RANGE_COMPRESSION, MMAL_PARAMETER_DRC_T,
+      OMX_IndexConfigDynamicRangeExpansion, OMX_CONFIG_DYNAMICRANGEEXPANSIONTYPE, mmalomx_param_enum_drc),
+   MMALOMX_PARAM_STRAIGHT_MAPPING_PORTLESS(MMAL_PARAMETER_ALGORITHM_CONTROL, MMAL_PARAMETER_ALGORITHM_CONTROL_T,
+      OMX_IndexParamCameraDisableAlgorithm, OMX_PARAM_CAMERADISABLEALGORITHMTYPE, mmalomx_param_mapping_algo_ctrl),
+   MMALOMX_PARAM_RATIONAL(MMAL_PARAMETER_SHARPNESS, MMAL_PARAMETER_RATIONAL_T,
+      OMX_IndexConfigCommonSharpness, OMX_CONFIG_SHARPNESSTYPE, 100),
+   MMALOMX_PARAM_RATIONAL(MMAL_PARAMETER_CONTRAST, MMAL_PARAMETER_RATIONAL_T,
+      OMX_IndexConfigCommonContrast, OMX_CONFIG_CONTRASTTYPE, 100),
+   MMALOMX_PARAM_RATIONAL(MMAL_PARAMETER_BRIGHTNESS, MMAL_PARAMETER_RATIONAL_T,
+      OMX_IndexConfigCommonContrast, OMX_CONFIG_CONTRASTTYPE, 100),
+   MMALOMX_PARAM_RATIONAL(MMAL_PARAMETER_SATURATION, MMAL_PARAMETER_RATIONAL_T,
+      OMX_IndexConfigCommonSaturation, OMX_CONFIG_SATURATIONTYPE, 100),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_ANTISHAKE,
+      OMX_IndexConfigStillsAntiShakeEnable),
+   MMALOMX_PARAM_STRAIGHT_MAPPING(MMAL_PARAMETER_IMAGE_EFFECT_PARAMETERS, MMAL_PARAMETER_IMAGEFX_PARAMETERS_T,
+      OMX_IndexConfigCommonImageFilterParameters, OMX_CONFIG_IMAGEFILTERPARAMSTYPE, mmalomx_param_mapping_image_effect_params),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_CAMERA_BURST_CAPTURE,
+      OMX_IndexConfigBurstCapture),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_CAMERA_MIN_ISO, MMAL_PARAMETER_UINT32_T,
+      OMX_IndexConfigCameraIsoReferenceValue, OMX_PARAM_U32TYPE),
+   MMALOMX_PARAM_ENUM_PORTLESS(MMAL_PARAMETER_CAMERA_USE_CASE, MMAL_PARAMETER_CAMERA_USE_CASE_T,
+      OMX_IndexConfigCameraUseCase, OMX_CONFIG_CAMERAUSECASETYPE, mmalomx_param_enum_use_case),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_CAPTURE_STATS_PASS,
+      OMX_IndexConfigCameraEnableStatsPass),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_CAMERA_CUSTOM_SENSOR_CONFIG, MMAL_PARAMETER_UINT32_T,
+      OMX_IndexParamCameraCustomSensorConfig, OMX_PARAM_U32TYPE),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_ENABLE_REGISTER_FILE,
+      OMX_IndexConfigBrcmUseRegisterFile),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_REGISTER_FAIL_IS_FATAL,
+      OMX_IndexConfigBrcmRegisterFileFailFatal),
+   MMALOMX_PARAM_PASSTHROUGH_PORTLESS(MMAL_PARAMETER_CONFIGFILE_REGISTERS, MMAL_PARAMETER_CONFIGFILE_T,
+      OMX_IndexParamBrcmConfigFileRegisters, OMX_PARAM_BRCMCONFIGFILETYPE),
+   MMALOMX_PARAM_PASSTHROUGH_PORTLESS(MMAL_PARAMETER_CONFIGFILE_CHUNK_REGISTERS, MMAL_PARAMETER_CONFIGFILE_CHUNK_T,
+      OMX_IndexParamBrcmConfigFileChunkRegisters, OMX_PARAM_BRCMCONFIGFILECHUNKTYPE),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_JPEG_ATTACH_LOG,
+      OMX_IndexParamBrcmAttachLog),
+   MMALOMX_PARAM_PASSTHROUGH_PORTLESS(MMAL_PARAMETER_ZERO_SHUTTER_LAG, MMAL_PARAMETER_ZEROSHUTTERLAG_T,
+      OMX_IndexParamCameraZeroShutterLag, OMX_CONFIG_ZEROSHUTTERLAGTYPE),
+   MMALOMX_PARAM_STRAIGHT_MAPPING(MMAL_PARAMETER_FPS_RANGE, MMAL_PARAMETER_FPS_RANGE_T,
+      OMX_IndexParamBrcmFpsRange, OMX_PARAM_BRCMFRAMERATERANGETYPE, mmalomx_param_mapping_fps_range),
+   MMALOMX_PARAM_STRAIGHT_MAPPING(MMAL_PARAMETER_CAPTURE_EXPOSURE_COMP, MMAL_PARAMETER_INT32_T,
+      OMX_IndexParamCaptureExposureCompensation, OMX_PARAM_S32TYPE, mmalomx_param_mapping_ev_comp),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_SW_SHARPEN_DISABLE,
+      OMX_IndexParamSWSharpenDisable),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_FLASH_REQUIRED,
+      OMX_IndexConfigBrcmFlashRequired),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_SW_SATURATION_DISABLE,
+      OMX_IndexParamSWSaturationDisable),
+   MMALOMX_PARAM_TERMINATE()
+};
+
+#if 0 /* Conversions which are still left to implement */
+MMALOMX_PARAM_CUSTOM(MMAL_PARAMETER_CAMERA_CONFIG, MMAL_PARAMETER_CAMERA_CONFIG_T,
+    0, 0, mmal_ril_param_set_cam_config),
+MMALOMX_PARAM_STRAIGHT_MAPPING(MMAL_PARAMETER_EXPOSURE_COMP, MMAL_PARAMETER_INT32_T,
+   OMX_IndexConfigCommonExposureValue, OMX_CONFIG_EXPOSUREVALUETYPE, 0),
+MMALOMX_PARAM_STRAIGHT_MAPPING(MMAL_PARAMETER_EXP_METERING_MODE, MMAL_PARAMETER_EXPOSUREMETERINGMODE_T,
+   OMX_IndexConfigCommonExposureValue, OMX_CONFIG_EXPOSUREVALUETYPE, 0),
+MMALOMX_PARAM_STRAIGHT_MAPPING(MMAL_PARAMETER_ISO, MMAL_PARAMETER_UINT32_T,
+   OMX_IndexConfigCommonExposureValue, OMX_CONFIG_EXPOSUREVALUETYPE, 0),
+MMALOMX_PARAM_STRAIGHT_MAPPING(MMAL_PARAMETER_FOCUS_STATUS, MMAL_PARAMETER_FOCUS_STATUS_T,
+   OMX_IndexConfigCommonFocusStatus, OMX_PARAM_FOCUSSTATUSTYPE, mmalomx_param_mapping_focus_status),
+MMALOMX_PARAM_STRAIGHT_MAPPING(MMAL_PARAMETER_EXIF, MMAL_PARAMETER_EXIF_T,
+   OMX_IndexConfigMetadataItem, OMX_CONFIG_METADATAITEMTYPE, 0),
+MMALOMX_PARAM_STRAIGHT_MAPPING(MMAL_PARAMETER_FACE_TRACK_RESULTS, MMAL_PARAMETER_FACE_TRACK_RESULTS_T,
+   OMX_IndexConfigCommonFaceDetectionRegion, OMX_CONFIG_FACEDETECTIONREGIONTYPE, 0),
+MMALOMX_PARAM_STRAIGHT_MAPPING(MMAL_PARAMETER_ENABLE_RAW_CAPTURE, MMAL_PARAMETER_BOOLEAN_T,
+   OMX_IndexConfigCaptureRawImageURI, OMX_PARAM_CONTENTURITYPE, 0),
+MMALOMX_PARAM_PASSTHROUGH_PORTLESS(MMAL_PARAMETER_DPF_FILE, MMAL_PARAMETER_URI_T,
+   OMX_IndexParamDynamicParameterFile, OMX_PARAM_CONTENTURITYPE),
+MMALOMX_PARAM_PASSTHROUGH_PORTLESS(MMAL_PARAMETER_FOCUS_REGIONS, ,
+   OMX_IndexConfigCommonFocusRegionXY, ),
+#endif
diff --git a/interface/mmal/openmaxil/mmalomx_util_params_common.h b/interface/mmal/openmaxil/mmalomx_util_params_common.h
new file mode 100755 (executable)
index 0000000..f0f2f96
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file
+ * OpenMAX IL adaptation layer for MMAL - Parameters related functions
+ */
+
+#include "interface/vmcs_host/khronos/IL/OMX_Broadcom.h"
+#include "mmalomx_util_params.h"
+#include "util/mmal_util_rational.h"
+
+/* Sanity check that OMX is defining the right int32 types */
+vcos_static_assert(sizeof(OMX_U32) == 4);
+
+MMAL_STATUS_T mmalomx_param_enum_generic(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   const struct MMALOMX_PARAM_TRANSLATION_T *xlat,
+   MMAL_PARAMETER_HEADER_T *mmal, OMX_PTR omx, MMAL_PORT_T *mmal_port);
+MMAL_STATUS_T mmalomx_param_rational_generic(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   const struct MMALOMX_PARAM_TRANSLATION_T *xlat,
+   MMAL_PARAMETER_HEADER_T *mmal, OMX_PTR omx, MMAL_PORT_T *mmal_port);
+MMAL_STATUS_T mmalomx_param_mapping_generic(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   const struct MMALOMX_PARAM_TRANSLATION_T *xlat,
+   MMAL_PARAMETER_HEADER_T *mmal, OMX_PTR omx, MMAL_PORT_T *mmal_port);
+
+extern const MMALOMX_PARAM_TRANSLATION_T mmalomx_param_xlator_audio[];
+extern const MMALOMX_PARAM_TRANSLATION_T mmalomx_param_xlator_video[];
+extern const MMALOMX_PARAM_TRANSLATION_T mmalomx_param_xlator_camera[];
+extern const MMALOMX_PARAM_TRANSLATION_T mmalomx_param_xlator_misc[];
+
+#define MMALOMX_PARAM_ENUM_FIND(TYPE, VAR, TABLE, DIR, MMAL, OMX)  \
+   const TYPE *VAR = TABLE; \
+   const TYPE *VAR##_end = VAR + MMAL_COUNTOF(TABLE); \
+   if (DIR == MMALOMX_PARAM_MAPPING_TO_MMAL) \
+      while (VAR < VAR##_end && VAR->omx != OMX) VAR++; \
+   else \
+      while (VAR < VAR##_end && VAR->mmal != MMAL) VAR++; \
+   do { if (VAR == VAR##_end) { \
+      VAR = 0; \
+      if (DIR == MMALOMX_PARAM_MAPPING_TO_MMAL) \
+         VCOS_ALERT("omx enum value %u not supported", (unsigned int)OMX); \
+      else \
+         VCOS_ALERT("mmal enum value %u not supported", (unsigned int)MMAL); \
+   } } while(0)
+
+#define mmalomx_ct_assert(e) (sizeof(char[1 - 2*!(e)]))
+
+/** List of macros used to define parameters mapping */
+#define MMALOMX_PARAM_PASSTHROUGH(a,b,c,d) \
+   {a, (uint32_t)c, sizeof(b), sizeof(d), \
+   !(offsetof(d, nPortIndex) | mmalomx_ct_assert(sizeof(b)+4==sizeof(d))), \
+   0, MMALOMX_PARAM_TRANSLATION_TYPE_CUSTOM, {0, mmalomx_param_mapping_generic, 0, 0}, 0, 0, \
+   MMAL_TO_STRING(a), MMAL_TO_STRING(c)}
+#define MMALOMX_PARAM_BOOLEAN(a, b) \
+   MMALOMX_PARAM_PASSTHROUGH(a, MMAL_PARAMETER_BOOLEAN_T, b, OMX_CONFIG_PORTBOOLEANTYPE)
+#define MMALOMX_PARAM_PASSTHROUGH_PORTLESS(a,b,c,d) \
+   {a, (uint32_t)c, sizeof(b), sizeof(d), \
+   !!(mmalomx_ct_assert(sizeof(b)==sizeof(d))), \
+   0, MMALOMX_PARAM_TRANSLATION_TYPE_CUSTOM, {0, mmalomx_param_mapping_generic, 0, 0}, 0, 0, \
+   MMAL_TO_STRING(a), MMAL_TO_STRING(c)}
+#define MMALOMX_PARAM_BOOLEAN_PORTLESS(a, b) \
+   MMALOMX_PARAM_PASSTHROUGH_PORTLESS(a, MMAL_PARAMETER_BOOLEAN_T, b, OMX_CONFIG_BOOLEANTYPE)
+#define MMALOMX_PARAM_PASSTHROUGH_PORTLESS_DOUBLE_TRANSLATION(a,b,c,d) \
+   {a, (uint32_t)c, sizeof(b), sizeof(d), \
+   !!(mmalomx_ct_assert(sizeof(b)==sizeof(d))), \
+   1, MMALOMX_PARAM_TRANSLATION_TYPE_CUSTOM, {0, mmalomx_param_mapping_generic, 0, 0}, 0, 0, \
+   MMAL_TO_STRING(a), MMAL_TO_STRING(c)}
+#define MMALOMX_PARAM_DIRECT_PORTLESS(a,b,c,d) \
+   {a, (uint32_t)c, sizeof(b), sizeof(d), 1, \
+   0, MMALOMX_PARAM_TRANSLATION_TYPE_DIRECT, {0, 0, 0, 0}, 0, 0, \
+   MMAL_TO_STRING(a), MMAL_TO_STRING(c)}
+#define MMALOMX_PARAM_STRAIGHT_MAPPING(a,b,c,d,e) \
+   {a, (uint32_t)c, sizeof(b), sizeof(d), \
+   !offsetof(d, nPortIndex), \
+   0, MMALOMX_PARAM_TRANSLATION_TYPE_SIMPLE, {e, 0, 0, 0}, 0, 0, \
+   MMAL_TO_STRING(a), MMAL_TO_STRING(c)}
+#define MMALOMX_PARAM_STRAIGHT_MAPPING_PORTLESS(a,b,c,d,e) \
+   {a, (uint32_t)c, sizeof(b), sizeof(d), 1, \
+   0, MMALOMX_PARAM_TRANSLATION_TYPE_SIMPLE, {e, 0, 0, 0}, 0, 0, \
+   MMAL_TO_STRING(a), MMAL_TO_STRING(c)}
+#define MMALOMX_PARAM_STRAIGHT_MAPPING_DOUBLE_TRANSLATION(a,b,c,d,e) \
+   {a, (uint32_t)c, sizeof(b), sizeof(d), 0, \
+   1, MMALOMX_PARAM_TRANSLATION_TYPE_SIMPLE, {e, 0, 0, 0}, 0, 0, \
+   MMAL_TO_STRING(a), MMAL_TO_STRING(c)}
+#define MMALOMX_PARAM_ENUM(a,b,c,d,e) \
+   {a, (uint32_t)c, sizeof(b), sizeof(d), 0, \
+   0, MMALOMX_PARAM_TRANSLATION_TYPE_CUSTOM, {0, mmalomx_param_enum_generic, 0, 0}, e, MMAL_COUNTOF(e), \
+   MMAL_TO_STRING(a), MMAL_TO_STRING(c)}
+#define MMALOMX_PARAM_ENUM_PORTLESS(a,b,c,d,e) \
+   {a, (uint32_t)c, sizeof(b), sizeof(d), 1, \
+   0, MMALOMX_PARAM_TRANSLATION_TYPE_CUSTOM, {0, mmalomx_param_enum_generic, 0, 0}, e, MMAL_COUNTOF(e), \
+   MMAL_TO_STRING(a), MMAL_TO_STRING(c)}
+#define MMALOMX_PARAM_RATIONAL(a,b,c,d,e) \
+   {a, (uint32_t)c, sizeof(b), sizeof(d), 0, \
+   0, MMALOMX_PARAM_TRANSLATION_TYPE_CUSTOM, {0, mmalomx_param_rational_generic, 0, 0}, 0, e, \
+   MMAL_TO_STRING(a), MMAL_TO_STRING(c)}
+#define MMALOMX_PARAM_RATIONAL_PORTLESS(a,b,c,d,e) \
+   {a, (uint32_t)c, sizeof(b), sizeof(d), 1, \
+   0, MMALOMX_PARAM_TRANSLATION_TYPE_CUSTOM, {0, mmalomx_param_rational_generic, 0, 0}, 0, e, \
+   MMAL_TO_STRING(a), MMAL_TO_STRING(c)}
+#define MMALOMX_PARAM_CUSTOM(a,b,c,d,e) \
+   {a, (uint32_t)c, sizeof(b), sizeof(d), 0, \
+   0, MMALOMX_PARAM_TRANSLATION_TYPE_CUSTOM, {0, e, 0, 0}, 0, 0, \
+   MMAL_TO_STRING(a), MMAL_TO_STRING(c)}
+#define MMALOMX_PARAM_LIST(a,b,c,d,e,f) \
+   {a, (uint32_t)c, sizeof(b), sizeof(d), 0, \
+   0, MMALOMX_PARAM_TRANSLATION_TYPE_CUSTOM, {0, 0, f, 0}, 0, offsetof(d,e), \
+   MMAL_TO_STRING(a), MMAL_TO_STRING(c)}
+#define MMALOMX_PARAM_TERMINATE() \
+   {MMAL_PARAMETER_UNUSED, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, 0, 0, 0, 0}
diff --git a/interface/mmal/openmaxil/mmalomx_util_params_misc.c b/interface/mmal/openmaxil/mmalomx_util_params_misc.c
new file mode 100755 (executable)
index 0000000..e364033
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmalomx.h"
+#include "mmalomx_util_params_common.h"
+#include "mmalomx_logging.h"
+
+static MMAL_STATUS_T mmalomx_param_mapping_event_request(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param)
+{
+   OMX_CONFIG_REQUESTCALLBACKTYPE *omx = (OMX_CONFIG_REQUESTCALLBACKTYPE *)omx_param;
+   MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T *mmal = (MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T *)mmal_param;
+   const MMALOMX_PARAM_TRANSLATION_T *change_xlat;
+
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+   {
+      change_xlat = mmalomx_find_parameter_from_omx_id(omx->nIndex);
+      if (!change_xlat)
+      {
+         VCOS_ALERT("ommalomx_param_mapping_event_request: omx parameter "
+                    "0x%08x not recognised", omx->nIndex);
+         return MMAL_EINVAL;
+      }
+
+      mmal->change_id = change_xlat->mmal_id;
+      mmal->enable = omx->bEnable;
+   }
+   else
+   {
+      change_xlat = mmalomx_find_parameter_from_mmal_id(mmal->change_id);
+      if (!change_xlat)
+      {
+         VCOS_ALERT("mmalomx_param_mapping_event_request: mmal parameter "
+                    "0x%08x not recognised", mmal->change_id);
+         return MMAL_EINVAL;
+      }
+
+      omx->nIndex = change_xlat->omx_id;
+      omx->bEnable = mmal->enable;
+   }
+
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T mmalomx_param_mapping_statistics(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param)
+{
+   OMX_CONFIG_BRCMPORTSTATSTYPE *omx = (OMX_CONFIG_BRCMPORTSTATSTYPE *)omx_param;
+   MMAL_PARAMETER_STATISTICS_T *mmal = (MMAL_PARAMETER_STATISTICS_T *)mmal_param;
+
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+   {
+      mmal->buffer_count        = omx->nBufferCount;
+      mmal->frame_count         = omx->nImageCount + omx->nFrameCount;
+      mmal->frames_skipped      = omx->nFrameSkips;
+      mmal->frames_discarded    = omx->nDiscards;
+      mmal->eos_seen            = omx->nEOS;
+      mmal->maximum_frame_bytes = omx->nMaxFrameSize;
+      mmal->total_bytes         = omx_ticks_to_s64(omx->nByteCount);
+      mmal->corrupt_macroblocks = omx->nCorruptMBs;
+   }
+   else
+   {
+      omx->nBufferCount = mmal->buffer_count;
+      omx->nFrameCount = mmal->frame_count;
+      omx->nImageCount = 0;
+      omx->nFrameSkips = mmal->frames_skipped;
+      omx->nDiscards = mmal->frames_discarded;
+      omx->nEOS = mmal->eos_seen;
+      omx->nMaxFrameSize = mmal->maximum_frame_bytes;
+      omx->nByteCount = omx_ticks_from_s64(mmal->total_bytes);
+      omx->nCorruptMBs = mmal->corrupt_macroblocks;
+   }
+
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T mmalomx_param_mapping_buffer_flags(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param)
+{
+   OMX_PARAM_U32TYPE *omx = (OMX_PARAM_U32TYPE *)omx_param;
+   MMAL_PARAMETER_UINT32_T *mmal = (MMAL_PARAMETER_UINT32_T *)mmal_param;
+
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+      mmal->value = mmalil_buffer_flags_to_mmal(omx->nU32);
+   else
+      omx->nU32 = mmalil_buffer_flags_to_omx(mmal->value);
+
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T mmalomx_param_mapping_time(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param)
+{
+   OMX_TIME_CONFIG_TIMESTAMPTYPE *omx = (OMX_TIME_CONFIG_TIMESTAMPTYPE *)omx_param;
+   MMAL_PARAMETER_INT64_T *mmal = (MMAL_PARAMETER_INT64_T *)mmal_param;
+
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+      mmal->value = omx_ticks_to_s64(omx->nTimestamp);
+   else
+      omx->nTimestamp = omx_ticks_from_s64(mmal->value);
+
+   return MMAL_SUCCESS;
+}
+
+const MMALOMX_PARAM_TRANSLATION_T mmalomx_param_xlator_misc[] = {
+   MMALOMX_PARAM_STRAIGHT_MAPPING_DOUBLE_TRANSLATION(MMAL_PARAMETER_CHANGE_EVENT_REQUEST, MMAL_PARAMETER_CHANGE_EVENT_REQUEST_T,
+      OMX_IndexConfigRequestCallback, OMX_CONFIG_REQUESTCALLBACKTYPE,
+      mmalomx_param_mapping_event_request),
+   MMALOMX_PARAM_STRAIGHT_MAPPING(MMAL_PARAMETER_STATISTICS, MMAL_PARAMETER_STATISTICS_T,
+      OMX_IndexConfigBrcmPortStats, OMX_CONFIG_BRCMPORTSTATSTYPE,
+      mmalomx_param_mapping_statistics),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_MEM_USAGE, MMAL_PARAMETER_MEM_USAGE_T,
+      OMX_IndexConfigBrcmPoolMemAllocSize, OMX_PARAM_U32TYPE),
+   MMALOMX_PARAM_STRAIGHT_MAPPING(MMAL_PARAMETER_BUFFER_FLAG_FILTER, MMAL_PARAMETER_UINT32_T,
+      OMX_IndexConfigBrcmBufferFlagFilter, OMX_PARAM_U32TYPE,
+      mmalomx_param_mapping_buffer_flags),
+   MMALOMX_PARAM_BOOLEAN(MMAL_PARAMETER_ZERO_COPY,
+      OMX_IndexParamBrcmZeroCopy),
+   MMALOMX_PARAM_BOOLEAN(MMAL_PARAMETER_LOCKSTEP_ENABLE,
+      OMX_IndexParamBrcmLockStepEnable),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_POWERMON_ENABLE,
+      OMX_IndexConfigBrcmPowerMonitor),
+   MMALOMX_PARAM_STRAIGHT_MAPPING(MMAL_PARAMETER_CLOCK_TIME, MMAL_PARAMETER_INT64_T,
+      OMX_IndexConfigTimeCurrentMediaTime, OMX_TIME_CONFIG_TIMESTAMPTYPE,
+      mmalomx_param_mapping_time),
+   MMALOMX_PARAM_TERMINATE()
+};
+
+#if 0
+/* Conversions which are not done here. Should part of the core. */
+MMAL_PARAMETER_SUPPORTED_ENCODINGS
+#endif
diff --git a/interface/mmal/openmaxil/mmalomx_util_params_video.c b/interface/mmal/openmaxil/mmalomx_util_params_video.c
new file mode 100755 (executable)
index 0000000..83e3724
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmalomx.h"
+#include "mmalomx_util_params_common.h"
+#include "mmalomx_logging.h"
+
+static void rect_to_omx(OMX_DISPLAYRECTTYPE *dst, const MMAL_RECT_T *src)
+{
+   dst->x_offset  = src->x;
+   dst->y_offset  = src->y;
+   dst->width     = src->width;
+   dst->height    = src->height;
+}
+
+static void rect_to_mmal(MMAL_RECT_T *dst, const OMX_DISPLAYRECTTYPE *src)
+{
+   dst->x = src->x_offset;
+   dst->y = src->y_offset;
+   dst->width = src->width;
+   dst->height = src->height;
+}
+
+static MMAL_STATUS_T mmalomx_param_mapping_displayregion(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param)
+{
+   OMX_CONFIG_DISPLAYREGIONTYPE *omx = (OMX_CONFIG_DISPLAYREGIONTYPE *)omx_param;
+   MMAL_DISPLAYREGION_T *mmal = (MMAL_DISPLAYREGION_T *)mmal_param;
+
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+   {
+      mmal->set = omx->set;
+      mmal->display_num = omx->num;
+      mmal->fullscreen = omx->fullscreen;
+      mmal->transform = (MMAL_DISPLAYTRANSFORM_T)omx->transform;
+      rect_to_mmal(&mmal->dest_rect, &omx->dest_rect);
+      rect_to_mmal(&mmal->src_rect, &omx->src_rect);
+      mmal->noaspect = omx->noaspect;
+      mmal->mode = (MMAL_DISPLAYMODE_T)omx->mode;
+      mmal->pixel_x = omx->pixel_x;
+      mmal->pixel_y = omx->pixel_y;
+      mmal->layer = omx->layer;
+      mmal->copyprotect_required = omx->copyprotect_required;
+      mmal->alpha = omx->alpha;
+   }
+   else
+   {
+      omx->set        = mmal->set;
+      omx->num        = mmal->display_num;
+      omx->fullscreen = mmal->fullscreen;
+      omx->transform  = (OMX_DISPLAYTRANSFORMTYPE)mmal->transform;
+      rect_to_omx(&omx->dest_rect, &mmal->dest_rect);
+      rect_to_omx(&omx->src_rect, &mmal->src_rect);
+      omx->noaspect   = mmal->noaspect;
+      omx->mode       = (OMX_DISPLAYMODETYPE)mmal->mode;
+      omx->pixel_x    = mmal->pixel_x;
+      omx->pixel_y    = mmal->pixel_y;
+      omx->layer      = mmal->layer;
+      omx->copyprotect_required = mmal->copyprotect_required;
+      omx->alpha      = mmal->alpha;
+   }
+
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T mmalomx_param_list_supported_profiles(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   const MMALOMX_PARAM_TRANSLATION_T *xlat, unsigned int index,
+   MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param, MMAL_PORT_T *mmal_port)
+{
+   OMX_VIDEO_PARAM_PROFILELEVELTYPE *omx = (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)omx_param;
+   MMAL_PARAMETER_VIDEO_PROFILE_T *mmal = (MMAL_PARAMETER_VIDEO_PROFILE_T *)mmal_param;
+   MMAL_PARAM_UNUSED(xlat);
+
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+   {
+      OMX_VIDEO_CODINGTYPE coding = mmalil_encoding_to_omx_video_coding(mmal_port->format->encoding);
+      mmal->profile[index].profile = mmalil_omx_video_profile_to_mmal(omx->eProfile, coding);
+      mmal->profile[index].level = mmalil_omx_video_level_to_mmal(omx->eLevel, coding);
+   }
+   else
+   {
+      omx->eProfile = mmalil_video_profile_to_omx(mmal->profile[index].profile);
+      omx->eLevel = mmalil_video_level_to_omx(mmal->profile[index].level);
+   }
+
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T mmalomx_param_custom_profile(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   const MMALOMX_PARAM_TRANSLATION_T *xlat,
+   MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param, MMAL_PORT_T *mmal_port)
+{
+   OMX_VIDEO_PARAM_PROFILELEVELTYPE *omx = (OMX_VIDEO_PARAM_PROFILELEVELTYPE *)omx_param;
+   MMAL_PARAMETER_VIDEO_PROFILE_T *mmal = (MMAL_PARAMETER_VIDEO_PROFILE_T *)mmal_param;
+   MMAL_PARAM_UNUSED(xlat);
+
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+   {
+      OMX_VIDEO_CODINGTYPE coding = mmalil_encoding_to_omx_video_coding(mmal_port->format->encoding);
+      mmal->profile[0].profile = mmalil_omx_video_profile_to_mmal(omx->eProfile, coding);
+      mmal->profile[0].level = mmalil_omx_video_level_to_mmal(omx->eLevel, coding);
+   }
+   else
+   {
+      omx->eProfile = mmalil_video_profile_to_omx(mmal->profile[0].profile);
+      omx->eLevel = mmalil_video_level_to_omx(mmal->profile[0].level);
+   }
+
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T mmalomx_param_custom_ratecontrol(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   const MMALOMX_PARAM_TRANSLATION_T *xlat,
+   MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param, MMAL_PORT_T *mmal_port)
+{
+   OMX_VIDEO_PARAM_BITRATETYPE *omx = (OMX_VIDEO_PARAM_BITRATETYPE *)omx_param;
+   MMAL_PARAMETER_VIDEO_RATECONTROL_T *mmal = (MMAL_PARAMETER_VIDEO_RATECONTROL_T *)mmal_param;
+   MMAL_PARAM_UNUSED(xlat);
+
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+   {
+      mmal->control = mmalil_omx_video_ratecontrol_to_mmal(omx->eControlRate);
+      /* This does not apply nTargetBitrate but should not be necessary */
+   }
+   else
+   {
+      omx->eControlRate   = mmalil_video_ratecontrol_to_omx(mmal->control);
+      omx->nTargetBitrate = mmal_port->format->bitrate; /* Should not really be necessary */
+   }
+
+   return MMAL_SUCCESS;
+}
+
+static const MMALOMX_PARAM_ENUM_TRANSLATE_T mmalomx_param_enum_nalunitformat[] = {
+   {MMAL_VIDEO_NALUNITFORMAT_STARTCODES,               OMX_NaluFormatStartCodes},
+   {MMAL_VIDEO_NALUNITFORMAT_NALUNITPERBUFFER,         OMX_NaluFormatOneNaluPerBuffer},
+   {MMAL_VIDEO_NALUNITFORMAT_ONEBYTEINTERLEAVELENGTH,  OMX_NaluFormatOneByteInterleaveLength},
+   {MMAL_VIDEO_NALUNITFORMAT_TWOBYTEINTERLEAVELENGTH,  OMX_NaluFormatTwoByteInterleaveLength},
+   {MMAL_VIDEO_NALUNITFORMAT_FOURBYTEINTERLEAVELENGTH, OMX_NaluFormatFourByteInterleaveLength},
+};
+
+static MMAL_STATUS_T mmalomx_param_mapping_frame_rate(MMALOMX_PARAM_MAPPING_DIRECTION dir,
+   MMAL_PARAMETER_HEADER_T *mmal_param, OMX_PTR omx_param)
+{
+   OMX_CONFIG_FRAMERATETYPE *omx = (OMX_CONFIG_FRAMERATETYPE *)omx_param;
+   MMAL_PARAMETER_FRAME_RATE_T *mmal = (MMAL_PARAMETER_FRAME_RATE_T *)mmal_param;
+
+   if (dir == MMALOMX_PARAM_MAPPING_TO_MMAL)
+   {
+      mmal->frame_rate.num = omx->xEncodeFramerate;
+      mmal->frame_rate.den = (1<<16);
+   }
+   else
+   {
+      omx->xEncodeFramerate = 0;
+      if (mmal->frame_rate.den)
+         omx->xEncodeFramerate = (((int64_t)mmal->frame_rate.num)<<16)/mmal->frame_rate.den;
+   }
+
+   return MMAL_SUCCESS;
+}
+
+const MMALOMX_PARAM_TRANSLATION_T mmalomx_param_xlator_video[] = {
+   MMALOMX_PARAM_STRAIGHT_MAPPING(MMAL_PARAMETER_DISPLAYREGION, MMAL_DISPLAYREGION_T,
+      OMX_IndexConfigDisplayRegion, OMX_CONFIG_DISPLAYREGIONTYPE,
+      mmalomx_param_mapping_displayregion),
+   MMALOMX_PARAM_LIST(MMAL_PARAMETER_SUPPORTED_PROFILES, MMAL_PARAMETER_VIDEO_PROFILE_T,
+      OMX_IndexParamVideoProfileLevelQuerySupported, OMX_VIDEO_PARAM_PROFILELEVELTYPE,
+      nProfileIndex, mmalomx_param_list_supported_profiles),
+   MMALOMX_PARAM_CUSTOM(MMAL_PARAMETER_PROFILE, MMAL_PARAMETER_VIDEO_PROFILE_T,
+      OMX_IndexParamVideoProfileLevelCurrent, OMX_VIDEO_PARAM_PROFILELEVELTYPE,
+      mmalomx_param_custom_profile),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_INTRAPERIOD, MMAL_PARAMETER_UINT32_T,
+      OMX_IndexConfigBrcmVideoIntraPeriod, OMX_PARAM_U32TYPE),
+   MMALOMX_PARAM_CUSTOM(MMAL_PARAMETER_RATECONTROL, MMAL_PARAMETER_VIDEO_RATECONTROL_T,
+      OMX_IndexParamVideoBitrate, OMX_VIDEO_PARAM_BITRATETYPE,
+      mmalomx_param_custom_ratecontrol),
+   MMALOMX_PARAM_ENUM(MMAL_PARAMETER_NALUNITFORMAT, MMAL_PARAMETER_VIDEO_NALUNITFORMAT_T,
+      OMX_IndexParamNalStreamFormatSelect, OMX_NALSTREAMFORMATTYPE, mmalomx_param_enum_nalunitformat),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_MINIMISE_FRAGMENTATION,
+      OMX_IndexConfigMinimiseFragmentation),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_MB_ROWS_PER_SLICE, MMAL_PARAMETER_UINT32_T,
+      OMX_IndexConfigBrcmVideoEncoderMBRowsPerSlice, OMX_PARAM_U32TYPE),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION, MMAL_PARAMETER_VIDEO_LEVEL_EXTENSION_T,
+      OMX_IndexConfigEncLevelExtension, OMX_VIDEO_CONFIG_LEVEL_EXTEND),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_VIDEO_INTRA_REFRESH, MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T,
+      OMX_IndexConfigBrcmVideoIntraRefresh, OMX_VIDEO_PARAM_INTRAREFRESHTYPE),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_VIDEO_INTRA_REFRESH, MMAL_PARAMETER_VIDEO_INTRA_REFRESH_T,
+      OMX_IndexParamVideoIntraRefresh, OMX_VIDEO_PARAM_INTRAREFRESHTYPE),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_VIDEO_EEDE_ENABLE, MMAL_PARAMETER_VIDEO_EEDE_ENABLE_T,
+      OMX_IndexParamBrcmEEDEEnable, OMX_VIDEO_EEDE_ENABLE),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE, MMAL_PARAMETER_VIDEO_EEDE_LOSSRATE_T,
+      OMX_IndexParamBrcmEEDELossRate, OMX_VIDEO_EEDE_LOSSRATE),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_VIDEO_REQUEST_I_FRAME,
+      OMX_IndexConfigBrcmVideoRequestIFrame),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_VIDEO_IMMUTABLE_INPUT,
+      OMX_IndexParamBrcmImmutableInput),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_VIDEO_BIT_RATE, MMAL_PARAMETER_UINT32_T,
+      OMX_IndexConfigVideoBitrate, OMX_VIDEO_CONFIG_BITRATETYPE),
+   MMALOMX_PARAM_STRAIGHT_MAPPING(MMAL_PARAMETER_VIDEO_FRAME_RATE, MMAL_PARAMETER_FRAME_RATE_T,
+      OMX_IndexConfigVideoFramerate, OMX_CONFIG_FRAMERATETYPE, mmalomx_param_mapping_frame_rate),
+   MMALOMX_PARAM_STRAIGHT_MAPPING(MMAL_PARAMETER_FRAME_RATE, MMAL_PARAMETER_FRAME_RATE_T,
+      OMX_IndexConfigVideoFramerate, OMX_CONFIG_FRAMERATETYPE, mmalomx_param_mapping_frame_rate),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_VIDEO_ENCODE_MIN_QUANT, MMAL_PARAMETER_UINT32_T,
+      OMX_IndexParamBrcmVideoEncodeMinQuant, OMX_PARAM_U32TYPE),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_VIDEO_ENCODE_MAX_QUANT, MMAL_PARAMETER_UINT32_T,
+      OMX_IndexParamBrcmVideoEncodeMaxQuant, OMX_PARAM_U32TYPE),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL, MMAL_PARAMETER_VIDEO_ENCODE_RC_MODEL_T,
+      OMX_IndexParamRateControlModel, OMX_PARAM_U32TYPE),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_EXTRA_BUFFERS, MMAL_PARAMETER_UINT32_T,
+      OMX_IndexParamBrcmExtraBuffers, OMX_PARAM_U32TYPE),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_VIDEO_ALIGN_HORIZ, MMAL_PARAMETER_UINT32_T,
+      OMX_IndexParamBrcmAlignHoriz, OMX_PARAM_U32TYPE),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_VIDEO_ALIGN_VERT, MMAL_PARAMETER_UINT32_T,
+      OMX_IndexParamBrcmAlignVert, OMX_PARAM_U32TYPE),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_VIDEO_DROPPABLE_PFRAMES,
+      OMX_IndexParamBrcmDroppablePFrames),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_VIDEO_ENCODE_INITIAL_QUANT, MMAL_PARAMETER_UINT32_T,
+      OMX_IndexParamBrcmVideoInitialQuant, OMX_PARAM_U32TYPE),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_VIDEO_ENCODE_QP_P, MMAL_PARAMETER_UINT32_T,
+      OMX_IndexParamBrcmVideoInitialQuant, OMX_PARAM_U32TYPE),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_VIDEO_ENCODE_RC_SLICE_DQUANT, MMAL_PARAMETER_UINT32_T,
+      OMX_IndexParamBrcmVideoRCSliceDQuant, OMX_PARAM_U32TYPE),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_VIDEO_ENCODE_FRAME_LIMIT_BITS, MMAL_PARAMETER_UINT32_T,
+      OMX_IndexParamBrcmVideoFrameLimitBits, OMX_PARAM_U32TYPE),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_VIDEO_ENCODE_PEAK_RATE, MMAL_PARAMETER_UINT32_T,
+      OMX_IndexParamBrcmVideoPeakRate, OMX_PARAM_U32TYPE),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_VIDEO_ENCODE_H264_DISABLE_CABAC,
+      OMX_IndexConfigBrcmVideoH264DisableCABAC),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_VIDEO_ENCODE_H264_LOW_LATENCY,
+      OMX_IndexConfigBrcmVideoH264LowLatency),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_VIDEO_ENCODE_H264_AU_DELIMITERS,
+      OMX_IndexConfigBrcmVideoH264AUDelimiters),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_VIDEO_ENCODE_H264_DEBLOCK_IDC, MMAL_PARAMETER_UINT32_T,
+      OMX_IndexConfigBrcmVideoH264DeblockIDC, OMX_PARAM_U32TYPE),
+   MMALOMX_PARAM_PASSTHROUGH(MMAL_PARAMETER_VIDEO_ENCODE_H264_MB_INTRA_MODE, MMAL_PARAMETER_VIDEO_ENCODER_H264_MB_INTRA_MODES_T,
+      OMX_IndexConfigBrcmVideoH264IntraMBMode, OMX_PARAM_U32TYPE),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_VIDEO_ENCODE_HEADER_ON_OPEN,
+      OMX_IndexParamBrcmHeaderOnOpen),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_VIDEO_ENCODE_PRECODE_FOR_QP,
+      OMX_IndexParamBrcmVideoPrecodeForQP),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_VIDEO_TIMESTAMP_FIFO,
+      OMX_IndexParamBrcmVideoTimestampFifo),
+   MMALOMX_PARAM_BOOLEAN_PORTLESS(MMAL_PARAMETER_VIDEO_DECODE_ERROR_CONCEALMENT,
+      OMX_IndexParamBrcmVideoDecodeErrorConcealment),
+   MMALOMX_PARAM_PASSTHROUGH_PORTLESS_DOUBLE_TRANSLATION(MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER, MMAL_PARAMETER_VIDEO_DRM_PROTECT_BUFFER_T,
+      OMX_IndexParamBrcmVideoDrmProtectBuffer, OMX_PARAM_BRCMVIDEODRMPROTECTBUFFERTYPE),
+   MMALOMX_PARAM_PASSTHROUGH_PORTLESS(MMAL_PARAMETER_VIDEO_DECODE_CONFIG_VD3, MMAL_PARAMETER_BYTES_T,
+      OMX_IndexParamBrcmVideoDecodeConfigVD3, OMX_PARAM_BRCMVIDEODECODECONFIGVD3TYPE),
+   MMALOMX_PARAM_BOOLEAN(MMAL_PARAMETER_VIDEO_ENCODE_INLINE_HEADER,
+      OMX_IndexParamBrcmVideoAVCInlineHeaderEnable),
+   MMALOMX_PARAM_TERMINATE()
+};
diff --git a/interface/mmal/test/CMakeLists.txt b/interface/mmal/test/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..4ee91d9
--- /dev/null
@@ -0,0 +1,29 @@
+SET( MMAL_TOP ../../.. )
+
+include_directories(${PROJECT_SOURCE_DIR}/host_applications/linux/libs/bcm_host/include)
+
+SET( MMALPLAY_TOP ${MMAL_TOP}/host_applications/vmcs/test_apps/mmalplay )
+add_executable(mmalplay ${MMALPLAY_TOP}/playback.c ${MMALPLAY_TOP}/mmalplay.c)
+target_link_libraries(mmalplay mmal_core mmal_util bcm_host mmal_vc_client)
+target_link_libraries(mmalplay -Wl,--whole-archive mmal_components containers -Wl,--no-whole-archive mmal_core)
+target_link_libraries(mmalplay vcos)
+
+SET( MMALCAM_TOP ${MMAL_TOP}/host_applications/vmcs/test_apps/mmalcam )
+add_executable(mmalcam ${MMALCAM_TOP}/viewfinder.c ${MMALCAM_TOP}/mmalcam.c)
+target_link_libraries(mmalcam mmal_core mmal_util bcm_host mmal_vc_client)
+target_link_libraries(mmalcam -Wl,--whole-archive mmal_components -Wl,--no-whole-archive mmal_core)
+target_link_libraries(mmalcam vcos)
+
+SET( MMALEXAMPLES_TOP ${MMAL_TOP}/interface/mmal/test/examples )
+add_executable(mmal_example_connections ${MMALEXAMPLES_TOP}/example_connections.c)
+target_link_libraries(mmal_example_connections mmal_core mmal_util bcm_host mmal_vc_client)
+target_link_libraries(mmal_example_connections -Wl,--whole-archive mmal_components -Wl,--no-whole-archive mmal_core)
+add_executable(mmal_example_graph ${MMALEXAMPLES_TOP}/example_graph.c)
+target_link_libraries(mmal_example_graph mmal_core mmal_util bcm_host mmal_vc_client)
+target_link_libraries(mmal_example_graph -Wl,--whole-archive mmal_components -Wl,--no-whole-archive mmal_core)
+add_executable(mmal_example_basic_1 ${MMALEXAMPLES_TOP}/example_basic_1.c)
+target_link_libraries(mmal_example_basic_1 mmal_core mmal_util bcm_host mmal_vc_client)
+target_link_libraries(mmal_example_basic_1 -Wl,--whole-archive mmal_components -Wl,--no-whole-archive mmal_core)
+add_executable(mmal_example_basic_2 ${MMALEXAMPLES_TOP}/example_basic_2.c)
+target_link_libraries(mmal_example_basic_2 mmal_core mmal_util bcm_host mmal_vc_client)
+target_link_libraries(mmal_example_basic_2 -Wl,--whole-archive mmal_components -Wl,--no-whole-archive mmal_core)
diff --git a/interface/mmal/test/examples/example_basic_1.c b/interface/mmal/test/examples/example_basic_1.c
new file mode 100755 (executable)
index 0000000..49b984e
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "bcm_host.h"
+#include "mmal.h"
+#include "util/mmal_default_components.h"
+#include "interface/vcos/vcos.h"
+#include <stdio.h>
+
+#define CHECK_STATUS(status, msg) if (status != MMAL_SUCCESS) { fprintf(stderr, msg"\n"); goto error; }
+
+static uint8_t codec_header_bytes[512];
+static unsigned int codec_header_bytes_size = sizeof(codec_header_bytes);
+
+static FILE *source_file;
+
+/* Macros abstracting the I/O, just to make the example code clearer */
+#define SOURCE_OPEN(uri) \
+   source_file = fopen(uri, "rb"); if (!source_file) goto error;
+#define SOURCE_READ_CODEC_CONFIG_DATA(bytes, size) \
+   size = fread(bytes, 1, size, source_file); rewind(source_file)
+#define SOURCE_READ_DATA_INTO_BUFFER(a) \
+   a->length = fread(a->data, 1, a->alloc_size - 128, source_file); \
+   a->offset = 0; a->pts = a->dts = MMAL_TIME_UNKNOWN
+#define SOURCE_CLOSE() \
+   if (source_file) fclose(source_file)
+
+/** Context for our application */
+static struct CONTEXT_T {
+   VCOS_SEMAPHORE_T semaphore;
+   MMAL_QUEUE_T *queue;
+} context;
+
+/** Callback from the input port.
+ * Buffer has been consumed and is available to be used again. */
+static void input_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   struct CONTEXT_T *ctx = (struct CONTEXT_T *)port->userdata;
+
+   /* The decoder is done with the data, just recycle the buffer header into its pool */
+   mmal_buffer_header_release(buffer);
+
+   /* Kick the processing thread */
+   vcos_semaphore_post(&ctx->semaphore);
+}
+
+/** Callback from the output port.
+ * Buffer has been produced by the port and is available for processing. */
+static void output_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   struct CONTEXT_T *ctx = (struct CONTEXT_T *)port->userdata;
+
+   /* Queue the decoded video frame */
+   mmal_queue_put(ctx->queue, buffer);
+
+   /* Kick the processing thread */
+   vcos_semaphore_post(&ctx->semaphore);
+}
+
+int main(int argc, char **argv)
+{
+   MMAL_STATUS_T status = MMAL_EINVAL;
+   MMAL_COMPONENT_T *decoder = 0;
+   MMAL_POOL_T *pool_in = 0, *pool_out = 0;
+   unsigned int count;
+
+   if (argc < 2)
+   {
+      fprintf(stderr, "invalid arguments\n");
+      return -1;
+   }
+
+   bcm_host_init();
+
+   vcos_semaphore_create(&context.semaphore, "example", 1);
+
+   SOURCE_OPEN(argv[1]);
+
+   /* Create the decoder component.
+    * This specific component exposes 2 ports (1 input and 1 output). Like most components
+    * its expects the format of its input port to be set by the client in order for it to
+    * know what kind of data it will be fed. */
+   status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, &decoder);
+   CHECK_STATUS(status, "failed to create decoder");
+
+   /* Set format of video decoder input port */
+   MMAL_ES_FORMAT_T *format_in = decoder->input[0]->format;
+   format_in->type = MMAL_ES_TYPE_VIDEO;
+   format_in->encoding = MMAL_ENCODING_H264;
+   format_in->es->video.width = 1280;
+   format_in->es->video.height = 720;
+   format_in->es->video.frame_rate.num = 30;
+   format_in->es->video.frame_rate.den = 1;
+   format_in->es->video.par.num = 1;
+   format_in->es->video.par.den = 1;
+   /* If the data is known to be framed then the following flag should be set:
+    * format_in->flags |= MMAL_ES_FORMAT_FLAG_FRAMED; */
+
+   SOURCE_READ_CODEC_CONFIG_DATA(codec_header_bytes, codec_header_bytes_size);
+   status = mmal_format_extradata_alloc(format_in, codec_header_bytes_size);
+   CHECK_STATUS(status, "failed to allocate extradata");
+   format_in->extradata_size = codec_header_bytes_size;
+   if (format_in->extradata_size)
+      memcpy(format_in->extradata, codec_header_bytes, format_in->extradata_size);
+
+   status = mmal_port_format_commit(decoder->input[0]);
+   CHECK_STATUS(status, "failed to commit format");
+
+   /* Display the output port format */
+   MMAL_ES_FORMAT_T *format_out = decoder->output[0]->format;
+   fprintf(stderr, "%s\n", decoder->output[0]->name);
+   fprintf(stderr, " type: %i, fourcc: %4.4s\n", format_out->type, (char *)&format_out->encoding);
+   fprintf(stderr, " bitrate: %i, framed: %i\n", format_out->bitrate,
+           !!(format_out->flags & MMAL_ES_FORMAT_FLAG_FRAMED));
+   fprintf(stderr, " extra data: %i, %p\n", format_out->extradata_size, format_out->extradata);
+   fprintf(stderr, " width: %i, height: %i, (%i,%i,%i,%i)\n",
+           format_out->es->video.width, format_out->es->video.height,
+           format_out->es->video.crop.x, format_out->es->video.crop.y,
+           format_out->es->video.crop.width, format_out->es->video.crop.height);
+
+   /* The format of both ports is now set so we can get their buffer requirements and create
+    * our buffer headers. We use the buffer pool API to create these. */
+   decoder->input[0]->buffer_num = decoder->input[0]->buffer_num_min;
+   decoder->input[0]->buffer_size = decoder->input[0]->buffer_size_min;
+   decoder->output[0]->buffer_num = decoder->output[0]->buffer_num_min;
+   decoder->output[0]->buffer_size = decoder->output[0]->buffer_size_min;
+   pool_in = mmal_pool_create(decoder->input[0]->buffer_num,
+                              decoder->input[0]->buffer_size);
+   pool_out = mmal_pool_create(decoder->output[0]->buffer_num,
+                               decoder->output[0]->buffer_size);
+
+   /* Create a queue to store our decoded video frames. The callback we will get when
+    * a frame has been decoded will put the frame into this queue. */
+   context.queue = mmal_queue_create();
+
+   /* Store a reference to our context in each port (will be used during callbacks) */
+   decoder->input[0]->userdata = (void *)&context;
+   decoder->output[0]->userdata = (void *)&context;
+
+   /* Enable all the input port and the output port.
+    * The callback specified here is the function which will be called when the buffer header
+    * we sent to the component has been processed. */
+   status = mmal_port_enable(decoder->input[0], input_callback);
+   CHECK_STATUS(status, "failed to enable input port");
+   status = mmal_port_enable(decoder->output[0], output_callback);
+   CHECK_STATUS(status, "failed to enable output port");
+
+   /* Component won't start processing data until it is enabled. */
+   status = mmal_component_enable(decoder);
+   CHECK_STATUS(status, "failed to enable component");
+
+   /* Start decoding */
+   fprintf(stderr, "start decoding\n");
+
+   /* This is the main processing loop */
+   for (count = 0; count < 500; count++)
+   {
+      MMAL_BUFFER_HEADER_T *buffer;
+
+      /* Wait for buffer headers to be available on either of the decoder ports */
+      vcos_semaphore_wait(&context.semaphore);
+
+      /* Send data to decode to the input port of the video decoder */
+      if ((buffer = mmal_queue_get(pool_in->queue)) != NULL)
+      {
+         SOURCE_READ_DATA_INTO_BUFFER(buffer);
+         if (!buffer->length)
+            break;
+
+         fprintf(stderr, "sending %i bytes\n", (int)buffer->length);
+         status = mmal_port_send_buffer(decoder->input[0], buffer);
+         CHECK_STATUS(status, "failed to send buffer");
+      }
+
+      /* Get our decoded frames */
+      while ((buffer = mmal_queue_get(context.queue)) != NULL)
+      {
+         /* We have a frame, do something with it (why not display it for instance?).
+          * Once we're done with it, we release it. It will automatically go back
+          * to its original pool so it can be reused for a new video frame.
+          */
+         fprintf(stderr, "decoded frame\n");
+         mmal_buffer_header_release(buffer);
+      }
+
+      /* Send empty buffers to the output port of the decoder */
+      while ((buffer = mmal_queue_get(pool_out->queue)) != NULL)
+      {
+         status = mmal_port_send_buffer(decoder->output[0], buffer);
+         CHECK_STATUS(status, "failed to send buffer");
+      }
+   }
+
+   /* Stop decoding */
+   fprintf(stderr, "stop decoding\n");
+
+   /* Stop everything. Not strictly necessary since mmal_component_destroy()
+    * will do that anyway */
+   mmal_port_disable(decoder->input[0]);
+   mmal_port_disable(decoder->output[0]);
+   mmal_component_disable(decoder);
+
+ error:
+   /* Cleanup everything */
+   if (decoder)
+      mmal_component_destroy(decoder);
+   if (pool_in)
+      mmal_pool_destroy(pool_in);
+   if (pool_out)
+      mmal_pool_destroy(pool_out);
+   if (context.queue)
+      mmal_queue_destroy(context.queue);
+
+   SOURCE_CLOSE();
+   vcos_semaphore_delete(&context.semaphore);
+   return status == MMAL_SUCCESS ? 0 : -1;
+}
diff --git a/interface/mmal/test/examples/example_basic_2.c b/interface/mmal/test/examples/example_basic_2.c
new file mode 100755 (executable)
index 0000000..cc474f2
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "bcm_host.h"
+#include "mmal.h"
+#include "util/mmal_default_components.h"
+#include "util/mmal_util_params.h"
+#include "util/mmal_util.h"
+#include "interface/vcos/vcos.h"
+#include <stdio.h>
+
+#define CHECK_STATUS(status, msg) if (status != MMAL_SUCCESS) { fprintf(stderr, msg"\n"); goto error; }
+
+static uint8_t codec_header_bytes[512];
+static unsigned int codec_header_bytes_size = sizeof(codec_header_bytes);
+
+static FILE *source_file;
+
+/* Macros abstracting the I/O, just to make the example code clearer */
+#define SOURCE_OPEN(uri) \
+   source_file = fopen(uri, "rb"); if (!source_file) goto error;
+#define SOURCE_READ_CODEC_CONFIG_DATA(bytes, size) \
+   size = fread(bytes, 1, size, source_file); rewind(source_file)
+#define SOURCE_READ_DATA_INTO_BUFFER(a) \
+   a->length = fread(a->data, 1, a->alloc_size - 128, source_file); \
+   a->offset = 0
+#define SOURCE_CLOSE() \
+   if (source_file) fclose(source_file)
+
+/** Context for our application */
+static struct CONTEXT_T {
+   VCOS_SEMAPHORE_T semaphore;
+   MMAL_QUEUE_T *queue;
+   MMAL_STATUS_T status;
+} context;
+
+static void log_video_format(MMAL_ES_FORMAT_T *format)
+{
+   if (format->type != MMAL_ES_TYPE_VIDEO)
+      return;
+
+   fprintf(stderr, "fourcc: %4.4s, width: %i, height: %i, (%i,%i,%i,%i)\n",
+            (char *)&format->encoding,
+            format->es->video.width, format->es->video.height,
+            format->es->video.crop.x, format->es->video.crop.y,
+            format->es->video.crop.width, format->es->video.crop.height);
+}
+
+/** Callback from the control port.
+ * Component is sending us an event. */
+static void control_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   struct CONTEXT_T *ctx = (struct CONTEXT_T *)port->userdata;
+
+   switch (buffer->cmd)
+   {
+   case MMAL_EVENT_EOS:
+      /* Only sink component generate EOS events */
+      break;
+   case MMAL_EVENT_ERROR:
+      /* Something went wrong. Signal this to the application */
+      ctx->status = *(MMAL_STATUS_T *)buffer->data;
+      break;
+   default:
+      break;
+   }
+
+   /* Done with the event, recycle it */
+   mmal_buffer_header_release(buffer);
+
+   /* Kick the processing thread */
+   vcos_semaphore_post(&ctx->semaphore);
+}
+
+/** Callback from the input port.
+ * Buffer has been consumed and is available to be used again. */
+static void input_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   struct CONTEXT_T *ctx = (struct CONTEXT_T *)port->userdata;
+
+   /* The decoder is done with the data, just recycle the buffer header into its pool */
+   mmal_buffer_header_release(buffer);
+
+   /* Kick the processing thread */
+   vcos_semaphore_post(&ctx->semaphore);
+}
+
+/** Callback from the output port.
+ * Buffer has been produced by the port and is available for processing. */
+static void output_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   struct CONTEXT_T *ctx = (struct CONTEXT_T *)port->userdata;
+
+   /* Queue the decoded video frame */
+   mmal_queue_put(ctx->queue, buffer);
+
+   /* Kick the processing thread */
+   vcos_semaphore_post(&ctx->semaphore);
+}
+
+int main(int argc, char **argv)
+{
+   MMAL_STATUS_T status = MMAL_EINVAL;
+   MMAL_COMPONENT_T *decoder = 0;
+   MMAL_POOL_T *pool_in = 0, *pool_out = 0;
+   MMAL_BOOL_T eos_sent = MMAL_FALSE, eos_received = MMAL_FALSE;
+   unsigned int count;
+
+   if (argc < 2)
+   {
+      fprintf(stderr, "invalid arguments\n");
+      return -1;
+   }
+
+   bcm_host_init();
+
+   vcos_semaphore_create(&context.semaphore, "example", 1);
+
+   SOURCE_OPEN(argv[1]);
+
+   /* Create the decoder component.
+    * This specific component exposes 2 ports (1 input and 1 output). Like most components
+    * its expects the format of its input port to be set by the client in order for it to
+    * know what kind of data it will be fed. */
+   status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, &decoder);
+   CHECK_STATUS(status, "failed to create decoder");
+
+   /* Enable control port so we can receive events from the component */
+   decoder->control->userdata = (void *)&context;
+   status = mmal_port_enable(decoder->control, control_callback);
+   CHECK_STATUS(status, "failed to enable control port");
+
+   /* Get statistics on the input port */
+   MMAL_PARAMETER_CORE_STATISTICS_T stats = {{0}};
+   stats.hdr.id = MMAL_PARAMETER_CORE_STATISTICS;
+   stats.hdr.size = sizeof(MMAL_PARAMETER_CORE_STATISTICS_T);
+   status = mmal_port_parameter_get(decoder->input[0], &stats.hdr);
+   CHECK_STATUS(status, "failed to get stats");
+   fprintf(stderr, "stats: %i, %i", stats.stats.buffer_count, stats.stats.max_delay);
+
+   /* Set the zero-copy parameter on the input port */
+   MMAL_PARAMETER_BOOLEAN_T zc = {{MMAL_PARAMETER_ZERO_COPY, sizeof(zc)}, MMAL_TRUE};
+   status = mmal_port_parameter_set(decoder->input[0], &zc.hdr);
+   fprintf(stderr, "status: %i\n", status);
+
+   /* Set the zero-copy parameter on the output port */
+   status = mmal_port_parameter_set_boolean(decoder->output[0], MMAL_PARAMETER_ZERO_COPY, MMAL_TRUE);
+   fprintf(stderr, "status: %i\n", status);
+
+   /* Set format of video decoder input port */
+   MMAL_ES_FORMAT_T *format_in = decoder->input[0]->format;
+   format_in->type = MMAL_ES_TYPE_VIDEO;
+   format_in->encoding = MMAL_ENCODING_H264;
+   format_in->es->video.width = 1280;
+   format_in->es->video.height = 720;
+   format_in->es->video.frame_rate.num = 30;
+   format_in->es->video.frame_rate.den = 1;
+   format_in->es->video.par.num = 1;
+   format_in->es->video.par.den = 1;
+   /* If the data is known to be framed then the following flag should be set:
+    * format_in->flags |= MMAL_ES_FORMAT_FLAG_FRAMED; */
+
+   SOURCE_READ_CODEC_CONFIG_DATA(codec_header_bytes, codec_header_bytes_size);
+   status = mmal_format_extradata_alloc(format_in, codec_header_bytes_size);
+   CHECK_STATUS(status, "failed to allocate extradata");
+   format_in->extradata_size = codec_header_bytes_size;
+   if (format_in->extradata_size)
+      memcpy(format_in->extradata, codec_header_bytes, format_in->extradata_size);
+
+   status = mmal_port_format_commit(decoder->input[0]);
+   CHECK_STATUS(status, "failed to commit format");
+
+   /* Our decoder can do internal colour conversion, ask for a conversion to RGB565 */
+   MMAL_ES_FORMAT_T *format_out = decoder->output[0]->format;
+   format_out->encoding = MMAL_ENCODING_RGB16;
+   status = mmal_port_format_commit(decoder->output[0]);
+   CHECK_STATUS(status, "failed to commit format");
+
+   /* Display the output port format */
+   fprintf(stderr, "%s\n", decoder->output[0]->name);
+   fprintf(stderr, " type: %i, fourcc: %4.4s\n", format_out->type, (char *)&format_out->encoding);
+   fprintf(stderr, " bitrate: %i, framed: %i\n", format_out->bitrate,
+           !!(format_out->flags & MMAL_ES_FORMAT_FLAG_FRAMED));
+   fprintf(stderr, " extra data: %i, %p\n", format_out->extradata_size, format_out->extradata);
+   fprintf(stderr, " width: %i, height: %i, (%i,%i,%i,%i)\n",
+           format_out->es->video.width, format_out->es->video.height,
+           format_out->es->video.crop.x, format_out->es->video.crop.y,
+           format_out->es->video.crop.width, format_out->es->video.crop.height);
+
+   /* The format of both ports is now set so we can get their buffer requirements and create
+    * our buffer headers. We use the buffer pool API to create these. */
+   decoder->input[0]->buffer_num = decoder->input[0]->buffer_num_min;
+   decoder->input[0]->buffer_size = decoder->input[0]->buffer_size_min;
+   decoder->output[0]->buffer_num = decoder->output[0]->buffer_num_min;
+   decoder->output[0]->buffer_size = decoder->output[0]->buffer_size_min;
+   pool_in = mmal_port_pool_create(decoder->output[0],
+                                   decoder->input[0]->buffer_num,
+                                   decoder->input[0]->buffer_size);
+   pool_out = mmal_port_pool_create(decoder->output[0],
+                                    decoder->output[0]->buffer_num,
+                                    decoder->output[0]->buffer_size);
+
+   /* Create a queue to store our decoded video frames. The callback we will get when
+    * a frame has been decoded will put the frame into this queue. */
+   context.queue = mmal_queue_create();
+
+   /* Store a reference to our context in each port (will be used during callbacks) */
+   decoder->input[0]->userdata = (void *)&context;
+   decoder->output[0]->userdata = (void *)&context;
+
+   /* Enable all the input port and the output port.
+    * The callback specified here is the function which will be called when the buffer header
+    * we sent to the component has been processed. */
+   status = mmal_port_enable(decoder->input[0], input_callback);
+   CHECK_STATUS(status, "failed to enable input port");
+   status = mmal_port_enable(decoder->output[0], output_callback);
+   CHECK_STATUS(status, "failed to enable output port");
+
+   /* Component won't start processing data until it is enabled. */
+   status = mmal_component_enable(decoder);
+   CHECK_STATUS(status, "failed to enable component");
+
+   /* Start decoding */
+   fprintf(stderr, "start decoding\n");
+
+   /* This is the main processing loop */
+   for (count = 0; !eos_received && count < 500; count++)
+   {
+      MMAL_BUFFER_HEADER_T *buffer;
+
+      /* Wait for buffer headers to be available on either of the decoder ports */
+      vcos_semaphore_wait(&context.semaphore);
+
+      /* Check for errors */
+      if (context.status != MMAL_SUCCESS)
+      {
+         fprintf(stderr, "Aborting due to error\n");
+         break;
+      }
+
+      /* Send data to decode to the input port of the video decoder */
+      if (!eos_sent && (buffer = mmal_queue_get(pool_in->queue)) != NULL)
+      {
+         SOURCE_READ_DATA_INTO_BUFFER(buffer);
+         if(!buffer->length) eos_sent = MMAL_TRUE;
+
+         buffer->flags = buffer->length ? 0 : MMAL_BUFFER_HEADER_FLAG_EOS;
+         buffer->pts = buffer->dts = MMAL_TIME_UNKNOWN;
+         fprintf(stderr, "sending %i bytes\n", (int)buffer->length);
+         status = mmal_port_send_buffer(decoder->input[0], buffer);
+         CHECK_STATUS(status, "failed to send buffer");
+      }
+
+      /* Get our decoded frames */
+      while ((buffer = mmal_queue_get(context.queue)) != NULL)
+      {
+         /* We have a frame, do something with it (why not display it for instance?).
+          * Once we're done with it, we release it. It will automatically go back
+          * to its original pool so it can be reused for a new video frame.
+          */
+         eos_received = buffer->flags & MMAL_BUFFER_HEADER_FLAG_EOS;
+
+         if (buffer->cmd)
+         {
+            fprintf(stderr, "received event %4.4s\n", (char *)&buffer->cmd);
+            if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED)
+            {
+               MMAL_EVENT_FORMAT_CHANGED_T *event = mmal_event_format_changed_get(buffer);
+               if (event)
+               {
+                  fprintf(stderr, "----------Port format changed----------\n");
+                  log_video_format(decoder->output[0]->format);
+                  fprintf(stderr, "-----------------to---------------------\n");
+                  log_video_format(event->format);
+                  fprintf(stderr, " buffers num (opt %i, min %i), size (opt %i, min: %i)\n",
+                           event->buffer_num_recommended, event->buffer_num_min,
+                           event->buffer_size_recommended, event->buffer_size_min);
+                  fprintf(stderr, "----------------------------------------\n");
+               }
+
+               //Assume we can't reuse the buffers, so have to disable, destroy
+               //pool, create new pool, enable port, feed in buffers.
+               status = mmal_port_disable(decoder->output[0]);
+               CHECK_STATUS(status, "failed to disable port");
+
+               //Clear the queue of all buffers
+               while(mmal_queue_length(pool_out->queue) != pool_out->headers_num)
+               {
+                  MMAL_BUFFER_HEADER_T *buf;
+                  fprintf(stderr, "Wait for buffers to be returned. Have %d of %d buffers\n",
+                        mmal_queue_length(pool_out->queue), pool_out->headers_num);
+                  vcos_semaphore_wait(&context.semaphore);
+                  fprintf(stderr, "Got semaphore\n");
+                  buf = mmal_queue_get(context.queue);
+                  mmal_buffer_header_release(buf);
+               }
+               fprintf(stderr, "Got all buffers\n");
+
+               mmal_port_pool_destroy(decoder->output[0], pool_out);
+               status = mmal_format_full_copy(decoder->output[0]->format, event->format);
+               CHECK_STATUS(status, "failed to copy port format");
+               status = mmal_port_format_commit(decoder->output[0]);
+               CHECK_STATUS(status, "failed to commit port format");
+
+               pool_out = mmal_port_pool_create(decoder->output[0],
+                                    decoder->output[0]->buffer_num,
+                                    decoder->output[0]->buffer_size);
+
+               status = mmal_port_enable(decoder->output[0], output_callback);
+               CHECK_STATUS(status, "failed to enable port");
+               //Allow the following loop to send all the buffers back to the decoder
+            }
+
+         }
+         else
+            fprintf(stderr, "decoded frame (flags %x)\n", buffer->flags);
+         mmal_buffer_header_release(buffer);
+      }
+
+      /* Send empty buffers to the output port of the decoder */
+      while ((buffer = mmal_queue_get(pool_out->queue)) != NULL)
+      {
+         status = mmal_port_send_buffer(decoder->output[0], buffer);
+         CHECK_STATUS(status, "failed to send buffer");
+      }
+   }
+
+   /* Stop decoding */
+   fprintf(stderr, "stop decoding - count %d, eos_received %d\n", count, eos_received);
+
+   /* Stop everything. Not strictly necessary since mmal_component_destroy()
+    * will do that anyway */
+   mmal_port_disable(decoder->input[0]);
+   mmal_port_disable(decoder->output[0]);
+   mmal_component_disable(decoder);
+
+ error:
+   /* Cleanup everything */
+   if (pool_in)
+      mmal_port_pool_destroy(decoder->input[0], pool_in);
+   if (pool_out)
+      mmal_port_pool_destroy(decoder->output[0], pool_out);
+   if (decoder)
+      mmal_component_destroy(decoder);
+   if (context.queue)
+      mmal_queue_destroy(context.queue);
+
+   SOURCE_CLOSE();
+   vcos_semaphore_delete(&context.semaphore);
+   return status == MMAL_SUCCESS ? 0 : -1;
+}
diff --git a/interface/mmal/test/examples/example_connections.c b/interface/mmal/test/examples/example_connections.c
new file mode 100755 (executable)
index 0000000..51b585b
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "bcm_host.h"
+
+#include "mmal.h"
+#include "util/mmal_connection.h"
+#include "util/mmal_default_components.h"
+#include "util/mmal_util_params.h"
+#include "interface/vcos/vcos.h"
+#include <stdio.h>
+
+#define CHECK_STATUS(status, msg) if (status != MMAL_SUCCESS) { fprintf(stderr, msg"\n"); goto error; }
+
+/** Context for our application */
+static struct CONTEXT_T {
+   VCOS_SEMAPHORE_T semaphore;
+   MMAL_STATUS_T status;
+   MMAL_BOOL_T eos;
+} context;
+
+/** Callback from a control port. Error and EOS events stop playback. */
+static void control_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   struct CONTEXT_T *ctx = (struct CONTEXT_T *)port->userdata;
+
+   if (buffer->cmd == MMAL_EVENT_ERROR)
+      ctx->status = *(MMAL_STATUS_T *)buffer->data;
+   else if (buffer->cmd == MMAL_EVENT_EOS)
+      ctx->eos = MMAL_TRUE;
+
+   mmal_buffer_header_release(buffer);
+
+   /* The processing is done in our main thread */
+   vcos_semaphore_post(&ctx->semaphore);
+}
+
+/** Callback from the connection. Buffer is available. */
+static void connection_callback(MMAL_CONNECTION_T *connection)
+{
+   struct CONTEXT_T *ctx = (struct CONTEXT_T *)connection->user_data;
+
+   /* The processing is done in our main thread */
+   vcos_semaphore_post(&ctx->semaphore);
+}
+
+int main(int argc, char **argv)
+{
+   MMAL_STATUS_T status;
+   MMAL_COMPONENT_T *reader = 0, *decoder = 0, *renderer = 0;
+   MMAL_CONNECTION_T *connection[2] = {0};
+   unsigned int i, count, connection_num = vcos_countof(connection);
+
+   if (argc < 2)
+   {
+      fprintf(stderr, "invalid arguments\n");
+      return -1;
+   }
+
+   bcm_host_init();
+
+   vcos_semaphore_create(&context.semaphore, "example", 1);
+
+   /* Create the components */
+   status = mmal_component_create(MMAL_COMPONENT_DEFAULT_CONTAINER_READER, &reader);
+   CHECK_STATUS(status, "failed to create reader");
+   reader->control->userdata = (void *)&context;
+   status = mmal_port_enable(reader->control, control_callback);
+   CHECK_STATUS(status, "failed to enable control port");
+   status = mmal_component_enable(reader);
+   CHECK_STATUS(status, "failed to enable component");
+
+   status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, &decoder);
+   CHECK_STATUS(status, "failed to create decoder");
+   decoder->control->userdata = (void *)&context;
+   status = mmal_port_enable(decoder->control, control_callback);
+   CHECK_STATUS(status, "failed to enable control port");
+   status = mmal_component_enable(decoder);
+   CHECK_STATUS(status, "failed to enable component");
+
+   status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, &renderer);
+   CHECK_STATUS(status, "failed to create renderer");
+   renderer->control->userdata = (void *)&context;
+   status = mmal_port_enable(renderer->control, control_callback);
+   CHECK_STATUS(status, "failed to enable control port");
+   status = mmal_component_enable(renderer);
+   CHECK_STATUS(status, "failed to enable component");
+
+   /* Configure the reader using the given URI */
+   status = mmal_util_port_set_uri(reader->control, argv[1]);
+   CHECK_STATUS(status, "failed to set uri");
+
+   /* Create the connections between the components */
+   status = mmal_connection_create(&connection[0], reader->output[0], decoder->input[0], 0);
+   CHECK_STATUS(status, "failed to create connection between reader / decoder");
+   connection[0]->user_data = &context;
+   connection[0]->callback = connection_callback;
+   status = mmal_connection_create(&connection[1], decoder->output[0], renderer->input[0], 0);
+   CHECK_STATUS(status, "failed to create connection between decoder / renderer");
+   connection[1]->user_data = &context;
+   connection[1]->callback = connection_callback;
+
+   /* Enable all our connections */
+   for (i = connection_num; i; i--)
+   {
+      status = mmal_connection_enable(connection[i-1]);
+      CHECK_STATUS(status, "failed to enable connection");
+   }
+
+   /* Start playback */
+   fprintf(stderr, "start playback\n");
+
+   /* This is the main processing loop */
+   for (count = 0; count < 500; count++)
+   {
+      MMAL_BUFFER_HEADER_T *buffer;
+      vcos_semaphore_wait(&context.semaphore);
+
+      /* Check for errors */
+      status = context.status;
+      CHECK_STATUS(status, "error during playback");
+
+      /* Check for end of stream */
+      if (context.eos)
+         break;
+
+      /* Handle buffers for all our connections */
+      for (i = 0; i < connection_num; i++)
+      {
+         if (connection[i]->flags & MMAL_CONNECTION_FLAG_TUNNELLING)
+            continue; /* Nothing else to do in tunnelling mode */
+
+         /* Send empty buffers to the output port of the connection */
+         while ((buffer = mmal_queue_get(connection[i]->pool->queue)) != NULL)
+         {
+            status = mmal_port_send_buffer(connection[i]->out, buffer);
+            CHECK_STATUS(status, "failed to send buffer");
+         }
+
+         /* Send any queued buffer to the next component */
+         while ((buffer = mmal_queue_get(connection[i]->queue)) != NULL)
+         {
+            status = mmal_port_send_buffer(connection[i]->in, buffer);
+            CHECK_STATUS(status, "failed to send buffer");
+         }
+      }
+   }
+
+   /* Stop everything */
+   fprintf(stderr, "stop playback\n");
+   for (i = 0; i < connection_num; i++)
+   {
+      mmal_connection_disable(connection[i]);
+   }
+
+ error:
+   /* Cleanup everything */
+   for (i = 0; i < connection_num; i++)
+   {
+      if (connection[i])
+         mmal_connection_destroy(connection[i]);
+   }
+   if (reader)
+      mmal_component_destroy(reader);
+   if (decoder)
+      mmal_component_destroy(decoder);
+   if (renderer)
+      mmal_component_destroy(renderer);
+
+   vcos_semaphore_delete(&context.semaphore);
+   return status == MMAL_SUCCESS ? 0 : -1;
+}
diff --git a/interface/mmal/test/examples/example_graph.c b/interface/mmal/test/examples/example_graph.c
new file mode 100755 (executable)
index 0000000..731bbb9
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "bcm_host.h"
+#include "mmal.h"
+#include "util/mmal_graph.h"
+#include "util/mmal_default_components.h"
+#include "util/mmal_util_params.h"
+#include <stdio.h>
+
+#define CHECK_STATUS(status, msg) if (status != MMAL_SUCCESS) { fprintf(stderr, msg"\n"); goto error; }
+
+int main(int argc, char **argv)
+{
+   MMAL_STATUS_T status;
+   MMAL_GRAPH_T *graph = 0;
+   MMAL_COMPONENT_T *reader = 0, *decoder = 0, *renderer = 0;
+
+   if (argc < 2)
+   {
+      fprintf(stderr, "invalid arguments\n");
+      return -1;
+   }
+
+   bcm_host_init();
+
+   /* Create the graph */
+   status = mmal_graph_create(&graph, 0);
+   CHECK_STATUS(status, "failed to create graph");
+
+   /* Add the components */
+   status = mmal_graph_new_component(graph, MMAL_COMPONENT_DEFAULT_CONTAINER_READER, &reader);
+   CHECK_STATUS(status, "failed to create reader");
+
+   status = mmal_graph_new_component(graph, MMAL_COMPONENT_DEFAULT_VIDEO_DECODER, &decoder);
+   CHECK_STATUS(status, "failed to create decoder");
+
+   status = mmal_graph_new_component(graph, MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, &renderer);
+   CHECK_STATUS(status, "failed to create renderer");
+
+   /* Configure the reader using the given URI */
+   status = mmal_util_port_set_uri(reader->control, argv[1]);
+   CHECK_STATUS(status, "failed to set uri");
+
+   /* connect them up - this propagates port settings from outputs to inputs */
+   status = mmal_graph_new_connection(graph, reader->output[0], decoder->input[0], 0, NULL);
+   CHECK_STATUS(status, "failed to connect reader to decoder");
+   status = mmal_graph_new_connection(graph, decoder->output[0], renderer->input[0], 0, NULL);
+   CHECK_STATUS(status, "failed to connect decoder to renderer");
+
+   /* Start playback */
+   fprintf(stderr, "start playback\n");
+   status = mmal_graph_enable(graph, NULL, NULL);
+   CHECK_STATUS(status, "failed to enable graph");
+
+   sleep(5);
+
+   /* Stop everything */
+   fprintf(stderr, "stop playback\n");
+   mmal_graph_disable(graph);
+
+ error:
+   /* Cleanup everything */
+   if (reader)
+      mmal_component_release(reader);
+   if (decoder)
+      mmal_component_release(decoder);
+   if (renderer)
+      mmal_component_release(renderer);
+   if (graph)
+      mmal_graph_destroy(graph);
+
+   return status == MMAL_SUCCESS ? 0 : -1;
+}
diff --git a/interface/mmal/util/CMakeLists.txt b/interface/mmal/util/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..b2a6858
--- /dev/null
@@ -0,0 +1,28 @@
+add_library (mmal_util ${LIBRARY_TYPE}
+   mmal_il.c
+   mmal_util.c
+   mmal_connection.c
+   mmal_graph.c
+   mmal_list.c
+   mmal_param_convert.c
+   mmal_util_params.c
+   mmal_component_wrapper.c
+   mmal_util_rational.c
+)
+
+target_link_libraries (mmal_util vcos)
+
+install(TARGETS mmal_util DESTINATION lib)
+install(FILES
+   mmal_component_wrapper.h
+   mmal_connection.h
+   mmal_default_components.h
+   mmal_graph.h
+   mmal_il.h
+   mmal_list.h
+   mmal_param_convert.h
+   mmal_util.h
+   mmal_util_params.h
+   mmal_util_rational.h
+   DESTINATION include/interface/mmal/util
+)
diff --git a/interface/mmal/util/mmal_component_wrapper.c b/interface/mmal/util/mmal_component_wrapper.c
new file mode 100755 (executable)
index 0000000..daf5e31
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "util/mmal_util.h"
+#include "util/mmal_component_wrapper.h"
+#include "mmal_logging.h"
+#include <stdio.h>
+
+typedef struct
+{
+   MMAL_WRAPPER_T wrapper; /**< Must be the first member! */
+
+   VCOS_SEMAPHORE_T sema;
+
+} MMAL_WRAPPER_PRIVATE_T;
+
+/** Callback from a control port. Error events will be received there. */
+static void mmal_wrapper_control_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_WRAPPER_PRIVATE_T *private = (MMAL_WRAPPER_PRIVATE_T *)port->userdata;
+   LOG_TRACE("%s(%p),%p,%4.4s", port->name, port, buffer, (char *)&buffer->cmd);
+
+   if (buffer->cmd == MMAL_EVENT_ERROR)
+   {
+      private->wrapper.status = *(MMAL_STATUS_T *)buffer->data;
+      mmal_buffer_header_release(buffer);
+
+      vcos_semaphore_post(&private->sema);
+
+      if (private->wrapper.callback)
+         private->wrapper.callback(&private->wrapper);
+      return;
+   }
+
+   mmal_buffer_header_release(buffer);
+}
+
+/** Callback from an input port. Buffer is released. */
+static void mmal_wrapper_bh_in_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_PARAM_UNUSED(port);
+   LOG_TRACE("(%s)%p,%p,%p,%i", port->name, port, buffer, buffer->data, (int)buffer->length);
+
+   /* We're done with the buffer, just recycle it */
+   mmal_buffer_header_release(buffer);
+}
+
+/** Callback from an output port. Buffer is queued for the next component. */
+static void mmal_wrapper_bh_out_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_WRAPPER_PRIVATE_T *private = (MMAL_WRAPPER_PRIVATE_T *)port->userdata;
+   LOG_TRACE("(%s)%p,%p,%p,%i", port->name, port, buffer, buffer->data, (int)buffer->length);
+
+   /* Queue the buffer produced by the output port */
+   mmal_queue_put(private->wrapper.output_queue[port->index], buffer);
+   vcos_semaphore_post(&private->sema);
+
+   if (private->wrapper.callback)
+      private->wrapper.callback(&private->wrapper);
+}
+
+/** Callback from the pool. Buffer is available. */
+static MMAL_BOOL_T mmal_wrapper_bh_release_cb(MMAL_POOL_T *pool, MMAL_BUFFER_HEADER_T *buffer,
+   void *userdata)
+{
+   MMAL_WRAPPER_PRIVATE_T *private = (MMAL_WRAPPER_PRIVATE_T *)userdata;
+
+   mmal_queue_put(pool->queue, buffer);
+   vcos_semaphore_post(&private->sema);
+
+   if (private->wrapper.callback)
+      private->wrapper.callback(&private->wrapper);
+
+   return 0;
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_wrapper_destroy(MMAL_WRAPPER_T *wrapper)
+{
+   MMAL_WRAPPER_PRIVATE_T *private = (MMAL_WRAPPER_PRIVATE_T *)wrapper;
+   unsigned int i;
+
+   LOG_TRACE("%p, %s", wrapper, wrapper->component->name);
+
+   /* Cleanup resources */
+   mmal_component_destroy(wrapper->component);
+
+   for (i = 0; i < wrapper->input_num; i++)
+   {
+      if (wrapper->input_pool[i])
+         mmal_pool_destroy(wrapper->input_pool[i]);
+   }
+
+   for (i = 0; i < wrapper->output_num; i++)
+   {
+      if (wrapper->output_pool[i])
+         mmal_pool_destroy(wrapper->output_pool[i]);
+      if (wrapper->output_queue[i])
+         mmal_queue_destroy(wrapper->output_queue[i]);
+   }
+
+   vcos_semaphore_delete(&private->sema);
+   vcos_free(private);
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_wrapper_create(MMAL_WRAPPER_T **ctx, const char *name)
+{
+   MMAL_STATUS_T status;
+   MMAL_COMPONENT_T *component;
+   MMAL_WRAPPER_PRIVATE_T *private;
+   MMAL_WRAPPER_T *wrapper;
+   int64_t start_time;
+   unsigned int i, extra_size;
+
+   LOG_TRACE("wrapper %p, name %s", ctx, name);
+
+   /* Sanity checking */
+   if (!ctx || !name)
+      return MMAL_EINVAL;
+
+   start_time = vcos_getmicrosecs();
+
+   status = mmal_component_create(name, &component);
+   if (status != MMAL_SUCCESS)
+      return status;
+
+   extra_size = (component->input_num * sizeof(MMAL_POOL_T*)) + (component->output_num * (sizeof(MMAL_POOL_T*) + sizeof(MMAL_QUEUE_T*)));
+   private = vcos_calloc(1, sizeof(*private) + extra_size, "mmal wrapper");
+   if (!private)
+   {
+      mmal_component_destroy(component);
+      return MMAL_ENOMEM;
+   }
+
+   if (vcos_semaphore_create(&private->sema, "mmal wrapper", 0) != VCOS_SUCCESS)
+   {
+      mmal_component_destroy(component);
+      vcos_free(private);
+      return MMAL_ENOMEM;
+   }
+
+   wrapper = &private->wrapper;
+   wrapper->component = component;
+   wrapper->control = component->control;
+   wrapper->input_num = component->input_num;
+   wrapper->input = component->input;
+   wrapper->output_num = component->output_num;
+   wrapper->output = component->output;
+   wrapper->input_pool = (MMAL_POOL_T **)&private[1];
+   wrapper->output_pool = (MMAL_POOL_T **)&wrapper->input_pool[component->input_num];
+   wrapper->output_queue = (MMAL_QUEUE_T **)&wrapper->output_pool[component->output_num];
+
+   /* Create our pools and queues */
+   for (i = 0; i < wrapper->input_num; i++)
+   {
+      wrapper->input_pool[i] = mmal_port_pool_create(wrapper->input[i], 0, 0);
+      if (!wrapper->input_pool[i])
+         goto error;
+      mmal_pool_callback_set(wrapper->input_pool[i], mmal_wrapper_bh_release_cb, (void *)wrapper);
+
+      wrapper->input[i]->userdata = (void *)wrapper;
+   }
+   for (i = 0; i < wrapper->output_num; i++)
+   {
+      wrapper->output_pool[i] = mmal_port_pool_create(wrapper->output[i], 0, 0);
+      wrapper->output_queue[i] = mmal_queue_create();
+      if (!wrapper->output_pool[i] || !wrapper->output_queue[i])
+         goto error;
+      mmal_pool_callback_set(wrapper->output_pool[i], mmal_wrapper_bh_release_cb, (void *)wrapper);
+
+      wrapper->output[i]->userdata = (void *)wrapper;
+   }
+
+   /* Setup control port */
+   wrapper->control->userdata = (void *)wrapper;
+   status = mmal_port_enable(wrapper->control, mmal_wrapper_control_cb);
+   if (status != MMAL_SUCCESS)
+      goto error;
+
+   wrapper->time_setup = vcos_getmicrosecs() - start_time;
+   *ctx = wrapper;
+   return MMAL_SUCCESS;
+
+ error:
+   mmal_wrapper_destroy(wrapper);
+   return status == MMAL_SUCCESS ? MMAL_ENOMEM : status;
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_wrapper_port_enable(MMAL_PORT_T *port, uint32_t flags)
+{
+   MMAL_WRAPPER_PRIVATE_T *private = (MMAL_WRAPPER_PRIVATE_T *)port->userdata;
+   MMAL_WRAPPER_T *wrapper = &private->wrapper;
+   int64_t start_time = vcos_getmicrosecs();
+   uint32_t buffer_size;
+   MMAL_STATUS_T status;
+   MMAL_POOL_T *pool;
+
+   LOG_TRACE("%p, %s", wrapper, port->name);
+
+   if (port->type != MMAL_PORT_TYPE_INPUT && port->type != MMAL_PORT_TYPE_OUTPUT)
+      return MMAL_EINVAL;
+
+   if (port->is_enabled)
+      return MMAL_SUCCESS;
+
+   pool = port->type == MMAL_PORT_TYPE_INPUT ?
+      wrapper->input_pool[port->index] : wrapper->output_pool[port->index];
+   buffer_size = (flags & MMAL_WRAPPER_FLAG_PAYLOAD_ALLOCATE) ? port->buffer_size : 0;
+
+   /* FIXME: we don't support switching between shared and non-shared memory.
+    * We would need to save the flag and force a pool resize when switching. */
+   if (flags & MMAL_WRAPPER_FLAG_PAYLOAD_USE_SHARED_MEMORY)
+   {
+      MMAL_PARAMETER_BOOLEAN_T param_zc =
+         {{MMAL_PARAMETER_ZERO_COPY, sizeof(MMAL_PARAMETER_BOOLEAN_T)}, 1};
+      status = mmal_port_parameter_set(port, &param_zc.hdr);
+      if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
+      {
+         LOG_ERROR("failed to set zero copy on %s", port->name);
+         return status;
+      }
+   }
+
+   /* Resize the pool */
+   status = mmal_pool_resize(pool, port->buffer_num, buffer_size);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("could not resize pool (%i/%i)", (int)port->buffer_num, (int)buffer_size);
+      return status;
+   }
+
+   /* Enable port. The callback specified here is the function which
+    * will be called when a buffer header comes back to the port. */
+   status = mmal_port_enable(port, port->type == MMAL_PORT_TYPE_INPUT ?
+                             mmal_wrapper_bh_in_cb : mmal_wrapper_bh_out_cb);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("could not enable port");
+      return status;
+   }
+
+   wrapper->time_enable += vcos_getmicrosecs() - start_time;
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_wrapper_port_disable(MMAL_PORT_T *port)
+{
+   MMAL_WRAPPER_PRIVATE_T *private = (MMAL_WRAPPER_PRIVATE_T *)port->userdata;
+   MMAL_WRAPPER_T *wrapper = &private->wrapper;
+   int64_t start_time = vcos_getmicrosecs();
+   MMAL_STATUS_T status;
+
+   LOG_TRACE("%p, %s", wrapper, port->name);
+
+   if (port->type != MMAL_PORT_TYPE_INPUT && port->type != MMAL_PORT_TYPE_OUTPUT)
+      return MMAL_EINVAL;
+
+   if (!port->is_enabled)
+      return MMAL_SUCCESS;
+
+   /* Disable port */
+   status = mmal_port_disable(port);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("could not disable port");
+      return status;
+   }
+
+   /* Flush the queue */
+   if (port->type == MMAL_PORT_TYPE_OUTPUT)
+   {
+      MMAL_POOL_T *pool = wrapper->output_pool[port->index];
+      MMAL_QUEUE_T *queue = wrapper->output_queue[port->index];
+      MMAL_BUFFER_HEADER_T *buffer;
+
+      while ((buffer = mmal_queue_get(queue)) != NULL)
+         mmal_buffer_header_release(buffer);
+
+      if ( !vcos_verify(mmal_queue_length(pool->queue) == pool->headers_num) )
+      {
+         LOG_ERROR("coul dnot release all buffers");
+      }
+   }
+
+   wrapper->time_disable = vcos_getmicrosecs() - start_time;
+   return status;
+}
+
+/** Wait for an empty buffer to be available on a port */
+MMAL_STATUS_T mmal_wrapper_buffer_get_empty(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T **buffer,
+   uint32_t flags)
+{
+   MMAL_WRAPPER_PRIVATE_T *private = (MMAL_WRAPPER_PRIVATE_T *)port->userdata;
+   MMAL_WRAPPER_T *wrapper = &private->wrapper;
+   MMAL_POOL_T *pool;
+
+   LOG_TRACE("%p, %s", wrapper, port->name);
+
+   if (!buffer || (port->type != MMAL_PORT_TYPE_INPUT && port->type != MMAL_PORT_TYPE_OUTPUT))
+      return MMAL_EINVAL;
+
+   pool = port->type == MMAL_PORT_TYPE_INPUT ?
+      wrapper->input_pool[port->index] : wrapper->output_pool[port->index];
+
+   while (wrapper->status == MMAL_SUCCESS &&
+          (*buffer = mmal_queue_get(pool->queue)) == NULL)
+   {
+      if (!(flags & MMAL_WRAPPER_FLAG_WAIT))
+         break;
+      vcos_semaphore_wait(&private->sema);
+   }
+
+   return wrapper->status == MMAL_SUCCESS && !*buffer ? MMAL_EAGAIN : wrapper->status;
+}
+
+/** Wait for a full buffer to be available on a port */
+MMAL_STATUS_T mmal_wrapper_buffer_get_full(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T **buffer,
+   uint32_t flags)
+{
+   MMAL_WRAPPER_PRIVATE_T *private = (MMAL_WRAPPER_PRIVATE_T *)port->userdata;
+   MMAL_WRAPPER_T *wrapper = &private->wrapper;
+   MMAL_QUEUE_T *queue;
+
+   LOG_TRACE("%p, %s", wrapper, port->name);
+
+   if (!buffer || port->type != MMAL_PORT_TYPE_OUTPUT)
+      return MMAL_EINVAL;
+   queue = wrapper->output_queue[port->index];
+
+   while (wrapper->status == MMAL_SUCCESS &&
+          (*buffer = mmal_queue_get(queue)) == NULL)
+   {
+      if (!(flags & MMAL_WRAPPER_FLAG_WAIT))
+         break;
+      vcos_semaphore_wait(&private->sema);
+   }
+
+   return wrapper->status == MMAL_SUCCESS && !*buffer ? MMAL_EAGAIN : wrapper->status;
+}
diff --git a/interface/mmal/util/mmal_component_wrapper.h b/interface/mmal/util/mmal_component_wrapper.h
new file mode 100755 (executable)
index 0000000..ce29ae6
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_WRAPPER_H
+#define MMAL_WRAPPER_H
+
+/** \defgroup MmalComponentWrapper utility
+ * \ingroup MmalUtilities
+ * The component wrapper utility functions can be used in place of common sequences
+ * of calls to the MMAL API in order to control a standalone component. It hides some
+ * of the complexity in using standalone components behind a fully synchronous
+ * interface.
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Forward type definition for a wrapper */
+typedef struct MMAL_WRAPPER_T MMAL_WRAPPER_T;
+
+/** Definition of the callback used by a wrapper to signal back to the client
+ * that a buffer header is available either in the pool or in the output queue.
+ *
+ * @param wrapper Pointer to the wrapper
+ */
+typedef void (*MMAL_WRAPPER_CALLBACK_T)(MMAL_WRAPPER_T *wrapper);
+
+/** Structure describing a wrapper around a component */
+struct MMAL_WRAPPER_T {
+
+   void *user_data;           /**< Field reserved for use by the client. */
+   MMAL_WRAPPER_CALLBACK_T callback; /**< Callback set by the client. */
+   MMAL_COMPONENT_T *component;
+   MMAL_STATUS_T status;
+
+   MMAL_PORT_T *control;        /**< Control port (Read Only). */
+
+   uint32_t    input_num;       /**< Number of input ports (Read Only). */
+   MMAL_PORT_T **input;         /**< Array of input ports (Read Only). */
+   MMAL_POOL_T **input_pool;    /**< Array of input pools (Read Only). */
+
+   uint32_t    output_num;      /**< Number of output ports (Read Only). */
+   MMAL_PORT_T **output;        /**< Array of output ports (Read Only). */
+   MMAL_POOL_T **output_pool;   /**< Array of output pools (Read Only). */
+   MMAL_QUEUE_T **output_queue; /**< Array of output queues (Read Only). */
+
+   /* Used for debug / statistics */
+   int64_t time_setup;          /**< Time in microseconds taken to setup the connection. */
+   int64_t time_enable;         /**< Time in microseconds taken to enable the connection. */
+   int64_t time_disable;        /**< Time in microseconds taken to disable the connection. */
+
+};
+
+/** Create a wrapper around a component.
+ * The wrapper shall include a pool of buffer headers for each port. The pools will be suitable
+ * for the current format of its associated port.
+ *
+ * @param wrapper    The address of a wrapper pointer that will be set to point to the created
+ *                   wrapper.
+ * @param name       The name of the component to create.
+ * @return MMAL_SUCCESS on success.
+ */
+MMAL_STATUS_T mmal_wrapper_create(MMAL_WRAPPER_T **wrapper, const char *name);
+
+/** \name MMAL wrapper flags
+ * \anchor wrapperflags
+ */
+/* @{ */
+/** The operation should be blocking */
+#define MMAL_WRAPPER_FLAG_WAIT 1
+/** The pool for the port should allocate memory for the payloads */
+#define MMAL_WRAPPER_FLAG_PAYLOAD_ALLOCATE 2
+/** The port will use shared memory payloads */
+#define MMAL_WRAPPER_FLAG_PAYLOAD_USE_SHARED_MEMORY 4
+/* @} */
+
+/** Enable a port on a component wrapper.
+ *
+ * @param port port to enable
+ * @param flags used to specify payload allocation flags for the pool
+ * @return MMAL_SUCCESS on success.
+ */
+MMAL_STATUS_T mmal_wrapper_port_enable(MMAL_PORT_T *port, uint32_t flags);
+
+/** Disable a port on a component wrapper.
+ *
+ * @param port port to disable
+ * @return MMAL_SUCCESS on success.
+ */
+MMAL_STATUS_T mmal_wrapper_port_disable(MMAL_PORT_T *port);
+
+/** Wait for an empty buffer to be available on a port.
+ *
+ * @param port port to get an empty buffer from
+ * @param buffer points to the retreived buffer on return
+ * @param flags specify MMAL_WRAPPER_FLAG_WAIT for a blocking operation
+ * @return MMAL_SUCCESS on success.
+ */
+MMAL_STATUS_T mmal_wrapper_buffer_get_empty(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T **buffer, uint32_t flags);
+
+/** Wait for a full buffer to be available on a port.
+ *
+ * @param port port to get a full buffer from
+ * @param buffer points to the retreived buffer on return
+ * @param flags specify MMAL_WRAPPER_FLAG_WAIT for a blocking operation
+ * @return MMAL_SUCCESS on success.
+ */
+MMAL_STATUS_T mmal_wrapper_buffer_get_full(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T **buffer, uint32_t flags);
+
+/** Cancel any ongoing blocking operation on a component wrapper.
+ *
+ * @param wrapper The wrapper on which to cancel operations.
+ * @return MMAL_SUCCESS on success.
+ */
+MMAL_STATUS_T mmal_wrapper_cancel(MMAL_WRAPPER_T *wrapper);
+
+/** Destroy a wrapper.
+ * Destroys a component wrapper and any resources it owns.
+ *
+ * @param wrapper The wrapper to be destroyed.
+ * @return MMAL_SUCCESS on success.
+ */
+MMAL_STATUS_T mmal_wrapper_destroy(MMAL_WRAPPER_T *wrapper);
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+#endif /* MMAL_WRAPPER_H */
diff --git a/interface/mmal/util/mmal_connection.c b/interface/mmal/util/mmal_connection.c
new file mode 100755 (executable)
index 0000000..485ba77
--- /dev/null
@@ -0,0 +1,529 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "util/mmal_util.h"
+#include "util/mmal_connection.h"
+#include "mmal_logging.h"
+#include <stdio.h>
+
+#define CONNECTION_NAME_FORMAT "%s:%.2222s:%i/%s:%.2222s:%i"
+
+typedef struct
+{
+   MMAL_CONNECTION_T connection; /**< Must be the first member! */
+   MMAL_PORT_T *pool_port;       /**< Port used to create the pool */
+
+   /** Reference counting */
+   int refcount;
+
+} MMAL_CONNECTION_PRIVATE_T;
+
+/** Callback from a clock port. Buffer is immediately sent to next component. */
+static void mmal_connection_bh_clock_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   MMAL_CONNECTION_T *connection = (MMAL_CONNECTION_T *)port->userdata;
+   MMAL_PORT_T *other_port = (port == connection->in) ? connection->out : connection->in;
+
+   LOG_TRACE("(%s)%p,%p,%p,%i", port->name, port, buffer, buffer->data, (int)buffer->length);
+
+   if (other_port->is_enabled)
+   {
+      status = mmal_port_send_buffer(other_port, buffer);
+      if (status != MMAL_SUCCESS)
+      {
+         LOG_ERROR("error sending buffer to clock port (%i)", status);
+         mmal_buffer_header_release(buffer);
+      }
+   }
+   else
+   {
+      mmal_buffer_header_release(buffer);
+   }
+}
+
+/** Callback from an input port. Buffer is released. */
+static void mmal_connection_bh_in_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   LOG_TRACE("(%s)%p,%p,%p,%i", port->name, port, buffer, buffer->data, (int)buffer->length);
+
+   /* We're done with the buffer, just recycle it */
+   mmal_buffer_header_release(buffer);
+}
+
+/** Callback from an output port. Buffer is queued for the next component. */
+static void mmal_connection_bh_out_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_CONNECTION_T *connection = (MMAL_CONNECTION_T *)port->userdata;
+
+   LOG_TRACE("(%s)%p,%p,%p,%i", port->name, port, buffer, buffer->data, (int)buffer->length);
+
+   /* Queue the buffer produced by the output port */
+   mmal_queue_put(connection->queue, buffer);
+
+   if (connection->callback)
+      connection->callback(connection);
+}
+
+/** Callback from the pool. Buffer is available. */
+static MMAL_BOOL_T mmal_connection_bh_release_cb(MMAL_POOL_T *pool, MMAL_BUFFER_HEADER_T *buffer,
+   void *userdata)
+{
+   MMAL_CONNECTION_T *connection = (MMAL_CONNECTION_T *)userdata;
+   MMAL_PARAM_UNUSED(pool);
+
+   /* Queue the buffer produced by the output port */
+   mmal_queue_put(pool->queue, buffer);
+
+   if (connection->callback)
+      connection->callback(connection);
+
+   return 0;
+}
+
+/*****************************************************************************/
+static MMAL_STATUS_T mmal_connection_destroy_internal(MMAL_CONNECTION_T *connection)
+{
+   MMAL_STATUS_T status;
+
+   if (connection->is_enabled)
+   {
+      status = mmal_connection_disable(connection);
+      if (status != MMAL_SUCCESS)
+         return status;
+   }
+
+   /* Special case for tunnelling */
+   if (connection->flags & MMAL_CONNECTION_FLAG_TUNNELLING)
+   {
+      status = mmal_port_disconnect(connection->out);
+      if (status != MMAL_SUCCESS)
+         LOG_ERROR("connection %s could not be cleared", connection->name);
+   }
+
+   /* Cleanup resources */
+   if (connection->pool)
+      mmal_pool_destroy(connection->pool);
+   if (connection->queue)
+      mmal_queue_destroy(connection->queue);
+
+   vcos_free(connection);
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_connection_destroy(MMAL_CONNECTION_T *connection)
+{
+   MMAL_CONNECTION_PRIVATE_T *private = (MMAL_CONNECTION_PRIVATE_T *)connection;
+
+   LOG_TRACE("%p, %s", connection, connection->name);
+
+   if (--private->refcount)
+   {
+      LOG_DEBUG("delaying destruction of %s (refount %i)", connection->name,
+                private->refcount);
+      return MMAL_SUCCESS;
+   }
+
+   return mmal_connection_destroy_internal(connection);
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_connection_create(MMAL_CONNECTION_T **cx,
+   MMAL_PORT_T *out, MMAL_PORT_T *in, uint32_t flags)
+{
+   MMAL_STATUS_T status = MMAL_ENOMEM;
+   unsigned int name_size = strlen(out->component->name) + strlen(in->component->name) + sizeof(CONNECTION_NAME_FORMAT);
+   unsigned int size = sizeof(MMAL_CONNECTION_PRIVATE_T) + name_size;
+   MMAL_CONNECTION_PRIVATE_T *private;
+   MMAL_CONNECTION_T *connection;
+   char *name;
+
+   /* Sanity checking */
+   if (!cx)
+      return MMAL_EINVAL;
+
+   private = vcos_malloc(size, "mmal connection");
+   if (!private)
+      return MMAL_ENOMEM;
+   memset(private, 0, size);
+   connection = &private->connection;
+   private->refcount = 1;
+   name = (char *)&private[1];
+
+   vcos_snprintf(name, name_size - 1, CONNECTION_NAME_FORMAT,
+            out->component->name,
+            mmal_port_type_to_string(out->type), (int)out->index,
+            in->component->name,
+            mmal_port_type_to_string(in->type), (int)in->index);
+
+   LOG_TRACE("out %p, in %p, flags %x, %s", out, in, flags, name);
+
+   connection->out = out;
+   connection->in = in;
+   connection->flags = flags;
+   connection->name = name;
+
+   connection->time_setup = vcos_getmicrosecs();
+
+   /* Set the format of the input port to match the output one */
+   status = mmal_format_full_copy(in->format, out->format);
+   if (status == MMAL_SUCCESS)
+      status = mmal_port_format_commit(in);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("format not set on input port");
+      goto error;
+   }
+
+   /* In pass-through mode we need to propagate the buffer requirements of the
+    * connected input port */
+   if (out->capabilities & MMAL_PORT_CAPABILITY_PASSTHROUGH)
+   {
+      MMAL_PARAMETER_BUFFER_REQUIREMENTS_T param =
+         {{MMAL_PARAMETER_BUFFER_REQUIREMENTS, sizeof(MMAL_PARAMETER_BUFFER_REQUIREMENTS_T)},
+           in->buffer_num_min, in->buffer_size_min, in->buffer_alignment_min,
+           in->buffer_num_recommended, in->buffer_size_recommended};
+      status = mmal_port_parameter_set(out, &param.hdr);
+      if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
+      {
+         LOG_ERROR("failed to propagate buffer requirements");
+         goto error;
+      }
+      status = MMAL_SUCCESS;
+   }
+
+   /* Special case for tunnelling */
+   if (connection->flags & MMAL_CONNECTION_FLAG_TUNNELLING)
+   {
+      status = mmal_port_connect(out, in);
+      if (status != MMAL_SUCCESS)
+         LOG_ERROR("connection could not be made");
+      goto done;
+   }
+
+   /* Create empty pool of buffer headers for now (will be resized later on) */
+   private->pool_port = (in->capabilities & MMAL_PORT_CAPABILITY_ALLOCATION) ? in : out;
+   if (flags & MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT)
+      private->pool_port = in;
+   if (flags & MMAL_CONNECTION_FLAG_ALLOCATION_ON_OUTPUT)
+      private->pool_port = out;
+   connection->pool = mmal_port_pool_create(private->pool_port, 0, 0);
+   if (!connection->pool)
+      goto error;
+   mmal_pool_callback_set(connection->pool, mmal_connection_bh_release_cb, (void *)connection);
+
+   /* Create a queue to store the buffers from the output port */
+   connection->queue = mmal_queue_create();
+   if (!connection->queue)
+      goto error;
+
+ done:
+   out->userdata = (void *)connection;
+   in->userdata = (void *)connection;
+   connection->time_setup = vcos_getmicrosecs() - connection->time_setup;
+   *cx = connection;
+   return status;
+
+ error:
+   /* coverity[var_deref_model] mmal_connection_destroy_internal will check connection->pool correctly */
+   mmal_connection_destroy_internal(connection);
+   return status == MMAL_SUCCESS ? MMAL_ENOMEM : status;
+}
+
+/*****************************************************************************/
+void mmal_connection_acquire(MMAL_CONNECTION_T *connection)
+{
+   MMAL_CONNECTION_PRIVATE_T *private = (MMAL_CONNECTION_PRIVATE_T *)connection;
+   LOG_TRACE("connection %s(%p), refcount %i", connection->name, connection,
+             private->refcount);
+   private->refcount++;
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_connection_release(MMAL_CONNECTION_T *connection)
+{
+   MMAL_CONNECTION_PRIVATE_T *private = (MMAL_CONNECTION_PRIVATE_T *)connection;
+   LOG_TRACE("connection %s(%p), refcount %i", connection->name, connection,
+             private->refcount);
+
+   if (--private->refcount)
+      return MMAL_SUCCESS;
+
+   LOG_TRACE("destroying connection %s(%p)", connection->name, connection);
+   return mmal_connection_destroy_internal(connection);
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_connection_enable(MMAL_CONNECTION_T *connection)
+{
+   MMAL_PORT_T *in = connection->in, *out = connection->out;
+   uint32_t buffer_num, buffer_size;
+   MMAL_STATUS_T status;
+
+   LOG_TRACE("%p, %s", connection, connection->name);
+
+   if (connection->is_enabled)
+      return MMAL_SUCCESS;
+
+   connection->time_enable = vcos_getmicrosecs();
+
+   /* Override the buffer values with the recommended ones (the port probably knows best) */
+   if (!(connection->flags & MMAL_CONNECTION_FLAG_KEEP_BUFFER_REQUIREMENTS))
+   {
+      if (out->buffer_num_recommended)
+         out->buffer_num = out->buffer_num_recommended;
+      if (out->buffer_size_recommended)
+         out->buffer_size = out->buffer_size_recommended;
+      if (in->buffer_num_recommended)
+         in->buffer_num = in->buffer_num_recommended;
+      if (in->buffer_size_recommended)
+         in->buffer_size = in->buffer_size_recommended;
+   }
+
+   /* Special case for tunnelling */
+   if (connection->flags & MMAL_CONNECTION_FLAG_TUNNELLING)
+   {
+      /* Enable port. No callback because the port is connected. Other end of the connection
+       * will be enabled automatically. */
+      status = mmal_port_enable(out, NULL);
+      if (status)
+         LOG_ERROR("output port couldn't be enabled");
+      goto done;
+   }
+
+   /* Set the buffering properties on both ports */
+   buffer_num = MMAL_MAX(out->buffer_num, in->buffer_num);
+   buffer_size = MMAL_MAX(out->buffer_size, in->buffer_size);
+   out->buffer_num = in->buffer_num = buffer_num;
+   out->buffer_size = in->buffer_size = buffer_size;
+
+   /* In pass-through mode there isn't any need to allocate memory */
+   if (out->capabilities & MMAL_PORT_CAPABILITY_PASSTHROUGH)
+      buffer_size = 0;
+
+   /* Resize the output pool */
+   status = mmal_pool_resize(connection->pool, buffer_num, buffer_size);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("couldn't resize pool");
+      goto done;
+   }
+
+   /* Enable output port. The callback specified here is the function which
+    * will be called when an empty buffer header comes back to the port. */
+   status = mmal_port_enable(out, (out->type == MMAL_PORT_TYPE_CLOCK) ?
+                             mmal_connection_bh_clock_cb : mmal_connection_bh_out_cb);
+   if(status)
+   {
+      LOG_ERROR("output port couldn't be enabled");
+      goto done;
+   }
+
+   /* Enable input port. The callback specified here is the function which
+    * will be called when an empty buffer header comes back to the port. */
+   status = mmal_port_enable(in, (in->type == MMAL_PORT_TYPE_CLOCK) ?
+                             mmal_connection_bh_clock_cb : mmal_connection_bh_in_cb);
+   if(status)
+   {
+      LOG_ERROR("input port couldn't be enabled");
+      mmal_port_disable(out);
+      goto done;
+   }
+
+   /* Clock ports need buffers to send clock updates, so
+    * populate both connected clock ports */
+   if ((out->type == MMAL_PORT_TYPE_CLOCK) && (in->type == MMAL_PORT_TYPE_CLOCK))
+   {
+      MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(connection->pool->queue);
+      while (buffer)
+      {
+         mmal_port_send_buffer(out, buffer);
+         buffer = mmal_queue_get(connection->pool->queue);
+         if (buffer)
+         {
+            mmal_port_send_buffer(in, buffer);
+            buffer = mmal_queue_get(connection->pool->queue);
+         }
+      }
+   }
+
+ done:
+   connection->time_enable = vcos_getmicrosecs() - connection->time_enable;
+   connection->is_enabled = status == MMAL_SUCCESS;
+   return status;
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_connection_disable(MMAL_CONNECTION_T *connection)
+{
+   MMAL_STATUS_T status;
+   MMAL_BUFFER_HEADER_T *buffer;
+
+   LOG_TRACE("%p, %s", connection, connection->name);
+
+   if (!connection->is_enabled)
+      return MMAL_SUCCESS;
+
+   connection->time_disable = vcos_getmicrosecs();
+
+   /* Special case for tunnelling */
+   if (connection->flags & MMAL_CONNECTION_FLAG_TUNNELLING)
+   {
+      /* Disable port. Other end of the connection will be disabled automatically. */
+      status = mmal_port_disable(connection->out);
+      if (status)
+         LOG_ERROR("output port couldn't be disabled");
+      goto done;
+   }
+
+   /* Disable input port. */
+   status = mmal_port_disable(connection->in);
+   if(status)
+   {
+      LOG_ERROR("input port couldn't be disabled");
+      goto done;
+   }
+
+   /* Disable output port */
+   status = mmal_port_disable(connection->out);
+   if(status)
+   {
+      LOG_ERROR("output port couldn't be disabled");
+      goto done;
+   }
+
+   /* Flush the queue */
+   buffer = mmal_queue_get(connection->queue);
+   while (buffer)
+   {
+      mmal_buffer_header_release(buffer);
+      buffer = mmal_queue_get(connection->queue);
+   }
+   vcos_assert(mmal_queue_length(connection->pool->queue) == connection->pool->headers_num);
+
+ done:
+   connection->time_disable = vcos_getmicrosecs() - connection->time_disable;
+   connection->is_enabled = !(status == MMAL_SUCCESS);
+   return status;
+}
+
+/*****************************************************************************/
+static MMAL_STATUS_T mmal_connection_reconfigure(MMAL_CONNECTION_T *connection, MMAL_ES_FORMAT_T *format)
+{
+   MMAL_STATUS_T status;
+   LOG_TRACE("%p, %s", connection, connection->name);
+
+   status = mmal_connection_disable(connection);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("connection couldn't be disabled");
+      return status;
+   }
+
+   /* Set the new format for the output port */
+   status = mmal_format_full_copy(connection->out->format, format);
+   if (status == MMAL_SUCCESS)
+      status = mmal_port_format_commit(connection->out);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("commit failed on port %s(%p) (%i)",
+                connection->out->name, connection->out, status);
+      return status;
+   }
+
+   /* Set the new format for the input port */
+   status = mmal_format_full_copy(connection->in->format, connection->out->format);
+   if (status == MMAL_SUCCESS)
+      status = mmal_port_format_commit(connection->in);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("commit failed on port %s(%p) (%i)",
+                connection->in->name, connection->in, status);
+      return status;
+   }
+
+   /* Enable ports */
+   status = mmal_connection_enable(connection);
+   if (status)
+   {
+      LOG_ERROR("connection couldn't be enabled");
+      return status;
+   }
+
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_connection_event_format_changed(MMAL_CONNECTION_T *connection,
+   MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_EVENT_FORMAT_CHANGED_T *event;
+   MMAL_STATUS_T status;
+
+   LOG_TRACE("%p, %s", connection, connection->name);
+
+   if (buffer->cmd != MMAL_EVENT_FORMAT_CHANGED)
+      return MMAL_EINVAL;
+
+   event = mmal_event_format_changed_get(buffer);
+   if (!event)
+      return MMAL_EINVAL;
+
+   /* If we don't need to recreate our buffers then we can just forward the event
+    * to the next component (so it gets configured properly) */
+   if ((connection->in->capabilities & MMAL_PORT_CAPABILITY_SUPPORTS_EVENT_FORMAT_CHANGE) &&
+       event->buffer_size_min <= connection->out->buffer_size &&
+       event->buffer_num_min <= connection->out->buffer_num)
+   {
+      status = mmal_format_full_copy(connection->out->format, event->format);
+      if (status == MMAL_SUCCESS)
+         status = mmal_port_format_commit(connection->out);
+      if (status != MMAL_SUCCESS)
+      {
+         LOG_ERROR("format commit failed on port %s(%p) (%i)",
+                   connection->out->name, connection->out, status);
+         return status;
+      }
+
+      mmal_buffer_header_acquire(buffer);
+      status = mmal_port_send_buffer(connection->in, buffer);
+      if (status != MMAL_SUCCESS)
+      {
+         LOG_ERROR("buffer send failed on port %s(%p) (%i)",
+                   connection->in->name, connection->in, status);
+         mmal_buffer_header_release(buffer);
+         return status;
+      }
+
+      return MMAL_SUCCESS;
+   }
+
+   /* Otherwise we have to reconfigure our pipeline */
+   return mmal_connection_reconfigure(connection, event->format);
+}
diff --git a/interface/mmal/util/mmal_connection.h b/interface/mmal/util/mmal_connection.h
new file mode 100755 (executable)
index 0000000..d2a02b1
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_CONNECTION_H
+#define MMAL_CONNECTION_H
+
+/** \defgroup MmalConnectionUtility Port connection utility
+ * \ingroup MmalUtilities
+ * The port connection utility functions can be used in place of common sequences
+ * of calls to the MMAL API in order to process buffers being passed between two
+ * ports.
+ *
+ * \section ProcessingConnectionBufferHeaders Processing connection buffer headers
+ * Either in response to the client callback function being called, or simply on a
+ * timer, the client will need to process the buffer headers of the connection
+ * (unless tunneling is used).
+ *
+ * Buffer headers that are in the pool queue will need to be sent to the output port,
+ * while buffer headers in the connection queue are sent to the input port. The
+ * buffer headers in the connection queue may contain pixel data (the cmd field is
+ * zero) or an event (the cmd field is non-zero). In general, pixel data buffer
+ * headers need to be passed on, while event buffer headers are released. In the
+ * case of the format changed event, mmal_connection_event_format_changed() can be
+ * called before the event is released.
+ *
+ * Other, specialized use cases may also be implemented, such as getting and
+ * immediately releasing buffer headers from the connection queue in order to
+ * prevent their propagation. This could be used to drop out video, for example.
+ *
+ * \section TunnellingConnections Tunnelling connections
+ * If the \ref MMAL_CONNECTION_FLAG_TUNNELLING flag is set when the connection is
+ * created, MMAL tunneling will be used. This automates the passing of the buffer
+ * headers between the output port and input port, and back again. It will also do
+ * this as efficiently as possible, avoiding trips between the ARM and the VideoCore
+ * if both components are implemented on the VideoCore. The consequence of this is
+ * that there is no client callback made as buffer headers get transferred.
+ *
+ * The client can still monitor the control port of a component (usually a sink
+ * component, such as video_render) for the end of stream, in order to know when to
+ * dismantle the connection.
+ *
+ * \section ConnectionClientCallback Client callback
+ * When not using tunnelling, the client callback function is called each time a
+ * buffer arrives from a port (either input or output).
+ *
+ * \note The callback is made on a different thread from the one used by the
+ * client to set up the connection, so care must be taken with thread safety.
+ * One option is to raise a signal to the main client thread that queue processing
+ * needs to be done, another is for the callback to perform the queue processing
+ * itself.
+ *
+ * The client can also store an opaque pointer in the connection object, which is
+ * never used by the MMAL code and is only meaningful to the client.
+ *
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \name Connection flags
+ * \anchor connectionflags
+ * The following flags describe the properties of the connection. */
+/* @{ */
+/** The connection is tunnelled. Buffer headers do not transit via the client but
+ * directly from the output port to the input port. */
+#define MMAL_CONNECTION_FLAG_TUNNELLING 0x1
+/** Force the pool of buffer headers used by the connection to be allocated on the input port. */
+#define MMAL_CONNECTION_FLAG_ALLOCATION_ON_INPUT 0x2
+/** Force the pool of buffer headers used by the connection to be allocated on the output port. */
+#define MMAL_CONNECTION_FLAG_ALLOCATION_ON_OUTPUT 0x4
+/** Specify that the connection should not modify the buffer requirements. */
+#define MMAL_CONNECTION_FLAG_KEEP_BUFFER_REQUIREMENTS 0x8
+/** The connection is flagged as direct. This doesn't change the behaviour of
+ * the connection itself but is used by the the graph utility to specify that
+ * the buffer should be sent to the input port from with the port callback. */
+#define MMAL_CONNECTION_FLAG_DIRECT 0x10
+/* @} */
+
+/** Forward type definition for a connection */
+typedef struct MMAL_CONNECTION_T MMAL_CONNECTION_T;
+
+/** Definition of the callback used by a connection to signal back to the client
+ * that a buffer header is available either in the pool or in the output queue.
+ *
+ * @param connection Pointer to the connection
+ */
+typedef void (*MMAL_CONNECTION_CALLBACK_T)(MMAL_CONNECTION_T *connection);
+
+/** Structure describing a connection between 2 ports (1 output and 1 input port) */
+struct MMAL_CONNECTION_T {
+
+   void *user_data;           /**< Field reserved for use by the client. */
+   MMAL_CONNECTION_CALLBACK_T callback; /**< Callback set by the client. */
+
+   uint32_t is_enabled;       /**< Specifies whether the connection is enabled or not (Read Only). */
+
+   uint32_t flags;            /**< Flags passed during the create call (Read Only). A bitwise
+                               * combination of \ref connectionflags "Connection flags" values.
+                               */
+   MMAL_PORT_T *in;           /**< Input port used for the connection (Read Only). */
+   MMAL_PORT_T *out;          /**< Output port used for the connection (Read Only). */
+
+   MMAL_POOL_T *pool;         /**< Pool of buffer headers used by the output port (Read Only). */
+   MMAL_QUEUE_T *queue;       /**< Queue for the buffer headers produced by the output port (Read Only). */
+
+   const char *name;          /**< Connection name (Read Only). Used for debugging purposes. */
+
+   /* Used for debug / statistics */
+   int64_t time_setup;        /**< Time in microseconds taken to setup the connection. */
+   int64_t time_enable;       /**< Time in microseconds taken to enable the connection. */
+   int64_t time_disable;      /**< Time in microseconds taken to disable the connection. */
+};
+
+/** Create a connection between two ports.
+ * The connection shall include a pool of buffer headers suitable for the current format of
+ * the output port. The format of the input port shall have been set to the same as that of
+ * the input port.
+ * Note that connections are reference counted and creating a connection automatically
+ * acquires a reference to it (released when \ref mmal_connection_destroy is called).
+ *
+ * @param connection The address of a connection pointer that will be set to point to the created
+ * connection.
+ * @param out        The output port to use for the connection.
+ * @param in         The input port to use for the connection.
+ * @param flags      The flags specifying which type of connection should be created.
+ *    A bitwise combination of \ref connectionflags "Connection flags" values.
+ * @return MMAL_SUCCESS on success.
+ */
+MMAL_STATUS_T mmal_connection_create(MMAL_CONNECTION_T **connection,
+   MMAL_PORT_T *out, MMAL_PORT_T *in, uint32_t flags);
+
+/** Acquire a reference on a connection.
+ * Acquiring a reference on a connection will prevent a connection from being destroyed until
+ * the acquired reference is released (by a call to \ref mmal_connection_destroy).
+ * References are internally counted so all acquired references need a matching call to
+ * release them.
+ *
+ * @param connection connection to acquire
+ */
+void mmal_connection_acquire(MMAL_CONNECTION_T *connection);
+
+/** Release a reference on a connection
+ * Release an acquired reference on a connection. Triggers the destruction of the connection when
+ * the last reference is being released.
+ * \note This is in fact an alias of \ref mmal_connection_destroy which is added to make client
+ * code clearer.
+ *
+ * @param connection connection to release
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_connection_release(MMAL_CONNECTION_T *connection);
+
+/** Destroy a connection.
+ * Release an acquired reference on a connection. Only actually destroys the connection when
+ * the last reference is being released.
+ * The actual destruction of the connection will start by disabling it, if necessary.
+ * Any pool, queue, and so on owned by the connection shall then be destroyed.
+ *
+ * @param connection The connection to be destroyed.
+ * @return MMAL_SUCCESS on success.
+ */
+MMAL_STATUS_T mmal_connection_destroy(MMAL_CONNECTION_T *connection);
+
+/** Enable a connection.
+ * The format of the two ports must have been committed before calling this function,
+ * although note that on creation, the connection automatically copies and commits the
+ * output port's format to the input port.
+ *
+ * The MMAL_CONNECTION_T::callback field must have been set if the \ref MMAL_CONNECTION_FLAG_TUNNELLING
+ * flag was not specified on creation. The client may also set the MMAL_CONNECTION_T::user_data
+ * in order to get a pointer passed, via the connection, to the callback.
+ *
+ * @param connection The connection to be enabled.
+ * @return MMAL_SUCCESS on success.
+ */
+MMAL_STATUS_T mmal_connection_enable(MMAL_CONNECTION_T *connection);
+
+/** Disable a connection.
+ *
+ * @param connection The connection to be disabled.
+ * @return MMAL_SUCCESS on success.
+ */
+MMAL_STATUS_T mmal_connection_disable(MMAL_CONNECTION_T *connection);
+
+/** Apply a format changed event to the connection.
+ * This function can be used when the client is processing buffer headers and receives
+ * a format changed event (\ref MMAL_EVENT_FORMAT_CHANGED). The connection is
+ * reconfigured, changing the format of the ports, the number of buffer headers and
+ * the size of the payload buffers as necessary.
+ *
+ * @param connection The connection to which the event shall be applied.
+ * @param buffer The buffer containing a format changed event.
+ * @return MMAL_SUCCESS on success.
+ */
+MMAL_STATUS_T mmal_connection_event_format_changed(MMAL_CONNECTION_T *connection,
+   MMAL_BUFFER_HEADER_T *buffer);
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+#endif /* MMAL_CONNECTION_H */
diff --git a/interface/mmal/util/mmal_default_components.h b/interface/mmal/util/mmal_default_components.h
new file mode 100755 (executable)
index 0000000..fb0ece4
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_DEFAULT_COMPONENTS_H
+#define MMAL_DEFAULT_COMPONENTS_H
+
+/** \defgroup MmalDefaultComponents List of default components
+ * This provides a list of default components on a per platform basis.
+ * @{
+ */
+
+#define MMAL_COMPONENT_DEFAULT_CONTAINER_READER "container_reader"
+#define MMAL_COMPONENT_DEFAULT_CONTAINER_WRITER "container_writer"
+
+#if defined(ENABLE_MMAL_STANDALONE)
+# define MMAL_COMPONENT_DEFAULT_VIDEO_DECODER    "avcodec.video_decode"
+# define MMAL_COMPONENT_DEFAULT_VIDEO_ENCODER    "avcodec.video_encode"
+# define MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER   "sdl.video_render"
+# define MMAL_COMPONENT_DEFAULT_IMAGE_DECODER    "avcodec.video_decode"
+# define MMAL_COMPONENT_DEFAULT_IMAGE_ENCODER    "avcodec.video_encode"
+# define MMAL_COMPONENT_DEFAULT_CAMERA           "artificial_camera"
+# define MMAL_COMPONENT_DEFAULT_VIDEO_CONVERTER  "avcodec.video_convert"
+# define MMAL_COMPONENT_DEFAULT_SPLITTER         "splitter"
+# define MMAL_COMPONENT_DEFAULT_SCHEDULER        "scheduler"
+# define MMAL_COMPONENT_DEFAULT_VIDEO_INJECTER   "video_inject"
+# define MMAL_COMPONENT_DEFAULT_AUDIO_DECODER    "avcodec.audio_decode"
+# define MMAL_COMPONENT_DEFAULT_AUDIO_RENDERER   "sdl.audio_render"
+# define MMAL_COMPONENT_DEFAULT_MIRACAST         "miracast"
+# define MMAL_COMPONENT_DEFAULT_CLOCK            "clock"
+#elif defined(__VIDEOCORE__)
+# define MMAL_COMPONENT_DEFAULT_VIDEO_DECODER    "ril.video_decode"
+# define MMAL_COMPONENT_DEFAULT_VIDEO_ENCODER    "ril.video_encode"
+# define MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER   "ril.video_render"
+# define MMAL_COMPONENT_DEFAULT_IMAGE_DECODER    "ril.image_decode"
+# define MMAL_COMPONENT_DEFAULT_IMAGE_ENCODER    "ril.image_encode"
+# define MMAL_COMPONENT_DEFAULT_CAMERA           "ril.camera"
+# define MMAL_COMPONENT_DEFAULT_VIDEO_CONVERTER  "video_convert"
+# define MMAL_COMPONENT_DEFAULT_SPLITTER         "splitter"
+# define MMAL_COMPONENT_DEFAULT_SCHEDULER        "scheduler"
+# define MMAL_COMPONENT_DEFAULT_VIDEO_INJECTER   "video_inject"
+# define MMAL_COMPONENT_DEFAULT_VIDEO_SPLITTER   "ril.video_splitter"
+# define MMAL_COMPONENT_DEFAULT_AUDIO_DECODER    "none"
+# define MMAL_COMPONENT_DEFAULT_AUDIO_RENDERER   "ril.audio_render"
+# define MMAL_COMPONENT_DEFAULT_MIRACAST         "miracast"
+# define MMAL_COMPONENT_DEFAULT_CLOCK            "clock"
+# define MMAL_COMPONENT_DEFAULT_CAMERA_INFO      "camera_info"
+#else
+# define MMAL_COMPONENT_DEFAULT_VIDEO_DECODER    "vc.ril.video_decode"
+# define MMAL_COMPONENT_DEFAULT_VIDEO_ENCODER    "vc.ril.video_encode"
+# define MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER   "vc.ril.video_render"
+# define MMAL_COMPONENT_DEFAULT_IMAGE_DECODER    "vc.ril.image_decode"
+# define MMAL_COMPONENT_DEFAULT_IMAGE_ENCODER    "vc.ril.image_encode"
+# define MMAL_COMPONENT_DEFAULT_CAMERA           "vc.ril.camera"
+# define MMAL_COMPONENT_DEFAULT_VIDEO_CONVERTER  "vc.video_convert"
+# define MMAL_COMPONENT_DEFAULT_SPLITTER         "vc.splitter"
+# define MMAL_COMPONENT_DEFAULT_SCHEDULER        "vc.scheduler"
+# define MMAL_COMPONENT_DEFAULT_VIDEO_INJECTER   "vc.video_inject"
+# define MMAL_COMPONENT_DEFAULT_VIDEO_SPLITTER   "vc.ril.video_splitter"
+# define MMAL_COMPONENT_DEFAULT_AUDIO_DECODER    "none"
+# define MMAL_COMPONENT_DEFAULT_AUDIO_RENDERER   "vc.ril.audio_render"
+# define MMAL_COMPONENT_DEFAULT_MIRACAST         "vc.miracast"
+# define MMAL_COMPONENT_DEFAULT_CLOCK            "vc.clock"
+# define MMAL_COMPONENT_DEFAULT_CAMERA_INFO      "vc.camera_info"
+#endif
+
+/** @} */
+
+#endif /* MMAL_DEFAULT_COMPONENTS_H */
diff --git a/interface/mmal/util/mmal_graph.c b/interface/mmal/util/mmal_graph.c
new file mode 100755 (executable)
index 0000000..d66527b
--- /dev/null
@@ -0,0 +1,1560 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "util/mmal_util.h"
+#include "util/mmal_graph.h"
+#include "core/mmal_component_private.h"
+#include "core/mmal_port_private.h"
+#include "mmal_logging.h"
+
+#define GRAPH_CONNECTIONS_MAX 16
+#define PROCESSING_TIME_MAX 20000
+
+/*****************************************************************************/
+
+/** Private context for our graph.
+ * This also acts as a MMAL_COMPONENT_MODULE_T for when components are instantiated from graphs */
+typedef struct MMAL_COMPONENT_MODULE_T
+{
+   MMAL_GRAPH_T graph; /**< Must be the first member! */
+
+   MMAL_COMPONENT_T *component[GRAPH_CONNECTIONS_MAX];
+   MMAL_GRAPH_TOPOLOGY_T topology[GRAPH_CONNECTIONS_MAX];
+   unsigned int component_num;
+
+   MMAL_CONNECTION_T *connection[GRAPH_CONNECTIONS_MAX];
+   unsigned int connection_num;
+   unsigned int connection_current;
+
+   MMAL_PORT_T *input[GRAPH_CONNECTIONS_MAX];
+   unsigned int input_num;
+   MMAL_PORT_T *output[GRAPH_CONNECTIONS_MAX];
+   unsigned int output_num;
+   MMAL_PORT_T *clock[GRAPH_CONNECTIONS_MAX];
+   unsigned int clock_num;
+
+   MMAL_COMPONENT_T *graph_component;
+
+   MMAL_BOOL_T stop_thread;      /**< informs the worker thread to exit */
+   VCOS_THREAD_T thread;         /**< worker thread which processes all internal connections */
+   VCOS_SEMAPHORE_T sema;        /**< informs the worker thread that buffers are available */
+
+   MMAL_GRAPH_EVENT_CB event_cb; /**< callback for sending control port events to the client */
+   void *event_cb_data;          /**< callback data supplied by the client */
+
+} MMAL_GRAPH_PRIVATE_T;
+
+typedef MMAL_GRAPH_PRIVATE_T MMAL_COMPONENT_MODULE_T;
+
+/*****************************************************************************/
+static MMAL_STATUS_T mmal_component_create_from_graph(const char *name, MMAL_COMPONENT_T *component);
+static MMAL_BOOL_T graph_do_processing(MMAL_GRAPH_PRIVATE_T *graph);
+static void graph_process_buffer(MMAL_GRAPH_PRIVATE_T *graph_private,
+   MMAL_CONNECTION_T *connection, MMAL_BUFFER_HEADER_T *buffer);
+
+/*****************************************************************************/
+static void graph_control_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_GRAPH_PRIVATE_T *graph = (MMAL_GRAPH_PRIVATE_T *)port->userdata;
+
+   LOG_TRACE("port: %s(%p), buffer: %p, event: %4.4s", port->name, port,
+             buffer, (char *)&buffer->cmd);
+
+   if (graph->event_cb)
+   {
+      graph->event_cb((MMAL_GRAPH_T *)graph, port, buffer, graph->event_cb_data);
+   }
+   else
+   {
+      LOG_ERROR("event lost on port %i,%i (event callback not defined)",
+                (int)port->type, (int)port->index);
+      mmal_buffer_header_release(buffer);
+   }
+}
+
+/*****************************************************************************/
+static void graph_connection_cb(MMAL_CONNECTION_T *connection)
+{
+   MMAL_GRAPH_PRIVATE_T *graph = (MMAL_GRAPH_PRIVATE_T *)connection->user_data;
+   MMAL_BUFFER_HEADER_T *buffer;
+
+   if (connection->flags == MMAL_CONNECTION_FLAG_DIRECT &&
+       (buffer = mmal_queue_get(connection->queue)) != NULL)
+   {
+      graph_process_buffer(graph, connection, buffer);
+      return;
+   }
+
+   vcos_semaphore_post(&graph->sema);
+}
+
+/*****************************************************************************/
+static void* graph_worker_thread(void* ctx)
+{
+   MMAL_GRAPH_PRIVATE_T *graph = (MMAL_GRAPH_PRIVATE_T *)ctx;
+
+   while (1)
+   {
+      vcos_semaphore_wait(&graph->sema);
+      if (graph->stop_thread)
+         break;
+      while(graph_do_processing(graph));
+   }
+
+   LOG_TRACE("worker thread exit %p", graph);
+
+   return 0;
+}
+
+/*****************************************************************************/
+static void graph_stop_worker_thread(MMAL_GRAPH_PRIVATE_T *graph)
+{
+   graph->stop_thread = MMAL_TRUE;
+   vcos_semaphore_post(&graph->sema);
+   vcos_thread_join(&graph->thread, NULL);
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_graph_create(MMAL_GRAPH_T **graph, unsigned int userdata_size)
+{
+   MMAL_GRAPH_PRIVATE_T *private;
+
+   LOG_TRACE("graph %p, userdata_size %u", graph, userdata_size);
+
+   /* Sanity checking */
+   if (!graph)
+      return MMAL_EINVAL;
+
+   private = vcos_calloc(1, sizeof(MMAL_GRAPH_PRIVATE_T) + userdata_size, "mmal connection graph");
+   if (!private)
+      return MMAL_ENOMEM;
+   *graph = &private->graph;
+   if (userdata_size)
+      (*graph)->userdata = (struct MMAL_GRAPH_USERDATA_T *)&private[1];
+
+   if (vcos_semaphore_create(&private->sema, "mmal graph sema", 0) != VCOS_SUCCESS)
+   {
+      LOG_ERROR("failed to create semaphore %p", graph);
+      vcos_free(private);
+      return MMAL_ENOSPC;
+   }
+
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_graph_destroy(MMAL_GRAPH_T *graph)
+{
+   unsigned i;
+   MMAL_GRAPH_PRIVATE_T *private = (MMAL_GRAPH_PRIVATE_T *)graph;
+
+   if (!graph)
+      return MMAL_EINVAL;
+
+   LOG_TRACE("%p", graph);
+
+   /* Notify client of destruction */
+   if (graph->pf_destroy)
+      graph->pf_destroy(graph);
+
+   for (i = 0; i < private->connection_num; i++)
+      mmal_connection_release(private->connection[i]);
+
+   for (i = 0; i < private->component_num; i++)
+      mmal_component_release(private->component[i]);
+
+   vcos_semaphore_delete(&private->sema);
+
+   vcos_free(graph);
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_graph_add_component(MMAL_GRAPH_T *graph, MMAL_COMPONENT_T *component)
+{
+   MMAL_GRAPH_PRIVATE_T *private = (MMAL_GRAPH_PRIVATE_T *)graph;
+
+   LOG_TRACE("graph: %p, component: %s(%p)", graph, component ? component->name: 0, component);
+
+   if (!component)
+      return MMAL_EINVAL;
+
+   if (private->component_num >= GRAPH_CONNECTIONS_MAX)
+   {
+      LOG_ERROR("no space for component %s", component->name);
+      return MMAL_ENOSPC;
+   }
+
+   mmal_component_acquire(component);
+   private->component[private->component_num++] = component;
+
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_graph_component_topology(MMAL_GRAPH_T *graph, MMAL_COMPONENT_T *component,
+    MMAL_GRAPH_TOPOLOGY_T topology, int8_t *input, unsigned int input_num,
+    int8_t *output, unsigned int output_num)
+{
+   MMAL_GRAPH_PRIVATE_T *private = (MMAL_GRAPH_PRIVATE_T *)graph;
+   MMAL_PARAM_UNUSED(input); MMAL_PARAM_UNUSED(input_num);
+   MMAL_PARAM_UNUSED(output); MMAL_PARAM_UNUSED(output_num);
+   unsigned int i;
+
+   LOG_TRACE("graph: %p, component: %s(%p)", graph, component ? component->name: 0, component);
+
+   if (!component)
+      return MMAL_EINVAL;
+
+   for (i = 0; i < private->component_num; i++)
+      if (component == private->component[i])
+         break;
+
+   if (i == private->component_num)
+      return MMAL_EINVAL; /* Component not found */
+
+   if (topology > MMAL_GRAPH_TOPOLOGY_STRAIGHT)
+      return MMAL_ENOSYS; /* Currently not supported */
+
+   private->topology[i] = topology;
+
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_graph_add_connection(MMAL_GRAPH_T *graph, MMAL_CONNECTION_T *cx)
+{
+   MMAL_GRAPH_PRIVATE_T *private = (MMAL_GRAPH_PRIVATE_T *)graph;
+
+   LOG_TRACE("graph: %p, connection: %s(%p)", graph, cx ? cx->name: 0, cx);
+
+   if (!cx)
+      return MMAL_EINVAL;
+
+   if (private->connection_num >= GRAPH_CONNECTIONS_MAX)
+   {
+      LOG_ERROR("no space for connection %s", cx->name);
+      return MMAL_ENOSPC;
+   }
+
+   mmal_connection_acquire(cx);
+   private->connection[private->connection_num++] = cx;
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_graph_add_port(MMAL_GRAPH_T *graph, MMAL_PORT_T *port)
+{
+   MMAL_GRAPH_PRIVATE_T *private = (MMAL_GRAPH_PRIVATE_T *)graph;
+   MMAL_PORT_T **list;
+   unsigned int *list_num;
+
+   LOG_TRACE("graph: %p, port: %s(%p)", graph, port ? port->name: 0, port);
+
+   if (!port)
+      return MMAL_EINVAL;
+
+   switch (port->type)
+   {
+   case MMAL_PORT_TYPE_INPUT:
+      list = private->input;
+      list_num = &private->input_num;
+      break;
+   case MMAL_PORT_TYPE_OUTPUT:
+      list = private->output;
+      list_num = &private->output_num;
+      break;
+   case MMAL_PORT_TYPE_CLOCK:
+      list = private->clock;
+      list_num = &private->clock_num;
+      break;
+   default:
+      return MMAL_EINVAL;
+   }
+
+   if (*list_num >= GRAPH_CONNECTIONS_MAX)
+   {
+      LOG_ERROR("no space for port %s", port->name);
+      return MMAL_ENOSPC;
+   }
+
+   list[(*list_num)++] = port;
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_graph_new_component(MMAL_GRAPH_T *graph, const char *name,
+   MMAL_COMPONENT_T **component)
+{
+   MMAL_GRAPH_PRIVATE_T *private = (MMAL_GRAPH_PRIVATE_T *)graph;
+   MMAL_COMPONENT_T *comp;
+   MMAL_STATUS_T status;
+
+   LOG_TRACE("graph: %p, name: %s, component: %p", graph, name, component);
+
+   if (private->component_num >= GRAPH_CONNECTIONS_MAX)
+   {
+      LOG_ERROR("no space for component %s", name);
+      return MMAL_ENOSPC;
+   }
+
+   status = mmal_component_create(name, &comp);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("could not create component %s (%i)", name, status);
+      return status;
+   }
+
+   private->component[private->component_num++] = comp;
+   if (component)
+   {
+      mmal_component_acquire(comp);
+      *component = comp;
+   }
+
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_graph_new_connection(MMAL_GRAPH_T *graph, MMAL_PORT_T *out, MMAL_PORT_T *in,
+   uint32_t flags, MMAL_CONNECTION_T **connection)
+{
+   MMAL_GRAPH_PRIVATE_T *private = (MMAL_GRAPH_PRIVATE_T *)graph;
+   MMAL_CONNECTION_T *cx;
+   MMAL_STATUS_T status;
+
+   if (!out || !in)
+      return MMAL_EINVAL;
+   if (out->type == MMAL_PORT_TYPE_CLOCK && in->type != MMAL_PORT_TYPE_CLOCK)
+      return MMAL_EINVAL;
+   if (out->type != MMAL_PORT_TYPE_CLOCK &&
+       (out->type != MMAL_PORT_TYPE_OUTPUT || in->type != MMAL_PORT_TYPE_INPUT))
+      return MMAL_EINVAL;
+
+   LOG_TRACE("graph: %p, out: %s(%p), in: %s(%p), flags %x, connection: %p",
+             graph, out->name, out, in->name, in, (int)flags, connection);
+
+   if (private->connection_num >= GRAPH_CONNECTIONS_MAX)
+   {
+      LOG_ERROR("no space for connection %s/%s", out->name, in->name);
+      return MMAL_ENOSPC;
+   }
+
+   status = mmal_connection_create(&cx, out, in, flags);
+   if (status != MMAL_SUCCESS)
+      return status;
+
+   private->connection[private->connection_num++] = cx;
+   if (connection)
+   {
+      mmal_connection_acquire(cx);
+      *connection = cx;
+   }
+
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_graph_enable(MMAL_GRAPH_T *graph, MMAL_GRAPH_EVENT_CB cb, void *cb_data)
+{
+   MMAL_GRAPH_PRIVATE_T *private = (MMAL_GRAPH_PRIVATE_T *)graph;
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   unsigned int i;
+
+   LOG_TRACE("graph: %p", graph);
+
+   if (vcos_thread_create(&private->thread, "mmal graph thread", NULL,
+                          graph_worker_thread, private) != VCOS_SUCCESS)
+   {
+      LOG_ERROR("failed to create worker thread %p", graph);
+      return MMAL_ENOSPC;
+   }
+
+   private->event_cb = cb;
+   private->event_cb_data = cb_data;
+
+   /* Enable all control ports */
+   for (i = 0; i < private->component_num; i++)
+   {
+      private->component[i]->control->userdata = (void *)private;
+      status = mmal_port_enable(private->component[i]->control, graph_control_cb);
+      if (status != MMAL_SUCCESS)
+         LOG_ERROR("could not enable port %s", private->component[i]->control->name);
+   }
+
+   /* Enable all our connections */
+   for (i = 0; i < private->connection_num; i++)
+   {
+      MMAL_CONNECTION_T *cx = private->connection[i];
+
+      cx->callback = graph_connection_cb;
+      cx->user_data = private;
+
+      status = mmal_connection_enable(cx);
+      if (status != MMAL_SUCCESS)
+         goto error;
+   }
+
+   /* Trigger the worker thread to populate the output ports with empty buffers */
+   vcos_semaphore_post(&private->sema);
+   return status;
+
+ error:
+   graph_stop_worker_thread(private);
+   return status;
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_graph_disable(MMAL_GRAPH_T *graph)
+{
+   MMAL_GRAPH_PRIVATE_T *private = (MMAL_GRAPH_PRIVATE_T *)graph;
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   unsigned int i;
+
+   LOG_TRACE("graph: %p", graph);
+
+   graph_stop_worker_thread(private);
+
+   /* Disable all our connections */
+   for (i = 0; i < private->connection_num; i++)
+   {
+      status = mmal_connection_disable(private->connection[i]);
+      if (status != MMAL_SUCCESS)
+         break;
+   }
+
+   return status;
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_graph_build(MMAL_GRAPH_T *graph,
+   const char *name, MMAL_COMPONENT_T **component)
+{
+   LOG_TRACE("graph: %p, name: %s, component: %p", graph, name, component);
+   return mmal_component_create_with_constructor(name, mmal_component_create_from_graph,
+      (MMAL_GRAPH_PRIVATE_T *)graph, component);
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_graph_component_constructor(const char *name,
+   MMAL_COMPONENT_T *component)
+{
+   LOG_TRACE("name: %s, component: %p", name, component);
+   return mmal_component_create_from_graph(name, component);
+}
+
+/*****************************************************************************/
+static void graph_component_control_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_COMPONENT_T *graph_component = (MMAL_COMPONENT_T *)port->userdata;
+   MMAL_GRAPH_PRIVATE_T *graph_private = graph_component->priv->module;
+   MMAL_STATUS_T status;
+
+   LOG_TRACE("%s(%p),%p,%4.4s", port->name, port, buffer, (char *)&buffer->cmd);
+
+   /* Call user defined function first */
+   if (graph_private->graph.pf_control_callback)
+   {
+      status = graph_private->graph.pf_control_callback(&graph_private->graph,
+         port, buffer);
+      if (status != MMAL_ENOSYS)
+         return;
+   }
+
+   /* Forward the event on the graph control port */
+   mmal_port_event_send(graph_component->control, buffer);
+}
+
+/*****************************************************************************/
+static void graph_component_connection_cb(MMAL_CONNECTION_T *connection)
+{
+   MMAL_COMPONENT_T *component = (MMAL_COMPONENT_T *)connection->user_data;
+   MMAL_BUFFER_HEADER_T *buffer;
+
+   if (connection->flags == MMAL_CONNECTION_FLAG_DIRECT &&
+       (buffer = mmal_queue_get(connection->queue)) != NULL)
+   {
+      graph_process_buffer((MMAL_GRAPH_PRIVATE_T *)component->priv->module,
+         connection, buffer);
+      return;
+   }
+
+   mmal_component_action_trigger(component);
+}
+
+/*****************************************************************************/
+static void graph_port_event_handler(MMAL_CONNECTION_T *connection,
+   MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_STATUS_T status;
+
+   LOG_TRACE("port: %s(%p), buffer: %p, event: %4.4s", port->name, port,
+             buffer, (char *)&buffer->cmd);
+
+   if (buffer->cmd == MMAL_EVENT_FORMAT_CHANGED && port->type == MMAL_PORT_TYPE_OUTPUT)
+   {
+      MMAL_EVENT_FORMAT_CHANGED_T *event = mmal_event_format_changed_get(buffer);
+      if (event)
+      {
+         LOG_DEBUG("----------Port format changed----------");
+         mmal_log_dump_port(port);
+         LOG_DEBUG("-----------------to---------------------");
+         mmal_log_dump_format(event->format);
+         LOG_DEBUG(" buffers num (opt %i, min %i), size (opt %i, min: %i)",
+                   event->buffer_num_recommended, event->buffer_num_min,
+                   event->buffer_size_recommended, event->buffer_size_min);
+         LOG_DEBUG("----------------------------------------");
+      }
+
+      status = mmal_connection_event_format_changed(connection, buffer);
+   }
+
+   else
+      status = MMAL_SUCCESS; /* FIXME: ignore any other event for now */
+
+   mmal_buffer_header_release(buffer);
+
+   if (status != MMAL_SUCCESS)
+      mmal_event_error_send(port->component, status);
+}
+
+/*****************************************************************************/
+static void graph_process_buffer(MMAL_GRAPH_PRIVATE_T *graph_private,
+   MMAL_CONNECTION_T *connection, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_STATUS_T status;
+
+   /* Call user defined function first */
+   if (graph_private->graph.pf_connection_buffer)
+   {
+      status = graph_private->graph.pf_connection_buffer(&graph_private->graph, connection, buffer);
+      if (status != MMAL_ENOSYS)
+         return;
+   }
+
+   if (buffer->cmd)
+   {
+      graph_port_event_handler(connection, connection->out, buffer);
+      return;
+   }
+
+   status = mmal_port_send_buffer(connection->in, buffer);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("%s(%p) could not send buffer to %s(%p) (%s)",
+                connection->out->name, connection->out,
+                connection->in->name, connection->in,
+                mmal_status_to_string(status));
+      mmal_buffer_header_release(buffer);
+      mmal_event_error_send(connection->out->component, status);
+   }
+}
+
+/*****************************************************************************/
+static MMAL_BOOL_T graph_do_processing(MMAL_GRAPH_PRIVATE_T *graph_private)
+{
+   MMAL_BUFFER_HEADER_T *buffer;
+   MMAL_BOOL_T run_again = 0;
+   MMAL_STATUS_T status;
+   unsigned int i, j;
+
+   /* Process all the empty buffers first */
+   for (i = 0, j = graph_private->connection_current;
+        i < graph_private->connection_num; i++, j++)
+   {
+      MMAL_CONNECTION_T *connection =
+         graph_private->connection[j%graph_private->connection_num];
+
+      if ((connection->flags & MMAL_CONNECTION_FLAG_TUNNELLING) ||
+          !connection->pool)
+         continue; /* Nothing else to do in tunnelling mode */
+
+      /* Send empty buffers to the output port of the connection */
+      while ((buffer = mmal_queue_get(connection->pool->queue)) != NULL)
+      {
+         run_again = 1;
+
+         status = mmal_port_send_buffer(connection->out, buffer);
+         if (status != MMAL_SUCCESS)
+         {
+            if (connection->out->is_enabled)
+               LOG_ERROR("mmal_port_send_buffer failed (%i)", status);
+            mmal_queue_put_back(connection->pool->queue, buffer);
+            run_again = 0;
+            break;
+         }
+      }
+   }
+
+   /* Loop through all the connections */
+   for (i = 0, j = graph_private->connection_current++;
+        i < graph_private->connection_num; i++, j++)
+   {
+      MMAL_CONNECTION_T *connection =
+         graph_private->connection[j%graph_private->connection_num];
+      int64_t duration = vcos_getmicrosecs64();
+
+      if (connection->flags & MMAL_CONNECTION_FLAG_TUNNELLING)
+         continue; /* Nothing else to do in tunnelling mode */
+      if (connection->flags & MMAL_CONNECTION_FLAG_DIRECT)
+         continue; /* Nothing else to do in direct mode */
+
+      /* Send any queued buffer to the next component.
+       * We also make sure no connection can starve the others by
+       * having a timeout. */
+      while (vcos_getmicrosecs64() - duration < PROCESSING_TIME_MAX &&
+             (buffer = mmal_queue_get(connection->queue)) != NULL)
+      {
+         run_again = 1;
+
+         graph_process_buffer(graph_private, connection, buffer);
+      }
+   }
+
+   return run_again;
+}
+
+/*****************************************************************************/
+static void graph_do_processing_loop(MMAL_COMPONENT_T *component)
+{
+   while (graph_do_processing((MMAL_GRAPH_PRIVATE_T *)component->priv->module));
+}
+
+/*****************************************************************************/
+static MMAL_PORT_T *find_port_from_graph(MMAL_GRAPH_PRIVATE_T *graph, MMAL_PORT_T *port)
+{
+   MMAL_PORT_T **list;
+   unsigned int *list_num;
+
+   switch (port->type)
+   {
+   case MMAL_PORT_TYPE_INPUT:
+      list = graph->input;
+      list_num = &graph->input_num;
+      break;
+   case MMAL_PORT_TYPE_OUTPUT:
+      list = graph->output;
+      list_num = &graph->output_num;
+      break;
+   case MMAL_PORT_TYPE_CLOCK:
+      list = graph->clock;
+      list_num = &graph->clock_num;
+      break;
+   default:
+      return 0;
+   }
+
+   if (port->index > *list_num)
+      return 0;
+
+   return list[port->index];
+}
+
+static MMAL_PORT_T *find_port_to_graph(MMAL_GRAPH_PRIVATE_T *graph, MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = graph->graph_component;
+   MMAL_PORT_T **list, **component_list;
+   unsigned int i, *list_num;
+
+   switch (port->type)
+   {
+   case MMAL_PORT_TYPE_INPUT:
+      list = graph->input;
+      list_num = &graph->input_num;
+      component_list = component->input;
+      break;
+   case MMAL_PORT_TYPE_OUTPUT:
+      list = graph->output;
+      list_num = &graph->output_num;
+      component_list = component->output;
+      break;
+   case MMAL_PORT_TYPE_CLOCK:
+      list = graph->clock;
+      list_num = &graph->clock_num;
+      component_list = component->clock;
+      break;
+   default:
+      return 0;
+   }
+
+   for (i = 0; i < *list_num; i++)
+      if (list[i] == port)
+         break;
+
+   if (i == *list_num)
+      return 0;
+   return component_list[i];
+}
+
+static MMAL_STATUS_T graph_port_update(MMAL_GRAPH_PRIVATE_T *graph,
+   MMAL_PORT_T *graph_port, MMAL_BOOL_T init)
+{
+   MMAL_STATUS_T status;
+   MMAL_PORT_T *port;
+
+   port = find_port_from_graph(graph, graph_port);
+   if (!port)
+   {
+      LOG_ERROR("could not find matching port for %p", graph_port);
+      return MMAL_EINVAL;
+   }
+
+   status = mmal_format_full_copy(graph_port->format, port->format);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("format copy failed on port %s", port->name);
+      return status;
+   }
+
+   graph_port->buffer_num_min = port->buffer_num_min;
+   graph_port->buffer_num_recommended = port->buffer_num_recommended;
+   graph_port->buffer_size_min = port->buffer_size_min;
+   graph_port->buffer_size_recommended = port->buffer_size_recommended;
+   graph_port->buffer_alignment_min = port->buffer_alignment_min;
+   graph_port->capabilities = port->capabilities;
+   if (init)
+   {
+      graph_port->buffer_num = port->buffer_num;
+      graph_port->buffer_size = port->buffer_size;
+   }
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T graph_port_update_requirements(MMAL_GRAPH_PRIVATE_T *graph,
+   MMAL_PORT_T *graph_port)
+{
+   MMAL_PORT_T *port;
+
+   port = find_port_from_graph(graph, graph_port);
+   if (!port)
+   {
+      LOG_ERROR("could not find matching port for %p", graph_port);
+      return MMAL_EINVAL;
+   }
+
+   graph_port->buffer_num_min = port->buffer_num_min;
+   graph_port->buffer_num_recommended = port->buffer_num_recommended;
+   graph_port->buffer_size_min = port->buffer_size_min;
+   graph_port->buffer_size_recommended = port->buffer_size_recommended;
+   graph_port->buffer_alignment_min = port->buffer_alignment_min;
+   return MMAL_SUCCESS;
+}
+
+/** Destroy a previously created component */
+static MMAL_STATUS_T graph_component_destroy(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *graph = component->priv->module;
+
+   /* Notify client of destruction */
+   if (graph->graph.pf_destroy)
+      graph->graph.pf_destroy(&graph->graph);
+   graph->graph.pf_destroy = NULL;
+
+   if (component->input_num)
+      mmal_ports_free(component->input, component->input_num);
+
+   if (component->output_num)
+      mmal_ports_free(component->output, component->output_num);
+
+   if (component->clock_num)
+      mmal_ports_clock_free(component->clock, component->clock_num);
+
+   /* coverity[address_free] Freeing the first item in the structure is safe */
+   mmal_graph_destroy(&graph->graph);
+   return MMAL_SUCCESS;
+}
+
+/** Enable processing on a component */
+static MMAL_STATUS_T graph_component_enable(MMAL_COMPONENT_T *component)
+{
+   MMAL_GRAPH_PRIVATE_T *graph_private = component->priv->module;
+   MMAL_STATUS_T status = MMAL_ENOSYS;
+
+   /* Call user defined function first */
+   if (graph_private->graph.pf_graph_enable)
+      status = graph_private->graph.pf_graph_enable(&graph_private->graph, MMAL_TRUE);
+
+   return status;
+}
+
+/** Disable processing on a component */
+static MMAL_STATUS_T graph_component_disable(MMAL_COMPONENT_T *component)
+{
+   MMAL_GRAPH_PRIVATE_T *graph_private = component->priv->module;
+   MMAL_STATUS_T status = MMAL_ENOSYS;
+
+   /* Call user defined function first */
+   if (graph_private->graph.pf_graph_enable)
+      status = graph_private->graph.pf_graph_enable(&graph_private->graph, MMAL_FALSE);
+
+   return status;
+}
+
+/** Callback given to mmal_port_enable() */
+static void graph_port_enable_cb(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_GRAPH_PRIVATE_T *graph_private = (MMAL_GRAPH_PRIVATE_T *)port->userdata;
+   MMAL_PORT_T *graph_port;
+   MMAL_STATUS_T status;
+
+   graph_port = find_port_to_graph(graph_private, port);
+   if (!graph_port)
+   {
+      vcos_assert(0);
+      mmal_buffer_header_release(buffer);
+      return;
+   }
+
+   /* Call user defined function first */
+   if (graph_private->graph.pf_return_buffer)
+   {
+      status = graph_private->graph.pf_return_buffer(&graph_private->graph, graph_port, buffer);
+      if (status != MMAL_ENOSYS)
+         return;
+   }
+
+   /* Forward the callback */
+   if (buffer->cmd)
+      mmal_port_event_send(graph_port, buffer);
+   else
+      mmal_port_buffer_header_callback(graph_port, buffer);
+}
+
+/** Check whether 2 ports of a component are linked */
+static MMAL_BOOL_T graph_component_topology_ports_linked(MMAL_GRAPH_PRIVATE_T *graph,
+   MMAL_PORT_T *port1, MMAL_PORT_T *port2)
+{
+   MMAL_COMPONENT_T *component = port1->component;
+   unsigned int i;
+
+   for (i = 0; i < graph->component_num; i++)
+      if (component == graph->component[i])
+         break;
+
+   if (i == graph->component_num)
+      return MMAL_FALSE; /* Component not found */
+
+   if (graph->topology[i] == MMAL_GRAPH_TOPOLOGY_STRAIGHT)
+      return port1->index == port2->index;
+
+   return MMAL_TRUE;
+}
+
+/** Propagate a port enable */
+static MMAL_STATUS_T graph_port_state_propagate(MMAL_GRAPH_PRIVATE_T *graph,
+   MMAL_PORT_T *port, MMAL_BOOL_T enable)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   MMAL_PORT_TYPE_T type = port->type;
+   unsigned int i, j;
+
+   LOG_TRACE("graph: %p, port %s(%p)", graph, port->name, port);
+
+   if (port->type == MMAL_PORT_TYPE_OUTPUT)
+      type = MMAL_PORT_TYPE_INPUT;
+   if (port->type == MMAL_PORT_TYPE_INPUT)
+      type = MMAL_PORT_TYPE_OUTPUT;
+
+   /* Loop through all the output ports of the component and if they are not enabled and
+    * match one of the connections we maintain, then we need to propagate the port enable. */
+   for (i = 0; i < component->port_num; i++)
+   {
+      if (component->port[i]->type != type)
+         continue;
+
+      if ((component->port[i]->is_enabled && enable) ||
+          (!component->port[i]->is_enabled && !enable))
+         continue;
+
+      /* Find the matching connection */
+      for (j = 0; j < graph->connection_num; j++)
+         if (graph->connection[j]->out == component->port[i] ||
+             graph->connection[j]->in == component->port[i])
+            break;
+
+      if (j == graph->connection_num)
+         continue; /* No match */
+
+      if (!graph_component_topology_ports_linked(graph, port, component->port[i]))
+            continue; /* Ports are independent */
+
+      if (enable)
+      {
+         status = mmal_connection_enable(graph->connection[j]);
+         if (status != MMAL_SUCCESS)
+            break;
+
+         mmal_log_dump_port(graph->connection[j]->out);
+         mmal_log_dump_port(graph->connection[j]->in);
+      }
+
+      status = graph_port_state_propagate(graph, graph->connection[j]->in == component->port[i] ?
+         graph->connection[j]->out : graph->connection[j]->in, enable);
+      if (status != MMAL_SUCCESS)
+         break;
+
+      if (!enable)
+      {
+         status = mmal_connection_disable(graph->connection[j]);
+         if (status != MMAL_SUCCESS)
+            break;
+      }
+   }
+
+   return status;
+}
+
+/** Enable processing on a port */
+static MMAL_STATUS_T graph_port_enable(MMAL_PORT_T *graph_port, MMAL_PORT_BH_CB_T cb)
+{
+   MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
+   MMAL_PORT_T *port;
+   MMAL_STATUS_T status;
+   MMAL_PARAM_UNUSED(cb);
+
+   port = find_port_from_graph(graph_private, graph_port);
+   if (!port)
+      return MMAL_EINVAL;
+
+   /* Update the buffer requirements */
+   port->buffer_num = graph_port->buffer_num;
+   port->buffer_size = graph_port->buffer_size;
+
+   /* Call user defined function first */
+   if (graph_private->graph.pf_enable)
+   {
+      status = graph_private->graph.pf_enable(&graph_private->graph, graph_port);
+      if (status != MMAL_ENOSYS)
+         return status;
+   }
+
+   /* We'll intercept the callback */
+   port->userdata = (void *)graph_private;
+   status = mmal_port_enable(port, graph_port_enable_cb);
+   if (status != MMAL_SUCCESS)
+      return status;
+
+   /* We need to enable all the connected connections */
+   status = graph_port_state_propagate(graph_private, port, 1);
+
+   mmal_component_action_trigger(graph_port->component);
+   return status;
+}
+
+/** Disable processing on a port */
+static MMAL_STATUS_T graph_port_disable(MMAL_PORT_T *graph_port)
+{
+   MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
+   MMAL_STATUS_T status;
+   MMAL_PORT_T *port;
+
+   port = find_port_from_graph(graph_port->component->priv->module, graph_port);
+   if (!port)
+      return MMAL_EINVAL;
+
+   /* Call user defined function first */
+   if (graph_private->graph.pf_disable)
+   {
+      status = graph_private->graph.pf_disable(&graph_private->graph, graph_port);
+      if (status != MMAL_ENOSYS)
+         return status;
+   }
+
+   /* We need to disable all the connected connections.
+    * Since disable does an implicit flush, we only want to do that if
+    * we're acting on an input port or we risk discarding buffers along
+    * the way. */
+   if (!graph_private->input_num || port->type == MMAL_PORT_TYPE_INPUT)
+   {
+      MMAL_STATUS_T status = graph_port_state_propagate(graph_private, port, 0);
+      if (status != MMAL_SUCCESS)
+         return status;
+   }
+
+   /* Forward the call */
+   return mmal_port_disable(port);
+}
+
+/** Propagate a port flush */
+static MMAL_STATUS_T graph_port_flush_propagate(MMAL_GRAPH_PRIVATE_T *graph,
+   MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_STATUS_T status;
+   unsigned int i, j;
+
+   LOG_TRACE("graph: %p, port %s(%p)", graph, port->name, port);
+
+   status = mmal_port_flush(port);
+   if (status != MMAL_SUCCESS)
+      return status;
+
+   if (port->type == MMAL_PORT_TYPE_OUTPUT)
+      return MMAL_SUCCESS;
+
+   /* Loop through all the output ports of the component and if they match one
+    * of the connections we maintain, then we need to propagate the flush. */
+   for (i = 0; i < component->port_num; i++)
+   {
+      if (component->port[i]->type != MMAL_PORT_TYPE_OUTPUT)
+         continue;
+      if (!component->port[i]->is_enabled)
+         continue;
+
+      /* Find the matching connection */
+      for (j = 0; j < graph->connection_num; j++)
+         if (graph->connection[j]->out == component->port[i])
+            break;
+
+      if (j == graph->connection_num)
+         continue; /* No match */
+
+      if (!graph_component_topology_ports_linked(graph, port, component->port[i]))
+         continue; /* Ports are independent */
+
+      /* Flush any buffer waiting in the connection queue */
+      if (graph->connection[j]->queue)
+      {
+         MMAL_BUFFER_HEADER_T *buffer = mmal_queue_get(graph->connection[j]->queue);
+         while(buffer)
+         {
+            mmal_buffer_header_release(buffer);
+            buffer = mmal_queue_get(graph->connection[j]->queue);
+         }
+      }
+
+      status = graph_port_flush_propagate(graph, graph->connection[j]->in);
+      if (status != MMAL_SUCCESS)
+         break;
+   }
+
+   return status;
+}
+
+/** Flush a port */
+static MMAL_STATUS_T graph_port_flush(MMAL_PORT_T *graph_port)
+{
+   MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
+   MMAL_STATUS_T status;
+   MMAL_PORT_T *port;
+
+   port = find_port_from_graph(graph_private, graph_port);
+   if (!port)
+      return MMAL_EINVAL;
+
+   /* Call user defined function first */
+   if (graph_private->graph.pf_flush)
+   {
+      status = graph_private->graph.pf_flush(&graph_private->graph, graph_port);
+      if (status != MMAL_ENOSYS)
+         return status;
+   }
+
+   /* Forward the call */
+   return graph_port_flush_propagate(graph_private, port);
+}
+
+/** Send a buffer header to a port */
+static MMAL_STATUS_T graph_port_send(MMAL_PORT_T *graph_port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
+   MMAL_STATUS_T status;
+   MMAL_PORT_T *port;
+
+   port = find_port_from_graph(graph_port->component->priv->module, graph_port);
+   if (!port)
+      return MMAL_EINVAL;
+
+   /* Call user defined function first */
+   if (graph_private->graph.pf_send_buffer)
+   {
+      status = graph_private->graph.pf_send_buffer(&graph_private->graph, graph_port, buffer);
+      if (status != MMAL_ENOSYS)
+         return status;
+   }
+
+   /* Forward the call */
+   return mmal_port_send_buffer(port, buffer);
+}
+
+/** Propagate a format change */
+static MMAL_STATUS_T graph_port_format_commit_propagate(MMAL_GRAPH_PRIVATE_T *graph,
+   MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   unsigned int i, j;
+
+   LOG_TRACE("graph: %p, port %s(%p)", graph, port->name, port);
+
+   if (port->type == MMAL_PORT_TYPE_OUTPUT || port->type == MMAL_PORT_TYPE_CLOCK)
+      return MMAL_SUCCESS; /* Nothing to do */
+
+   /* Loop through all the output ports of the component and if they are not enabled and
+    * match one of the connections we maintain, then we need to propagate the format change. */
+   for (i = 0; i < component->output_num; i++)
+   {
+      MMAL_PORT_T *in, *out;
+
+      if (component->output[i]->is_enabled)
+         continue;
+
+      /* Find the matching connection */
+      for (j = 0; j < graph->connection_num; j++)
+         if (graph->connection[j]->out == component->output[i])
+            break;
+
+      if (j == graph->connection_num)
+         continue; /* No match */
+
+      if (!graph_component_topology_ports_linked(graph, port, component->output[i]))
+         continue; /* Ports are independent */
+
+      in = graph->connection[j]->in;
+      out = graph->connection[j]->out;
+
+      /* Apply the format to the input port */
+      status = mmal_format_full_copy(in->format, out->format);
+      if (status != MMAL_SUCCESS)
+         break;
+      status = mmal_port_format_commit(in);
+      if (status != MMAL_SUCCESS)
+         break;
+
+      mmal_log_dump_port(out);
+      mmal_log_dump_port(in);
+
+      status = graph_port_format_commit_propagate(graph, in);
+      if (status != MMAL_SUCCESS)
+         break;
+   }
+
+   return status;
+}
+
+/** Set format on a port */
+static MMAL_STATUS_T graph_port_format_commit(MMAL_PORT_T *graph_port)
+{
+   MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
+   MMAL_STATUS_T status;
+   MMAL_PORT_T *port;
+   unsigned int i;
+
+   /* Call user defined function first */
+   if (graph_private->graph.pf_format_commit)
+   {
+      status = graph_private->graph.pf_format_commit(&graph_private->graph, graph_port);
+      if (status == MMAL_SUCCESS)
+         goto end;
+      if (status != MMAL_ENOSYS)
+         return status;
+   }
+
+   port = find_port_from_graph(graph_private, graph_port);
+   if (!port)
+      return MMAL_EINVAL;
+
+   /* Update actual port */
+   status = mmal_format_full_copy(port->format, graph_port->format);
+   if (status != MMAL_SUCCESS)
+      return status;
+   port->buffer_num = graph_port->buffer_num;
+   port->buffer_size = graph_port->buffer_size;
+
+   /* Forward the call */
+   status = mmal_port_format_commit(port);
+   if (status != MMAL_SUCCESS)
+      return status;
+
+   /* Propagate format changes to the connections */
+   status = graph_port_format_commit_propagate(graph_private, port);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("couldn't propagate format commit of port %s(%p)", port->name, port);
+      return status;
+   }
+
+ end:
+   /* Read the values back */
+   status = graph_port_update(graph_private, graph_port, MMAL_FALSE);
+   if (status != MMAL_SUCCESS)
+      return status;
+
+   /* Get the settings for the output ports in case they have changed */
+   if (graph_port->type == MMAL_PORT_TYPE_INPUT)
+   {
+      for (i = 0; i < graph_private->output_num; i++)
+      {
+         status = graph_port_update(graph_private, graph_port->component->output[i], MMAL_FALSE);
+         if (status != MMAL_SUCCESS)
+            return status;
+      }
+   }
+
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T graph_port_control_parameter_get(MMAL_PORT_T *graph_port,
+   MMAL_PARAMETER_HEADER_T *param)
+{
+   MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
+   MMAL_STATUS_T status = MMAL_ENOSYS;
+   unsigned int i;
+
+   /* Call user defined function first */
+   if (graph_private->graph.pf_parameter_get)
+   {
+      status = graph_private->graph.pf_parameter_get(&graph_private->graph, graph_port, param);
+      if (status != MMAL_ENOSYS)
+         return status;
+   }
+
+   /* By default we do a get parameter on each component until one succeeds */
+   for (i = 0; i < graph_private->component_num && status != MMAL_SUCCESS; i++)
+      status = mmal_port_parameter_get(graph_private->component[i]->control, param);
+
+   return status;
+}
+
+static MMAL_STATUS_T graph_port_parameter_get(MMAL_PORT_T *graph_port,
+   MMAL_PARAMETER_HEADER_T *param)
+{
+   MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
+   MMAL_STATUS_T status;
+   MMAL_PORT_T *port;
+
+   /* Call user defined function first */
+   if (graph_private->graph.pf_parameter_get)
+   {
+      status = graph_private->graph.pf_parameter_get(&graph_private->graph, graph_port, param);
+      if (status != MMAL_ENOSYS)
+         return status;
+   }
+
+   port = find_port_from_graph(graph_private, graph_port);
+   if (!port)
+      return MMAL_EINVAL;
+
+   /* Forward the call */
+   return mmal_port_parameter_get(port, param);
+}
+
+static MMAL_STATUS_T graph_port_control_parameter_set(MMAL_PORT_T *graph_port,
+   const MMAL_PARAMETER_HEADER_T *param)
+{
+   MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
+   MMAL_STATUS_T status = MMAL_ENOSYS;
+   unsigned int i;
+
+   /* Call user defined function first */
+   if (graph_private->graph.pf_parameter_set)
+   {
+      status = graph_private->graph.pf_parameter_set(&graph_private->graph, graph_port, param);
+      if (status != MMAL_ENOSYS)
+         return status;
+   }
+
+   /* By default we do a set parameter on each component until one succeeds */
+   for (i = 0; i < graph_private->component_num && status != MMAL_SUCCESS; i++)
+      status = mmal_port_parameter_set(graph_private->component[i]->control, param);
+
+   return status;
+}
+
+static MMAL_STATUS_T graph_port_parameter_set(MMAL_PORT_T *graph_port,
+   const MMAL_PARAMETER_HEADER_T *param)
+{
+   MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
+   MMAL_STATUS_T status;
+   MMAL_PORT_T *port;
+
+   /* Call user defined function first */
+   if (graph_private->graph.pf_parameter_set)
+   {
+      status = graph_private->graph.pf_parameter_set(&graph_private->graph, graph_port, param);
+      if (status != MMAL_ENOSYS)
+         return status;
+   }
+
+   port = find_port_from_graph(graph_private, graph_port);
+   if (!port)
+      return MMAL_EINVAL;
+
+   /* Forward the call */
+   status = mmal_port_parameter_set(port, param);
+   if (status != MMAL_SUCCESS)
+      goto end;
+
+   if (param->id == MMAL_PARAMETER_BUFFER_REQUIREMENTS)
+   {
+      /* This might have changed the buffer requirements of other ports so fetch them all */
+      MMAL_COMPONENT_T *component = graph_port->component;
+      unsigned int i;
+      for (i = 0; status == MMAL_SUCCESS && i < component->input_num; i++)
+         status = graph_port_update_requirements(graph_private, component->input[i]);
+      for (i = 0; status == MMAL_SUCCESS && i < component->output_num; i++)
+         status = graph_port_update_requirements(graph_private, component->output[i]);
+   }
+
+ end:
+   return status;
+}
+
+static MMAL_STATUS_T graph_port_connect(MMAL_PORT_T *graph_port, MMAL_PORT_T *other_port)
+{
+   MMAL_PORT_T *port;
+
+   LOG_TRACE("%s(%p) %s(%p)", graph_port->name, graph_port, other_port->name, other_port);
+
+   port = find_port_from_graph(graph_port->component->priv->module, graph_port);
+   if (!port)
+      return MMAL_EINVAL;
+
+   /* Forward the call */
+   return other_port ? mmal_port_connect(port, other_port) : mmal_port_disconnect(port);
+}
+
+static uint8_t *graph_port_payload_alloc(MMAL_PORT_T *graph_port, uint32_t payload_size)
+{
+   MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
+   MMAL_STATUS_T status;
+   MMAL_PORT_T *port;
+   uint8_t *payload;
+
+   port = find_port_from_graph(graph_port->component->priv->module, graph_port);
+   if (!port)
+      return 0;
+
+   /* Call user defined function first */
+   if (graph_private->graph.pf_payload_alloc)
+   {
+      status = graph_private->graph.pf_payload_alloc(&graph_private->graph, graph_port,
+         payload_size, &payload);
+      if (status != MMAL_ENOSYS)
+         return status == MMAL_SUCCESS ? payload : NULL;
+   }
+
+   /* Forward the call */
+   return mmal_port_payload_alloc(port, payload_size);
+}
+
+static void graph_port_payload_free(MMAL_PORT_T *graph_port, uint8_t *payload)
+{
+   MMAL_GRAPH_PRIVATE_T *graph_private = graph_port->component->priv->module;
+   MMAL_STATUS_T status;
+   MMAL_PORT_T *port;
+
+   port = find_port_from_graph(graph_port->component->priv->module, graph_port);
+   if (!port)
+      return;
+
+   /* Call user defined function first */
+   if (graph_private->graph.pf_payload_free)
+   {
+      status = graph_private->graph.pf_payload_free(&graph_private->graph, graph_port, payload);
+      if (status == MMAL_SUCCESS)
+         return;
+   }
+
+   /* Forward the call */
+   mmal_port_payload_free(port, payload);
+}
+
+/** Create an instance of a component  */
+static MMAL_STATUS_T mmal_component_create_from_graph(const char *name, MMAL_COMPONENT_T *component)
+{
+   MMAL_STATUS_T status = MMAL_ENOMEM;
+   /* Our context is already allocated and available */
+   MMAL_GRAPH_PRIVATE_T *graph = component->priv->module;
+   unsigned int i;
+   MMAL_PARAM_UNUSED(name);
+
+   component->control->priv->pf_parameter_get = graph_port_control_parameter_get;
+   component->control->priv->pf_parameter_set = graph_port_control_parameter_set;
+
+   /* Allocate the ports for this component */
+   if(graph->input_num)
+   {
+      component->input = mmal_ports_alloc(component, graph->input_num, MMAL_PORT_TYPE_INPUT, 0);
+      if(!component->input)
+         goto error;
+   }
+   component->input_num = graph->input_num;
+   for(i = 0; i < component->input_num; i++)
+   {
+      component->input[i]->priv->pf_enable = graph_port_enable;
+      component->input[i]->priv->pf_disable = graph_port_disable;
+      component->input[i]->priv->pf_flush = graph_port_flush;
+      component->input[i]->priv->pf_send = graph_port_send;
+      component->input[i]->priv->pf_set_format = graph_port_format_commit;
+      component->input[i]->priv->pf_parameter_get = graph_port_parameter_get;
+      component->input[i]->priv->pf_parameter_set = graph_port_parameter_set;
+      if (graph->input[i]->priv->pf_connect && 0 /* FIXME: disabled for now */)
+         component->input[i]->priv->pf_connect = graph_port_connect;
+      component->input[i]->priv->pf_payload_alloc = graph_port_payload_alloc;
+      component->input[i]->priv->pf_payload_free = graph_port_payload_free;
+
+      /* Mirror the port values */
+      status = graph_port_update(graph, component->input[i], MMAL_TRUE);
+      if (status != MMAL_SUCCESS)
+         goto error;
+   }
+   if(graph->output_num)
+   {
+      component->output = mmal_ports_alloc(component, graph->output_num, MMAL_PORT_TYPE_OUTPUT, 0);
+      if(!component->output)
+         goto error;
+   }
+   component->output_num = graph->output_num;
+   for(i = 0; i < component->output_num; i++)
+   {
+      component->output[i]->priv->pf_enable = graph_port_enable;
+      component->output[i]->priv->pf_disable = graph_port_disable;
+      component->output[i]->priv->pf_flush = graph_port_flush;
+      component->output[i]->priv->pf_send = graph_port_send;
+      component->output[i]->priv->pf_set_format = graph_port_format_commit;
+      component->output[i]->priv->pf_parameter_get = graph_port_parameter_get;
+      component->output[i]->priv->pf_parameter_set = graph_port_parameter_set;
+      if (graph->output[i]->priv->pf_connect && 0 /* FIXME: disabled for now */)
+         component->output[i]->priv->pf_connect = graph_port_connect;
+      component->output[i]->priv->pf_payload_alloc = graph_port_payload_alloc;
+      component->output[i]->priv->pf_payload_free = graph_port_payload_free;
+
+      /* Mirror the port values */
+      status = graph_port_update(graph, component->output[i], MMAL_TRUE);
+      if (status != MMAL_SUCCESS)
+         goto error;
+   }
+   if(graph->clock_num)
+   {
+      component->clock = mmal_ports_clock_alloc(component, graph->clock_num, 0, NULL);
+      if(!component->clock)
+      {
+         status = MMAL_ENOMEM;
+         goto error;
+      }
+   }
+   component->clock_num = graph->clock_num;
+   for(i = 0; i < component->clock_num; i++)
+   {
+      component->clock[i]->priv->pf_enable = graph_port_enable;
+      component->clock[i]->priv->pf_disable = graph_port_disable;
+      component->clock[i]->priv->pf_flush = graph_port_flush;
+      component->clock[i]->priv->pf_send = graph_port_send;
+      component->clock[i]->priv->pf_set_format = graph_port_format_commit;
+      component->clock[i]->priv->pf_parameter_get = graph_port_parameter_get;
+      component->clock[i]->priv->pf_parameter_set = graph_port_parameter_set;
+      component->clock[i]->priv->pf_connect = NULL; /* FIXME: disabled for now */
+      component->clock[i]->priv->pf_payload_alloc = graph_port_payload_alloc;
+      component->clock[i]->priv->pf_payload_free = graph_port_payload_free;
+
+      /* Mirror the port values */
+      status = graph_port_update(graph, component->clock[i], MMAL_TRUE);
+      if (status != MMAL_SUCCESS)
+         goto error;
+   }
+
+   status = mmal_component_action_register(component, graph_do_processing_loop);
+   if (status != MMAL_SUCCESS)
+      goto error;
+
+#if 1 // FIXME
+   /* Set our connection callback */
+   for (i = 0; i < graph->connection_num; i++)
+   {
+      graph->connection[i]->callback = graph_component_connection_cb;
+      graph->connection[i]->user_data = (void *)component;
+   }
+#endif
+
+   component->priv->pf_destroy = graph_component_destroy;
+   component->priv->pf_enable = graph_component_enable;
+   component->priv->pf_disable = graph_component_disable;
+   graph->graph_component = component;
+
+   /* Enable all the control ports */
+   for (i = 0; i < graph->component_num; i++)
+   {
+      graph->component[i]->control->userdata = (void *)component;
+      status = mmal_port_enable(graph->component[i]->control, graph_component_control_cb);
+      if (status != MMAL_SUCCESS)
+         LOG_ERROR("could not enable port %s", component->control->name);
+   }
+
+   return MMAL_SUCCESS;
+
+ error:
+   graph_component_destroy(component);
+   return status;
+}
+
+MMAL_PORT_T *mmal_graph_find_port(MMAL_GRAPH_T *graph,
+                                  const char *name,
+                                  MMAL_PORT_TYPE_T type,
+                                  unsigned index)
+{
+   unsigned i;
+   MMAL_GRAPH_PRIVATE_T *private = (MMAL_GRAPH_PRIVATE_T *)graph;
+   for (i=0; i<private->component_num; i++)
+   {
+      MMAL_COMPONENT_T *comp = private->component[i];
+      if (vcos_strcasecmp(name, comp->name) == 0)
+      {
+         unsigned num;
+         MMAL_PORT_T **ports;
+         if (type == MMAL_PORT_TYPE_INPUT) {
+            num = comp->input_num;
+            ports = comp->input;
+         }
+         else if (type == MMAL_PORT_TYPE_OUTPUT) {
+            num = comp->output_num;
+            ports = comp->output;
+         }
+         else if (type == MMAL_PORT_TYPE_CLOCK) {
+            num = comp->clock_num;
+            ports = comp->clock;
+         }
+         else if (type == MMAL_PORT_TYPE_CONTROL) {
+            num = 1;
+            ports = &comp->control;
+         }
+         else {
+            vcos_assert(0);
+            return NULL;
+         }
+         if (index < num)
+         {
+            /* coverity[ptr_arith] num is 1 at this point */
+            return ports[index];
+         }
+      }
+   }
+   LOG_INFO("port %s:%d not found", name, index);
+   return NULL;
+}
diff --git a/interface/mmal/util/mmal_graph.h b/interface/mmal/util/mmal_graph.h
new file mode 100755 (executable)
index 0000000..e6284ba
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_GRAPH_H
+#define MMAL_GRAPH_H
+
+#include "util/mmal_connection.h"
+
+/** \defgroup MmalGraphUtility Graph Utility
+ * \ingroup MmalUtilities
+ * The graph utility functions allows one to easily create graphs of MMAL components.
+ *
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** List of topology types */
+typedef enum
+{
+   MMAL_GRAPH_TOPOLOGY_ALL = 0,    /**< All input ports and output ports are linked */
+   MMAL_GRAPH_TOPOLOGY_STRAIGHT,   /**< Input ports and output ports of the same index are linked */
+   MMAL_GRAPH_TOPOLOGY_CUSTOM,     /**< Custom defined topology */
+   MMAL_GRAPH_TOPOLOGY_MAX
+
+} MMAL_GRAPH_TOPOLOGY_T;
+
+/** Structure describing a graph */
+typedef struct MMAL_GRAPH_T
+{
+   /** Pointer to private data of the client */
+   struct MMAL_GRAPH_USERDATA_T *userdata;
+
+   /** Optional callback that the client can set to get notified when the graph is going to be destroyed */
+   void (*pf_destroy)(struct MMAL_GRAPH_T *);
+
+   /** Optional callback that the client can set to intercept parameter requests on ports exposed by the graph */
+   MMAL_STATUS_T (*pf_parameter_set)(struct MMAL_GRAPH_T *, MMAL_PORT_T *port, const MMAL_PARAMETER_HEADER_T *param);
+   /** Optional callback that the client can set to intercept parameter requests on ports exposed by the graph */
+   MMAL_STATUS_T (*pf_parameter_get)(struct MMAL_GRAPH_T *, MMAL_PORT_T *port, MMAL_PARAMETER_HEADER_T *param);
+   /** Optional callback that the client can set to intercept format commit calls on ports exposed by the graph */
+   MMAL_STATUS_T (*pf_format_commit)(struct MMAL_GRAPH_T *, MMAL_PORT_T *port);
+   /** Optional callback that the client can set to intercept send buffer calls on ports exposed by the graph */
+   MMAL_STATUS_T (*pf_send_buffer)(struct MMAL_GRAPH_T *, MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
+   /** Optional callback that the client can set to intercept buffer callbacks on ports exposed by the graph */
+   MMAL_STATUS_T (*pf_return_buffer)(struct MMAL_GRAPH_T *, MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
+   /** Optional callback that the client can set to intercept payload alloc calls on ports exposed by the graph */
+   MMAL_STATUS_T (*pf_payload_alloc)(struct MMAL_GRAPH_T *, MMAL_PORT_T *port, uint32_t payload_size, uint8_t **);
+   /** Optional callback that the client can set to intercept payload free calls on ports exposed by the graph */
+   MMAL_STATUS_T (*pf_payload_free)(struct MMAL_GRAPH_T *, MMAL_PORT_T *port, uint8_t *payload);
+   /** Optional callback that the client can set to intercept flush calls on ports exposed by the graph */
+   MMAL_STATUS_T (*pf_flush)(struct MMAL_GRAPH_T *, MMAL_PORT_T *port);
+   /** Optional callback that the client can set to control callbacks from the internal components of the graph */
+   /** Optional callback that the client can set to intercept enable calls on ports exposed by the graph */
+   MMAL_STATUS_T (*pf_enable)(struct MMAL_GRAPH_T *, MMAL_PORT_T *port);
+   /** Optional callback that the client can set to intercept disable calls on ports exposed by the graph */
+   MMAL_STATUS_T (*pf_disable)(struct MMAL_GRAPH_T *, MMAL_PORT_T *port);
+   /** Optional callback that the client can set to control callbacks from the internal components of the graph */
+   MMAL_STATUS_T (*pf_control_callback)(struct MMAL_GRAPH_T *, MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer);
+   /** Optional callback that the client can set to intercept component_enable/disable calls made to the graph */
+   MMAL_STATUS_T (*pf_graph_enable)(struct MMAL_GRAPH_T *, MMAL_BOOL_T enable);
+   /** Optional callback that the client can set to intercept buffers going through internal connections.
+    * This will only be triggered if the connection is not tunnelled */
+   MMAL_STATUS_T (*pf_connection_buffer)(struct MMAL_GRAPH_T *, MMAL_CONNECTION_T *connection, MMAL_BUFFER_HEADER_T *buffer);
+
+} MMAL_GRAPH_T;
+
+/** Create an instance of a graph.
+ * The newly created graph will need to be populated by the client.
+ *
+ * @param graph returned graph
+ * @param userdata_size size to be allocated for the userdata field
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_graph_create(MMAL_GRAPH_T **graph, unsigned int userdata_size);
+
+/** Add a component to a graph.
+ * Allows the client to add a component to the graph.
+ *
+ * @param graph instance of the graph
+ * @param component component to add to a graph
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_graph_add_component(MMAL_GRAPH_T *graph, MMAL_COMPONENT_T *component);
+
+/** Describe the topology of the ports of a component.
+ * Allows the client to describe the topology of a component. This information
+ * is used by the graph to choose which action to perform when
+ * enabling / disabling / committing / flushing a port exposed by the graph.
+ * Note that by default the topology of a component is set to MMAL_GRAPH_TOPOLOGY_ALL.
+ *
+ * @param graph instance of the graph
+ * @param component component to describe
+ * @param topology type of topology used by this component
+ * @param input output index (or -1 if sink) linked to each input port
+ * @param input_num number of indexes in the input list
+ * @param output input index (or -1 if source) linked to each output port
+ * @param output_num number of indexes in the output list
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_graph_component_topology(MMAL_GRAPH_T *graph, MMAL_COMPONENT_T *component,
+    MMAL_GRAPH_TOPOLOGY_T topology, int8_t *input, unsigned int input_num,
+    int8_t *output, unsigned int output_num);
+
+/** Add a port to a graph.
+ * Allows the client to add an input or output port to a graph. The given port
+ * will effectively become an end point for the graph.
+ *
+ * @param graph instance of the graph
+ * @param port port to add to the graph
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_graph_add_port(MMAL_GRAPH_T *graph, MMAL_PORT_T *port);
+
+/** Add a connection to a graph.
+ * Allows the client to add an internal connection to a graph.
+ *
+ * @param graph instance of the graph
+ * @param connection connection to add to the graph
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_graph_add_connection(MMAL_GRAPH_T *graph, MMAL_CONNECTION_T *connection);
+
+/** Create a new component and add it to a graph.
+ * Allows the client to create and add a component to the graph.
+ *
+ * @param graph instance of the graph
+ * @param name name of the component to create
+ * @param component if not NULL, will contain a pointer to the created component
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_graph_new_component(MMAL_GRAPH_T *graph, const char *name,
+   MMAL_COMPONENT_T **component);
+
+/** Create and add a connection to a graph.
+ * Allows the client to create and add an internal connection to a graph.
+ *
+ * @param graph      instance of the graph
+ * @param out        the output port to use for the connection
+ * @param in         the input port to use for the connection
+ * @param flags      the flags specifying which type of connection should be created
+ * @param connection if not NULL, will contain a pointer to the created connection
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_graph_new_connection(MMAL_GRAPH_T *graph, MMAL_PORT_T *out, MMAL_PORT_T *in,
+   uint32_t flags, MMAL_CONNECTION_T **connection);
+
+/** Definition of the callback used by a graph to send events to the client.
+ *
+ * @param graph   the graph sending the event
+ * @param port    the port which generated the event
+ * @param buffer  the buffer header containing the event data
+ * @param cb_data data passed back to the client when the callback is invoked
+ */
+typedef void (*MMAL_GRAPH_EVENT_CB)(MMAL_GRAPH_T *graph, MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer,
+   void *cb_data);
+
+/** Enable the graph and start processing.
+ *
+ * @param graph   the graph to enable
+ * @param cb      the callback to invoke when an event occurs on any of the internal control ports
+ * @param cb_data data passed back to the client when the callback is invoked
+ *
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_graph_enable(MMAL_GRAPH_T *graph, MMAL_GRAPH_EVENT_CB cb, void *cb_data);
+
+MMAL_STATUS_T mmal_graph_disable(MMAL_GRAPH_T *graph);
+
+/** Find a port in the graph.
+ *
+ * @param graph graph instance
+ * @param name  name of the component of interest
+ * @param type  type of port (in/out)
+ * @param index which port index within the component
+ *
+ * @return port, or NULL if not found
+ */
+MMAL_PORT_T *mmal_graph_find_port(MMAL_GRAPH_T *graph,
+                                  const char *name,
+                                  MMAL_PORT_TYPE_T type,
+                                  unsigned index);
+
+/** Create an instance of a component from a graph.
+ * The newly created component will expose input and output ports to the client.
+ * Not that all the exposed ports will be in a disabled state by default.
+ *
+ * @param graph graph to create the component from
+ * @param name name of the component to create
+ * @param component returned component
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_graph_build(MMAL_GRAPH_T *ctx,
+   const char *name, MMAL_COMPONENT_T **component);
+
+/** Component constructor for a graph.
+ * FIXME: private function
+ *
+ * @param name name of the component to create
+ * @param component component
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_graph_component_constructor(const char *name, MMAL_COMPONENT_T *component);
+
+/** Destroy a previously created graph
+ * @param graph graph to destroy
+ * @return MMAL_SUCCESS on success
+ */
+MMAL_STATUS_T mmal_graph_destroy(MMAL_GRAPH_T *ctx);
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+#endif /* MMAL_GRAPH_H */
diff --git a/interface/mmal/util/mmal_il.c b/interface/mmal/util/mmal_il.c
new file mode 100755 (executable)
index 0000000..8e0d8bb
--- /dev/null
@@ -0,0 +1,1022 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal.h"
+#include "util/mmal_il.h"
+#include "interface/vmcs_host/khronos/IL/OMX_Broadcom.h"
+
+/*****************************************************************************/
+static struct {
+   MMAL_STATUS_T mmal;
+   OMX_ERRORTYPE omx;
+} mmal_omx_error[] =
+{
+   {MMAL_SUCCESS, OMX_ErrorNone},
+   {MMAL_ENOMEM, OMX_ErrorInsufficientResources},
+   {MMAL_ENOSPC, OMX_ErrorInsufficientResources},
+   {MMAL_EINVAL, OMX_ErrorBadParameter},
+   {MMAL_ENOSYS, OMX_ErrorNotImplemented},
+   {(MMAL_STATUS_T)-1, OMX_ErrorUndefined},
+};
+
+OMX_ERRORTYPE mmalil_error_to_omx(MMAL_STATUS_T status)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_error[i].mmal != (MMAL_STATUS_T)-1; i++)
+      if(mmal_omx_error[i].mmal == status) break;
+   return mmal_omx_error[i].omx;
+}
+
+MMAL_STATUS_T mmalil_error_to_mmal(OMX_ERRORTYPE error)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_error[i].mmal != (MMAL_STATUS_T)-1; i++)
+      if(mmal_omx_error[i].omx == error) break;
+   return mmal_omx_error[i].mmal;
+}
+
+/*****************************************************************************/
+OMX_U32 mmalil_buffer_flags_to_omx(uint32_t flags)
+{
+   OMX_U32 omx_flags = 0;
+
+   if(flags & MMAL_BUFFER_HEADER_FLAG_KEYFRAME)
+      omx_flags |= OMX_BUFFERFLAG_SYNCFRAME;
+   if(flags & MMAL_BUFFER_HEADER_FLAG_FRAME_END)
+      omx_flags |= OMX_BUFFERFLAG_ENDOFFRAME;
+   if(flags & MMAL_BUFFER_HEADER_FLAG_EOS)
+      omx_flags |= OMX_BUFFERFLAG_EOS;
+   if(flags & MMAL_BUFFER_HEADER_FLAG_CONFIG)
+      omx_flags |= OMX_BUFFERFLAG_CODECCONFIG;
+   if(flags & MMAL_BUFFER_HEADER_FLAG_DISCONTINUITY)
+      omx_flags |= OMX_BUFFERFLAG_DISCONTINUITY;
+   if (flags & MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO)
+      omx_flags |= OMX_BUFFERFLAG_CODECSIDEINFO;
+   if (flags & MMAL_BUFFER_HEADER_FLAGS_SNAPSHOT)
+      omx_flags |= OMX_BUFFERFLAG_CAPTURE_PREVIEW;
+   if (flags & MMAL_BUFFER_HEADER_FLAG_CORRUPTED)
+      omx_flags |= OMX_BUFFERFLAG_DATACORRUPT;
+   if (flags & MMAL_BUFFER_HEADER_FLAG_DECODEONLY)
+      omx_flags |= OMX_BUFFERFLAG_DECODEONLY;
+   if (flags & MMAL_BUFFER_HEADER_VIDEO_FLAG_INTERLACED)
+      omx_flags |= OMX_BUFFERFLAG_INTERLACED;
+   if (flags & MMAL_BUFFER_HEADER_VIDEO_FLAG_TOP_FIELD_FIRST)
+     omx_flags |= OMX_BUFFERFLAG_TOP_FIELD_FIRST;
+   if (flags & MMAL_BUFFER_HEADER_FLAG_USER0)
+      omx_flags |= 1<<28;
+   if (flags & MMAL_BUFFER_HEADER_FLAG_USER1)
+      omx_flags |= 1<<29;
+   if (flags & MMAL_BUFFER_HEADER_FLAG_USER2)
+      omx_flags |= 1<<30;
+   if (flags & MMAL_BUFFER_HEADER_FLAG_USER3)
+      omx_flags |= 1<<31;
+
+   return omx_flags;
+}
+
+uint32_t mmalil_buffer_flags_to_mmal(OMX_U32 flags)
+{
+   uint32_t mmal_flags = 0;
+
+   if (flags & OMX_BUFFERFLAG_SYNCFRAME)
+      mmal_flags |= MMAL_BUFFER_HEADER_FLAG_KEYFRAME;
+   if (flags & OMX_BUFFERFLAG_ENDOFFRAME)
+      mmal_flags |= MMAL_BUFFER_HEADER_FLAG_FRAME_END;
+   if (flags & OMX_BUFFERFLAG_EOS)
+      mmal_flags |= MMAL_BUFFER_HEADER_FLAG_EOS;
+   if (flags & OMX_BUFFERFLAG_CODECCONFIG)
+      mmal_flags |= MMAL_BUFFER_HEADER_FLAG_CONFIG;
+   if (flags & OMX_BUFFERFLAG_DISCONTINUITY)
+      mmal_flags |= MMAL_BUFFER_HEADER_FLAG_DISCONTINUITY;
+   if (flags & OMX_BUFFERFLAG_CODECSIDEINFO)
+      mmal_flags |= MMAL_BUFFER_HEADER_FLAG_CODECSIDEINFO;
+   if (flags & OMX_BUFFERFLAG_CAPTURE_PREVIEW)
+      mmal_flags |= MMAL_BUFFER_HEADER_FLAGS_SNAPSHOT;
+   if (flags & OMX_BUFFERFLAG_DATACORRUPT)
+      mmal_flags |= MMAL_BUFFER_HEADER_FLAG_CORRUPTED;
+   if (flags & OMX_BUFFERFLAG_DECODEONLY)
+      mmal_flags |= MMAL_BUFFER_HEADER_FLAG_DECODEONLY;
+   if (flags & OMX_BUFFERFLAG_INTERLACED)
+      mmal_flags |= MMAL_BUFFER_HEADER_VIDEO_FLAG_INTERLACED;
+   if (flags & OMX_BUFFERFLAG_TOP_FIELD_FIRST)
+      mmal_flags |= MMAL_BUFFER_HEADER_VIDEO_FLAG_TOP_FIELD_FIRST;
+   if (flags & 1<<28)
+      mmal_flags |= MMAL_BUFFER_HEADER_FLAG_USER0;
+   if (flags & 1<<29)
+      mmal_flags |= MMAL_BUFFER_HEADER_FLAG_USER1;
+   if (flags & 1<<30)
+      mmal_flags |= MMAL_BUFFER_HEADER_FLAG_USER2;
+   if (flags & 1<<31)
+      mmal_flags |= MMAL_BUFFER_HEADER_FLAG_USER3;
+
+   return mmal_flags;
+}
+
+/*****************************************************************************/
+void mmalil_buffer_header_to_omx(OMX_BUFFERHEADERTYPE *omx, MMAL_BUFFER_HEADER_T *mmal)
+{
+   omx->pBuffer = mmal->data;
+   omx->nAllocLen = mmal->alloc_size;
+   omx->nFilledLen = mmal->length;
+   omx->nOffset = mmal->offset;
+   omx->nFlags = mmalil_buffer_flags_to_omx(mmal->flags);
+   omx->nTimeStamp = omx_ticks_from_s64(mmal->pts);
+   if (mmal->pts == MMAL_TIME_UNKNOWN)
+   {
+      if (mmal->dts == MMAL_TIME_UNKNOWN)
+      {
+         omx->nTimeStamp = omx_ticks_from_s64(0);
+         omx->nFlags |= OMX_BUFFERFLAG_TIME_UNKNOWN;
+      }
+      else
+      {
+        omx->nTimeStamp = omx_ticks_from_s64(mmal->dts);
+        omx->nFlags |= OMX_BUFFERFLAG_TIME_IS_DTS;
+      }
+   }
+}
+
+void mmalil_buffer_header_to_mmal(MMAL_BUFFER_HEADER_T *mmal, OMX_BUFFERHEADERTYPE *omx)
+{
+   mmal->cmd = 0;
+   mmal->data = omx->pBuffer;
+   mmal->alloc_size = omx->nAllocLen;
+   mmal->length = omx->nFilledLen;
+   mmal->offset = omx->nOffset;
+   if (omx->nFlags & OMX_BUFFERFLAG_TIME_IS_DTS)
+   {
+     mmal->dts = omx_ticks_to_s64(omx->nTimeStamp);
+     mmal->pts = MMAL_TIME_UNKNOWN;
+   }
+   else if (omx->nFlags & OMX_BUFFERFLAG_TIME_UNKNOWN)
+   {
+     mmal->dts = MMAL_TIME_UNKNOWN;
+     mmal->pts = MMAL_TIME_UNKNOWN;
+   }
+   else
+   {
+     mmal->dts = MMAL_TIME_UNKNOWN;
+     mmal->pts = omx_ticks_to_s64(omx->nTimeStamp);
+   }
+   mmal->flags = mmalil_buffer_flags_to_mmal(omx->nFlags);
+}
+
+/*****************************************************************************/
+static struct {
+   MMAL_ES_TYPE_T type;
+   OMX_PORTDOMAINTYPE domain;
+} mmal_omx_es_type_table[] =
+{
+   {MMAL_ES_TYPE_VIDEO,           OMX_PortDomainVideo},
+   {MMAL_ES_TYPE_VIDEO,           OMX_PortDomainImage},
+   {MMAL_ES_TYPE_AUDIO,           OMX_PortDomainAudio},
+   {MMAL_ES_TYPE_UNKNOWN,         OMX_PortDomainMax}
+};
+
+OMX_PORTDOMAINTYPE mmalil_es_type_to_omx_domain(MMAL_ES_TYPE_T type)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_es_type_table[i].type != MMAL_ES_TYPE_UNKNOWN; i++)
+      if(mmal_omx_es_type_table[i].type == type) break;
+   return mmal_omx_es_type_table[i].domain;
+}
+
+MMAL_ES_TYPE_T mmalil_omx_domain_to_es_type(OMX_PORTDOMAINTYPE domain)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_es_type_table[i].type != MMAL_ES_TYPE_UNKNOWN; i++)
+      if(mmal_omx_es_type_table[i].domain == domain) break;
+   return mmal_omx_es_type_table[i].type;
+}
+
+/*****************************************************************************/
+static struct {
+   uint32_t encoding;
+   OMX_AUDIO_CODINGTYPE coding;
+} mmal_omx_audio_coding_table[] =
+{
+   {MMAL_ENCODING_MP4A,           OMX_AUDIO_CodingAAC},
+   {MMAL_ENCODING_MPGA,           OMX_AUDIO_CodingMP3},
+   {MMAL_ENCODING_WMA2,           OMX_AUDIO_CodingWMA},
+   {MMAL_ENCODING_WMA1,           OMX_AUDIO_CodingWMA},
+   {MMAL_ENCODING_AMRNB,          OMX_AUDIO_CodingAMR},
+   {MMAL_ENCODING_AMRWB,          OMX_AUDIO_CodingAMR},
+   {MMAL_ENCODING_AMRWBP,         OMX_AUDIO_CodingAMR},
+   {MMAL_ENCODING_VORBIS,         OMX_AUDIO_CodingVORBIS},
+   {MMAL_ENCODING_ALAW,           OMX_AUDIO_CodingPCM},
+   {MMAL_ENCODING_MULAW,          OMX_AUDIO_CodingPCM},
+   {MMAL_ENCODING_PCM_SIGNED_LE,  OMX_AUDIO_CodingPCM},
+   {MMAL_ENCODING_PCM_UNSIGNED_LE,OMX_AUDIO_CodingPCM},
+   {MMAL_ENCODING_PCM_SIGNED_BE,  OMX_AUDIO_CodingPCM},
+   {MMAL_ENCODING_PCM_UNSIGNED_BE,OMX_AUDIO_CodingPCM},
+   {MMAL_ENCODING_AC3,            OMX_AUDIO_CodingDDP},
+   {MMAL_ENCODING_EAC3,           OMX_AUDIO_CodingDDP},
+   {MMAL_ENCODING_DTS,            OMX_AUDIO_CodingDTS},
+   {MMAL_ENCODING_UNKNOWN,        OMX_AUDIO_CodingUnused}
+};
+
+uint32_t mmalil_omx_audio_coding_to_encoding(OMX_AUDIO_CODINGTYPE coding)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_audio_coding_table[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
+      if(mmal_omx_audio_coding_table[i].coding == coding) break;
+   return mmal_omx_audio_coding_table[i].encoding;
+}
+
+OMX_AUDIO_CODINGTYPE mmalil_encoding_to_omx_audio_coding(uint32_t encoding)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_audio_coding_table[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
+      if(mmal_omx_audio_coding_table[i].encoding == encoding) break;
+   return mmal_omx_audio_coding_table[i].coding;
+}
+
+static struct {
+   OMX_AUDIO_CODINGTYPE coding;
+   OMX_INDEXTYPE index;
+   unsigned int size;
+} mmal_omx_audio_format_table[] =
+{
+   {OMX_AUDIO_CodingPCM, OMX_IndexParamAudioPcm, sizeof(OMX_AUDIO_PARAM_PCMMODETYPE)},
+   {OMX_AUDIO_CodingADPCM, OMX_IndexParamAudioAdpcm, sizeof(OMX_AUDIO_PARAM_ADPCMTYPE)},
+   {OMX_AUDIO_CodingAMR, OMX_IndexParamAudioAmr, sizeof(OMX_AUDIO_PARAM_AMRTYPE)},
+   {OMX_AUDIO_CodingGSMFR, OMX_IndexParamAudioGsm_FR, sizeof(OMX_AUDIO_PARAM_GSMFRTYPE)},
+   {OMX_AUDIO_CodingGSMEFR, OMX_IndexParamAudioGsm_EFR, sizeof(OMX_AUDIO_PARAM_GSMEFRTYPE)},
+   {OMX_AUDIO_CodingGSMHR, OMX_IndexParamAudioGsm_HR, sizeof(OMX_AUDIO_PARAM_GSMHRTYPE)},
+   {OMX_AUDIO_CodingPDCFR, OMX_IndexParamAudioPdc_FR, sizeof(OMX_AUDIO_PARAM_PDCFRTYPE)},
+   {OMX_AUDIO_CodingPDCEFR, OMX_IndexParamAudioPdc_EFR, sizeof(OMX_AUDIO_PARAM_PDCEFRTYPE)},
+   {OMX_AUDIO_CodingPDCHR, OMX_IndexParamAudioPdc_HR, sizeof(OMX_AUDIO_PARAM_PDCHRTYPE)},
+   {OMX_AUDIO_CodingTDMAFR, OMX_IndexParamAudioTdma_FR, sizeof(OMX_AUDIO_PARAM_TDMAFRTYPE)},
+   {OMX_AUDIO_CodingTDMAEFR, OMX_IndexParamAudioTdma_EFR, sizeof(OMX_AUDIO_PARAM_TDMAEFRTYPE)},
+   {OMX_AUDIO_CodingQCELP8, OMX_IndexParamAudioQcelp8, sizeof(OMX_AUDIO_PARAM_QCELP8TYPE)},
+   {OMX_AUDIO_CodingQCELP13, OMX_IndexParamAudioQcelp13, sizeof(OMX_AUDIO_PARAM_QCELP13TYPE)},
+   {OMX_AUDIO_CodingEVRC, OMX_IndexParamAudioEvrc, sizeof(OMX_AUDIO_PARAM_EVRCTYPE)},
+   {OMX_AUDIO_CodingSMV, OMX_IndexParamAudioSmv, sizeof(OMX_AUDIO_PARAM_SMVTYPE)},
+   {OMX_AUDIO_CodingG723, OMX_IndexParamAudioG723, sizeof(OMX_AUDIO_PARAM_G723TYPE)},
+   {OMX_AUDIO_CodingG726, OMX_IndexParamAudioG726, sizeof(OMX_AUDIO_PARAM_G726TYPE)},
+   {OMX_AUDIO_CodingG729, OMX_IndexParamAudioG729, sizeof(OMX_AUDIO_PARAM_G729TYPE)},
+   {OMX_AUDIO_CodingAAC, OMX_IndexParamAudioAac, sizeof(OMX_AUDIO_PARAM_AACPROFILETYPE)},
+   {OMX_AUDIO_CodingMP3, OMX_IndexParamAudioMp3, sizeof(OMX_AUDIO_PARAM_MP3TYPE)},
+   {OMX_AUDIO_CodingSBC, OMX_IndexParamAudioSbc, sizeof(OMX_AUDIO_PARAM_SBCTYPE)},
+   {OMX_AUDIO_CodingVORBIS, OMX_IndexParamAudioVorbis, sizeof(OMX_AUDIO_PARAM_VORBISTYPE)},
+   {OMX_AUDIO_CodingWMA, OMX_IndexParamAudioWma, sizeof(OMX_AUDIO_PARAM_WMATYPE)},
+   {OMX_AUDIO_CodingRA, OMX_IndexParamAudioRa, sizeof(OMX_AUDIO_PARAM_RATYPE)},
+   {OMX_AUDIO_CodingMIDI, OMX_IndexParamAudioMidi, sizeof(OMX_AUDIO_PARAM_MIDITYPE)},
+   {OMX_AUDIO_CodingDDP, OMX_IndexParamAudioDdp, sizeof(OMX_AUDIO_PARAM_DDPTYPE)},
+   {OMX_AUDIO_CodingDTS, OMX_IndexParamAudioDts, sizeof(OMX_AUDIO_PARAM_DTSTYPE)},
+   {OMX_AUDIO_CodingUnused, 0, 0}
+};
+
+OMX_AUDIO_CODINGTYPE mmalil_omx_audio_param_index_to_coding(OMX_INDEXTYPE index)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_audio_format_table[i].coding != OMX_AUDIO_CodingUnused; i++)
+      if(mmal_omx_audio_format_table[i].index == index) break;
+
+   return mmal_omx_audio_format_table[i].coding;
+}
+
+OMX_INDEXTYPE mmalil_omx_audio_param_index(OMX_AUDIO_CODINGTYPE coding, OMX_U32 *size)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_audio_format_table[i].coding != OMX_AUDIO_CodingUnused; i++)
+      if(mmal_omx_audio_format_table[i].coding == coding) break;
+
+   if(size) *size = mmal_omx_audio_format_table[i].size;
+   return mmal_omx_audio_format_table[i].index;
+}
+
+MMAL_STATUS_T mmalil_omx_default_channel_mapping(OMX_AUDIO_CHANNELTYPE *channel_mapping, unsigned int nchannels)
+{
+   static const OMX_AUDIO_CHANNELTYPE default_mapping[][8] = {
+      {OMX_AUDIO_ChannelNone},
+      {OMX_AUDIO_ChannelCF},
+      {OMX_AUDIO_ChannelLF, OMX_AUDIO_ChannelRF},
+      {OMX_AUDIO_ChannelLF, OMX_AUDIO_ChannelRF, OMX_AUDIO_ChannelCF},
+      {OMX_AUDIO_ChannelLF, OMX_AUDIO_ChannelRF, OMX_AUDIO_ChannelCF,
+         OMX_AUDIO_ChannelCS},
+      {OMX_AUDIO_ChannelLF, OMX_AUDIO_ChannelRF, OMX_AUDIO_ChannelCF,
+         OMX_AUDIO_ChannelLR, OMX_AUDIO_ChannelRR},
+      {OMX_AUDIO_ChannelLF, OMX_AUDIO_ChannelRF, OMX_AUDIO_ChannelCF,
+         OMX_AUDIO_ChannelLFE, OMX_AUDIO_ChannelLR, OMX_AUDIO_ChannelRR},
+      {OMX_AUDIO_ChannelLF, OMX_AUDIO_ChannelRF, OMX_AUDIO_ChannelCF,
+         OMX_AUDIO_ChannelLFE, OMX_AUDIO_ChannelLR, OMX_AUDIO_ChannelRR,
+         OMX_AUDIO_ChannelCS},
+      {OMX_AUDIO_ChannelLF, OMX_AUDIO_ChannelRF, OMX_AUDIO_ChannelCF,
+         OMX_AUDIO_ChannelLFE, OMX_AUDIO_ChannelLR, OMX_AUDIO_ChannelRR,
+         OMX_AUDIO_ChannelLS, OMX_AUDIO_ChannelRS}
+   };
+
+   if (!nchannels || nchannels >= MMAL_COUNTOF(default_mapping))
+      return MMAL_EINVAL;
+
+   memcpy(channel_mapping, default_mapping[nchannels],
+      sizeof(default_mapping[0][0]) * nchannels);
+   return MMAL_SUCCESS;
+}
+
+MMAL_FOURCC_T mmalil_omx_audio_param_to_format(MMAL_ES_FORMAT_T *format,
+   OMX_AUDIO_CODINGTYPE coding, OMX_FORMAT_PARAM_TYPE *param)
+{
+   MMAL_AUDIO_FORMAT_T *audio = &format->es->audio;
+   format->encoding = mmalil_omx_audio_coding_to_encoding(coding);
+   format->encoding_variant = 0;
+
+   switch(coding)
+   {
+   case OMX_AUDIO_CodingPCM:
+      audio->channels = param->pcm.nChannels;
+      audio->sample_rate = param->pcm.nSamplingRate;
+      audio->bits_per_sample = param->pcm.nBitPerSample;
+      if(param->pcm.ePCMMode == OMX_AUDIO_PCMModeLinear && param->pcm.bInterleaved)
+      {
+         if(param->pcm.eEndian == OMX_EndianBig &&
+            param->pcm.eNumData == OMX_NumericalDataSigned)
+            format->encoding = MMAL_ENCODING_PCM_SIGNED_BE;
+         else if(param->pcm.eEndian == OMX_EndianLittle &&
+            param->pcm.eNumData == OMX_NumericalDataSigned)
+            format->encoding = MMAL_ENCODING_PCM_SIGNED_LE;
+         if(param->pcm.eEndian == OMX_EndianBig &&
+            param->pcm.eNumData == OMX_NumericalDataUnsigned)
+            format->encoding = MMAL_ENCODING_PCM_UNSIGNED_BE;
+         if(param->pcm.eEndian == OMX_EndianLittle &&
+            param->pcm.eNumData == OMX_NumericalDataUnsigned)
+            format->encoding = MMAL_ENCODING_PCM_UNSIGNED_LE;
+      }
+      else if(param->pcm.ePCMMode == OMX_AUDIO_PCMModeALaw)
+         format->encoding = MMAL_ENCODING_ALAW;
+      else if(param->pcm.ePCMMode == OMX_AUDIO_PCMModeMULaw)
+         format->encoding = MMAL_ENCODING_MULAW;
+      break;
+   case OMX_AUDIO_CodingAAC:
+      audio->channels = param->aac.nChannels;
+      audio->sample_rate = param->aac.nSampleRate;
+      format->bitrate = param->aac.nBitRate;
+      switch(param->aac.eAACStreamFormat)
+      {
+      case OMX_AUDIO_AACStreamFormatMP2ADTS:
+      case OMX_AUDIO_AACStreamFormatMP4ADTS:
+         format->encoding = MMAL_ENCODING_MP4A;
+         format->encoding_variant = MMAL_ENCODING_VARIANT_MP4A_ADTS;
+         break;
+      case OMX_AUDIO_AACStreamFormatMP4FF:
+      case OMX_AUDIO_AACStreamFormatRAW:
+         format->encoding = MMAL_ENCODING_MP4A;
+         format->encoding_variant = MMAL_ENCODING_VARIANT_MP4A_DEFAULT;
+         break;
+      default: break;
+      }
+      break;
+   case OMX_AUDIO_CodingMP3:
+      format->encoding = MMAL_ENCODING_MPGA;
+      audio->channels = param->mp3.nChannels;
+      audio->sample_rate = param->mp3.nSampleRate;
+      format->bitrate = param->mp3.nBitRate;
+      break;
+   case OMX_AUDIO_CodingWMA:
+      audio->channels = param->wma.nChannels;
+      audio->sample_rate = param->wma.nSamplingRate;
+      audio->block_align = param->wma.nBlockAlign;
+      format->bitrate = param->wma.nBitRate;
+      switch(param->wma.eFormat)
+      {
+      case OMX_AUDIO_WMAFormat7:
+         format->encoding = MMAL_ENCODING_WMA1;
+         break;
+      case OMX_AUDIO_WMAFormat8:
+      case OMX_AUDIO_WMAFormat9:
+         format->encoding = MMAL_ENCODING_WMA2;
+         break;
+      default: break;
+      }
+      break;
+   case OMX_AUDIO_CodingVORBIS:
+      audio->channels = param->vorbis.nChannels;
+      audio->sample_rate = param->vorbis.nSampleRate;
+      format->bitrate = param->vorbis.nBitRate;
+      break;
+   case OMX_AUDIO_CodingAMR:
+      audio->channels = param->amr.nChannels;
+      audio->sample_rate = 8000;
+      format->bitrate = param->amr.nBitRate;
+      if(param->amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeNB0 &&
+         param->amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeNB7)
+         format->encoding = MMAL_ENCODING_AMRNB;
+      if(param->amr.eAMRBandMode >= OMX_AUDIO_AMRBandModeWB0 &&
+         param->amr.eAMRBandMode <= OMX_AUDIO_AMRBandModeWB8)
+         format->encoding = MMAL_ENCODING_AMRWB;
+      break;
+   case OMX_AUDIO_CodingDDP:
+      audio->channels = param->ddp.nChannels;
+      audio->sample_rate = param->ddp.nSampleRate;
+      if(param->ddp.eBitStreamId > OMX_AUDIO_DDPBitStreamIdAC3)
+         format->encoding = MMAL_ENCODING_EAC3;
+      break;
+   case OMX_AUDIO_CodingDTS:
+      audio->channels = param->dts.nChannels;
+      audio->sample_rate = param->dts.nSampleRate;
+      audio->block_align = param->dts.nDtsFrameSizeBytes;
+      break;
+
+   case OMX_AUDIO_CodingADPCM:
+   case OMX_AUDIO_CodingGSMFR:
+   case OMX_AUDIO_CodingGSMEFR:
+   case OMX_AUDIO_CodingGSMHR:
+   case OMX_AUDIO_CodingPDCFR:
+   case OMX_AUDIO_CodingPDCEFR:
+   case OMX_AUDIO_CodingPDCHR:
+   case OMX_AUDIO_CodingTDMAFR:
+   case OMX_AUDIO_CodingTDMAEFR:
+   case OMX_AUDIO_CodingQCELP8:
+   case OMX_AUDIO_CodingQCELP13:
+   case OMX_AUDIO_CodingEVRC:
+   case OMX_AUDIO_CodingSMV:
+   case OMX_AUDIO_CodingG711:
+   case OMX_AUDIO_CodingG723:
+   case OMX_AUDIO_CodingG726:
+   case OMX_AUDIO_CodingG729:
+   case OMX_AUDIO_CodingSBC:
+   case OMX_AUDIO_CodingRA:
+   case OMX_AUDIO_CodingMIDI:
+   default:
+      vcos_assert(0);
+      break;
+   }
+
+   return format->encoding;
+}
+
+OMX_AUDIO_CODINGTYPE mmalil_format_to_omx_audio_param(OMX_FORMAT_PARAM_TYPE *param,
+   OMX_INDEXTYPE *param_index, MMAL_ES_FORMAT_T *format)
+{
+   MMAL_AUDIO_FORMAT_T *audio = &format->es->audio;
+   OMX_AUDIO_CODINGTYPE coding = mmalil_encoding_to_omx_audio_coding(format->encoding);
+   OMX_U32 size = 0;
+   OMX_INDEXTYPE index = mmalil_omx_audio_param_index(coding, &size);
+
+   if(param_index) *param_index = index;
+   memset(param, 0, size);
+   param->common.nSize = size;
+
+   switch(coding)
+   {
+   case OMX_AUDIO_CodingPCM:
+      param->pcm.nChannels = audio->channels;
+      param->pcm.nSamplingRate = audio->sample_rate;
+      param->pcm.nBitPerSample = audio->bits_per_sample;
+      mmalil_omx_default_channel_mapping(param->pcm.eChannelMapping, audio->channels);
+      if(format->encoding == MMAL_ENCODING_PCM_SIGNED_BE ||
+         format->encoding == MMAL_ENCODING_PCM_SIGNED_LE ||
+         format->encoding == MMAL_ENCODING_PCM_UNSIGNED_BE ||
+         format->encoding == MMAL_ENCODING_PCM_UNSIGNED_LE)
+      {
+         param->pcm.ePCMMode = OMX_AUDIO_PCMModeLinear;
+         param->pcm.bInterleaved = OMX_TRUE;
+         param->pcm.eEndian = OMX_EndianLittle;
+         param->pcm.eNumData = OMX_NumericalDataSigned;
+         if(format->encoding == MMAL_ENCODING_PCM_SIGNED_BE ||
+            format->encoding == MMAL_ENCODING_PCM_UNSIGNED_BE)
+            param->pcm.eEndian = OMX_EndianBig;
+         if(format->encoding == MMAL_ENCODING_PCM_UNSIGNED_LE ||
+            format->encoding == MMAL_ENCODING_PCM_UNSIGNED_BE)
+            param->pcm.eNumData = OMX_NumericalDataUnsigned;
+      }
+      else if(format->encoding == MMAL_ENCODING_ALAW)
+         param->pcm.ePCMMode = OMX_AUDIO_PCMModeALaw;
+      else if(format->encoding == MMAL_ENCODING_MULAW)
+         param->pcm.ePCMMode = OMX_AUDIO_PCMModeMULaw;
+      break;
+   case OMX_AUDIO_CodingAAC:
+      param->aac.nChannels = audio->channels;
+      param->aac.nSampleRate = audio->sample_rate;
+      param->aac.nBitRate = format->bitrate;
+      switch(format->encoding_variant)
+      {
+      case MMAL_ENCODING_VARIANT_MP4A_ADTS:
+         param->aac.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4ADTS;
+         break;
+      case MMAL_ENCODING_VARIANT_MP4A_DEFAULT:
+         param->aac.eAACStreamFormat = OMX_AUDIO_AACStreamFormatRAW;
+         break;
+      default: break;
+      }
+      break;
+   case OMX_AUDIO_CodingMP3:
+      param->mp3.nChannels = audio->channels;
+      param->mp3.nSampleRate = audio->sample_rate;
+      param->mp3.nBitRate = format->bitrate;
+      break;
+   case OMX_AUDIO_CodingWMA:
+      param->wma.nChannels = audio->channels;
+      param->wma.nSamplingRate = audio->sample_rate;
+      param->wma.nBlockAlign = audio->block_align;
+      param->wma.nBitRate = format->bitrate;
+      switch(format->encoding)
+      {
+      case MMAL_ENCODING_WMA1:
+         param->wma.eFormat = OMX_AUDIO_WMAFormat7;
+         break;
+      case MMAL_ENCODING_WMA2:
+         param->wma.eFormat = OMX_AUDIO_WMAFormat8;
+         break;
+      default: break;
+      }
+      break;
+   case OMX_AUDIO_CodingVORBIS:
+      param->vorbis.nChannels = audio->channels;
+      param->vorbis.nSampleRate = audio->sample_rate;
+      param->vorbis.nBitRate = format->bitrate;
+      break;
+   case OMX_AUDIO_CodingAMR:
+      param->amr.nChannels = audio->channels;
+      param->amr.nBitRate = format->bitrate;
+      if(format->encoding == MMAL_ENCODING_AMRNB)
+         param->amr.eAMRBandMode = OMX_AUDIO_AMRBandModeNB0;
+      if(format->encoding == MMAL_ENCODING_AMRWB)
+         param->amr.eAMRBandMode = OMX_AUDIO_AMRBandModeWB0;
+      break;
+   case OMX_AUDIO_CodingDDP:
+      param->ddp.nChannels = audio->channels;
+      param->ddp.nSampleRate = audio->sample_rate;
+      param->ddp.eBitStreamId = OMX_AUDIO_DDPBitStreamIdAC3;
+      if(format->encoding == MMAL_ENCODING_EAC3)
+         param->ddp.eBitStreamId = OMX_AUDIO_DDPBitStreamIdEAC3;
+      param->ddp.eBitStreamMode = 0;
+      param->ddp.eDolbySurroundMode = 0;
+      mmalil_omx_default_channel_mapping(param->ddp.eChannelMapping, audio->channels);
+      break;
+   case OMX_AUDIO_CodingDTS:
+      param->dts.nChannels = audio->channels;
+      param->dts.nSampleRate = audio->sample_rate;
+      param->dts.nDtsFrameSizeBytes = audio->block_align;
+      param->dts.nDtsType = 1;
+      param->dts.nFormat = 0;
+      mmalil_omx_default_channel_mapping(param->dts.eChannelMapping, audio->channels);
+      break;
+   case OMX_AUDIO_CodingADPCM:
+   case OMX_AUDIO_CodingGSMFR:
+   case OMX_AUDIO_CodingGSMEFR:
+   case OMX_AUDIO_CodingGSMHR:
+   case OMX_AUDIO_CodingPDCFR:
+   case OMX_AUDIO_CodingPDCEFR:
+   case OMX_AUDIO_CodingPDCHR:
+   case OMX_AUDIO_CodingTDMAFR:
+   case OMX_AUDIO_CodingTDMAEFR:
+   case OMX_AUDIO_CodingQCELP8:
+   case OMX_AUDIO_CodingQCELP13:
+   case OMX_AUDIO_CodingEVRC:
+   case OMX_AUDIO_CodingSMV:
+   case OMX_AUDIO_CodingG711:
+   case OMX_AUDIO_CodingG723:
+   case OMX_AUDIO_CodingG726:
+   case OMX_AUDIO_CodingG729:
+   case OMX_AUDIO_CodingSBC:
+   case OMX_AUDIO_CodingRA:
+   case OMX_AUDIO_CodingMIDI:
+   default:
+      vcos_assert(0);
+      break;
+   }
+
+   return coding;
+}
+
+/*****************************************************************************/
+static struct {
+   uint32_t encoding;
+   OMX_VIDEO_CODINGTYPE coding;
+} mmal_omx_video_coding_table[] =
+{
+   {MMAL_ENCODING_H264,           OMX_VIDEO_CodingAVC},
+   {MMAL_ENCODING_MVC,            OMX_VIDEO_CodingMVC},
+   {MMAL_ENCODING_MP4V,           OMX_VIDEO_CodingMPEG4},
+   {MMAL_ENCODING_MP2V,           OMX_VIDEO_CodingMPEG2},
+   {MMAL_ENCODING_MP1V,           OMX_VIDEO_CodingMPEG2},
+   {MMAL_ENCODING_H263,           OMX_VIDEO_CodingH263},
+   {MMAL_ENCODING_WVC1,           OMX_VIDEO_CodingWMV},
+   {MMAL_ENCODING_WMV3,           OMX_VIDEO_CodingWMV},
+   {MMAL_ENCODING_WMV2,           OMX_VIDEO_CodingWMV},
+   {MMAL_ENCODING_WMV1,           OMX_VIDEO_CodingWMV},
+   {MMAL_ENCODING_VP6,            OMX_VIDEO_CodingVP6},
+   {MMAL_ENCODING_VP7,            OMX_VIDEO_CodingVP7},
+   {MMAL_ENCODING_VP8,            OMX_VIDEO_CodingVP8},
+   {MMAL_ENCODING_SPARK,          OMX_VIDEO_CodingSorenson},
+   {MMAL_ENCODING_THEORA,         OMX_VIDEO_CodingTheora},
+   {MMAL_ENCODING_MJPEG,          OMX_VIDEO_CodingMJPEG},
+   {MMAL_ENCODING_UNKNOWN,        OMX_VIDEO_CodingUnused}
+};
+
+uint32_t mmalil_omx_video_coding_to_encoding(OMX_VIDEO_CODINGTYPE coding)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_video_coding_table[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
+      if(mmal_omx_video_coding_table[i].coding == coding) break;
+   return mmal_omx_video_coding_table[i].encoding;
+}
+
+OMX_VIDEO_CODINGTYPE mmalil_encoding_to_omx_video_coding(uint32_t encoding)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_video_coding_table[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
+      if(mmal_omx_video_coding_table[i].encoding == encoding) break;
+   return mmal_omx_video_coding_table[i].coding;
+}
+
+/*****************************************************************************/
+static struct {
+   uint32_t encoding;
+   OMX_IMAGE_CODINGTYPE coding;
+} mmal_omx_image_coding_table[] =
+{
+   {MMAL_ENCODING_JPEG,           OMX_IMAGE_CodingJPEG},
+   {MMAL_ENCODING_GIF,            OMX_IMAGE_CodingGIF},
+   {MMAL_ENCODING_PNG,            OMX_IMAGE_CodingPNG},
+   {MMAL_ENCODING_BMP,            OMX_IMAGE_CodingBMP},
+   {MMAL_ENCODING_TGA,            OMX_IMAGE_CodingTGA},
+   {MMAL_ENCODING_PPM,            OMX_IMAGE_CodingPPM},
+   {MMAL_ENCODING_UNKNOWN,        OMX_IMAGE_CodingUnused}
+};
+
+uint32_t mmalil_omx_image_coding_to_encoding(OMX_IMAGE_CODINGTYPE coding)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_image_coding_table[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
+      if(mmal_omx_image_coding_table[i].coding == coding) break;
+   return mmal_omx_image_coding_table[i].encoding;
+}
+
+OMX_IMAGE_CODINGTYPE mmalil_encoding_to_omx_image_coding(uint32_t encoding)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_image_coding_table[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
+      if(mmal_omx_image_coding_table[i].encoding == encoding) break;
+   return mmal_omx_image_coding_table[i].coding;
+}
+
+uint32_t mmalil_omx_coding_to_encoding(uint32_t encoding, OMX_PORTDOMAINTYPE domain)
+{
+   if(domain == OMX_PortDomainVideo)
+      return mmalil_omx_video_coding_to_encoding((OMX_VIDEO_CODINGTYPE)encoding);
+   else if(domain == OMX_PortDomainAudio)
+      return mmalil_omx_audio_coding_to_encoding((OMX_AUDIO_CODINGTYPE)encoding);
+   else if(domain == OMX_PortDomainImage)
+      return mmalil_omx_image_coding_to_encoding((OMX_IMAGE_CODINGTYPE)encoding);
+   else
+      return MMAL_ENCODING_UNKNOWN;
+}
+
+/*****************************************************************************/
+static struct {
+   uint32_t encoding;
+   OMX_COLOR_FORMATTYPE coding;
+} mmal_omx_colorformat_coding_table[] =
+{
+   {MMAL_ENCODING_I420,           OMX_COLOR_FormatYUV420PackedPlanar},
+   {MMAL_ENCODING_I422,           OMX_COLOR_FormatYUV422PackedPlanar},
+   {MMAL_ENCODING_I420_SLICE,     OMX_COLOR_FormatYUV420PackedPlanar},
+   {MMAL_ENCODING_I422_SLICE,     OMX_COLOR_FormatYUV422PackedPlanar},
+   {MMAL_ENCODING_I420,           OMX_COLOR_FormatYUV420Planar},
+   {MMAL_ENCODING_YV12,           OMX_COLOR_FormatYVU420PackedPlanar},
+   {MMAL_ENCODING_NV12,           OMX_COLOR_FormatYUV420PackedSemiPlanar},
+   {MMAL_ENCODING_NV12,           OMX_COLOR_FormatYUV420SemiPlanar},
+   {MMAL_ENCODING_NV21,           OMX_COLOR_FormatYVU420PackedSemiPlanar},
+   {MMAL_ENCODING_YUVUV128,       OMX_COLOR_FormatYUVUV128},
+   {MMAL_ENCODING_YUYV,           OMX_COLOR_FormatYCbYCr},
+   {MMAL_ENCODING_YVYU,           OMX_COLOR_FormatYCrYCb},
+   {MMAL_ENCODING_UYVY,           OMX_COLOR_FormatCbYCrY},
+   {MMAL_ENCODING_VYUY,           OMX_COLOR_FormatCrYCbY},
+   {MMAL_ENCODING_RGB16,          OMX_COLOR_Format16bitRGB565},
+   {MMAL_ENCODING_BGR24,          OMX_COLOR_Format24bitRGB888},
+   {MMAL_ENCODING_BGRA,           OMX_COLOR_Format32bitARGB8888},
+   {MMAL_ENCODING_BGR16,          OMX_COLOR_Format16bitBGR565},
+   {MMAL_ENCODING_RGB24,          OMX_COLOR_Format24bitBGR888},
+   {MMAL_ENCODING_ARGB,           OMX_COLOR_Format32bitBGRA8888},
+   {MMAL_ENCODING_RGBA,           OMX_COLOR_Format32bitABGR8888},
+   {MMAL_ENCODING_RGB16_SLICE,    OMX_COLOR_Format16bitRGB565},
+   {MMAL_ENCODING_BGR24_SLICE,    OMX_COLOR_Format24bitRGB888},
+   {MMAL_ENCODING_BGRA_SLICE,     OMX_COLOR_Format32bitARGB8888},
+   {MMAL_ENCODING_BGR16_SLICE,    OMX_COLOR_Format16bitBGR565},
+   {MMAL_ENCODING_RGB24_SLICE,    OMX_COLOR_Format24bitBGR888},
+   {MMAL_ENCODING_ARGB_SLICE,     OMX_COLOR_Format32bitBGRA8888},
+   {MMAL_ENCODING_RGBA_SLICE,     OMX_COLOR_Format32bitABGR8888},
+   {MMAL_ENCODING_EGL_IMAGE,      OMX_COLOR_FormatBRCMEGL},
+   {MMAL_ENCODING_BAYER_SBGGR8,   OMX_COLOR_FormatRawBayer8bit},
+   {MMAL_ENCODING_BAYER_SBGGR10P, OMX_COLOR_FormatRawBayer10bit},
+   {MMAL_ENCODING_BAYER_SGRBG10P, OMX_COLOR_FormatRawBayer10bit},
+   {MMAL_ENCODING_BAYER_SGBRG10P, OMX_COLOR_FormatRawBayer10bit},
+   {MMAL_ENCODING_BAYER_SRGGB10P, OMX_COLOR_FormatRawBayer10bit},
+   {MMAL_ENCODING_BAYER_SBGGR12P, OMX_COLOR_FormatRawBayer12bit},
+   {MMAL_ENCODING_BAYER_SGRBG12P, OMX_COLOR_FormatRawBayer12bit},
+   {MMAL_ENCODING_BAYER_SGBRG12P, OMX_COLOR_FormatRawBayer12bit},
+   {MMAL_ENCODING_BAYER_SRGGB12P, OMX_COLOR_FormatRawBayer12bit},
+   {MMAL_ENCODING_BAYER_SBGGR16,  OMX_COLOR_FormatRawBayer16bit},
+   {MMAL_ENCODING_BAYER_SGBRG16,  OMX_COLOR_FormatRawBayer16bit},
+   {MMAL_ENCODING_BAYER_SGRBG16,  OMX_COLOR_FormatRawBayer16bit},
+   {MMAL_ENCODING_BAYER_SRGGB16,  OMX_COLOR_FormatRawBayer16bit},
+   {MMAL_ENCODING_BAYER_SBGGR10DPCM8,OMX_COLOR_FormatRawBayer8bitcompressed},
+   {MMAL_ENCODING_OPAQUE,         OMX_COLOR_FormatBRCMOpaque},
+   {MMAL_ENCODING_I420_16,        OMX_COLOR_FormatYUV420_16PackedPlanar},
+   {MMAL_ENCODING_YUVUV64_16,     OMX_COLOR_FormatYUVUV64_16},
+   {MMAL_ENCODING_I420_10,        OMX_COLOR_FormatYUV420_10PackedPlanar},
+   {MMAL_ENCODING_YUVUV64_10,     OMX_COLOR_FormatYUVUV64_10},
+   {MMAL_ENCODING_UNKNOWN,        OMX_COLOR_FormatUnused}
+};
+
+uint32_t mmalil_omx_color_format_to_encoding(OMX_COLOR_FORMATTYPE coding)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_colorformat_coding_table[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
+      if(mmal_omx_colorformat_coding_table[i].coding == coding) break;
+   return mmal_omx_colorformat_coding_table[i].encoding;
+}
+
+OMX_COLOR_FORMATTYPE mmalil_encoding_to_omx_color_format(uint32_t encoding)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_colorformat_coding_table[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
+      if(mmal_omx_colorformat_coding_table[i].encoding == encoding) break;
+   return mmal_omx_colorformat_coding_table[i].coding;
+}
+
+static struct {
+   uint32_t encoding;
+   OMX_COLOR_FORMATTYPE color_format;
+   OMX_BAYERORDERTYPE bayer_order;
+} mmal_omx_bayer_order_coding_table[] =
+{
+   //Colour format required for conversion from OMX to MMAL.
+   //Not used for MMAL encoding to OMX color format.
+   {MMAL_ENCODING_BAYER_SBGGR8, OMX_COLOR_FormatRawBayer8bit, OMX_BayerOrderBGGR},
+   {MMAL_ENCODING_BAYER_SGBRG8, OMX_COLOR_FormatRawBayer8bit, OMX_BayerOrderGBRG},
+   {MMAL_ENCODING_BAYER_SGRBG8, OMX_COLOR_FormatRawBayer8bit, OMX_BayerOrderGRBG},
+   {MMAL_ENCODING_BAYER_SRGGB8, OMX_COLOR_FormatRawBayer8bit, OMX_BayerOrderRGGB},
+
+   {MMAL_ENCODING_BAYER_SBGGR10P, OMX_COLOR_FormatRawBayer10bit, OMX_BayerOrderBGGR},
+   {MMAL_ENCODING_BAYER_SGRBG10P, OMX_COLOR_FormatRawBayer10bit, OMX_BayerOrderGRBG},
+   {MMAL_ENCODING_BAYER_SGBRG10P, OMX_COLOR_FormatRawBayer10bit, OMX_BayerOrderGBRG},
+   {MMAL_ENCODING_BAYER_SRGGB10P, OMX_COLOR_FormatRawBayer10bit, OMX_BayerOrderRGGB},
+
+   {MMAL_ENCODING_BAYER_SBGGR12P, OMX_COLOR_FormatRawBayer12bit, OMX_BayerOrderBGGR},
+   {MMAL_ENCODING_BAYER_SGRBG12P, OMX_COLOR_FormatRawBayer12bit, OMX_BayerOrderGRBG},
+   {MMAL_ENCODING_BAYER_SGBRG12P, OMX_COLOR_FormatRawBayer12bit, OMX_BayerOrderGBRG},
+   {MMAL_ENCODING_BAYER_SRGGB12P, OMX_COLOR_FormatRawBayer12bit, OMX_BayerOrderRGGB},
+
+   {MMAL_ENCODING_BAYER_SBGGR16,  OMX_COLOR_FormatRawBayer16bit, OMX_BayerOrderBGGR},
+   {MMAL_ENCODING_BAYER_SGRBG16,  OMX_COLOR_FormatRawBayer16bit, OMX_BayerOrderGRBG},
+   {MMAL_ENCODING_BAYER_SGBRG16,  OMX_COLOR_FormatRawBayer16bit, OMX_BayerOrderGBRG},
+   {MMAL_ENCODING_BAYER_SRGGB16,  OMX_COLOR_FormatRawBayer16bit, OMX_BayerOrderRGGB},
+
+   {MMAL_ENCODING_BAYER_SBGGR10DPCM8,OMX_COLOR_FormatRawBayer8bitcompressed, OMX_BayerOrderBGGR},
+   {MMAL_ENCODING_BAYER_SGRBG10DPCM8,OMX_COLOR_FormatRawBayer8bitcompressed, OMX_BayerOrderGRBG},
+   {MMAL_ENCODING_BAYER_SGBRG10DPCM8,OMX_COLOR_FormatRawBayer8bitcompressed, OMX_BayerOrderGBRG},
+   {MMAL_ENCODING_BAYER_SRGGB10DPCM8,OMX_COLOR_FormatRawBayer8bitcompressed, OMX_BayerOrderRGGB},
+
+   {MMAL_ENCODING_UNKNOWN,        OMX_COLOR_FormatMax,            OMX_BayerOrderMax}
+};
+
+uint32_t mmalil_omx_bayer_format_order_to_encoding(OMX_BAYERORDERTYPE bayer_order, OMX_COLOR_FORMATTYPE color_format)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_bayer_order_coding_table[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
+      if(mmal_omx_bayer_order_coding_table[i].bayer_order == bayer_order &&
+         mmal_omx_bayer_order_coding_table[i].color_format == color_format)
+         break;
+   return mmal_omx_bayer_order_coding_table[i].encoding;
+}
+
+OMX_BAYERORDERTYPE mmalil_encoding_to_omx_bayer_order(uint32_t encoding)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_bayer_order_coding_table[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
+      if(mmal_omx_bayer_order_coding_table[i].encoding == encoding) break;
+   return mmal_omx_bayer_order_coding_table[i].bayer_order;
+}
+
+/*****************************************************************************/
+static struct {
+   uint32_t mmal;
+   OMX_COLORSPACETYPE omx;
+} mmal_omx_colorspace_coding_table[] =
+{
+   {MMAL_COLOR_SPACE_ITUR_BT601,    OMX_COLORSPACE_ITU_R_BT601},
+   {MMAL_COLOR_SPACE_ITUR_BT709,    OMX_COLORSPACE_ITU_R_BT709},
+   {MMAL_COLOR_SPACE_JPEG_JFIF,     OMX_COLORSPACE_JPEG_JFIF},
+   {MMAL_COLOR_SPACE_FCC,           OMX_COLORSPACE_FCC},
+   {MMAL_COLOR_SPACE_SMPTE240M,     OMX_COLORSPACE_SMPTE240M},
+   {MMAL_COLOR_SPACE_BT470_2_M,     OMX_COLORSPACE_BT470_2_M},
+   {MMAL_COLOR_SPACE_BT470_2_BG,    OMX_COLORSPACE_BT470_2_BG},
+   {MMAL_COLOR_SPACE_JFIF_Y16_255,  OMX_COLORSPACE_JFIF_Y16_255},
+   {MMAL_COLOR_SPACE_UNKNOWN,       OMX_COLORSPACE_UNKNOWN}
+};
+
+uint32_t mmalil_omx_color_space_to_mmal(OMX_COLORSPACETYPE coding)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_colorspace_coding_table[i].mmal != MMAL_COLOR_SPACE_UNKNOWN; i++)
+      if(mmal_omx_colorspace_coding_table[i].omx == coding) break;
+   return mmal_omx_colorspace_coding_table[i].mmal;
+}
+
+OMX_COLORSPACETYPE mmalil_color_space_to_omx(uint32_t coding)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_colorspace_coding_table[i].mmal != MMAL_COLOR_SPACE_UNKNOWN; i++)
+      if(mmal_omx_colorspace_coding_table[i].mmal == coding) break;
+   return mmal_omx_colorspace_coding_table[i].omx;
+}
+
+/*****************************************************************************/
+static struct {
+   uint32_t mmal;
+   OMX_U32 omx;
+   OMX_VIDEO_CODINGTYPE omx_coding;
+} mmal_omx_video_profile_table[] =
+{
+   { MMAL_VIDEO_PROFILE_H263_BASELINE,           OMX_VIDEO_H263ProfileBaseline,           OMX_VIDEO_CodingH263},
+   { MMAL_VIDEO_PROFILE_H263_H320CODING,         OMX_VIDEO_H263ProfileH320Coding,         OMX_VIDEO_CodingH263},
+   { MMAL_VIDEO_PROFILE_H263_BACKWARDCOMPATIBLE, OMX_VIDEO_H263ProfileBackwardCompatible, OMX_VIDEO_CodingH263},
+   { MMAL_VIDEO_PROFILE_H263_ISWV2,              OMX_VIDEO_H263ProfileISWV2,              OMX_VIDEO_CodingH263},
+   { MMAL_VIDEO_PROFILE_H263_ISWV3,              OMX_VIDEO_H263ProfileISWV3,              OMX_VIDEO_CodingH263},
+   { MMAL_VIDEO_PROFILE_H263_HIGHCOMPRESSION,    OMX_VIDEO_H263ProfileHighCompression,    OMX_VIDEO_CodingH263},
+   { MMAL_VIDEO_PROFILE_H263_INTERNET,           OMX_VIDEO_H263ProfileInternet,           OMX_VIDEO_CodingH263},
+   { MMAL_VIDEO_PROFILE_H263_INTERLACE,          OMX_VIDEO_H263ProfileInterlace,          OMX_VIDEO_CodingH263},
+   { MMAL_VIDEO_PROFILE_H263_HIGHLATENCY,        OMX_VIDEO_H263ProfileHighLatency,        OMX_VIDEO_CodingH263},
+   { MMAL_VIDEO_PROFILE_MP4V_SIMPLE,             OMX_VIDEO_MPEG4ProfileSimple,            OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_PROFILE_MP4V_SIMPLESCALABLE,     OMX_VIDEO_MPEG4ProfileSimpleScalable,    OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_PROFILE_MP4V_CORE,               OMX_VIDEO_MPEG4ProfileCore,              OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_PROFILE_MP4V_MAIN,               OMX_VIDEO_MPEG4ProfileMain,              OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_PROFILE_MP4V_NBIT,               OMX_VIDEO_MPEG4ProfileNbit,              OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_PROFILE_MP4V_SCALABLETEXTURE,    OMX_VIDEO_MPEG4ProfileScalableTexture,   OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_PROFILE_MP4V_SIMPLEFACE,         OMX_VIDEO_MPEG4ProfileSimpleFace,        OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_PROFILE_MP4V_SIMPLEFBA,          OMX_VIDEO_MPEG4ProfileSimpleFBA,         OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_PROFILE_MP4V_BASICANIMATED,      OMX_VIDEO_MPEG4ProfileBasicAnimated,     OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_PROFILE_MP4V_HYBRID,             OMX_VIDEO_MPEG4ProfileHybrid,            OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_PROFILE_MP4V_ADVANCEDREALTIME,   OMX_VIDEO_MPEG4ProfileAdvancedRealTime,  OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_PROFILE_MP4V_CORESCALABLE,       OMX_VIDEO_MPEG4ProfileCoreScalable,      OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCODING,     OMX_VIDEO_MPEG4ProfileAdvancedCoding,    OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_PROFILE_MP4V_ADVANCEDCORE,       OMX_VIDEO_MPEG4ProfileAdvancedCore,      OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSCALABLE,   OMX_VIDEO_MPEG4ProfileAdvancedScalable,  OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_PROFILE_MP4V_ADVANCEDSIMPLE,     OMX_VIDEO_MPEG4ProfileAdvancedSimple,    OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_PROFILE_H264_BASELINE,           OMX_VIDEO_AVCProfileBaseline,            OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_PROFILE_H264_MAIN,               OMX_VIDEO_AVCProfileMain,                OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_PROFILE_H264_EXTENDED,           OMX_VIDEO_AVCProfileExtended,            OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_PROFILE_H264_HIGH,               OMX_VIDEO_AVCProfileHigh,                OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_PROFILE_H264_HIGH10,             OMX_VIDEO_AVCProfileHigh10,              OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_PROFILE_H264_HIGH422,            OMX_VIDEO_AVCProfileHigh422,             OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_PROFILE_H264_HIGH444,            OMX_VIDEO_AVCProfileHigh444,             OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_PROFILE_H264_CONSTRAINED_BASELINE, OMX_VIDEO_AVCProfileConstrainedBaseline,             OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_PROFILE_DUMMY,                   OMX_VIDEO_AVCProfileMax,                 OMX_VIDEO_CodingAVC},
+};
+
+uint32_t mmalil_omx_video_profile_to_mmal(OMX_U32 profile, OMX_VIDEO_CODINGTYPE coding)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_video_profile_table[i].mmal != MMAL_VIDEO_PROFILE_DUMMY; i++)
+      if(mmal_omx_video_profile_table[i].omx == profile
+         && mmal_omx_video_profile_table[i].omx_coding == coding) break;
+   return mmal_omx_video_profile_table[i].mmal;
+}
+
+OMX_U32 mmalil_video_profile_to_omx(uint32_t profile)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_video_profile_table[i].mmal != MMAL_VIDEO_PROFILE_DUMMY; i++)
+      if(mmal_omx_video_profile_table[i].mmal == profile) break;
+   return mmal_omx_video_profile_table[i].omx;
+}
+
+/*****************************************************************************/
+static struct {
+   uint32_t mmal;
+   OMX_U32 omx;
+   OMX_VIDEO_CODINGTYPE omx_coding;
+} mmal_omx_video_level_table[] =
+{
+   { MMAL_VIDEO_LEVEL_H263_10, OMX_VIDEO_H263Level10,  OMX_VIDEO_CodingH263},
+   { MMAL_VIDEO_LEVEL_H263_20, OMX_VIDEO_H263Level20,  OMX_VIDEO_CodingH263},
+   { MMAL_VIDEO_LEVEL_H263_30, OMX_VIDEO_H263Level30,  OMX_VIDEO_CodingH263},
+   { MMAL_VIDEO_LEVEL_H263_40, OMX_VIDEO_H263Level40,  OMX_VIDEO_CodingH263},
+   { MMAL_VIDEO_LEVEL_H263_45, OMX_VIDEO_H263Level45,  OMX_VIDEO_CodingH263},
+   { MMAL_VIDEO_LEVEL_H263_50, OMX_VIDEO_H263Level50,  OMX_VIDEO_CodingH263},
+   { MMAL_VIDEO_LEVEL_H263_60, OMX_VIDEO_H263Level60,  OMX_VIDEO_CodingH263},
+   { MMAL_VIDEO_LEVEL_H263_70, OMX_VIDEO_H263Level70,  OMX_VIDEO_CodingH263},
+   { MMAL_VIDEO_LEVEL_MP4V_0,  OMX_VIDEO_MPEG4Level0,  OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_LEVEL_MP4V_0b, OMX_VIDEO_MPEG4Level0b, OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_LEVEL_MP4V_1,  OMX_VIDEO_MPEG4Level1,  OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_LEVEL_MP4V_2,  OMX_VIDEO_MPEG4Level2,  OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_LEVEL_MP4V_3,  OMX_VIDEO_MPEG4Level3,  OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_LEVEL_MP4V_4,  OMX_VIDEO_MPEG4Level4,  OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_LEVEL_MP4V_4a, OMX_VIDEO_MPEG4Level4a, OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_LEVEL_MP4V_5,  OMX_VIDEO_MPEG4Level5,  OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_LEVEL_MP4V_6,  OMX_VIDEO_MPEG4Level6,  OMX_VIDEO_CodingMPEG4},
+   { MMAL_VIDEO_LEVEL_H264_1,  OMX_VIDEO_AVCLevel1,    OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_LEVEL_H264_1b, OMX_VIDEO_AVCLevel1b,   OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_LEVEL_H264_11, OMX_VIDEO_AVCLevel11,   OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_LEVEL_H264_12, OMX_VIDEO_AVCLevel12,   OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_LEVEL_H264_13, OMX_VIDEO_AVCLevel13,   OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_LEVEL_H264_2,  OMX_VIDEO_AVCLevel2,    OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_LEVEL_H264_21, OMX_VIDEO_AVCLevel21,   OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_LEVEL_H264_22, OMX_VIDEO_AVCLevel22,   OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_LEVEL_H264_3,  OMX_VIDEO_AVCLevel3,    OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_LEVEL_H264_31, OMX_VIDEO_AVCLevel31,   OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_LEVEL_H264_32, OMX_VIDEO_AVCLevel32,   OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_LEVEL_H264_4,  OMX_VIDEO_AVCLevel4,    OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_LEVEL_H264_41, OMX_VIDEO_AVCLevel41,   OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_LEVEL_H264_42, OMX_VIDEO_AVCLevel42,   OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_LEVEL_H264_5,  OMX_VIDEO_AVCLevel5,    OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_LEVEL_H264_51, OMX_VIDEO_AVCLevel51,   OMX_VIDEO_CodingAVC},
+   { MMAL_VIDEO_LEVEL_DUMMY,   OMX_VIDEO_AVCLevelMax,  OMX_VIDEO_CodingMax},
+};
+
+uint32_t mmalil_omx_video_level_to_mmal(OMX_U32 level, OMX_VIDEO_CODINGTYPE coding)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_video_level_table[i].mmal != MMAL_VIDEO_LEVEL_DUMMY; i++)
+      if(mmal_omx_video_level_table[i].omx == level
+         && mmal_omx_video_level_table[i].omx_coding == coding) break;
+   return mmal_omx_video_level_table[i].mmal;
+}
+
+OMX_U32 mmalil_video_level_to_omx(uint32_t level)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_video_level_table[i].mmal != MMAL_VIDEO_LEVEL_DUMMY; i++)
+      if(mmal_omx_video_level_table[i].mmal == level) break;
+   return mmal_omx_video_level_table[i].omx;
+}
+
+/*****************************************************************************/
+static struct {
+   MMAL_VIDEO_RATECONTROL_T mmal;
+   OMX_VIDEO_CONTROLRATETYPE omx;
+} mmal_omx_video_ratecontrol_table[] =
+{
+   { MMAL_VIDEO_RATECONTROL_DEFAULT,              OMX_Video_ControlRateDisable},
+   { MMAL_VIDEO_RATECONTROL_VARIABLE,             OMX_Video_ControlRateVariable},
+   { MMAL_VIDEO_RATECONTROL_CONSTANT,             OMX_Video_ControlRateConstant},
+   { MMAL_VIDEO_RATECONTROL_VARIABLE_SKIP_FRAMES, OMX_Video_ControlRateVariableSkipFrames},
+   { MMAL_VIDEO_RATECONTROL_CONSTANT_SKIP_FRAMES, OMX_Video_ControlRateConstantSkipFrames},
+   { MMAL_VIDEO_RATECONTROL_DUMMY,                OMX_Video_ControlRateMax},
+};
+
+MMAL_VIDEO_RATECONTROL_T mmalil_omx_video_ratecontrol_to_mmal(OMX_VIDEO_CONTROLRATETYPE omx)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_video_ratecontrol_table[i].mmal != MMAL_VIDEO_RATECONTROL_DUMMY; i++)
+      if(mmal_omx_video_ratecontrol_table[i].omx == omx) break;
+   return mmal_omx_video_ratecontrol_table[i].mmal;
+}
+
+OMX_VIDEO_CONTROLRATETYPE mmalil_video_ratecontrol_to_omx(MMAL_VIDEO_RATECONTROL_T mmal)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_video_ratecontrol_table[i].mmal != MMAL_VIDEO_RATECONTROL_DUMMY; i++)
+      if(mmal_omx_video_ratecontrol_table[i].mmal == mmal) break;
+   return mmal_omx_video_ratecontrol_table[i].omx;
+}
+
+/*****************************************************************************/
+static struct {
+   MMAL_VIDEO_INTRA_REFRESH_T mmal;
+   OMX_VIDEO_INTRAREFRESHTYPE omx;
+} mmal_omx_video_intrarefresh_table[] =
+{
+   { MMAL_VIDEO_INTRA_REFRESH_CYCLIC,             OMX_VIDEO_IntraRefreshCyclic},
+   { MMAL_VIDEO_INTRA_REFRESH_ADAPTIVE,           OMX_VIDEO_IntraRefreshAdaptive},
+   { MMAL_VIDEO_INTRA_REFRESH_BOTH,               OMX_VIDEO_IntraRefreshBoth},
+   { MMAL_VIDEO_INTRA_REFRESH_KHRONOSEXTENSIONS,  OMX_VIDEO_IntraRefreshKhronosExtensions},
+   { MMAL_VIDEO_INTRA_REFRESH_VENDORSTARTUNUSED,  OMX_VIDEO_IntraRefreshVendorStartUnused},
+   { MMAL_VIDEO_INTRA_REFRESH_DUMMY,              OMX_VIDEO_IntraRefreshMax},
+};
+
+MMAL_VIDEO_INTRA_REFRESH_T mmalil_omx_video_intrarefresh_to_mmal(OMX_VIDEO_INTRAREFRESHTYPE omx)
+{
+   unsigned int i;
+   for(i = 0; mmal_omx_video_intrarefresh_table[i].mmal != MMAL_VIDEO_INTRA_REFRESH_DUMMY; i++)
+      if(mmal_omx_video_intrarefresh_table[i].omx == omx) break;
+   return mmal_omx_video_intrarefresh_table[i].mmal;
+}
diff --git a/interface/mmal/util/mmal_il.h b/interface/mmal/util/mmal_il.h
new file mode 100755 (executable)
index 0000000..b047a28
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_IL_H
+#define MMAL_IL_H
+
+/** \defgroup MmalILUtility MMAL to OMX IL conversion utilities
+ * \ingroup MmalUtilities
+ *
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vmcs_host/khronos/IL/OMX_Core.h"
+#include "interface/vmcs_host/khronos/IL/OMX_Component.h"
+#include "interface/vmcs_host/khronos/IL/OMX_Video.h"
+#include "interface/vmcs_host/khronos/IL/OMX_Audio.h"
+#include "interface/vmcs_host/khronos/IL/OMX_Broadcom.h"
+
+/** Convert MMAL status codes into OMX error codes.
+ *
+ * @param status MMAL status code.
+ * @return OMX error code.
+ */
+OMX_ERRORTYPE mmalil_error_to_omx(MMAL_STATUS_T status);
+
+/** Convert OMX error codes into MMAL status codes.
+ *
+ * @param error OMX error code.
+ * @return MMAL status code.
+ */
+MMAL_STATUS_T mmalil_error_to_mmal(OMX_ERRORTYPE error);
+
+/** Convert MMAL buffer header flags into OMX buffer header flags.
+ *
+ * @param flags OMX buffer header flags.
+ * @return MMAL buffer header flags.
+ */
+uint32_t mmalil_buffer_flags_to_mmal(OMX_U32 flags);
+
+/** Convert OMX buffer header flags into MMAL buffer header flags.
+ *
+ * @param flags MMAL buffer header flags.
+ * @return OMX buffer header flags.
+ */
+OMX_U32 mmalil_buffer_flags_to_omx(uint32_t flags);
+
+/** Convert a MMAL buffer header into an OMX buffer header.
+ * Note that only the fields which have a direct mapping between OMX and MMAL are converted.
+ *
+ * @param omx  Pointer to the destination OMX buffer header.
+ * @param mmal Pointer to the source MMAL buffer header.
+ */
+void mmalil_buffer_header_to_omx(OMX_BUFFERHEADERTYPE *omx, MMAL_BUFFER_HEADER_T *mmal);
+
+/** Convert an OMX buffer header into a MMAL buffer header.
+ *
+ * @param mmal Pointer to the destination MMAL buffer header.
+ * @param omx  Pointer to the source OMX buffer header.
+ */
+void mmalil_buffer_header_to_mmal(MMAL_BUFFER_HEADER_T *mmal, OMX_BUFFERHEADERTYPE *omx);
+
+
+OMX_PORTDOMAINTYPE mmalil_es_type_to_omx_domain(MMAL_ES_TYPE_T type);
+MMAL_ES_TYPE_T mmalil_omx_domain_to_es_type(OMX_PORTDOMAINTYPE domain);
+uint32_t mmalil_omx_audio_coding_to_encoding(OMX_AUDIO_CODINGTYPE coding);
+OMX_AUDIO_CODINGTYPE mmalil_encoding_to_omx_audio_coding(uint32_t encoding);
+uint32_t mmalil_omx_video_coding_to_encoding(OMX_VIDEO_CODINGTYPE coding);
+OMX_VIDEO_CODINGTYPE mmalil_encoding_to_omx_video_coding(uint32_t encoding);
+uint32_t mmalil_omx_image_coding_to_encoding(OMX_IMAGE_CODINGTYPE coding);
+OMX_IMAGE_CODINGTYPE mmalil_encoding_to_omx_image_coding(uint32_t encoding);
+uint32_t mmalil_omx_coding_to_encoding(uint32_t encoding, OMX_PORTDOMAINTYPE domain);
+uint32_t mmalil_omx_color_format_to_encoding(OMX_COLOR_FORMATTYPE coding);
+OMX_COLOR_FORMATTYPE mmalil_encoding_to_omx_color_format(uint32_t encoding);
+uint32_t mmalil_omx_bayer_format_order_to_encoding(OMX_BAYERORDERTYPE bayer_order, OMX_COLOR_FORMATTYPE color_format);
+OMX_BAYERORDERTYPE mmalil_encoding_to_omx_bayer_order(uint32_t encoding);
+uint32_t mmalil_omx_color_space_to_mmal(OMX_COLORSPACETYPE coding);
+OMX_COLORSPACETYPE mmalil_color_space_to_omx(uint32_t coding);
+uint32_t mmalil_omx_video_profile_to_mmal(OMX_U32 level, OMX_VIDEO_CODINGTYPE coding);
+OMX_U32 mmalil_video_profile_to_omx(uint32_t profile);
+uint32_t mmalil_omx_video_level_to_mmal(OMX_U32 level, OMX_VIDEO_CODINGTYPE coding);
+OMX_U32 mmalil_video_level_to_omx(uint32_t level);
+MMAL_VIDEO_RATECONTROL_T mmalil_omx_video_ratecontrol_to_mmal(OMX_VIDEO_CONTROLRATETYPE omx);
+OMX_VIDEO_CONTROLRATETYPE mmalil_video_ratecontrol_to_omx(MMAL_VIDEO_RATECONTROL_T mmal);
+MMAL_VIDEO_INTRA_REFRESH_T mmalil_omx_video_intrarefresh_to_mmal(OMX_VIDEO_INTRAREFRESHTYPE omx);
+
+/** Union of all the OMX_VIDEO/AUDIO_PARAM types */
+typedef union OMX_FORMAT_PARAM_TYPE {
+   OMX_PARAM_U32TYPE common;
+
+   /* Video */
+   OMX_VIDEO_PARAM_AVCTYPE avc;
+   OMX_VIDEO_PARAM_H263TYPE h263;
+   OMX_VIDEO_PARAM_MPEG2TYPE mpeg2;
+   OMX_VIDEO_PARAM_MPEG4TYPE mpeg4;
+   OMX_VIDEO_PARAM_WMVTYPE wmv;
+   OMX_VIDEO_PARAM_RVTYPE rv;
+
+   /* Audio */
+   OMX_AUDIO_PARAM_PCMMODETYPE pcm;
+   OMX_AUDIO_PARAM_MP3TYPE mp3;
+   OMX_AUDIO_PARAM_AACPROFILETYPE aac;
+   OMX_AUDIO_PARAM_VORBISTYPE vorbis;
+   OMX_AUDIO_PARAM_WMATYPE wma;
+   OMX_AUDIO_PARAM_RATYPE ra;
+   OMX_AUDIO_PARAM_SBCTYPE sbc;
+   OMX_AUDIO_PARAM_ADPCMTYPE adpcm;
+   OMX_AUDIO_PARAM_G723TYPE g723;
+   OMX_AUDIO_PARAM_G726TYPE g726;
+   OMX_AUDIO_PARAM_G729TYPE g729;
+   OMX_AUDIO_PARAM_AMRTYPE amr;
+   OMX_AUDIO_PARAM_GSMFRTYPE gsmfr;
+   OMX_AUDIO_PARAM_GSMHRTYPE gsmhr;
+   OMX_AUDIO_PARAM_GSMEFRTYPE gsmefr;
+   OMX_AUDIO_PARAM_TDMAFRTYPE tdmafr;
+   OMX_AUDIO_PARAM_TDMAEFRTYPE tdmaefr;
+   OMX_AUDIO_PARAM_PDCFRTYPE pdcfr;
+   OMX_AUDIO_PARAM_PDCEFRTYPE pdcefr;
+   OMX_AUDIO_PARAM_PDCHRTYPE pdchr;
+   OMX_AUDIO_PARAM_QCELP8TYPE qcelp8;
+   OMX_AUDIO_PARAM_QCELP13TYPE qcelp13;
+   OMX_AUDIO_PARAM_EVRCTYPE evrc;
+   OMX_AUDIO_PARAM_SMVTYPE smv;
+   OMX_AUDIO_PARAM_MIDITYPE midi;
+#ifdef OMX_AUDIO_CodingDDP_Supported
+   OMX_AUDIO_PARAM_DDPTYPE ddp;
+#endif
+#ifdef OMX_AUDIO_CodingDTS_Supported
+   OMX_AUDIO_PARAM_DTSTYPE dts;
+#endif
+
+} OMX_FORMAT_PARAM_TYPE;
+
+/** Get the OMX_IndexParamAudio index corresponding to a specified audio coding type.
+ *
+ * @param coding Audio coding type.
+ * @param size  Pointer used to return the size of the parameter.
+ *
+ * @return OMX index or 0 if no match was found.
+ */
+OMX_INDEXTYPE mmalil_omx_audio_param_index(OMX_AUDIO_CODINGTYPE coding, OMX_U32 *size);
+
+/** Get the audio coding corresponding to a specified OMX_IndexParamAudio index.
+ *
+ * @param index Audio coding type.
+ *
+ * @return Audio coding type.
+ */
+OMX_AUDIO_CODINGTYPE mmalil_omx_audio_param_index_to_coding(OMX_INDEXTYPE index);
+
+/** Setup a default channel mapping based on the number of channels
+ * @param channel_mapping The output channel mapping
+ * @param nchannels Number of channels
+ *
+ * @return MMAL_SUCCESS if we managed to produce a channel mapping
+ */
+MMAL_STATUS_T mmalil_omx_default_channel_mapping(OMX_AUDIO_CHANNELTYPE *channel_mapping, unsigned int nchannels);
+
+/** Convert an OMX_IndexParamAudio into a MMAL elementary stream format.
+ *
+ * @param format Format structure to update.
+ * @param coding Audio coding type.
+ * @param param  Source OMX_IndexParamAudio structure.
+ *
+ * @return The MMAL encoding if a match was found or MMAL_ENCODING_UNKNOWN otherwise.
+ */
+MMAL_FOURCC_T mmalil_omx_audio_param_to_format(MMAL_ES_FORMAT_T *format,
+   OMX_AUDIO_CODINGTYPE coding, OMX_FORMAT_PARAM_TYPE *param);
+
+/** Convert a MMAL elementary stream format into a OMX_IndexParamAudio structure.
+ *
+ * @param param  OMX_IndexParamAudio structure to update.
+ * @param param_index returns the OMX_IndexParamAudio index corresponding to the format.
+ * @param format Source format structure.
+ *
+ * @return The OMX aduio coding type if a match was found or OMX_AUDIO_CodingUnused otherwise.
+ */
+OMX_AUDIO_CODINGTYPE mmalil_format_to_omx_audio_param(OMX_FORMAT_PARAM_TYPE *param,
+   OMX_INDEXTYPE *param_index, MMAL_ES_FORMAT_T *format);
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+#endif /* MMAL_IL_H */
diff --git a/interface/mmal/util/mmal_list.c b/interface/mmal/util/mmal_list.c
new file mode 100755 (executable)
index 0000000..6f45d78
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/vcos/vcos.h"
+#include "interface/mmal/util/mmal_list.h"
+
+
+/* Private list context */
+typedef struct MMAL_LIST_PRIVATE_T
+{
+   MMAL_LIST_T list;    /* must be first */
+   VCOS_MUTEX_T lock;
+} MMAL_LIST_PRIVATE_T;
+
+
+/* Lock the list. */
+static inline void mmal_list_lock(MMAL_LIST_T *list)
+{
+   vcos_mutex_lock(&((MMAL_LIST_PRIVATE_T*)list)->lock);
+}
+
+/* Unlock the list. */
+static inline void mmal_list_unlock(MMAL_LIST_T *list)
+{
+   vcos_mutex_unlock(&((MMAL_LIST_PRIVATE_T*)list)->lock);
+}
+
+/* Create a new linked list. */
+MMAL_LIST_T* mmal_list_create(void)
+{
+   MMAL_LIST_PRIVATE_T *private;
+
+   private = vcos_malloc(sizeof(MMAL_LIST_PRIVATE_T), "mmal-list");
+   if (private == NULL)
+      goto error;
+
+   if (vcos_mutex_create(&private->lock, "mmal-list lock") != VCOS_SUCCESS)
+      goto error;
+
+   /* lock to keep coverity happy */
+   vcos_mutex_lock(&private->lock);
+   private->list.first = NULL;
+   private->list.last = NULL;
+   private->list.length = 0;
+   vcos_mutex_unlock(&private->lock);
+
+   return &private->list;
+
+error:
+   vcos_free(private);
+   return NULL;
+}
+
+/* Destroy a linked list. */
+void mmal_list_destroy(MMAL_LIST_T *list)
+{
+   MMAL_LIST_PRIVATE_T *private = (MMAL_LIST_PRIVATE_T*)list;
+
+   vcos_mutex_delete(&private->lock);
+   vcos_free(private);
+}
+
+/* Remove the last element in the list. */
+MMAL_LIST_ELEMENT_T* mmal_list_pop_back(MMAL_LIST_T *list)
+{
+   MMAL_LIST_ELEMENT_T *element;
+
+   mmal_list_lock(list);
+
+   element = list->last;
+   if (element != NULL)
+   {
+      list->length--;
+
+      list->last = element->prev;
+      if (list->last)
+         list->last->next = NULL;
+      else
+         list->first = NULL; /* list is now empty */
+
+      element->prev = NULL;
+      element->next = NULL;
+   }
+
+   mmal_list_unlock(list);
+
+   return element;
+}
+
+/* Remove the first element in the list. */
+MMAL_LIST_ELEMENT_T* mmal_list_pop_front(MMAL_LIST_T *list)
+{
+   MMAL_LIST_ELEMENT_T *element;
+
+   mmal_list_lock(list);
+
+   element = list->first;
+   if (element != NULL)
+   {
+      list->length--;
+
+      list->first = element->next;
+      if (list->first)
+         list->first->prev = NULL;
+      else
+         list->last = NULL; /* list is now empty */
+
+      element->prev = NULL;
+      element->next = NULL;
+   }
+
+   mmal_list_unlock(list);
+
+   return element;
+}
+
+/* Add an element to the front of the list. */
+void mmal_list_push_front(MMAL_LIST_T *list, MMAL_LIST_ELEMENT_T *element)
+{
+   mmal_list_lock(list);
+
+   list->length++;
+
+   element->prev = NULL;
+   element->next = list->first;
+
+   if (list->first)
+      list->first->prev = element;
+   else
+      list->last = element; /* list was empty */
+
+   list->first = element;
+
+   mmal_list_unlock(list);
+}
+
+/* Add an element to the back of the list. */
+void mmal_list_push_back(MMAL_LIST_T *list, MMAL_LIST_ELEMENT_T *element)
+{
+   mmal_list_lock(list);
+
+   list->length++;
+
+   element->next = NULL;
+   element->prev = list->last;
+
+   if (list->last)
+      list->last->next = element;
+   else
+      list->first = element; /* list was empty */
+
+   list->last = element;
+
+   mmal_list_unlock(list);
+}
+
+/* Insert an element into the list. */
+void mmal_list_insert(MMAL_LIST_T *list, MMAL_LIST_ELEMENT_T *element, MMAL_LIST_COMPARE_T compare)
+{
+   MMAL_LIST_ELEMENT_T *cur;
+
+   mmal_list_lock(list);
+
+   if (list->first == NULL)
+   {
+      /* List empty */
+      mmal_list_unlock(list);
+      mmal_list_push_front(list, element);
+      return;
+   }
+
+   cur = list->first;
+   while (cur)
+   {
+      if (compare(element, cur))
+      {
+         /* Slot found! */
+         list->length++;
+         if (cur == list->first)
+            list->first = element;
+         else
+            cur->prev->next = element;
+         element->prev = cur->prev;
+         element->next = cur;
+         cur->prev = element;
+         mmal_list_unlock(list);
+         return;
+      }
+
+      cur = cur->next;
+   }
+
+   /* If we get here, none of the existing elements are greater
+    * than the new on, so just add it to the back of the list */
+   mmal_list_unlock(list);
+   mmal_list_push_back(list, element);
+}
diff --git a/interface/mmal/util/mmal_list.h b/interface/mmal/util/mmal_list.h
new file mode 100755 (executable)
index 0000000..967cc7b
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_LIST_H
+#define MMAL_LIST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \defgroup MmalList Generic Linked List
+ * This provides a thread-safe implementation of a linked list which can be used
+ * with any data type. */
+/* @{ */
+
+/** Single element in the list */
+typedef struct MMAL_LIST_ELEMENT_T
+{
+   struct MMAL_LIST_ELEMENT_T *next;
+   struct MMAL_LIST_ELEMENT_T *prev;
+} MMAL_LIST_ELEMENT_T;
+
+/** Linked list type.
+ * Clients shouldn't modify this directly. Use the provided API functions to
+ * add new elements. The public members are only for debug purposes.
+ * */
+typedef struct MMAL_LIST_T
+{
+   unsigned int length;         /**< Number of elements in the list (read-only) */
+   MMAL_LIST_ELEMENT_T *first;  /**< First element in the list (read-only) */
+   MMAL_LIST_ELEMENT_T *last;   /**< Last element in the list (read-only) */
+} MMAL_LIST_T;
+
+/** Create a new linked list.
+ *
+ * @return Pointer to new queue (NULL on failure).
+ */
+MMAL_LIST_T* mmal_list_create(void);
+
+/** Destroy a linked list.
+ *
+ * @param list List to destroy
+ */
+void mmal_list_destroy(MMAL_LIST_T *list);
+
+/** Remove the last element in the list.
+ *
+ * @param list    List to remove from
+ *
+ * @return Pointer to the last element (or NULL if empty)
+ */
+MMAL_LIST_ELEMENT_T* mmal_list_pop_back(MMAL_LIST_T *list);
+
+/** Remove the first element in the list.
+ *
+ * @param list    List to remove from
+ *
+ * @return Pointer to the first element (or NULL if empty)
+ */
+MMAL_LIST_ELEMENT_T* mmal_list_pop_front(MMAL_LIST_T *list);
+
+/** Add an element to the front of the list.
+ *
+ * @param list    List to add to
+ * @param element The element to add
+ */
+void mmal_list_push_front(MMAL_LIST_T *list, MMAL_LIST_ELEMENT_T *element);
+
+/** Add an element to the back of the list.
+ *
+ * @param list    List to add to
+ * @param element The element to add
+ */
+void mmal_list_push_back(MMAL_LIST_T *list, MMAL_LIST_ELEMENT_T *element);
+
+/** List comparison function.
+ * This is supplied by a client when inserting an element in
+ * the middle of the list. The list will always insert a smaller
+ * element in front of a larger element.
+ *
+ * @return TRUE:  lhs <  rhs
+ *         FALSE: lhs >= rhs
+ */
+typedef int (*MMAL_LIST_COMPARE_T)(MMAL_LIST_ELEMENT_T *lhs, MMAL_LIST_ELEMENT_T *rhs);
+
+/** Insert an element into the list.
+ * The location where the element is inserted is determined using
+ * the supplied comparison function. Smaller elements are inserted
+ * in front of larger elements.
+ *
+ * @param list    List to add to
+ * @param element The element to insert
+ * @param compare Comparison function supplied by the client
+ */
+void mmal_list_insert(MMAL_LIST_T *list, MMAL_LIST_ELEMENT_T *element, MMAL_LIST_COMPARE_T compare);
+
+/* @} */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MMAL_LIST_H */
diff --git a/interface/mmal/util/mmal_param_convert.c b/interface/mmal/util/mmal_param_convert.c
new file mode 100755 (executable)
index 0000000..ec48a5b
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "mmal_param_convert.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+typedef struct string_pair_t
+{
+   const char *string;
+   int value;
+} string_pair_t;
+
+static MMAL_STATUS_T parse_enum(int *dest, string_pair_t *pairs, size_t n_pairs, const char *str)
+{
+   size_t i;
+   for (i=0; i<n_pairs; i++)
+   {
+      if (vcos_strcasecmp(str, pairs[i].string) == 0)
+      {
+         *dest = pairs[i].value;
+         return MMAL_SUCCESS;
+      }
+   }
+   return MMAL_EINVAL;
+}
+
+MMAL_STATUS_T mmal_parse_video_size(uint32_t *w, uint32_t *h, const char *str)
+{
+   static struct {
+      const char *name;
+      uint32_t width;
+      uint32_t height;
+   } sizes[] = {
+      { "1080p", 1920, 1080 },
+      { "720p",  1280,  720 },
+      { "vga",    640,  480 },
+      { "wvga",   800,  480 },
+      { "cif",    352,  288 },
+      { "qcif",   352/2, 288/2 },
+   };
+   size_t i;
+   for (i=0; i<vcos_countof(sizes); i++)
+   {
+      if (vcos_strcasecmp(str, sizes[i].name) == 0)
+      {
+         *w = sizes[i].width;
+         *h = sizes[i].height;
+         return MMAL_SUCCESS;
+      }
+   }
+   return MMAL_EINVAL;
+}
+
+MMAL_STATUS_T mmal_parse_rational(MMAL_RATIONAL_T *dest, const char *str)
+{
+   MMAL_STATUS_T ret;
+   char *endptr;
+   long num, den = 1;
+   num = strtoul(str, &endptr, 0);
+   if (endptr[0] == '\0')
+   {
+      /* that's it */
+      ret = MMAL_SUCCESS;
+   }
+   else if (endptr[0] == '/')
+   {
+      den = strtoul(endptr+1, &endptr, 0);
+      if (endptr[0] == '\0')
+         ret = MMAL_SUCCESS;
+      else
+         ret = MMAL_EINVAL;
+   }
+   else
+   {
+      ret = MMAL_EINVAL;
+   }
+   dest->num = num;
+   dest->den = den;
+   return ret;
+}
+
+MMAL_STATUS_T mmal_parse_int(int *dest, const char *str)
+{
+   char *endptr;
+   long i = strtol(str, &endptr, 0);
+   if (endptr[0] == '\0')
+   {
+      *dest = i;
+      return MMAL_SUCCESS;
+   }
+   else
+   {
+      return MMAL_EINVAL;
+   }
+}
+
+MMAL_STATUS_T mmal_parse_uint(unsigned int *dest, const char *str)
+{
+   char *endptr;
+   unsigned long i = strtoul(str, &endptr, 0);
+   if (endptr[0] == '\0')
+   {
+      *dest = i;
+      return MMAL_SUCCESS;
+   }
+   else
+   {
+      return MMAL_EINVAL;
+   }
+}
+
+MMAL_STATUS_T mmal_parse_video_codec(uint32_t *dest, const char *str)
+{
+   static string_pair_t video_codec_enums[] = {
+      { "h264",  MMAL_ENCODING_H264 },
+      { "h263",  MMAL_ENCODING_H263 },
+      { "mpeg4", MMAL_ENCODING_MP4V },
+      { "mpeg2", MMAL_ENCODING_MP2V },
+      { "vp8",   MMAL_ENCODING_VP8 },
+      { "vp7",   MMAL_ENCODING_VP7 },
+      { "vp6",   MMAL_ENCODING_VP6 },
+   };
+   int i = 0;
+   MMAL_STATUS_T ret;
+
+   ret = parse_enum(&i, video_codec_enums, vcos_countof(video_codec_enums), str);
+   *dest = i;
+   return ret;
+}
+
+MMAL_STATUS_T mmal_parse_geometry(MMAL_RECT_T *dest, const char *str)
+{
+   MMAL_STATUS_T ret;
+   uint32_t w, h, x, y;
+   x = y = w = h = 0;
+   /* coverity[secure_coding] */
+   if (sscanf(str, "%d*%d+%d+%d", &w,&h,&x,&y) == 4 ||
+       sscanf(str, "%d*%d", &w,&h) == 2)
+   {
+      dest->x = x;
+      dest->y = y;
+      dest->width = w;
+      dest->height = h;
+      ret = MMAL_SUCCESS;
+   }
+   else
+   {
+      ret = MMAL_EINVAL;
+   }
+   return ret;
+}
+
diff --git a/interface/mmal/util/mmal_param_convert.h b/interface/mmal/util/mmal_param_convert.h
new file mode 100755 (executable)
index 0000000..1d653c2
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file
+ * Support for setting/getting parameters as string values.
+ */
+
+#ifndef MMAL_PARAM_CONVERT_H
+#define MMAL_PARAM_CONVERT_H
+
+#include "interface/mmal/mmal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Parse a video size. e.g. "1080p" gives 1920x1080.
+ *
+ * @param w width result
+ * @param h height result
+ * @param str string to convert
+ * @return MMAL_SUCCESS or error code
+ */
+MMAL_STATUS_T mmal_parse_video_size(uint32_t *w, uint32_t *h, const char *str);
+
+/** Parse a rational number. e.g. "30000/1001", "30", etc.
+ * @param dest filled in with result
+ * @param str string to convert
+ * @return MMAL_SUCCESS or error code
+ */
+MMAL_STATUS_T mmal_parse_rational(MMAL_RATIONAL_T *dest, const char *str);
+
+/** Parse an integer, e.g. -10, 0x1A, etc.
+ * @param dest filled in with result
+ * @param str string to convert
+ * @return MMAL_SUCCESS or error code
+ */
+MMAL_STATUS_T mmal_parse_int(int *dest, const char *str);
+
+/** Parse an unsigned integer, e.g. 10, 0x1A, etc.
+ * @param dest filled in with result
+ * @param str string to convert
+ * @return MMAL_SUCCESS or error code
+ */
+MMAL_STATUS_T mmal_parse_uint(unsigned int *dest, const char *str);
+
+/** Parse a geometry for a rectangle
+ *
+ * e.g. 100*100+50+75
+ * or   200*150
+ * @param dest filled in with result
+ * @param str string to convert
+ * @return MMAL_SUCCESS or error code
+ */
+MMAL_STATUS_T mmal_parse_geometry(MMAL_RECT_T *dest, const char *str);
+
+/** Parse a video codec name (something that can be encoded/decoded)
+ * @param str string to convert
+ * @param dest filled in with result
+ * @return MMAL_SUCCESS or error code
+ */
+MMAL_STATUS_T mmal_parse_video_codec(uint32_t *dest, const char *str);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/interface/mmal/util/mmal_util.c b/interface/mmal/util/mmal_util.c
new file mode 100755 (executable)
index 0000000..aa1f3f9
--- /dev/null
@@ -0,0 +1,473 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "interface/mmal/mmal.h"
+#include "mmal_encodings.h"
+#include "mmal_util.h"
+#include "mmal_logging.h"
+#include <string.h>
+#include <stdio.h>
+
+#define STATUS_TO_STR(x) { MMAL_##x, #x }
+
+static struct {
+   MMAL_STATUS_T status;
+   const char *str;
+} status_to_string_map[] =
+{
+   STATUS_TO_STR(SUCCESS),
+   STATUS_TO_STR(ENOMEM),
+   STATUS_TO_STR(ENOSPC),
+   STATUS_TO_STR(EINVAL),
+   STATUS_TO_STR(ENOSYS),
+   STATUS_TO_STR(ENOENT),
+   STATUS_TO_STR(ENXIO),
+   STATUS_TO_STR(EIO),
+   STATUS_TO_STR(ESPIPE),
+   STATUS_TO_STR(ECORRUPT),
+   STATUS_TO_STR(ENOTREADY),
+   STATUS_TO_STR(ECONFIG),
+   {0, 0}
+};
+
+const char *mmal_status_to_string(MMAL_STATUS_T status)
+{
+   unsigned i;
+
+   for (i=0; status_to_string_map[i].str; i++)
+      if (status_to_string_map[i].status == status)
+         break;
+
+   return status_to_string_map[i].str ? status_to_string_map[i].str : "UNKNOWN";
+}
+
+static struct {
+   uint32_t encoding;
+   uint32_t pitch_num;
+   uint32_t pitch_den;
+   uint32_t alignment;
+} pixel_pitch[] =
+{
+   {MMAL_ENCODING_I420,  1, 1, 1},
+   {MMAL_ENCODING_YV12,  1, 1, 1},
+   {MMAL_ENCODING_I422,  1, 1, 1},
+   {MMAL_ENCODING_NV21,  1, 1, 1},
+   {MMAL_ENCODING_NV12,  1, 1, 1},
+   {MMAL_ENCODING_ARGB,  4, 1, 1},
+   {MMAL_ENCODING_RGBA,  4, 1, 1},
+   {MMAL_ENCODING_RGB32, 4, 1, 1},
+   {MMAL_ENCODING_ABGR,  4, 1, 1},
+   {MMAL_ENCODING_BGRA,  4, 1, 1},
+   {MMAL_ENCODING_BGR32, 4, 1, 1},
+   {MMAL_ENCODING_RGB16, 2, 1, 1},
+   {MMAL_ENCODING_RGB24, 3, 1, 1},
+   {MMAL_ENCODING_BGR16, 2, 1, 1},
+   {MMAL_ENCODING_BGR24, 3, 1, 1},
+   {MMAL_ENCODING_I420_16, 2, 1, 1},
+   {MMAL_ENCODING_I420_10, 2, 1, 1},
+
+   {MMAL_ENCODING_I420_SLICE,  1, 1, 1},
+   {MMAL_ENCODING_I422_SLICE,  1, 1, 1},
+   {MMAL_ENCODING_ARGB_SLICE,  4, 1, 1},
+   {MMAL_ENCODING_RGBA_SLICE,  4, 1, 1},
+   {MMAL_ENCODING_RGB32_SLICE, 4, 1, 1},
+   {MMAL_ENCODING_ABGR_SLICE,  4, 1, 1},
+   {MMAL_ENCODING_BGRA_SLICE,  4, 1, 1},
+   {MMAL_ENCODING_BGR32_SLICE, 4, 1, 1},
+   {MMAL_ENCODING_RGB16_SLICE, 2, 1, 1},
+   {MMAL_ENCODING_RGB24_SLICE, 3, 1, 1},
+   {MMAL_ENCODING_BGR16_SLICE, 2, 1, 1},
+   {MMAL_ENCODING_BGR24_SLICE, 3, 1, 1},
+
+   {MMAL_ENCODING_YUYV,  2, 1, 1},
+   {MMAL_ENCODING_YVYU,  2, 1, 1},
+   {MMAL_ENCODING_UYVY,  2, 1, 1},
+   {MMAL_ENCODING_VYUY,  2, 1, 1},
+
+   // Bayer formats, the resulting alignment must also be a multiple of 16.
+   // Camplus padded to a multiple of 32, so let's copy that.
+   {MMAL_ENCODING_BAYER_SBGGR8,        1, 1, 32},
+   {MMAL_ENCODING_BAYER_SGBRG8,        1, 1, 32},
+   {MMAL_ENCODING_BAYER_SGRBG8,        1, 1, 32},
+   {MMAL_ENCODING_BAYER_SRGGB8,        1, 1, 32},
+   {MMAL_ENCODING_BAYER_SBGGR10DPCM8,  1, 1, 32},
+   {MMAL_ENCODING_BAYER_SGBRG10DPCM8,  1, 1, 32},
+   {MMAL_ENCODING_BAYER_SGRBG10DPCM8,  1, 1, 32},
+   {MMAL_ENCODING_BAYER_SRGGB10DPCM8,  1, 1, 32},
+   {MMAL_ENCODING_BAYER_SBGGR10P,      10,8, 32},
+   {MMAL_ENCODING_BAYER_SGRBG10P,      10,8, 32},
+   {MMAL_ENCODING_BAYER_SGBRG10P,      10,8, 32},
+   {MMAL_ENCODING_BAYER_SRGGB10P,      10,8, 32},
+   {MMAL_ENCODING_BAYER_SBGGR12P,      12,8, 32},
+   {MMAL_ENCODING_BAYER_SGRBG12P,      12,8, 32},
+   {MMAL_ENCODING_BAYER_SGBRG12P,      12,8, 32},
+   {MMAL_ENCODING_BAYER_SRGGB12P,      12,8, 32},
+   {MMAL_ENCODING_BAYER_SBGGR16,       2, 1, 32},
+   {MMAL_ENCODING_BAYER_SGBRG16,       2, 1, 32},
+   {MMAL_ENCODING_BAYER_SGRBG16,       2, 1, 32},
+   {MMAL_ENCODING_BAYER_SRGGB16,       2, 1, 32},
+
+   /* {MMAL_ENCODING_YUVUV128, 1, 1}, That's a special case which must not be included */
+   /* {MMAL_ENCODING_YUVUV64_16, 1, 1}, That's a special case which must not be included */
+   /* {MMAL_ENCODING_YUVUV64_10, 1, 1}, That's a special case which must not be included */
+   {MMAL_ENCODING_UNKNOWN, 0, 0}
+};
+
+static struct {
+   uint32_t encoding;
+   uint32_t sliced_encoding;
+} slice_equivalents[] =
+{
+   { MMAL_ENCODING_I420,      MMAL_ENCODING_I420_SLICE   },
+   { MMAL_ENCODING_I422,      MMAL_ENCODING_I422_SLICE   },
+   { MMAL_ENCODING_ARGB,      MMAL_ENCODING_ARGB_SLICE   },
+   { MMAL_ENCODING_RGBA,      MMAL_ENCODING_RGBA_SLICE   },
+   { MMAL_ENCODING_RGB32,     MMAL_ENCODING_RGB32_SLICE  },
+   { MMAL_ENCODING_ABGR,      MMAL_ENCODING_ABGR_SLICE   },
+   { MMAL_ENCODING_BGRA,      MMAL_ENCODING_BGRA_SLICE   },
+   { MMAL_ENCODING_BGR32,     MMAL_ENCODING_BGR32_SLICE  },
+   { MMAL_ENCODING_RGB16,     MMAL_ENCODING_RGB16_SLICE  },
+   { MMAL_ENCODING_RGB24,     MMAL_ENCODING_RGB24_SLICE  },
+   { MMAL_ENCODING_BGR16,     MMAL_ENCODING_BGR16_SLICE  },
+   { MMAL_ENCODING_BGR24,     MMAL_ENCODING_BGR24_SLICE  },
+   { MMAL_ENCODING_UNKNOWN,   MMAL_ENCODING_UNKNOWN      },
+};
+
+
+uint32_t mmal_encoding_stride_to_width(uint32_t encoding, uint32_t stride)
+{
+   unsigned int i;
+
+   for(i = 0; pixel_pitch[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
+      if(pixel_pitch[i].encoding == encoding) break;
+
+   if(pixel_pitch[i].encoding == MMAL_ENCODING_UNKNOWN)
+      return 0;
+
+   return pixel_pitch[i].pitch_den * stride / pixel_pitch[i].pitch_num;
+}
+
+uint32_t mmal_encoding_width_to_stride(uint32_t encoding, uint32_t width)
+{
+   unsigned int i;
+
+   for(i = 0; pixel_pitch[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
+      if(pixel_pitch[i].encoding == encoding) break;
+
+   if(pixel_pitch[i].encoding == MMAL_ENCODING_UNKNOWN)
+      return 0;
+
+   return VCOS_ALIGN_UP(pixel_pitch[i].pitch_num * width / pixel_pitch[i].pitch_den, pixel_pitch[i].alignment);
+}
+
+uint32_t mmal_encoding_get_slice_variant(uint32_t encoding)
+{
+   unsigned int i;
+
+   for(i = 0; slice_equivalents[i].encoding != MMAL_ENCODING_UNKNOWN; i++)
+      if(slice_equivalents[i].encoding == encoding) break;
+
+   return slice_equivalents[i].sliced_encoding;
+}
+
+const char* mmal_port_type_to_string(MMAL_PORT_TYPE_T type)
+{
+   const char *str;
+
+   switch (type)
+   {
+   case MMAL_PORT_TYPE_INPUT:   str = "in";  break;
+   case MMAL_PORT_TYPE_OUTPUT:  str = "out"; break;
+   case MMAL_PORT_TYPE_CLOCK:   str = "clk"; break;
+   case MMAL_PORT_TYPE_CONTROL: str = "ctr"; break;
+   default:                     str = "invalid"; break;
+   }
+
+   return str;
+}
+
+MMAL_PARAMETER_HEADER_T *mmal_port_parameter_alloc_get(MMAL_PORT_T *port,
+   uint32_t id, uint32_t size, MMAL_STATUS_T *p_status)
+{
+   MMAL_PARAMETER_HEADER_T *param = NULL;
+   MMAL_STATUS_T status = MMAL_ENOSYS;
+
+   if (size < sizeof(MMAL_PARAMETER_HEADER_T))
+      size = sizeof(MMAL_PARAMETER_HEADER_T);
+
+   if ((param = vcos_calloc(1, size, "mmal_port_param_get")) == NULL)
+   {
+      status = MMAL_ENOMEM;
+      goto error;
+   }
+
+   param->id = id;
+   param->size = size;
+
+   if ((status = mmal_port_parameter_get(port, param)) == MMAL_ENOSPC)
+   {
+      /* We need to reallocate to get enough space for all parameter data */
+      size = param->size;
+      vcos_free(param);
+      if ((param = vcos_calloc(1, size, "mmal_port_param_get")) == NULL)
+      {
+         status = MMAL_ENOMEM;
+         goto error;
+      }
+
+      /* Now retrieve it again */
+      param->id = id;
+      param->size = size;
+      status = mmal_port_parameter_get(port, param);
+   }
+
+   if (status != MMAL_SUCCESS)
+      goto error;
+
+end:
+   if (p_status) *p_status = status;
+   return param;
+error:
+   if (param) vcos_free(param);
+   param = NULL;
+   goto end;
+}
+
+void mmal_port_parameter_free(MMAL_PARAMETER_HEADER_T *param)
+{
+   vcos_free(param);
+}
+
+/** Copy buffer header metadata from source to dest
+ */
+void mmal_buffer_header_copy_header(MMAL_BUFFER_HEADER_T *dest, const MMAL_BUFFER_HEADER_T *src)
+{
+   dest->cmd    = src->cmd;
+   dest->offset = src->offset;
+   dest->length = src->length;
+   dest->flags  = src->flags;
+   dest->pts    = src->pts;
+   dest->dts    = src->dts;
+   *dest->type = *src->type;
+}
+
+/** Create a pool of MMAL_BUFFER_HEADER_T */
+MMAL_POOL_T *mmal_port_pool_create(MMAL_PORT_T *port, unsigned int headers, uint32_t payload_size)
+{
+   if (!port || !port->priv)
+      return NULL;
+
+   LOG_TRACE("%s(%i:%i) port %p, headers %u, size %i", port->component->name,
+             (int)port->type, (int)port->index, port, headers, (int)payload_size);
+
+   /* Create a pool and ask the port for some memory */
+   return mmal_pool_create_with_allocator(headers, payload_size, (void *)port,
+                                          (mmal_pool_allocator_alloc_t)mmal_port_payload_alloc,
+                                          (mmal_pool_allocator_free_t)mmal_port_payload_free);
+}
+
+/** Destroy a pool of MMAL_BUFFER_HEADER_T */
+void mmal_port_pool_destroy(MMAL_PORT_T *port, MMAL_POOL_T *pool)
+{
+   if (!port || !port->priv || !pool)
+      return;
+
+   LOG_TRACE("%s(%i:%i) port %p, pool %p", port->component->name,
+             (int)port->type, (int)port->index, port, pool);
+
+   if (!vcos_verify(!port->is_enabled))
+   {
+      LOG_ERROR("port %p, pool %p destroyed while port enabled", port, pool);
+      mmal_port_disable(port);
+   }
+
+   mmal_pool_destroy(pool);
+}
+
+/*****************************************************************************/
+void mmal_log_dump_port(MMAL_PORT_T *port)
+{
+   if (!port)
+      return;
+
+   LOG_DEBUG("%s(%p)", port->name, port);
+
+   mmal_log_dump_format(port->format);
+
+   LOG_DEBUG(" buffers num: %i(opt %i, min %i), size: %i(opt %i, min: %i), align: %i",
+            port->buffer_num, port->buffer_num_recommended, port->buffer_num_min,
+            port->buffer_size, port->buffer_size_recommended, port->buffer_size_min,
+            port->buffer_alignment_min);
+}
+
+/*****************************************************************************/
+void mmal_log_dump_format(MMAL_ES_FORMAT_T *format)
+{
+   const char *name_type;
+
+   if (!format)
+      return;
+
+   switch(format->type)
+   {
+   case MMAL_ES_TYPE_AUDIO: name_type = "audio"; break;
+   case MMAL_ES_TYPE_VIDEO: name_type = "video"; break;
+   case MMAL_ES_TYPE_SUBPICTURE: name_type = "subpicture"; break;
+   default: name_type = "unknown"; break;
+   }
+
+   LOG_DEBUG("type: %s, fourcc: %4.4s", name_type, (char *)&format->encoding);
+   LOG_DEBUG(" bitrate: %i, framed: %i", format->bitrate,
+            !!(format->flags & MMAL_ES_FORMAT_FLAG_FRAMED));
+   LOG_DEBUG(" extra data: %i, %p", format->extradata_size, format->extradata);
+   switch(format->type)
+   {
+   case MMAL_ES_TYPE_AUDIO:
+      LOG_DEBUG(" samplerate: %i, channels: %i, bps: %i, block align: %i",
+               format->es->audio.sample_rate, format->es->audio.channels,
+               format->es->audio.bits_per_sample, format->es->audio.block_align);
+      break;
+
+   case MMAL_ES_TYPE_VIDEO:
+      LOG_DEBUG(" width: %i, height: %i, (%i,%i,%i,%i)",
+               format->es->video.width, format->es->video.height,
+               format->es->video.crop.x, format->es->video.crop.y,
+               format->es->video.crop.width, format->es->video.crop.height);
+      LOG_DEBUG(" pixel aspect ratio: %i/%i, frame rate: %i/%i",
+               format->es->video.par.num, format->es->video.par.den,
+               format->es->video.frame_rate.num, format->es->video.frame_rate.den);
+      break;
+
+   case MMAL_ES_TYPE_SUBPICTURE:
+      break;
+
+   default: break;
+   }
+}
+
+MMAL_PORT_T *mmal_util_get_port(MMAL_COMPONENT_T *comp, MMAL_PORT_TYPE_T type, unsigned index)
+{
+   unsigned num;
+   MMAL_PORT_T **list;
+
+   switch (type)
+   {
+   case MMAL_PORT_TYPE_INPUT:
+      num = comp->input_num;
+      list = comp->input;
+      break;
+
+   case MMAL_PORT_TYPE_OUTPUT:
+      num = comp->output_num;
+      list = comp->output;
+      break;
+
+   case MMAL_PORT_TYPE_CLOCK:
+      num = comp->clock_num;
+      list = comp->clock;
+      break;
+
+   case MMAL_PORT_TYPE_CONTROL:
+      num = 1;
+      list = &comp->control;
+      break;
+
+   default:
+      vcos_assert(0);
+      return NULL;
+   }
+   if (index < num)
+      /* coverity[ptr_arith] num is 1 here */
+      return list[index];
+   else
+      return NULL;
+}
+
+char *mmal_4cc_to_string(char *buf, size_t len, uint32_t fourcc)
+{
+   char *src = (char*)&fourcc;
+   vcos_assert(len >= 5);
+   if (len < 5)
+   {
+      buf[0] = '\0';
+   }
+   else if (fourcc)
+   {
+      memcpy(buf, src, 4);
+      buf[4] = '\0';
+   }
+   else
+   {
+      snprintf(buf, len, "<0>");
+   }
+   return buf;
+}
+
+#define MAX_ENCODINGS_NUM 25
+typedef struct {
+   MMAL_PARAMETER_HEADER_T header;
+   MMAL_FOURCC_T encodings[MAX_ENCODINGS_NUM];
+} MMAL_SUPPORTED_ENCODINGS_T;
+
+
+int mmal_util_rgb_order_fixed(MMAL_PORT_T *port)
+{
+   int new_fw = 0;
+   MMAL_STATUS_T ret;
+   //Firmware support of RGB24 vs BGR24 colour ordering from camera
+   //and video splitter components has been corrected as of June 2016.
+   //New firmwares always report MMAL_ENCODING_RGB24 before BGR24, and
+   //that is the format we want.
+   //Old firmware reported BGR24 first, and also returned an error on
+   //the still port on querying MMAL_PARAMETER_SUPPORTED_ENCODINGS.
+
+   MMAL_SUPPORTED_ENCODINGS_T sup_encodings = {{MMAL_PARAMETER_SUPPORTED_ENCODINGS, sizeof(sup_encodings)}, {0}};
+   ret = mmal_port_parameter_get(port, &sup_encodings.header);
+   if (ret == MMAL_SUCCESS || ret == MMAL_ENOSPC)
+   {
+      //Allow ENOSPC error and hope that the desired formats are in the first
+      //MAX_ENCODINGS_NUM entries.
+      int i;
+      int num_encodings = (sup_encodings.header.size - sizeof(sup_encodings.header)) /
+          sizeof(sup_encodings.encodings[0]);
+      if(num_encodings > MAX_ENCODINGS_NUM)
+         num_encodings = MAX_ENCODINGS_NUM;
+      for (i=0; i<num_encodings; i++)
+      {
+         if (sup_encodings.encodings[i] == MMAL_ENCODING_BGR24)
+         {
+            //Found BGR24 first - old firmware.
+            break;
+         }
+         if (sup_encodings.encodings[i] == MMAL_ENCODING_RGB24)
+         {
+            //Found RGB24 first - new firmware, so use RGB24.
+            new_fw = 1;
+         }
+      }
+   }
+   return new_fw;
+}
diff --git a/interface/mmal/util/mmal_util.h b/interface/mmal/util/mmal_util.h
new file mode 100755 (executable)
index 0000000..556c228
--- /dev/null
@@ -0,0 +1,191 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_UTIL_H
+#define MMAL_UTIL_H
+
+#include "interface/mmal/mmal.h"
+
+/** \defgroup MmalUtilities Utility functions
+ * The utility functions provide helpers for common functionality that is not part
+ * of the core MMAL API.
+ * @{
+ */
+
+/** Offset in bytes of FIELD in TYPE. */
+#define MMAL_OFFSET(TYPE, FIELD) ((size_t)((uint8_t *)&((TYPE*)0)->FIELD - (uint8_t *)0))
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Convert a status to a statically-allocated string.
+ *
+ * @param status The MMAL status code.
+ * @return A C string describing the status code.
+ */
+const char *mmal_status_to_string(MMAL_STATUS_T status);
+
+/** Convert stride to pixel width for a given pixel encoding.
+ *
+ * @param encoding The pixel encoding (such as one of the \ref MmalEncodings "pre-defined encodings")
+ * @param stride The stride in bytes.
+ * @return The width in pixels.
+ */
+uint32_t mmal_encoding_stride_to_width(uint32_t encoding, uint32_t stride);
+
+/** Convert pixel width to stride for a given pixel encoding
+ *
+ * @param encoding The pixel encoding (such as one of the \ref MmalEncodings "pre-defined encodings")
+ * @param width The width in pixels.
+ * @return The stride in bytes.
+ */
+uint32_t mmal_encoding_width_to_stride(uint32_t encoding, uint32_t width);
+
+/** Return the 16 line high sliced version of a given pixel encoding
+ *
+ * @param encoding The pixel encoding (such as one of the \ref MmalEncodings "pre-defined encodings")
+ * @return The sliced equivalent, or MMAL_ENCODING_UNKNOWN if not supported.
+ */
+uint32_t mmal_encoding_get_slice_variant(uint32_t encoding);
+
+/** Convert a port type to a string.
+ *
+ * @param type The MMAL port type.
+ * @return A NULL-terminated string describing the port type.
+ */
+const char* mmal_port_type_to_string(MMAL_PORT_TYPE_T type);
+
+/** Get a parameter from a port allocating the required amount of memory
+ * for the parameter (i.e. for variable length parameters like URI or arrays).
+ * The size field will be set on output to the actual size of the
+ * parameter allocated and retrieved.
+ *
+ * The pointer returned must be released by a call to \ref mmal_port_parameter_free().
+ *
+ * @param port port to send request to
+ * @param id parameter id
+ * @param size initial size hint for allocation (can be 0)
+ * @param status status of the parameter get operation (can be 0)
+ * @return pointer to the header of the parameter or NULL on failure.
+ */
+MMAL_PARAMETER_HEADER_T *mmal_port_parameter_alloc_get(MMAL_PORT_T *port,
+   uint32_t id, uint32_t size, MMAL_STATUS_T *status);
+
+/** Free a parameter structure previously allocated via
+ * \ref mmal_port_parameter_alloc_get().
+ *
+ * @param param pointer to header of the parameter
+ */
+void mmal_port_parameter_free(MMAL_PARAMETER_HEADER_T *param);
+
+/** Copy buffer header metadata from source to destination.
+ *
+ * @param dest The destination buffer header.
+ * @param src  The source buffer header.
+ */
+void mmal_buffer_header_copy_header(MMAL_BUFFER_HEADER_T *dest, const MMAL_BUFFER_HEADER_T *src);
+
+/** Create a pool of MMAL_BUFFER_HEADER_T associated with a specific port.
+ * This allows a client to allocate memory for the payload buffers based on the preferences
+ * of a port. This for instance will allow the port to allocate memory which can be shared
+ * between the host processor and videocore.
+ * After allocation, all allocated buffer headers will have been added to the queue.
+ *
+ * It is valid to create a pool with no buffer headers, or with zero size payload buffers.
+ * The mmal_pool_resize() function can be used to increase or decrease the number of buffer
+ * headers, or the size of the payload buffers, after creation of the pool.
+ *
+ * @param port         Port responsible for creating the pool.
+ * @param headers      Number of buffers which will be allocated with the pool.
+ * @param payload_size Size of the payload buffer which will be allocated in
+ *                     each of the buffer headers.
+ * @return Pointer to the newly created pool or NULL on failure.
+ */
+MMAL_POOL_T *mmal_port_pool_create(MMAL_PORT_T *port,
+   unsigned int headers, uint32_t payload_size);
+
+/** Destroy a pool of MMAL_BUFFER_HEADER_T associated with a specific port.
+ * This will also deallocate all of the memory which was allocated when creating or
+ * resizing the pool.
+ *
+ * @param port  Pointer to the port responsible for creating the pool.
+ * @param pool  Pointer to the pool to be destroyed.
+ */
+void mmal_port_pool_destroy(MMAL_PORT_T *port, MMAL_POOL_T *pool);
+
+/** Log the content of a \ref MMAL_PORT_T structure.
+ *
+ * @param port  Pointer to the port to dump.
+ */
+void mmal_log_dump_port(MMAL_PORT_T *port);
+
+/** Log the content of a \ref MMAL_ES_FORMAT_T structure.
+ *
+ * @param format  Pointer to the format to dump.
+ */
+void mmal_log_dump_format(MMAL_ES_FORMAT_T *format);
+
+/** Return the nth port.
+ *
+ * @param comp   component to query
+ * @param index  port index
+ * @param type   port type
+ *
+ * @return port or NULL if not found
+ */
+MMAL_PORT_T *mmal_util_get_port(MMAL_COMPONENT_T *comp, MMAL_PORT_TYPE_T type, unsigned index);
+
+/** Convert a 4cc into a string.
+ *
+ * @param buf    Destination for result
+ * @param len    Size of result buffer
+ * @param fourcc 4cc to be converted
+ * @return converted string (buf)
+ *
+ */
+char *mmal_4cc_to_string(char *buf, size_t len, uint32_t fourcc);
+
+
+/** On FW prior to June 2016, camera and video_splitter
+ *  had BGR24 and RGB24 support reversed.
+ *  This is now fixed, and this function will return whether the
+ *  FW has the fix or not.
+ *
+ * @param port   MMAL port to check (on camera or video_splitter)
+ * @return 0 if old firmware, 1 if new.
+ *
+ */
+int mmal_util_rgb_order_fixed(MMAL_PORT_T *port);
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+#endif
diff --git a/interface/mmal/util/mmal_util_params.c b/interface/mmal/util/mmal_util_params.c
new file mode 100755 (executable)
index 0000000..6e24791
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal_util_params.h"
+
+/** Helper function to set the value of a boolean parameter */
+MMAL_STATUS_T mmal_port_parameter_set_boolean(MMAL_PORT_T *port, uint32_t id, MMAL_BOOL_T value)
+{
+   MMAL_PARAMETER_BOOLEAN_T param = {{id, sizeof(param)}, value};
+   return mmal_port_parameter_set(port, &param.hdr);
+}
+
+/** Helper function to get the value of a boolean parameter */
+MMAL_STATUS_T mmal_port_parameter_get_boolean(MMAL_PORT_T *port, uint32_t id, MMAL_BOOL_T *value)
+{
+   MMAL_PARAMETER_BOOLEAN_T param = {{id, sizeof(param)}, 0};
+   // coverity[overrun-buffer-val] Structure accessed correctly via size field
+   MMAL_STATUS_T status = mmal_port_parameter_get(port, &param.hdr);
+   if (status == MMAL_SUCCESS)
+      *value = param.enable;
+   return status;
+}
+
+/** Helper function to set the value of a 64 bits unsigned integer parameter */
+MMAL_STATUS_T mmal_port_parameter_set_uint64(MMAL_PORT_T *port, uint32_t id, uint64_t value)
+{
+   MMAL_PARAMETER_UINT64_T param = {{id, sizeof(param)}, value};
+   return mmal_port_parameter_set(port, &param.hdr);
+}
+
+/** Helper function to get the value of a 64 bits unsigned integer parameter */
+MMAL_STATUS_T mmal_port_parameter_get_uint64(MMAL_PORT_T *port, uint32_t id, uint64_t *value)
+{
+   MMAL_PARAMETER_UINT64_T param = {{id, sizeof(param)}, 0LL};
+   // coverity[overrun-buffer-val] Structure accessed correctly via size field
+   MMAL_STATUS_T status = mmal_port_parameter_get(port, &param.hdr);
+   if (status == MMAL_SUCCESS)
+      *value = param.value;
+   return status;
+}
+
+/** Helper function to set the value of a 64 bits signed integer parameter */
+MMAL_STATUS_T mmal_port_parameter_set_int64(MMAL_PORT_T *port, uint32_t id, int64_t value)
+{
+   MMAL_PARAMETER_INT64_T param = {{id, sizeof(param)}, value};
+   return mmal_port_parameter_set(port, &param.hdr);
+}
+
+/** Helper function to get the value of a 64 bits signed integer parameter */
+MMAL_STATUS_T mmal_port_parameter_get_int64(MMAL_PORT_T *port, uint32_t id, int64_t *value)
+{
+   MMAL_PARAMETER_INT64_T param = {{id, sizeof(param)}, 0LL};
+   // coverity[overrun-buffer-val] Structure accessed correctly via size field
+   MMAL_STATUS_T status = mmal_port_parameter_get(port, &param.hdr);
+   if (status == MMAL_SUCCESS)
+      *value = param.value;
+   return status;
+}
+
+/** Helper function to set the value of a 32 bits unsigned integer parameter */
+MMAL_STATUS_T mmal_port_parameter_set_uint32(MMAL_PORT_T *port, uint32_t id, uint32_t value)
+{
+   MMAL_PARAMETER_UINT32_T param = {{id, sizeof(param)}, value};
+   return mmal_port_parameter_set(port, &param.hdr);
+}
+
+/** Helper function to get the value of a 32 bits unsigned integer parameter */
+MMAL_STATUS_T mmal_port_parameter_get_uint32(MMAL_PORT_T *port, uint32_t id, uint32_t *value)
+{
+   MMAL_PARAMETER_UINT32_T param = {{id, sizeof(param)}, 0};
+   // coverity[overrun-buffer-val] Structure accessed correctly via size field
+   MMAL_STATUS_T status = mmal_port_parameter_get(port, &param.hdr);
+   if (status == MMAL_SUCCESS)
+      *value = param.value;
+   return status;
+}
+
+/** Helper function to set the value of a 32 bits signed integer parameter */
+MMAL_STATUS_T mmal_port_parameter_set_int32(MMAL_PORT_T *port, uint32_t id, int32_t value)
+{
+   MMAL_PARAMETER_INT32_T param = {{id, sizeof(param)}, value};
+   return mmal_port_parameter_set(port, &param.hdr);
+}
+
+/** Helper function to get the value of a 32 bits signed integer parameter */
+MMAL_STATUS_T mmal_port_parameter_get_int32(MMAL_PORT_T *port, uint32_t id, int32_t *value)
+{
+   MMAL_PARAMETER_INT32_T param = {{id, sizeof(param)}, 0};
+   // coverity[overrun-buffer-val] Structure accessed correctly via size field
+   MMAL_STATUS_T status = mmal_port_parameter_get(port, &param.hdr);
+   if (status == MMAL_SUCCESS)
+      *value = param.value;
+   return status;
+}
+
+/** Helper function to set the value of a rational parameter */
+MMAL_STATUS_T mmal_port_parameter_set_rational(MMAL_PORT_T *port, uint32_t id, MMAL_RATIONAL_T value)
+{
+   MMAL_PARAMETER_RATIONAL_T param = {{id, sizeof(param)}, {value.num, value.den}};
+   return mmal_port_parameter_set(port, &param.hdr);
+}
+
+/** Helper function to get the value of a rational parameter */
+MMAL_STATUS_T mmal_port_parameter_get_rational(MMAL_PORT_T *port, uint32_t id, MMAL_RATIONAL_T *value)
+{
+   MMAL_PARAMETER_RATIONAL_T param = {{id, sizeof(param)}, {0,0}};
+   // coverity[overrun-buffer-val] Structure accessed correctly via size field
+   MMAL_STATUS_T status = mmal_port_parameter_get(port, &param.hdr);
+   if (status == MMAL_SUCCESS)
+      *value = param.value;
+   return status;
+}
+
+/** Helper function to set the value of a string parameter */
+MMAL_STATUS_T mmal_port_parameter_set_string(MMAL_PORT_T *port, uint32_t id, const char *value)
+{
+   MMAL_PARAMETER_STRING_T *param = 0;
+   MMAL_STATUS_T status;
+   size_t param_size = sizeof(param->hdr) + strlen(value) + 1;
+
+   param = calloc(1, param_size);
+   if (!param)
+      return MMAL_ENOMEM;
+
+   param->hdr.id = id;
+   param->hdr.size = param_size;
+   memcpy(param->str, value, strlen(value)+1);
+   status = mmal_port_parameter_set(port, &param->hdr);
+   free(param);
+   return status;
+}
+
+/** Helper function to set a MMAL_PARAMETER_URI_T parameter on a port */
+MMAL_STATUS_T mmal_util_port_set_uri(MMAL_PORT_T *port, const char *uri)
+{
+   return mmal_port_parameter_set_string(port, MMAL_PARAMETER_URI, uri);
+}
+
+/** Helper function to set the value of an array of bytes parameter */
+MMAL_STATUS_T mmal_port_parameter_set_bytes(MMAL_PORT_T *port, uint32_t id,
+   const uint8_t *data, unsigned int size)
+{
+   MMAL_PARAMETER_BYTES_T *param = 0;
+   MMAL_STATUS_T status;
+   size_t param_size = sizeof(param->hdr) + size;
+
+   param = calloc(1, param_size);
+   if (!param)
+      return MMAL_ENOMEM;
+
+   param->hdr.id = id;
+   param->hdr.size = param_size;
+   memcpy(param->data, data, size);
+   status = mmal_port_parameter_set(port, &param->hdr);
+   free(param);
+   return status;
+}
+
+/** Set the display region.
+ * @param port   port to configure
+ * @param region region
+ *
+ * @return MMAL_SUCCESS or error
+ */
+
+MMAL_STATUS_T mmal_util_set_display_region(MMAL_PORT_T *port,
+                                           MMAL_DISPLAYREGION_T *region)
+{
+   region->hdr.id = MMAL_PARAMETER_DISPLAYREGION;
+   region->hdr.size = sizeof(*region);
+   return mmal_port_parameter_set(port, &region->hdr);
+}
+
+MMAL_STATUS_T mmal_util_camera_use_stc_timestamp(MMAL_PORT_T *port, MMAL_CAMERA_STC_MODE_T mode)
+{
+   MMAL_PARAMETER_CAMERA_STC_MODE_T param =
+      {{MMAL_PARAMETER_USE_STC, sizeof(MMAL_PARAMETER_CAMERA_STC_MODE_T)},mode};
+   return mmal_port_parameter_set(port, &param.hdr);
+}
+
+MMAL_STATUS_T mmal_util_get_core_port_stats(MMAL_PORT_T *port, 
+                                            MMAL_CORE_STATS_DIR dir,
+                                            MMAL_BOOL_T reset,
+                                            MMAL_CORE_STATISTICS_T *stats)
+{
+   MMAL_PARAMETER_CORE_STATISTICS_T param;
+   MMAL_STATUS_T ret;
+
+   memset(&param, 0, sizeof(param));
+   param.hdr.id = MMAL_PARAMETER_CORE_STATISTICS;
+   param.hdr.size = sizeof(param);
+   param.dir = dir;
+   param.reset = reset;
+   // coverity[overrun-buffer-val] Structure accessed correctly via size field
+   ret = mmal_port_parameter_get(port, &param.hdr);
+   if (ret == MMAL_SUCCESS)
+      *stats = param.stats;
+   return ret;
+}
diff --git a/interface/mmal/util/mmal_util_params.h b/interface/mmal/util/mmal_util_params.h
new file mode 100755 (executable)
index 0000000..9379e03
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_UTIL_PARAMS_H
+#define MMAL_UTIL_PARAMS_H
+
+#include "interface/mmal/mmal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file
+ * Utility functions to set some common parameters.
+ */
+
+/** Helper function to set the value of a boolean parameter.
+ * @param port   port on which to set the parameter
+ * @param id     parameter id
+ * @param value  value to set the parameter to
+ *
+ * @return MMAL_SUCCESS or error
+ */
+MMAL_STATUS_T mmal_port_parameter_set_boolean(MMAL_PORT_T *port, uint32_t id, MMAL_BOOL_T value);
+
+/** Helper function to get the value of a boolean parameter.
+ * @param port   port on which to get the parameter
+ * @param id     parameter id
+ * @param value  pointer to where the value will be returned
+ *
+ * @return MMAL_SUCCESS or error
+ */
+MMAL_STATUS_T mmal_port_parameter_get_boolean(MMAL_PORT_T *port, uint32_t id, MMAL_BOOL_T *value);
+
+/** Helper function to set the value of a 64 bits unsigned integer parameter.
+ * @param port   port on which to set the parameter
+ * @param id     parameter id
+ * @param value  value to set the parameter to
+ *
+ * @return MMAL_SUCCESS or error
+ */
+MMAL_STATUS_T mmal_port_parameter_set_uint64(MMAL_PORT_T *port, uint32_t id, uint64_t value);
+
+/** Helper function to get the value of a 64 bits unsigned integer parameter.
+ * @param port   port on which to get the parameter
+ * @param id     parameter id
+ * @param value  pointer to where the value will be returned
+ *
+ * @return MMAL_SUCCESS or error
+ */
+MMAL_STATUS_T mmal_port_parameter_get_uint64(MMAL_PORT_T *port, uint32_t id, uint64_t *value);
+
+/** Helper function to set the value of a 64 bits signed integer parameter.
+ * @param port   port on which to set the parameter
+ * @param id     parameter id
+ * @param value  value to set the parameter to
+ *
+ * @return MMAL_SUCCESS or error
+ */
+MMAL_STATUS_T mmal_port_parameter_set_int64(MMAL_PORT_T *port, uint32_t id, int64_t value);
+
+/** Helper function to get the value of a 64 bits signed integer parameter.
+ * @param port   port on which to get the parameter
+ * @param id     parameter id
+ * @param value  pointer to where the value will be returned
+ *
+ * @return MMAL_SUCCESS or error
+ */
+MMAL_STATUS_T mmal_port_parameter_get_int64(MMAL_PORT_T *port, uint32_t id, int64_t *value);
+
+/** Helper function to set the value of a 32 bits unsigned integer parameter.
+ * @param port   port on which to set the parameter
+ * @param id     parameter id
+ * @param value  value to set the parameter to
+ *
+ * @return MMAL_SUCCESS or error
+ */
+MMAL_STATUS_T mmal_port_parameter_set_uint32(MMAL_PORT_T *port, uint32_t id, uint32_t value);
+
+/** Helper function to get the value of a 32 bits unsigned integer parameter.
+ * @param port   port on which to get the parameter
+ * @param id     parameter id
+ * @param value  pointer to where the value will be returned
+ *
+ * @return MMAL_SUCCESS or error
+ */
+MMAL_STATUS_T mmal_port_parameter_get_uint32(MMAL_PORT_T *port, uint32_t id, uint32_t *value);
+
+/** Helper function to set the value of a 32 bits signed integer parameter.
+ * @param port   port on which to set the parameter
+ * @param id     parameter id
+ * @param value  value to set the parameter to
+ *
+ * @return MMAL_SUCCESS or error
+ */
+MMAL_STATUS_T mmal_port_parameter_set_int32(MMAL_PORT_T *port, uint32_t id, int32_t value);
+
+/** Helper function to get the value of a 32 bits signed integer parameter.
+ * @param port   port on which to get the parameter
+ * @param id     parameter id
+ * @param value  pointer to where the value will be returned
+ *
+ * @return MMAL_SUCCESS or error
+ */
+MMAL_STATUS_T mmal_port_parameter_get_int32(MMAL_PORT_T *port, uint32_t id, int32_t *value);
+
+/** Helper function to set the value of a rational parameter.
+ * @param port   port on which to set the parameter
+ * @param id     parameter id
+ * @param value  value to set the parameter to
+ *
+ * @return MMAL_SUCCESS or error
+ */
+MMAL_STATUS_T mmal_port_parameter_set_rational(MMAL_PORT_T *port, uint32_t id, MMAL_RATIONAL_T value);
+
+/** Helper function to get the value of a rational parameter.
+ * @param port   port on which to get the parameter
+ * @param id     parameter id
+ * @param value  pointer to where the value will be returned
+ *
+ * @return MMAL_SUCCESS or error
+ */
+MMAL_STATUS_T mmal_port_parameter_get_rational(MMAL_PORT_T *port, uint32_t id, MMAL_RATIONAL_T *value);
+
+/** Helper function to set the value of a string parameter.
+ * @param port   port on which to set the parameter
+ * @param id     parameter id
+ * @param value  null-terminated string value
+ *
+ * @return MMAL_SUCCESS or error
+ */
+MMAL_STATUS_T mmal_port_parameter_set_string(MMAL_PORT_T *port, uint32_t id, const char *value);
+
+/** Helper function to set the value of an array of bytes parameter.
+ * @param port   port on which to set the parameter
+ * @param id     parameter id
+ * @param data   pointer to the array of bytes
+ * @param size   size of the array of bytes
+ *
+ * @return MMAL_SUCCESS or error
+ */
+MMAL_STATUS_T mmal_port_parameter_set_bytes(MMAL_PORT_T *port, uint32_t id,
+   const uint8_t *data, unsigned int size);
+
+/** Helper function to set a MMAL_PARAMETER_URI_T parameter on a port.
+ * @param port   port on which to set the parameter
+ * @param uri    URI string
+ *
+ * @return MMAL_SUCCESS or error
+ */
+MMAL_STATUS_T mmal_util_port_set_uri(MMAL_PORT_T *port, const char *uri);
+
+/** Set the display region.
+ * @param port   port to configure
+ * @param region region
+ *
+ * @return MMAL_SUCCESS or error
+ */
+MMAL_STATUS_T mmal_util_set_display_region(MMAL_PORT_T *port,
+                                           MMAL_DISPLAYREGION_T *region);
+
+/** Tell the camera to use the STC for timestamps rather than the clock.
+ *
+ * @param port   port to configure
+ * @param mode   STC mode to use
+ * @return MMAL_SUCCESS or error
+ */
+MMAL_STATUS_T mmal_util_camera_use_stc_timestamp(MMAL_PORT_T *port, MMAL_CAMERA_STC_MODE_T mode);
+
+/** Get the MMAL core statistics for a given port.
+ *
+ * @param port  port to query
+ * @param dir   port direction
+ * @param reset reset the stats as well
+ * @param stats filled in with results
+ * @return MMAL_SUCCESS or error
+ */
+MMAL_STATUS_T mmal_util_get_core_port_stats(MMAL_PORT_T *port, MMAL_CORE_STATS_DIR dir, MMAL_BOOL_T reset,
+                                            MMAL_CORE_STATISTICS_T *stats);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/interface/mmal/util/mmal_util_rational.c b/interface/mmal/util/mmal_util_rational.c
new file mode 100755 (executable)
index 0000000..288b27b
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <limits.h>
+#include "interface/mmal/util/mmal_util_rational.h"
+
+#define Q16_ONE   (1 << 16)
+
+#define ABS(v)    (((v) < 0) ? -(v) : (v))
+
+/** Calculate the greatest common denominator between 2 integers.
+ * Avoids division. */
+static int32_t gcd(int32_t a, int32_t b)
+{
+   int shift;
+
+   if (a == 0 || b == 0)
+      return 1;
+
+   a = ABS(a);
+   b = ABS(b);
+   for (shift = 0; !((a | b) & 0x01); shift++)
+      a >>= 1, b >>= 1;
+
+   while (a > 0)
+   {
+      while (!(a & 0x01))
+         a >>= 1;
+      while (!(b & 0x01))
+         b >>= 1;
+      if (a >= b)
+         a = (a - b) >> 1;
+      else
+         b = (b - a) >> 1;
+   }
+   return b << shift;
+}
+
+/** Calculate a + b. */
+MMAL_RATIONAL_T mmal_rational_add(MMAL_RATIONAL_T a, MMAL_RATIONAL_T b)
+{
+   MMAL_RATIONAL_T result;
+   int32_t g = gcd(a.den, b.den);
+   a.den /= g;
+   a.num = a.num * (b.den / g) + b.num * a.den;
+   g = gcd(a.num, g);
+   a.num /= g;
+   a.den *= b.den / g;
+
+   result.num = a.num;
+   result.den = a.den;
+   return result;
+}
+
+/** Calculate a - b. */
+MMAL_RATIONAL_T mmal_rational_subtract(MMAL_RATIONAL_T a, MMAL_RATIONAL_T b)
+{
+   b.num = -b.num;
+   return mmal_rational_add(a, b);
+}
+
+/** Calculate a * b */
+MMAL_RATIONAL_T mmal_rational_multiply(MMAL_RATIONAL_T a, MMAL_RATIONAL_T b)
+{
+   MMAL_RATIONAL_T result;
+   int32_t gcd1 = gcd(a.num, b.den);
+   int32_t gcd2 = gcd(b.num, a.den);
+   result.num = (a.num / gcd1) * (b.num / gcd2);
+   result.den = (a.den / gcd2) * (b.den / gcd1);
+
+   return result;
+}
+
+/** Calculate a / b */
+MMAL_RATIONAL_T mmal_rational_divide(MMAL_RATIONAL_T a, MMAL_RATIONAL_T b)
+{
+   MMAL_RATIONAL_T result;
+   int32_t gcd1, gcd2;
+
+   if (b.num == 0)
+   {
+      vcos_assert(0);
+      return a;
+   }
+
+   if (a.num == 0)
+      return a;
+
+   gcd1 = gcd(a.num, b.num);
+   gcd2 = gcd(b.den, a.den);
+   result.num = (a.num / gcd1) * (b.den / gcd2);
+   result.den = (a.den / gcd2) * (b.num / gcd1);
+
+   return result;
+}
+
+/** Convert a rational number to a signed 32-bit Q16 number. */
+int32_t mmal_rational_to_fixed_16_16(MMAL_RATIONAL_T rational)
+{
+   int64_t result = (int64_t)rational.num << 16;
+   if (rational.den)
+      result /= rational.den;
+
+   if (result > INT_MAX)
+      result = INT_MAX;
+   else if (result < INT_MIN)
+      result = INT_MIN;
+
+   return (int32_t)result;
+}
+
+/** Convert a rational number to a signed 32-bit Q16 number. */
+MMAL_RATIONAL_T mmal_rational_from_fixed_16_16(int32_t fixed)
+{
+   MMAL_RATIONAL_T result = { fixed, Q16_ONE };
+   mmal_rational_simplify(&result);
+   return result;
+}
+
+/** Reduce a rational number to it's simplest form. */
+void mmal_rational_simplify(MMAL_RATIONAL_T *rational)
+{
+   int g = gcd(rational->num, rational->den);
+   rational->num /= g;
+   rational->den /= g;
+}
+
+/** Tests for equality */
+MMAL_BOOL_T mmal_rational_equal(MMAL_RATIONAL_T a, MMAL_RATIONAL_T b)
+{
+   if (a.num != b.num && a.num * (int64_t)b.num == 0)
+      return MMAL_FALSE;
+   return a.num * (int64_t)b.den == b.num * (int64_t)a.den;
+}
diff --git a/interface/mmal/util/mmal_util_rational.h b/interface/mmal/util/mmal_util_rational.h
new file mode 100755 (executable)
index 0000000..f459f51
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_UTIL_RATIONAL_H
+#define MMAL_UTIL_RATIONAL_H
+
+#include "interface/mmal/mmal_types.h"
+
+/** \defgroup MmalRationalUtilities Rational Utility Functions
+ * \ingroup MmalUtilities
+ * The rational utility functions allow easy manipulation of rational numbers.
+ *
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Add 2 rational numbers.
+ * It is assumed that both input rational numbers are in
+ * their simplest form.
+ *
+ * @param a First operand
+ * @param b Second operand
+ *
+ * @return a + b
+ */
+MMAL_RATIONAL_T mmal_rational_add(MMAL_RATIONAL_T a, MMAL_RATIONAL_T b);
+
+/** Subtract 2 rational numbers.
+ * It is assumed that both input rational numbers are in
+ * their simplest form.
+ *
+ * @param a        First operand
+ * @param b        Second operand
+ *
+ * @return a - b
+ */
+MMAL_RATIONAL_T mmal_rational_subtract(MMAL_RATIONAL_T a, MMAL_RATIONAL_T b);
+
+/** Multiply 2 rational numbers.
+ * It is assumed that both input rational numbers are in
+ * their simplest form.
+ *
+ * @param a        First operand
+ * @param b        Second operand
+ *
+ * @return a * b
+ */
+MMAL_RATIONAL_T mmal_rational_multiply(MMAL_RATIONAL_T a, MMAL_RATIONAL_T b);
+
+/** Divide 2 rational numbers.
+ * It is assumed that both input rational numbers are in
+ * their simplest form.
+ *
+ * @param a        First operand
+ * @param b        Second operand
+ *
+ * @return a / b
+ */
+MMAL_RATIONAL_T mmal_rational_divide(MMAL_RATIONAL_T a, MMAL_RATIONAL_T b);
+
+/** Convert a rational number to a 32-bit signed Q16 number.
+ * Saturation will occur for rational numbers with an absolute
+ * value greater than 32768.
+ *
+ * @param rational Rational number to convert
+ *
+ * @return 32-bit signed Q16 number
+ */
+int32_t mmal_rational_to_fixed_16_16(MMAL_RATIONAL_T rational);
+
+/** Convert a signed 32-bit Q16 number to a rational number.
+ *
+ * @param fixed    Signed 32-bit Q16 number to convert
+ *
+ * @return Rational number
+ */
+MMAL_RATIONAL_T mmal_rational_from_fixed_16_16(int32_t fixed);
+
+/** Reduce a rational number to it's simplest form.
+ *
+ * @param rational Rational number to simplify
+ */
+void mmal_rational_simplify(MMAL_RATIONAL_T *rational);
+
+/** Test 2 rational numbers for equality.
+ *
+ * @param a        First operand
+ * @param b        Second operand
+ *
+ * @return true if equal
+ */
+MMAL_BOOL_T mmal_rational_equal(MMAL_RATIONAL_T a, MMAL_RATIONAL_T b);
+
+#ifdef __cplusplus
+}
+#endif
+
+/** @} */
+
+#endif
diff --git a/interface/mmal/vc/CMakeLists.txt b/interface/mmal/vc/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..d6e80db
--- /dev/null
@@ -0,0 +1,26 @@
+add_definitions(-DENABLE_MMAL_VCSM)
+
+add_library(mmal_vc_client ${LIBRARY_TYPE} mmal_vc_client.c mmal_vc_shm.c mmal_vc_api.c mmal_vc_opaque_alloc.c mmal_vc_msgnames.c mmal_vc_api_drm.c)
+#target_link_libraries(mmal_vc_client vchiq_arm vcos)
+
+target_link_libraries(mmal_vc_client vchiq_arm vcos vcsm)
+
+if(BUILD_MMAL_APPS)
+add_executable(mmal_vc_diag mmal_vc_diag.c)
+target_link_libraries(mmal_vc_diag mmal mmal_vc_client debug_sym vcos)
+install(TARGETS mmal_vc_diag RUNTIME DESTINATION bin)
+endif(BUILD_MMAL_APPS)
+
+include_directories ( ../../../host_applications/linux/libs/sm )
+
+install(TARGETS mmal_vc_client DESTINATION lib)
+install(FILES
+   mmal_vc_api.h
+   mmal_vc_api_drm.h
+   mmal_vc_client_priv.h
+   mmal_vc_msgnames.h
+   mmal_vc_msgs.h
+   mmal_vc_opaque_alloc.h
+   mmal_vc_shm.h
+   DESTINATION include/interface/mmal/vc
+)
diff --git a/interface/mmal/vc/mmal_vc_api.c b/interface/mmal/vc/mmal_vc_api.c
new file mode 100755 (executable)
index 0000000..31502a0
--- /dev/null
@@ -0,0 +1,1505 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/mmal/mmal_logging.h"
+#include "interface/mmal/mmal.h"
+#include "mmal_vc_api.h"
+#include "mmal_vc_msgs.h"
+#include "mmal_vc_client_priv.h"
+#include "mmal_vc_opaque_alloc.h"
+#include "mmal_vc_shm.h"
+#include "interface/mmal/util/mmal_util.h"
+#include "interface/mmal/core/mmal_component_private.h"
+#include "interface/mmal/core/mmal_port_private.h"
+#include "interface/mmal/core/mmal_buffer_private.h"
+#include "interface/vcos/vcos.h"
+
+/** Private information for MMAL VC components
+ */
+
+typedef enum MMAL_ZEROLEN_CHECK_T
+{
+   ZEROLEN_NOT_INITIALIZED,
+   ZEROLEN_COMPATIBLE,
+   ZEROLEN_INCOMPATIBLE
+} MMAL_ZEROLEN_CHECK_T;
+
+typedef enum MMAL_PORT_FLUSH_CHECK_T
+{
+   PORT_FLUSH_NOT_INITIALIZED,
+   PORT_FLUSH_COMPATIBLE,
+   PORT_FLUSH_INCOMPATIBLE
+} MMAL_PORT_FLUSH_CHECK_T;
+
+typedef struct MMAL_PORT_MODULE_T
+{
+   uint32_t magic;
+   uint32_t component_handle;
+   MMAL_PORT_T *port;
+   uint32_t port_handle;
+
+   MMAL_BOOL_T has_pool;
+   VCOS_BLOCKPOOL_T pool;
+
+   MMAL_BOOL_T is_zero_copy;
+   MMAL_BOOL_T zero_copy_workaround;
+   uint32_t opaque_allocs;
+
+   MMAL_BOOL_T sent_data_on_port;
+
+   MMAL_PORT_T *connected;           /**< Connected port if any */
+} MMAL_PORT_MODULE_T;
+
+typedef struct MMAL_COMPONENT_MODULE_T
+{
+   uint32_t component_handle;
+
+   MMAL_PORT_MODULE_T **ports;
+   uint32_t ports_num;
+
+   MMAL_QUEUE_T *callback_queue;   /**< Used to queue the callbacks we need to make to the client */
+
+   MMAL_BOOL_T event_ctx_initialised;
+   MMAL_VC_CLIENT_BUFFER_CONTEXT_T event_ctx; /**< Used as the ctx for event buffers */
+} MMAL_COMPONENT_MODULE_T;
+
+/*****************************************************************************
+ * Local function prototypes
+ *****************************************************************************/
+static void mmal_vc_do_callback(MMAL_COMPONENT_T *component);
+static MMAL_STATUS_T mmal_vc_port_info_get(MMAL_PORT_T *port);
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_vc_get_version(uint32_t *major, uint32_t *minor, uint32_t *minimum)
+{
+   mmal_worker_version msg;
+   size_t len = sizeof(msg);
+   MMAL_STATUS_T status;
+
+   status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
+                                     MMAL_WORKER_GET_VERSION, &msg, &len, MMAL_FALSE);
+
+   if (status != MMAL_SUCCESS)
+      return status;
+
+   if (!vcos_verify(len == sizeof(msg)))
+      return MMAL_EINVAL;
+
+   *major = msg.major;
+   *minor = msg.minor;
+   *minimum = msg.minimum;
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+MMAL_STATUS_T mmal_vc_get_stats(MMAL_VC_STATS_T *stats, int reset)
+{
+   mmal_worker_stats msg;
+   size_t len = sizeof(msg);
+   msg.reset = reset;
+
+   MMAL_STATUS_T status = mmal_vc_sendwait_message(mmal_vc_get_client(),
+                                                   &msg.header, sizeof(msg),
+                                                   MMAL_WORKER_GET_STATS,
+                                                   &msg, &len, MMAL_FALSE);
+
+
+   if (status == MMAL_SUCCESS)
+   {
+      vcos_assert(len == sizeof(msg));
+      *stats = msg.stats;
+   }
+   return status;
+}
+
+/** Set port buffer requirements. */
+static MMAL_STATUS_T mmal_vc_port_requirements_set(MMAL_PORT_T *port)
+{
+   MMAL_PORT_MODULE_T *module = port->priv->module;
+   MMAL_STATUS_T status;
+   mmal_worker_reply reply;
+   mmal_worker_port_action msg;
+   size_t replylen = sizeof(reply);
+
+   msg.component_handle = module->component_handle;
+   msg.action = MMAL_WORKER_PORT_ACTION_SET_REQUIREMENTS;
+   msg.port_handle = module->port_handle;
+   msg.param.enable.port = *port;
+
+   status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
+                                     MMAL_WORKER_PORT_ACTION, &reply, &replylen, MMAL_FALSE);
+   if (status == MMAL_SUCCESS)
+   {
+      vcos_assert(replylen == sizeof(reply));
+      status = reply.status;
+   }
+   if (status != MMAL_SUCCESS)
+      LOG_ERROR("failed to set port requirements (%i/%i,%i/%i)",
+                port->buffer_num, port->buffer_num_min,
+                port->buffer_size, port->buffer_size_min);
+
+   return status;
+}
+
+/** Get port buffer requirements. */
+static MMAL_STATUS_T mmal_vc_port_requirements_get(MMAL_PORT_T *port)
+{
+   MMAL_PORT_MODULE_T *module = port->priv->module;
+   mmal_worker_port_info_get msg;
+   mmal_worker_port_info reply;
+   size_t replylen = sizeof(reply);
+   MMAL_STATUS_T status;
+
+   msg.component_handle = module->component_handle;
+   msg.port_type = port->type;
+   msg.index = port->index;
+
+   LOG_TRACE("get port requirements (%i:%i)", port->type, port->index);
+
+   status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
+                                     MMAL_WORKER_PORT_INFO_GET, &reply, &replylen, MMAL_FALSE);
+   if (status == MMAL_SUCCESS)
+   {
+      vcos_assert(replylen == sizeof(reply));
+      status = reply.status;
+   }
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("failed to get port requirements (%i:%i)", port->type, port->index);
+      return status;
+   }
+
+   port->buffer_num_min = reply.port.buffer_num_min;
+   port->buffer_num_recommended = reply.port.buffer_num_recommended;
+   port->buffer_size_min = reply.port.buffer_size_min;
+   port->buffer_size_recommended = reply.port.buffer_size_recommended;
+   port->buffer_alignment_min = reply.port.buffer_alignment_min;
+
+   return MMAL_SUCCESS;
+}
+
+/** Enable processing on a port */
+static MMAL_STATUS_T mmal_vc_port_enable(MMAL_PORT_T *port, MMAL_PORT_BH_CB_T cb)
+{
+   MMAL_PORT_MODULE_T *module = port->priv->module;
+   MMAL_STATUS_T status;
+   mmal_worker_reply reply;
+   mmal_worker_port_action msg;
+   size_t replylen = sizeof(reply);
+   MMAL_PARAM_UNUSED(cb);
+
+   if (!port->component->priv->module->event_ctx_initialised)
+   {
+      MMAL_POOL_T *pool = port->component->priv->event_pool;
+      MMAL_DRIVER_BUFFER_T *drv;
+      unsigned int i;
+
+      /* We need to associate our vc client context to all our event buffers.
+       * This only needs to be done when the first port is enabled because no event
+       * can be received on disabled ports. */
+      for (i = 0; i < pool->headers_num; i++)
+      {
+         drv = mmal_buffer_header_driver_data(pool->header[i]);
+         drv->client_context = &port->component->priv->module->event_ctx;
+         drv->magic = MMAL_MAGIC;
+      }
+
+      port->component->priv->module->event_ctx_initialised = MMAL_TRUE;
+   }
+
+   if (!module->connected)
+   {
+      if (vcos_blockpool_create_on_heap(&module->pool, port->buffer_num,
+             sizeof(MMAL_VC_CLIENT_BUFFER_CONTEXT_T),
+             VCOS_BLOCKPOOL_ALIGN_DEFAULT, VCOS_BLOCKPOOL_FLAG_NONE, "mmal vc port pool") != VCOS_SUCCESS)
+      {
+         LOG_ERROR("failed to create port pool");
+         return MMAL_ENOMEM;
+      }
+      module->has_pool = 1;
+   }
+
+   if (module->connected)
+   {
+      /* The connected port won't be enabled explicitly so make sure we apply
+       * the buffer requirements now. */
+      status = mmal_vc_port_requirements_set(module->connected);
+      if (status != MMAL_SUCCESS)
+         goto error;
+   }
+
+   msg.component_handle = module->component_handle;
+   msg.action = MMAL_WORKER_PORT_ACTION_ENABLE;
+   msg.port_handle = module->port_handle;
+   msg.param.enable.port = *port;
+
+   status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
+                                     MMAL_WORKER_PORT_ACTION, &reply, &replylen, MMAL_FALSE);
+   if (status == MMAL_SUCCESS)
+   {
+      vcos_assert(replylen == sizeof(reply));
+      status = reply.status;
+   }
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("failed to enable port %s: %s",
+               port->name, mmal_status_to_string(status));
+      goto error;
+   }
+
+   if (module->connected)
+      mmal_vc_port_info_get(module->connected);
+
+   return MMAL_SUCCESS;
+
+ error:
+   if (module->has_pool)
+      vcos_blockpool_delete(&module->pool);
+   return status;
+}
+
+/** Disable processing on a port */
+static MMAL_STATUS_T mmal_vc_port_disable(MMAL_PORT_T *port)
+{
+   MMAL_PORT_MODULE_T *module = port->priv->module;
+   MMAL_STATUS_T status;
+   mmal_worker_reply reply;
+   mmal_worker_port_action msg;
+   size_t replylen = sizeof(reply);
+
+   msg.component_handle = module->component_handle;
+   msg.action = MMAL_WORKER_PORT_ACTION_DISABLE;
+   msg.port_handle = module->port_handle;
+
+   status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
+                                     MMAL_WORKER_PORT_ACTION, &reply, &replylen, MMAL_FALSE);
+   if (status == MMAL_SUCCESS)
+   {
+      vcos_assert(replylen == sizeof(reply));
+      status = reply.status;
+   }
+   if (status != MMAL_SUCCESS)
+      LOG_ERROR("failed to disable port - reason %d", status);
+
+   if (module->has_pool)
+   {
+      /* MMAL server should make sure that all buffers are sent back before it
+       * disables the port. */
+      vcos_assert(vcos_blockpool_available_count(&module->pool) == port->buffer_num);
+      vcos_blockpool_delete(&module->pool);
+      module->has_pool = 0;
+   }
+
+   /* We need to make sure all the queued callbacks have been done */
+   while (mmal_queue_length(port->component->priv->module->callback_queue))
+      mmal_vc_do_callback(port->component);
+
+   if (module->connected)
+      mmal_vc_port_info_get(module->connected);
+
+   return status;
+}
+
+/** Flush a port using MMAL_WORKER_PORT_ACTION - when the port is zero-copy or no data has been sent */
+static MMAL_STATUS_T mmal_vc_port_flush_normal(MMAL_PORT_T *port)
+{
+   MMAL_PORT_MODULE_T *module = port->priv->module;
+   MMAL_STATUS_T status;
+   mmal_worker_reply reply;
+   mmal_worker_port_action msg;
+   size_t replylen = sizeof(reply);
+
+   msg.component_handle = module->component_handle;
+   msg.action = MMAL_WORKER_PORT_ACTION_FLUSH;
+   msg.port_handle = module->port_handle;
+
+   status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
+                                     MMAL_WORKER_PORT_ACTION, &reply, &replylen, MMAL_FALSE);
+   if (status == MMAL_SUCCESS)
+   {
+      vcos_assert(replylen == sizeof(reply));
+      status = reply.status;
+   }
+   if (status != MMAL_SUCCESS)
+      LOG_ERROR("failed to disable port - reason %d", status);
+
+   return status;
+}
+
+
+/** Flush a port using PORT_FLUSH - generates a dummy bulk transfer to keep it in sync
+  * with buffers being passed using bulk transfer */
+static MMAL_STATUS_T mmal_vc_port_flush_sync(MMAL_PORT_T *port)
+{
+   MMAL_PORT_MODULE_T *module = port->priv->module;
+   MMAL_STATUS_T status;
+   mmal_worker_reply reply;
+   MMAL_VC_CLIENT_BUFFER_CONTEXT_T client_context;
+   mmal_worker_buffer_from_host *msg;
+
+   size_t replylen = sizeof(reply);
+
+   msg = &client_context.msg;
+
+   client_context.magic = MMAL_MAGIC;
+   client_context.port = port;
+
+   msg->drvbuf.client_context = &client_context;
+   msg->drvbuf.component_handle = module->component_handle;
+   msg->drvbuf.port_handle = module->port_handle;
+   msg->drvbuf.magic = MMAL_MAGIC;
+
+
+   status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg->header, sizeof(*msg),
+                                     MMAL_WORKER_PORT_FLUSH, &reply, &replylen, MMAL_TRUE);
+   if (status == MMAL_SUCCESS)
+   {
+      vcos_assert(replylen == sizeof(reply));
+      status = reply.status;
+   }
+   if (status != MMAL_SUCCESS)
+      LOG_ERROR("failed to disable port - reason %d", status);
+
+   return status;
+}
+
+/** Flush a port */
+static MMAL_STATUS_T mmal_vc_port_flush(MMAL_PORT_T *port)
+{
+   static MMAL_PORT_FLUSH_CHECK_T is_port_flush_compatible = PORT_FLUSH_NOT_INITIALIZED;
+   uint32_t major = 0, minor = 0, minimum = 0;
+   MMAL_STATUS_T status;
+   /* Buffers sent to videocore, if not zero-copy, use vchiq bulk transfers to copy the data.
+      A flush could be sent while one of these buffers is being copied. If the normal flushing method
+      is used, the flush can arrive before the buffer, which causes confusion when a pre-flush buffer
+      arrives after the flush. So use a special flush mode that uses a dummy vchiq transfer to synchronise
+      things.
+      If data has never been sent on the port, then we don't need to worry about a flush overtaking data.
+      In that case, the port may not actually be set up on the other end to receive bulk transfers, so use
+      the normal flushing mechanism in that case.
+    */
+
+   if (port->priv->module->is_zero_copy || !port->priv->module->sent_data_on_port)
+      return mmal_vc_port_flush_normal(port);
+
+   if (is_port_flush_compatible == PORT_FLUSH_NOT_INITIALIZED)
+   {
+      status = mmal_vc_get_version(&major, &minor, &minimum);
+      if (major >= 15)
+      {
+         is_port_flush_compatible = PORT_FLUSH_COMPATIBLE;
+      }
+      else
+      {
+         LOG_ERROR("Version number of MMAL Server incompatible. Required Major:14 Minor: 2 \
+          or Greater. Current Major %d , Minor %d",major,minor);
+         is_port_flush_compatible = PORT_FLUSH_INCOMPATIBLE;
+      }
+   }
+
+   if (is_port_flush_compatible == PORT_FLUSH_COMPATIBLE)
+      return mmal_vc_port_flush_sync(port);
+   else
+      return mmal_vc_port_flush_normal(port);
+}
+
+
+/** Connect 2 ports together */
+static MMAL_STATUS_T mmal_vc_port_connect(MMAL_PORT_T *port, MMAL_PORT_T *other_port)
+{
+   MMAL_PORT_MODULE_T *module = port->priv->module;
+   MMAL_STATUS_T status;
+   mmal_worker_reply reply;
+   mmal_worker_port_action msg;
+   size_t replylen = sizeof(reply);
+
+   /* We only support connecting vc components together */
+   if (other_port && port->priv->pf_enable != other_port->priv->pf_enable)
+      return MMAL_ENOSYS;
+
+   /* Send the request to the video side */
+   msg.component_handle = module->component_handle;
+   msg.action = other_port ? MMAL_WORKER_PORT_ACTION_CONNECT : MMAL_WORKER_PORT_ACTION_DISCONNECT;
+   msg.port_handle = module->port_handle;
+   if (other_port)
+   {
+      msg.param.connect.component_handle = other_port->priv->module->component_handle;
+      msg.param.connect.port_handle = other_port->priv->module->port_handle;
+   }
+
+   status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
+                                     MMAL_WORKER_PORT_ACTION, &reply, &replylen, MMAL_FALSE);
+   if (status == MMAL_SUCCESS)
+   {
+      vcos_assert(replylen == sizeof(reply));
+      status = reply.status;
+   }
+
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("failed to connect ports: %s", mmal_status_to_string(status));
+      return status;
+   }
+
+   if (other_port)
+   {
+      /* Connection */
+      module->connected = other_port;
+      other_port->priv->module->connected = port;
+   }
+   else
+   {
+      /* Disconnection */
+      if (module->connected)
+         module->connected->priv->module->connected = NULL;
+      module->connected = NULL;
+   }
+
+   return MMAL_SUCCESS;
+}
+
+/*****************************************************************************/
+static void mmal_vc_do_callback(MMAL_COMPONENT_T *component)
+{
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_BUFFER_HEADER_T *buffer;
+   MMAL_PORT_T *port;
+
+   /* Get a buffer from this port */
+   buffer = mmal_queue_get(module->callback_queue);
+   if (!buffer)
+      return; /* Will happen when a port gets disabled */
+
+   port = (MMAL_PORT_T *)buffer->priv->component_data;
+
+   /* Catch and report any transmission error */
+   if (buffer->flags & MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED)
+       mmal_event_error_send(port->component, MMAL_EIO);
+
+   /* Events generated by this component are handled differently */
+   if (mmal_buffer_header_driver_data(buffer)->client_context ==
+       &component->priv->module->event_ctx)
+   {
+      mmal_port_event_send(port, buffer);
+      return;
+   }
+
+   buffer->data = mmal_vc_shm_lock(buffer->data, port->priv->module->zero_copy_workaround);
+   mmal_port_buffer_header_callback(port, buffer);
+}
+
+static void mmal_vc_do_callback_loop(MMAL_COMPONENT_T *component)
+{
+   while (mmal_queue_length(component->priv->module->callback_queue))
+      mmal_vc_do_callback(component);
+}
+
+/** Called back from VCHI(Q) event handler when buffers come back from the copro.
+ *
+ * The message points to the message sent by videocore, and which should have
+ * a pointer back to our original client side context.
+ *
+ */
+static void mmal_vc_port_send_callback(mmal_worker_buffer_from_host *msg)
+{
+   MMAL_BUFFER_HEADER_T *buffer;
+   MMAL_PORT_T *port;
+   MMAL_VC_CLIENT_BUFFER_CONTEXT_T *client_context = msg->drvbuf.client_context;
+
+   vcos_assert(client_context);
+   vcos_assert(client_context->magic == MMAL_MAGIC);
+
+   buffer = client_context->buffer;
+   port = client_context->port;
+   vcos_blockpool_free(msg->drvbuf.client_context);
+
+   vcos_assert(port->priv->module->magic == MMAL_MAGIC);
+   mmal_vc_msg_to_buffer_header(buffer, msg);
+
+   /* Queue the callback so it is delivered by the action thread */
+   buffer->priv->component_data = (void *)port;
+   mmal_queue_put(port->component->priv->module->callback_queue, buffer);
+   mmal_component_action_trigger(port->component);
+}
+
+static void mmal_vc_port_send_event_callback(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   /* Queue the event to be delivered by the action thread */
+   buffer->priv->component_data = (void *)port;
+   mmal_queue_put(port->component->priv->module->callback_queue, buffer);
+   mmal_component_action_trigger(port->component);
+}
+
+/** Called from the client to send a buffer (empty or full) to
+  * the copro.
+  */
+static MMAL_STATUS_T mmal_vc_port_send(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
+{
+   MMAL_PORT_MODULE_T *module = port->priv->module;
+   MMAL_STATUS_T status;
+   MMAL_VC_CLIENT_BUFFER_CONTEXT_T *client_context;
+   mmal_worker_buffer_from_host *msg;
+   uint32_t length;
+   uint32_t msgid = MMAL_WORKER_BUFFER_FROM_HOST;
+   uint32_t major = 0, minor = 0, minimum = 0;
+   static MMAL_ZEROLEN_CHECK_T is_vc_zerolength_compatible = ZEROLEN_NOT_INITIALIZED;
+
+   vcos_assert(port);
+   vcos_assert(module);
+   vcos_assert(module->magic == MMAL_MAGIC);
+
+   /* Handle event buffers */
+   if (buffer->cmd)
+   {
+      MMAL_EVENT_FORMAT_CHANGED_T *event = mmal_event_format_changed_get(buffer);
+      if (event)
+      {
+         mmal_format_copy(port->format, event->format);
+         status = port->priv->pf_set_format(port);
+         if(status != MMAL_SUCCESS)
+            LOG_ERROR("format not set on port %p", port);
+      }
+      else
+      {
+         LOG_ERROR("discarding event %i on port %p", (int)buffer->cmd, port);
+      }
+
+      buffer->length = 0;
+      mmal_port_buffer_header_callback(port, buffer);
+      return MMAL_SUCCESS;
+   }
+
+   /* We can only send buffers if we have a pool */
+   if (!module->has_pool)
+   {
+      LOG_ERROR("no pool on port %p", port);
+      return MMAL_EINVAL;
+   }
+
+   client_context = vcos_blockpool_alloc(&module->pool);
+   if(!client_context)
+   {
+      LOG_INFO("couldn't allocate client buffer context from pool");
+      return MMAL_ENOMEM;
+   }
+   msg = &client_context->msg;
+
+   client_context->magic = MMAL_MAGIC;
+   client_context->buffer = buffer;
+   client_context->callback = mmal_vc_port_send_callback;
+   client_context->callback_event = NULL;
+   client_context->port = port;
+
+   msg->drvbuf.client_context = client_context;
+   msg->drvbuf.component_handle = module->component_handle;
+   msg->drvbuf.port_handle = module->port_handle;
+   msg->drvbuf.magic = MMAL_MAGIC;
+
+   length = buffer->length;
+
+   if (length <= MMAL_VC_SHORT_DATA && !port->priv->module->is_zero_copy &&
+       (port->format->encoding == MMAL_ENCODING_OPAQUE ||
+        port->type == MMAL_PORT_TYPE_CLOCK))
+   {
+      memcpy(msg->short_data, buffer->data + buffer->offset, buffer->length);
+      msg->payload_in_message = length;
+      length = 0;
+   }
+   else
+   {
+      msg->payload_in_message = 0;
+   }
+
+   buffer->data =
+      mmal_vc_shm_unlock(buffer->data, &length, port->priv->module->zero_copy_workaround);
+   mmal_vc_buffer_header_to_msg(msg, buffer);
+
+   if (!VCOS_BLOCKPOOL_IS_VALID_HANDLE_FORMAT(msg->drvbuf.component_handle, 256))
+   {
+      LOG_ERROR("bad component handle 0x%x", msg->drvbuf.component_handle);
+      return MMAL_EINVAL;
+   }
+
+   if (msg->drvbuf.port_handle > 255)
+   {
+      LOG_ERROR("bad port handle 0x%x", msg->drvbuf.port_handle);
+      return MMAL_EINVAL;
+   }
+
+   if (module->is_zero_copy)
+      length = 0;
+
+   if (is_vc_zerolength_compatible == ZEROLEN_NOT_INITIALIZED)
+   {
+      status = mmal_vc_get_version(&major, &minor, &minimum);
+      if ((major > 12 ) || ((major == 12) && (minor >= 2)))
+      {
+         is_vc_zerolength_compatible = ZEROLEN_COMPATIBLE;
+      }
+      else
+      {
+         LOG_ERROR("Version number of MMAL Server incompatible. Required Major:12 Minor: 2 \
+          or Greater. Current Major %d , Minor %d",major,minor);
+         is_vc_zerolength_compatible = ZEROLEN_INCOMPATIBLE;
+      }
+   }
+
+   if ((is_vc_zerolength_compatible == ZEROLEN_COMPATIBLE) && !(module->is_zero_copy) && !length
+       && (msg->buffer_header.flags & MMAL_BUFFER_HEADER_FLAG_EOS))
+   {
+      length = 8;
+      msgid = MMAL_WORKER_BUFFER_FROM_HOST_ZEROLEN;
+   }
+
+   if (length)
+   {
+      // We're doing a bulk transfer. Note this so that flushes know
+      // they need to use the more cumbersome fake-bulk-transfer mechanism
+      // to guarantee correct ordering.
+      port->priv->module->sent_data_on_port = MMAL_TRUE;
+
+      // Data will be received at the start of the destination buffer, so fixup
+      // the offset in the destination buffer header.
+      msg->buffer_header.offset = 0;
+   }
+
+   status = mmal_vc_send_message(mmal_vc_get_client(), &msg->header, sizeof(*msg),
+                                 buffer->data + buffer->offset, length,
+                                 msgid);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_INFO("failed %d", status);
+      vcos_blockpool_free(msg->drvbuf.client_context);
+      buffer->data = mmal_vc_shm_lock(buffer->data, port->priv->module->zero_copy_workaround);
+   }
+
+   return status;
+}
+
+static MMAL_STATUS_T mmal_vc_component_disable(MMAL_COMPONENT_T *component)
+{
+   MMAL_STATUS_T status;
+   mmal_worker_reply reply;
+   mmal_worker_component_disable msg;
+   size_t replylen = sizeof(reply);
+
+   vcos_assert(component && component->priv && component->priv->module);
+
+   msg.component_handle = component->priv->module->component_handle;
+
+   status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
+         MMAL_WORKER_COMPONENT_DISABLE,
+         &reply, &replylen, MMAL_FALSE);
+
+   if (status == MMAL_SUCCESS)
+   {
+      vcos_assert(replylen == sizeof(reply));
+      status = reply.status;
+   }
+
+   if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
+   {
+      LOG_ERROR("failed to disable component - reason %d", status);
+      goto fail;
+   }
+
+   return status;
+fail:
+   return status;
+}
+
+static MMAL_STATUS_T mmal_vc_component_enable(MMAL_COMPONENT_T *component)
+{
+   MMAL_STATUS_T status;
+   mmal_worker_reply reply;
+   mmal_worker_component_enable msg;
+   size_t replylen = sizeof(reply);
+
+   vcos_assert(component && component->priv && component->priv->module);
+
+   msg.component_handle = component->priv->module->component_handle;
+
+   status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
+                                     MMAL_WORKER_COMPONENT_ENABLE, &reply, &replylen, MMAL_FALSE);
+
+   if (status == MMAL_SUCCESS)
+   {
+      vcos_assert(replylen == sizeof(reply));
+      status = reply.status;
+   }
+
+   if (status != MMAL_SUCCESS && status != MMAL_ENOSYS)
+   {
+      LOG_ERROR("failed to enable component: %s", mmal_status_to_string(status));
+      return status;
+   }
+
+   return MMAL_SUCCESS;
+}
+
+static MMAL_STATUS_T mmal_vc_component_destroy(MMAL_COMPONENT_T *component)
+{
+   MMAL_STATUS_T status;
+   mmal_worker_component_destroy msg;
+   mmal_worker_reply reply;
+   size_t replylen = sizeof(reply);
+
+   vcos_assert(component && component->priv && component->priv->module);
+
+   msg.component_handle = component->priv->module->component_handle;
+
+   status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
+         MMAL_WORKER_COMPONENT_DESTROY,
+         &reply, &replylen, MMAL_FALSE);
+
+   if (status == MMAL_SUCCESS)
+   {
+      vcos_assert(replylen == sizeof(reply));
+      status = reply.status;
+   }
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("failed to destroy component - reason %d", status );
+      goto fail;
+   }
+
+   if(component->input_num)
+      mmal_ports_free(component->input, component->input_num);
+   if(component->output_num)
+      mmal_ports_free(component->output, component->output_num);
+   if(component->clock_num)
+      mmal_ports_free(component->clock, component->clock_num);
+
+   mmal_queue_destroy(component->priv->module->callback_queue);
+
+   vcos_free(component->priv->module);
+   component->priv->module = NULL;
+
+fail:
+   // no longer require videocore
+   mmal_vc_release();
+   mmal_vc_deinit();
+   return status;
+}
+
+MMAL_STATUS_T mmal_vc_consume_mem(size_t size, uint32_t *handle)
+{
+   MMAL_STATUS_T status;
+   mmal_worker_consume_mem req;
+   mmal_worker_consume_mem reply;
+   size_t len = sizeof(reply);
+
+   req.size = (uint32_t) size;
+
+   status = mmal_vc_sendwait_message(mmal_vc_get_client(),
+                                     &req.header, sizeof(req),
+                                     MMAL_WORKER_CONSUME_MEM,
+                                     &reply, &len, MMAL_FALSE);
+   if (status == MMAL_SUCCESS)
+   {
+      vcos_assert(len == sizeof(reply));
+      status = reply.status;
+      *handle = reply.handle;
+   }
+   return status;
+}
+
+MMAL_STATUS_T mmal_vc_compact(MMAL_VC_COMPACT_MODE_T mode, uint32_t *duration)
+{
+   MMAL_STATUS_T status;
+   mmal_worker_compact req;
+   mmal_worker_compact reply;
+   size_t len = sizeof(reply);
+
+   req.mode = (uint32_t)mode;
+   status = mmal_vc_sendwait_message(mmal_vc_get_client(),
+                                     &req.header, sizeof(req),
+                                     MMAL_WORKER_COMPACT,
+                                     &reply, &len, MMAL_FALSE);
+   if (status == MMAL_SUCCESS)
+   {
+      vcos_assert(len == sizeof(reply));
+      status = reply.status;
+      *duration = reply.duration;
+   }
+   return status;
+}
+
+MMAL_STATUS_T mmal_vc_lmk(uint32_t alloc_size)
+{
+   MMAL_STATUS_T status;
+   mmal_worker_lmk req;
+   mmal_worker_lmk reply;
+   size_t len = sizeof(reply);
+
+   req.alloc_size = alloc_size;
+
+   status = mmal_vc_sendwait_message(mmal_vc_get_client(),
+                                     &req.header, sizeof(req),
+                                     MMAL_WORKER_LMK,
+                                     &reply, &len, MMAL_FALSE);
+   return status;
+}
+
+MMAL_STATUS_T mmal_vc_host_log(const char *msg)
+{
+   MMAL_STATUS_T status = MMAL_EINVAL;
+   if (msg)
+   {
+      mmal_worker_host_log req;
+      mmal_worker_reply reply;
+      size_t replylen = sizeof(reply);
+      size_t msg_len = vcos_safe_strcpy(req.msg, msg, sizeof(req.msg), 0);
+
+      /* Reduce the length if it is shorter than the max message length */
+      status = mmal_vc_sendwait_message(mmal_vc_get_client(), &req.header,
+            sizeof(req) - sizeof(req.msg) + vcos_min(sizeof(req.msg), msg_len + 1),
+            MMAL_WORKER_HOST_LOG,
+            &reply, &replylen, MMAL_FALSE);
+
+      if (status == MMAL_SUCCESS)
+      {
+         vcos_assert(replylen == sizeof(reply));
+         status = reply.status;
+      }
+   }
+   return status;
+}
+
+MMAL_STATUS_T mmal_vc_get_core_stats(MMAL_CORE_STATISTICS_T *stats,
+                                     MMAL_STATS_RESULT_T *result,
+                                     char *name,
+                                     size_t namelen,
+                                     MMAL_PORT_TYPE_T type,
+                                     unsigned component_index,
+                                     unsigned port_index,
+                                     MMAL_CORE_STATS_DIR dir,
+                                     MMAL_BOOL_T reset)
+{
+   mmal_worker_get_core_stats_for_port req;
+   mmal_worker_get_core_stats_for_port_reply reply;
+   MMAL_STATUS_T status;
+   size_t len = sizeof(reply);
+
+   req.component_index = component_index;
+   req.port_index = port_index;
+   req.type = type;
+   req.reset = reset;
+   req.dir = dir;
+   
+   status = mmal_vc_sendwait_message(mmal_vc_get_client(),
+                                     &req.header, sizeof(req),
+                                     MMAL_WORKER_GET_CORE_STATS_FOR_PORT,
+                                     &reply, &len, MMAL_FALSE);
+
+   if (status == MMAL_SUCCESS)
+   {
+      vcos_assert(len == sizeof(reply));
+      *stats = reply.stats;
+      *result = reply.result;
+      strncpy(name, reply.component_name, namelen);
+      name[namelen-1] = '\0';
+   }
+   return status;
+}
+
+
+/** Get port context data. */
+static MMAL_STATUS_T mmal_vc_port_info_get(MMAL_PORT_T *port)
+{
+   MMAL_PORT_MODULE_T *module = port->priv->module;
+   mmal_worker_port_info_get msg;
+   mmal_worker_port_info reply;
+   size_t replylen = sizeof(reply);
+   MMAL_STATUS_T status;
+
+   msg.component_handle = module->component_handle;
+   msg.port_type = port->type;
+   msg.index = port->index;
+
+   LOG_TRACE("get port info (%i:%i)", port->type, port->index);
+
+   status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
+                                     MMAL_WORKER_PORT_INFO_GET, &reply, &replylen, MMAL_FALSE);
+   if (status == MMAL_SUCCESS)
+   {
+      vcos_assert(replylen == sizeof(reply));
+      status = reply.status;
+   }
+
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("failed to get port info (%i:%i): %s", port->type, port->index,
+                mmal_status_to_string(status));
+      return status;
+   }
+
+   module->port_handle = reply.port_handle;
+   port->buffer_num_min = reply.port.buffer_num_min;
+   port->buffer_num_recommended = reply.port.buffer_num_recommended;
+   port->buffer_num = reply.port.buffer_num;
+   port->buffer_size_min = reply.port.buffer_size_min;
+   port->buffer_size_recommended = reply.port.buffer_size_recommended;
+   port->buffer_size = reply.port.buffer_size;
+   port->buffer_alignment_min = reply.port.buffer_alignment_min;
+   port->is_enabled = reply.port.is_enabled;
+   port->capabilities = reply.port.capabilities;
+   reply.format.extradata = port->format->extradata;
+   reply.format.es = port->format->es;
+   *port->format = reply.format;
+   *port->format->es = reply.es;
+   if(port->format->extradata_size)
+   {
+      status = mmal_format_extradata_alloc(port->format, port->format->extradata_size);
+      if(status != MMAL_SUCCESS)
+      {
+         vcos_assert(0);
+         port->format->extradata_size = 0;
+         LOG_ERROR("couldn't allocate extradata %i", port->format->extradata_size);
+         return MMAL_ENOMEM;
+      }
+      memcpy(port->format->extradata, reply.extradata, port->format->extradata_size);
+   }
+
+   return MMAL_SUCCESS;
+}
+
+/** Set port context data. */
+static MMAL_STATUS_T mmal_vc_port_info_set(MMAL_PORT_T *port)
+{
+   MMAL_PORT_MODULE_T *module = port->priv->module;
+   mmal_worker_port_info_set msg;
+   mmal_worker_port_info reply;
+   size_t replylen = sizeof(reply);
+   MMAL_STATUS_T status;
+
+   msg.component_handle = module->component_handle;
+   msg.port_type = port->type;
+   msg.index = port->index;
+   msg.port = *port;
+   msg.format = *port->format;
+   msg.es = *port->format->es;
+   if(msg.format.extradata_size > MMAL_FORMAT_EXTRADATA_MAX_SIZE)
+   {
+      vcos_assert(0);
+      msg.format.extradata_size = MMAL_FORMAT_EXTRADATA_MAX_SIZE;
+   }
+   memcpy(msg.extradata, msg.format.extradata, msg.format.extradata_size);
+
+   LOG_TRACE("set port info (%i:%i)", port->type, port->index);
+
+   status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
+                                     MMAL_WORKER_PORT_INFO_SET, &reply, &replylen, MMAL_FALSE);
+   if (status == MMAL_SUCCESS)
+   {
+      vcos_assert(replylen == sizeof(reply));
+      status = reply.status;
+   }
+
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("failed to set port info (%i:%i): %s", port->type, port->index,
+                mmal_status_to_string(status));
+      return status;
+   }
+
+   port->buffer_num_min = reply.port.buffer_num_min;
+   port->buffer_num_recommended = reply.port.buffer_num_recommended;
+   port->buffer_num = reply.port.buffer_num;
+   port->buffer_size_min = reply.port.buffer_size_min;
+   port->buffer_size_recommended = reply.port.buffer_size_recommended;
+   port->buffer_size = reply.port.buffer_size;
+   port->buffer_alignment_min = reply.port.buffer_alignment_min;
+   port->is_enabled = reply.port.is_enabled;
+   port->capabilities = reply.port.capabilities;
+   reply.format.extradata = port->format->extradata;
+   reply.format.es = port->format->es;
+   *port->format = reply.format;
+   *port->format->es = reply.es;
+   if(port->format->extradata_size)
+   {
+      status = mmal_format_extradata_alloc(port->format, port->format->extradata_size);
+      if(status != MMAL_SUCCESS)
+      {
+         vcos_assert(0);
+         port->format->extradata_size = 0;
+         LOG_ERROR("couldn't allocate extradata %i", port->format->extradata_size);
+         return MMAL_ENOMEM;
+      }
+      memcpy(port->format->extradata, reply.extradata, port->format->extradata_size);
+   }
+
+   return MMAL_SUCCESS;
+}
+
+/** Set format on a port */
+static MMAL_STATUS_T mmal_vc_port_set_format(MMAL_PORT_T *port)
+{
+   MMAL_COMPONENT_T *component = port->component;
+   MMAL_COMPONENT_MODULE_T *module = component->priv->module;
+   MMAL_STATUS_T status;
+   unsigned int i;
+
+   status = mmal_vc_port_info_set(port);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("mmal_vc_port_info_set failed %p (%s)", port,
+                mmal_status_to_string(status));
+      return status;
+   }
+
+   /* Get the setting back for this port */
+   status = mmal_vc_port_info_get(port);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("mmal_vc_port_info_get failed %p (%s)", port,
+                mmal_status_to_string(status));
+      return status;
+   }
+
+   /* Get the settings for the output ports in case they have changed */
+   if (port->type == MMAL_PORT_TYPE_INPUT)
+   {
+      for (i = 0; i < module->ports_num; i++)
+      {
+         if (module->ports[i]->port->type != MMAL_PORT_TYPE_OUTPUT)
+            continue;
+
+         status = mmal_vc_port_info_get(module->ports[i]->port);
+         if (status != MMAL_SUCCESS)
+         {
+            LOG_ERROR("mmal_vc_port_info_get failed %p (%i)",
+                      module->ports[i]->port, status);
+            return status;
+         }
+      }
+   }
+
+   return MMAL_SUCCESS;
+}
+
+/** Set parameter on a port */
+static MMAL_STATUS_T mmal_vc_port_parameter_set(MMAL_PORT_T *port, const MMAL_PARAMETER_HEADER_T *param)
+{
+   MMAL_PORT_MODULE_T *module = port->priv->module;
+   MMAL_STATUS_T status;
+   mmal_worker_port_param_set msg;
+   size_t msglen = MMAL_OFFSET(mmal_worker_port_param_set, param) + param->size;
+   mmal_worker_reply reply;
+   size_t replylen = sizeof(reply);
+
+   if(param->size > MMAL_WORKER_PORT_PARAMETER_SET_MAX)
+   {
+      LOG_ERROR("parameter too large (%u > %u)", param->size, MMAL_WORKER_PORT_PARAMETER_SET_MAX);
+      return MMAL_ENOSPC;
+   }
+
+   /* Intercept the zero copy parameter */
+   if (param->id == MMAL_PARAMETER_ZERO_COPY &&
+       param->size >= sizeof(MMAL_PARAMETER_BOOLEAN_T) )
+   {
+      module->is_zero_copy = !!((MMAL_PARAMETER_BOOLEAN_T *)param)->enable;
+      module->zero_copy_workaround = ((MMAL_PARAMETER_BOOLEAN_T *)param)->enable == 0xBEEF;
+      LOG_DEBUG("%s zero copy on port %p", module->is_zero_copy ? "enable" : "disable", port);
+   }
+
+   msg.component_handle = module->component_handle;
+   msg.port_handle = module->port_handle;
+   /* coverity[overrun-buffer-arg] */
+   memcpy(&msg.param, param, param->size);
+
+   status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, msglen,
+                                     MMAL_WORKER_PORT_PARAMETER_SET, &reply, &replylen, MMAL_FALSE);
+
+   if (status == MMAL_SUCCESS)
+   {
+      vcos_assert(replylen == sizeof(reply));
+      status = reply.status;
+   }
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_WARN("failed to set port parameter %u:%u %u:%u %s", msg.component_handle, msg.port_handle,
+            param->id, param->size, mmal_status_to_string(status));
+      return status;
+   }
+
+   if (param->id == MMAL_PARAMETER_BUFFER_REQUIREMENTS)
+   {
+      /* This might have changed the buffer requirements of other ports so fetch them all */
+      MMAL_COMPONENT_T *component = port->component;
+      unsigned int i;
+      for (i = 0; status == MMAL_SUCCESS && i < component->input_num; i++)
+         status = mmal_vc_port_requirements_get(component->input[i]);
+      for (i = 0; status == MMAL_SUCCESS && i < component->output_num; i++)
+         status = mmal_vc_port_requirements_get(component->output[i]);
+   }
+
+   return status;
+}
+
+/** Get parameter on a port */
+static MMAL_STATUS_T mmal_vc_port_parameter_get(MMAL_PORT_T *port, MMAL_PARAMETER_HEADER_T *param)
+{
+   MMAL_PORT_MODULE_T *module = port->priv->module;
+   MMAL_STATUS_T status;
+   mmal_worker_port_param_get msg;
+   size_t msglen = MMAL_OFFSET(mmal_worker_port_param_get, param) + param->size;
+   mmal_worker_port_param_get_reply reply;
+   size_t replylen = MMAL_OFFSET(mmal_worker_port_param_get_reply, param) + param->size;
+
+   if(param->size > MMAL_WORKER_PORT_PARAMETER_GET_MAX)
+   {
+      LOG_ERROR("parameter too large (%u > %u) id %u", param->size,
+            MMAL_WORKER_PORT_PARAMETER_GET_MAX, param->id);
+      return MMAL_ENOMEM;
+   }
+
+   msg.component_handle = module->component_handle;
+   msg.port_handle = module->port_handle;
+   memcpy(&msg.param, param, param->size);
+
+   status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, msglen,
+                                     MMAL_WORKER_PORT_PARAMETER_GET, &reply, &replylen, MMAL_FALSE);
+   if (status == MMAL_SUCCESS)
+   {
+      status = reply.status;
+      /* Reply must include the parameter header */
+      vcos_assert(replylen >= MMAL_OFFSET(mmal_worker_port_param_get_reply, space));
+      
+      /* If the call fails with MMAL_ENOSPC then reply.param.size is set to the size required for
+       * the call to succeed, and that may be bigger than the buffers, so only check these asserts
+       * if the call succeeded.
+       */
+      if ( status == MMAL_SUCCESS )
+      {
+         /* Reply mustn't be bigger than the parameter given */
+         vcos_assert(replylen <= (MMAL_OFFSET(mmal_worker_port_param_get_reply, param) + param->size));
+         /* Reply must be consistent with the parameter size embedded in it */
+         vcos_assert(replylen == (MMAL_OFFSET(mmal_worker_port_param_get_reply, param) + reply.param.size));
+      }
+   }
+
+   if (status != MMAL_SUCCESS && status != MMAL_ENOSPC)
+   {
+      LOG_WARN("failed to get port parameter %u:%u %u:%u %s", msg.component_handle, msg.port_handle,
+            param->id, param->size, mmal_status_to_string(status));
+      return status;
+   }
+   
+   if (status == MMAL_ENOSPC)
+   {
+      /* Copy only as much as we have space for but report true size of parameter */
+      /* coverity[overrun-buffer-arg] */
+      memcpy(param, &reply.param, param->size);
+      param->size = reply.param.size;
+   }
+   else
+   {
+      memcpy(param, &reply.param, reply.param.size);
+   }
+
+   return status;
+}
+
+static uint8_t *mmal_vc_port_payload_alloc(MMAL_PORT_T *port, uint32_t payload_size)
+{
+   MMAL_PORT_MODULE_T *module = port->priv->module;
+   MMAL_BOOL_T can_deref = MMAL_TRUE;
+   char buf[5];
+   void *ret;
+   (void)buf;
+
+   LOG_TRACE("%s: allocating %d bytes, format %s, is_zero_copy %d",
+             port->name,
+             payload_size,
+             mmal_4cc_to_string(buf, sizeof(buf), port->format->encoding),
+             module->is_zero_copy);
+
+   if (port->format->encoding == MMAL_ENCODING_OPAQUE &&
+       module->is_zero_copy)
+   {
+      MMAL_OPAQUE_IMAGE_HANDLE_T h = mmal_vc_opaque_alloc_desc(port->name);
+      can_deref = MMAL_FALSE;
+      ret = (void*)h;
+      if (!ret)
+      {
+         LOG_ERROR("%s: failed to allocate %d bytes opaque memory",
+                   port->name, payload_size);
+         return NULL;
+      }
+      module->opaque_allocs++;
+   }
+
+   else if (module->is_zero_copy)
+   {
+      ret = mmal_vc_shm_alloc(payload_size);
+      if (!ret)
+      {
+         LOG_ERROR("%s: failed to allocate %d bytes of shared memory",
+                   port->name, payload_size);
+         return NULL;
+      }
+   }
+
+   else
+   {
+      /* Allocate conventional memory */
+      ret = vcos_malloc(payload_size, "mmal_vc_port payload");
+      if (!ret)
+      {
+         LOG_ERROR("could not allocate %i bytes", (int)payload_size);
+         return NULL;
+      }
+   }
+
+   /* Ensure that newly minted opaque buffers are always in a sensible
+    * state, and don't have random garbage in them.
+    */
+   if (can_deref && port->format->encoding == MMAL_ENCODING_OPAQUE)
+      memset(ret, 0, payload_size);
+
+   LOG_DEBUG("%s: allocated at %p", port->name, ret);
+   return ret;
+}
+
+static void mmal_vc_port_payload_free(MMAL_PORT_T *port, uint8_t *payload)
+{
+   MMAL_PORT_MODULE_T *module = port->priv->module;
+
+   if (module->opaque_allocs)
+   {
+      module->opaque_allocs--;
+      mmal_vc_opaque_release((MMAL_OPAQUE_IMAGE_HANDLE_T)payload);
+      return;
+   }
+
+   else if (mmal_vc_shm_free(payload) == MMAL_SUCCESS)
+      return;
+
+   /* We're dealing with conventional memory */
+   vcos_free(payload);
+}
+
+/** Create a component given its name. */
+static MMAL_STATUS_T mmal_vc_component_create(const char *name, MMAL_COMPONENT_T *component)
+{
+   MMAL_STATUS_T status;
+   const char *basename;
+   mmal_worker_component_create msg;
+   mmal_worker_component_create_reply reply;
+   size_t replylen = sizeof(reply);
+   MMAL_COMPONENT_MODULE_T *module = NULL;
+   unsigned int ports_num, i;
+
+   LOG_TRACE("%s", name);
+
+   if (strstr(name, VIDEOCORE_PREFIX ".") != name)
+      return MMAL_ENOSYS;
+
+   basename = name + sizeof(VIDEOCORE_PREFIX ".") - 1;
+   if (strlen(basename) >= sizeof(msg.name)-1)
+   {
+      vcos_assert(0);
+      return MMAL_EINVAL;
+   }
+
+   msg.client_component = component;
+   /* coverity[secure_coding] Length tested above */
+   strcpy(msg.name, basename);
+#ifdef __linux__
+   msg.pid = getpid();
+#endif
+
+   status = mmal_vc_init();
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("failed to initialise mmal ipc for '%s' (%i:%s)",
+                name, status, mmal_status_to_string(status));
+      return status;
+   }
+   // claim VC for entire duration of component.
+   status = mmal_vc_use();
+
+   status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
+                                     MMAL_WORKER_COMPONENT_CREATE, &reply, &replylen, MMAL_FALSE);
+
+   vcos_log_info("%s: %s: handle 0x%x status %d reply status %d",
+                 __FUNCTION__, name, reply.component_handle, status, reply.status);
+
+   if (status == MMAL_SUCCESS)
+   {
+      vcos_assert(replylen == sizeof(reply));
+      status = reply.status;
+   }
+
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("failed to create component '%s' (%i:%s)", name, status,
+                mmal_status_to_string(status));
+      mmal_vc_release();
+      mmal_vc_deinit();
+      return status;
+   }
+
+   /* Component has been created, allocate our context. */
+   status = MMAL_ENOMEM;
+   ports_num = 1 + reply.input_num + reply.output_num + reply.clock_num;
+   module = vcos_calloc(1, sizeof(*module) + ports_num * sizeof(*module->ports), "mmal_vc_module");
+   if (!module)
+   {
+      mmal_worker_component_destroy msg;
+      mmal_worker_reply reply;
+      size_t replylen = sizeof(reply);
+      MMAL_STATUS_T destroy_status;
+
+      destroy_status = mmal_vc_sendwait_message(mmal_vc_get_client(), &msg.header, sizeof(msg),
+                               MMAL_WORKER_COMPONENT_DESTROY, &reply, &replylen, MMAL_FALSE);
+      vcos_assert(destroy_status == MMAL_SUCCESS);
+      mmal_vc_release();
+      mmal_vc_deinit();
+      return status;
+   }
+   module->ports = (MMAL_PORT_MODULE_T **)&module[1];
+   module->component_handle = reply.component_handle;
+   component->priv->module = module;
+
+   /* Allocate our local ports. Control port reallocated to set module size. */
+   mmal_port_free(component->control);
+   component->control = mmal_port_alloc(component, MMAL_PORT_TYPE_CONTROL,
+                                        sizeof(MMAL_PORT_MODULE_T));
+   if (!component->control)
+      goto fail;
+
+   if (reply.input_num)
+   {
+      component->input = mmal_ports_alloc(component, reply.input_num, MMAL_PORT_TYPE_INPUT,
+                                          sizeof(MMAL_PORT_MODULE_T));
+      if (!component->input)
+         goto fail;
+   }
+   component->input_num = reply.input_num;
+
+   if (reply.output_num)
+   {
+      component->output = mmal_ports_alloc(component, reply.output_num, MMAL_PORT_TYPE_OUTPUT,
+                                           sizeof(MMAL_PORT_MODULE_T));
+      if (!component->output)
+         goto fail;
+   }
+   component->output_num = reply.output_num;
+
+   if (reply.clock_num)
+   {
+      component->clock = mmal_ports_alloc(component, reply.clock_num, MMAL_PORT_TYPE_CLOCK,
+                                           sizeof(MMAL_PORT_MODULE_T));
+      if (!component->clock)
+         goto fail;
+   }
+   component->clock_num = reply.clock_num;
+
+   /* We want to do the buffer callbacks to the client into a separate thread.
+    * We'll need to queue these callbacks and have an action which does the actual callback. */
+   module->callback_queue = mmal_queue_create();
+   if (!module->callback_queue)
+      goto fail;
+   status = mmal_component_action_register(component, mmal_vc_do_callback_loop);
+   if (status != MMAL_SUCCESS)
+      goto fail;
+
+   LOG_TRACE(" handle %i", reply.component_handle);
+
+   module->ports[module->ports_num] = component->control->priv->module;
+   module->ports[module->ports_num]->port = component->control;
+   module->ports[module->ports_num]->component_handle = module->component_handle;
+   module->ports_num++;
+
+   for (i = 0; i < component->input_num; i++, module->ports_num++)
+   {
+      module->ports[module->ports_num] = component->input[i]->priv->module;
+      module->ports[module->ports_num]->port = component->input[i];
+      module->ports[module->ports_num]->component_handle = module->component_handle;
+   }
+
+   for (i = 0; i < component->output_num; i++, module->ports_num++)
+   {
+      module->ports[module->ports_num] = component->output[i]->priv->module;
+      module->ports[module->ports_num]->port = component->output[i];
+      module->ports[module->ports_num]->component_handle = module->component_handle;
+   }
+
+   for (i = 0; i < component->clock_num; i++, module->ports_num++)
+   {
+      module->ports[module->ports_num] = component->clock[i]->priv->module;
+      module->ports[module->ports_num]->port = component->clock[i];
+      module->ports[module->ports_num]->component_handle = module->component_handle;
+   }
+
+   /* Get the ports info */
+   for (i = 0; i < module->ports_num; i++)
+   {
+      MMAL_PORT_T *port = module->ports[i]->port;
+      port->priv->pf_set_format = mmal_vc_port_set_format;
+      port->priv->pf_enable = mmal_vc_port_enable;
+      port->priv->pf_disable = mmal_vc_port_disable;
+      port->priv->pf_send = mmal_vc_port_send;
+      port->priv->pf_flush = mmal_vc_port_flush;
+      port->priv->pf_connect = mmal_vc_port_connect;
+      port->priv->pf_parameter_set = mmal_vc_port_parameter_set;
+      port->priv->pf_parameter_get = mmal_vc_port_parameter_get;
+      port->priv->pf_payload_alloc = mmal_vc_port_payload_alloc;
+      port->priv->pf_payload_free = mmal_vc_port_payload_free;
+      port->priv->module->component_handle = module->component_handle;
+      port->priv->module->magic = MMAL_MAGIC;
+
+      status = mmal_vc_port_info_get(port);
+      if (status != MMAL_SUCCESS)
+         goto fail;
+   }
+
+   /* Initialise the vc client context which will be used for our event buffers */
+   module->event_ctx_initialised = MMAL_FALSE;
+   module->event_ctx.magic = MMAL_MAGIC;
+   module->event_ctx.callback_event = mmal_vc_port_send_event_callback;
+
+   /* populate component structure */
+   component->priv->pf_enable = mmal_vc_component_enable;
+   component->priv->pf_disable = mmal_vc_component_disable;
+   component->priv->pf_destroy = mmal_vc_component_destroy;
+   return MMAL_SUCCESS;
+
+fail:
+   mmal_vc_component_destroy(component);
+   return status;
+}
+
+MMAL_CONSTRUCTOR(mmal_register_component_videocore);
+void mmal_register_component_videocore(void)
+{
+   mmal_vc_shm_init();
+   mmal_component_supplier_register(VIDEOCORE_PREFIX, mmal_vc_component_create);
+}
+
diff --git a/interface/mmal/vc/mmal_vc_api.h b/interface/mmal/vc/mmal_vc_api.h
new file mode 100755 (executable)
index 0000000..cf9dd27
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_VC_API_H
+#define MMAL_VC_API_H
+
+/** @file
+  *
+  * Public API for MMAL VC client. Most functionality is exposed
+  * via MMAL itself.
+  */
+
+#include "interface/mmal/mmal_types.h"
+#include "interface/mmal/mmal_parameters.h"
+#include "interface/mmal/mmal_port.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** State of components created by the VC adaptation layer, used for
+ * statistics reporting.
+ */
+typedef enum {
+   MMAL_STATS_COMP_IDLE,
+   MMAL_STATS_COMP_CREATED,
+   MMAL_STATS_COMP_DESTROYING,
+   MMAL_STATS_COMP_DESTROYED,
+   MMAL_STATS_COMP_UNUSED = 0xffffffff /* force 32bit */
+} MMAL_STATS_COMP_STATE_T;
+
+/** Per-component statistics collected by the VC adaptation layer.
+ */
+struct MMAL_VC_COMP_STATS_T {
+   struct MMAL_DRIVER_COMPONENT_T *comp;
+   MMAL_STATS_COMP_STATE_T state;
+   uint32_t pid;
+   uint32_t pool_mem_alloc_size;
+   char name[20];
+};
+
+/** VC adaptation layer statistics.
+ */
+struct MMAL_VC_STATS_T
+{
+   struct
+   {
+      uint32_t rx;               /**< Count of data buffers received */
+      uint32_t rx_zero_copy;     /**< Count of zero-copy data buffers received */
+      uint32_t rx_empty;         /**< Empty data buffers (to be filled) */
+      uint32_t rx_fails;         /**< Gave up partway through */
+      uint32_t tx;               /**< Count of data buffers sent */
+      uint32_t tx_zero_copy;     /**< Count of zero-copy data buffers sent */
+      uint32_t tx_empty;         /**< Count of empty data buffers sent */
+      uint32_t tx_fails;         /**< Gave up partway through */
+      uint32_t tx_short_msg;     /**< Messages sent directly in the control message */
+      uint32_t rx_short_msg;     /**< Messages received directly in the control message */
+   } buffers;
+   struct service
+   {
+      uint32_t created;          /**< How many services created */
+      uint32_t pending_destroy;  /**< How many destroyed */
+      uint32_t destroyed;        /**< How many destroyed */
+      uint32_t failures;         /**< Failures to create a service */
+   } service;
+   struct commands
+   {
+      uint32_t bad_messages;
+      uint32_t executed;
+      uint32_t failed;
+      uint32_t replies;
+      uint32_t reply_fails;
+   } commands;
+   struct
+   {
+      uint32_t tx;               /**< Count of events sent */
+      uint32_t tx_fails;         /**< Count of events not fully sent */
+   } events;
+   struct
+   {
+      uint32_t created;
+      uint32_t destroyed;
+      uint32_t destroying;
+      uint32_t failed;
+      uint32_t list_size;
+      struct MMAL_VC_COMP_STATS_T component_list[8];
+   } components;
+   struct
+   {
+      uint32_t enqueued_messages;
+      uint32_t dequeued_messages;
+      uint32_t max_parameter_set_delay;
+      uint32_t max_messages_waiting;
+   } worker;
+
+};
+typedef struct MMAL_VC_STATS_T MMAL_VC_STATS_T;
+
+/* Simple circular text buffer used to store 'interesting' data
+ * from MMAL clients. e.g. settings for each picture taken */
+struct MMAL_VC_HOST_LOG_T
+{
+   /** Simple circular buffer of plain text log messages separated by NUL */
+   char buffer[16 << 10];
+   /** For VCDBG validation and to help detect buffer overflow */
+   uint32_t magic;
+   /** Write offset into buffer */
+   int32_t offset;
+   /** Counter of host messages logged since boot */
+   unsigned count;
+};
+typedef struct MMAL_VC_HOST_LOG_T MMAL_VC_HOST_LOG_T;
+
+/** Status from querying MMAL core statistics.
+ */
+typedef enum
+{
+   MMAL_STATS_FOUND,
+   MMAL_STATS_COMPONENT_NOT_FOUND,
+   MMAL_STATS_PORT_NOT_FOUND,
+   MMAL_STATS_INVALID = 0x7fffffff
+} MMAL_STATS_RESULT_T;
+
+/* If opening dev_vchiq outside mmal/vchiq this is the file path and mode */
+#define MMAL_DEV_VCHIQ_PATH "/dev/vchiq"
+#define MMAL_DEV_VCHIQ_MODE O_RDWR
+
+MMAL_STATUS_T mmal_vc_init(void);
+MMAL_STATUS_T mmal_vc_init_fd(int dev_vchiq_fd);
+void mmal_vc_deinit(void);
+
+MMAL_STATUS_T mmal_vc_use(void);
+MMAL_STATUS_T mmal_vc_release(void);
+
+MMAL_STATUS_T mmal_vc_get_version(uint32_t *major, uint32_t *minor, uint32_t *minimum);
+MMAL_STATUS_T mmal_vc_get_stats(MMAL_VC_STATS_T *stats, int reset);
+
+/** Return the MMAL core statistics for a given component/port.
+ *
+ * @param stats         Updated with given port statistics
+ * @param result        Whether the port/component was found
+ * @param name          Filled in with the name of the port
+ * @param namelen       Length of name
+ * @param component     Which component (indexed from zero)
+ * @param port_type     Which type of port
+ * @param port          Which port (index from zero)
+ * @param reset         Reset the stats.
+ */
+MMAL_STATUS_T mmal_vc_get_core_stats(MMAL_CORE_STATISTICS_T *stats,
+                                     MMAL_STATS_RESULT_T *result,
+                                     char *name,
+                                     size_t namelen,
+                                     MMAL_PORT_TYPE_T type,
+                                     unsigned component,
+                                     unsigned port,
+                                     MMAL_CORE_STATS_DIR dir,
+                                     MMAL_BOOL_T reset);
+/**
+ * Stores an arbitrary text message in a circular buffer inside the MMAL VC server.
+ * The purpose of this message is to log high level events from the host in order
+ * to diagnose problems that require multiple actions to reproduce. e.g. taking
+ * multiple pictures with different settings.
+ *
+ * @param   msg  The message text.
+ * @return  MMAL_SUCCESS if the message was logged or MMAL_ENOSYS if the API
+ *          if not supported.
+ */
+MMAL_STATUS_T mmal_vc_host_log(const char *msg);
+
+/* For backwards compatibility in builds */
+#define MMAL_VC_API_HAVE_HOST_LOG
+
+/* VC DEBUG ONLY ************************************************************/
+/** Consumes memory in the relocatable heap.
+ *
+ * The existing reserved memory is freed first then the new chunk is allocated.
+ * If zero is specified for the size then the previously reserved memory
+ * is freed and no allocation occurs.
+ *
+ * At startup no memory is reserved.
+ *
+ * @param size    Size of memory to consume in bytes.
+ * @param handle  Set to the mem handle for the reserved memory or zero
+ *                if no memory was allocated.
+ * @return        MMAL_SUCCESS if memory was reserved (or size zero requested),
+ *                MMAL_ENOSPC if the allocation failed or MMAL_ENOSYS if the
+ *                API is not supported e.g in release mode VC images.
+ * @internal
+ */
+MMAL_STATUS_T mmal_vc_consume_mem(size_t size, uint32_t *handle);
+
+typedef enum
+{
+   MMAL_VC_COMPACT_NONE       = 0,
+   MMAL_VC_COMPACT_NORMAL     = 1,
+   MMAL_VC_COMPACT_DISCARD    = 2,
+   MMAL_VC_COMPACT_AGGRESSIVE = 4,
+   MMAL_VC_COMPACT_SHUFFLE    = 0x80,
+   MMAL_VC_COMPACT_ALL        = MMAL_VC_COMPACT_NORMAL | MMAL_VC_COMPACT_DISCARD | MMAL_VC_COMPACT_AGGRESSIVE,
+} MMAL_VC_COMPACT_MODE_T;
+
+/** Trigger relocatable heap compaction.
+ * @internal
+ */
+MMAL_STATUS_T mmal_vc_compact(MMAL_VC_COMPACT_MODE_T mode, uint32_t *duration);
+
+/** Trigger LMK action from VC, for diagnostics.
+ * @internal
+ */
+MMAL_STATUS_T mmal_vc_lmk(uint32_t alloc_size);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/interface/mmal/vc/mmal_vc_api_drm.c b/interface/mmal/vc/mmal_vc_api_drm.c
new file mode 100755 (executable)
index 0000000..a926a86
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "mmal_vc_api_drm.h"
+#include "mmal_vc_api.h"
+#include "interface/mmal/mmal_logging.h"
+#include "interface/mmal/mmal.h"
+#include "mmal_vc_api.h"
+#include "mmal_vc_msgs.h"
+#include "mmal_vc_client_priv.h"
+#include "mmal_vc_opaque_alloc.h"
+#include "mmal_vc_shm.h"
+#include "interface/mmal/util/mmal_util.h"
+#include "interface/mmal/core/mmal_component_private.h"
+#include "interface/mmal/core/mmal_port_private.h"
+#include "interface/mmal/core/mmal_buffer_private.h"
+#include "interface/vcos/vcos.h"
+
+
+int mmal_vc_drm_get_time(unsigned int * time)
+{
+   MMAL_STATUS_T status;
+   mmal_worker_msg_header req;
+   mmal_worker_drm_get_time_reply reply;
+   size_t len = sizeof(reply);
+   status = mmal_vc_init();
+   if (status != MMAL_SUCCESS) return status;
+   status = mmal_vc_sendwait_message(mmal_vc_get_client(),
+                                     &req, sizeof(req),
+                                     MMAL_WORKER_DRM_GET_TIME,
+                                     &reply, &len, MMAL_FALSE);
+   *time = reply.time;
+   mmal_vc_deinit();
+   return status;
+}
+
+
+int mmal_vc_drm_get_lhs32(unsigned char * into)
+{
+   MMAL_STATUS_T status;
+   mmal_worker_msg_header req;
+   mmal_worker_drm_get_lhs32_reply reply;
+   size_t len = sizeof(reply);
+   status = mmal_vc_init();
+   if (status != MMAL_SUCCESS) return status;
+
+   status = mmal_vc_sendwait_message(mmal_vc_get_client(),
+                                     &req, sizeof(req),
+                                     MMAL_WORKER_DRM_GET_LHS32,
+                                     &reply, &len, MMAL_FALSE);
+   memcpy(into, reply.secret, 32);
+   mmal_vc_deinit();
+   return status;
+}
diff --git a/interface/mmal/vc/mmal_vc_api_drm.h b/interface/mmal/vc/mmal_vc_api_drm.h
new file mode 100755 (executable)
index 0000000..04688b6
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef MMAL_VC_API_DRM_H
+#define MMAL_VC_API_DRM_H
+
+/** @file
+  *
+  * Public API for MMAL VC client. (Divx DRM part)
+  */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// Reads the current clock (in microseconds) into the "time" variable.
+// Returns zero on success, nonszero on failure
+int mmal_vc_drm_get_time(unsigned int * time);
+
+// Reads the local hardware secret into the "into" variable (needs to be 32 bytes of space for this)
+// Returns 0 on success, nonzero on failure
+// Usage:
+//   unsigned char buffer[32];
+//   success = mmal_vc_divx_drm_get_lhs(buffer);
+int mmal_vc_drm_get_lhs32(unsigned char * into);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/interface/mmal/vc/mmal_vc_client.c b/interface/mmal/vc/mmal_vc_client.c
new file mode 100755 (executable)
index 0000000..db64dc6
--- /dev/null
@@ -0,0 +1,827 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
+#include "mmal.h"
+#include "mmal_vc_msgs.h"
+#include "mmal_vc_api.h"
+#include "mmal_vc_client_priv.h"
+#include "interface/vcos/vcos.h"
+#include "vchiq_util.h"
+#include "interface/mmal/core/mmal_buffer_private.h"
+#include "interface/mmal/core/mmal_component_private.h"
+#include "interface/mmal/core/mmal_port_private.h"
+#include "interface/mmal/util/mmal_list.h"
+#include "interface/mmal/util/mmal_util.h"
+
+#define VCOS_LOG_CATEGORY (&mmal_ipc_log_category)
+#include "interface/mmal/mmal_logging.h"
+
+#include <stdio.h>
+
+#define MAX_WAITERS 16
+static VCOS_ONCE_T once = VCOS_ONCE_INIT;
+static VCHIQ_INSTANCE_T mmal_vchiq_instance;
+static VCOS_LOG_CAT_T mmal_ipc_log_category;
+
+/** Client threads use one of these to wait for
+ * a reply from VideoCore.
+ */
+typedef struct MMAL_WAITER_T
+{
+   VCOS_SEMAPHORE_T sem;
+   unsigned inuse;
+   void *dest;                   /**< Where to write reply */
+   size_t destlen;               /**< Max length for reply */
+} MMAL_WAITER_T;
+
+/** We have an array of waiters and allocate them to waiting
+  * threads. They can be released back to the pool in any order.
+  * If there are none free, the calling thread will block until
+  * one becomes available.
+  */
+typedef struct 
+{
+   MMAL_WAITER_T waiters[MAX_WAITERS];
+   VCOS_SEMAPHORE_T sem;
+} MMAL_WAITPOOL_T;
+
+struct MMAL_CLIENT_T
+{
+   int refcount;
+   int usecount;
+   VCOS_MUTEX_T lock;
+   VCHIQ_SERVICE_HANDLE_T service;
+   MMAL_WAITPOOL_T waitpool;
+   VCOS_MUTEX_T bulk_lock;
+
+   MMAL_BOOL_T inited;
+};
+
+/* One client per process/VC connection. Multiple threads may
+ * be using a single client.
+ */
+static MMAL_CLIENT_T client;
+
+static void init_once(void)
+{
+   vcos_mutex_create(&client.lock, VCOS_FUNCTION);
+}
+
+/** Create a pool of wait-structures.
+  */
+static MMAL_STATUS_T create_waitpool(MMAL_WAITPOOL_T *waitpool)
+{
+   VCOS_STATUS_T status;
+   int i;
+
+   status = vcos_semaphore_create(&waitpool->sem, VCOS_FUNCTION,
+                                  MAX_WAITERS);
+   if (status != VCOS_SUCCESS)
+      return status==VCOS_SUCCESS ? MMAL_SUCCESS : MMAL_ENOSPC;
+
+   for (i=0; i<MAX_WAITERS; i++)
+   {
+      waitpool->waiters[i].inuse = 0;
+      status = vcos_semaphore_create(&waitpool->waiters[i].sem,
+                                     "mmal waiter", 0);
+      if (status != VCOS_SUCCESS)
+         break;
+   }
+
+   if (status != VCOS_SUCCESS)
+   {
+      /* clean up */
+      i--;
+      while (i>=0)
+      {
+         vcos_semaphore_delete(&waitpool->waiters[i].sem);
+         i--;
+      }
+      vcos_semaphore_delete(&waitpool->sem);
+   }
+   return status==VCOS_SUCCESS ? MMAL_SUCCESS : MMAL_ENOSPC;
+}
+
+static void destroy_waitpool(MMAL_WAITPOOL_T *waitpool)
+{
+   int i;
+   for (i=0; i<MAX_WAITERS; i++)
+      vcos_semaphore_delete(&waitpool->waiters[i].sem);
+
+   vcos_semaphore_delete(&waitpool->sem);
+}
+
+/** Grab a waiter from the pool. Return immediately if one already
+  * available, or wait for one to become available.
+  */
+static MMAL_WAITER_T *get_waiter(MMAL_CLIENT_T *client)
+{
+   int i;
+   MMAL_WAITER_T *waiter = NULL;
+   vcos_semaphore_wait(&client->waitpool.sem);
+   vcos_mutex_lock(&client->lock);
+   for (i=0; i<MAX_WAITERS; i++)
+   {
+      if (client->waitpool.waiters[i].inuse == 0)
+         break;
+   }
+   /* If this fails, the semaphore is not working */
+   if (vcos_verify(i != MAX_WAITERS))
+   {
+      waiter = client->waitpool.waiters+i;
+      waiter->inuse = 1;
+   }
+   vcos_mutex_unlock(&client->lock);
+
+   return waiter;
+}
+
+/** Return a waiter to the pool.
+  */
+static void release_waiter(MMAL_CLIENT_T *client, MMAL_WAITER_T *waiter)
+{
+   LOG_TRACE("at %p", waiter);
+   vcos_assert(waiter);
+   vcos_assert(waiter->inuse);
+   waiter->inuse = 0;
+   vcos_semaphore_post(&client->waitpool.sem);
+}
+
+static MMAL_PORT_T *mmal_vc_port_by_number(MMAL_COMPONENT_T *component, uint32_t type, uint32_t number)
+{
+   switch (type)
+   {
+      case MMAL_PORT_TYPE_CONTROL:
+         vcos_assert(number == 0);
+         return component->control;
+      case MMAL_PORT_TYPE_INPUT:
+         vcos_assert(number < component->input_num);
+         return component->input[number];
+      case MMAL_PORT_TYPE_OUTPUT:
+         vcos_assert(number < component->output_num);
+         return component->output[number];
+      case MMAL_PORT_TYPE_CLOCK:
+         vcos_assert(number < component->clock_num);
+         return component->clock[number];
+   }
+
+   return NULL;
+}
+
+static void mmal_vc_handle_event_msg(VCHIQ_HEADER_T *vchiq_header,
+                                    VCHIQ_SERVICE_HANDLE_T service,
+                                    void *context)
+{
+   mmal_worker_event_to_host *msg = (mmal_worker_event_to_host *)vchiq_header->data;
+   MMAL_COMPONENT_T *component = msg->client_component;
+   MMAL_BUFFER_HEADER_T *buffer;
+   MMAL_STATUS_T status;
+   MMAL_PORT_T *port;
+
+   LOG_DEBUG("event to host, cmd 0x%08x len %d to component %p port (%d,%d)",
+         msg->cmd, msg->length, msg->client_component, msg->port_type, msg->port_num);
+   (void)context;
+
+   port = mmal_vc_port_by_number(component, msg->port_type, msg->port_num);
+   if (!vcos_verify(port))
+   {
+      LOG_ERROR("port (%i,%i) doesn't exist", (int)msg->port_type, (int)msg->port_num);
+      goto error;
+   }
+
+   status = mmal_port_event_get(port, &buffer, msg->cmd);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("no event buffer available to receive event (%i)", (int)status);
+      goto error;
+   }
+
+   if (!vcos_verify(msg->length <= buffer->alloc_size))
+   {
+      LOG_ERROR("event buffer to small to receive event (%i/%i)",
+                (int)buffer->alloc_size, (int)msg->length);
+      goto error;
+   }
+   buffer->length = msg->length;
+
+   /* Sanity check that the event buffers have the proper vc client context */
+   if (!vcos_verify(mmal_buffer_header_driver_data(buffer)->magic == MMAL_MAGIC &&
+          mmal_buffer_header_driver_data(buffer)->client_context &&
+          mmal_buffer_header_driver_data(buffer)->client_context->magic == MMAL_MAGIC &&
+          mmal_buffer_header_driver_data(buffer)->client_context->callback_event))
+   {
+      LOG_ERROR("event buffers not configured properly by component");
+      goto error;
+   }
+
+   if (buffer->length > MMAL_WORKER_EVENT_SPACE)
+   {
+      /* a buffer full of data for us to process */
+      int len = buffer->length;
+      len = (len+3) & (~3);
+      LOG_DEBUG("queue event bulk rx: %p, %d", buffer->data, buffer->length);
+      msg->delayed_buffer = buffer;
+
+      VCHIQ_STATUS_T vst = vchiq_queue_bulk_receive(service, buffer->data, len, vchiq_header);
+      if (vst != VCHIQ_SUCCESS)
+      {
+         LOG_TRACE("queue event bulk rx len %d failed to start", buffer->length);
+         mmal_buffer_header_release(buffer);
+         goto error;
+      }
+   }
+   else
+   {
+      if (msg->length)
+         memcpy(buffer->data, msg->data, msg->length);
+
+      mmal_buffer_header_driver_data(buffer)->client_context->callback_event(port, buffer);
+      LOG_DEBUG("done callback back to client");
+      vchiq_release_message(service, vchiq_header);
+   }
+
+   return;
+
+error:
+   /* FIXME: How to abort bulk receive if necessary? */
+   msg->length = 0; /* FIXME: set a buffer flag to signal error */
+   vchiq_release_message(service, vchiq_header);
+}
+
+static MMAL_STATUS_T mmal_vc_use_internal(MMAL_CLIENT_T *client)
+{
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   vcos_mutex_lock(&client->lock);
+   if(client->usecount++ == 0)
+   {
+      if(vchiq_use_service(client->service) != VCHIQ_SUCCESS)
+      {
+         client->usecount--;
+         status = MMAL_EIO;
+      }
+   }
+   vcos_mutex_unlock(&client->lock);
+   return status;
+}
+
+static MMAL_STATUS_T mmal_vc_release_internal(MMAL_CLIENT_T *client)
+{
+   MMAL_STATUS_T status = MMAL_SUCCESS;
+   vcos_mutex_lock(&client->lock);
+   if(--client->usecount == 0)
+   {
+      if(vchiq_release_service(client->service) != VCHIQ_SUCCESS)
+      {
+         client->usecount++;
+         status = MMAL_EIO;
+      }
+   }
+   vcos_mutex_unlock(&client->lock);
+   return status;
+}
+
+
+/** Callback invoked by VCHIQ
+  */
+static VCHIQ_STATUS_T mmal_vc_vchiq_callback(VCHIQ_REASON_T reason,
+                                             VCHIQ_HEADER_T *vchiq_header,
+                                             VCHIQ_SERVICE_HANDLE_T service,
+                                             void *context)
+{
+   LOG_TRACE("reason %d", reason);
+
+   switch (reason)
+   {
+   case VCHIQ_MESSAGE_AVAILABLE:
+      {
+         mmal_worker_msg_header *msg = (mmal_worker_msg_header*)vchiq_header->data;
+         vcos_assert(msg->magic == MMAL_MAGIC);
+
+         if (msg->msgid == MMAL_WORKER_BUFFER_TO_HOST)
+         {
+            LOG_TRACE("buffer to host");
+            mmal_worker_buffer_from_host *msg = (mmal_worker_buffer_from_host *)vchiq_header->data;
+            LOG_TRACE("len %d context %p", msg->buffer_header.length, msg->drvbuf.client_context);
+            vcos_assert(msg->drvbuf.client_context);
+            vcos_assert(msg->drvbuf.client_context->magic == MMAL_MAGIC);
+
+            /* If the buffer is referencing another, need to replicate it here
+             * in order to use the reference buffer's payload and ensure the
+             * reference is not released prematurely */
+            if (msg->has_reference)
+               mmal_buffer_header_replicate(msg->drvbuf.client_context->buffer,
+                                            msg->drvbuf_ref.client_context->buffer);
+
+            /* Sanity check the size of the transfer so we don't overrun our buffer */
+            if (!vcos_verify(msg->buffer_header.offset + msg->buffer_header.length <=
+                             msg->drvbuf.client_context->buffer->alloc_size))
+            {
+               LOG_TRACE("buffer too small (%i, %i)",
+                         msg->buffer_header.offset + msg->buffer_header.length,
+                         msg->drvbuf.client_context->buffer->alloc_size);
+               msg->buffer_header.length = 0; /* FIXME: set a buffer flag to signal error */
+               msg->drvbuf.client_context->callback(msg);
+               vchiq_release_message(service, vchiq_header);
+               break;
+            }
+            /*To handle VC to HOST filled buffer callback of EOS buffer to receive in sync with data buffers*/
+            if (!msg->is_zero_copy &&
+                  (msg->buffer_header.length != 0 ||
+                     (msg->buffer_header.flags & MMAL_BUFFER_HEADER_FLAG_EOS)))
+            {
+               /* a buffer full of data for us to process */
+               VCHIQ_STATUS_T vst = VCHIQ_SUCCESS;
+               LOG_TRACE("queue bulk rx: %p, %d", msg->drvbuf.client_context->buffer->data +
+                         msg->buffer_header.offset, msg->buffer_header.length);
+               int len = msg->buffer_header.length;
+               len = (len+3) & (~3);
+
+               if (!len && (msg->buffer_header.flags & MMAL_BUFFER_HEADER_FLAG_EOS))
+               {
+                  len = 8;
+               }
+               if (!msg->payload_in_message)
+               {
+                  /* buffer transferred using vchiq bulk xfer */
+                  vst = vchiq_queue_bulk_receive(service,
+                     msg->drvbuf.client_context->buffer->data + msg->buffer_header.offset,
+                     len, vchiq_header);
+
+                  if (vst != VCHIQ_SUCCESS)
+                  {
+                     LOG_TRACE("queue bulk rx len %d failed to start", msg->buffer_header.length);
+                     msg->buffer_header.length = 0; /* FIXME: set a buffer flag to signal error */
+                     msg->drvbuf.client_context->callback(msg);
+                     vchiq_release_message(service, vchiq_header);
+                  }
+               }
+               else if (msg->payload_in_message <= MMAL_VC_SHORT_DATA)
+               {
+                  /* we have already received the buffer data in the message! */
+                  MMAL_BUFFER_HEADER_T *dst = msg->drvbuf.client_context->buffer;
+                  LOG_TRACE("short data: dst = %p, dst->data = %p, len %d short len %d", dst, dst? dst->data : 0, msg->buffer_header.length, msg->payload_in_message);
+                  memcpy(dst->data, msg->short_data, msg->payload_in_message);
+                  dst->offset = 0;
+                  dst->length = msg->payload_in_message;
+                  vchiq_release_message(service, vchiq_header);
+                  msg->drvbuf.client_context->callback(msg);
+               }
+               else
+               {
+                  /* impossible short data length */
+                  LOG_ERROR("Message with invalid short payload length %d",
+                            msg->payload_in_message);
+                  vcos_assert(0);
+               }
+            }
+            else
+            {
+
+               /* Message received from videocore; the client_context should have
+                * been passed all the way through by videocore back to us, and will
+                * be picked up in the callback to complete the sequence.
+                */
+               LOG_TRACE("doing cb (%p) context %p",
+                         msg->drvbuf.client_context, msg->drvbuf.client_context ?
+                         msg->drvbuf.client_context->callback : 0);
+               msg->drvbuf.client_context->callback(msg);
+               LOG_TRACE("done callback back to client");
+               vchiq_release_message(service, vchiq_header);
+            }
+         }
+         else if (msg->msgid == MMAL_WORKER_EVENT_TO_HOST)
+         {
+            mmal_vc_handle_event_msg(vchiq_header, service, context);
+         }
+         else
+         {
+            MMAL_WAITER_T *waiter = msg->u.waiter;
+            LOG_TRACE("waking up waiter at %p", waiter);
+            vcos_assert(waiter->inuse);
+            int len = vcos_min(waiter->destlen, vchiq_header->size);
+            waiter->destlen = len;
+            LOG_TRACE("copying payload @%p to %p len %d", waiter->dest, msg, len);
+            memcpy(waiter->dest, msg, len);
+            vchiq_release_message(service, vchiq_header);
+            vcos_semaphore_post(&waiter->sem);
+         }
+      }
+      break;
+   case VCHIQ_BULK_TRANSMIT_DONE:
+      {
+         /* nothing to do here, need to wait for the copro to tell us it
+          * has emptied the buffer before we can recycle it, otherwise we
+          * end up feeding the copro with buffers it cannot handle.
+          */
+#ifdef VCOS_LOGGING_ENABLED
+         mmal_worker_buffer_from_host *msg = (mmal_worker_buffer_from_host *)context;
+#endif
+         LOG_TRACE("bulk tx done: %p, %d", msg->buffer_header.data, msg->buffer_header.length);
+      }
+      break;
+   case VCHIQ_BULK_RECEIVE_DONE:
+      {
+         VCHIQ_HEADER_T *header = (VCHIQ_HEADER_T *)context;
+         mmal_worker_msg_header *msg_hdr = (mmal_worker_msg_header*)header->data;
+         if (msg_hdr->msgid == MMAL_WORKER_BUFFER_TO_HOST)
+         {
+            mmal_worker_buffer_from_host *msg = (mmal_worker_buffer_from_host *)msg_hdr;
+            vcos_assert(msg->drvbuf.client_context->magic == MMAL_MAGIC);
+            msg->drvbuf.client_context->callback(msg);
+            LOG_TRACE("bulk rx done: %p, %d", msg->buffer_header.data, msg->buffer_header.length);
+         }
+         else
+         {
+            mmal_worker_event_to_host *msg = (mmal_worker_event_to_host *)msg_hdr;
+            MMAL_PORT_T *port = mmal_vc_port_by_number(msg->client_component, msg->port_type, msg->port_num);
+
+            vcos_assert(port);
+            mmal_buffer_header_driver_data(msg->delayed_buffer)->
+               client_context->callback_event(port, msg->delayed_buffer);
+            LOG_DEBUG("event bulk rx done, length %d", msg->length);
+         }
+         vchiq_release_message(service, header);
+      }
+      break;
+   case VCHIQ_BULK_RECEIVE_ABORTED:
+      {
+         VCHIQ_HEADER_T *header = (VCHIQ_HEADER_T *)context;
+         mmal_worker_msg_header *msg_hdr = (mmal_worker_msg_header*)header->data;
+         if (msg_hdr->msgid == MMAL_WORKER_BUFFER_TO_HOST)
+         {
+            mmal_worker_buffer_from_host *msg = (mmal_worker_buffer_from_host *)msg_hdr;
+            LOG_TRACE("bulk rx aborted: %p, %d", msg->buffer_header.data, msg->buffer_header.length);
+            vcos_assert(msg->drvbuf.client_context->magic == MMAL_MAGIC);
+            msg->buffer_header.flags |= MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED;
+            msg->drvbuf.client_context->callback(msg);
+         }
+         else
+         {
+            mmal_worker_event_to_host *msg = (mmal_worker_event_to_host *)msg_hdr;
+            MMAL_PORT_T *port = mmal_vc_port_by_number(msg->client_component, msg->port_type, msg->port_num);
+
+            vcos_assert(port);
+            LOG_DEBUG("event bulk rx aborted");
+            msg->delayed_buffer->flags |= MMAL_BUFFER_HEADER_FLAG_TRANSMISSION_FAILED;
+            mmal_buffer_header_driver_data(msg->delayed_buffer)->
+               client_context->callback_event(port, msg->delayed_buffer);
+         }
+         vchiq_release_message(service, header);
+      }
+      break;
+   case VCHIQ_BULK_TRANSMIT_ABORTED:
+      {
+         mmal_worker_buffer_from_host *msg = (mmal_worker_buffer_from_host *)context;
+         LOG_INFO("bulk tx aborted: %p, %d", msg->buffer_header.data, msg->buffer_header.length);
+         vcos_assert(msg->drvbuf.client_context->magic == MMAL_MAGIC);
+         /* Nothing to do as the VC side will release the buffer and notify us of the error */
+      }
+      break;
+   default:
+      break;
+   }
+
+   return VCHIQ_SUCCESS;
+}
+
+/** Send a message and wait for a reply.
+  *
+  * @param client       client to send message for
+  * @param msg_header   message vchiq_header to send
+  * @param size         length of message, including header
+  * @param msgid        message id
+  * @param dest         destination for reply
+  * @param destlen      size of destination, updated with actual length
+  * @param send_dummy_bulk whether to send a dummy bulk transfer
+  */
+MMAL_STATUS_T mmal_vc_sendwait_message(struct MMAL_CLIENT_T *client,
+                                       mmal_worker_msg_header *msg_header,
+                                       size_t size,
+                                       uint32_t msgid,
+                                       void *dest,
+                                       size_t *destlen,
+                                       MMAL_BOOL_T send_dummy_bulk)
+{
+   MMAL_STATUS_T ret;
+   MMAL_WAITER_T *waiter;
+   VCHIQ_STATUS_T vst;
+   VCHIQ_ELEMENT_T elems[] = {{msg_header, size}};
+
+   vcos_assert(size >= sizeof(mmal_worker_msg_header));
+   vcos_assert(dest);
+
+   if (!client->inited)
+   {
+      vcos_assert(0);
+      return MMAL_EINVAL;
+   }
+
+   if (send_dummy_bulk)
+      vcos_mutex_lock(&client->bulk_lock);
+
+   waiter = get_waiter(client);
+   msg_header->msgid  = msgid;
+   msg_header->u.waiter = waiter;
+   msg_header->magic  = MMAL_MAGIC;
+
+   waiter->dest    = dest;
+   waiter->destlen = *destlen;
+   LOG_TRACE("wait %p, reply to %p", waiter, dest);
+   mmal_vc_use_internal(client);
+
+   vst = vchiq_queue_message(client->service, elems, 1);
+
+   if (vst != VCHIQ_SUCCESS)
+   {
+      ret = MMAL_EIO;
+      if (send_dummy_bulk)
+        vcos_mutex_unlock(&client->bulk_lock);
+      goto fail_msg;
+   }
+
+   if (send_dummy_bulk)
+   {
+      uint32_t data_size = 8;
+      /* The data is just some dummy bytes so it's fine for it to be static */
+      static uint8_t data[8];
+      vst = vchiq_queue_bulk_transmit(client->service, data, data_size, msg_header);
+
+      vcos_mutex_unlock(&client->bulk_lock);
+
+      if (!vcos_verify(vst == VCHIQ_SUCCESS))
+      {
+         LOG_ERROR("failed bulk transmit");
+         /* This really should not happen and if it does, things will go wrong as
+          * we've already queued the vchiq message above. */
+         vcos_assert(0);
+         ret = MMAL_EIO;
+         goto fail_msg;
+      }
+   }
+
+   /* now wait for the reply...
+    *
+    * FIXME: we could do with a timeout here. Need to be careful to cancel
+    * the semaphore on a timeout.
+    */
+   /* coverity[lock] This semaphore isn't being used as a mutex */
+   vcos_semaphore_wait(&waiter->sem);
+
+   mmal_vc_release_internal(client);
+   LOG_TRACE("got reply (len %i/%i)", (int)*destlen, (int)waiter->destlen);
+   *destlen = waiter->destlen;
+
+   release_waiter(client, waiter);
+   return MMAL_SUCCESS;
+
+fail_msg:
+   mmal_vc_release_internal(client);
+
+   release_waiter(client, waiter);
+   return ret;
+}
+
+/** Send a message and do not wait for a reply.
+  *
+  * @note
+  * This function should only be called from within a mmal component, so
+  * vchiq_use/release_service calls aren't required (dealt with at higher level).
+  *
+  * @param client       client to send message for
+  * @param msg_header   message header to send
+  * @param size         length of message, including header
+  * @param msgid        message id
+  */
+MMAL_STATUS_T mmal_vc_send_message(MMAL_CLIENT_T *client,
+                                   mmal_worker_msg_header *msg_header, size_t size,
+                                   uint8_t *data, size_t data_size,
+                                   uint32_t msgid)
+{
+   VCHIQ_STATUS_T vst;
+   VCHIQ_ELEMENT_T elems[] = {{msg_header, size}};
+   MMAL_BOOL_T using_bulk_transfer = (data_size != 0);
+
+   LOG_TRACE("len %d", data_size);
+   vcos_assert(size >= sizeof(mmal_worker_msg_header));
+
+   if (!client->inited)
+   {
+      vcos_assert(0);
+      return MMAL_EINVAL;
+   }
+
+   if (using_bulk_transfer)
+      vcos_mutex_lock(&client->bulk_lock);
+
+   msg_header->msgid  = msgid;
+   msg_header->magic  = MMAL_MAGIC;
+
+   vst = vchiq_queue_message(client->service, elems, 1);
+
+   if (vst != VCHIQ_SUCCESS)
+   {
+      if (using_bulk_transfer)
+         vcos_mutex_unlock(&client->bulk_lock);
+
+      LOG_ERROR("failed");
+      goto error;
+   }
+
+   if (using_bulk_transfer)
+   {
+      LOG_TRACE("bulk transmit: %p, %i", data, data_size);
+
+      data_size = (data_size + 3) & ~3;
+      vst = vchiq_queue_bulk_transmit(client->service, data, data_size, msg_header);
+
+      vcos_mutex_unlock(&client->bulk_lock);
+
+      if (!vcos_verify(vst == VCHIQ_SUCCESS))
+      {
+         LOG_ERROR("failed bulk transmit");
+         /* This really should not happen and if it does, things will go wrong as
+          * we've already queued the vchiq message above. */
+         vcos_assert(0);
+         goto error;
+      }
+   }
+
+   return MMAL_SUCCESS;
+
+ error:
+   return MMAL_EIO;
+}
+
+MMAL_STATUS_T mmal_vc_use(void)
+{
+   MMAL_STATUS_T status = MMAL_ENOTCONN;
+   if(client.inited)
+      status = mmal_vc_use_internal(&client);
+   return status;
+}
+
+MMAL_STATUS_T mmal_vc_release(void)
+{
+   MMAL_STATUS_T status = MMAL_ENOTCONN;
+   if(client.inited)
+      status = mmal_vc_release_internal(&client);
+   return status;
+}
+
+MMAL_STATUS_T mmal_vc_init_fd(int dev_vchiq_fd)
+{
+   VCHIQ_SERVICE_PARAMS_T vchiq_params;
+   MMAL_BOOL_T vchiq_initialised = 0, waitpool_initialised = 0;
+   MMAL_BOOL_T service_initialised = 0;
+   MMAL_STATUS_T status = MMAL_EIO;
+   VCHIQ_STATUS_T vchiq_status;
+   int count;
+
+   vcos_once(&once, init_once);
+
+   vcos_mutex_lock(&client.lock);
+
+   count = client.refcount++;
+   if (count > 0)
+   {
+      /* Already initialised so nothing to do */
+      vcos_mutex_unlock(&client.lock);
+      return MMAL_SUCCESS;
+   }
+
+   vcos_log_register("mmalipc", VCOS_LOG_CATEGORY);
+
+   /* Initialise a VCHIQ instance */
+   vchiq_status = vchiq_initialise_fd(&mmal_vchiq_instance, dev_vchiq_fd);
+   if (vchiq_status != VCHIQ_SUCCESS)
+   {
+      LOG_ERROR("failed to initialise vchiq");
+      status = MMAL_EIO;
+      goto error;
+   }
+   vchiq_initialised = 1;
+
+   vchiq_status = vchiq_connect(mmal_vchiq_instance);
+   if (vchiq_status != VCHIQ_SUCCESS)
+   {
+      LOG_ERROR("failed to connect to vchiq");
+      status = MMAL_EIO;
+      goto error;
+   }
+
+   memset(&vchiq_params,0,sizeof(vchiq_params));
+   vchiq_params.fourcc = MMAL_CONTROL_FOURCC();
+   vchiq_params.callback = mmal_vc_vchiq_callback;
+   vchiq_params.userdata = &client;
+   vchiq_params.version = WORKER_VER_MAJOR;
+   vchiq_params.version_min = WORKER_VER_MINIMUM;
+
+   vchiq_status = vchiq_open_service(mmal_vchiq_instance, &vchiq_params, &client.service);
+   if (vchiq_status != VCHIQ_SUCCESS)
+   {
+      LOG_ERROR("could not open vchiq service");
+      status = MMAL_EIO;
+      goto error;
+   }
+   client.usecount = 1; /* usecount set to 1 by the open call. */
+   service_initialised = 1;
+
+   status = create_waitpool(&client.waitpool);
+   if (status != MMAL_SUCCESS)
+   {
+      LOG_ERROR("could not create wait pool");
+      goto error;
+   }
+   waitpool_initialised = 1;
+
+   if (vcos_mutex_create(&client.bulk_lock, "mmal client bulk lock") != VCOS_SUCCESS)
+   {
+      LOG_ERROR("could not create bulk lock");
+      status = MMAL_ENOSPC;
+      goto error;
+   }
+
+   client.inited = 1;
+
+   vcos_mutex_unlock(&client.lock);
+   /* assume we're not using VC immediately.  Do this outside the lock */
+   mmal_vc_release();
+
+
+   return MMAL_SUCCESS;
+
+ error:
+   if (waitpool_initialised)
+      destroy_waitpool(&client.waitpool);
+   if (service_initialised)
+   {
+      client.usecount = 0;
+      vchiq_close_service(client.service);
+   }
+   if (vchiq_initialised)
+      vchiq_shutdown(mmal_vchiq_instance);
+   vcos_log_unregister(VCOS_LOG_CATEGORY);
+   client.refcount--;
+
+   vcos_mutex_unlock(&client.lock);
+   return status;
+}
+
+MMAL_STATUS_T mmal_vc_init(void)
+{
+   return mmal_vc_init_fd(-1);
+}
+
+void mmal_vc_deinit(void)
+{
+   int count;
+
+   vcos_mutex_lock(&client.lock);
+   count = --client.refcount;
+   if (count != 0)
+   {
+      /* Still in use so don't do anything */
+      vcos_mutex_unlock(&client.lock);
+      return;
+   }
+
+   vcos_mutex_delete(&client.bulk_lock);
+   destroy_waitpool(&client.waitpool);
+   vchiq_close_service(client.service);
+   vchiq_shutdown(mmal_vchiq_instance);
+   vcos_log_unregister(VCOS_LOG_CATEGORY);
+
+   client.service = VCHIQ_SERVICE_HANDLE_INVALID;
+   client.inited = 0;
+   vcos_mutex_unlock(&client.lock);
+}
+
+MMAL_CLIENT_T *mmal_vc_get_client(void)
+{
+   return &client;
+}
diff --git a/interface/mmal/vc/mmal_vc_client_priv.h b/interface/mmal/vc/mmal_vc_client_priv.h
new file mode 100755 (executable)
index 0000000..0fc3aaa
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_VC_CLIENT_H
+#define MMAL_VC_CLIENT_H
+
+/** @file mmal_vc_client_priv.h
+  *
+  * Internal API for vchiq_arm MMAL client.
+  */
+
+struct MMAL_CLIENT_T;
+typedef struct MMAL_CLIENT_T MMAL_CLIENT_T;
+
+void mmal_vc_client_init(void);
+
+/** Hold the context required when sending a buffer to the copro.
+ */
+typedef struct MMAL_VC_CLIENT_BUFFER_CONTEXT_T
+{
+   uint32_t magic;
+
+   /** Called when VC is done with the buffer */
+   void (*callback)(struct mmal_worker_buffer_from_host *);
+
+   /** Called when VC sends an event */
+   void (*callback_event)(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *event);
+
+   /** The port this buffer was sent to */
+   MMAL_PORT_T *port;
+
+   /** The original buffer from the host. */
+   MMAL_BUFFER_HEADER_T *buffer;
+
+   /** The actual message sent to the host */
+   struct mmal_worker_buffer_from_host msg;
+} MMAL_VC_CLIENT_BUFFER_CONTEXT_T;
+
+
+MMAL_CLIENT_T *mmal_vc_get_client(void);
+
+MMAL_STATUS_T mmal_vc_sendwait_message(MMAL_CLIENT_T *client,
+                                       mmal_worker_msg_header *header,
+                                       size_t size,
+                                       uint32_t msgid,
+                                       void *dest,
+                                       size_t *destlen,
+                                       MMAL_BOOL_T send_dummy_bulk);
+
+MMAL_STATUS_T mmal_vc_send_message(MMAL_CLIENT_T *client,
+                                   mmal_worker_msg_header *header, size_t size,
+                                   uint8_t *data, size_t data_size,
+                                   uint32_t msgid);
+
+#endif
+
diff --git a/interface/mmal/vc/mmal_vc_dbglog.h b/interface/mmal/vc/mmal_vc_dbglog.h
new file mode 100755 (executable)
index 0000000..0008bc4
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** \file
+ * Multi-Media Abstraction Layer API
+ */
+#ifndef MMAL_VC_DBGLOG_H
+#define MMAL_VC_DBGLOG_H
+
+#include "interface/mmal/mmal.h"
+#include "mmal_vc_msgs.h"
+
+/* Debug log for MMAL messages going past */
+
+typedef enum {
+   MMAL_DBG_MSG,
+   MMAL_DBG_BULK,
+   MMAL_DBG_OPENED,
+   MMAL_DBG_CLOSED,
+   MMAL_DBG_BULK_ACK,
+   MMAL_DBG_BULK_TX,
+   MMAL_DBG_BULK_RX,
+} MMAL_DBG_EVENT_TYPE_T;
+
+
+/** Debug log data. */
+typedef union
+{
+   struct {
+      mmal_worker_msg_header header;
+      uint32_t msg[4];     /**< Snarf this much message data */
+   } msg;
+
+   struct {
+      uint32_t len;        /**< Length of transfer */
+      uint32_t data[4];    /**< Snarf this much payload data */
+   } bulk;
+
+   uint32_t uint;
+
+   uint32_t arr[15];       /** Pad complete DBG_ENTRY_T to 64 bytes per line */
+
+} MMAL_DBG_DATA_T;
+
+/** One entry in the debug log */
+typedef struct
+{
+   uint32_t time;
+   uint32_t event_type;
+   MMAL_DBG_DATA_T u;
+} MMAL_DBG_ENTRY_T;
+
+#define MMAL_DBG_ENTRIES_MAX  64
+#define MMAL_DBG_ENTRIES_MASK (MMAL_DBG_ENTRIES_MAX-1)
+#define MMAL_DBG_VERSION  1
+
+/** The debug log itself. This is currently allocated in uncached
+  * memory so that the ARM can easily access it.
+  */
+typedef struct
+{
+   uint32_t version;
+   uint32_t magic;
+   uint32_t num_entries;
+   uint32_t index;
+   uint32_t size;
+   uint32_t elemsize;
+   uint32_t pad[2];
+   MMAL_DBG_ENTRY_T entries[MMAL_DBG_ENTRIES_MAX];
+
+} MMAL_DBG_LOG_T;
+
+extern VCOS_MUTEX_T mmal_dbg_lock;
+extern MMAL_DBG_LOG_T *mmal_dbg_log;
+
+/** Get the next event and hold the lock. Should only be
+  * accessed by the macros below.
+  */
+static inline MMAL_DBG_ENTRY_T *mmal_log_lock_event(MMAL_DBG_EVENT_TYPE_T event_type ) {
+   uint32_t index;
+   MMAL_DBG_ENTRY_T *entry;
+   vcos_mutex_lock(&mmal_dbg_lock);
+   index = mmal_dbg_log->index++;
+   entry = mmal_dbg_log->entries + (index & MMAL_DBG_ENTRIES_MASK);
+   entry->time = vcos_getmicrosecs();
+   entry->event_type = event_type;
+   return entry;
+}
+
+/** Release the lock. Should only be accessed by the macros below. */
+static inline void mmal_log_unlock_event(void) {
+   vcos_mutex_unlock(&mmal_dbg_lock);
+}
+
+/** Initialise the logging module. */
+MMAL_STATUS_T mmal_vc_dbglog_init(void);
+
+/** Deinitialise the logging module. */
+void mmal_vc_dbglog_deinit(void);
+
+/** Put an entry into the log.
+  *
+  * @param short_type  type of event, e.g. OPENED
+  * @param name        union entry name,  e.g. uint.
+  * @param event       event data
+  */
+#define MMAL_LOG_EVENT(short_type, name, value)  {\
+   MMAL_DBG_ENTRY_T *entry = mmal_log_lock_event(MMAL_DBG_##short_type); \
+   entry->u.name = value;\
+   mmal_log_unlock_event(); \
+}
+
+/** Log an uint event (i.e. all just the fact that it occurred */
+#define LOG_EVENT_UINT(short_type,u) MMAL_LOG_EVENT(short_type, uint, u)
+
+#define LOG_EVENT_OPENED()         LOG_EVENT_UINT(OPENED,0)
+#define LOG_EVENT_CLOSED()         LOG_EVENT_UINT(CLOSED,0)
+#define LOG_EVENT_BULK_ACK(reason) LOG_EVENT_UINT(BULK_ACK,reason)
+
+/** Log a message. Grabs part of the message data.
+  */
+#define LOG_EVENT_MSG(header) {\
+   MMAL_DBG_ENTRY_T *entry = mmal_log_lock_event(MMAL_DBG_MSG); \
+   memcpy(&entry->u.msg, header, sizeof(entry->u.msg)); \
+   mmal_log_unlock_event(); \
+}
+
+/** Log bulk data. For now, do not grab the actual data itself */
+#define LOG_EVENT_BULK(type, len, data) {\
+   MMAL_DBG_ENTRY_T *entry = mmal_log_lock_event(MMAL_DBG_BULK_##type); \
+   entry->u.bulk.len = len; \
+   mmal_log_unlock_event(); \
+}
+
+
+#endif
diff --git a/interface/mmal/vc/mmal_vc_diag.c b/interface/mmal/vc/mmal_vc_diag.c
new file mode 100755 (executable)
index 0000000..e9712af
--- /dev/null
@@ -0,0 +1,880 @@
+/*
+Copyright (c) 2013, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/mmal/mmal.h"
+#include "interface/mmal/util/mmal_util.h"
+#include "mmal_vc_api.h"
+#include <stdio.h>
+#include <stddef.h>
+#include <sys/time.h>
+#include <limits.h>
+#ifdef __ANDROID__
+#include <android/log.h>
+#endif
+#include "host_applications/linux/libs/debug_sym/debug_sym.h"
+#include "mmal_vc_msgnames.h"
+#include "mmal_vc_dbglog.h"
+#include "vchiq.h"
+#include "interface/vmcs_host/vc_imageconv_defs.h"
+
+/** Command-line diagnostics at the VC MMAL API level.
+  *
+  * @fixme: how does this work with multiple videocores?
+  */
+
+struct cmd {
+   const char *name;
+   int (*pfn)(int argc, const char **argv);
+   const char *descr;
+   int flags;
+};
+
+#define CONNECT 1
+
+static int do_commands(int argc, const char **argv);
+static int do_version(int argc, const char **argv);
+static int do_stats(int argc, const char **argv);
+static int do_usage(int argc, const char **argv);
+static int do_create(int argc, const char **argv);
+static int do_eventlog(int argc, const char **argv);
+static int do_components(int argc, const char **argv);
+static int do_mmal_stats(int argc, const char **argv);
+static int do_imageconv_stats(int argc, const char **argv);
+static int do_compact(int argc, const char **argv);
+static int do_autosusptest(int argc, const char **argv);
+static int do_camerainfo(int argc, const char **argv);
+static int do_host_log(int argc, const char **argv);
+static int do_host_log_write(int argc, const char **argv);
+
+static struct cmd cmds[] = {
+   { "help",       do_usage, "give this help", 0 },
+   { "version",    do_version, "report VC MMAL server version number", CONNECT },
+   { "stats",      do_stats, "report VC MMAL statistics", CONNECT },
+   { "reset",      do_stats, "reset VC MMAL statistics", CONNECT },
+   { "commands",   do_commands, "list available commands", CONNECT },
+   { "create",     do_create, "create a component", CONNECT },
+   { "eventlog",   do_eventlog, "display event log", 0 },
+   { "components", do_components, "[update] list components", 0 },
+   { "mmal-stats", do_mmal_stats, "list mmal core stats", CONNECT },
+   { "ic-stats",   do_imageconv_stats, "[reset] list imageconv stats", CONNECT },
+   { "compact",    do_compact, "trigger memory compaction", CONNECT },
+   { "autosusp",   do_autosusptest, "test out auto-suspend/resume", CONNECT },
+   { "camerainfo", do_camerainfo, "get camera info", CONNECT },
+   { "host_log",   do_host_log, "dumps the MMAL VC log", CONNECT },
+   { "host_log_write",  do_host_log_write, "appends a message to the MMAL VC log of host messages", CONNECT },
+   { NULL, NULL, NULL, 0},
+};
+
+static void do_connect(void)
+{
+   /* this command needs a vchiq connection */
+   MMAL_STATUS_T st;
+   if ((st = mmal_vc_init()) != MMAL_SUCCESS)
+   {
+      fprintf(stderr, "failed to initialize mmal vc library (%i:%s)\n",
+            st, mmal_status_to_string(st));
+      exit(1);
+   }
+}
+
+int main(int argc, const char **argv)
+{
+   int i;
+
+   if (argc < 2)
+   {
+      do_usage(argc, argv);
+      exit(1);
+   }
+
+   for (i = 0; cmds[i].name; i++)
+   {
+      if (strcasecmp(cmds[i].name, argv[1]) == 0)
+      {
+         int rc;
+         if (cmds[i].flags & CONNECT)
+         {
+            do_connect();
+         }
+         rc = cmds[i].pfn(argc, argv);
+
+         if (cmds[i].flags & CONNECT)
+            mmal_vc_deinit();
+         return rc;
+      }
+   }
+   fprintf(stderr,"unknown command %s\n", argv[1]);
+   return -1;
+}
+
+static int do_commands(int argc, const char **argv)
+{
+   int i = 0;
+   (void)argc; (void)argv;
+   while (cmds[i].name)
+   {
+      printf("%-20s %s\n", cmds[i].name, cmds[i].descr);
+      i++;
+   }
+   return 0;
+}
+
+static int do_create(int argc, const char **argv)
+{
+   MMAL_COMPONENT_T *comp;
+   MMAL_STATUS_T st;
+   if (argc != 3)
+   {
+      printf("usage: mmal-vc-diag create <name>\n");
+      printf("   e.g. vc.camera\n");
+      exit(1);
+   }
+   st = mmal_component_create(argv[2], &comp);
+   if (comp)
+      printf("Created component\n");
+   else
+      printf("Failed to create %s: %d\n", argv[2], st);
+
+   return 0;
+}
+
+static int do_version(int argc, const char **argv)
+{
+   uint32_t maj = UINT_MAX, min = UINT_MAX, minimum;
+   MMAL_STATUS_T st = mmal_vc_get_version(&maj, &min, &minimum);
+   (void)argc; (void)argv;
+   if (st == MMAL_SUCCESS)
+   {
+      printf("version %d.%02d (min %d)\n", maj, min, minimum);
+      return 0;
+   }
+   else
+   {
+      fprintf(stderr, "error getting version (%i:%s)\n", st, mmal_status_to_string(st));
+      return -1;
+   }
+}
+
+#define STATS_FIELD(x) { #x, offsetof(MMAL_VC_STATS_T, x) }
+
+static struct {
+   const char *name;
+   unsigned offset;
+} stats_fields [] = {
+   STATS_FIELD(buffers.rx),
+   STATS_FIELD(buffers.rx_zero_copy),
+   STATS_FIELD(buffers.rx_empty),
+   STATS_FIELD(buffers.rx_fails),
+   STATS_FIELD(buffers.tx),
+   STATS_FIELD(buffers.tx_zero_copy),
+   STATS_FIELD(buffers.tx_empty),
+   STATS_FIELD(buffers.tx_fails),
+   STATS_FIELD(buffers.tx_short_msg),
+   STATS_FIELD(buffers.rx_short_msg),
+   STATS_FIELD(service.created),
+   STATS_FIELD(service.pending_destroy),
+   STATS_FIELD(service.destroyed),
+   STATS_FIELD(service.failures),
+   STATS_FIELD(commands.bad_messages),
+   STATS_FIELD(commands.executed),
+   STATS_FIELD(commands.failed),
+   STATS_FIELD(commands.replies),
+   STATS_FIELD(commands.reply_fails),
+   STATS_FIELD(events.tx),
+   STATS_FIELD(events.tx_fails),
+   STATS_FIELD(worker.enqueued_messages),
+   STATS_FIELD(worker.dequeued_messages),
+   STATS_FIELD(worker.max_parameter_set_delay),
+   STATS_FIELD(worker.max_messages_waiting)
+};
+
+static int do_stats(int argc, const char **argv)
+{
+   MMAL_VC_STATS_T stats;
+   int reset_stats = strcasecmp(argv[1], "reset") == 0;
+   MMAL_STATUS_T st = mmal_vc_get_stats(&stats, reset_stats);
+   int ret;
+   (void)argc; (void)argv;
+   if (st != MMAL_SUCCESS)
+   {
+      fprintf(stderr, "error getting status (%i,%s)\n", st, mmal_status_to_string(st));
+      ret = -1;
+   }
+   else
+   {
+      unsigned i;
+      uint32_t *ptr = (uint32_t*)&stats;
+      for (i=0; i<vcos_countof(stats_fields); i++)
+      {
+         printf("%-32s: %u\n", stats_fields[i].name, ptr[stats_fields[i].offset/sizeof(uint32_t)]);
+      }
+      ret = 0;
+   }
+   return ret;
+}
+
+static int do_usage(int argc, const char **argv)
+{
+   const char *last_slash = strrchr(argv[0], '/');
+   const char *progname = last_slash ? last_slash+1:argv[0];
+   (void)argc;
+   printf("usage: %s [command [args]]\n", progname);
+   printf("   %s commands - list available commands\n", progname);
+   return 0;
+}
+
+/*
+ * Print out the event log
+ */
+
+struct event_handler
+{
+   MMAL_DBG_EVENT_TYPE_T type;
+   void (*handler)(MMAL_DBG_ENTRY_T *entry, char *, size_t);
+};
+
+static void on_openclose(MMAL_DBG_ENTRY_T *entry,
+                         char *buf,
+                         size_t buflen)
+{
+   switch (entry->event_type) {
+      case MMAL_DBG_OPENED: snprintf(buf,buflen,"opened"); break;
+      case MMAL_DBG_CLOSED: snprintf(buf,buflen,"closed"); break;
+      default: break;
+   }
+}
+
+static void on_bulk_ack(MMAL_DBG_ENTRY_T *entry,
+                        char *buf,
+                        size_t buflen)
+{
+   switch (entry->u.uint)
+   {
+   case VCHIQ_BULK_RECEIVE_ABORTED: snprintf(buf,buflen,"vchiq bulk rx abort"); break;
+   case VCHIQ_BULK_TRANSMIT_ABORTED: snprintf(buf,buflen,"vchiq bulk tx abort"); break;
+   case VCHIQ_BULK_TRANSMIT_DONE: snprintf(buf,buflen,"vchiq bulk tx done"); break;
+   case VCHIQ_BULK_RECEIVE_DONE: snprintf(buf,buflen,"vchiq bulk rx done"); break;
+   default: snprintf(buf,buflen,"vchiq unknown reason %d", entry->u.uint); break;
+   }
+}
+
+static void on_msg(MMAL_DBG_ENTRY_T *entry,
+                   char *buf,
+                   size_t buflen)
+{
+   uint32_t id = entry->u.msg.header.msgid;
+   snprintf(buf,buflen,"msgid %d (%s)", id, mmal_msgname(id));
+}
+
+static void on_bulk(MMAL_DBG_ENTRY_T *entry,
+                    char *buf,
+                    size_t buflen)
+{
+   const char *name = entry->event_type == MMAL_DBG_BULK_TX ? "tx" : "rx";
+   snprintf(buf,buflen,"bulk %s len %d", name, entry->u.bulk.len);
+}
+
+static struct event_handler handlers[] = {
+   { MMAL_DBG_OPENED, on_openclose },
+   { MMAL_DBG_CLOSED, on_openclose },
+   { MMAL_DBG_BULK_ACK, on_bulk_ack },
+   { MMAL_DBG_MSG, on_msg },
+   { MMAL_DBG_BULK_TX, on_bulk },
+   { MMAL_DBG_BULK_RX, on_bulk },
+};
+static int n_handlers = sizeof(handlers)/sizeof(handlers[0]);
+
+static void print_mmal_event_log(VC_MEM_ACCESS_HANDLE_T vc, MMAL_DBG_LOG_T *log)
+{
+   uint32_t i;
+   uint32_t n = vcos_min(log->num_entries, log->index);
+   uint32_t mask = log->num_entries-1;
+   uint32_t start = log->index < log->num_entries ?
+      0 : log->index & mask;
+   uint32_t last_t = 0;
+   (void)vc;
+
+   for (i=0; i<n; i++)
+   {
+      MMAL_DBG_ENTRY_T *e = &log->entries[(start+i) & mask];
+      char buf[256];
+      int j;
+      uint32_t t = e->time;
+      printf("[%08u]: ", t-last_t);
+      last_t = t;
+      for (j=0; j<n_handlers; j++)
+      {
+         if (handlers[j].type == e->event_type)
+         {
+            handlers[j].handler(e, buf, sizeof(buf));
+            printf("%s\n", buf);
+            break;
+         }
+      }
+      if (j == n_handlers )
+         printf("Unknown event type %d\n", e->event_type);
+   }
+}
+
+static int do_eventlog(int argc, const char **argv)
+{
+   VC_MEM_ACCESS_HANDLE_T vc;
+   VC_MEM_ADDR_T addr;     /** The address of the pointer to the log */
+   size_t size;
+   VC_MEM_ADDR_T logaddr;       /** The address of the log itself */
+   MMAL_DBG_LOG_T log;
+
+   (void)argc; (void)argv;
+   int rc;
+   if ((rc = OpenVideoCoreMemory(&vc)) < 0)
+   {
+      fprintf(stderr,"Unable to open videocore memory: %d\n", rc);
+      return -1;
+   }
+   if (!LookupVideoCoreSymbol(vc, "mmal_dbg_log", &addr, &size))
+   {
+      fprintf(stderr,"Could not get MMAL log address\n");
+      goto fail;
+   }
+   if (!ReadVideoCoreUInt32(vc, &logaddr, addr))
+   {
+      fprintf(stderr,"Could not read MMAL log pointer at address 0x%x\n",
+              addr);
+      goto fail;
+   }
+   if (!ReadVideoCoreMemory(vc, &log, logaddr, sizeof(log)))
+   {
+      fprintf(stderr,"Could not read MMAL log at address 0x%x\n",
+              logaddr);
+      goto fail;
+   }
+   if (log.magic != MMAL_MAGIC)
+   {
+      fprintf(stderr,"Bad magic 0x%08x in log at 0x%x\n", log.magic, logaddr);
+      goto fail;
+   }
+   if (log.size != sizeof(log))
+   {
+      fprintf(stderr,"MMAL Log size mismatch (got %d, expected %d)\n",
+              log.size, sizeof(log));
+      goto fail;
+   }
+   if (log.elemsize != sizeof(MMAL_DBG_ENTRY_T))
+   {
+      fprintf(stderr,"MMAL log element size mismatch (got %d, expected %d)\n",
+              log.elemsize, sizeof(MMAL_DBG_ENTRY_T));
+      goto fail;
+   }
+
+   printf("reading MMAL log at 0x%x version %d magic %x\n",
+          logaddr, log.version, log.magic);
+   printf("%d events, %d entries each size %d\n", log.index, log.num_entries,
+          log.elemsize);
+   print_mmal_event_log(vc, &log);
+
+   CloseVideoCoreMemory(vc);
+   return 0;
+fail:
+   CloseVideoCoreMemory(vc);
+   return -1;
+
+}
+
+static int print_component_stats(const MMAL_VC_STATS_T *stats)
+{
+   size_t i;
+   if (stats->components.list_size > 64)
+   {
+      fprintf(stderr,"component array looks corrupt (list size %d\n",
+            stats->components.list_size);
+      goto fail;
+   }
+   printf("%d created, %d destroyed (%d destroying), %d create failures\n",
+         stats->components.created,
+         stats->components.destroyed,
+         stats->components.destroying,
+         stats->components.failed);
+
+   for (i=0; i < stats->components.list_size; i++)
+   {
+      const struct MMAL_VC_COMP_STATS_T *cs = stats->components.component_list+i;
+      const char *state;
+      /* coverity[overrun-local] */
+      if (cs->state != MMAL_STATS_COMP_IDLE)
+      {
+         switch (cs->state)
+         {
+            case MMAL_STATS_COMP_CREATED: state = "created"; break;
+            case MMAL_STATS_COMP_DESTROYING: state = "destroying"; break;
+            case MMAL_STATS_COMP_DESTROYED: state = "destroyed"; break;
+            default: state = "corrupt"; break;
+         }
+         printf("%-32s: %s: pid %d address %p pool mem alloc size %d\n",
+               cs->name, state, cs->pid, cs->comp, cs->pool_mem_alloc_size);
+      }
+   }
+   return 0;
+fail:
+   return -1;
+}
+
+static int do_components(int argc, const char **argv)
+{
+   VC_MEM_ACCESS_HANDLE_T vc;
+   VC_MEM_ADDR_T addr, statsaddr;
+   size_t size;
+   MMAL_VC_STATS_T stats;
+   int rc;
+
+
+   if (argc > 2 && (strcasecmp(argv[2], "update") == 0))
+   {
+      MMAL_STATUS_T status;
+      do_connect();
+      status = mmal_vc_get_stats(&stats, 0);
+      if (status != MMAL_SUCCESS)
+      {
+         fprintf(stderr, "Failed to update MMAL stats. error %s",
+              mmal_status_to_string(status));
+         return -1;
+      }
+   }
+   else
+   {
+      if ((rc = OpenVideoCoreMemory(&vc)) < 0)
+      {
+         fprintf(stderr,"Unable to open videocore memory: %d\n", rc);
+         return -1;
+      }
+      if (!LookupVideoCoreSymbol(vc, "mmal_vc_stats", &addr, &size))
+      {
+         fprintf(stderr,"Could not get MMAL stats address\n");
+         goto fail;
+      }
+      if (!ReadVideoCoreUInt32(vc, &statsaddr, addr))
+      {
+         fprintf(stderr,"Could not read MMAL stats pointer at address 0x%x\n",
+               addr);
+         goto fail;
+      }
+      if (!ReadVideoCoreMemory(vc, &stats, statsaddr, sizeof(stats)))
+      {
+         fprintf(stderr,"Could not read MMAL stats at address 0x%x\n", addr);
+         goto fail;
+      }
+      CloseVideoCoreMemory(vc);
+   }
+   rc = print_component_stats(&stats);
+   return rc;
+
+fail:
+   CloseVideoCoreMemory(vc);
+   return -1;
+}
+
+static int do_mmal_stats(int argc, const char **argv)
+{
+   unsigned comp_index = 0;
+   MMAL_BOOL_T more_ports = MMAL_TRUE, reset = MMAL_FALSE;
+   unsigned port_index = 0;
+   MMAL_PORT_TYPE_T type = MMAL_PORT_TYPE_INPUT;
+
+   if (argc >= 3)
+      reset = strcasecmp(argv[2], "reset") == 0;
+
+   printf("component\t\tport\t\tbuffers\t\tfps\tdelay\n");
+   while (more_ports)
+   {
+      int dir;
+      const char *dirnames[] = {"rx","tx"};
+      MMAL_STATS_RESULT_T result;
+
+      for (dir = MMAL_CORE_STATS_RX; dir <= MMAL_CORE_STATS_TX; dir++)
+      {
+         double framerate;
+         MMAL_CORE_STATISTICS_T stats;
+         char name[32];
+         MMAL_STATUS_T status = mmal_vc_get_core_stats(&stats,
+                                                      &result,
+                                                      name, sizeof(name),
+                                                      type,
+                                                      comp_index,
+                                                      port_index,
+                                                      dir,
+                                                      reset);
+         if (status != MMAL_SUCCESS)
+         {
+            fprintf(stderr, "could not get core stats: %s\n",
+                  mmal_status_to_string(status));
+            exit(1);
+         }
+
+         if (result == MMAL_STATS_FOUND)
+         {
+            if (stats.first_buffer_time == stats.last_buffer_time)
+               framerate = 0;
+            else
+               framerate = 1.0e6*(1+stats.buffer_count)/(stats.last_buffer_time-stats.first_buffer_time);
+
+            printf("%-20s\t%d [%s]%2s\t%-10d\t%4.1f\t%d\n",
+                  name, port_index,
+                  type == MMAL_PORT_TYPE_INPUT ? "in " : "out",
+                  dirnames[dir],
+                  stats.buffer_count, framerate, stats.max_delay);
+
+         }
+      }
+
+      switch (result)
+      {
+      case MMAL_STATS_FOUND:
+         port_index++;
+         break;
+
+      case MMAL_STATS_COMPONENT_NOT_FOUND:
+         more_ports = MMAL_FALSE;
+         break;
+
+      case MMAL_STATS_PORT_NOT_FOUND:
+         port_index = 0;
+         if (type == MMAL_PORT_TYPE_INPUT)
+         {
+            type = MMAL_PORT_TYPE_OUTPUT;
+         }
+         else
+         {
+            type = MMAL_PORT_TYPE_INPUT;
+            comp_index++;
+         }
+         break;
+      default:
+         fprintf(stderr, "bad result from query: %d\n", result);
+         vcos_assert(0);
+         exit(1);
+      }
+   }
+   return 0;
+}
+
+static int do_imageconv_stats(int argc, const char **argv)
+{
+   VC_MEM_ACCESS_HANDLE_T vc;
+   VC_MEM_ADDR_T addr, statsaddr;
+   size_t size;
+   IMAGECONV_STATS_T stats;
+   long convert_time;
+   double frame_rate;
+   int rc;
+   int reset_stats = 0;
+
+   if (argc > 2)
+      reset_stats = strcasecmp(argv[2], "reset") == 0;
+
+   if ((rc = OpenVideoCoreMemory(&vc)) < 0)
+   {
+      fprintf(stderr,"Unable to open videocore memory: %d\n", rc);
+      return -1;
+   }
+   if (!LookupVideoCoreSymbol(vc, "imageconv_stats", &addr, &size))
+   {
+      fprintf(stderr,"Could not get imageconv stats address\n");
+      goto fail;
+   }
+   if (!ReadVideoCoreUInt32(vc, &statsaddr, addr))
+   {
+      fprintf(stderr, "Could not read imageconv stats address\n");
+      goto fail;
+   }
+
+   if (reset_stats)
+   {
+      memset(&stats, 0, sizeof(stats));
+      stats.magic = IMAGECONV_STATS_MAGIC;
+      if (!WriteVideoCoreMemory(vc, &stats, statsaddr, sizeof(stats)))
+      {
+         fprintf(stderr, "Could not write stats at 0x%x\n", statsaddr);
+         goto fail;
+      }
+   }
+
+   if (!ReadVideoCoreMemory(vc, &stats, statsaddr, sizeof(stats)))
+   {
+      fprintf(stderr, "Could not read stats at 0x%x\n", statsaddr);
+      goto fail;
+   }
+
+   if (stats.magic != IMAGECONV_STATS_MAGIC)
+   {
+      fprintf(stderr, "Bad magic 0x%x\n", stats.magic);
+      goto fail;
+   }
+
+   if (stats.conversions)
+      convert_time = stats.time_spent / stats.conversions;
+   else
+      convert_time = 0;
+
+   if (stats.conversions)
+      frame_rate = 1000000.0 * stats.conversions /
+         (stats.last_image_ts - stats.first_image_ts);
+   else
+      frame_rate = 0;
+
+   printf("%-25s:\t%d\n", "conversions", stats.conversions);
+   printf("%-25s:\t%d\n", "size requests", stats.size_requests);
+   printf("%-25s:\t%d\n", "max vrf delay", stats.max_vrf_delay);
+   printf("%-25s:\t%d\n", "vrf wait time", stats.vrf_wait_time);
+   printf("%-25s:\t%d\n", "duplicate conversions", stats.duplicate_conversions);
+   printf("%-25s:\t%d\n", "failures", stats.failures);
+   printf("%-25s:\t%ld\n", "convert time / image (us)", convert_time);
+   printf("%-25s:\t%.1f\n", "client frame_rate", frame_rate);
+   printf("%-25s:\t%d us\n", "max delay to consume", stats.max_delay);
+
+   CloseVideoCoreMemory(vc);
+   return 0;
+fail:
+   CloseVideoCoreMemory(vc);
+   return -1;
+
+}
+
+static int do_compact(int argc, const char **argv)
+{
+   uint32_t duration;
+
+   if (argc > 2)
+   {
+      if (strcmp(argv[2], "a") == 0)
+      {
+         mmal_vc_compact(MMAL_VC_COMPACT_AGGRESSIVE, &duration);
+         printf("Triggered aggressive compaction on VC - duration %u us.\n", duration);
+      }
+      else if (strcmp(argv[2], "d") == 0)
+      {
+         mmal_vc_compact(MMAL_VC_COMPACT_DISCARD, &duration);
+         printf("Triggered discard compaction on VC - duration %u us.\n", duration);
+      }
+      else if (strcmp(argv[2], "n") == 0)
+      {
+         mmal_vc_compact(MMAL_VC_COMPACT_NORMAL, &duration);
+         printf("Triggered normal compaction on VC - duration %u us.\n", duration);
+      }
+      else
+      {
+         printf("Invalid memory compaction option %s\n.", argv[2]);
+         exit(1);
+      }
+   }
+   else
+   {
+      printf("Invalid memory compaction arguments.  Need to specify 'a', 'n' or 't'.\n");
+      exit(1);
+   }
+   return 0;
+}
+
+/* Autosuspend test. Create a component, but kill process
+ * shortly after startup.
+ */
+
+static int autosusp_signal;
+
+static void autosusp_timeout_handler(int cause, siginfo_t *how, void *ucontext)
+{
+   (void)how; (void)ucontext; (void)cause;
+   printf("Sending signal %d\n", autosusp_signal);
+   kill(getpid(), autosusp_signal);
+}
+
+static int do_autosusptest(int argc, const char **argv)
+{
+   long timeout;
+   struct timeval interval;
+   MMAL_STATUS_T status;
+
+   if (argc != 4)
+   {
+      printf("usage: %s autosusp <timeout-ms> <signal>\n",
+             argv[0]);
+      printf("   e.g. 650 9\n");
+      exit(1);
+   }
+   timeout = 1000 * atoi(argv[2]);
+   autosusp_signal = atoi(argv[3]);
+
+   if ((status=mmal_vc_use()) != MMAL_SUCCESS)
+   {
+      fprintf(stderr,"mmal_vc_use failed: %d\n", status);
+      exit(1);
+   }
+
+   /* install a signal handler for the alarm */
+   struct sigaction sa;
+   memset(&sa, 0, sizeof(struct sigaction));
+   sa.sa_sigaction = autosusp_timeout_handler;
+   sigemptyset(&sa.sa_mask);
+   sa.sa_flags = SA_SIGINFO;
+   if (sigaction(SIGALRM, &sa, 0))
+   {
+      perror("sigaction");
+      exit(1);
+   }
+
+   /* when to expire */
+   interval.tv_sec = timeout / 1000000;
+   interval.tv_usec = timeout % 1000000;
+
+   struct itimerval alarm_spec = {
+     .it_interval = {0,0},
+     .it_value = interval
+   };
+
+   int rc = setitimer(ITIMER_REAL, &alarm_spec, NULL);
+   if (rc < 0)
+   {
+      perror("setitimer failed");
+      exit(1);
+   }
+
+   usleep(timeout + 1000000);
+   printf("%s: not killed by timer\n", argv[0]);
+   mmal_vc_release();
+
+   return 0;
+}
+
+static int do_camerainfo(int argc, const char **argv)
+{
+   MMAL_COMPONENT_T *comp;
+   MMAL_STATUS_T st;
+   MMAL_PARAMETER_CAMERA_INFO_T mmal_camera_config_info;
+   unsigned i;
+   (void)argc;
+   (void)argv;
+
+   st = mmal_component_create("vc.camera_info", &comp);
+   if (st != MMAL_SUCCESS)
+   {
+      fprintf(stderr, "Failed to create camera_info: %d\n", st);
+      exit(1);
+   }
+
+   mmal_camera_config_info.hdr.id = MMAL_PARAMETER_CAMERA_INFO;
+   mmal_camera_config_info.hdr.size = sizeof(mmal_camera_config_info);
+   st = mmal_port_parameter_get(comp->control, &mmal_camera_config_info.hdr);
+   if (st != MMAL_SUCCESS)
+   {
+      fprintf(stderr, "%s: get param failed:%d", __FUNCTION__, st);
+      exit(1);
+   }
+
+   printf("cameras  : %d\n", mmal_camera_config_info.num_cameras);
+   printf("flashes  : %d\n", mmal_camera_config_info.num_flashes);
+
+   for (i=0; i<mmal_camera_config_info.num_cameras; i++)
+   {
+      printf("camera %u : port %u: %u x %u lens %s\n",
+             i,
+             mmal_camera_config_info.cameras[i].port_id,
+             mmal_camera_config_info.cameras[i].max_width,
+             mmal_camera_config_info.cameras[i].max_height,
+             mmal_camera_config_info.cameras[i].lens_present ? "present" : "absent");
+   }
+   for (i=0; i<mmal_camera_config_info.num_flashes; i++)
+   {
+      const char *flash_type;
+      switch (mmal_camera_config_info.flashes[i].flash_type)
+      {
+      case MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_XENON:
+         flash_type = "Xenon";
+         break;
+      case MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_LED:
+         flash_type = "LED";
+         break;
+      case MMAL_PARAMETER_CAMERA_INFO_FLASH_TYPE_OTHER:
+         flash_type = "Other";
+         break;
+      default:
+         flash_type = "invalid";
+      }
+      printf("flash %u  : flash type %s\n", i, flash_type);
+   }
+   mmal_component_destroy(comp);
+   return 0;
+}
+
+static int do_host_log(int argc, const char **argv)
+{
+   VC_MEM_ACCESS_HANDLE_T vc;
+   VC_MEM_ADDR_T log_addr;
+   MMAL_VC_HOST_LOG_T log;
+   const char *msg = &log.buffer[0];
+   const char *log_end = &log.buffer[sizeof(log.buffer)];
+   int rc;
+
+   (void) argc;
+   (void) argv;
+
+   if ((rc = OpenVideoCoreMemory(&vc)) < 0)
+   {
+      fprintf(stderr,"Unable to open videocore memory: %d\n", rc);
+      return -1;
+   }
+   if (!ReadVideoCoreUInt32BySymbol(vc, "mmal_host_log", &log_addr))
+   {
+      fprintf(stderr, "Could not read mmal_host_log address\n");
+      goto fail;
+   }
+   if (!ReadVideoCoreMemory(vc, &log, log_addr, sizeof(log)))
+   {
+      fprintf(stderr, "Could not read log at 0x%x\n", log_addr);
+      goto fail;
+   }
+
+   while (msg < log_end)
+   {
+      if (*msg)
+         msg += printf("%s", msg);
+
+      /* Skip multiple null characters */
+      while (msg < log_end && *msg == 0) ++msg;
+   }
+
+   CloseVideoCoreMemory(vc);
+   return 0;
+
+fail:
+   CloseVideoCoreMemory(vc);
+   return -1;
+}
+
+static int do_host_log_write(int argc, const char **argv)
+{
+   if (argc > 2)
+      mmal_vc_host_log(argv[2]);
+   return 0;
+}
diff --git a/interface/mmal/vc/mmal_vc_msgnames.c b/interface/mmal/vc/mmal_vc_msgnames.c
new file mode 100755 (executable)
index 0000000..052b392
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "mmal_vc_msgnames.h"
+#include "mmal_vc_msgs.h"
+
+/** Convert a message id to a name.
+  */
+const char *mmal_msgname(uint32_t id)
+{
+#define MSGNAME(x) { MMAL_WORKER_##x, #x }
+   static struct {
+      uint32_t id;
+      const char *name;
+   } msgnames[] = {
+      MSGNAME(QUIT),
+      MSGNAME(SERVICE_CLOSED),
+      MSGNAME(GET_VERSION),
+      MSGNAME(COMPONENT_CREATE),
+      MSGNAME(COMPONENT_DESTROY),
+      MSGNAME(COMPONENT_ENABLE),
+      MSGNAME(COMPONENT_DISABLE),
+      MSGNAME(PORT_INFO_GET),
+      MSGNAME(PORT_INFO_SET),
+      MSGNAME(PORT_ACTION),
+      MSGNAME(BUFFER_FROM_HOST),
+      MSGNAME(BUFFER_TO_HOST),
+      MSGNAME(GET_STATS),
+      MSGNAME(PORT_PARAMETER_SET),
+      MSGNAME(PORT_PARAMETER_GET),
+      MSGNAME(EVENT_TO_HOST),
+      MSGNAME(GET_CORE_STATS_FOR_PORT),
+      MSGNAME(OPAQUE_ALLOCATOR),
+      MSGNAME(CONSUME_MEM),
+      MSGNAME(LMK),
+      MSGNAME(OPAQUE_ALLOCATOR_DESC),
+      MSGNAME(DRM_GET_LHS32),
+      MSGNAME(DRM_GET_TIME),
+      MSGNAME(BUFFER_FROM_HOST_ZEROLEN),
+      MSGNAME(PORT_FLUSH),
+      MSGNAME(HOST_LOG),
+      MSGNAME(COMPACT),
+      { 0, NULL },
+   };
+   vcos_static_assert(sizeof(msgnames)/sizeof(msgnames[0]) == MMAL_WORKER_MSG_LAST);
+   int i = 0;
+   while (msgnames[i].name)
+   {
+      if (msgnames[i].id == id)
+         return msgnames[i].name;
+      i++;
+   }
+   return "unknown-message";
+}
diff --git a/interface/mmal/vc/mmal_vc_msgnames.h b/interface/mmal/vc/mmal_vc_msgnames.h
new file mode 100755 (executable)
index 0000000..12a97c7
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_VC_MSGNAMES_H
+#define MMAL_VC_MSGNAMES_H
+
+#include "interface/vcos/vcos.h"
+
+/** Convert a message id to a name.
+  */
+const char *mmal_msgname(uint32_t id);
+
+#endif
diff --git a/interface/mmal/vc/mmal_vc_msgs.h b/interface/mmal/vc/mmal_vc_msgs.h
new file mode 100755 (executable)
index 0000000..343922b
--- /dev/null
@@ -0,0 +1,535 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_VC_MSGS_H
+#define MMAL_VC_MSGS_H
+
+/** @file mmal_vc_msgs.h
+  *
+  * Private message definitions, defining the message API between
+  * the host and VideoCore.
+  */
+#include "interface/vcos/vcos.h"
+#include "interface/mmal/mmal.h"
+#include "mmal_vc_api.h"
+
+#define MMAL_CONTROL_FOURCC() VCHIQ_MAKE_FOURCC('m','m','a','l')
+
+/* Major version indicates binary backwards compatibility */
+#define WORKER_VER_MAJOR   16
+#define WORKER_VER_MINIMUM 10
+/* Minor version is not used normally.
+ */
+#define WORKER_VER_MINOR   1
+#ifndef WORKER_VER_MINIMUM
+#endif
+
+#define VIDEOCORE_PREFIX "vc"
+
+#define MMAL_MAX_PORTS     8                 /**< Max ports per component */
+
+#define MMAL_WORKER_MAX_MSG_LEN  512
+#define MMAL_VC_CORE_STATS_NAME_MAX      32  /**< Length of the name in the core stats message */
+
+/** A MMAL_CONTROL_SERVICE_T gets space for a single message. This
+  * is the space allocated for these messages.
+  */
+#define MMAL_WORKER_MSG_LEN  28
+
+/** Maximum size of the format extradata.
+ * FIXME: should probably be made bigger and maybe be passed separately from the info.
+ */
+#define MMAL_FORMAT_EXTRADATA_MAX_SIZE 128
+
+/** Size of space reserved in a buffer message for short messages.
+ */
+#define MMAL_VC_SHORT_DATA 128
+
+/** Message ids sent to worker thread.
+  */
+
+/* Please update the array in mmal_vc_msgnames.c if this is updated.
+ */
+typedef enum {
+   MMAL_WORKER_QUIT = 1,
+   MMAL_WORKER_SERVICE_CLOSED,
+   MMAL_WORKER_GET_VERSION,
+   MMAL_WORKER_COMPONENT_CREATE,
+   MMAL_WORKER_COMPONENT_DESTROY,
+   MMAL_WORKER_COMPONENT_ENABLE,
+   MMAL_WORKER_COMPONENT_DISABLE,
+   MMAL_WORKER_PORT_INFO_GET,
+   MMAL_WORKER_PORT_INFO_SET,
+   MMAL_WORKER_PORT_ACTION,
+   MMAL_WORKER_BUFFER_FROM_HOST,
+   MMAL_WORKER_BUFFER_TO_HOST,
+   MMAL_WORKER_GET_STATS,
+   MMAL_WORKER_PORT_PARAMETER_SET,
+   MMAL_WORKER_PORT_PARAMETER_GET,
+   MMAL_WORKER_EVENT_TO_HOST,
+   MMAL_WORKER_GET_CORE_STATS_FOR_PORT,
+   MMAL_WORKER_OPAQUE_ALLOCATOR,
+   /* VC debug mode only - due to security, denial of service implications */
+   MMAL_WORKER_CONSUME_MEM,
+   MMAL_WORKER_LMK,
+   MMAL_WORKER_OPAQUE_ALLOCATOR_DESC,
+   MMAL_WORKER_DRM_GET_LHS32,
+   MMAL_WORKER_DRM_GET_TIME,
+   MMAL_WORKER_BUFFER_FROM_HOST_ZEROLEN,
+   MMAL_WORKER_PORT_FLUSH,
+   MMAL_WORKER_HOST_LOG,
+   MMAL_WORKER_COMPACT,
+   MMAL_WORKER_MSG_LAST
+} MMAL_WORKER_CMD_T;
+
+/** Every message has one of these at the start.
+  */
+typedef struct
+{
+   uint32_t magic;
+   uint32_t msgid;
+   struct MMAL_CONTROL_SERVICE_T *control_service;       /** Handle to the control service */
+
+   union {
+      struct MMAL_WAITER_T *waiter;    /** User-land wait structure, passed back */
+   } u;
+
+   MMAL_STATUS_T status;            /** Result code, passed back */
+   /* Make sure this structure is 64 bit aligned */
+   uint32_t dummy;
+} mmal_worker_msg_header;
+
+/* Make sure mmal_worker_msg_header will preserve 64 bits alignment */
+vcos_static_assert(!(sizeof(mmal_worker_msg_header) & 0x7));
+
+/* Message structures sent to worker thread.
+ */
+
+/** Tell the worker a service has closed. It should start to delete
+  * the associated components.
+  */
+typedef struct
+{
+   mmal_worker_msg_header header;
+} mmal_worker_service_closed;
+vcos_static_assert(sizeof(mmal_worker_service_closed) <= MMAL_WORKER_MSG_LEN);
+
+/** Send from VC to host to report our version */
+typedef struct
+{
+   mmal_worker_msg_header header;
+   uint32_t flags;
+   uint32_t major;
+   uint32_t minor;
+   uint32_t minimum;
+} mmal_worker_version;
+
+/** Request component creation */
+typedef struct
+{
+   mmal_worker_msg_header header;
+   void *client_component;             /** Client component */
+   char name[128];
+   uint32_t pid;                       /**< For debug */
+} mmal_worker_component_create;
+
+/** Reply to component-creation message. Reports back
+  * the number of ports.
+  */
+typedef struct
+{
+   mmal_worker_msg_header header;
+   MMAL_STATUS_T status;
+   uint32_t component_handle;          /** Handle on VideoCore for component */
+   uint32_t input_num;                 /**< Number of input ports */
+   uint32_t output_num;                /**< Number of output ports */
+   uint32_t clock_num;                 /**< Number of clock ports */
+} mmal_worker_component_create_reply;
+vcos_static_assert(sizeof(mmal_worker_component_create_reply) <= MMAL_WORKER_MAX_MSG_LEN);
+
+/** Destroys a component
+  */
+typedef struct
+{
+   mmal_worker_msg_header header;
+   uint32_t component_handle;          /**< which component */
+} mmal_worker_component_destroy;
+
+/** Enables a component
+  */
+typedef struct
+{
+   mmal_worker_msg_header header;
+   uint32_t component_handle;          /**< which component */
+} mmal_worker_component_enable;
+
+/** Disable a component
+  */
+typedef struct
+{
+   mmal_worker_msg_header header;
+   uint32_t component_handle;          /**< Which component */
+} mmal_worker_component_disable;
+
+/** Component port info. Used to get port info.
+  */
+typedef struct
+{
+   mmal_worker_msg_header header;
+   uint32_t component_handle;          /**< Which component */
+   MMAL_PORT_TYPE_T port_type;         /**< Type of port */
+   uint32_t index;                     /**< Which port of given type to get */
+} mmal_worker_port_info_get;
+vcos_static_assert(sizeof(mmal_worker_port_info_get) <= MMAL_WORKER_MAX_MSG_LEN);
+
+/** Component port info. Used to set port info.
+  */
+typedef struct
+{
+   mmal_worker_msg_header header;
+   uint32_t component_handle;          /**< Which component */
+   MMAL_PORT_TYPE_T port_type;         /**< Type of port */
+   uint32_t index;                     /**< Which port of given type to get */
+   MMAL_PORT_T port;
+   MMAL_ES_FORMAT_T format;
+   MMAL_ES_SPECIFIC_FORMAT_T es;
+   uint8_t  extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
+} mmal_worker_port_info_set;
+vcos_static_assert(sizeof(mmal_worker_port_info_set) <= MMAL_WORKER_MAX_MSG_LEN);
+
+/** Report port info back in response to a get / set. */
+typedef struct
+{
+   mmal_worker_msg_header header;
+   MMAL_STATUS_T status;               /**< Result of query */
+   uint32_t component_handle;          /**< Which component */
+   MMAL_PORT_TYPE_T port_type;         /**< Type of port */
+   uint32_t index;                     /**< Which port of given type to get */
+   int32_t found;                      /**< Did we find anything? */
+   uint32_t port_handle;               /**< Handle to use for this port */
+   MMAL_PORT_T port;
+   MMAL_ES_FORMAT_T format;
+   MMAL_ES_SPECIFIC_FORMAT_T es;
+   uint8_t  extradata[MMAL_FORMAT_EXTRADATA_MAX_SIZE];
+} mmal_worker_port_info;
+vcos_static_assert(sizeof(mmal_worker_port_info) <= MMAL_WORKER_MAX_MSG_LEN);
+
+typedef struct
+{
+   mmal_worker_msg_header header;
+   MMAL_STATUS_T status;
+} mmal_worker_reply;
+
+typedef struct
+{
+   mmal_worker_msg_header header;
+   MMAL_STATUS_T status;
+   uint8_t secret[32];
+} mmal_worker_drm_get_lhs32_reply;
+vcos_static_assert(sizeof(mmal_worker_drm_get_lhs32_reply) <= MMAL_WORKER_MAX_MSG_LEN);
+
+typedef struct
+{
+   mmal_worker_msg_header header;
+   MMAL_STATUS_T status;
+   uint32_t time;
+} mmal_worker_drm_get_time_reply;
+vcos_static_assert(sizeof(mmal_worker_drm_get_time_reply) <= MMAL_WORKER_MAX_MSG_LEN);
+
+/** List of actions for a port */
+enum MMAL_WORKER_PORT_ACTIONS
+{
+   MMAL_WORKER_PORT_ACTION_UNKNOWN = 0,        /**< Unknown action */
+   MMAL_WORKER_PORT_ACTION_ENABLE,             /**< Enable a port */
+   MMAL_WORKER_PORT_ACTION_DISABLE,            /**< Disable a port */
+   MMAL_WORKER_PORT_ACTION_FLUSH,              /**< Flush a port */
+   MMAL_WORKER_PORT_ACTION_CONNECT,            /**< Connect 2 ports together */
+   MMAL_WORKER_PORT_ACTION_DISCONNECT,         /**< Disconnect 2 ports connected together */
+   MMAL_WORKER_PORT_ACTION_SET_REQUIREMENTS,   /**< Set buffer requirements  */
+   MMAL_WORKER_PORT_ACTION_MAX = 0x7fffffff    /**< Make the enum 32bits */
+};
+
+/** Trigger an action on a port.
+  */
+typedef struct
+{
+   mmal_worker_msg_header header;
+   uint32_t component_handle;
+   uint32_t port_handle;
+   enum MMAL_WORKER_PORT_ACTIONS action;
+
+   /** Action parameter */
+   union {
+      struct {
+         MMAL_PORT_T port;
+      } enable;
+      struct {
+         uint32_t component_handle;
+         uint32_t port_handle;
+      } connect;
+   } param;
+
+} mmal_worker_port_action;
+vcos_static_assert(sizeof(mmal_worker_port_action) <= MMAL_WORKER_MAX_MSG_LEN);
+
+#define MMAL_WORKER_PORT_PARAMETER_SPACE      96
+
+#define MMAL_WORKER_PORT_PARAMETER_SET_MAX \
+   (MMAL_WORKER_PORT_PARAMETER_SPACE*sizeof(uint32_t)+sizeof(MMAL_PARAMETER_HEADER_T))
+
+#define MMAL_WORKER_PORT_PARAMETER_GET_MAX   MMAL_WORKER_PORT_PARAMETER_SET_MAX
+
+/** Component port parameter set. Doesn't include space for the parameter data.
+  */
+typedef struct
+{
+   mmal_worker_msg_header header;
+   uint32_t component_handle;          /**< Which component */
+   uint32_t port_handle;               /**< Which port */
+   MMAL_PARAMETER_HEADER_T param;      /**< Parameter ID and size */
+   uint32_t space[MMAL_WORKER_PORT_PARAMETER_SPACE];
+} mmal_worker_port_param_set;
+vcos_static_assert(sizeof(mmal_worker_port_param_set) <= MMAL_WORKER_MAX_MSG_LEN);
+
+/** Component port parameter get.
+  */
+typedef struct
+{
+   mmal_worker_msg_header header;
+   uint32_t component_handle;          /**< Which component */
+   uint32_t port_handle;               /**< Which port */
+   MMAL_PARAMETER_HEADER_T param;      /**< Parameter ID and size */
+   uint32_t space[MMAL_WORKER_PORT_PARAMETER_SPACE];
+} mmal_worker_port_param_get;
+vcos_static_assert(sizeof(mmal_worker_port_param_get) <= MMAL_WORKER_MAX_MSG_LEN);
+
+typedef struct
+{
+   mmal_worker_msg_header header;
+   uint32_t component_handle;          /**< Which component */
+   uint32_t port_handle;               /**< Which port */
+   MMAL_PARAMETER_HEADER_T param;      /**< Parameter ID and size */
+} mmal_worker_port_param_get_old;
+
+/** Component port parameter get reply. Doesn't include space for the parameter data.
+  */
+typedef struct
+{
+   mmal_worker_msg_header header;
+   MMAL_STATUS_T status;               /**< Status of mmal_port_parameter_get call */
+   MMAL_PARAMETER_HEADER_T param;      /**< Parameter ID and size */
+   uint32_t space[MMAL_WORKER_PORT_PARAMETER_SPACE];
+} mmal_worker_port_param_get_reply;
+vcos_static_assert(sizeof(mmal_worker_port_param_get_reply) <= MMAL_WORKER_MAX_MSG_LEN);
+
+/** Buffer header driver area structure. In the private area
+  * of a buffer header there is a driver area where we can
+  * put values. This structure defines the layout of that.
+  */
+struct MMAL_DRIVER_BUFFER_T
+{
+   uint32_t magic;
+   uint32_t component_handle;    /**< The component this buffer is from */
+   uint32_t port_handle;         /**< Index into array of ports for this component */
+
+   /** Client side uses this to get back to its context structure. */
+   struct MMAL_VC_CLIENT_BUFFER_CONTEXT_T *client_context;
+};
+
+/** Receive a buffer from the host.
+  *
+  * @sa mmal_port_send_buffer()
+  */
+
+typedef struct mmal_worker_buffer_from_host
+{
+   mmal_worker_msg_header header;
+
+   /** Our control data, copied from the buffer header "driver area"
+    * @sa mmal_buffer_header_driver_data().
+    */
+   struct MMAL_DRIVER_BUFFER_T drvbuf;
+
+   /** Referenced buffer control data.
+    * This is set if the buffer is referencing another
+    * buffer as is the case with passthrough ports where
+    * buffers on the output port reference buffers on the
+    * input port. */
+   struct MMAL_DRIVER_BUFFER_T drvbuf_ref;
+
+   /** the buffer header itself */
+   MMAL_BUFFER_HEADER_T buffer_header;
+   MMAL_BUFFER_HEADER_TYPE_SPECIFIC_T buffer_header_type_specific;
+
+   MMAL_BOOL_T is_zero_copy;
+   MMAL_BOOL_T has_reference;
+
+   /** If the data is short enough, then send it in the control message rather
+    * than using a separate VCHIQ bulk transfer.
+    */
+   uint32_t payload_in_message;
+   uint8_t short_data[MMAL_VC_SHORT_DATA];
+
+} mmal_worker_buffer_from_host;
+vcos_static_assert(sizeof(mmal_worker_buffer_from_host) <= MMAL_WORKER_MAX_MSG_LEN);
+
+/** Maximum number of event data bytes that can be passed in the message.
+ * More than this and the data is passed in a bulk message.
+ */
+#define MMAL_WORKER_EVENT_SPACE 256
+
+/** Send an event buffer from the host.
+  *
+  * @sa mmal_port_send_event()
+  */
+
+typedef struct mmal_worker_event_to_host
+{
+   mmal_worker_msg_header header;
+
+   struct MMAL_COMPONENT_T *client_component;
+   uint32_t port_type;
+   uint32_t port_num;
+
+   uint32_t cmd;
+   uint32_t length;
+   uint8_t data[MMAL_WORKER_EVENT_SPACE];
+   MMAL_BUFFER_HEADER_T *delayed_buffer;  /* Only used to remember buffer for bulk rx */
+} mmal_worker_event_to_host;
+vcos_static_assert(sizeof(mmal_worker_event_to_host) <= MMAL_WORKER_MAX_MSG_LEN);
+
+typedef struct
+{
+   mmal_worker_msg_header header;
+   MMAL_VC_STATS_T stats;
+   uint32_t reset;
+} mmal_worker_stats;
+vcos_static_assert(sizeof(mmal_worker_stats) <= MMAL_WORKER_MAX_MSG_LEN);
+
+typedef enum {
+   MMAL_WORKER_OPAQUE_MEM_ALLOC,
+   MMAL_WORKER_OPAQUE_MEM_RELEASE,
+   MMAL_WORKER_OPAQUE_MEM_ACQUIRE,
+   MMAL_WORKER_OPAQUE_MEM_MAX = 0x7fffffff,
+} MMAL_WORKER_OPAQUE_MEM_OP;
+
+typedef struct
+{
+   mmal_worker_msg_header header;
+   MMAL_WORKER_OPAQUE_MEM_OP op;
+   uint32_t handle;
+   MMAL_STATUS_T status;
+   char description[32];
+} mmal_worker_opaque_allocator;
+
+/*
+ * Per-port core statistics
+ */
+typedef struct
+{
+   mmal_worker_msg_header header;
+   uint32_t component_index;
+   uint32_t port_index;
+   MMAL_PORT_TYPE_T type;
+   MMAL_CORE_STATS_DIR dir;
+   MMAL_BOOL_T reset;
+} mmal_worker_get_core_stats_for_port;
+
+typedef struct
+{
+   mmal_worker_msg_header header;
+   MMAL_STATUS_T status;
+   MMAL_STATS_RESULT_T result;
+   MMAL_CORE_STATISTICS_T stats;
+   char component_name[MMAL_VC_CORE_STATS_NAME_MAX];
+} mmal_worker_get_core_stats_for_port_reply;
+
+typedef struct
+{
+   mmal_worker_msg_header header;
+   MMAL_STATUS_T status;
+   /* The amount of memory to reserve */
+   uint32_t size;
+   /* Handle to newly allocated memory or MEM_HANDLE_INVALD on failure */
+   uint32_t handle;
+} mmal_worker_consume_mem;
+vcos_static_assert(sizeof(mmal_worker_consume_mem) <= MMAL_WORKER_MAX_MSG_LEN);
+
+typedef struct
+{
+   mmal_worker_msg_header header;
+   MMAL_STATUS_T status;
+   uint32_t mode;
+   uint32_t duration;
+} mmal_worker_compact;
+vcos_static_assert(sizeof(mmal_worker_compact) <= MMAL_WORKER_MAX_MSG_LEN);
+
+typedef struct
+{
+   mmal_worker_msg_header header;
+   /* Message text to add to the circular buffer */
+   char msg[MMAL_WORKER_MAX_MSG_LEN - sizeof(mmal_worker_msg_header)];
+} mmal_worker_host_log;
+vcos_static_assert(sizeof(mmal_worker_host_log) <= MMAL_WORKER_MAX_MSG_LEN);
+
+typedef struct
+{
+   mmal_worker_msg_header header;
+   /* The memory allocation size to pass to lmk, as if in a response to an
+    * allocation for this amount of memory. */
+   uint32_t alloc_size;
+} mmal_worker_lmk;
+vcos_static_assert(sizeof(mmal_worker_lmk) <= MMAL_WORKER_MAX_MSG_LEN);
+
+static inline void mmal_vc_buffer_header_to_msg(mmal_worker_buffer_from_host *msg,
+                                                MMAL_BUFFER_HEADER_T *header)
+{
+   msg->buffer_header.cmd           = header->cmd;
+   msg->buffer_header.offset        = header->offset;
+   msg->buffer_header.length        = header->length;
+   msg->buffer_header.flags         = header->flags;
+   msg->buffer_header.pts           = header->pts;
+   msg->buffer_header.dts           = header->dts;
+   msg->buffer_header.alloc_size    = header->alloc_size;
+   msg->buffer_header.data          = header->data;
+   msg->buffer_header_type_specific = *header->type;
+}
+
+static inline void mmal_vc_msg_to_buffer_header(MMAL_BUFFER_HEADER_T *header,
+                                                mmal_worker_buffer_from_host *msg)
+{
+   header->cmd    = msg->buffer_header.cmd;
+   header->offset = msg->buffer_header.offset;
+   header->length = msg->buffer_header.length;
+   header->flags  = msg->buffer_header.flags;
+   header->pts    = msg->buffer_header.pts;
+   header->dts    = msg->buffer_header.dts;
+   *header->type  = msg->buffer_header_type_specific;
+}
+
+#endif
+
diff --git a/interface/mmal/vc/mmal_vc_opaque_alloc.c b/interface/mmal/vc/mmal_vc_opaque_alloc.c
new file mode 100755 (executable)
index 0000000..b5b5ba9
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/mmal/vc/mmal_vc_opaque_alloc.h"
+#include "mmal_vc_msgs.h"
+#include "mmal_vc_client_priv.h"
+
+MMAL_OPAQUE_IMAGE_HANDLE_T mmal_vc_opaque_alloc_desc(const char *description)
+{
+   MMAL_STATUS_T ret;
+   MMAL_OPAQUE_IMAGE_HANDLE_T h = 0;
+   mmal_worker_opaque_allocator msg;
+   size_t len = sizeof(msg);
+   msg.op = MMAL_WORKER_OPAQUE_MEM_ALLOC;
+   vcos_safe_strcpy(msg.description, description, sizeof(msg.description), 0);
+   ret = mmal_vc_sendwait_message(mmal_vc_get_client(),
+                                  &msg.header, sizeof(msg),
+                                  MMAL_WORKER_OPAQUE_ALLOCATOR_DESC,
+                                  &msg, &len, MMAL_FALSE);
+   if (ret == MMAL_SUCCESS)
+   {
+      h = msg.handle;
+   }
+   return h;
+}
+
+MMAL_OPAQUE_IMAGE_HANDLE_T mmal_vc_opaque_alloc(void)
+{
+   return mmal_vc_opaque_alloc_desc("?");
+}
+
+MMAL_STATUS_T mmal_vc_opaque_acquire(unsigned int handle)
+{
+   MMAL_STATUS_T ret;
+   mmal_worker_opaque_allocator msg;
+   size_t len = sizeof(msg);
+   msg.handle = handle;
+   msg.op = MMAL_WORKER_OPAQUE_MEM_ACQUIRE;
+   ret = mmal_vc_sendwait_message(mmal_vc_get_client(),
+                                  &msg.header, sizeof(msg),
+                                  MMAL_WORKER_OPAQUE_ALLOCATOR,
+                                  &msg, &len, MMAL_FALSE);
+   if (ret == MMAL_SUCCESS)
+      ret = msg.status;
+   return ret;
+}
+
+MMAL_STATUS_T mmal_vc_opaque_release(unsigned int handle)
+{
+   MMAL_STATUS_T ret;
+   mmal_worker_opaque_allocator msg;
+   size_t len = sizeof(msg);
+   msg.handle = handle;
+   msg.op = MMAL_WORKER_OPAQUE_MEM_RELEASE;
+   ret = mmal_vc_sendwait_message(mmal_vc_get_client(),
+                                  &msg.header, sizeof(msg),
+                                  MMAL_WORKER_OPAQUE_ALLOCATOR,
+                                  &msg, &len, MMAL_FALSE);
+   if (ret == MMAL_SUCCESS)
+      ret = msg.status;
+   return ret;
+}
+
diff --git a/interface/mmal/vc/mmal_vc_opaque_alloc.h b/interface/mmal/vc/mmal_vc_opaque_alloc.h
new file mode 100755 (executable)
index 0000000..60a5e56
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef MMAL_VC_OPAQUE_ALLOC_H
+#define MMAL_VC_OPAQUE_ALLOC_H
+
+
+#include <stdint.h>
+#include "interface/mmal/mmal.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef uint32_t MMAL_OPAQUE_IMAGE_HANDLE_T;
+
+/** Allocate an opaque image on VideoCore.
+ *
+ * @return allocated handle, or zero if allocation failed.
+ */
+MMAL_OPAQUE_IMAGE_HANDLE_T mmal_vc_opaque_alloc(void);
+
+/** Allocate an opaque image on VideoCore, providing a description.
+ * @return allocated handle, or zero if allocation failed.
+ */
+MMAL_OPAQUE_IMAGE_HANDLE_T mmal_vc_opaque_alloc_desc(const char *description);
+
+/** Release an opaque image.
+ *
+ * @param handle  handle allocated earlier
+ * @return MMAL_SUCCESS or error code if handle not found
+ */
+MMAL_STATUS_T mmal_vc_opaque_release(MMAL_OPAQUE_IMAGE_HANDLE_T h);
+
+/** Acquire an additional reference to an opaque image.
+ *
+ * @param handle  handle allocated earlier
+ * @return MMAL_SUCCESS or error code if handle not found
+ */
+MMAL_STATUS_T mmal_vc_opaque_acquire(MMAL_OPAQUE_IMAGE_HANDLE_T h);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif
+
diff --git a/interface/mmal/vc/mmal_vc_shm.c b/interface/mmal/vc/mmal_vc_shm.c
new file mode 100755 (executable)
index 0000000..e22a53a
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "interface/mmal/mmal_logging.h"
+#include "interface/mmal/mmal.h"
+#include "interface/vcos/vcos.h"
+
+#include "interface/mmal/vc/mmal_vc_shm.h"
+
+#ifdef ENABLE_MMAL_VCSM
+# include "user-vcsm.h"
+#endif /* ENABLE_MMAL_VCSM */
+
+#define MMAL_VC_PAYLOAD_ELEM_MAX 512
+
+typedef struct MMAL_VC_PAYLOAD_ELEM_T
+{
+   struct MMAL_VC_PAYLOAD_ELEM_T *next;
+   void *handle;
+   void *vc_handle;
+   uint8_t *mem;
+   MMAL_BOOL_T in_use;
+} MMAL_VC_PAYLOAD_ELEM_T;
+
+typedef struct MMAL_VC_PAYLOAD_LIST_T
+{
+   MMAL_VC_PAYLOAD_ELEM_T list[MMAL_VC_PAYLOAD_ELEM_MAX];
+   VCOS_MUTEX_T lock;
+} MMAL_VC_PAYLOAD_LIST_T;
+
+static MMAL_VC_PAYLOAD_LIST_T mmal_vc_payload_list;
+
+static void mmal_vc_payload_list_init()
+{
+   vcos_mutex_create(&mmal_vc_payload_list.lock, "mmal_vc_payload_list");
+}
+
+static MMAL_VC_PAYLOAD_ELEM_T *mmal_vc_payload_list_get()
+{
+   MMAL_VC_PAYLOAD_ELEM_T *elem = 0;
+   unsigned int i;
+
+   vcos_mutex_lock(&mmal_vc_payload_list.lock);
+   for (i = 0; i < MMAL_VC_PAYLOAD_ELEM_MAX; i++)
+   {
+      if (mmal_vc_payload_list.list[i].in_use)
+         continue;
+      elem = &mmal_vc_payload_list.list[i];
+      elem->in_use = 1;
+      break;
+   }
+   vcos_mutex_unlock(&mmal_vc_payload_list.lock);
+
+   return elem;
+}
+
+static void mmal_vc_payload_list_release(MMAL_VC_PAYLOAD_ELEM_T *elem)
+{
+   vcos_mutex_lock(&mmal_vc_payload_list.lock);
+   elem->handle = elem->vc_handle = 0;
+   elem->mem = 0;
+   elem->in_use = 0;
+   vcos_mutex_unlock(&mmal_vc_payload_list.lock);
+}
+
+static MMAL_VC_PAYLOAD_ELEM_T *mmal_vc_payload_list_find_mem(uint8_t *mem)
+{
+   MMAL_VC_PAYLOAD_ELEM_T *elem = 0;
+   unsigned int i;
+
+   vcos_mutex_lock(&mmal_vc_payload_list.lock);
+   for (i = 0; i < MMAL_VC_PAYLOAD_ELEM_MAX; i++)
+   {
+      if (!mmal_vc_payload_list.list[i].in_use)
+         continue;
+      if (mmal_vc_payload_list.list[i].mem != mem)
+         continue;
+      elem = &mmal_vc_payload_list.list[i];
+      break;
+   }
+   vcos_mutex_unlock(&mmal_vc_payload_list.lock);
+
+   return elem;
+}
+
+static MMAL_VC_PAYLOAD_ELEM_T *mmal_vc_payload_list_find_handle(uint8_t *mem)
+{
+   MMAL_VC_PAYLOAD_ELEM_T *elem = 0;
+   unsigned int i;
+
+   vcos_mutex_lock(&mmal_vc_payload_list.lock);
+   for (i = 0; i < MMAL_VC_PAYLOAD_ELEM_MAX; i++)
+   {
+      if (!mmal_vc_payload_list.list[i].in_use)
+         continue;
+      if (mmal_vc_payload_list.list[i].vc_handle != (void *)mem)
+         continue;
+      elem = &mmal_vc_payload_list.list[i];
+      break;
+   }
+   vcos_mutex_unlock(&mmal_vc_payload_list.lock);
+
+   return elem;
+}
+
+/** Initialise the shared memory system */
+MMAL_STATUS_T mmal_vc_shm_init(void)
+{
+#ifdef ENABLE_MMAL_VCSM
+   if (vcsm_init() != 0)
+   {
+      LOG_ERROR("could not initialize vc shared memory service");
+      return MMAL_EIO;
+   }
+#endif /* ENABLE_MMAL_VCSM */
+
+   mmal_vc_payload_list_init();
+   return MMAL_SUCCESS;
+}
+
+/** Allocate a shared memory buffer */
+uint8_t *mmal_vc_shm_alloc(uint32_t size)
+{
+   uint8_t *mem = NULL;
+
+   MMAL_VC_PAYLOAD_ELEM_T *payload_elem = mmal_vc_payload_list_get();
+   if (!payload_elem)
+   {
+      LOG_ERROR("could not get a free slot in the payload list");
+      return NULL;
+   }
+
+#ifdef ENABLE_MMAL_VCSM
+   unsigned int vcsm_handle = vcsm_malloc_cache(size, VCSM_CACHE_TYPE_HOST, "mmal_vc_port buffer");
+   unsigned int vc_handle = vcsm_vc_hdl_from_hdl(vcsm_handle);
+   mem = (uint8_t *)vcsm_lock( vcsm_handle );
+   if (!mem || !vc_handle)
+   {
+      LOG_ERROR("could not allocate %i bytes of shared memory (handle %x)",
+                (int)size, vcsm_handle);
+      if (mem)
+         vcsm_unlock_hdl(vcsm_handle);
+      if (vcsm_handle)
+         vcsm_free(vcsm_handle);
+      mmal_vc_payload_list_release(payload_elem);
+      return NULL;
+   }
+
+   /* The memory area is automatically mem-locked by vcsm's fault
+    * handler when it is next used. So leave it unlocked until it
+    * is needed.
+    */
+   vcsm_unlock_hdl(vcsm_handle);
+
+   payload_elem->mem = mem;
+   payload_elem->handle = (void *)vcsm_handle;
+   payload_elem->vc_handle = (void *)vc_handle;
+#else /* ENABLE_MMAL_VCSM */
+   MMAL_PARAM_UNUSED(size);
+   mmal_vc_payload_list_release(payload_elem);
+#endif /* ENABLE_MMAL_VCSM */
+
+   return mem;
+}
+
+/** Free a shared memory buffer */
+MMAL_STATUS_T mmal_vc_shm_free(uint8_t *mem)
+{
+   MMAL_VC_PAYLOAD_ELEM_T *payload_elem = mmal_vc_payload_list_find_mem(mem);
+   if (payload_elem)
+   {
+#ifdef ENABLE_MMAL_VCSM
+      vcsm_free((unsigned int)payload_elem->handle);
+#endif /* ENABLE_MMAL_VCSM */
+      mmal_vc_payload_list_release(payload_elem);
+      return MMAL_SUCCESS;
+   }
+
+   return MMAL_EINVAL;
+}
+
+/** Lock a shared memory buffer */
+uint8_t *mmal_vc_shm_lock(uint8_t *mem, uint32_t workaround)
+{
+   /* Zero copy stuff */
+   MMAL_VC_PAYLOAD_ELEM_T *elem = mmal_vc_payload_list_find_handle(mem);
+   MMAL_PARAM_UNUSED(workaround);
+
+   if (elem) {
+      mem = elem->mem;
+#ifdef ENABLE_MMAL_VCSM
+      void *p = vcsm_lock((unsigned int)elem->handle);
+      if (!p)
+         assert(0);
+#endif /* ENABLE_MMAL_VCSM */
+   }
+
+   return mem;
+}
+
+/** Unlock a shared memory buffer */
+uint8_t *mmal_vc_shm_unlock(uint8_t *mem, uint32_t *length, uint32_t workaround)
+{
+   /* Zero copy stuff */
+   MMAL_VC_PAYLOAD_ELEM_T *elem = mmal_vc_payload_list_find_mem(mem);
+   MMAL_PARAM_UNUSED(workaround);
+
+   if (elem)
+   {
+      *length = 0;
+      mem = (uint8_t *)elem->vc_handle;
+#ifdef ENABLE_MMAL_VCSM
+      vcsm_unlock_ptr(elem->mem);
+#endif /* ENABLE_MMAL_VCSM */
+   }
+
+   return mem;
+}
diff --git a/interface/mmal/vc/mmal_vc_shm.h b/interface/mmal/vc/mmal_vc_shm.h
new file mode 100755 (executable)
index 0000000..0aacb5b
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef MMAL_VC_SHM_H
+#define MMAL_VC_SHM_H
+
+/** @file
+  *
+  * Abstraction layer for MMAL VC shared memory.
+  * This API is only used by the MMAL VC component.
+  */
+
+#include "mmal_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Initialise the shared memory system */
+MMAL_STATUS_T mmal_vc_shm_init(void);
+
+/** Allocate a shared memory buffer */
+uint8_t *mmal_vc_shm_alloc(uint32_t size);
+
+/** Free a shared memory buffer */
+MMAL_STATUS_T mmal_vc_shm_free(uint8_t *mem);
+
+/** Lock a shared memory buffer */
+uint8_t *mmal_vc_shm_lock(uint8_t *mem, uint32_t workaround);
+
+/** Unlock a shared memory buffer */
+uint8_t *mmal_vc_shm_unlock(uint8_t *mem, uint32_t *length, uint32_t workaround);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MMAL_VC_SHM_H */
diff --git a/interface/peer/vc_vchi_dispmanx_common.h b/interface/peer/vc_vchi_dispmanx_common.h
new file mode 100755 (executable)
index 0000000..3ccea84
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef VC_VCHI_DISPMANX_COMMON_H
+#define VC_VCHI_DISPMANX_COMMON_H
+
+typedef enum  {
+   // IMPORTANT - DO NOT ALTER THE ORDER OF COMMANDS IN THIS ENUMERATION
+   // NEW FUNCTIONS SHOULD BE ADDED TO THE END, AND MUST ALSO BE ADDED TO
+   // THE HOST SIDE FUNCTION TABLE IN display_server.c.
+   
+   // No function configured - do not use
+   EDispmanNoFunction = 0,
+   
+   // Dispman pre-configure functions
+   EDispmanGetDevices,
+   EDispmanGetModes,
+   
+   // Dispman resource-related functions
+   EDispmanResourceCreate,
+   EDispmanResourceCreateFromImage,
+   EDispmanResourceDelete,
+   EDispmanResourceGetData,
+   EDispmanResourceGetImage,
+   
+   // Dispman display-related functions
+   EDispmanDisplayOpen,
+   EDispmanDisplayOpenMode,
+   EDispmanDisplayOpenOffscreen,
+   EDispmanDisplayReconfigure,
+   EDispmanDisplaySetDestination,
+   EDispmanDisplaySetBackground,
+   EDispmanDisplayGetInfo,
+   EDispmanDisplayClose,
+   
+   // Dispman update-related functions
+   EDispmanUpdateStart,
+   EDispmanUpdateSubmit,
+   EDispmanUpdateSubmitSync,
+   
+   // Dispman element-related functions
+   EDispmanElementAdd,
+   EDispmanElementModified,
+   EDispmanElementRemove,
+   EDispmanElementChangeSource,
+   EDispmanElementChangeLayer,
+   EDispmanElementChangeAttributes,
+
+   //More commands go here...
+   EDispmanResourceFill,    //Comes from uideck
+   EDispmanQueryImageFormats,
+   EDispmanBulkWrite,
+   EDispmanBulkRead,
+   EDispmanDisplayOrientation,
+   EDispmanSnapshot,
+   EDispmanSetPalette,
+   EDispmanVsyncCallback,
+
+   EDispmanMaxFunction
+} DISPMANX_COMMAND_T;
+
+#endif
diff --git a/interface/vchi/common/endian.h b/interface/vchi/common/endian.h
new file mode 100755 (executable)
index 0000000..3f1b68e
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _VCHI_ENDIAN_H_
+#define _VCHI_ENDIAN_H_
+
+#include "interface/vcos/vcos.h"
+
+int16_t  vchi_readbuf_int16 ( const void *ptr );
+uint16_t vchi_readbuf_uint16( const void *ptr );
+uint32_t vchi_readbuf_uint32( const void *ptr );
+vcos_fourcc_t vchi_readbuf_fourcc( const void *ptr );
+
+void vchi_writebuf_uint16( void *ptr, uint16_t value );
+void vchi_writebuf_uint32( void *ptr, uint32_t value );
+void vchi_writebuf_fourcc( void *ptr, vcos_fourcc_t value );
+
+#endif /* _VCHI_ENDIAN_H_ */
+
+/********************************** End of file ******************************************/
diff --git a/interface/vchi/connections/connection.h b/interface/vchi/connections/connection.h
new file mode 100755 (executable)
index 0000000..91bc91d
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * \file
+ *
+ * \brief Contains the protypes for the interface functions.
+*/
+
+#ifndef CONNECTION_H_
+#define CONNECTION_H_
+
+#include "interface/vchi/vchi_cfg_internal.h"
+#include "interface/vchi/vchi_common.h"
+#include "interface/vchi/message_drivers/message.h"
+
+/******************************************************************************
+ Global defs
+ *****************************************************************************/
+
+// Opaque handle for a connection / service pair
+typedef struct opaque_vchi_connection_connected_service_handle_t *VCHI_CONNECTION_SERVICE_HANDLE_T;
+
+// opaque handle to the connection state information
+typedef struct opaque_vchi_connection_info_t VCHI_CONNECTION_STATE_T;
+
+typedef struct vchi_connection_t VCHI_CONNECTION_T;
+
+
+/******************************************************************************
+ API
+ *****************************************************************************/
+
+// Routine to init a connection with a particular low level driver
+typedef VCHI_CONNECTION_STATE_T * (*VCHI_CONNECTION_INIT_T)( struct vchi_connection_t * connection,
+                                                             const VCHI_MESSAGE_DRIVER_T * driver );
+
+// Routine to control CRC enabling at a connection level
+typedef int32_t (*VCHI_CONNECTION_CRC_CONTROL_T)( VCHI_CONNECTION_STATE_T *state_handle,
+                                                  VCHI_CRC_CONTROL_T control );
+
+// Routine to create a service
+typedef int32_t (*VCHI_CONNECTION_SERVICE_CONNECT_T)( VCHI_CONNECTION_STATE_T *state_handle,
+                                                      vcos_fourcc_t service_id,
+                                                      uint32_t rx_fifo_size,
+                                                      uint32_t tx_fifo_size,
+                                                      int server,
+                                                      VCHI_CALLBACK_T callback,
+                                                      void *callback_param,
+                                                      vcos_bool_t want_crc,
+                                                      vcos_bool_t want_unaligned_bulk_rx,
+                                                      vcos_bool_t want_unaligned_bulk_tx,
+                                                      VCHI_CONNECTION_SERVICE_HANDLE_T *service_handle );
+
+// Routine to close a service
+typedef int32_t (*VCHI_CONNECTION_SERVICE_DISCONNECT_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle );
+
+// Routine to queue a message
+typedef int32_t (*VCHI_CONNECTION_SERVICE_QUEUE_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
+                                                            const void *data,
+                                                            uint32_t data_size,
+                                                            VCHI_FLAGS_T flags,
+                                                            void *msg_handle );
+
+// scatter-gather (vector) message queueing
+typedef int32_t (*VCHI_CONNECTION_SERVICE_QUEUE_MESSAGEV_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
+                                                             VCHI_MSG_VECTOR_T *vector,
+                                                             uint32_t count,
+                                                             VCHI_FLAGS_T flags,
+                                                             void *msg_handle );
+
+// Routine to dequeue a message
+typedef int32_t (*VCHI_CONNECTION_SERVICE_DEQUEUE_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
+                                                              void *data,
+                                                              uint32_t max_data_size_to_read,
+                                                              uint32_t *actual_msg_size,
+                                                              VCHI_FLAGS_T flags );
+
+// Routine to peek at a message
+typedef int32_t (*VCHI_CONNECTION_SERVICE_PEEK_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
+                                                           void **data,
+                                                           uint32_t *msg_size,
+                                                           VCHI_FLAGS_T flags );
+
+// Routine to hold a message
+typedef int32_t (*VCHI_CONNECTION_SERVICE_HOLD_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
+                                                           void **data,
+                                                           uint32_t *msg_size,
+                                                           VCHI_FLAGS_T flags,
+                                                           void **message_handle );
+
+// Routine to initialise a received message iterator
+typedef int32_t (*VCHI_CONNECTION_SERVICE_LOOKAHEAD_MESSAGE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
+                                                                VCHI_MSG_ITER_T *iter,
+                                                                VCHI_FLAGS_T flags );
+
+// Routine to release a held message
+typedef int32_t (*VCHI_CONNECTION_HELD_MSG_RELEASE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
+                                                       void *message_handle );
+
+// Routine to get info on a held message
+typedef int32_t (*VCHI_CONNECTION_HELD_MSG_INFO_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
+                                                    void *message_handle,
+                                                    void **data,
+                                                    int32_t *msg_size,
+                                                    uint32_t *tx_timestamp,
+                                                    uint32_t *rx_timestamp );
+
+// Routine to check whether the iterator has a next message
+typedef vcos_bool_t (*VCHI_CONNECTION_MSG_ITER_HAS_NEXT_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service,
+                                                       const VCHI_MSG_ITER_T *iter );
+
+// Routine to advance the iterator
+typedef int32_t (*VCHI_CONNECTION_MSG_ITER_NEXT_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service,
+                                                    VCHI_MSG_ITER_T *iter,
+                                                    void **data,
+                                                    uint32_t *msg_size );
+
+// Routine to remove the last message returned by the iterator
+typedef int32_t (*VCHI_CONNECTION_MSG_ITER_REMOVE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service,
+                                                      VCHI_MSG_ITER_T *iter );
+
+// Routine to hold the last message returned by the iterator
+typedef int32_t (*VCHI_CONNECTION_MSG_ITER_HOLD_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service,
+                                                    VCHI_MSG_ITER_T *iter,
+                                                    void **msg_handle );
+
+// Routine to transmit bulk data
+typedef int32_t (*VCHI_CONNECTION_BULK_QUEUE_TRANSMIT_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
+                                                          const void *data_src,
+                                                          uint32_t data_size,
+                                                          VCHI_FLAGS_T flags,
+                                                          void *bulk_handle );
+
+// Routine to receive data
+typedef int32_t (*VCHI_CONNECTION_BULK_QUEUE_RECEIVE_T)( VCHI_CONNECTION_SERVICE_HANDLE_T service_handle,
+                                                         void *data_dst,
+                                                         uint32_t data_size,
+                                                         VCHI_FLAGS_T flags,
+                                                         void *bulk_handle );
+
+// Routine to report if a server is available
+typedef int32_t (*VCHI_CONNECTION_SERVER_PRESENT)( VCHI_CONNECTION_STATE_T *state, vcos_fourcc_t service_id, int32_t peer_flags );
+
+// Routine to report the number of RX slots available
+typedef int (*VCHI_CONNECTION_RX_SLOTS_AVAILABLE)( const VCHI_CONNECTION_STATE_T *state );
+
+// Routine to report the RX slot size
+typedef uint32_t (*VCHI_CONNECTION_RX_SLOT_SIZE)( const VCHI_CONNECTION_STATE_T *state );
+
+// Callback to indicate that the other side has added a buffer to the rx bulk DMA FIFO
+typedef void (*VCHI_CONNECTION_RX_BULK_BUFFER_ADDED)(VCHI_CONNECTION_STATE_T *state,
+                                                     vcos_fourcc_t service,
+                                                     uint32_t length,
+                                                     MESSAGE_TX_CHANNEL_T channel,
+                                                     uint32_t channel_params,
+                                                     uint32_t data_length,
+                                                     uint32_t data_offset);
+
+// Callback to inform a service that a Xon or Xoff message has been received
+typedef void (*VCHI_CONNECTION_FLOW_CONTROL)(VCHI_CONNECTION_STATE_T *state, vcos_fourcc_t service_id, int32_t xoff);
+
+// Callback to inform a service that a server available reply message has been received
+typedef void (*VCHI_CONNECTION_SERVER_AVAILABLE_REPLY)(VCHI_CONNECTION_STATE_T *state, vcos_fourcc_t service_id, uint32_t flags);
+
+// Callback to indicate that bulk auxiliary messages have arrived
+typedef void (*VCHI_CONNECTION_BULK_AUX_RECEIVED)(VCHI_CONNECTION_STATE_T *state);
+
+// Callback to indicate that bulk auxiliary messages have arrived
+typedef void (*VCHI_CONNECTION_BULK_AUX_TRANSMITTED)(VCHI_CONNECTION_STATE_T *state, void *handle);
+
+// Callback with all the connection info you require
+typedef void (*VCHI_CONNECTION_INFO)(VCHI_CONNECTION_STATE_T *state, uint32_t protocol_version, uint32_t slot_size, uint32_t num_slots, uint32_t min_bulk_size);
+
+// Callback to inform of a disconnect
+typedef void (*VCHI_CONNECTION_DISCONNECT)(VCHI_CONNECTION_STATE_T *state, uint32_t flags);
+
+// Callback to inform of a power control request
+typedef void (*VCHI_CONNECTION_POWER_CONTROL)(VCHI_CONNECTION_STATE_T *state, MESSAGE_TX_CHANNEL_T channel, vcos_bool_t enable);
+
+// allocate memory suitably aligned for this connection
+typedef void * (*VCHI_BUFFER_ALLOCATE)(VCHI_CONNECTION_SERVICE_HANDLE_T service_handle, uint32_t * length);
+
+// free memory allocated by buffer_allocate
+typedef void   (*VCHI_BUFFER_FREE)(VCHI_CONNECTION_SERVICE_HANDLE_T service_handle, void * address);
+
+
+/******************************************************************************
+ System driver struct
+ *****************************************************************************/
+
+struct opaque_vchi_connection_api_t
+{
+   // Routine to init the connection
+   VCHI_CONNECTION_INIT_T                      init;
+
+   // Connection-level CRC control
+   VCHI_CONNECTION_CRC_CONTROL_T               crc_control;
+
+   // Routine to connect to or create service
+   VCHI_CONNECTION_SERVICE_CONNECT_T           service_connect;
+
+   // Routine to disconnect from a service
+   VCHI_CONNECTION_SERVICE_DISCONNECT_T        service_disconnect;
+
+   // Routine to queue a message
+   VCHI_CONNECTION_SERVICE_QUEUE_MESSAGE_T     service_queue_msg;
+
+   // scatter-gather (vector) message queue
+   VCHI_CONNECTION_SERVICE_QUEUE_MESSAGEV_T    service_queue_msgv;
+
+   // Routine to dequeue a message
+   VCHI_CONNECTION_SERVICE_DEQUEUE_MESSAGE_T   service_dequeue_msg;
+
+   // Routine to peek at a message
+   VCHI_CONNECTION_SERVICE_PEEK_MESSAGE_T      service_peek_msg;
+
+   // Routine to hold a message
+   VCHI_CONNECTION_SERVICE_HOLD_MESSAGE_T      service_hold_msg;
+
+   // Routine to initialise a received message iterator
+   VCHI_CONNECTION_SERVICE_LOOKAHEAD_MESSAGE_T service_look_ahead_msg;
+
+   // Routine to release a message
+   VCHI_CONNECTION_HELD_MSG_RELEASE_T          held_msg_release;
+
+   // Routine to get information on a held message
+   VCHI_CONNECTION_HELD_MSG_INFO_T             held_msg_info;
+
+   // Routine to check for next message on iterator
+   VCHI_CONNECTION_MSG_ITER_HAS_NEXT_T         msg_iter_has_next;
+
+   // Routine to get next message on iterator
+   VCHI_CONNECTION_MSG_ITER_NEXT_T             msg_iter_next;
+
+   // Routine to remove the last message returned by iterator
+   VCHI_CONNECTION_MSG_ITER_REMOVE_T           msg_iter_remove;
+
+   // Routine to hold the last message returned by iterator
+   VCHI_CONNECTION_MSG_ITER_HOLD_T             msg_iter_hold;
+
+   // Routine to transmit bulk data
+   VCHI_CONNECTION_BULK_QUEUE_TRANSMIT_T       bulk_queue_transmit;
+
+   // Routine to receive data
+   VCHI_CONNECTION_BULK_QUEUE_RECEIVE_T        bulk_queue_receive;
+
+   // Routine to report the available servers
+   VCHI_CONNECTION_SERVER_PRESENT              server_present;
+
+   // Routine to report the number of RX slots available
+   VCHI_CONNECTION_RX_SLOTS_AVAILABLE          connection_rx_slots_available;
+
+   // Routine to report the RX slot size
+   VCHI_CONNECTION_RX_SLOT_SIZE                connection_rx_slot_size;
+
+   // Callback to indicate that the other side has added a buffer to the rx bulk DMA FIFO
+   VCHI_CONNECTION_RX_BULK_BUFFER_ADDED        rx_bulk_buffer_added;
+
+   // Callback to inform a service that a Xon or Xoff message has been received
+   VCHI_CONNECTION_FLOW_CONTROL                flow_control;
+
+   // Callback to inform a service that a server available reply message has been received
+   VCHI_CONNECTION_SERVER_AVAILABLE_REPLY      server_available_reply;
+
+   // Callback to indicate that bulk auxiliary messages have arrived
+   VCHI_CONNECTION_BULK_AUX_RECEIVED           bulk_aux_received;
+
+   // Callback to indicate that a bulk auxiliary message has been transmitted
+   VCHI_CONNECTION_BULK_AUX_TRANSMITTED        bulk_aux_transmitted;
+
+   // Callback to provide information about the connection
+   VCHI_CONNECTION_INFO                        connection_info;
+
+   // Callback to notify that peer has requested disconnect
+   VCHI_CONNECTION_DISCONNECT                  disconnect;
+
+   // Callback to notify that peer has requested power change
+   VCHI_CONNECTION_POWER_CONTROL               power_control;
+
+   // allocate memory suitably aligned for this connection
+   VCHI_BUFFER_ALLOCATE                        buffer_allocate;
+
+   // free memory allocated by buffer_allocate
+   VCHI_BUFFER_FREE                            buffer_free;
+
+};
+
+struct vchi_connection_t {
+   const VCHI_CONNECTION_API_T *api;
+   VCHI_CONNECTION_STATE_T     *state;
+#ifdef VCHI_COARSE_LOCKING
+   VCOS_SEMAPHORE_T             sem;
+#endif
+};
+
+
+#endif /* CONNECTION_H_ */
+
+/****************************** End of file **********************************/
diff --git a/interface/vchi/message_drivers/message.h b/interface/vchi/message_drivers/message.h
new file mode 100755 (executable)
index 0000000..4dc4e58
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// MPHI videocore message driver
+
+#ifndef _VCHI_MESSAGE_H_
+#define _VCHI_MESSAGE_H_
+
+#include "interface/vchi/vchi_cfg_internal.h"
+#include "interface/vcos/vcos.h"
+#include "interface/vchi/vchi_common.h"
+
+
+typedef enum message_event_type {
+   MESSAGE_EVENT_NONE,
+   MESSAGE_EVENT_NOP,
+   MESSAGE_EVENT_MESSAGE,
+   MESSAGE_EVENT_SLOT_COMPLETE,
+   MESSAGE_EVENT_RX_BULK_PAUSED,
+   MESSAGE_EVENT_RX_BULK_COMPLETE,
+   MESSAGE_EVENT_TX_COMPLETE,
+   MESSAGE_EVENT_MSG_DISCARDED
+} MESSAGE_EVENT_TYPE_T;
+
+typedef enum vchi_msg_flags
+{
+   VCHI_MSG_FLAGS_NONE                  = 0x0,
+   VCHI_MSG_FLAGS_TERMINATE_DMA         = 0x1
+} VCHI_MSG_FLAGS_T;
+
+typedef enum message_tx_channel
+{
+   MESSAGE_TX_CHANNEL_MESSAGE           = 0,
+   MESSAGE_TX_CHANNEL_BULK              = 1 // drivers may provide multiple bulk channels, from 1 upwards
+} MESSAGE_TX_CHANNEL_T;
+
+// Macros used for cycling through bulk channels
+#define MESSAGE_TX_CHANNEL_BULK_PREV(c) (MESSAGE_TX_CHANNEL_BULK+((c)-MESSAGE_TX_CHANNEL_BULK+VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION-1)%VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION)
+#define MESSAGE_TX_CHANNEL_BULK_NEXT(c) (MESSAGE_TX_CHANNEL_BULK+((c)-MESSAGE_TX_CHANNEL_BULK+1)%VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION)
+
+typedef enum message_rx_channel
+{
+   MESSAGE_RX_CHANNEL_MESSAGE           = 0,
+   MESSAGE_RX_CHANNEL_BULK              = 1 // drivers may provide multiple bulk channels, from 1 upwards
+} MESSAGE_RX_CHANNEL_T;
+
+// Message receive slot information
+typedef struct rx_msg_slot_info {
+
+   struct rx_msg_slot_info *next;
+   //struct slot_info *prev;
+#if !defined VCHI_COARSE_LOCKING
+   VCOS_SEMAPHORE_T   sem;
+#endif
+
+   uint8_t           *addr;               // base address of slot
+   uint32_t           len;                // length of slot in bytes
+
+   uint32_t           write_ptr;          // hardware causes this to advance
+   uint32_t           read_ptr;           // this module does the reading
+   int                active;             // is this slot in the hardware dma fifo?
+   uint32_t           msgs_parsed;        // count how many messages are in this slot
+   uint32_t           msgs_released;      // how many messages have been released
+   void              *state;              // connection state information
+   uint8_t            ref_count[VCHI_MAX_SERVICES_PER_CONNECTION];          // reference count for slots held by services
+} RX_MSG_SLOTINFO_T;
+
+// The message driver no longer needs to know about the fields of RX_BULK_SLOTINFO_T - sort this out.
+// In particular, it mustn't use addr and len - they're the client buffer, but the message
+// driver will be tasked with sending the aligned core section.
+typedef struct rx_bulk_slotinfo_t {
+   struct rx_bulk_slotinfo_t *next;
+
+   VCOS_SEMAPHORE_T *blocking;
+
+   // needed by DMA
+   void        *addr;
+   uint32_t     len;
+
+   // needed for the callback
+   void        *service;
+   void        *handle;
+   VCHI_FLAGS_T flags;
+} RX_BULK_SLOTINFO_T;
+
+
+/* ----------------------------------------------------------------------
+ * each connection driver will have a pool of the following struct.
+ *
+ * the pool will be managed by vchi_qman_*
+ * this means there will be multiple queues (single linked lists)
+ * a given struct message_info will be on exactly one of these queues
+ * at any one time
+ * -------------------------------------------------------------------- */
+typedef struct rx_message_info {
+
+   struct message_info *next;
+   //struct message_info *prev;
+
+   uint8_t    *addr;
+   uint32_t   len;
+   RX_MSG_SLOTINFO_T *slot; // points to whichever slot contains this message
+   uint32_t   tx_timestamp;
+   uint32_t   rx_timestamp;
+
+} RX_MESSAGE_INFO_T;
+
+typedef struct {
+   MESSAGE_EVENT_TYPE_T type;
+
+   struct {
+      // for messages
+      void    *addr;           // address of message
+      uint16_t slot_delta;     // whether this message indicated slot delta
+      uint32_t len;            // length of message
+      RX_MSG_SLOTINFO_T *slot; // slot this message is in
+      vcos_fourcc_t service;   // service id this message is destined for
+      uint32_t tx_timestamp;   // timestamp from the header
+      uint32_t rx_timestamp;   // timestamp when we parsed it
+   } message;
+
+   // FIXME: cleanup slot reporting...
+   RX_MSG_SLOTINFO_T *rx_msg;
+   RX_BULK_SLOTINFO_T *rx_bulk;
+   void *tx_handle;
+   MESSAGE_TX_CHANNEL_T tx_channel;
+
+} MESSAGE_EVENT_T;
+
+
+// callbacks
+typedef void VCHI_MESSAGE_DRIVER_EVENT_CALLBACK_T( void *state );
+
+typedef struct {
+   VCHI_MESSAGE_DRIVER_EVENT_CALLBACK_T *event_callback;
+} VCHI_MESSAGE_DRIVER_OPEN_T;
+
+
+// handle to this instance of message driver (as returned by ->open)
+typedef struct opaque_mhandle_t *VCHI_MDRIVER_HANDLE_T;
+
+struct opaque_vchi_message_driver_t {
+   VCHI_MDRIVER_HANDLE_T *(*open)( VCHI_MESSAGE_DRIVER_OPEN_T *params, void *state );
+   int32_t (*suspending)( VCHI_MDRIVER_HANDLE_T *handle );
+   int32_t (*resumed)( VCHI_MDRIVER_HANDLE_T *handle );
+   int32_t (*power_control)( VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T, vcos_bool_t enable );
+   int32_t (*add_msg_rx_slot)( VCHI_MDRIVER_HANDLE_T *handle, RX_MSG_SLOTINFO_T *slot );      // rx message
+   int32_t (*add_bulk_rx)( VCHI_MDRIVER_HANDLE_T *handle, void *data, uint32_t len, RX_BULK_SLOTINFO_T *slot );  // rx data (bulk)
+   int32_t (*send)( VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel, const void *data, uint32_t len, VCHI_MSG_FLAGS_T flags, void *send_handle );      // tx (message & bulk)
+   void    (*next_event)( VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_EVENT_T *event );     // get the next event from message_driver
+   int32_t (*enable)( VCHI_MDRIVER_HANDLE_T *handle );
+   int32_t (*form_message)( VCHI_MDRIVER_HANDLE_T *handle, vcos_fourcc_t service_id, VCHI_MSG_VECTOR_T *vector, uint32_t count, void
+                            *address, uint32_t length_avail, uint32_t max_total_length, vcos_bool_t pad_to_fill, vcos_bool_t allow_partial );
+
+   int32_t (*update_message)( VCHI_MDRIVER_HANDLE_T *handle, void *dest, int16_t *slot_count );
+   int32_t (*buffer_aligned)( VCHI_MDRIVER_HANDLE_T *handle, int tx, int uncached, const void *address, const uint32_t length );
+   void *  (*allocate_buffer)( VCHI_MDRIVER_HANDLE_T *handle, uint32_t *length );
+   void    (*free_buffer)( VCHI_MDRIVER_HANDLE_T *handle, void *address );
+   int     (*rx_slot_size)( VCHI_MDRIVER_HANDLE_T *handle, int msg_size );
+   int     (*tx_slot_size)( VCHI_MDRIVER_HANDLE_T *handle, int msg_size );
+
+   vcos_bool_t  (*tx_supports_terminate)( const VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel );
+   uint32_t (*tx_bulk_chunk_size)( const VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel );
+   int     (*tx_alignment)( const VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel );
+   int     (*rx_alignment)( const VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_RX_CHANNEL_T channel );
+   void    (*form_bulk_aux)( VCHI_MDRIVER_HANDLE_T *handle, MESSAGE_TX_CHANNEL_T channel, const void *data, uint32_t len, uint32_t chunk_size, const void **aux_data, int32_t *aux_len );
+   void    (*debug)( VCHI_MDRIVER_HANDLE_T *handle );
+};
+
+
+#endif // _VCHI_MESSAGE_H_
+
+/****************************** End of file ***********************************/
diff --git a/interface/vchi/vchi.h b/interface/vchi/vchi.h
new file mode 100755 (executable)
index 0000000..8775d07
--- /dev/null
@@ -0,0 +1,382 @@
+/*
+Copyright (c) 2012-2014, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Contains the protypes for the vchi functions.
+
+#ifndef VCHI_H_
+#define VCHI_H_
+
+#include "interface/vcos/vcos.h"
+#include "interface/vchi/vchi_cfg.h"
+#include "interface/vchi/vchi_common.h"
+#include "interface/vchi/connections/connection.h"
+#include "vchi_mh.h"
+
+
+/******************************************************************************
+ Global defs
+ *****************************************************************************/
+
+#define VCHI_SERVICE_HANDLE_INVALID 0
+
+#define VCHI_BULK_ROUND_UP(x)     ((((unsigned long)(x))+VCHI_BULK_ALIGN-1) & ~(VCHI_BULK_ALIGN-1))
+#define VCHI_BULK_ROUND_DOWN(x)   (((unsigned long)(x)) & ~(VCHI_BULK_ALIGN-1))
+#define VCHI_BULK_ALIGN_NBYTES(x) (VCHI_BULK_ALIGNED(x) ? 0 : (VCHI_BULK_ALIGN - ((unsigned long)(x) & (VCHI_BULK_ALIGN-1))))
+
+#ifdef USE_VCHIQ_ARM
+#define VCHI_BULK_ALIGNED(x)      1
+#else
+#define VCHI_BULK_ALIGNED(x)      (((unsigned long)(x) & (VCHI_BULK_ALIGN-1)) == 0)
+#endif
+
+typedef struct 
+{
+   uint32_t version;
+   uint32_t version_min;
+} VCHI_VERSION_T;
+#define VCHI_VERSION(v_) { v_, v_ }
+#define VCHI_VERSION_EX(v_,m_) { v_, m_ }
+
+typedef enum
+{
+   VCHI_VEC_POINTER,
+   VCHI_VEC_HANDLE,
+   VCHI_VEC_LIST
+} VCHI_MSG_VECTOR_TYPE_T;
+
+typedef struct vchi_msg_vector_ex {
+
+   VCHI_MSG_VECTOR_TYPE_T type;
+   union
+   {
+      // a memory handle
+      struct
+      {
+         VCHI_MEM_HANDLE_T handle;
+         uint32_t offset;
+         int32_t vec_len;
+      } handle;
+
+      // an ordinary data pointer
+      struct
+      {
+         const void *vec_base;
+         int32_t vec_len;
+      } ptr;
+
+      // a nested vector list
+      struct
+      {
+         struct vchi_msg_vector_ex *vec;
+         uint32_t vec_len;
+      } list;
+   } u;
+} VCHI_MSG_VECTOR_EX_T;
+
+
+// Construct an entry in a msg vector for a pointer (p) of length (l)
+#define VCHI_VEC_POINTER(p,l)  VCHI_VEC_POINTER, { { (VCHI_MEM_HANDLE_T)(p), (l) } }
+
+// Construct an entry in a msg vector for a message handle (h), starting at offset (o) of length (l)
+#define VCHI_VEC_HANDLE(h,o,l) VCHI_VEC_HANDLE,  { { (h), (o), (l) } }
+
+// Macros to manipulate fourcc_t values
+#define MAKE_FOURCC(x) ((fourcc_t)( (x[0] << 24) | (x[1] << 16) | (x[2] << 8) | x[3] ))
+#define FOURCC_TO_CHAR(x) (x >> 24) & 0xFF,(x >> 16) & 0xFF,(x >> 8) & 0xFF, x & 0xFF
+
+
+// Opaque service information
+struct opaque_vchi_service_t;
+
+// Descriptor for a held message. Allocated by client, initialised by vchi_msg_hold,
+// vchi_msg_iter_hold or vchi_msg_iter_hold_next. Fields are for internal VCHI use only.
+typedef struct
+{
+   struct opaque_vchi_service_t *service;
+   void *message;
+} VCHI_HELD_MSG_T;
+
+
+
+// structure used to provide the information needed to open a server or a client
+typedef struct {
+   VCHI_VERSION_T version;
+   vcos_fourcc_t service_id;
+   VCHI_CONNECTION_T *connection;
+   uint32_t rx_fifo_size;
+   uint32_t tx_fifo_size;
+   VCHI_CALLBACK_T callback;
+   void *callback_param;
+   vcos_bool_t want_unaligned_bulk_rx;    // client intends to receive bulk transfers of odd lengths or into unaligned buffers
+   vcos_bool_t want_unaligned_bulk_tx;    // client intends to transmit bulk transfers of odd lengths or out of unaligned buffers
+   vcos_bool_t want_crc;                  // client wants to check CRCs on (bulk) transfers. Only needs to be set at 1 end - will do both directions.
+} SERVICE_CREATION_T;
+
+// Opaque handle for a VCHI instance
+typedef struct opaque_vchi_instance_handle_t *VCHI_INSTANCE_T;
+
+// Opaque handle for a server or client
+typedef unsigned int VCHI_SERVICE_HANDLE_T;
+
+// Service registration & startup
+typedef void (*VCHI_SERVICE_INIT)(VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections);
+
+typedef struct service_info_tag {
+   const char * const vll_filename; /* VLL to load to start this service. This is an empty string if VLL is "static" */
+   VCHI_SERVICE_INIT init;          /* Service initialisation function */
+   void *vll_handle;                /* VLL handle; NULL when unloaded or a "static VLL" in build */
+} SERVICE_INFO_T;
+
+// Pagelist structure for copy callback
+struct pagelist_struct;
+
+/******************************************************************************
+ Global funcs - implementation is specific to which side you are on (local / remote)
+ *****************************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern /*@observer@*/ VCHI_CONNECTION_T * vchi_create_connection( const VCHI_CONNECTION_API_T * function_table,
+                                                   const VCHI_MESSAGE_DRIVER_T * low_level);
+
+
+// Routine used to initialise the vchi on both local + remote connections
+extern int32_t vchi_initialise( VCHI_INSTANCE_T *instance_handle );
+
+extern int32_t vchi_connect( VCHI_CONNECTION_T **connections,
+                             const uint32_t num_connections,
+                             VCHI_INSTANCE_T instance_handle );
+
+//When this is called, ensure that all services have no data pending.
+//Bulk transfers can remain 'queued'
+extern int32_t vchi_disconnect( VCHI_INSTANCE_T instance_handle );
+
+// Global control over bulk CRC checking
+extern int32_t vchi_crc_control( VCHI_CONNECTION_T *connection,
+                                 VCHI_CRC_CONTROL_T control );
+
+// helper functions
+extern void * vchi_allocate_buffer(VCHI_SERVICE_HANDLE_T handle, uint32_t *length);
+extern void vchi_free_buffer(VCHI_SERVICE_HANDLE_T handle, void *address);
+extern uint32_t vchi_current_time(VCHI_INSTANCE_T instance_handle);
+
+
+/******************************************************************************
+ Global service API
+ *****************************************************************************/
+// Routine to create a named service
+extern int32_t vchi_service_create( VCHI_INSTANCE_T instance_handle,
+                                    SERVICE_CREATION_T *setup,
+                                    VCHI_SERVICE_HANDLE_T *handle );
+
+// Routine to destroy a service
+extern int32_t vchi_service_destroy( const VCHI_SERVICE_HANDLE_T handle );
+
+// Routine to open a named service
+extern int32_t vchi_service_open( VCHI_INSTANCE_T instance_handle,
+                                  SERVICE_CREATION_T *setup,
+                                  VCHI_SERVICE_HANDLE_T *handle);
+
+extern int32_t vchi_get_peer_version( const VCHI_SERVICE_HANDLE_T handle,
+                                      short *peer_version );
+
+// Routine to close a named service
+extern int32_t vchi_service_close( const VCHI_SERVICE_HANDLE_T handle );
+
+// Routine to increment ref count on a named service
+extern int32_t vchi_service_use( const VCHI_SERVICE_HANDLE_T handle );
+
+// Routine to decrement ref count on a named service
+extern int32_t vchi_service_release( const VCHI_SERVICE_HANDLE_T handle );
+
+// Routine to set a control option for a named service
+extern int32_t vchi_service_set_option( const VCHI_SERVICE_HANDLE_T handle,
+                                        VCHI_SERVICE_OPTION_T option,
+                                        int value);
+
+// Routine to send a message across a service
+extern int32_t vchi_msg_queue( VCHI_SERVICE_HANDLE_T handle,
+                               const void *data,
+                               uint32_t data_size,
+                               VCHI_FLAGS_T flags,
+                               void *msg_handle );
+
+// scatter-gather (vector) and send message
+int32_t vchi_msg_queuev_ex( VCHI_SERVICE_HANDLE_T handle,
+                            VCHI_MSG_VECTOR_EX_T *vector,
+                            uint32_t count,
+                            VCHI_FLAGS_T flags,
+                            void *msg_handle );
+
+// legacy scatter-gather (vector) and send message, only handles pointers
+int32_t vchi_msg_queuev( VCHI_SERVICE_HANDLE_T handle,
+                         VCHI_MSG_VECTOR_T *vector,
+                         uint32_t count,
+                         VCHI_FLAGS_T flags,
+                         void *msg_handle );
+
+// Routine to receive a msg from a service
+// Dequeue is equivalent to hold, copy into client buffer, release
+extern int32_t vchi_msg_dequeue( VCHI_SERVICE_HANDLE_T handle,
+                                 void *data,
+                                 uint32_t max_data_size_to_read,
+                                 uint32_t *actual_msg_size,
+                                 VCHI_FLAGS_T flags );
+
+// Routine to look at a message in place.
+// The message is not dequeued, so a subsequent call to peek or dequeue
+// will return the same message.
+extern int32_t vchi_msg_peek( VCHI_SERVICE_HANDLE_T handle,
+                              void **data,
+                              uint32_t *msg_size,
+                              VCHI_FLAGS_T flags );
+
+// Routine to remove a message after it has been read in place with peek
+// The first message on the queue is dequeued.
+extern int32_t vchi_msg_remove( VCHI_SERVICE_HANDLE_T handle );
+
+// Routine to look at a message in place.
+// The message is dequeued, so the caller is left holding it; the descriptor is
+// filled in and must be released when the user has finished with the message.
+extern int32_t vchi_msg_hold( VCHI_SERVICE_HANDLE_T handle,
+                              void **data,        // } may be NULL, as info can be
+                              uint32_t *msg_size, // } obtained from HELD_MSG_T
+                              VCHI_FLAGS_T flags,
+                              VCHI_HELD_MSG_T *message_descriptor );
+
+// Initialise an iterator to look through messages in place
+extern int32_t vchi_msg_look_ahead( VCHI_SERVICE_HANDLE_T handle,
+                                    VCHI_MSG_ITER_T *iter,
+                                    VCHI_FLAGS_T flags );
+
+/******************************************************************************
+ Global service support API - operations on held messages and message iterators
+ *****************************************************************************/
+
+// Routine to get the address of a held message
+extern void *vchi_held_msg_ptr( const VCHI_HELD_MSG_T *message );
+
+// Routine to get the size of a held message
+extern int32_t vchi_held_msg_size( const VCHI_HELD_MSG_T *message );
+
+// Routine to get the transmit timestamp as written into the header by the peer
+extern uint32_t vchi_held_msg_tx_timestamp( const VCHI_HELD_MSG_T *message );
+
+// Routine to get the reception timestamp, written as we parsed the header
+extern uint32_t vchi_held_msg_rx_timestamp( const VCHI_HELD_MSG_T *message );
+
+// Routine to release a held message after it has been processed
+extern int32_t vchi_held_msg_release( VCHI_HELD_MSG_T *message );
+
+// Indicates whether the iterator has a next message.
+extern vcos_bool_t vchi_msg_iter_has_next( const VCHI_MSG_ITER_T *iter );
+
+// Return the pointer and length for the next message and advance the iterator.
+extern int32_t vchi_msg_iter_next( VCHI_MSG_ITER_T *iter,
+                                   void **data,
+                                   uint32_t *msg_size );
+
+// Remove the last message returned by vchi_msg_iter_next.
+// Can only be called once after each call to vchi_msg_iter_next.
+extern int32_t vchi_msg_iter_remove( VCHI_MSG_ITER_T *iter );
+
+// Hold the last message returned by vchi_msg_iter_next.
+// Can only be called once after each call to vchi_msg_iter_next.
+extern int32_t vchi_msg_iter_hold( VCHI_MSG_ITER_T *iter,
+                                   VCHI_HELD_MSG_T *message );
+
+// Return information for the next message, and hold it, advancing the iterator.
+extern int32_t vchi_msg_iter_hold_next( VCHI_MSG_ITER_T *iter,
+                                        void **data,        // } may be NULL
+                                        uint32_t *msg_size, // }
+                                        VCHI_HELD_MSG_T *message );
+
+
+/******************************************************************************
+ Global bulk API
+ *****************************************************************************/
+
+// Routine to prepare interface for a transfer from the other side
+extern int32_t vchi_bulk_queue_receive( VCHI_SERVICE_HANDLE_T handle,
+                                        void *data_dst,
+                                        uint32_t data_size,
+                                        VCHI_FLAGS_T flags,
+                                        void *transfer_handle );
+
+
+// Prepare interface for a transfer from the other side into relocatable memory.
+int32_t vchi_bulk_queue_receive_reloc( const VCHI_SERVICE_HANDLE_T handle,
+                                       VCHI_MEM_HANDLE_T h_dst,
+                                       uint32_t offset,
+                                       uint32_t data_size,
+                                       const VCHI_FLAGS_T flags,
+                                       void * const bulk_handle );
+
+// Prepare interface for a transfer from the other side into relocatable memory.
+int32_t vchi_bulk_queue_receive_reloc_func( const VCHI_SERVICE_HANDLE_T handle,
+                                       VCHI_MEM_HANDLE_T h_dst,
+                                       uint32_t offset,
+                                       uint32_t data_size,
+                                       const VCHI_FLAGS_T flags,
+                                       void * const bulk_handle,
+                                       int copy_pagelist(char *vcptr, const struct pagelist_struct *pagelist));
+
+// Routine to queue up data ready for transfer to the other (once they have signalled they are ready)
+extern int32_t vchi_bulk_queue_transmit( VCHI_SERVICE_HANDLE_T handle,
+                                         const void *data_src,
+                                         uint32_t data_size,
+                                         VCHI_FLAGS_T flags,
+                                         void *transfer_handle );
+
+
+/******************************************************************************
+ Configuration plumbing
+ *****************************************************************************/
+
+// function prototypes for the different mid layers (the state info gives the different physical connections)
+extern const VCHI_CONNECTION_API_T *single_get_func_table( void );
+//extern const VCHI_CONNECTION_API_T *local_server_get_func_table( void );
+//extern const VCHI_CONNECTION_API_T *local_client_get_func_table( void );
+
+// declare all message drivers here
+const VCHI_MESSAGE_DRIVER_T *vchi_mphi_message_driver_func_table( void );
+
+#ifdef __cplusplus
+}
+#endif
+
+extern int32_t vchi_bulk_queue_transmit_reloc( VCHI_SERVICE_HANDLE_T handle,
+                                               VCHI_MEM_HANDLE_T h_src,
+                                               uint32_t offset,
+                                               uint32_t data_size,
+                                               VCHI_FLAGS_T flags,
+                                               void *transfer_handle );
+#endif /* VCHI_H_ */
+
+/****************************** End of file **********************************/
diff --git a/interface/vchi/vchi_cfg.h b/interface/vchi/vchi_cfg.h
new file mode 100755 (executable)
index 0000000..d179f8a
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Contains the #defines for the number of servers / clients etc, these can be
+// over-ridden from the platform makefile if needed
+
+
+#ifndef VCHI_CFG_H_
+#define VCHI_CFG_H_
+
+/****************************************************************************************
+ * Defines in this first section are part of the VCHI API and may be examined by VCHI
+ * services.
+ ***************************************************************************************/
+
+/* Required alignment of base addresses for bulk transfer, if unaligned transfers are not enabled */
+/* Really determined by the message driver, and should be available from a run-time call. */
+#ifndef VCHI_BULK_ALIGN
+#   if __VCCOREVER__ >= 0x04000000
+#       define VCHI_BULK_ALIGN 32 // Allows for the need to do cache cleans
+#   else
+#       define VCHI_BULK_ALIGN 16
+#   endif
+#endif
+
+/* Required length multiple for bulk transfers, if unaligned transfers are not enabled */
+/* May be less than or greater than VCHI_BULK_ALIGN */
+/* Really determined by the message driver, and should be available from a run-time call. */
+#ifndef VCHI_BULK_GRANULARITY
+#   if __VCCOREVER__ >= 0x04000000
+#       define VCHI_BULK_GRANULARITY 32 // Allows for the need to do cache cleans
+#   else
+#       define VCHI_BULK_GRANULARITY 16
+#   endif
+#endif
+
+/* The largest possible message to be queued with vchi_msg_queue. */
+#ifndef VCHI_MAX_MSG_SIZE
+#   if defined VCHI_LOCAL_HOST_PORT
+#       define VCHI_MAX_MSG_SIZE     16384         // makes file transfers fast, but should they be using bulk?
+#   else
+#       define VCHI_MAX_MSG_SIZE      4096 // NOTE: THIS MUST BE LARGER THAN OR EQUAL TO THE SIZE OF THE KHRONOS MERGE BUFFER!!
+#   endif
+#endif
+
+/******************************************************************************************
+ * Defines below are system configuration options, and should not be used by VCHI services.
+ *****************************************************************************************/
+
+/* How many connections can we support? A localhost implementation uses 2 connections,
+ * 1 for host-app, 1 for VMCS, and these are hooked together by a loopback MPHI VCFW
+ * driver. */
+#ifndef VCHI_MAX_NUM_CONNECTIONS
+#   define VCHI_MAX_NUM_CONNECTIONS 3
+#endif
+
+/* How many services can we open per connection? Extending this doesn't cost processing time, just a small
+ * amount of static memory. */
+#ifndef VCHI_MAX_SERVICES_PER_CONNECTION
+#  define VCHI_MAX_SERVICES_PER_CONNECTION 36
+#endif
+
+/* Adjust if using a message driver that supports more logical TX channels */
+#ifndef VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION
+#   define VCHI_MAX_BULK_TX_CHANNELS_PER_CONNECTION 9 // 1 MPHI + 8 CCP2 logical channels
+#endif
+
+/* Adjust if using a message driver that supports more logical RX channels */
+#ifndef VCHI_MAX_BULK_RX_CHANNELS_PER_CONNECTION
+#   define VCHI_MAX_BULK_RX_CHANNELS_PER_CONNECTION 1 // 1 MPHI
+#endif
+
+/* How many receive slots do we use. This times VCHI_MAX_MSG_SIZE gives the effective
+ * receive queue space, less message headers. */
+#ifndef VCHI_NUM_READ_SLOTS
+#  if defined(VCHI_LOCAL_HOST_PORT)
+#     define VCHI_NUM_READ_SLOTS 4
+#  else
+#     define VCHI_NUM_READ_SLOTS 48
+#  endif
+#endif
+
+/* Do we utilise overrun facility for receive message slots? Can aid peer transmit
+ * performance. Only define on VideoCore end, talking to host.
+ */
+//#define VCHI_MSG_RX_OVERRUN
+
+/* How many transmit slots do we use. Generally don't need many, as the hardware driver
+ * underneath VCHI will usually have its own buffering. */
+#ifndef VCHI_NUM_WRITE_SLOTS
+#  define VCHI_NUM_WRITE_SLOTS 4
+#endif
+
+/* If a service has held or queued received messages in VCHI_XOFF_THRESHOLD or more slots,
+ * then it's taking up too much buffer space, and the peer service will be told to stop
+ * transmitting with an XOFF message. For this to be effective, the VCHI_NUM_READ_SLOTS
+ * needs to be considerably bigger than VCHI_NUM_WRITE_SLOTS, or the transmit latency
+ * is too high. */
+#ifndef VCHI_XOFF_THRESHOLD
+#  define VCHI_XOFF_THRESHOLD (VCHI_NUM_READ_SLOTS / 2)
+#endif
+
+/* After we've sent an XOFF, the peer will be told to resume transmission once the local
+ * service has dequeued/released enough messages that it's now occupying
+ * VCHI_XON_THRESHOLD slots or fewer. */
+#ifndef VCHI_XON_THRESHOLD
+#  define VCHI_XON_THRESHOLD (VCHI_NUM_READ_SLOTS / 4)
+#endif
+
+/* A size below which a bulk transfer omits the handshake completely and always goes
+ * via the message channel, if bulk auxiliary is being sent on that service. (The user
+ * can guarantee this by enabling unaligned transmits).
+ * Not API. */
+#ifndef VCHI_MIN_BULK_SIZE
+#  define VCHI_MIN_BULK_SIZE    ( VCHI_MAX_MSG_SIZE / 2 < 4096 ? VCHI_MAX_MSG_SIZE / 2 : 4096 )
+#endif
+
+/* Maximum size of bulk transmission chunks, for each interface type. A trade-off between
+ * speed and latency; the smaller the chunk size the better change of messages and other
+ * bulk transmissions getting in when big bulk transfers are happening. Set to 0 to not
+ * break transmissions into chunks.
+ */
+#ifndef VCHI_MAX_BULK_CHUNK_SIZE_MPHI
+#  define VCHI_MAX_BULK_CHUNK_SIZE_MPHI (16 * 1024)
+#endif
+
+/* NB Chunked CCP2 transmissions violate the letter of the CCP2 spec by using "JPEG8" mode
+ * with multiple-line frames. Only use if the receiver can cope. */
+#ifndef VCHI_MAX_BULK_CHUNK_SIZE_CCP2
+#  define VCHI_MAX_BULK_CHUNK_SIZE_CCP2 0
+#endif
+
+/* How many TX messages can we have pending in our transmit slots. Once exhausted,
+ * vchi_msg_queue will be blocked. */
+#ifndef VCHI_TX_MSG_QUEUE_SIZE
+#  define VCHI_TX_MSG_QUEUE_SIZE           256
+#endif
+
+/* How many RX messages can we have parsed in the receive slots. Once exhausted, parsing
+ * will be suspended until older messages are dequeued/released. */
+#ifndef VCHI_RX_MSG_QUEUE_SIZE
+#  define VCHI_RX_MSG_QUEUE_SIZE           256
+#endif
+
+/* Really should be able to cope if we run out of received message descriptors, by
+ * suspending parsing as the comment above says, but we don't. This sweeps the issue
+ * under the carpet. */
+#if VCHI_RX_MSG_QUEUE_SIZE < (VCHI_MAX_MSG_SIZE/16 + 1) * VCHI_NUM_READ_SLOTS
+#  undef VCHI_RX_MSG_QUEUE_SIZE
+#  define VCHI_RX_MSG_QUEUE_SIZE (VCHI_MAX_MSG_SIZE/16 + 1) * VCHI_NUM_READ_SLOTS
+#endif
+
+/* How many bulk transmits can we have pending. Once exhausted, vchi_bulk_queue_transmit
+ * will be blocked. */
+#ifndef VCHI_TX_BULK_QUEUE_SIZE
+#  define VCHI_TX_BULK_QUEUE_SIZE           64
+#endif
+
+/* How many bulk receives can we have pending. Once exhausted, vchi_bulk_queue_receive
+ * will be blocked. */
+#ifndef VCHI_RX_BULK_QUEUE_SIZE
+#  define VCHI_RX_BULK_QUEUE_SIZE           64
+#endif
+
+/* A limit on how many outstanding bulk requests we expect the peer to give us. If
+ * the peer asks for more than this, VCHI will fail and assert. The number is determined
+ * by the peer's hardware - it's the number of outstanding requests that can be queued
+ * on all bulk channels. VC3's MPHI peripheral allows 16. */
+#ifndef VCHI_MAX_PEER_BULK_REQUESTS
+#  define VCHI_MAX_PEER_BULK_REQUESTS       32
+#endif
+
+/* Define VCHI_CCP2TX_MANUAL_POWER if the host tells us when to turn the CCP2
+ * transmitter on and off.
+ */
+/*#define VCHI_CCP2TX_MANUAL_POWER*/
+
+#ifndef VCHI_CCP2TX_MANUAL_POWER
+
+/* Timeout (in milliseconds) for putting the CCP2TX interface into IDLE state. Set
+ * negative for no IDLE.
+ */
+#  ifndef VCHI_CCP2TX_IDLE_TIMEOUT
+#    define VCHI_CCP2TX_IDLE_TIMEOUT        5
+#  endif
+
+/* Timeout (in milliseconds) for putting the CCP2TX interface into OFF state. Set
+ * negative for no OFF.
+ */
+#  ifndef VCHI_CCP2TX_OFF_TIMEOUT
+#    define VCHI_CCP2TX_OFF_TIMEOUT         1000
+#  endif
+
+#endif /* VCHI_CCP2TX_MANUAL_POWER */
+
+#endif /* VCHI_CFG_H_ */
+
+/****************************** End of file **********************************/
diff --git a/interface/vchi/vchi_cfg_internal.h b/interface/vchi/vchi_cfg_internal.h
new file mode 100755 (executable)
index 0000000..13a0b83
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VCHI_CFG_INTERNAL_H_
+#define VCHI_CFG_INTERNAL_H_
+
+/****************************************************************************************
+ * Control optimisation attempts.
+ ***************************************************************************************/
+
+// Don't use lots of short-term locks - use great long ones, reducing the overall locks-per-second
+#define VCHI_COARSE_LOCKING
+
+// Avoid lock then unlock on exit from blocking queue operations (msg tx, bulk rx/tx)
+// (only relevant if VCHI_COARSE_LOCKING)
+#define VCHI_ELIDE_BLOCK_EXIT_LOCK
+
+// Avoid lock on non-blocking peek
+// (only relevant if VCHI_COARSE_LOCKING)
+#define VCHI_AVOID_PEEK_LOCK
+
+// Use one slot-handler thread per connection, rather than 1 thread dealing with all connections in rotation.
+#define VCHI_MULTIPLE_HANDLER_THREADS
+
+// Put free descriptors onto the head of the free queue, rather than the tail, so that we don't thrash
+// our way through the pool of descriptors.
+#define VCHI_PUSH_FREE_DESCRIPTORS_ONTO_HEAD
+
+// Don't issue a MSG_AVAILABLE callback for every single message. Possibly only safe if VCHI_COARSE_LOCKING.
+#define VCHI_FEWER_MSG_AVAILABLE_CALLBACKS
+
+// Don't use message descriptors for TX messages that don't need them
+#define VCHI_MINIMISE_TX_MSG_DESCRIPTORS
+
+// Nano-locks for multiqueue
+//#define VCHI_MQUEUE_NANOLOCKS
+
+// Lock-free(er) dequeuing
+//#define VCHI_RX_NANOLOCKS
+
+#endif /*VCHI_CFG_INTERNAL_H_*/
diff --git a/interface/vchi/vchi_common.h b/interface/vchi/vchi_common.h
new file mode 100755 (executable)
index 0000000..4942669
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+Copyright (c) 2012-2014, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Contains global defs used by submodules within vchi
+
+#ifndef VCHI_COMMON_H_
+#define VCHI_COMMON_H_
+
+
+//flags used when sending messages (must be bitmapped)
+typedef enum
+{
+   VCHI_FLAGS_NONE                      = 0x0,
+   VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE   = 0x1,   // waits for message to be received, or sent (NB. not the same as being seen on other side)
+   VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE = 0x2,   // run a callback when message sent
+   VCHI_FLAGS_BLOCK_UNTIL_QUEUED        = 0x4,   // return once the transfer is in a queue ready to go
+   VCHI_FLAGS_ALLOW_PARTIAL             = 0x8,
+   VCHI_FLAGS_BLOCK_UNTIL_DATA_READ     = 0x10,
+   VCHI_FLAGS_CALLBACK_WHEN_DATA_READ   = 0x20,
+
+   VCHI_FLAGS_ALIGN_SLOT            = 0x000080,  // internal use only
+   VCHI_FLAGS_BULK_AUX_QUEUED       = 0x010000,  // internal use only
+   VCHI_FLAGS_BULK_AUX_COMPLETE     = 0x020000,  // internal use only
+   VCHI_FLAGS_BULK_DATA_QUEUED      = 0x040000,  // internal use only
+   VCHI_FLAGS_BULK_DATA_COMPLETE    = 0x080000,  // internal use only
+   VCHI_FLAGS_INTERNAL              = 0xFF0000
+} VCHI_FLAGS_T;
+
+// constants for vchi_crc_control()
+typedef enum {
+   VCHI_CRC_NOTHING = -1,
+   VCHI_CRC_PER_SERVICE = 0,
+   VCHI_CRC_EVERYTHING = 1,
+} VCHI_CRC_CONTROL_T;
+
+//callback reasons when an event occurs on a service
+typedef enum
+{
+   VCHI_CALLBACK_REASON_MIN,
+
+   //This indicates that there is data available
+   //handle is the msg id that was transmitted with the data
+   //    When a message is received and there was no FULL message available previously, send callback
+   //    Tasks get kicked by the callback, reset their event and try and read from the fifo until it fails
+   VCHI_CALLBACK_MSG_AVAILABLE,
+   VCHI_CALLBACK_MSG_SENT,
+   VCHI_CALLBACK_MSG_SPACE_AVAILABLE, // XXX not yet implemented
+
+   // This indicates that a transfer from the other side has completed
+   VCHI_CALLBACK_BULK_RECEIVED,
+   //This indicates that data queued up to be sent has now gone
+   //handle is the msg id that was used when sending the data
+   VCHI_CALLBACK_BULK_SENT,
+   VCHI_CALLBACK_BULK_RX_SPACE_AVAILABLE, // XXX not yet implemented
+   VCHI_CALLBACK_BULK_TX_SPACE_AVAILABLE, // XXX not yet implemented
+
+   VCHI_CALLBACK_SERVICE_CLOSED,
+
+   // this side has sent XOFF to peer due to lack of data consumption by service
+   // (suggests the service may need to take some recovery action if it has
+   // been deliberately holding off consuming data)
+   VCHI_CALLBACK_SENT_XOFF,
+   VCHI_CALLBACK_SENT_XON,
+
+   // indicates that a bulk transfer has finished reading the source buffer
+   VCHI_CALLBACK_BULK_DATA_READ,
+
+   // power notification events (currently host side only)
+   VCHI_CALLBACK_PEER_OFF,
+   VCHI_CALLBACK_PEER_SUSPENDED,
+   VCHI_CALLBACK_PEER_ON,
+   VCHI_CALLBACK_PEER_RESUMED,
+   VCHI_CALLBACK_FORCED_POWER_OFF,
+
+#ifdef USE_VCHIQ_ARM
+   // some extra notifications provided by vchiq_arm
+   VCHI_CALLBACK_SERVICE_OPENED,
+   VCHI_CALLBACK_BULK_RECEIVE_ABORTED,
+   VCHI_CALLBACK_BULK_TRANSMIT_ABORTED,
+#endif
+
+   VCHI_CALLBACK_REASON_MAX
+} VCHI_CALLBACK_REASON_T;
+
+// service control options
+typedef enum
+{
+   VCHI_SERVICE_OPTION_MIN,
+
+   VCHI_SERVICE_OPTION_TRACE,
+   VCHI_SERVICE_OPTION_SYNCHRONOUS,
+
+   VCHI_SERVICE_OPTION_MAX
+} VCHI_SERVICE_OPTION_T;
+
+//Callback used by all services / bulk transfers
+typedef void (*VCHI_CALLBACK_T)( void *callback_param, //my service local param
+                                 VCHI_CALLBACK_REASON_T reason,
+                                 void *handle ); //for transmitting msg's only
+
+
+
+/*
+ * Define vector struct for scatter-gather (vector) operations
+ * Vectors can be nested - if a vector element has negative length, then
+ * the data pointer is treated as pointing to another vector array, with
+ * '-vec_len' elements. Thus to append a header onto an existing vector,
+ * you can do this:
+ *
+ * void foo(const VCHI_MSG_VECTOR_T *v, int n)
+ * {
+ *    VCHI_MSG_VECTOR_T nv[2];
+ *    nv[0].vec_base = my_header;
+ *    nv[0].vec_len = sizeof my_header;
+ *    nv[1].vec_base = v;
+ *    nv[1].vec_len = -n;
+ *    ...
+ *
+ */
+typedef struct vchi_msg_vector {
+   const void *vec_base;
+   int32_t vec_len;
+} VCHI_MSG_VECTOR_T;
+
+// Opaque type for a connection API
+typedef struct opaque_vchi_connection_api_t VCHI_CONNECTION_API_T;
+
+// Opaque type for a message driver
+typedef struct opaque_vchi_message_driver_t VCHI_MESSAGE_DRIVER_T;
+
+
+// Iterator structure for reading ahead through received message queue. Allocated by client,
+// initialised by vchi_msg_look_ahead. Fields are for internal VCHI use only.
+// Iterates over messages in queue at the instant of the call to vchi_msg_lookahead -
+// will not proceed to messages received since. Behaviour is undefined if an iterator
+// is used again after messages for that service are removed/dequeued by any
+// means other than vchi_msg_iter_... calls on the iterator itself.
+typedef struct {
+   struct opaque_vchi_service_t *service;
+   void *last;
+   void *next;
+   void *remove;
+} VCHI_MSG_ITER_T;
+
+
+#endif // VCHI_COMMON_H_
diff --git a/interface/vchi/vchi_mh.h b/interface/vchi/vchi_mh.h
new file mode 100755 (executable)
index 0000000..a8d78c8
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VCHI_MH_H_
+#define VCHI_MH_H_
+
+#include <interface/vcos/vcos.h>
+
+typedef int32_t VCHI_MEM_HANDLE_T;
+#define VCHI_MEM_HANDLE_INVALID 0
+
+#endif
diff --git a/interface/vchiq_arm/CMakeLists.txt b/interface/vchiq_arm/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..7af383d
--- /dev/null
@@ -0,0 +1,20 @@
+
+add_library(vchiq_arm SHARED
+            vchiq_lib.c vchiq_util.c)
+
+# pull in VCHI cond variable emulation
+target_link_libraries(vchiq_arm vcos)
+
+install(TARGETS vchiq_arm DESTINATION lib)
+#install(FILES etc/10-vchiq.rules DESTINATION /etc/udev/rules.d)
+
+include_directories(../..)
+
+add_executable(vchiq_test
+               vchiq_test.c)
+
+target_link_libraries(vchiq_test
+                      vchiq_arm
+                      vcos)
+
+install(TARGETS vchiq_test RUNTIME DESTINATION bin)
diff --git a/interface/vchiq_arm/vchiq.h b/interface/vchiq_arm/vchiq.h
new file mode 100755 (executable)
index 0000000..5995e82
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VCHIQ_VCHIQ_H
+#define VCHIQ_VCHIQ_H
+
+#include "vchiq_if.h"
+#include "vchiq_util.h"
+#include "interface/vcos/vcos.h"
+
+#endif
+
diff --git a/interface/vchiq_arm/vchiq_cfg.h b/interface/vchiq_arm/vchiq_cfg.h
new file mode 100755 (executable)
index 0000000..faa3e89
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+Copyright (c) 2014, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef VCHIQ_CFG_H
+#define VCHIQ_CFG_H
+
+#define VCHIQ_MAGIC              VCHIQ_MAKE_FOURCC('V', 'C', 'H', 'I')
+/* The version of VCHIQ - change with any non-trivial change */
+#define VCHIQ_VERSION            8
+/* The minimum compatible version - update to match VCHIQ_VERSION with any
+** incompatible change */
+#define VCHIQ_VERSION_MIN        3
+
+/* The version that introduced the VCHIQ_IOC_LIB_VERSION ioctl */
+#define VCHIQ_VERSION_LIB_VERSION 7
+
+/* The version that introduced the VCHIQ_IOC_CLOSE_DELIVERED ioctl */
+#define VCHIQ_VERSION_CLOSE_DELIVERED 7
+
+/* The version that made it safe to use SYNCHRONOUS mode */
+#define VCHIQ_VERSION_SYNCHRONOUS_MODE 8
+
+#define VCHIQ_MAX_STATES         2
+#define VCHIQ_MAX_SERVICES       4096
+#define VCHIQ_MAX_SLOTS          128
+#define VCHIQ_MAX_SLOTS_PER_SIDE 64
+
+#define VCHIQ_NUM_CURRENT_BULKS        32
+#define VCHIQ_NUM_SERVICE_BULKS        4
+
+#ifndef VCHIQ_ENABLE_DEBUG
+#define VCHIQ_ENABLE_DEBUG             1
+#endif
+
+#ifndef VCHIQ_ENABLE_STATS
+#define VCHIQ_ENABLE_STATS             1
+#endif
+
+#endif /* VCHIQ_CFG_H */
diff --git a/interface/vchiq_arm/vchiq_if.h b/interface/vchiq_arm/vchiq_if.h
new file mode 100755 (executable)
index 0000000..8b0630d
--- /dev/null
@@ -0,0 +1,200 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef VCHIQ_IF_H
+#define VCHIQ_IF_H
+
+#include "interface/vchi/vchi_mh.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define VCHIQ_SERVICE_HANDLE_INVALID 0
+
+#define VCHIQ_SLOT_SIZE          4096
+#define VCHIQ_MAX_MSG_SIZE       (VCHIQ_SLOT_SIZE - sizeof(VCHIQ_HEADER_T))
+#define VCHIQ_CHANNEL_SIZE       VCHIQ_MAX_MSG_SIZE /* For backwards compatibility */
+
+#define VCHIQ_MAKE_FOURCC(x0, x1, x2, x3)     (((x0) << 24) | ((x1) << 16) | ((x2) << 8) | (x3))
+#define VCHIQ_GET_SERVICE_USERDATA(service) vchiq_get_service_userdata(service)
+#define VCHIQ_GET_SERVICE_FOURCC(service)   vchiq_get_service_fourcc(service)
+
+typedef enum {
+   VCHIQ_SERVICE_OPENED,         // service, -, -
+   VCHIQ_SERVICE_CLOSED,         // service, -, -
+   VCHIQ_MESSAGE_AVAILABLE,      // service, header, -
+   VCHIQ_BULK_TRANSMIT_DONE,     // service, -, bulk_userdata
+   VCHIQ_BULK_RECEIVE_DONE,      // service, -, bulk_userdata
+   VCHIQ_BULK_TRANSMIT_ABORTED,  // service, -, bulk_userdata
+   VCHIQ_BULK_RECEIVE_ABORTED    // service, -, bulk_userdata
+} VCHIQ_REASON_T;
+
+typedef enum
+{
+   VCHIQ_ERROR   = -1,
+   VCHIQ_SUCCESS = 0,
+   VCHIQ_RETRY   = 1
+} VCHIQ_STATUS_T;
+
+typedef enum
+{
+   VCHIQ_BULK_MODE_CALLBACK,
+   VCHIQ_BULK_MODE_BLOCKING,
+   VCHIQ_BULK_MODE_NOCALLBACK
+} VCHIQ_BULK_MODE_T;
+
+typedef enum
+{
+   VCHIQ_SERVICE_OPTION_AUTOCLOSE,
+   VCHIQ_SERVICE_OPTION_SLOT_QUOTA,
+   VCHIQ_SERVICE_OPTION_MESSAGE_QUOTA,
+   VCHIQ_SERVICE_OPTION_SYNCHRONOUS,
+   VCHIQ_SERVICE_OPTION_TRACE
+} VCHIQ_SERVICE_OPTION_T;
+
+#ifdef __HIGHC__
+/* Allow zero-sized arrays without warnings */
+#pragma warning (push)
+#pragma warning (disable : 4200)
+#endif
+
+typedef struct vchiq_header_struct {
+   /* The message identifier - opaque to applications. */
+   int msgid;
+
+   /* Size of message data. */
+   unsigned int size;      
+
+   char data[0];           /* message */
+} VCHIQ_HEADER_T;
+
+#ifdef __HIGHC__
+#pragma warning (pop)
+#endif
+
+typedef struct {
+   const void *data;
+   int size;
+} VCHIQ_ELEMENT_T;
+
+typedef unsigned int VCHIQ_SERVICE_HANDLE_T;
+
+typedef VCHIQ_STATUS_T (*VCHIQ_CALLBACK_T)(VCHIQ_REASON_T, VCHIQ_HEADER_T *,
+   VCHIQ_SERVICE_HANDLE_T, void *);
+
+typedef struct vchiq_service_base_struct {
+   int fourcc;
+   VCHIQ_CALLBACK_T callback;
+   void *userdata;
+} VCHIQ_SERVICE_BASE_T;
+
+typedef struct vchiq_service_params_struct {
+   int fourcc;
+   VCHIQ_CALLBACK_T callback;
+   void *userdata;
+   short version;       /* Increment for non-trivial changes */
+   short version_min;   /* Update for incompatible changes */
+} VCHIQ_SERVICE_PARAMS_T;
+
+typedef struct vchiq_config_struct {
+   int max_msg_size;
+   int bulk_threshold; /* The message size aboce which it is better to use
+                          a bulk transfer (<= max_msg_size) */
+   int max_outstanding_bulks;
+   int max_services;
+   short version;      /* The version of VCHIQ */
+   short version_min;  /* The minimum compatible version of VCHIQ */
+} VCHIQ_CONFIG_T;
+
+typedef struct vchiq_instance_struct *VCHIQ_INSTANCE_T;
+typedef void (*VCHIQ_REMOTE_USE_CALLBACK_T)(void* cb_arg);
+struct pagelist_struct;
+
+extern VCHIQ_STATUS_T vchiq_initialise(VCHIQ_INSTANCE_T *pinstance);
+extern VCHIQ_STATUS_T vchiq_initialise_fd(VCHIQ_INSTANCE_T *pinstance, int dev_vchiq_fd);
+extern VCHIQ_STATUS_T vchiq_shutdown(VCHIQ_INSTANCE_T instance);
+extern VCHIQ_STATUS_T vchiq_connect(VCHIQ_INSTANCE_T instance);
+extern VCHIQ_STATUS_T vchiq_add_service(VCHIQ_INSTANCE_T instance,
+   const VCHIQ_SERVICE_PARAMS_T *params,
+   VCHIQ_SERVICE_HANDLE_T *pservice);
+extern VCHIQ_STATUS_T vchiq_open_service(VCHIQ_INSTANCE_T instance,
+   const VCHIQ_SERVICE_PARAMS_T *params,
+   VCHIQ_SERVICE_HANDLE_T *pservice);
+extern VCHIQ_STATUS_T vchiq_close_service(VCHIQ_SERVICE_HANDLE_T service);
+extern VCHIQ_STATUS_T vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T service);
+extern VCHIQ_STATUS_T vchiq_use_service(VCHIQ_SERVICE_HANDLE_T service);
+extern VCHIQ_STATUS_T vchiq_release_service(VCHIQ_SERVICE_HANDLE_T service);
+
+extern VCHIQ_STATUS_T vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T service,
+   const VCHIQ_ELEMENT_T *elements, int count);
+extern void           vchiq_release_message(VCHIQ_SERVICE_HANDLE_T service,
+   VCHIQ_HEADER_T *header);
+extern VCHIQ_STATUS_T vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service,
+   const void *data, int size, void *userdata);
+extern VCHIQ_STATUS_T vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T service,
+   void *data, int size, void *userdata);
+extern VCHIQ_STATUS_T vchiq_queue_bulk_transmit_handle(
+   VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle,
+   const void *offset, int size, void *userdata);
+extern VCHIQ_STATUS_T vchiq_queue_bulk_receive_handle(
+   VCHIQ_SERVICE_HANDLE_T service, VCHI_MEM_HANDLE_T handle,
+   void *offset, int size, void *userdata);
+extern VCHIQ_STATUS_T vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T service,
+   const void *data, int size, void *userdata, VCHIQ_BULK_MODE_T mode);
+extern VCHIQ_STATUS_T vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T service,
+   void *data, int size, void *userdata, VCHIQ_BULK_MODE_T mode);
+extern VCHIQ_STATUS_T vchiq_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T service,
+   VCHI_MEM_HANDLE_T handle, const void *offset, int size, void *userdata,
+   VCHIQ_BULK_MODE_T mode);
+extern VCHIQ_STATUS_T vchiq_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T service,
+   VCHI_MEM_HANDLE_T handle, void *offset, int size, void *userdata,
+   VCHIQ_BULK_MODE_T mode,
+   int copy_pagelist(char *vcptr, const struct pagelist_struct *pagelist));
+extern int   vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T service);
+extern void *vchiq_get_service_userdata(VCHIQ_SERVICE_HANDLE_T service);
+extern int   vchiq_get_service_fourcc(VCHIQ_SERVICE_HANDLE_T service);
+extern VCHIQ_STATUS_T vchiq_get_config(VCHIQ_INSTANCE_T instance,
+   int config_size, VCHIQ_CONFIG_T *pconfig);
+extern VCHIQ_STATUS_T vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T service,
+   VCHIQ_SERVICE_OPTION_T option, int value);
+
+extern VCHIQ_STATUS_T vchiq_remote_use(VCHIQ_INSTANCE_T instance,
+   VCHIQ_REMOTE_USE_CALLBACK_T callback, void *cb_arg);
+extern VCHIQ_STATUS_T vchiq_remote_release(VCHIQ_INSTANCE_T instance);
+
+extern VCHIQ_STATUS_T vchiq_dump_phys_mem(VCHIQ_SERVICE_HANDLE_T service,
+   void *ptr, size_t num_bytes);
+
+extern VCHIQ_STATUS_T vchiq_get_peer_version(VCHIQ_SERVICE_HANDLE_T handle,
+      short *peer_version);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* VCHIQ_IF_H */
diff --git a/interface/vchiq_arm/vchiq_ioctl.h b/interface/vchiq_arm/vchiq_ioctl.h
new file mode 100755 (executable)
index 0000000..dab4a8b
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef VCHIQ_IOCTLS_H
+#define VCHIQ_IOCTLS_H
+
+#include <linux/ioctl.h>
+#include "vchiq_if.h"
+
+#define VCHIQ_IOC_MAGIC 0xc4
+#define VCHIQ_INVALID_HANDLE (~0)
+
+typedef struct {
+   VCHIQ_SERVICE_PARAMS_T params;
+   int is_open;
+   int is_vchi;
+   unsigned int handle;       /* OUT */
+} VCHIQ_CREATE_SERVICE_T;
+
+typedef struct {
+   unsigned int handle;
+   unsigned int count;
+   const VCHIQ_ELEMENT_T *elements;
+} VCHIQ_QUEUE_MESSAGE_T;
+
+typedef struct {
+   unsigned int handle;
+   void *data;
+   unsigned int size;
+   void *userdata;
+   VCHIQ_BULK_MODE_T mode;
+} VCHIQ_QUEUE_BULK_TRANSFER_T;
+
+typedef struct {
+   VCHIQ_REASON_T reason;
+   VCHIQ_HEADER_T *header;
+   void *service_userdata;
+   void *bulk_userdata;
+} VCHIQ_COMPLETION_DATA_T;
+
+typedef struct {
+   unsigned int count;
+   VCHIQ_COMPLETION_DATA_T *buf;
+   unsigned int msgbufsize;
+   unsigned int msgbufcount; /* IN/OUT */
+   void **msgbufs;
+} VCHIQ_AWAIT_COMPLETION_T;
+
+typedef struct {
+   unsigned int handle;
+   int blocking;
+   unsigned int bufsize;
+   void *buf;
+} VCHIQ_DEQUEUE_MESSAGE_T;
+
+typedef struct {
+   unsigned int config_size;
+   VCHIQ_CONFIG_T *pconfig;
+} VCHIQ_GET_CONFIG_T;
+
+typedef struct {
+   unsigned int handle;
+   VCHIQ_SERVICE_OPTION_T option;
+   int value;
+} VCHIQ_SET_SERVICE_OPTION_T;
+
+typedef struct {
+   void     *virt_addr;
+   size_t    num_bytes;
+} VCHIQ_DUMP_MEM_T;
+
+#define VCHIQ_IOC_CONNECT              _IO(VCHIQ_IOC_MAGIC,   0)
+#define VCHIQ_IOC_SHUTDOWN             _IO(VCHIQ_IOC_MAGIC,   1)
+#define VCHIQ_IOC_CREATE_SERVICE       _IOWR(VCHIQ_IOC_MAGIC, 2, VCHIQ_CREATE_SERVICE_T)
+#define VCHIQ_IOC_REMOVE_SERVICE       _IO(VCHIQ_IOC_MAGIC,   3)
+#define VCHIQ_IOC_QUEUE_MESSAGE        _IOW(VCHIQ_IOC_MAGIC,  4, VCHIQ_QUEUE_MESSAGE_T)
+#define VCHIQ_IOC_QUEUE_BULK_TRANSMIT  _IOWR(VCHIQ_IOC_MAGIC, 5, VCHIQ_QUEUE_BULK_TRANSFER_T)
+#define VCHIQ_IOC_QUEUE_BULK_RECEIVE   _IOWR(VCHIQ_IOC_MAGIC, 6, VCHIQ_QUEUE_BULK_TRANSFER_T)
+#define VCHIQ_IOC_AWAIT_COMPLETION     _IOWR(VCHIQ_IOC_MAGIC, 7, VCHIQ_AWAIT_COMPLETION_T)
+#define VCHIQ_IOC_DEQUEUE_MESSAGE      _IOWR(VCHIQ_IOC_MAGIC, 8, VCHIQ_DEQUEUE_MESSAGE_T)
+#define VCHIQ_IOC_GET_CLIENT_ID        _IO(VCHIQ_IOC_MAGIC,   9)
+#define VCHIQ_IOC_GET_CONFIG           _IOWR(VCHIQ_IOC_MAGIC, 10, VCHIQ_GET_CONFIG_T)
+#define VCHIQ_IOC_CLOSE_SERVICE        _IO(VCHIQ_IOC_MAGIC,   11)
+#define VCHIQ_IOC_USE_SERVICE          _IO(VCHIQ_IOC_MAGIC,   12)
+#define VCHIQ_IOC_RELEASE_SERVICE      _IO(VCHIQ_IOC_MAGIC,   13)
+#define VCHIQ_IOC_SET_SERVICE_OPTION   _IOW(VCHIQ_IOC_MAGIC,  14, VCHIQ_SET_SERVICE_OPTION_T)
+#define VCHIQ_IOC_DUMP_PHYS_MEM        _IOW(VCHIQ_IOC_MAGIC,  15, VCHIQ_DUMP_MEM_T)
+#define VCHIQ_IOC_LIB_VERSION          _IO(VCHIQ_IOC_MAGIC,   16)
+#define VCHIQ_IOC_CLOSE_DELIVERED      _IO(VCHIQ_IOC_MAGIC,   17)
+#define VCHIQ_IOC_MAX                  17
+
+#endif
diff --git a/interface/vchiq_arm/vchiq_lib.c b/interface/vchiq_arm/vchiq_lib.c
new file mode 100755 (executable)
index 0000000..133d5ca
--- /dev/null
@@ -0,0 +1,1764 @@
+/*
+Copyright (c) 2012-2014, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+
+#include "vchiq.h"
+#include "vchiq_cfg.h"
+#include "vchiq_ioctl.h"
+#include "interface/vchi/vchi.h"
+#include "interface/vchi/common/endian.h"
+#include "interface/vcos/vcos.h"
+
+#define IS_POWER_2(x) ((x & (x - 1)) == 0)
+#define VCHIQ_MAX_INSTANCE_SERVICES 32
+#define MSGBUF_SIZE (VCHIQ_MAX_MSG_SIZE + sizeof(VCHIQ_HEADER_T))
+
+#define RETRY(r,x) do { r = x; } while ((r == -1) && (errno == EINTR))
+
+#define VCOS_LOG_CATEGORY (&vchiq_lib_log_category)
+
+typedef struct vchiq_service_struct
+{
+   VCHIQ_SERVICE_BASE_T base;
+   VCHIQ_SERVICE_HANDLE_T handle;
+   VCHIQ_SERVICE_HANDLE_T lib_handle;
+   int fd;
+   VCHI_CALLBACK_T vchi_callback;
+   void *peek_buf;
+   int peek_size;
+   int client_id;
+   char is_client;
+} VCHIQ_SERVICE_T;
+
+typedef struct vchiq_service_struct VCHI_SERVICE_T;
+
+struct vchiq_instance_struct
+{
+   int fd;
+   int initialised;
+   int connected;
+   int use_close_delivered;
+   VCOS_THREAD_T completion_thread;
+   VCOS_MUTEX_T mutex;
+   int used_services;
+   VCHIQ_SERVICE_T services[VCHIQ_MAX_INSTANCE_SERVICES];
+} vchiq_instance;
+
+typedef struct vchiq_instance_struct VCHI_STATE_T;
+
+/* Local data */
+static VCOS_LOG_LEVEL_T vchiq_default_lib_log_level = VCOS_LOG_WARN;
+static VCOS_LOG_CAT_T vchiq_lib_log_category;
+static VCOS_MUTEX_T vchiq_lib_mutex;
+static void *free_msgbufs;
+static unsigned int handle_seq;
+
+vcos_static_assert(IS_POWER_2(VCHIQ_MAX_INSTANCE_SERVICES));
+
+/* Local utility functions */
+static VCHIQ_INSTANCE_T
+vchiq_lib_init(const int dev_vchiq_fd);
+
+static void *completion_thread(void *);
+
+static VCHIQ_STATUS_T
+create_service(VCHIQ_INSTANCE_T instance,
+   const VCHIQ_SERVICE_PARAMS_T *params,
+   VCHI_CALLBACK_T vchi_callback,
+   int is_open,
+   VCHIQ_SERVICE_HANDLE_T *phandle);
+
+static int
+fill_peek_buf(VCHI_SERVICE_T *service,
+   VCHI_FLAGS_T flags);
+
+static void *
+alloc_msgbuf(void);
+
+static void
+free_msgbuf(void *buf);
+
+static __inline int
+is_valid_instance(VCHIQ_INSTANCE_T instance)
+{
+   return (instance == &vchiq_instance) && (instance->initialised > 0);
+}
+
+static inline VCHIQ_SERVICE_T *
+handle_to_service(VCHIQ_SERVICE_HANDLE_T handle)
+{
+   return &vchiq_instance.services[handle & (VCHIQ_MAX_INSTANCE_SERVICES - 1)];
+}
+
+static VCHIQ_SERVICE_T *
+find_service_by_handle(VCHIQ_SERVICE_HANDLE_T handle)
+{
+   VCHIQ_SERVICE_T *service;
+
+   service = handle_to_service(handle);
+   if (service && (service->lib_handle != handle))
+      service = NULL;
+
+   if (!service)
+      vcos_log_info("Invalid service handle 0x%x", handle);
+
+   return service;
+}
+
+/*
+ * VCHIQ API
+ */
+
+// If dev_vchiq_fd == -1 then /dev/vchiq will be opened by this fn (as normal)
+//
+// Otherwise the given fd will be used.  N.B. in this case the fd is duped
+// so the caller will probably want to close whatever fd was passed once
+// this call has returned.  This slightly odd behaviour makes shutdown and
+// error cases much simpler.
+VCHIQ_STATUS_T
+vchiq_initialise_fd(VCHIQ_INSTANCE_T *pinstance, int dev_vchiq_fd)
+{
+   VCHIQ_INSTANCE_T instance;
+
+   instance = vchiq_lib_init(dev_vchiq_fd);
+
+   vcos_log_trace( "%s: returning instance handle %p", __func__, instance );
+
+   *pinstance = instance;
+
+   return (instance != NULL) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
+}
+
+VCHIQ_STATUS_T
+vchiq_initialise(VCHIQ_INSTANCE_T *pinstance)
+{
+   return vchiq_initialise_fd(pinstance, -1);
+}
+
+VCHIQ_STATUS_T
+vchiq_shutdown(VCHIQ_INSTANCE_T instance)
+{
+   vcos_log_trace( "%s called", __func__ );
+
+   if (!is_valid_instance(instance))
+      return VCHIQ_ERROR;
+
+   vcos_mutex_lock(&instance->mutex);
+
+   if (instance->initialised == 1)
+   {
+      int i;
+
+      instance->initialised = -1; /* Enter limbo */
+
+      /* Remove all services */
+
+      for (i = 0; i < instance->used_services; i++)
+      {
+         if (instance->services[i].lib_handle != VCHIQ_SERVICE_HANDLE_INVALID)
+         {
+            vchiq_remove_service(instance->services[i].lib_handle);
+            instance->services[i].lib_handle = VCHIQ_SERVICE_HANDLE_INVALID;
+         }
+      }
+
+      if (instance->connected)
+      {
+         int ret;
+         RETRY(ret, ioctl(instance->fd, VCHIQ_IOC_SHUTDOWN, 0));
+         vcos_assert(ret == 0);
+         vcos_thread_join(&instance->completion_thread, NULL);
+         instance->connected = 0;
+      }
+
+      close(instance->fd);
+      instance->fd = -1;
+   }
+   else if (instance->initialised > 1)
+   {
+      instance->initialised--;
+   }
+
+   vcos_mutex_unlock(&instance->mutex);
+
+   vcos_global_lock();
+
+   if (instance->initialised == -1)
+   {
+      vcos_mutex_delete(&instance->mutex);
+      instance->initialised = 0;
+   }
+
+   vcos_global_unlock();
+
+   vcos_log_trace( "%s returning", __func__ );
+
+   vcos_log_unregister(&vchiq_lib_log_category);
+
+   return VCHIQ_SUCCESS;
+}
+
+VCHIQ_STATUS_T
+vchiq_connect(VCHIQ_INSTANCE_T instance)
+{
+   VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
+   VCOS_THREAD_ATTR_T attrs;
+   int ret;
+
+   vcos_log_trace( "%s called", __func__ );
+
+   if (!is_valid_instance(instance))
+      return VCHIQ_ERROR;
+
+   vcos_mutex_lock(&instance->mutex);
+
+   if (instance->connected)
+      goto out;
+
+   ret = ioctl(instance->fd, VCHIQ_IOC_CONNECT, 0);
+   if (ret != 0)
+   {
+      status = VCHIQ_ERROR;
+      goto out;
+   }
+
+   vcos_thread_attr_init(&attrs);
+   if (vcos_thread_create(&instance->completion_thread, "VCHIQ completion",
+                          &attrs, completion_thread, instance) != VCOS_SUCCESS)
+   {
+      status = VCHIQ_ERROR;
+      goto out;
+   }
+
+   instance->connected = 1;
+
+out:
+   vcos_mutex_unlock(&instance->mutex);
+   return status;
+}
+
+VCHIQ_STATUS_T
+vchiq_add_service(VCHIQ_INSTANCE_T instance,
+   const VCHIQ_SERVICE_PARAMS_T *params,
+   VCHIQ_SERVICE_HANDLE_T *phandle)
+{
+   VCHIQ_STATUS_T status;
+
+   vcos_log_trace( "%s called fourcc = 0x%08x (%c%c%c%c)",
+                   __func__,
+                   params->fourcc,
+                   (params->fourcc >> 24) & 0xff,
+                   (params->fourcc >> 16) & 0xff,
+                   (params->fourcc >>  8) & 0xff,
+                   (params->fourcc      ) & 0xff );
+
+   if (!params->callback)
+      return VCHIQ_ERROR;
+
+   if (!is_valid_instance(instance))
+      return VCHIQ_ERROR;
+
+   status = create_service(instance,
+      params,
+      NULL/*vchi_callback*/,
+      0/*!open*/,
+      phandle);
+
+   vcos_log_trace( "%s returning service handle = 0x%08x", __func__, (uint32_t)*phandle );
+
+   return status;
+}
+
+VCHIQ_STATUS_T
+vchiq_open_service(VCHIQ_INSTANCE_T instance,
+   const VCHIQ_SERVICE_PARAMS_T *params,
+   VCHIQ_SERVICE_HANDLE_T *phandle)
+{
+   VCHIQ_STATUS_T status;
+
+   vcos_log_trace( "%s called fourcc = 0x%08x (%c%c%c%c)",
+                   __func__,
+                   params->fourcc,
+                   (params->fourcc >> 24) & 0xff,
+                   (params->fourcc >> 16) & 0xff,
+                   (params->fourcc >>  8) & 0xff,
+                   (params->fourcc      ) & 0xff );
+
+   if (!params->callback)
+      return VCHIQ_ERROR;
+
+   if (!is_valid_instance(instance))
+      return VCHIQ_ERROR;
+
+   status = create_service(instance,
+      params,
+      NULL/*vchi_callback*/,
+      1/*open*/,
+      phandle);
+
+   vcos_log_trace( "%s returning service handle = 0x%08x", __func__, (uint32_t)*phandle );
+
+   return status;
+}
+
+VCHIQ_STATUS_T
+vchiq_close_service(VCHIQ_SERVICE_HANDLE_T handle)
+{
+   VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
+   int ret;
+
+   vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   RETRY(ret,ioctl(service->fd, VCHIQ_IOC_CLOSE_SERVICE, service->handle));
+
+   if (service->is_client)
+      service->lib_handle = VCHIQ_SERVICE_HANDLE_INVALID;
+
+   if (ret != 0)
+      return VCHIQ_ERROR;
+
+   return VCHIQ_SUCCESS;
+}
+
+VCHIQ_STATUS_T
+vchiq_remove_service(VCHIQ_SERVICE_HANDLE_T handle)
+{
+   VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
+   int ret;
+
+   vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   RETRY(ret,ioctl(service->fd, VCHIQ_IOC_REMOVE_SERVICE, service->handle));
+
+   service->lib_handle = VCHIQ_SERVICE_HANDLE_INVALID;
+
+   if (ret != 0)
+      return VCHIQ_ERROR;
+
+   return VCHIQ_SUCCESS;
+}
+
+VCHIQ_STATUS_T
+vchiq_queue_message(VCHIQ_SERVICE_HANDLE_T handle,
+   const VCHIQ_ELEMENT_T *elements,
+   int count)
+{
+   VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
+   VCHIQ_QUEUE_MESSAGE_T args;
+   int ret;
+
+   vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   args.handle = service->handle;
+   args.elements = elements;
+   args.count = count;
+   RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_MESSAGE, &args));
+
+   return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
+}
+
+void
+vchiq_release_message(VCHIQ_SERVICE_HANDLE_T handle,
+   VCHIQ_HEADER_T *header)
+{
+   vcos_log_trace( "%s handle=%08x, header=%x", __func__, (uint32_t)handle, (uint32_t)header );
+
+   free_msgbuf(header);
+}
+
+VCHIQ_STATUS_T
+vchiq_queue_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
+   const void *data,
+   int size,
+   void *userdata)
+{
+   VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
+   VCHIQ_QUEUE_BULK_TRANSFER_T args;
+   int ret;
+
+   vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   args.handle = service->handle;
+   args.data = (void *)data;
+   args.size = size;
+   args.userdata = userdata;
+   args.mode = VCHIQ_BULK_MODE_CALLBACK;
+   RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_BULK_TRANSMIT, &args));
+
+   return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
+}
+
+VCHIQ_STATUS_T
+vchiq_queue_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle,
+   void *data,
+   int size,
+   void *userdata)
+{
+   VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
+   VCHIQ_QUEUE_BULK_TRANSFER_T args;
+   int ret;
+
+   vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   args.handle = service->handle;
+   args.data = data;
+   args.size = size;
+   args.userdata = userdata;
+   args.mode = VCHIQ_BULK_MODE_CALLBACK;
+   RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_BULK_RECEIVE, &args));
+
+   return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
+}
+
+VCHIQ_STATUS_T
+vchiq_queue_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T handle,
+   VCHI_MEM_HANDLE_T memhandle,
+   const void *offset,
+   int size,
+   void *userdata)
+{
+   vcos_assert(memhandle == VCHI_MEM_HANDLE_INVALID);
+
+   vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
+
+   return vchiq_queue_bulk_transmit(handle, offset, size, userdata);
+}
+
+VCHIQ_STATUS_T
+vchiq_queue_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T handle,
+   VCHI_MEM_HANDLE_T memhandle,
+   void *offset,
+   int size,
+   void *userdata)
+{
+   vcos_assert(memhandle == VCHI_MEM_HANDLE_INVALID);
+
+   vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
+
+   return vchiq_queue_bulk_receive(handle, offset, size, userdata);
+}
+
+VCHIQ_STATUS_T
+vchiq_bulk_transmit(VCHIQ_SERVICE_HANDLE_T handle,
+   const void *data,
+   int size,
+   void *userdata,
+   VCHIQ_BULK_MODE_T mode)
+{
+   VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
+   VCHIQ_QUEUE_BULK_TRANSFER_T args;
+   int ret;
+
+   vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   args.handle = service->handle;
+   args.data = (void *)data;
+   args.size = size;
+   args.userdata = userdata;
+   args.mode = mode;
+   RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_BULK_TRANSMIT, &args));
+
+   return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
+}
+
+VCHIQ_STATUS_T
+vchiq_bulk_receive(VCHIQ_SERVICE_HANDLE_T handle,
+   void *data,
+   int size,
+   void *userdata,
+   VCHIQ_BULK_MODE_T mode)
+{
+   return vchiq_bulk_receive_handle(handle, VCHI_MEM_HANDLE_INVALID, data, size, userdata, mode, NULL);
+}
+
+VCHIQ_STATUS_T
+vchiq_bulk_transmit_handle(VCHIQ_SERVICE_HANDLE_T handle,
+   VCHI_MEM_HANDLE_T memhandle,
+   const void *offset,
+   int size,
+   void *userdata,
+   VCHIQ_BULK_MODE_T mode)
+{
+   vcos_assert(memhandle == VCHI_MEM_HANDLE_INVALID);
+
+   return vchiq_bulk_transmit(handle, offset, size, userdata, mode);
+}
+
+VCHIQ_STATUS_T
+vchiq_bulk_receive_handle(VCHIQ_SERVICE_HANDLE_T handle,
+   VCHI_MEM_HANDLE_T memhandle,
+   void *offset,
+   int size,
+   void *userdata,
+   VCHIQ_BULK_MODE_T mode,
+   int (*copy_pagelist)())
+{
+   VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
+   VCHIQ_QUEUE_BULK_TRANSFER_T args;
+   int ret;
+
+   vcos_assert(memhandle == VCHI_MEM_HANDLE_INVALID);
+
+   vcos_log_trace( "%s called service handle = 0x%08x", __func__, (uint32_t)handle );
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   args.handle = service->handle;
+   args.data = offset;
+   args.size = size;
+   args.userdata = userdata;
+   args.mode = mode;
+   RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_BULK_RECEIVE, &args));
+
+   return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
+}
+
+int
+vchiq_get_client_id(VCHIQ_SERVICE_HANDLE_T handle)
+{
+   VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   return ioctl(service->fd, VCHIQ_IOC_GET_CLIENT_ID, service->handle);
+}
+
+void *
+vchiq_get_service_userdata(VCHIQ_SERVICE_HANDLE_T handle)
+{
+   VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
+
+   return service ? service->base.userdata : NULL;
+}
+
+int
+vchiq_get_service_fourcc(VCHIQ_SERVICE_HANDLE_T handle)
+{
+   VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
+
+   return service ? service->base.fourcc : 0;
+}
+
+VCHIQ_STATUS_T
+vchiq_get_config(VCHIQ_INSTANCE_T instance,
+   int config_size,
+   VCHIQ_CONFIG_T *pconfig)
+{
+   VCHIQ_GET_CONFIG_T args;
+   int ret;
+
+   if (!is_valid_instance(instance))
+      return VCHIQ_ERROR;
+
+   args.config_size = config_size;
+   args.pconfig = pconfig;
+
+   RETRY(ret, ioctl(instance->fd, VCHIQ_IOC_GET_CONFIG, &args));
+
+   return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
+}
+
+int32_t
+vchiq_use_service( const VCHIQ_SERVICE_HANDLE_T handle )
+{
+   VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
+   int ret;
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   RETRY(ret,ioctl(service->fd, VCHIQ_IOC_USE_SERVICE, service->handle));
+   return ret;
+}
+
+int32_t
+vchiq_release_service( const VCHIQ_SERVICE_HANDLE_T handle )
+{
+   VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
+   int ret;
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   RETRY(ret,ioctl(service->fd, VCHIQ_IOC_RELEASE_SERVICE, service->handle));
+   return ret;
+}
+
+VCHIQ_STATUS_T
+vchiq_set_service_option(VCHIQ_SERVICE_HANDLE_T handle,
+   VCHIQ_SERVICE_OPTION_T option, int value)
+{
+   VCHIQ_SET_SERVICE_OPTION_T args;
+   VCHIQ_SERVICE_T *service = find_service_by_handle(handle);
+   int ret;
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   args.handle = service->handle;
+   args.option = option;
+   args.value  = value;
+
+   RETRY(ret, ioctl(service->fd, VCHIQ_IOC_SET_SERVICE_OPTION, &args));
+
+   return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
+}
+
+/*
+ * VCHI API
+ */
+
+/* ----------------------------------------------------------------------
+ * return pointer to the mphi message driver function table
+ * -------------------------------------------------------------------- */
+const VCHI_MESSAGE_DRIVER_T *
+vchi_mphi_message_driver_func_table( void )
+{
+   return NULL;
+}
+
+/* ----------------------------------------------------------------------
+ * return a pointer to the 'single' connection driver fops
+ * -------------------------------------------------------------------- */
+const VCHI_CONNECTION_API_T *
+single_get_func_table( void )
+{
+   return NULL;
+}
+
+VCHI_CONNECTION_T *
+vchi_create_connection( const VCHI_CONNECTION_API_T * function_table,
+   const VCHI_MESSAGE_DRIVER_T * low_level )
+{
+   vcos_unused(function_table);
+   vcos_unused(low_level);
+
+   return NULL;
+}
+
+/***********************************************************
+ * Name: vchi_msg_peek
+ *
+ * Arguments:  const VCHI_SERVICE_HANDLE_T handle,
+ *             void **data,
+ *             uint32_t *msg_size,
+ *             VCHI_FLAGS_T flags
+ *
+ * Description: Routine to return a pointer to the current message (to allow in place processing)
+ *              The message can be removed using vchi_msg_remove when you're finished
+ *
+ * Returns: int32_t - success == 0
+ *
+ ***********************************************************/
+int32_t
+vchi_msg_peek( VCHI_SERVICE_HANDLE_T handle,
+   void **data,
+   uint32_t *msg_size,
+   VCHI_FLAGS_T flags )
+{
+   VCHI_SERVICE_T *service = find_service_by_handle(handle);
+   int ret;
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   ret = fill_peek_buf(service, flags);
+
+   if (ret == 0)
+   {
+      *data = service->peek_buf;
+      *msg_size = service->peek_size;
+   }
+
+   return ret;
+}
+
+/***********************************************************
+ * Name: vchi_msg_remove
+ *
+ * Arguments:  const VCHI_SERVICE_HANDLE_T handle,
+ *
+ * Description: Routine to remove a message (after it has been read with vchi_msg_peek)
+ *
+ * Returns: int32_t - success == 0
+ *
+ ***********************************************************/
+int32_t
+vchi_msg_remove( VCHI_SERVICE_HANDLE_T handle )
+{
+   VCHI_SERVICE_T *service = find_service_by_handle(handle);
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   /* Why would you call vchi_msg_remove without calling vchi_msg_peek first? */
+   vcos_assert(service->peek_size >= 0);
+
+   /* Invalidate the content but reuse the buffer */
+   service->peek_size = -1;
+
+   return 0;
+}
+
+/***********************************************************
+ * Name: vchi_msg_queue
+ *
+ * Arguments:  VCHI_SERVICE_HANDLE_T handle,
+ *             const void *data,
+ *             uint32_t data_size,
+ *             VCHI_FLAGS_T flags,
+ *             void *msg_handle,
+ *
+ * Description: Thin wrapper to queue a message onto a connection
+ *
+ * Returns: int32_t - success == 0
+ *
+ ***********************************************************/
+int32_t
+vchi_msg_queue( VCHI_SERVICE_HANDLE_T handle,
+   const void * data,
+   uint32_t data_size,
+   VCHI_FLAGS_T flags,
+   void * msg_handle )
+{
+   VCHI_SERVICE_T *service = find_service_by_handle(handle);
+   VCHIQ_QUEUE_MESSAGE_T args;
+   VCHIQ_ELEMENT_T element = {data, data_size};
+   int ret;
+
+   vcos_unused(msg_handle);
+   vcos_assert(flags == VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   args.handle = service->handle;
+   args.elements = &element;
+   args.count = 1;
+   RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_MESSAGE, &args));
+
+   return ret;
+}
+
+/***********************************************************
+ * Name: vchi_bulk_queue_receive
+ *
+ * Arguments:  VCHI_BULK_HANDLE_T handle,
+ *             void *data_dst,
+ *             const uint32_t data_size,
+ *             VCHI_FLAGS_T flags
+ *             void *bulk_handle
+ *
+ * Description: Routine to setup a rcv buffer
+ *
+ * Returns: int32_t - success == 0
+ *
+ ***********************************************************/
+int32_t
+vchi_bulk_queue_receive( VCHI_SERVICE_HANDLE_T handle,
+   void * data_dst,
+   uint32_t data_size,
+   VCHI_FLAGS_T flags,
+   void * bulk_handle )
+{
+   VCHI_SERVICE_T *service = find_service_by_handle(handle);
+   VCHIQ_QUEUE_BULK_TRANSFER_T args;
+   int ret;
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   switch ((int)flags) {
+   case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
+      args.mode = VCHIQ_BULK_MODE_CALLBACK;
+      break;
+   case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
+      args.mode = VCHIQ_BULK_MODE_BLOCKING;
+      break;
+   case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
+   case VCHI_FLAGS_NONE:
+      args.mode = VCHIQ_BULK_MODE_NOCALLBACK;
+      break;
+   default:
+      vcos_assert(0);
+      break;
+   }
+
+   args.handle = service->handle;
+   args.data = data_dst;
+   args.size = data_size;
+   args.userdata = bulk_handle;
+   RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_BULK_RECEIVE, &args));
+
+   return ret;
+}
+
+/***********************************************************
+ * Name: vchi_bulk_queue_transmit
+ *
+ * Arguments:  VCHI_BULK_HANDLE_T handle,
+ *             const void *data_src,
+ *             uint32_t data_size,
+ *             VCHI_FLAGS_T flags,
+ *             void *bulk_handle
+ *
+ * Description: Routine to transmit some data
+ *
+ * Returns: int32_t - success == 0
+ *
+ ***********************************************************/
+int32_t
+vchi_bulk_queue_transmit( VCHI_SERVICE_HANDLE_T handle,
+   const void * data_src,
+   uint32_t data_size,
+   VCHI_FLAGS_T flags,
+   void * bulk_handle )
+{
+   VCHI_SERVICE_T *service = find_service_by_handle(handle);
+   VCHIQ_QUEUE_BULK_TRANSFER_T args;
+   int ret;
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   switch ((int)flags) {
+   case VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
+      args.mode = VCHIQ_BULK_MODE_CALLBACK;
+      break;
+   case VCHI_FLAGS_BLOCK_UNTIL_DATA_READ:
+   case VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE:
+      args.mode = VCHIQ_BULK_MODE_BLOCKING;
+      break;
+   case VCHI_FLAGS_BLOCK_UNTIL_QUEUED:
+   case VCHI_FLAGS_NONE:
+      args.mode = VCHIQ_BULK_MODE_NOCALLBACK;
+      break;
+   default:
+      vcos_assert(0);
+      break;
+   }
+
+   args.handle = service->handle;
+   args.data = (void *)data_src;
+   args.size = data_size;
+   args.userdata = bulk_handle;
+   RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_BULK_TRANSMIT, &args));
+
+   return ret;
+}
+
+/***********************************************************
+ * Name: vchi_msg_dequeue
+ *
+ * Arguments:  VCHI_SERVICE_HANDLE_T handle,
+ *             void *data,
+ *             uint32_t max_data_size_to_read,
+ *             uint32_t *actual_msg_size
+ *             VCHI_FLAGS_T flags
+ *
+ * Description: Routine to dequeue a message into the supplied buffer
+ *
+ * Returns: int32_t - success == 0
+ *
+ ***********************************************************/
+int32_t
+vchi_msg_dequeue( VCHI_SERVICE_HANDLE_T handle,
+   void *data,
+   uint32_t max_data_size_to_read,
+   uint32_t *actual_msg_size,
+   VCHI_FLAGS_T flags )
+{
+   VCHI_SERVICE_T *service = find_service_by_handle(handle);
+   VCHIQ_DEQUEUE_MESSAGE_T args;
+   int ret;
+
+   vcos_assert(flags == VCHI_FLAGS_NONE || flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   if (service->peek_size >= 0)
+   {
+      vcos_log_error("vchi_msg_dequeue -> using peek buffer\n");
+      if ((uint32_t)service->peek_size <= max_data_size_to_read)
+      {
+         memcpy(data, service->peek_buf, service->peek_size);
+         *actual_msg_size = service->peek_size;
+         /* Invalidate the peek data, but retain the buffer */
+         service->peek_size = -1;
+         ret = 0;
+      }
+      else
+      {
+         ret = -1;
+      }
+   }
+   else
+   {
+      args.handle = service->handle;
+      args.blocking = (flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
+      args.bufsize = max_data_size_to_read;
+      args.buf = data;
+      RETRY(ret, ioctl(service->fd, VCHIQ_IOC_DEQUEUE_MESSAGE, &args));
+      if (ret >= 0)
+      {
+         *actual_msg_size = ret;
+         ret = 0;
+      }
+   }
+
+   if ((ret < 0) && (errno != EWOULDBLOCK))
+      fprintf(stderr, "vchi_msg_dequeue -> %d(%d)\n", ret, errno);
+
+   return ret;
+}
+
+/***********************************************************
+ * Name: vchi_msg_queuev
+ *
+ * Arguments:  VCHI_SERVICE_HANDLE_T handle,
+ *             const void *data,
+ *             uint32_t data_size,
+ *             VCHI_FLAGS_T flags,
+ *             void *msg_handle
+ *
+ * Description: Thin wrapper to queue a message onto a connection
+ *
+ * Returns: int32_t - success == 0
+ *
+ ***********************************************************/
+
+vcos_static_assert(sizeof(VCHI_MSG_VECTOR_T) == sizeof(VCHIQ_ELEMENT_T));
+vcos_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_base) == offsetof(VCHIQ_ELEMENT_T, data));
+vcos_static_assert(offsetof(VCHI_MSG_VECTOR_T, vec_len) == offsetof(VCHIQ_ELEMENT_T, size));
+
+int32_t
+vchi_msg_queuev( VCHI_SERVICE_HANDLE_T handle,
+   VCHI_MSG_VECTOR_T * vector,
+   uint32_t count,
+   VCHI_FLAGS_T flags,
+   void *msg_handle )
+{
+   VCHI_SERVICE_T *service = find_service_by_handle(handle);
+   VCHIQ_QUEUE_MESSAGE_T args;
+   int ret;
+
+   vcos_unused(msg_handle);
+
+   vcos_assert(flags == VCHI_FLAGS_BLOCK_UNTIL_QUEUED);
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   args.handle = service->handle;
+   args.elements = (const VCHIQ_ELEMENT_T *)vector;
+   args.count = count;
+   RETRY(ret, ioctl(service->fd, VCHIQ_IOC_QUEUE_MESSAGE, &args));
+
+   return ret;
+}
+
+/***********************************************************
+ * Name: vchi_held_msg_release
+ *
+ * Arguments:  VCHI_HELD_MSG_T *message
+ *
+ * Description: Routine to release a held message (after it has been read with vchi_msg_hold)
+ *
+ * Returns: int32_t - success == 0
+ *
+ ***********************************************************/
+int32_t
+vchi_held_msg_release( VCHI_HELD_MSG_T *message )
+{
+   int ret = -1;
+
+   if (message && message->message && !message->service)
+   {
+      free_msgbuf(message->message);
+      ret = 0;
+   }
+
+   return ret;
+}
+
+/***********************************************************
+ * Name: vchi_msg_hold
+ *
+ * Arguments:  VCHI_SERVICE_HANDLE_T handle,
+ *             void **data,
+ *             uint32_t *msg_size,
+ *             VCHI_FLAGS_T flags,
+ *             VCHI_HELD_MSG_T *message_handle
+ *
+ * Description: Routine to return a pointer to the current message (to allow in place processing)
+ *              The message is dequeued - don't forget to release the message using
+ *              vchi_held_msg_release when you're finished
+ *
+ * Returns: int32_t - success == 0
+ *
+ ***********************************************************/
+int32_t
+vchi_msg_hold( VCHI_SERVICE_HANDLE_T handle,
+   void **data,
+   uint32_t *msg_size,
+   VCHI_FLAGS_T flags,
+   VCHI_HELD_MSG_T *message_handle )
+{
+   VCHI_SERVICE_T *service = find_service_by_handle(handle);
+   int ret;
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   ret = fill_peek_buf(service, flags);
+
+   if (ret == 0)
+   {
+      *data = service->peek_buf;
+      *msg_size = service->peek_size;
+
+      message_handle->message = service->peek_buf;
+      message_handle->service = NULL;
+
+      service->peek_size = -1;
+      service->peek_buf = NULL;
+   }
+
+   return 0;
+}
+
+/***********************************************************
+ * Name: vchi_initialise
+ *
+ * Arguments: VCHI_INSTANCE_T *instance_handle
+ *            VCHI_CONNECTION_T **connections
+ *            const uint32_t num_connections
+ *
+ * Description: Initialises the hardware but does not transmit anything
+ *              When run as a Host App this will be called twice hence the need
+ *              to malloc the state information
+ *
+ * Returns: 0 if successful, failure otherwise
+ *
+ ***********************************************************/
+int32_t
+vchi_initialise( VCHI_INSTANCE_T *instance_handle )
+{
+   VCHIQ_INSTANCE_T instance;
+
+   instance = vchiq_lib_init(-1);
+
+   vcos_log_trace( "%s: returning instance handle %p", __func__, instance );
+
+   *instance_handle = (VCHI_INSTANCE_T)instance;
+
+   return (instance != NULL) ? 0 : -1;
+}
+
+/***********************************************************
+ * Name: vchi_connect
+ *
+ * Arguments: VCHI_CONNECTION_T **connections
+ *            const uint32_t num_connections
+ *            VCHI_INSTANCE_T instance_handle )
+ *
+ * Description: Starts the command service on each connection,
+ *              causing INIT messages to be pinged back and forth
+ *
+ * Returns: 0 if successful, failure otherwise
+ *
+ ***********************************************************/
+int32_t
+vchi_connect( VCHI_CONNECTION_T **connections,
+   const uint32_t num_connections,
+   VCHI_INSTANCE_T instance_handle )
+{
+   VCHIQ_STATUS_T status;
+
+   vcos_unused(connections);
+   vcos_unused(num_connections);
+
+   status = vchiq_connect((VCHIQ_INSTANCE_T)instance_handle);
+
+   return (status == VCHIQ_SUCCESS) ? 0 : -1;
+}
+
+
+/***********************************************************
+ * Name: vchi_disconnect
+ *
+ * Arguments: VCHI_INSTANCE_T instance_handle
+ *
+ * Description: Stops the command service on each connection,
+ *              causing DE-INIT messages to be pinged back and forth
+ *
+ * Returns: 0 if successful, failure otherwise
+ *
+ ***********************************************************/
+int32_t
+vchi_disconnect( VCHI_INSTANCE_T instance_handle )
+{
+   VCHIQ_STATUS_T status;
+
+   status = vchiq_shutdown((VCHIQ_INSTANCE_T)instance_handle);
+
+   return (status == VCHIQ_SUCCESS) ? 0 : -1;
+}
+
+
+/***********************************************************
+ * Name: vchi_service_open
+ * Name: vchi_service_create
+ *
+ * Arguments: VCHI_INSTANCE_T *instance_handle
+ *            SERVICE_CREATION_T *setup,
+ *            VCHI_SERVICE_HANDLE_T *handle
+ *
+ * Description: Routine to open a service
+ *
+ * Returns: int32_t - success == 0
+ *
+ ***********************************************************/
+int32_t
+vchi_service_open( VCHI_INSTANCE_T instance_handle,
+   SERVICE_CREATION_T *setup,
+   VCHI_SERVICE_HANDLE_T *handle )
+{
+   VCHIQ_SERVICE_PARAMS_T params;
+   VCHIQ_STATUS_T status;
+
+   memset(&params, 0, sizeof(params));
+   params.fourcc = setup->service_id;
+   params.userdata = setup->callback_param;
+   params.version = (short)setup->version.version;
+   params.version_min = (short)setup->version.version_min;
+
+   status = create_service((VCHIQ_INSTANCE_T)instance_handle,
+      &params,
+      setup->callback,
+      1/*open*/,
+      (VCHIQ_SERVICE_HANDLE_T *)handle);
+
+   return (status == VCHIQ_SUCCESS) ? 0 : -1;
+}
+
+int32_t
+vchi_service_create( VCHI_INSTANCE_T instance_handle,
+   SERVICE_CREATION_T *setup, VCHI_SERVICE_HANDLE_T *handle )
+{
+   VCHIQ_SERVICE_PARAMS_T params;
+   VCHIQ_STATUS_T status;
+
+   memset(&params, 0, sizeof(params));
+   params.fourcc = setup->service_id;
+   params.userdata = setup->callback_param;
+   params.version = (short)setup->version.version;
+   params.version_min = (short)setup->version.version_min;
+
+   status = create_service((VCHIQ_INSTANCE_T)instance_handle,
+      &params,
+      setup->callback,
+      0/*!open*/,
+      (VCHIQ_SERVICE_HANDLE_T *)handle);
+
+   return (status == VCHIQ_SUCCESS) ? 0 : -1;
+}
+
+int32_t
+vchi_service_close( const VCHI_SERVICE_HANDLE_T handle )
+{
+   VCHI_SERVICE_T *service = find_service_by_handle(handle);
+   int ret;
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   RETRY(ret,ioctl(service->fd, VCHIQ_IOC_CLOSE_SERVICE, service->handle));
+
+   if (service->is_client)
+      service->lib_handle = VCHIQ_SERVICE_HANDLE_INVALID;
+
+   return ret;
+}
+
+int32_t
+vchi_service_destroy( const VCHI_SERVICE_HANDLE_T handle )
+{
+   VCHI_SERVICE_T *service = find_service_by_handle(handle);
+   int ret;
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   RETRY(ret,ioctl(service->fd, VCHIQ_IOC_REMOVE_SERVICE, service->handle));
+
+   service->lib_handle = VCHIQ_SERVICE_HANDLE_INVALID;
+
+   return ret;
+}
+
+/* ----------------------------------------------------------------------
+ * read a uint32_t from buffer.
+ * network format is defined to be little endian
+ * -------------------------------------------------------------------- */
+uint32_t
+vchi_readbuf_uint32( const void *_ptr )
+{
+   const unsigned char *ptr = _ptr;
+   return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
+}
+
+/* ----------------------------------------------------------------------
+ * write a uint32_t to buffer.
+ * network format is defined to be little endian
+ * -------------------------------------------------------------------- */
+void
+vchi_writebuf_uint32( void *_ptr, uint32_t value )
+{
+   unsigned char *ptr = _ptr;
+   ptr[0] = (unsigned char)((value >> 0)  & 0xFF);
+   ptr[1] = (unsigned char)((value >> 8)  & 0xFF);
+   ptr[2] = (unsigned char)((value >> 16) & 0xFF);
+   ptr[3] = (unsigned char)((value >> 24) & 0xFF);
+}
+
+/* ----------------------------------------------------------------------
+ * read a uint16_t from buffer.
+ * network format is defined to be little endian
+ * -------------------------------------------------------------------- */
+uint16_t
+vchi_readbuf_uint16( const void *_ptr )
+{
+   const unsigned char *ptr = _ptr;
+   return ptr[0] | (ptr[1] << 8);
+}
+
+/* ----------------------------------------------------------------------
+ * write a uint16_t into the buffer.
+ * network format is defined to be little endian
+ * -------------------------------------------------------------------- */
+void
+vchi_writebuf_uint16( void *_ptr, uint16_t value )
+{
+   unsigned char *ptr = _ptr;
+   ptr[0] = (value >> 0)  & 0xFF;
+   ptr[1] = (value >> 8)  & 0xFF;
+}
+
+/***********************************************************
+ * Name: vchi_service_use
+ *
+ * Arguments: const VCHI_SERVICE_HANDLE_T handle
+ *
+ * Description: Routine to increment refcount on a service
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+int32_t
+vchi_service_use( const VCHI_SERVICE_HANDLE_T handle )
+{
+   VCHI_SERVICE_T *service = find_service_by_handle(handle);
+   int ret;
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   RETRY(ret,ioctl(service->fd, VCHIQ_IOC_USE_SERVICE, service->handle));
+   return ret;
+}
+
+/***********************************************************
+ * Name: vchi_service_release
+ *
+ * Arguments: const VCHI_SERVICE_HANDLE_T handle
+ *
+ * Description: Routine to decrement refcount on a service
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+int32_t vchi_service_release( const VCHI_SERVICE_HANDLE_T handle )
+{
+   VCHI_SERVICE_T *service = find_service_by_handle(handle);
+   int ret;
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   RETRY(ret,ioctl(service->fd, VCHIQ_IOC_RELEASE_SERVICE, service->handle));
+   return ret;
+}
+
+/***********************************************************
+ * Name: vchi_service_set_option
+ *
+ * Arguments: const VCHI_SERVICE_HANDLE_T handle
+ *            VCHI_SERVICE_OPTION_T option
+ *            int value
+ *
+ * Description: Routine to set a service control option
+ *
+ * Returns: 0 on success, otherwise a non-zero error code
+ *
+ ***********************************************************/
+int32_t vchi_service_set_option( const VCHI_SERVICE_HANDLE_T handle,
+   VCHI_SERVICE_OPTION_T option, int value)
+{
+   VCHIQ_SET_SERVICE_OPTION_T args;
+   VCHI_SERVICE_T *service = find_service_by_handle(handle);
+   int ret;
+
+   switch (option)
+   {
+   case VCHI_SERVICE_OPTION_TRACE:
+      args.option = VCHIQ_SERVICE_OPTION_TRACE;
+      break;
+   default:
+      service = NULL;
+      break;
+   }
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   args.handle = service->handle;
+   args.value  = value;
+
+   RETRY(ret, ioctl(service->fd, VCHIQ_IOC_SET_SERVICE_OPTION, &args));
+
+   return ret;
+}
+
+/***********************************************************
+ * Name: vchiq_dump_phys_mem
+ *
+ * Arguments: const VCHI_SERVICE_HANDLE_T handle
+ *            void *buffer
+ *            size_t num_bytes
+ *
+ * Description: Dumps the physical memory associated with
+ *              a buffer.
+ *
+ * Returns: void
+ *
+ ***********************************************************/
+VCHIQ_STATUS_T vchiq_dump_phys_mem( VCHIQ_SERVICE_HANDLE_T handle,
+                             void *ptr,
+                             size_t num_bytes )
+{
+   VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)handle;
+   VCHIQ_DUMP_MEM_T  dump_mem;
+   int ret;
+
+   if (!service)
+      return VCHIQ_ERROR;
+
+   dump_mem.virt_addr = ptr;
+   dump_mem.num_bytes = num_bytes;
+
+   RETRY(ret,ioctl(service->fd, VCHIQ_IOC_DUMP_PHYS_MEM, &dump_mem));
+   return (ret >= 0) ? VCHIQ_SUCCESS : VCHIQ_ERROR;
+}
+
+
+
+/*
+ * Support functions
+ */
+
+static VCHIQ_INSTANCE_T
+vchiq_lib_init(const int dev_vchiq_fd)
+{
+   static int mutex_initialised = 0;
+   static VCOS_MUTEX_T vchiq_lib_mutex;
+   VCHIQ_INSTANCE_T instance = &vchiq_instance;
+
+   vcos_global_lock();
+   if (!mutex_initialised)
+   {
+      vcos_mutex_create(&vchiq_lib_mutex, "vchiq-init");
+
+      vcos_log_set_level( &vchiq_lib_log_category, vchiq_default_lib_log_level );
+      vcos_log_register( "vchiq_lib", &vchiq_lib_log_category );
+
+      mutex_initialised = 1;
+   }
+   vcos_global_unlock();
+
+   vcos_mutex_lock(&vchiq_lib_mutex);
+
+   if (instance->initialised == 0)
+   {
+      instance->fd = dev_vchiq_fd == -1 ?
+         open("/dev/vchiq", O_RDWR) :
+         dup(dev_vchiq_fd);
+      if (instance->fd >= 0)
+      {
+         VCHIQ_GET_CONFIG_T args;
+         VCHIQ_CONFIG_T config;
+         int ret;
+         args.config_size = sizeof(config);
+         args.pconfig = &config;
+         RETRY(ret, ioctl(instance->fd, VCHIQ_IOC_GET_CONFIG, &args));
+         if ((ret == 0) && (config.version >= VCHIQ_VERSION_MIN) && (config.version_min <= VCHIQ_VERSION))
+         {
+            if (config.version >= VCHIQ_VERSION_LIB_VERSION)
+            {
+               RETRY(ret, ioctl(instance->fd, VCHIQ_IOC_LIB_VERSION, VCHIQ_VERSION));
+            }
+            if (ret == 0)
+            {
+               instance->used_services = 0;
+               instance->use_close_delivered = (config.version >= VCHIQ_VERSION_CLOSE_DELIVERED);
+               vcos_mutex_create(&instance->mutex, "VCHIQ instance");
+               instance->initialised = 1;
+            }
+         }
+         else
+         {
+            if (ret == 0)
+            {
+               vcos_log_error("Incompatible VCHIQ library - driver version %d (min %d), library version %d (min %d)",
+                  config.version, config.version_min, VCHIQ_VERSION, VCHIQ_VERSION_MIN);
+            }
+            else
+            {
+               vcos_log_error("Very incompatible VCHIQ library - cannot retrieve driver version");
+            }
+            close(instance->fd);
+            instance = NULL;
+         }
+      }
+      else
+      {
+         instance = NULL;
+      }
+   }
+   else if (instance->initialised > 0)
+   {
+      instance->initialised++;
+   }
+
+   vcos_mutex_unlock(&vchiq_lib_mutex);
+
+   return instance;
+}
+
+static void *
+completion_thread(void *arg)
+{
+   VCHIQ_INSTANCE_T instance = (VCHIQ_INSTANCE_T)arg;
+   VCHIQ_AWAIT_COMPLETION_T args;
+   VCHIQ_COMPLETION_DATA_T completions[8];
+   void *msgbufs[8];
+
+   static const VCHI_CALLBACK_REASON_T vchiq_reason_to_vchi[] =
+   {
+      VCHI_CALLBACK_SERVICE_OPENED,        // VCHIQ_SERVICE_OPENED
+      VCHI_CALLBACK_SERVICE_CLOSED,        // VCHIQ_SERVICE_CLOSED
+      VCHI_CALLBACK_MSG_AVAILABLE,         // VCHIQ_MESSAGE_AVAILABLE
+      VCHI_CALLBACK_BULK_SENT,             // VCHIQ_BULK_TRANSMIT_DONE
+      VCHI_CALLBACK_BULK_RECEIVED,         // VCHIQ_BULK_RECEIVE_DONE
+      VCHI_CALLBACK_BULK_TRANSMIT_ABORTED, // VCHIQ_BULK_TRANSMIT_ABORTED
+      VCHI_CALLBACK_BULK_RECEIVE_ABORTED,  // VCHIQ_BULK_RECEIVE_ABORTED
+   };
+
+   args.count = vcos_countof(completions);
+   args.buf = completions;
+   args.msgbufsize = MSGBUF_SIZE;
+   args.msgbufcount = 0;
+   args.msgbufs = msgbufs;
+
+   while (1)
+   {
+      int count, i;
+
+      while ((unsigned int)args.msgbufcount < vcos_countof(msgbufs))
+      {
+         void *msgbuf = alloc_msgbuf();
+         if (msgbuf)
+         {
+            msgbufs[args.msgbufcount++] = msgbuf;
+         }
+         else
+         {
+            vcos_log_error("vchiq_lib: failed to allocate a message buffer\n");
+            vcos_demand(args.msgbufcount != 0);
+         }
+      }
+
+      RETRY(count, ioctl(instance->fd, VCHIQ_IOC_AWAIT_COMPLETION, &args));
+
+      if (count <= 0)
+         break;
+
+      for (i = 0; i < count; i++)
+      {
+         VCHIQ_COMPLETION_DATA_T *completion = &completions[i];
+         VCHIQ_SERVICE_T *service = (VCHIQ_SERVICE_T *)completion->service_userdata;
+         if (service->base.callback)
+         {
+            vcos_log_trace( "callback(%x, %x, %x(%x,%x), %x)",
+               completion->reason, (uint32_t)completion->header,
+               (uint32_t)&service->base, (uint32_t)service->lib_handle, (uint32_t)service->base.userdata, (uint32_t)completion->bulk_userdata );
+            service->base.callback(completion->reason, completion->header,
+               service->lib_handle, completion->bulk_userdata);
+         }
+         else if (service->vchi_callback)
+         {
+            VCHI_CALLBACK_REASON_T vchi_reason =
+               vchiq_reason_to_vchi[completion->reason];
+            service->vchi_callback(service->base.userdata, vchi_reason, completion->bulk_userdata);
+         }
+
+         if ((completion->reason == VCHIQ_SERVICE_CLOSED) &&
+             instance->use_close_delivered)
+         {
+            int ret;
+            RETRY(ret,ioctl(service->fd, VCHIQ_IOC_CLOSE_DELIVERED, service->handle));
+         }
+      }
+   }
+
+   while (args.msgbufcount)
+   {
+      void *msgbuf = msgbufs[--args.msgbufcount];
+      free_msgbuf(msgbuf);
+   }
+
+   return NULL;
+}
+
+static VCHIQ_STATUS_T
+create_service(VCHIQ_INSTANCE_T instance,
+   const VCHIQ_SERVICE_PARAMS_T *params,
+   VCHI_CALLBACK_T vchi_callback,
+   int is_open,
+   VCHIQ_SERVICE_HANDLE_T *phandle)
+{
+   VCHIQ_SERVICE_T *service = NULL;
+   VCHIQ_STATUS_T status = VCHIQ_SUCCESS;
+   int i;
+
+   if (!is_valid_instance(instance))
+      return VCHIQ_ERROR;
+
+   vcos_mutex_lock(&instance->mutex);
+
+   /* Find a free service */
+   if (is_open)
+   {
+      /* Find a free service */
+      for (i = 0; i < instance->used_services; i++)
+      {
+         if (instance->services[i].lib_handle == VCHIQ_SERVICE_HANDLE_INVALID)
+         {
+            service = &instance->services[i];
+            break;
+         }
+      }
+   }
+   else
+   {
+      for (i = (instance->used_services - 1); i >= 0; i--)
+      {
+         VCHIQ_SERVICE_T *srv = &instance->services[i];
+         if (srv->lib_handle == VCHIQ_SERVICE_HANDLE_INVALID)
+         {
+            service = srv;
+         }
+         else if (
+            (srv->base.fourcc == params->fourcc) &&
+            ((srv->base.callback != params->callback) ||
+            (srv->vchi_callback != vchi_callback)))
+         {
+            /* There is another server using this fourcc which doesn't match */
+            vcos_log_info("service %x already using fourcc 0x%x",
+               srv->lib_handle, params->fourcc);
+            service = NULL;
+            status = VCHIQ_ERROR;
+            break;
+         }
+      }
+   }
+
+   if (!service && (status == VCHIQ_SUCCESS))
+   {
+      if (instance->used_services < VCHIQ_MAX_INSTANCE_SERVICES)
+         service = &instance->services[instance->used_services++];
+      else
+         status = VCHIQ_ERROR;
+   }
+
+   if (service)
+   {
+      if (!handle_seq)
+         handle_seq = VCHIQ_MAX_INSTANCE_SERVICES;
+      service->lib_handle = handle_seq | (service - instance->services);
+      handle_seq += VCHIQ_MAX_INSTANCE_SERVICES;
+   }
+
+   vcos_mutex_unlock(&instance->mutex);
+
+   if (service)
+   {
+      VCHIQ_CREATE_SERVICE_T args;
+      int ret;
+
+      service->base.fourcc = params->fourcc;
+      service->base.callback = params->callback;
+      service->vchi_callback = vchi_callback;
+      service->base.userdata = params->userdata;
+      service->fd = instance->fd;
+      service->peek_size = -1;
+      service->peek_buf = NULL;
+      service->is_client = is_open;
+
+      args.params = *params;
+      args.params.userdata = service;
+      args.is_open = is_open;
+      args.is_vchi = (params->callback == NULL);
+      args.handle = VCHIQ_SERVICE_HANDLE_INVALID; /* OUT parameter */
+      RETRY(ret, ioctl(instance->fd, VCHIQ_IOC_CREATE_SERVICE, &args));
+      if (ret == 0)
+         service->handle = args.handle;
+      else
+         status = VCHIQ_ERROR;
+   }
+
+   if (status == VCHIQ_SUCCESS)
+   {
+      *phandle = service->lib_handle;
+      vcos_log_info("service handle %x lib_handle %x using fourcc 0x%x",
+         service->handle, service->lib_handle, params->fourcc);
+   }
+   else
+   {
+      vcos_mutex_lock(&instance->mutex);
+
+      if (service)
+         service->lib_handle = VCHIQ_SERVICE_HANDLE_INVALID;
+
+      vcos_mutex_unlock(&instance->mutex);
+
+      *phandle = VCHIQ_SERVICE_HANDLE_INVALID;
+   }
+
+   return status;
+}
+
+static int
+fill_peek_buf(VCHI_SERVICE_T *service,
+   VCHI_FLAGS_T flags)
+{
+   VCHIQ_DEQUEUE_MESSAGE_T args;
+   int ret = 0;
+
+   vcos_assert(flags == VCHI_FLAGS_NONE || flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
+
+   if (service->peek_size < 0)
+   {
+      if (!service->peek_buf)
+         service->peek_buf = alloc_msgbuf();
+
+      if (service->peek_buf)
+      {
+         args.handle = service->handle;
+         args.blocking = (flags == VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
+         args.bufsize = MSGBUF_SIZE;
+         args.buf = service->peek_buf;
+
+         RETRY(ret, ioctl(service->fd, VCHIQ_IOC_DEQUEUE_MESSAGE, &args));
+
+         if (ret >= 0)
+         {
+            service->peek_size = ret;
+            ret = 0;
+         }
+         else
+         {
+            ret = -1;
+         }
+      }
+      else
+      {
+         ret = -1;
+      }
+   }
+
+   return ret;
+}
+
+
+static void *
+alloc_msgbuf(void)
+{
+   void *msgbuf;
+   vcos_mutex_lock(&vchiq_lib_mutex);
+   msgbuf = free_msgbufs;
+   if (msgbuf)
+      free_msgbufs = *(void **)msgbuf;
+   vcos_mutex_unlock(&vchiq_lib_mutex);
+   if (!msgbuf)
+      msgbuf = vcos_malloc(MSGBUF_SIZE, "alloc_msgbuf");
+   return msgbuf;
+}
+
+static void
+free_msgbuf(void *buf)
+{
+   vcos_mutex_lock(&vchiq_lib_mutex);
+   *(void **)buf = free_msgbufs;
+   free_msgbufs = buf;
+   vcos_mutex_unlock(&vchiq_lib_mutex);
+}
diff --git a/interface/vchiq_arm/vchiq_test.c b/interface/vchiq_arm/vchiq_test.c
new file mode 100755 (executable)
index 0000000..127c683
--- /dev/null
@@ -0,0 +1,1766 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "vchiq_test.h"
+#ifndef USE_VCHIQ_ARM
+#define USE_VCHIQ_ARM
+#endif
+#include "interface/vchi/vchi.h"
+
+#define NUM_BULK_BUFS 2
+#define BULK_SIZE (1024*256)
+#ifndef PAGE_SIZE
+#define PAGE_SIZE 4096
+#endif
+
+#define INIT_PARAMS(sp_, fourcc_, cb_, userdata_, ver_) \
+   do {                                \
+      memset((sp_), 0, sizeof(*(sp_)));   \
+      (sp_)->fourcc = fourcc_;            \
+      (sp_)->callback = cb_;              \
+      (sp_)->userdata = userdata_;        \
+      (sp_)->version = ver_;              \
+      (sp_)->version_min = ver_;          \
+   } while (0)
+
+
+static struct test_params g_params = { MSG_CONFIG, 64, 100, 1, 1, 1, 0, 0, 0, 0 };
+static const char *g_servname = "echo";
+
+static VCOS_EVENT_T g_server_reply;
+static VCOS_EVENT_T g_shutdown;
+static VCOS_MUTEX_T g_mutex;
+
+static const char *g_server_error = NULL;
+
+static volatile int g_sync_mode = 0;
+
+static VCOS_EVENT_T func_test_sync;
+static int want_echo = 1;
+static int func_error = 0;
+static int fun2_error = 0;
+static int func_data_test_start = -1;
+static int func_data_test_end = 0x7fffffff;
+static int func_data_test_iter;
+
+char *bulk_bufs[NUM_BULK_BUFS * 2];
+char *bulk_tx_data[NUM_BULK_BUFS];
+char *bulk_rx_data[NUM_BULK_BUFS];
+
+static int ctrl_received = 0;
+static int bulk_tx_sent = 0;
+static int bulk_rx_sent = 0;
+static int bulk_tx_received = 0;
+static int bulk_rx_received = 0;
+
+static char clnt_service1_data[SERVICE1_DATA_SIZE];
+static char clnt_service2_data[SERVICE2_DATA_SIZE];
+
+static VCOS_LOG_CAT_T vchiq_test_log_category;
+
+static int vchiq_test(int argc, char **argv);
+static VCHIQ_STATUS_T vchiq_bulk_test(void);
+static VCHIQ_STATUS_T vchiq_ctrl_test(void);
+static VCHIQ_STATUS_T vchiq_functional_test(void);
+static VCHIQ_STATUS_T vchiq_ping_test(void);
+static VCHIQ_STATUS_T vchiq_signal_test(void);
+
+static VCHIQ_STATUS_T do_functional_test(void);
+static void do_ping_test(VCHIQ_SERVICE_HANDLE_T service, int size, int async, int oneway, int iters);
+static void do_vchi_ping_test(VCHI_SERVICE_HANDLE_T service, int size, int async, int oneway, int iters);
+
+static VCHIQ_STATUS_T func_data_test(VCHIQ_SERVICE_HANDLE_T service, int size, int align, int server_align);
+
+#ifdef VCHIQ_LOCAL
+static void *vchiq_test_server(void *);
+#endif
+
+static VCHIQ_STATUS_T
+clnt_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
+   VCHIQ_SERVICE_HANDLE_T service, void *bulk_userdata);
+static void
+vchi_clnt_callback(void *callback_param, VCHI_CALLBACK_REASON_T reason,
+   void *handle);
+static VCHIQ_STATUS_T func_clnt_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
+                                         VCHIQ_SERVICE_HANDLE_T service, void *bulk_userdata);
+static VCHIQ_STATUS_T fun2_clnt_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
+                                         VCHIQ_SERVICE_HANDLE_T service, void *bulk_userdata);
+static int mem_check(const void *expected, const void *actual, int size);
+static void usage(void);
+static void check_timer(void);
+static char *buf_align(char *buf, int align_size, int align);
+
+#ifdef ANDROID
+
+static int g_timeout_ms = 0;
+static pid_t main_process_pid;
+static void kill_timeout_handler(int cause, siginfo_t *how, void *ucontext);
+static int setup_auto_kill(int timeout_ms);
+
+#endif
+
+#ifdef __linux__
+
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include "interface/vmcs_host/vc_cma.h"
+
+static void reserve_test(int reserve, int delay)
+{
+   int fd = open("/dev/vc-cma", O_RDWR);
+   int rc = -1;
+   if (fd >= 0)
+   {
+      rc = ioctl(fd, VC_CMA_IOC_RESERVE, reserve);
+      if (rc == 0)
+      {
+         printf("Sleeping for %d seconds...\n", delay);
+         sleep(delay);
+      }
+      else
+         printf("* failed to ioctl /dev/vc-cma - rc %d\n", rc);
+      close(fd);
+   }
+   else
+      printf("* failed to open /dev/vc-cma - rc %d\n", fd);
+}
+
+#endif
+
+static int vchiq_test(int argc, char **argv)
+{
+   VCHIQ_STATUS_T status;
+   int run_bulk_test = 0;
+   int run_ctrl_test = 0;
+   int run_functional_test = 0;
+   int run_ping_test = 0;
+   int run_signal_test = 0;
+   int verbose = 0;
+   int argn;
+   argn = 1;
+   while ((argn < argc) && (argv[argn][0] == '-'))
+   {
+      const char *arg = argv[argn++];
+      if (strcmp(arg, "-s") == 0)
+      {
+         g_servname = argv[argn++];
+         if (!g_servname || (strlen(g_servname) != 4))
+         {
+            usage();
+         }
+      }
+      else if (strcasecmp(arg, "-a") == 0)
+      {
+         g_params.align_size = (strcmp(arg, "-A") == 0) ? 4096 : 32;
+         g_params.client_align = atoi(argv[argn++]);
+         g_params.server_align = atoi(argv[argn++]);
+      }
+      else if (strcmp(arg, "-b") == 0)
+      {
+         run_bulk_test = 1;
+         g_params.blocksize = atoi(argv[argn++]);
+      }
+      else if (strcmp(arg, "-c") == 0)
+      {
+         run_ctrl_test = 1;
+         g_params.blocksize = atoi(argv[argn++]);
+      }
+      else if (strcmp(arg, "-e") == 0)
+      {
+         want_echo = 0;
+      }
+      else if (strcmp(arg, "-f") == 0)
+      {
+         run_functional_test = 1;
+      }
+      else if (strcmp(arg, "-h") == 0)
+      {
+         usage();
+      }
+      else if (strcmp(arg, "-i") == 0)
+      {
+         run_signal_test = 1;
+      }
+      else if (strcmp(arg, "-m") == 0)
+      {
+         g_params.client_message_quota = atoi(argv[argn++]);
+      }
+      else if (strcmp(arg, "-M") == 0)
+      {
+         g_params.server_message_quota = atoi(argv[argn++]);
+      }
+      else if (strcmp(arg, "-p") == 0)
+      {
+         run_ping_test = 1;
+         g_params.iters = 1000;
+      }
+      else if (strcmp(arg, "-q") == 0)
+      {
+         /* coverity[missing_lock : FALSE] - g_server_reply is not used for mutual exclusion */
+         g_params.verify = 0;
+      }
+#ifdef __linux__
+      else if (strcmp(arg, "-r") == 0)
+      {
+         int reserve, delay;
+         if (argn+1 < argc)
+         {
+            reserve = atoi(argv[argn++]);
+            delay = atoi(argv[argn++]);
+            reserve_test(reserve, delay);
+            exit(0);
+         }
+         else
+         {
+            printf("not enough arguments (-r reserve delay)\n");
+            exit(-1);
+         }
+      }
+#endif
+#ifdef ANDROID
+      else if (strcmp(arg, "-K") == 0)
+      {
+         if (argn < argc)
+            g_timeout_ms = atoi(argv[argn++]);
+         else
+         {
+            printf("not enough arguments (-K timeout)\n");
+            exit(-1);
+         }
+      }
+#endif
+      else if (strcmp(arg, "-t") == 0)
+      {
+         check_timer();
+         exit(0);
+      }
+      else if (strcmp(arg, "-v") == 0)
+      {
+         verbose = 1;
+      }
+      else if (strcmp(arg, "-S") == 0)
+      {
+         func_data_test_start = atoi(argv[argn++]);
+      }
+      else if (strcmp(arg, "-E") == 0)
+      {
+         func_data_test_end = atoi(argv[argn++]);
+      }
+      else
+      {
+         printf("* unknown option '%s'\n", arg);
+         usage();
+      }
+   }
+
+   if ((run_ctrl_test + run_bulk_test + run_functional_test + run_ping_test + run_signal_test) != 1)
+      usage();
+
+   if (argn < argc)
+   {
+      g_params.iters = atoi(argv[argn++]);
+      if (argn != argc)
+      {
+         usage();
+      }
+   }
+
+   vcos_log_set_level(VCOS_LOG_CATEGORY, verbose ? VCOS_LOG_TRACE : VCOS_LOG_INFO);
+   vcos_log_register("vchiq_test", VCOS_LOG_CATEGORY);
+
+#ifdef VCHIQ_LOCAL
+   {
+      static VCOS_THREAD_T server_task;
+      void          *pointer = NULL;
+      int stack_size = 4096;
+
+#if VCOS_CAN_SET_STACK_ADDR
+      pointer = malloc(stack_size);
+      vcos_demand(pointer);
+#endif
+      vcos_thread_create_classic(&server_task, "vchiq_test server", vchiq_test_server, (void *)0, pointer, stack_size,
+                                 10 | VCOS_AFFINITY_CPU1, 20, VCOS_START);
+   }
+#endif
+
+   vcos_event_create(&g_server_reply, "g_server_reply");
+   vcos_event_create(&g_shutdown, "g_shutdown");
+   vcos_mutex_create(&g_mutex, "g_mutex");
+
+
+   status = VCHIQ_ERROR;
+
+   if (run_bulk_test)
+      status = vchiq_bulk_test();
+   else if (run_ctrl_test)
+      status = vchiq_ctrl_test();
+   else if (run_functional_test)
+      status = vchiq_functional_test();
+   else if (run_ping_test)
+      status = vchiq_ping_test();
+   else if (run_signal_test)
+      status = vchiq_signal_test();
+
+   return (status == VCHIQ_SUCCESS) ? 0 : -1;
+}
+
+static VCHIQ_STATUS_T
+vchiq_bulk_test(void)
+{
+   VCHIQ_INSTANCE_T vchiq_instance;
+   VCHIQ_SERVICE_HANDLE_T vchiq_service;
+   VCHIQ_SERVICE_PARAMS_T service_params;
+   VCHIQ_ELEMENT_T elements[4];
+   VCHIQ_ELEMENT_T *element;
+   int num_bulk_bufs = NUM_BULK_BUFS;
+   uint32_t start, end;
+   int i;
+
+   g_params.blocksize *= 1024;
+
+   for (i = 0; i < (NUM_BULK_BUFS * 2); i++)
+   {
+      bulk_bufs[i] = malloc(g_params.blocksize + BULK_ALIGN_SIZE - 1);
+      if (!bulk_bufs[i])
+      {
+         printf("* out of memory\n");
+         while (i > 0)
+         {
+            free(bulk_bufs[--i]);
+         }
+         return VCHIQ_ERROR;
+      }
+   }
+
+   for (i = 0; i < NUM_BULK_BUFS; i++)
+   {
+      int j;
+      bulk_tx_data[i] = buf_align(bulk_bufs[i*2 + 0], g_params.align_size, g_params.client_align);
+      bulk_rx_data[i] = buf_align(bulk_bufs[i*2 + 1], g_params.align_size, g_params.client_align);
+      for (j = 0; j < g_params.blocksize; j+=4)
+      {
+         *(unsigned int *)(bulk_tx_data[i] + j) = ((0x80 | i) << 24) + j;
+      }
+      memset(bulk_rx_data[i], 0xff, g_params.blocksize);
+   }
+
+#ifdef ANDROID
+   if (g_timeout_ms)
+   {
+      setup_auto_kill(g_timeout_ms);
+   }
+#endif
+
+   if (vchiq_initialise(&vchiq_instance) != VCHIQ_SUCCESS)
+   {
+      printf("* failed to open vchiq instance\n");
+      return VCHIQ_ERROR;
+   }
+
+   vchiq_connect(vchiq_instance);
+
+   memset(&service_params, 0, sizeof(service_params));
+
+   service_params.version = service_params.version_min = VCHIQ_TEST_VER;
+   service_params.fourcc = VCHIQ_MAKE_FOURCC(g_servname[0], g_servname[1], g_servname[2], g_servname[3]);
+   service_params.callback = clnt_callback;
+   service_params.userdata = "clnt userdata";
+
+   if (vchiq_open_service(vchiq_instance, &service_params, &vchiq_service) != VCHIQ_SUCCESS)
+   {
+      printf("* failed to open service - already in use?\n");
+      return VCHIQ_ERROR;
+   }
+
+   printf("Bulk test - service:%s, block size:%d, iters:%d\n", g_servname, g_params.blocksize, g_params.iters);
+
+   /* coverity[missing_lock : FALSE] - g_server_reply is not used for mutual exclusion */
+   g_params.echo = want_echo;
+   element = elements;
+   element->data = &g_params;
+   element->size = sizeof(g_params);
+   element++;
+   
+   vchiq_queue_message(vchiq_service, elements, element - elements);
+
+   vcos_event_wait(&g_server_reply);
+
+   if (g_server_error)
+   {
+      printf("* server error: %s\n", g_server_error);
+      return VCHIQ_ERROR;
+   }
+
+   if ( num_bulk_bufs > g_params.iters )
+      num_bulk_bufs = g_params.iters;
+
+   start = vcos_getmicrosecs();
+
+   vcos_mutex_lock(&g_mutex);
+
+   for (i = 0; i < num_bulk_bufs; i++)
+   {
+      vchiq_queue_bulk_transmit(vchiq_service, bulk_tx_data[i], g_params.blocksize, (void *)i);
+
+      vcos_log_trace("vchiq_test: queued bulk tx %d", i);
+      bulk_tx_sent++;
+
+      if (g_params.echo)
+      {
+         vchiq_queue_bulk_receive(vchiq_service, bulk_rx_data[i], g_params.blocksize, (void *)i);
+
+         vcos_log_trace("vchiq_test: queued bulk rx %d", i);
+         bulk_rx_sent++;
+      }
+   }
+
+   vcos_mutex_unlock(&g_mutex);
+
+   vcos_log_trace("Sent all messages");
+
+   vcos_log_trace("vchiq_test: waiting for shutdown");
+
+   vcos_event_wait(&g_shutdown);
+
+   end = vcos_getmicrosecs();
+
+   for (i = 0; i < (NUM_BULK_BUFS * 2); i++)
+   {
+      free(bulk_bufs[i]);
+   }
+
+   vchiq_remove_service(vchiq_service);
+
+   vcos_log_trace("vchiq_test: shutting down");
+
+   vchiq_shutdown(vchiq_instance);
+
+   printf("Elapsed time: %dus per iteration\n", (end - start) / g_params.iters);
+
+   return VCHIQ_SUCCESS;
+}
+
+static VCHIQ_STATUS_T
+vchiq_ctrl_test(void)
+{
+   VCHIQ_INSTANCE_T vchiq_instance;
+   VCHIQ_SERVICE_HANDLE_T vchiq_service;
+   VCHIQ_SERVICE_PARAMS_T service_params;
+   uint32_t start, end;
+   int i;
+
+   ctrl_received = 0;
+   if (g_params.blocksize < 4)
+      g_params.blocksize = 4;
+
+   for (i = 0; i < NUM_BULK_BUFS; i++)
+   {
+      int j;
+      bulk_tx_data[i] = malloc(g_params.blocksize);
+      if (!bulk_tx_data[i])
+      {
+         printf("* out of memory\n");
+         return VCHIQ_ERROR;
+      }
+      *(int *)bulk_tx_data[i] = MSG_ECHO;
+      for (j = 4; j < g_params.blocksize; j+=4)
+      {
+         *(unsigned int *)(bulk_tx_data[i] + j) = ((0x80 | i) << 24) + j;
+      }
+   }
+
+#ifdef ANDROID
+   if (g_timeout_ms)
+   {
+      setup_auto_kill(g_timeout_ms);
+   }
+#endif
+
+   if (vchiq_initialise(&vchiq_instance) != VCHIQ_SUCCESS)
+   {
+      printf("* failed to open vchiq instance\n");
+      return VCHIQ_ERROR;
+   }
+
+   vchiq_connect(vchiq_instance);
+
+   memset(&service_params, 0, sizeof(service_params));
+
+   service_params.fourcc = VCHIQ_MAKE_FOURCC(g_servname[0], g_servname[1], g_servname[2], g_servname[3]);
+   service_params.callback = clnt_callback;
+   service_params.userdata = "clnt userdata";
+   service_params.version = VCHIQ_TEST_VER;
+   service_params.version_min = VCHIQ_TEST_VER;
+
+   if (vchiq_open_service(vchiq_instance, &service_params, &vchiq_service) != VCHIQ_SUCCESS)
+   {
+      printf("* failed to open service - already in use?\n");
+      return VCHIQ_ERROR;
+   }
+
+   printf("Ctrl test - service:%s, block size:%d, iters:%d\n", g_servname, g_params.blocksize, g_params.iters);
+
+   start = vcos_getmicrosecs();
+
+   for (i = 0; i < g_params.iters; i++)
+   {
+      VCHIQ_ELEMENT_T element;
+      element.data = bulk_tx_data[i % NUM_BULK_BUFS];
+      element.size = g_params.blocksize;
+
+      if (vchiq_queue_message(vchiq_service, &element, 1) != VCHIQ_SUCCESS)
+      {
+         printf("* failed to send a message\n");
+         goto error_exit;
+      }
+      if (g_server_error)
+      {
+         printf("* error - %s\n", g_server_error);
+         goto error_exit;
+      }
+   }
+
+   vcos_log_trace("Sent all messages");
+
+   if (g_params.echo)
+   {
+      vcos_log_trace("vchiq_test: waiting for shutdown");
+
+      vcos_event_wait(&g_shutdown);
+   }
+
+   if (g_server_error)
+   {
+      printf("* error - %s\n", g_server_error);
+      goto error_exit;
+   }
+
+   end = vcos_getmicrosecs();
+
+   vchiq_remove_service(vchiq_service);
+
+   vcos_log_trace("vchiq_test: shutting down");
+
+   vchiq_shutdown(vchiq_instance);
+
+   printf("Elapsed time: %dus per iteration\n", (end - start) / g_params.iters);
+
+   return VCHIQ_SUCCESS;
+
+error_exit:
+   vchiq_remove_service(vchiq_service);
+   vchiq_shutdown(vchiq_instance);
+   return VCHIQ_ERROR;
+}
+
+static VCHIQ_STATUS_T
+vchiq_functional_test(void)
+{
+   int i;
+   printf("Functional test - iters:%d\n", g_params.iters);
+   for (i = 0; i < g_params.iters; i++)
+   {
+      printf("======== iteration %d ========\n", i+1);
+
+      if (do_functional_test() != VCHIQ_SUCCESS)
+         return VCHIQ_ERROR;
+   }
+   return VCHIQ_SUCCESS;
+}
+
+static VCHIQ_STATUS_T
+vchiq_ping_test(void)
+{
+   /* Measure message round trip time for various sizes*/
+   VCHIQ_INSTANCE_T vchiq_instance;
+   VCHIQ_SERVICE_HANDLE_T vchiq_service;
+   VCHI_SERVICE_HANDLE_T vchi_service;
+   SERVICE_CREATION_T service_params;
+   VCHIQ_SERVICE_PARAMS_T vchiq_service_params;
+   int fourcc;
+
+   static int sizes[] = { 0, 1024, 2048, VCHIQ_MAX_MSG_SIZE };
+   unsigned int i;
+
+   fourcc = VCHIQ_MAKE_FOURCC(g_servname[0], g_servname[1], g_servname[2], g_servname[3]);
+
+   printf("Ping test - service:%s, iters:%d, version %d\n", g_servname, g_params.iters, VCHIQ_TEST_VER);
+
+#ifdef ANDROID
+   if (g_timeout_ms)
+   {
+      setup_auto_kill(g_timeout_ms);
+   }
+#endif
+
+   if (vchiq_initialise(&vchiq_instance) != VCHIQ_SUCCESS)
+   {
+      printf("* failed to open vchiq instance\n");
+      return VCHIQ_ERROR;
+   }
+
+   vchiq_connect(vchiq_instance);
+
+   memset(&service_params, 0, sizeof(service_params));
+   service_params.version.version = service_params.version.version_min = VCHIQ_TEST_VER;
+   service_params.service_id = fourcc;
+   service_params.callback = vchi_clnt_callback;
+   service_params.callback_param = &vchi_service;
+
+   if (vchi_service_open((VCHI_INSTANCE_T)vchiq_instance, &service_params, &vchi_service) != VCHIQ_SUCCESS)
+   {
+      printf("* failed to open service - already in use?\n");
+      return VCHIQ_ERROR;
+   }
+
+   for (i = 0; i < sizeof(sizes)/sizeof(sizes[0]); i++)
+   {
+      const int iter_count = g_params.iters;
+      do_vchi_ping_test(vchi_service, sizes[i], 0, 0, iter_count);
+      do_vchi_ping_test(vchi_service, sizes[i], 0, 0, iter_count);
+      do_vchi_ping_test(vchi_service, sizes[i], 1, 0, iter_count);
+      do_vchi_ping_test(vchi_service, sizes[i], 2, 0, iter_count);
+      do_vchi_ping_test(vchi_service, sizes[i], 10, 0, iter_count);
+      do_vchi_ping_test(vchi_service, sizes[i], 0, 1, iter_count);
+      do_vchi_ping_test(vchi_service, sizes[i], 0, 2, iter_count);
+      do_vchi_ping_test(vchi_service, sizes[i], 0, 10, iter_count);
+      do_vchi_ping_test(vchi_service, sizes[i], 10, 10, iter_count);
+      do_vchi_ping_test(vchi_service, sizes[i], 100, 0, iter_count/10);
+      do_vchi_ping_test(vchi_service, sizes[i], 0, 100, iter_count/10);
+      do_vchi_ping_test(vchi_service, sizes[i], 100, 100, iter_count/10);
+      do_vchi_ping_test(vchi_service, sizes[i], 200, 0, iter_count/10);
+      do_vchi_ping_test(vchi_service, sizes[i], 0, 200, iter_count/10);
+      do_vchi_ping_test(vchi_service, sizes[i], 200, 200, iter_count/10);
+      do_vchi_ping_test(vchi_service, sizes[i], 400, 0, iter_count/20);
+      do_vchi_ping_test(vchi_service, sizes[i], 0, 400, iter_count/20);
+      do_vchi_ping_test(vchi_service, sizes[i], 400, 400, iter_count/20);
+      do_vchi_ping_test(vchi_service, sizes[i], 1000, 0, iter_count/50);
+      do_vchi_ping_test(vchi_service, sizes[i], 0, 1000, iter_count/50);
+      do_vchi_ping_test(vchi_service, sizes[i], 1000, 1000, iter_count/50);
+   }
+
+   vchi_service_close(vchi_service);
+
+   INIT_PARAMS(&vchiq_service_params, fourcc, clnt_callback, "clnt userdata", VCHIQ_TEST_VER);
+   if (vchiq_open_service(vchiq_instance, &vchiq_service_params, &vchiq_service) != VCHIQ_SUCCESS)
+   {
+      printf("* failed to open service - already in use?\n");
+      return VCHIQ_ERROR;
+   }
+
+   for (i = 0; i < sizeof(sizes)/sizeof(sizes[0]); i++)
+   {
+      const int iter_count = g_params.iters;
+      do_ping_test(vchiq_service, sizes[i], 0, 0, iter_count);
+      do_ping_test(vchiq_service, sizes[i], 0, 0, iter_count);
+      do_ping_test(vchiq_service, sizes[i], 1, 0, iter_count);
+      do_ping_test(vchiq_service, sizes[i], 2, 0, iter_count);
+      do_ping_test(vchiq_service, sizes[i], 10, 0, iter_count);
+      do_ping_test(vchiq_service, sizes[i], 0, 1, iter_count);
+      do_ping_test(vchiq_service, sizes[i], 0, 2, iter_count);
+      do_ping_test(vchiq_service, sizes[i], 0, 10, iter_count);
+      do_ping_test(vchiq_service, sizes[i], 10, 10, iter_count);
+      do_ping_test(vchiq_service, sizes[i], 100, 0, iter_count/10);
+      do_ping_test(vchiq_service, sizes[i], 0, 100, iter_count/10);
+      do_ping_test(vchiq_service, sizes[i], 100, 100, iter_count/10);
+      do_ping_test(vchiq_service, sizes[i], 200, 0, iter_count/10);
+      do_ping_test(vchiq_service, sizes[i], 0, 200, iter_count/10);
+      do_ping_test(vchiq_service, sizes[i], 200, 200, iter_count/10);
+      do_ping_test(vchiq_service, sizes[i], 400, 0, iter_count/20);
+      do_ping_test(vchiq_service, sizes[i], 0, 400, iter_count/20);
+      do_ping_test(vchiq_service, sizes[i], 400, 400, iter_count/20);
+      do_ping_test(vchiq_service, sizes[i], 1000, 0, iter_count/50);
+      do_ping_test(vchiq_service, sizes[i], 0, 1000, iter_count/50);
+      do_ping_test(vchiq_service, sizes[i], 1000, 1000, iter_count/50);
+   }
+
+   vchiq_close_service(vchiq_service);
+
+   return VCHIQ_SUCCESS;
+}
+
+static VCHIQ_STATUS_T
+vchiq_signal_test(void)
+{
+   /* Measure message round trip time for various sizes*/
+   VCHIQ_INSTANCE_T vchiq_instance;
+   VCHIQ_SERVICE_HANDLE_T vchiq_service;
+   VCHIQ_SERVICE_PARAMS_T vchiq_service_params;
+   int fourcc;
+
+   static int sizes[] = { 0, 1024, 2048, VCHIQ_MAX_MSG_SIZE };
+
+   fourcc = VCHIQ_MAKE_FOURCC(g_servname[0], g_servname[1], g_servname[2], g_servname[3]);
+
+   printf("signal test - service:%s, iters:%d, version %d\n", g_servname, g_params.iters, VCHIQ_TEST_VER);
+
+#ifdef ANDROID
+   if (g_timeout_ms)
+   {
+      setup_auto_kill(g_timeout_ms);
+   }
+#endif
+
+   if (vchiq_initialise(&vchiq_instance) != VCHIQ_SUCCESS)
+   {
+      printf("* failed to open vchiq instance\n");
+      return VCHIQ_ERROR;
+   }
+
+   vchiq_connect(vchiq_instance);
+
+   INIT_PARAMS(&vchiq_service_params, fourcc, clnt_callback, "clnt userdata", VCHIQ_TEST_VER);
+   if (vchiq_open_service(vchiq_instance, &vchiq_service_params, &vchiq_service) != VCHIQ_SUCCESS)
+   {
+      printf("* failed to open service - already in use?\n");
+      return VCHIQ_ERROR;
+   }
+
+   vchiq_bulk_transmit(vchiq_service, &sizes, 16, 0, VCHIQ_BULK_MODE_BLOCKING);
+
+   vchiq_close_service(vchiq_service);
+
+   return VCHIQ_SUCCESS;
+}
+
+static VCHIQ_STATUS_T
+do_functional_test(void)
+{
+   VCHIQ_ELEMENT_T elements[4];
+   VCHIQ_INSTANCE_T instance;
+   VCHIQ_SERVICE_HANDLE_T service, service2, service3;
+   VCHIQ_SERVICE_PARAMS_T service_params;
+   VCHIQ_CONFIG_T config;
+   unsigned int size, i;
+
+   vcos_event_create(&func_test_sync, "test_sync");
+
+#ifdef ANDROID
+   if (g_timeout_ms)
+   {
+      setup_auto_kill(g_timeout_ms);
+   }
+#endif
+
+   if (func_data_test_start != -1)
+      goto bulk_tests_only;
+
+   EXPECT(vchiq_initialise(&instance), VCHIQ_SUCCESS);
+   EXPECT(vchiq_get_config(instance, sizeof(config) - 1, &config), VCHIQ_SUCCESS); // too small, but allowed for backwards compatibility
+   EXPECT(vchiq_get_config(instance, sizeof(config) + 1, &config), VCHIQ_ERROR);   // too large
+   EXPECT(vchiq_get_config(instance, sizeof(config), &config), VCHIQ_SUCCESS);    // just right
+   EXPECT(config.max_msg_size, VCHIQ_MAX_MSG_SIZE);
+
+   INIT_PARAMS(&service_params, FUNC_FOURCC, func_clnt_callback, (void *)1, VCHIQ_TEST_VER);
+   EXPECT(vchiq_add_service(instance, &service_params, &service), VCHIQ_SUCCESS);
+
+   INIT_PARAMS(&service_params, FUNC_FOURCC, func_clnt_callback, (void *)2, VCHIQ_TEST_VER);
+   EXPECT(vchiq_add_service(instance, &service_params, &service2), VCHIQ_SUCCESS);
+
+   INIT_PARAMS(&service_params, FUNC_FOURCC, clnt_callback, (void *)3, VCHIQ_TEST_VER);
+   EXPECT(vchiq_add_service(instance, &service_params, &service3), VCHIQ_ERROR); // callback doesn't match
+
+   EXPECT(vchiq_set_service_option(service, VCHIQ_SERVICE_OPTION_AUTOCLOSE, 0), VCHIQ_SUCCESS);
+   EXPECT(vchiq_set_service_option(service, VCHIQ_SERVICE_OPTION_AUTOCLOSE, 1), VCHIQ_SUCCESS);
+   EXPECT(vchiq_set_service_option(service, 42, 1), VCHIQ_ERROR); // invalid option
+   EXPECT(vchiq_remove_service(service), VCHIQ_SUCCESS);
+   EXPECT(vchiq_remove_service(service), VCHIQ_ERROR); // service already removed
+   EXPECT(vchiq_remove_service(service2), VCHIQ_SUCCESS);
+   EXPECT(vchiq_queue_message(service, NULL, 0), VCHIQ_ERROR); // service not valid
+   EXPECT(vchiq_set_service_option(service, VCHIQ_SERVICE_OPTION_AUTOCLOSE, 0), VCHIQ_ERROR); // service not valid
+
+   INIT_PARAMS(&service_params, FUNC_FOURCC, clnt_callback, (void *)3, VCHIQ_TEST_VER);
+   EXPECT(vchiq_add_service(instance, &service_params, &service3), VCHIQ_SUCCESS);
+
+   EXPECT(vchiq_queue_message(service, NULL, 0), VCHIQ_ERROR); // service not open
+   EXPECT(vchiq_queue_bulk_transmit(service, clnt_service1_data, sizeof(clnt_service1_data), (void *)1), VCHIQ_ERROR); // service not open
+   EXPECT(vchiq_queue_bulk_receive(service2, clnt_service2_data, sizeof(clnt_service2_data), (void *)2), VCHIQ_ERROR); // service not open
+   EXPECT(vchiq_queue_bulk_receive(service, 0, sizeof(clnt_service1_data), (void *)1), VCHIQ_ERROR); // invalid buffer
+   EXPECT(vchiq_shutdown(instance), VCHIQ_SUCCESS);
+   EXPECT(vchiq_initialise(&instance), VCHIQ_SUCCESS);
+   INIT_PARAMS(&service_params, FUNC_FOURCC, func_clnt_callback, (void*)1, 0);
+   EXPECT(vchiq_open_service(instance, &service_params, &service), VCHIQ_ERROR); // not connected
+   EXPECT(vchiq_connect(instance), VCHIQ_SUCCESS);
+   EXPECT(vchiq_open_service(instance, &service_params, &service), VCHIQ_ERROR); // wrong version number
+   memset(&service_params, 0, sizeof(service_params));
+   service_params.fourcc = FUNC_FOURCC;
+   service_params.callback = func_clnt_callback;
+   service_params.userdata = (void*)1;
+   service_params.version = 1;
+   service_params.version_min = 1;
+   EXPECT(vchiq_open_service(instance, &service_params, &service), VCHIQ_ERROR); // Still the wrong version number
+   service_params.version = VCHIQ_TEST_VER + 1;
+   service_params.version_min = VCHIQ_TEST_VER + 1;
+   EXPECT(vchiq_open_service(instance, &service_params, &service), VCHIQ_ERROR); // Still the wrong version number
+   service_params.version = VCHIQ_TEST_VER;
+   service_params.version_min = VCHIQ_TEST_VER;
+   EXPECT(vchiq_open_service(instance, &service_params, &service), VCHIQ_SUCCESS); // That's better
+
+   INIT_PARAMS(&service_params, VCHIQ_MAKE_FOURCC('n','o','n','e'), func_clnt_callback, (void*)2, VCHIQ_TEST_VER);
+   EXPECT(vchiq_open_service(instance, &service_params, &service2), VCHIQ_ERROR); // no listener
+   INIT_PARAMS(&service_params, FUNC_FOURCC, func_clnt_callback, (void*)2, VCHIQ_TEST_VER);
+   EXPECT(vchiq_open_service(instance, &service_params, &service2), VCHIQ_SUCCESS);
+   INIT_PARAMS(&service_params, FUNC_FOURCC, func_clnt_callback, (void*)3, VCHIQ_TEST_VER);
+   EXPECT(vchiq_open_service(instance, &service_params, &service3), VCHIQ_ERROR); // no more listeners
+   EXPECT(vchiq_remove_service(service2), VCHIQ_SUCCESS);
+   INIT_PARAMS(&service_params, FUNC_FOURCC, func_clnt_callback, (void*)2, VCHIQ_TEST_VER);
+   EXPECT(vchiq_open_service(instance, &service_params, &service2), VCHIQ_SUCCESS);
+
+   elements[0].data = "a";
+   elements[0].size = 1;
+   elements[1].data = "bcdef";
+   elements[1].size = 5;
+   elements[2].data = "ghijklmnopq";
+   elements[2].size = 11;
+   elements[3].data = "rstuvwxyz";
+   elements[3].size = 9;
+   EXPECT(vchiq_queue_message(service, elements, 4), VCHIQ_SUCCESS);
+
+   EXPECT(vchiq_queue_bulk_transmit(service2, clnt_service2_data, sizeof(clnt_service2_data), (void *)0x2001), VCHIQ_SUCCESS);
+   for (i = 0; i < sizeof(clnt_service1_data); i++)
+   {
+      clnt_service1_data[i] = (char)i;
+   }
+   EXPECT(vchiq_queue_bulk_transmit(service, clnt_service1_data, sizeof(clnt_service1_data), (void*)0x1001), VCHIQ_SUCCESS);
+
+   vcos_event_wait(&func_test_sync);
+   EXPECT(func_error, 0);
+   EXPECT(vchiq_remove_service(service), VCHIQ_SUCCESS);
+   vcos_event_wait(&func_test_sync);
+
+   EXPECT(vchiq_shutdown(instance), VCHIQ_SUCCESS);
+
+   vcos_event_wait(&func_test_sync);
+   EXPECT(func_error, 0);
+
+   INIT_PARAMS(&service_params, FUNC_FOURCC, func_clnt_callback, NULL, VCHIQ_TEST_VER);
+   EXPECT(vchiq_open_service(instance, &service_params, &service), VCHIQ_ERROR); /* Instance not initialised */
+   EXPECT(vchiq_add_service(instance, &service_params, &service), VCHIQ_ERROR); /* Instance not initialised */
+   EXPECT(vchiq_connect(instance), VCHIQ_ERROR); /* Instance not initialised */
+
+bulk_tests_only:
+   /* Now test the bulk data transfers */
+   EXPECT(vchiq_initialise(&instance), VCHIQ_SUCCESS);
+   EXPECT(vchiq_connect(instance), VCHIQ_SUCCESS);
+
+   func_data_test_iter = 0;
+
+   INIT_PARAMS(&service_params, FUN2_FOURCC, fun2_clnt_callback, NULL, VCHIQ_TEST_VER);
+   EXPECT(vchiq_open_service(instance, &service_params, &service), VCHIQ_SUCCESS);
+
+   if (func_data_test_end < func_data_test_start)
+      goto skip_bulk_tests;
+
+   printf("Testing bulk transfer for alignment.\n");
+   for (size = 1; size < 64; size++)
+   {
+      int align, srvr_align;
+      for (srvr_align = 32; srvr_align; srvr_align >>= 1)
+      {
+          for (align = 32; align; align >>= 1)
+          {
+             EXPECT(func_data_test(service, size, align & 31, srvr_align & 31), VCHIQ_SUCCESS);
+          }
+      }
+   }
+
+   printf("Testing bulk transfer at PAGE_SIZE.\n");
+   for (size = 1; size < 64; size++)
+   {
+      int align, srvr_align;
+      for (srvr_align = 32; srvr_align; srvr_align >>= 1)
+      {
+          for (align = 32; align; align >>= 1)
+          {
+             EXPECT(func_data_test(service, size, PAGE_SIZE - align, srvr_align & 31), VCHIQ_SUCCESS);
+          }
+      }
+   }
+
+   for (size = 64; size < FUN2_MAX_DATA_SIZE; size<<=1)
+   {
+      static const int aligns[] = { 0, 1, 31 };
+
+      for (i = 0; i < vcos_countof(aligns); i++)
+      {
+         int srvr_align = aligns[i];
+         unsigned int j;
+         for (j = 0; j < vcos_countof(aligns); j++)
+         {
+            int k;
+            int align = aligns[j];
+            for (k = 0; k <= 8; k++)
+            {
+               EXPECT(func_data_test(service, size, align, srvr_align + k), VCHIQ_SUCCESS);
+            }
+         }
+      }
+   }
+
+skip_bulk_tests:
+
+   EXPECT(vchiq_shutdown(instance), VCHIQ_SUCCESS);
+
+   vcos_event_delete(&func_test_sync);
+
+   return VCHIQ_SUCCESS;
+
+error_exit:
+   return VCHIQ_ERROR;
+}
+
+static void
+do_ping_test(VCHIQ_SERVICE_HANDLE_T service, int size, int async, int oneway, int iters)
+{
+   uint32_t start, end;
+   char *ping_buf = malloc(size + sizeof(struct test_params));
+   struct test_params *params = (struct test_params *)ping_buf;
+   VCHIQ_ELEMENT_T element;
+   int i;
+
+   element.data = ping_buf;
+
+   /* Set up the quotas for messages */
+   *params = g_params;
+   params->magic = MSG_CONFIG;
+   params->blocksize = 0;
+   element.size = sizeof(*params);
+   vchiq_queue_message(service, &element, 1);
+   vcos_event_wait(&g_server_reply);
+   vchiq_set_service_option(service, VCHIQ_SERVICE_OPTION_MESSAGE_QUOTA, params->client_message_quota);
+
+   /* Allow enough room for the type header */
+   element.size = (size < 4) ? 4 : size;
+
+   bulk_tx_received = -1;
+
+   start = vcos_getmicrosecs();
+   for (i = 0; i < iters; i++)
+   {
+      int j;
+      for (j = 0; j < vcos_max(async, oneway); j++)
+      {
+         if (j < async)
+         {
+            params->magic = MSG_ASYNC;
+            vchiq_queue_message(service, &element, 1);
+         }
+         if (j < oneway)
+         {
+            params->magic = MSG_ONEWAY;
+            vchiq_queue_message(service, &element, 1);
+         }
+      }
+      params->magic = MSG_SYNC;
+      vchiq_queue_message(service, &element, 1);
+      vcos_event_wait(&g_server_reply);
+   }
+   end = vcos_getmicrosecs();
+
+   printf("ping (size %d, %d async, %d oneway) -> %fus\n", size, async, oneway, ((float)(end - start))/iters);
+
+   vcos_sleep(20);
+
+   if ((async == 0) && (oneway == 0))
+   {
+      *params = g_params;
+      params->magic = MSG_CONFIG;
+      params->blocksize = size ? size : 8;
+      params->iters = iters;
+      params->verify = 0;
+      params->echo = 0;
+
+      element.size = sizeof(*params);
+      vchiq_queue_message(service, &element, 1);
+      vcos_event_wait(&g_server_reply);
+
+      vcos_sleep(30);
+
+      start = vcos_getmicrosecs();
+      for (i = 0; i < iters; i++)
+      {
+         vchiq_queue_bulk_transmit(service, ping_buf, params->blocksize, 0);
+         vcos_event_wait(&g_server_reply);
+      }
+      end = vcos_getmicrosecs();
+
+      printf("bulk (size %d, async) -> %fus\n", size, ((float)(end - start))/iters);
+
+      vcos_sleep(40);
+   }
+
+   if (oneway == 0)
+   {
+      *params = g_params;
+      params->magic = MSG_CONFIG;
+      params->blocksize = size ? size : 8;
+      params->iters = iters * (async + 1);
+      params->verify = 0;
+      params->echo = 0;
+
+      element.size = sizeof(*params);
+      vchiq_queue_message(service, &element, 1);
+      vcos_event_wait(&g_server_reply);
+
+      vcos_sleep(50);
+
+      start = vcos_getmicrosecs();
+      for (i = 0; i < iters; i++)
+      {
+         int j;
+         for (j = 0; j < async; j++)
+            vchiq_bulk_transmit(service, ping_buf, params->blocksize, 0, VCHIQ_BULK_MODE_NOCALLBACK);
+         vchiq_bulk_transmit(service, ping_buf, params->blocksize, 0, VCHIQ_BULK_MODE_BLOCKING);
+      }
+      end = vcos_getmicrosecs();
+
+      printf("bulk (size %d, %d async) -> %fus\n", size, async, ((float)(end - start))/iters);
+
+      vcos_sleep(60);
+   }
+
+   free(ping_buf);
+
+   bulk_tx_received = 0;
+}
+
+static void
+do_vchi_ping_test(VCHI_SERVICE_HANDLE_T service, int size, int async, int oneway, int iters)
+{
+   uint32_t start, end;
+   uint32_t actual;
+   char *ping_buf = malloc(size + sizeof(struct test_params));
+   char pong_buf[100];
+   struct test_params *params = (struct test_params *)ping_buf;
+   int msg_size;
+   int i;
+
+   /* Set up the quotas for messages */
+   *params = g_params;
+   params->magic = MSG_CONFIG;
+   params->blocksize = 0;
+   vchi_msg_queue(service, params, sizeof(*params), VCHI_FLAGS_BLOCK_UNTIL_QUEUED, 0);
+   vcos_event_wait(&g_server_reply);
+   vchiq_set_service_option((VCHIQ_SERVICE_HANDLE_T)service, VCHIQ_SERVICE_OPTION_MESSAGE_QUOTA, params->client_message_quota);
+
+   /* Allow enough room for the type header */
+   msg_size = (size < 4) ? 4 : size;
+
+   bulk_tx_received = -1;
+
+   if ((oneway == 0) && (async == 0))
+   {
+      params->magic = MSG_SYNC;
+
+      g_sync_mode = 1;
+
+      start = vcos_getmicrosecs();
+      for (i = 0; i < iters; i++)
+      {
+         vchi_msg_queue(service, ping_buf, msg_size, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, 0);
+         vchi_msg_dequeue(service, pong_buf, sizeof(pong_buf), &actual, VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE);
+      }
+      end = vcos_getmicrosecs();
+
+      printf("vchi ping (size %d) -> %fus\n", size, ((float)(end - start))/iters);
+
+      vcos_sleep(10);
+
+      g_sync_mode = 0;
+   }
+
+   while (vchi_msg_dequeue(service, pong_buf, sizeof(pong_buf), &actual, VCHI_FLAGS_NONE) != -1)
+   {
+      printf("* Unexpected message found in queue - size %d\n", actual);
+   }
+
+   start = vcos_getmicrosecs();
+   for (i = 0; i < iters; i++)
+   {
+      int j;
+      for (j = 0; j < vcos_max(async, oneway); j++)
+      {
+         if (j < async)
+         {
+            params->magic = MSG_ASYNC;
+            vchi_msg_queue(service, ping_buf, msg_size, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, 0);
+         }
+         if (j < oneway)
+         {
+            params->magic = MSG_ONEWAY;
+            vchi_msg_queue(service, ping_buf, msg_size, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, 0);
+         }
+      }
+      params->magic = MSG_SYNC;
+      vchi_msg_queue(service, ping_buf, msg_size, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, 0);
+      vcos_event_wait(&g_server_reply);
+   }
+   end = vcos_getmicrosecs();
+
+   printf("vchi ping (size %d, %d async, %d oneway) -> %fus\n", size, async, oneway, ((float)(end - start))/iters);
+
+   vcos_sleep(20);
+
+   if ((async == 0) && (oneway == 0))
+   {
+      *params = g_params;
+      params->magic = MSG_CONFIG;
+      params->blocksize = size ? size : 8;
+      params->iters = iters;
+      params->verify = 0;
+      params->echo = 0;
+
+      vchi_msg_queue(service, params, sizeof(*params), VCHI_FLAGS_BLOCK_UNTIL_QUEUED, 0);
+      vcos_event_wait(&g_server_reply);
+
+      vcos_sleep(30);
+
+      start = vcos_getmicrosecs();
+      for (i = 0; i < iters; i++)
+      {
+         vchi_bulk_queue_transmit(service, ping_buf, params->blocksize,
+            VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | VCHI_FLAGS_BLOCK_UNTIL_QUEUED, 0);
+         vcos_event_wait(&g_server_reply);
+      }
+      end = vcos_getmicrosecs();
+
+      printf("vchi bulk (size %d, %d async, %d oneway) -> %fus\n", size, async, oneway, ((float)(end - start))/iters);
+
+      vcos_sleep(40);
+   }
+
+   if (oneway == 0)
+   {
+      *params = g_params;
+      params->magic = MSG_CONFIG;
+      params->blocksize = size ? size : 8;
+      params->iters = iters * (async + 1);
+      params->verify = 0;
+      params->echo = 0;
+
+      vchi_msg_queue(service, params, sizeof(*params), VCHI_FLAGS_BLOCK_UNTIL_QUEUED, 0);
+      vcos_event_wait(&g_server_reply);
+
+      vcos_sleep(50);
+
+      start = vcos_getmicrosecs();
+      for (i = 0; i < iters; i++)
+      {
+         int j;
+         for (j = 0; j < async; j++)
+            vchi_bulk_queue_transmit(service, ping_buf, params->blocksize, VCHI_FLAGS_NONE, 0);
+         vchi_bulk_queue_transmit(service, ping_buf, params->blocksize, VCHI_FLAGS_BLOCK_UNTIL_DATA_READ, 0);
+      }
+      end = vcos_getmicrosecs();
+
+      printf("vchi bulk (size %d, %d oneway) -> %fus\n", size, oneway, ((float)(end - start))/iters);
+
+      vcos_sleep(60);
+   }
+
+   free(ping_buf);
+
+   bulk_tx_received = 0;
+}
+
+static VCHIQ_STATUS_T
+func_data_test(VCHIQ_SERVICE_HANDLE_T service, int datalen, int align, int server_align)
+{
+   enum { PROLOGUE_SIZE = 32, EPILOGUE_SIZE = 32 };
+   static uint8_t databuf[PAGE_SIZE + PROLOGUE_SIZE + FUN2_MAX_DATA_SIZE + EPILOGUE_SIZE];
+   static uint8_t databuf2[PAGE_SIZE + PROLOGUE_SIZE + FUN2_MAX_DATA_SIZE + EPILOGUE_SIZE];
+   uint8_t *data, *data2, *prologue, *epilogue;
+   VCHIQ_ELEMENT_T element;
+   int params[4] = { datalen, server_align, align, func_data_test_iter };
+   int success = 1, i;
+
+   if (!vcos_verify(datalen < FUN2_MAX_DATA_SIZE))
+      return VCHIQ_ERROR;
+
+   if ((func_data_test_iter < func_data_test_start) || (func_data_test_iter > func_data_test_end))
+      goto skip_iter;
+
+   element.size = sizeof(params);
+   element.data = &params;
+   EXPECT(vchiq_queue_message(service, &element, 1), VCHIQ_SUCCESS);
+
+   memset(databuf, 0xff, sizeof(databuf));
+   data = (uint8_t *)((uintptr_t)databuf & ~(PAGE_SIZE - 1)) + align;
+   data = (uint8_t *)((((intptr_t)databuf + PROLOGUE_SIZE) & ~(FUN2_MAX_ALIGN - 1)) + align - PROLOGUE_SIZE);
+   if (data < databuf)
+      data += PAGE_SIZE;
+   data += PROLOGUE_SIZE;
+
+   EXPECT(vchiq_queue_bulk_receive(service, data, datalen, NULL), VCHIQ_SUCCESS);
+
+   data2 = (uint8_t *)(((uintptr_t)databuf2 + PROLOGUE_SIZE) & ~(PAGE_SIZE - 1)) + align - PROLOGUE_SIZE;
+   if (data2 < databuf2)
+      data2 += PAGE_SIZE;
+   prologue = data2;
+   data2 += PROLOGUE_SIZE;
+   epilogue = data2 + datalen;
+
+   memset(prologue, 0xff, PROLOGUE_SIZE);
+   memset(epilogue, 0xff, EPILOGUE_SIZE);
+
+   for (i = 0; i < (datalen - 1); i++)
+   {
+      data2[i] = (uint8_t)(((i & 0x1f) == 0) ? (i >> 5) : i);
+   }
+   data2[i] = '\0';
+
+   /* Attempt to pull the boundaries into the cache */
+   prologue = data - PROLOGUE_SIZE;
+   epilogue = data + datalen;
+   prologue[PROLOGUE_SIZE - 1] = 0xfe;
+   epilogue[0] = 0xfe;
+
+   EXPECT(vchiq_queue_bulk_transmit(service, data2, datalen, NULL), VCHIQ_SUCCESS);
+   vcos_event_wait(&func_test_sync); /* Wait for the receive to complete */
+
+   for (i = 0; i < PROLOGUE_SIZE; i++)
+   {
+      if (prologue[i] != (uint8_t)((i == PROLOGUE_SIZE - 1) ? '\xfe' : '\xff'))
+      {
+         vcos_log_error("%d: Prologue corrupted at %x (datalen %x, align %x, server_align %x) -> %02x", func_data_test_iter, i, datalen, align, server_align, prologue[i]);
+         VCOS_BKPT;
+         success = 0;
+         break;
+      }
+   }
+   for (i = 0; i < EPILOGUE_SIZE; i++)
+   {
+      if (epilogue[i] != (uint8_t)((i == 0) ? '\xfe' : '\xff'))
+      {
+         vcos_log_error("%d: Epilogue corrupted at %x (datalen %x, align %x, server_align %x) -> %02x", func_data_test_iter, i, datalen, align, server_align, epilogue[i]);
+         VCOS_BKPT;
+         success = 0;
+         break;
+      }
+   }
+
+   if (success)
+   {
+      int diffs = 0;
+      for (i = 0; i < datalen; i++)
+      {
+         int diff = (i == datalen - 1) ?
+            (data[i] != 0) :
+            ((i & 0x1f) == 0) ?
+            (data[i] != (uint8_t)(i >> 5)) :
+            (data[i] != (uint8_t)i);
+
+         if (diff)
+            diffs++;
+         else if (diffs)
+         {
+            vcos_log_error("%d: Data corrupted at %x-%x (datalen %x, align %x, server_align %x) -> %02x", func_data_test_iter, i - diffs, i - 1, datalen, align, server_align, data[i-1]);
+            VCOS_BKPT;
+            success = 0;
+            diffs = 0;
+         }
+      }
+      if (diffs)
+      {
+         vcos_log_error("%d: Data corrupted at %x-%x (datalen %x, align %x, server_align %x) -> %02x", func_data_test_iter, i - diffs, i - 1, datalen, align, server_align, data[i-1]);
+         VCOS_BKPT;
+         success = 0;
+      }
+   }
+
+skip_iter:
+   if (success)
+   {
+      func_data_test_iter++;
+      return VCHIQ_SUCCESS;
+   }
+
+error_exit:
+   return VCHIQ_ERROR;
+}
+
+
+#ifdef VCHIQ_LOCAL
+
+static void *vchiq_test_server(void *param)
+{
+   VCHIQ_INSTANCE_T instance;
+
+   vcos_demand(vchiq_initialise(&instance) == VCHIQ_SUCCESS);
+   vchiq_test_start_services(instance);
+   vchiq_connect(instance);
+   printf("test server started\n");
+   return 0;
+}
+
+#endif
+
+static VCHIQ_STATUS_T
+clnt_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
+   VCHIQ_SERVICE_HANDLE_T service, void *bulk_userdata)
+{
+   int data;
+   vcos_mutex_lock(&g_mutex);
+   if (reason == VCHIQ_MESSAGE_AVAILABLE)
+   {
+      /* 
+       * Store the header size as it is going to be released
+       * and the size may be overwritten by the release.
+       */
+      size_t header_size = header->size;
+
+      if (header_size <= 1)
+         vchiq_release_message(service, header);
+      else
+      /* Responses of length 0 are not sync points */
+      if ((header_size >= 4) && (memcpy(&data, header->data, sizeof(data)), data == MSG_ECHO))
+      {
+         /* This is a complete echoed packet */
+         if (g_params.verify && (mem_check(header->data, bulk_tx_data[ctrl_received % NUM_BULK_BUFS], g_params.blocksize) != 0))
+            g_server_error = "corrupt data";
+         else
+            ctrl_received++;
+         if (g_server_error || (ctrl_received == g_params.iters))
+            vcos_event_signal(&g_shutdown);
+         vchiq_release_message(service, header);
+      }
+      else if (header_size != 0)
+         g_server_error = header->data;
+
+      if ((header_size != 0) || g_server_error)
+         vcos_event_signal(&g_server_reply);
+   }
+   else if (reason == VCHIQ_BULK_TRANSMIT_DONE)
+   {
+      int i = (int)bulk_userdata;
+      vcos_log_trace("  BULK_TRANSMIT_DONE(%d)", i);
+      if (bulk_tx_received < 0)
+         vcos_event_signal(&g_server_reply);
+      else
+      {
+         vcos_assert(i == bulk_tx_received);
+         bulk_tx_received++;
+         if (bulk_tx_sent < g_params.iters)
+         {
+            vchiq_queue_bulk_transmit(service, bulk_tx_data[i % NUM_BULK_BUFS], g_params.blocksize, (void *)bulk_tx_sent);
+            bulk_tx_sent++;
+         }
+      }
+   }
+   else if (reason == VCHIQ_BULK_RECEIVE_DONE)
+   {
+      int i = (int)bulk_userdata;
+      vcos_log_trace("  BULK_RECEIVE_DONE(%d): data '%s'", i, bulk_rx_data[i % NUM_BULK_BUFS]);
+      vcos_assert(i == bulk_rx_received);
+      if (g_params.verify && (mem_check(bulk_tx_data[i % NUM_BULK_BUFS], bulk_rx_data[i % NUM_BULK_BUFS], g_params.blocksize) != 0))
+      {
+         vcos_log_error("* Data corruption - %d: %x, %x, %x", i, (unsigned int)bulk_tx_data[i % NUM_BULK_BUFS], (unsigned int)bulk_rx_data[i % NUM_BULK_BUFS], g_params.blocksize);
+         VCOS_BKPT;
+      }
+      bulk_rx_received++;
+      if (bulk_rx_sent < g_params.iters)
+      {
+         if (g_params.verify)
+            memset(bulk_rx_data[i % NUM_BULK_BUFS], 0xff, g_params.blocksize);
+         vchiq_queue_bulk_receive(service, bulk_rx_data[i % NUM_BULK_BUFS], g_params.blocksize, (void *)bulk_rx_sent);
+         bulk_rx_sent++;
+      }
+   }
+   else if (reason == VCHIQ_BULK_TRANSMIT_ABORTED)
+   {
+      int i = (int)bulk_userdata;
+      vcos_log_info("  BULK_TRANSMIT_ABORTED(%d)", i);
+   }
+   else if (reason == VCHIQ_BULK_RECEIVE_ABORTED)
+   {
+      int i = (int)bulk_userdata;
+      vcos_log_info("  BULK_RECEIVE_ABORTED(%d)", i);
+   }
+   if ((bulk_tx_received == g_params.iters) &&
+      ((g_params.echo == 0) || (bulk_rx_received == g_params.iters)))
+      vcos_event_signal(&g_shutdown);
+   vcos_mutex_unlock(&g_mutex);
+   return VCHIQ_SUCCESS;
+}
+
+static void
+vchi_clnt_callback(void *callback_param,
+   VCHI_CALLBACK_REASON_T reason,
+   void *handle)
+{
+   VCHI_SERVICE_HANDLE_T service = *(VCHI_SERVICE_HANDLE_T *)callback_param;
+   vcos_mutex_lock(&g_mutex);
+   if (reason == VCHI_CALLBACK_MSG_AVAILABLE)
+   {
+      if (!g_sync_mode)
+      {
+         static char pong_buf[100];
+         uint32_t actual;
+         while (vchi_msg_dequeue(service, pong_buf, sizeof(pong_buf), &actual, VCHI_FLAGS_NONE) == 0)
+         {
+            if (actual > 1)
+               g_server_error = pong_buf;
+            if (actual != 0)
+            {
+               /* Responses of length 0 are not sync points */
+               vcos_event_signal(&g_server_reply);
+               break;
+            }
+         }
+      }
+   }
+   else if (reason == VCHI_CALLBACK_BULK_SENT)
+   {
+      int i = (int)handle;
+      vcos_log_trace("  BULK_TRANSMIT_DONE(%d)", i);
+      if (bulk_tx_received < 0)
+         vcos_event_signal(&g_server_reply);
+      else
+      {
+         vcos_assert(i == bulk_tx_received);
+         bulk_tx_received++;
+         if (bulk_tx_sent < g_params.iters)
+         {
+            vchi_bulk_queue_transmit(service, bulk_tx_data[i % NUM_BULK_BUFS],
+               g_params.blocksize,
+               VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
+               (void *)bulk_tx_sent);
+            bulk_tx_sent++;
+         }
+      }
+   }
+   else if (reason == VCHI_CALLBACK_BULK_RECEIVED)
+   {
+      int i = (int)handle;
+      vcos_log_trace("  BULK_RECEIVE_DONE(%d): data '%s'", i, bulk_rx_data[i % NUM_BULK_BUFS]);
+      vcos_assert(i == bulk_rx_received);
+      if (g_params.verify && (mem_check(bulk_tx_data[i % NUM_BULK_BUFS], bulk_rx_data[i % NUM_BULK_BUFS], g_params.blocksize) != 0))
+      {
+         vcos_log_error("* Data corruption - %x, %x, %x", (unsigned int)bulk_tx_data[i % NUM_BULK_BUFS], (unsigned int)bulk_rx_data[i % NUM_BULK_BUFS], g_params.blocksize);
+         VCOS_BKPT;
+      }
+      bulk_rx_received++;
+      if (bulk_rx_sent < g_params.iters)
+      {
+         if (g_params.verify)
+            memset(bulk_rx_data[i % NUM_BULK_BUFS], 0xff, g_params.blocksize);
+         vchi_bulk_queue_receive(service, bulk_rx_data[i % NUM_BULK_BUFS], g_params.blocksize,
+            VCHI_FLAGS_CALLBACK_WHEN_OP_COMPLETE | VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
+            (void *)bulk_rx_sent);
+         bulk_rx_sent++;
+      }
+   }
+   else if (reason == VCHI_CALLBACK_BULK_TRANSMIT_ABORTED)
+   {
+      int i = (int)handle;
+      vcos_log_info("  BULK_TRANSMIT_ABORTED(%d)", i);
+   }
+   else if (reason == VCHI_CALLBACK_BULK_RECEIVE_ABORTED)
+   {
+      int i = (int)handle;
+      vcos_log_info("  BULK_RECEIVE_ABORTED(%d)", i);
+   }
+   if ((bulk_tx_received == g_params.iters) && (bulk_rx_received == g_params.iters))
+      vcos_event_signal(&g_shutdown);
+   vcos_mutex_unlock(&g_mutex);
+}
+
+static VCHIQ_STATUS_T
+func_clnt_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
+   VCHIQ_SERVICE_HANDLE_T service, void *bulk_userdata)
+{
+   static int callback_count = 0, bulk_count = 0;
+   int callback_index = 0, bulk_index = 0;
+
+   if (reason < VCHIQ_BULK_TRANSMIT_DONE)
+   {
+      callback_count++;
+
+      START_CALLBACK(VCHIQ_SERVICE_CLOSED, 2)
+      END_CALLBACK(VCHIQ_SUCCESS)
+
+      START_CALLBACK(VCHIQ_MESSAGE_AVAILABLE, 1)
+      EXPECT(bulk_userdata, NULL);
+      EXPECT(header->size, 26);
+      EXPECT(mem_check(header->data, "abcdefghijklmnopqrstuvwxyz", 26), 0);
+      vchiq_release_message(service, header);
+      END_CALLBACK(VCHIQ_SUCCESS)
+
+      START_CALLBACK(VCHIQ_MESSAGE_AVAILABLE, 1)
+      EXPECT(bulk_userdata, NULL);
+      EXPECT(header->size, 0);
+      vchiq_release_message(service, header);
+      EXPECT(vchiq_queue_bulk_receive(service, clnt_service2_data, sizeof(clnt_service2_data), (void*)0x1004), VCHIQ_SUCCESS);
+      vcos_event_signal(&func_test_sync);
+      END_CALLBACK(VCHIQ_SUCCESS)
+
+      START_CALLBACK(VCHIQ_SERVICE_CLOSED, 1)
+      vcos_event_signal(&func_test_sync);
+      END_CALLBACK(VCHIQ_SUCCESS)
+
+      START_CALLBACK(VCHIQ_SERVICE_CLOSED, 2)
+      vcos_event_signal(&func_test_sync);
+      callback_count = 0;
+      bulk_count = 0;
+      END_CALLBACK(VCHIQ_SUCCESS)
+   }
+   else
+   {
+      bulk_count++;
+
+      START_BULK_CALLBACK(VCHIQ_BULK_TRANSMIT_DONE, 1, 0x1001)
+      memset(clnt_service2_data, 0xff, sizeof(clnt_service2_data));
+      EXPECT(vchiq_queue_bulk_receive(service, clnt_service2_data, sizeof(clnt_service2_data), (void*)0x1002), VCHIQ_SUCCESS);
+      END_CALLBACK(VCHIQ_SUCCESS)
+
+      START_BULK_CALLBACK(VCHIQ_BULK_RECEIVE_ABORTED, 1, 0x1002)
+      EXPECT(vchiq_queue_bulk_receive(service, clnt_service2_data, sizeof(clnt_service2_data), (void*)0x1003), VCHIQ_SUCCESS);
+      END_CALLBACK(VCHIQ_SUCCESS)
+
+      START_BULK_CALLBACK(VCHIQ_BULK_RECEIVE_DONE, 1, 0x1003)
+      (void)(mem_check(clnt_service1_data, clnt_service2_data, sizeof(clnt_service1_data)), 0);
+      (void)(mem_check(clnt_service1_data, clnt_service2_data + sizeof(clnt_service1_data), sizeof(clnt_service1_data)), 0);
+      END_CALLBACK(VCHIQ_SUCCESS)
+
+      START_BULK_CALLBACK(VCHIQ_BULK_RECEIVE_ABORTED, 1, 0x1004)
+      END_CALLBACK(VCHIQ_SUCCESS)
+
+      START_BULK_CALLBACK(VCHIQ_BULK_TRANSMIT_ABORTED, 2, 0x2001)
+      END_CALLBACK(VCHIQ_SUCCESS)
+   }
+
+error_exit:
+   callback_count = 0;
+   bulk_count = 0;
+
+   func_error = 1;
+   vcos_event_signal(&func_test_sync);
+
+   return VCHIQ_ERROR;
+}
+
+static VCHIQ_STATUS_T
+fun2_clnt_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header,
+   VCHIQ_SERVICE_HANDLE_T service, void *bulk_userdata)
+{
+   vcos_unused(header);
+   vcos_unused(service);
+   vcos_unused(bulk_userdata);
+
+   switch (reason)
+   {
+   case VCHIQ_SERVICE_OPENED:
+   case VCHIQ_SERVICE_CLOSED:
+   case VCHIQ_BULK_TRANSMIT_DONE:
+      break;
+   case VCHIQ_BULK_RECEIVE_DONE:
+      vcos_event_signal(&func_test_sync);
+      break;
+   default:
+      fun2_error = 1;
+      vcos_event_signal(&func_test_sync);
+      break;
+   }
+
+   return VCHIQ_SUCCESS;
+}
+
+static int mem_check(const void *expected, const void *actual, int size)
+{
+   if (memcmp(expected, actual, size) != 0)
+   {
+      int i;
+      for (i = 0; i < size; i++)
+      {
+         int ce = ((const char *)expected)[i];
+         int ca = ((const char *)actual)[i];
+         if (ca != ce)
+            printf("%08x,%x: %02x <-> %02x\n", i + (unsigned int)actual, i, ce, ca);
+      }
+      printf("mem_check failed - buffer %x, size %d\n", (unsigned int)actual, size);
+      return 1;
+   }
+   return 0;
+}
+
+static void usage(void)
+{
+   printf("Usage: vchiq_test [<options>] <mode> <iters>\n");
+   printf("  where <options> is any of:\n");
+   printf("    -a <c> <s>  set the client and server bulk alignment (modulo 32)\n");
+   printf("    -A <c> <s>  set the client and server bulk alignment (modulo 4096)\n");
+   printf("    -e          disable echoing in the main bulk transfer mode\n");
+   printf("    -k <n>      skip the first <n> func data tests\n");
+   printf("    -m <n>      set the client message quota to <n>\n");
+   printf("    -M <n>      set the server message quota to <n>\n");
+   printf("    -q          disable data verification\n");
+   printf("    -s ????     service (any 4 characters)\n");
+   printf("    -v          enable more verbose output\n");
+   printf("    -r <b> <s>  reserve <b> bytes for <s> seconds\n");
+   printf("    -K <t>      send a SIGKILL after <t> ms\n");
+   printf("  and <mode> is one of:\n");
+   printf("    -c <size>   control test (size in bytes)\n");
+   printf("    -b <size>   bulk test (size in kilobytes)\n");
+   printf("    -f          functional test\n");
+   printf("    -p          ping test\n");
+   printf("    -t          check the timer\n");
+   printf("  and <iters> is the number of test iterations\n");
+   exit(1);
+}
+
+static void check_timer(void)
+{
+   uint32_t start = vcos_getmicrosecs();
+   uint32_t sleep_time = 1000;
+
+   printf("0\n");
+
+   while (1)
+   {
+      uint32_t now;
+      vcos_sleep(sleep_time);
+      now = vcos_getmicrosecs();
+      printf("%d - sleep %d\n", now - start, sleep_time);
+   }
+}
+
+static char *buf_align(char *buf, int align_size, int align)
+{
+   char *aligned = buf - ((intptr_t)buf & (align_size - 1)) + align;
+   if (aligned < buf)
+      aligned += align_size;
+   return aligned;
+}
+
+#ifdef ANDROID
+
+static void kill_timeout_handler(int cause, siginfo_t *how, void *ucontext)
+{
+   printf("Sending signal SIGKILL\n");
+   kill(main_process_pid, SIGKILL);
+}
+
+static int setup_auto_kill(int timeout_ms)
+{
+   long timeout;
+   struct timeval interval;
+
+   if (timeout_ms <= 0)
+   {
+      return -1;
+   }
+   timeout = 1000 * timeout_ms;
+
+   /* install a signal handler for the alarm */
+   struct sigaction sa;
+   memset(&sa, 0, sizeof(struct sigaction));
+   sa.sa_sigaction = kill_timeout_handler;
+   sigemptyset(&sa.sa_mask);
+   sa.sa_flags = SA_SIGINFO;
+   if (sigaction(SIGALRM, &sa, 0))
+   {
+      perror("sigaction");
+      exit(1);
+   }
+
+   /* when to expire */
+   interval.tv_sec = timeout / 1000000;
+   interval.tv_usec = timeout % 1000000;
+
+   struct itimerval alarm_spec = {
+     .it_interval = {0,0},
+     .it_value = interval
+   };
+
+   int rc = setitimer(ITIMER_REAL, &alarm_spec, NULL);
+   if (rc < 0)
+   {
+      perror("setitimer failed");
+      exit(1);
+   }
+
+   return 0;
+}
+
+
+
+#endif
+
+#ifdef VCOS_APPLICATION_INITIALIZE
+
+static VCOS_THREAD_T   Task_0;
+
+void *main_task(void *param)
+{
+   vchiq_test(rtos_argc, rtos_argv);
+
+   VCOS_BKPT;
+
+   return NULL;
+}
+
+#include "vcfw/logging/logging.h"
+
+void VCOS_APPLICATION_INITIALIZE(void *first_available_memory)
+{
+   const int      stack_size = 64*1024;
+   void          *pointer = NULL;
+   VCOS_STATUS_T  status;
+
+   logging_init();
+   logging_level(LOGGING_VCOS);
+   vcos_init();
+
+   /* Create task 0.  */
+#if VCOS_CAN_SET_STACK_ADDR
+   pointer = malloc(stack_size);
+   vcos_demand(pointer);
+#endif
+   status = vcos_thread_create_classic( &Task_0, "TASK 0", main_task, (void *)0, pointer, stack_size,
+                                        10 | VCOS_AFFINITY_DEFAULT, 20, VCOS_START );
+   vcos_demand(status == VCOS_SUCCESS);
+}
+
+#else
+
+int main(int argc, char **argv)
+{
+#ifdef ANDROID
+   main_process_pid = getpid();
+#endif
+
+   vcos_init();
+   vcos_use_android_log = 0;
+   return vchiq_test(argc, argv);
+}
+
+#endif
diff --git a/interface/vchiq_arm/vchiq_test.h b/interface/vchiq_arm/vchiq_test.h
new file mode 100755 (executable)
index 0000000..4a93345
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef VCHIQ_TEST_H
+#define VCHIQ_TEST_H
+
+#include "vchiq_test_if.h"
+
+#define VCOS_LOG_CATEGORY (&vchiq_test_log_category)
+
+#define VERBOSE_TRACE 1
+
+#define FUNC_FOURCC VCHIQ_MAKE_FOURCC('f','u','n','c')
+#define FUN2_FOURCC VCHIQ_MAKE_FOURCC('f','u','n','2')
+
+#define SERVICE1_DATA_SIZE 1024
+#define SERVICE2_DATA_SIZE 2048
+#define FUN2_MAX_DATA_SIZE 16384
+#define FUN2_MAX_ALIGN     4096
+#define BULK_ALIGN_SIZE    4096
+
+#define VCHIQ_TEST_VER     3
+
+enum {
+   MSG_ERROR,
+   MSG_ONEWAY,
+   MSG_ASYNC,
+   MSG_SYNC,
+   MSG_CONFIG,
+   MSG_ECHO
+};
+
+struct test_params
+{
+   int magic; /* = MSG_CONFIG */
+   int blocksize;
+   int iters;
+   int verify;
+   int echo;
+   int align_size;
+   int client_align;
+   int server_align;
+   int client_message_quota;
+   int server_message_quota;
+};
+
+#if VERBOSE_TRACE
+
+#define EXPECT(_e, _v) if (_e != _v) { vcos_log_error("%d: " #_e " != " #_v, __LINE__); VCOS_BKPT; goto error_exit; } else { vcos_log_trace("%d: " #_e " == " #_v, __LINE__); }
+
+#define START_CALLBACK(_r, _u) \
+   if (++callback_index == callback_count) { \
+      if (reason != _r) { \
+         vcos_log_error("%d: expected callback reason " #_r ", got %d", __LINE__, reason); VCOS_BKPT; goto error_exit; \
+      } \
+      else if ((int)VCHIQ_GET_SERVICE_USERDATA(service) != _u) { \
+         vcos_log_error("%d: expected userdata %d, got %d", __LINE__, _u, (int)VCHIQ_GET_SERVICE_USERDATA(service)); VCOS_BKPT; goto error_exit; \
+      } \
+      else \
+      { \
+         vcos_log_trace("%d: " #_r ", " #_u, __LINE__); \
+      }
+
+#define START_BULK_CALLBACK(_r, _u, _bu)   \
+   if (++bulk_index == bulk_count) {  \
+      if (reason != _r) { \
+         vcos_log_error("%d: expected callback reason " #_r ", got %d", __LINE__, reason); VCOS_BKPT; goto error_exit; \
+      } \
+      else if ((int)VCHIQ_GET_SERVICE_USERDATA(service) != _u) { \
+         vcos_log_error("%d: expected userdata %d, got %d", __LINE__, _u, (int)VCHIQ_GET_SERVICE_USERDATA(service)); VCOS_BKPT; goto error_exit; \
+      } \
+      else if ((int)bulk_userdata != _bu) { \
+         vcos_log_error("%d: expected bulk_userdata %d, got %d", __LINE__, _bu, (int)bulk_userdata); VCOS_BKPT; goto error_exit; \
+      } \
+      else \
+      { \
+         vcos_log_trace("%d: " #_r ", " #_u ", " #_bu, __LINE__); \
+      }
+
+#else
+
+#define EXPECT(_e, _v) if (_e != _v) { vcos_log_trace("%d: " #_e " != " #_v, __LINE__); VCOS_BKPT; goto error_exit; }
+
+#define START_CALLBACK(_r, _u) \
+   if (++callback_index == callback_count) { \
+      if (reason != _r) { \
+         vcos_log_error("%d: expected callback reason " #_r ", got %d", __LINE__, reason); VCOS_BKPT; goto error_exit; \
+      } \
+      else if ((int)VCHIQ_GET_SERVICE_USERDATA(service) != _u) { \
+         vcos_log_error("%d: expected userdata %d, got %d", __LINE__, _u, (int)VCHIQ_GET_SERVICE_USERDATA(service)); VCOS_BKPT; goto error_exit; \
+      }
+
+#define START_BULK_CALLBACK(_r, _u, _bu)   \
+   if (++bulk_index == bulk_count) {  \
+      if (reason != _r) { \
+         vcos_log_error("%d: expected callback reason " #_r ", got %d", __LINE__, reason); VCOS_BKPT; goto error_exit; \
+      } \
+      else if ((int)VCHIQ_GET_SERVICE_USERDATA(service) != _u) { \
+         vcos_log_error("%d: expected userdata %d, got %d", __LINE__, _u, (int)VCHIQ_GET_SERVICE_USERDATA(service)); VCOS_BKPT; goto error_exit; \
+      } \
+      else if ((int)bulk_userdata != _bu) { \
+         vcos_log_error("%d: expected bulkuserdata %d, got %d", __LINE__, _bu, (int)bulk_userdata); VCOS_BKPT; goto error_exit; \
+      }
+
+#endif
+
+#define END_CALLBACK(_s) \
+      return _s; \
+   }
+
+#endif
diff --git a/interface/vchiq_arm/vchiq_test_if.h b/interface/vchiq_arm/vchiq_test_if.h
new file mode 100755 (executable)
index 0000000..665c1a6
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VCHIQ_TEST_IF_H
+#define VCHIQ_TEST_IF_H
+
+#include "vchiq.h"
+
+extern void vchiq_test_start_services(VCHIQ_INSTANCE_T instance);
+
+#endif
diff --git a/interface/vchiq_arm/vchiq_util.c b/interface/vchiq_arm/vchiq_util.c
new file mode 100755 (executable)
index 0000000..f6e361f
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "vchiq_util.h"
+
+#if !defined(__KERNEL__)
+#include <stdlib.h>
+#endif
+
+static __inline int is_pow2(int i)
+{
+  return i && !(i & (i - 1));
+}
+
+int vchiu_queue_init(VCHIU_QUEUE_T *queue, int size)
+{
+   vcos_assert(is_pow2(size));
+
+   queue->size = size;
+   queue->read = 0;
+   queue->write = 0;
+
+   vcos_event_create(&queue->pop, "vchiu");
+   vcos_event_create(&queue->push, "vchiu");
+
+   queue->storage = vcos_malloc(size * sizeof(VCHIQ_HEADER_T *), VCOS_FUNCTION);
+   if (queue->storage == NULL)
+   {
+      vchiu_queue_delete(queue);
+      return 0;
+   }
+   return 1;
+}
+
+void vchiu_queue_delete(VCHIU_QUEUE_T *queue)
+{
+   vcos_event_delete(&queue->pop);
+   vcos_event_delete(&queue->push);
+   if (queue->storage != NULL)
+      vcos_free(queue->storage);
+}
+
+int vchiu_queue_is_empty(VCHIU_QUEUE_T *queue)
+{
+   return queue->read == queue->write;
+}
+
+int vchiu_queue_is_full(VCHIU_QUEUE_T *queue)
+{
+   return queue->write == queue->read + queue->size;
+}
+
+void vchiu_queue_push(VCHIU_QUEUE_T *queue, VCHIQ_HEADER_T *header)
+{
+   while (queue->write == queue->read + queue->size)
+      vcos_event_wait(&queue->pop);
+
+   queue->storage[queue->write & (queue->size - 1)] = header;
+
+   queue->write++;
+
+   vcos_event_signal(&queue->push);
+}
+
+VCHIQ_HEADER_T *vchiu_queue_peek(VCHIU_QUEUE_T *queue)
+{
+   while (queue->write == queue->read)
+      vcos_event_wait(&queue->push);
+
+   return queue->storage[queue->read & (queue->size - 1)];
+}
+
+VCHIQ_HEADER_T *vchiu_queue_pop(VCHIU_QUEUE_T *queue)
+{
+   VCHIQ_HEADER_T *header;
+
+   while (queue->write == queue->read)
+      vcos_event_wait(&queue->push);
+
+   header = queue->storage[queue->read & (queue->size - 1)];
+
+   queue->read++;
+
+   vcos_event_signal(&queue->pop);
+
+   return header;
+}
diff --git a/interface/vchiq_arm/vchiq_util.h b/interface/vchiq_arm/vchiq_util.h
new file mode 100755 (executable)
index 0000000..3628da7
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef VCHIQ_UTIL_H
+#define VCHIQ_UTIL_H
+
+#include "vchiq_if.h"
+#include "interface/vcos/vcos.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+   int size;
+   int read;
+   int write;
+
+   VCOS_EVENT_T pop;
+   VCOS_EVENT_T push;
+
+   VCHIQ_HEADER_T **storage;
+} VCHIU_QUEUE_T;
+
+extern int  vchiu_queue_init(VCHIU_QUEUE_T *queue, int size);
+extern void vchiu_queue_delete(VCHIU_QUEUE_T *queue);
+
+extern int vchiu_queue_is_empty(VCHIU_QUEUE_T *queue);
+extern int vchiu_queue_is_full(VCHIU_QUEUE_T *queue);
+
+extern void vchiu_queue_push(VCHIU_QUEUE_T *queue, VCHIQ_HEADER_T *header);
+
+extern VCHIQ_HEADER_T *vchiu_queue_peek(VCHIU_QUEUE_T *queue);
+extern VCHIQ_HEADER_T *vchiu_queue_pop(VCHIU_QUEUE_T *queue);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/interface/vcos/CMakeLists.txt b/interface/vcos/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..23a8d72
--- /dev/null
@@ -0,0 +1,68 @@
+cmake_minimum_required (VERSION 2.8)
+
+get_filename_component (VIDEOCORE_ROOT "../.." ABSOLUTE)
+include (${VIDEOCORE_ROOT}/makefiles/cmake/global_settings.cmake)
+
+set (HEADERS
+   vcos_assert.h
+   vcos_atomic_flags.h
+   vcos_blockpool.h
+   vcos_cmd.h
+   vcos_dlfcn.h
+   vcos_event_flags.h
+   vcos_event.h
+   vcos.h
+   vcos_init.h
+   vcos_inttypes.h
+   vcos_isr.h
+   vcos_legacy_isr.h
+   vcos_logging.h
+   vcos_logging_control.h
+   vcos_lowlevel_thread.h
+   vcos_mem.h
+   vcos_mempool.h
+   vcos_msgqueue.h
+   vcos_mutex.h
+   vcos_named_semaphore.h
+   vcos_once.h
+   vcos_queue.h
+   vcos_quickslow_mutex.h
+   vcos_reentrant_mutex.h
+   vcos_semaphore.h
+   vcos_stdint.h
+   vcos_string.h
+   vcos_thread_attr.h
+   vcos_thread.h
+   vcos_timer.h
+   vcos_tls.h
+   vcos_types.h
+)
+
+foreach (header ${HEADERS})
+   configure_file ("${header}" "${VCOS_HEADERS_BUILD_DIR}/${header}" COPYONLY)
+endforeach ()
+
+if (CMAKE_COMPILER_IS_GNUCC)
+   add_definitions (-ggdb -Werror -Wall)
+endif ()
+
+if (CMAKE_COMPILER_2005)
+   add_definitions (/WX /W4 /wd4127 /D_CRT_SECURE_NO_DEPRECATE)
+endif ()
+
+include_directories (${VIDEOCORE_ROOT} ${VCOS_HEADERS_BUILD_DIR})
+
+add_subdirectory (${RTOS})
+
+set(VCOS_EXCLUDE_TESTS TRUE)
+if (NOT DEFINED VCOS_EXCLUDE_TESTS)
+add_testapp_subdirectory (test)
+endif (NOT DEFINED VCOS_EXCLUDE_TESTS)
+
+if (WIN32)
+   build_command (RELEASE_BUILD_CMD CONFIGURATION Release)
+   build_command (DEBUG_BUILD_CMD CONFIGURATION Debug)
+   configure_file (build_all.bat.in build_all.bat @ONLY)
+endif ()
+
+#install (FILES ${HEADERS} DESTINATION include/interface/vcos)
diff --git a/interface/vcos/generic/CMakeLists.txt b/interface/vcos/generic/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..c09f376
--- /dev/null
@@ -0,0 +1,21 @@
+
+set (HEADERS
+   vcos_common.h
+   vcos_generic_blockpool.h
+   vcos_generic_event_flags.h
+   vcos_generic_named_sem.h
+   vcos_generic_quickslow_mutex.h
+   vcos_generic_reentrant_mtx.h
+   vcos_generic_tls.h
+   vcos_joinable_thread_from_plain.h
+   vcos_latch_from_sem.h
+   vcos_mem_from_malloc.h
+   vcos_mutexes_are_reentrant.h
+   vcos_thread_reaper.h
+)
+
+foreach (header ${HEADERS})
+   configure_file ("${header}" "${VCOS_HEADERS_BUILD_DIR}/generic/${header}" COPYONLY)
+endforeach ()
+
+install (FILES ${HEADERS} DESTINATION include/interface/vcos/generic)
diff --git a/interface/vcos/generic/vcos_abort.c b/interface/vcos/generic/vcos_abort.c
new file mode 100755 (executable)
index 0000000..7da16ac
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/vcos/vcos.h"
+#ifdef __VIDEOCORE__
+#include "host_support/include/vc_debug_sym.h"
+#include "vcfw/vclib/vclib.h"
+#endif
+#include <stdlib.h>
+
+
+int vcos_verify_bkpts = 0;
+#ifdef __VIDEOCORE__
+VC_DEBUG_VAR(vcos_verify_bkpts);
+#endif
+
+int vcos_verify_bkpts_enabled(void)
+{
+   return vcos_verify_bkpts;
+}
+
+int vcos_verify_bkpts_enable(int enable)
+{
+   int old = vcos_verify_bkpts;
+   vcos_verify_bkpts = enable;
+   return old;
+}
+
+/**
+  * Call the fatal error handler.
+  */
+void vcos_abort(void)
+{
+   VCOS_ALERT("vcos_abort: Halting");
+
+#ifdef __VIDEOCORE__
+   _bkpt();
+#endif
+
+#if defined(VCOS_HAVE_BACKTRACE) && !defined(NDEBUG)
+   vcos_backtrace_self();
+#endif
+
+#ifdef __VIDEOCORE__
+   /* Flush the cache to help with postmortem RAM-dump debugging */
+   vclib_cache_flush();
+#endif
+
+#ifdef PLATFORM_RASPBERRYPI
+   extern void pattern(int);
+   while(1)
+      pattern(8);
+#endif
+
+   /* Insert chosen fatal error handler here */
+#if defined __VIDEOCORE__ && !defined(NDEBUG)
+   while(1); /* allow us to attach a debugger after the fact and see where we came from. */
+#else
+   abort(); /* on vc this ends up in _exit_halt which doesn't give us any stack backtrace */
+#endif
+}
diff --git a/interface/vcos/generic/vcos_cmd.c b/interface/vcos/generic/vcos_cmd.c
new file mode 100755 (executable)
index 0000000..3dfbdb3
--- /dev/null
@@ -0,0 +1,722 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/***************************************************************************** 
+* 
+*    This file provides a generic command line interface which allows
+*    vcos internals to be manipulated and/or displayed.
+*  
+*****************************************************************************/
+
+/* ---- Include Files ---------------------------------------------------- */
+
+#include "interface/vcos/vcos.h"
+
+#ifdef HAVE_VCOS_VERSION
+#include "interface/vcos/vcos_build_info.h"
+#endif
+
+#ifdef _VIDEOCORE
+#include "vcfw/logging/logging.h"
+#endif
+
+/* ---- Public Variables ------------------------------------------------- */
+
+/* ---- Private Constants and Types -------------------------------------- */
+
+#define  VCOS_LOG_CATEGORY (&vcos_cmd_log_category)
+VCOS_LOG_CAT_T vcos_cmd_log_category;
+
+/* ---- Private Variables ------------------------------------------------ */
+
+static struct VCOS_CMD_GLOBALS_T
+{
+    VCOS_MUTEX_T    lock;
+    VCOS_ONCE_T     initialized;
+
+    unsigned        num_cmd_entries;
+    unsigned        num_cmd_alloc;
+    VCOS_CMD_T     *cmd_entry;
+
+    VCOS_LOG_CAT_T *log_category;
+} cmd_globals;
+
+#ifdef HAVE_VCOS_VERSION
+/* Keep the static strings in the image from being dropped by
+ * the linker.
+ */
+extern const char *vcos_get_build_strings(unsigned id);
+const char *(*vcos_keep_static_strings)(unsigned);
+#endif
+
+/* ---- Private Function Prototypes -------------------------------------- */
+
+static VCOS_STATUS_T help_cmd( VCOS_CMD_PARAM_T *param );
+
+/* ---- Functions  ------------------------------------------------------- */
+
+/***************************************************************************** 
+*
+*   Walks through the commands looking for a particular command
+*
+*****************************************************************************/
+
+static VCOS_CMD_T *find_cmd( VCOS_CMD_T *cmd_entry, const char *name )
+{
+    VCOS_CMD_T   *scan_entry = cmd_entry;
+
+    while ( scan_entry->name != NULL )
+    {
+        if ( vcos_strcmp( scan_entry->name, name ) == 0 )
+        {
+            return scan_entry;
+        }
+        scan_entry++;
+    }
+
+    return NULL;
+}
+
+/***************************************************************************** 
+*
+*   Saves away 
+*   each line individually.
+*
+*****************************************************************************/
+
+void vcos_cmd_always_log_output( VCOS_LOG_CAT_T *log_category )
+{
+    cmd_globals.log_category = log_category;
+}
+
+/***************************************************************************** 
+*
+*   Walks through a buffer containing newline separated lines, and logs
+*   each line individually.
+*
+*****************************************************************************/
+
+static void cmd_log_results( VCOS_CMD_PARAM_T *param )
+{
+    char    *start;
+    char    *end;
+
+    start = end = param->result_buf;
+
+    while ( *start != '\0' )
+    {
+        while (( *end != '\0' ) && ( *end != '\n' ))
+            end++;
+
+        if ( *end == '\n' )
+        {
+            *end++ = '\0';
+        }
+
+        if ( cmd_globals.log_category != NULL )
+        {
+            if ( vcos_is_log_enabled( cmd_globals.log_category, VCOS_LOG_INFO ))
+            {
+                vcos_log_impl( cmd_globals.log_category, VCOS_LOG_INFO, "%s", start );
+            }
+        }
+        else
+        {
+            vcos_log_info( "%s", start );
+        }
+
+        start = end;
+    }
+
+    /* Since we logged the buffer, reset the pointer back to the beginning. */
+
+    param->result_ptr = param->result_buf;
+    param->result_buf[0] = '\0';
+}
+
+/***************************************************************************** 
+*
+*   Since we may have limited output space, we create a generic routine
+*   which tries to use the result space, but will switch over to using
+*   logging if the output is too large.
+*
+*****************************************************************************/
+
+void vcos_cmd_vprintf( VCOS_CMD_PARAM_T *param, const char *fmt, va_list args )
+{
+    int     bytes_written;
+    int     bytes_remaining;
+
+    bytes_remaining = (int)(param->result_size - ( param->result_ptr - param->result_buf ));
+
+    bytes_written = vcos_vsnprintf( param->result_ptr, bytes_remaining, fmt, args );
+
+    if ( cmd_globals.log_category != NULL )
+    {
+        /* We're going to log each line as we encounter it. If the buffer
+         * doesn't end in a newline, then we'll wait for one first.
+         */
+
+        if ( (( bytes_written + 1 ) >= bytes_remaining ) 
+        ||   ( param->result_ptr[ bytes_written - 1 ] == '\n' ))
+        {
+            cmd_log_results( param );
+        }
+        else
+        {
+            param->result_ptr += bytes_written;
+        }
+    }
+    else
+    {
+        if (( bytes_written + 1 ) >= bytes_remaining )
+        {
+            /* Output doesn't fit - switch over to logging */
+
+            param->use_log = 1;
+
+            *param->result_ptr = '\0';  /* Zap the partial line that didn't fit above. */
+
+            cmd_log_results( param );   /* resets result_ptr */
+
+            bytes_written = vcos_vsnprintf( param->result_ptr, bytes_remaining, fmt, args );
+        }
+        param->result_ptr += bytes_written;
+    }
+}
+
+/***************************************************************************** 
+*
+*   Prints the output.
+*
+*****************************************************************************/
+
+void vcos_cmd_printf( VCOS_CMD_PARAM_T *param, const char *fmt, ... )
+{
+    va_list args;
+
+    va_start( args, fmt );
+    vcos_cmd_vprintf( param, fmt, args );
+    va_end( args );
+}
+
+/***************************************************************************** 
+*
+*   Prints the arguments which were on the command line prior to ours.
+*
+*****************************************************************************/
+
+static void print_argument_prefix( VCOS_CMD_PARAM_T *param )
+{
+    int arg_idx;
+
+    for ( arg_idx = 0; &param->argv_orig[arg_idx] != param->argv; arg_idx++ )
+    {
+        vcos_cmd_printf( param, "%s ", param->argv_orig[arg_idx] );
+    }
+}
+
+/***************************************************************************** 
+*
+*   Prints an error message, prefixed by the command chain required to get
+*   to where we're at.
+*
+*****************************************************************************/
+
+void vcos_cmd_error( VCOS_CMD_PARAM_T *param, const char *fmt, ... )
+{
+    va_list args;
+
+    print_argument_prefix( param );
+
+    va_start( args, fmt );
+    vcos_cmd_vprintf( param, fmt, args );
+    va_end( args );
+    vcos_cmd_printf( param, "\n" );
+}
+
+/****************************************************************************
+*
+*  usage - prints command usage for an array of commands.
+*
+***************************************************************************/
+
+static void usage( VCOS_CMD_PARAM_T *param, VCOS_CMD_T *cmd_entry )
+{
+    int         cmd_idx;
+    int         nameWidth = 0;
+    int         argsWidth = 0;
+    VCOS_CMD_T *scan_entry;
+
+    vcos_cmd_printf( param, "Usage: " );
+    print_argument_prefix( param );
+    vcos_cmd_printf( param, "command [args ...]\n" );
+    vcos_cmd_printf( param, "\n" );
+    vcos_cmd_printf( param, "Where command is one of the following:\n" );
+
+    for ( cmd_idx = 0; cmd_entry[cmd_idx].name != NULL; cmd_idx++ )
+    {
+        int aw;
+        int nw;
+
+        scan_entry = &cmd_entry[cmd_idx];
+
+        nw = vcos_strlen( scan_entry->name );
+        aw = vcos_strlen( scan_entry->args );
+
+        if ( nw > nameWidth )
+        {
+            nameWidth = nw;
+        }
+        if ( aw > argsWidth )
+        {
+            argsWidth = aw;
+        }
+    }
+
+    for ( cmd_idx = 0; cmd_entry[cmd_idx].name != NULL; cmd_idx++ )
+    {
+        scan_entry = &cmd_entry[cmd_idx];
+
+        vcos_cmd_printf( param, "  %-*s %-*s - %s\n", 
+                    nameWidth, scan_entry->name,
+                    argsWidth, scan_entry->args,
+                    scan_entry->descr );
+    }
+}
+
+/****************************************************************************
+*
+*  Prints the usage for the current command.
+*
+***************************************************************************/
+
+void vcos_cmd_usage( VCOS_CMD_PARAM_T *param )
+{
+    VCOS_CMD_T *cmd_entry;
+
+    cmd_entry = param->cmd_entry;
+
+    if ( cmd_entry->sub_cmd_entry != NULL )
+    {
+        /* This command is command with sub-commands */
+
+        usage( param, param->cmd_entry->sub_cmd_entry );
+    }
+    else
+    {
+        vcos_cmd_printf( param, "Usage: " );
+        print_argument_prefix( param );
+        vcos_cmd_printf( param, "%s %s - %s\n",
+                         param->argv[0],
+                         param->cmd_entry->args,
+                         param->cmd_entry->descr );
+    }
+}
+
+/***************************************************************************** 
+*
+*   Command to print out the help
+* 
+*   This help command is only called from the main menu.
+* 
+*****************************************************************************/
+
+static VCOS_STATUS_T help_cmd( VCOS_CMD_PARAM_T *param )
+{
+    VCOS_CMD_T  *found_entry;
+
+#if 0
+    {
+        int arg_idx;
+
+        vcos_log_trace( "%s: argc = %d", __func__, param->argc );
+        for ( arg_idx = 0; arg_idx < param->argc; arg_idx++ )
+        {
+            vcos_log_trace( "%s:  argv[%d] = '%s'", __func__, arg_idx, param->argv[arg_idx] );
+        }
+    }
+#endif
+
+    /* If there is an argument after the word help, then we want to print
+     * help for that command.
+     */
+
+    if ( param->argc == 1 )
+    {
+        if ( param->cmd_parent_entry == cmd_globals.cmd_entry )
+        {
+            /* Bare help - print the command usage for the root */
+
+            usage( param, cmd_globals.cmd_entry );
+            return VCOS_SUCCESS;
+        }
+
+        /* For all other cases help requires an argument */
+            
+        vcos_cmd_error( param, "%s requires an argument", param->argv[0] );
+        return VCOS_EINVAL;
+    }
+
+    /* We were given an argument. */
+
+    if (( found_entry = find_cmd( param->cmd_parent_entry, param->argv[1] )) != NULL )
+    {
+        /* Make it look like the command that was specified is the one that's
+         * currently running
+         */
+
+        param->cmd_entry = found_entry;
+        param->argv[0] = param->argv[1];
+        param->argv++;
+        param->argc--;
+
+        vcos_cmd_usage( param );
+        return VCOS_SUCCESS;
+    }
+
+    vcos_cmd_error( param, "- unrecognized command: '%s'", param->argv[1] );
+    return VCOS_ENOENT;
+}
+
+/***************************************************************************** 
+*
+*   Command to print out the version/build information.
+*
+*****************************************************************************/
+
+#ifdef HAVE_VCOS_VERSION
+
+static VCOS_STATUS_T version_cmd( VCOS_CMD_PARAM_T *param )
+{
+    static const char* copyright = "Copyright (c) 2011 Broadcom";
+
+    vcos_cmd_printf( param, "%s %s\n%s\nversion %s\nhost %s",
+                     vcos_get_build_date(),
+                     vcos_get_build_time(),
+                     copyright,
+                     vcos_get_build_version(),
+                     vcos_get_build_hostname() );
+
+    return VCOS_SUCCESS;
+}
+
+#endif
+
+/*****************************************************************************
+*
+*   Internal commands
+*
+*****************************************************************************/
+
+static VCOS_CMD_T cmd_help    = { "help",    "[command]", help_cmd,    NULL, "Prints command help information" };
+
+#ifdef HAVE_VCOS_VERSION
+static VCOS_CMD_T cmd_version = { "version", "",          version_cmd, NULL, "Prints build/version information" };
+#endif
+
+/***************************************************************************** 
+*
+*   Walks the command table and executes the commands
+*
+*****************************************************************************/
+
+static VCOS_STATUS_T execute_cmd( VCOS_CMD_PARAM_T *param, VCOS_CMD_T *cmd_entry )
+{
+    const char     *cmdStr;
+    VCOS_CMD_T     *found_entry;
+
+#if 0
+    {
+        int arg_idx;
+
+        vcos_cmd_printf( param, "%s: argc = %d", __func__, param->argc );
+        for ( arg_idx = 0; arg_idx < param->argc; arg_idx++ )
+        {
+            vcos_cmd_printf( param, " argv[%d] = '%s'", arg_idx, param->argv[arg_idx] );
+        }
+        vcos_cmd_printf( param, "\n" );
+    }
+#endif
+
+    if ( param->argc <= 1 )
+    {
+        /* No command specified */
+
+        vcos_cmd_error( param, "%s - no command specified", param->argv[0] );
+        return VCOS_EINVAL;
+    }
+
+    /* argv[0] is the command/program that caused us to get invoked, so we strip
+     * it off.
+     */
+
+    param->argc--;
+    param->argv++;
+    param->cmd_parent_entry = cmd_entry;
+
+    /* Not the help command, scan for the command and execute it. */
+
+    cmdStr = param->argv[0];
+
+    if (( found_entry = find_cmd( cmd_entry, cmdStr )) != NULL )
+    {
+        if ( found_entry->sub_cmd_entry != NULL )
+        {
+            return execute_cmd( param, found_entry->sub_cmd_entry );
+        }
+
+        param->cmd_entry = found_entry;
+        return found_entry->cmd_fn( param );
+    }
+
+    /* Unrecognized command - check to see if it was the help command */
+
+    if ( vcos_strcmp( cmdStr, cmd_help.name ) == 0 )
+    {
+        return help_cmd( param );
+    }
+
+    vcos_cmd_error( param, "- unrecognized command: '%s'", cmdStr );
+    return VCOS_ENOENT;
+}
+
+/***************************************************************************** 
+*
+*   Initializes the command line parser.
+*
+*****************************************************************************/
+
+static void vcos_cmd_init( void )
+{
+    vcos_mutex_create( &cmd_globals.lock, "vcos_cmd" );
+
+    cmd_globals.num_cmd_entries = 0;
+    cmd_globals.num_cmd_alloc = 0;
+    cmd_globals.cmd_entry = NULL;
+
+#ifdef HAVE_VCOS_VERSION
+   vcos_keep_static_strings = vcos_get_build_strings;
+#endif
+}
+
+/***************************************************************************** 
+*
+*   Shuts down the command line parser.
+*
+*****************************************************************************/
+
+void vcos_cmd_shutdown( void )
+{
+    vcos_mutex_delete( &cmd_globals.lock );
+
+    vcos_free( cmd_globals.cmd_entry );
+    cmd_globals.cmd_entry = NULL;
+}
+
+/*****************************************************************************
+*
+*   Command line processor.
+*
+*****************************************************************************/
+
+VCOS_STATUS_T vcos_cmd_execute( int argc, char **argv, size_t result_size, char *result_buf )
+{
+    VCOS_STATUS_T       rc = VCOS_EINVAL;
+    VCOS_CMD_PARAM_T    param;
+
+    vcos_once( &cmd_globals.initialized, vcos_cmd_init );
+
+    param.argc = argc;
+    param.argv = param.argv_orig = argv;
+
+    param.use_log = 0;
+    param.result_size = result_size;
+    param.result_ptr = result_buf;
+    param.result_buf = result_buf;
+
+       result_buf[0] = '\0';
+
+    vcos_mutex_lock( &cmd_globals.lock );
+
+    rc = execute_cmd( &param, cmd_globals.cmd_entry );
+
+    if ( param.use_log )
+    {
+        cmd_log_results( &param );
+        vcos_snprintf( result_buf, result_size, "results logged" );
+    }
+    else
+    if ( cmd_globals.log_category != NULL )
+    {
+        if ( result_buf[0] != '\0' )
+        {
+            /* There is a partial line still buffered. */
+
+            vcos_cmd_printf( &param, "\n" );
+        }
+    }
+
+    vcos_mutex_unlock( &cmd_globals.lock );
+
+    return rc;
+}
+
+/***************************************************************************** 
+*
+*   Registers a command entry with the command line processor
+*
+*****************************************************************************/
+
+VCOS_STATUS_T vcos_cmd_register( VCOS_CMD_T *cmd_entry )
+{
+    VCOS_STATUS_T   rc;
+    VCOS_UNSIGNED   new_num_cmd_alloc;
+    VCOS_CMD_T     *new_cmd_entry;
+    VCOS_CMD_T     *old_cmd_entry;
+    VCOS_CMD_T     *scan_entry;
+
+    vcos_once( &cmd_globals.initialized, vcos_cmd_init );
+
+    vcos_assert( cmd_entry != NULL );
+    vcos_assert( cmd_entry->name != NULL );
+
+    vcos_log_trace( "%s: cmd '%s'", __FUNCTION__, cmd_entry->name );
+
+    vcos_assert( cmd_entry->args != NULL );
+    vcos_assert(( cmd_entry->cmd_fn != NULL ) || ( cmd_entry->sub_cmd_entry != NULL ));
+    vcos_assert( cmd_entry->descr != NULL );
+
+    /* We expect vcos_cmd_init to be called before vcos_logging_init, so we
+     * need to defer registering our logging category until someplace
+     * like right here.
+     */
+
+    if ( vcos_cmd_log_category.name == NULL )
+    {
+        /*
+         * If you're using the command interface, you pretty much always want
+         * log messages from this file to show up. So we change the default
+         * from ERROR to be the more reasonable INFO level.
+         */
+
+        vcos_log_set_level(&vcos_cmd_log_category, VCOS_LOG_INFO);
+        vcos_log_register("vcos_cmd", &vcos_cmd_log_category);
+
+        /* We register a help command so that it shows up in the usage. */
+
+        vcos_cmd_register( &cmd_help );
+#ifdef HAVE_VCOS_VERSION
+        vcos_cmd_register( &cmd_version );
+#endif
+    }
+
+    vcos_mutex_lock( &cmd_globals.lock );
+
+    if ( cmd_globals.num_cmd_entries >= cmd_globals.num_cmd_alloc )
+    {
+        if ( cmd_globals.num_cmd_alloc == 0 )
+        {
+            /* We haven't allocated a table yet */
+        }
+
+        /* The number 8 is rather arbitrary. */
+
+        new_num_cmd_alloc = cmd_globals.num_cmd_alloc + 8;
+
+        /* The + 1 is to ensure that we always have a NULL entry at the end. */
+
+        new_cmd_entry = (VCOS_CMD_T *)vcos_calloc( new_num_cmd_alloc + 1, sizeof( *cmd_entry ), "vcos_cmd_entries" );
+        if ( new_cmd_entry == NULL )
+        {
+            rc = VCOS_ENOMEM;
+            goto out;
+        }
+        memcpy( new_cmd_entry, cmd_globals.cmd_entry, cmd_globals.num_cmd_entries * sizeof( *cmd_entry ));
+        cmd_globals.num_cmd_alloc = new_num_cmd_alloc;
+        old_cmd_entry = cmd_globals.cmd_entry;
+        cmd_globals.cmd_entry = new_cmd_entry;
+        vcos_free( old_cmd_entry );
+    }
+
+    if ( cmd_globals.num_cmd_entries == 0 )
+    {
+        /* This is the first command being registered */
+
+        cmd_globals.cmd_entry[0] = *cmd_entry;
+    }
+    else
+    {
+        /* Keep the list in alphabetical order. We start at the end and work backwards
+         * shuffling entries up one until we find an insertion point.
+         */
+
+        for ( scan_entry = &cmd_globals.cmd_entry[cmd_globals.num_cmd_entries - 1];
+              scan_entry >= cmd_globals.cmd_entry; scan_entry-- )
+        {
+            if ( vcos_strcmp( cmd_entry->name, scan_entry->name ) > 0 )
+            {
+                /* We found an insertion point. */
+
+                break;
+            }
+
+            scan_entry[1] = scan_entry[0];
+        }
+        scan_entry[1] = *cmd_entry;
+    }
+    cmd_globals.num_cmd_entries++;
+
+    rc = VCOS_SUCCESS;
+
+out:
+
+    vcos_mutex_unlock( &cmd_globals.lock );
+    return rc;
+}
+
+/***************************************************************************** 
+*
+*   Registers multiple commands.
+*
+*****************************************************************************/
+
+VCOS_STATUS_T vcos_cmd_register_multiple( VCOS_CMD_T *cmd_entry )
+{
+    VCOS_STATUS_T   status;
+
+    while ( cmd_entry->name != NULL )
+    {
+        if (( status = vcos_cmd_register( cmd_entry )) != VCOS_SUCCESS )
+        {
+            return status;
+        }
+        cmd_entry++;
+    }
+    return VCOS_SUCCESS;
+}
+
diff --git a/interface/vcos/generic/vcos_common.h b/interface/vcos/generic/vcos_common.h
new file mode 100755 (executable)
index 0000000..93949e0
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - common postamble code
+=============================================================================*/
+
+/** \file
+  *
+  * Postamble code included by the platform-specific header files
+  */
+
+#define VCOS_THREAD_PRI_DEFAULT VCOS_THREAD_PRI_NORMAL
+
+#if !defined(VCOS_THREAD_PRI_INCREASE)
+#error Which way to thread priorities go?
+#endif
+
+#if VCOS_THREAD_PRI_INCREASE < 0
+/* smaller numbers are higher priority */
+#define VCOS_THREAD_PRI_LESS(x) ((x)<VCOS_THREAD_PRI_MAX?(x)+1:VCOS_THREAD_PRI_MAX)
+#define VCOS_THREAD_PRI_MORE(x) ((x)>VCOS_THREAD_PRI_MIN?(x)-1:VCOS_THREAD_PRI_MIN)
+#else
+/* bigger numbers are lower priority */
+#define VCOS_THREAD_PRI_MORE(x) ((x)<VCOS_THREAD_PRI_MAX?(x)+1:VCOS_THREAD_PRI_MAX)
+#define VCOS_THREAD_PRI_LESS(x) ((x)>VCOS_THREAD_PRI_MIN?(x)-1:VCOS_THREAD_PRI_MIN)
+#endif
+
+/* Convenience for Brits: */
+#define VCOS_APPLICATION_INITIALISE VCOS_APPLICATION_INITIALIZE
+
+/*
+ * Check for constant definitions
+ */
+#ifndef VCOS_TICKS_PER_SECOND
+#error VCOS_TICKS_PER_SECOND not defined
+#endif
+
+#if !defined(VCOS_THREAD_PRI_MIN) || !defined(VCOS_THREAD_PRI_MAX)
+#error Priority range not defined
+#endif
+
+#if !defined(VCOS_THREAD_PRI_HIGHEST) || !defined(VCOS_THREAD_PRI_LOWEST) || !defined(VCOS_THREAD_PRI_NORMAL)
+#error Priority ordering not defined
+#endif
+
+#if !defined(VCOS_CAN_SET_STACK_ADDR)
+#error Can stack addresses be set on this platform? Please set this macro to either 0 or 1.
+#endif
+
+#if (_VCOS_AFFINITY_CPU0|_VCOS_AFFINITY_CPU1) & (~_VCOS_AFFINITY_MASK) 
+#error _VCOS_AFFINITY_CPUxxx values are not consistent with _VCOS_AFFINITY_MASK
+#endif
+
+/** Append to the end of a singly-linked queue, O(1). Works with
+  * any structure where list has members 'head' and 'tail' and
+  * item has a 'next' pointer.
+  */
+#define VCOS_QUEUE_APPEND_TAIL(list, item) {\
+   (item)->next = NULL;\
+   if (!(list)->head) {\
+      (list)->head = (list)->tail = (item); \
+   } else {\
+      (list)->tail->next = (item); \
+      (list)->tail = (item); \
+   } \
+}
+
+#ifndef VCOS_HAVE_TIMER
+VCOSPRE_ void VCOSPOST_ vcos_timer_init(void);
+#endif
+
diff --git a/interface/vcos/generic/vcos_deprecated.h b/interface/vcos/generic/vcos_deprecated.h
new file mode 100755 (executable)
index 0000000..0efa5c4
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+The symbol vcos_deprecated_code may be defined at most once, by the inclusion of "vcos_deprecated.h" in vcos_init.c.
+Any other inclusions of this header will cause the linker to warn about multiple definitions of vcos_deprecated_code, for example:
+   [ldvc] (Warning) "vcos_deprecated_code" is multiply defined in libs/vcos_threadx/vcos_init.c.o and libs/xxxxx/xxxxx.c.o
+If you see a build message like this then the configuration you are building is using deprecated code.
+Contact the person named in the accompanying comment for advice - do not remove the inclusion.
+*/
+
+int vcos_deprecated_code;
diff --git a/interface/vcos/generic/vcos_generic_blockpool.c b/interface/vcos/generic/vcos_generic_blockpool.c
new file mode 100755 (executable)
index 0000000..5b228a8
--- /dev/null
@@ -0,0 +1,568 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define VCOS_LOG_CATEGORY (&vcos_blockpool_log)
+
+#include <stddef.h>
+#include <string.h>
+#include "interface/vcos/vcos.h"
+#include "interface/vcos/generic/vcos_generic_blockpool.h"
+
+#define VCOS_BLOCKPOOL_FOURCC(a,b,c,d) ((a) | (b << 8) | (c << 16) | (d << 24))
+#define VCOS_BLOCKPOOL_MAGIC           VCOS_BLOCKPOOL_FOURCC('v', 'b', 'p', 'l')
+#define VCOS_BLOCKPOOL_SUBPOOL_MAGIC   VCOS_BLOCKPOOL_FOURCC('v', 's', 'p', 'l')
+
+#define VCOS_BLOCKPOOL_SUBPOOL_FLAG_NONE        (0)
+#define VCOS_BLOCKPOOL_SUBPOOL_FLAG_OWNS_MEM    (1 << 0)
+#define VCOS_BLOCKPOOL_SUBPOOL_FLAG_EXTENSION   (1 << 1)
+
+/* Uncomment to enable really verbose debug messages */
+/* #define VCOS_BLOCKPOOL_DEBUGGING */
+/* Whether to overwrite freed blocks with 0xBD */
+#ifdef VCOS_BLOCKPOOL_DEBUGGING
+#define VCOS_BLOCKPOOL_OVERWRITE_ON_FREE        1
+#define VCOS_BLOCKPOOL_DEBUG_MEMSET_MAX_SIZE    (UINT32_MAX)
+#else
+#define VCOS_BLOCKPOOL_OVERWRITE_ON_FREE        0
+#define VCOS_BLOCKPOOL_DEBUG_MEMSET_MAX_SIZE    (2 * 1024 * 1024)
+#endif
+
+#ifdef VCOS_BLOCKPOOL_DEBUGGING
+#define VCOS_BLOCKPOOL_ASSERT vcos_demand
+#define VCOS_BLOCKPOOL_TRACE_LEVEL VCOS_LOG_TRACE
+#define VCOS_BLOCKPOOL_DEBUG_LOG(s, ...) vcos_log_trace("%s: " s, VCOS_FUNCTION, __VA_ARGS__)
+#undef  VCOS_BLOCKPOOL_OVERWRITE_ON_FREE
+#define VCOS_BLOCKPOOL_OVERWRITE_ON_FREE 1
+#else
+#define VCOS_BLOCKPOOL_ASSERT vcos_demand
+#define VCOS_BLOCKPOOL_TRACE_LEVEL VCOS_LOG_ERROR
+#define VCOS_BLOCKPOOL_DEBUG_LOG(s, ...)
+#endif
+
+#define ASSERT_POOL(p) \
+   VCOS_BLOCKPOOL_ASSERT((p) && (p)->magic == VCOS_BLOCKPOOL_MAGIC);
+
+#define ASSERT_SUBPOOL(p) \
+   VCOS_BLOCKPOOL_ASSERT((p) && (p)->magic == VCOS_BLOCKPOOL_SUBPOOL_MAGIC && \
+         p->start >= p->mem);
+
+#if defined(VCOS_LOGGING_ENABLED)
+static VCOS_LOG_CAT_T vcos_blockpool_log =
+VCOS_LOG_INIT("vcos_blockpool", VCOS_BLOCKPOOL_TRACE_LEVEL);
+#endif
+
+static void vcos_generic_blockpool_subpool_init(
+      VCOS_BLOCKPOOL_T *pool, VCOS_BLOCKPOOL_SUBPOOL_T *subpool,
+      void *mem, size_t pool_size, VCOS_UNSIGNED num_blocks, int align,
+      uint32_t flags)
+{
+   VCOS_BLOCKPOOL_HEADER_T *block;
+   VCOS_BLOCKPOOL_HEADER_T *end;
+
+   vcos_unused(flags);
+
+   vcos_log_trace(
+         "%s: pool %p subpool %p mem %p pool_size %d " \
+         "num_blocks %d align %d flags %x",
+         VCOS_FUNCTION,
+         pool, subpool, mem, (uint32_t) pool_size,
+         num_blocks, align, flags);
+
+   subpool->magic = VCOS_BLOCKPOOL_SUBPOOL_MAGIC;
+   subpool->mem = mem;
+
+   /* The block data pointers must be aligned according to align and the
+    * block header pre-preceeds the first block data.
+    * For large alignments there may be wasted space between subpool->mem
+    * and the first block header.
+    */
+   subpool->start = (char *) subpool->mem + sizeof(VCOS_BLOCKPOOL_HEADER_T);
+   subpool->start = (void*)
+      VCOS_BLOCKPOOL_ROUND_UP((unsigned long) subpool->start, align);
+   subpool->start = (char *) subpool->start - sizeof(VCOS_BLOCKPOOL_HEADER_T);
+
+   vcos_assert(subpool->start >= subpool->mem);
+
+   vcos_log_trace("%s: mem %p subpool->start %p" \
+         " pool->block_size %d pool->block_data_size %d",
+         VCOS_FUNCTION, mem, subpool->start,
+         (int) pool->block_size, (int) pool->block_data_size);
+
+   subpool->num_blocks = num_blocks;
+   subpool->available_blocks = num_blocks;
+   subpool->free_list = NULL;
+   subpool->owner = pool;
+
+   /* Initialise to a predictable bit pattern unless the pool is so big
+    * that the delay would be noticeable. */
+   if (pool_size < VCOS_BLOCKPOOL_DEBUG_MEMSET_MAX_SIZE)
+      memset(subpool->mem, 0xBC, pool_size); /* For debugging */
+
+   block = (VCOS_BLOCKPOOL_HEADER_T*) subpool->start;
+   end = (VCOS_BLOCKPOOL_HEADER_T*)
+      ((char *) subpool->start + (pool->block_size * num_blocks));
+   subpool->end = end;
+
+   /* Initialise the free list for this subpool */
+   while (block < end)
+   {
+      block->owner.next = subpool->free_list;
+      subpool->free_list = block;
+      block = (VCOS_BLOCKPOOL_HEADER_T*)((char*) block + pool->block_size);
+   }
+
+}
+
+VCOS_STATUS_T vcos_generic_blockpool_init(VCOS_BLOCKPOOL_T *pool,
+      VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size,
+      void *start, VCOS_UNSIGNED pool_size, VCOS_UNSIGNED align,
+      VCOS_UNSIGNED flags, const char *name)
+{
+   VCOS_STATUS_T status = VCOS_SUCCESS;
+
+   vcos_unused(name);
+   vcos_unused(flags);
+
+   vcos_log_trace(
+         "%s: pool %p num_blocks %d block_size %d start %p pool_size %d name %p",
+         VCOS_FUNCTION, pool, num_blocks, block_size, start, pool_size, name);
+
+   vcos_demand(pool);
+   vcos_demand(start);
+   vcos_assert((block_size > 0));
+   vcos_assert(num_blocks > 0);
+
+   if (! align)
+      align = VCOS_BLOCKPOOL_ALIGN_DEFAULT;
+
+   if (align & 0x3)
+   {
+      vcos_log_error("%s: invalid alignment %d", VCOS_FUNCTION, align);
+      return VCOS_EINVAL;
+   }
+
+   if (VCOS_BLOCKPOOL_SIZE(num_blocks, block_size, align) > pool_size)
+   {
+      vcos_log_error("%s: Pool is too small" \
+            " num_blocks %d block_size %d align %d"
+            " pool_size %d required size %d", VCOS_FUNCTION,
+            num_blocks, block_size, align,
+            pool_size, (int) VCOS_BLOCKPOOL_SIZE(num_blocks, block_size, align));
+      return VCOS_ENOMEM;
+   }
+
+   status = vcos_mutex_create(&pool->mutex, "vcos blockpool mutex");
+   if (status != VCOS_SUCCESS)
+      return status;
+
+   pool->block_data_size = block_size;
+
+   /* TODO - create flag that if set forces the header to be in its own cache
+    * line */
+   pool->block_size = VCOS_BLOCKPOOL_ROUND_UP(pool->block_data_size +
+         (align >= 4096 ? 32 : 0) +
+         sizeof(VCOS_BLOCKPOOL_HEADER_T), align);
+
+   pool->magic = VCOS_BLOCKPOOL_MAGIC;
+   pool->num_subpools = 1;
+   pool->num_extension_blocks = 0;
+   pool->align = align;
+   memset(pool->subpools, 0, sizeof(pool->subpools));
+
+   vcos_generic_blockpool_subpool_init(pool, &pool->subpools[0], start,
+         pool_size, num_blocks, align, VCOS_BLOCKPOOL_SUBPOOL_FLAG_NONE);
+
+   return status;
+}
+
+VCOS_STATUS_T vcos_generic_blockpool_create_on_heap(VCOS_BLOCKPOOL_T *pool,
+      VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size, VCOS_UNSIGNED align,
+      VCOS_UNSIGNED flags, const char *name)
+{
+   VCOS_STATUS_T status = VCOS_SUCCESS;
+   size_t size = VCOS_BLOCKPOOL_SIZE(num_blocks, block_size, align);
+   void* mem = vcos_malloc(size, name);
+
+   vcos_log_trace("%s: num_blocks %d block_size %d name %s",
+         VCOS_FUNCTION, num_blocks, block_size, name);
+
+   if (! mem)
+      return VCOS_ENOMEM;
+
+   status = vcos_generic_blockpool_init(pool, num_blocks,
+         block_size, mem, size, align, flags, name);
+
+   if (status != VCOS_SUCCESS)
+      goto fail;
+
+   pool->subpools[0].flags |= VCOS_BLOCKPOOL_SUBPOOL_FLAG_OWNS_MEM;
+   return status;
+
+fail:
+   vcos_free(mem);
+   return status;
+}
+
+VCOS_STATUS_T vcos_generic_blockpool_extend(VCOS_BLOCKPOOL_T *pool,
+      VCOS_UNSIGNED num_extensions, VCOS_UNSIGNED num_blocks)
+{
+   VCOS_UNSIGNED i;
+   ASSERT_POOL(pool);
+
+   vcos_log_trace("%s: pool %p num_extensions %d num_blocks %d",
+         VCOS_FUNCTION, pool, num_extensions, num_blocks);
+
+   /* Extend may only be called once */
+   if (pool->num_subpools > 1)
+      return VCOS_EACCESS;
+
+   if (num_extensions < 1 ||
+         num_extensions > VCOS_BLOCKPOOL_MAX_SUBPOOLS - 1)
+      return VCOS_EINVAL;
+
+   if (num_blocks < 1)
+      return VCOS_EINVAL;
+
+   pool->num_subpools += num_extensions;
+   pool->num_extension_blocks = num_blocks;
+
+   /* Mark these subpools as valid but unallocated */
+   for (i = 1; i < pool->num_subpools; ++i)
+   {
+      pool->subpools[i].magic = VCOS_BLOCKPOOL_SUBPOOL_MAGIC;
+      pool->subpools[i].start = NULL;
+      pool->subpools[i].mem = NULL;
+   }
+
+   return VCOS_SUCCESS;
+}
+
+void *vcos_generic_blockpool_alloc(VCOS_BLOCKPOOL_T *pool)
+{
+   VCOS_UNSIGNED i;
+   void* ret = NULL;
+   VCOS_BLOCKPOOL_SUBPOOL_T *subpool = NULL;
+
+   ASSERT_POOL(pool);
+   vcos_mutex_lock(&pool->mutex);
+
+   /* Starting with the main pool try and find a free block */
+   for (i = 0; i < pool->num_subpools; ++i)
+   {
+      if (pool->subpools[i].start && pool->subpools[i].available_blocks > 0)
+      {
+         subpool = &pool->subpools[i];
+         break; /* Found a subpool with free blocks */
+      }
+   }
+
+   if (! subpool)
+   {
+      /* All current subpools are full, try to allocate a new one */
+      for (i = 1; i < pool->num_subpools; ++i)
+      {
+         if (! pool->subpools[i].start)
+         {
+            VCOS_BLOCKPOOL_SUBPOOL_T *s = &pool->subpools[i];
+            size_t size = VCOS_BLOCKPOOL_SIZE(pool->num_extension_blocks,
+                  pool->block_data_size, pool->align);
+            void *mem = vcos_malloc(size, pool->name);
+            if (mem)
+            {
+               vcos_log_trace("%s: Allocated subpool %d", VCOS_FUNCTION, i);
+               vcos_generic_blockpool_subpool_init(pool, s, mem, size,
+                     pool->num_extension_blocks,
+                     pool->align,
+                     VCOS_BLOCKPOOL_SUBPOOL_FLAG_OWNS_MEM |
+                     VCOS_BLOCKPOOL_SUBPOOL_FLAG_EXTENSION);
+               subpool = s;
+               break; /* Created a subpool */
+            }
+            else
+            {
+               vcos_log_warn("%s: Failed to allocate subpool", VCOS_FUNCTION);
+            }
+         }
+      }
+   }
+
+   if (subpool)
+   {
+      /* Remove from free list */
+      VCOS_BLOCKPOOL_HEADER_T* nb = subpool->free_list;
+
+      vcos_assert(subpool->free_list);
+      subpool->free_list = nb->owner.next;
+
+      /* Owner is pool so free can be called without passing pool
+       * as a parameter */
+      nb->owner.subpool = subpool;
+
+      ret = nb + 1; /* Return pointer to block data */
+      --(subpool->available_blocks);
+   }
+   vcos_mutex_unlock(&pool->mutex);
+   VCOS_BLOCKPOOL_DEBUG_LOG("pool %p subpool %p ret %p", pool, subpool, ret);
+
+   if (ret)
+   {
+      vcos_assert(ret > subpool->start);
+      vcos_assert(ret < subpool->end);
+   }
+   return ret;
+}
+
+void *vcos_generic_blockpool_calloc(VCOS_BLOCKPOOL_T *pool)
+{
+   void* ret = vcos_generic_blockpool_alloc(pool);
+   if (ret)
+      memset(ret, 0, pool->block_data_size);
+   return ret;
+}
+
+void vcos_generic_blockpool_free(void *block)
+{
+   VCOS_BLOCKPOOL_DEBUG_LOG("block %p", block);
+   if (block)
+   {
+      VCOS_BLOCKPOOL_HEADER_T* hdr = (VCOS_BLOCKPOOL_HEADER_T*) block - 1;
+      VCOS_BLOCKPOOL_SUBPOOL_T *subpool = hdr->owner.subpool;
+      VCOS_BLOCKPOOL_T *pool = NULL;
+
+      ASSERT_SUBPOOL(subpool);
+      pool = subpool->owner;
+      ASSERT_POOL(pool);
+
+      vcos_mutex_lock(&pool->mutex);
+      vcos_assert((unsigned) subpool->available_blocks < subpool->num_blocks);
+
+      /* Change ownership of block to be the free list */
+      hdr->owner.next = subpool->free_list;
+      subpool->free_list = hdr;
+      ++(subpool->available_blocks);
+
+      if (VCOS_BLOCKPOOL_OVERWRITE_ON_FREE)
+         memset(block, 0xBD, pool->block_data_size); /* For debugging */
+
+      if ( (subpool->flags & VCOS_BLOCKPOOL_SUBPOOL_FLAG_EXTENSION) &&
+            subpool->available_blocks == subpool->num_blocks)
+      {
+         VCOS_BLOCKPOOL_DEBUG_LOG("%s: freeing subpool %p mem %p", VCOS_FUNCTION,
+               subpool, subpool->mem);
+         /* Free the sub-pool if it was dynamically allocated */
+         vcos_free(subpool->mem);
+         subpool->mem = NULL;
+         subpool->start = NULL;
+      }
+      vcos_mutex_unlock(&pool->mutex);
+   }
+}
+
+VCOS_UNSIGNED vcos_generic_blockpool_available_count(VCOS_BLOCKPOOL_T *pool)
+{
+   VCOS_UNSIGNED ret = 0;
+   VCOS_UNSIGNED i;
+
+   ASSERT_POOL(pool);
+   vcos_mutex_lock(&pool->mutex);
+   for (i = 0; i < pool->num_subpools; ++i)
+   {
+      VCOS_BLOCKPOOL_SUBPOOL_T *subpool = &pool->subpools[i];
+      ASSERT_SUBPOOL(subpool);
+
+      /* Assume the malloc of sub pool would succeed */
+      if (subpool->start)
+         ret += subpool->available_blocks;
+      else
+         ret += pool->num_extension_blocks;
+   }
+   vcos_mutex_unlock(&pool->mutex);
+   return ret;
+}
+
+VCOS_UNSIGNED vcos_generic_blockpool_used_count(VCOS_BLOCKPOOL_T *pool)
+{
+   VCOS_UNSIGNED ret = 0;
+   VCOS_UNSIGNED i;
+
+   ASSERT_POOL(pool);
+   vcos_mutex_lock(&pool->mutex);
+
+   for (i = 0; i < pool->num_subpools; ++i)
+   {
+      VCOS_BLOCKPOOL_SUBPOOL_T *subpool = &pool->subpools[i];
+      ASSERT_SUBPOOL(subpool);
+      if (subpool->start)
+         ret += (subpool->num_blocks - subpool->available_blocks);
+   }
+   vcos_mutex_unlock(&pool->mutex);
+   return ret;
+}
+
+void vcos_generic_blockpool_delete(VCOS_BLOCKPOOL_T *pool)
+{
+   vcos_log_trace("%s: pool %p", VCOS_FUNCTION, pool);
+
+   if (pool)
+   {
+      VCOS_UNSIGNED i;
+
+      ASSERT_POOL(pool);
+      for (i = 0; i < pool->num_subpools; ++i)
+      {
+         VCOS_BLOCKPOOL_SUBPOOL_T *subpool = &pool->subpools[i];
+         ASSERT_SUBPOOL(subpool);
+         if (subpool->mem)
+         {
+            /* For debugging */
+            memset(subpool->mem,
+                  0xBE,
+                  VCOS_BLOCKPOOL_SIZE(subpool->num_blocks,
+                     pool->block_data_size, pool->align));
+
+            if (subpool->flags & VCOS_BLOCKPOOL_SUBPOOL_FLAG_OWNS_MEM)
+               vcos_free(subpool->mem);
+            subpool->mem = NULL;
+            subpool->start = NULL;
+         }
+      }
+      vcos_mutex_delete(&pool->mutex);
+      memset(pool, 0xBE, sizeof(VCOS_BLOCKPOOL_T)); /* For debugging */
+   }
+}
+
+uint32_t vcos_generic_blockpool_elem_to_handle(void *block)
+{
+   uint32_t ret = -1;
+   uint32_t index = -1;
+   VCOS_BLOCKPOOL_HEADER_T *hdr = NULL;
+   VCOS_BLOCKPOOL_T *pool = NULL;
+   VCOS_BLOCKPOOL_SUBPOOL_T *subpool = NULL;
+   uint32_t subpool_id;
+
+   vcos_assert(block);
+   hdr = (VCOS_BLOCKPOOL_HEADER_T*) block - 1;
+   subpool = hdr->owner.subpool;
+   ASSERT_SUBPOOL(subpool);
+
+   pool = subpool->owner;
+   ASSERT_POOL(pool);
+   vcos_mutex_lock(&pool->mutex);
+
+   /* The handle is the index into the array of blocks combined
+    * with the subpool id.
+    */
+   index = ((size_t) hdr - (size_t) subpool->start) / pool->block_size;
+   vcos_assert(index < subpool->num_blocks);
+
+   subpool_id = ((char*) subpool - (char*) &pool->subpools[0]) /
+      sizeof(VCOS_BLOCKPOOL_SUBPOOL_T);
+
+   vcos_assert(subpool_id < VCOS_BLOCKPOOL_MAX_SUBPOOLS);
+   vcos_assert(subpool_id < pool->num_subpools);
+   ret = VCOS_BLOCKPOOL_HANDLE_CREATE(index, subpool_id);
+
+   vcos_log_trace("%s: index %d subpool_id %d handle 0x%08x",
+         VCOS_FUNCTION, index, subpool_id, ret);
+
+   vcos_mutex_unlock(&pool->mutex);
+   return ret;
+}
+
+void *vcos_generic_blockpool_elem_from_handle(
+      VCOS_BLOCKPOOL_T *pool, uint32_t handle)
+{
+   VCOS_BLOCKPOOL_SUBPOOL_T *subpool;
+   uint32_t subpool_id;
+   uint32_t index;
+   void *ret = NULL;
+
+
+   ASSERT_POOL(pool);
+   vcos_mutex_lock(&pool->mutex);
+   subpool_id = VCOS_BLOCKPOOL_HANDLE_GET_SUBPOOL(handle);
+
+   if (subpool_id < pool->num_subpools)
+   {
+      index = VCOS_BLOCKPOOL_HANDLE_GET_INDEX(handle);
+      subpool = &pool->subpools[subpool_id];
+      if (pool->subpools[subpool_id].magic == VCOS_BLOCKPOOL_SUBPOOL_MAGIC &&
+            pool->subpools[subpool_id].mem && index < subpool->num_blocks)
+      {
+         VCOS_BLOCKPOOL_HEADER_T *hdr = (VCOS_BLOCKPOOL_HEADER_T*)
+            ((size_t) subpool->start + (index * pool->block_size));
+
+         if (hdr->owner.subpool == subpool) /* Check block is allocated */
+            ret = hdr + 1;
+      }
+   }
+   vcos_mutex_unlock(&pool->mutex);
+
+   vcos_log_trace("%s: pool %p handle 0x%08x elem %p", VCOS_FUNCTION, pool,
+         handle, ret);
+   return ret;
+}
+
+uint32_t vcos_generic_blockpool_is_valid_elem(
+      VCOS_BLOCKPOOL_T *pool, const void *block)
+{
+   uint32_t ret = 0;
+   const char *pool_end;
+   VCOS_UNSIGNED i = 0;
+
+   ASSERT_POOL(pool);
+   if (((size_t) block) & 0x3)
+      return 0;
+
+   vcos_mutex_lock(&pool->mutex);
+
+   for (i = 0; i < pool->num_subpools; ++i)
+   {
+      VCOS_BLOCKPOOL_SUBPOOL_T *subpool = &pool->subpools[i];
+      ASSERT_SUBPOOL(subpool);
+
+      if (subpool->mem && subpool->start)
+      {
+         pool_end = (const char*)subpool->start +
+            (subpool->num_blocks * pool->block_size);
+
+         if ((const char*)block > (const char*)subpool->start &&
+               (const char*)block < pool_end)
+         {
+            const VCOS_BLOCKPOOL_HEADER_T *hdr = (
+                  const VCOS_BLOCKPOOL_HEADER_T*) block - 1;
+
+            /* If the block has a header where the owner points to the pool then
+             * it's a valid block. */
+            ret = (hdr->owner.subpool == subpool && subpool->owner == pool);
+            break;
+         }
+      }
+   }
+   vcos_mutex_unlock(&pool->mutex);
+   return ret;
+}
diff --git a/interface/vcos/generic/vcos_generic_blockpool.h b/interface/vcos/generic/vcos_generic_blockpool.h
new file mode 100755 (executable)
index 0000000..1301f90
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - event flags implemented via a semaphore
+=============================================================================*/
+
+#ifndef VCOS_GENERIC_BLOCKPOOL_H
+#define VCOS_GENERIC_BLOCKPOOL_H
+
+/**
+  * \file
+  *
+  * This provides a generic, thread safe implementation of a VCOS block pool
+  * fixed size memory allocator.
+  */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+
+/** Bits 0 to (VCOS_BLOCKPOOL_SUBPOOL_BITS - 1) are used to store the
+ * subpool id. */
+#define VCOS_BLOCKPOOL_SUBPOOL_BITS 3
+#define VCOS_BLOCKPOOL_MAX_SUBPOOLS (1 << VCOS_BLOCKPOOL_SUBPOOL_BITS)
+
+/* Make zero an invalid handle at the cost of decreasing the maximum
+ * number of blocks (2^28) by 1. Alternatively, a spare bit could be
+ * used to indicated valid blocks but there are likely to be better
+ * uses for spare bits. e.g. allowing more subpools
+ */
+#define INDEX_OFFSET 1
+
+#define VCOS_BLOCKPOOL_HANDLE_GET_INDEX(h) \
+   (((h) >> VCOS_BLOCKPOOL_SUBPOOL_BITS) - INDEX_OFFSET)
+
+#define VCOS_BLOCKPOOL_HANDLE_GET_SUBPOOL(h) \
+   ((h) & ((1 << VCOS_BLOCKPOOL_SUBPOOL_BITS) - 1))
+
+#define VCOS_BLOCKPOOL_HANDLE_CREATE(i,s) \
+   ((((i) + INDEX_OFFSET) << VCOS_BLOCKPOOL_SUBPOOL_BITS) | (s))
+
+#define VCOS_BLOCKPOOL_INVALID_HANDLE 0
+#define VCOS_BLOCKPOOL_ALIGN_DEFAULT sizeof(unsigned long)
+#define VCOS_BLOCKPOOL_FLAG_NONE 0
+
+typedef struct VCOS_BLOCKPOOL_HEADER_TAG
+{
+   /* Blocks either refer to to the pool if they are allocated
+    * or the free list if they are available.
+    */
+   union {
+   struct VCOS_BLOCKPOOL_HEADER_TAG *next;
+   struct VCOS_BLOCKPOOL_SUBPOOL_TAG* subpool;
+   } owner;
+} VCOS_BLOCKPOOL_HEADER_T;
+
+typedef struct VCOS_BLOCKPOOL_SUBPOOL_TAG
+{
+   /** VCOS_BLOCKPOOL_SUBPOOL_MAGIC */
+   uint32_t magic;
+   VCOS_BLOCKPOOL_HEADER_T* free_list;
+   /* The start of the pool memory */
+   void *mem;
+   /* Address of the first block header */
+   void *start;
+   /* The end of the subpool */
+   void *end;
+   /** The number of blocks in this sub-pool */
+   VCOS_UNSIGNED num_blocks;
+   /** Current number of available blocks in this sub-pool */
+   VCOS_UNSIGNED available_blocks;
+   /** Pointers to the pool that owns this sub-pool */
+   struct VCOS_BLOCKPOOL_TAG* owner;
+   /** Define properties such as memory ownership */
+   uint32_t flags;
+} VCOS_BLOCKPOOL_SUBPOOL_T;
+
+typedef struct VCOS_BLOCKPOOL_TAG
+{
+   /** VCOS_BLOCKPOOL_MAGIC */
+   uint32_t magic;
+   /** Thread safety for Alloc, Free, Delete, Stats */
+   VCOS_MUTEX_T mutex;
+   /** Alignment of block data pointers */
+   VCOS_UNSIGNED align;
+   /** Flags for future use e.g. cache options */
+   VCOS_UNSIGNED flags;
+   /** The size of the block data */
+   size_t block_data_size;
+   /** Block size inc overheads */
+   size_t block_size;
+   /** Name for debugging */
+   const char *name;
+   /* The number of subpools that may be used */
+   VCOS_UNSIGNED num_subpools;
+   /** Number of blocks in each dynamically allocated subpool */
+   VCOS_UNSIGNED num_extension_blocks;
+   /** Array of subpools. Subpool zero is is not deleted until the pool is
+    * destroed. If the index of the pool is < num_subpools and
+    * subpool[index.mem] is null then the subpool entry is valid but
+    * "not currently allocated" */
+   VCOS_BLOCKPOOL_SUBPOOL_T subpools[VCOS_BLOCKPOOL_MAX_SUBPOOLS];
+} VCOS_BLOCKPOOL_T;
+
+#define VCOS_BLOCKPOOL_ROUND_UP(x,s)   (((x) + ((s) - 1)) & ~((s) - 1))
+/**
+ * Calculates the size in bytes required for a block pool containing
+ * num_blocks of size block_size plus any overheads.
+ *
+ * The block pool header (VCOS_BLOCKPOOL_T) is allocated separately
+ *
+ * Overheads:
+ * block_size + header must be rounded up to meet the required alignment
+ * The start of the first block may need to be up to align bytes
+ * into the given buffer because statically allocated buffers within structures
+ * are not guaranteed to be aligned as required.
+ */
+#define VCOS_BLOCKPOOL_SIZE(num_blocks, block_size, align) \
+   ((VCOS_BLOCKPOOL_ROUND_UP((block_size) + (align >= 4096 ? 32 : 0) + sizeof(VCOS_BLOCKPOOL_HEADER_T), \
+                             (align)) * (num_blocks)) + (align))
+
+/**
+ * Sanity check to verify whether a handle is potentially a blockpool handle
+ * when the pool pointer is not available.
+ *
+ * If the pool pointer is available use vcos_blockpool_elem_to_handle instead.
+ *
+ * @param handle       the handle to verify
+ * @param max_blocks   the expected maximum number of block in the pool
+ *                     that the handle belongs to.
+ */
+#define VCOS_BLOCKPOOL_IS_VALID_HANDLE_FORMAT(handle, max_blocks) \
+    ((handle) != VCOS_BLOCKPOOL_INVALID_HANDLE \
+     && VCOS_BLOCKPOOL_HANDLE_GET_INDEX((handle)) < (max_blocks))
+
+VCOSPRE_
+   VCOS_STATUS_T VCOSPOST_ vcos_generic_blockpool_init(VCOS_BLOCKPOOL_T *pool,
+      VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size,
+      void *start, VCOS_UNSIGNED pool_size,
+      VCOS_UNSIGNED align, VCOS_UNSIGNED flags,
+      const char *name);
+
+VCOSPRE_
+   VCOS_STATUS_T VCOSPOST_ vcos_generic_blockpool_create_on_heap(
+         VCOS_BLOCKPOOL_T *pool, VCOS_UNSIGNED num_blocks,
+         VCOS_UNSIGNED block_size,
+         VCOS_UNSIGNED align, VCOS_UNSIGNED flags,
+         const char *name);
+
+VCOSPRE_
+   VCOS_STATUS_T VCOSPOST_ vcos_generic_blockpool_extend(VCOS_BLOCKPOOL_T *pool,
+         VCOS_UNSIGNED num_extensions, VCOS_UNSIGNED num_blocks);
+
+VCOSPRE_ void VCOSPOST_ *vcos_generic_blockpool_alloc(VCOS_BLOCKPOOL_T *pool);
+
+VCOSPRE_ void VCOSPOST_ *vcos_generic_blockpool_calloc(VCOS_BLOCKPOOL_T *pool);
+
+VCOSPRE_ void VCOSPOST_ vcos_generic_blockpool_free(void *block);
+
+VCOSPRE_
+   VCOS_UNSIGNED VCOSPOST_ vcos_generic_blockpool_available_count(
+         VCOS_BLOCKPOOL_T *pool);
+
+VCOSPRE_
+   VCOS_UNSIGNED VCOSPOST_ vcos_generic_blockpool_used_count(
+         VCOS_BLOCKPOOL_T *pool);
+
+VCOSPRE_ void VCOSPOST_ vcos_generic_blockpool_delete(VCOS_BLOCKPOOL_T *pool);
+
+VCOSPRE_ uint32_t VCOSPOST_ vcos_generic_blockpool_elem_to_handle(void *block);
+
+VCOSPRE_ void VCOSPOST_
+   *vcos_generic_blockpool_elem_from_handle(
+         VCOS_BLOCKPOOL_T *pool, uint32_t handle);
+
+VCOSPRE_ uint32_t VCOSPOST_
+   vcos_generic_blockpool_is_valid_elem(
+         VCOS_BLOCKPOOL_T *pool, const void *block);
+#if defined(VCOS_INLINE_BODIES)
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_blockpool_init(VCOS_BLOCKPOOL_T *pool,
+      VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size,
+      void *start, VCOS_UNSIGNED pool_size,
+      VCOS_UNSIGNED align, VCOS_UNSIGNED flags, const char *name)
+{
+   return vcos_generic_blockpool_init(pool, num_blocks, block_size,
+         start, pool_size, align, flags, name);
+}
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_blockpool_create_on_heap(VCOS_BLOCKPOOL_T *pool,
+      VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size,
+      VCOS_UNSIGNED align, VCOS_UNSIGNED flags, const char *name)
+{
+   return vcos_generic_blockpool_create_on_heap(
+         pool, num_blocks, block_size, align, flags, name);
+}
+
+VCOS_INLINE_IMPL
+   VCOS_STATUS_T VCOSPOST_ vcos_blockpool_extend(VCOS_BLOCKPOOL_T *pool,
+         VCOS_UNSIGNED num_extensions, VCOS_UNSIGNED num_blocks)
+{
+    return vcos_generic_blockpool_extend(pool, num_extensions, num_blocks);
+}
+
+VCOS_INLINE_IMPL
+void *vcos_blockpool_alloc(VCOS_BLOCKPOOL_T *pool)
+{
+   return vcos_generic_blockpool_alloc(pool);
+}
+
+VCOS_INLINE_IMPL
+void *vcos_blockpool_calloc(VCOS_BLOCKPOOL_T *pool)
+{
+   return vcos_generic_blockpool_calloc(pool);
+}
+
+VCOS_INLINE_IMPL
+void vcos_blockpool_free(void *block)
+{
+   vcos_generic_blockpool_free(block);
+}
+
+VCOS_INLINE_IMPL
+VCOS_UNSIGNED vcos_blockpool_available_count(VCOS_BLOCKPOOL_T *pool)
+{
+   return vcos_generic_blockpool_available_count(pool);
+}
+
+VCOS_INLINE_IMPL
+VCOS_UNSIGNED vcos_blockpool_used_count(VCOS_BLOCKPOOL_T *pool)
+{
+   return vcos_generic_blockpool_used_count(pool);
+}
+
+VCOS_INLINE_IMPL
+void vcos_blockpool_delete(VCOS_BLOCKPOOL_T *pool)
+{
+   vcos_generic_blockpool_delete(pool);
+}
+
+VCOS_INLINE_IMPL
+uint32_t vcos_blockpool_elem_to_handle(void *block)
+{
+   return vcos_generic_blockpool_elem_to_handle(block);
+}
+
+VCOS_INLINE_IMPL
+void *vcos_blockpool_elem_from_handle(VCOS_BLOCKPOOL_T *pool, uint32_t handle)
+{
+   return vcos_generic_blockpool_elem_from_handle(pool, handle);
+}
+
+VCOS_INLINE_IMPL
+uint32_t vcos_blockpool_is_valid_elem(VCOS_BLOCKPOOL_T *pool, const void *block)
+{
+   return vcos_generic_blockpool_is_valid_elem(pool, block);
+}
+#endif /* VCOS_INLINE_BODIES */
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* VCOS_GENERIC_BLOCKPOOL_H */
+
diff --git a/interface/vcos/generic/vcos_generic_event_flags.c b/interface/vcos/generic/vcos_generic_event_flags.c
new file mode 100755 (executable)
index 0000000..9a7c1bb
--- /dev/null
@@ -0,0 +1,320 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - event flags implemented via mutexes
+=============================================================================*/
+
+#include "interface/vcos/vcos.h"
+#include "interface/vcos/generic/vcos_generic_event_flags.h"
+
+#include <stddef.h>
+
+/** A structure created by a thread that waits on the event flags
+  * for a particular combination of flags to arrive.
+  */
+typedef struct VCOS_EVENT_WAITER_T
+{
+   VCOS_UNSIGNED requested_events;  /**< The events wanted */
+   VCOS_UNSIGNED actual_events;     /**< Actual events found */
+   VCOS_UNSIGNED op;                /**< The event operation to be used */
+   VCOS_STATUS_T return_status;     /**< The return status the waiter should pass back */
+   VCOS_EVENT_FLAGS_T *flags;       /**< Pointer to the original 'flags' structure */
+   VCOS_THREAD_T *thread;           /**< Thread waiting */
+   struct VCOS_EVENT_WAITER_T *next;
+} VCOS_EVENT_WAITER_T;
+
+#ifndef NDEBUG
+static int waiter_list_valid(VCOS_EVENT_FLAGS_T *flags);
+#endif
+static void event_flags_timer_expired(void *cxt);
+
+VCOS_STATUS_T vcos_generic_event_flags_create(VCOS_EVENT_FLAGS_T *flags, const char *name)
+{
+   VCOS_STATUS_T rc;
+   if ((rc=vcos_mutex_create(&flags->lock, name)) != VCOS_SUCCESS)
+   {
+      return rc;
+   }
+
+   flags->events = 0;
+   flags->waiters.head = flags->waiters.tail = 0;
+   return rc;
+}
+
+void vcos_generic_event_flags_set(VCOS_EVENT_FLAGS_T *flags,
+                                  VCOS_UNSIGNED bitmask,
+                                  VCOS_OPTION op)
+{
+   vcos_assert(flags);
+   vcos_mutex_lock(&flags->lock);
+   if (op == VCOS_OR)
+   {
+      flags->events |= bitmask;
+   }
+   else if (op == VCOS_AND)
+   {
+      flags->events &= bitmask;
+   }
+   else
+   {
+      vcos_assert(0);
+   }
+
+   /* Now wake up any threads that have now become signalled. */
+   if (flags->waiters.head != NULL)
+   {
+      VCOS_UNSIGNED consumed_events = 0;
+      VCOS_EVENT_WAITER_T **pcurrent_waiter = &flags->waiters.head;
+      VCOS_EVENT_WAITER_T *prev_waiter = NULL;
+
+      /* Walk the chain of tasks suspend on this event flag group to determine
+       * if any of their requests can be satisfied.
+       */
+      while ((*pcurrent_waiter) != NULL)
+      {
+         VCOS_EVENT_WAITER_T *curr_waiter = *pcurrent_waiter;
+
+         /* Determine if this request has been satisfied */
+
+         /* First, find the event flags in common. */
+         VCOS_UNSIGNED waiter_satisfied = flags->events & curr_waiter->requested_events;
+
+         /* Second, determine if all the event flags must match */
+         if (curr_waiter->op & VCOS_AND)
+         {
+            /* All requested events must be present */
+            waiter_satisfied = (waiter_satisfied == curr_waiter->requested_events);
+         }
+
+         /* Wake this one up? */
+         if (waiter_satisfied)
+         {
+
+            if (curr_waiter->op & VCOS_CONSUME)
+            {
+               consumed_events |= curr_waiter->requested_events;
+            }
+
+            /* remove this block from the list, taking care at the end */
+            *pcurrent_waiter = curr_waiter->next;
+            if (curr_waiter->next == NULL)
+               flags->waiters.tail = prev_waiter;
+
+            vcos_assert(waiter_list_valid(flags));
+
+            curr_waiter->return_status = VCOS_SUCCESS;
+            curr_waiter->actual_events = flags->events;
+
+            _vcos_thread_sem_post(curr_waiter->thread);
+         }
+         else
+         {
+            /* move to next element in the list */
+            prev_waiter = *pcurrent_waiter;
+            pcurrent_waiter = &(curr_waiter->next);
+         }
+      }
+
+      flags->events &= ~consumed_events;
+
+   }
+
+   vcos_mutex_unlock(&flags->lock);
+}
+
+void vcos_generic_event_flags_delete(VCOS_EVENT_FLAGS_T *flags)
+{
+   vcos_mutex_delete(&flags->lock);
+}
+
+extern VCOS_STATUS_T vcos_generic_event_flags_get(VCOS_EVENT_FLAGS_T *flags,
+                                                  VCOS_UNSIGNED bitmask,
+                                                  VCOS_OPTION op,
+                                                  VCOS_UNSIGNED suspend,
+                                                  VCOS_UNSIGNED *retrieved_bits)
+{
+   VCOS_EVENT_WAITER_T waitreq;
+   VCOS_STATUS_T rc = VCOS_EAGAIN;
+   int satisfied = 0;
+
+   vcos_assert(flags);
+
+   /* default retrieved bits to 0 */
+   *retrieved_bits = 0;
+
+   vcos_mutex_lock(&flags->lock);
+   switch (op & VCOS_EVENT_FLAG_OP_MASK)
+   {
+   case VCOS_AND:
+      if ((flags->events & bitmask) == bitmask)
+      {
+         *retrieved_bits = flags->events;
+         rc = VCOS_SUCCESS;
+         satisfied = 1;
+         if (op & VCOS_CONSUME)
+            flags->events &= ~bitmask;
+      }
+      break;
+
+   case VCOS_OR:
+      if (flags->events & bitmask)
+      {
+         *retrieved_bits = flags->events;
+         rc = VCOS_SUCCESS;
+         satisfied = 1;
+         if (op & VCOS_CONSUME)
+            flags->events &= ~bitmask;
+      }
+      break;
+
+   default:
+      vcos_assert(0);
+      rc = VCOS_EINVAL;
+      break;
+   }
+
+   if (!satisfied && suspend)
+   {
+      /* Have to go to sleep.
+       *
+       * Append to tail so we get FIFO ordering.
+       */
+      waitreq.requested_events = bitmask;
+      waitreq.op = op;
+      waitreq.return_status = VCOS_EAGAIN;
+      waitreq.flags = flags;
+      waitreq.actual_events = 0;
+      waitreq.thread = vcos_thread_current();
+      waitreq.next = 0;
+      vcos_assert(waitreq.thread != (VCOS_THREAD_T*)-1);
+      VCOS_QUEUE_APPEND_TAIL(&flags->waiters, &waitreq);
+
+      if (suspend != (VCOS_UNSIGNED)-1)
+         _vcos_task_timer_set(event_flags_timer_expired, &waitreq, suspend);
+
+      vcos_mutex_unlock(&flags->lock);
+      /* go to sleep and wait to be signalled or timeout */
+
+      _vcos_thread_sem_wait();
+
+      *retrieved_bits = waitreq.actual_events;
+      rc = waitreq.return_status;
+
+      /* cancel the timer - do not do this while holding the mutex as it
+       * might be waiting for the timeout function to complete, which will
+       * try to take the mutex.
+       */
+      if (suspend != (VCOS_UNSIGNED)-1)
+         _vcos_task_timer_cancel();
+   }
+   else
+   {
+      vcos_mutex_unlock(&flags->lock);
+   }
+
+   return rc;
+}
+
+
+/** Called when a get call times out. Remove this thread's
+  * entry from the waiting queue, then resume the thread.
+  */
+static void event_flags_timer_expired(void *cxt)
+{
+   VCOS_EVENT_WAITER_T *waitreq = (VCOS_EVENT_WAITER_T *)cxt;
+   VCOS_EVENT_FLAGS_T *flags = waitreq->flags;
+   VCOS_EVENT_WAITER_T **plist;
+   VCOS_EVENT_WAITER_T *prev = NULL;
+   VCOS_THREAD_T *thread = 0;
+
+   vcos_assert(flags);
+
+   vcos_mutex_lock(&flags->lock);
+
+   /* walk the list of waiting threads on this event group, and remove
+    * the one that has expired.
+    *
+    * FIXME: could use doubly-linked list if lots of threads are found
+    * to be waiting on a single event flag instance.
+    */
+   plist = &flags->waiters.head;
+   while (*plist != NULL)
+   {
+      if (*plist == waitreq)
+      {
+         int at_end;
+         /* found it */
+         thread = (*plist)->thread;
+         at_end = ((*plist)->next == NULL);
+
+         /* link past */
+         *plist = (*plist)->next;
+         if (at_end)
+            flags->waiters.tail = prev;
+
+         break;
+      }
+      prev = *plist;
+      plist = &(*plist)->next;
+   }
+   vcos_assert(waiter_list_valid(flags));
+
+   vcos_mutex_unlock(&flags->lock);
+
+   if (thread)
+   {
+      _vcos_thread_sem_post(thread);
+   }
+}
+
+#ifndef NDEBUG
+
+static int waiter_list_valid(VCOS_EVENT_FLAGS_T *flags)
+{
+   int valid;
+   /* Either both head and tail are NULL, or neither are NULL */
+   if (flags->waiters.head == NULL)
+   {
+      valid = (flags->waiters.tail == NULL);
+   }
+   else
+   {
+      valid = (flags->waiters.tail != NULL);
+   }
+
+   /* If head and tail point at the same non-NULL element, then there
+    * is only one element in the list.
+    */
+   if (flags->waiters.head && (flags->waiters.head == flags->waiters.tail))
+   {
+      valid = (flags->waiters.head->next == NULL);
+   }
+   return valid;
+}
+
+#endif
diff --git a/interface/vcos/generic/vcos_generic_event_flags.h b/interface/vcos/generic/vcos_generic_event_flags.h
new file mode 100755 (executable)
index 0000000..a21abd4
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - event flags implemented via a semaphore
+=============================================================================*/
+
+#ifndef VCOS_GENERIC_EVENT_FLAGS_H
+#define VCOS_GENERIC_EVENT_FLAGS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+
+/**
+  * \file
+  *
+  * This provides event flags (as per Nucleus Event Groups) based on a
+  * mutex, a semaphore (per waiting thread) and a timer (per waiting
+  * thread).
+  * 
+  * The data structure is a 32 bit unsigned int (the current set of
+  * flags) and a linked list of clients waiting to be 'satisfied'.
+  *
+  * The mutex merely locks access to the data structure. If a client
+  * calls vcos_event_flags_get() and the requested bits are not already
+  * present, it then sleeps on its per-thread semaphore after adding
+  * this semaphore to the queue waiting. It also sets up a timer.
+  *
+  * The per-thread semaphore and timer are actually stored in the
+  * thread context (joinable thread). In future it may become necessary
+  * to support non-VCOS threads by using thread local storage to
+  * create these objects and associate them with the thread.
+  */
+
+struct VCOS_EVENT_WAITER_T;
+
+typedef struct VCOS_EVENT_FLAGS_T
+{
+   VCOS_UNSIGNED events;      /**< Events currently set */
+   VCOS_MUTEX_T lock;         /**< Serialize access */
+   struct
+   {
+      struct VCOS_EVENT_WAITER_T *head;   /**< List of threads waiting */
+      struct VCOS_EVENT_WAITER_T *tail;   /**< List of threads waiting */
+   } waiters;
+} VCOS_EVENT_FLAGS_T;
+
+#define VCOS_OR      1
+#define VCOS_AND     2
+#define VCOS_CONSUME 4
+#define VCOS_OR_CONSUME (VCOS_OR | VCOS_CONSUME)
+#define VCOS_AND_CONSUME (VCOS_AND | VCOS_CONSUME)
+#define VCOS_EVENT_FLAG_OP_MASK (VCOS_OR|VCOS_AND)
+
+VCOSPRE_  VCOS_STATUS_T VCOSPOST_ vcos_generic_event_flags_create(VCOS_EVENT_FLAGS_T *flags, const char *name);
+VCOSPRE_  void VCOSPOST_ vcos_generic_event_flags_set(VCOS_EVENT_FLAGS_T *flags,
+                                                      VCOS_UNSIGNED events,
+                                                      VCOS_OPTION op);
+VCOSPRE_  void VCOSPOST_ vcos_generic_event_flags_delete(VCOS_EVENT_FLAGS_T *);
+VCOSPRE_  VCOS_STATUS_T VCOSPOST_ vcos_generic_event_flags_get(VCOS_EVENT_FLAGS_T *flags,
+                                                               VCOS_UNSIGNED requested_events,
+                                                               VCOS_OPTION op,
+                                                               VCOS_UNSIGNED suspend,
+                                                               VCOS_UNSIGNED *retrieved_events);
+
+#ifdef VCOS_INLINE_BODIES
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_event_flags_create(VCOS_EVENT_FLAGS_T *flags, const char *name) {
+   return vcos_generic_event_flags_create(flags, name);
+}
+
+VCOS_INLINE_IMPL
+void vcos_event_flags_set(VCOS_EVENT_FLAGS_T *flags,
+                          VCOS_UNSIGNED events,
+                          VCOS_OPTION op) {
+   vcos_generic_event_flags_set(flags, events, op);
+}
+
+VCOS_INLINE_IMPL
+void vcos_event_flags_delete(VCOS_EVENT_FLAGS_T *f) {
+   vcos_generic_event_flags_delete(f);
+}
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_event_flags_get(VCOS_EVENT_FLAGS_T *flags,
+                                   VCOS_UNSIGNED requested_events,
+                                   VCOS_OPTION op,
+                                   VCOS_UNSIGNED suspend,
+                                   VCOS_UNSIGNED *retrieved_events) {
+   return vcos_generic_event_flags_get(flags, requested_events, op, suspend, retrieved_events);
+}
+
+#endif /* VCOS_INLINE_BODIES */
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/interface/vcos/generic/vcos_generic_named_sem.c b/interface/vcos/generic/vcos_generic_named_sem.c
new file mode 100755 (executable)
index 0000000..cf47962
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define VCOS_LOG_CATEGORY (&vcos_named_sem_log_cat)
+
+#include "interface/vcos/vcos.h"
+#include "interface/vcos/generic/vcos_generic_named_sem.h"
+#include "interface/vcos/vcos_blockpool.h"
+
+#if defined(VCOS_LOGGING_ENABLED)
+static VCOS_LOG_CAT_T vcos_named_sem_log_cat =
+VCOS_LOG_INIT("vcos_named_sem", VCOS_LOG_ERROR);
+#endif
+
+/**
+  * \file
+  *
+  * Named semaphores, primarily for VCFW.
+  *
+  * Does not actually work across processes; merely emulate the API.
+  *
+  * The client initialises a VCOS_NAMED_SEMAPHORE_T, but this merely
+  * points at the real underlying VCOS_NAMED_SEMAPHORE_IMPL_T.
+  *
+  *      semaphore_t  ---\
+  *                       ----- semaphore_impl_t
+  *      semaphore_t  ---/
+  *                     /
+  *      semaphore_t  -/
+  *
+  */
+
+/* Maintain a block pool of semaphore implementations */
+#define NUM_SEMS  16
+
+/* Allow the pool to expand to MAX_SEMS in size */
+#define MAX_SEMS  512
+
+/** Each actual real semaphore is stored in one of these. Clients just
+  * get a structure with a pointer to this in it.
+  *
+  * It also contains a doubly linked list tracking the semaphores in-use.
+  */
+typedef struct VCOS_NAMED_SEMAPHORE_IMPL_T
+{
+   VCOS_SEMAPHORE_T sem;                     /**< Actual underlying semaphore */
+   char name[VCOS_NAMED_SEMAPHORE_NAMELEN];  /**< Name of semaphore, copied */
+   unsigned refs;                            /**< Reference count */
+   struct VCOS_NAMED_SEMAPHORE_IMPL_T *next; /**< Next in the in-use list   */
+   struct VCOS_NAMED_SEMAPHORE_IMPL_T *prev; /**< Previous in the in-use list */
+} VCOS_NAMED_SEMAPHORE_IMPL_T;
+
+static VCOS_MUTEX_T lock;
+static VCOS_NAMED_SEMAPHORE_IMPL_T* sems_in_use = NULL;
+static int sems_in_use_count = 0;
+static int sems_total_ref_count = 0;
+
+static VCOS_BLOCKPOOL_T sems_pool;
+static char pool_mem[VCOS_BLOCKPOOL_SIZE(
+      NUM_SEMS, sizeof(VCOS_NAMED_SEMAPHORE_IMPL_T), VCOS_BLOCKPOOL_ALIGN_DEFAULT)];
+
+VCOS_STATUS_T _vcos_named_semaphore_init()
+{
+   VCOS_STATUS_T status;
+
+   status = vcos_blockpool_init(&sems_pool,
+         NUM_SEMS, sizeof(VCOS_NAMED_SEMAPHORE_IMPL_T),
+         pool_mem, sizeof(pool_mem),
+         VCOS_BLOCKPOOL_ALIGN_DEFAULT, 0, "vcos named semaphores");
+
+   if (status != VCOS_SUCCESS)
+      goto fail_blockpool;
+
+   status = vcos_blockpool_extend(&sems_pool, VCOS_BLOCKPOOL_MAX_SUBPOOLS - 1,
+         (MAX_SEMS - NUM_SEMS) / (VCOS_BLOCKPOOL_MAX_SUBPOOLS - 1));
+   if (status != VCOS_SUCCESS)
+      goto fail_extend;
+
+   status = vcos_mutex_create(&lock, "vcosnmsem");
+   if (status != VCOS_SUCCESS)
+      goto fail_mutex;
+
+   return status;
+
+fail_mutex:
+fail_extend:
+   vcos_blockpool_delete(&sems_pool);
+fail_blockpool:
+   return status;
+}
+
+void _vcos_named_semaphore_deinit(void)
+{
+   vcos_blockpool_delete(&sems_pool);
+   vcos_mutex_delete(&lock);
+   sems_in_use = NULL;
+}
+
+VCOS_STATUS_T
+vcos_generic_named_semaphore_create(VCOS_NAMED_SEMAPHORE_T *sem,
+      const char *name, VCOS_UNSIGNED count)
+{
+   VCOS_STATUS_T status = VCOS_ENOSPC;
+   int name_len, cmp = -1;
+   VCOS_NAMED_SEMAPHORE_IMPL_T *impl;
+   VCOS_NAMED_SEMAPHORE_IMPL_T *new_impl;
+
+   vcos_log_trace("%s: sem %p name %s count %d", __FUNCTION__,
+         sem, (name ? name : "null"), count);
+
+   vcos_assert(name);
+
+   vcos_mutex_lock(&lock);
+   name_len = vcos_strlen(name);
+   if (name_len >= VCOS_NAMED_SEMAPHORE_NAMELEN)
+   {
+      vcos_assert(0);
+      status = VCOS_EINVAL;
+      goto end;
+   }
+
+   /* do we already have this semaphore? */
+   impl = sems_in_use;
+   while (impl && (cmp = vcos_strcmp(name, impl->name)) < 0)
+      impl = impl->next;
+
+   if (impl && cmp == 0)
+   {
+      /* Semaphore is already in use so just increase the ref count */
+      impl->refs++;
+      sems_total_ref_count++;
+      sem->actual = impl;
+      sem->sem = &impl->sem;
+      status = VCOS_SUCCESS;
+      vcos_log_trace(
+            "%s: ref count %d name %s total refs %d num sems %d",
+            __FUNCTION__, impl->refs, impl->name,
+            sems_total_ref_count, sems_in_use_count);
+      goto end;
+   }
+
+   /* search for unused semaphore */
+   new_impl = vcos_blockpool_calloc(&sems_pool);
+   if (new_impl)
+   {
+      status = vcos_semaphore_create(&new_impl->sem, name, count);
+      if (status == VCOS_SUCCESS)
+      {
+         new_impl->refs = 1;
+         sems_total_ref_count++;
+         sems_in_use_count++;
+         memcpy(new_impl->name, name, name_len + 1); /* already checked length! */
+         sem->actual = new_impl;
+         sem->sem = &new_impl->sem;
+
+         /* Insert into the sorted list
+          * impl is either NULL or the first element where
+          * name > impl->name.
+          */
+         if (impl)
+         {
+            new_impl->prev = impl->prev;
+            impl->prev = new_impl;
+            new_impl->next = impl;
+
+            if (new_impl->prev)
+               new_impl->prev->next = new_impl;
+         }
+         else
+         {
+            /* Appending to the tail of the list / empty list */
+            VCOS_NAMED_SEMAPHORE_IMPL_T *tail = sems_in_use;
+            while(tail && tail->next)
+               tail = tail->next;
+
+            if (tail)
+            {
+               tail->next = new_impl;
+               new_impl->prev = tail;
+            }
+         }
+
+         if (sems_in_use == impl)
+         {
+            /* Inserted at head or list was empty */
+            sems_in_use = new_impl;
+         }
+
+      vcos_log_trace(
+            "%s: new ref actual %p prev %p next %p count %d name %s " \
+            "total refs %d num sems %d",
+            __FUNCTION__,
+            new_impl, new_impl->prev, new_impl->next,
+            new_impl->refs, new_impl->name,
+            sems_total_ref_count, sems_in_use_count);
+      }
+   }
+
+end:
+   vcos_mutex_unlock(&lock);
+   if (status != VCOS_SUCCESS)
+   {
+      vcos_log_error("%s: failed to create named semaphore name %s status %d " \
+            "total refs %d num sems %d",
+            __FUNCTION__, (name ? name : "NULL"), status,
+            sems_total_ref_count, sems_in_use_count);
+   }
+   return status;
+}
+
+void vcos_named_semaphore_delete(VCOS_NAMED_SEMAPHORE_T *sem)
+{
+   VCOS_NAMED_SEMAPHORE_IMPL_T *actual = sem->actual;
+   vcos_mutex_lock(&lock);
+
+   /* if this fires, the semaphore has already been deleted */
+   vcos_assert(actual->refs);
+
+   vcos_log_trace(
+         "%s: actual %p ref count %d name %s prev %p next %p total refs %d num sems %d",
+         __FUNCTION__, actual, actual->refs, actual->name,
+         actual->prev, actual->next,
+         sems_total_ref_count, sems_in_use_count);
+
+   sems_total_ref_count--;
+   if (--actual->refs == 0)
+   {
+      sems_in_use_count--;
+      if (actual->prev)
+         actual->prev->next = actual->next;
+
+      if (actual->next)
+         actual->next->prev = actual->prev;
+
+      if (sems_in_use == actual)
+         sems_in_use = actual->next;
+
+      vcos_semaphore_delete(&actual->sem);
+      sem->actual = NULL;
+      sem->sem = NULL;
+      vcos_blockpool_free(actual);
+   }
+   vcos_mutex_unlock(&lock);
+}
diff --git a/interface/vcos/generic/vcos_generic_named_sem.h b/interface/vcos/generic/vcos_generic_named_sem.h
new file mode 100755 (executable)
index 0000000..81a0716
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - named semaphores
+=============================================================================*/
+
+#ifndef VCOS_GENERIC_NAMED_SEM_H
+#define VCOS_GENERIC_NAMED_SEM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+
+/**
+ * \file
+ *
+ * Generic support for named semaphores, using regular ones. This is only
+ * suitable for emulating them on an embedded MMUless system, since there is
+ * no support for opening semaphores across process boundaries.
+ *
+ */
+
+#define VCOS_NAMED_SEMAPHORE_NAMELEN   64
+
+/* In theory we could use the name facility provided within Nucleus. However, this
+ * is hard to do as semaphores are constantly being created and destroyed; we
+ * would need to stop everything while allocating the memory for the semaphore
+ * list and then walking it. So keep our own list.
+ */
+typedef struct VCOS_NAMED_SEMAPHORE_T
+{
+   struct VCOS_NAMED_SEMAPHORE_IMPL_T *actual; /**< There are 'n' named semaphores per 1 actual semaphore  */
+   VCOS_SEMAPHORE_T *sem;                      /**< Pointer to actual underlying semaphore */
+} VCOS_NAMED_SEMAPHORE_T;
+
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_
+vcos_generic_named_semaphore_create(VCOS_NAMED_SEMAPHORE_T *sem, const char *name, VCOS_UNSIGNED count);
+
+VCOSPRE_ void VCOSPOST_ vcos_named_semaphore_delete(VCOS_NAMED_SEMAPHORE_T *sem);
+
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ _vcos_named_semaphore_init(void);
+VCOSPRE_ void VCOSPOST_ _vcos_named_semaphore_deinit(void);
+
+#if defined(VCOS_INLINE_BODIES)
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_named_semaphore_create(VCOS_NAMED_SEMAPHORE_T *sem, const char *name, VCOS_UNSIGNED count) {
+   return vcos_generic_named_semaphore_create(sem, name, count);
+}
+
+VCOS_INLINE_IMPL
+void vcos_named_semaphore_wait(VCOS_NAMED_SEMAPHORE_T *sem) {
+   vcos_semaphore_wait(sem->sem);
+}
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_named_semaphore_trywait(VCOS_NAMED_SEMAPHORE_T *sem) {
+   return vcos_semaphore_trywait(sem->sem);
+}
+
+VCOS_INLINE_IMPL
+void vcos_named_semaphore_post(VCOS_NAMED_SEMAPHORE_T *sem) {
+   vcos_semaphore_post(sem->sem);
+}
+
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+
diff --git a/interface/vcos/generic/vcos_generic_quickslow_mutex.h b/interface/vcos/generic/vcos_generic_quickslow_mutex.h
new file mode 100755 (executable)
index 0000000..ddc7b97
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - reentrant mutexes created from regular ones.
+=============================================================================*/
+
+#ifndef VCOS_GENERIC_QUICKSLOW_MUTEX_H
+#define VCOS_GENERIC_QUICKSLOW_MUTEX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+
+/**
+ * \file
+ *
+ * Quickslow Mutexes implemented as regular ones (i.e. quick and slow modes are the same).
+ *
+ */
+
+typedef VCOS_MUTEX_T VCOS_QUICKSLOW_MUTEX_T;
+
+#if defined(VCOS_INLINE_BODIES)
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_quickslow_mutex_create(VCOS_QUICKSLOW_MUTEX_T *m, const char *name)
+{
+   return vcos_mutex_create(m, name);
+}
+
+VCOS_INLINE_IMPL
+void vcos_quickslow_mutex_delete(VCOS_QUICKSLOW_MUTEX_T *m)
+{
+   vcos_mutex_delete(m);
+}
+
+VCOS_INLINE_IMPL
+void vcos_quickslow_mutex_lock(VCOS_QUICKSLOW_MUTEX_T *m)
+{
+   while (vcos_mutex_lock(m) == VCOS_EAGAIN);
+}
+
+VCOS_INLINE_IMPL
+void vcos_quickslow_mutex_unlock(VCOS_QUICKSLOW_MUTEX_T *m)
+{
+   vcos_mutex_unlock(m);
+}
+
+VCOS_INLINE_IMPL
+void vcos_quickslow_mutex_lock_quick(VCOS_QUICKSLOW_MUTEX_T *m)
+{
+   while (vcos_mutex_lock(m) == VCOS_EAGAIN);
+}
+
+VCOS_INLINE_IMPL
+void vcos_quickslow_mutex_unlock_quick(VCOS_QUICKSLOW_MUTEX_T *m)
+{
+   vcos_mutex_unlock(m);
+}
+
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+
diff --git a/interface/vcos/generic/vcos_generic_reentrant_mtx.c b/interface/vcos/generic/vcos_generic_reentrant_mtx.c
new file mode 100755 (executable)
index 0000000..7258cbf
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/vcos/vcos.h"
+#include "interface/vcos/vcos_reentrant_mutex.h"
+
+VCOS_STATUS_T vcos_generic_reentrant_mutex_create(VCOS_REENTRANT_MUTEX_T *m, const char *name)
+{
+   m->count = 0;
+   m->owner = 0;
+   return vcos_mutex_create(&m->mutex, name);
+}
+
+void vcos_generic_reentrant_mutex_delete(VCOS_REENTRANT_MUTEX_T *m)
+{
+   vcos_assert(m->count == 0);
+   vcos_mutex_delete(&m->mutex);
+}
+
+void vcos_generic_reentrant_mutex_lock(VCOS_REENTRANT_MUTEX_T *m)
+{
+   VCOS_THREAD_T *thread = vcos_thread_current();
+   vcos_assert(m);
+
+   vcos_assert(thread != 0);
+
+   if (m->owner != thread)
+   {
+      vcos_mutex_lock(&m->mutex);
+      m->owner = thread;
+      vcos_assert(m->count == 0);
+   }
+   m->count++;
+}
+
+void vcos_generic_reentrant_mutex_unlock(VCOS_REENTRANT_MUTEX_T *m)
+{
+   vcos_assert(m->count != 0);
+   vcos_assert(m->owner == vcos_thread_current());
+   m->count--;
+   if (m->count == 0)
+   {
+      m->owner = 0;
+      vcos_mutex_unlock(&m->mutex);
+   }
+}
+
+
+
+
+
+
diff --git a/interface/vcos/generic/vcos_generic_reentrant_mtx.h b/interface/vcos/generic/vcos_generic_reentrant_mtx.h
new file mode 100755 (executable)
index 0000000..21ae1c9
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - reentrant mutexes created from regular ones.
+=============================================================================*/
+
+#ifndef VCOS_GENERIC_REENTRANT_MUTEX_H
+#define VCOS_GENERIC_REENTRANT_MUTEX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+
+/**
+ * \file
+ *
+ * Reentrant Mutexes from regular ones.
+ *
+ */
+
+typedef struct VCOS_REENTRANT_MUTEX_T
+{
+   VCOS_MUTEX_T mutex;
+   VCOS_THREAD_T *owner;
+   unsigned count;
+} VCOS_REENTRANT_MUTEX_T;
+
+/* Extern definitions of functions that do the actual work */
+
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_generic_reentrant_mutex_create(VCOS_REENTRANT_MUTEX_T *m, const char *name);
+
+VCOSPRE_ void VCOSPOST_ vcos_generic_reentrant_mutex_delete(VCOS_REENTRANT_MUTEX_T *m);
+
+VCOSPRE_ void VCOSPOST_ vcos_generic_reentrant_mutex_lock(VCOS_REENTRANT_MUTEX_T *m);
+
+VCOSPRE_ void VCOSPOST_ vcos_generic_reentrant_mutex_unlock(VCOS_REENTRANT_MUTEX_T *m);
+
+/* Inline forwarding functions */
+
+#if defined(VCOS_INLINE_BODIES)
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_reentrant_mutex_create(VCOS_REENTRANT_MUTEX_T *m, const char *name) {
+   return vcos_generic_reentrant_mutex_create(m,name);
+}
+
+VCOS_INLINE_IMPL
+void vcos_reentrant_mutex_delete(VCOS_REENTRANT_MUTEX_T *m) {
+   vcos_generic_reentrant_mutex_delete(m);
+}
+
+VCOS_INLINE_IMPL
+void vcos_reentrant_mutex_lock(VCOS_REENTRANT_MUTEX_T *m) {
+   vcos_generic_reentrant_mutex_lock(m);
+}
+
+VCOS_INLINE_IMPL
+void vcos_reentrant_mutex_unlock(VCOS_REENTRANT_MUTEX_T *m) {
+   vcos_generic_reentrant_mutex_unlock(m);
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+
diff --git a/interface/vcos/generic/vcos_generic_safe_string.c b/interface/vcos/generic/vcos_generic_safe_string.c
new file mode 100755 (executable)
index 0000000..6b88694
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/vcos/vcos.h"
+
+#if defined( __KERNEL__ )
+#include <linux/string.h>
+#include <linux/module.h>
+#else
+#include <string.h>
+#endif
+
+#include <stdarg.h>
+
+/** Like vsnprintf, except it places the output at the specified offset.
+  * Output is truncated to fit in buflen bytes, and is guaranteed to be NUL-terminated.
+  * Returns the string length before/without truncation.
+  */
+size_t vcos_safe_vsprintf(char *buf, size_t buflen, size_t offset, const char *fmt, va_list ap)
+{
+   size_t space = (offset < buflen) ? (buflen - offset) : 0;
+
+   offset += vcos_vsnprintf(buf ? (buf + offset) : NULL, space, fmt, ap);
+
+   return offset;
+}
+
+/** Like snprintf, except it places the output at the specified offset.
+  * Output is truncated to fit in buflen bytes, and is guaranteed to be NUL-terminated.
+  * Returns the string length before/without truncation.
+  */
+size_t vcos_safe_sprintf(char *buf, size_t buflen, size_t offset, const char *fmt, ...)
+{
+   size_t space = (offset < buflen) ? (buflen - offset) : 0;
+   va_list ap;
+   
+   va_start(ap, fmt);
+
+   offset += vcos_vsnprintf(buf ? (buf + offset) : NULL, space, fmt, ap);
+
+   va_end(ap);
+
+   return offset;
+}
+
+/** Copies string src to dst at the specified offset.
+  * Output is truncated to fit in dstlen bytes, i.e. the string is at most
+  * (buflen - 1) characters long. Unlike strncpy, exactly one NUL is written
+  * to dst, which is always NUL-terminated.
+  * Returns the string length before/without truncation.
+  */
+size_t vcos_safe_strcpy(char *dst, const char *src, size_t dstlen, size_t offset)
+{
+   if (offset < dstlen)
+   {
+      const char *p = src;
+      char *endp = dst + dstlen -1;
+
+      dst += offset;
+
+      for (; *p!='\0' && dst != endp; dst++, p++)
+         *dst = *p;
+      *dst = '\0';
+   }
+   offset += strlen(src);
+
+   return offset;
+}
diff --git a/interface/vcos/generic/vcos_generic_tls.h b/interface/vcos/generic/vcos_generic_tls.h
new file mode 100755 (executable)
index 0000000..6460ae7
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - generic thread local storage
+=============================================================================*/
+
+#ifndef VCOS_GENERIC_TLS_H
+#define VCOS_GENERIC_TLS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+
+/**
+  * \file
+  *
+  * Do an emulation of Thread Local Storage. The platform needs to
+  * provide a way to set and get a per-thread pointer which is
+  * where the TLS data itself is stored.
+  *
+  *
+  * Each thread that wants to join in this scheme needs to call
+  * vcos_tls_thread_register().
+  *
+  * The platform needs to support the macros/functions
+  * _vcos_tls_thread_ptr_set() and _vcos_tls_thread_ptr_get().
+  */
+
+#ifndef VCOS_WANT_TLS_EMULATION
+#error Should not be included unless TLS emulation is defined
+#endif
+
+/** Number of slots to reserve per thread. This results in an overhead
+  * of this many words per thread.
+  */
+#define VCOS_TLS_MAX_SLOTS 4
+
+/** TLS key. Allocating one of these reserves the client one of the 
+  * available slots.
+  */
+typedef VCOS_UNSIGNED VCOS_TLS_KEY_T;
+
+/** TLS per-thread structure. Each thread gets one of these
+  * if TLS emulation (rather than native TLS support) is
+  * being used.
+  */
+typedef struct VCOS_TLS_THREAD_T
+{
+   void *slots[VCOS_TLS_MAX_SLOTS];
+} VCOS_TLS_THREAD_T;
+
+/*
+ * Internal APIs 
+ */
+
+/** Register this thread's TLS storage area. */
+VCOSPRE_ void VCOSPOST_ vcos_tls_thread_register(VCOS_TLS_THREAD_T *);
+
+/** Create a new TLS key */
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_generic_tls_create(VCOS_TLS_KEY_T *key);
+
+/** Delete a TLS key */
+VCOSPRE_ void VCOSPOST_ vcos_generic_tls_delete(VCOS_TLS_KEY_T tls);
+
+/** Initialise the TLS library */
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_tls_init(void);
+
+/** Deinitialise the TLS library */
+VCOSPRE_ void VCOSPOST_ vcos_tls_deinit(void);
+
+#if defined(VCOS_INLINE_BODIES)
+
+#undef VCOS_ASSERT_LOGGING_DISABLE
+#define VCOS_ASSERT_LOGGING_DISABLE 1
+
+/*
+ * Implementations of public API functions
+ */
+
+/** Set the given value. Since everything is per-thread, there is no need
+  * for any locking.
+  */
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_tls_set(VCOS_TLS_KEY_T tls, void *v) {
+   VCOS_TLS_THREAD_T *tlsdata = _vcos_tls_thread_ptr_get();
+   vcos_assert(tlsdata); /* Fires if this thread has not been registered */
+   if (tls<VCOS_TLS_MAX_SLOTS)
+   {
+      tlsdata->slots[tls] = v;
+      return VCOS_SUCCESS;
+   }
+   else
+   {
+      vcos_assert(0);
+      return VCOS_EINVAL;
+   }
+}
+
+/** Get the given value. No locking required.
+  */
+VCOS_INLINE_IMPL
+void *vcos_tls_get(VCOS_TLS_KEY_T tls) {
+   VCOS_TLS_THREAD_T *tlsdata = _vcos_tls_thread_ptr_get();
+   vcos_assert(tlsdata); /* Fires if this thread has not been registered */
+   if (tls<VCOS_TLS_MAX_SLOTS)
+   {
+      return tlsdata->slots[tls];
+   }
+   else
+   {
+      vcos_assert(0);
+      return NULL;
+   }
+}
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_tls_create(VCOS_TLS_KEY_T *key) {
+   return vcos_generic_tls_create(key);
+}
+
+VCOS_INLINE_IMPL
+void vcos_tls_delete(VCOS_TLS_KEY_T tls) {
+   vcos_generic_tls_delete(tls);
+}
+
+#undef VCOS_ASSERT_LOGGING_DISABLE
+#define VCOS_ASSERT_LOGGING_DISABLE 0
+
+#endif /* VCOS_INLINE_BODIES */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/interface/vcos/generic/vcos_init.c b/interface/vcos/generic/vcos_init.c
new file mode 100755 (executable)
index 0000000..6f4c1bb
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+The following header is included in order to provide one instance of the symbol vcos_deprecated_code.
+Any other inclusions of this header (or "vcos_deprecated_code.inc" for assembly language) will cause the linker to warn
+about multiple definitions of vcos_deprecated_code.
+The idea is to include this header file for the source files which are deprecated.
+Therefore the above warnning in a build indicates that the build is using deprecated code! 
+Contact the person named in the accompanying comment for advice - do not remove the inclusion.
+*/
+#include "vcos_deprecated.h"
+
+#include "interface/vcos/vcos.h"
+
+static int init_refcount;
+
+VCOS_STATUS_T vcos_init(void)
+{
+   VCOS_STATUS_T st = VCOS_SUCCESS;
+
+   vcos_global_lock();
+
+   if (init_refcount++ == 0)
+      st = vcos_platform_init();
+
+   vcos_global_unlock();
+
+   return st;
+}
+
+void vcos_deinit(void)
+{
+   vcos_global_lock();
+
+   vcos_assert(init_refcount > 0);
+
+   if (init_refcount > 0 && --init_refcount == 0)
+      vcos_platform_deinit();
+
+   vcos_global_unlock();
+}
+
+#if defined(__GNUC__) && (__GNUC__ > 2)
+
+void vcos_ctor(void) __attribute__((constructor, used));
+
+void vcos_ctor(void)
+{
+   vcos_init();
+}
+
+void vcos_dtor(void) __attribute__((destructor, used));
+
+void vcos_dtor(void)
+{
+   vcos_deinit();
+}
+
+#endif
diff --git a/interface/vcos/generic/vcos_joinable_thread_from_plain.h b/interface/vcos/generic/vcos_joinable_thread_from_plain.h
new file mode 100755 (executable)
index 0000000..4471168
--- /dev/null
@@ -0,0 +1,229 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - implementation: joinable thread from plain
+=============================================================================*/
+
+/** \file
+  *
+  * Header file for platforms creating the joinable thread from a lowlevel
+  * thread.
+  *
+  * In addition to the actual thread, the following are also created:
+  *
+  * - a semaphore to wait on when joining the thread
+  * - a semaphore to support counted suspend/resume (used by event group)
+  * - a per-thread timer (used by event group, but could be removed)
+  */
+
+#ifndef VCOS_JOINABLE_THREAD_FROM_PLAIN_H
+#define VCOS_JOINABLE_THREAD_FROM_PLAIN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef VCOS_SEMAPHORE_H
+#include "interface/vcos/vcos_semaphore.h"
+#endif
+#ifndef VCOS_LOWLEVEL_THREAD_H
+#include "interface/vcos/vcos_lowlevel_thread.h"
+#endif
+#ifndef VCOS_TIMER_H
+#include "interface/vcos/vcos_timer.h"
+#endif
+
+#ifdef VCOS_WANT_TLS_EMULATION
+#include "interface/vcos/generic/vcos_generic_tls.h"
+#endif
+
+#define VCOS_THREAD_MAGIC 0x56436a74
+
+#define VCOS_THREAD_VALID(t) (t->magic == VCOS_THREAD_MAGIC)
+#define VCOS_HAVE_THREAD_AT_EXIT        1
+
+/** Thread attribute structure. Clients should not manipulate this directly, but
+  * should instead use the provided functions.
+  */
+typedef struct VCOS_THREAD_ATTR_T
+{
+   void *ta_stackaddr;
+   VCOS_UNSIGNED ta_stacksz;
+   VCOS_UNSIGNED ta_priority;
+   VCOS_UNSIGNED ta_affinity;
+   VCOS_UNSIGNED ta_timeslice;
+   VCOS_UNSIGNED legacy;
+   VCOS_UNSIGNED ta_autostart;
+} VCOS_THREAD_ATTR_T;
+
+/** Each thread gets a timer, which is for internal VCOS use.
+  */
+typedef struct _VCOS_THREAD_TIMER_T
+{
+   VCOS_TIMER_T timer;
+   void (*pfn)(void *);
+   void *cxt;
+} _VCOS_THREAD_TIMER_T;
+
+typedef void (*VCOS_THREAD_EXIT_HANDLER_T)(void *);
+/** Called at thread exit.
+  */
+typedef struct VCOS_THREAD_EXIT_T
+{
+   VCOS_THREAD_EXIT_HANDLER_T pfn;
+   void *cxt;
+} VCOS_THREAD_EXIT_T;
+#define VCOS_MAX_EXIT_HANDLERS  8
+
+/* The name field isn't used for anything, so we can just copy the
+ * the pointer. Nucleus makes its own copy.
+ */
+typedef const char *          VCOS_LLTHREAD_T_NAME;
+#define _VCOS_LLTHREAD_NAME(dst,src) (dst)=(src)
+
+/*
+ * Simulated TLS support
+ */
+
+
+/** Thread structure.
+  *
+  * \warning Do not access the members of this structure directly!
+  */
+typedef struct VCOS_THREAD_T
+{
+   VCOS_LLTHREAD_T  thread;      /**< The underlying thread */
+   char name[16];                /**< The name */
+   unsigned int     magic;       /**< For debug */
+   void            *exit_data;   /**< Exit data passed out in vcos_joinable_thread_exit() */
+   void            *stack;       /**< Stack, if not supplied by caller */
+   VCOS_SEMAPHORE_T wait;        /**< Semaphore to wait on at join */
+   VCOS_SEMAPHORE_T suspend;     /**< Semaphore to wait on for counted suspend */
+   int16_t          joined;      /**< Joined yet? For debug. */
+   VCOS_UNSIGNED    legacy;      /**< Use (argc,argv) for entry point arguments */
+   void *(*entry)(void*);        /**< Entry point */
+   void             *arg;        /**< Argument passed to entry point */
+   void *(*term)(void*);         /**< Termination function, used by reaper */
+   void             *term_arg;   /**< Argument passed to termination function */
+   _VCOS_THREAD_TIMER_T _timer;  /**< Internal timer, mainly for event groups */
+#ifdef VCOS_WANT_TLS_EMULATION
+   VCOS_TLS_THREAD_T   _tls;     /**< TLS data when native TLS not available, or NULL */
+#endif
+   /** Array of functions to call at thread exit */
+   VCOS_THREAD_EXIT_T at_exit[VCOS_MAX_EXIT_HANDLERS];
+
+   struct VCOS_THREAD_T *next;   /**< For linked lists of threads */
+} VCOS_THREAD_T;
+
+#if defined(VCOS_INLINE_BODIES)
+
+VCOS_INLINE_IMPL
+void vcos_thread_attr_setstack(VCOS_THREAD_ATTR_T *attrs, void *addr, VCOS_UNSIGNED stacksz) {
+   attrs->ta_stackaddr = addr;
+   attrs->ta_stacksz = stacksz;
+}
+
+VCOS_INLINE_IMPL
+void vcos_thread_attr_setstacksize(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED stacksz) {
+   attrs->ta_stacksz = stacksz;
+}
+
+VCOS_INLINE_IMPL
+void vcos_thread_attr_setpriority(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED pri) {
+   attrs->ta_priority = pri;
+}
+
+VCOS_INLINE_IMPL
+void vcos_thread_attr_setaffinity(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED affinity) {
+   attrs->ta_affinity = affinity;
+}
+
+VCOS_INLINE_IMPL
+void vcos_thread_attr_settimeslice(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED ts) {
+   attrs->ta_timeslice = ts;
+}
+
+VCOS_INLINE_IMPL
+void _vcos_thread_attr_setlegacyapi(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED legacy) {
+   attrs->legacy = legacy;
+}
+
+VCOS_INLINE_IMPL
+void vcos_thread_attr_setautostart(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED autostart) {
+   attrs->ta_autostart = autostart;
+}
+
+VCOS_INLINE_IMPL
+VCOS_THREAD_T *vcos_thread_current(void) {
+   VCOS_THREAD_T *ret =  (VCOS_THREAD_T*)vcos_llthread_current();
+   /*If we're called from a non-vcos thread, this assert will fail.
+    *XXX FIXME why is this commented out?
+    *vcos_assert(ret->magic == VCOS_THREAD_MAGIC);
+    */
+   return ret;
+}
+
+VCOS_INLINE_IMPL
+int vcos_thread_running(VCOS_THREAD_T *thread) {
+   return vcos_llthread_running(&thread->thread);
+}
+
+VCOS_INLINE_IMPL
+void vcos_thread_resume(VCOS_THREAD_T *thread) {
+   vcos_llthread_resume(&thread->thread);
+}
+
+#endif /* VCOS_INLINE_BODIES */
+
+/**
+  * \brief Create a VCOS_THREAD_T for the current thread. This is so we can have
+  * VCOS_THREAD_Ts even for threads not originally created by VCOS (eg the
+  * thread that calls vcos_init)
+  */
+extern VCOS_STATUS_T _vcos_thread_create_attach(VCOS_THREAD_T *thread,
+                                                const char *name);
+
+/**
+  * \brief Deletes the VCOS_THREAD_T, but does not wait for the underlying
+  * thread to exit. This will cleanup everything created by
+  * _vcos_thread_create_attach
+  */
+extern void _vcos_thread_delete(VCOS_THREAD_T *thread);
+
+/** Register a function to be called when the current thread exits.
+  */
+extern VCOS_STATUS_T vcos_thread_at_exit(void (*pfn)(void*), void *cxt);
+
+/** Deregister a previously registered at-exit function.
+  */
+extern void vcos_thread_deregister_at_exit(void (*pfn)(void*), void *cxt);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* VCOS_JOINABLE_THREAD_FROM_PLAIN_H */
diff --git a/interface/vcos/generic/vcos_latch_from_sem.h b/interface/vcos/generic/vcos_latch_from_sem.h
new file mode 100755 (executable)
index 0000000..94f4b13
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - Construct a latch from a semaphore
+=============================================================================*/
+
+/** FIXME: rename to vcos_mutex_from_sem.c
+  */
+
+typedef struct VCOS_MUTEX_T {
+   VCOS_SEMAPHORE_T sem;
+   struct VCOS_THREAD_T *owner;
+} VCOS_MUTEX_T;
+
+extern VCOS_STATUS_T vcos_generic_mutex_create(VCOS_MUTEX_T *latch, const char *name);
+extern void vcos_generic_mutex_delete(VCOS_MUTEX_T *latch);
+extern VCOS_STATUS_T vcos_generic_mutex_lock(VCOS_MUTEX_T *latch);
+extern void vcos_generic_mutex_unlock(VCOS_MUTEX_T *latch);
+
+#if defined(VCOS_INLINE_BODIES)
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_mutex_create(VCOS_MUTEX_T *latch, const char *name) {
+   return vcos_generic_mutex_create(latch,name);
+}
+
+VCOS_INLINE_IMPL
+void vcos_mutex_delete(VCOS_MUTEX_T *latch) {
+   vcos_generic_mutex_delete(latch);
+}
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_mutex_lock(VCOS_MUTEX_T *latch) {
+   return vcos_generic_mutex_lock(latch);
+}
+
+VCOS_INLINE_IMPL
+void vcos_mutex_unlock(VCOS_MUTEX_T *latch) {
+   vcos_generic_mutex_unlock(latch);
+}
+
+#endif /* VCOS_INLINE_BODIES */
+
diff --git a/interface/vcos/generic/vcos_logcat.c b/interface/vcos/generic/vcos_logcat.c
new file mode 100755 (executable)
index 0000000..b9b9c88
--- /dev/null
@@ -0,0 +1,571 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+Categorized logging for VCOS - a generic implementation.
+=============================================================================*/
+
+#include "interface/vcos/vcos.h"
+#include "interface/vcos/vcos_ctype.h"
+#include "interface/vcos/vcos_string.h"
+#include "interface/vcos/vcos_inttypes.h"
+
+static VCOS_MUTEX_T lock;
+static int warned_loglevel;             /* only warn about invalid log level once */
+static VCOS_VLOG_IMPL_FUNC_T vcos_vlog_impl_func = vcos_vlog_default_impl;
+
+#define  VCOS_LOG_CATEGORY (&dflt_log_category)
+static VCOS_LOG_CAT_T dflt_log_category;
+VCOS_LOG_CAT_T *vcos_logging_categories = NULL;
+static int inited;
+
+#if VCOS_HAVE_CMD
+
+/*
+ * For kernel or videocore purposes, we generally want the log command. For 
+ * user-space apps, they might want to provide their own log command, so we 
+ * don't include the built in on. 
+ *  
+ * So pthreads/vcos_platform.h defines VCOS_WANT_LOG_CMD to be 0. It is 
+ * undefined elsewhere. 
+ */
+
+#  if !defined( VCOS_WANT_LOG_CMD )
+#     define  VCOS_WANT_LOG_CMD 1
+#  endif
+#else
+#  define VCOS_WANT_LOG_CMD   0
+#endif
+
+#if VCOS_WANT_LOG_CMD
+
+/*****************************************************************************
+*
+*   Does a vcos_assert(0), which is useful to test logging.
+*
+*****************************************************************************/
+
+VCOS_STATUS_T vcos_log_assert_cmd( VCOS_CMD_PARAM_T *param )
+{
+   (void)param;
+
+#if defined( NDEBUG ) && !defined( VCOS_RELEASE_ASSERTS )
+   vcos_log_error( "vcos_asserts have been compiled out" );
+   vcos_cmd_printf( param, "vcos_asserts have been compiled out - did a vcos_log_error instead\n" );
+#else
+   vcos_assert(0);
+   vcos_cmd_printf( param, "Executed vcos_assert(0)\n" );
+#endif
+
+   return VCOS_SUCCESS;
+}
+
+/*****************************************************************************
+*
+*   Sets a vcos logging level
+*
+*****************************************************************************/
+
+VCOS_STATUS_T vcos_log_set_cmd( VCOS_CMD_PARAM_T *param )
+{
+   VCOS_LOG_CAT_T   *cat;
+   char             *name;
+   char             *levelStr;
+   VCOS_LOG_LEVEL_T  level;
+   VCOS_STATUS_T     status;
+
+   if ( param->argc != 3 )
+   {
+      vcos_cmd_usage( param );
+      return VCOS_EINVAL;
+   }
+
+   name = param->argv[1];
+   levelStr = param->argv[2];
+
+   if ( vcos_string_to_log_level( levelStr, &level ) != VCOS_SUCCESS )
+   {
+      vcos_cmd_printf( param, "Unrecognized logging level: '%s'\n", levelStr );
+      return VCOS_EINVAL;
+   }
+
+   vcos_mutex_lock(&lock);
+
+   status = VCOS_SUCCESS;
+   for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
+   {
+      if ( vcos_strcmp( name, cat->name ) == 0 )
+      {
+         cat->level = level;
+         vcos_cmd_printf( param, "Category %s level set to %s\n", name, levelStr );
+         break;
+      }
+   }
+   if ( cat == NULL )
+   {
+      vcos_cmd_printf( param, "Unrecognized category: '%s'\n", name );
+      status = VCOS_ENOENT;
+   }
+
+   vcos_mutex_unlock(&lock);
+
+   return status;
+}
+
+/*****************************************************************************
+*
+*   Prints out the current settings for a given category (or all cvategories)
+*
+*****************************************************************************/
+
+VCOS_STATUS_T vcos_log_status_cmd( VCOS_CMD_PARAM_T *param )
+{
+   VCOS_LOG_CAT_T   *cat;
+   VCOS_STATUS_T     status;
+
+   vcos_mutex_lock(&lock);
+
+   if ( param->argc == 1)
+   {
+      int   nw;
+      int   nameWidth = 0;
+
+      /* Print information about all of the categories. */
+
+      for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
+      {
+         nw = (int)strlen( cat->name );
+
+         if ( nw > nameWidth )
+         {
+            nameWidth = nw;
+         }
+      }
+
+      for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
+      {
+         vcos_cmd_printf( param, "%-*s - %s\n", nameWidth, cat->name, vcos_log_level_to_string( cat->level ));
+      }
+   }
+   else
+   {
+      /* Print information about a particular category */
+
+      for ( cat = vcos_logging_categories; cat != NULL; cat = cat->next )
+      {
+         if ( vcos_strcmp( cat->name, param->argv[1] ) == 0 )
+         {
+            vcos_cmd_printf( param, "%s - %s\n", cat->name, vcos_log_level_to_string( cat->level ));
+            break;
+         }
+      }
+      if ( cat == NULL )
+      {
+         vcos_cmd_printf( param, "Unrecognized logging category: '%s'\n", param->argv[1] );
+         status = VCOS_ENOENT;
+         goto out;
+      }
+   }
+
+   status = VCOS_SUCCESS;
+out:
+   vcos_mutex_unlock(&lock);
+
+   return status;
+}
+
+/*****************************************************************************
+*
+*   Prints out the current settings for a given category (or all cvategories)
+*
+*****************************************************************************/
+
+VCOS_STATUS_T vcos_log_test_cmd( VCOS_CMD_PARAM_T *param )
+{
+   if ( param->argc == 1 )
+   {
+      static   int seq_num = 100;
+
+      /* No additional arguments - generate a message with an incrementing number */
+
+      vcos_log_error( "Test message %d", seq_num );
+
+      seq_num++;
+      vcos_cmd_printf( param, "Logged 'Test message %d'\n", seq_num );
+   }
+   else
+   {
+      int   arg_idx;
+
+      /* Arguments supplied - log these */
+
+      for ( arg_idx = 0; arg_idx < param->argc; arg_idx++ )
+      {
+         vcos_log_error( "argv[%d] = '%s'", arg_idx, param->argv[arg_idx] );
+      }
+      vcos_cmd_printf( param, "Logged %d line(s) of test data\n", param->argc );
+   }
+   return VCOS_SUCCESS;
+}
+
+/*****************************************************************************
+*
+*   Internal commands
+*
+*****************************************************************************/
+
+static VCOS_CMD_T log_cmd_entry[] =
+{
+    { "assert",   "",                  vcos_log_assert_cmd, NULL,    "Does a vcos_assert(0) to test logging" },
+    { "set",      "category level",    vcos_log_set_cmd,    NULL,    "Sets the vcos logging level for a category" },
+    { "status",   "[category]",        vcos_log_status_cmd, NULL,    "Prints the vcos log status for a (or all) categories" },
+    { "test",     "[arbitrary text]",  vcos_log_test_cmd,   NULL,    "Does a vcos_log to test logging" },
+
+    { NULL,       NULL,                NULL,                NULL,    NULL }
+};
+
+static VCOS_CMD_T cmd_log =
+    { "log",        "command [args]",  NULL,    log_cmd_entry, "Commands related to vcos logging" };
+
+#endif
+
+void vcos_logging_init(void)
+{
+   if (inited)
+   {
+      /* FIXME: should print a warning or something here */
+      return;
+   }
+   vcos_mutex_create(&lock, "vcos_log");
+
+   vcos_log_platform_init();
+
+   vcos_log_register("default", &dflt_log_category);
+
+#if VCOS_WANT_LOG_CMD
+   vcos_cmd_register( &cmd_log );
+#endif
+
+   vcos_assert(!inited);
+   inited = 1;
+}
+
+/** Read an alphanumeric token, returning True if we succeeded.
+  */
+
+static int read_tok(char *tok, size_t toklen, const char **pstr, char sep)
+{
+   const char *str = *pstr;
+   size_t n = 0;
+   char ch;
+
+   /* skip past any whitespace */
+   while (str[0] && isspace((int)(str[0])))
+      str++;
+
+   while ((ch = *str) != '\0' &&
+          ch != sep &&
+          (isalnum((int)ch) || (ch == '_')) &&
+          n != toklen-1)
+   {
+      tok[n++] = ch;
+      str++;
+   }
+
+   /* did it work out? */
+   if (ch == '\0' || ch == sep)
+   {
+      if (ch) str++; /* move to next token if not at end */
+      /* yes */
+      tok[n] = '\0';
+      *pstr = str;
+      return 1;
+   }
+   else
+   {
+      /* no */
+      return 0;
+   }
+}
+
+const char *vcos_log_level_to_string( VCOS_LOG_LEVEL_T level )
+{
+   switch (level)
+   {
+      case VCOS_LOG_UNINITIALIZED:  return "uninit";
+      case VCOS_LOG_NEVER:          return "never";
+      case VCOS_LOG_ERROR:          return "error";
+      case VCOS_LOG_WARN:           return "warn";
+      case VCOS_LOG_INFO:           return "info";
+      case VCOS_LOG_TRACE:          return "trace";
+   }
+   return "???";
+}
+
+VCOS_STATUS_T vcos_string_to_log_level( const char *str, VCOS_LOG_LEVEL_T *level )
+{
+   if (strcmp(str,"error") == 0)
+      *level = VCOS_LOG_ERROR;
+   else if (strcmp(str,"never") == 0)
+      *level = VCOS_LOG_NEVER;
+   else if (strcmp(str,"warn") == 0)
+      *level = VCOS_LOG_WARN;
+   else if (strcmp(str,"warning") == 0)
+      *level = VCOS_LOG_WARN;
+   else if (strcmp(str,"info") == 0)
+      *level = VCOS_LOG_INFO;
+   else if (strcmp(str,"trace") == 0)
+      *level = VCOS_LOG_TRACE;
+   else
+      return VCOS_EINVAL;
+
+   return VCOS_SUCCESS;
+}
+
+static int read_level(VCOS_LOG_LEVEL_T *level, const char **pstr, char sep)
+{
+   char buf[16];
+   int ret = 1;
+   if (read_tok(buf,sizeof(buf),pstr,sep))
+   {
+      if (vcos_string_to_log_level(buf,level) != VCOS_SUCCESS)
+      {
+         vcos_log("Invalid trace level '%s'\n", buf);
+         ret = 0;
+      }
+   }
+   else
+   {
+      ret = 0;
+   }
+   return ret;
+}
+
+void vcos_log_register(const char *name, VCOS_LOG_CAT_T *category)
+{
+   const char *env;
+   VCOS_LOG_CAT_T *i;
+
+   category->name  = name;
+   if ( category->level == VCOS_LOG_UNINITIALIZED )
+   {
+      category->level = VCOS_LOG_ERROR;
+   }
+   category->flags.want_prefix = (category != &dflt_log_category );
+
+   vcos_mutex_lock(&lock);
+
+   /* is it already registered? */
+   for (i = vcos_logging_categories; i ; i = i->next )
+   {
+      if (i == category)
+      {
+         i->refcount++;
+         break;
+      }
+   }
+
+   if (!i)
+   {
+      /* not yet registered */
+      category->next = vcos_logging_categories;
+      vcos_logging_categories = category;
+      category->refcount++;
+
+      vcos_log_platform_register(category);
+   }
+
+   vcos_mutex_unlock(&lock);
+
+   /* Check to see if this log level has been enabled. Look for
+    * (<category:level>,)*
+    *
+    * VC_LOGLEVEL=ilcs:info,vchiq:warn
+    */
+
+   env = _VCOS_LOG_LEVEL();
+   if (env)
+   {
+      do
+      {
+         char env_name[64];
+         VCOS_LOG_LEVEL_T level;
+         if (read_tok(env_name, sizeof(env_name), &env, ':') &&
+             read_level(&level, &env, ','))
+         {
+            if (strcmp(env_name, name) == 0)
+            {
+               category->level = level;
+               break;
+            }
+         }
+         else
+         {
+            if (!warned_loglevel)
+            {
+                vcos_log("VC_LOGLEVEL format invalid at %s\n", env);
+                warned_loglevel = 1;
+            }
+            return;
+         }
+      } while (env[0] != '\0');
+   }
+
+   vcos_log_info( "Registered log category '%s' with level %s",
+                  category->name,
+                  vcos_log_level_to_string( category->level ));
+}
+
+void vcos_log_unregister(VCOS_LOG_CAT_T *category)
+{
+   VCOS_LOG_CAT_T **pcat;
+
+   vcos_mutex_lock(&lock);
+   category->refcount--;
+   if (category->refcount == 0)
+   {
+      pcat = &vcos_logging_categories;
+      while (*pcat != category)
+      {
+         if (!*pcat)
+            break;   /* possibly deregistered twice? */
+         if ((*pcat)->next == NULL)
+         {
+            vcos_assert(0); /* already removed! */
+            vcos_mutex_unlock(&lock);
+            return;
+         }
+         pcat = &(*pcat)->next;
+      }
+      if (*pcat)
+         *pcat = category->next;
+
+      vcos_log_platform_unregister(category);
+   }
+   vcos_mutex_unlock(&lock);
+}
+
+VCOSPRE_ const VCOS_LOG_CAT_T * VCOSPOST_ vcos_log_get_default_category(void)
+{
+   return &dflt_log_category;
+}
+
+void vcos_set_log_options(const char *opt)
+{
+   (void)opt;
+}
+
+void vcos_log_dump_mem_impl( const VCOS_LOG_CAT_T *cat,
+                             const char           *label,
+                             uint32_t              addr,
+                             const void           *voidMem,
+                             size_t                numBytes )
+{
+   const uint8_t  *mem = (const uint8_t *)voidMem;
+   size_t          offset;
+   char            lineBuf[ 100 ];
+   char           *s;
+
+   while ( numBytes > 0 )
+   {
+       s = lineBuf;
+
+       for ( offset = 0; offset < 16; offset++ )
+       {
+           if ( offset < numBytes )
+           {
+               s += vcos_snprintf( s, 4, "%02x ", mem[ offset ]);
+           }
+           else
+           {
+               s += vcos_snprintf( s, 4, "   " );
+           }
+       }
+
+       for ( offset = 0; offset < 16; offset++ )
+       {
+           if ( offset < numBytes )
+           {
+               uint8_t ch = mem[ offset ];
+
+               if (( ch < ' ' ) || ( ch > '~' ))
+               {
+                   ch = '.';
+               }
+               *s++ = (char)ch;
+           }
+       }
+       *s++ = '\0';
+
+       if (( label != NULL ) && ( *label != '\0' ))
+       {
+          vcos_log_impl( cat, VCOS_LOG_INFO, "%s: %08" PRIx32 ": %s", label, addr, lineBuf );
+       }
+       else
+       {
+          vcos_log_impl( cat, VCOS_LOG_INFO, "%08" PRIx32 ": %s", addr, lineBuf );
+       }
+
+       addr += 16;
+       mem += 16;
+       if ( numBytes > 16 )
+       {
+           numBytes -= 16;
+       }
+       else
+       {
+           numBytes = 0;
+       }
+   }
+
+}
+
+void vcos_log_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, ...)
+{
+   va_list ap;
+   va_start(ap,fmt);
+   vcos_vlog_impl( cat, _level, fmt, ap );
+   va_end(ap);
+}
+
+void vcos_vlog_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args)
+{
+   vcos_vlog_impl_func( cat, _level, fmt, args );
+}
+
+void vcos_set_vlog_impl( VCOS_VLOG_IMPL_FUNC_T vlog_impl_func )
+{
+   if ( vlog_impl_func == NULL )
+   {
+      vcos_vlog_impl_func = vcos_vlog_default_impl;
+   }
+   else
+   {
+      vcos_vlog_impl_func = vlog_impl_func;
+   }
+}
+
diff --git a/interface/vcos/generic/vcos_mem_from_malloc.c b/interface/vcos/generic/vcos_mem_from_malloc.c
new file mode 100755 (executable)
index 0000000..02f9f28
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - memory alloc implementation
+=============================================================================*/
+
+#include "interface/vcos/vcos.h"
+
+#ifndef _vcos_platform_malloc
+#include <stdlib.h>
+#define _vcos_platform_malloc malloc
+#define _vcos_platform_free   free
+#endif
+
+typedef struct malloc_header_s {
+   uint32_t guardword;
+   uint32_t size;
+   const char *description;
+   void *ptr;
+} MALLOC_HEADER_T;
+
+
+#define MIN_ALIGN sizeof(MALLOC_HEADER_T)
+
+#define GUARDWORDHEAP  0xa55a5aa5
+
+void *vcos_generic_mem_alloc_aligned(VCOS_UNSIGNED size, VCOS_UNSIGNED align, const char *desc)
+{
+   int local_align = align == 0 ? 1 : align;
+   int required_size = size + local_align + sizeof(MALLOC_HEADER_T);
+   void *ptr = _vcos_platform_malloc(required_size);
+   void *ret = NULL;
+   MALLOC_HEADER_T *h;
+
+   if (ptr)
+   {
+      ret = (void *)VCOS_ALIGN_UP(((char *)ptr)+sizeof(MALLOC_HEADER_T), local_align);
+      h = ((MALLOC_HEADER_T *)ret)-1;
+      h->size = size;
+      h->description = desc;
+      h->guardword = GUARDWORDHEAP;
+      h->ptr = ptr;
+   }
+
+   return ret;
+}
+
+void *vcos_generic_mem_alloc(VCOS_UNSIGNED size, const char *desc)
+{
+   return vcos_generic_mem_alloc_aligned(size,MIN_ALIGN,desc);
+}
+
+void *vcos_generic_mem_calloc(VCOS_UNSIGNED count, VCOS_UNSIGNED sz, const char *desc)
+{
+   uint32_t size = count*sz;
+   void *ptr = vcos_generic_mem_alloc_aligned(size,MIN_ALIGN,desc);
+   if (ptr)
+   {
+      memset(ptr, 0, size);
+   }
+   return ptr;
+}
+
+void vcos_generic_mem_free(void *ptr)
+{
+   MALLOC_HEADER_T *h;
+   if (! ptr) return;
+
+   h = ((MALLOC_HEADER_T *)ptr)-1;
+   vcos_assert(h->guardword == GUARDWORDHEAP);
+   _vcos_platform_free(h->ptr);
+}
+
diff --git a/interface/vcos/generic/vcos_mem_from_malloc.h b/interface/vcos/generic/vcos_mem_from_malloc.h
new file mode 100755 (executable)
index 0000000..e0bd99d
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+Create the vcos_malloc API from the regular system malloc/free
+=============================================================================*/
+
+/**
+  * \file
+  *
+  * Create the vcos malloc API from a regular system malloc/free library.
+  *
+  * The API lets callers specify an alignment.
+  *
+  * Under VideoCore this is not needed, as we can simply use the rtos_malloc routines.
+  * But on host platforms that won't be the case.
+  *
+  */
+
+VCOSPRE_ void * VCOSPOST_  vcos_generic_mem_alloc(VCOS_UNSIGNED sz, const char *desc);
+VCOSPRE_  void * VCOSPOST_ vcos_generic_mem_calloc(VCOS_UNSIGNED count, VCOS_UNSIGNED sz, const char *descr);
+VCOSPRE_  void VCOSPOST_   vcos_generic_mem_free(void *ptr);
+VCOSPRE_  void * VCOSPOST_ vcos_generic_mem_alloc_aligned(VCOS_UNSIGNED sz, VCOS_UNSIGNED align, const char *desc);
+
+#ifdef VCOS_INLINE_BODIES
+
+VCOS_INLINE_IMPL
+void *vcos_malloc(VCOS_UNSIGNED size, const char *description) {
+   return vcos_generic_mem_alloc(size, description);
+}
+
+VCOS_INLINE_IMPL
+void *vcos_calloc(VCOS_UNSIGNED num, VCOS_UNSIGNED size, const char *description) {
+   return vcos_generic_mem_calloc(num, size, description);
+}
+
+VCOS_INLINE_IMPL
+void vcos_free(void *ptr) {
+   vcos_generic_mem_free(ptr);
+}
+
+VCOS_INLINE_IMPL
+void * vcos_malloc_aligned(VCOS_UNSIGNED size, VCOS_UNSIGNED align, const char *description) {
+   return vcos_generic_mem_alloc_aligned(size, align, description);
+}
+
+/* Returns invalid result, do not use */
+
+VCOS_INLINE_IMPL
+unsigned long VCOS_DEPRECATED("returns invalid result") vcos_get_free_mem(void) {
+   return 0;
+}
+
+#endif /* VCOS_INLINE_BODIES */
+
+
diff --git a/interface/vcos/generic/vcos_msgqueue.c b/interface/vcos/generic/vcos_msgqueue.c
new file mode 100755 (executable)
index 0000000..b8e558b
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "vcos.h"
+#include "vcos_msgqueue.h"
+#include <stddef.h>
+#include <string.h>
+#include <stdio.h>
+
+#define MAGIC VCOS_MSGQ_MAGIC
+
+/* Probably a good idea for MSG_T to be multiple of 8 so that doubles
+ * are naturally aligned without problem.
+ */
+vcos_static_assert((sizeof(VCOS_MSG_T) & 7) == 0);
+
+static void vcos_msgq_pool_on_reply(VCOS_MSG_WAITER_T *waiter,
+                                    VCOS_MSG_T *msg);
+static void vcos_msgq_queue_waiter_on_reply(VCOS_MSG_WAITER_T *waiter,
+                                    VCOS_MSG_T *msg);
+
+/** Simple reply protocol. The client creates a semaphore and waits
+ * for it. No queuing of multiple replies is possible but nothing needs
+ * to be setup in advance. Because creating semaphores is very fast on
+ * VideoCore there's no need to do anything elaborate to optimize create
+ * time - this might need revisiting on other platforms.
+ */
+
+typedef struct
+{
+   VCOS_MSG_WAITER_T waiter;
+   VCOS_SEMAPHORE_T waitsem;
+} VCOS_MSG_SIMPLE_WAITER_T;
+
+static void vcos_msgq_simple_waiter_on_reply(VCOS_MSG_WAITER_T *waiter,
+                                             VCOS_MSG_T *msg)
+{
+   VCOS_MSG_SIMPLE_WAITER_T *self;
+   (void)msg;
+   self = (VCOS_MSG_SIMPLE_WAITER_T*)waiter;
+   vcos_semaphore_post(&self->waitsem);
+}
+
+static VCOS_STATUS_T vcos_msgq_simple_waiter_init(VCOS_MSG_SIMPLE_WAITER_T *waiter)
+{
+   VCOS_STATUS_T status;
+   status = vcos_semaphore_create(&waiter->waitsem, "waiter", 0);
+   waiter->waiter.on_reply = vcos_msgq_simple_waiter_on_reply;
+   return status;
+}
+
+static void vcos_msgq_simple_waiter_deinit(VCOS_MSG_SIMPLE_WAITER_T *waiter)
+{
+   vcos_semaphore_delete(&waiter->waitsem);
+}
+
+/*
+ * Message queues
+ */
+
+static VCOS_STATUS_T vcos_msgq_create_internal(VCOS_MSGQUEUE_T *q, const char *name)
+{
+   VCOS_STATUS_T st;
+
+   memset(q, 0, sizeof(*q));
+
+   q->waiter.on_reply = vcos_msgq_queue_waiter_on_reply;
+   st = vcos_semaphore_create(&q->sem, name, 0);
+   if (st != VCOS_SUCCESS)
+      goto fail_sem;
+
+   st = vcos_mutex_create(&q->lock, name);
+   if (st != VCOS_SUCCESS)
+      goto fail_mtx;
+
+   return st;
+
+fail_mtx:
+   vcos_semaphore_delete(&q->sem);
+fail_sem:
+   return st;
+}
+
+static void vcos_msgq_delete_internal(VCOS_MSGQUEUE_T *q)
+{
+   vcos_semaphore_delete(&q->sem);
+   vcos_mutex_delete(&q->lock);
+}
+
+VCOS_STATUS_T vcos_msgq_create(VCOS_MSGQUEUE_T *q, const char *name)
+{
+   VCOS_STATUS_T st;
+
+   st = vcos_msgq_create_internal(q, name);
+
+   return st;
+}
+
+void vcos_msgq_delete(VCOS_MSGQUEUE_T *q)
+{
+   vcos_msgq_delete_internal(q);
+}
+
+/* append a message to a message queue */
+static _VCOS_INLINE void msgq_append(VCOS_MSGQUEUE_T *q, VCOS_MSG_T *msg)
+{
+   vcos_mutex_lock(&q->lock);
+   if (q->head == NULL)
+   {
+      q->head = q->tail = msg;
+   }
+   else
+   {
+      q->tail->next = msg;
+      q->tail = msg;
+   }
+   vcos_mutex_unlock(&q->lock);
+}
+
+/*
+ * A waiter for a message queue. Just appends the message to the
+ * queue, waking up the waiting thread.
+ */
+static void vcos_msgq_queue_waiter_on_reply(VCOS_MSG_WAITER_T *waiter,
+                                            VCOS_MSG_T *msg)
+{
+   VCOS_MSGQUEUE_T *queue = (VCOS_MSGQUEUE_T*)waiter;
+   msgq_append(queue, msg);
+   vcos_semaphore_post(&queue->sem);
+}
+
+/* initialise this library */
+
+VCOS_STATUS_T vcos_msgq_init(void)
+{
+   return VCOS_SUCCESS;
+}
+
+void vcos_msgq_deinit(void)
+{
+}
+
+static _VCOS_INLINE
+void vcos_msg_send_helper(VCOS_MSG_WAITER_T *waiter,
+                          VCOS_MSGQUEUE_T *dest,
+                          uint32_t code,
+                          VCOS_MSG_T *msg)
+{
+   vcos_assert(msg);
+   vcos_assert(dest);
+
+   msg->code = code;
+   if (waiter)
+      msg->waiter = waiter;
+   msg->next = NULL;
+   msg->src_thread = vcos_thread_current();
+
+   msgq_append(dest, msg);
+   vcos_semaphore_post(&dest->sem);
+}
+
+/* wait on a queue for a message */
+VCOS_MSG_T *vcos_msg_wait(VCOS_MSGQUEUE_T *queue)
+{
+   VCOS_MSG_T *msg;
+   vcos_semaphore_wait(&queue->sem);
+   vcos_mutex_lock(&queue->lock);
+
+   msg = queue->head;
+   vcos_assert(msg);    /* should always be a message here! */
+
+   queue->head = msg->next;
+   if (queue->head == NULL)
+      queue->tail = NULL;
+
+   vcos_mutex_unlock(&queue->lock);
+   return msg;
+}
+
+/* peek on a queue for a message */
+VCOS_MSG_T *vcos_msg_peek(VCOS_MSGQUEUE_T *queue)
+{
+   VCOS_MSG_T *msg;
+   vcos_mutex_lock(&queue->lock);
+
+   msg = queue->head;
+
+   /* if there's a message, remove it from the queue */
+   if (msg)
+   {
+      queue->head = msg->next;
+      if (queue->head == NULL)
+         queue->tail = NULL;
+
+      /* keep the semaphore count consistent */
+
+      /* coverity[lock_order]
+       * the semaphore must have a non-zero count so cannot block here.
+       */
+      vcos_semaphore_wait(&queue->sem);
+   }
+
+   vcos_mutex_unlock(&queue->lock);
+   return msg;
+}
+
+void vcos_msg_send(VCOS_MSGQUEUE_T *dest, uint32_t code, VCOS_MSG_T *msg)
+{
+   vcos_assert(msg->magic == MAGIC);
+   vcos_msg_send_helper(NULL, dest, code, msg);
+}
+
+/** Send on to the target queue, then wait on a simple waiter for the reply
+ */
+VCOS_STATUS_T vcos_msg_sendwait(VCOS_MSGQUEUE_T *dest, uint32_t code, VCOS_MSG_T *msg)
+{
+   VCOS_STATUS_T st;
+   VCOS_MSG_SIMPLE_WAITER_T waiter;
+
+   vcos_assert(msg->magic == MAGIC);
+
+   /* if this fires, you've set a waiter up but are now about to obliterate it
+    * with the 'wait for a reply' waiter.
+    */
+   vcos_assert(msg->waiter == NULL);
+
+   if ((st=vcos_msgq_simple_waiter_init(&waiter)) != VCOS_SUCCESS)
+      return st;
+
+   vcos_msg_send_helper(&waiter.waiter, dest, code, msg);
+   vcos_semaphore_wait(&waiter.waitsem);
+   vcos_msgq_simple_waiter_deinit(&waiter);
+
+   return VCOS_SUCCESS;
+}
+
+/** Send a reply to a message
+  */
+void vcos_msg_reply(VCOS_MSG_T *msg)
+{
+   vcos_assert(msg->magic == MAGIC);
+   msg->code |= MSG_REPLY_BIT;
+   if (msg->waiter)
+   {
+      msg->waiter->on_reply(msg->waiter, msg);
+   }
+   else
+   {
+      VCOS_ALERT("%s: reply to non-reply message id %d",
+                 VCOS_FUNCTION,
+                 msg->code);
+      vcos_assert(0);
+   }
+}
+
+void vcos_msg_set_source(VCOS_MSG_T *msg, VCOS_MSGQUEUE_T *queue)
+{
+   vcos_assert(msg);
+   vcos_assert(msg->magic == MAGIC);
+   vcos_assert(queue);
+   msg->waiter = &queue->waiter;
+}
+
+/*
+ * Message pools
+ */
+
+VCOS_STATUS_T vcos_msgq_pool_create(VCOS_MSGQ_POOL_T *pool,
+                                    size_t count,
+                                    size_t payload_size,
+                                    const char *name)
+{
+   VCOS_STATUS_T status;
+   int bp_size = payload_size + sizeof(VCOS_MSG_T);
+   status = vcos_blockpool_create_on_heap(&pool->blockpool,
+                                          count, bp_size,
+                                          VCOS_BLOCKPOOL_ALIGN_DEFAULT,
+                                          0,
+                                          name);
+   if (status != VCOS_SUCCESS)
+      goto fail_pool;
+
+   status = vcos_semaphore_create(&pool->sem, name, count);
+   if (status != VCOS_SUCCESS)
+      goto fail_sem;
+
+   pool->waiter.on_reply = vcos_msgq_pool_on_reply;
+   pool->magic = MAGIC;
+   return status;
+
+fail_sem:
+   vcos_blockpool_delete(&pool->blockpool);
+fail_pool:
+   return status;
+}
+
+void vcos_msgq_pool_delete(VCOS_MSGQ_POOL_T *pool)
+{
+   vcos_blockpool_delete(&pool->blockpool);
+   vcos_semaphore_delete(&pool->sem);
+}
+
+/** Called when a message from a pool is replied-to. Just returns
+ * the message back to the blockpool.
+ */
+static void vcos_msgq_pool_on_reply(VCOS_MSG_WAITER_T *waiter,
+                                    VCOS_MSG_T *msg)
+{
+   vcos_unused(waiter);
+   vcos_assert(msg->magic == MAGIC);
+   vcos_msgq_pool_free(msg);
+}
+
+VCOS_MSG_T *vcos_msgq_pool_alloc(VCOS_MSGQ_POOL_T *pool)
+{
+   VCOS_MSG_T *msg;
+   if (vcos_semaphore_trywait(&pool->sem) == VCOS_SUCCESS)
+   {
+      msg = vcos_blockpool_calloc(&pool->blockpool);
+      vcos_assert(msg);
+      msg->magic = MAGIC;
+      msg->waiter = &pool->waiter;
+      msg->pool = pool;
+   }
+   else
+   {
+      msg = NULL;
+   }
+   return msg;
+}
+
+void vcos_msgq_pool_free(VCOS_MSG_T *msg)
+{
+   if (msg)
+   {
+      VCOS_MSGQ_POOL_T *pool;
+      vcos_assert(msg->pool);
+
+      pool = msg->pool;
+      vcos_assert(msg->pool->magic == MAGIC);
+
+      vcos_blockpool_free(msg);
+      vcos_semaphore_post(&pool->sem);
+   }
+}
+
+VCOS_MSG_T *vcos_msgq_pool_wait(VCOS_MSGQ_POOL_T *pool)
+{
+   VCOS_MSG_T *msg;
+   vcos_semaphore_wait(&pool->sem);
+   msg = vcos_blockpool_calloc(&pool->blockpool);
+   vcos_assert(msg);
+   msg->magic = MAGIC;
+   msg->waiter = &pool->waiter;
+   msg->pool = pool;
+   return msg;
+}
+
+void vcos_msg_init(VCOS_MSG_T *msg)
+{
+   msg->magic = MAGIC;
+   msg->next = NULL;
+   msg->waiter = NULL;
+   msg->pool = NULL;
+}
diff --git a/interface/vcos/generic/vcos_mutexes_are_reentrant.h b/interface/vcos/generic/vcos_mutexes_are_reentrant.h
new file mode 100755 (executable)
index 0000000..976b61a
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - reentrant mutexes mapped directly to regular ones
+=============================================================================*/
+
+#ifndef VCOS_GENERIC_REENTRANT_MUTEX_H
+#define VCOS_GENERIC_REENTRANT_MUTEX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#include "interface/vcos/vcos_mutex.h"
+
+/**
+ * \file
+ *
+ * Reentrant Mutexes directly using the native re-entrant mutex.
+ *
+ */
+
+typedef VCOS_MUTEX_T VCOS_REENTRANT_MUTEX_T;
+
+/* Inline forwarding functions */
+
+#if defined(VCOS_INLINE_BODIES)
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_reentrant_mutex_create(VCOS_REENTRANT_MUTEX_T *m, const char *name) {
+   return vcos_mutex_create(m,name);
+}
+
+VCOS_INLINE_IMPL
+void vcos_reentrant_mutex_delete(VCOS_REENTRANT_MUTEX_T *m) {
+   vcos_mutex_delete(m);
+}
+
+VCOS_INLINE_IMPL
+void vcos_reentrant_mutex_lock(VCOS_REENTRANT_MUTEX_T *m) {
+   vcos_mutex_lock(m);
+}
+
+VCOS_INLINE_IMPL
+void vcos_reentrant_mutex_unlock(VCOS_REENTRANT_MUTEX_T *m) {
+   vcos_mutex_unlock(m);
+}
+
+VCOS_INLINE_IMPL
+int vcos_reentrant_mutex_is_locked(VCOS_REENTRANT_MUTEX_T *m) {
+   return vcos_mutex_is_locked(m);
+}
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+
+
diff --git a/interface/vcos/generic/vcos_thread_reaper.h b/interface/vcos/generic/vcos_thread_reaper.h
new file mode 100755 (executable)
index 0000000..4190dba
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - thread reaping
+=============================================================================*/
+
+#ifndef VCOS_THREAD_REAPER_H
+#define VCOS_THREAD_REAPER_H
+
+#define VCOS_HAVE_THREAD_REAPER
+
+/** Initialise the thread reaper.
+  */
+VCOS_STATUS_T vcos_thread_reaper_init(void);
+
+/** Reap a thread. Arranges for the thread to be automatically
+  * joined.
+  *
+  * @sa vcos_thread_join().
+  *
+  * @param thread           the thread to terminate
+  * @param on_terminated    called after the thread has exited
+  * @param cxt              pass back to the callback
+  *
+  */
+void vcos_thread_reap(VCOS_THREAD_T *thread, void (*on_terminated)(void*), void *cxt);
+
+#endif
+
+
diff --git a/interface/vcos/glibc/vcos_backtrace.c b/interface/vcos/glibc/vcos_backtrace.c
new file mode 100755 (executable)
index 0000000..3bb8aa3
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <interface/vcos/vcos.h>
+#ifdef HAVE_CMAKE_CONFIG
+#include "cmake_config.h"
+#endif
+#ifdef HAVE_EXECINFO_H
+#include <execinfo.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+
+void vcos_backtrace_self(void)
+{
+#ifdef HAVE_EXECINFO_H
+   void *stack[64];
+   int depth = backtrace(stack, sizeof(stack)/sizeof(stack[0]));
+   char **names = backtrace_symbols(stack, depth);
+   int i;
+   if (names)
+   {
+      for (i=0; i<depth; i++)
+      {
+         printf("%s\n", names[i]);
+      }
+      free(names);
+   }
+#endif
+}
+
diff --git a/interface/vcos/pthreads/CMakeLists.txt b/interface/vcos/pthreads/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..1d81ca3
--- /dev/null
@@ -0,0 +1,46 @@
+# MSVC5 does not fully support C99, enabling declaration-after-statement
+# warnings allows a common MSVC5 build error to be detected in Linux builds.
+if (CMAKE_COMPILER_IS_GNUCC)
+   set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Werror -Wdeclaration-after-statement")
+   add_definitions (-D_GNU_SOURCE)
+endif ()
+
+set (HEADERS
+   vcos_platform.h
+   vcos_platform_types.h
+)
+
+foreach (header ${HEADERS})
+   configure_file ("${header}" "${VCOS_HEADERS_BUILD_DIR}/${header}" COPYONLY)
+endforeach ()
+
+add_subdirectory (../generic generic)
+
+set (SOURCES
+   vcos_pthreads.c
+   vcos_dlfcn.c
+   ../glibc/vcos_backtrace.c
+   ../generic/vcos_generic_event_flags.c
+   ../generic/vcos_mem_from_malloc.c
+   ../generic/vcos_generic_named_sem.c
+   ../generic/vcos_generic_safe_string.c
+   ../generic/vcos_generic_reentrant_mtx.c
+   ../generic/vcos_abort.c
+   ../generic/vcos_cmd.c
+   ../generic/vcos_init.c
+   ../generic/vcos_msgqueue.c
+   ../generic/vcos_logcat.c
+   ../generic/vcos_generic_blockpool.c
+)
+
+if (VCOS_PTHREADS_BUILD_SHARED)
+   add_library (vcos SHARED ${SOURCES})
+   target_link_libraries (vcos pthread dl rt)
+else ()
+   add_library (vcos ${SOURCES})
+   target_link_libraries (vcos pthread rt)
+endif ()
+
+
+#install(FILES ${HEADERS} DESTINATION include)
+install(TARGETS vcos DESTINATION lib)
diff --git a/interface/vcos/pthreads/vcos_dlfcn.c b/interface/vcos/pthreads/vcos_dlfcn.c
new file mode 100755 (executable)
index 0000000..85d18c6
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/vcos/vcos.h"
+#include "interface/vcos/vcos_dlfcn.h"
+
+#include <dlfcn.h>
+
+void *vcos_dlopen(const char *name, int mode)
+{
+   return dlopen(name, mode);
+}
+
+void (*vcos_dlsym(void *handle, const char *name))(void)
+{
+   return dlsym(handle, name);
+}
+
+int vcos_dlclose (void *handle)
+{
+   return dlclose(handle);
+}
+
+int vcos_dlerror(int *err, char *buf, size_t buflen)
+{
+   /* not really threadsafe! */
+   const char *errmsg = dlerror();
+
+   vcos_assert(buflen > 0);
+
+   if (errmsg)
+   {
+      *err = -1;
+      strncpy(buf, errmsg, buflen);
+      buf[buflen-1] = '\0';
+   }
+   else
+   {
+      *err = 0;
+      buf[0] = '\0';
+   }
+   return 0;
+}
+
+
+
+
diff --git a/interface/vcos/pthreads/vcos_futex_mutex.h b/interface/vcos/pthreads/vcos_futex_mutex.h
new file mode 100755 (executable)
index 0000000..3c44720
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+FIXME: This code should be moved to 'linux', it is linux-specific and not generic
+on 'pthreads'.
+============================================================================*/
+
+#ifndef VCOS_MUTEX_FROM_FUTEX_H
+#define VCOS_MUTEX_FROM_FUTEX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#include "vcos_platform.h"
+
+typedef struct VCOS_FUTEX_T
+{
+   volatile int value;
+} VCOS_FUTEX_T;
+
+typedef VCOS_FUTEX_T VCOS_MUTEX_T;
+
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_futex_init(VCOS_FUTEX_T *futex);
+VCOSPRE_ void VCOSPOST_ vcos_futex_delete(VCOS_FUTEX_T *futex);
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_futex_lock(VCOS_FUTEX_T *futex);
+VCOSPRE_ void VCOSPOST_ vcos_futex_unlock(VCOS_FUTEX_T *futex);
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_futex_trylock(VCOS_FUTEX_T *futex);
+
+#if defined(VCOS_INLINE_BODIES)
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_mutex_create(VCOS_MUTEX_T *latch, const char *name) {
+   vcos_unused(name);
+   return vcos_futex_init(latch);
+}
+
+VCOS_INLINE_IMPL
+void vcos_mutex_delete(VCOS_MUTEX_T *latch) {
+   vcos_futex_delete(latch);
+}
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_mutex_lock(VCOS_MUTEX_T *latch) {
+   return vcos_futex_lock(latch);
+}
+
+VCOS_INLINE_IMPL
+void vcos_mutex_unlock(VCOS_MUTEX_T *latch) {
+   vcos_futex_unlock(latch);
+}
+
+VCOS_INLINE_IMPL
+int vcos_mutex_is_locked(VCOS_MUTEX_T *latch) {
+   int rc = latch->value;
+   if (!rc) {
+      /* it wasn't locked */
+      return 0;
+   }
+   else {
+      return 1; /* it was locked */
+   }
+}
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_mutex_trylock(VCOS_MUTEX_T *m) {
+   return vcos_futex_trylock(m);
+}
+
+#endif /* VCOS_INLINE_BODIES */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* VCOS_MUTEX_FROM_FUTEX_H */
+
diff --git a/interface/vcos/pthreads/vcos_platform.h b/interface/vcos/pthreads/vcos_platform.h
new file mode 100755 (executable)
index 0000000..ba64e16
--- /dev/null
@@ -0,0 +1,828 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - pthreads types
+=============================================================================*/
+
+/* DO NOT include this file directly - instead include it via vcos.h */
+
+/** @file
+  *
+  * Pthreads implementation of VCOS.
+  *
+  */
+
+#ifndef VCOS_PLATFORM_H
+#define VCOS_PLATFORM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <pthread.h>
+#include <semaphore.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sched.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <strings.h>
+#include <time.h>
+#include <signal.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+
+
+#define VCOS_HAVE_RTOS         1
+#define VCOS_HAVE_SEMAPHORE    1
+#define VCOS_HAVE_EVENT        1
+#define VCOS_HAVE_QUEUE        0
+#define VCOS_HAVE_LEGACY_ISR   0
+#define VCOS_HAVE_TIMER        1
+#define VCOS_HAVE_CANCELLATION_SAFE_TIMER 1
+#define VCOS_HAVE_MEMPOOL      0
+#define VCOS_HAVE_ISR          0
+#define VCOS_HAVE_ATOMIC_FLAGS 1
+#define VCOS_HAVE_THREAD_AT_EXIT        1
+#define VCOS_HAVE_ONCE         1
+#define VCOS_HAVE_BLOCK_POOL   1
+#define VCOS_HAVE_FILE         0
+#define VCOS_HAVE_PROC         0
+#define VCOS_HAVE_CFG          0
+#define VCOS_HAVE_ALIEN_THREADS  1
+#define VCOS_HAVE_CMD          1
+#define VCOS_HAVE_EVENT_FLAGS  1
+#define VCOS_WANT_LOG_CMD      0    /* User apps should do their own thing */
+
+#define VCOS_ALWAYS_WANT_LOGGING
+
+#ifdef __linux__
+#define VCOS_HAVE_BACKTRACE    1
+#endif
+
+#define VCOS_SO_EXT  ".so"
+
+/* Linux/pthreads seems to have different timer characteristics */
+#define VCOS_TIMER_MARGIN_EARLY 0
+#define VCOS_TIMER_MARGIN_LATE 15
+
+typedef sem_t                 VCOS_SEMAPHORE_T;
+typedef uint32_t              VCOS_UNSIGNED;
+typedef uint32_t              VCOS_OPTION;
+typedef pthread_key_t         VCOS_TLS_KEY_T;
+typedef pthread_once_t        VCOS_ONCE_T;
+
+typedef struct VCOS_LLTHREAD_T
+{
+   pthread_t thread; // Must be first field.
+} VCOS_LLTHREAD_T;
+
+/* VCOS_CASSERT(offsetof(VCOS_LLTHREAD_T, thread) == 0); */
+
+#ifndef VCOS_USE_VCOS_FUTEX
+typedef pthread_mutex_t       VCOS_MUTEX_T;
+#else
+#include "vcos_futex_mutex.h"
+#endif /* VCOS_USE_VCOS_FUTEX */
+
+typedef struct
+{
+   VCOS_MUTEX_T   mutex;
+   sem_t          sem;
+} VCOS_EVENT_T;
+
+#define VCOS_ONCE_INIT        PTHREAD_ONCE_INIT
+
+typedef struct VCOS_TIMER_T
+{
+   pthread_t thread;                      /**< id of the timer thread */
+
+   pthread_mutex_t lock;                  /**< lock protecting all other members of the struct */
+   pthread_cond_t settings_changed;       /**< cond. var. for informing the timer thread about changes*/
+   int quit;                              /**< non-zero if the timer thread is requested to quit*/
+
+   struct timespec expires;               /**< absolute time of next expiration, or 0 if disarmed*/
+
+   void (*orig_expiration_routine)(void*);/**< the expiration routine provided by the user of the timer*/
+   void *orig_context;                    /**< the context for exp. routine provided by the user*/
+
+} VCOS_TIMER_T;
+
+/** Thread attribute structure. Don't use pthread_attr directly, as
+  * the calls can fail, and inits must match deletes.
+  */
+typedef struct VCOS_THREAD_ATTR_T
+{
+   void *ta_stackaddr;
+   VCOS_UNSIGNED ta_stacksz;
+   VCOS_UNSIGNED ta_priority;
+   VCOS_UNSIGNED ta_affinity;
+   VCOS_UNSIGNED ta_timeslice;
+   VCOS_UNSIGNED legacy;
+} VCOS_THREAD_ATTR_T;
+
+/** Called at thread exit.
+  */
+typedef struct VCOS_THREAD_EXIT_T
+{
+   void (*pfn)(void *);
+   void *cxt;
+} VCOS_THREAD_EXIT_T;
+#define VCOS_MAX_EXIT_HANDLERS  4
+
+typedef struct VCOS_THREAD_T
+{
+   pthread_t thread;             /**< The thread itself */
+   VCOS_THREAD_ENTRY_FN_T entry; /**< The thread entry point */
+   void *arg;                    /**< The argument to be passed to entry */
+   VCOS_SEMAPHORE_T suspend;     /**< For support event groups and similar - a per thread semaphore */
+
+   VCOS_TIMER_T task_timer;
+   int task_timer_created;       /**< non-zero if the task timer has already been created*/
+   void (*orig_task_timer_expiration_routine)(void*);
+   void *orig_task_timer_context;
+
+   VCOS_UNSIGNED legacy;
+   char name[16];                /**< Record the name of this thread, for diagnostics */
+   VCOS_UNSIGNED dummy;          /**< Dummy thread created for non-vcos created threads */
+
+   /** Callback invoked at thread exit time */
+   VCOS_THREAD_EXIT_T at_exit[VCOS_MAX_EXIT_HANDLERS];
+} VCOS_THREAD_T;
+
+#ifdef VCOS_PTHREADS_WANT_HISR_EMULATION
+
+typedef struct
+{
+   VCOS_THREAD_T thread;
+   char stack[1024];
+   VCOS_SEMAPHORE_T waitsem;
+} VCOS_HISR_T;
+
+#endif
+
+#define VCOS_SUSPEND          -1
+#define VCOS_NO_SUSPEND       0
+
+#define VCOS_START 1
+#define VCOS_NO_START 0
+
+#define VCOS_THREAD_PRI_MIN   (sched_get_priority_min(SCHED_OTHER))
+#define VCOS_THREAD_PRI_MAX   (sched_get_priority_max(SCHED_OTHER))
+
+#define VCOS_THREAD_PRI_INCREASE (1)
+#define VCOS_THREAD_PRI_HIGHEST  VCOS_THREAD_PRI_MAX
+#define VCOS_THREAD_PRI_LOWEST   VCOS_THREAD_PRI_MIN
+#define VCOS_THREAD_PRI_NORMAL ((VCOS_THREAD_PRI_MAX+VCOS_THREAD_PRI_MIN)/2)
+#define VCOS_THREAD_PRI_BELOW_NORMAL (VCOS_THREAD_PRI_NORMAL-VCOS_THREAD_PRI_INCREASE)
+#define VCOS_THREAD_PRI_ABOVE_NORMAL (VCOS_THREAD_PRI_NORMAL+VCOS_THREAD_PRI_INCREASE)
+#define VCOS_THREAD_PRI_REALTIME VCOS_THREAD_PRI_MAX
+
+#define _VCOS_AFFINITY_DEFAULT 0
+#define _VCOS_AFFINITY_CPU0    0x100
+#define _VCOS_AFFINITY_CPU1    0x200
+#define _VCOS_AFFINITY_MASK    0x300
+#define VCOS_CAN_SET_STACK_ADDR  0
+
+#define VCOS_TICKS_PER_SECOND _vcos_get_ticks_per_second()
+
+#include "interface/vcos/generic/vcos_generic_event_flags.h"
+#include "interface/vcos/generic/vcos_generic_blockpool.h"
+#include "interface/vcos/generic/vcos_mem_from_malloc.h"
+
+/** Convert errno values into the values recognized by vcos */
+VCOSPRE_ VCOS_STATUS_T vcos_pthreads_map_error(int error);
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_pthreads_map_errno(void);
+
+/** Register a function to be called when the current thread exits.
+  */
+extern VCOS_STATUS_T vcos_thread_at_exit(void (*pfn)(void*), void *cxt);
+
+extern uint32_t _vcos_get_ticks_per_second(void);
+
+/**
+ * Set to 1 by default when ANDROID is defined. Allows runtime
+ * switching for console apps.
+ */
+extern int vcos_use_android_log;
+
+typedef struct {
+   VCOS_MUTEX_T mutex;
+   uint32_t flags;
+} VCOS_ATOMIC_FLAGS_T;
+
+#if defined(VCOS_INLINE_BODIES)
+
+#undef VCOS_ASSERT_LOGGING_DISABLE
+#define VCOS_ASSERT_LOGGING_DISABLE 1
+
+
+/*
+ * Counted Semaphores
+ */
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_semaphore_wait(VCOS_SEMAPHORE_T *sem) {
+   int ret;
+   /* gdb causes sem_wait() to EINTR when a breakpoint is hit, retry here */
+   while ((ret = sem_wait(sem)) == -1 && errno == EINTR)
+      continue;
+   vcos_assert(ret==0);
+   return VCOS_SUCCESS;
+}
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_semaphore_trywait(VCOS_SEMAPHORE_T *sem) {
+   int ret;
+   while ((ret = sem_trywait(sem)) == -1 && errno == EINTR)
+      continue;
+   if (ret == 0)
+      return VCOS_SUCCESS;
+   else if (errno == EAGAIN)
+      return VCOS_EAGAIN;
+   else {
+      vcos_assert(0);
+      return VCOS_EINVAL;
+   }
+}
+
+/**
+  * \brief Wait on a semaphore with a timeout.
+  *
+  * Note that this function may not be implemented on all
+  * platforms, and may not be efficient on all platforms
+  * (see comment in vcos_semaphore_wait)
+  *
+  * Try to obtain the semaphore. If it is already taken, return
+  * VCOS_EAGAIN.
+  * @param sem Semaphore to wait on
+  * @param timeout Number of milliseconds to wait before
+  *                returning if the semaphore can't be acquired.
+  * @return VCOS_SUCCESS - semaphore was taken.
+  *         VCOS_EAGAIN - could not take semaphore (i.e. timeout
+  *         expired)
+  *         VCOS_EINVAL - Some other error (most likely bad
+  *         parameters).
+  */
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_semaphore_wait_timeout(VCOS_SEMAPHORE_T *sem, VCOS_UNSIGNED timeout) {
+   struct timespec ts;
+   int ret;
+   if (clock_gettime(CLOCK_REALTIME, &ts) == -1)
+      return VCOS_EINVAL;
+   ts.tv_sec  += timeout/1000;
+   ts.tv_nsec += (timeout%1000)*1000*1000;
+   if (ts.tv_nsec > 1000000000) {
+      ts.tv_sec++;
+      ts.tv_nsec -= 1000000000;
+   }
+
+   while (1) {
+      ret = sem_timedwait( sem, &ts );
+      if (ret == 0) {
+         return VCOS_SUCCESS;
+      } else {
+         if (errno == EINTR) {
+            continue;
+         } else if (errno == ETIMEDOUT) {
+            return VCOS_EAGAIN;
+         } else {
+            vcos_assert(0);
+            return VCOS_EINVAL;
+         }
+      }
+   }
+}
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_semaphore_create(VCOS_SEMAPHORE_T *sem,
+                                    const char *name,
+                                    VCOS_UNSIGNED initial_count) {
+   int rc = sem_init(sem, 0, initial_count);
+   (void)name;
+   if (rc != -1) return VCOS_SUCCESS;
+   else return vcos_pthreads_map_errno();
+}
+
+VCOS_INLINE_IMPL
+void vcos_semaphore_delete(VCOS_SEMAPHORE_T *sem) {
+   int rc = sem_destroy(sem);
+   vcos_assert(rc != -1);
+   (void)rc;
+}
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_semaphore_post(VCOS_SEMAPHORE_T *sem) {
+   int rc = sem_post(sem);
+   vcos_assert(rc == 0);
+   (void)rc;
+   return VCOS_SUCCESS;
+}
+
+/***********************************************************
+ *
+ * Threads
+ *
+ ***********************************************************/
+
+
+extern VCOS_THREAD_T *vcos_dummy_thread_create(void);
+extern pthread_key_t _vcos_thread_current_key;
+extern uint64_t vcos_getmicrosecs64_internal(void);
+
+VCOS_INLINE_IMPL
+uint32_t vcos_getmicrosecs(void) { return (uint32_t)vcos_getmicrosecs64_internal(); }
+
+VCOS_INLINE_IMPL
+uint64_t vcos_getmicrosecs64(void) { return vcos_getmicrosecs64_internal(); }
+
+VCOS_INLINE_IMPL
+VCOS_THREAD_T *vcos_thread_current(void) {
+   void *ret = pthread_getspecific(_vcos_thread_current_key);
+   if (ret == NULL)
+   {
+      ret = vcos_dummy_thread_create();
+   }
+
+#ifdef __cplusplus
+   return static_cast<VCOS_THREAD_T*>(ret);
+#else
+   return (VCOS_THREAD_T *)ret;
+#endif
+}
+
+VCOS_INLINE_IMPL
+void vcos_sleep(uint32_t ms) {
+   struct timespec ts;
+   ts.tv_sec = ms/1000;
+   ts.tv_nsec = ms % 1000 * (1000000);
+   nanosleep(&ts, NULL);
+}
+
+VCOS_INLINE_IMPL
+void vcos_thread_attr_setstack(VCOS_THREAD_ATTR_T *attr, void *addr, VCOS_UNSIGNED sz) {
+   attr->ta_stackaddr = addr;
+   attr->ta_stacksz = sz;
+}
+
+VCOS_INLINE_IMPL
+void vcos_thread_attr_setstacksize(VCOS_THREAD_ATTR_T *attr, VCOS_UNSIGNED sz) {
+   attr->ta_stacksz = sz;
+}
+
+VCOS_INLINE_IMPL
+void vcos_thread_attr_setpriority(VCOS_THREAD_ATTR_T *attr, VCOS_UNSIGNED pri) {
+   (void)attr;
+   (void)pri;
+}
+
+VCOS_INLINE_IMPL
+void vcos_thread_set_priority(VCOS_THREAD_T *thread, VCOS_UNSIGNED p) {
+   /* not implemented */
+   (void)thread;
+   (void)p;
+}
+
+VCOS_INLINE_IMPL
+VCOS_UNSIGNED vcos_thread_get_priority(VCOS_THREAD_T *thread) {
+   /* not implemented */
+   (void)thread;
+   return 0;
+}
+
+VCOS_INLINE_IMPL
+void vcos_thread_set_affinity(VCOS_THREAD_T *thread, VCOS_UNSIGNED affinity) {
+   /* not implemented */
+   vcos_unused(thread);
+   vcos_unused(affinity);
+}
+
+
+VCOS_INLINE_IMPL
+void vcos_thread_attr_setaffinity(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED affinity) {
+   attrs->ta_affinity = affinity;
+}
+
+VCOS_INLINE_IMPL
+void vcos_thread_attr_settimeslice(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED ts) {
+   attrs->ta_timeslice = ts;
+}
+
+VCOS_INLINE_IMPL
+void _vcos_thread_attr_setlegacyapi(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED legacy) {
+   attrs->legacy = legacy;
+}
+
+VCOS_INLINE_IMPL
+void vcos_thread_attr_setautostart(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED autostart) {
+   (void)attrs;
+   (void)autostart;
+}
+
+VCOS_INLINE_IMPL
+VCOS_LLTHREAD_T *vcos_llthread_current(void) {
+   return (VCOS_LLTHREAD_T *)pthread_self();
+}
+
+VCOS_INLINE_IMPL
+VCOS_UNSIGNED vcos_thread_get_affinity(VCOS_THREAD_T *thread) {
+   vcos_unused(thread);
+   return _VCOS_AFFINITY_CPU0;
+}
+
+VCOS_INLINE_IMPL
+int vcos_thread_running(VCOS_THREAD_T *thread) {
+   vcos_unused(thread);
+   /* Not applicable to pthreads */
+   return 0;
+}
+
+VCOS_INLINE_IMPL
+VCOS_UNSIGNED vcos_change_preemption(VCOS_UNSIGNED pe) {
+   vcos_unused(pe);
+   /* Nothing to do */
+   return 0;
+}
+
+VCOS_INLINE_IMPL
+void vcos_thread_relinquish(void) {
+   /* Nothing to do */
+}
+
+VCOS_INLINE_IMPL
+void vcos_thread_resume(VCOS_THREAD_T *thread) {
+   vcos_unused(thread);
+   /* Nothing to do */
+}
+
+
+/*
+ * Mutexes
+ */
+
+#ifndef VCOS_USE_VCOS_FUTEX
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_mutex_create(VCOS_MUTEX_T *latch, const char *name) {
+   int rc = pthread_mutex_init(latch, NULL);
+   (void)name;
+   if (rc == 0) return VCOS_SUCCESS;
+   else return vcos_pthreads_map_errno();
+}
+
+VCOS_INLINE_IMPL
+void vcos_mutex_delete(VCOS_MUTEX_T *latch) {
+   int rc = pthread_mutex_destroy(latch);
+   (void)rc;
+   vcos_assert(rc==0);
+}
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_mutex_lock(VCOS_MUTEX_T *latch) {
+   int rc = pthread_mutex_lock(latch);
+   vcos_assert(rc==0);
+   (void)rc;
+   return VCOS_SUCCESS;
+}
+
+VCOS_INLINE_IMPL
+void vcos_mutex_unlock(VCOS_MUTEX_T *latch) {
+   int rc = pthread_mutex_unlock(latch);
+   (void)rc;
+   vcos_assert(rc==0);
+}
+
+VCOS_INLINE_IMPL
+int vcos_mutex_is_locked(VCOS_MUTEX_T *m) {
+   int rc = pthread_mutex_trylock(m);
+   if (rc == 0) {
+      pthread_mutex_unlock(m);
+      /* it wasn't locked */
+      return 0;
+   }
+   else {
+      return 1; /* it was locked */
+   }
+}
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_mutex_trylock(VCOS_MUTEX_T *m) {
+   int rc = pthread_mutex_trylock(m);
+   (void)rc;
+   return (rc == 0) ? VCOS_SUCCESS : VCOS_EAGAIN;
+}
+
+#endif /* VCOS_USE_VCOS_FUTEX */
+
+/*
+ * Events
+ */
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_event_create(VCOS_EVENT_T *event, const char *debug_name)
+{
+   VCOS_STATUS_T status;
+
+   int rc = sem_init(&event->sem, 0, 0);
+   if (rc != 0) return vcos_pthreads_map_errno();
+
+   status = vcos_mutex_create(&event->mutex, debug_name);
+   if (status != VCOS_SUCCESS) {
+      sem_destroy(&event->sem);
+      return status;
+   }
+
+   return VCOS_SUCCESS;
+}
+
+VCOS_INLINE_IMPL
+void vcos_event_signal(VCOS_EVENT_T *event)
+{
+   int ok = 0;
+   int value;
+
+   if (vcos_mutex_lock(&event->mutex) != VCOS_SUCCESS)
+      goto fail_mtx;
+
+   if (sem_getvalue(&event->sem, &value) != 0)
+      goto fail_sem;
+
+   if (value == 0)
+      if (sem_post(&event->sem) != 0)
+         goto fail_sem;
+
+   ok = 1;
+fail_sem:
+   vcos_mutex_unlock(&event->mutex);
+fail_mtx:
+   if (!ok)
+      vcos_assert(ok);
+}
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_event_wait(VCOS_EVENT_T *event)
+{
+   int ret;
+   /* gdb causes sem_wait() to EINTR when a breakpoint is hit, retry here */
+   while ((ret = sem_wait(&event->sem)) == -1 && errno == EINTR)
+      continue;
+   vcos_assert(ret==0);
+   return ret == 0 ? VCOS_SUCCESS : (VCOS_STATUS_T)errno;
+}
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_event_try(VCOS_EVENT_T *event)
+{
+   int ret;
+   while ((ret = sem_trywait(&event->sem)) == -1 && errno == EINTR)
+      continue;
+
+   if (ret == -1 && errno == EAGAIN)
+      return VCOS_EAGAIN;
+   else
+      return VCOS_SUCCESS;
+}
+
+VCOS_INLINE_IMPL
+void vcos_event_delete(VCOS_EVENT_T *event)
+{
+   int rc = sem_destroy(&event->sem);
+   vcos_assert(rc != -1);
+   (void)rc;
+
+   vcos_mutex_delete(&event->mutex);
+}
+
+VCOS_INLINE_IMPL
+VCOS_UNSIGNED vcos_process_id_current(void) {
+   return (VCOS_UNSIGNED) getpid();
+}
+
+VCOS_INLINE_IMPL
+int vcos_strcasecmp(const char *s1, const char *s2) {
+   return strcasecmp(s1,s2);
+}
+
+VCOS_INLINE_IMPL
+int vcos_strncasecmp(const char *s1, const char *s2, size_t n) {
+   return strncasecmp(s1,s2,n);
+}
+
+VCOS_INLINE_IMPL
+int vcos_in_interrupt(void) {
+   return 0;
+}
+
+/* For support event groups - per thread semaphore */
+VCOS_INLINE_IMPL
+void _vcos_thread_sem_wait(void) {
+   VCOS_THREAD_T *t = vcos_thread_current();
+   vcos_semaphore_wait(&t->suspend);
+}
+
+VCOS_INLINE_IMPL
+void _vcos_thread_sem_post(VCOS_THREAD_T *target) {
+   vcos_semaphore_post(&target->suspend);
+}
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_tls_create(VCOS_TLS_KEY_T *key) {
+   int st = pthread_key_create(key, NULL);
+   return st == 0 ? VCOS_SUCCESS: VCOS_ENOMEM;
+}
+
+VCOS_INLINE_IMPL
+void vcos_tls_delete(VCOS_TLS_KEY_T tls) {
+   pthread_key_delete(tls);
+}
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_tls_set(VCOS_TLS_KEY_T tls, void *v) {
+   pthread_setspecific(tls, v);
+   return VCOS_SUCCESS;
+}
+
+VCOS_INLINE_IMPL
+void *vcos_tls_get(VCOS_TLS_KEY_T tls) {
+   return pthread_getspecific(tls);
+}
+
+/***********************************************************
+ *
+ * Timers
+ *
+ ***********************************************************/
+
+//Other platforms can call compatible OS implementations directly
+//from inline functions with minimal overhead.
+//Pthreads needs a little bit more, so call functions
+//in vcos_pthreads.c from the inline functions.
+VCOS_STATUS_T vcos_pthreads_timer_create(VCOS_TIMER_T *timer,
+                                const char *name,
+                                void (*expiration_routine)(void *context),
+                                void *context);
+void vcos_pthreads_timer_set(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay_ms);
+void vcos_pthreads_timer_cancel(VCOS_TIMER_T *timer);
+void vcos_pthreads_timer_reset(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay_ms);
+void vcos_pthreads_timer_delete(VCOS_TIMER_T *timer);
+
+/** Create a timer.
+  *
+  * Note that we just cast the expiry function - this assumes that UNSIGNED
+  * and VOID* are the same size.
+  */
+
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_timer_create(VCOS_TIMER_T *timer,
+                                const char *name,
+                                void (*expiration_routine)(void *context),
+                                void *context) {
+   return vcos_pthreads_timer_create(timer, name, expiration_routine, context);
+}
+
+VCOS_INLINE_IMPL
+void vcos_timer_set(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay_ms) {
+   return vcos_pthreads_timer_set(timer, delay_ms);
+}
+
+VCOS_INLINE_IMPL
+void vcos_timer_cancel(VCOS_TIMER_T *timer) {
+   return vcos_pthreads_timer_cancel(timer);
+}
+
+VCOS_INLINE_IMPL
+void vcos_timer_reset(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay) {
+   vcos_timer_set(timer, delay);
+}
+
+VCOS_INLINE_IMPL
+void vcos_timer_delete(VCOS_TIMER_T *timer) {
+   vcos_pthreads_timer_delete(timer);
+}
+
+#if VCOS_HAVE_ATOMIC_FLAGS
+
+/*
+ * Atomic flags
+ */
+
+/* TODO implement properly... */
+
+VCOS_INLINE_IMPL
+VCOS_STATUS_T vcos_atomic_flags_create(VCOS_ATOMIC_FLAGS_T *atomic_flags)
+{
+   atomic_flags->flags = 0;
+   return vcos_mutex_create(&atomic_flags->mutex, "VCOS_ATOMIC_FLAGS_T");
+}
+
+VCOS_INLINE_IMPL
+void vcos_atomic_flags_or(VCOS_ATOMIC_FLAGS_T *atomic_flags, uint32_t flags)
+{
+   vcos_mutex_lock(&atomic_flags->mutex);
+   atomic_flags->flags |= flags;
+   vcos_mutex_unlock(&atomic_flags->mutex);
+}
+
+VCOS_INLINE_IMPL
+uint32_t vcos_atomic_flags_get_and_clear(VCOS_ATOMIC_FLAGS_T *atomic_flags)
+{
+   uint32_t flags;
+   vcos_mutex_lock(&atomic_flags->mutex);
+   flags = atomic_flags->flags;
+   atomic_flags->flags = 0;
+   vcos_mutex_unlock(&atomic_flags->mutex);
+   return flags;
+}
+
+VCOS_INLINE_IMPL
+void vcos_atomic_flags_delete(VCOS_ATOMIC_FLAGS_T *atomic_flags)
+{
+   vcos_mutex_delete(&atomic_flags->mutex);
+}
+
+#endif
+
+#ifdef VCOS_PTHREADS_WANT_HISR_EMULATION
+VCOS_STATUS_T vcos_legacy_hisr_create(VCOS_HISR_T *hisr, const char *name,
+                                      void (*entry)(void),
+                                      VCOS_UNSIGNED pri,
+                                      void *stack, VCOS_UNSIGNED stack_size);
+
+void vcos_legacy_hisr_activate(VCOS_HISR_T *hisr);
+
+void vcos_legacy_hisr_delete(VCOS_HISR_T *hisr);
+
+#endif
+
+#undef VCOS_ASSERT_LOGGING_DISABLE
+#define VCOS_ASSERT_LOGGING_DISABLE 0
+
+#endif /* VCOS_INLINE_BODIES */
+
+#define  vcos_log_platform_init()               _vcos_log_platform_init()
+VCOSPRE_ void VCOSPOST_             _vcos_log_platform_init(void);
+
+VCOS_INLINE_DECL void _vcos_thread_sem_wait(void);
+VCOS_INLINE_DECL void _vcos_thread_sem_post(VCOS_THREAD_T *);
+
+#define VCOS_APPLICATION_ARGC          vcos_get_argc()
+#define VCOS_APPLICATION_ARGV          vcos_get_argv()
+
+#include "interface/vcos/generic/vcos_generic_reentrant_mtx.h"
+#include "interface/vcos/generic/vcos_generic_named_sem.h"
+#include "interface/vcos/generic/vcos_generic_quickslow_mutex.h"
+#include "interface/vcos/generic/vcos_common.h"
+
+#define _VCOS_LOG_LEVEL() getenv("VC_LOGLEVEL")
+
+VCOS_STATIC_INLINE
+char *vcos_strdup(const char *str)
+{
+   size_t len = strlen(str) + 1;
+   void *p = malloc(len);
+
+   if (p == NULL)
+      return NULL;
+
+   return (char *)memcpy(p, str, len);
+}
+
+typedef void (*VCOS_ISR_HANDLER_T)(VCOS_UNSIGNED vecnum);
+
+#define VCOS_DL_LAZY RTLD_LAZY
+#define VCOS_DL_NOW  RTLD_NOW
+#define VCOS_DL_LOCAL  RTLD_LOCAL
+#define VCOS_DL_GLOBAL  RTLD_GLOBAL
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* VCOS_PLATFORM_H */
+
diff --git a/interface/vcos/pthreads/vcos_platform_types.h b/interface/vcos/pthreads/vcos_platform_types.h
new file mode 100755 (executable)
index 0000000..17b422d
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - platform-specific types and defines
+=============================================================================*/
+
+#ifndef VCOS_PLATFORM_TYPES_H
+#define VCOS_PLATFORM_TYPES_H
+
+#include "interface/vcos/vcos_inttypes.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define VCOSPRE_ extern
+#define VCOSPOST_
+
+#if defined(__GNUC__) && (( __GNUC__ > 2 ) || (( __GNUC__ == 2 ) && ( __GNUC_MINOR__ >= 3 )))
+#define VCOS_FORMAT_ATTR_(ARCHETYPE, STRING_INDEX, FIRST_TO_CHECK)  __attribute__ ((format (ARCHETYPE, STRING_INDEX, FIRST_TO_CHECK)))
+#else
+#define VCOS_FORMAT_ATTR_(ARCHETYPE, STRING_INDEX, FIRST_TO_CHECK)
+#endif
+
+#if defined(__linux__) && !defined(NDEBUG) && defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
+   #define VCOS_BKPT ({ __asm volatile ("int3":::"memory"); })
+#endif
+/*#define VCOS_BKPT vcos_abort() */
+
+#define VCOS_ASSERT_LOGGING         1
+#define VCOS_ASSERT_LOGGING_DISABLE 0
+
+extern void
+vcos_pthreads_logging_assert(const char *file, const char *func, unsigned int line, const char *fmt, ...);
+
+#define VCOS_ASSERT_MSG(...) ((VCOS_ASSERT_LOGGING && !VCOS_ASSERT_LOGGING_DISABLE) ? vcos_pthreads_logging_assert(__FILE__, __func__, __LINE__, __VA_ARGS__) : (void)0)
+
+#define VCOS_INLINE_BODIES
+#define VCOS_INLINE_DECL extern __inline__
+#define VCOS_INLINE_IMPL static __inline__
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/interface/vcos/pthreads/vcos_pthreads.c b/interface/vcos/pthreads/vcos_pthreads.c
new file mode 100755 (executable)
index 0000000..77ce58c
--- /dev/null
@@ -0,0 +1,897 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*#define VCOS_INLINE_BODIES */
+#include "interface/vcos/vcos.h"
+#include "interface/vcos/vcos_msgqueue.h"
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <linux/param.h>
+
+/* Cygwin doesn't always have prctl.h and it doesn't have PR_SET_NAME */
+#if defined( __linux__ )
+# if !defined(HAVE_PRCTL)
+#  define HAVE_PRCTL
+# endif
+#include <sys/prctl.h>
+#endif
+
+#ifdef HAVE_CMAKE_CONFIG
+#include "cmake_config.h"
+#endif
+
+#ifdef HAVE_MTRACE
+#include <mcheck.h>
+#endif
+
+#if defined(ANDROID)
+#include <android/log.h>
+#endif
+
+#ifndef VCOS_DEFAULT_STACK_SIZE
+#define VCOS_DEFAULT_STACK_SIZE 4096
+#endif
+
+static int vcos_argc;
+static const char **vcos_argv;
+
+typedef void (*LEGACY_ENTRY_FN_T)(int, void *);
+
+static VCOS_THREAD_ATTR_T default_attrs = {
+   .ta_stacksz = VCOS_DEFAULT_STACK_SIZE,
+};
+
+/** Singleton global lock used for vcos_global_lock/unlock(). */
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+#ifdef ANDROID
+static VCOS_MUTEX_T printf_lock;
+#endif
+
+/* Create a per-thread key for faking up vcos access
+ * on non-vcos threads.
+ */
+pthread_key_t _vcos_thread_current_key;
+
+static VCOS_UNSIGNED _vcos_thread_current_key_created = 0;
+static VCOS_ONCE_T current_thread_key_once;  /* init just once */
+
+static void vcos_thread_cleanup(VCOS_THREAD_T *thread)
+{
+   vcos_semaphore_delete(&thread->suspend);
+   if (thread->task_timer_created)
+   {
+      vcos_timer_delete(&thread->task_timer);
+   }
+}
+
+static void vcos_dummy_thread_cleanup(void *cxt)
+{
+   VCOS_THREAD_T *thread = cxt;
+   if (thread->dummy)
+   {
+      int i;
+      /* call termination functions */
+      for (i=0; thread->at_exit[i].pfn != NULL; i++)
+      {
+         thread->at_exit[i].pfn(thread->at_exit[i].cxt);
+      }
+      vcos_thread_cleanup(thread);
+      vcos_free(thread);
+   }
+}
+
+static void current_thread_key_init(void)
+{
+   vcos_assert(!_vcos_thread_current_key_created);
+   pthread_key_create (&_vcos_thread_current_key, vcos_dummy_thread_cleanup);
+   _vcos_thread_current_key_created = 1;
+}
+
+
+/* A VCOS wrapper for the thread which called vcos_init. */
+static VCOS_THREAD_T vcos_thread_main;
+
+static void *vcos_thread_entry(void *arg)
+{
+   int i;
+   void *ret;
+   VCOS_THREAD_T *thread = (VCOS_THREAD_T *)arg;
+
+   vcos_assert(thread != NULL);
+   thread->dummy = 0;
+
+   pthread_setspecific(_vcos_thread_current_key, thread);
+#if defined( HAVE_PRCTL ) && defined( PR_SET_NAME )
+   /* cygwin doesn't have PR_SET_NAME */
+   prctl( PR_SET_NAME, (unsigned long)thread->name, 0, 0, 0 );
+#endif
+   if (thread->legacy)
+   {
+      LEGACY_ENTRY_FN_T fn = (LEGACY_ENTRY_FN_T)thread->entry;
+      (*fn)(0, thread->arg);
+      ret = 0;
+   }
+   else
+   {
+      ret = (*thread->entry)(thread->arg);
+   }
+
+   /* call termination functions */
+   for (i=0; thread->at_exit[i].pfn != NULL; i++)
+   {
+      thread->at_exit[i].pfn(thread->at_exit[i].cxt);
+   }
+
+   return ret;
+}
+
+static void _task_timer_expiration_routine(void *cxt)
+{
+   VCOS_THREAD_T *thread = (VCOS_THREAD_T *)cxt;
+
+   vcos_assert(thread->orig_task_timer_expiration_routine);
+   thread->orig_task_timer_expiration_routine(thread->orig_task_timer_context);
+   thread->orig_task_timer_expiration_routine = NULL;
+}
+
+VCOS_STATUS_T vcos_thread_create(VCOS_THREAD_T *thread,
+                                 const char *name,
+                                 VCOS_THREAD_ATTR_T *attrs,
+                                 VCOS_THREAD_ENTRY_FN_T entry,
+                                 void *arg)
+{
+   VCOS_STATUS_T st;
+   pthread_attr_t pt_attrs;
+   VCOS_THREAD_ATTR_T *local_attrs = attrs ? attrs : &default_attrs;
+   int rc;
+
+   vcos_assert(thread);
+   memset(thread, 0, sizeof(VCOS_THREAD_T));
+
+   rc = pthread_attr_init(&pt_attrs);
+   if (rc < 0)
+      return VCOS_ENOMEM;
+
+   st = vcos_semaphore_create(&thread->suspend, NULL, 0);
+   if (st != VCOS_SUCCESS)
+   {
+      pthread_attr_destroy(&pt_attrs);
+      return st;
+   }
+
+   pthread_attr_setstacksize(&pt_attrs, local_attrs->ta_stacksz);
+#if VCOS_CAN_SET_STACK_ADDR
+   if (local_attrs->ta_stackaddr)
+   {
+      pthread_attr_setstackaddr(&pt_attrs, local_attrs->ta_stackaddr);
+   }
+#else
+   vcos_demand(local_attrs->ta_stackaddr == 0);
+#endif
+
+   /* pthread_attr_setpriority(&pt_attrs, local_attrs->ta_priority); */
+
+   vcos_assert(local_attrs->ta_stackaddr == 0); /* Not possible */
+
+   thread->entry = entry;
+   thread->arg = arg;
+   thread->legacy = local_attrs->legacy;
+
+   strncpy(thread->name, name, sizeof(thread->name));
+   thread->name[sizeof(thread->name)-1] = '\0';
+   memset(thread->at_exit, 0, sizeof(thread->at_exit));
+
+   rc = pthread_create(&thread->thread, &pt_attrs, vcos_thread_entry, thread);
+
+   pthread_attr_destroy(&pt_attrs);
+
+   if (rc < 0)
+   {
+      vcos_semaphore_delete(&thread->suspend);
+      return VCOS_ENOMEM;
+   }
+   else
+   {
+      return VCOS_SUCCESS;
+   }
+}
+
+void vcos_thread_join(VCOS_THREAD_T *thread,
+                             void **pData)
+{
+   pthread_join(thread->thread, pData);
+   vcos_thread_cleanup(thread);
+}
+
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_thread_create_classic(VCOS_THREAD_T *thread,
+                                                            const char *name,
+                                                            void *(*entry)(void *arg),
+                                                            void *arg,
+                                                            void *stack,
+                                                            VCOS_UNSIGNED stacksz,
+                                                            VCOS_UNSIGNED priaff,
+                                                            VCOS_UNSIGNED timeslice,
+                                                            VCOS_UNSIGNED autostart)
+{
+   VCOS_THREAD_ATTR_T attrs;
+   vcos_thread_attr_init(&attrs);
+   vcos_thread_attr_setstacksize(&attrs, stacksz);
+   vcos_thread_attr_setpriority(&attrs, priaff & ~_VCOS_AFFINITY_MASK);
+   vcos_thread_attr_setaffinity(&attrs, priaff & _VCOS_AFFINITY_MASK);
+   (void)timeslice;
+   (void)autostart;
+
+   if (VCOS_CAN_SET_STACK_ADDR)
+   {
+      vcos_thread_attr_setstack(&attrs, stack, stacksz);
+   }
+
+   return vcos_thread_create(thread, name, &attrs, entry, arg);
+}
+
+uint64_t vcos_getmicrosecs64_internal(void)
+{
+   struct timeval tv;
+   uint64_t tm = 0;
+
+   if (!gettimeofday(&tv, NULL))
+   {
+      tm = (tv.tv_sec * 1000000LL) + tv.tv_usec;
+   }
+
+   return tm;
+}
+
+#ifdef ANDROID
+
+static int log_prio[] =
+{
+   ANDROID_LOG_INFO,    /* VCOS_LOG_UNINITIALIZED */
+   ANDROID_LOG_INFO,    /* VCOS_LOG_NEVER */
+   ANDROID_LOG_ERROR,   /* VCOS_LOG_ERROR */
+   ANDROID_LOG_WARN,    /* VCOS_LOG_WARN */
+   ANDROID_LOG_INFO,    /* VCOS_LOG_INFO */
+   ANDROID_LOG_DEBUG    /* VCOS_LOG_TRACE */
+};
+
+int vcos_use_android_log = 1;
+int vcos_log_to_file = 0;
+#else
+int vcos_use_android_log = 0;
+int vcos_log_to_file = 0;
+#endif
+
+static FILE * log_fhandle = NULL;
+
+void vcos_vlog_default_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args)
+{
+   (void)_level;
+
+#ifdef ANDROID
+   if ( vcos_use_android_log )
+   {
+      __android_log_vprint(log_prio[_level], cat->name, fmt, args);
+   }
+   else
+   {
+      vcos_mutex_lock(&printf_lock);
+#endif
+      if(NULL != log_fhandle)
+      {
+         if (cat->flags.want_prefix)
+            fprintf( log_fhandle, "%s: ", cat->name );
+         vfprintf(log_fhandle, fmt, args);
+         fputs("\n", log_fhandle);
+         fflush(log_fhandle);
+      }
+#ifdef ANDROID
+      vcos_mutex_unlock(&printf_lock);
+   }
+#endif
+}
+
+void _vcos_log_platform_init(void)
+{
+   if(vcos_log_to_file)
+   {
+      char log_fname[100];
+#ifdef ANDROID
+      snprintf(log_fname, 100, "/data/log/vcos_log%u.txt", vcos_process_id_current());
+#else
+      snprintf(log_fname, 100, "/var/log/vcos_log%u.txt", vcos_process_id_current());
+#endif
+      log_fhandle = fopen(log_fname, "w");
+   }
+   else
+      log_fhandle = stderr;
+}
+
+/* Flags for init/deinit components */
+enum
+{
+   VCOS_INIT_NAMED_SEM   = (1 << 0),
+   VCOS_INIT_PRINTF_LOCK = (1 << 1),
+   VCOS_INIT_MAIN_SEM    = (1 << 2),
+   VCOS_INIT_MSGQ        = (1 << 3),
+   VCOS_INIT_ALL         = 0xffffffff
+};
+
+static void vcos_term(uint32_t flags)
+{
+   if (flags & VCOS_INIT_MSGQ)
+      vcos_msgq_deinit();
+
+   if (flags & VCOS_INIT_MAIN_SEM)
+      vcos_semaphore_delete(&vcos_thread_main.suspend);
+
+#ifdef ANDROID
+   if (flags & VCOS_INIT_PRINTF_LOCK)
+      vcos_mutex_delete(&printf_lock);
+#endif
+
+   if (flags & VCOS_INIT_NAMED_SEM)
+      _vcos_named_semaphore_deinit();
+}
+
+VCOS_STATUS_T vcos_platform_init(void)
+{
+   VCOS_STATUS_T st;
+   uint32_t flags = 0;
+   int pst;
+
+   st = _vcos_named_semaphore_init();
+   if (!vcos_verify(st == VCOS_SUCCESS))
+      goto end;
+
+   flags |= VCOS_INIT_NAMED_SEM;
+
+#ifdef HAVE_MTRACE
+   /* enable glibc memory debugging, if the environment
+    * variable MALLOC_TRACE names a valid file.
+    */
+   mtrace();
+#endif
+
+#ifdef ANDROID
+   st = vcos_mutex_create(&printf_lock, "printf");
+   if (!vcos_verify(st == VCOS_SUCCESS))
+      goto end;
+
+   flags |= VCOS_INIT_PRINTF_LOCK;
+#endif
+
+   st = vcos_once(&current_thread_key_once, current_thread_key_init);
+   if (!vcos_verify(st == VCOS_SUCCESS))
+      goto end;
+
+   /* Initialise a VCOS wrapper for the thread which called vcos_init. */
+   st = vcos_semaphore_create(&vcos_thread_main.suspend, NULL, 0);
+   if (!vcos_verify(st == VCOS_SUCCESS))
+      goto end;
+
+   flags |= VCOS_INIT_MAIN_SEM;
+
+   vcos_thread_main.thread = pthread_self();
+
+   pst = pthread_setspecific(_vcos_thread_current_key, &vcos_thread_main);
+   if (!vcos_verify(pst == 0))
+   {
+      st = VCOS_EINVAL;
+      goto end;
+   }
+
+   st = vcos_msgq_init();
+   if (!vcos_verify(st == VCOS_SUCCESS))
+      goto end;
+
+   flags |= VCOS_INIT_MSGQ;
+
+   vcos_logging_init();
+
+end:
+   if (st != VCOS_SUCCESS)
+      vcos_term(flags);
+
+   return st;
+}
+
+void vcos_platform_deinit(void)
+{
+   vcos_term(VCOS_INIT_ALL);
+}
+
+void vcos_global_lock(void)
+{
+   pthread_mutex_lock(&lock);
+}
+
+void vcos_global_unlock(void)
+{
+   pthread_mutex_unlock(&lock);
+}
+
+void vcos_thread_exit(void *arg)
+{
+   VCOS_THREAD_T *thread = vcos_thread_current();
+
+   if ( thread && thread->dummy )
+   {
+      vcos_free ( (void*) thread );
+      thread = NULL;
+   }
+
+   pthread_exit(arg);
+}
+
+
+void vcos_thread_attr_init(VCOS_THREAD_ATTR_T *attrs)
+{
+   *attrs = default_attrs;
+}
+
+VCOS_STATUS_T vcos_pthreads_map_error(int error)
+{
+   switch (error)
+   {
+   case ENOMEM:
+      return VCOS_ENOMEM;
+   case ENXIO:
+      return VCOS_ENXIO;
+   case EAGAIN:
+      return VCOS_EAGAIN;
+   case ENOSPC:
+      return VCOS_ENOSPC;
+   default:
+      return VCOS_EINVAL;
+   }
+}
+
+VCOS_STATUS_T vcos_pthreads_map_errno(void)
+{
+   return vcos_pthreads_map_error(errno);
+}
+
+void _vcos_task_timer_set(void (*pfn)(void*), void *cxt, VCOS_UNSIGNED ms)
+{
+   VCOS_THREAD_T *thread = vcos_thread_current();
+
+   if (thread == NULL)
+      return;
+
+   vcos_assert(thread->orig_task_timer_expiration_routine == NULL);
+
+   if (!thread->task_timer_created)
+   {
+      VCOS_STATUS_T st = vcos_timer_create(&thread->task_timer, NULL,
+                                _task_timer_expiration_routine, thread);
+      (void)st;
+      vcos_assert(st == VCOS_SUCCESS);
+      thread->task_timer_created = 1;
+   }
+
+   thread->orig_task_timer_expiration_routine = pfn;
+   thread->orig_task_timer_context = cxt;
+
+   vcos_timer_set(&thread->task_timer, ms);
+}
+
+void _vcos_task_timer_cancel(void)
+{
+   VCOS_THREAD_T *thread = vcos_thread_current();
+
+   if (thread == NULL || !thread->task_timer_created)
+     return;
+
+   vcos_timer_cancel(&thread->task_timer);
+   thread->orig_task_timer_expiration_routine = NULL;
+}
+
+int vcos_vsnprintf( char *buf, size_t buflen, const char *fmt, va_list ap )
+{
+   return vsnprintf( buf, buflen, fmt, ap );
+}
+
+int vcos_snprintf(char *buf, size_t buflen, const char *fmt, ...)
+{
+   int ret;
+   va_list ap;
+   va_start(ap,fmt);
+   ret = vsnprintf(buf, buflen, fmt, ap);
+   va_end(ap);
+   return ret;
+}
+
+int vcos_have_rtos(void)
+{
+   return 1;
+}
+
+const char * vcos_thread_get_name(const VCOS_THREAD_T *thread)
+{
+   return thread->name;
+}
+
+#ifdef VCOS_HAVE_BACKTRACK
+void __attribute__((weak)) vcos_backtrace_self(void);
+#endif
+
+void vcos_pthreads_logging_assert(const char *file, const char *func, unsigned int line, const char *fmt, ...)
+{
+   va_list ap;
+   va_start(ap, fmt);
+   fprintf(stderr, "assertion failure:%s:%d:%s():",
+           file, line, func);
+   vfprintf(stderr, fmt, ap);
+   va_end(ap);
+   fprintf(stderr, "\n");
+
+#ifdef VCOS_HAVE_BACKTRACK
+   if (vcos_backtrace_self)
+      vcos_backtrace_self();
+#endif
+   abort();
+}
+
+extern VCOS_STATUS_T vcos_thread_at_exit(void (*pfn)(void*), void *cxt)
+{
+   int i;
+   VCOS_THREAD_T *self = vcos_thread_current();
+   if (!self)
+   {
+      vcos_assert(0);
+      return VCOS_EINVAL;
+   }
+   for (i=0; i<VCOS_MAX_EXIT_HANDLERS; i++)
+   {
+      if (self->at_exit[i].pfn == NULL)
+      {
+         self->at_exit[i].pfn = pfn;
+         self->at_exit[i].cxt = cxt;
+         return VCOS_SUCCESS;
+      }
+   }
+   return VCOS_ENOSPC;
+}
+
+void vcos_set_args(int argc, const char **argv)
+{
+   vcos_argc = argc;
+   vcos_argv = argv;
+}
+
+int vcos_get_argc(void)
+{
+   return vcos_argc;
+}
+
+const char ** vcos_get_argv(void)
+{
+   return vcos_argv;
+}
+
+/* we can't inline this, because HZ comes from sys/param.h which
+ * dumps all sorts of junk into the global namespace, notable MIN and
+ * MAX.
+ */
+uint32_t _vcos_get_ticks_per_second(void)
+{
+   return HZ;
+}
+
+VCOS_STATUS_T vcos_once(VCOS_ONCE_T *once_control,
+                        void (*init_routine)(void))
+{
+   int rc = pthread_once(once_control, init_routine);
+   if (rc != 0)
+   {
+      switch (errno)
+      {
+      case EINVAL:
+         return VCOS_EINVAL;
+      default:
+         vcos_assert(0);
+         return VCOS_EACCESS;
+      }
+   }
+   else
+   {
+      return VCOS_SUCCESS;
+   }
+}
+
+
+VCOS_THREAD_T *vcos_dummy_thread_create(void)
+{
+   VCOS_STATUS_T st;
+   VCOS_THREAD_T *thread_hndl = NULL;
+   int rc;
+
+   thread_hndl = (VCOS_THREAD_T *)vcos_malloc(sizeof(VCOS_THREAD_T), NULL);
+   vcos_assert(thread_hndl != NULL);
+
+   memset(thread_hndl, 0, sizeof(VCOS_THREAD_T));
+
+   thread_hndl->dummy = 1;
+   thread_hndl->thread = pthread_self();
+
+   st = vcos_semaphore_create(&thread_hndl->suspend, NULL, 0);
+   if (st != VCOS_SUCCESS)
+   {
+      vcos_free(thread_hndl);
+      return( thread_hndl );
+   }
+
+   vcos_once(&current_thread_key_once, current_thread_key_init);
+
+   rc = pthread_setspecific(_vcos_thread_current_key,
+                            thread_hndl);
+   (void)rc;
+
+   return( thread_hndl );
+}
+
+
+/***********************************************************
+ *
+ * Timers
+ *
+ ***********************************************************/
+
+/* On Linux we could use POSIX timers with a bit of synchronization.
+ * Unfortunately POSIX timers on Bionic are NOT POSIX compliant
+ * what makes that option not viable.
+ * That's why we ended up with our own implementation of timers.
+ * NOTE: That condition variables on Bionic are also buggy and
+ * they work incorrectly with CLOCK_MONOTONIC, so we have to
+ * use CLOCK_REALTIME (and hope that no one will change the time
+ * significantly after the timer has been set up
+ */
+#define NSEC_IN_SEC  (1000*1000*1000)
+#define MSEC_IN_SEC  (1000)
+#define NSEC_IN_MSEC (1000*1000)
+
+static int _timespec_is_zero(struct timespec *ts)
+{
+   return ((ts->tv_sec == 0) && (ts->tv_nsec == 0));
+}
+
+static void _timespec_set_zero(struct timespec *ts)
+{
+   ts->tv_sec = ts->tv_nsec = 0;
+}
+
+/* Adds left to right and stores the result in left */
+static void _timespec_add(struct timespec *left, struct timespec *right)
+{
+   left->tv_sec += right->tv_sec;
+   left->tv_nsec += right->tv_nsec;
+   if (left->tv_nsec >= (NSEC_IN_SEC))
+   {
+      left->tv_nsec -= NSEC_IN_SEC;
+      left->tv_sec++;
+   }
+}
+
+static int _timespec_is_larger(struct timespec *left, struct timespec *right)
+{
+   if (left->tv_sec != right->tv_sec)
+      return left->tv_sec > right->tv_sec;
+   else
+      return left->tv_nsec > right->tv_nsec;
+}
+
+static void* _timer_thread(void *arg)
+{
+   VCOS_TIMER_T *timer = (VCOS_TIMER_T*)arg;
+
+   pthread_mutex_lock(&timer->lock);
+   while (!timer->quit)
+   {
+      struct timespec now;
+
+      /* Wait until next expiry time, or until timer's settings are changed */
+      if (_timespec_is_zero(&timer->expires))
+         pthread_cond_wait(&timer->settings_changed, &timer->lock);
+      else
+         pthread_cond_timedwait(&timer->settings_changed, &timer->lock, &timer->expires);
+
+      /* See if the timer has expired - reloop if it didn't */
+      clock_gettime(CLOCK_REALTIME, &now);
+      if (_timespec_is_zero(&timer->expires) || _timespec_is_larger(&timer->expires, &now))
+         continue;
+
+      /* The timer has expired. Clear the expiry time and call the
+       * expiration routine
+       */
+      _timespec_set_zero(&timer->expires);
+      timer->orig_expiration_routine(timer->orig_context);
+   }
+   pthread_mutex_unlock(&timer->lock);
+
+   return NULL;
+}
+
+VCOS_STATUS_T vcos_timer_init(void)
+{
+   return VCOS_SUCCESS;
+}
+
+VCOS_STATUS_T vcos_pthreads_timer_create(VCOS_TIMER_T *timer,
+                                const char *name,
+                                void (*expiration_routine)(void *context),
+                                void *context)
+{
+   pthread_mutexattr_t lock_attr;
+   VCOS_STATUS_T result = VCOS_SUCCESS;
+   int settings_changed_initialized = 0;
+   int lock_attr_initialized = 0;
+   int lock_initialized = 0;
+
+   (void)name;
+
+   vcos_assert(timer);
+   vcos_assert(expiration_routine);
+
+   memset(timer, 0, sizeof(VCOS_TIMER_T));
+
+   timer->orig_expiration_routine = expiration_routine;
+   timer->orig_context = context;
+
+   /* Create conditional variable for notifying the timer's thread
+    * when settings change.
+    */
+   if (result == VCOS_SUCCESS)
+   {
+      int rc = pthread_cond_init(&timer->settings_changed, NULL);
+      if (rc == 0)
+         settings_changed_initialized = 1;
+      else
+         result = vcos_pthreads_map_error(rc);
+   }
+
+   /* Create attributes for the lock (we want it to be recursive) */
+   if (result == VCOS_SUCCESS)
+   {
+      int rc = pthread_mutexattr_init(&lock_attr);
+      if (rc == 0)
+      {
+         pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_RECURSIVE);
+         lock_attr_initialized = 1;
+      }
+      else
+      {
+         result = vcos_pthreads_map_error(rc);
+      }
+   }
+
+   /* Create lock for the timer structure */
+   if (result == VCOS_SUCCESS)
+   {
+      int rc = pthread_mutex_init(&timer->lock, &lock_attr);
+      if (rc == 0)
+         lock_initialized = 1;
+      else
+         result = vcos_pthreads_map_error(rc);
+   }
+
+   /* Lock attributes are no longer needed */
+   if (lock_attr_initialized)
+      pthread_mutexattr_destroy(&lock_attr);
+
+   /* Create the underlying thread */
+   if (result == VCOS_SUCCESS)
+   {
+      int rc = pthread_create(&timer->thread, NULL, _timer_thread, timer);
+      if (rc != 0)
+         result = vcos_pthreads_map_error(rc);
+   }
+
+   /* Clean up if anything went wrong */
+   if (result != VCOS_SUCCESS)
+   {
+      if (lock_initialized)
+         pthread_mutex_destroy(&timer->lock);
+
+      if (settings_changed_initialized)
+         pthread_cond_destroy(&timer->settings_changed);
+   }
+
+   return result;
+}
+
+void vcos_pthreads_timer_set(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay_ms)
+{
+   struct timespec now;
+
+   vcos_assert(timer);
+
+   /* Other implementations of this function do undefined things
+    * when delay_ms is 0. This implementation will simply assert and return
+    */
+   vcos_assert(delay_ms != 0);
+   if (delay_ms == 0)
+      return;
+
+   pthread_mutex_lock(&timer->lock);
+
+   /* Calculate the new absolute expiry time */
+   clock_gettime(CLOCK_REALTIME, &now);
+   timer->expires.tv_sec = delay_ms / MSEC_IN_SEC;
+   timer->expires.tv_nsec = (delay_ms % MSEC_IN_SEC) * NSEC_IN_MSEC;
+   _timespec_add(&timer->expires, &now);
+
+   /* Notify the timer's thread about the change */
+   pthread_cond_signal(&timer->settings_changed);
+
+   pthread_mutex_unlock(&timer->lock);
+}
+
+void vcos_pthreads_timer_cancel(VCOS_TIMER_T *timer)
+{
+   vcos_assert(timer);
+
+   pthread_mutex_lock(&timer->lock);
+
+   _timespec_set_zero(&timer->expires);
+   pthread_cond_signal(&timer->settings_changed);
+
+   pthread_mutex_unlock(&timer->lock);
+}
+
+void vcos_pthreads_timer_delete(VCOS_TIMER_T *timer)
+{
+   vcos_assert(timer);
+
+   pthread_mutex_lock(&timer->lock);
+
+   /* Other implementation of this function (e.g. ThreadX)
+    * disallow it being called from the expiration routine
+    */
+   vcos_assert(pthread_self() != timer->thread);
+
+   /* Stop the timer and set flag telling the timer thread to quit */
+   _timespec_set_zero(&timer->expires);
+   timer->quit = 1;
+
+   /* Notify the timer's thread about the change */
+   pthread_cond_signal(&timer->settings_changed);
+
+   /* Release the lock, so that the timer's thread can quit */
+   pthread_mutex_unlock(&timer->lock);
+
+   /* Wait for the timer thread to finish */
+   pthread_join(timer->thread, NULL);
+
+   /* Free resources used by the timer */
+   pthread_mutex_destroy(&timer->lock);
+   pthread_cond_destroy(&timer->settings_changed);
+}
+
diff --git a/interface/vcos/user_nodefs.h b/interface/vcos/user_nodefs.h
new file mode 100755 (executable)
index 0000000..ded2fb4
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef USER_NODEFS_H
+#define USER_NODEFS_H
+
+/*
+ * This tells coverity not to expand the assert macro, so it still sees the
+ * asserts in the code, even in release builds (we currently run coverity on
+ * our release builds). Unfortunately MetaWare won't compile it, even though
+ * __COVERITY__ isn't defined, so we put this in its own header.
+ *
+ * FIXME: This belongs in the Coverity config (in a file called
+ * config/user_nodefs.h)
+ */
+#nodef assert
+
+/*
+ * So we need to declare the function now that it isn't a macro any more. It's
+ * already built into coverity that assert is a "killpath".
+ */
+extern void assert(int cond);
+
+#endif /* USER_NODEFS_H */
diff --git a/interface/vcos/vcos.h b/interface/vcos/vcos.h
new file mode 100755 (executable)
index 0000000..2b83226
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - public header file
+=============================================================================*/
+
+/**
+  * \mainpage OS Abstraction Layer
+  *
+  * \section intro Introduction
+  *
+  * This abstraction layer is here to allow the underlying OS to be easily changed (e.g. from
+  * Nucleus to ThreadX) and to aid in porting host applications to new targets.
+  *
+  * \subsection error Error handling
+  *
+  * Wherever possible, VCOS functions assert internally and return void. The only exceptions
+  * are creation functions (which might fail due to lack of resources) and functions that
+  * might timeout or fail due to lack of space. Errors that might be reported by the underlying
+  * OS API (e.g. invalid mutex) are treated as a programming error, and are merely asserted on.
+  *
+  * \section thread_synch Threads and synchronisation
+  *
+  * \subsection thread Threads
+  *
+  * The thread API is somewhat different to that found in Nucleus. In particular, threads
+  * cannot just be destroyed at arbitrary times and nor can they merely exit. This is so
+  * that the same API can be implemented across all interesting platforms without too much
+  * difficulty. See vcos_thread.h for details. Thread attributes are configured via
+  * the VCOS_THREAD_ATTR_T structure, found in vcos_thread_attr.h.
+  *
+  * \subsection sema Semaphores
+  *
+  * Counted semaphores (c.f. Nucleus NU_SEMAPHORE) are created with VCOS_SEMAPHORE_T.
+  * Under ThreadX on VideoCore, semaphores are implemented using VideoCore spinlocks, and
+  * so are quite a lot faster than ordinary ThreadX semaphores. See vcos_semaphore.h.
+  *
+  * \subsection mtx Mutexes
+  *
+  * Mutexes are used for locking. Attempts to take a mutex twice, or to unlock it
+  * in a different thread to the one in which it was locked should be expected to fail.
+  * Mutexes are not re-entrant (see vcos_reentrant_mutex.h for a slightly slower
+  * re-entrant mutex).
+  *
+  * \subsection evflags Event flags
+  *
+  * Event flags (the ThreadX name - also known as event groups under Nucleus) provide
+  * 32 flags which can be waited on by multiple clients, and signalled by multiple clients.
+  * A timeout can be specified. See vcos_event_flags.h. An alternative to this is the
+  * VCOS_EVENT_T (see vcos_event.h) which is akin to the Win32 auto-reset event, or a
+  * saturating counted semaphore.
+  *
+  * \subsection event Events
+  *
+  * A VCOS_EVENT_T is a bit like a saturating semaphore. No matter how many times it
+  * is signalled, the waiter will only wake up once. See vcos_event.h. You might think this
+  * is useful if you suspect that the cost of reading the semaphore count (perhaps via a
+  * system call) is expensive on your platform.
+  *
+  * \subsection tls Thread local storage
+  *
+  * Thread local storage is supported using vcos_tls.h. This is emulated on Nucleus
+  * and ThreadX.
+  *
+  * \section int Interrupts
+  *
+  * The legacy LISR/HISR scheme found in Nucleus is supported via the legacy ISR API,
+  * which is also supported on ThreadX. New code should avoid this, and old code should
+  * be migrated away from it, since it is slow. See vcos_legacy_isr.h.
+  *
+  * Registering an interrupt handler, and disabling/restoring interrupts, is handled
+  * using the functions in vcos_isr.h.
+  *
+  */
+
+/**
+  * \file vcos.h
+  *
+  * This is the top level header file. Clients include this. It pulls in the platform-specific
+  * header file (vcos_platform.h) together with header files defining the expected APIs, such
+  * as vcos_mutex.h, vcos_semaphore.h, etc. It is also possible to include these header files
+  * directly.
+  *
+  */
+
+#ifndef VCOS_H
+#define VCOS_H
+
+#include "interface/vcos/vcos_assert.h"
+#include "vcos_types.h"
+
+#if defined(__unix__) && !defined(__ANDROID__)
+#include "interface/vcos/pthreads/vcos_platform.h"
+#else
+#include "vcos_platform.h"
+#endif
+
+#ifndef VCOS_INIT_H
+#include "interface/vcos/vcos_init.h"
+#endif
+
+#ifndef VCOS_SEMAPHORE_H
+#include "interface/vcos/vcos_semaphore.h"
+#endif
+
+#ifndef VCOS_THREAD_H
+#include "interface/vcos/vcos_thread.h"
+#endif
+
+#ifndef VCOS_MUTEX_H
+#include "interface/vcos/vcos_mutex.h"
+#endif
+
+#ifndef VCOS_MEM_H
+#include "interface/vcos/vcos_mem.h"
+#endif
+
+#ifndef VCOS_LOGGING_H
+#include "interface/vcos/vcos_logging.h"
+#endif
+
+#ifndef VCOS_STRING_H
+#include "interface/vcos/vcos_string.h"
+#endif
+
+#ifndef VCOS_EVENT_H
+#include "interface/vcos/vcos_event.h"
+#endif
+
+#ifndef VCOS_THREAD_ATTR_H
+#include "interface/vcos/vcos_thread_attr.h"
+#endif
+
+#ifndef VCOS_TLS_H
+#include "interface/vcos/vcos_tls.h"
+#endif
+
+#ifndef VCOS_REENTRANT_MUTEX_H
+#include "interface/vcos/vcos_reentrant_mutex.h"
+#endif
+
+#ifndef VCOS_NAMED_SEMAPHORE_H
+#include "interface/vcos/vcos_named_semaphore.h"
+#endif
+
+#ifndef VCOS_QUICKSLOW_MUTEX_H
+#include "interface/vcos/vcos_quickslow_mutex.h"
+#endif
+
+/* Headers with predicates */
+
+#if VCOS_HAVE_EVENT_FLAGS
+#include "interface/vcos/vcos_event_flags.h"
+#endif
+
+#if VCOS_HAVE_QUEUE
+#include "interface/vcos/vcos_queue.h"
+#endif
+
+#if VCOS_HAVE_LEGACY_ISR
+#include "interface/vcos/vcos_legacy_isr.h"
+#endif
+
+#if VCOS_HAVE_TIMER
+#include "interface/vcos/vcos_timer.h"
+#endif
+
+#if VCOS_HAVE_MEMPOOL
+#include "interface/vcos/vcos_mempool.h"
+#endif
+
+#if VCOS_HAVE_ISR
+#include "interface/vcos/vcos_isr.h"
+#endif
+
+#if VCOS_HAVE_ATOMIC_FLAGS
+#include "interface/vcos/vcos_atomic_flags.h"
+#endif
+
+#if VCOS_HAVE_ONCE
+#include "interface/vcos/vcos_once.h"
+#endif
+
+#if VCOS_HAVE_BLOCK_POOL
+#include "interface/vcos/vcos_blockpool.h"
+#endif
+
+#if VCOS_HAVE_FILE
+#include "interface/vcos/vcos_file.h"
+#endif
+
+#if VCOS_HAVE_CFG
+#include "interface/vcos/vcos_cfg.h"
+#endif
+
+#if VCOS_HAVE_CMD
+#include "interface/vcos/vcos_cmd.h"
+#endif
+
+#endif /* VCOS_H */
+
diff --git a/interface/vcos/vcos_assert.h b/interface/vcos/vcos_assert.h
new file mode 100755 (executable)
index 0000000..3645494
--- /dev/null
@@ -0,0 +1,324 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - Assertion and error-handling macros.
+=============================================================================*/
+
+
+#ifndef VCOS_ASSERT_H
+#define VCOS_ASSERT_H
+
+/*
+ * Macro:
+ *    vcos_assert(cond)
+ *    vcos_assert_msg(cond, fmt, ...)
+ * Use:
+ *    Detecting programming errors by ensuring that assumptions are correct.
+ * On failure:
+ *    Performs a platform-dependent "breakpoint", usually with an assert-style
+ *    message. The '_msg' variant expects a printf-style format string and
+ *    parameters.
+ *    If a failure is detected, the code should be fixed and rebuilt.
+ * In release builds:
+ *    Generates no code, i.e. does not evaluate 'cond'.
+ * Returns:
+ *    Nothing.
+ *
+ * Macro:
+ *    vcos_demand(cond)
+ *    vcos_demand_msg(cond, fmt, ...)
+ * Use:
+ *    Detecting fatal system errors that require a reboot.
+ * On failure:
+ *    Performs a platform-dependent "breakpoint", usually with an assert-style
+ *    message, then calls vcos_abort (see below).
+ * In release builds:
+ *    Calls vcos_abort() if 'cond' is false.
+ * Returns:
+ *    Nothing (never, on failure).
+ *
+ * Macro:
+ *    vcos_verify(cond)
+ *    vcos_verify_msg(cond, fmt, ...)
+ * Use:
+ *    Detecting run-time errors and interesting conditions, normally within an
+ *    'if' statement to catch the failures, i.e.
+ *       if (!vcos_verify(cond)) handle_error();
+ * On failure:
+ *    Generates a message and optionally stops at a platform-dependent
+ *    "breakpoint" (usually disabled). See vcos_verify_bkpts_enable below.
+ * In release builds:
+ *    Just evaluates and returns 'cond'.
+ * Returns:
+ *    Non-zero if 'cond' is true, otherwise zero.
+ *
+ * Macro:
+ *    vcos_static_assert(cond)
+ * Use:
+ *    Detecting compile-time errors.
+ * On failure:
+ *    Generates a compiler error.
+ * In release builds:
+ *    Generates a compiler error.
+ *
+ * Function:
+ *    void vcos_abort(void)
+ * Use:
+ *    Invokes the fatal error handling mechanism, alerting the host where
+ *    applicable.
+ * Returns:
+ *    Never.
+ *
+ * Macro:
+ *    VCOS_VERIFY_BKPTS
+ * Use:
+ *    Define in a module (before including vcos.h) to specify an alternative
+ *    flag to control breakpoints on vcos_verify() failures.
+ * Returns:
+ *    Non-zero values enable breakpoints.
+ *
+ * Function:
+ *    int vcos_verify_bkpts_enable(int enable);
+ * Use:
+ *    Sets the global flag controlling breakpoints on vcos_verify failures,
+ *    enabling the breakpoints iff 'enable' is non-zero.
+ * Returns:
+ *    The previous state of the flag.
+ *
+ * Function:
+ *    int vcos_verify_bkpts_enabled(void);
+ * Use:
+ *    Queries the state of the global flag enabling breakpoints on vcos_verify
+ *    failures.
+ * Returns:
+ *    The current state of the flag.
+ *
+ * Examples:
+ *
+ * int my_breakpoint_enable_flag = 1;
+ *
+ * #define VCOS_VERIFY_BKPTS my_breakpoint_enable_flag
+ *
+ * #include "interface/vcos/vcos.h"
+ *
+ * vcos_static_assert((sizeof(object) % 32) == 0);
+ *
+ * // ...
+ *
+ *    vcos_assert_msg(postcondition_is_true, "Coding error");
+ *
+ *    if (!vcos_verify_msg(buf, "Buffer allocation failed (%d bytes)", size))
+ *    {
+ *       // Tidy up
+ *       // ...
+ *       return OUT_OF_MEMORY;
+ *    }
+ *
+ *    vcos_demand(*p++==GUARDWORDHEAP);
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+
+#ifdef __COVERITY__
+#include "interface/vcos/user_nodefs.h"
+
+extern void __coverity_panic__(void);
+#undef VCOS_ASSERT_BKPT
+#define VCOS_ASSERT_BKPT __coverity_panic__()
+#endif
+
+/*
+ * ANDROID should NOT be defined for files built for Videocore, but currently it
+ * is. FIXME When that's fixed, remove the __VIDEOCORE__ band-aid.
+ */
+#if (defined(ANDROID) && !defined(__VIDEOCORE__))
+#  include "assert.h"
+#  define vcos_assert assert
+#endif
+
+#ifndef VCOS_VERIFY_BKPTS
+#define VCOS_VERIFY_BKPTS vcos_verify_bkpts_enabled()
+#endif
+
+#ifndef VCOS_BKPT
+#if defined(__VIDEOCORE__) && !defined(VCOS_ASSERT_NO_BKPTS)
+#define VCOS_BKPT _bkpt()
+#else
+#define VCOS_BKPT (void )0
+#endif
+#endif
+
+#ifndef VCOS_ASSERT_BKPT
+#define VCOS_ASSERT_BKPT VCOS_BKPT
+#endif
+
+#ifndef VCOS_VERIFY_BKPT
+#define VCOS_VERIFY_BKPT (VCOS_VERIFY_BKPTS ? VCOS_BKPT : (void)0)
+#endif
+
+VCOSPRE_ int VCOSPOST_ vcos_verify_bkpts_enabled(void);
+VCOSPRE_ int VCOSPOST_ vcos_verify_bkpts_enable(int enable);
+VCOSPRE_ void VCOSPOST_ vcos_abort(void);
+
+#ifndef VCOS_ASSERT_MSG
+#ifdef LOGGING
+extern void logging_assert(const char *file, const char *func, int line, const char *format, ...);
+extern void logging_assert_dump(void);
+#define VCOS_ASSERT_MSG(...) ((VCOS_ASSERT_LOGGING && !VCOS_ASSERT_LOGGING_DISABLE) ? logging_assert_dump(), logging_assert(__FILE__, __func__, __LINE__, __VA_ARGS__) : (void)0)
+#else
+#define VCOS_ASSERT_MSG(...) ((void)0)
+#endif
+#endif
+
+#ifndef VCOS_VERIFY_MSG
+#define VCOS_VERIFY_MSG(...) VCOS_ASSERT_MSG(__VA_ARGS__)
+#endif
+
+#ifndef VCOS_ASSERT_LOGGING
+#define VCOS_ASSERT_LOGGING 0
+#endif
+
+#ifndef VCOS_ASSERT_LOGGING_DISABLE
+#define VCOS_ASSERT_LOGGING_DISABLE 0
+#endif
+
+#if !defined(NDEBUG) || defined(VCOS_RELEASE_ASSERTS)
+#define VCOS_ASSERT_ENABLED 1
+#define VCOS_VERIFY_ENABLED 1
+#else
+#define VCOS_ASSERT_ENABLED 0
+#define VCOS_VERIFY_ENABLED 0
+#endif
+
+#define VCOS_DEMAND_ENABLED 1
+
+#if VCOS_ASSERT_ENABLED
+
+#ifndef vcos_assert
+#define vcos_assert(cond) \
+   ( (cond) ? (void)0 : (VCOS_ASSERT_BKPT, VCOS_ASSERT_MSG("%s", #cond)) )
+#endif
+
+#ifndef vcos_assert_msg
+#define vcos_assert_msg(cond, ...) \
+   ( (cond) ? (void)0 : (VCOS_ASSERT_BKPT, VCOS_ASSERT_MSG(__VA_ARGS__)) )
+#endif
+
+#else  /* VCOS_ASSERT_ENABLED */
+
+#ifndef vcos_assert
+#define vcos_assert(cond) (void)0
+#endif
+
+#ifndef vcos_assert_msg
+#define vcos_assert_msg(cond, ...) (void)0
+#endif
+
+#endif /* VCOS_ASSERT_ENABLED */
+
+
+#if VCOS_DEMAND_ENABLED
+
+#ifndef vcos_demand
+#define vcos_demand(cond) \
+   ( (cond) ? (void)0 : (VCOS_ASSERT_BKPT, VCOS_ASSERT_MSG("%s", #cond), vcos_abort()) )
+#endif
+
+#ifndef vcos_demand_msg
+#define vcos_demand_msg(cond, ...) \
+   ( (cond) ? (void)0 : (VCOS_ASSERT_BKPT, VCOS_ASSERT_MSG(__VA_ARGS__), vcos_abort()) )
+#endif
+
+#else  /* VCOS_DEMAND_ENABLED */
+
+#ifndef vcos_demand
+#define vcos_demand(cond) \
+   ( (cond) ? (void)0 : vcos_abort() )
+#endif
+
+#ifndef vcos_demand_msg
+#define vcos_demand_msg(cond, ...) \
+   ( (cond) ? (void)0 : vcos_abort() )
+#endif
+
+#endif /* VCOS_DEMAND_ENABLED */
+
+
+#if VCOS_VERIFY_ENABLED
+
+#ifndef vcos_verify
+#define vcos_verify(cond) \
+   ( (cond) ? 1 : (VCOS_VERIFY_MSG("%s", #cond), VCOS_VERIFY_BKPT, 0) )
+#endif
+
+#ifndef vcos_verify_msg
+#define vcos_verify_msg(cond, ...) \
+   ( (cond) ? 1 : (VCOS_VERIFY_MSG(__VA_ARGS__), VCOS_VERIFY_BKPT, 0) )
+#endif
+
+#else /* VCOS_VERIFY_ENABLED */
+
+#ifndef vcos_verify
+#define vcos_verify(cond) (cond)
+#endif
+
+#ifndef vcos_verify_msg
+#define vcos_verify_msg(cond, ...) (cond)
+#endif
+
+#endif /* VCOS_VERIFY_ENABLED */
+
+
+#ifndef vcos_static_assert
+#if defined(__GNUC__)
+#define vcos_static_assert(cond) __attribute__((unused)) extern int vcos_static_assert[(cond)?1:-1]
+#else
+#define vcos_static_assert(cond) extern int vcos_static_assert[(cond)?1:-1]
+#endif
+#endif
+
+#ifndef vc_assert
+#define vc_assert(cond) vcos_assert(cond)
+#endif
+
+#define vcos_unreachable() vcos_assert(0)
+#define vcos_not_impl() vcos_assert(0)
+
+/** Print out a backtrace, on supported platforms.
+  */
+extern void vcos_backtrace_self(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* VCOS_ASSERT_H */
diff --git a/interface/vcos/vcos_atomic_flags.h b/interface/vcos/vcos_atomic_flags.h
new file mode 100755 (executable)
index 0000000..d0ddd92
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - public header file
+=============================================================================*/
+
+#ifndef VCOS_ATOMIC_FLAGS_H
+#define VCOS_ATOMIC_FLAGS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#include "vcos.h"
+
+/**
+ * \file vcos_atomic_flags.h
+ *
+ * Defines atomic flags API.
+ *
+ * 32 flags. Atomic "or" and "get and clear" operations
+ */
+
+/**
+ * Create an atomic flags instance.
+ *
+ * @param atomic_flags Pointer to atomic flags instance, filled in on return
+ *
+ * @return VCOS_SUCCESS if succeeded.
+ */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_atomic_flags_create(VCOS_ATOMIC_FLAGS_T *atomic_flags);
+
+/**
+ * Atomically set the specified flags.
+ *
+ * @param atomic_flags Instance to set flags on
+ * @param flags        Mask of flags to set
+ */
+VCOS_INLINE_DECL
+void vcos_atomic_flags_or(VCOS_ATOMIC_FLAGS_T *atomic_flags, uint32_t flags);
+
+/**
+ * Retrieve the current flags and then clear them. The entire operation is
+ * atomic.
+ *
+ * @param atomic_flags Instance to get/clear flags from/on
+ *
+ * @return Mask of flags which were set (and we cleared)
+ */
+VCOS_INLINE_DECL
+uint32_t vcos_atomic_flags_get_and_clear(VCOS_ATOMIC_FLAGS_T *atomic_flags);
+
+/**
+ * Delete an atomic flags instance.
+ *
+ * @param atomic_flags Instance to delete
+ */
+VCOS_INLINE_DECL
+void vcos_atomic_flags_delete(VCOS_ATOMIC_FLAGS_T *atomic_flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/interface/vcos/vcos_attr.h b/interface/vcos/vcos_attr.h
new file mode 100755 (executable)
index 0000000..33f7eee
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - compiler-specific attributes
+=============================================================================*/
+
+#ifndef VCOS_ATTR_H
+#define VCOS_ATTR_H
+
+/**
+ * Type attribute indicating the enum should be stored in as few bytes as
+ * possible. MetaWare does this by default, so the attribute is useful when
+ * structs need to be portable to GCC too.
+ *
+ * MSVC doesn't support VCOS_ENUM_PACKED, so code that needs to be portable
+ * across all platforms but wants the type-safety and debug-info benefits
+ * of enum types when possible, should do:
+ *
+ *    typedef enum VCOS_ENUM_PACKED { a = 0, b = 0xffff } EXAMPLE_T;
+ *    struct foo {
+ *       int bar;
+ *       #if VCOS_HAS_ENUM_PACKED
+ *       EXAMPLE_T baz;
+ *       #else
+ *       uint16_t baz;
+ *       #endif
+ *    };
+ */
+
+#if defined(__VECTORC__)
+# define VCOS_ENUM_PACKED
+# define VCOS_HAS_ENUM_PACKED 0
+#elif defined(__GNUC__)
+# define VCOS_ENUM_PACKED  __attribute__ ((packed))
+# define VCOS_HAS_ENUM_PACKED 1
+#elif defined(__HIGHC__)
+# define VCOS_ENUM_PACKED /* packed enums are default on Metaware */
+# define VCOS_HAS_ENUM_PACKED 1
+#else
+# define VCOS_ENUM_PACKED
+# define VCOS_HAS_ENUM_PACKED 0
+#endif
+
+/** Variable attribute indicating the variable must be emitted even if it appears unused. */
+#if defined(__GNUC__) || defined(__HIGHC__)
+# define VCOS_ATTR_USED  __attribute__ ((used))
+#else
+# define VCOS_ATTR_USED
+#endif
+
+/** Variable attribute indicating the compiler should not warn if the variable is unused. */
+#if defined(__GNUC__) || defined(__HIGHC__)
+# define VCOS_ATTR_POSSIBLY_UNUSED  __attribute__ ((unused))
+#else
+# define VCOS_ATTR_POSSIBLY_UNUSED
+#endif
+
+/** Variable attribute requiring specific alignment.
+ *
+ * Use as:
+ *   int VCOS_ATTR_ALIGNED(256) n;
+ * or:
+ *   VCOS_ATTR_ALIGNED(256) int n;
+ * or if you don't want to support MSVC:
+ *   int n VCOS_ATTR_ALIGNED(256);
+ */
+#if defined(__GNUC__) || defined(__HIGHC__)
+# define VCOS_ATTR_ALIGNED(n)  __attribute__ ((aligned(n)))
+#elif defined(_MSC_VER)
+# define VCOS_ATTR_ALIGNED(n)  __declspec(align(n))
+#else
+/* Force a syntax error if this is used when the compiler doesn't support it,
+ * instead of silently misaligning */
+# define VCOS_ATTR_ALIGNED(n) VCOS_ATTR_ALIGNED_NOT_SUPPORTED_ON_THIS_COMPILER
+#endif
+
+/** Variable attribute requiring specific ELF section.
+ *
+ * Use as:
+ *   int n VCOS_ATTR_SECTION(".foo") = 1;
+ *
+ * A pointer like &n will have type "VCOS_ATTR_SECTION_QUALIFIER int *".
+ */
+#if defined(__HIGHC__) || defined(__VECTORC__)
+/* hcvc requires 'far' else it'll put small objects in .sdata/.rsdata/.sbss */
+# define VCOS_ATTR_SECTION(s)  __attribute__ ((far, section(s)))
+# define VCOS_ATTR_SECTION_QUALIFIER _Far
+#elif defined(__GNUC__)
+# define VCOS_ATTR_SECTION(s)  __attribute__ ((section(s)))
+# define VCOS_ATTR_SECTION_QUALIFIER
+#else
+/* Force a syntax error if this is used when the compiler doesn't support it */
+# define VCOS_ATTR_SECTION(s) VCOS_ATTR_SECTION_NOT_SUPPORTED_ON_THIS_COMPILER
+# define VCOS_ATTR_SECTION_QUALIFIER
+#endif
+
+/** Define a function as a weak alias to another function.
+ * @param ret_type     Function return type.
+ * @param alias_name   Name of the alias.
+ * @param param_list   Function parameter list, including the parentheses.
+ * @param target_name  Target function (bare function name, not a string).
+ */
+#if defined(__GNUC__) || defined(__HIGHC__)
+  /* N.B. gcc allows __attribute__ after parameter list, but hcvc seems to silently ignore it. */
+# define VCOS_WEAK_ALIAS(ret_type, alias_name, param_list, target_name) \
+   __attribute__ ((weak, alias(#target_name))) ret_type alias_name param_list
+#else
+# define VCOS_WEAK_ALIAS(ret_type, alias, params, target)  VCOS_CASSERT(0)
+#endif
+
+/** Define a function as a weak alias to another function, specified as a string.
+ * @param ret_type     Function return type.
+ * @param alias_name   Name of the alias.
+ * @param param_list   Function parameter list, including the parentheses.
+ * @param target_name  Target function name as a string.
+ * @note Prefer the use of VCOS_WEAK_ALIAS - it is likely to be more portable.
+ *       Only use VCOS_WEAK_ALIAS_STR if you need to do pre-processor mangling of the target
+ *       symbol.
+ */
+#if defined(__GNUC__) || defined(__HIGHC__)
+  /* N.B. gcc allows __attribute__ after parameter list, but hcvc seems to silently ignore it. */
+# define VCOS_WEAK_ALIAS_STR(ret_type, alias_name, param_list, target_name) \
+   __attribute__ ((weak, alias(target_name))) ret_type alias_name param_list
+#else
+# define VCOS_WEAK_ALIAS_STR(ret_type, alias, params, target)  VCOS_CASSERT(0)
+#endif
+
+#endif /* VCOS_ATTR_H */
diff --git a/interface/vcos/vcos_blockpool.h b/interface/vcos/vcos_blockpool.h
new file mode 100755 (executable)
index 0000000..f82013a
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - fixed size allocator support
+=============================================================================*/
+
+#ifndef VCOS_BLOCKPOOL_H
+#define VCOS_BLOCKPOOL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#include "vcos.h"
+
+/** \file
+  *
+  * Thread safe, fixed size allocator API.
+  *
+  */
+
+/** Initialises a block pool to use already allocated (e.g. statically)
+ * allocated memory.
+ *
+ * Different implementations will incur different overheads. Use
+ * VCOS_BLOCKPOOL_SIZE(num_blocks, block_size) to calculate the number
+ * of bytes required including overheads for the desired pools.
+ *
+ * @param pool        Pointer to pool object
+ * @param num_blocks  The number of blocks required.
+ * @param block_size  The size of an individual block.
+ * @param start       The address of the start of the pool.
+ * @param pool_size   The size of the pool in bytes.
+ * @param align       Alignment for block data. Use VCOS_BLOCKPOOL_ALIGN_DEFAULT
+ *                    for default word alignment.
+ * @param flags       Reserved for future use.
+ * @param name        Name of the pool. Used for diagnostics.
+ *
+ * @return VCOS_SUCCESS if the pool was created.
+ */
+
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_blockpool_init(VCOS_BLOCKPOOL_T *pool,
+      VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size,
+      void *start, VCOS_UNSIGNED pool_size, VCOS_UNSIGNED align,
+      VCOS_UNSIGNED flags, const char *name);
+
+/** Creates a pool of blocks of a given size within a buffer allocated on
+ * the heap.
+ *
+ * The heap memory is freed when the block pool is destroyed by
+ * calling vcos_blockpool_delete.
+ *
+ * @param pool        Pointer to pool object
+ * @param num_blocks  The number of blocks required.
+ * @param block_size  The size of an individual block.
+ * @param align       Alignment for block data. Use VCOS_BLOCKPOOL_ALIGN_DEFAULT
+ *                    for default word alignment.
+ * @param flags       Reserved for future use.
+ * @param name        Name of the pool. Used for diagnostics.
+ *
+ * @return VCOS_SUCCESS if the pool was created.
+ */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_blockpool_create_on_heap(VCOS_BLOCKPOOL_T *pool,
+      VCOS_UNSIGNED num_blocks, VCOS_UNSIGNED block_size,
+      VCOS_UNSIGNED align, VCOS_UNSIGNED flags,
+      const char *name);
+
+/** Allocate a block from the pool
+ *
+ * @param pool Pointer to the pool to allocate from.
+ * @return a pointer to the newly allocated block or NULL if no blocks were
+ * available.
+ */
+VCOS_INLINE_DECL
+void *vcos_blockpool_alloc(VCOS_BLOCKPOOL_T *pool);
+
+/** Allocate a block from the pool and zero it.
+ *
+ * @param pool Pointer to the pool to allocate from.
+ * @return a pointer to the newly allocated block or NULL if no blocks were
+ * available.
+ */
+VCOS_INLINE_DECL
+void *vcos_blockpool_calloc(VCOS_BLOCKPOOL_T *pool);
+
+/** Returns a block to the pool.
+ *
+ * @param block The block to free.
+ */
+VCOS_INLINE_DECL
+void vcos_blockpool_free(void *block);
+
+/** Queries the number of available blocks in the pool.
+ * @param pool The pool to query.
+ */
+VCOS_INLINE_IMPL
+   VCOS_UNSIGNED vcos_blockpool_available_count(VCOS_BLOCKPOOL_T *pool);
+
+/** Queries the number of used blocks in the pool.
+ * @param pool The pool to query.
+ */
+VCOS_INLINE_IMPL
+   VCOS_UNSIGNED vcos_blockpool_used_count(VCOS_BLOCKPOOL_T *pool);
+
+/** Deinitialize a memory pool.
+ *
+ * @param pool The pool to de-initialize.
+ */
+VCOS_INLINE_DECL
+void vcos_blockpool_delete(VCOS_BLOCKPOOL_T *pool);
+
+/** Return an integer handle for a given allocated block. */
+VCOS_INLINE_DECL
+uint32_t vcos_blockpool_elem_to_handle(void *block);
+
+/** Convert an integer handle back into a pointer.
+  * Returns NULL if invalid. */
+VCOS_INLINE_DECL
+void *vcos_blockpool_elem_from_handle(VCOS_BLOCKPOOL_T *pool, uint32_t handle);
+
+/** Checks whether a pointer is an allocated block within the specified pool.
+  * Returns true if the block is valid, otherwise, false is returned. */
+VCOS_INLINE_DECL
+uint32_t vcos_blockpool_is_valid_elem(
+      VCOS_BLOCKPOOL_T *pool, const void *block);
+
+/** May be called once to allow the block pool to be extended by dynamically
+ * adding subpools. The block size cannot be altered.
+ *
+ * @param num_extensions The number of extensions that may be created.
+ *                       The maximum is (VCOS_BLOCKPOOL_MAX_SUBPOOLS - 1)
+ * @param num_blocks     The number of blocks to allocate in each in each
+ *                       dynamically allocated subpool.
+ * @return VCOS_SUCCESS if successful.
+ */
+VCOS_INLINE_DECL
+   VCOS_STATUS_T vcos_blockpool_extend(VCOS_BLOCKPOOL_T *pool,
+         VCOS_UNSIGNED num_extensions, VCOS_UNSIGNED num_blocks);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/interface/vcos/vcos_build_info.h b/interface/vcos/vcos_build_info.h
new file mode 100755 (executable)
index 0000000..710619e
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+const char *vcos_get_build_hostname( void );
+const char *vcos_get_build_version( void );
+const char *vcos_get_build_time( void );
+const char *vcos_get_build_date( void );
+
diff --git a/interface/vcos/vcos_cfg.h b/interface/vcos/vcos_cfg.h
new file mode 100755 (executable)
index 0000000..132ed3e
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined( VCOS_CFG_H )
+#define VCOS_CFG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#include "vcos.h"
+
+typedef struct opaque_vcos_cfg_buf_t    *VCOS_CFG_BUF_T;
+typedef struct opaque_vcos_cfg_entry_t  *VCOS_CFG_ENTRY_T;
+
+/** \file vcos_file.h
+  *
+  * API for accessing configuration/statistics information. This
+  * is loosely modelled on the linux proc entries.
+  */
+
+typedef void (*VCOS_CFG_SHOW_FPTR)( VCOS_CFG_BUF_T buf, void *data );
+typedef void (*VCOS_CFG_PARSE_FPTR)( VCOS_CFG_BUF_T buf, void *data );
+
+/** Create a configuration directory.
+  *
+  * @param entry        Place to store the created config entry.
+  * @param parent       Parent entry (for directory like config 
+  *                     options).
+  * @param entryName    Name of the directory.
+  */
+
+VCOS_STATUS_T vcos_cfg_mkdir( VCOS_CFG_ENTRY_T *entry,
+                              VCOS_CFG_ENTRY_T *parent,
+                              const char *dirName );           
+
+/** Create a configuration entry.
+  *
+  * @param entry        Place to store the created config entry.
+  * @param parent       Parent entry (for directory like config 
+  *                     options).
+  * @param entryName    Name of the configuration entry.
+  * @param showFunc     Function pointer to show configuration 
+  *                     data.
+  * @param parseFunc    Function pointer to parse new data. 
+  */
+
+VCOS_STATUS_T vcos_cfg_create_entry( VCOS_CFG_ENTRY_T *entry,
+                                     VCOS_CFG_ENTRY_T *parent,
+                                     const char *entryName,
+                                     VCOS_CFG_SHOW_FPTR showFunc,
+                                     VCOS_CFG_PARSE_FPTR parseFunc,
+                                     void *data );
+
+/** Determines if a configuration entry has been created or not.
+  *
+  * @param entry        Configuration entry to query.
+  */
+
+int vcos_cfg_is_entry_created( VCOS_CFG_ENTRY_T entry );
+
+/** Returns the name of a configuration entry.
+  *
+  * @param entry        Configuration entry to query.
+  */
+
+const char *vcos_cfg_get_entry_name( VCOS_CFG_ENTRY_T entry );
+
+/** Removes a configuration entry.
+  *
+  * @param entry        Configuration entry to remove.
+  */
+
+VCOS_STATUS_T vcos_cfg_remove_entry( VCOS_CFG_ENTRY_T *entry );
+
+
+/** Writes data into a configuration buffer. Only valid inside
+  * the show function. 
+  *
+  * @param buf      Buffer to write data into.
+  * @param fmt      printf style format string. 
+  */
+
+void vcos_cfg_buf_printf( VCOS_CFG_BUF_T buf, const char *fmt, ... );
+
+/** Retrieves a null terminated string of the data associated
+  * with the buffer. Only valid inside the parse function.
+  *
+  * @param buf      Buffer to get data from.
+  * @param fmt      printf style format string. 
+  */
+
+char *vcos_cfg_buf_get_str( VCOS_CFG_BUF_T buf );
+
+void *vcos_cfg_get_proc_entry( VCOS_CFG_ENTRY_T entry );
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/interface/vcos/vcos_cmd.h b/interface/vcos/vcos_cmd.h
new file mode 100755 (executable)
index 0000000..9d617fd
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined( VCOS_CMD_H )
+#define VCOS_CMD_H
+
+/* ---- Include Files ----------------------------------------------------- */
+
+#ifndef VCOS_H
+#include "interface/vcos/vcos.h"
+#endif
+#include "interface/vcos/vcos_stdint.h"
+
+
+/* ---- Constants and Types ---------------------------------------------- */
+
+struct VCOS_CMD_S;
+typedef struct VCOS_CMD_S VCOS_CMD_T;
+
+typedef struct
+{
+    int         argc;           /* Number of arguments (includes the command/sub-command) */
+    char      **argv;           /* Array of arguments */
+    char      **argv_orig;      /* Original array of arguments */
+
+    VCOS_CMD_T *cmd_entry;
+    VCOS_CMD_T *cmd_parent_entry;
+
+    int         use_log;        /* Output being logged? */
+    size_t      result_size;    /* Size of result buffer. */
+    char       *result_ptr;     /* Next place to put output. */
+    char       *result_buf;     /* Start of the buffer. */
+
+} VCOS_CMD_PARAM_T;
+
+typedef VCOS_STATUS_T (*VCOS_CMD_FUNC_T)( VCOS_CMD_PARAM_T *param );
+
+struct VCOS_CMD_S
+{
+    const char         *name;
+    const char         *args;
+    VCOS_CMD_FUNC_T     cmd_fn;
+    VCOS_CMD_T         *sub_cmd_entry;
+    const char         *descr;
+
+};
+
+/* ---- Variable Externs ------------------------------------------------- */
+
+/* ---- Function Prototypes ---------------------------------------------- */
+
+/*
+ * Common printing routine for generating command output.
+ */
+VCOSPRE_ void VCOSPOST_ vcos_cmd_error( VCOS_CMD_PARAM_T *param, const char *fmt, ... ) VCOS_FORMAT_ATTR_(printf, 2, 3);
+VCOSPRE_ void VCOSPOST_ vcos_cmd_printf( VCOS_CMD_PARAM_T *param, const char *fmt, ... ) VCOS_FORMAT_ATTR_(printf, 2, 3);
+VCOSPRE_ void VCOSPOST_ vcos_cmd_vprintf( VCOS_CMD_PARAM_T *param, const char *fmt, va_list args ) VCOS_FORMAT_ATTR_(printf, 2, 0);
+
+/*
+ * Cause vcos_cmd_error, printf and vprintf to always log to the provided
+ * category. When this call is made, the results buffer passed into
+ * vcos_cmd_execute is used as a line buffer and does not need to be
+ * output by the caller.
+ */
+struct VCOS_LOG_CAT_T;
+VCOSPRE_ void VCOSPOST_ vcos_cmd_always_log_output( struct VCOS_LOG_CAT_T *log_category );
+
+/*
+ * Prints command usage for the current command.
+ */
+VCOSPRE_ void VCOSPOST_ vcos_cmd_usage( VCOS_CMD_PARAM_T *param );
+
+/*
+ * Register commands to be processed
+ */
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_cmd_register( VCOS_CMD_T *cmd_entry );
+
+/*
+ * Registers multiple commands to be processed. The array should
+ * be terminated by an entry with all zeros.
+ */
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_cmd_register_multiple( VCOS_CMD_T *cmd_entry );
+
+/*
+ * Executes a command based on a command line.
+ */
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_cmd_execute( int argc, char **argv, size_t result_size, char *result_buf );
+
+/*
+ * Shut down the command system and free all allocated data.
+ * Do not call any other command functions after this.
+ */
+VCOSPRE_ void VCOSPOST_ vcos_cmd_shutdown( void );
+
+#endif /* VCOS_CMD_H */
+
diff --git a/interface/vcos/vcos_ctype.h b/interface/vcos/vcos_ctype.h
new file mode 100755 (executable)
index 0000000..64bda96
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - public header file
+=============================================================================*/
+
+#ifndef VCOS_CTYPE_H
+#define VCOS_CTYPE_H
+
+/**
+  * \file
+  *
+  * ctype functions.
+  *
+  */
+
+#ifdef __KERNEL__
+#include <linux/ctype.h>
+#else
+#include <ctype.h>
+#endif
+
+#endif
+
diff --git a/interface/vcos/vcos_dlfcn.h b/interface/vcos/vcos_dlfcn.h
new file mode 100755 (executable)
index 0000000..6971d74
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VCOS - abstraction over dynamic library opening
+=============================================================================*/
+
+#ifndef VCOS_DLFCN_H
+#define VCOS_DLFCN_H
+
+#include "interface/vcos/vcos_types.h"
+#include "vcos.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \file
+ *
+ * Loading dynamic libraries. See also dlfcn.h.
+ */
+
+/** Open a dynamic library.
+  *
+  * @param name  name of the library
+  * @param mode  Load lazily or immediately (VCOS_DL_LAZY, VCOS_DL_NOW, VCOS_DL_LOCAL, VCOS_DL_GLOBAL).
+  *
+  * @return A handle for use in subsequent calls.
+  */
+VCOSPRE_ void * VCOSPOST_ vcos_dlopen(const char *name, int mode);
+
+/** Look up a symbol.
+  *
+  * @param handle Handle to open
+  * @param name   Name of function
+  *
+  * @return Function pointer, or NULL.
+  */
+VCOSPRE_ void VCOSPOST_ (*vcos_dlsym(void *handle, const char *name))(void);
+
+/** Close a library
+  *
+  * @param handle Handle to close
+  */
+VCOSPRE_ int VCOSPOST_ vcos_dlclose (void *handle);
+
+/** Return error message from library.
+  *
+  * @param err  On return, set to non-zero if an error has occurred
+  * @param buf  Buffer to write error to
+  * @param len  Size of buffer (including terminating NUL).
+  */
+VCOSPRE_ int VCOSPOST_ vcos_dlerror(int *err, char *buf, size_t buflen);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+
diff --git a/interface/vcos/vcos_event.h b/interface/vcos/vcos_event.h
new file mode 100755 (executable)
index 0000000..f047ded
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - public header file for events
+=============================================================================*/
+
+#ifndef VCOS_EVENT_H
+#define VCOS_EVENT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#include "vcos.h"
+
+/** 
+  * \file
+  *
+  * An event is akin to the Win32 auto-reset event.
+  *
+  *
+  * Signalling an event will wake up one waiting thread only. Once one
+  * thread has been woken the event atomically returns to the unsignalled
+  * state.
+  * 
+  * If no threads are waiting on the event when it is signalled it remains
+  * signalled.
+  *
+  * This is almost, but not quite, completely unlike the "event flags"
+  * object based on Nucleus event groups and ThreadX event flags.
+  *
+  * In particular, it should be similar in speed to a semaphore, unlike
+  * the event flags.
+  */
+
+/**
+  * Create an event instance.
+  *
+  * @param event  Filled in with constructed event.
+  * @param name   Name of the event (for debugging)
+  *
+  * @return VCOS_SUCCESS on success, or error code.
+  */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_event_create(VCOS_EVENT_T *event, const char *name);
+
+#ifndef vcos_event_signal
+
+/**
+  * Signal the event. The event will return to being unsignalled
+  * after exactly one waiting thread has been woken up. If no
+  * threads are waiting it remains signalled.
+  *
+  * @param event The event to signal
+  */
+VCOS_INLINE_DECL
+void vcos_event_signal(VCOS_EVENT_T *event);
+
+/**
+  * Wait for the event.
+  *
+  * @param event The event to wait for
+  * @return VCOS_SUCCESS on success, VCOS_EAGAIN if the wait was interrupted.
+  */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_event_wait(VCOS_EVENT_T *event);
+
+/**
+  * Try event, but don't block.
+  *
+  * @param event The event to try
+  * @return VCOS_SUCCESS on success, VCOS_EAGAIN if the event is not currently signalled
+  */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_event_try(VCOS_EVENT_T *event);
+
+#endif
+
+/*
+ * Destroy an event.
+ */
+VCOS_INLINE_DECL
+void vcos_event_delete(VCOS_EVENT_T *event);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/interface/vcos/vcos_event_flags.h b/interface/vcos/vcos_event_flags.h
new file mode 100755 (executable)
index 0000000..cd5fbb2
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - public header file
+=============================================================================*/
+
+#ifndef VCOS_EVENT_FLAGS_H
+#define VCOS_EVENT_FLAGS_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#include "vcos.h"
+
+#define VCOS_EVENT_FLAGS_SUSPEND    VCOS_SUSPEND
+#define VCOS_EVENT_FLAGS_NO_SUSPEND VCOS_NO_SUSPEND
+typedef VCOS_OPTION VCOS_EVENTGROUP_OPERATION_T;
+
+/**
+ * \file vcos_event_flags.h
+ *
+ * Defines event flags API.
+ *
+ * Similar to Nucleus event groups.
+ *
+ * These have the same semantics as Nucleus event groups and ThreadX event
+ * flags. As such, they are quite complex internally; if speed is important
+ * they might not be your best choice.
+ *
+ */
+
+/**
+ * Create an event flags instance.
+ *
+ * @param flags   Pointer to event flags instance, filled in on return.
+ * @param name    Name for the event flags, used for debug.
+ *
+ * @return VCOS_SUCCESS if succeeded.
+ */
+
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_event_flags_create(VCOS_EVENT_FLAGS_T *flags, const char *name);
+
+/**
+  * Set some events.
+  *
+  * @param flags   Instance to set flags on
+  * @param events  Bitmask of the flags to actually set
+  * @param op      How the flags should be set. VCOS_OR will OR in the flags; VCOS_AND
+  *                will AND them in, possibly clearing existing flags.
+  */
+VCOS_INLINE_DECL
+void vcos_event_flags_set(VCOS_EVENT_FLAGS_T *flags,
+                          VCOS_UNSIGNED events,
+                          VCOS_OPTION op);
+
+/**
+ * Retrieve some events.
+ *
+ * Waits until the specified events have been set.
+ *
+ * @param flags            Instance to wait on
+ * @param requested_events The bitmask to wait for
+ * @param op               VCOS_OR - get any; VCOS_AND - get all.
+ * @param ms_suspend       How long to wait, in milliseconds
+ * @param retrieved_events the events actually retrieved.
+ *
+ * @return VCOS_SUCCESS if events were retrieved. VCOS_EAGAIN if the
+ * timeout expired.
+ */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_event_flags_get(VCOS_EVENT_FLAGS_T *flags,
+                                                     VCOS_UNSIGNED requested_events,
+                                                     VCOS_OPTION op,
+                                                     VCOS_UNSIGNED ms_suspend,
+                                                     VCOS_UNSIGNED *retrieved_events);
+
+
+/**
+ * Delete an event flags instance.
+ */
+VCOS_INLINE_DECL
+void vcos_event_flags_delete(VCOS_EVENT_FLAGS_T *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/interface/vcos/vcos_init.h b/interface/vcos/vcos_init.h
new file mode 100755 (executable)
index 0000000..2d770a5
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - initialization routines
+=============================================================================*/
+
+
+#include "interface/vcos/vcos_types.h"
+#include "vcos.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file
+  *
+  * Some OS support libraries need some initialization. To support this, call
+  * vcos_init() function at the start of day; vcos_deinit() at the end.
+  */
+
+/**
+ * vcos initialization. Call this function before using other vcos functions.
+ * Calls can be nested within the same process; they are reference counted so
+ * that only a call from uninitialized state has any effect.
+ * @note On platforms/toolchains that support it, gcc's constructor attribute or
+ *       similar is used to invoke this function before main() or equivalent.
+ * @return Status of initialisation.
+ */
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_init(void);
+
+/**
+ * vcos deinitialization. Call this function when vcos is no longer required,
+ * in order to free resources.
+ * Calls can be nested within the same process; they are reference counted so
+ * that only a call that decrements the reference count to 0 has any effect.
+ * @note On platforms/toolchains that support it, gcc's destructor attribute or
+ *       similar is used to invoke this function after exit() or equivalent.
+ * @return Status of initialisation.
+ */
+VCOSPRE_ void VCOSPOST_ vcos_deinit(void);
+
+/**
+ * Acquire global lock. This must be available independent of vcos_init()/vcos_deinit().
+ */
+VCOSPRE_ void VCOSPOST_ vcos_global_lock(void);
+
+/**
+ * Release global lock. This must be available independent of vcos_init()/vcos_deinit().
+ */
+VCOSPRE_ void VCOSPOST_ vcos_global_unlock(void);
+
+/** Pass in the argv/argc arguments passed to main() */
+VCOSPRE_ void VCOSPOST_ vcos_set_args(int argc, const char **argv);
+
+/** Return argc. */
+VCOSPRE_ int VCOSPOST_ vcos_get_argc(void);
+
+/** Return argv. */
+VCOSPRE_ const char ** VCOSPOST_ vcos_get_argv(void);
+
+/**
+ * Platform-specific initialisation.
+ * VCOS internal function, not part of public API, do not call from outside
+ * vcos. vcos_init()/vcos_deinit() reference count calls, so this function is
+ * only called from an uninitialized state, i.e. there will not be two
+ * consecutive calls to vcos_platform_init() without an intervening call to
+ * vcos_platform_deinit().
+ * This function is called with vcos_global_lock held.
+ * @return Status of initialisation.
+ */
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_platform_init(void);
+
+/**
+ * Platform-specific de-initialisation.
+ * VCOS internal function, not part of public API, do not call from outside
+ * vcos.
+ * See vcos_platform_init() re reference counting.
+ * This function is called with vcos_global_lock held.
+ */
+VCOSPRE_ void VCOSPOST_ vcos_platform_deinit(void);
+
+#ifdef __cplusplus
+}
+#endif
+
diff --git a/interface/vcos/vcos_inttypes.h b/interface/vcos/vcos_inttypes.h
new file mode 100755 (executable)
index 0000000..7818ab8
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VCOS_INTTYPES_H
+#define VCOS_INTTYPES_H
+
+/** \file
+ * Attempt to provide the support for fixed width integer types as per
+ * inttypes.h. This simply includes inttypes.h, which should find the
+ * system/toolchain version if present, otherwise falling back to the version
+ * in interface/vcos/<platform>. The vcos versions initially only provide the
+ * most common printf() macros.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <inttypes.h>
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* VCOS_INTTYPES_H */
diff --git a/interface/vcos/vcos_isr.h b/interface/vcos/vcos_isr.h
new file mode 100755 (executable)
index 0000000..79e371b
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - IRQ support
+=============================================================================*/
+
+#ifndef VCOS_ISR_H
+#define VCOS_ISR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#include "vcos.h"
+
+/**
+  * \file vcos_isr.h
+  *
+  * \section isr ISR support
+  *
+  * API for dispatching interrupts.
+  */
+
+/**
+  *
+  * Register an interrupt handler. The old handler (if any) is returned in
+  * old_handler. The old handler should be called if the interrupt was not
+  * for you.
+  *
+  * The handler function will be called in a context with interrupts disabled,
+  * so should be written to be as short as possible. If significant processing
+  * is needed, the handler should delegate to a thread.
+  *
+  * The handler function can call any OS primitive that does not block (e.g.
+  * post a semaphore or set an event flag). Blocking operations (including memory
+  * allocation from the system heap) are not permitted.
+  *
+  * To deregister an ISR, pass in NULL.
+  *
+  * @param vec  Vector to register for
+  * @param handler Handler to be called
+  * @param old_handler Updated with the old handler, or NULL.
+  */
+
+VCOS_INLINE_DECL
+void vcos_register_isr(VCOS_UNSIGNED vec,
+                       VCOS_ISR_HANDLER_T handler,
+                       VCOS_ISR_HANDLER_T *old_handler);
+
+/** Disable interrupts, returning the old value (enabled/disabled) to the caller.
+  */
+VCOS_INLINE_DECL
+VCOS_UNSIGNED vcos_int_disable(void);
+
+/** Restore the previous interrupt enable/disable state.
+  */
+VCOS_INLINE_DECL
+void vcos_int_restore(VCOS_UNSIGNED previous);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/interface/vcos/vcos_legacy_isr.h b/interface/vcos/vcos_legacy_isr.h
new file mode 100755 (executable)
index 0000000..dd8c3bf
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - legacy (Nucleus) IRQ support
+=============================================================================*/
+
+#ifndef VCOS_LEGACY_ISR_H
+#define VCOS_LEGACY_ISR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#include "vcos.h"
+
+/** \file vcos_legacy_isr.h
+  *
+  * API for dispatching interrupts the Nucleus way, via a LISR and HISR.
+  * New code should use the single-dispatch scheme - the LISR/HISR
+  * distinction is not necessary.
+  *
+  * Under ThreadX, a HISR is implemented as a high-priority thread which 
+  * waits on a counting semaphore to call the HISR function. Although this
+  * provides a good approximation to the Nucleus semantics, it is potentially
+  * slow if all you are trying to do is to wake a thread from LISR context.
+  */
+
+/** Register a LISR. This is identical to the NU_Register_LISR API.
+  */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_register_legacy_lisr(VCOS_UNSIGNED vecnum,
+                                        void (*lisr)(VCOS_INT),
+                                        void (**old_lisr)(VCOS_INT));
+
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_legacy_hisr_create(VCOS_HISR_T *hisr, const char *name,
+                                      void (*entry)(void),
+                                      VCOS_UNSIGNED pri,
+                                      void *stack, VCOS_UNSIGNED stack_size);
+
+/** Activate a HISR. On an OS which has no distinction between a HISR and LISR,
+  * this may use some kind of emulation, which could well be less efficient than
+  * a normal ISR.`
+  *
+  * @param hisr HISR to activate.
+  */
+VCOS_INLINE_DECL
+void vcos_legacy_hisr_activate(VCOS_HISR_T *hisr);
+
+/** Delete a HISR. 
+  *
+  * @param hisr HISR to delete.
+  */
+VCOS_INLINE_DECL
+void vcos_legacy_hisr_delete(VCOS_HISR_T *hisr);
+
+/** Are we in a legacy LISR?
+  *
+  * @return On Nucleus, non-zero if in a LISR. On other platforms, non-zero if
+  * in an interrupt.
+  */
+VCOS_INLINE_DECL
+int vcos_in_legacy_lisr(void);
+
+/** Is the current thread actually a fake HISR thread? Only implemented
+  * on platforms that fake up HISRs.
+  */
+
+#ifndef VCOS_LISRS_NEED_HISRS
+VCOSPRE_ int VCOSPOST_ vcos_current_thread_is_fake_hisr_thread(VCOS_HISR_T *);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/interface/vcos/vcos_logging.h b/interface/vcos/vcos_logging.h
new file mode 100755 (executable)
index 0000000..a9a132f
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - logging support
+=============================================================================*/
+
+#ifndef VCOS_LOGGING_H
+#define VCOS_LOGGING_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdarg.h>
+
+#include "interface/vcos/vcos_types.h"
+#include "vcos.h"
+#include "vcos_logging_control.h"
+
+/**
+ * \file
+ *
+ * Logging support
+ *
+ * This provides categorised logging. Clients register
+ * a category, and then get a number of logging levels for
+ * that category.
+ *
+ * The logging level flag is tested using a flag *before* the
+ * function call, which makes logging very fast when disabled - there
+ * is no function call overhead just to find out that this log
+ * message is disabled.
+ *
+ * \section VCOS_LOG_CATEGORY
+ *
+ * As a convenience, clients define VCOS_LOG_CATEGORY to point to
+ * their category; the various vcos_log_xxx() macros then expand to
+ * use this.
+ *
+ * e.g.
+ *
+ *     #define VCOS_LOG_CATEGORY (&my_category)
+ *
+ *     #include <interface/vcos/vcos.h>
+ *
+ *     VCOS_LOG_CAT_T my_category;
+ *
+ *     ....
+ *
+ *     vcos_log_trace("Stuff happened: %d", n_stuff);
+ *
+ */
+
+/** Logging levels */
+typedef enum VCOS_LOG_LEVEL_T
+{
+   VCOS_LOG_UNINITIALIZED   = 0,
+   VCOS_LOG_NEVER,
+   VCOS_LOG_ERROR,
+   VCOS_LOG_WARN,
+   VCOS_LOG_INFO,
+   VCOS_LOG_TRACE,
+} VCOS_LOG_LEVEL_T;
+
+
+/** Initialize a logging category without going through vcos_log_register().
+ *
+ * This is useful for the case where there is no obvious point to do the
+ * registration (no initialization function for the module). However, it
+ * means that your logging category is not registered, so cannot be easily
+ * changed at run-time.
+ */
+#define VCOS_LOG_INIT(n,l) { l, n, 0, {0}, 0, 0 }
+
+/** A registered logging category.
+  */
+typedef struct VCOS_LOG_CAT_T
+{
+   VCOS_LOG_LEVEL_T level;      /**< Which levels are enabled for this category */
+   const char *name;            /**< Name for this category. */
+   struct VCOS_LOG_CAT_T *next;
+   struct {
+      unsigned int want_prefix:1;
+   } flags;
+   unsigned int refcount;
+   void *platform_data;         /**< platform specific data */
+} VCOS_LOG_CAT_T;
+
+typedef void (*VCOS_VLOG_IMPL_FUNC_T)(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args);
+
+/** Convert a VCOS_LOG_LEVEL_T into a printable string.
+  * The platform needs to implement this function.
+  */
+VCOSPRE_ const char * VCOSPOST_ vcos_log_level_to_string( VCOS_LOG_LEVEL_T level );
+
+/** Convert a string into a VCOS_LOG_LEVEL_T
+  * The platform needs to implement this function.
+  */
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_string_to_log_level( const char *str, VCOS_LOG_LEVEL_T *level );
+
+/** Log a message. Basic API. Normal code should not use this.
+  * The platform needs to implement this function.
+  */
+VCOSPRE_ void VCOSPOST_ vcos_log_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, ...) VCOS_FORMAT_ATTR_(printf, 3, 4);
+
+/** Log a message using a varargs parameter list. Normal code should
+  * not use this.
+  */
+VCOSPRE_ void VCOSPOST_ vcos_vlog_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args) VCOS_FORMAT_ATTR_(printf, 3, 0);
+
+/** Set the function which does the actual logging output.
+ *  Passing in NULL causes the default logging function to be
+ *  used.
+  */
+VCOSPRE_ void VCOSPOST_ vcos_set_vlog_impl( VCOS_VLOG_IMPL_FUNC_T vlog_impl_func );
+
+/** The default logging function, which is provided by each
+  * platform.
+  */
+
+VCOSPRE_ void VCOSPOST_ vcos_vlog_default_impl(const VCOS_LOG_CAT_T *cat, VCOS_LOG_LEVEL_T _level, const char *fmt, va_list args) VCOS_FORMAT_ATTR_(printf, 3, 0);
+
+/*
+ * Initialise the logging subsystem. This is called from
+ * vcos_init() so you don't normally need to call it.
+ */
+VCOSPRE_ void VCOSPOST_ vcos_logging_init(void);
+
+/** Register a logging category.
+  *
+  * @param name the name of this category.
+  * @param category the category to register.
+  */
+VCOSPRE_ void VCOSPOST_ vcos_log_register(const char *name, VCOS_LOG_CAT_T *category);
+
+/** Unregister a logging category.
+  */
+VCOSPRE_ void VCOSPOST_ vcos_log_unregister(VCOS_LOG_CAT_T *category);
+
+/** Return a default logging category, for people too lazy to create their own.
+  *
+  * Using the default category will be slow (there's an extra function
+  * call overhead). Don't do this in normal code.
+  */
+VCOSPRE_ const VCOS_LOG_CAT_T * VCOSPOST_ vcos_log_get_default_category(void);
+
+VCOSPRE_ void VCOSPOST_ vcos_set_log_options(const char *opt);
+
+/** Set the logging level for a category at run time. Without this, the level
+  * will be that set by vcos_log_register from a platform-specific source.
+  *
+  * @param category the category to modify.
+  * @param level the new logging level for this category.
+  */
+VCOS_STATIC_INLINE void vcos_log_set_level(VCOS_LOG_CAT_T *category, VCOS_LOG_LEVEL_T level)
+{
+   category->level = level;
+}
+
+#define vcos_log_dump_mem(cat,label,addr,voidMem,numBytes)  do { if (vcos_is_log_enabled(cat,VCOS_LOG_TRACE)) vcos_log_dump_mem_impl(cat,label,addr,voidMem,numBytes); } while (0)
+
+void vcos_log_dump_mem_impl( const VCOS_LOG_CAT_T *cat,
+                             const char           *label,
+                             uint32_t              addr,
+                             const void           *voidMem,
+                             size_t                numBytes );
+
+/*
+ * Platform specific hooks (optional).
+ */
+#ifndef vcos_log_platform_init
+#define vcos_log_platform_init()                (void)0
+#endif
+
+#ifndef vcos_log_platform_register
+#define vcos_log_platform_register(category)    (void)0
+#endif
+
+#ifndef vcos_log_platform_unregister
+#define vcos_log_platform_unregister(category)  (void)0
+#endif
+
+/* VCOS_TRACE() - deprecated macro which just outputs in a debug build and
+ * is a no-op in a release build.
+ *
+ * _VCOS_LOG_X() - internal macro which outputs if the current level for the
+ * particular category is higher than the supplied message level.
+ */
+
+#define VCOS_LOG_DFLT_CATEGORY vcos_log_get_default_category()
+
+#define _VCOS_LEVEL(x) (x)
+
+#define vcos_is_log_enabled(cat,_level)  (_VCOS_LEVEL((cat)->level) >= _VCOS_LEVEL(_level))
+
+#if defined(_VCOS_METAWARE) || defined(__GNUC__)
+
+# if !defined(AMPUTATE_ALL_VCOS_LOGGING) && (!defined(NDEBUG) || defined(VCOS_ALWAYS_WANT_LOGGING))
+#  define VCOS_LOGGING_ENABLED
+#  define _VCOS_LOG_X(cat, _level, fmt...)   do { if (vcos_is_log_enabled(cat,_level)) vcos_log_impl(cat,_level,fmt); } while (0)
+#  define _VCOS_VLOG_X(cat, _level, fmt, ap) do { if (vcos_is_log_enabled(cat,_level)) vcos_vlog_impl(cat,_level,fmt,ap); } while (0)
+# else
+#  define _VCOS_LOG_X(cat, _level, fmt...) (void)0
+#  define _VCOS_VLOG_X(cat, _level, fmt, ap) (void)0
+# endif
+
+
+
+# define vcos_log_error(...)   _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_ERROR, __VA_ARGS__)
+# define vcos_log_warn(...)    _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_WARN, __VA_ARGS__)
+# define vcos_log_info(...)    _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_INFO, __VA_ARGS__)
+# define vcos_log_trace(...)   _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_TRACE, __VA_ARGS__)
+
+# define vcos_vlog_error(fmt,ap)  _VCOS_VLOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_ERROR, fmt, ap)
+# define vcos_vlog_warn(fmt,ap)   _VCOS_VLOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_WARN, fmt, ap)
+# define vcos_vlog_info(fmt,ap)   _VCOS_VLOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_INFO, fmt, ap)
+# define vcos_vlog_trace(fmt,ap)  _VCOS_VLOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_TRACE, fmt, ap)
+
+# define vcos_logc_error(cat,...)   _VCOS_LOG_X(cat, VCOS_LOG_ERROR, __VA_ARGS__)
+# define vcos_logc_warn(cat,...)    _VCOS_LOG_X(cat, VCOS_LOG_WARN, __VA_ARGS__)
+# define vcos_logc_info(cat,...)    _VCOS_LOG_X(cat, VCOS_LOG_INFO, __VA_ARGS__)
+# define vcos_logc_trace(cat,...)   _VCOS_LOG_X(cat, VCOS_LOG_TRACE, __VA_ARGS__)
+
+# define vcos_vlogc_error(cat,fmt,ap)  _VCOS_VLOG_X(cat, VCOS_LOG_ERROR, fmt, ap)
+# define vcos_vlogc_warn(cat,fmt,ap)   _VCOS_VLOG_X(cat, VCOS_LOG_WARN, fmt, ap)
+# define vcos_vlogc_info(cat,fmt,ap)   _VCOS_VLOG_X(cat, VCOS_LOG_INFO, fmt, ap)
+# define vcos_vlogc_trace(cat,fmt,ap)  _VCOS_VLOG_X(cat, VCOS_LOG_TRACE, fmt, ap)
+
+# define vcos_log(...)   _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_INFO, __VA_ARGS__)
+# define vcos_vlog(fmt,ap)  _VCOS_VLOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_INFO, fmt, ap)
+# define VCOS_ALERT(...) _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_ERROR, __VA_ARGS__)
+# define VCOS_TRACE(...) _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_INFO, __VA_ARGS__)
+
+/*
+ * MS Visual Studio - pre 2005 does not grok variadic macros
+ */
+#elif defined(_MSC_VER)
+
+# if _MSC_VER >= 1400
+
+#  if !defined(AMPUTATE_ALL_VCOS_LOGGING) && (!defined(NDEBUG) || defined(VCOS_ALWAYS_WANT_LOGGING))
+#   define VCOS_LOGGING_ENABLED
+#   define _VCOS_LOG_X(cat, _level, fmt,...) do { if (vcos_is_log_enabled(cat,_level)) vcos_log_impl(cat, _level, fmt, __VA_ARGS__); } while (0)
+#  else
+#   define _VCOS_LOG_X(cat, _level, fmt,...) (void)0
+#  endif
+
+# define vcos_log_error(fmt,...)   _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_ERROR, fmt, __VA_ARGS__)
+# define vcos_log_warn(fmt,...)    _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_WARN, fmt, __VA_ARGS__)
+# define vcos_log_info(fmt,...)    _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_INFO, fmt, __VA_ARGS__)
+# define vcos_log_trace(fmt,...)   _VCOS_LOG_X(VCOS_LOG_CATEGORY, VCOS_LOG_TRACE, fmt, __VA_ARGS__)
+
+# define vcos_logc_error(cat,fmt,...)   _VCOS_LOG_X(cat, VCOS_LOG_ERROR, fmt, __VA_ARGS__)
+# define vcos_logc_warn(cat,fmt,...)    _VCOS_LOG_X(cat, VCOS_LOG_WARN, fmt, __VA_ARGS__)
+# define vcos_logc_info(cat,fmt,...)    _VCOS_LOG_X(cat, VCOS_LOG_INFO, fmt, __VA_ARGS__)
+# define vcos_logc_trace(cat,fmt,...)   _VCOS_LOG_X(cat, VCOS_LOG_TRACE, fmt, __VA_ARGS__)
+
+# define vcos_log(fmt,...)   _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_INFO, fmt, __VA_ARGS__)
+# define VCOS_ALERT(fmt,...) _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_ERROR, fmt, __VA_ARGS__)
+# define VCOS_TRACE(fmt,...) _VCOS_LOG_X(VCOS_LOG_DFLT_CATEGORY, VCOS_LOG_INFO, fmt, __VA_ARGS__)
+
+# else /* _MSC_VER >= 1400 */
+
+/* do not define these */
+
+# endif /* _MSC_VER >= 1400 */
+
+#endif
+
+#if VCOS_HAVE_CMD
+
+#include "interface/vcos/vcos_cmd.h"
+
+/*
+ * These are the log sub-commands. They're exported here for user-mode apps which 
+ * may want to call these, since the "log" command isn't registered for user-mode 
+ * apps (vcdbg for example, has its own log command). 
+ */
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_log_assert_cmd( VCOS_CMD_PARAM_T *param );
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_log_set_cmd( VCOS_CMD_PARAM_T *param );
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_log_status_cmd( VCOS_CMD_PARAM_T *param );
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_log_test_cmd( VCOS_CMD_PARAM_T *param );
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* VCOS_LOGGING_H */
+
+
diff --git a/interface/vcos/vcos_logging_control.h b/interface/vcos/vcos_logging_control.h
new file mode 100755 (executable)
index 0000000..b180ad8
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+
diff --git a/interface/vcos/vcos_lowlevel_thread.h b/interface/vcos/vcos_lowlevel_thread.h
new file mode 100755 (executable)
index 0000000..c6e3ced
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - low level thread support
+=============================================================================*/
+
+#ifndef VCOS_LOWLEVEL_THREAD_H
+#define VCOS_LOWLEVEL_THREAD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#ifndef VCOS_PLATFORM_H
+#include "vcos.h"
+#endif
+
+/**
+ * \file
+ *
+ * This defines a low level thread API that is supported by *some* operating systems
+ * and can be used to construct the regular "joinable thread" API on those operating
+ * systems.
+ *
+ * Most clients will not need to use this code.
+ *
+ * \sa vcos_joinable_thread.h
+ */
+
+/**
+  * \brief Create a thread.
+  *
+  * This creates a thread which can be stopped either by returning from the
+  * entry point function or by calling vcos_llthread_exit from within the entry
+  * point function. The thread must be cleaned up by calling
+  * vcos_llthread_delete. vcos_llthread_delete may or may not terminate the
+  * thread.
+  *
+  * The preemptible parameter familiar from Nucleus is removed, as it is unused in
+  *  VideoCore code. Affinity is added, since we do use this.
+  *
+  * @param thread       Filled in with thread instance
+  * @param name         An optional name for the thread. "" may be used (but
+  *                     a name will aid in debugging).
+  * @param entry        Entry point
+  * @param arg          A single argument passed to the entry point function
+  * @param stack        Pointer to stack address
+  * @param stacksz      Size of stack in bytes
+  * @param priority     Priority of task, between VCOS_PRI_LOW and VCOS_PRI_HIGH
+  * @param affinity     CPU affinity
+  *
+  * @sa vcos_llthread_terminate vcos_llthread_delete
+  */
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_llthread_create(VCOS_LLTHREAD_T *thread,
+                                                      const char *name,
+                                                      VCOS_LLTHREAD_ENTRY_FN_T entry,
+                                                      void *arg,
+                                                      void *stack,
+                                                      VCOS_UNSIGNED stacksz,
+                                                      VCOS_UNSIGNED priority,
+                                                      VCOS_UNSIGNED affinity,
+                                                      VCOS_UNSIGNED timeslice,
+                                                      VCOS_UNSIGNED autostart);
+
+/**
+  * \brief Exits the current thread.
+  */
+VCOSPRE_ void VCOSPOST_ vcos_llthread_exit(void);
+
+/**
+  * \brief Delete a thread. This must be called to cleanup after
+  * vcos_llthread_create. This may or may not terminate the thread.
+  * It does not clean up any resources that may have been
+  * allocated by the thread.
+  */
+VCOSPRE_ void VCOSPOST_ vcos_llthread_delete(VCOS_LLTHREAD_T *thread);
+
+/**
+  * \brief Return current lowlevel thread pointer.
+  */
+VCOS_INLINE_DECL
+VCOS_LLTHREAD_T *vcos_llthread_current(void);
+
+/**
+  * Resume a thread.
+  */
+VCOS_INLINE_DECL
+void vcos_llthread_resume(VCOS_LLTHREAD_T *thread);
+
+VCOSPRE_ int VCOSPOST_ vcos_llthread_running(VCOS_LLTHREAD_T *thread);
+
+/**
+  * \brief Create a VCOS_LLTHREAD_T for the current thread. This is so we can
+  * have VCOS_LLTHREAD_Ts even for threads not originally created by VCOS (eg
+  * the thread that calls vcos_init).
+  */
+extern VCOS_STATUS_T _vcos_llthread_create_attach(VCOS_LLTHREAD_T *thread);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/interface/vcos/vcos_mem.h b/interface/vcos/vcos_mem.h
new file mode 100755 (executable)
index 0000000..03720df
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - memory support
+=============================================================================*/
+
+#ifndef VCOS_MEM_H
+#define VCOS_MEM_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#include "vcos.h"
+
+/** \file
+  *
+  * Memory allocation api (malloc/free equivalents) is for benefit of host
+  * applications. VideoCore code should use rtos_XXX functions.
+  *
+  */
+
+
+/** Allocate memory
+  *
+  * @param size Size of memory to allocate
+  * @param description Description, to aid in debugging. May be ignored internally on some platforms.
+  */
+VCOS_INLINE_DECL
+void *vcos_malloc(VCOS_UNSIGNED size, const char *description);
+
+void *vcos_kmalloc(VCOS_UNSIGNED size, const char *description);
+void *vcos_kcalloc(VCOS_UNSIGNED num, VCOS_UNSIGNED size, const char *description);
+
+/** Allocate cleared memory
+  *
+  * @param num Number of items to allocate.
+  * @param size Size of each item in bytes.
+  * @param description Description, to aid in debugging. May be ignored internally on some platforms.
+  */
+VCOS_INLINE_DECL
+void *vcos_calloc(VCOS_UNSIGNED num, VCOS_UNSIGNED size, const char *description);
+
+/** Free memory
+  *
+  * Free memory that has been allocated.
+  */
+VCOS_INLINE_DECL
+void vcos_free(void *ptr);
+
+void vcos_kfree(void *ptr);
+
+/** Allocate aligned memory
+  *
+  * Allocate memory aligned on the specified boundary.
+  *
+  * @param size Size of memory to allocate
+  * @param description Description, to aid in debugging. May be ignored internally on some platforms.
+  */
+VCOS_INLINE_DECL
+void *vcos_malloc_aligned(VCOS_UNSIGNED size, VCOS_UNSIGNED align, const char *description);
+
+/** Return the amount of free heap memory
+  *
+  */
+VCOS_INLINE_DECL
+unsigned long vcos_get_free_mem(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/interface/vcos/vcos_mempool.h b/interface/vcos/vcos_mempool.h
new file mode 100755 (executable)
index 0000000..4fb9596
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - memory pool support
+=============================================================================*/
+
+#ifndef VCOS_MEMPOOL_H
+#define VCOS_MEMPOOL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#include "vcos.h"
+
+/** \file
+  *
+  * Memory pools - variable sized allocator.
+  *
+  * A very basic memory pool API.
+  *
+  * This interface is deliberately not thread safe - clients should add
+  * their own locking, if required.
+  *
+  *
+  * \fixme: Add fixed-size allocator.
+  *
+  */
+
+
+/** Initialize a memory pool. The control data is taken from the memory
+  * supplied itself.
+  *
+  * Note: the dmalloc pool uses the memory supplied for its control
+  * area. This is probably a bit broken, as it stops you creating
+  * a pool in some "special" area of memory, while leaving the control
+  * information in normal memory.
+  *
+  * @param pool  Pointer to pool object.
+  *
+  * @param name  Name for the pool. Used for diagnostics.
+  *
+  * @param start Starting address. Must be at least 8byte aligned.
+  *
+  * @param size  Size of pool in bytes.
+  *
+  * @return VCOS_SUCCESS if pool was created.
+  */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_mempool_create(VCOS_MEMPOOL_T *pool, const char *name, void *start, VCOS_UNSIGNED size);
+
+/** Allocate some memory from a pool. If no memory is available, it
+  * returns NULL.
+  *
+  * @param pool Pool to allocate from
+  * @param len  Length of memory to allocate
+  *
+  */
+VCOS_INLINE_DECL
+void *vcos_mempool_alloc(VCOS_MEMPOOL_T *pool, VCOS_UNSIGNED len);
+
+/** Free some memory back to a pool.
+  *
+  * @param pool Pool to return to
+  * @param mem Memory to return
+  */
+VCOS_INLINE_DECL
+void vcos_mempool_free(VCOS_MEMPOOL_T *pool, void *mem);
+
+/** Deinitialize a memory pool.
+  *
+  * @param pool Pool to return to
+  */
+VCOS_INLINE_DECL
+void vcos_mempool_delete(VCOS_MEMPOOL_T *pool);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+
+
diff --git a/interface/vcos/vcos_msgqueue.h b/interface/vcos/vcos_msgqueue.h
new file mode 100755 (executable)
index 0000000..99144d0
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VCOS - packet-like messages, based loosely on those found in TRIPOS.
+
+In the simple case, only the server thread creates a message queue, and
+clients wait for replies on a semaphore. In more complex cases, clients can
+also create message queues (not yet implemented).
+
+Although it's possible for a thread to create multiple queues and listen
+on them in turn, if you find yourself doing this it's probably a bug.
+=============================================================================*/
+
+#ifndef VCOS_MSGQUEUE_H
+#define VCOS_MSGQUEUE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "vcos_types.h"
+#include "vcos.h"
+#include "vcos_blockpool.h"
+
+/**
+ * \file
+ *
+ * Packet-like messages, based loosely on those found in TRIPOS and
+ * derivatives thereof.
+ *
+ * A task can send a message *pointer* to another task, where it is
+ * queued on a linked list and the task woken up. The receiving task
+ * consumes all of the messages on its input queue, and optionally
+ * sends back replies using the original message memory.
+ *
+ * A caller can wait for the reply to a specific message - any other
+ * messages that arrive in the meantime are queued separately.
+ *
+ *
+ * All messages have a standard common layout, but the payload area can
+ * be used freely to extend this.
+ */
+
+#define VCOS_MSGQ_MAGIC 0x5147534d
+
+/** Map the payload portion of a message to a structure pointer.
+  */
+#define VCOS_MSG_DATA(_msg) (void*)((_msg)->data)
+
+/** Standard message ids - FIXME - these need to be done properly! */
+#define VCOS_MSG_N_QUIT            1
+#define VCOS_MSG_N_OPEN            2
+#define VCOS_MSG_N_CLOSE           3
+#define VCOS_MSG_N_PRIVATE         (1<<20)
+
+#define VCOS_MSG_REPLY_BIT         (1<<31)
+
+/** Make gnuc compiler be happy about pointer punning */
+#ifdef __GNUC__
+#define __VCOS_MAY_ALIAS __attribute__((__may_alias__))
+#else
+#define __VCOS_MAY_ALIAS
+#endif
+
+struct VCOS_MSG_T;
+
+/* Replies go to one of these objects.
+ */
+typedef struct VCOS_MSG_WAITER_T
+{
+   /* When the reply is sent, this function gets called with the
+    * address of the waiter.
+    */
+   void (*on_reply)(struct VCOS_MSG_WAITER_T *waiter,
+                    struct VCOS_MSG_T *msg);
+} VCOS_MSG_WAITER_T;
+
+/** A single message queue.
+  */
+typedef struct VCOS_MSGQUEUE_T
+{
+   VCOS_MSG_WAITER_T waiter;           /**< So we can wait on a queue */
+   struct VCOS_MSG_T *head;            /**< head of linked list of messages waiting on this queue */
+   struct VCOS_MSG_T *tail;            /**< tail of message queue */
+   VCOS_SEMAPHORE_T sem;               /**< thread waits on this for new messages */
+   VCOS_MUTEX_T lock;                  /**< locks the messages list */
+   int attached;                       /**< Is this attached to a thread? */
+} VCOS_MSGQUEUE_T;
+
+/** A single message
+  */
+typedef struct VCOS_MSG_T
+{
+   uint32_t magic;                     /**< Sanity checking */
+   uint32_t code;                      /**< message code */
+   struct VCOS_MSG_T *next;            /**< next in queue */
+   VCOS_THREAD_T *src_thread;          /**< for debug */
+   struct VCOS_MSG_WAITER_T *waiter;   /**< client waiter structure */
+   struct VCOS_MSGQ_POOL_T *pool;      /**< Pool allocated from, or NULL */
+} VCOS_MSG_T;
+
+#define MSG_REPLY_BIT (1<<31)
+
+/** Initialize a VCOS_MSG_T. Can also use vcos_msg_init().
+ */
+#define VCOS_MSG_INITIALIZER {VCOS_MSGQ_MAGIC, 0, NULL, NULL, NULL, 0}
+
+/** A pool of messages. This contains its own waiter and
+ * semaphore, as well as a blockpool for the actual memory
+ * management.
+ *
+ * When messages are returned to the waiter, it posts the
+ * semaphore.
+ *
+ * When waiting for a message, we just wait on the semaphore.
+ * When allocating without waiting, we just try-wait on the
+ * semaphore.
+ *
+ * If we managed to claim the semaphore, then by definition
+ * there must be at least that many free messages in the
+ * blockpool.
+ */
+typedef struct VCOS_MSGQ_POOL_T
+{
+   VCOS_MSG_WAITER_T waiter;
+   VCOS_BLOCKPOOL_T blockpool;
+   VCOS_SEMAPHORE_T sem;
+   uint32_t magic;
+} VCOS_MSGQ_POOL_T;
+
+/** Initialise the library. Normally called from vcos_init().
+  */
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_msgq_init(void);
+
+/** De-initialise the library. Normally called from vcos_deinit().
+ */
+VCOSPRE_ void VCOSPOST_ vcos_msgq_deinit(void);
+
+/** Send a message.
+ *
+ * @param dest    Destination message queue
+ * @param code    Message code.
+ * @param msg     Pointer to message to send. Must not go out of scope before
+ *                message is received (do not declare on the stack).
+ */
+VCOSPRE_ void VCOSPOST_ vcos_msg_send(VCOS_MSGQUEUE_T *dest, uint32_t code, VCOS_MSG_T *msg);
+
+/** Send a message and wait for a reply.
+ *
+ * @param dest    Destination message queue
+ * @param code    Message code.
+ * @param msg     Pointer to message to send. May be declared on the stack.
+ */
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_msg_sendwait(VCOS_MSGQUEUE_T *queue, uint32_t code, VCOS_MSG_T *msg);
+
+/** Wait for a message on a queue.
+  */
+VCOSPRE_ VCOS_MSG_T * VCOSPOST_ vcos_msg_wait(VCOS_MSGQUEUE_T *queue);
+
+/** Peek for a message on this thread's endpoint. If a message is not
+ * available, NULL is returned. If a message is available it will be
+ * removed from the endpoint and returned.
+ */
+VCOSPRE_ VCOS_MSG_T * VCOSPOST_ vcos_msg_peek(VCOS_MSGQUEUE_T *queue);
+
+/** Send a reply to a message
+  */
+VCOSPRE_ void VCOSPOST_ vcos_msg_reply(VCOS_MSG_T *msg);
+
+/** Set the reply queue for a message. When the message is replied-to, it
+ * will return to the given queue.
+ *
+ * @param msg      Message
+ * @param queue    Message queue the message should return to
+ */
+VCOSPRE_ void VCOSPOST_ vcos_msg_set_source(VCOS_MSG_T *msg, VCOS_MSGQUEUE_T *queue);
+
+/** Initialise a newly allocated message. This only needs to be called
+ * for messages allocated on the stack, heap or statically. It is not
+ * needed for messages allocated from a pool.
+ */
+VCOSPRE_ void VCOSPOST_ vcos_msg_init(VCOS_MSG_T *msg);
+
+/** Create a message queue to wait on.
+  */
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_msgq_create(VCOS_MSGQUEUE_T *queue, const char *name);
+
+/** Destroy a queue
+  */
+VCOSPRE_ void  VCOSPOST_ vcos_msgq_delete(VCOS_MSGQUEUE_T *queue);
+
+/*
+ * Message pools
+ */
+
+/** Create a pool of messages. Messages can be allocated from the pool and
+ * sent to a message queue. Replying to the message will automatically
+ * free it back to the pool.
+ *
+ * The pool is threadsafe.
+ *
+ * @param count          number of messages in the pool
+ * @param payload_size   maximum message payload size, not including MSG_T.
+ */
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_msgq_pool_create(
+   VCOS_MSGQ_POOL_T *pool,
+   size_t count,
+   size_t payload_size,
+   const char *name);
+
+/** Destroy a message pool.
+ */
+VCOSPRE_ void VCOSPOST_ vcos_msgq_pool_delete(VCOS_MSGQ_POOL_T *pool);
+
+/** Allocate a message from a message pool.
+ *
+ * Note:
+ *
+ * If the alloc fails (returns NULL) then your worker thread has stopped
+ * servicing requests or your pool is too small for the latency in
+ * the system. Your best bet to handle this is to fail the call that
+ * needs to send the message.
+ *
+ * The returned message payload area is initialised to zero.
+ *
+ * @param  pool  Pool to allocate from.
+ * @return Message or NULL if pool exhausted.
+ */
+VCOSPRE_ VCOS_MSG_T *VCOSPOST_ vcos_msgq_pool_alloc(VCOS_MSGQ_POOL_T *pool);
+
+/** Wait for a message from a message pool. Waits until a
+ * message is available in the pool and then allocates it. If
+ * one is already available, returns immediately.
+ *
+ * This call can never fail.
+ *
+ * The returned message payload area is initialised to zero.
+ *
+ * @param  pool  Pool to allocate from.
+ * @return Message
+ */
+VCOSPRE_ VCOS_MSG_T *VCOSPOST_ vcos_msgq_pool_wait(VCOS_MSGQ_POOL_T *pool);
+
+/** Explicitly free a message and return it to its pool.
+ *
+ * @param  msg  Message to free. No-op if NULL.
+ */
+VCOSPRE_ void VCOSPOST_ vcos_msgq_pool_free(VCOS_MSG_T *msg);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
+
diff --git a/interface/vcos/vcos_mutex.h b/interface/vcos/vcos_mutex.h
new file mode 100755 (executable)
index 0000000..4825074
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - mutex public header file
+=============================================================================*/
+
+#ifndef VCOS_MUTEX_H
+#define VCOS_MUTEX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#include "vcos.h"
+
+/**
+ * \file vcos_mutex.h
+ *
+ * Mutex API. Mutexes are not re-entrant, as supporting this adds extra code
+ * that slows down clients which have been written sensibly.
+ *
+ * \sa vcos_reentrant_mutex.h
+ *
+ */
+
+/** Create a mutex.
+  *
+  * @param m      Filled in with mutex on return
+  * @param name   A non-null name for the mutex, used for diagnostics.
+  *
+  * @return VCOS_SUCCESS if mutex was created, or error code.
+  */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_mutex_create(VCOS_MUTEX_T *m, const char *name);
+
+/** Delete the mutex.
+  */
+VCOS_INLINE_DECL
+void vcos_mutex_delete(VCOS_MUTEX_T *m);
+
+/**
+  * \brief Wait to claim the mutex.
+  *
+  * On most platforms this always returns VCOS_SUCCESS, and so would ideally be
+  * a void function, however some platforms allow a wait to be interrupted so
+  * it remains non-void.
+  *
+  * Try to obtain the mutex.
+  * @param m   Mutex to wait on
+  * @return VCOS_SUCCESS - mutex was taken.
+  *         VCOS_EAGAIN  - could not take mutex.
+  */
+#ifndef vcos_mutex_lock
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_mutex_lock(VCOS_MUTEX_T *m);
+
+/** Release the mutex.
+  */
+VCOS_INLINE_DECL
+void vcos_mutex_unlock(VCOS_MUTEX_T *m);
+#endif
+
+/** Test if the mutex is already locked.
+  *
+  * @return 1 if mutex is locked, 0 if it is unlocked.
+  */
+VCOS_INLINE_DECL
+int vcos_mutex_is_locked(VCOS_MUTEX_T *m);
+
+/** Obtain the mutex if possible.
+  *
+  * @param m  the mutex to try to obtain
+  *
+  * @return VCOS_SUCCESS if mutex is successfully obtained, or VCOS_EAGAIN
+  * if it is already in use by another thread.
+  */
+#ifndef vcos_mutex_trylock
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_mutex_trylock(VCOS_MUTEX_T *m);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/interface/vcos/vcos_named_semaphore.h b/interface/vcos/vcos_named_semaphore.h
new file mode 100755 (executable)
index 0000000..a477577
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - named semaphores
+=============================================================================*/
+
+#ifndef VCOS_NAMED_SEMAPHORE_H
+#define VCOS_NAMED_SEMAPHORE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#include "vcos.h"
+
+/**
+ * \file
+ *
+ * Create a named semaphore, or open an existing one by name.
+ *
+ */
+
+/** 
+  * \brief Create a named semaphore.
+  *
+  * Semaphores are not re-entrant.
+  *
+  * @param sem   Pointer to memory to be initialized
+  * @param name  A name for this semaphore.
+  * @param count The initial count for the semaphore.
+  *
+  * @return VCOS_SUCCESS if the semaphore was created.
+  * 
+  */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_named_semaphore_create(VCOS_NAMED_SEMAPHORE_T *sem, const char *name, VCOS_UNSIGNED count);
+
+/**
+  * \brief Wait on a named semaphore.
+  *
+  * There is no timeout option on a semaphore, as adding this will slow down
+  * implementations on some platforms. If you need that kind of behaviour, use
+  * an event group.
+  *
+  * This always returns VCOS_SUCCESS and so should really be a void function. However
+  * too many lines of code would need to be changed in non-trivial ways, so for now
+  * it is non-void.
+  *
+  * @param sem Semaphore to wait on
+  * @return VCOS_SUCCESS - semaphore was taken.
+  *
+  */
+VCOS_INLINE_DECL
+void vcos_named_semaphore_wait(VCOS_NAMED_SEMAPHORE_T *sem);
+
+/**
+  * \brief Try to wait for a semaphore.
+  *
+  * Try to obtain the semaphore. If it is already taken, return VCOS_TIMEOUT.
+  * @param sem Semaphore to wait on
+  * @return VCOS_SUCCESS - semaphore was taken.
+  *         VCOS_EAGAIN - could not take semaphore
+  */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_named_semaphore_trywait(VCOS_NAMED_SEMAPHORE_T *sem);
+
+/**
+  * \brief Post a semaphore.
+  *
+  * @param sem Semaphore to wait on
+  */
+VCOS_INLINE_DECL
+void vcos_named_semaphore_post(VCOS_NAMED_SEMAPHORE_T *sem);
+
+/**
+  * \brief Delete a semaphore, releasing any resources consumed by it.
+  *
+  * @param sem Semaphore to wait on
+  */
+void vcos_named_semaphore_delete(VCOS_NAMED_SEMAPHORE_T *sem);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/interface/vcos/vcos_once.h b/interface/vcos/vcos_once.h
new file mode 100755 (executable)
index 0000000..f5d82c1
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - 'once'
+=============================================================================*/
+
+#ifndef VCOS_ONCE_H
+#define VCOS_ONCE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#include "vcos.h"
+
+/**
+ * \file vcos_once.h
+ *
+ * Ensure something is called only once.
+ *
+ * Initialize once_control to VCOS_ONCE_INIT. The first
+ * time this is called, the init_routine will be called. Thereafter
+ * it won't.
+ *
+ * \sa pthread_once()
+ *
+ */
+
+VCOS_STATUS_T vcos_once(VCOS_ONCE_T *once_control,
+                        void (*init_routine)(void));
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/interface/vcos/vcos_queue.h b/interface/vcos/vcos_queue.h
new file mode 100755 (executable)
index 0000000..7515860
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - Queue public header file
+=============================================================================*/
+
+#ifndef VCOS_QUEUE_H
+#define VCOS_QUEUE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#include "vcos.h"
+
+/** \file vcos_queue.h
+  *
+  * API for accessing a fixed length queue.
+  *
+  * Nucleus offers variable length items, but this feature is not used
+  * in the current code base, so is withdrawn to simplify the API.
+  */
+
+/** Create a fixed length queue.
+  *
+  * @param queue        Pointer to queue control block
+  * @param name         Name of queue
+  * @param message_size Size of each queue message item in words (words are sizeof VCOS_UNSIGNED).
+  * @param queue_start  Start address of queue area
+  * @param queue_size   Size in words (words are sizeof VCOS_UNSIGNED) of queue
+  *
+  */
+
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_queue_create(VCOS_QUEUE_T *queue,
+                                const char *name,
+                                VCOS_UNSIGNED message_size,
+                                void *queue_start,
+                                VCOS_UNSIGNED queue_size);
+
+/** Delete a queue.
+  * @param queue The queue to delete
+  */
+VCOS_INLINE_DECL
+void vcos_queue_delete(VCOS_QUEUE_T *queue);
+
+/** Send an item to a queue. If there is no space, the call with
+  * either block waiting for space, or return an error, depending
+  * on the value of the wait parameter.
+  *
+  * @param queue The queue to send to
+  * @param src   The data to send (length set when queue was created)
+  * @param wait  Whether to wait for space (VCOS_SUSPEND) or fail if
+  *              no space (VCOS_NO_SUSPEND).
+  *
+  * @return If space available, returns VCOS_SUCCESS. Otherwise returns
+  * VCOS_EAGAIN if no space available before timeout expires.
+  *
+  */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_queue_send(VCOS_QUEUE_T *queue, const void *src, VCOS_UNSIGNED wait);
+
+/** Receive an item from a queue.
+  * @param queue The queue to receive from
+  * @param dst   Where to write the data to
+  * @param wait  Whether to wait (VCOS_SUSPEND) or fail if
+  *              empty (VCOS_NO_SUSPEND).
+  *
+  * @return If an item is available, returns VCOS_SUCCESS. Otherwise returns
+  * VCOS_EAGAIN if no item available before timeout expires.
+  */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_queue_receive(VCOS_QUEUE_T *queue, void *dst, VCOS_UNSIGNED wait);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/interface/vcos/vcos_quickslow_mutex.h b/interface/vcos/vcos_quickslow_mutex.h
new file mode 100755 (executable)
index 0000000..2a4465d
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - mutex public header file
+=============================================================================*/
+
+#ifndef VCOS_QUICKSLOW_MUTEX_H
+#define VCOS_QUICKSLOW_MUTEX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#include "vcos.h"
+
+/**
+ * \file vcos_quickslow_mutex.h
+ *
+ * "Quick/Slow" Mutex API. This is a mutex which supports an additional "quick"
+ * (spinlock-based) locking mechanism. While in this quick locked state, other
+ * operating system commands will be unavailable and the caller should complete
+ * whatever it has to do in a short, bounded length of time (as the spinlock
+ * completely locks out other system activity).
+ *
+ * \sa vcos_mutex.h
+ *
+ */
+
+/** Create a mutex.
+  *
+  * @param m      Filled in with mutex on return
+  * @param name   A non-null name for the mutex, used for diagnostics.
+  *
+  * @return VCOS_SUCCESS if mutex was created, or error code.
+  */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_quickslow_mutex_create(VCOS_QUICKSLOW_MUTEX_T *m, const char *name);
+
+/** Delete the mutex.
+  */
+VCOS_INLINE_DECL
+void vcos_quickslow_mutex_delete(VCOS_QUICKSLOW_MUTEX_T *m);
+
+/**
+  * \brief Wait to claim the mutex ("slow" mode).
+  *
+  * Obtain the mutex.
+  */
+VCOS_INLINE_DECL
+void vcos_quickslow_mutex_lock(VCOS_QUICKSLOW_MUTEX_T *m);
+
+/** Release the mutex ("slow" mode).
+  */
+VCOS_INLINE_DECL
+void vcos_quickslow_mutex_unlock(VCOS_QUICKSLOW_MUTEX_T *m);
+
+/**
+  * \brief Wait to claim the mutex ("quick" mode).
+  *
+  * Obtain the mutex. The caller must not call any OS functions or do anything
+  * "slow" before the corresponding call to vcos_mutex_quickslow_unlock_quick.
+  */
+VCOS_INLINE_DECL
+void vcos_quickslow_mutex_lock_quick(VCOS_QUICKSLOW_MUTEX_T *m);
+
+/** Release the mutex ("quick" mode).
+  */
+VCOS_INLINE_DECL
+void vcos_quickslow_mutex_unlock_quick(VCOS_QUICKSLOW_MUTEX_T *m);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/interface/vcos/vcos_reentrant_mutex.h b/interface/vcos/vcos_reentrant_mutex.h
new file mode 100755 (executable)
index 0000000..69777d8
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - reentrant mutex public header file
+=============================================================================*/
+
+#ifndef VCOS_REENTRANT_MUTEX_H
+#define VCOS_REENTRANT_MUTEX_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#include "vcos.h"
+
+/**
+ * \file
+ *
+ * Reentrant Mutex API. You can take one of these mutexes even if you've already
+ * taken it. Just to make sure.
+ *
+ * A re-entrant mutex may be slower on some platforms than a regular one.
+ *
+ * \sa vcos_mutex.h
+ *
+ */
+
+/** Create a mutex.
+  *
+  * @param m      Filled in with mutex on return
+  * @param name   A non-null name for the mutex, used for diagnostics.
+  *
+  * @return VCOS_SUCCESS if mutex was created, or error code.
+  */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_reentrant_mutex_create(VCOS_REENTRANT_MUTEX_T *m, const char *name);
+
+/** Delete the mutex.
+  */
+VCOS_INLINE_DECL
+void vcos_reentrant_mutex_delete(VCOS_REENTRANT_MUTEX_T *m);
+
+/** Wait to claim the mutex. Must not have already been claimed by the current thread.
+  */
+#ifndef vcos_reentrant_mutexlock
+VCOS_INLINE_DECL
+void vcos_reentrant_mutex_lock(VCOS_REENTRANT_MUTEX_T *m);
+
+/** Release the mutex.
+  */
+VCOS_INLINE_DECL
+void vcos_reentrant_mutex_unlock(VCOS_REENTRANT_MUTEX_T *m);
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/interface/vcos/vcos_semaphore.h b/interface/vcos/vcos_semaphore.h
new file mode 100755 (executable)
index 0000000..839faac
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - public header file
+=============================================================================*/
+
+#ifndef VCOS_SEMAPHORE_H
+#define VCOS_SEMAPHORE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#ifndef VCOS_PLATFORM_H
+#include "vcos.h"
+#endif
+
+/**
+ * \file vcos_semaphore.h
+ *
+ * \section sem Semaphores
+ *
+ * This provides counting semaphores. Semaphores are not re-entrant. On sensible
+ * operating systems a semaphore can always be posted but can only be taken in 
+ * thread (not interrupt) context. Under Nucleus, a LISR cannot post a semaphore,
+ * although it would not be hard to lift this restriction.
+ *
+ * \subsection timeout Timeout
+ *
+ * On both Nucleus and ThreadX a semaphore can be taken with a timeout. This is
+ * not supported by VCOS because it makes the non-timeout code considerably more
+ * complicated (and hence slower). In the unlikely event that you need a timeout
+ * with a semaphore, and you cannot simply redesign your code to avoid it, use
+ * an event flag (vcos_event_flags.h).
+ *
+ * \subsection sem_nucleus Changes from Nucleus:
+ *
+ *  Semaphores are always "FIFO" - i.e. sleeping threads are woken in FIFO order. That's
+ *  because:
+ *  \arg there's no support for NU_PRIORITY in threadx (though it can be emulated, slowly)
+ *  \arg we don't appear to actually consciously use it - for example, Dispmanx uses
+ *  it, but all threads waiting are the same priority.
+ *         
+ */
+
+/** 
+  * \brief Create a semaphore.
+  *
+  * Create a semaphore.
+  *
+  * @param sem   Pointer to memory to be initialized
+  * @param name  A name for this semaphore. The name may be truncated internally.
+  * @param count The initial count for the semaphore.
+  *
+  * @return VCOS_SUCCESS if the semaphore was created.
+  * 
+  */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_semaphore_create(VCOS_SEMAPHORE_T *sem, const char *name, VCOS_UNSIGNED count);
+
+/**
+  * \brief Wait on a semaphore.
+  *
+  * There is no timeout option on a semaphore, as adding this will slow down
+  * implementations on some platforms. If you need that kind of behaviour, use
+  * an event group.
+  *
+  * On most platforms this always returns VCOS_SUCCESS, and so would ideally be
+  * a void function, however some platforms allow a wait to be interrupted so
+  * it remains non-void.
+  *
+  * @param sem Semaphore to wait on
+  * @return VCOS_SUCCESS - semaphore was taken.
+  *         VCOS_EAGAIN  - could not take semaphore
+  *
+  */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_semaphore_wait(VCOS_SEMAPHORE_T *sem);
+
+/**
+  * \brief Wait on a semaphore with a timeout.
+  *
+  * Note that this function may not be implemented on all
+  * platforms, and may not be efficient on all platforms
+  * (see comment in vcos_semaphore_wait)
+  *
+  * Try to obtain the semaphore. If it is already taken, return
+  * VCOS_EAGAIN.
+  * @param sem Semaphore to wait on
+  * @param timeout Number of milliseconds to wait before
+  *                returning if the semaphore can't be acquired.
+  * @return VCOS_SUCCESS - semaphore was taken.
+  *         VCOS_EAGAIN - could not take semaphore (i.e. timeout
+  *         expired)
+  *         VCOS_EINVAL - Some other error (most likely bad
+  *         parameters).
+  */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_semaphore_wait_timeout(VCOS_SEMAPHORE_T *sem, VCOS_UNSIGNED timeout);
+
+/**
+  * \brief Try to wait for a semaphore.
+  *
+  * Try to obtain the semaphore. If it is already taken, return VCOS_TIMEOUT.
+  * @param sem Semaphore to wait on
+  * @return VCOS_SUCCESS - semaphore was taken.
+  *         VCOS_EAGAIN - could not take semaphore
+  */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_semaphore_trywait(VCOS_SEMAPHORE_T *sem);
+
+/**
+  * \brief Post a semaphore.
+  *
+  * @param sem Semaphore to wait on
+  */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_semaphore_post(VCOS_SEMAPHORE_T *sem);
+
+/**
+  * \brief Delete a semaphore, releasing any resources consumed by it.
+  *
+  * @param sem Semaphore to wait on
+  */
+VCOS_INLINE_DECL
+void vcos_semaphore_delete(VCOS_SEMAPHORE_T *sem);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
+
diff --git a/interface/vcos/vcos_stdbool.h b/interface/vcos/vcos_stdbool.h
new file mode 100755 (executable)
index 0000000..25b0e09
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef VCOS_STDBOOL_H
+#define VCOS_STDBOOL_H
+
+#ifndef __cplusplus
+
+#if defined(__STDC__) && (__STDC_VERSION__ >= 199901L)
+#include <stdbool.h>
+#else
+/* sizeof(bool) == 1. hopefully this matches up with c++ (so structures and
+ * such containing bool are binary compatible), but the c++ standard doesn't
+ * require sizeof(bool) == 1, so there's no guarantee */
+typedef unsigned char bool;
+enum {
+   false,
+   true
+};
+#endif
+
+#endif /* __cplusplus */
+
+#endif
diff --git a/interface/vcos/vcos_stdint.h b/interface/vcos/vcos_stdint.h
new file mode 100755 (executable)
index 0000000..6b5851a
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VCOS_STDINT_H
+#define VCOS_STDINT_H
+
+/** \file
+ * Attempt to provide the types defined in stdint.h.
+ *
+ * Except for use with lcc, this simply includes stdint.h, which should find
+ * the system/toolchain version if present, otherwise falling back to the
+ * version in interface/vcos/<platform>.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined (VCMODS_LCC)
+
+#include <limits.h>
+
+typedef signed   char      int8_t;
+typedef unsigned char      uint8_t;
+
+typedef signed   short     int16_t;
+typedef unsigned short     uint16_t;
+
+typedef signed   long      int32_t;
+typedef unsigned long      uint32_t;
+
+typedef int32_t            intptr_t;
+typedef uint32_t           uintptr_t;
+
+typedef int32_t            intmax_t;
+typedef uint32_t           uintmax_t;
+
+typedef int8_t             int_least8_t;
+typedef int16_t            int_least16_t;
+typedef int32_t            int_least32_t;
+typedef uint8_t            uint_least8_t;
+typedef uint16_t           uint_least16_t;
+typedef uint32_t           uint_least32_t;
+
+#define INT8_MIN SCHAR_MIN
+#define INT8_MAX SCHAR_MAX
+#define UINT8_MAX UCHAR_MAX
+
+#define INT16_MIN SHRT_MIN
+#define INT16_MAX SHRT_MAX
+#define UINT16_MAX USHRT_MAX
+
+#define INT32_MIN LONG_MIN
+#define INT32_MAX LONG_MAX
+#define UINT32_MAX ULONG_MAX
+
+#define INTPTR_MIN INT32_MIN
+#define INTPTR_MAX INT32_MAX
+#define UINTPTR_MAX UINT32_MAX
+
+#define INTMAX_MIN INT32_MIN
+#define INTMAX_MAX INT32_MAX
+#define UINTMAX_MAX UINT32_MAX
+
+/* N.B. 64-bit integer types are not currently supported by lcc.
+ * However, these symbols are referenced in header files included by files
+ * compiled by lcc for VCE, so removing them would break the build.
+ * The solution here then is to define them, as the correct size, but in a
+ * way that should make them unusable in normal arithmetic operations.
+ */
+typedef struct { uint32_t a; uint32_t b; }  int64_t;
+typedef struct { uint32_t a; uint32_t b; } uint64_t;
+
+#else
+
+#include <stdint.h>
+
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* VCOS_STDINT_H */
diff --git a/interface/vcos/vcos_string.h b/interface/vcos/vcos_string.h
new file mode 100755 (executable)
index 0000000..7a6b938
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - public header file
+=============================================================================*/
+
+#ifndef VCOS_STRING_H
+#define VCOS_STRING_H
+
+/**
+  * \file
+  *
+  * String functions.
+  *
+  */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#include "vcos.h"
+
+#ifdef __KERNEL__
+#include <linux/string.h>
+#else
+#include <string.h>
+#endif
+
+/** Case insensitive string comparison.
+  *
+  */
+
+VCOS_INLINE_DECL
+int vcos_strcasecmp(const char *s1, const char *s2);
+
+VCOS_INLINE_DECL
+int vcos_strncasecmp(const char *s1, const char *s2, size_t n);
+
+VCOSPRE_ int VCOSPOST_ vcos_vsnprintf(char *buf, size_t buflen, const char *fmt, va_list ap);
+
+VCOSPRE_ int VCOSPOST_ vcos_snprintf(char *buf, size_t buflen, const char *fmt, ...);
+
+/** Like vsnprintf, except it places the output at the specified offset.
+  * Output is truncated to fit in buflen bytes, and is guaranteed to be NUL-terminated.
+  * Returns the string length before/without truncation.
+  */
+VCOSPRE_ size_t VCOSPOST_ vcos_safe_vsprintf(char *buf, size_t buflen, size_t offset, const char *fmt, va_list ap);
+
+#define VCOS_SAFE_VSPRINTF(buf, offset, fmt, ap) \
+   vcos_safe_vsprintf(buf, sizeof(buf) + ((char (*)[sizeof(buf)])buf - &(buf)), offset, fmt, ap)
+
+/** Like snprintf, except it places the output at the specified offset.
+  * Output is truncated to fit in buflen bytes, and is guaranteed to be NUL-terminated.
+  * Returns the string length before/without truncation.
+  */
+VCOSPRE_ size_t VCOSPOST_ vcos_safe_sprintf(char *buf, size_t buflen, size_t offset, const char *fmt, ...);
+
+/* The Metaware compiler currently has a bug in its variadic macro handling which
+   causes it to append a spurious command to the end of its __VA_ARGS__ data.
+   Do not use until this has been fixed (and this comment has been deleted). */
+
+#define VCOS_SAFE_SPRINTF(buf, offset, ...) \
+   vcos_safe_sprintf(buf, sizeof(buf) + ((char (*)[sizeof(buf)])buf - &(buf)), offset, __VA_ARGS__)
+
+/** Copies string src to dst at the specified offset.
+  * Output is truncated to fit in dstlen bytes, i.e. the string is at most
+  * (buflen - 1) characters long. Unlike strncpy, exactly one NUL is written
+  * to dst, which is always NUL-terminated.
+  * Returns the string length before/without truncation.
+  */
+VCOSPRE_ size_t VCOSPOST_ vcos_safe_strcpy(char *dst, const char *src, size_t dstlen, size_t offset);
+
+#define VCOS_SAFE_STRCPY(dst, src, offset) \
+   vcos_safe_strcpy(dst, src, sizeof(dst) + ((char (*)[sizeof(dst)])dst - &(dst)), offset)
+
+VCOS_STATIC_INLINE
+int vcos_strlen(const char *s) { return (int)strlen(s); }
+
+VCOS_STATIC_INLINE
+int vcos_strcmp(const char *s1, const char *s2) { return strcmp(s1,s2); }
+
+VCOS_STATIC_INLINE
+int vcos_strncmp(const char *cs, const char *ct, size_t count) { return strncmp(cs, ct, count); }
+
+VCOS_STATIC_INLINE
+char *vcos_strcpy(char *dst, const char *src) { return strcpy(dst, src); }
+
+VCOS_STATIC_INLINE
+char *vcos_strncpy(char *dst, const char *src, size_t count) { return strncpy(dst, src, count); }
+
+VCOS_STATIC_INLINE
+void *vcos_memcpy(void *dst, const void *src, size_t n) {  memcpy(dst, src, n);  return dst;  }
+
+VCOS_STATIC_INLINE
+void *vcos_memset(void *p, int c, size_t n) { return memset(p, c, n); }
+
+VCOS_STATIC_INLINE
+int vcos_memcmp(const void *ptr1, const void *ptr2, size_t count) { return memcmp(ptr1, ptr2, count); }
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/interface/vcos/vcos_thread.h b/interface/vcos/vcos_thread.h
new file mode 100755 (executable)
index 0000000..e43d591
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - public header file
+=============================================================================*/
+
+#ifndef VCOS_THREAD_H
+#define VCOS_THREAD_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#include "vcos.h"
+
+/**
+ * \file vcos_thread.h
+ *
+ * \section thread Threads
+ *
+ * Under Nucleus, a thread is created by NU_Create_Task, passing in the stack
+ * and various other parameters. To stop the thread, NU_Terminate_Thread() and
+ * NU_Delete_Thread() are called.
+ *
+ * Unfortunately it's not possible to emulate this API under some fairly common
+ * operating systems. Under Windows you can't pass in the stack, and you can't
+ * safely terminate a thread.
+ *
+ * Therefore, an API which is similar to the pthreads API is used instead. This
+ * API can (mostly) be emulated under all interesting operating systems.
+ *
+ * Obviously this makes the code somewhat more complicated on VideoCore than it
+ * would otherwise be - we end up with an extra mutex per thread, and some code
+ * that waits for it. The benefit is that we have a single way of creating
+ * threads that works consistently on all platforms (apart from stack supplying).
+ *
+ * \subsection stack Stack
+ *
+ * It's still not possible to pass in the stack address, but this can be made
+ * much more obvious in the API: the relevant function is missing and the
+ * CPP symbol VCOS_CAN_SET_STACK_ADDR is zero rather than one.
+ *
+ * \subsection thr_create Creating a thread
+ *
+ * The simplest way to create a thread is with vcos_thread_create() passing in a
+ * NULL thread parameter argument. To wait for the thread to exit, call
+ * vcos_thread_join().
+ *
+ * \subsection back Backward compatibility
+ *
+ * To ease migration, a "classic" thread creation API is provided for code
+ * that used to make use of Nucleus, vcos_thread_create_classic(). The
+ * arguments are not exactly the same, as the PREEMPT parameter is dropped.
+ *
+ */
+
+#define VCOS_AFFINITY_CPU0    _VCOS_AFFINITY_CPU0
+#define VCOS_AFFINITY_CPU1    _VCOS_AFFINITY_CPU1
+#define VCOS_AFFINITY_MASK    _VCOS_AFFINITY_MASK
+#define VCOS_AFFINITY_DEFAULT _VCOS_AFFINITY_DEFAULT
+#define VCOS_AFFINITY_THISCPU _VCOS_AFFINITY_THISCPU
+
+/** Report whether or not we have an RTOS at all, and hence the ability to
+  * create threads.
+  */
+VCOSPRE_ int VCOSPOST_ vcos_have_rtos(void);
+
+/** Create a thread. It must be cleaned up by calling vcos_thread_join().
+  *
+  * @param thread   Filled in on return with thread
+  * @param name     A name for the thread. May be the empty string.
+  * @param attrs    Attributes; default attributes will be used if this is NULL.
+  * @param entry    Entry point.
+  * @param arg      Argument passed to the entry point.
+  */
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_thread_create(VCOS_THREAD_T *thread,
+                                                    const char *name,
+                                                    VCOS_THREAD_ATTR_T *attrs,
+                                                    VCOS_THREAD_ENTRY_FN_T entry,
+                                                    void *arg);
+
+/** Exit the thread from within the thread function itself.
+  * Resources must still be cleaned up via a call to thread_join().
+  *
+  * The thread can also be terminated by simply exiting the thread function.
+  *
+  * @param data Data passed to thread_join. May be NULL.
+  */
+VCOSPRE_ void VCOSPOST_ vcos_thread_exit(void *data);
+
+/** Wait for a thread to terminate and then clean up its resources.
+  *
+  * @param thread Thread to wait for
+  * @param pData  Updated to point at data provided in vcos_thread_exit or exit
+  * code of thread function.
+  */
+VCOSPRE_ void VCOSPOST_ vcos_thread_join(VCOS_THREAD_T *thread,
+                             void **pData);
+
+
+/**
+  * \brief Create a thread using an API similar to the one "traditionally"
+  * used under Nucleus.
+  *
+  * This creates a thread which must be cleaned up by calling vcos_thread_join().
+  * The thread cannot be simply terminated (as in Nucleus and ThreadX) as thread
+  * termination is not universally supported.
+  *
+  * @param thread       Filled in with thread instance
+  * @param name         An optional name for the thread. NULL or "" may be used (but
+  *                     a name will aid in debugging).
+  * @param entry        Entry point
+  * @param arg          A single argument passed to the entry point function
+  * @param stack        Pointer to stack address
+  * @param stacksz      Size of stack in bytes
+  * @param priaff       Priority of task, between VCOS_PRI_LOW and VCOS_PRI_HIGH, ORed with the CPU affinity
+  * @param autostart    If non-zero the thread will start immediately.
+  * @param timeslice    Timeslice (system ticks) for this thread.
+  *
+  * @sa vcos_thread_terminate vcos_thread_delete
+  */
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_thread_create_classic(VCOS_THREAD_T *thread,
+                                                            const char *name,
+                                                            void *(*entry)(void *arg),
+                                                            void *arg,
+                                                            void *stack,
+                                                            VCOS_UNSIGNED stacksz,
+                                                            VCOS_UNSIGNED priaff,
+                                                            VCOS_UNSIGNED timeslice,
+                                                            VCOS_UNSIGNED autostart);
+
+/**
+  * \brief Set a thread's priority
+  *
+  * Set the priority for a thread.
+  *
+  * @param thread  The thread
+  * @param pri     Thread priority in VCOS_PRI_MASK bits; affinity in VCOS_AFFINITY_MASK bits.
+  */
+VCOS_INLINE_DECL
+void vcos_thread_set_priority(VCOS_THREAD_T *thread, VCOS_UNSIGNED pri);
+
+/**
+  * \brief Return the currently executing thread.
+  *
+  */
+VCOS_INLINE_DECL
+VCOS_THREAD_T *vcos_thread_current(void);
+
+/**
+  * \brief Return the thread's priority.
+  */
+VCOS_INLINE_DECL
+VCOS_UNSIGNED vcos_thread_get_priority(VCOS_THREAD_T *thread);
+
+/**
+  * \brief Return the thread's cpu affinity.
+  */
+VCOS_INLINE_DECL
+VCOS_UNSIGNED vcos_thread_get_affinity(VCOS_THREAD_T *thread);
+
+/**
+  * \brief Set the thread's cpu affinity.
+  */
+
+VCOS_INLINE_DECL
+void vcos_thread_set_affinity(VCOS_THREAD_T *thread, VCOS_UNSIGNED affinity);
+
+/**
+  * \brief Query whether we are in an interrupt.
+  *
+  * @return 1 if in interrupt context.
+  */
+VCOS_INLINE_DECL
+int vcos_in_interrupt(void);
+
+/**
+  * \brief Sleep a while.
+  *
+  * @param ms Number of milliseconds to sleep for
+  *
+  * This may actually sleep a whole number of ticks.
+  */
+VCOS_INLINE_DECL
+void vcos_sleep(uint32_t ms);
+
+/**
+  * \brief Return the value of the hardware microsecond counter.
+  *
+  */
+VCOS_INLINE_DECL
+uint32_t vcos_getmicrosecs(void);
+
+VCOS_INLINE_DECL
+uint64_t vcos_getmicrosecs64(void);
+
+#define vcos_get_ms() (vcos_getmicrosecs()/1000)
+
+/**
+  * \brief Return a unique identifier for the current process
+  *
+  */
+VCOS_INLINE_DECL
+VCOS_UNSIGNED vcos_process_id_current(void);
+
+/** Relinquish this time slice. */
+VCOS_INLINE_DECL
+void vcos_thread_relinquish(void);
+
+/** Return the name of the given thread.
+  */
+VCOSPRE_ const char * VCOSPOST_ vcos_thread_get_name(const VCOS_THREAD_T *thread);
+
+/** Change preemption. This is almost certainly not what you want, as it won't
+  * work reliably in a multicore system: although you can affect the preemption
+  * on *this* core, you won't affect what's happening on the other core(s).
+  *
+  * It's mainly here to ease migration. If you're using it in new code, you
+  * probably need to think again.
+  *
+  * @param pe New preemption, VCOS_PREEMPT or VCOS_NO_PREEMPT
+  * @return Old value of preemption.
+  */
+VCOS_INLINE_DECL
+VCOS_UNSIGNED vcos_change_preemption(VCOS_UNSIGNED pe);
+
+/** Is a thread still running, or has it exited?
+  *
+  * Note: this exists for some fairly scary code in the video codec tests. Don't
+  * try to use it for anything else, as it may well not do what you expect.
+  *
+  * @param thread   thread to query
+  * @return non-zero if thread is running, or zero if it has exited.
+  */
+VCOS_INLINE_DECL
+int vcos_thread_running(VCOS_THREAD_T *thread);
+
+/** Resume a thread.
+  *
+  * @param thread thread to resume
+  */
+VCOS_INLINE_DECL
+void vcos_thread_resume(VCOS_THREAD_T *thread);
+
+/*
+ * Internal APIs - may not always be present and should not be used in
+ * client code.
+ */
+
+extern void _vcos_task_timer_set(void (*pfn)(void*), void *, VCOS_UNSIGNED ms);
+extern void _vcos_task_timer_cancel(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/interface/vcos/vcos_thread_attr.h b/interface/vcos/vcos_thread_attr.h
new file mode 100755 (executable)
index 0000000..9eddd69
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - thread attributes
+=============================================================================*/
+
+#ifndef VCOS_THREAD_ATTR_H
+#define VCOS_THREAD_ATTR_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * \file
+ *
+ * Attributes for thread creation.
+ *
+ */
+
+/** Initialize thread attribute struct. This call does not allocate memory,
+  * and so cannot fail.
+  *
+  */
+VCOSPRE_ void VCOSPOST_ vcos_thread_attr_init(VCOS_THREAD_ATTR_T *attrs);
+
+/** Set the stack address and size. If not set, a stack will be allocated automatically.
+  *
+  * This can only be set on some platforms. It will always be possible to set the stack
+  * address on VideoCore, but on host platforms, support may well not be available.
+  */
+#if VCOS_CAN_SET_STACK_ADDR
+VCOS_INLINE_DECL
+void vcos_thread_attr_setstack(VCOS_THREAD_ATTR_T *attrs, void *addr, VCOS_UNSIGNED sz);
+#endif
+
+/** Set the stack size. If not set, a default size will be used. Attempting to call this after having
+  * set the stack location with vcos_thread_attr_setstack() will result in undefined behaviour.
+  */
+VCOS_INLINE_DECL
+void vcos_thread_attr_setstacksize(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED sz);
+
+/** Set the task priority. If not set, a default value will be used.
+  */
+VCOS_INLINE_DECL
+void vcos_thread_attr_setpriority(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED pri);
+
+/** Set the task cpu affinity. If not set, the default will be used.
+  */
+VCOS_INLINE_DECL
+void vcos_thread_attr_setaffinity(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED aff);
+
+/** Set the timeslice. If not set the default will be used.
+  */
+VCOS_INLINE_DECL
+void vcos_thread_attr_settimeslice(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED ts);
+
+/** The thread entry function takes (argc,argv), as per Nucleus, with
+  * argc being 0. This may be withdrawn in a future release and should not
+  * be used in new code.
+  */
+VCOS_INLINE_DECL
+void _vcos_thread_attr_setlegacyapi(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED legacy);
+
+VCOS_INLINE_DECL
+void vcos_thread_attr_setautostart(VCOS_THREAD_ATTR_T *attrs, VCOS_UNSIGNED autostart);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/interface/vcos/vcos_timer.h b/interface/vcos/vcos_timer.h
new file mode 100755 (executable)
index 0000000..d61391c
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - timer support
+=============================================================================*/
+
+#ifndef VCOS_TIMER_H
+#define VCOS_TIMER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#ifndef VCOS_PLATFORM_H
+#include "vcos.h"
+#endif
+
+/** \file vcos_timer.h
+  *
+  * Timers are single shot.
+  *
+  * Timer times are in milliseconds.
+  *
+  * \note that timer callback functions are called from an arbitrary thread
+  * context. The expiration function should do its work as quickly as possible;
+  * blocking should be avoided.
+  *
+  * \note On Windows, the separate function vcos_timer_init() must be called
+  * as timer initialization from DllMain is not possible.
+  */
+
+/** Perform timer subsystem initialization. This function is not needed
+  * on non-Windows platforms but is still present so that it can be
+  * called. On Windows it is needed because vcos_init() gets called
+  * from DLL initialization where it is not possible to create a
+  * time queue (deadlock occurs if you try).
+  *
+  * @return VCOS_SUCCESS on success. VCOS_EEXIST if this has already been called
+  * once. VCOS_ENOMEM if resource allocation failed.
+  */
+VCOSPRE_ VCOS_STATUS_T VCOSPOST_ vcos_timer_init(void);
+
+/** Create a timer in a disabled state.
+  *
+  * The timer is initially disabled.
+  *
+  * @param timer     timer handle
+  * @param name      name for timer
+  * @param expiration_routine function to call when timer expires
+  * @param context   context passed to expiration routine
+  *
+  */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_timer_create(VCOS_TIMER_T *timer,
+                                const char *name,
+                                void (*expiration_routine)(void *context),
+                                void *context);
+
+
+
+/** Start a timer running.
+  *
+  * Timer must be stopped.
+  *
+  * @param timer     timer handle
+  * @param delay     Delay to wait for, in ms
+  */
+VCOS_INLINE_DECL
+void vcos_timer_set(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay);
+
+/** Stop an already running timer.
+  *
+  * @param timer     timer handle
+  */
+VCOS_INLINE_DECL
+void vcos_timer_cancel(VCOS_TIMER_T *timer);
+
+/** Stop a timer and restart it.
+  * @param timer     timer handle
+  * @param delay     delay in ms
+  */
+VCOS_INLINE_DECL
+void vcos_timer_reset(VCOS_TIMER_T *timer, VCOS_UNSIGNED delay);
+
+VCOS_INLINE_DECL
+void vcos_timer_delete(VCOS_TIMER_T *timer);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/interface/vcos/vcos_tls.h b/interface/vcos/vcos_tls.h
new file mode 100755 (executable)
index 0000000..a0df40c
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - thread local storage
+=============================================================================*/
+
+#ifndef VCOS_TLS_H
+#define VCOS_TLS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "interface/vcos/vcos_types.h"
+#include "vcos.h"
+
+
+/** Create a new thread local storage data key visible to all threads in
+  * the current process.
+  *
+  * @param key    The key to create
+  */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_tls_create(VCOS_TLS_KEY_T *key);
+
+/** Delete an existing TLS data key.
+  */
+VCOS_INLINE_DECL
+void vcos_tls_delete(VCOS_TLS_KEY_T tls);
+
+/** Set the value seen by the current thread.
+  *
+  * @param key    The key to update
+  * @param v      The value to set for the current thread.
+  *
+  * @return VCOS_SUCCESS, or VCOS_ENOMEM if memory for this slot
+  * could not be allocated.
+  *
+  * If TLS is being emulated via VCOS then the memory required
+  * can be preallocated at thread creation time
+  */
+VCOS_INLINE_DECL
+VCOS_STATUS_T vcos_tls_set(VCOS_TLS_KEY_T tls, void *v);
+
+/** Get the value for the current thread.
+  *
+  * @param key    The key to update
+  *
+  * @return The current value for this thread.
+  */
+VCOS_INLINE_DECL
+void *vcos_tls_get(VCOS_TLS_KEY_T tls);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/interface/vcos/vcos_types.h b/interface/vcos/vcos_types.h
new file mode 100755 (executable)
index 0000000..835a77f
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+VideoCore OS Abstraction Layer - basic types
+=============================================================================*/
+
+#ifndef VCOS_TYPES_H
+#define VCOS_TYPES_H
+
+#define VCOS_VERSION   1
+
+#include <stddef.h>
+#if defined(__unix__) && !defined(__ANDROID__)
+#include "interface/vcos/pthreads/vcos_platform_types.h"
+#else
+#include "vcos_platform_types.h"
+#endif
+#include "interface/vcos/vcos_attr.h"
+
+#if !defined(VCOSPRE_) || !defined(VCOSPOST_)
+#error VCOSPRE_ or VCOSPOST_ not defined!
+#endif
+
+/* Redefine these here; this means that existing header files can carry on
+ * using the VCHPOST/VCHPRE macros rather than having huge changes, which
+ * could cause nasty merge problems.
+ */
+#ifndef VCHPOST_
+#define VCHPOST_ VCOSPOST_
+#endif
+#ifndef VCHPRE_
+#define VCHPRE_  VCOSPRE_
+#endif
+
+/** Entry function for a lowlevel thread.
+  *
+  * Returns void for consistency with Nucleus/ThreadX.
+  */
+typedef void (*VCOS_LLTHREAD_ENTRY_FN_T)(void *);
+
+/** Thread entry point. Returns a void* for consistency
+  * with pthreads.
+  */
+typedef void *(*VCOS_THREAD_ENTRY_FN_T)(void*);
+
+
+/* Error return codes - chosen to be similar to errno values */
+typedef enum
+{
+   VCOS_SUCCESS,
+   VCOS_EAGAIN,
+   VCOS_ENOENT,
+   VCOS_ENOSPC,
+   VCOS_EINVAL,
+   VCOS_EACCESS,
+   VCOS_ENOMEM,
+   VCOS_ENOSYS,
+   VCOS_EEXIST,
+   VCOS_ENXIO,
+   VCOS_EINTR
+} VCOS_STATUS_T;
+
+/* Some compilers (MetaWare) won't inline with -g turned on, which then results
+ * in a lot of code bloat. To overcome this, inline functions are forward declared
+ * with the prefix VCOS_INLINE_DECL, and implemented with the prefix VCOS_INLINE_IMPL.
+ *
+ * That then means that in a release build, "static inline" can be used in the obvious
+ * way, but in a debug build the implementations can be skipped in all but one file,
+ * by using VCOS_INLINE_BODIES.
+ *
+ * VCOS_INLINE_DECL - put this at the start of an inline forward declaration of a VCOS
+ * function.
+ *
+ * VCOS_INLINE_IMPL - put this at the start of an inlined implementation of a VCOS
+ * function.
+ *
+ */
+
+/* VCOS_EXPORT - it turns out that in some circumstances we need the implementation of
+ * a function even if it is usually inlined.
+ *
+ * In particular, if we have a codec that is usually provided in object form, if it
+ * was built for a debug build it will be full of calls to vcos_XXX(). If this is used
+ * in a *release* build, then there won't be any of these calls around in the main image
+ * as they will all have been inlined. The problem also exists for vcos functions called
+ * from assembler.
+ *
+ * VCOS_EXPORT ensures that the named function will be emitted as a regular (not static-inline)
+ * function inside vcos_<platform>.c so that it can be linked against. Doing this for every
+ * VCOS function would be a bit code-bloat-tastic, so it is only done for those that need it.
+ *
+ */
+
+#ifdef __cplusplus
+#define _VCOS_INLINE inline
+#else
+#define _VCOS_INLINE __inline
+#endif
+
+#if defined(NDEBUG)
+
+#ifdef __GNUC__
+# define VCOS_INLINE_DECL extern __inline__
+# define VCOS_INLINE_IMPL static __inline__
+#else
+# define VCOS_INLINE_DECL static _VCOS_INLINE   /* declare a func */
+# define VCOS_INLINE_IMPL static _VCOS_INLINE   /* implement a func inline */
+#endif
+
+# if defined(VCOS_WANT_IMPL)
+#  define VCOS_EXPORT
+# else
+#  define VCOS_EXPORT VCOS_INLINE_IMPL
+# endif /* VCOS_WANT_IMPL */
+
+#define VCOS_INLINE_BODIES
+
+#else /* NDEBUG */
+
+#if !defined(VCOS_INLINE_DECL)
+   #define VCOS_INLINE_DECL extern
+#endif
+#if !defined(VCOS_INLINE_IMPL)
+   #define VCOS_INLINE_IMPL
+#endif
+#define VCOS_EXPORT VCOS_INLINE_IMPL
+#endif
+
+#define VCOS_STATIC_INLINE static _VCOS_INLINE
+
+#if defined(__HIGHC__) || defined(__HIGHC_ANSI__)
+#define _VCOS_METAWARE
+#endif
+
+/** It seems that __FUNCTION__ isn't standard!
+  */
+#if __STDC_VERSION__ < 199901L
+# if __GNUC__ >= 2 || defined(__VIDEOCORE__)
+#  define VCOS_FUNCTION __FUNCTION__
+# else
+#  define VCOS_FUNCTION "<unknown>"
+# endif
+#else
+# define VCOS_FUNCTION __func__
+#endif
+
+#define _VCOS_MS_PER_TICK (1000/VCOS_TICKS_PER_SECOND)
+
+/* Convert a number of milliseconds to a tick count. Internal use only - fails to
+ * convert VCOS_SUSPEND correctly.
+ */
+#define _VCOS_MS_TO_TICKS(ms) (((ms)+_VCOS_MS_PER_TICK-1)/_VCOS_MS_PER_TICK)
+
+#define VCOS_TICKS_TO_MS(ticks) ((ticks) * _VCOS_MS_PER_TICK)
+
+/** VCOS version of DATESTR, from pcdisk.h. Used by the hostreq service.
+ */
+typedef struct vcos_datestr
+{
+   uint8_t       cmsec;              /**< Centesimal mili second */
+   uint16_t      date;               /**< Date */
+   uint16_t      time;               /**< Time */
+
+} VCOS_DATESTR;
+
+/* Compile-time assert - declares invalid array length if condition
+ * not met, or array of length one if OK.
+ */
+#define VCOS_CASSERT(e) extern char vcos_compile_time_check[1/(e)]
+
+#define vcos_min(x,y) ((x) < (y) ? (x) : (y))
+#define vcos_max(x,y) ((x) > (y) ? (x) : (y))
+
+/** Return the count of an array. FIXME: under gcc we could make
+ * this report an error for pointers using __builtin_types_compatible().
+ */
+#define vcos_countof(x) (sizeof((x)) / sizeof((x)[0]))
+
+/* for backward compatibility */
+#define countof(x) (sizeof((x)) / sizeof((x)[0]))
+
+#define VCOS_ALIGN_DOWN(p,n) (((ptrdiff_t)(p)) & ~((n)-1))
+#define VCOS_ALIGN_UP(p,n) VCOS_ALIGN_DOWN((ptrdiff_t)(p)+(n)-1,(n))
+
+#ifdef _MSC_VER
+   #define vcos_alignof(T) __alignof(T)
+#elif defined(__GNUC__)
+   #define vcos_alignof(T) __alignof__(T)
+#else
+   #define vcos_alignof(T) (sizeof(struct { T t; char ch; }) - sizeof(T))
+#endif
+
+/** bool_t is not a POSIX type so cannot rely on it. Define it here.
+  * It's not even defined in stdbool.h.
+  */
+typedef int32_t vcos_bool_t;
+typedef int32_t vcos_fourcc_t;
+
+#define VCOS_FALSE   0
+#define VCOS_TRUE    (!VCOS_FALSE)
+
+/** Mark unused arguments to keep compilers quiet */
+#define vcos_unused(x) (void)(x)
+
+/** For backward compatibility */
+typedef vcos_fourcc_t fourcc_t;
+typedef vcos_fourcc_t FOURCC_T;
+
+#ifdef __cplusplus
+#define VCOS_EXTERN_C_BEGIN extern "C" {
+#define VCOS_EXTERN_C_END }
+#else
+#define VCOS_EXTERN_C_BEGIN
+#define VCOS_EXTERN_C_END
+#endif
+
+/** Variable attribute indicating the variable must be emitted even if it appears unused. */
+#if defined(__GNUC__) || defined(_VCOS_METAWARE)
+# define VCOS_ATTR_USED  __attribute__ ((used))
+#else
+# define VCOS_ATTR_USED
+#endif
+
+/** Variable attribute requiring specific alignment. */
+#if defined(__GNUC__) || defined(_VCOS_METAWARE)
+# define VCOS_ATTR_ALIGNED(n)  __attribute__ ((aligned(n)))
+#else
+# define VCOS_ATTR_ALIGNED(n)
+#endif
+
+/** Define a function as a weak alias to another function.
+ * @param ret_type     Function return type.
+ * @param alias_name   Name of the alias.
+ * @param param_list   Function parameter list, including the parentheses.
+ * @param target_name  Target function (bare function name, not a string).
+ */
+#if defined(__GNUC__) || defined(_VCOS_METAWARE)
+  /* N.B. gcc allows __attribute__ after parameter list, but hcvc seems to silently ignore it. */
+# define VCOS_WEAK_ALIAS(ret_type, alias_name, param_list, target_name) \
+   __attribute__ ((weak, alias(#target_name))) ret_type alias_name param_list
+#else
+# define VCOS_WEAK_ALIAS(ret_type, alias, params, target)  VCOS_CASSERT(0)
+#endif
+
+/** Define a function as a weak alias to another function, specified as a string.
+ * @param ret_type     Function return type.
+ * @param alias_name   Name of the alias.
+ * @param param_list   Function parameter list, including the parentheses.
+ * @param target_name  Target function name as a string.
+ * @note Prefer the use of VCOS_WEAK_ALIAS - it is likely to be more portable.
+ *       Only use VCOS_WEAK_ALIAS_STR if you need to do pre-processor mangling of the target
+ *       symbol.
+ */
+#if defined(__GNUC__) || defined(_VCOS_METAWARE)
+  /* N.B. gcc allows __attribute__ after parameter list, but hcvc seems to silently ignore it. */
+# define VCOS_WEAK_ALIAS_STR(ret_type, alias_name, param_list, target_name) \
+   __attribute__ ((weak, alias(target_name))) ret_type alias_name param_list
+#else
+# define VCOS_WEAK_ALIAS_STR(ret_type, alias, params, target)  VCOS_CASSERT(0)
+#endif
+
+#if defined(__GNUC__)
+#define VCOS_DEPRECATED(msg) __attribute__((deprecated(msg)))
+#else
+#define VCOS_DEPRECATED(msg)
+#endif
+
+#endif
diff --git a/interface/vctypes/vc_display_types.h b/interface/vctypes/vc_display_types.h
new file mode 100755 (executable)
index 0000000..dfde9d6
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*=============================================================================
+Common image types used by the vc_image library.
+=============================================================================*/
+
+#ifndef INTERFACE_VC_DISPLAY_TYPES_H
+#define INTERFACE_VC_DISPLAY_TYPES_H
+
+//enums of display input format
+typedef enum
+{
+   VCOS_DISPLAY_INPUT_FORMAT_INVALID = 0,
+   VCOS_DISPLAY_INPUT_FORMAT_RGB888,
+   VCOS_DISPLAY_INPUT_FORMAT_RGB565
+}
+VCOS_DISPLAY_INPUT_FORMAT_T;
+
+/** For backward compatibility */
+#define DISPLAY_INPUT_FORMAT_INVALID VCOS_DISPLAY_INPUT_FORMAT_INVALID
+#define DISPLAY_INPUT_FORMAT_RGB888  VCOS_DISPLAY_INPUT_FORMAT_RGB888
+#define DISPLAY_INPUT_FORMAT_RGB565  VCOS_DISPLAY_INPUT_FORMAT_RGB565
+typedef VCOS_DISPLAY_INPUT_FORMAT_T DISPLAY_INPUT_FORMAT_T;
+
+// Enum determining how image data for 3D displays has to be supplied
+typedef enum
+{
+   DISPLAY_3D_UNSUPPORTED = 0,   // default
+   DISPLAY_3D_INTERLEAVED,       // For autosteroscopic displays
+   DISPLAY_3D_SBS_FULL_AUTO,     // Side-By-Side, Full Width (also used by some autostereoscopic displays)
+   DISPLAY_3D_SBS_HALF_HORIZ,    // Side-By-Side, Half Width, Horizontal Subsampling (see HDMI spec)
+   DISPLAY_3D_TB_HALF,           // Top-bottom 3D
+   DISPLAY_3D_FRAME_PACKING,     // Frame Packed 3D
+   DISPLAY_3D_FRAME_SEQUENTIAL,  // Output left on even frames and right on odd frames (typically 120Hz)
+   DISPLAY_3D_FORMAT_MAX
+} DISPLAY_3D_FORMAT_T;
+
+//enums of display types
+typedef enum
+{
+   DISPLAY_INTERFACE_MIN,
+   DISPLAY_INTERFACE_SMI,
+   DISPLAY_INTERFACE_DPI,
+   DISPLAY_INTERFACE_DSI,
+   DISPLAY_INTERFACE_LVDS,
+   DISPLAY_INTERFACE_MAX
+
+} DISPLAY_INTERFACE_T;
+
+/* display dither setting, used on B0 */
+typedef enum {
+   DISPLAY_DITHER_NONE   = 0,   /* default if not set */
+   DISPLAY_DITHER_RGB666 = 1,
+   DISPLAY_DITHER_RGB565 = 2,
+   DISPLAY_DITHER_RGB555 = 3,
+   DISPLAY_DITHER_MAX
+} DISPLAY_DITHER_T;
+
+//info struct
+typedef struct
+{
+   //type
+   DISPLAY_INTERFACE_T type;
+   //width / height
+   uint32_t width;
+   uint32_t height;
+   //output format
+   DISPLAY_INPUT_FORMAT_T input_format;
+   //interlaced?
+   uint32_t interlaced;
+   /* output dither setting (if required) */
+   DISPLAY_DITHER_T output_dither;
+   /* Pixel frequency */
+   uint32_t pixel_freq;
+   /* Line rate in lines per second */
+   uint32_t line_rate;
+   // Format required for image data for 3D displays
+   DISPLAY_3D_FORMAT_T format_3d;
+   // If display requires PV1 (e.g. DSI1), special config is required in HVS
+   uint32_t use_pixelvalve_1;
+   // Set for DSI displays which use video mode.
+   uint32_t dsi_video_mode;
+   // Select HVS channel (usually 0).
+   uint32_t hvs_channel;
+} DISPLAY_INFO_T;
+
+#endif /* __VC_INCLUDE_IMAGE_TYPES_H__ */
+
+
diff --git a/interface/vctypes/vc_image_structs.h b/interface/vctypes/vc_image_structs.h
new file mode 100755 (executable)
index 0000000..f877e1a
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef INTERFACE_VC_IMAGE_STRUCTS_H
+#define INTERFACE_VC_IMAGE_STRUCTS_H
+
+/* This file gets included by the VCE compiler, which gets confused
+ * easily by the VCOS headers. So cannot include vcos.h here.
+ */
+#include "interface/vcos/vcos_stdint.h"
+#include "interface/vcos/vcos_attr.h"
+
+#include "helpers/debug_utils/debug_writer.h"
+
+#include "interface/vctypes/vc_image_types.h"
+
+   /* Format specific infos for vc images */
+
+   /* YUV information, co-sited h/v flags & colour space words */
+   typedef enum {
+      VC_IMAGE_YUVINFO_UNSPECIFIED    = 0,   /* Unknown or unset - defaults to BT601 interstitial */
+
+      /* colour-space conversions data [4 bits] */
+      /* Note that colour conversions for SMPTE 170M are identical to BT.601 */
+      VC_IMAGE_YUVINFO_CSC_ITUR_BT601      = 1,   /* ITU-R BT.601-5 [SDTV] (compatible with VideoCore-II) */
+      VC_IMAGE_YUVINFO_CSC_ITUR_BT709      = 2,   /* ITU-R BT.709-3 [HDTV] */
+      VC_IMAGE_YUVINFO_CSC_JPEG_JFIF       = 3,   /* JPEG JFIF */
+      VC_IMAGE_YUVINFO_CSC_FCC             = 4,   /* Title 47 Code of Federal Regulations (2003) 73.682 (a) (20) */
+      VC_IMAGE_YUVINFO_CSC_SMPTE_240M      = 5,   /* Society of Motion Picture and Television Engineers 240M (1999) */
+      VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_M  = 6,  /* ITU-R BT.470-2 System M */
+      VC_IMAGE_YUVINFO_CSC_ITUR_BT470_2_BG = 7,  /* ITU-R BT.470-2 System B,G */
+      VC_IMAGE_YUVINFO_CSC_JPEG_JFIF_Y16_255 = 8, /* JPEG JFIF, but with 16..255 luma */
+      VC_IMAGE_YUVINFO_CSC_CUSTOM          = 15,  /* Custom colour matrix follows header */
+      VC_IMAGE_YUVINFO_CSC_SMPTE_170M      = VC_IMAGE_YUVINFO_CSC_ITUR_BT601,
+
+      /* co-sited flags, assumed interstitial if not co-sited [2 bits] */
+      VC_IMAGE_YUVINFO_H_COSITED      = 256,
+      VC_IMAGE_YUVINFO_V_COSITED      = 512,
+
+      VC_IMAGE_YUVINFO_TOP_BOTTOM     = 1024,
+      VC_IMAGE_YUVINFO_DECIMATED      = 2048,
+      VC_IMAGE_YUVINFO_PACKED         = 4096,
+
+      /* Certain YUV image formats can either be V/U interleaved or U/V interleaved */
+      VC_IMAGE_YUVINFO_IS_VU          = 0x8000,
+
+      /* Force Metaware to use 16 bits */
+      VC_IMAGE_YUVINFO_FORCE_ENUM_16BIT = 0xffff,
+   } VC_IMAGE_YUVINFO_T;
+
+#define VC_IMAGE_YUV_UV_STRIPE_WIDTH_LOG2 7
+#define VC_IMAGE_YUV_UV_STRIPE_WIDTH (1 << VC_IMAGE_YUV_UV_STRIPE_WIDTH_LOG2)
+
+#define VC_IMAGE_YUV_UV32_STRIPE_WIDTH_LOG2 5
+#define VC_IMAGE_YUV_UV32_STRIPE_WIDTH (1 << VC_IMAGE_YUV_UV32_STRIPE_WIDTH_LOG2)
+
+/* 64 pixel wide stripes, 128 byte wide as 16bits/component */
+#define VC_IMAGE_YUV_UV_16_STRIPE_WIDTH_LOG2 6
+#define VC_IMAGE_YUV_UV_16_STRIPE_WIDTH (1 << VC_IMAGE_YUV_UV_16_STRIPE_WIDTH_LOG2)
+#define VC_IMAGE_YUV_UV_16_STRIPE_STRIDE_LOG2 7
+#define VC_IMAGE_YUV_UV_16_STRIPE_STRIDE (1 << VC_IMAGE_YUV_UV_16_STRIPE_STRIDE_LOG2)
+
+   /* The image structure. */
+   typedef struct vc_image_extra_uv_s {
+      void *u, *v;
+      int vpitch;
+   } VC_IMAGE_EXTRA_UV_T;
+
+   typedef struct vc_image_extra_rgba_s {
+      unsigned component_order   : 24, /* diagnostic use only */
+               normalised_alpha  : 1,
+               transparent_colour: 1,
+               unused_26_31      : 6;
+      unsigned int arg;
+   } VC_IMAGE_EXTRA_RGBA_T;
+
+   typedef struct vc_image_extra_pal_s {
+      short *palette;
+      int palette32 : 1;
+   } VC_IMAGE_EXTRA_PAL_T;
+
+// These fields are subject to change / being moved around
+   typedef struct vc_image_extra_tf_s {
+signed int mipmap_levels        : 8;
+unsigned int xxx                : 23;
+unsigned int cube_map           : 1;
+      void *palette;
+   } VC_IMAGE_EXTRA_TF_T;
+
+   typedef struct vc_image_extra_bayer_s {
+      unsigned short order;
+      unsigned short format;
+      int block_length;
+   } VC_IMAGE_EXTRA_BAYER_T;
+
+//The next block can be used with Visual C++
+//which treats enums as long ints
+   typedef struct vc_image_extra_msbayer_s {
+      unsigned char order;
+      unsigned char format;
+      unsigned char dummy1;
+      unsigned char dummy2;
+      int block_length;
+   } VC_IMAGE_EXTRA_MSBAYER_T;
+
+   typedef struct vc_image_extra_codec_s {
+      int fourcc;
+      int maxsize;  //NB this will be copied to image.size in parmalloc()
+   } VC_IMAGE_EXTRA_CODEC_T;
+
+#define VC_IMAGE_OPENGL_RGBA32    0x14011908       //GL_UNSIGNED_BYTE GL_RGBA
+#define VC_IMAGE_OPENGL_RGB24     0x14011907       //GL_UNSIGNED_BYTE GL_RGB
+#define VC_IMAGE_OPENGL_RGBA16    0x80331908       //GL_UNSIGNED_SHORT_4_4_4_4 GL_RGBA
+#define VC_IMAGE_OPENGL_RGBA5551  0x80341908       //GL_UNSIGNED_SHORT_5_5_5_1 GL_RGBA
+#define VC_IMAGE_OPENGL_RGB565    0x83631907       //GL_UNSIGNED_SHORT_5_6_5 GL_RGB
+#define VC_IMAGE_OPENGL_YA88      0x1401190A       //GL_UNSIGNED_BYTE GL_LUMINANCE_ALPHA
+#define VC_IMAGE_OPENGL_Y8        0x14011909       //GL_UNSIGNED_BYTE GL_LUMINANCE
+#define VC_IMAGE_OPENGL_A8        0x14011906       //GL_UNSIGNED_BYTE GL_ALPHA
+#define VC_IMAGE_OPENGL_ETC1      0x8D64           //GL_ETC1_RGB8_OES
+#define VC_IMAGE_OPENGL_PALETTE4_RGB24             0x8B90   //GL_PALETTE4_RGB8_OES
+#define VC_IMAGE_OPENGL_PALETTE4_RGBA32            0x8B91   //GL_PALETTE4_RGBA8_OES
+#define VC_IMAGE_OPENGL_PALETTE4_RGB565            0x8B92   //GL_PALETTE4_R5_G6_B5_OES
+#define VC_IMAGE_OPENGL_PALETTE4_RGBA16            0x8B93   //GL_PALETTE4_RGBA4_OES
+#define VC_IMAGE_OPENGL_PALETTE4_RGB5551           0x8B94   //GL_PALETTE4_RGB5_A1_OES
+#define VC_IMAGE_OPENGL_PALETTE8_RGB24             0x8B95   //GL_PALETTE8_RGB8_OES
+#define VC_IMAGE_OPENGL_PALETTE8_RGBA32            0x8B96   //GL_PALETTE8_RGBA8_OES
+#define VC_IMAGE_OPENGL_PALETTE8_RGB565            0x8B97   //GL_PALETTE8_R5_G6_B5_OES
+#define VC_IMAGE_OPENGL_PALETTE8_RGBA16            0x8B98   //GL_PALETTE8_RGBA4_OES
+#define VC_IMAGE_OPENGL_PALETTE8_RGB5551           0x8B99   //GL_PALETTE8_RGB5_A1_OES
+
+   typedef struct vc_image_extra_opengl_s {
+      unsigned int format_and_type;
+      void const *palette;
+   } VC_IMAGE_EXTRA_OPENGL_T;
+
+   typedef union {
+      VC_IMAGE_EXTRA_UV_T uv;
+      VC_IMAGE_EXTRA_RGBA_T rgba;
+      VC_IMAGE_EXTRA_PAL_T pal;
+      VC_IMAGE_EXTRA_TF_T tf;
+      VC_IMAGE_EXTRA_BAYER_T bayer;
+      VC_IMAGE_EXTRA_MSBAYER_T msbayer;
+      VC_IMAGE_EXTRA_CODEC_T codec;
+      VC_IMAGE_EXTRA_OPENGL_T opengl;
+   } VC_IMAGE_EXTRA_T;
+
+   /* structure containing various colour meta-data for each format */
+   typedef union {
+#ifdef __HIGHC__
+      VC_IMAGE_YUVINFO_T      yuv;   /* We know Metaware will use 16 bits for this enum, so use the correct type for debug info */
+#else
+      unsigned short          yuv;   /* Information pertinent to all YUV implementations */
+#endif
+      unsigned short          info;  /* dummy, force size to min 16 bits */
+   } VC_IMAGE_INFO_T;
+
+
+   /**
+    * Image handle object, which must be locked before image data becomes
+    * accessible.
+    *
+    * A handle to an image where the image data does not have a guaranteed
+    * storage location.  A call to \c vc_image_lock() must be made to convert
+    * this into a \c VC_IMAGE_BUF_T, which guarantees that image data can
+    * be accessed safely.
+    *
+    * This type will also be used in cases where it's unclear whether or not
+    * the buffer is already locked, and in legacy code.
+    */
+   struct VC_IMAGE_T {
+#ifdef __HIGHC__
+      VC_IMAGE_TYPE_T                 type;           /* Metaware will use 16 bits for this enum
+                                                         so use the correct type for debug info */
+#else
+      unsigned short                  type;           /* should restrict to 16 bits */
+#endif
+      VC_IMAGE_INFO_T                 info;           /* format-specific info; zero for VC02 behaviour */
+      unsigned short                  width;          /* width in pixels */
+      unsigned short                  height;         /* height in pixels */
+      int                             pitch;          /* pitch of image_data array in bytes */
+      int                             size;           /* number of bytes available in image_data array */
+      void                           *image_data;     /* pixel data */
+      VC_IMAGE_EXTRA_T                extra;          /* extra data like palette pointer */
+      struct vc_metadata_header_s    *metadata;       /* metadata header for the image */
+      struct opaque_vc_pool_object_s *pool_object;    /* nonNULL if image was allocated from a vc_pool */
+      uint32_t                        mem_handle;     /* the mem handle for relocatable memory storage */
+      int                             metadata_size;  /* size of metadata of each channel in bytes */
+      int                             channel_offset; /* offset of consecutive channels in bytes */
+      uint32_t                        video_timestamp;/* 90000 Hz RTP times domain - derived from audio timestamp */
+      uint8_t                         num_channels;   /* number of channels (2 for stereo) */
+      uint8_t                         current_channel;/* the channel this header is currently pointing to */
+      uint8_t                         linked_multichann_flag;/* Indicate the header has the linked-multichannel structure*/
+      uint8_t                         is_channel_linked;     /* Track if the above structure is been used to link the header
+                                                                into a linked-mulitchannel image */
+      uint8_t                         channel_index;         /* index of the channel this header represents while  
+                                                                it is being linked. */
+      uint8_t                         _dummy[3];      /* pad struct to 64 bytes */
+   };
+
+
+# ifdef __COVERITY__
+   /* Currently battling with the size of enums when running through static analysis stage */
+   typedef int vc_image_t_size_check[(sizeof(VC_IMAGE_T) == 68) * 2 - 1];
+# else
+   /* compile time assert to ensure size of VC_IMAGE_T is as expected, if the
+      compiler kicks out a "negative subscript" message then the size
+      of VC_IMAGE_T is *not* 64 bytes, which is a problem ... */
+   typedef int vc_image_t_size_check[(sizeof(VC_IMAGE_T) == 64) * 2 - 1];
+#endif
+
+/******************************************************************************
+ Debugging rules (defined in camera_debug.c)
+ *****************************************************************************/
+extern DEBUG_WRITE_ENUM_LOOKUP_T vc_image_type_lookup[];
+extern DEBUG_WRITE_ENUM_LOOKUP_T vc_image_bayer_order_lookup[];
+extern DEBUG_WRITE_ENUM_LOOKUP_T vc_image_bayer_format_lookup[];
+extern DEBUG_WRITE_RULE_T vc_image_info_rule[];
+extern DEBUG_WRITE_RULE_T vc_image_rule[];
+
+#endif /* __VC_INCLUDE_IMAGE_TYPES_H__ */
+
diff --git a/interface/vctypes/vc_image_types.h b/interface/vctypes/vc_image_types.h
new file mode 100755 (executable)
index 0000000..922cd23
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Common image types used by the vc_image library
+
+#ifndef INTERFACE_VC_IMAGE_TYPES_H
+#define INTERFACE_VC_IMAGE_TYPES_H
+
+/* This file gets included by the VCE compiler, which gets confused
+ * easily by the VCOS headers. So cannot include vcos.h here.
+ */
+#include "interface/vcos/vcos_stdint.h"
+
+/* We have so many rectangle types; let's try to introduce a common one. */
+typedef struct tag_VC_RECT_T {
+   int32_t x;
+   int32_t y;
+   int32_t width;
+   int32_t height;
+} VC_RECT_T;
+
+struct VC_IMAGE_T;
+typedef struct VC_IMAGE_T VC_IMAGE_T;
+
+/* Types of image supported. */
+/* Please add any new types to the *end* of this list.  Also update
+ * case_VC_IMAGE_ANY_xxx macros (below), and the vc_image_type_info table in
+ * vc_image/vc_image_helper.c.
+ */
+typedef enum
+{
+   VC_IMAGE_MIN = 0, //bounds for error checking
+
+   VC_IMAGE_RGB565 = 1,
+   VC_IMAGE_1BPP,
+   VC_IMAGE_YUV420,
+   VC_IMAGE_48BPP,
+   VC_IMAGE_RGB888,
+   VC_IMAGE_8BPP,
+   VC_IMAGE_4BPP,    // 4bpp palettised image
+   VC_IMAGE_3D32,    /* A separated format of 16 colour/light shorts followed by 16 z values */
+   VC_IMAGE_3D32B,   /* 16 colours followed by 16 z values */
+   VC_IMAGE_3D32MAT, /* A separated format of 16 material/colour/light shorts followed by 16 z values */
+   VC_IMAGE_RGB2X9,   /* 32 bit format containing 18 bits of 6.6.6 RGB, 9 bits per short */
+   VC_IMAGE_RGB666,   /* 32-bit format holding 18 bits of 6.6.6 RGB */
+   VC_IMAGE_PAL4_OBSOLETE,     // 4bpp palettised image with embedded palette
+   VC_IMAGE_PAL8_OBSOLETE,     // 8bpp palettised image with embedded palette
+   VC_IMAGE_RGBA32,   /* RGB888 with an alpha byte after each pixel */ /* xxx: isn't it BEFORE each pixel? */
+   VC_IMAGE_YUV422,   /* a line of Y (32-byte padded), a line of U (16-byte padded), and a line of V (16-byte padded) */
+   VC_IMAGE_RGBA565,  /* RGB565 with a transparent patch */
+   VC_IMAGE_RGBA16,   /* Compressed (4444) version of RGBA32 */
+   VC_IMAGE_YUV_UV,   /* VCIII codec format */
+   VC_IMAGE_TF_RGBA32, /* VCIII T-format RGBA8888 */
+   VC_IMAGE_TF_RGBX32,  /* VCIII T-format RGBx8888 */
+   VC_IMAGE_TF_FLOAT, /* VCIII T-format float */
+   VC_IMAGE_TF_RGBA16, /* VCIII T-format RGBA4444 */
+   VC_IMAGE_TF_RGBA5551, /* VCIII T-format RGB5551 */
+   VC_IMAGE_TF_RGB565, /* VCIII T-format RGB565 */
+   VC_IMAGE_TF_YA88, /* VCIII T-format 8-bit luma and 8-bit alpha */
+   VC_IMAGE_TF_BYTE, /* VCIII T-format 8 bit generic sample */
+   VC_IMAGE_TF_PAL8, /* VCIII T-format 8-bit palette */
+   VC_IMAGE_TF_PAL4, /* VCIII T-format 4-bit palette */
+   VC_IMAGE_TF_ETC1, /* VCIII T-format Ericsson Texture Compressed */
+   VC_IMAGE_BGR888,  /* RGB888 with R & B swapped */
+   VC_IMAGE_BGR888_NP,  /* RGB888 with R & B swapped, but with no pitch, i.e. no padding after each row of pixels */
+   VC_IMAGE_BAYER,  /* Bayer image, extra defines which variant is being used */
+   VC_IMAGE_CODEC,  /* General wrapper for codec images e.g. JPEG from camera */
+   VC_IMAGE_YUV_UV32,   /* VCIII codec format */
+   VC_IMAGE_TF_Y8,   /* VCIII T-format 8-bit luma */
+   VC_IMAGE_TF_A8,   /* VCIII T-format 8-bit alpha */
+   VC_IMAGE_TF_SHORT,/* VCIII T-format 16-bit generic sample */
+   VC_IMAGE_TF_1BPP, /* VCIII T-format 1bpp black/white */
+   VC_IMAGE_OPENGL,
+   VC_IMAGE_YUV444I, /* VCIII-B0 HVS YUV 4:4:4 interleaved samples */
+   VC_IMAGE_YUV422PLANAR,  /* Y, U, & V planes separately (VC_IMAGE_YUV422 has them interleaved on a per line basis) */
+   VC_IMAGE_ARGB8888,   /* 32bpp with 8bit alpha at MS byte, with R, G, B (LS byte) */
+   VC_IMAGE_XRGB8888,   /* 32bpp with 8bit unused at MS byte, with R, G, B (LS byte) */
+
+   VC_IMAGE_YUV422YUYV,  /* interleaved 8 bit samples of Y, U, Y, V */
+   VC_IMAGE_YUV422YVYU,  /* interleaved 8 bit samples of Y, V, Y, U */
+   VC_IMAGE_YUV422UYVY,  /* interleaved 8 bit samples of U, Y, V, Y */
+   VC_IMAGE_YUV422VYUY,  /* interleaved 8 bit samples of V, Y, U, Y */
+
+   VC_IMAGE_RGBX32,      /* 32bpp like RGBA32 but with unused alpha */
+   VC_IMAGE_RGBX8888,    /* 32bpp, corresponding to RGBA with unused alpha */
+   VC_IMAGE_BGRX8888,    /* 32bpp, corresponding to BGRA with unused alpha */
+
+   VC_IMAGE_YUV420SP,    /* Y as a plane, then UV byte interleaved in plane with with same pitch, half height */
+   
+   VC_IMAGE_YUV444PLANAR,  /* Y, U, & V planes separately 4:4:4 */
+
+   VC_IMAGE_TF_U8,   /* T-format 8-bit U - same as TF_Y8 buf from U plane */
+   VC_IMAGE_TF_V8,   /* T-format 8-bit U - same as TF_Y8 buf from V plane */
+   
+   VC_IMAGE_YUV420_16,  /* YUV4:2:0 planar, 16bit values */
+   VC_IMAGE_YUV_UV_16,  /* YUV4:2:0 codec format, 16bit values */
+
+   VC_IMAGE_MAX,     //bounds for error checking
+   VC_IMAGE_FORCE_ENUM_16BIT = 0xffff,
+} VC_IMAGE_TYPE_T;
+
+/* Image transformations (flips and 90 degree rotations).
+   These are made out of 3 primitives (transpose is done first).
+   These must match the DISPMAN and Media Player definitions. */
+
+#define TRANSFORM_HFLIP     (1<<0)
+#define TRANSFORM_VFLIP     (1<<1)
+#define TRANSFORM_TRANSPOSE (1<<2)
+
+typedef enum {
+   VC_IMAGE_ROT0           = 0,
+   VC_IMAGE_MIRROR_ROT0    = TRANSFORM_HFLIP,
+   VC_IMAGE_MIRROR_ROT180  = TRANSFORM_VFLIP,
+   VC_IMAGE_ROT180         = TRANSFORM_HFLIP|TRANSFORM_VFLIP,
+   VC_IMAGE_MIRROR_ROT90   = TRANSFORM_TRANSPOSE,
+   VC_IMAGE_ROT270         = TRANSFORM_TRANSPOSE|TRANSFORM_HFLIP,
+   VC_IMAGE_ROT90          = TRANSFORM_TRANSPOSE|TRANSFORM_VFLIP,
+   VC_IMAGE_MIRROR_ROT270  = TRANSFORM_TRANSPOSE|TRANSFORM_HFLIP|TRANSFORM_VFLIP,
+} VC_IMAGE_TRANSFORM_T;
+
+typedef enum
+{ //defined to be identical to register bits
+   VC_IMAGE_BAYER_RGGB     = 0,
+   VC_IMAGE_BAYER_GBRG     = 1,
+   VC_IMAGE_BAYER_BGGR     = 2,
+   VC_IMAGE_BAYER_GRBG     = 3
+} VC_IMAGE_BAYER_ORDER_T;
+
+typedef enum
+{ //defined to be identical to register bits
+   VC_IMAGE_BAYER_RAW6     = 0,
+   VC_IMAGE_BAYER_RAW7     = 1,
+   VC_IMAGE_BAYER_RAW8     = 2,
+   VC_IMAGE_BAYER_RAW10    = 3,
+   VC_IMAGE_BAYER_RAW12    = 4,
+   VC_IMAGE_BAYER_RAW14    = 5,
+   VC_IMAGE_BAYER_RAW16    = 6,
+   VC_IMAGE_BAYER_RAW10_8  = 7,
+   VC_IMAGE_BAYER_RAW12_8  = 8,
+   VC_IMAGE_BAYER_RAW14_8  = 9,
+   VC_IMAGE_BAYER_RAW10L   = 11,
+   VC_IMAGE_BAYER_RAW12L   = 12,
+   VC_IMAGE_BAYER_RAW14L   = 13,
+   VC_IMAGE_BAYER_RAW16_BIG_ENDIAN = 14, 
+   VC_IMAGE_BAYER_RAW4    = 15,
+} VC_IMAGE_BAYER_FORMAT_T;
+
+#endif /* __VC_INCLUDE_IMAGE_TYPES_H__ */
+
diff --git a/interface/vmcs_host/CMakeLists.txt b/interface/vmcs_host/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..fde18da
--- /dev/null
@@ -0,0 +1,35 @@
+
+# interface/vmcs_host
+
+# not working in release build
+# add_definitions(-Werror)
+
+# vc_vchi_gencmd.c has a type-punning problem in vc_gencmd_read_response
+add_definitions(-fno-strict-aliasing)
+
+include_directories(${VMCS_TARGET}/vcfiled)
+
+add_library(vchostif
+            ${VMCS_TARGET}/vcfilesys.c ${VMCS_TARGET}/vcmisc.c
+            vc_vchi_gencmd.c vc_vchi_filesys.c vc_vchi_gpuserv.c
+            vc_vchi_tvservice.c vc_vchi_cecservice.c
+            vc_vchi_dispmanx.c vc_service_common.c)
+#            ${VMCS_TARGET}/vmcs_main.c
+#  vc_vchi_haud.c
+#add_library(bufman            vc_vchi_bufman.c            )
+
+# OpenMAX/IL component service
+add_library(vcilcs
+            vcilcs.c vcilcs_in.c vcilcs_out.c vcilcs_common.c)
+
+# ILCS pulls in EGL for the ILCS/EGL surface API support
+target_link_libraries(vcilcs brcmEGL brcmGLESv2 khrn_client vchiq_arm vcos)
+
+# vchostif needs ilcore as well (vmcs_main pulls it in)
+target_link_libraries(vchostif vchiq_arm vcos vcfiled_check)
+
+#target_link_libraries(bufman WFC)
+
+add_subdirectory(linux/vcfiled)
+install(TARGETS vchostif vcilcs DESTINATION lib)
+
diff --git a/interface/vmcs_host/khronos/IL/OMX_Audio.h b/interface/vmcs_host/khronos/IL/OMX_Audio.h
new file mode 100755 (executable)
index 0000000..75d83c8
--- /dev/null
@@ -0,0 +1,1391 @@
+/*
+ * Copyright (c) 2008 The Khronos Group Inc. 
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions: 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
+ *
+ */
+
+/** @file OMX_Audio.h - OpenMax IL version 1.1.2
+ *  The structures needed by Audio components to exchange
+ *  parameters and configuration data with the componenmilts.
+ */
+
+#ifndef OMX_Audio_h
+#define OMX_Audio_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* Each OMX header must include all required header files to allow the
+ *  header to compile without errors.  The includes below are required
+ *  for this header file to compile successfully 
+ */
+
+#include "OMX_Core.h"
+
+/** @defgroup midi MIDI
+ * @ingroup audio
+ */
+/** @defgroup effects Audio effects
+ * @ingroup audio
+ */
+
+/** @defgroup audio OpenMAX IL Audio Domain
+ * Structures for OpenMAX IL Audio domain
+ * @{
+ */
+
+/** Enumeration used to define the possible audio codings.  
+ *  If "OMX_AUDIO_CodingUnused" is selected, the coding selection must 
+ *  be done in a vendor specific way.  Since this is for an audio 
+ *  processing element this enum is relevant.  However, for another 
+ *  type of component other enums would be in this area.
+ */
+typedef enum OMX_AUDIO_CODINGTYPE {
+    OMX_AUDIO_CodingUnused = 0,  /**< Placeholder value when coding is N/A  */
+    OMX_AUDIO_CodingAutoDetect,  /**< auto detection of audio format */
+    OMX_AUDIO_CodingPCM,         /**< Any variant of PCM coding */
+    OMX_AUDIO_CodingADPCM,       /**< Any variant of ADPCM encoded data */
+    OMX_AUDIO_CodingAMR,         /**< Any variant of AMR encoded data */
+    OMX_AUDIO_CodingGSMFR,       /**< Any variant of GSM fullrate (i.e. GSM610) */
+    OMX_AUDIO_CodingGSMEFR,      /**< Any variant of GSM Enhanced Fullrate encoded data*/
+    OMX_AUDIO_CodingGSMHR,       /**< Any variant of GSM Halfrate encoded data */
+    OMX_AUDIO_CodingPDCFR,       /**< Any variant of PDC Fullrate encoded data */
+    OMX_AUDIO_CodingPDCEFR,      /**< Any variant of PDC Enhanced Fullrate encoded data */
+    OMX_AUDIO_CodingPDCHR,       /**< Any variant of PDC Halfrate encoded data */
+    OMX_AUDIO_CodingTDMAFR,      /**< Any variant of TDMA Fullrate encoded data (TIA/EIA-136-420) */
+    OMX_AUDIO_CodingTDMAEFR,     /**< Any variant of TDMA Enhanced Fullrate encoded data (TIA/EIA-136-410) */
+    OMX_AUDIO_CodingQCELP8,      /**< Any variant of QCELP 8kbps encoded data */
+    OMX_AUDIO_CodingQCELP13,     /**< Any variant of QCELP 13kbps encoded data */
+    OMX_AUDIO_CodingEVRC,        /**< Any variant of EVRC encoded data */
+    OMX_AUDIO_CodingSMV,         /**< Any variant of SMV encoded data */
+    OMX_AUDIO_CodingG711,        /**< Any variant of G.711 encoded data */
+    OMX_AUDIO_CodingG723,        /**< Any variant of G.723 dot 1 encoded data */
+    OMX_AUDIO_CodingG726,        /**< Any variant of G.726 encoded data */
+    OMX_AUDIO_CodingG729,        /**< Any variant of G.729 encoded data */
+    OMX_AUDIO_CodingAAC,         /**< Any variant of AAC encoded data */
+    OMX_AUDIO_CodingMP3,         /**< Any variant of MP3 encoded data */
+    OMX_AUDIO_CodingSBC,         /**< Any variant of SBC encoded data */
+    OMX_AUDIO_CodingVORBIS,      /**< Any variant of VORBIS encoded data */
+    OMX_AUDIO_CodingWMA,         /**< Any variant of WMA encoded data */
+    OMX_AUDIO_CodingRA,          /**< Any variant of RA encoded data */
+    OMX_AUDIO_CodingMIDI,        /**< Any variant of MIDI encoded data */
+    OMX_AUDIO_CodingKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_AUDIO_CodingVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+
+#define OMX_AUDIO_CodingFLAC_Supported 1
+    OMX_AUDIO_CodingFLAC,        /**< Any variant of FLAC */
+#define OMX_AUDIO_CodingDDP_Supported 1
+    OMX_AUDIO_CodingDDP,         /**< Any variant of Dolby Digital Plus */
+#define OMX_AUDIO_CodingDTS_Supported 1
+    OMX_AUDIO_CodingDTS,         /**< Any variant of DTS */
+#define OMX_AUDIO_CodingWMAPRO_Supported 1
+    OMX_AUDIO_CodingWMAPRO,      /**< Any variant of WMA Professional */
+#define OMX_AUDIO_CodingATRAC3_Supported 1
+    OMX_AUDIO_CodingATRAC3,      /**< Sony ATRAC-3 variants */
+#define OMX_AUDIO_CodingATRACX_Supported 1
+    OMX_AUDIO_CodingATRACX,      /**< Sony ATRAC-X variants */
+#define OMX_AUDIO_CodingATRACAAL_Supported 1
+    OMX_AUDIO_CodingATRACAAL,    /**< Sony ATRAC advanced-lossless variants  */
+
+    OMX_AUDIO_CodingMax = 0x7FFFFFFF
+} OMX_AUDIO_CODINGTYPE;
+
+
+/** The PortDefinition structure is used to define all of the parameters 
+ *  necessary for the compliant component to setup an input or an output audio 
+ *  path.  If additional information is needed to define the parameters of the
+ *  port (such as frequency), additional structures must be sent such as the
+ *  OMX_AUDIO_PARAM_PCMMODETYPE structure to supply the extra parameters for the port.
+ */
+typedef struct OMX_AUDIO_PORTDEFINITIONTYPE {
+    OMX_STRING cMIMEType;            /**< MIME type of data for the port */
+    OMX_NATIVE_DEVICETYPE pNativeRender; /** < platform specific reference
+                                               for an output device, 
+                                               otherwise this field is 0 */
+    OMX_BOOL bFlagErrorConcealment;  /**< Turns on error concealment if it is 
+                                          supported by the OMX component */
+    OMX_AUDIO_CODINGTYPE eEncoding;  /**< Type of data expected for this 
+                                          port (e.g. PCM, AMR, MP3, etc) */
+} OMX_AUDIO_PORTDEFINITIONTYPE;
+
+
+/**  Port format parameter.  This structure is used to enumerate
+  *  the various data input/output format supported by the port.
+  */
+typedef struct OMX_AUDIO_PARAM_PORTFORMATTYPE {
+    OMX_U32 nSize;                  /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;       /**< OMX specification version information */
+    OMX_U32 nPortIndex;             /**< Indicates which port to set */
+    OMX_U32 nIndex;                 /**< Indicates the enumeration index for the format from 0x0 to N-1 */
+    OMX_AUDIO_CODINGTYPE eEncoding; /**< Type of data expected for this port (e.g. PCM, AMR, MP3, etc) */
+} OMX_AUDIO_PARAM_PORTFORMATTYPE;
+
+
+/** PCM mode type  */ 
+typedef enum OMX_AUDIO_PCMMODETYPE { 
+    OMX_AUDIO_PCMModeLinear = 0,  /**< Linear PCM encoded data */ 
+    OMX_AUDIO_PCMModeALaw,        /**< A law PCM encoded data (G.711) */ 
+    OMX_AUDIO_PCMModeMULaw,       /**< Mu law PCM encoded data (G.711)  */ 
+    OMX_AUDIO_PCMModeKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_AUDIO_PCMModeVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_AUDIO_PCMModeMax = 0x7FFFFFFF 
+} OMX_AUDIO_PCMMODETYPE; 
+
+
+typedef enum OMX_AUDIO_CHANNELTYPE {
+    OMX_AUDIO_ChannelNone = 0x0,    /**< Unused or empty */
+    OMX_AUDIO_ChannelLF   = 0x1,    /**< Left front */
+    OMX_AUDIO_ChannelRF   = 0x2,    /**< Right front */
+    OMX_AUDIO_ChannelCF   = 0x3,    /**< Center front */
+    OMX_AUDIO_ChannelLS   = 0x4,    /**< Left surround */
+    OMX_AUDIO_ChannelRS   = 0x5,    /**< Right surround */
+    OMX_AUDIO_ChannelLFE  = 0x6,    /**< Low frequency effects */
+    OMX_AUDIO_ChannelCS   = 0x7,    /**< Back surround */
+    OMX_AUDIO_ChannelLR   = 0x8,    /**< Left rear. */
+    OMX_AUDIO_ChannelRR   = 0x9,    /**< Right rear. */
+    OMX_AUDIO_ChannelKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_AUDIO_ChannelVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_AUDIO_ChannelMax  = 0x7FFFFFFF 
+} OMX_AUDIO_CHANNELTYPE;
+
+#define OMX_AUDIO_MAXCHANNELS 16  /**< maximum number distinct audio channels that a buffer may contain */
+#define OMX_MIN_PCMPAYLOAD_MSEC 5 /**< Minimum audio buffer payload size for uncompressed (PCM) audio */
+
+/** PCM format description */ 
+typedef struct OMX_AUDIO_PARAM_PCMMODETYPE { 
+    OMX_U32 nSize;                    /**< Size of this structure, in Bytes */ 
+    OMX_VERSIONTYPE nVersion;         /**< OMX specification version information */ 
+    OMX_U32 nPortIndex;               /**< port that this structure applies to */ 
+    OMX_U32 nChannels;                /**< Number of channels (e.g. 2 for stereo) */ 
+    OMX_NUMERICALDATATYPE eNumData;   /**< indicates PCM data as signed or unsigned */ 
+    OMX_ENDIANTYPE eEndian;           /**< indicates PCM data as little or big endian */ 
+    OMX_BOOL bInterleaved;            /**< True for normal interleaved data; false for 
+                                           non-interleaved data (e.g. block data) */ 
+    OMX_U32 nBitPerSample;            /**< Bit per sample */ 
+    OMX_U32 nSamplingRate;            /**< Sampling rate of the source data.  Use 0 for 
+                                           variable or unknown sampling rate. */ 
+    OMX_AUDIO_PCMMODETYPE ePCMMode;   /**< PCM mode enumeration */ 
+    OMX_AUDIO_CHANNELTYPE eChannelMapping[OMX_AUDIO_MAXCHANNELS]; /**< Slot i contains channel defined by eChannelMap[i] */
+
+} OMX_AUDIO_PARAM_PCMMODETYPE; 
+
+
+/** Audio channel mode.  This is used by both AAC and MP3, although the names are more appropriate
+ * for the MP3.  For example, JointStereo for MP3 is CouplingChannels for AAC. 
+ */
+typedef enum OMX_AUDIO_CHANNELMODETYPE {
+    OMX_AUDIO_ChannelModeStereo = 0,  /**< 2 channels, the bitrate allocation between those 
+                                          two channels changes accordingly to each channel information */
+    OMX_AUDIO_ChannelModeJointStereo, /**< mode that takes advantage of what is common between 
+                                           2 channels for higher compression gain */
+    OMX_AUDIO_ChannelModeDual,        /**< 2 mono-channels, each channel is encoded with half 
+                                           the bitrate of the overall bitrate */
+    OMX_AUDIO_ChannelModeMono,        /**< Mono channel mode */
+    OMX_AUDIO_ChannelModeKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_AUDIO_ChannelModeVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_AUDIO_ChannelModeMax = 0x7FFFFFFF
+} OMX_AUDIO_CHANNELMODETYPE;
+
+
+typedef enum OMX_AUDIO_MP3STREAMFORMATTYPE {
+    OMX_AUDIO_MP3StreamFormatMP1Layer3 = 0, /**< MP3 Audio MPEG 1 Layer 3 Stream format */
+    OMX_AUDIO_MP3StreamFormatMP2Layer3,     /**< MP3 Audio MPEG 2 Layer 3 Stream format */
+    OMX_AUDIO_MP3StreamFormatMP2_5Layer3,   /**< MP3 Audio MPEG2.5 Layer 3 Stream format */
+    OMX_AUDIO_MP3StreamFormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_AUDIO_MP3StreamFormatVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_AUDIO_MP3StreamFormatMax = 0x7FFFFFFF
+} OMX_AUDIO_MP3STREAMFORMATTYPE;
+
+/** MP3 params */
+typedef struct OMX_AUDIO_PARAM_MP3TYPE {
+    OMX_U32 nSize;                 /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;      /**< OMX specification version information */
+    OMX_U32 nPortIndex;            /**< port that this structure applies to */
+    OMX_U32 nChannels;             /**< Number of channels */
+    OMX_U32 nBitRate;              /**< Bit rate of the input data.  Use 0 for variable
+                                        rate or unknown bit rates */
+    OMX_U32 nSampleRate;           /**< Sampling rate of the source data.  Use 0 for
+                                        variable or unknown sampling rate. */
+    OMX_U32 nAudioBandWidth;       /**< Audio band width (in Hz) to which an encoder should
+                                        limit the audio signal. Use 0 to let encoder decide */
+    OMX_AUDIO_CHANNELMODETYPE eChannelMode;   /**< Channel mode enumeration */
+    OMX_AUDIO_MP3STREAMFORMATTYPE eFormat;  /**< MP3 stream format */
+} OMX_AUDIO_PARAM_MP3TYPE;
+
+typedef enum OMX_AUDIO_DDPBITSTREAMID {
+   OMX_AUDIO_DDPBitStreamIdAC3 = 8,
+   OMX_AUDIO_DDPBitStreamIdEAC3 = 16,
+   OMX_AUDIO_DDPBitStreamIdKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+   OMX_AUDIO_DDPBitStreamIdVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+   OMX_AUDIO_DDPBitStreamIdMax = 0x7FFFFFFF
+} OMX_AUDIO_DDPBITSTREAMID;
+
+typedef enum OMX_AUDIO_DDPBITSTREAMMODE {
+   OMX_AUDIO_DDPBitStreamModeCM = 0,   /**< DDP any main audio service: complete main (CM) */
+   OMX_AUDIO_DDPBitStreamModeME,       /**< DDP any main audio service: music and effects (ME) */
+   OMX_AUDIO_DDPBitStreamModeVI,       /**< DDP any associated service: visually impaired (VI) */
+   OMX_AUDIO_DDPBitStreamModeHI,       /**< DDP any associated service: hearing impaired (HI)  */
+   OMX_AUDIO_DDPBitStreamModeD,        /**< DDP any associated service: dialogue (D)           */
+   OMX_AUDIO_DDPBitStreamModeC,        /**< DDP any associated service: commentary (C)         */
+   OMX_AUDIO_DDPBitStreamModeE,        /**< DDP any associated service: emergency (E)          */
+   OMX_AUDIO_DDPBitStreamModeVO,       /**< DDP associated service: voice over (VO)            */
+   OMX_AUDIO_DDPBitStreamModeK,        /**< DDP main audio service: karaoke                    */
+   OMX_AUDIO_DDPBitStreamModeKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+   OMX_AUDIO_DDPBitStreamModeVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+   OMX_AUDIO_DDPBitStreamModeMax = 0x7FFFFFFF
+} OMX_AUDIO_DDPBITSTREAMMODE;
+
+typedef enum OMX_AUDIO_DDPDOLBYSURROUNDMODE {
+   OMX_AUDIO_DDPDolbySurroundModeNotIndicated = 0,               /**< Not indicated */
+   OMX_AUDIO_DDPDolbySurroundModeNotDolbySurround,               /**< Not Dolby Surround */
+   OMX_AUDIO_DDPDolbySurroundModeDolbySurroundEncoded,           /**< Dolby Surround encoded */
+   OMX_AUDIO_DDPDolbySurroundModeReserverd,                      /**< Reserved */
+   OMX_AUDIO_DDPDolbySurroundModeKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+   OMX_AUDIO_DDPDolbySurroundModeVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+   OMX_AUDIO_DDPDolbySurroundModeMax = 0x7FFFFFFF
+} OMX_AUDIO_DDPDOLBYSURROUNDMODE;
+
+/** DDP params */
+typedef struct OMX_AUDIO_PARAM_DDPTYPE {
+    OMX_U32 nSize;                 /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;      /**< OMX specification version information */
+    OMX_U32 nPortIndex;            /**< port that this structure applies to */
+    OMX_U32 nChannels;             /**< Number of channels */
+    OMX_U32 nBitRate;              /**< Bit rate of the input data.  Use 0 for variable
+                                        rate or unknown bit rates */
+    OMX_U32 nSampleRate;           /**< Sampling rate of the source data. Use 0 for
+                                        variable or unknown sampling rate. */
+    OMX_AUDIO_DDPBITSTREAMID eBitStreamId;
+    OMX_AUDIO_DDPBITSTREAMMODE eBitStreamMode;
+    OMX_AUDIO_DDPDOLBYSURROUNDMODE eDolbySurroundMode;
+    OMX_AUDIO_CHANNELTYPE eChannelMapping[OMX_AUDIO_MAXCHANNELS]; /**< Slot i contains channel defined by eChannelMapping[i] */    
+} OMX_AUDIO_PARAM_DDPTYPE;
+
+/** DTS params */
+typedef struct OMX_AUDIO_PARAM_DTSTYPE {
+    OMX_U32 nSize;                 /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;      /**< OMX specification version information */
+    OMX_U32 nPortIndex;            /**< port that this structure applies to */
+    OMX_U32 nChannels;             /**< Number of channels */
+    OMX_U32 nBitRate;              /**< Bit rate of the input data.  Use 0 for variable
+                                        rate or unknown bit rates */
+    OMX_U32 nSampleRate;           /**< Sampling rate of the source data. Use 0 for
+                                        variable or unknown sampling rate. */
+    OMX_U32 nDtsType;              /** DTS type 1, 2, or 3. */
+    OMX_U32 nFormat;               /** DTS stream is either big/little endian and 16/14 bit packing */
+    OMX_U32 nDtsFrameSizeBytes;    /** DTS frame size in bytes */
+    OMX_AUDIO_CHANNELTYPE eChannelMapping[OMX_AUDIO_MAXCHANNELS]; /**< Slot i contains channel defined by eChannelMapping[i] */
+} OMX_AUDIO_PARAM_DTSTYPE;
+
+typedef enum OMX_AUDIO_AACSTREAMFORMATTYPE {
+    OMX_AUDIO_AACStreamFormatMP2ADTS = 0, /**< AAC Audio Data Transport Stream 2 format */
+    OMX_AUDIO_AACStreamFormatMP4ADTS,     /**< AAC Audio Data Transport Stream 4 format */
+    OMX_AUDIO_AACStreamFormatMP4LOAS,     /**< AAC Low Overhead Audio Stream format */
+    OMX_AUDIO_AACStreamFormatMP4LATM,     /**< AAC Low overhead Audio Transport Multiplex */
+    OMX_AUDIO_AACStreamFormatADIF,        /**< AAC Audio Data Interchange Format */
+    OMX_AUDIO_AACStreamFormatMP4FF,       /**< AAC inside MPEG-4/ISO File Format */
+    OMX_AUDIO_AACStreamFormatRAW,         /**< AAC Raw Format */
+    OMX_AUDIO_AACStreamFormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_AUDIO_AACStreamFormatVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_AUDIO_AACStreamFormatMax = 0x7FFFFFFF
+} OMX_AUDIO_AACSTREAMFORMATTYPE;
+
+
+/** AAC mode type.  Note that the term profile is used with the MPEG-2
+ * standard and the term object type and profile is used with MPEG-4 */
+typedef enum OMX_AUDIO_AACPROFILETYPE{
+  OMX_AUDIO_AACObjectNull = 0,      /**< Null, not used */
+  OMX_AUDIO_AACObjectMain = 1,      /**< AAC Main object */
+  OMX_AUDIO_AACObjectLC,            /**< AAC Low Complexity object (AAC profile) */
+  OMX_AUDIO_AACObjectSSR,           /**< AAC Scalable Sample Rate object */
+  OMX_AUDIO_AACObjectLTP,           /**< AAC Long Term Prediction object */
+  OMX_AUDIO_AACObjectHE,            /**< AAC High Efficiency (object type SBR, HE-AAC profile) */
+  OMX_AUDIO_AACObjectScalable,      /**< AAC Scalable object */
+  OMX_AUDIO_AACObjectERLC = 17,     /**< ER AAC Low Complexity object (Error Resilient AAC-LC) */
+  OMX_AUDIO_AACObjectLD = 23,       /**< AAC Low Delay object (Error Resilient) */
+  OMX_AUDIO_AACObjectHE_PS = 29,    /**< AAC High Efficiency with Parametric Stereo coding (HE-AAC v2, object type PS) */
+  OMX_AUDIO_AACObjectKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+  OMX_AUDIO_AACObjectVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+  OMX_AUDIO_AACObjectMax = 0x7FFFFFFF
+} OMX_AUDIO_AACPROFILETYPE;
+
+
+/** AAC tool usage (for nAACtools in OMX_AUDIO_PARAM_AACPROFILETYPE).
+ * Required for encoder configuration and optional as decoder info output.
+ * For MP3, OMX_AUDIO_CHANNELMODETYPE is sufficient. */
+#define OMX_AUDIO_AACToolNone 0x00000000 /**< no AAC tools allowed (encoder config) or active (decoder info output) */
+#define OMX_AUDIO_AACToolMS   0x00000001 /**< MS: Mid/side joint coding tool allowed or active */
+#define OMX_AUDIO_AACToolIS   0x00000002 /**< IS: Intensity stereo tool allowed or active */
+#define OMX_AUDIO_AACToolTNS  0x00000004 /**< TNS: Temporal Noise Shaping tool allowed or active */
+#define OMX_AUDIO_AACToolPNS  0x00000008 /**< PNS: MPEG-4 Perceptual Noise substitution tool allowed or active */
+#define OMX_AUDIO_AACToolLTP  0x00000010 /**< LTP: MPEG-4 Long Term Prediction tool allowed or active */
+#define OMX_AUDIO_AACToolAll  0x7FFFFFFF /**< all AAC tools allowed or active (*/
+
+/** MPEG-4 AAC error resilience (ER) tool usage (for nAACERtools in OMX_AUDIO_PARAM_AACPROFILETYPE).
+ * Required for ER encoder configuration and optional as decoder info output */
+#define OMX_AUDIO_AACERNone  0x00000000  /**< no AAC ER tools allowed/used */
+#define OMX_AUDIO_AACERVCB11 0x00000001  /**< VCB11: Virtual Code Books for AAC section data */
+#define OMX_AUDIO_AACERRVLC  0x00000002  /**< RVLC: Reversible Variable Length Coding */
+#define OMX_AUDIO_AACERHCR   0x00000004  /**< HCR: Huffman Codeword Reordering */
+#define OMX_AUDIO_AACERAll   0x7FFFFFFF  /**< all AAC ER tools allowed/used */
+
+
+/** AAC params */
+typedef struct OMX_AUDIO_PARAM_AACPROFILETYPE {
+    OMX_U32 nSize;                 /**< Size of this structure, in Bytes */
+    OMX_VERSIONTYPE nVersion;      /**< OMX specification version information */
+    OMX_U32 nPortIndex;            /**< Port that this structure applies to */
+    OMX_U32 nChannels;             /**< Number of channels */
+    OMX_U32 nSampleRate;           /**< Sampling rate of the source data.  Use 0 for
+                                        variable or unknown sampling rate. */
+    OMX_U32 nBitRate;              /**< Bit rate of the input data.  Use 0 for variable
+                                        rate or unknown bit rates */
+    OMX_U32 nAudioBandWidth;       /**< Audio band width (in Hz) to which an encoder should
+                                        limit the audio signal. Use 0 to let encoder decide */
+    OMX_U32 nFrameLength;          /**< Frame length (in audio samples per channel) of the codec.
+                                        Can be 1024 or 960 (AAC-LC), 2048 (HE-AAC), 480 or 512 (AAC-LD).
+                                        Use 0 to let encoder decide */
+    OMX_U32 nAACtools;             /**< AAC tool usage */
+    OMX_U32 nAACERtools;           /**< MPEG-4 AAC error resilience tool usage */
+    OMX_AUDIO_AACPROFILETYPE eAACProfile;   /**< AAC profile enumeration */
+    OMX_AUDIO_AACSTREAMFORMATTYPE eAACStreamFormat; /**< AAC stream format enumeration */
+    OMX_AUDIO_CHANNELMODETYPE eChannelMode;   /**< Channel mode enumeration */
+} OMX_AUDIO_PARAM_AACPROFILETYPE;
+
+
+/** VORBIS params */
+typedef struct OMX_AUDIO_PARAM_VORBISTYPE {
+    OMX_U32 nSize;            /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
+    OMX_U32 nPortIndex;       /**< port that this structure applies to */
+    OMX_U32 nChannels;        /**< Number of channels */
+    OMX_U32 nBitRate;         /**< Bit rate of the encoded data data.  Use 0 for variable
+                                   rate or unknown bit rates. Encoding is set to the
+                                   bitrate closest to specified  value (in bps) */
+    OMX_U32 nMinBitRate;      /**< Sets minimum bitrate (in bps). */
+    OMX_U32 nMaxBitRate;      /**< Sets maximum bitrate (in bps). */
+
+    OMX_U32 nSampleRate;      /**< Sampling rate of the source data.  Use 0 for
+                                   variable or unknown sampling rate. */
+    OMX_U32 nAudioBandWidth;  /**< Audio band width (in Hz) to which an encoder should
+                                   limit the audio signal. Use 0 to let encoder decide */
+    OMX_S32 nQuality;            /**< Sets encoding quality to n, between -1 (low) and 10 (high).
+                                   In the default mode of operation, the quality level is 3.
+                                   Normal quality range is 0 - 10. */
+    OMX_BOOL bManaged;           /**< Set  bitrate  management  mode. This turns off the
+                                   normal VBR encoding, but allows hard or soft bitrate
+                                   constraints to be enforced by the encoder. This mode can
+                                   be slower, and may also be lower quality. It is
+                                   primarily useful for streaming. */
+    OMX_BOOL bDownmix;           /**< Downmix input from stereo to mono (has no effect on 
+                                   non-stereo streams). Useful for lower-bitrate encoding. */     
+} OMX_AUDIO_PARAM_VORBISTYPE;
+
+
+/** WMA Version */
+typedef enum OMX_AUDIO_WMAFORMATTYPE {
+  OMX_AUDIO_WMAFormatUnused = 0, /**< format unused or unknown */
+  OMX_AUDIO_WMAFormat7,          /**< Windows Media Audio format 7 */
+  OMX_AUDIO_WMAFormat8,          /**< Windows Media Audio format 8 */
+  OMX_AUDIO_WMAFormat9,          /**< Windows Media Audio format 9 */
+  OMX_AUDIO_WMAFormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+  OMX_AUDIO_WMAFormatVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+  OMX_AUDIO_WMAFormatMax = 0x7FFFFFFF
+} OMX_AUDIO_WMAFORMATTYPE;
+
+
+/** WMA Profile */
+typedef enum OMX_AUDIO_WMAPROFILETYPE {
+  OMX_AUDIO_WMAProfileUnused = 0,  /**< profile unused or unknown */
+  OMX_AUDIO_WMAProfileL1,          /**< Windows Media audio version 9 profile L1 */
+  OMX_AUDIO_WMAProfileL2,          /**< Windows Media audio version 9 profile L2 */
+  OMX_AUDIO_WMAProfileL3,          /**< Windows Media audio version 9 profile L3 */
+  OMX_AUDIO_WMAProfileKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+  OMX_AUDIO_WMAProfileVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+  OMX_AUDIO_WMAProfileMax = 0x7FFFFFFF
+} OMX_AUDIO_WMAPROFILETYPE;
+
+
+/** WMA params */
+typedef struct OMX_AUDIO_PARAM_WMATYPE {
+    OMX_U32 nSize;            /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
+    OMX_U32 nPortIndex;       /**< port that this structure applies to */
+    OMX_U16 nChannels;        /**< Number of channels */
+    OMX_U32 nBitRate;         /**< Bit rate of the input data.  Use 0 for variable
+                                   rate or unknown bit rates */
+    OMX_AUDIO_WMAFORMATTYPE eFormat; /**< Version of WMA stream / data */
+       OMX_AUDIO_WMAPROFILETYPE eProfile;  /**< Profile of WMA stream / data */
+    OMX_U32 nSamplingRate;    /**< Sampling rate of the source data */
+    OMX_U16 nBlockAlign;      /**< is the block alignment, or block size, in bytes of the audio codec */
+    OMX_U16 nEncodeOptions;   /**< WMA Type-specific data */
+    OMX_U32 nSuperBlockAlign; /**< WMA Type-specific data */
+} OMX_AUDIO_PARAM_WMATYPE;
+
+/** 
+ * RealAudio format
+ */
+typedef enum OMX_AUDIO_RAFORMATTYPE {
+    OMX_AUDIO_RAFormatUnused = 0, /**< Format unused or unknown */
+    OMX_AUDIO_RA8,                /**< RealAudio 8 codec */
+    OMX_AUDIO_RA9,                /**< RealAudio 9 codec */
+    OMX_AUDIO_RA10_AAC,           /**< MPEG-4 AAC codec for bitrates of more than 128kbps */
+    OMX_AUDIO_RA10_CODEC,         /**< RealAudio codec for bitrates less than 128 kbps */
+    OMX_AUDIO_RA10_LOSSLESS,      /**< RealAudio Lossless */
+    OMX_AUDIO_RA10_MULTICHANNEL,  /**< RealAudio Multichannel */
+    OMX_AUDIO_RA10_VOICE,         /**< RealAudio Voice for bitrates below 15 kbps */
+    OMX_AUDIO_RAFormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_AUDIO_RAFormatVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_VIDEO_RAFormatMax = 0x7FFFFFFF
+} OMX_AUDIO_RAFORMATTYPE;
+
+/** RA (Real Audio) params */ 
+typedef struct OMX_AUDIO_PARAM_RATYPE { 
+    OMX_U32 nSize;              /**< Size of this structure, in Bytes */ 
+    OMX_VERSIONTYPE nVersion;   /**< OMX specification version information */ 
+    OMX_U32 nPortIndex;         /**< Port that this structure applies to */ 
+    OMX_U32 nChannels;          /**< Number of channels */ 
+    OMX_U32 nSamplingRate;      /**< is the sampling rate of the source data */ 
+    OMX_U32 nBitsPerFrame;      /**< is the value for bits per frame  */ 
+    OMX_U32 nSamplePerFrame;    /**< is the value for samples per frame */ 
+    OMX_U32 nCouplingQuantBits; /**< is the number of coupling quantization bits in the stream */ 
+    OMX_U32 nCouplingStartRegion;   /**< is the coupling start region in the stream  */ 
+    OMX_U32 nNumRegions;        /**< is the number of regions value */ 
+    OMX_AUDIO_RAFORMATTYPE eFormat; /**< is the RealAudio audio format */
+} OMX_AUDIO_PARAM_RATYPE; 
+
+
+/** SBC Allocation Method Type */
+typedef enum OMX_AUDIO_SBCALLOCMETHODTYPE {
+  OMX_AUDIO_SBCAllocMethodLoudness, /**< Loudness allocation method */
+  OMX_AUDIO_SBCAllocMethodSNR,      /**< SNR allocation method */
+  OMX_AUDIO_SBCAllocMethodKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+  OMX_AUDIO_SBCAllocMethodVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+  OMX_AUDIO_SBCAllocMethodMax = 0x7FFFFFFF
+} OMX_AUDIO_SBCALLOCMETHODTYPE;
+
+
+/** SBC params */
+typedef struct OMX_AUDIO_PARAM_SBCTYPE {
+    OMX_U32 nSize;             /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;  /**< OMX specification version information */
+    OMX_U32 nPortIndex;        /**< port that this structure applies to */
+    OMX_U32 nChannels;         /**< Number of channels */
+    OMX_U32 nBitRate;          /**< Bit rate of the input data.  Use 0 for variable
+                                    rate or unknown bit rates */
+    OMX_U32 nSampleRate;       /**< Sampling rate of the source data.  Use 0 for
+                                    variable or unknown sampling rate. */
+    OMX_U32 nBlocks;           /**< Number of blocks */
+    OMX_U32 nSubbands;         /**< Number of subbands */
+    OMX_U32 nBitPool;          /**< Bitpool value */
+    OMX_BOOL bEnableBitrate;   /**< Use bitrate value instead of bitpool */
+    OMX_AUDIO_CHANNELMODETYPE eChannelMode; /**< Channel mode enumeration */
+    OMX_AUDIO_SBCALLOCMETHODTYPE eSBCAllocType;   /**< SBC Allocation method type */
+} OMX_AUDIO_PARAM_SBCTYPE;
+
+
+/** ADPCM stream format parameters */ 
+typedef struct OMX_AUDIO_PARAM_ADPCMTYPE { 
+    OMX_U32 nSize;              /**< size of the structure in bytes */ 
+    OMX_VERSIONTYPE nVersion;   /**< OMX specification version information */ 
+    OMX_U32 nPortIndex;         /**< port that this structure applies to */ 
+    OMX_U32 nChannels;          /**< Number of channels in the data stream (not 
+                                     necessarily the same as the number of channels 
+                                     to be rendered. */ 
+    OMX_U32 nBitsPerSample;     /**< Number of bits in each sample */ 
+    OMX_U32 nSampleRate;        /**< Sampling rate of the source data.  Use 0 for 
+                                    variable or unknown sampling rate. */ 
+} OMX_AUDIO_PARAM_ADPCMTYPE; 
+
+
+/** G723 rate */
+typedef enum OMX_AUDIO_G723RATE {
+    OMX_AUDIO_G723ModeUnused = 0,  /**< AMRNB Mode unused / unknown */
+    OMX_AUDIO_G723ModeLow,         /**< 5300 bps */
+    OMX_AUDIO_G723ModeHigh,        /**< 6300 bps */
+    OMX_AUDIO_G723ModeKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_AUDIO_G723ModeVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_AUDIO_G723ModeMax = 0x7FFFFFFF
+} OMX_AUDIO_G723RATE;
+
+
+/** G723 - Sample rate must be 8 KHz */
+typedef struct OMX_AUDIO_PARAM_G723TYPE { 
+    OMX_U32 nSize;                /**< size of the structure in bytes */ 
+    OMX_VERSIONTYPE nVersion;     /**< OMX specification version information */ 
+    OMX_U32 nPortIndex;           /**< port that this structure applies to */ 
+    OMX_U32 nChannels;            /**< Number of channels in the data stream (not 
+                                       necessarily the same as the number of channels 
+                                       to be rendered. */ 
+    OMX_BOOL bDTX;                /**< Enable Discontinuous Transmisssion */ 
+    OMX_AUDIO_G723RATE eBitRate;  /**< todo: Should this be moved to a config? */
+    OMX_BOOL bHiPassFilter;       /**< Enable High Pass Filter */ 
+    OMX_BOOL bPostFilter;         /**< Enable Post Filter */ 
+} OMX_AUDIO_PARAM_G723TYPE; 
+
+
+/** ITU G726 (ADPCM) rate */
+typedef enum OMX_AUDIO_G726MODE {
+    OMX_AUDIO_G726ModeUnused = 0,  /**< G726 Mode unused / unknown */
+    OMX_AUDIO_G726Mode16,          /**< 16 kbps */
+    OMX_AUDIO_G726Mode24,          /**< 24 kbps */
+    OMX_AUDIO_G726Mode32,          /**< 32 kbps, most common rate, also G721 */
+    OMX_AUDIO_G726Mode40,          /**< 40 kbps */
+    OMX_AUDIO_G726ModeKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_AUDIO_G726ModeVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_AUDIO_G726ModeMax = 0x7FFFFFFF
+} OMX_AUDIO_G726MODE;
+
+
+/** G.726 stream format parameters - must be at 8KHz */ 
+typedef struct OMX_AUDIO_PARAM_G726TYPE { 
+    OMX_U32 nSize;              /**< size of the structure in bytes */ 
+    OMX_VERSIONTYPE nVersion;   /**< OMX specification version information */ 
+    OMX_U32 nPortIndex;         /**< port that this structure applies to */ 
+    OMX_U32 nChannels;          /**< Number of channels in the data stream (not 
+                                     necessarily the same as the number of channels 
+                                     to be rendered. */ 
+     OMX_AUDIO_G726MODE eG726Mode;
+} OMX_AUDIO_PARAM_G726TYPE; 
+
+
+/** G729 coder type */
+typedef enum OMX_AUDIO_G729TYPE {
+    OMX_AUDIO_G729 = 0,           /**< ITU G.729  encoded data */
+    OMX_AUDIO_G729A,              /**< ITU G.729 annex A  encoded data */
+    OMX_AUDIO_G729B,              /**< ITU G.729 with annex B encoded data */
+    OMX_AUDIO_G729AB,             /**< ITU G.729 annexes A and B encoded data */
+    OMX_AUDIO_G729KhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_AUDIO_G729VendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_AUDIO_G729Max = 0x7FFFFFFF
+} OMX_AUDIO_G729TYPE;
+
+
+/** G729 stream format parameters - fixed 6KHz sample rate */
+typedef struct OMX_AUDIO_PARAM_G729TYPE {
+    OMX_U32 nSize;            /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
+    OMX_U32 nPortIndex;       /**< port that this structure applies to */
+    OMX_U32 nChannels;        /**< Number of channels in the data stream (not
+                                   necessarily the same as the number of channels
+                                   to be rendered. */
+    OMX_BOOL bDTX;            /**< Enable Discontinuous Transmisssion */
+    OMX_AUDIO_G729TYPE eBitType;
+} OMX_AUDIO_PARAM_G729TYPE;
+
+
+/** AMR Frame format */ 
+typedef enum OMX_AUDIO_AMRFRAMEFORMATTYPE { 
+    OMX_AUDIO_AMRFrameFormatConformance = 0,  /**< Frame Format is AMR Conformance 
+                                                   (Standard) Format */ 
+    OMX_AUDIO_AMRFrameFormatIF1,              /**< Frame Format is AMR Interface 
+                                                   Format 1 */ 
+    OMX_AUDIO_AMRFrameFormatIF2,              /**< Frame Format is AMR Interface 
+                                                   Format 2*/ 
+    OMX_AUDIO_AMRFrameFormatFSF,              /**< Frame Format is AMR File Storage 
+                                                   Format */ 
+    OMX_AUDIO_AMRFrameFormatRTPPayload,       /**< Frame Format is AMR Real-Time 
+                                                   Transport Protocol Payload Format */ 
+    OMX_AUDIO_AMRFrameFormatITU,              /**< Frame Format is ITU Format (added at Motorola request) */ 
+    OMX_AUDIO_AMRFrameFormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_AUDIO_AMRFrameFormatVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_AUDIO_AMRFrameFormatMax = 0x7FFFFFFF 
+} OMX_AUDIO_AMRFRAMEFORMATTYPE; 
+
+
+/** AMR band mode */
+typedef enum OMX_AUDIO_AMRBANDMODETYPE {
+    OMX_AUDIO_AMRBandModeUnused = 0,          /**< AMRNB Mode unused / unknown */
+    OMX_AUDIO_AMRBandModeNB0,                 /**< AMRNB Mode 0 =  4750 bps */
+    OMX_AUDIO_AMRBandModeNB1,                 /**< AMRNB Mode 1 =  5150 bps */
+    OMX_AUDIO_AMRBandModeNB2,                 /**< AMRNB Mode 2 =  5900 bps */ 
+    OMX_AUDIO_AMRBandModeNB3,                 /**< AMRNB Mode 3 =  6700 bps */
+    OMX_AUDIO_AMRBandModeNB4,                 /**< AMRNB Mode 4 =  7400 bps */
+    OMX_AUDIO_AMRBandModeNB5,                 /**< AMRNB Mode 5 =  7950 bps */
+    OMX_AUDIO_AMRBandModeNB6,                 /**< AMRNB Mode 6 = 10200 bps */
+    OMX_AUDIO_AMRBandModeNB7,                 /**< AMRNB Mode 7 = 12200 bps */
+    OMX_AUDIO_AMRBandModeWB0,                 /**< AMRWB Mode 0 =  6600 bps */
+    OMX_AUDIO_AMRBandModeWB1,                 /**< AMRWB Mode 1 =  8850 bps */
+    OMX_AUDIO_AMRBandModeWB2,                 /**< AMRWB Mode 2 = 12650 bps */ 
+    OMX_AUDIO_AMRBandModeWB3,                 /**< AMRWB Mode 3 = 14250 bps */ 
+    OMX_AUDIO_AMRBandModeWB4,                 /**< AMRWB Mode 4 = 15850 bps */
+    OMX_AUDIO_AMRBandModeWB5,                 /**< AMRWB Mode 5 = 18250 bps */
+    OMX_AUDIO_AMRBandModeWB6,                 /**< AMRWB Mode 6 = 19850 bps */
+    OMX_AUDIO_AMRBandModeWB7,                 /**< AMRWB Mode 7 = 23050 bps */
+    OMX_AUDIO_AMRBandModeWB8,                 /**< AMRWB Mode 8 = 23850 bps */      
+    OMX_AUDIO_AMRBandModeKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_AUDIO_AMRBandModeVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_AUDIO_AMRBandModeMax = 0x7FFFFFFF
+} OMX_AUDIO_AMRBANDMODETYPE;
+     
+
+/** AMR Discontinuous Transmission mode */ 
+typedef enum OMX_AUDIO_AMRDTXMODETYPE { 
+    OMX_AUDIO_AMRDTXModeOff = 0,        /**< AMR Discontinuous Transmission Mode is disabled */ 
+    OMX_AUDIO_AMRDTXModeOnVAD1,         /**< AMR Discontinuous Transmission Mode using 
+                                             Voice Activity Detector 1 (VAD1) is enabled */ 
+    OMX_AUDIO_AMRDTXModeOnVAD2,         /**< AMR Discontinuous Transmission Mode using 
+                                             Voice Activity Detector 2 (VAD2) is enabled */       
+    OMX_AUDIO_AMRDTXModeOnAuto,         /**< The codec will automatically select between 
+                                             Off, VAD1 or VAD2 modes */ 
+
+    OMX_AUDIO_AMRDTXasEFR,             /**< DTX as EFR instead of AMR standard (3GPP 26.101, frame type =8,9,10) */
+
+    OMX_AUDIO_AMRDTXModeKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_AUDIO_AMRDTXModeVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_AUDIO_AMRDTXModeMax = 0x7FFFFFFF 
+} OMX_AUDIO_AMRDTXMODETYPE; 
+
+/** AMR params */
+typedef struct OMX_AUDIO_PARAM_AMRTYPE {
+    OMX_U32 nSize;                          /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;               /**< OMX specification version information */
+    OMX_U32 nPortIndex;                     /**< port that this structure applies to */
+    OMX_U32 nChannels;                      /**< Number of channels */
+    OMX_U32 nBitRate;                       /**< Bit rate read only field */
+    OMX_AUDIO_AMRBANDMODETYPE eAMRBandMode; /**< AMR Band Mode enumeration */ 
+    OMX_AUDIO_AMRDTXMODETYPE  eAMRDTXMode;  /**< AMR DTX Mode enumeration */
+    OMX_AUDIO_AMRFRAMEFORMATTYPE eAMRFrameFormat; /**< AMR frame format enumeration */
+} OMX_AUDIO_PARAM_AMRTYPE;
+
+
+/** GSM_FR (ETSI 06.10, 3GPP 46.010) stream format parameters */
+typedef struct OMX_AUDIO_PARAM_GSMFRTYPE {
+    OMX_U32 nSize;            /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
+    OMX_U32 nPortIndex;       /**< port that this structure applies to */
+    OMX_BOOL bDTX;            /**< Enable Discontinuous Transmisssion */
+    OMX_BOOL bHiPassFilter;   /**< Enable High Pass Filter */
+} OMX_AUDIO_PARAM_GSMFRTYPE;
+
+
+/** GSM-HR (ETSI 06.20, 3GPP 46.020) stream format parameters */
+typedef struct OMX_AUDIO_PARAM_GSMHRTYPE {
+    OMX_U32 nSize;            /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
+    OMX_U32 nPortIndex;       /**< port that this structure applies to */
+    OMX_BOOL bDTX;            /**< Enable Discontinuous Transmisssion */
+    OMX_BOOL bHiPassFilter;   /**< Enable High Pass Filter */
+} OMX_AUDIO_PARAM_GSMHRTYPE;
+
+
+/** GSM-EFR (ETSI 06.60, 3GPP 46.060) stream format parameters */
+typedef struct OMX_AUDIO_PARAM_GSMEFRTYPE {
+    OMX_U32 nSize;            /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
+    OMX_U32 nPortIndex;       /**< port that this structure applies to */
+    OMX_BOOL bDTX;            /**< Enable Discontinuous Transmisssion */
+    OMX_BOOL bHiPassFilter;   /**< Enable High Pass Filter */
+} OMX_AUDIO_PARAM_GSMEFRTYPE;
+
+
+/** TDMA FR (TIA/EIA-136-420, VSELP 7.95kbps coder) stream format parameters */
+typedef struct OMX_AUDIO_PARAM_TDMAFRTYPE {
+    OMX_U32 nSize;                /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;     /**< OMX specification version information */
+    OMX_U32 nPortIndex;           /**< port that this structure applies to */
+    OMX_U32 nChannels;            /**< Number of channels in the data stream (not
+                                       necessarily the same as the number of channels
+                                       to be rendered. */
+    OMX_BOOL bDTX;                /**< Enable Discontinuous Transmisssion */
+    OMX_BOOL bHiPassFilter;       /**< Enable High Pass Filter */
+} OMX_AUDIO_PARAM_TDMAFRTYPE;
+
+
+/** TDMA EFR (TIA/EIA-136-410, ACELP 7.4kbps coder) stream format parameters */
+typedef struct OMX_AUDIO_PARAM_TDMAEFRTYPE {
+    OMX_U32 nSize;                /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;     /**< OMX specification version information */
+    OMX_U32 nPortIndex;           /**< port that this structure applies to */
+    OMX_U32 nChannels;            /**< Number of channels in the data stream (not
+                                       necessarily the same as the number of channels
+                                       to be rendered. */
+    OMX_BOOL bDTX;                /**< Enable Discontinuous Transmisssion */
+    OMX_BOOL bHiPassFilter;       /**< Enable High Pass Filter */
+} OMX_AUDIO_PARAM_TDMAEFRTYPE;
+
+
+/** PDC FR ( RCR-27, VSELP 6.7kbps coder) stream format parameters */
+typedef struct OMX_AUDIO_PARAM_PDCFRTYPE {
+    OMX_U32 nSize;                /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;     /**< OMX specification version information */
+    OMX_U32 nPortIndex;           /**< port that this structure applies to */
+    OMX_U32 nChannels;            /**< Number of channels in the data stream (not
+                                       necessarily the same as the number of channels
+                                       to be rendered. */
+    OMX_BOOL bDTX;                /**< Enable Discontinuous Transmisssion */
+    OMX_BOOL bHiPassFilter;       /**< Enable High Pass Filter */
+} OMX_AUDIO_PARAM_PDCFRTYPE;
+
+
+/** PDC EFR ( RCR-27, ACELP 6.7kbps coder) stream format parameters */
+typedef struct OMX_AUDIO_PARAM_PDCEFRTYPE {
+    OMX_U32 nSize;                /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;     /**< OMX specification version information */
+    OMX_U32 nPortIndex;           /**< port that this structure applies to */
+    OMX_U32 nChannels;            /**< Number of channels in the data stream (not
+                                       necessarily the same as the number of channels
+                                       to be rendered. */
+    OMX_BOOL bDTX;                /**< Enable Discontinuous Transmisssion */
+    OMX_BOOL bHiPassFilter;       /**< Enable High Pass Filter */
+} OMX_AUDIO_PARAM_PDCEFRTYPE;
+
+/** PDC HR ( RCR-27, PSI-CELP 3.45kbps coder) stream format parameters */
+typedef struct OMX_AUDIO_PARAM_PDCHRTYPE {
+    OMX_U32 nSize;                /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;     /**< OMX specification version information */
+    OMX_U32 nPortIndex;           /**< port that this structure applies to */
+    OMX_U32 nChannels;            /**< Number of channels in the data stream (not
+                                       necessarily the same as the number of channels
+                                       to be rendered. */
+    OMX_BOOL bDTX;                /**< Enable Discontinuous Transmisssion */
+    OMX_BOOL bHiPassFilter;       /**< Enable High Pass Filter */
+} OMX_AUDIO_PARAM_PDCHRTYPE;
+
+
+/** CDMA Rate types */
+typedef enum OMX_AUDIO_CDMARATETYPE {
+    OMX_AUDIO_CDMARateBlank = 0,          /**< CDMA encoded frame is blank */
+    OMX_AUDIO_CDMARateFull,               /**< CDMA encoded frame in full rate */
+    OMX_AUDIO_CDMARateHalf,               /**< CDMA encoded frame in half rate */
+    OMX_AUDIO_CDMARateQuarter,            /**< CDMA encoded frame in quarter rate */
+    OMX_AUDIO_CDMARateEighth,             /**< CDMA encoded frame in eighth rate (DTX)*/
+    OMX_AUDIO_CDMARateErasure,            /**< CDMA erasure frame */
+    OMX_AUDIO_CDMARateKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_AUDIO_CDMARateVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_AUDIO_CDMARateMax = 0x7FFFFFFF
+} OMX_AUDIO_CDMARATETYPE;
+
+
+/** QCELP8 (TIA/EIA-96, up to 8kbps coder) stream format parameters */
+typedef struct OMX_AUDIO_PARAM_QCELP8TYPE {
+    OMX_U32 nSize;                /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;     /**< OMX specification version information */
+    OMX_U32 nPortIndex;           /**< port that this structure applies to */
+    OMX_U32 nChannels;            /**< Number of channels in the data stream (not
+                                       necessarily the same as the number of channels
+                                       to be rendered. */
+    OMX_U32 nBitRate;             /**< Bit rate of the input data.  Use 0 for variable
+                                       rate or unknown bit rates */
+    OMX_AUDIO_CDMARATETYPE eCDMARate; /**< Frame rate */
+    OMX_U32 nMinBitRate;          /**< minmal rate for the encoder = 1,2,3,4, default = 1 */
+    OMX_U32 nMaxBitRate;          /**< maximal rate for the encoder = 1,2,3,4, default = 4 */
+} OMX_AUDIO_PARAM_QCELP8TYPE;
+
+
+/** QCELP13 ( CDMA, EIA/TIA-733, 13.3kbps coder) stream format parameters */
+typedef struct OMX_AUDIO_PARAM_QCELP13TYPE {
+    OMX_U32 nSize;                /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;     /**< OMX specification version information */
+    OMX_U32 nPortIndex;           /**< port that this structure applies to */
+    OMX_U32 nChannels;            /**< Number of channels in the data stream (not
+                                       necessarily the same as the number of channels
+                                       to be rendered. */
+    OMX_AUDIO_CDMARATETYPE eCDMARate; /**< Frame rate */
+    OMX_U32 nMinBitRate;          /**< minmal rate for the encoder = 1,2,3,4, default = 1 */
+    OMX_U32 nMaxBitRate;          /**< maximal rate for the encoder = 1,2,3,4, default = 4 */
+} OMX_AUDIO_PARAM_QCELP13TYPE;
+
+
+/** EVRC ( CDMA, EIA/TIA-127, RCELP up to 8.55kbps coder) stream format parameters */
+typedef struct OMX_AUDIO_PARAM_EVRCTYPE {
+    OMX_U32 nSize;                /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;     /**< OMX specification version information */
+    OMX_U32 nPortIndex;           /**< port that this structure applies to */
+    OMX_U32 nChannels;            /**< Number of channels in the data stream (not
+                                       necessarily the same as the number of channels
+                                       to be rendered. */
+    OMX_AUDIO_CDMARATETYPE eCDMARate; /**< actual Frame rate */
+    OMX_BOOL bRATE_REDUCon;       /**< RATE_REDUCtion is requested for this frame */
+    OMX_U32 nMinBitRate;          /**< minmal rate for the encoder = 1,2,3,4, default = 1 */
+    OMX_U32 nMaxBitRate;          /**< maximal rate for the encoder = 1,2,3,4, default = 4 */
+    OMX_BOOL bHiPassFilter;       /**< Enable encoder's High Pass Filter */
+    OMX_BOOL bNoiseSuppressor;    /**< Enable encoder's noise suppressor pre-processing */
+    OMX_BOOL bPostFilter;         /**< Enable decoder's post Filter */
+} OMX_AUDIO_PARAM_EVRCTYPE;
+
+
+/** SMV ( up to 8.55kbps coder) stream format parameters */
+typedef struct OMX_AUDIO_PARAM_SMVTYPE {
+    OMX_U32 nSize;                /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;     /**< OMX specification version information */
+    OMX_U32 nPortIndex;           /**< port that this structure applies to */
+    OMX_U32 nChannels;            /**< Number of channels in the data stream (not
+                                       necessarily the same as the number of channels
+                                       to be rendered. */
+    OMX_AUDIO_CDMARATETYPE eCDMARate; /**< Frame rate */
+    OMX_BOOL bRATE_REDUCon;           /**< RATE_REDUCtion is requested for this frame */
+    OMX_U32 nMinBitRate;          /**< minmal rate for the encoder = 1,2,3,4, default = 1 ??*/
+    OMX_U32 nMaxBitRate;          /**< maximal rate for the encoder = 1,2,3,4, default = 4 ??*/
+    OMX_BOOL bHiPassFilter;       /**< Enable encoder's High Pass Filter ??*/
+    OMX_BOOL bNoiseSuppressor;    /**< Enable encoder's noise suppressor pre-processing */
+    OMX_BOOL bPostFilter;         /**< Enable decoder's post Filter ??*/
+} OMX_AUDIO_PARAM_SMVTYPE;
+
+
+/** MIDI Format 
+ * @ingroup midi
+ */
+typedef enum OMX_AUDIO_MIDIFORMATTYPE
+{
+    OMX_AUDIO_MIDIFormatUnknown = 0, /**< MIDI Format unknown or don't care */
+    OMX_AUDIO_MIDIFormatSMF0,        /**< Standard MIDI File Type 0 */
+    OMX_AUDIO_MIDIFormatSMF1,        /**< Standard MIDI File Type 1 */
+    OMX_AUDIO_MIDIFormatSMF2,        /**< Standard MIDI File Type 2 */
+    OMX_AUDIO_MIDIFormatSPMIDI,      /**< SP-MIDI */
+    OMX_AUDIO_MIDIFormatXMF0,        /**< eXtensible Music Format type 0 */
+    OMX_AUDIO_MIDIFormatXMF1,        /**< eXtensible Music Format type 1 */
+    OMX_AUDIO_MIDIFormatMobileXMF,   /**< Mobile XMF (eXtensible Music Format type 2) */
+    OMX_AUDIO_MIDIFormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_AUDIO_MIDIFormatVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_AUDIO_MIDIFormatMax = 0x7FFFFFFF
+} OMX_AUDIO_MIDIFORMATTYPE;
+
+
+/** MIDI params 
+ * @ingroup midi
+ */
+typedef struct OMX_AUDIO_PARAM_MIDITYPE {
+    OMX_U32 nSize;                 /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;      /**< OMX specification version information */
+    OMX_U32 nPortIndex;            /**< port that this structure applies to */
+    OMX_U32 nFileSize;             /**< size of the MIDI file in bytes, where the entire 
+                                        MIDI file passed in, otherwise if 0x0, the MIDI data 
+                                        is merged and streamed (instead of passed as an 
+                                        entire MIDI file) */
+    OMX_BU32 sMaxPolyphony;        /**< Specifies the maximum simultaneous polyphonic 
+                                        voices. A value of zero indicates that the default 
+                                        polyphony of the device is used  */                                    
+    OMX_BOOL bLoadDefaultSound;    /**< Whether to load default sound 
+                                        bank at initialization */
+    OMX_AUDIO_MIDIFORMATTYPE eMidiFormat; /**< Version of the MIDI file */                                                                           
+} OMX_AUDIO_PARAM_MIDITYPE;
+
+
+/** Type of the MIDI sound bank 
+ * @ingroup midi
+ */
+typedef enum OMX_AUDIO_MIDISOUNDBANKTYPE {
+    OMX_AUDIO_MIDISoundBankUnused = 0,           /**< unused/unknown soundbank type */
+    OMX_AUDIO_MIDISoundBankDLS1,                 /**< DLS version 1 */
+    OMX_AUDIO_MIDISoundBankDLS2,                 /**< DLS version 2 */
+    OMX_AUDIO_MIDISoundBankMobileDLSBase,        /**< Mobile DLS, using the base functionality */
+    OMX_AUDIO_MIDISoundBankMobileDLSPlusOptions, /**< Mobile DLS, using the specification-defined optional feature set */
+    OMX_AUDIO_MIDISoundBankKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_AUDIO_MIDISoundBankVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_AUDIO_MIDISoundBankMax = 0x7FFFFFFF
+} OMX_AUDIO_MIDISOUNDBANKTYPE;
+
+
+/** Bank Layout describes how bank MSB & LSB are used in the DLS instrument definitions sound bank 
+ * @ingroup midi
+ */
+typedef enum OMX_AUDIO_MIDISOUNDBANKLAYOUTTYPE {
+   OMX_AUDIO_MIDISoundBankLayoutUnused = 0,   /**< unused/unknown soundbank type */
+   OMX_AUDIO_MIDISoundBankLayoutGM,           /**< GS layout (based on bank MSB 0x00) */
+   OMX_AUDIO_MIDISoundBankLayoutGM2,          /**< General MIDI 2 layout (using MSB 0x78/0x79, LSB 0x00) */
+   OMX_AUDIO_MIDISoundBankLayoutUser,         /**< Does not conform to any bank numbering standards */
+   OMX_AUDIO_MIDISoundBankLayoutKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+   OMX_AUDIO_MIDISoundBankLayoutVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+   OMX_AUDIO_MIDISoundBankLayoutMax = 0x7FFFFFFF
+} OMX_AUDIO_MIDISOUNDBANKLAYOUTTYPE;
+
+
+/** MIDI params to load/unload user soundbank 
+ * @ingroup midi
+ */
+typedef struct OMX_AUDIO_PARAM_MIDILOADUSERSOUNDTYPE {
+    OMX_U32 nSize;            /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
+    OMX_U32 nPortIndex;       /**< port that this structure applies to */
+    OMX_U32 nDLSIndex;        /**< DLS file index to be loaded */
+    OMX_U32 nDLSSize;         /**< Size in bytes */
+    OMX_PTR pDLSData;         /**< Pointer to DLS file data */
+    OMX_AUDIO_MIDISOUNDBANKTYPE eMidiSoundBank;   /**< Midi sound bank type enumeration */
+    OMX_AUDIO_MIDISOUNDBANKLAYOUTTYPE eMidiSoundBankLayout; /**< Midi sound bank layout enumeration */
+} OMX_AUDIO_PARAM_MIDILOADUSERSOUNDTYPE;
+
+
+/** Structure for Live MIDI events and MIP messages. 
+ * (MIP = Maximum Instantaneous Polyphony; part of the SP-MIDI standard.) 
+ * @ingroup midi
+ */
+typedef struct OMX_AUDIO_CONFIG_MIDIIMMEDIATEEVENTTYPE {
+    OMX_U32 nSize;            /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
+    OMX_U32 nPortIndex;       /**< Port that this structure applies to */
+    OMX_U32 nMidiEventSize;   /**< Size of immediate MIDI events or MIP message in bytes  */
+    OMX_U8 nMidiEvents[1];    /**< MIDI event array to be rendered immediately, or an
+                                   array for the MIP message buffer, where the size is 
+                                   indicated by nMidiEventSize */
+} OMX_AUDIO_CONFIG_MIDIIMMEDIATEEVENTTYPE;
+
+
+/** MIDI sound bank/ program pair in a given channel 
+ * @ingroup midi
+ */
+typedef struct OMX_AUDIO_CONFIG_MIDISOUNDBANKPROGRAMTYPE {
+    OMX_U32 nSize;              /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;   /**< OMX specification version information */
+    OMX_U32 nPortIndex;         /**< Port that this structure applies to */
+    OMX_U32 nChannel;           /**< Valid channel values range from 1 to 16 */
+    OMX_U16 nIDProgram;         /**< Valid program ID range is 1 to 128 */
+    OMX_U16 nIDSoundBank;       /**< Sound bank ID */
+    OMX_U32 nUserSoundBankIndex;/**< User soundbank index, easier to access soundbanks 
+                                     by index if multiple banks are present */
+} OMX_AUDIO_CONFIG_MIDISOUNDBANKPROGRAMTYPE;
+
+
+/** MIDI control 
+ * @ingroup midi
+ */
+typedef struct OMX_AUDIO_CONFIG_MIDICONTROLTYPE {
+    OMX_U32 nSize;                /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;     /**< OMX specification version information */
+    OMX_U32 nPortIndex;           /**< port that this structure applies to */
+    OMX_BS32 sPitchTransposition; /**< Pitch transposition in semitones, stored as Q22.10 
+                                       format based on JAVA MMAPI (JSR-135) requirement */
+    OMX_BU32 sPlayBackRate;       /**< Relative playback rate, stored as Q14.17 fixed-point
+                                       number based on JSR-135 requirement */
+    OMX_BU32 sTempo ;             /**< Tempo in beats per minute (BPM), stored as Q22.10 
+                                       fixed-point number based on JSR-135 requirement */
+    OMX_U32 nMaxPolyphony;        /**< Specifies the maximum simultaneous polyphonic 
+                                       voices. A value of zero indicates that the default 
+                                       polyphony of the device is used  */
+    OMX_U32 nNumRepeat;           /**< Number of times to repeat playback */
+    OMX_U32 nStopTime;            /**< Time in milliseconds to indicate when playback 
+                                       will stop automatically.  Set to zero if not used */
+    OMX_U16 nChannelMuteMask;     /**< 16 bit mask for channel mute status */
+    OMX_U16 nChannelSoloMask;     /**< 16 bit mask for channel solo status */
+    OMX_U32 nTrack0031MuteMask;   /**< 32 bit mask for track mute status. Note: This is for tracks 0-31 */
+    OMX_U32 nTrack3263MuteMask;   /**< 32 bit mask for track mute status. Note: This is for tracks 32-63 */
+    OMX_U32 nTrack0031SoloMask;   /**< 32 bit mask for track solo status. Note: This is for tracks 0-31 */
+    OMX_U32 nTrack3263SoloMask;   /**< 32 bit mask for track solo status. Note: This is for tracks 32-63 */
+
+} OMX_AUDIO_CONFIG_MIDICONTROLTYPE;
+
+
+/** MIDI Playback States 
+ * @ingroup midi
+ */
+typedef enum OMX_AUDIO_MIDIPLAYBACKSTATETYPE {
+  OMX_AUDIO_MIDIPlayBackStateUnknown = 0,      /**< Unknown state or state does not map to 
+                                                                                                       other defined states */
+  OMX_AUDIO_MIDIPlayBackStateClosedEngaged,    /**< No MIDI resource is currently open. 
+                                                    The MIDI engine is currently processing 
+                                                    MIDI events. */
+  OMX_AUDIO_MIDIPlayBackStateParsing,          /**< A MIDI resource is open and is being 
+                                                    primed. The MIDI engine is currently 
+                                                    processing MIDI events. */
+  OMX_AUDIO_MIDIPlayBackStateOpenEngaged,      /**< A MIDI resource is open and primed but 
+                                                    not playing. The MIDI engine is currently
+                                                    processing MIDI events. The transition to
+                                                    this state is only possible from the 
+                                                    OMX_AUDIO_MIDIPlayBackStatePlaying state,
+                                                    when the 'playback head' reaches the end
+                                                    of media data or the playback stops due
+                                                    to stop time set.*/
+  OMX_AUDIO_MIDIPlayBackStatePlaying,          /**< A MIDI resource is open and currently
+                                                    playing. The MIDI engine is currently
+                                                    processing MIDI events.*/
+  OMX_AUDIO_MIDIPlayBackStatePlayingPartially, /**< Best-effort playback due to SP-MIDI/DLS
+                                                    resource constraints */
+  OMX_AUDIO_MIDIPlayBackStatePlayingSilently,  /**< Due to system resource constraints and
+                                                    SP-MIDI content constraints, there is
+                                                    no audible MIDI content during playback
+                                                    currently. The situation may change if
+                                                    resources are freed later.*/
+  OMX_AUDIO_MIDIPlayBackStateKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+  OMX_AUDIO_MIDIPlayBackStateVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+  OMX_AUDIO_MIDIPlayBackStateMax = 0x7FFFFFFF
+} OMX_AUDIO_MIDIPLAYBACKSTATETYPE;
+
+
+/** MIDI status 
+ * @ingroup midi
+ */
+typedef struct OMX_AUDIO_CONFIG_MIDISTATUSTYPE {
+    OMX_U32 nSize;              /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;   /**< OMX specification version information */
+    OMX_U32 nPortIndex;         /**< port that this structure applies to */
+    OMX_U16 nNumTracks;         /**< Number of MIDI tracks in the file, read only field. 
+                                     NOTE: May not return a meaningful value until the entire 
+                                     file is parsed and buffered.  */
+    OMX_U32 nDuration;          /**< The length of the currently open MIDI resource 
+                                     in milliseconds. NOTE: May not return a meaningful value 
+                                     until the entire file is parsed and buffered.  */  
+    OMX_U32 nPosition;          /**< Current Position of the MIDI resource being played 
+                                     in milliseconds */
+    OMX_BOOL bVibra;            /**< Does Vibra track exist? NOTE: May not return a meaningful 
+                                     value until the entire file is parsed and buffered. */
+    OMX_U32 nNumMetaEvents;     /**< Total number of MIDI Meta Events in the currently 
+                                     open MIDI resource. NOTE: May not return a meaningful value 
+                                     until the entire file is parsed and buffered.  */
+    OMX_U32 nNumActiveVoices;   /**< Number of active voices in the currently playing 
+                                     MIDI resource. NOTE: May not return a meaningful value until 
+                                     the entire file is parsed and buffered. */
+    OMX_AUDIO_MIDIPLAYBACKSTATETYPE eMIDIPlayBackState;  /**< MIDI playback state enumeration, read only field */
+} OMX_AUDIO_CONFIG_MIDISTATUSTYPE;
+
+
+/** MIDI Meta Event structure one per Meta Event.
+ *  MIDI Meta Events are like audio metadata, except that they are interspersed 
+ *  with the MIDI content throughout the file and are not localized in the header. 
+ *  As such, it is necessary to retrieve information about these Meta Events from 
+ *  the engine, as it encounters these Meta Events within the MIDI content. 
+ *  For example, SMF files can have up to 14 types of MIDI Meta Events (copyright, 
+ *  author, default tempo, etc.) scattered throughout the file. 
+ *  @ingroup midi
+ */
+typedef struct OMX_AUDIO_CONFIG_MIDIMETAEVENTTYPE{ 
+    OMX_U32 nSize;            /**< size of the structure in bytes */ 
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ 
+    OMX_U32 nPortIndex;       /**< port that this structure applies to */ 
+    OMX_U32 nIndex;           /**< Index of Meta Event */ 
+    OMX_U8 nMetaEventType;    /**< Meta Event Type, 7bits (i.e. 0 - 127) */ 
+    OMX_U32 nMetaEventSize;   /**< size of the Meta Event in bytes */ 
+    OMX_U32 nTrack;           /**< track number for the meta event */
+    OMX_U32 nPosition;        /**< Position of the meta-event in milliseconds */
+} OMX_AUDIO_CONFIG_MIDIMETAEVENTTYPE; 
+
+
+/** MIDI Meta Event Data structure - one per Meta Event. 
+ * @ingroup midi
+ */ 
+typedef struct OMX_AUDIO_CONFIG_MIDIMETAEVENTDATATYPE{ 
+    OMX_U32 nSize;            /**< size of the structure in bytes */ 
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */ 
+    OMX_U32 nPortIndex;       /**< port that this structure applies to */ 
+    OMX_U32 nIndex;           /**< Index of Meta Event */ 
+    OMX_U32 nMetaEventSize;   /**< size of the Meta Event in bytes */ 
+    OMX_U8 nData[1];          /**< array of one or more bytes of meta data 
+                                   as indicated by the nMetaEventSize field */ 
+} OMX_AUDIO_CONFIG__MIDIMETAEVENTDATATYPE; 
+
+
+/** Audio Volume adjustment for a port */
+typedef struct OMX_AUDIO_CONFIG_VOLUMETYPE {
+    OMX_U32 nSize;              /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;   /**< OMX specification version information */
+    OMX_U32 nPortIndex;         /**< Port index indicating which port to 
+                                     set.  Select the input port to set 
+                                     just that port's volume.  Select the 
+                                     output port to adjust the master 
+                                     volume. */
+    OMX_BOOL bLinear;           /**< Is the volume to be set in linear (0.100) 
+                                     or logarithmic scale (mB) */
+    OMX_BS32 sVolume;           /**< Volume linear setting in the 0..100 range, OR
+                                     Volume logarithmic setting for this port.  The values
+                                     for volume are in mB (millibels = 1/100 dB) relative
+                                     to a gain of 1 (e.g. the output is the same as the 
+                                     input level).  Values are in mB from nMax 
+                                     (maximum volume) to nMin mB (typically negative).
+                                     Since the volume is "voltage"
+                                     and not a "power", it takes a setting of
+                                     -600 mB to decrease the volume by 1/2.  If
+                                     a component cannot accurately set the 
+                                     volume to the requested value, it must
+                                     set the volume to the closest value BELOW
+                                     the requested value.  When getting the
+                                     volume setting, the current actual volume
+                                     must be returned. */
+} OMX_AUDIO_CONFIG_VOLUMETYPE;
+
+
+/** Audio Volume adjustment for a channel */
+typedef struct OMX_AUDIO_CONFIG_CHANNELVOLUMETYPE {
+    OMX_U32 nSize;              /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;   /**< OMX specification version information */
+    OMX_U32 nPortIndex;         /**< Port index indicating which port to 
+                                     set.  Select the input port to set 
+                                     just that port's volume.  Select the 
+                                     output port to adjust the master 
+                                     volume. */
+    OMX_U32 nChannel;           /**< channel to select from 0 to N-1, 
+                                     using OMX_ALL to apply volume settings
+                                     to all channels */
+    OMX_BOOL bLinear;           /**< Is the volume to be set in linear (0.100) or 
+                                     logarithmic scale (mB) */
+    OMX_BS32 sVolume;           /**< Volume linear setting in the 0..100 range, OR
+                                     Volume logarithmic setting for this port.  
+                                     The values for volume are in mB 
+                                     (millibels = 1/100 dB) relative to a gain
+                                     of 1 (e.g. the output is the same as the 
+                                     input level).  Values are in mB from nMax 
+                                     (maximum volume) to nMin mB (typically negative).  
+                                     Since the volume is "voltage"
+                                     and not a "power", it takes a setting of
+                                     -600 mB to decrease the volume by 1/2.  If
+                                     a component cannot accurately set the 
+                                     volume to the requested value, it must
+                                     set the volume to the closest value BELOW
+                                     the requested value.  When getting the
+                                     volume setting, the current actual volume
+                                     must be returned. */
+    OMX_BOOL bIsMIDI;           /**< TRUE if nChannel refers to a MIDI channel,
+                                     FALSE otherwise */
+} OMX_AUDIO_CONFIG_CHANNELVOLUMETYPE;
+
+
+/** Audio balance setting */
+typedef struct OMX_AUDIO_CONFIG_BALANCETYPE {
+    OMX_U32 nSize;              /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;   /**< OMX specification version information */
+    OMX_U32 nPortIndex;         /**< Port index indicating which port to 
+                                     set.  Select the input port to set 
+                                     just that port's balance.  Select the 
+                                     output port to adjust the master 
+                                     balance. */
+    OMX_S32 nBalance;           /**< balance setting for this port 
+                                     (-100 to 100, where -100 indicates
+                                     all left, and no right */
+} OMX_AUDIO_CONFIG_BALANCETYPE;
+
+
+/** Audio Port mute */
+typedef struct OMX_AUDIO_CONFIG_MUTETYPE {
+    OMX_U32 nSize;              /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;   /**< OMX specification version information */
+    OMX_U32 nPortIndex;         /**< Port index indicating which port to 
+                                     set.  Select the input port to set 
+                                     just that port's mute.  Select the 
+                                     output port to adjust the master 
+                                     mute. */
+    OMX_BOOL bMute;             /**< Mute setting for this port */
+} OMX_AUDIO_CONFIG_MUTETYPE;
+
+
+/** Audio Channel mute */
+typedef struct OMX_AUDIO_CONFIG_CHANNELMUTETYPE {
+    OMX_U32 nSize;              /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;   /**< OMX specification version information */
+    OMX_U32 nPortIndex;         /**< port that this structure applies to */
+    OMX_U32 nChannel;           /**< channel to select from 0 to N-1, 
+                                     using OMX_ALL to apply mute settings
+                                     to all channels */
+    OMX_BOOL bMute;             /**< Mute setting for this channel */
+    OMX_BOOL bIsMIDI;           /**< TRUE if nChannel refers to a MIDI channel,
+                                     FALSE otherwise */ 
+} OMX_AUDIO_CONFIG_CHANNELMUTETYPE;
+
+
+
+/** Enable / Disable for loudness control, which boosts bass and to a 
+ *  smaller extent high end frequencies to compensate for hearing
+ *  ability at the extreme ends of the audio spectrum
+ */ 
+typedef struct OMX_AUDIO_CONFIG_LOUDNESSTYPE {
+    OMX_U32 nSize;             /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;  /**< OMX specification version information */
+    OMX_U32 nPortIndex;        /**< port that this structure applies to */
+    OMX_BOOL bLoudness;        /**< Enable/disable for loudness */
+} OMX_AUDIO_CONFIG_LOUDNESSTYPE;
+
+
+/** Enable / Disable for bass, which controls low frequencies
+ */ 
+typedef struct OMX_AUDIO_CONFIG_BASSTYPE {
+    OMX_U32 nSize;             /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;  /**< OMX specification version information */
+    OMX_U32 nPortIndex;        /**< port that this structure applies to */
+    OMX_BOOL bEnable;          /**< Enable/disable for bass control */
+    OMX_S32 nBass;             /**< bass setting for the port, as a 
+                                    continuous value from -100 to 100  
+                                    (0 means no change in bass level)*/
+} OMX_AUDIO_CONFIG_BASSTYPE;
+
+
+/** Enable / Disable for treble, which controls high frequencies tones
+ */ 
+typedef struct OMX_AUDIO_CONFIG_TREBLETYPE {
+    OMX_U32 nSize;             /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;  /**< OMX specification version information */
+    OMX_U32 nPortIndex;        /**< port that this structure applies to */
+    OMX_BOOL bEnable;          /**< Enable/disable for treble control */
+    OMX_S32  nTreble;          /**< treble setting for the port, as a
+                                    continuous value from -100 to 100  
+                                    (0 means no change in treble level) */
+} OMX_AUDIO_CONFIG_TREBLETYPE;
+
+
+/** An equalizer is typically used for two reasons: to compensate for an 
+ *  sub-optimal frequency response of a system to make it sound more natural 
+ *  or to create intentionally some unnatural coloring to the sound to create
+ *  an effect.
+ *  @ingroup effects
+ */
+typedef struct OMX_AUDIO_CONFIG_EQUALIZERTYPE {
+    OMX_U32 nSize;             /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;  /**< OMX specification version information */
+    OMX_U32 nPortIndex;        /**< port that this structure applies to */
+    OMX_BOOL bEnable;          /**< Enable/disable for equalizer */
+    OMX_BU32 sBandIndex;       /**< Band number to be set.  Upper Limit is 
+                                    N-1, where N is the number of bands, lower limit is 0 */
+    OMX_BU32 sCenterFreq;      /**< Center frequecies in Hz.  This is a
+                                    read only element and is used to determine 
+                                    the lower, center and upper frequency of 
+                                    this band.  */
+    OMX_BS32 sBandLevel;       /**< band level in millibels */
+} OMX_AUDIO_CONFIG_EQUALIZERTYPE;
+
+
+/** Stereo widening mode type 
+ * @ingroup effects
+ */ 
+typedef enum OMX_AUDIO_STEREOWIDENINGTYPE {
+    OMX_AUDIO_StereoWideningHeadphones,    /**< Stereo widening for loudspeakers */
+    OMX_AUDIO_StereoWideningLoudspeakers,  /**< Stereo widening for closely spaced loudspeakers */
+    OMX_AUDIO_StereoWideningKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_AUDIO_StereoWideningVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_AUDIO_StereoWideningMax = 0x7FFFFFFF
+} OMX_AUDIO_STEREOWIDENINGTYPE;
+
+
+/** Control for stereo widening, which is a special 2-channel
+ *  case of the audio virtualizer effect. For example, for 5.1-channel 
+ *  output, it translates to virtual surround sound. 
+ * @ingroup effects
+ */ 
+typedef struct OMX_AUDIO_CONFIG_STEREOWIDENINGTYPE {
+    OMX_U32 nSize;             /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;  /**< OMX specification version information */
+    OMX_U32 nPortIndex;        /**< port that this structure applies to */
+    OMX_BOOL bEnable;          /**< Enable/disable for stereo widening control */
+    OMX_AUDIO_STEREOWIDENINGTYPE eWideningType; /**< Stereo widening algorithm type */
+    OMX_U32  nStereoWidening;  /**< stereo widening setting for the port,
+                                    as a continuous value from 0 to 100  */
+} OMX_AUDIO_CONFIG_STEREOWIDENINGTYPE;
+
+
+/** The chorus effect (or ``choralizer'') is any signal processor which makes
+ *  one sound source (such as a voice) sound like many such sources singing 
+ *  (or playing) in unison. Since performance in unison is never exact, chorus 
+ *  effects simulate this by making independently modified copies of the input 
+ *  signal. Modifications may include (1) delay, (2) frequency shift, and 
+ *  (3) amplitude modulation.
+ * @ingroup effects
+ */
+typedef struct OMX_AUDIO_CONFIG_CHORUSTYPE {
+    OMX_U32 nSize;             /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;  /**< OMX specification version information */
+    OMX_U32 nPortIndex;        /**< port that this structure applies to */
+    OMX_BOOL bEnable;          /**< Enable/disable for chorus */
+    OMX_BU32 sDelay;           /**< average delay in milliseconds */
+    OMX_BU32 sModulationRate;  /**< rate of modulation in millihertz */
+    OMX_U32 nModulationDepth;  /**< depth of modulation as a percentage of 
+                                    delay (i.e. 0 to 100) */
+    OMX_BU32 nFeedback;        /**< Feedback from chorus output to input in percentage */
+} OMX_AUDIO_CONFIG_CHORUSTYPE;
+
+
+/** Reverberation is part of the reflected sound that follows the early 
+ *  reflections. In a typical room, this consists of a dense succession of 
+ *  echoes whose energy decays exponentially. The reverberation effect structure 
+ *  as defined here includes both (early) reflections as well as (late) reverberations. 
+ * @ingroup effects
+ */
+typedef struct OMX_AUDIO_CONFIG_REVERBERATIONTYPE {
+    OMX_U32 nSize;                /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;     /**< OMX specification version information */
+    OMX_U32 nPortIndex;           /**< port that this structure applies to */
+    OMX_BOOL bEnable;             /**< Enable/disable for reverberation control */
+    OMX_BS32 sRoomLevel;          /**< Intensity level for the whole room effect 
+                                       (i.e. both early reflections and late 
+                                       reverberation) in millibels */
+    OMX_BS32 sRoomHighFreqLevel;  /**< Attenuation at high frequencies
+                                       relative to the intensity at low
+                                       frequencies in millibels */
+    OMX_BS32 sReflectionsLevel;   /**< Intensity level of early reflections
+                                       (relative to room value), in millibels */
+    OMX_BU32 sReflectionsDelay;   /**< Delay time of the first reflection relative 
+                                       to the direct path, in milliseconds */
+    OMX_BS32 sReverbLevel;        /**< Intensity level of late reverberation
+                                       relative to room level, in millibels */
+    OMX_BU32 sReverbDelay;        /**< Time delay from the first early reflection 
+                                       to the beginning of the late reverberation 
+                                       section, in milliseconds */
+    OMX_BU32 sDecayTime;          /**< Late reverberation decay time at low
+                                       frequencies, in milliseconds */
+    OMX_BU32 nDecayHighFreqRatio; /**< Ratio of high frequency decay time relative 
+                                       to low frequency decay time in percent  */
+    OMX_U32 nDensity;             /**< Modal density in the late reverberation decay,
+                                       in percent (i.e. 0 - 100) */
+    OMX_U32 nDiffusion;           /**< Echo density in the late reverberation decay,
+                                       in percent (i.e. 0 - 100) */
+    OMX_BU32 sReferenceHighFreq;  /**< Reference high frequency in Hertz. This is 
+                                       the frequency used as the reference for all 
+                                       the high-frequency settings above */
+
+} OMX_AUDIO_CONFIG_REVERBERATIONTYPE;
+
+
+/** Possible settings for the Echo Cancelation structure to use 
+ * @ingroup effects
+ */
+typedef enum OMX_AUDIO_ECHOCANTYPE {
+   OMX_AUDIO_EchoCanOff = 0,    /**< Echo Cancellation is disabled */
+   OMX_AUDIO_EchoCanNormal,     /**< Echo Cancellation normal operation - 
+                                     echo from plastics and face */
+   OMX_AUDIO_EchoCanHFree,      /**< Echo Cancellation optimized for 
+                                     Hands Free operation */
+   OMX_AUDIO_EchoCanCarKit,    /**< Echo Cancellation optimized for 
+                                     Car Kit (longer echo) */
+   OMX_AUDIO_EchoCanKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+   OMX_AUDIO_EchoCanVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+   OMX_AUDIO_EchoCanMax = 0x7FFFFFFF
+} OMX_AUDIO_ECHOCANTYPE;
+
+
+/** Enable / Disable for echo cancelation, which removes undesired echo's
+ *  from the audio
+ * @ingroup effects
+ */ 
+typedef struct OMX_AUDIO_CONFIG_ECHOCANCELATIONTYPE {
+    OMX_U32 nSize;             /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;  /**< OMX specification version information */
+    OMX_U32 nPortIndex;        /**< port that this structure applies to */
+    OMX_AUDIO_ECHOCANTYPE eEchoCancelation; /**< Echo cancelation settings */
+} OMX_AUDIO_CONFIG_ECHOCANCELATIONTYPE;
+
+
+/** Enable / Disable for noise reduction, which undesired noise from
+ * the audio
+ * @ingroup effects
+ */ 
+typedef struct OMX_AUDIO_CONFIG_NOISEREDUCTIONTYPE {
+    OMX_U32 nSize;             /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;  /**< OMX specification version information */
+    OMX_U32 nPortIndex;        /**< port that this structure applies to */
+    OMX_BOOL bNoiseReduction;  /**< Enable/disable for noise reduction */
+} OMX_AUDIO_CONFIG_NOISEREDUCTIONTYPE;
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
+/* File EOF */
+
diff --git a/interface/vmcs_host/khronos/IL/OMX_Broadcom.h b/interface/vmcs_host/khronos/IL/OMX_Broadcom.h
new file mode 100755 (executable)
index 0000000..697f1ca
--- /dev/null
@@ -0,0 +1,2685 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// OpenMAX IL - Broadcom specific types
+
+#ifndef OMX_Broadcom_h
+#define OMX_Broadcom_h
+
+#include "OMX_Component.h"
+
+// for use in buffer headers - marks the contained data
+// as being a codec header
+#define OMX_BUFFERFLAG_TIME_UNKNOWN 0x00000100
+
+//for use in buffer headers - marks the buffer as being the
+//snapshot preview image from a still capture.
+//Mainly to be used with the DisplayFunction callback from camera.
+#define OMX_BUFFERFLAG_CAPTURE_PREVIEW 0x00000200
+
+/* Mark the end of a NAL unit produced by a video encoder.
+ */
+#define OMX_BUFFERFLAG_ENDOFNAL    0x00000400
+
+/* Marks pBuffer in OMX_BUFFERHEADERTYPE as containing a fragment list instead of the actual buffer
+ */
+#define OMX_BUFFERFLAG_FRAGMENTLIST 0x00000800
+
+/* Marks the start of a new sequence of data following any kind of seek operation.
+ */
+#define OMX_BUFFERFLAG_DISCONTINUITY 0x00001000
+
+/** Codec side information Flag:
+* OMX_BUFFERFLAG_CODECSIDEINFO is an optional flag that is set by an
+* output port when all bytes in the buffer form part or all of a set of
+* codec specific side information. For example, distortion information
+* estimated by H.264 encoder can be sent using this flag to signal
+* the decoder quality
+*/
+#define OMX_BUFFERFLAG_CODECSIDEINFO 0x00002000
+
+// for use in buffer headers - indicated the timestamp is a DTS rather than PTS
+#define OMX_BUFFERFLAG_TIME_IS_DTS 0x000004000
+
+// for use in buffer headers - signals that a video picture is interlaced
+#define OMX_BUFFERFLAG_INTERLACED 0x000010000
+
+// Signals that the top field of the current interlaced frame should be displayed first
+#define OMX_BUFFERFLAG_TOP_FIELD_FIRST 0x000020000
+
+/**
+ * Macros to convert to <code>OMX_TICKS</code> from a signed 64 bit value and
+ * vice-versa. These macros don't actually do anything unless <code>OMX_TICKS</code>
+ * is defined as a two-part structure (instead of a native signed 64-bit type).
+ **/
+#ifndef OMX_SKIP64BIT
+   #define omx_ticks_from_s64(s) (s)
+   #define omx_ticks_to_s64(t) (t)
+#else
+   static inline OMX_TICKS omx_ticks_from_s64(signed long long s) { OMX_TICKS t; t.nLowPart = (OMX_U32)s; t.nHighPart = (OMX_U32)(s>>32); return t; }
+   #define omx_ticks_to_s64(t) ((t).nLowPart | ((uint64_t)((t).nHighPart) << 32))
+#endif /* OMX_SKIP64BIT */
+
+/* Buffer fragment descriptor */
+typedef struct OMX_BUFFERFRAGMENTTYPE {
+   OMX_PTR pBuffer; /**< Pointer to actual block of memory that is acting as the fragment buffer */
+   OMX_U32 nLen;    /**< number of bytes in the buffer */
+} OMX_BUFFERFRAGMENTTYPE;
+
+/* OMX_IndexParamBrcmEnableIJGTableScaling: JPEG Quality Table Setting. */
+typedef struct OMX_PARAM_IJGSCALINGTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_BOOL bEnabled;
+} OMX_PARAM_IJGSCALINGTYPE;
+/*
+The boolean \code{bEnabled} value determines whether the component uses
+the standard IJG quality tables when encoding images.
+*/
+
+
+/* OMX_IndexConfigTimeInvalidStartTime: Invalid Start Times */
+/*
+This allows clock clients to supply a start time notification to the
+clock whilst indicating that this time is invalid.
+*/
+
+/* OMX_IndexParamBrcmMaxFrameSkips: Frame timestamp jumps */
+/*
+This number represents the number of times a jump in frame timestamps
+has been observed that is greater than expected.
+*/
+
+/* OMX_IndexConfigAsynchronousFailureURI: Asynchronous Failure Filename */
+/*
+This allows the client to query for the filename that cause an asynchronous
+output error.
+*/
+
+/* OMX_IndexParamAsynchronousOutput: Asynchronous Output */
+/*
+The allows the client to specify to a component that is writing files
+that this writing may happen asynchronously, including opening and closing
+of files.
+*/
+
+/* OMX_IndexConfigClockAdjustment: Clock Adjustment */
+/*
+This allows the client to read from the clock the total time
+adjustment made to the clock whilst running by the reference clock.
+If the reference clock sends a time that causes the media time to jump
+this difference is added to the total, which can be reported via this
+index.  When the stream restarts by setting the clock state to
+\code{OMX_TIME_ClockStateRunning} or
+\code{OMX_TIME_ClockStateWaitingForStartTime} this adjustment total is
+set to zero.
+*/
+
+/* OMX_IndexParamBrcmDataUnit: Data Unit */
+/*
+The data unit is an indication to components connected to this
+component of the type of data delivery available.
+\code{OMX_DataUnitCodedPicture} indicates that we are able to give
+framing information, using the \code{OMX_BUFFERFLAG_ENDOFFRAME} flag to
+indicate that the data contained finishes a complete
+frame. \code{OMX_DataUnitArbitraryStreamSection} indicates that no
+end-of-frame markers will be present, and the decoder should perform
+the steps necessary to decode the stream. The other enum values are
+not used.
+*/
+
+/* OMX_IndexConfigPresentationOffset: Presentation Offset */
+/*
+The value of \code{nTimestamp} is added to the offset requested for
+each new input frame. Takes effect for all new input frames, and has
+no effect on the offset used for currently-queued frames. A positive
+value will make the requested port earlier relative to other streams,
+a negative value will make the requested port later relative to other
+streams.
+*/
+
+/* OMX_IndexConfigSingleStep: Single Step */
+/*
+When setting this config on a paused clock, where the \code{nU32}
+value is non-zero and \code{nPortIndex} is OMX_ALL, the media clock
+will advance through the next \code{nU32} next requested media
+times. A paused clock is in running state but has a time scale of
+0. This will trigger the display of some video frames, so allowing
+single-stepping functionality. This config can be set multiple times,
+and will buffer up stepping requests until we have media requests to
+fulfil, or the clock is stopped or un-paused.
+
+This config can also be used on some video output ports and, if
+\code{nU32} is non-zero, requests that the output port forwards the
+next \code{nU32} frames appending an EOS marker on the last frame, and
+then ceases to forward data on this port.  If \code{nU32} is zero, any
+previous request to forward a limited number of frames is cancelled
+and the default behaviour of this port will resume.
+*/
+
+/* OMX_IndexParamCameraCamplusId: Camera Subsystem Identification */
+/*
+This parameter allows the configuration of the identifier to be used
+to initialise the Broadcom Camplus subsystem that sits beneath the
+camera component. If only one instance of the camera component is
+used, the default value can be used. If more than one instance is
+required, they must each have their own unique values for this
+parameter. It is also used to tie the component to the image pool
+created with \code{OMX_Set upCamPools}.
+*/
+
+/* OMX_IndexConfigAudioRenderingLatency: Audio Rendering Latency */
+/*
+This config allows the client to query the current latency of audio
+rendering.  The latency is returned as the number of samples that
+an audio rendering component has received but have not been played.
+*/
+
+/* OMX_IndexConfigBrcmPoolMemAllocSize: Pool memory usage values */
+/*
+This config allows the client to query how much memory is being used by
+the component for any image pools. 
+*/
+
+/* OMX_IndexConfigDisplayRegion: Display Region */
+typedef enum OMX_DISPLAYTRANSFORMTYPE{
+   OMX_DISPLAY_ROT0 = 0,
+   OMX_DISPLAY_MIRROR_ROT0 = 1,
+   OMX_DISPLAY_MIRROR_ROT180 = 2,
+   OMX_DISPLAY_ROT180 = 3,
+   OMX_DISPLAY_MIRROR_ROT90 = 4,
+   OMX_DISPLAY_ROT270 = 5,
+   OMX_DISPLAY_ROT90 = 6,
+   OMX_DISPLAY_MIRROR_ROT270 = 7,
+   OMX_DISPLAY_DUMMY = 0x7FFFFFFF
+} OMX_DISPLAYTRANSFORMTYPE;
+
+typedef struct OMX_DISPLAYRECTTYPE {
+   OMX_S16 x_offset;
+   OMX_S16 y_offset;
+   OMX_S16 width;
+   OMX_S16 height;
+} OMX_DISPLAYRECTTYPE;
+
+typedef enum OMX_DISPLAYMODETYPE {
+   OMX_DISPLAY_MODE_FILL = 0,
+   OMX_DISPLAY_MODE_LETTERBOX = 1,
+   // these allow a left eye source->dest to be specified and the right eye mapping will be inferred by symmetry
+   OMX_DISPLAY_MODE_STEREO_LEFT_TO_LEFT = 2,
+   OMX_DISPLAY_MODE_STEREO_TOP_TO_TOP = 3,
+   OMX_DISPLAY_MODE_STEREO_LEFT_TO_TOP = 4,
+   OMX_DISPLAY_MODE_STEREO_TOP_TO_LEFT = 5,
+   OMX_DISPLAY_MODE_DUMMY = 0x7FFFFFFF
+} OMX_DISPLAYMODETYPE;
+
+typedef enum OMX_DISPLAYSETTYPE {
+   OMX_DISPLAY_SET_NONE = 0,
+   OMX_DISPLAY_SET_NUM = 1,
+   OMX_DISPLAY_SET_FULLSCREEN = 2,
+   OMX_DISPLAY_SET_TRANSFORM = 4,
+   OMX_DISPLAY_SET_DEST_RECT = 8,
+   OMX_DISPLAY_SET_SRC_RECT = 0x10,
+   OMX_DISPLAY_SET_MODE = 0x20,
+   OMX_DISPLAY_SET_PIXEL = 0x40,
+   OMX_DISPLAY_SET_NOASPECT = 0x80,
+   OMX_DISPLAY_SET_LAYER = 0x100,
+   OMX_DISPLAY_SET_COPYPROTECT = 0x200,
+   OMX_DISPLAY_SET_ALPHA = 0x400,
+   OMX_DISPLAY_SET_DUMMY = 0x7FFFFFFF
+} OMX_DISPLAYSETTYPE;
+
+typedef struct OMX_CONFIG_DISPLAYREGIONTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_DISPLAYSETTYPE set;
+   OMX_U32 num;
+   OMX_BOOL fullscreen;
+   OMX_DISPLAYTRANSFORMTYPE transform;
+   OMX_DISPLAYRECTTYPE dest_rect;
+   OMX_DISPLAYRECTTYPE src_rect;
+   OMX_BOOL noaspect;
+   OMX_DISPLAYMODETYPE mode;
+   OMX_U32 pixel_x;
+   OMX_U32 pixel_y;
+   OMX_S32 layer;
+   OMX_BOOL copyprotect_required;
+   OMX_U32 alpha;
+   OMX_U32 wfc_context_width;
+   OMX_U32 wfc_context_height;
+} OMX_CONFIG_DISPLAYREGIONTYPE;
+/*
+This config sets the output display device, as well as the region used
+on the output display, any display transformation, and some flags to
+indicate how to scale the image.
+
+The structure uses a bitfield, \code{set}, to indicate which fields are set
+and should be used. All other fields will maintain their current
+value.
+
+\code{num} describes the display output device, with 0 typically being
+a directly connected LCD display.
+
+\code{fullscreen} indicates that we are using the full device screen
+area, rather than a window of the display.  If fullscreen is false,
+then dest_rect is used to specify a region of the display to use.
+
+\code{transform} indicates any rotation or flipping used to map frames
+onto the natural display orientation.
+
+The \code{src_rect} indicates which area of the frame to display. If
+all values are zero, the whole frame will be used.
+
+The \code{noaspect} flag, if set, indicates that any display scaling
+should disregard the aspect ratio of the frame region being displayed.
+
+\code{mode} indicates how the image should be scaled to fit the
+display. \code{OMX_DISPLAY_MODE_FILL} indicates that the image should
+fill the screen by potentially cropping the frames.  Setting
+\code{mode} to \code{OMX_DISPLAY_MODE_LETTERBOX} indicates that all
+the source region should be displayed and black bars added if
+necessary.
+
+The \code{pixel_x} and \code{pixel_y} values, if non-zero, are used to
+describe the size of a source pixel. If values are zero, then pixels
+default to being square.
+
+Set the \code{layer} that the image will appear on with the
+\code{layer} field.
+*/
+
+
+
+/* OMX_IndexParamSource: Source Image Configuration */
+typedef enum OMX_SOURCETYPE {
+   OMX_SOURCE_WHITE = 0,    // all white images
+   OMX_SOURCE_BLACK = 1,    // all black images
+   OMX_SOURCE_DIAGONAL = 2, // greyscale diagonal stripes
+   OMX_SOURCE_NOISE = 3,    // random pixel values
+   OMX_SOURCE_RANDOM = 4,   // a shaded random pattern of colours
+   OMX_SOURCE_COLOUR = 5,   // a solid colour determined by nParam
+   OMX_SOURCE_BLOCKS = 6,   // random coloured blocks of 16x16 size
+   OMX_SOURCE_SWIRLY,       // a swirly pattern used for encode testing
+   OMX_SOURCE_DUMMY = 0x7FFFFFFF
+} OMX_SOURCETYPE;
+
+typedef struct OMX_PARAM_SOURCETYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_SOURCETYPE eType;
+   OMX_U32 nParam;
+   OMX_U32 nFrameCount;
+   OMX_U32 xFrameRate;
+} OMX_PARAM_SOURCETYPE;
+/*
+The source type determines the kind of image that is produced. Not all
+combinations of source type and image type are supported.  The
+\code{OMX_SOURCE_SWIRLY} setting can only be used with YUV420 packed
+planar image formats.  When producing RGB565 image format, the
+\code{OMX_SOURCE_DIAGONAL} and \code{OMX_SOURCE_RANDOM} modes are
+treated as \code{OMX_SOURCE_NOISE}.
+
+The \code{nParam} field is used to specify the colour for the source
+colour mode, and the offset of the diagonal pattern for diagonal mode.
+For the blocks mode, \code{nParam} is used as the seed for the random
+colour generator.
+
+The \code{nFrameCount} parameter determines how many frames to send.
+If it is zero, then frames are sent continuously. For any other value,
+it counts down until it has sent that many frames, and then stops,
+sending out an EOS. The \code{xFrameRate} setting is used to determine
+the timestamp for each frame produced, or can be set to zero if
+timestamps should all remain at zero.
+*/
+
+/* OMX_IndexParamSourceSeed: Source Random Seed */
+typedef struct OMX_PARAM_SOURCESEEDTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_U16 nData[16];
+} OMX_PARAM_SOURCESEEDTYPE;
+/*
+This structure sets the current state of the random number generator
+used for \code{OMX_SOURCE_RANDOM} source type, allowing repeatable
+random image creation.
+*/
+
+/* OMX_IndexParamResize: Resize Control */
+typedef enum OMX_RESIZEMODETYPE {
+   OMX_RESIZE_NONE,
+   OMX_RESIZE_CROP,
+   OMX_RESIZE_BOX,
+   OMX_RESIZE_BYTES,
+   OMX_RESIZE_DUMMY = 0x7FFFFFFF
+} OMX_RESIZEMODETYPE;
+
+typedef struct OMX_PARAM_RESIZETYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_RESIZEMODETYPE eMode;
+   OMX_U32 nMaxWidth;
+   OMX_U32 nMaxHeight;
+   OMX_U32 nMaxBytes;
+   OMX_BOOL bPreserveAspectRatio;
+   OMX_BOOL bAllowUpscaling;
+} OMX_PARAM_RESIZETYPE;
+/*
+The mode determines the kind of resize. \code{OMX_RESIZE_BOX} allow
+the \code{nMaxWidth} and \code{nMaxHeight} to set a bounding box into
+which the output must fit. \code{OMX_RESIZE_BYTES} allows
+\code{nMaxBytes} to set the maximum number of bytes into which the
+full output frame must fit.  Two flags aid the setting of the output
+size. \code{bPreseveAspectRatio} sets whether the resize should
+preserve the aspect ratio of the incoming
+image. \code{bAllowUpscaling} sets whether the resize is allowed to
+increase the size of the output image compared to the size of the
+input image.
+*/
+
+typedef struct OMX_PARAM_TESTINTERFACETYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_BOOL bTest;
+   OMX_BOOL bSetExtra;
+   OMX_U32 nExtra;
+   OMX_BOOL bSetError;
+   OMX_BOOL stateError[2];
+} OMX_PARAM_TESTINTERFACETYPE;
+
+/* OMX_IndexConfigVisualisation: Visualisation Mode */
+typedef struct OMX_CONFIG_VISUALISATIONTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_U8 name[16];
+   OMX_U8 property[64];
+} OMX_CONFIG_VISUALISATIONTYPE;
+
+/*
+\code{name} is a string of characters specifying the type of
+visualization. The component appends \code{"_vis.vll"} to the name
+provided, and attempts to load a visualisation library contained in
+this VLL.  \code{property} contains configuration parameters and
+values, which is interpreted by the visualisation library. Typically
+all visualisations will accept a property string containing
+\code{'mode=<number>'}, where \code{<number>} may be a random 32 bit
+integer in decimal format. If provided, this may select a random mode
+from that visualisation library.
+*/
+
+/*
+This parameter is used when creating proprietary communication with
+the display component, and provides the display function for passing
+images to be displayed, together with a function used to flush all
+pending image updates and release all images.
+*/
+
+/* OMX_IndexConfigBrcmAudioDestination: Audio Destination */
+typedef struct OMX_CONFIG_BRCMAUDIODESTINATIONTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U8 sName[16];
+} OMX_CONFIG_BRCMAUDIODESTINATIONTYPE;
+/*
+This config sets the platform-specific audio destination or output
+device for audio sink components (e.g. audio_render).
+
+\code{sName} describes the audio destination, with \code{"local"}
+typically being directly connected to headphones.
+*/
+
+/* OMX_IndexConfigBrcmAudioSource: Audio Source */
+typedef struct OMX_CONFIG_BRCMAUDIOSOURCETYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U8 sName[16];
+} OMX_CONFIG_BRCMAUDIOSOURCETYPE;
+/*
+This config sets the platform-specific audio source or input device
+for audio source components (e.g. audio_capture).
+
+\code{sName} describes the audio source, with \code{"local"}
+typically being directly connected to microphone.
+*/
+
+/* OMX_IndexConfigBrcmAudioDownmixCoefficients: Audio Downmix Coefficients */
+typedef struct OMX_CONFIG_BRCMAUDIODOWNMIXCOEFFICIENTS {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_U32 coeff[16];
+} OMX_CONFIG_BRCMAUDIODOWNMIXCOEFFICIENTS;
+/*
+This config sets the platform-specific audio downmixing coefficients for the 
+audio mixer component. The coefficients are 16.16 fixed point.
+The even coefficients contribute to the left channel. 
+The odd coefficients contribute to the right channel. 
+L' = coeff[0] * sample[N] + coeff[2] * sample[N+1] + coeff[4] * sample[N+2] + coeff[6] * sample[N+3] 
+   + coeff[8] * sample[N+4] + coeff[10] * sample[N+5] + coeff[12] * sample[N+6] + coeff[14] * sample[N+7]
+R' = coeff[1] * sample[N] + coeff[3] * sample[N+1] + coeff[5] * sample[N+2] + coeff[7] * sample[N+3] 
+   + coeff[9] * sample[N+4] + coeff[11] * sample[N+5] + coeff[13] * sample[N+6] + coeff[15] * sample[N+7]
+
+\code{coeff} describes the downmixing coefficients
+*/
+
+/* OMX_IndexConfigBrcmAudioDownmixCoefficients8x8: Audio Downmix Coefficient matrix */
+typedef struct OMX_CONFIG_BRCMAUDIODOWNMIXCOEFFICIENTS8x8 {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_U32 coeff[64];
+} OMX_CONFIG_BRCMAUDIODOWNMIXCOEFFICIENTS8x8;
+/*
+This config sets the platform-specific audio downmixing coefficients for the 
+audio mixer component. The coefficients are 16.16 fixed point.
+The coefficients are a 8*8 mixing matrix from 8 input channels to 8 outputs channels
+
+\code{coeff} describes the downmixing coefficients
+*/
+
+/* OMX_IndexConfigBrcmAudioMaxSample: Maximum sample seen */
+typedef struct OMX_CONFIG_BRCMAUDIOMAXSAMPLE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_U32 nMaxSample;
+   OMX_TICKS nTimeStamp;
+} OMX_CONFIG_BRCMAUDIOMAXSAMPLE;
+/*
+This gets the largest sample produced (after downmixing with OMX_CONFIG_BRCMAUDIODOWNMIXCOEFFICIENTS8x8) 
+since this config was last read. The nTimestamp is the earliest timestamp processed. 
+This can be used for DRC schemes 
+
+\code{coeff} maximum sample seen in current block
+*/
+
+/* OMX_IndexConfigPlayMode: Play Mode */
+typedef enum OMX_PLAYMODETYPE {
+   OMX_PLAYMODE_NORMAL,
+   OMX_PLAYMODE_FF,
+   OMX_PLAYMODE_REW,
+   OMX_PLAYMODE_DUMMY = 0x7FFFFFFF
+} OMX_PLAYMODETYPE;
+
+typedef struct OMX_CONFIG_PLAYMODETYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_PLAYMODETYPE eMode;
+} OMX_CONFIG_PLAYMODETYPE;
+/*
+The playmode affects which frames are extracted from the media file
+and passed on the output ports. \code{OMX_PLAYMODE_NORMAL} will
+extract all frames, \code{OMX_PLAYMODE_FF} extracts only IDR frames
+when video is present, or only occasional packets of audio if no video
+is present. \code{OMX_PLAYMODE_REW} is similar to
+\code{OMX_PLAYMODE_FF} but extracts packets in reverse time
+order.
+*/
+
+typedef enum OMX_DELIVERYFORMATTYPE {
+   OMX_DELIVERYFORMAT_STREAM,         // no framing information is known
+   OMX_DELIVERYFORMAT_SINGLE_PACKET,  // packetised, at most one frame per buffer
+   OMX_DELIVERYFORMAT_DUMMY = 0x7FFFFFFF
+} OMX_DELIVERYFORMATTYPE;
+
+typedef struct OMX_PARAM_DELIVERYFORMATTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_DELIVERYFORMATTYPE eFormat;
+} OMX_PARAM_DELIVERYFORMATTYPE;
+
+/* OMX_IndexParamCodecConfig: Codec Configuration */
+
+typedef struct OMX_PARAM_CODECCONFIGTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_U32 bCodecConfigIsComplete;
+   OMX_U8 nData[1];
+} OMX_PARAM_CODECCONFIGTYPE;
+
+/*
+This parameter contains opaque data in a format specified by Broadcom
+and allows out-of-band information such as cropping rectangles, aspect
+ratio information, codec-specific header bytes, and other essential
+information to be passed between connected components.
+
+\code{bCodecConfigIsCompete} specifies if the codec config is fully
+contained in here and there is no need to wait for OMX_BUFFERFLAG_CODECCONFIG
+buffers
+*/
+
+typedef struct OMX_PARAM_STILLSFUNCTIONTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_BOOL bBuffer;
+   OMX_PTR (*pOpenFunc)(void);
+   OMX_PTR (*pCloseFunc)(void);
+   OMX_PTR (*pReadFunc)(void);
+   OMX_PTR (*pSeekFunc)(void);
+   OMX_PTR (*pWriteFunc)(void);
+} OMX_PARAM_STILLSFUNCTIONTYPE;
+
+typedef void* OMX_BUFFERADDRESSHANDLETYPE;
+
+typedef struct OMX_PARAM_BUFFERADDRESSTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_U32 nAllocLen;
+   OMX_BUFFERADDRESSHANDLETYPE handle;
+} OMX_PARAM_BUFFERADDRESSTYPE;
+
+typedef struct OMX_PARAM_TUNNELSETUPTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_TUNNELSETUPTYPE sSetup;
+} OMX_PARAM_TUNNELSETUPTYPE;
+
+/* OMX_IndexParamBrcmPortEGL: Used for querying whether a port is an EGL port or not. */
+typedef struct OMX_PARAM_BRCMPORTEGLTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_BOOL bPortIsEGL;
+} OMX_PARAM_BRCMPORTEGLTYPE;
+/*
+*/
+
+#define OMX_CONFIG_IMAGEFILTERPARAMS_MAXPARAMS 6
+/* OMX_IndexConfigCommonImageFilterParameters: Parameterized Image Filter */
+typedef struct OMX_CONFIG_IMAGEFILTERPARAMSTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_IMAGEFILTERTYPE eImageFilter;
+   OMX_U32 nNumParams;
+   OMX_U32 nParams[OMX_CONFIG_IMAGEFILTERPARAMS_MAXPARAMS];
+} OMX_CONFIG_IMAGEFILTERPARAMSTYPE;
+/*
+This structure contains optional parameters for some image
+filters. The following table lists all image filters that support
+parameters.
+
+<table border="1" cellspacing="0" cellpadding="2">
+<tr><td>Filter<td>Parameters<td>Notes
+
+<tr><td>\code{OMX_ImageFilterSolarize}
+<td>\code{[x0 y0 y1 y2]}
+<td>Linear mapping of \code{[0,x0]} to \code{[0,y0>]}
+and \code{[x0,255]} to \code{[y1,y2]}.
+Default is \code{"128 128 128 0"}.
+
+<tr><td>\code{OMX_ImageFilterSharpen}
+<td>\code{[sz [str [th]]}
+<td>\code{sz} size of filter, either 1 or 2.
+\code{str} strength of filter.
+\code{th} threshold of filter.
+Default is \code{"1 40 20"}.
+
+<tr><td>\code{OMX_ImageFilterFilm}
+<td>\code{[[str] [u v]]}
+<td>\code{str} strength of effect.
+\code{u} sets u to constant value.
+\code{v} sets v to constant value.
+Default is \code{"24"}.
+
+<tr><td>\code{OMX_ImageFilterBlur}
+<td>\code{[sz]}
+<td>\code{sz} size of filter, either 1 or 2.
+Default is \code{"2"}.
+
+<tr><td>\code{OMX_ImageFilterSaturation}
+<td>\code{[str]}
+<td>\code{str} strength of effect, in 8.8 fixed point format. u/v value
+differences from 128 are multiplied by \code{str}.
+Default is \code{"272"}.
+</table>
+*/
+
+
+/* OMX_IndexConfigTransitionControl: Transition Control */
+typedef struct OMX_CONFIG_TRANSITIONCONTROLTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_U32 nPosStart;
+   OMX_U32 nPosEnd;
+   OMX_S32 nPosIncrement;
+   OMX_TICKS nFrameIncrement;
+   OMX_BOOL bSwapInputs;
+   OMX_U8 name[16];
+   OMX_U8 property[64];
+} OMX_CONFIG_TRANSITIONCONTROLTYPE;
+/*
+This structure represents the internal configuration of the
+transition. Transitions are generated by a loadable plug-in described
+by the \code{name} field. The component appends \code{"_tran.vll"} to
+the name provided, and attempts to load a transition library contained
+in this VLL.  The exact type of transition is configured in a
+plug-in-dependent manner with the \code{property} field. All plug-ins
+should accept a \code{property} field equal to
+\code{"flags=<number>"}, where \code{<number>} can be a random 32 bit
+number.  If \code{bSwapInputs} is false, then the start image is on
+port 210, the stop image on port 211. These are reversed if
+\code{bSwapInputs} is true.
+
+Transition frames are generated from the plug-in by referencing a
+frame position in [0,65536], where position 0 is the start image,
+position 65536 is the stop image. The first frame position generated
+is \code{nPosStart}. The last frame position generated is
+\code{nPosEnd}. Each frame will increment the position by
+\code{nPosIncrement}. The timestamp attached to each frame will
+increment by \code{nFrameIncrement}.
+*/
+
+
+/*
+This parameter is used to provide a callback function pointer for
+release events. It is used for internal clients on VideoCore.
+*/
+
+
+/* OMX_IndexConfigAudioMonoTrackControl: Dual Mono Control */
+typedef enum OMX_AUDIOMONOTRACKOPERATIONSTYPE {
+   OMX_AUDIOMONOTRACKOPERATIONS_NOP,
+   OMX_AUDIOMONOTRACKOPERATIONS_L_TO_R,
+   OMX_AUDIOMONOTRACKOPERATIONS_R_TO_L,
+   OMX_AUDIOMONOTRACKOPERATIONS_DUMMY = 0x7FFFFFFF
+} OMX_AUDIOMONOTRACKOPERATIONSTYPE ;
+
+typedef struct OMX_CONFIG_AUDIOMONOTRACKCONTROLTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_AUDIOMONOTRACKOPERATIONSTYPE eMode;
+} OMX_CONFIG_AUDIOMONOTRACKCONTROLTYPE;
+/*
+This config controls the options to support dual mono audio
+streams. The output can be unchanged, or the left channel copied over
+the right channel, or the right channel copied over the left
+channel. This config can be applied at any time with stereo
+16-bit-per-sample data. Since audio output is typically buffered, any
+change will not be audible until that buffering has been played out.
+*/
+
+/* OMX_IndexParamCameraImagePool: Camera Image Pools */
+typedef enum OMX_CAMERAIMAGEPOOLINPUTMODETYPE {
+   OMX_CAMERAIMAGEPOOLINPUTMODE_ONEPOOL,     /*All input images are allocated from one pool
+                                               Works for simple stills capture use cases
+                                               Can not be used with parallel stills capture
+                                               and video encode, as the pool will be sized for
+                                               capture or viewfinder, not both simultaneously.
+                                               The pool wouldn't divide sensibly in this mode
+                                               anyway.
+                                             */
+   OMX_CAMERAIMAGEPOOLINPUTMODE_TWOPOOLS,    /*All stills & video input images are allocated
+                                               from two separate pools.
+                                               This ensures that parallel capture can work, but
+                                               would consume more memory if used on a simple
+                                               stills capture use case.
+                                             */
+} OMX_CAMERAIMAGEPOOLINPUTMODETYPE;
+
+typedef struct OMX_PARAM_CAMERAIMAGEPOOLTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nNumHiResVideoFrames;
+   OMX_U32 nHiResVideoWidth;
+   OMX_U32 nHiResVideoHeight;
+   OMX_COLOR_FORMATTYPE eHiResVideoType;
+   OMX_U32 nNumHiResStillsFrames;
+   OMX_U32 nHiResStillsWidth;
+   OMX_U32 nHiResStillsHeight;
+   OMX_COLOR_FORMATTYPE eHiResStillsType;
+   OMX_U32 nNumLoResFrames;
+   OMX_U32 nLoResWidth;
+   OMX_U32 nLoResHeight;
+   OMX_COLOR_FORMATTYPE eLoResType;
+   OMX_U32 nNumSnapshotFrames;
+   OMX_COLOR_FORMATTYPE eSnapshotType;
+   OMX_CAMERAIMAGEPOOLINPUTMODETYPE eInputPoolMode;
+   OMX_U32 nNumInputVideoFrames;
+   OMX_U32 nInputVideoWidth;
+   OMX_U32 nInputVideoHeight;
+   OMX_COLOR_FORMATTYPE eInputVideoType;
+   OMX_U32 nNumInputStillsFrames;
+   OMX_U32 nInputStillsWidth;
+   OMX_U32 nInputStillsHeight;
+   OMX_COLOR_FORMATTYPE eInputStillsType;
+} OMX_PARAM_CAMERAIMAGEPOOLTYPE;
+/*
+\sloppy This parameter specifies the size, type, and number, of images to
+allow in the images pools required by Camplus. Supported types are
+\code{OMX_COLOR_FormatYUV420PackedPlanar},
+\code{OMX_COLOR_FormatYUV422PackedPlanar},
+\code{OMX_COLOR_FormatRawBayer8bit},
+\code{OMX_COLOR_FormatRawBayer10bit},
+\code{OMX_COLOR_FormatRawBayer8bitcompressed}, and 0 (reserved for the
+Broadcom-specific format required by the video encoder). The input
+pool width, height, and type can be set as 0 to make the component
+query Camplus for the sensor mode that would correspond to the largest
+of the viewfinder port definition, the capture port definition, or the
+high resolution image pool.
+*/
+
+/* OMX_IndexParamImagePoolSize: Specifying Image Pool Properties */
+typedef struct OMX_PARAM_IMAGEPOOLSIZETYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 width;
+   OMX_U32 height;
+   OMX_U32 num_pages;
+} OMX_PARAM_IMAGEPOOLSIZETYPE;
+/*
+This parameter is used to control the size of pool that the component
+will allocate in the absence of setting an external pool.  The default
+can be reset by setting this parameter with all three fields set to
+zero.
+*/
+
+
+/* OMX_IndexParamImagePoolExternal: Client Allocated Image Pools */
+struct opaque_vc_pool_s;
+typedef struct opaque_vc_pool_s OMX_BRCM_POOL_T;
+
+typedef struct OMX_PARAM_IMAGEPOOLEXTERNALTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_BRCM_POOL_T *image_pool;
+   OMX_BRCM_POOL_T *image_pool2;
+   OMX_BRCM_POOL_T *image_pool3;
+   OMX_BRCM_POOL_T *image_pool4;
+   OMX_BRCM_POOL_T *image_pool5;
+} OMX_PARAM_IMAGEPOOLEXTERNALTYPE;
+/*
+This config allows the client to pass in handles to pre-allocated
+image pools for use within the component.
+*/
+
+
+struct _IL_FIFO_T;
+typedef struct OMX_PARAM_RUTILFIFOINFOTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   struct _IL_FIFO_T *pILFifo;
+} OMX_PARAM_RUTILFIFOINFOTYPE;
+
+/* OMX_IndexParamILFifoConfig: Allows configuration of the FIFO settings. */
+typedef struct OMX_PARAM_ILFIFOCONFIG {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_U32 nDataSize;         /**< The size of the FIFO's data area */
+   OMX_U32 nHeaderCount;      /**< The number of headers allocated */
+} OMX_PARAM_ILFIFOCONFIG;
+/**
+ * Allows configuring the size of the ILFIFO used in a component.
+ */
+
+/* OMX_IndexConfigCameraSensorModes: Camera Sensor Mode */
+typedef struct OMX_CONFIG_CAMERASENSORMODETYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_U32 nModeIndex;
+   OMX_U32 nNumModes;
+   OMX_U32 nWidth;
+   OMX_U32 nHeight;
+   OMX_U32 nPaddingRight;
+   OMX_U32 nPaddingDown;
+   OMX_COLOR_FORMATTYPE eColorFormat;
+   OMX_U32 nFrameRateMax;
+   OMX_U32 nFrameRateMin;
+} OMX_CONFIG_CAMERASENSORMODETYPE;
+/*
+This parameter is used by clients to determine the sensor mode, and
+hence the memory usage, of the camera module. This is primarily used
+for determining the size of the input image pool.
+
+It can be used in two ways dependent on \code{nPortIndex}. If
+\code{nPortIndex} is \code{OMX_ALL}, it returns the sensor mode
+corresponding to \code{nModeIndex}, and the number of modes in
+\code{nNumModes}. If \code{nModeIndex} is greater than or equal to
+\code{nNumModes} only \code{nNumModes} is returned. If
+\code{nPortIndex} is equal to a camera video output port index, it
+returns the sensor mode that would be selected for the values
+currently in \code{OMX_IndexParamPortDefinition} for that port.
+
+The \code{nPaddingRight} and \code{nPaddingDown} values determine the
+extra padding the sensor adds to the image. These values must be added
+to \code{nWidth} and \code{nHeight} respectively if the client is
+specifying the input image pool size.
+*/
+
+typedef struct OMX_BRCMBUFFERSTATSTYPE {
+   OMX_U32 nOrdinal;
+   OMX_TICKS nTimeStamp;
+   OMX_U32 nFilledLen;
+   OMX_U32 nFlags;
+   union
+   {
+      OMX_U32 nU32;
+      struct
+      {
+         OMX_U32 nYpart;
+         OMX_U32 nUVpart;
+      } image;
+   } crc;
+} OMX_BRCMBUFFERSTATSTYPE;
+
+/*
+Ports that gather statistics for debugging and diagnostics
+might also collect information about buffer header fields
+and data.
+
+Note that:
+
+The \code{nOrdinal} field increases monotonically whenever
+a new buffer is received or emitted and shall not be reset
+upon a port flush.
+
+The \code{nFilledLen} might indicate the size of a data area
+larger than the data area that actually contributed to the
+checksums (e.g. when image data is provided with cropping
+information).
+*/
+
+/* OMX_IndexConfigBrcmPortBufferStats: Query port buffer stats history */
+typedef struct OMX_CONFIG_BRCMPORTBUFFERSTATSTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_U32 nCount;
+   OMX_BRCMBUFFERSTATSTYPE sData[1];
+} OMX_CONFIG_BRCMPORTBUFFERSTATSTYPE;
+/*
+Ports that gather statistics for debugging and diagnostics
+might also collect information about buffer header fields
+and data.
+
+The \code{sStatsData} field is a variable length array and
+the number of items is denoted by \code{nStatsCount}.
+*/
+
+/* OMX_IndexConfigBrcmPortStats: Query port statistics */
+typedef struct OMX_CONFIG_BRCMPORTSTATSTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_U32 nImageCount;
+   OMX_U32 nBufferCount;
+   OMX_U32 nFrameCount;
+   OMX_U32 nFrameSkips;
+   OMX_U32 nDiscards;
+   OMX_U32 nEOS;
+   OMX_U32 nMaxFrameSize;
+
+   OMX_TICKS nByteCount;
+   OMX_TICKS nMaxTimeDelta;
+   OMX_U32 nCorruptMBs;   /**< Number of corrupt macroblocks in the stream */
+} OMX_CONFIG_BRCMPORTSTATSTYPE;
+/*
+Some ports gather various statistics that can be used by clients for
+debugging purposes.  This structure is the set of all statistics that
+are gathered.
+
+The \code{nFrameSkips} field indicates the number of frames that did
+not have an expected PTS value based on the port frame rate.
+
+The \code{nByteCount} field is a 64 bit value, that will either use a
+64 bit type or two 32 bit types, similarly to \code{OMX_TICKS}.
+*/
+
+/* OMX_IndexConfigBrcmClockMissCount: Missed clock request accounting */
+/*
+For each port on the clock component, requests for media times may be
+made.  These are typically done one per video frame to allow for
+scheduling the display of that frame at the correct time.  If a
+request is made after the time has occurred, then that frame will be
+displayed late, and the clock component keeps a per-port record of the
+number of times this occurs.  This record can be read using this
+index.
+*/
+
+typedef struct OMX_CONFIG_BRCMCAMERASTATSTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nOutFrameCount;
+   OMX_U32 nDroppedFrameCount;
+} OMX_CONFIG_BRCMCAMERASTATSTYPE;
+
+// for backward compatibility
+typedef struct OMX_CONFIG_BRCMCAMERASTATSTYPE OMX_CONFIG_BRCMCAMERASTATS;
+
+
+#define OMX_BRCM_MAXIOPERFBANDS 10
+typedef struct {
+   OMX_U32 count[OMX_BRCM_MAXIOPERFBANDS];
+   OMX_U32 num[OMX_BRCM_MAXIOPERFBANDS];
+} OMX_BRCM_PERFSTATS;
+
+/* OMX_IndexConfigBrcmIOPerfStats: Query I/O performance statistics */
+typedef struct OMX_CONFIG_BRCMIOPERFSTATSTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_BOOL bEnabled;                              /**< Enable/disable I/O performance statistics */
+   OMX_BRCM_PERFSTATS write; /**< count:bytes     num:microseconds */
+   OMX_BRCM_PERFSTATS flush; /**< count:frequency num:microseconds waiting to flush data */
+   OMX_BRCM_PERFSTATS wait;  /**< count:frequency num:microseconds waiting in calling function */
+} OMX_CONFIG_BRCMIOPERFSTATSTYPE;
+/*
+A sink component can gather various statistics about I/O (eg. file media) performance that can be used by
+clients for debugging purposes.  The \code{bEnabled} field is used to turn the gathering of statistics
+on/off.
+*/
+
+typedef struct OMX_CONFIG_SHARPNESSTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_S32 nSharpness;
+} OMX_CONFIG_SHARPNESSTYPE;
+
+/* OMX_IndexConfigCommonFlickerCancellation: Flicker cancellation */
+typedef enum OMX_COMMONFLICKERCANCELTYPE {
+   OMX_COMMONFLICKERCANCEL_OFF,
+   OMX_COMMONFLICKERCANCEL_AUTO,
+   OMX_COMMONFLICKERCANCEL_50,
+   OMX_COMMONFLICKERCANCEL_60,
+   OMX_COMMONFLICKERCANCEL_DUMMY = 0x7FFFFFFF
+} OMX_COMMONFLICKERCANCELTYPE;
+
+typedef struct OMX_CONFIG_FLICKERCANCELTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_COMMONFLICKERCANCELTYPE eFlickerCancel;
+} OMX_CONFIG_FLICKERCANCELTYPE;
+/*
+Query / set the flicker cancellation frequency. Values are defined for Off,
+50Hz, 60Hz, or auto. The method for auto detecting the flicker frequency is
+not defined, and currently results in the feature being turned off.
+*/
+
+/* OMX_IndexConfigCommonRedEyeRemoval: Red eye removal/reduction */
+typedef enum OMX_REDEYEREMOVALTYPE {
+   OMX_RedEyeRemovalNone,                           /**< No red eye removal */
+   OMX_RedEyeRemovalOn,                             /**< Red eye removal on */
+   OMX_RedEyeRemovalAuto,                           /**< Red eye removal will be done automatically when detected */
+   OMX_RedEyeRemovalKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+   OMX_RedEyeRemovalVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+   OMX_RedEyeRemovalSimple,                         /**< Use simple red eye reduction mechanism if supported by algorithm */
+   OMX_RedEyeRemovalMax = 0x7FFFFFFF
+} OMX_REDEYEREMOVALTYPE;
+
+typedef struct OMX_CONFIG_REDEYEREMOVALTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_REDEYEREMOVALTYPE eMode;
+} OMX_CONFIG_REDEYEREMOVALTYPE;
+/*
+   Configures the red eye reduction algorithm in the camera processing
+   pipeline. The stage is only enabled if the flash mode is not FlashOff.
+   The OMX_RedEyeRemovalSimple mode requests that the algorithm uses a
+   reduced complexity algorithm to reduce the processing time.
+*/
+
+
+typedef enum OMX_FACEDETECTIONCONTROLTYPE {
+   OMX_FaceDetectionControlNone,                           /**< Disables face detection */
+   OMX_FaceDetectionControlOn,                             /**< Enables face detection */
+   OMX_FaceDetectionControlKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+   OMX_FaceDetectionControlVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+   OMX_FaceDetectionControlMax = 0x7FFFFFFF
+} OMX_FACEDETECTIONCONTROLTYPE;
+
+typedef struct OMX_CONFIG_FACEDETECTIONCONTROLTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_FACEDETECTIONCONTROLTYPE eMode;
+   OMX_U32 nFrames;      /**< number of frames to apply this setting for,
+                              0 for unlimited */
+   OMX_U32 nMaxRegions;  /**< maximum number of regions to detect, 0 for unlimited */
+   OMX_U32 nQuality;     /**< hint for algorithmic complexity, range is 0-100.
+                              0 for simplest algorithm, 100 for best quality */
+} OMX_CONFIG_FACEDETECTIONCONTROLTYPE;
+
+typedef enum OMX_FACEREGIONFLAGSTYPE {
+   OMX_FaceRegionFlagsNone    = 0,
+   OMX_FaceRegionFlagsBlink   = 1,
+   OMX_FaceRegionFlagsSmile   = 2,
+   OMX_FaceRegionFlagsKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+   OMX_FaceRegionFlagsVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+   OMX_FaceRegionFlagsMax = 0x7FFFFFFF
+} OMX_FACEREGIONFLAGSTYPE;
+
+typedef struct OMX_FACEREGIONTYPE {
+   OMX_S16 nLeft;              /**< X Coordinate of the top left corner of the rectangle */
+   OMX_S16 nTop;               /**< Y Coordinate of the top left corner of the rectangle */
+   OMX_U16 nWidth;             /**< Width of the rectangle */
+   OMX_U16 nHeight;            /**< Height of the rectangle */
+   OMX_FACEREGIONFLAGSTYPE nFlags;  /**< Flags for the region */
+#ifndef OMX_SKIP64BIT
+   OMX_U64 nFaceRecognitionId; /**< ID returned by face recognition for this face */
+#else
+   struct
+   {
+      OMX_U32 nLowPart;   /**< low bits of the signed 64 bit value */
+      OMX_U32 nHighPart;  /**< high bits of the signed 64 bit value */
+   } nFaceRecognitionId;
+#endif
+} OMX_FACEREGIONTYPE;
+
+typedef struct OMX_CONFIG_FACEDETECTIONREGIONTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;            /**< index of port with face detection enabled */
+   OMX_U32 nIndex;                /**< first requested region number, allowing retrieval of many regions
+                                       over several requests */
+   OMX_U32 nDetectedRegions;      /**< total number of detected regions */
+   OMX_S32 nValidRegions;         /**< number of valid regions in sRegion array
+                                       When getting, the client sets this to the number of regions available.
+                                       The component writes region data and updates this field with how many
+                                       regions have been written to. */
+   OMX_U32 nImageWidth;           /**< Width of the image, hence reference for the face coordinates */
+   OMX_U32 nImageHeight;          /**< Height of the image, hence reference for the face coordinates */
+   OMX_FACEREGIONTYPE sRegion[1]; /**< variable length array of face regions */
+} OMX_CONFIG_FACEDETECTIONREGIONTYPE;
+
+typedef enum OMX_INTERLACETYPE {
+   OMX_InterlaceProgressive,                    /**< The data is not interlaced, it is progressive scan */
+   OMX_InterlaceFieldSingleUpperFirst,          /**< The data is interlaced, fields sent
+                                                     separately in temporal order, with upper field first */
+   OMX_InterlaceFieldSingleLowerFirst,          /**< The data is interlaced, fields sent
+                                                     separately in temporal order, with lower field first */
+   OMX_InterlaceFieldsInterleavedUpperFirst,    /**< The data is interlaced, two fields sent together line
+                                                     interleaved, with the upper field temporally earlier */
+   OMX_InterlaceFieldsInterleavedLowerFirst,    /**< The data is interlaced, two fields sent together line
+                                                     interleaved, with the lower field temporally earlier */
+   OMX_InterlaceMixed,                          /**< The stream may contain a mixture of progressive
+                                                     and interlaced frames */
+   OMX_InterlaceKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+   OMX_InterlaceVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+   OMX_InterlaceMax = 0x7FFFFFFF
+} OMX_INTERLACETYPE;
+
+typedef struct OMX_CONFIG_INTERLACETYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;            /**< index of port emitting or accepting the content */
+   OMX_INTERLACETYPE eMode;       /**< The interlace type of the content */
+   OMX_BOOL bRepeatFirstField;    /**< Whether to repeat the first field */
+} OMX_CONFIG_INTERLACETYPE;
+
+/* OMX_IndexParamIspTuner: Custom ISP tuner */
+typedef struct OMX_PARAM_CAMERAISPTUNERTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U8 tuner_name[64];
+} OMX_PARAM_CAMERAISPTUNERTYPE;
+/*
+This parameter allows a custom ISP tuner to be loaded instead of
+the default one specified for the camera module. Setting an empty
+string uses the default value.
+*/
+
+/* OMX_IndexConfigCameraInputFrame: Pointer to the raw input image */
+typedef struct OMX_CONFIG_IMAGEPTRTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_PTR pImage;
+} OMX_CONFIG_IMAGEPTRTYPE;
+/*
+This parameter parameter allows the return of a pointer to a
+VideoCore image resource.
+*/
+
+/* OMX_IndexConfigAFAssistLight: Autofocus assist light mode selection */
+typedef enum OMX_AFASSISTTYPE {
+   OMX_AFAssistAuto,
+   OMX_AFAssistOn,
+   OMX_AFAssistOff,
+   OMX_AFAssistTorch,
+   OMX_AFAssistKhronosExtensions = 0x6F000000,
+   OMX_AFAssistVendorStartUnused = 0x7F000000,
+   OMX_AFAssistMax = 0x7FFFFFFF
+} OMX_AFASSISTTYPE;
+
+typedef struct OMX_CONFIG_AFASSISTTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_AFASSISTTYPE eMode;
+} OMX_CONFIG_AFASSISTTYPE;
+/*
+Set the mode to adopt for the autofocus assist light.
+\code{OMX_AFAssistTorch} will turn the AF assist light on permanently, allowing
+it to be used as a torch.
+*/
+
+/* OMX_IndexConfigInputCropPercentage: Specify input crop as a percentage */
+typedef struct OMX_CONFIG_INPUTCROPTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_U32 xLeft;     /**< Fraction of the width for the top left corner of the rectangle */
+   OMX_U32 xTop;      /**< Fraction of the height for the top left corner of the rectangle */
+   OMX_U32 xWidth;    /**< Fraction of the image width desired */
+   OMX_U32 xHeight;   /**< Fraction of the image height desired */
+} OMX_CONFIG_INPUTCROPTYPE;
+/*
+This parameter allows the input cropping to be specified as a
+percentage of the current width/height.  Required for the camera
+component where the output resolution varies dependent on the port.
+All percentage values are as 16p16 fixed point numbers (0x10000 =
+100\%)
+*/
+
+/* OMX_IndexParamCodecRequirements: Advanced codec requirements */
+typedef struct OMX_PARAM_CODECREQUIREMENTSTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nCallbackID;
+   OMX_BOOL bTryHWCodec;
+} OMX_PARAM_CODECREQUIREMENTSTYPE;
+/*
+This parameter allows internal users of RIL components controlling
+video codecs to request that the component loads the component and
+queries for requirements.  The component will perform a callback with
+the given nCallbackID value passing a pointer to the requirements
+structure as the data field.
+*/
+
+/* OMX_IndexConfigBrcmEGLImageMemHandle: Mapping from an EGLImage to a VideoCore mem handle */
+typedef struct OMX_CONFIG_BRCMEGLIMAGEMEMHANDLETYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_PTR eglImage;
+   OMX_PTR memHandle;
+} OMX_CONFIG_BRCMEGLIMAGEMEMHANDLETYPE;
+/*
+This config allows the EGL server to notify a RIL component that an
+EGLImage is available for rendering into and to provide a mapping from
+an EGLImage to a mem handle.
+*/
+
+/* OMX_IndexConfigPrivacyIndicator: Privacy indicator control */
+typedef enum OMX_PRIVACYINDICATORTYPE {
+   OMX_PrivacyIndicatorOff,
+   OMX_PrivacyIndicatorOn,
+   OMX_PrivacyIndicatorForceOn,
+   OMX_PrivacyIndicatorKhronosExtensions = 0x6F000000,
+   OMX_PrivacyIndicatorVendorStartUnused = 0x7F000000,
+   OMX_PrivacyIndicatorMax = 0x7FFFFFFF
+} OMX_PRIVACYINDICATORTYPE;
+
+typedef struct OMX_CONFIG_PRIVACYINDICATORTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_PRIVACYINDICATORTYPE ePrivacyIndicatorMode;
+} OMX_CONFIG_PRIVACYINDICATORTYPE;
+/*
+This config allows control over the privacy indicator light.  This
+light indicates when a capture is in progress.
+
+\code{OMX_PrivacyIndicatorOff} indicator is disabled.
+
+\code{OMX_PrivacyIndicatorOn} indicator will be
+turned on whenever an image is being captured as determined by the
+capturing bit. Minimum on duration of approx 200ms.
+
+\code{OMX_PrivacyIndicatorForceOn} results in turning the indicator on
+immediately, whether an image is being captured or not. The mode will
+automatically revert to \code{OMX_PrivacyIndicatorOff} once the
+indicator has been turned on, so \code{OMX_PrivacyIndicatorForceOn}
+must be requested at least every 200ms if the indicator is to remain
+on.
+*/
+
+
+/* OMX_IndexParamCameraFlashType: Select flash type */
+typedef enum OMX_CAMERAFLASHTYPE {
+   OMX_CameraFlashDefault,
+   OMX_CameraFlashXenon,
+   OMX_CameraFlashLED,
+   OMX_CameraFlashNone,
+   OMX_CameraFlashKhronosExtensions = 0x6F000000,
+   OMX_CameraFlashVendorStartUnused = 0x7F000000,
+   OMX_CameraFlashMax = 0x7FFFFFFF
+} OMX_CAMERAFLASHTYPE;
+
+typedef struct OMX_PARAM_CAMERAFLASHTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_CAMERAFLASHTYPE eFlashType;
+   OMX_BOOL bRedEyeUsesTorchMode;
+} OMX_PARAM_CAMERAFLASHTYPE;
+/*
+This parameter allows the selection of xenon or LED flash devices
+to be used with the currently selected camera. If that device is not
+available, then the component will revert back to whatever flash
+device is available for that camera.
+\code{bRedEyeUsesTorchMode} allows the blinking for red eye reduction to
+be switched between using the indicator mode, and the torch mode for the
+flash driver.
+*/
+
+/* OMX_IndexConfigCameraFlashConfig: Flash cycle configuration */
+typedef enum OMX_CAMERAFLASHCONFIGSYNCTYPE {
+   OMX_CameraFlashConfigSyncFrontSlow,
+   OMX_CameraFlashConfigSyncRearSlow,
+   OMX_CameraFlashConfigSyncFrontFast,
+   OMX_CameraFlashConfigSyncKhronosExtensions = 0x6F000000,
+   OMX_CameraFlashConfigSyncVendorStartUnused = 0x7F000000,
+   OMX_CameraFlashConfigSyncMax = 0x7FFFFFFF
+} OMX_CAMERAFLASHCONFIGSYNCTYPE;
+
+typedef struct OMX_CONFIG_CAMERAFLASHCONFIGTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_BOOL bUsePreFlash;
+   OMX_BOOL bUseFocusDistanceInfo;
+   OMX_CAMERAFLASHCONFIGSYNCTYPE eFlashSync;
+   OMX_BOOL bIgnoreChargeState;
+} OMX_CONFIG_CAMERAFLASHCONFIGTYPE;
+/*
+This parameter allows the configuration of various parameters relating to
+the flash cycle. Some of the options are only applicable to xenon flash.
+
+\code{bUsePreFlash} uses a low intensity pre-flash to determine flash intensity. This setting
+is recommended for almost all flash situations.
+
+\code{bUseFocusDistanceInfo} uses the distance of the subject, as measured by the AF algorithm
+to set the intensity of the flash.
+
+\code{eFlashSync} configures which edge of the shutter is used to synchronise the flash, and
+the duration of the exposure.
+
+\code{eIgnoreChargeState} will make the flash fire, even if it is not fully charged.
+*/
+
+/* OMX_IndexConfigBrcmAudioTrackGaplessPlayback: Encoder/decoder delay and padding information for gapless playback. */
+typedef struct OMX_CONFIG_BRCMAUDIOTRACKGAPLESSPLAYBACKTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_U32 nDelay;   /**< number of samples delay added by the codec */
+   OMX_U32 nPadding; /**< number of silent samples added to the end */
+} OMX_CONFIG_BRCMAUDIOTRACKGAPLESSPLAYBACKTYPE;
+/*
+This config allows communication between components to facilitate gapless playback.
+*/
+
+
+/* OMX_IndexConfigBrcmAudioTrackChangeControl: Configure gapless/crossfaded audio track change. */
+typedef struct OMX_CONFIG_BRCMAUDIOTRACKCHANGECONTROLTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nSrcPortIndex;
+   OMX_U32 nDstPortIndex;
+   OMX_U32 nXFade;
+} OMX_CONFIG_BRCMAUDIOTRACKCHANGECONTROLTYPE;
+/*
+This config allows the client to specify the gapless or crossfade
+parameters to be used on a track change.  If \code{nXFade} is 0, then
+a normal or gapless track change will result, otherwise a crossfade of
+\code{nXFade} ms is used.
+*/
+
+/* OMX_IndexParamBrcmPixelValueRange: Describing the pixel value range */
+typedef enum OMX_BRCMPIXELVALUERANGETYPE
+{
+   OMX_PixelValueRangeUnspecified = 0,
+   OMX_PixelValueRangeITU_R_BT601,
+   OMX_PixelValueRangeFull8Bit,
+   OMX_PixelValueRangeKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+   OMX_PixelValueRangeVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+   OMX_PixelValueRangeMax = 0x7FFFFFFF
+} OMX_BRCMPIXELVALUERANGETYPE;
+
+typedef struct OMX_PARAM_BRCMPIXELVALUERANGETYPE
+{
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_BRCMPIXELVALUERANGETYPE ePixelValueRange;
+} OMX_PARAM_BRCMPIXELVALUERANGETYPE;
+/*
+This structure allows a description of the range that pixel values may
+have.  This is typically useful since some standards use the full 8
+bit range, whereas others introduce pedastals which reduce the range
+at the top and bottom end.
+*/
+
+/* OMX_IndexParamCameraDisableAlgorithm: Disabling camera processing stages. */
+typedef enum OMX_CAMERADISABLEALGORITHMTYPE {
+      OMX_CameraDisableAlgorithmFacetracking,
+      OMX_CameraDisableAlgorithmRedEyeReduction,
+      OMX_CameraDisableAlgorithmVideoStabilisation,
+      OMX_CameraDisableAlgorithmWriteRaw,
+      OMX_CameraDisableAlgorithmVideoDenoise,
+      OMX_CameraDisableAlgorithmStillsDenoise,
+      OMX_CameraDisableAlgorithmAntiShake,
+      OMX_CameraDisableAlgorithmImageEffects,
+      OMX_CameraDisableAlgorithmDarkSubtract,
+      OMX_CameraDisableAlgorithmDynamicRangeExpansion,
+      OMX_CameraDisableAlgorithmFaceRecognition,
+      OMX_CameraDisableAlgorithmFaceBeautification,
+      OMX_CameraDisableAlgorithmSceneDetection,
+      OMX_CameraDisableAlgorithmHighDynamicRange,
+   OMX_CameraDisableAlgorithmKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+   OMX_CameraDisableAlgorithmVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+   OMX_CameraDisableAlgorithmMax = 0x7FFFFFFF
+} OMX_CAMERADISABLEALGORITHMTYPE;
+
+typedef struct OMX_PARAM_CAMERADISABLEALGORITHMTYPE
+{
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_CAMERADISABLEALGORITHMTYPE eAlgorithm;
+   OMX_BOOL bDisabled;
+} OMX_PARAM_CAMERADISABLEALGORITHMTYPE;
+/*
+Allows plugin algorithms to be disabled to save memory
+within the camera component
+*/
+
+/* OMX_IndexConfigBrcmAudioEffectControl: Audio Effect Control */
+typedef struct OMX_CONFIG_BRCMAUDIOEFFECTCONTROLTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_BOOL bEnable;
+   OMX_U8 name[16];
+   OMX_U8 property[256];
+} OMX_CONFIG_BRCMAUDIOEFFECTCONTROLTYPE;
+/*
+This structure represents the internal configuration of an audio effect.
+The audio effect is provided by a loadable plug-in described
+in the \code{name} field and is configured in a plug-in-dependent
+manner with the \code{property} field. The \code{bEnable} field is used to
+turn the effect on/off.
+*/
+
+/* OMX_IndexConfigBrcmMinimumProcessingLatency: Processing Latency Bound */
+typedef struct OMX_CONFIG_BRCMMINIMUMPROCESSINGLATENCY {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_TICKS nOffset;
+} OMX_CONFIG_BRCMMINIMUMPROCESSINGLATENCY;
+/*
+Query/set the difference between the actual media time and when the
+component receives request fulfillments for media time requests. This
+can be used with e.g. splitter/mixer components to control when the
+component stops waiting for input or output packets from active
+streams and continues with processing (to maintain a constant
+processing rate).
+*/
+
+/** Enable or disable Supplemental Enhancment Information (SEI) messages to be inserted in
+  * the H.264 bitstream.
+  */
+typedef struct OMX_PARAM_BRCMVIDEOAVCSEIENABLETYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_BOOL bEnable;
+} OMX_PARAM_BRCMVIDEOAVCSEIENABLETYPE;
+
+/* OMX_IndexParamBrcmAllowMemChange: Allowing changing memory allocation on state transition */
+typedef struct OMX_PARAM_BRCMALLOWMEMCHANGETYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_BOOL bEnable;
+} OMX_PARAM_BRCMALLOWMEMCHANGETYPE;
+/*
+Let the component change the amount of memory it has allocated when
+going from LOADED to IDLE. By default this is enabled, but if it is
+disabled the component will fail to transition to IDLE if the
+component requires more memory than has already been allocated.  This
+might occur if (for example) the component was configured, taken to
+IDLE, then taken back to LOADED, the profile increased and the
+component taken back to IDLE.
+*/
+
+typedef enum OMX_CONFIG_CAMERAUSECASE {
+   OMX_CameraUseCaseAuto,
+   OMX_CameraUseCaseVideo,
+   OMX_CameraUseCaseStills,
+   OMX_CameraUseCaseKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+   OMX_CameraUseCaseVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+   OMX_CameraUseCaseMax = 0x7FFFFFFF
+} OMX_CONFIG_CAMERAUSECASE;
+
+typedef struct OMX_CONFIG_CAMERAUSECASETYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_CONFIG_CAMERAUSECASE eUseCase;
+} OMX_CONFIG_CAMERAUSECASETYPE;
+
+/* OMX_IndexParamBrcmDisableProprietaryTunnels: Disabling proprietary tunnelling */
+typedef struct OMX_PARAM_BRCMDISABLEPROPRIETARYTUNNELSTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_BOOL bUseBuffers;
+}  OMX_PARAM_BRCMDISABLEPROPRIETARYTUNNELSTYPE;
+/*
+Tell a source component to refuse to support proprietary tunnelling. Buffers will be used instead.
+*/
+
+
+//
+// Control for memory allocation and component-internal buffering
+//
+
+/* OMX_IndexParamBrcmRetainMemory: Controlling memory use on state transition */
+typedef struct OMX_PARAM_BRCMRETAINMEMORYTYPE
+{
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_BOOL bEnable;
+} OMX_PARAM_BRCMRETAINMEMORYTYPE;
+/*
+Ask a component to retain its memory when going from IDLE to LOADED, if possible.
+This has the benefit that you are then guaranteed that the transition to IDLE cannot
+fail due to lack of memory, but has the disadvantage that you cannot leave the component
+lying around in LOADED, unused, since it is using significant amounts of memory.
+*/
+
+/** Tell write media how large the output buffer should be. This is a hint, and
+  * may be ignored. A good size is bandwidth*<SDcard-delay>, which works out at
+  * around 1Mbyte for up to 16Mbit/s. Sizes may (and probably will) be rounded down
+  * to the nearest power of 2.
+  */
+typedef struct OMX_PARAM_BRCMOUTPUTBUFFERSIZETYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nBufferSize;
+} OMX_PARAM_BRCMOUTPUTBUFFERSIZETYPE;
+
+/* OMX_IndexConfigCameraInfo: Camera device driver information */
+#define OMX_CONFIG_CAMERAINFOTYPE_NAME_LEN 16
+typedef struct OMX_CONFIG_LENSCALIBRATIONVALUETYPE
+{
+   OMX_U16  nShutterDelayTime;
+   OMX_U16  nNdTransparency;
+   OMX_U16  nPwmPulseNearEnd;  /**< Num pulses to move lens 1um at near end */
+   OMX_U16  nPwmPulseFarEnd;   /**< Num pulses to move lens 1um at far end */
+   OMX_U16  nVoltagePIOutNearEnd[3];
+   OMX_U16  nVoltagePIOut10cm[3];
+   OMX_U16  nVoltagePIOutInfinity[3];
+   OMX_U16  nVoltagePIOutFarEnd[3];
+   OMX_U32  nAdcConversionNearEnd;
+   OMX_U32  nAdcConversionFarEnd;
+} OMX_CONFIG_LENSCALIBRATIONVALUETYPE;
+/*
+Ask the camera component for the driver info on the current camera device
+*/
+
+#define OMX_CONFIG_CAMERAINFOTYPE_NAME_LEN 16
+#define OMX_CONFIG_CAMERAINFOTYPE_SERIALNUM_LEN 20
+#define OMX_CONFIG_CAMERAINFOTYPE_EPROMVER_LEN 8
+typedef struct OMX_CONFIG_CAMERAINFOTYPE
+{
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U8 cameraname[OMX_CONFIG_CAMERAINFOTYPE_NAME_LEN];
+   OMX_U8 lensname[OMX_CONFIG_CAMERAINFOTYPE_NAME_LEN];
+   OMX_U16 nModelId;
+   OMX_U8 nManufacturerId;
+   OMX_U8 nRevNum;
+   OMX_U8 sSerialNumber[OMX_CONFIG_CAMERAINFOTYPE_SERIALNUM_LEN];
+   OMX_U8 sEpromVersion[OMX_CONFIG_CAMERAINFOTYPE_EPROMVER_LEN];
+   OMX_CONFIG_LENSCALIBRATIONVALUETYPE sLensCalibration;
+   OMX_U32 xFNumber;
+   OMX_U32 xFocalLength;
+} OMX_CONFIG_CAMERAINFOTYPE;
+
+
+typedef enum OMX_CONFIG_CAMERAFEATURESSHUTTER {
+   OMX_CameraFeaturesShutterUnknown,
+   OMX_CameraFeaturesShutterNotPresent,
+   OMX_CameraFeaturesShutterPresent,
+   OMX_CameraFeaturesShutterKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+   OMX_CameraFeaturesShutterVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+   OMX_CameraFeaturesShutterMax = 0x7FFFFFFF
+} OMX_CONFIG_CAMERAFEATURESSHUTTER;
+
+typedef struct OMX_CONFIG_CAMERAFEATURESTYPE
+{
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_CONFIG_CAMERAFEATURESSHUTTER eHasMechanicalShutter;
+   OMX_BOOL bHasLens;
+} OMX_CONFIG_CAMERAFEATURESTYPE;
+
+
+//Should be added to the spec as part of IL416c
+/* OMX_IndexConfigRequestCallback: Enable config change notifications. */
+typedef struct OMX_CONFIG_REQUESTCALLBACKTYPE
+{
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_INDEXTYPE nIndex;
+   OMX_BOOL bEnable;
+} OMX_CONFIG_REQUESTCALLBACKTYPE;
+/*
+This config implements IL416c to allow clients to request notification
+of when a config or parameter is changed. When the parameter specified
+in \code{nIndex} for port \code{nPortIndex} changes, an
+\code{OMX_EventParamOrConfigChanged} event is generated for the client.
+*/
+
+/* OMX_IndexConfigCommonFocusRegionXY: Define focus regions */
+typedef enum OMX_FOCUSREGIONTYPE {
+   OMX_FocusRegionNormal,
+   OMX_FocusRegionFace,
+   OMX_FocusRegionMax
+} OMX_FOCUSREGIONTYPE;
+
+typedef struct OMX_FOCUSREGIONXY {
+   OMX_U32 xLeft;
+   OMX_U32 xTop;
+   OMX_U32 xWidth;
+   OMX_U32 xHeight;
+   OMX_U32 nWeight;
+   OMX_U32 nMask;
+   OMX_FOCUSREGIONTYPE eType;
+} OMX_FOCUSREGIONXY;
+
+typedef struct OMX_CONFIG_FOCUSREGIONXYTYPE
+{
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_U32 nIndex;
+   OMX_U32 nTotalRegions;
+   OMX_S32 nValidRegions;
+   OMX_BOOL bLockToFaces;
+   OMX_U32 xFaceTolerance;
+   OMX_FOCUSREGIONXY sRegion[1];
+} OMX_CONFIG_FOCUSREGIONXYTYPE;
+/*
+Query / set the focus regions to use as a set of x/y/width/height boxes relative
+to the overall image.
+
+\code{nIndex} - first region number being set/read, allowing retrieval/setting
+of many regions over several requests.
+
+\code{nTotalRegions} - total number of regions currently defined.
+
+\code{nValidRegions} - number of valid regions in the \code{sRegion} array.
+When getting, the client sets this to the number of regions available.
+The component writes region data and updates this field with how many
+regions have been written to.
+When setting, this is the number of regions defined with this structure
+
+\code{bLockToFaces} - compare the region(s) given to the latest face tracking results.
+If a face is found within xFaceTolerance of the defined region, then amend the
+region to correspond to the face.
+
+\code{xFaceTolerance} - 0p16 value to define the max difference between the region centre
+and face tracking result centre to take the FT results
+
+\code{sRegions} - variable length array of focus regions.
+*/
+
+typedef struct OMX_CONFIG_U8TYPE {
+    OMX_U32 nSize;                    /**< Size of this structure, in Bytes */
+    OMX_VERSIONTYPE nVersion;         /**< OMX specification version information */
+    OMX_U32 nPortIndex;               /**< port that this structure applies to */
+    OMX_U8  nU8;                     /**< U8 value */
+} OMX_PARAM_U8TYPE;
+
+typedef struct OMX_CONFIG_CAMERASETTINGSTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;               /**< port that this structure applies to */
+    OMX_U32 nExposure;
+    OMX_U32 nAnalogGain;
+    OMX_U32 nDigitalGain;
+    OMX_U32 nLux;
+    OMX_U32 nRedGain;
+    OMX_U32 nBlueGain;
+    OMX_U32 nFocusPosition;
+} OMX_CONFIG_CAMERASETTINGSTYPE;
+
+/* OMX_IndexConfigDrawBoxLineParams: Face box style parameters. */
+typedef struct OMX_YUVCOLOUR {
+   OMX_U8 nY;
+   OMX_U8 nU;
+   OMX_U8 nV;
+} OMX_YUVCOLOUR;
+
+typedef struct OMX_CONFIG_DRAWBOXLINEPARAMS {
+    OMX_U32 nSize;                           /**< Size of this structure, in Bytes */
+    OMX_VERSIONTYPE nVersion;                /**< OMX specification version information */
+    OMX_U32 nPortIndex;                      /**< Port to which this config applies */
+    OMX_U32 xCornerSize;                     /**< Size of the corners as a fraction of the complete side */
+    OMX_U32 nPrimaryFaceLineWidth;           /**< Width of the box line for the primary face in pixels */
+    OMX_U32 nOtherFaceLineWidth;             /**< Width of the box line for other faces in pixels */
+    OMX_U32 nFocusRegionLineWidth;           /**< Width of the box line for focus regions in pixels */
+    OMX_YUVCOLOUR sPrimaryFaceColour;        /**< YUV colour for the primary face */
+    OMX_YUVCOLOUR sPrimaryFaceSmileColour;   /**< YUV colour for the primary face if smiling */
+    OMX_YUVCOLOUR sPrimaryFaceBlinkColour;   /**< YUV colour for the primary face if blinking */
+    OMX_YUVCOLOUR sOtherFaceColour;          /**< YUV colour for the all other faces */
+    OMX_YUVCOLOUR sOtherFaceSmileColour;     /**< YUV colour for the all other faces if smiling */
+    OMX_YUVCOLOUR sOtherFaceBlinkColour;     /**< YUV colour for the all other faces if blinking */
+    OMX_BOOL bShowFocusRegionsWhenIdle;      /**< Are focus regions displayed when just in viewfinder/AF idle */
+    OMX_YUVCOLOUR sFocusRegionColour;        /**< YUV colour for focus regions */
+    OMX_BOOL bShowAfState;                   /**< Change to the colours specified below if AF cycle has run */
+    OMX_BOOL bShowOnlyPrimaryAfState;        /**< Only show the primary face when displaying the AF status */
+    OMX_BOOL bCombineNonFaceRegions;         /**< Combine all regions not defined as faces into one single box covering them all */
+    OMX_YUVCOLOUR sAfLockPrimaryFaceColour;  /**< YUV colour for the primary face */
+    OMX_YUVCOLOUR sAfLockOtherFaceColour;    /**< YUV colour for the all other faces */
+    OMX_YUVCOLOUR sAfLockFocusRegionColour;  /**< YUV colour for focus regions */
+    OMX_YUVCOLOUR sAfFailPrimaryFaceColour;  /**< YUV colour for the primary face */
+    OMX_YUVCOLOUR sAfFailOtherFaceColour;    /**< YUV colour for the all other faces */
+    OMX_YUVCOLOUR sAfFailFocusRegionColour;  /**< YUV colour for focus regions */
+ } OMX_CONFIG_DRAWBOXLINEPARAMS;
+/*
+Query / set the parameters for the box to be drawn around faces/focus regions.
+*/
+
+ #define OMX_PARAM_CAMERARMITYPE_RMINAME_LEN 16
+ //OMX_IndexParamCameraRmiControl
+ typedef struct OMX_PARAM_CAMERARMITYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_BOOL bEnabled;
+    OMX_U8 sRmiName[OMX_PARAM_CAMERARMITYPE_RMINAME_LEN];
+    OMX_U32 nInputBufferHeight;
+    OMX_U32 nRmiBufferSize;
+    OMX_BRCM_POOL_T *pImagePool;
+ } OMX_PARAM_CAMERARMITYPE;
+
+/* OMX_IndexConfigBrcmSyncOutput: Forcing a write sync */
+typedef struct OMX_CONFIG_BRCMSYNCOUTPUTTYPE {
+    OMX_U32 nSize;                           /**< Size of this structure, in Bytes */
+    OMX_VERSIONTYPE nVersion;                /**< OMX specification version information */
+}  OMX_CONFIG_BRCMSYNCOUTPUTTYPE;
+/*
+Setting this config forces a sync of data to the filesystem.
+*/
+
+/* OMX_IndexConfigDrmView: View information for DRM rental files */
+typedef struct OMX_CONFIG_DRMVIEWTYPE {
+   OMX_U32 nSize;             /**< Size of this structure, in Bytes */
+   OMX_VERSIONTYPE nVersion;  /**< OMX specification version information */
+   OMX_U32 nCurrentView;      /**< Current view count */
+   OMX_U32 nMaxView;          /**< Max. no. of view allowed */
+} OMX_CONFIG_DRMVIEWTYPE;
+/*
+This structure contains information about the number of available
+views in the selected DRM rental file, which typically have a given
+maximum view count.  It allows the user to explicitly agree to playing
+the file, which will increment the number of current views the file
+has had.
+*/
+
+typedef struct OMX_PARAM_BRCMU64TYPE {
+    OMX_U32 nSize;                    /**< Size of this structure, in Bytes */
+    OMX_VERSIONTYPE nVersion;         /**< OMX specification version information */
+    OMX_U32 nPortIndex;               /**< port that this structure applies to */
+    OMX_U32 nLowPart;                 /**< low bits of the unsigned 64 bit value */
+    OMX_U32 nHighPart;                /**< high bits of the unsigned 64 bit value */
+} OMX_PARAM_BRCMU64TYPE;
+
+/* OMX_IndexParamBrcmDisableEXIF: Disable generation of EXIF data */
+/*
+This parameter is used by clients to control the generation of exif
+data in JPEG images.
+*/
+
+/* OMX_IndexParamBrcmThumbnail: Control generation of thumbnail */
+typedef struct OMX_PARAM_BRCMTHUMBNAILTYPE {
+    OMX_U32 nSize;                    /**< Size of this structure, in Bytes */
+    OMX_VERSIONTYPE nVersion;         /**< OMX specification version information */
+    OMX_BOOL bEnable;                 /**< Enable generation of thumbnails during still capture */
+    OMX_BOOL bUsePreview;             /**< Use the preview image (as is) as thumbnail */
+    OMX_U32 nWidth;                   /**< Desired width of the thumbnail */
+    OMX_U32 nHeight;                  /**< Desired height of the thumbnail */
+} OMX_PARAM_BRCMTHUMBNAILTYPE;
+/*
+This parameter is used by clients to control how thumbnails are
+generated when creating still images.
+
+Thumbnail generation will be turned on or off depending on the
+\code{bEnable} field.
+
+The \code{bUsePreview} field will let the component know whether it
+should use the low resolution preview image (if the component has one
+available) as is for the thumbnail. When this is set to true, it should
+make the generation of thumbnails faster (if a preview image is available)
+and should use less memory as well.
+
+The \code{nWidth} and \code{nHeight} fields allow the client to
+specify the dimensions of the thumbnail.  If both \code{nWidth} and
+\code{nHeight} are 0, we will calculate a sensible size for the
+thumbnail.
+*/
+
+typedef struct OMX_PARAM_BRCMASPECTRATIOTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_U32 nWidth;
+    OMX_U32 nHeight;
+} OMX_PARAM_BRCMASPECTRATIOTYPE;
+
+/* OMX_IndexParamBrcmVideoDecodeErrorConcealment: Control error concealment for video decode */
+typedef struct OMX_PARAM_BRCMVIDEODECODEERRORCONCEALMENTTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_BOOL bStartWithValidFrame; /**< Decoder will only start emitting frames from a non-corrupted frame */
+} OMX_PARAM_BRCMVIDEODECODEERRORCONCEALMENTTYPE;
+/*
+ This parameter is used by clients to control the type of error concealment
+ that will be done by the video decoder.
+ */
+
+#define OMX_CONFIG_FLASHINFOTYPE_NAME_LEN 16
+typedef struct OMX_CONFIG_FLASHINFOTYPE
+{
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U8 sFlashName[OMX_CONFIG_FLASHINFOTYPE_NAME_LEN];
+   OMX_CAMERAFLASHTYPE eFlashType;
+   OMX_U8 nDeviceId;
+   OMX_U8 nDeviceVersion;
+} OMX_CONFIG_FLASHINFOTYPE;
+
+/* OMX_IndexParamBrcmInterpolateMissingTimestamps: Configure component to interpolate missing timestamps */
+/*
+Configures a component so that it tries to timestamp all the buffers it outputs.
+If the timestamp information is missing from the original buffer, the
+component will try its best to interpolate a value for the missing timestamp.
+ */
+
+/* OMX_IndexParamBrcmSetCodecPerformanceMonitoring: Configure component to output performance statistics */
+/*
+Configures a codec component so that it outputs performance statistics to
+the given DECODE_PROGRESS_REPORT_T structure (passed as a pointer).
+This structure can then be read by the client to find out where the codec is
+at in its processing.
+ */
+
+/* OMX_IndexConfigDynamicRangeExpansion: Configure image dynamic range expansion processing */
+typedef enum OMX_DYNAMICRANGEEXPANSIONMODETYPE {
+   OMX_DynRangeExpOff,
+   OMX_DynRangeExpLow,
+   OMX_DynRangeExpMedium,
+   OMX_DynRangeExpHigh,
+   OMX_DynRangeExpKhronosExtensions = 0x6F000000,
+   OMX_DynRangeExpVendorStartUnused = 0x7F000000,
+   OMX_DynRangeExpMax = 0x7FFFFFFF
+} OMX_DYNAMICRANGEEXPANSIONMODETYPE;
+
+typedef struct OMX_CONFIG_DYNAMICRANGEEXPANSIONTYPE
+{
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_DYNAMICRANGEEXPANSIONMODETYPE eMode;
+} OMX_CONFIG_DYNAMICRANGEEXPANSIONTYPE;
+/*
+Configures the intensity of an image dynamic range expansion processing stage
+*/
+
+/* OMX_IndexParamBrcmTransposeBufferCount: Configure the number of pre-allocated transpose buffers  */
+/*
+This config allows the client to explicitly set the number of destination buffers pre-allocated for
+ports that support 90/270 degree rotation (e.g. in video_render). The buffers will be pre-allocated during
+a state transition from LOADED to IDLE (the transition will fail if there is not enough memory available
+for the buffers).
+.
+*/
+
+
+/* OMX_IndexParamBrcmThreadAffinity: Control the CPU affinity of component thread(s) */
+typedef enum OMX_BRCMTHREADAFFINITYTYPE {
+   OMX_BrcmThreadAffinityCPU0,
+   OMX_BrcmThreadAffinityCPU1,
+   OMX_BrcmThreadAffinityMax = 0x7FFFFFFF
+} OMX_BRCMTHREADAFFINITYTYPE;
+
+typedef struct OMX_PARAM_BRCMTHREADAFFINITYTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_BRCMTHREADAFFINITYTYPE eAffinity;  /**< Thread CPU affinity */
+} OMX_PARAM_BRCMTHREADAFFINITYTYPE;
+/*
+ This parameter is used by clients to hint the CPU that a component thread should run on.
+ */
+
+ /* OMX_IndexConfigCommonSceneDetected: Reports the scene type detected by a scene detection algorithm. */
+typedef enum OMX_SCENEDETECTTYPE {
+   OMX_SceneDetectUnknown,
+   OMX_SceneDetectLandscape,
+   OMX_SceneDetectPortrait,
+   OMX_SceneDetectMacro,
+   OMX_SceneDetectNight,
+   OMX_SceneDetectPortraitNight,
+   OMX_SceneDetectBacklit,
+   OMX_SceneDetectPortraitBacklit,
+   OMX_SceneDetectSunset,
+   OMX_SceneDetectBeach,
+   OMX_SceneDetectSnow,
+   OMX_SceneDetectFireworks,
+   OMX_SceneDetectMax = 0x7FFFFFFF
+} OMX_SCENEDETECTTYPE;
+
+/* OMX_IndexConfigCommonSceneDetected: Reports the scene type detected by a scene detection algorithm. */
+typedef struct OMX_CONFIG_SCENEDETECTTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_SCENEDETECTTYPE eScene;  /**< Scene type detected */
+} OMX_CONFIG_SCENEDETECTTYPE;
+/*
+ This config is used to report to clients the scene type that has been detected.
+ */
+
+/* OMX_IndexParamNalStreamFormat: Control the NAL unit packaging. This is a Khronos extension. */
+typedef enum OMX_INDEXEXTTYPE {
+    /* Video parameters and configurations */
+    OMX_IndexExtVideoStartUnused = OMX_IndexKhronosExtensions + 0x00600000,
+    OMX_IndexParamNalStreamFormatSupported,         /**< reference: OMX_NALSTREAMFORMATTYPE */
+    OMX_IndexParamNalStreamFormat,                  /**< reference: OMX_NALSTREAMFORMATTYPE */
+    OMX_IndexParamNalStreamFormatSelect,            /**< reference: OMX_NALSTREAMFORMATTYPE */
+
+    OMX_IndexExtMax = 0x7FFFFFFF
+} OMX_INDEXEXTTYPE;
+
+/* OMX_IndexParamNalStreamFormat: Control the NAL unit packaging. This is a Khronos extension. */
+typedef enum OMX_NALUFORMATSTYPE {
+    OMX_NaluFormatStartCodes = 1,
+    OMX_NaluFormatOneNaluPerBuffer = 2,
+    OMX_NaluFormatOneByteInterleaveLength = 4,
+    OMX_NaluFormatTwoByteInterleaveLength = 8,
+    OMX_NaluFormatFourByteInterleaveLength = 16,
+    OMX_NaluFormatCodingMax = 0x7FFFFFFF
+} OMX_NALUFORMATSTYPE;
+
+/* OMX_IndexParamNalStreamFormat: Control the NAL unit packaging. This is a Khronos extension. */
+typedef struct OMX_NALSTREAMFORMATTYPE{
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_NALUFORMATSTYPE eNaluFormat;
+} OMX_NALSTREAMFORMATTYPE;
+/*
+ This parameter is used to control the NAL unit packaging of an H264 video port.
+ */
+
+/* OMX_IndexParamVideoMvc: MVC codec parameters */
+typedef  struct OMX_VIDEO_PARAM_AVCTYPE  OMX_VIDEO_PARAM_MVCTYPE;
+/*
+This parameter is currently identical to the AVC parameter type.
+*/
+
+ /* OMX_IndexConfigBrcmDrawStaticBox: Define static box to be drawn */
+typedef enum OMX_STATICBOXTYPE {
+   OMX_StaticBoxNormal,
+   OMX_StaticBoxPrimaryFaceAfIdle,
+   OMX_StaticBoxNonPrimaryFaceAfIdle,
+   OMX_StaticBoxFocusRegionAfIdle,
+   OMX_StaticBoxPrimaryFaceAfSuccess,
+   OMX_StaticBoxNonPrimaryFaceAfSuccess,
+   OMX_StaticBoxFocusRegionAfSuccess,
+   OMX_StaticBoxPrimaryFaceAfFail,
+   OMX_StaticBoxNonPrimaryFaceAfFail,
+   OMX_StaticBoxFocusRegionAfFail,
+   OMX_StaticBoxMax
+} OMX_STATICBOXTYPE;
+
+typedef struct OMX_STATICBOX {
+   OMX_U32 xLeft;
+   OMX_U32 xTop;
+   OMX_U32 xWidth;
+   OMX_U32 xHeight;
+   OMX_STATICBOXTYPE eType;
+} OMX_STATICBOX;
+
+typedef struct OMX_CONFIG_STATICBOXTYPE
+{
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_U32 nIndex;
+   OMX_U32 nTotalBoxes;
+   OMX_S32 nValidBoxes;
+   OMX_BOOL bDrawOtherBoxes;
+   OMX_STATICBOX sBoxes[1];
+} OMX_CONFIG_STATICBOXTYPE;
+/*
+Query / set the parameters for a box to always be drawn on viewfinder images
+The x/y/width/height values for the boxes are relative to the overall image.
+
+\code{nIndex} - first box number being set/read, allowing retrieval/setting
+of many boxes over several requests.
+
+\code{nValidBoxes} - total number of boxes currently defined.
+
+\code{nValidBoxes} - number of valid boxes in the \code{sBoxes} array.
+When getting, the client sets this to the number of boxes available.
+The component writes box data and updates this field with how many
+boxes have been written to.
+When setting, this is the number of boxes defined with this structure
+
+\code{sBoxes} - variable length array of static boxes.
+*/
+
+/* OMX_IndexConfigPortCapturing: Per-port capturing state */
+typedef struct OMX_CONFIG_PORTBOOLEANTYPE{
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_BOOL bEnabled;
+} OMX_CONFIG_PORTBOOLEANTYPE;
+/*
+This is proposed in IL533f for controlling
+which ports of a multi-port camera component are capturing frames.
+*/
+
+/* OMX_IndexConfigCaptureMode: Capturing mode type */
+typedef enum OMX_CAMERACAPTUREMODETYPE {
+   OMX_CameraCaptureModeWaitForCaptureEnd,
+   OMX_CameraCaptureModeWaitForCaptureEndAndUsePreviousInputImage,
+   OMX_CameraCaptureModeResumeViewfinderImmediately,
+   OMX_CameraCaptureModeMax,
+} OMX_CAMERACAPTUREMODETYPE;
+
+typedef struct OMX_PARAM_CAMERACAPTUREMODETYPE{
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_CAMERACAPTUREMODETYPE eMode;
+} OMX_PARAM_CAMERACAPTUREMODETYPE;
+/*
+This controls the mode of operation for
+still image capture in the camera component.
+*/
+
+/* OMX_IndexParamBrcmDrmEncryption: Set DRM encryption scheme */
+typedef enum OMX_BRCMDRMENCRYPTIONTYPE
+{
+   OMX_DrmEncryptionNone = 0,
+   OMX_DrmEncryptionHdcp2,
+   OMX_DrmEncryptionKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+   OMX_DrmEncryptionVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+   OMX_DrmEncryptionRangeMax = 0x7FFFFFFF
+} OMX_BRCMDRMENCRYPTIONTYPE;
+
+typedef struct OMX_PARAM_BRCMDRMENCRYPTIONTYPE
+{
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_BRCMDRMENCRYPTIONTYPE eEncryption;
+   OMX_U32 nConfigDataLen;
+   OMX_U8 configData[1];
+} OMX_PARAM_BRCMDRMENCRYPTIONTYPE;
+/*
+Query/set the DRM encryption scheme used by a port writing out data.
+*/
+
+
+/* OMX_IndexConfigBufferStall: Advertise buffer stall state */
+typedef struct OMX_CONFIG_BUFFERSTALLTYPE
+{
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_BOOL bStalled;      /**< Whether we are stalled */
+   OMX_U32 nDelay;         /**< Delay in real time (us) from last buffer to current time */
+} OMX_CONFIG_BUFFERSTALLTYPE;
+/*
+Query/set the buffer stall threashold.  When set the \code{nDelay}
+parameter specifies a time to class whether buffer output is stalled.
+When get, the \code{nDelay} parameter indicates the current buffer
+delay, and the {bStalled} parameter indicates whether this time is
+over a previously set threashold.  When
+\code{OMX_IndexConfigRequestCallback} is used with this index, a
+notification is given when \code{bStalled} changes.
+*/
+
+/* OMX_IndexConfigLatencyTarget: Maintain target latency by adjusting clock speed */
+typedef struct OMX_CONFIG_LATENCYTARGETTYPE
+{
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_BOOL bEnabled; /**< whether this mode is enabled */
+   OMX_U32 nFilter; /**< number of latency samples to filter on, good value: 1 */
+   OMX_U32 nTarget; /**< target latency, us */
+   OMX_U32 nShift;  /**< shift for storing latency values, good value: 7 */
+   OMX_S32 nSpeedFactor; /**< multiplier for speed changes, in 24.8 format, good value: 256-512 */
+   OMX_S32 nInterFactor; /**< divider for comparing latency versus gradiant, good value: 300 */
+   OMX_S32 nAdjCap; /**< limit for speed change before nSpeedFactor is applied, good value: 100 */
+} OMX_CONFIG_LATENCYTARGETTYPE;
+/*
+Query/set parameters used when adjusting clock speed to match the
+measured latency to a specified value.
+*/
+
+/* OMX_IndexConfigBrcmUseProprietaryCallback: Force use of proprietary callback */
+typedef struct OMX_CONFIG_BRCMUSEPROPRIETARYCALLBACKTYPE
+{
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_BOOL bEnable;
+} OMX_CONFIG_BRCMUSEPROPRIETARYCALLBACKTYPE;
+/*
+Disable/enable the use of proprietary callbacks rather than OpenMAX IL buffer handling.
+*/
+
+/* OMX_IndexParamCommonUseStcTimestamps: Select timestamp mode */
+typedef enum OMX_TIMESTAMPMODETYPE
+{
+   OMX_TimestampModeZero = 0,       /**< Use a timestamp of 0 */
+   OMX_TimestampModeRawStc,         /**< Use the raw STC as the timestamp */
+   OMX_TimestampModeResetStc,       /**< Store the STC when video capture port goes active, and subtract that from STC for the timestamp */
+   OMX_TimestampModeKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+   OMX_TimestampModeVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+   OMX_TimestampModeMax = 0x7FFFFFFF
+} OMX_TIMESTAMPMODETYPE;
+
+typedef struct OMX_PARAM_TIMESTAMPMODETYPE
+{
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_TIMESTAMPMODETYPE eTimestampMode;
+} OMX_PARAM_TIMESTAMPMODETYPE;
+/*
+ Specifies what to use as timestamps in the absence of a clock component.
+*/
+
+/* EGL image buffer for passing to video port.
+ * Used when port color format is OMX_COLOR_FormatBRCMEGL.
+ */
+typedef struct OMX_BRCMVEGLIMAGETYPE
+{
+   /* Passed between ARM + VC; use fixed width types. */
+   OMX_U32 nWidth;
+   OMX_U32 nHeight;
+   OMX_U32 nStride;
+   OMX_U32 nUmemHandle;
+   OMX_U32 nUmemOffset;
+   OMX_U32 nFlipped;    /* Non-zero -> vertically flipped image */
+} OMX_BRCMVEGLIMAGETYPE;
+
+/* Provides field of view 
+ */
+typedef struct OMX_CONFIG_BRCMFOVTYPE
+{
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_U32 xFieldOfViewHorizontal;  /**< Horizontal field of view in degrees. 16p16 value */
+   OMX_U32 xFieldOfViewVertical;    /**< Vertical field of view in degrees. 16p16 value */
+} OMX_CONFIG_BRCMFOVTYPE;
+
+/* OMX_IndexConfigBrcmDecoderPassThrough: Enabling Audio Passthrough */
+/*
+This allows an audio decoder to disable decoding the stream and pass through correctly framed
+data to enable playback of compressed audio to supported output devices.
+*/
+
+/* OMX_IndexConfigBrcmClockReferenceSource: Select Clock Reference Source */
+/*
+This control allows communicating directly to an audio renderer component whether it should
+act as a clock reference source or act as a slave.
+*/
+
+/* OMX_IndexConfigEncLevelExtension: AVC Override encode capabilities */
+typedef struct OMX_VIDEO_CONFIG_LEVEL_EXTEND {
+   OMX_U32 nSize; 
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_U32 nCustomMaxMBPS;     /**< Specifies maximum macro-blocks per second */
+   OMX_U32 nCustomMaxFS;       /**< Specifies maximum frame size (macro-blocks per frame) */
+   OMX_U32 nCustomMaxBRandCPB; /**< Specifies maximum bitrate in units of 1000 bits/s and Codec Picture Buffer (CPB derived from bitrate) */
+} OMX_VIDEO_CONFIG_LEVEL_EXTEND;
+/*
+This allows finer control of the H264 encode internal parameters.
+*/
+
+/* OMX_IndexParamBrcmEEDEEnable: Enable/Disable end to end distortion estimator */
+typedef struct OMX_VIDEO_EEDE_ENABLE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_U32 enable;
+} OMX_VIDEO_EEDE_ENABLE;
+/*
+This enables or disables the use of end to end distortion estimation.
+*/
+
+/* OMX_IndexParamBrcmEEDELossRate: Loss rate configuration for end to end distortion */
+typedef struct OMX_VIDEO_EEDE_LOSSRATE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+   OMX_U32 loss_rate; /**< loss rate, 5 means 5% */
+} OMX_VIDEO_EEDE_LOSSRATE;
+/*
+Set the packet loss rate used by the end to end distortion estimator.
+*/
+
+/* OMX_IndexParamColorSpace: Colour space information */
+typedef enum OMX_COLORSPACETYPE
+{
+   OMX_COLORSPACE_UNKNOWN,
+   OMX_COLORSPACE_JPEG_JFIF,
+   OMX_COLORSPACE_ITU_R_BT601,
+   OMX_COLORSPACE_ITU_R_BT709,
+   OMX_COLORSPACE_FCC,
+   OMX_COLORSPACE_SMPTE240M,
+   OMX_COLORSPACE_BT470_2_M,
+   OMX_COLORSPACE_BT470_2_BG,
+   OMX_COLORSPACE_JFIF_Y16_255,
+   OMX_COLORSPACE_MAX = 0x7FFFFFFF
+} OMX_COLORSPACETYPE;
+
+typedef struct OMX_PARAM_COLORSPACETYPE
+{
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_COLORSPACETYPE eColorSpace;
+} OMX_PARAM_COLORSPACETYPE;
+/*
+Sets the colourspace with which pixel buffers should be generated / interpreted.
+*/
+
+typedef enum OMX_CAPTURESTATETYPE
+{
+   OMX_NotCapturing,
+   OMX_CaptureStarted,
+   OMX_CaptureComplete,
+   OMX_CaptureMax = 0x7FFFFFFF
+} OMX_CAPTURESTATETYPE;
+
+typedef struct OMX_PARAM_CAPTURESTATETYPE
+{
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_CAPTURESTATETYPE eCaptureState;
+} OMX_PARAM_CAPTURESTATETYPE;
+
+/*
+Provides information on the colour space that's in use during image/video processing.
+*/
+
+/* OMX_IndexConfigMinimiseFragmentation: Minimising Fragmentation */
+/*
+This control can be supported to enable the client to request that the component works
+to minimise fragmentation of output buffers.
+*/
+
+/* OMX_IndexConfigBrcmBufferFlagFilter: Filter buffers based on flags */
+/*
+This control can be set to request that buffers are conditionally forwarded on 
+output ports based on matching flags set on that buffer.
+*/
+
+/* OMX_IndexParamPortMaxFrameSize: Specifying maximum frame size */
+/*
+This control can be used to control the maximum frame size allowed on an output port.
+*/
+
+/* OMX_IndexConfigBrcmCameraRnDPreprocess: Enable use of development ISP software stage */
+/*
+This control can be used to enable a developmental software stage to be inserted into
+the preprocessor stage of the ISP.
+*/
+
+/* OMX_IndexConfigBrcmCameraRnDPostprocess: Enable use of development ISP software stage */
+/*
+This control can be used to enable a developmental software stage to be inserted into
+the postprocessor stage of the ISP.
+*/
+
+/* OMX_IndexParamDisableVllPool: Controlling use of memory for loadable modules */
+/*
+This control can be used to control whether loadable modules used a dedicated memory
+pool or use heap allocated memory.
+*/
+
+/* OMX_IndexParamBrcmVideoPrecodeForQP: Pre-code 1st frame for QP.*/
+/*
+This control selects a pre-encode of the first frame to set up a better initial QP value.
+*/
+
+/* OMX_IndexParamBrcmVideoTimestampFifo: Video timestamp FIFO mode. */
+/*
+When enabled, the timestamp fifo mode will change the way
+incoming timestamps are associated with output images so the incoming timestamps
+get used without re-ordering on output images.
+*/
+
+/* OMX_IndexParamCameraCustomSensorConfig: Custom camera sensor configuration. */
+/*
+This parameter is passed down to the camera sensor driver to be interpreted as a
+request for a different configuration to normal. How the configuration varies is
+sensor specific.
+*/
+
+/* OMX_IndexParamCameraDeviceNumber: Camera device selection .*/
+/*
+Controls which camera driver, or camera peripheral, to use.
+*/
+
+/* OMX_IndexParamBrcmMaxNumCallbacks: Codec callback limit. */
+/*
+The codec can queue up a significant number of frames internally if the sink is
+not consuming the output fast enough. This control limits the number of frames
+that can be queued up.
+*/
+
+typedef struct OMX_PARAM_BRCMCONFIGFILETYPE {
+   OMX_U32 nSize;                      /**< size of the structure in bytes, including
+                                            actual URI name */
+   OMX_VERSIONTYPE nVersion;           /**< OMX specification version information */
+   OMX_U32 fileSize;                   /**< Size of complete file data */
+} OMX_PARAM_BRCMCONFIGFILETYPE;
+
+typedef struct OMX_PARAM_BRCMCONFIGFILECHUNKTYPE {
+   OMX_U32 nSize;                      /**< size of the structure in bytes, including
+                                            actual chunk data */
+   OMX_VERSIONTYPE nVersion;           /**< OMX specification version information */
+   OMX_U32 size;                       /**< Number of bytes being transferred in this chunk */
+   OMX_U32 offset;                     /**< Offset of this chunk in the file */
+   OMX_U8 data[1];                     /**< Chunk data */
+} OMX_PARAM_BRCMCONFIGFILECHUNKTYPE;
+
+typedef struct OMX_PARAM_BRCMFRAMERATERANGETYPE {
+   OMX_U32 nSize;                      /**< size of the structure in bytes, including
+                                            actual chunk data */
+   OMX_VERSIONTYPE nVersion;           /**< OMX specification version information */
+   OMX_U32 nPortIndex;
+   OMX_U32 xFramerateLow;              /**< Low end of framerate range. Q16 format */
+   OMX_U32 xFramerateHigh;             /**< High end of framerate range. Q16 format */
+} OMX_PARAM_BRCMFRAMERATERANGETYPE;
+
+typedef struct OMX_PARAM_S32TYPE {
+    OMX_U32 nSize;                    /**< Size of this structure, in Bytes */
+    OMX_VERSIONTYPE nVersion;         /**< OMX specification version information */
+    OMX_U32 nPortIndex;               /**< port that this structure applies to */
+    OMX_S32 nS32;                     /**< S32 value */
+} OMX_PARAM_S32TYPE;
+
+typedef struct OMX_PARAM_BRCMVIDEODRMPROTECTBUFFERTYPE
+{
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+
+   OMX_U32 size_wanted;     /**< Input. Zero size means internal video decoder buffer,
+                                 mem_handle and phys_addr not returned in this case */
+   OMX_U32 protect;         /**< Input. 1 = protect, 0 = unprotect */
+
+   OMX_U32 mem_handle;      /**< Output. Handle for protected buffer */
+   OMX_PTR phys_addr;       /**< Output. Physical memory address of protected buffer */
+} OMX_PARAM_BRCMVIDEODRMPROTECTBUFFERTYPE;
+
+typedef struct OMX_CONFIG_ZEROSHUTTERLAGTYPE
+{
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+
+   OMX_U32 bZeroShutterMode;        /**< Select ZSL mode from the camera. */
+   OMX_U32 bConcurrentCapture;      /**< Perform concurrent captures for full ZSL. */
+
+} OMX_CONFIG_ZEROSHUTTERLAGTYPE;
+
+/* OMX_IndexParamBrcmVideoDecodeConfigVD3: VDec3 configuration. */
+typedef struct OMX_PARAM_BRCMVIDEODECODECONFIGVD3TYPE {
+   OMX_U32 nSize;                      /**< size of the structure in bytes, including
+                                            configuration data */
+   OMX_VERSIONTYPE nVersion;           /**< OMX specification version information */
+   OMX_U8 config[1];                   /**< Configuration data (a VD3_CONFIGURE_T) */
+} OMX_PARAM_BRCMVIDEODECODECONFIGVD3TYPE;
+/*
+Codec specific configuration block to set up internal state in a non-standard manner.
+*/
+
+/* OMX_IndexConfigCustomAwbGains: Manual AWB Gains. */
+typedef struct OMX_CONFIG_CUSTOMAWBGAINSTYPE {
+   OMX_U32 nSize;                      /**< size of the structure in bytes, including
+                                            configuration data */
+   OMX_VERSIONTYPE nVersion;           /**< OMX specification version information */
+   OMX_U32 xGainR;                     /**< Red gain - 16p16 */
+   OMX_U32 xGainB;                     /**< Blue gain - 16p16 */
+} OMX_CONFIG_CUSTOMAWBGAINSTYPE;
+
+/* OMX_IndexConfigCustomAwbGains: Manual AWB Gains. */
+
+/* OMX_IndexConfigBrcmRenderStats: Render port statistics */
+typedef struct OMX_CONFIG_BRCMRENDERSTATSTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+   OMX_BOOL nValid;
+   OMX_U32 nMatch;
+   OMX_U32 nPeriod;
+   OMX_U32 nPhase;
+   OMX_U32 nPixelClockNominal;
+   OMX_U32 nPixelClock;
+   OMX_U32 nHvsStatus;
+   OMX_U32 dummy0[2];
+} OMX_CONFIG_BRCMRENDERSTATSTYPE;
+/*
+This provides statistics from the renderer to allow more accurate synchronisation
+between the scheduler and display VSYNC.
+*/
+
+#define OMX_BRCM_MAXANNOTATETEXTLEN 256
+typedef struct OMX_CONFIG_BRCMANNOTATETYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_BOOL bEnable;
+   OMX_BOOL bShowShutter;
+   OMX_BOOL bShowAnalogGain;
+   OMX_BOOL bShowLens;
+   OMX_BOOL bShowCaf;
+   OMX_BOOL bShowMotion;
+   OMX_BOOL bShowFrameNum;
+   OMX_BOOL bEnableBackground;
+   OMX_BOOL bCustomBackgroundColour;
+   OMX_U8 nBackgroundY;
+   OMX_U8 nBackgroundU;
+   OMX_U8 nBackgroundV;
+   OMX_U8 dummy1;
+   OMX_BOOL bCustomTextColour;
+   OMX_U8 nTextY;
+   OMX_U8 nTextU;
+   OMX_U8 nTextV;
+   OMX_U8 nTextSize;   /**< Text size: 6-150 pixels */
+   OMX_U8 sText[OMX_BRCM_MAXANNOTATETEXTLEN];
+} OMX_CONFIG_BRCMANNOTATETYPE;
+
+/* OMX_IndexParamBrcmStereoscopicMode: Stereoscopic camera support */
+typedef enum OMX_BRCMSTEREOSCOPICMODETYPE {
+   OMX_STEREOSCOPIC_NONE = 0,
+   OMX_STEREOSCOPIC_SIDEBYSIDE = 1,
+   OMX_STEREOSCOPIC_TOPBOTTOM = 2,
+   OMX_STEREOSCOPIC_MAX = 0x7FFFFFFF,
+} OMX_BRCMSTEREOSCOPICMODETYPE;
+
+typedef struct OMX_CONFIG_BRCMSTEREOSCOPICMODETYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+
+   OMX_U32 nPortIndex;                    /**< port that this structure applies to */
+   OMX_BRCMSTEREOSCOPICMODETYPE eMode;    /**< Packing mode */
+   OMX_BOOL bDecimate;                    /**< Half/half mode
+                                          (pixel aspect ratio = 1:2 or 2:1 if set. 1:1 if not set) */
+   OMX_BOOL bSwapEyes;                    /**< False = left eye first. True = right eye first. */
+} OMX_CONFIG_BRCMSTEREOSCOPICMODETYPE;
+/*
+This control sets up how stereoscopic images should be generated.
+*/
+
+/* OMX_IndexParamCameraInterface: Camera interface type. */
+typedef enum OMX_CAMERAINTERFACETYPE {
+   OMX_CAMERAINTERFACE_CSI = 0,
+   OMX_CAMERAINTERFACE_CCP2 = 1,
+   OMX_CAMERAINTERFACE_CPI = 2,
+   OMX_CAMERAINTERFACE_MAX = 0x7FFFFFFF,
+} OMX_CAMERAINTERFACETYPE;
+
+typedef struct OMX_PARAM_CAMERAINTERFACETYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+
+   OMX_U32 nPortIndex;                    /**< port that this structure applies to */
+   OMX_CAMERAINTERFACETYPE eMode;         /**< Interface mode */
+} OMX_PARAM_CAMERAINTERFACETYPE;
+/*
+This configures the physical camera interface type.
+*/
+
+typedef enum OMX_CAMERACLOCKINGMODETYPE {
+   OMX_CAMERACLOCKINGMODE_STROBE = 0,
+   OMX_CAMERACLOCKINGMODE_CLOCK = 1,
+   OMX_CAMERACLOCKINGMODE_MAX = 0x7FFFFFFF,
+} OMX_CAMERACLOCKINGMODETYPE;
+
+typedef struct OMX_PARAM_CAMERACLOCKINGMODETYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+
+   OMX_U32 nPortIndex;                    /**< port that this structure applies to */
+   OMX_CAMERACLOCKINGMODETYPE eMode;      /**< Clocking mode */
+} OMX_PARAM_CAMERACLOCKINGMODETYPE;
+
+/* OMX_IndexParamCameraRxConfig: Camera receiver configuration */
+typedef enum OMX_CAMERARXDECODETYPE {
+   OMX_CAMERARXDECODE_NONE = 0,
+   OMX_CAMERARXDECODE_DPCM8TO10 = 1,
+   OMX_CAMERARXDECODE_DPCM7TO10 = 2,
+   OMX_CAMERARXDECODE_DPCM6TO10 = 3,
+   OMX_CAMERARXDECODE_DPCM8TO12 = 4,
+   OMX_CAMERARXDECODE_DPCM7TO12 = 5,
+   OMX_CAMERARXDECODE_DPCM6TO12 = 6,
+   OMX_CAMERARXDECODE_DPCM10TO14 = 7,
+   OMX_CAMERARXDECODE_DPCM8TO14 = 8,
+   OMX_CAMERARXDECODE_DPCM12TO16 = 9,
+   OMX_CAMERARXDECODE_DPCM10TO16 = 10,
+   OMX_CAMERARXDECODE_DPCM8TO16 = 11,
+   OMX_CAMERARXDECODE_MAX = 0x7FFFFFFF
+} OMX_CAMERARXDECODETYPE;
+
+typedef enum OMX_CAMERARXENCODETYPE {
+   OMX_CAMERARXENCODE_NONE = 0,
+   OMX_CAMERARXENCODE_DPCM10TO8 = 1,
+   OMX_CAMERARXENCODE_DPCM12TO8 = 2,
+   OMX_CAMERARXENCODE_DPCM14TO8 = 3,
+   OMX_CAMERARXENCODE_MAX = 0x7FFFFFFF
+} OMX_CAMERARXENCODETYPE;
+
+typedef enum OMX_CAMERARXUNPACKTYPE {
+   OMX_CAMERARXUNPACK_NONE = 0,
+   OMX_CAMERARXUNPACK_6 = 1,
+   OMX_CAMERARXUNPACK_7 = 2,
+   OMX_CAMERARXUNPACK_8 = 3,
+   OMX_CAMERARXUNPACK_10 = 4,
+   OMX_CAMERARXUNPACK_12 = 5,
+   OMX_CAMERARXUNPACK_14 = 6,
+   OMX_CAMERARXUNPACK_16 = 7,
+   OMX_CAMERARXUNPACK_MAX = 0x7FFFFFFF
+} OMX_CAMERARXUNPACKYPE;
+
+typedef enum OMX_CAMERARXPACKTYPE {
+   OMX_CAMERARXPACK_NONE = 0,
+   OMX_CAMERARXPACK_8 = 1,
+   OMX_CAMERARXPACK_10 = 2,
+   OMX_CAMERARXPACK_12 = 3,
+   OMX_CAMERARXPACK_14 = 4,
+   OMX_CAMERARXPACK_16 = 5,
+   OMX_CAMERARXPACK_RAW10 = 6,
+   OMX_CAMERARXPACK_RAW12 = 7,
+   OMX_CAMERARXPACK_MAX = 0x7FFFFFFF
+} OMX_CAMERARXPACKTYPE;
+
+typedef struct OMX_PARAM_CAMERARXCONFIG_TYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+
+   OMX_U32 nPortIndex;                    /**< port that this structure applies to */
+   OMX_CAMERARXDECODETYPE eDecode;
+   OMX_CAMERARXENCODETYPE eEncode;
+   OMX_CAMERARXUNPACKYPE eUnpack;
+   OMX_CAMERARXPACKTYPE ePack;
+   OMX_U32 nDataLanes;
+   OMX_U32 nEncodeBlockLength;
+   OMX_U32 nEmbeddedDataLines;
+   OMX_U32 nImageId;
+} OMX_PARAM_CAMERARXCONFIG_TYPE;
+/*
+Configures the setup and processing options of the camera receiver peripheral.
+*/
+
+typedef struct OMX_PARAM_CAMERARXTIMING_TYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+
+   OMX_U32 nPortIndex;                    /**< port that this structure applies to */
+   OMX_U32 nTiming1;
+   OMX_U32 nTiming2;
+   OMX_U32 nTiming3;
+   OMX_U32 nTiming4;
+   OMX_U32 nTiming5;
+   OMX_U32 nTerm1;
+   OMX_U32 nTerm2;
+   OMX_U32 nCpiTiming1;
+   OMX_U32 nCpiTiming2;
+} OMX_PARAM_CAMERARXTIMING_TYPE;
+
+
+/* OMX_IndexParamBrcmBayerOrder: Bayer order */
+typedef enum OMX_BAYERORDERTYPE {
+   OMX_BayerOrderRGGB = 0,
+   OMX_BayerOrderGBRG = 1,
+   OMX_BayerOrderBGGR = 2,
+   OMX_BayerOrderGRBG = 3,
+
+   OMX_BayerOrderMax = 0x7FFFFFFF
+} OMX_BAYERORDERTYPE;
+
+typedef struct OMX_PARAM_BAYERORDERTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+
+   OMX_U32 nPortIndex;                    /**< port that this structure applies to */
+   OMX_BAYERORDERTYPE eBayerOrder;
+} OMX_PARAM_BAYERORDERTYPE;
+/*
+The IL standard does not support a way to specify the Bayer order of Bayer images.
+This control adds that missing functionality.
+*/
+
+/* OMX_IndexParamBrcmLensShadingOverride: Override or set a lens shading table.*/
+/*
+Allows the lens shading grid to be set.
+Configuration is based on a similar system to the OMAP3 ISP.
+A grid of gains is required for each of the 4 Bayer channels, with each value covering
+a nGridCellSize square of pixels.
+nWidth and nHeight should be equal or greater than the sensor resolution. In the
+case of the camera component, the firmware will crop the table based on the preconfigured
+mode set. nStride allows additional horizontal padding to be including in the table.
+nMemHandleTable needs to be set to a MEM_HANDLE_T, allocated via VC-SM or similar allocator.
+nRefTransform should be set to the transform in force when the reference table was
+captured. This allows correct compensation when the sensor is subsequently used with
+an alternate transform.
+*/
+typedef struct OMX_PARAM_LENSSHADINGOVERRIDETYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+
+   OMX_BOOL bEnabled;                     /**< Enable the override grid */
+   OMX_U32 nGridCellSize;                 /**< size of each grid element. Assumes square grid */
+   OMX_U32 nWidth;                        /**< grid width */
+   OMX_U32 nStride;                       /**< grid stride (allows for padding) */
+   OMX_U32 nHeight;                       /**< grid height */
+   OMX_U32 nMemHandleTable;               /**< Handle for grid */
+   OMX_U32 nRefTransform;                 /**< Reference transform taken from raw header */
+} OMX_PARAM_LENSSHADINGOVERRIDETYPE;
+
+/* OMX_IndexConfigBrcmPowerMonitor: Deprecated.*/
+/*
+Deprecated. Do not use.
+*/
+
+/* OMX_IndexParamBrcmZeroCopy: Deprecated */
+/*
+Deprecated. Do not use.
+*/
+
+/* OMX_IndexParamBrcmSupportsSlices: Sliced processing support */
+/*
+Mainly used by the MMAL framework.
+Some components support an nSliceHeight value of 16, to allow images
+to be passed in multiple chunks. All will support an nSliceHeight >=
+nFrameHeight (with some extra constraints).
+If a component supports nSliceHeight of 16, then it will respond to
+OMX_GetParameter on this index with no error and bEnabled set to OMX_TRUE.
+*/
+
+/* OMX_IndexParamBrcmSupportsUnalignedSliceheight: Unaligned nSliceHeight support */
+/*
+Most components require an nSliceHeight value which is a multiple of 16, but
+some components accepting any value >= nFrameHeight. Those ports/components will
+respond to OMX_GetParameter on this index with no error and bEnabled set to OMX_TRUE.
+*/
+
+typedef struct OMX_CCMTYPE {
+   OMX_S32 sCcm[3][3];
+   OMX_S32 soffsets[3];
+} OMX_PARAM_CCMTYPE;
+
+typedef struct OMX_PARAM_CUSTOMCCMTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+
+   OMX_BOOL bEnabled;          /**< Enable the custom CCM. */
+   OMX_S32 xColorMatrix[3][3]; /**< Stored in signed Q16 format */
+   OMX_S32 nColorOffset[3];    /**< CCM offsets */
+} OMX_PARAM_CUSTOMCCMTYPE;
+
+/* OMX_IndexConfigCameraDigitalGain: Manual digital gain. */
+/*
+Configures the digital gain within the ISP pipeline.
+*/
+typedef struct OMX_CONFIG_CAMERAGAINTYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_U32 nPortIndex;
+
+   OMX_U32 xGain;             /**< Gain to be applied, stored as Q16 format */
+   OMX_BOOL bAutoGain;        /**< Whether gain is set automatically */
+} OMX_CONFIG_CAMERAGAINTYPE;
+
+#endif
+/* File EOF */
diff --git a/interface/vmcs_host/khronos/IL/OMX_Component.h b/interface/vmcs_host/khronos/IL/OMX_Component.h
new file mode 100755 (executable)
index 0000000..b0b9b81
--- /dev/null
@@ -0,0 +1,579 @@
+/*
+ * Copyright (c) 2008 The Khronos Group Inc. 
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions: 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
+ *
+ */
+
+/** OMX_Component.h - OpenMax IL version 1.1.2
+ *  The OMX_Component header file contains the definitions used to define
+ *  the public interface of a component.  This header file is intended to
+ *  be used by both the application and the component.
+ */
+
+#ifndef OMX_Component_h
+#define OMX_Component_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+
+/* Each OMX header must include all required header files to allow the
+ *  header to compile without errors.  The includes below are required
+ *  for this header file to compile successfully 
+ */
+
+#include "OMX_Audio.h"
+#include "OMX_Video.h"
+#include "OMX_Image.h"
+#include "OMX_Other.h"
+
+/** @ingroup comp */
+typedef enum OMX_PORTDOMAINTYPE { 
+    OMX_PortDomainAudio, 
+    OMX_PortDomainVideo, 
+    OMX_PortDomainImage, 
+    OMX_PortDomainOther,
+    OMX_PortDomainKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_PortDomainVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_PortDomainMax = 0x7ffffff
+} OMX_PORTDOMAINTYPE;
+
+/** @ingroup comp */
+typedef struct OMX_PARAM_PORTDEFINITIONTYPE {
+    OMX_U32 nSize;                 /**< Size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;      /**< OMX specification version information */
+    OMX_U32 nPortIndex;            /**< Port number the structure applies to */
+    OMX_DIRTYPE eDir;              /**< Direction (input or output) of this port */
+    OMX_U32 nBufferCountActual;    /**< The actual number of buffers allocated on this port */
+    OMX_U32 nBufferCountMin;       /**< The minimum number of buffers this port requires */
+    OMX_U32 nBufferSize;           /**< Size, in bytes, for buffers to be used for this channel */
+    OMX_BOOL bEnabled;             /**< Ports default to enabled and are enabled/disabled by
+                                        OMX_CommandPortEnable/OMX_CommandPortDisable.
+                                        When disabled a port is unpopulated. A disabled port
+                                        is not populated with buffers on a transition to IDLE. */
+    OMX_BOOL bPopulated;           /**< Port is populated with all of its buffers as indicated by
+                                        nBufferCountActual. A disabled port is always unpopulated. 
+                                        An enabled port is populated on a transition to OMX_StateIdle
+                                        and unpopulated on a transition to loaded. */
+    OMX_PORTDOMAINTYPE eDomain;    /**< Domain of the port. Determines the contents of metadata below. */
+    union {
+        OMX_AUDIO_PORTDEFINITIONTYPE audio;
+        OMX_VIDEO_PORTDEFINITIONTYPE video;
+        OMX_IMAGE_PORTDEFINITIONTYPE image;
+        OMX_OTHER_PORTDEFINITIONTYPE other;
+    } format;
+    OMX_BOOL bBuffersContiguous;
+    OMX_U32 nBufferAlignment;
+} OMX_PARAM_PORTDEFINITIONTYPE;
+
+/** @ingroup comp */
+typedef struct OMX_PARAM_U32TYPE { 
+    OMX_U32 nSize;                    /**< Size of this structure, in Bytes */ 
+    OMX_VERSIONTYPE nVersion;         /**< OMX specification version information */ 
+    OMX_U32 nPortIndex;               /**< port that this structure applies to */ 
+    OMX_U32 nU32;                     /**< U32 value */
+} OMX_PARAM_U32TYPE;
+
+/** @ingroup rpm */
+typedef enum OMX_SUSPENSIONPOLICYTYPE {
+    OMX_SuspensionDisabled, /**< No suspension; v1.0 behavior */
+    OMX_SuspensionEnabled,  /**< Suspension allowed */   
+    OMX_SuspensionPolicyKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_SuspensionPolicyStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_SuspensionPolicyMax = 0x7fffffff
+} OMX_SUSPENSIONPOLICYTYPE;
+
+/** @ingroup rpm */
+typedef struct OMX_PARAM_SUSPENSIONPOLICYTYPE {
+    OMX_U32 nSize;                  
+    OMX_VERSIONTYPE nVersion;        
+    OMX_SUSPENSIONPOLICYTYPE ePolicy;
+} OMX_PARAM_SUSPENSIONPOLICYTYPE;
+
+/** @ingroup rpm */
+typedef enum OMX_SUSPENSIONTYPE {
+    OMX_NotSuspended, /**< component is not suspended */
+    OMX_Suspended,    /**< component is suspended */
+    OMX_SuspensionKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_SuspensionVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_SuspendMax = 0x7FFFFFFF
+} OMX_SUSPENSIONTYPE;
+
+/** @ingroup rpm */
+typedef struct OMX_PARAM_SUSPENSIONTYPE {
+    OMX_U32 nSize;                  
+    OMX_VERSIONTYPE nVersion;       
+    OMX_SUSPENSIONTYPE eType;             
+} OMX_PARAM_SUSPENSIONTYPE ;
+
+typedef struct OMX_CONFIG_BOOLEANTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_BOOL bEnabled;    
+} OMX_CONFIG_BOOLEANTYPE;
+
+/* Parameter specifying the content uri to use. */
+/** @ingroup cp */
+typedef struct OMX_PARAM_CONTENTURITYPE
+{
+    OMX_U32 nSize;                      /**< size of the structure in bytes, including
+                                             actual URI name */
+    OMX_VERSIONTYPE nVersion;           /**< OMX specification version information */
+    OMX_U8 contentURI[1];               /**< The URI name */
+} OMX_PARAM_CONTENTURITYPE;
+
+/* Parameter specifying the pipe to use. */
+/** @ingroup cp */
+typedef struct OMX_PARAM_CONTENTPIPETYPE
+{
+    OMX_U32 nSize;              /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;   /**< OMX specification version information */
+    OMX_HANDLETYPE hPipe;       /**< The pipe handle*/
+} OMX_PARAM_CONTENTPIPETYPE;
+
+/** @ingroup rpm */
+typedef struct OMX_RESOURCECONCEALMENTTYPE {
+    OMX_U32 nSize;             /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;  /**< OMX specification version information */
+    OMX_BOOL bResourceConcealmentForbidden; /**< disallow the use of resource concealment 
+                                            methods (like degrading algorithm quality to 
+                                            lower resource consumption or functional bypass) 
+                                            on a component as a resolution to resource conflicts. */
+} OMX_RESOURCECONCEALMENTTYPE;
+
+
+/** @ingroup metadata */
+typedef enum OMX_METADATACHARSETTYPE {
+    OMX_MetadataCharsetUnknown = 0,
+    OMX_MetadataCharsetASCII,
+    OMX_MetadataCharsetBinary,
+    OMX_MetadataCharsetCodePage1252,
+    OMX_MetadataCharsetUTF8,
+    OMX_MetadataCharsetJavaConformantUTF8,
+    OMX_MetadataCharsetUTF7,
+    OMX_MetadataCharsetImapUTF7,
+    OMX_MetadataCharsetUTF16LE, 
+    OMX_MetadataCharsetUTF16BE,
+    OMX_MetadataCharsetGB12345,
+    OMX_MetadataCharsetHZGB2312,
+    OMX_MetadataCharsetGB2312,
+    OMX_MetadataCharsetGB18030,
+    OMX_MetadataCharsetGBK,
+    OMX_MetadataCharsetBig5,
+    OMX_MetadataCharsetISO88591,
+    OMX_MetadataCharsetISO88592,
+    OMX_MetadataCharsetISO88593,
+    OMX_MetadataCharsetISO88594,
+    OMX_MetadataCharsetISO88595,
+    OMX_MetadataCharsetISO88596,
+    OMX_MetadataCharsetISO88597,
+    OMX_MetadataCharsetISO88598,
+    OMX_MetadataCharsetISO88599,
+    OMX_MetadataCharsetISO885910,
+    OMX_MetadataCharsetISO885913,
+    OMX_MetadataCharsetISO885914,
+    OMX_MetadataCharsetISO885915,
+    OMX_MetadataCharsetShiftJIS,
+    OMX_MetadataCharsetISO2022JP,
+    OMX_MetadataCharsetISO2022JP1,
+    OMX_MetadataCharsetISOEUCJP,
+    OMX_MetadataCharsetSMS7Bit,
+    OMX_MetadataCharsetKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_MetadataCharsetVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_MetadataCharsetTypeMax= 0x7FFFFFFF
+} OMX_METADATACHARSETTYPE;
+
+/** @ingroup metadata */
+typedef enum OMX_METADATASCOPETYPE
+{
+    OMX_MetadataScopeAllLevels,
+    OMX_MetadataScopeTopLevel,
+    OMX_MetadataScopePortLevel,
+    OMX_MetadataScopeNodeLevel,
+    OMX_MetadataScopeKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_MetadataScopeVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_MetadataScopeTypeMax = 0x7fffffff
+} OMX_METADATASCOPETYPE;
+
+/** @ingroup metadata */
+typedef enum OMX_METADATASEARCHMODETYPE
+{
+    OMX_MetadataSearchValueSizeByIndex,
+    OMX_MetadataSearchItemByIndex,
+    OMX_MetadataSearchNextItemByKey,
+    OMX_MetadataSearchKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_MetadataSearchVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_MetadataSearchTypeMax = 0x7fffffff
+} OMX_METADATASEARCHMODETYPE;
+/** @ingroup metadata */
+typedef struct OMX_CONFIG_METADATAITEMCOUNTTYPE
+{
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_METADATASCOPETYPE eScopeMode;
+    OMX_U32 nScopeSpecifier;
+    OMX_U32 nMetadataItemCount;
+} OMX_CONFIG_METADATAITEMCOUNTTYPE;
+
+/** @ingroup metadata */
+typedef struct OMX_CONFIG_METADATAITEMTYPE
+{
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_METADATASCOPETYPE eScopeMode;
+    OMX_U32 nScopeSpecifier;
+    OMX_U32 nMetadataItemIndex;  
+    OMX_METADATASEARCHMODETYPE eSearchMode;
+    OMX_METADATACHARSETTYPE eKeyCharset;
+    OMX_U8 nKeySizeUsed;
+    OMX_U8 nKey[128];
+    OMX_METADATACHARSETTYPE eValueCharset;
+    OMX_STRING sLanguageCountry;
+    OMX_U32 nValueMaxSize;
+    OMX_U32 nValueSizeUsed;
+    OMX_U8 nValue[1];
+} OMX_CONFIG_METADATAITEMTYPE;
+
+/* @ingroup metadata */
+typedef struct OMX_CONFIG_CONTAINERNODECOUNTTYPE
+{
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_BOOL bAllKeys;
+    OMX_U32 nParentNodeID;
+    OMX_U32 nNumNodes;
+} OMX_CONFIG_CONTAINERNODECOUNTTYPE;
+
+/** @ingroup metadata */
+typedef struct OMX_CONFIG_CONTAINERNODEIDTYPE
+{
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_BOOL bAllKeys;
+    OMX_U32 nParentNodeID;
+    OMX_U32 nNodeIndex; 
+    OMX_U32 nNodeID; 
+    OMX_STRING cNodeName;
+    OMX_BOOL bIsLeafType;
+} OMX_CONFIG_CONTAINERNODEIDTYPE;
+
+/** @ingroup metadata */
+typedef struct OMX_PARAM_METADATAFILTERTYPE 
+{ 
+    OMX_U32 nSize; 
+    OMX_VERSIONTYPE nVersion; 
+    OMX_BOOL bAllKeys; /* if true then this structure refers to all keys and 
+                         * the three key fields below are ignored */
+    OMX_METADATACHARSETTYPE eKeyCharset;
+    OMX_U32 nKeySizeUsed; 
+    OMX_U8   nKey [128]; 
+    OMX_U32 nLanguageCountrySizeUsed;
+    OMX_U8 nLanguageCountry[128];
+    OMX_BOOL bEnabled; /* if true then key is part of filter (e.g. 
+                         * retained for query later). If false then
+                         * key is not part of filter */
+} OMX_PARAM_METADATAFILTERTYPE; 
+
+/** The OMX_HANDLETYPE structure defines the component handle.  The component 
+ *  handle is used to access all of the component's public methods and also
+ *  contains pointers to the component's private data area.  The component
+ *  handle is initialized by the OMX core (with help from the component)
+ *  during the process of loading the component.  After the component is
+ *  successfully loaded, the application can safely access any of the
+ *  component's public functions (although some may return an error because
+ *  the state is inappropriate for the access).
+ * 
+ *  @ingroup comp
+ */
+typedef struct OMX_COMPONENTTYPE
+{
+    /** The size of this structure, in bytes.  It is the responsibility
+        of the allocator of this structure to fill in this value.  Since
+        this structure is allocated by the GetHandle function, this
+        function will fill in this value. */
+    OMX_U32 nSize;
+
+    /** nVersion is the version of the OMX specification that the structure 
+        is built against.  It is the responsibility of the creator of this 
+        structure to initialize this value and every user of this structure 
+        should verify that it knows how to use the exact version of 
+        this structure found herein. */
+    OMX_VERSIONTYPE nVersion;
+
+    /** pComponentPrivate is a pointer to the component private data area.  
+        This member is allocated and initialized by the component when the 
+        component is first loaded.  The application should not access this 
+        data area. */
+    OMX_PTR pComponentPrivate;
+
+    /** pApplicationPrivate is a pointer that is a parameter to the 
+        OMX_GetHandle method, and contains an application private value 
+        provided by the IL client.  This application private data is 
+        returned to the IL Client by OMX in all callbacks */
+    OMX_PTR pApplicationPrivate;
+
+    /** refer to OMX_GetComponentVersion in OMX_core.h or the OMX IL 
+        specification for details on the GetComponentVersion method.
+     */
+    OMX_ERRORTYPE (*GetComponentVersion)(
+            OMX_IN  OMX_HANDLETYPE hComponent,
+            OMX_OUT OMX_STRING pComponentName,
+            OMX_OUT OMX_VERSIONTYPE* pComponentVersion,
+            OMX_OUT OMX_VERSIONTYPE* pSpecVersion,
+            OMX_OUT OMX_UUIDTYPE* pComponentUUID);
+
+    /** refer to OMX_SendCommand in OMX_core.h or the OMX IL 
+        specification for details on the SendCommand method.
+     */
+    OMX_ERRORTYPE (*SendCommand)(
+            OMX_IN  OMX_HANDLETYPE hComponent,
+            OMX_IN  OMX_COMMANDTYPE Cmd,
+            OMX_IN  OMX_U32 nParam1,
+            OMX_IN  OMX_PTR pCmdData);
+
+    /** refer to OMX_GetParameter in OMX_core.h or the OMX IL 
+        specification for details on the GetParameter method.
+     */
+    OMX_ERRORTYPE (*GetParameter)(
+            OMX_IN  OMX_HANDLETYPE hComponent, 
+            OMX_IN  OMX_INDEXTYPE nParamIndex,  
+            OMX_INOUT OMX_PTR pComponentParameterStructure);
+
+
+    /** refer to OMX_SetParameter in OMX_core.h or the OMX IL 
+        specification for details on the SetParameter method.
+     */
+    OMX_ERRORTYPE (*SetParameter)(
+            OMX_IN  OMX_HANDLETYPE hComponent, 
+            OMX_IN  OMX_INDEXTYPE nIndex,
+            OMX_IN  OMX_PTR pComponentParameterStructure);
+
+
+    /** refer to OMX_GetConfig in OMX_core.h or the OMX IL 
+        specification for details on the GetConfig method.
+     */
+    OMX_ERRORTYPE (*GetConfig)(
+            OMX_IN  OMX_HANDLETYPE hComponent,
+            OMX_IN  OMX_INDEXTYPE nIndex, 
+            OMX_INOUT OMX_PTR pComponentConfigStructure);
+
+
+    /** refer to OMX_SetConfig in OMX_core.h or the OMX IL 
+        specification for details on the SetConfig method.
+     */
+    OMX_ERRORTYPE (*SetConfig)(
+            OMX_IN  OMX_HANDLETYPE hComponent,
+            OMX_IN  OMX_INDEXTYPE nIndex, 
+            OMX_IN  OMX_PTR pComponentConfigStructure);
+
+
+    /** refer to OMX_GetExtensionIndex in OMX_core.h or the OMX IL 
+        specification for details on the GetExtensionIndex method.
+     */
+    OMX_ERRORTYPE (*GetExtensionIndex)(
+            OMX_IN  OMX_HANDLETYPE hComponent,
+            OMX_IN  OMX_STRING cParameterName,
+            OMX_OUT OMX_INDEXTYPE* pIndexType);
+
+
+    /** refer to OMX_GetState in OMX_core.h or the OMX IL 
+        specification for details on the GetState method.
+     */
+    OMX_ERRORTYPE (*GetState)(
+            OMX_IN  OMX_HANDLETYPE hComponent,
+            OMX_OUT OMX_STATETYPE* pState);
+
+    
+    /** The ComponentTunnelRequest method will interact with another OMX
+        component to determine if tunneling is possible and to setup the
+        tunneling.  The return codes for this method can be used to 
+        determine if tunneling is not possible, or if tunneling is not
+        supported.  
+        
+        Base profile components (i.e. non-interop) do not support this
+        method and should return OMX_ErrorNotImplemented 
+
+        The interop profile component MUST support tunneling to another 
+        interop profile component with a compatible port parameters.  
+        A component may also support proprietary communication.
+        
+        If proprietary communication is supported the negotiation of 
+        proprietary communication is done outside of OMX in a vendor 
+        specific way. It is only required that the proper result be 
+        returned and the details of how the setup is done is left 
+        to the component implementation.  
+    
+        When this method is invoked when nPort in an output port, the
+        component will:
+        1.  Populate the pTunnelSetup structure with the output port's 
+            requirements and constraints for the tunnel.
+
+        When this method is invoked when nPort in an input port, the
+        component will:
+        1.  Query the necessary parameters from the output port to 
+            determine if the ports are compatible for tunneling
+        2.  If the ports are compatible, the component should store
+            the tunnel step provided by the output port
+        3.  Determine which port (either input or output) is the buffer
+            supplier, and call OMX_SetParameter on the output port to
+            indicate this selection.
+        
+        The component will return from this call within 5 msec.
+    
+        @param [in] hComp
+            Handle of the component to be accessed.  This is the component
+            handle returned by the call to the OMX_GetHandle method.
+        @param [in] nPort
+            nPort is used to select the port on the component to be used
+            for tunneling.
+        @param [in] hTunneledComp
+            Handle of the component to tunnel with.  This is the component 
+            handle returned by the call to the OMX_GetHandle method.  When
+            this parameter is 0x0 the component should setup the port for
+            communication with the application / IL Client.
+        @param [in] nPortOutput
+            nPortOutput is used indicate the port the component should
+            tunnel with.
+        @param [in] pTunnelSetup
+            Pointer to the tunnel setup structure.  When nPort is an output port
+            the component should populate the fields of this structure.  When
+            When nPort is an input port the component should review the setup
+            provided by the component with the output port.
+        @return OMX_ERRORTYPE
+            If the command successfully executes, the return code will be
+            OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
+        @ingroup tun
+    */
+
+    OMX_ERRORTYPE (*ComponentTunnelRequest)(
+        OMX_IN  OMX_HANDLETYPE hComp,
+        OMX_IN  OMX_U32 nPort,
+        OMX_IN  OMX_HANDLETYPE hTunneledComp,
+        OMX_IN  OMX_U32 nTunneledPort,
+        OMX_INOUT  OMX_TUNNELSETUPTYPE* pTunnelSetup); 
+
+    /** refer to OMX_UseBuffer in OMX_core.h or the OMX IL 
+        specification for details on the UseBuffer method.
+        @ingroup buf
+     */
+    OMX_ERRORTYPE (*UseBuffer)(
+            OMX_IN OMX_HANDLETYPE hComponent,
+            OMX_INOUT OMX_BUFFERHEADERTYPE** ppBufferHdr,
+            OMX_IN OMX_U32 nPortIndex,
+            OMX_IN OMX_PTR pAppPrivate,
+            OMX_IN OMX_U32 nSizeBytes,
+            OMX_IN OMX_U8* pBuffer);
+
+    /** refer to OMX_AllocateBuffer in OMX_core.h or the OMX IL 
+        specification for details on the AllocateBuffer method.
+        @ingroup buf
+     */
+    OMX_ERRORTYPE (*AllocateBuffer)(
+            OMX_IN OMX_HANDLETYPE hComponent,
+            OMX_INOUT OMX_BUFFERHEADERTYPE** ppBuffer,
+            OMX_IN OMX_U32 nPortIndex,
+            OMX_IN OMX_PTR pAppPrivate,
+            OMX_IN OMX_U32 nSizeBytes);
+
+    /** refer to OMX_FreeBuffer in OMX_core.h or the OMX IL 
+        specification for details on the FreeBuffer method.
+        @ingroup buf
+     */
+    OMX_ERRORTYPE (*FreeBuffer)(
+            OMX_IN  OMX_HANDLETYPE hComponent,
+            OMX_IN  OMX_U32 nPortIndex,
+            OMX_IN  OMX_BUFFERHEADERTYPE* pBuffer);
+
+    /** refer to OMX_EmptyThisBuffer in OMX_core.h or the OMX IL 
+        specification for details on the EmptyThisBuffer method.
+        @ingroup buf
+     */
+    OMX_ERRORTYPE (*EmptyThisBuffer)(
+            OMX_IN  OMX_HANDLETYPE hComponent,
+            OMX_IN  OMX_BUFFERHEADERTYPE* pBuffer);
+
+    /** refer to OMX_FillThisBuffer in OMX_core.h or the OMX IL 
+        specification for details on the FillThisBuffer method.
+        @ingroup buf
+     */
+    OMX_ERRORTYPE (*FillThisBuffer)(
+            OMX_IN  OMX_HANDLETYPE hComponent,
+            OMX_IN  OMX_BUFFERHEADERTYPE* pBuffer);
+
+    /** The SetCallbacks method is used by the core to specify the callback
+        structure from the application to the component.  This is a blocking
+        call.  The component will return from this call within 5 msec.
+        @param [in] hComponent
+            Handle of the component to be accessed.  This is the component
+            handle returned by the call to the GetHandle function.
+        @param [in] pCallbacks
+            pointer to an OMX_CALLBACKTYPE structure used to provide the 
+            callback information to the component
+        @param [in] pAppData
+            pointer to an application defined value.  It is anticipated that 
+            the application will pass a pointer to a data structure or a "this
+            pointer" in this area to allow the callback (in the application)
+            to determine the context of the call
+        @return OMX_ERRORTYPE
+            If the command successfully executes, the return code will be
+            OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
+     */
+    OMX_ERRORTYPE (*SetCallbacks)(
+            OMX_IN  OMX_HANDLETYPE hComponent,
+            OMX_IN  OMX_CALLBACKTYPE* pCallbacks, 
+            OMX_IN  OMX_PTR pAppData);
+
+    /** ComponentDeInit method is used to deinitialize the component
+        providing a means to free any resources allocated at component
+        initialization.  NOTE:  After this call the component handle is
+        not valid for further use.
+        @param [in] hComponent
+            Handle of the component to be accessed.  This is the component
+            handle returned by the call to the GetHandle function.
+        @return OMX_ERRORTYPE
+            If the command successfully executes, the return code will be
+            OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
+     */
+    OMX_ERRORTYPE (*ComponentDeInit)(
+            OMX_IN  OMX_HANDLETYPE hComponent);
+
+    /** @ingroup buf */
+    OMX_ERRORTYPE (*UseEGLImage)(
+            OMX_IN OMX_HANDLETYPE hComponent,
+            OMX_INOUT OMX_BUFFERHEADERTYPE** ppBufferHdr,
+            OMX_IN OMX_U32 nPortIndex,
+            OMX_IN OMX_PTR pAppPrivate,
+            OMX_IN void* eglImage);
+
+    OMX_ERRORTYPE (*ComponentRoleEnum)(
+        OMX_IN OMX_HANDLETYPE hComponent,
+               OMX_OUT OMX_U8 *cRole,
+               OMX_IN OMX_U32 nIndex);
+
+} OMX_COMPONENTTYPE;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
+/* File EOF */
diff --git a/interface/vmcs_host/khronos/IL/OMX_Core.h b/interface/vmcs_host/khronos/IL/OMX_Core.h
new file mode 100755 (executable)
index 0000000..d883d94
--- /dev/null
@@ -0,0 +1,1467 @@
+/*
+ * Copyright (c) 2008 The Khronos Group Inc. 
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions: 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
+ *
+ */
+
+/** OMX_Core.h - OpenMax IL version 1.1.2
+ *  The OMX_Core header file contains the definitions used by both the
+ *  application and the component to access common items.
+ */
+
+#ifndef OMX_Core_h
+#define OMX_Core_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#if !defined(OMX_SKIP64BIT) && !defined(_VIDEOCORE)
+  /* The Videocore compiler doesn't enforce 64 bit alignment on 64 bit variables,
+   * which is almost equivalent to OMX_SKIP64BIT.
+   * Annoyingly struct OMX_BUFFERHEADERTYPE doesn't do the sensible thing
+   * and add padding fields or similar to make it the same for all compilers,
+   * so all clients need to define this.
+   * Warn if this isn't set, as the GPU will not interpret your buffers correctly,
+   * or vice versa.
+   */
+  #warning OMX_SKIP64BIT is not defined - this will be incompatible with the VC GPU code.
+#endif
+
+/* Each OMX header shall include all required header files to allow the
+ *  header to compile without errors.  The includes below are required
+ *  for this header file to compile successfully 
+ */
+
+#include "OMX_Index.h"
+
+
+/** The OMX_COMMANDTYPE enumeration is used to specify the action in the
+ *  OMX_SendCommand macro.  
+ *  @ingroup core
+ */
+typedef enum OMX_COMMANDTYPE
+{
+    OMX_CommandStateSet,    /**< Change the component state */
+    OMX_CommandFlush,       /**< Flush the data queue(s) of a component */
+    OMX_CommandPortDisable, /**< Disable a port on a component. */
+    OMX_CommandPortEnable,  /**< Enable a port on a component. */
+    OMX_CommandMarkBuffer,  /**< Mark a component/buffer for observation */
+    OMX_CommandKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_CommandVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_CommandMax = 0X7FFFFFFF
+} OMX_COMMANDTYPE;
+
+
+
+/** The OMX_STATETYPE enumeration is used to indicate or change the component
+ *  state.  This enumeration reflects the current state of the component when
+ *  used with the OMX_GetState macro or becomes the parameter in a state change
+ *  command when used with the OMX_SendCommand macro.
+ *
+ *  The component will be in the Loaded state after the component is initially
+ *  loaded into memory.  In the Loaded state, the component is not allowed to
+ *  allocate or hold resources other than to build it's internal parameter
+ *  and configuration tables.  The application will send one or more
+ *  SetParameters/GetParameters and SetConfig/GetConfig commands to the
+ *  component and the component will record each of these parameter and
+ *  configuration changes for use later.  When the application sends the
+ *  Idle command, the component will acquire the resources needed for the
+ *  specified configuration and will transition to the idle state if the
+ *  allocation is successful.  If the component cannot successfully
+ *  transition to the idle state for any reason, the state of the component
+ *  shall be fully rolled back to the Loaded state (e.g. all allocated 
+ *  resources shall be released).  When the component receives the command
+ *  to go to the Executing state, it shall begin processing buffers by
+ *  sending all input buffers it holds to the application.  While
+ *  the component is in the Idle state, the application may also send the
+ *  Pause command.  If the component receives the pause command while in the
+ *  Idle state, the component shall send all input buffers it holds to the 
+ *  application, but shall not begin processing buffers.  This will allow the
+ *  application to prefill buffers.
+ * 
+ *  @ingroup comp
+ */
+
+typedef enum OMX_STATETYPE
+{
+    OMX_StateInvalid,      /**< component has detected that it's internal data 
+                                structures are corrupted to the point that
+                                it cannot determine it's state properly */
+    OMX_StateLoaded,      /**< component has been loaded but has not completed
+                                initialization.  The OMX_SetParameter macro
+                                and the OMX_GetParameter macro are the only 
+                                valid macros allowed to be sent to the 
+                                component in this state. */
+    OMX_StateIdle,        /**< component initialization has been completed
+                                successfully and the component is ready to
+                                to start. */
+    OMX_StateExecuting,   /**< component has accepted the start command and
+                                is processing data (if data is available) */
+    OMX_StatePause,       /**< component has received pause command */
+    OMX_StateWaitForResources, /**< component is waiting for resources, either after 
+                                preemption or before it gets the resources requested.
+                                See specification for complete details. */
+    OMX_StateKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_StateVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_StateMax = 0X7FFFFFFF
+} OMX_STATETYPE;
+
+/** The OMX_ERRORTYPE enumeration defines the standard OMX Errors.  These 
+ *  errors should cover most of the common failure cases.  However, 
+ *  vendors are free to add additional error messages of their own as 
+ *  long as they follow these rules:
+ *  1.  Vendor error messages shall be in the range of 0x90000000 to
+ *      0x9000FFFF.
+ *  2.  Vendor error messages shall be defined in a header file provided
+ *      with the component.  No error messages are allowed that are
+ *      not defined.
+ */
+typedef enum OMX_ERRORTYPE
+{
+  OMX_ErrorNone = 0,
+
+  /** There were insufficient resources to perform the requested operation */
+  OMX_ErrorInsufficientResources = (OMX_S32) 0x80001000,
+
+  /** There was an error, but the cause of the error could not be determined */
+  OMX_ErrorUndefined = (OMX_S32) 0x80001001,
+
+  /** The component name string was not valid */
+  OMX_ErrorInvalidComponentName = (OMX_S32) 0x80001002,
+
+  /** No component with the specified name string was found */
+  OMX_ErrorComponentNotFound = (OMX_S32) 0x80001003,
+
+  /** The component specified did not have a "OMX_ComponentInit" or
+      "OMX_ComponentDeInit entry point */
+  OMX_ErrorInvalidComponent = (OMX_S32) 0x80001004,
+
+  /** One or more parameters were not valid */
+  OMX_ErrorBadParameter = (OMX_S32) 0x80001005,
+
+  /** The requested function is not implemented */
+  OMX_ErrorNotImplemented = (OMX_S32) 0x80001006,
+
+  /** The buffer was emptied before the next buffer was ready */
+  OMX_ErrorUnderflow = (OMX_S32) 0x80001007,
+
+  /** The buffer was not available when it was needed */
+  OMX_ErrorOverflow = (OMX_S32) 0x80001008,
+
+  /** The hardware failed to respond as expected */
+  OMX_ErrorHardware = (OMX_S32) 0x80001009,
+
+  /** The component is in the state OMX_StateInvalid */
+  OMX_ErrorInvalidState = (OMX_S32) 0x8000100A,
+
+  /** Stream is found to be corrupt */
+  OMX_ErrorStreamCorrupt = (OMX_S32) 0x8000100B,
+
+  /** Ports being connected are not compatible */
+  OMX_ErrorPortsNotCompatible = (OMX_S32) 0x8000100C,
+
+  /** Resources allocated to an idle component have been
+      lost resulting in the component returning to the loaded state */
+  OMX_ErrorResourcesLost = (OMX_S32) 0x8000100D,
+
+  /** No more indicies can be enumerated */
+  OMX_ErrorNoMore = (OMX_S32) 0x8000100E,
+
+  /** The component detected a version mismatch */
+  OMX_ErrorVersionMismatch = (OMX_S32) 0x8000100F,
+
+  /** The component is not ready to return data at this time */
+  OMX_ErrorNotReady = (OMX_S32) 0x80001010,
+
+  /** There was a timeout that occurred */
+  OMX_ErrorTimeout = (OMX_S32) 0x80001011,
+
+  /** This error occurs when trying to transition into the state you are already in */
+  OMX_ErrorSameState = (OMX_S32) 0x80001012,
+
+  /** Resources allocated to an executing or paused component have been 
+      preempted, causing the component to return to the idle state */
+  OMX_ErrorResourcesPreempted = (OMX_S32) 0x80001013, 
+
+  /** A non-supplier port sends this error to the IL client (via the EventHandler callback) 
+      during the allocation of buffers (on a transition from the LOADED to the IDLE state or
+      on a port restart) when it deems that it has waited an unusually long time for the supplier 
+      to send it an allocated buffer via a UseBuffer call. */
+  OMX_ErrorPortUnresponsiveDuringAllocation = (OMX_S32) 0x80001014,
+
+  /** A non-supplier port sends this error to the IL client (via the EventHandler callback) 
+      during the deallocation of buffers (on a transition from the IDLE to LOADED state or 
+      on a port stop) when it deems that it has waited an unusually long time for the supplier 
+      to request the deallocation of a buffer header via a FreeBuffer call. */
+  OMX_ErrorPortUnresponsiveDuringDeallocation = (OMX_S32) 0x80001015,
+
+  /** A supplier port sends this error to the IL client (via the EventHandler callback) 
+      during the stopping of a port (either on a transition from the IDLE to LOADED 
+      state or a port stop) when it deems that it has waited an unusually long time for 
+      the non-supplier to return a buffer via an EmptyThisBuffer or FillThisBuffer call. */
+  OMX_ErrorPortUnresponsiveDuringStop = (OMX_S32) 0x80001016,
+
+  /** Attempting a state transtion that is not allowed */
+  OMX_ErrorIncorrectStateTransition = (OMX_S32) 0x80001017,
+
+  /* Attempting a command that is not allowed during the present state. */
+  OMX_ErrorIncorrectStateOperation = (OMX_S32) 0x80001018, 
+
+  /** The values encapsulated in the parameter or config structure are not supported. */
+  OMX_ErrorUnsupportedSetting = (OMX_S32) 0x80001019,
+
+  /** The parameter or config indicated by the given index is not supported. */
+  OMX_ErrorUnsupportedIndex = (OMX_S32) 0x8000101A,
+
+  /** The port index supplied is incorrect. */
+  OMX_ErrorBadPortIndex = (OMX_S32) 0x8000101B,
+
+  /** The port has lost one or more of its buffers and it thus unpopulated. */
+  OMX_ErrorPortUnpopulated = (OMX_S32) 0x8000101C,
+
+  /** Component suspended due to temporary loss of resources */
+  OMX_ErrorComponentSuspended = (OMX_S32) 0x8000101D,
+
+  /** Component suspended due to an inability to acquire dynamic resources */
+  OMX_ErrorDynamicResourcesUnavailable = (OMX_S32) 0x8000101E,
+
+  /** When the macroblock error reporting is enabled the component returns new error 
+  for every frame that has errors */
+  OMX_ErrorMbErrorsInFrame = (OMX_S32) 0x8000101F,
+
+  /** A component reports this error when it cannot parse or determine the format of an input stream. */
+  OMX_ErrorFormatNotDetected = (OMX_S32) 0x80001020, 
+
+  /** The content open operation failed. */
+  OMX_ErrorContentPipeOpenFailed = (OMX_S32) 0x80001021,
+
+  /** The content creation operation failed. */
+  OMX_ErrorContentPipeCreationFailed = (OMX_S32) 0x80001022,
+
+  /** Separate table information is being used */
+  OMX_ErrorSeperateTablesUsed = (OMX_S32) 0x80001023,
+
+  /** Tunneling is unsupported by the component*/
+  OMX_ErrorTunnelingUnsupported = (OMX_S32) 0x80001024,
+
+  OMX_ErrorKhronosExtensions = (OMX_S32)0x8F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+  OMX_ErrorVendorStartUnused = (OMX_S32)0x90000000, /**< Reserved region for introducing Vendor Extensions */
+
+  /** Disk Full error */
+  OMX_ErrorDiskFull = (OMX_S32) 0x90000001,
+  /** Max file size is reached */
+  OMX_ErrorMaxFileSize = (OMX_S32) 0x90000002,
+
+  /** Unauthorised to play a DRM protected file */
+  OMX_ErrorDrmUnauthorised = (OMX_S32) 0x90000003,
+
+  /** The DRM protected file has expired */
+  OMX_ErrorDrmExpired = (OMX_S32) 0x90000004,
+
+  /** Some other DRM library error */
+  OMX_ErrorDrmGeneral = (OMX_S32) 0x90000005,
+
+  OMX_ErrorMax = 0x7FFFFFFF
+} OMX_ERRORTYPE;
+
+/** @ingroup core */
+typedef OMX_ERRORTYPE (* OMX_COMPONENTINITTYPE)(OMX_IN  OMX_HANDLETYPE hComponent);
+
+/** @ingroup core */
+typedef struct OMX_COMPONENTREGISTERTYPE
+{
+  const char          * pName;       /* Component name, 128 byte limit (including '\0') applies */
+  OMX_COMPONENTINITTYPE pInitialize; /* Component instance initialization function */
+} OMX_COMPONENTREGISTERTYPE;
+
+/** @ingroup core */
+extern OMX_COMPONENTREGISTERTYPE OMX_ComponentRegistered[];
+
+/** @ingroup rpm */
+typedef struct OMX_PRIORITYMGMTTYPE {
+ OMX_U32 nSize;             /**< size of the structure in bytes */
+ OMX_VERSIONTYPE nVersion;  /**< OMX specification version information */
+ OMX_U32 nGroupPriority;            /**< Priority of the component group */
+ OMX_U32 nGroupID;                  /**< ID of the component group */
+} OMX_PRIORITYMGMTTYPE;
+
+/* Component name and Role names are limited to 128 characters including the terminating '\0'. */
+#define OMX_MAX_STRINGNAME_SIZE 128
+
+/** @ingroup comp */
+typedef struct OMX_PARAM_COMPONENTROLETYPE {
+    OMX_U32 nSize;              /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;   /**< OMX specification version information */
+    OMX_U8 cRole[OMX_MAX_STRINGNAME_SIZE];  /**< name of standard component which defines component role */
+} OMX_PARAM_COMPONENTROLETYPE;
+
+/** End of Stream Buffer Flag: 
+  *
+  * A component sets EOS when it has no more data to emit on a particular 
+  * output port. Thus an output port shall set EOS on the last buffer it 
+  * emits. A component's determination of when an output port should 
+  * cease sending data is implemenation specific.
+  * @ingroup buf
+  */
+
+#define OMX_BUFFERFLAG_EOS 0x00000001 
+
+/** Start Time Buffer Flag: 
+ *
+ * The source of a stream (e.g. a demux component) sets the STARTTIME
+ * flag on the buffer that contains the starting timestamp for the
+ * stream. The starting timestamp corresponds to the first data that
+ * should be displayed at startup or after a seek.
+ * The first timestamp of the stream is not necessarily the start time.
+ * For instance, in the case of a seek to a particular video frame, 
+ * the target frame may be an interframe. Thus the first buffer of 
+ * the stream will be the intra-frame preceding the target frame and
+ * the starttime will occur with the target frame (with any other
+ * required frames required to reconstruct the target intervening).
+ *
+ * The STARTTIME flag is directly associated with the buffer's 
+ * timestamp ' thus its association to buffer data and its 
+ * propagation is identical to the timestamp's.
+ *
+ * When a Sync Component client receives a buffer with the 
+ * STARTTIME flag it shall perform a SetConfig on its sync port 
+ * using OMX_ConfigTimeClientStartTime and passing the buffer's
+ * timestamp.
+ * 
+ * @ingroup buf
+ */
+
+#define OMX_BUFFERFLAG_STARTTIME 0x00000002
+
+
+/** Decode Only Buffer Flag: 
+ *
+ * The source of a stream (e.g. a demux component) sets the DECODEONLY
+ * flag on any buffer that should shall be decoded but should not be
+ * displayed. This flag is used, for instance, when a source seeks to 
+ * a target interframe that requires the decode of frames preceding the 
+ * target to facilitate the target's reconstruction. In this case the 
+ * source would emit the frames preceding the target downstream 
+ * but mark them as decode only.
+ *
+ * The DECODEONLY is associated with buffer data and propagated in a 
+ * manner identical to the buffer timestamp.
+ *
+ * A component that renders data should ignore all buffers with 
+ * the DECODEONLY flag set.
+ * 
+ * @ingroup buf
+ */
+
+#define OMX_BUFFERFLAG_DECODEONLY 0x00000004
+
+
+/* Data Corrupt Flag: This flag is set when the IL client believes the data in the associated buffer is corrupt 
+ * @ingroup buf
+ */
+
+#define OMX_BUFFERFLAG_DATACORRUPT 0x00000008
+
+/* End of Frame: The buffer contains exactly one end of frame and no data
+ *  occurs after the end of frame. This flag is an optional hint. The absence
+ *  of this flag does not imply the absence of an end of frame within the buffer. 
+ * @ingroup buf
+*/
+#define OMX_BUFFERFLAG_ENDOFFRAME 0x00000010
+
+/* Sync Frame Flag: This flag is set when the buffer content contains a coded sync frame ' 
+ *  a frame that has no dependency on any other frame information 
+ *  @ingroup buf
+ */
+#define OMX_BUFFERFLAG_SYNCFRAME 0x00000020
+
+/* Extra data present flag: there is extra data appended to the data stream
+ * residing in the buffer 
+ * @ingroup buf  
+ */
+#define OMX_BUFFERFLAG_EXTRADATA 0x00000040
+
+/** Codec Config Buffer Flag: 
+* OMX_BUFFERFLAG_CODECCONFIG is an optional flag that is set by an
+* output port when all bytes in the buffer form part or all of a set of
+* codec specific configuration data.  Examples include SPS/PPS nal units
+* for OMX_VIDEO_CodingAVC or AudioSpecificConfig data for
+* OMX_AUDIO_CodingAAC.  Any component that for a given stream sets 
+* OMX_BUFFERFLAG_CODECCONFIG shall not mix codec configuration bytes
+* with frame data in the same buffer, and shall send all buffers
+* containing codec configuration bytes before any buffers containing
+* frame data that those configurations bytes describe.
+* If the stream format for a particular codec has a frame specific
+* header at the start of each frame, for example OMX_AUDIO_CodingMP3 or
+* OMX_AUDIO_CodingAAC in ADTS mode, then these shall be presented as
+* normal without setting OMX_BUFFERFLAG_CODECCONFIG.
+ * @ingroup buf
+ */
+#define OMX_BUFFERFLAG_CODECCONFIG 0x00000080
+
+
+
+/** @ingroup buf */
+typedef struct OMX_BUFFERHEADERTYPE
+{
+    OMX_U32 nSize;              /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;   /**< OMX specification version information */
+    OMX_U8* pBuffer;            /**< Pointer to actual block of memory 
+                                     that is acting as the buffer */
+    OMX_U32 nAllocLen;          /**< size of the buffer allocated, in bytes */
+    OMX_U32 nFilledLen;         /**< number of bytes currently in the 
+                                     buffer */
+    OMX_U32 nOffset;            /**< start offset of valid data in bytes from
+                                     the start of the buffer */
+    OMX_PTR pAppPrivate;        /**< pointer to any data the application
+                                     wants to associate with this buffer */
+    OMX_PTR pPlatformPrivate;   /**< pointer to any data the platform
+                                     wants to associate with this buffer */ 
+    OMX_PTR pInputPortPrivate;  /**< pointer to any data the input port
+                                     wants to associate with this buffer */
+    OMX_PTR pOutputPortPrivate; /**< pointer to any data the output port
+                                     wants to associate with this buffer */
+    OMX_HANDLETYPE hMarkTargetComponent; /**< The component that will generate a 
+                                              mark event upon processing this buffer. */
+    OMX_PTR pMarkData;          /**< Application specific data associated with 
+                                     the mark sent on a mark event to disambiguate 
+                                     this mark from others. */
+    OMX_U32 nTickCount;         /**< Optional entry that the component and
+                                     application can update with a tick count
+                                     when they access the component.  This
+                                     value should be in microseconds.  Since
+                                     this is a value relative to an arbitrary
+                                     starting point, this value cannot be used 
+                                     to determine absolute time.  This is an
+                                     optional entry and not all components
+                                     will update it.*/
+ OMX_TICKS nTimeStamp;          /**< Timestamp corresponding to the sample 
+                                     starting at the first logical sample 
+                                     boundary in the buffer. Timestamps of 
+                                     successive samples within the buffer may
+                                     be inferred by adding the duration of the 
+                                     of the preceding buffer to the timestamp
+                                     of the preceding buffer.*/
+  OMX_U32     nFlags;           /**< buffer specific flags */
+  OMX_U32 nOutputPortIndex;     /**< The index of the output port (if any) using 
+                                     this buffer */
+  OMX_U32 nInputPortIndex;      /**< The index of the input port (if any) using
+                                     this buffer */
+} OMX_BUFFERHEADERTYPE;
+
+/** The OMX_EXTRADATATYPE enumeration is used to define the 
+ * possible extra data payload types.
+ * NB: this enum is binary backwards compatible with the previous
+ * OMX_EXTRADATA_QUANT define.  This should be replaced with
+ * OMX_ExtraDataQuantization.
+ */
+typedef enum OMX_EXTRADATATYPE
+{
+   OMX_ExtraDataNone = 0,                       /**< Indicates that no more extra data sections follow */        
+   OMX_ExtraDataQuantization,                   /**< The data payload contains quantization data */
+   OMX_ExtraDataKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+   OMX_ExtraDataVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+
+   OMX_ExtraDataSequenceGap,                    /**< Indicates a gap in sequence numbers, data is uint32_t 
+                                                     saying how many frames were lost */
+   OMX_ExtraDataDecodeOnlyUntil,                /**< Indicates a timestamp until which all data should be
+                                                     decoded only, and the first packets after should generate
+                                                     a client start time flag.  data is int32_t of seek time
+                                                     in milliseconds */
+
+   OMX_ExtraDataMax = 0x7FFFFFFF
+} OMX_EXTRADATATYPE;
+
+
+typedef struct OMX_OTHER_EXTRADATATYPE  {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;               
+    OMX_U32 nPortIndex;
+    OMX_EXTRADATATYPE eType;       /* Extra Data type */
+    OMX_U32 nDataSize;   /* Size of the supporting data to follow */
+    OMX_U8  data[1];     /* Supporting data hint  */
+} OMX_OTHER_EXTRADATATYPE;
+
+/** @ingroup comp */
+typedef struct OMX_PORT_PARAM_TYPE {
+    OMX_U32 nSize;              /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;   /**< OMX specification version information */
+    OMX_U32 nPorts;             /**< The number of ports for this component */
+    OMX_U32 nStartPortNumber;   /** first port number for this type of port */
+} OMX_PORT_PARAM_TYPE; 
+
+/** @ingroup comp */
+typedef enum OMX_EVENTTYPE
+{
+    OMX_EventCmdComplete,         /**< component has sucessfully completed a command */
+    OMX_EventError,               /**< component has detected an error condition */
+    OMX_EventMark,                /**< component has detected a buffer mark */
+    OMX_EventPortSettingsChanged, /**< component is reported a port settings change */
+    OMX_EventBufferFlag,          /**< component has detected an EOS */ 
+    OMX_EventResourcesAcquired,   /**< component has been granted resources and is
+                                       automatically starting the state change from
+                                       OMX_StateWaitForResources to OMX_StateIdle. */
+   OMX_EventComponentResumed,     /**< Component resumed due to reacquisition of resources */
+   OMX_EventDynamicResourcesAvailable, /**< Component has acquired previously unavailable dynamic resources */
+   OMX_EventPortFormatDetected,      /**< Component has detected a supported format. */
+   OMX_EventKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+   OMX_EventVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+   OMX_EventParamOrConfigChanged,   /* Should be added to the main spec as part of IL416c */
+   OMX_EventMax = 0x7FFFFFFF
+} OMX_EVENTTYPE;
+
+typedef struct OMX_CALLBACKTYPE
+{
+    /** The EventHandler method is used to notify the application when an
+        event of interest occurs.  Events are defined in the OMX_EVENTTYPE
+        enumeration.  Please see that enumeration for details of what will
+        be returned for each type of event. Callbacks should not return
+        an error to the component, so if an error occurs, the application 
+        shall handle it internally.  This is a blocking call.
+
+        The application should return from this call within 5 msec to avoid
+        blocking the component for an excessively long period of time.
+
+        @param hComponent
+            handle of the component to access.  This is the component
+            handle returned by the call to the GetHandle function.
+        @param pAppData
+            pointer to an application defined value that was provided in the 
+            pAppData parameter to the OMX_GetHandle method for the component.
+            This application defined value is provided so that the application 
+            can have a component specific context when receiving the callback.
+        @param eEvent
+            Event that the component wants to notify the application about.
+        @param nData1
+            nData will be the OMX_ERRORTYPE for an error event and will be 
+            an OMX_COMMANDTYPE for a command complete event and OMX_INDEXTYPE for a OMX_PortSettingsChanged event.
+         @param nData2
+            nData2 will hold further information related to the event. Can be OMX_STATETYPE for
+            a OMX_CommandStateSet command or port index for a OMX_PortSettingsChanged event.
+            Default value is 0 if not used. )
+        @param pEventData
+            Pointer to additional event-specific data (see spec for meaning).
+      */
+
+   OMX_ERRORTYPE (*EventHandler)(
+        OMX_IN OMX_HANDLETYPE hComponent,
+        OMX_IN OMX_PTR pAppData,
+        OMX_IN OMX_EVENTTYPE eEvent,
+        OMX_IN OMX_U32 nData1,
+        OMX_IN OMX_U32 nData2,
+        OMX_IN OMX_PTR pEventData);
+
+    /** The EmptyBufferDone method is used to return emptied buffers from an
+        input port back to the application for reuse.  This is a blocking call 
+        so the application should not attempt to refill the buffers during this
+        call, but should queue them and refill them in another thread.  There
+        is no error return, so the application shall handle any errors generated
+        internally.  
+        
+        The application should return from this call within 5 msec.
+        
+        @param hComponent
+            handle of the component to access.  This is the component
+            handle returned by the call to the GetHandle function.
+        @param pAppData
+            pointer to an application defined value that was provided in the 
+            pAppData parameter to the OMX_GetHandle method for the component.
+            This application defined value is provided so that the application 
+            can have a component specific context when receiving the callback.
+        @param pBuffer
+            pointer to an OMX_BUFFERHEADERTYPE structure allocated with UseBuffer
+            or AllocateBuffer indicating the buffer that was emptied.
+        @ingroup buf
+     */
+    OMX_ERRORTYPE (*EmptyBufferDone)(
+        OMX_IN OMX_HANDLETYPE hComponent,
+        OMX_IN OMX_PTR pAppData,
+        OMX_IN OMX_BUFFERHEADERTYPE* pBuffer);
+
+    /** The FillBufferDone method is used to return filled buffers from an
+        output port back to the application for emptying and then reuse.  
+        This is a blocking call so the application should not attempt to 
+        empty the buffers during this call, but should queue the buffers 
+        and empty them in another thread.  There is no error return, so 
+        the application shall handle any errors generated internally.  The 
+        application shall also update the buffer header to indicate the
+        number of bytes placed into the buffer.  
+
+        The application should return from this call within 5 msec.
+        
+        @param hComponent
+            handle of the component to access.  This is the component
+            handle returned by the call to the GetHandle function.
+        @param pAppData
+            pointer to an application defined value that was provided in the 
+            pAppData parameter to the OMX_GetHandle method for the component.
+            This application defined value is provided so that the application 
+            can have a component specific context when receiving the callback.
+        @param pBuffer
+            pointer to an OMX_BUFFERHEADERTYPE structure allocated with UseBuffer
+            or AllocateBuffer indicating the buffer that was filled.
+        @ingroup buf
+     */
+    OMX_ERRORTYPE (*FillBufferDone)(
+        OMX_OUT OMX_HANDLETYPE hComponent,
+        OMX_OUT OMX_PTR pAppData,
+        OMX_OUT OMX_BUFFERHEADERTYPE* pBuffer);
+
+} OMX_CALLBACKTYPE;
+
+/** The OMX_BUFFERSUPPLIERTYPE enumeration is used to dictate port supplier
+    preference when tunneling between two ports.
+    @ingroup tun buf
+*/
+typedef enum OMX_BUFFERSUPPLIERTYPE
+{
+    OMX_BufferSupplyUnspecified = 0x0, /**< port supplying the buffers is unspecified,
+                                              or don't care */
+    OMX_BufferSupplyInput,             /**< input port supplies the buffers */
+    OMX_BufferSupplyOutput,            /**< output port supplies the buffers */
+    OMX_BufferSupplyKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_BufferSupplyVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_BufferSupplyMax = 0x7FFFFFFF
+} OMX_BUFFERSUPPLIERTYPE;
+
+
+/** buffer supplier parameter 
+ * @ingroup tun
+ */
+typedef struct OMX_PARAM_BUFFERSUPPLIERTYPE {
+    OMX_U32 nSize; /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
+    OMX_U32 nPortIndex; /**< port that this structure applies to */
+    OMX_BUFFERSUPPLIERTYPE eBufferSupplier; /**< buffer supplier */
+} OMX_PARAM_BUFFERSUPPLIERTYPE;
+
+
+/**< indicates that buffers received by an input port of a tunnel 
+     may not modify the data in the buffers 
+     @ingroup tun
+ */
+#define OMX_PORTTUNNELFLAG_READONLY 0x00000001 
+
+
+/** The OMX_TUNNELSETUPTYPE structure is used to pass data from an output
+    port to an input port as part the two ComponentTunnelRequest calls
+    resulting from a OMX_SetupTunnel call from the IL Client. 
+    @ingroup tun
+ */   
+typedef struct OMX_TUNNELSETUPTYPE
+{
+    OMX_U32 nTunnelFlags;             /**< bit flags for tunneling */
+    OMX_BUFFERSUPPLIERTYPE eSupplier; /**< supplier preference */
+} OMX_TUNNELSETUPTYPE; 
+
+/* OMX Component headers is included to enable the core to use
+   macros for functions into the component for OMX release 1.0.  
+   Developers should not access any structures or data from within
+   the component header directly */
+/* TO BE REMOVED - #include <OMX_Component.h> */
+
+/** GetComponentVersion will return information about the component.  
+    This is a blocking call.  This macro will go directly from the
+    application to the component (via a core macro).  The
+    component will return from this call within 5 msec.
+    @param [in] hComponent
+        handle of component to execute the command
+    @param [out] pComponentName
+        pointer to an empty string of length 128 bytes.  The component 
+        will write its name into this string.  The name will be 
+        terminated by a single zero byte.  The name of a component will 
+        be 127 bytes or less to leave room for the trailing zero byte.  
+        An example of a valid component name is "OMX.ABC.ChannelMixer\0".
+    @param [out] pComponentVersion
+        pointer to an OMX Version structure that the component will fill 
+        in.  The component will fill in a value that indicates the 
+        component version.  NOTE: the component version is NOT the same 
+        as the OMX Specification version (found in all structures).  The 
+        component version is defined by the vendor of the component and 
+        its value is entirely up to the component vendor.
+    @param [out] pSpecVersion
+        pointer to an OMX Version structure that the component will fill 
+        in.  The SpecVersion is the version of the specification that the 
+        component was built against.  Please note that this value may or 
+        may not match the structure's version.  For example, if the 
+        component was built against the 2.0 specification, but the 
+        application (which creates the structure is built against the 
+        1.0 specification the versions would be different.
+    @param [out] pComponentUUID
+        pointer to the UUID of the component which will be filled in by 
+        the component.  The UUID is a unique identifier that is set at 
+        RUN time for the component and is unique to each instantion of 
+        the component.
+    @return OMX_ERRORTYPE
+        If the command successfully executes, the return code will be
+        OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
+    @ingroup comp
+ */
+#define OMX_GetComponentVersion(                            \
+        hComponent,                                         \
+        pComponentName,                                     \
+        pComponentVersion,                                  \
+        pSpecVersion,                                       \
+        pComponentUUID)                                     \
+    ((OMX_COMPONENTTYPE*)hComponent)->GetComponentVersion(  \
+        hComponent,                                         \
+        pComponentName,                                     \
+        pComponentVersion,                                  \
+        pSpecVersion,                                       \
+        pComponentUUID)                 /* Macro End */
+
+
+/** Send a command to the component.  This call is a non-blocking call.
+    The component should check the parameters and then queue the command
+    to the component thread to be executed.  The component thread shall 
+    send the EventHandler() callback at the conclusion of the command. 
+    This macro will go directly from the application to the component (via
+    a core macro).  The component will return from this call within 5 msec.
+    
+    When the command is "OMX_CommandStateSet" the component will queue a
+    state transition to the new state idenfied in nParam.
+    
+    When the command is "OMX_CommandFlush", to flush a port's buffer queues,
+    the command will force the component to return all buffers NOT CURRENTLY 
+    BEING PROCESSED to the application, in the order in which the buffers 
+    were received.
+    
+    When the command is "OMX_CommandPortDisable" or 
+    "OMX_CommandPortEnable", the component's port (given by the value of
+    nParam) will be stopped or restarted. 
+    
+    When the command "OMX_CommandMarkBuffer" is used to mark a buffer, the
+    pCmdData will point to a OMX_MARKTYPE structure containing the component
+    handle of the component to examine the buffer chain for the mark.  nParam1
+    contains the index of the port on which the buffer mark is applied.
+
+    Specification text for more details. 
+    
+    @param [in] hComponent
+        handle of component to execute the command
+    @param [in] Cmd
+        Command for the component to execute
+    @param [in] nParam
+        Parameter for the command to be executed.  When Cmd has the value 
+        OMX_CommandStateSet, value is a member of OMX_STATETYPE.  When Cmd has 
+        the value OMX_CommandFlush, value of nParam indicates which port(s) 
+        to flush. -1 is used to flush all ports a single port index will 
+        only flush that port.  When Cmd has the value "OMX_CommandPortDisable"
+        or "OMX_CommandPortEnable", the component's port is given by 
+        the value of nParam.  When Cmd has the value "OMX_CommandMarkBuffer"
+        the components pot is given by the value of nParam.
+    @param [in] pCmdData
+        Parameter pointing to the OMX_MARKTYPE structure when Cmd has the value
+        "OMX_CommandMarkBuffer".     
+    @return OMX_ERRORTYPE
+        If the command successfully executes, the return code will be
+        OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
+    @ingroup comp
+ */
+#define OMX_SendCommand(                                    \
+         hComponent,                                        \
+         Cmd,                                               \
+         nParam,                                            \
+         pCmdData)                                          \
+     ((OMX_COMPONENTTYPE*)hComponent)->SendCommand(         \
+         hComponent,                                        \
+         Cmd,                                               \
+         nParam,                                            \
+         pCmdData)                          /* Macro End */
+
+
+/** The OMX_GetParameter macro will get one of the current parameter 
+    settings from the component.  This macro cannot only be invoked when 
+    the component is in the OMX_StateInvalid state.  The nParamIndex
+    parameter is used to indicate which structure is being requested from
+    the component.  The application shall allocate the correct structure 
+    and shall fill in the structure size and version information before 
+    invoking this macro.  When the parameter applies to a port, the
+    caller shall fill in the appropriate nPortIndex value indicating the
+    port on which the parameter applies. If the component has not had 
+    any settings changed, then the component should return a set of 
+    valid DEFAULT  parameters for the component.  This is a blocking 
+    call.  
+    
+    The component should return from this call within 20 msec.
+    
+    @param [in] hComponent
+        Handle of the component to be accessed.  This is the component
+        handle returned by the call to the OMX_GetHandle function.
+    @param [in] nParamIndex
+        Index of the structure to be filled.  This value is from the
+        OMX_INDEXTYPE enumeration.
+    @param [in,out] pComponentParameterStructure
+        Pointer to application allocated structure to be filled by the 
+        component.
+    @return OMX_ERRORTYPE
+        If the command successfully executes, the return code will be
+        OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
+    @ingroup comp
+ */
+#define OMX_GetParameter(                                   \
+        hComponent,                                         \
+        nParamIndex,                                        \
+        pComponentParameterStructure)                        \
+    ((OMX_COMPONENTTYPE*)hComponent)->GetParameter(         \
+        hComponent,                                         \
+        nParamIndex,                                        \
+        pComponentParameterStructure)    /* Macro End */
+
+
+/** The OMX_SetParameter macro will send an initialization parameter
+    structure to a component.  Each structure shall be sent one at a time,
+    in a separate invocation of the macro.  This macro can only be
+    invoked when the component is in the OMX_StateLoaded state, or the
+    port is disabled (when the parameter applies to a port). The 
+    nParamIndex parameter is used to indicate which structure is being
+    passed to the component.  The application shall allocate the 
+    correct structure and shall fill in the structure size and version 
+    information (as well as the actual data) before invoking this macro.
+    The application is free to dispose of this structure after the call
+    as the component is required to copy any data it shall retain.  This 
+    is a blocking call.  
+    
+    The component should return from this call within 20 msec.
+    
+    @param [in] hComponent
+        Handle of the component to be accessed.  This is the component
+        handle returned by the call to the OMX_GetHandle function.
+    @param [in] nIndex
+        Index of the structure to be sent.  This value is from the
+        OMX_INDEXTYPE enumeration.
+    @param [in] pComponentParameterStructure
+        pointer to application allocated structure to be used for
+        initialization by the component.
+    @return OMX_ERRORTYPE
+        If the command successfully executes, the return code will be
+        OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
+    @ingroup comp
+ */
+#define OMX_SetParameter(                                   \
+        hComponent,                                         \
+        nParamIndex,                                        \
+        pComponentParameterStructure)                        \
+    ((OMX_COMPONENTTYPE*)hComponent)->SetParameter(         \
+        hComponent,                                         \
+        nParamIndex,                                        \
+        pComponentParameterStructure)    /* Macro End */
+
+
+/** The OMX_GetConfig macro will get one of the configuration structures 
+    from a component.  This macro can be invoked anytime after the 
+    component has been loaded.  The nParamIndex call parameter is used to 
+    indicate which structure is being requested from the component.  The 
+    application shall allocate the correct structure and shall fill in the 
+    structure size and version information before invoking this macro.  
+    If the component has not had this configuration parameter sent before, 
+    then the component should return a set of valid DEFAULT values for the 
+    component.  This is a blocking call.  
+    
+    The component should return from this call within 5 msec.
+    
+    @param [in] hComponent
+        Handle of the component to be accessed.  This is the component
+        handle returned by the call to the OMX_GetHandle function.
+    @param [in] nIndex
+        Index of the structure to be filled.  This value is from the
+        OMX_INDEXTYPE enumeration.
+    @param [in,out] pComponentConfigStructure
+        pointer to application allocated structure to be filled by the 
+        component.
+    @return OMX_ERRORTYPE
+        If the command successfully executes, the return code will be
+        OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
+    @ingroup comp
+*/        
+#define OMX_GetConfig(                                      \
+        hComponent,                                         \
+        nConfigIndex,                                       \
+        pComponentConfigStructure)                           \
+    ((OMX_COMPONENTTYPE*)hComponent)->GetConfig(            \
+        hComponent,                                         \
+        nConfigIndex,                                       \
+        pComponentConfigStructure)       /* Macro End */
+
+
+/** The OMX_SetConfig macro will send one of the configuration 
+    structures to a component.  Each structure shall be sent one at a time,
+    each in a separate invocation of the macro.  This macro can be invoked 
+    anytime after the component has been loaded.  The application shall 
+    allocate the correct structure and shall fill in the structure size 
+    and version information (as well as the actual data) before invoking 
+    this macro.  The application is free to dispose of this structure after 
+    the call as the component is required to copy any data it shall retain.  
+    This is a blocking call.  
+    
+    The component should return from this call within 5 msec.
+    
+    @param [in] hComponent
+        Handle of the component to be accessed.  This is the component
+        handle returned by the call to the OMX_GetHandle function.
+    @param [in] nConfigIndex
+        Index of the structure to be sent.  This value is from the
+        OMX_INDEXTYPE enumeration above.
+    @param [in] pComponentConfigStructure
+        pointer to application allocated structure to be used for
+        initialization by the component.
+    @return OMX_ERRORTYPE
+        If the command successfully executes, the return code will be
+        OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
+    @ingroup comp
+ */
+#define OMX_SetConfig(                                      \
+        hComponent,                                         \
+        nConfigIndex,                                       \
+        pComponentConfigStructure)                           \
+    ((OMX_COMPONENTTYPE*)hComponent)->SetConfig(            \
+        hComponent,                                         \
+        nConfigIndex,                                       \
+        pComponentConfigStructure)       /* Macro End */
+
+
+/** The OMX_GetExtensionIndex macro will invoke a component to translate 
+    a vendor specific configuration or parameter string into an OMX 
+    structure index.  There is no requirement for the vendor to support 
+    this command for the indexes already found in the OMX_INDEXTYPE 
+    enumeration (this is done to save space in small components).  The 
+    component shall support all vendor supplied extension indexes not found
+    in the master OMX_INDEXTYPE enumeration.  This is a blocking call.  
+    
+    The component should return from this call within 5 msec.
+    
+    @param [in] hComponent
+        Handle of the component to be accessed.  This is the component
+        handle returned by the call to the GetHandle function.
+    @param [in] cParameterName
+        OMX_STRING that shall be less than 128 characters long including
+        the trailing null byte.  This is the string that will get 
+        translated by the component into a configuration index.
+    @param [out] pIndexType
+        a pointer to a OMX_INDEXTYPE to receive the index value.
+    @return OMX_ERRORTYPE
+        If the command successfully executes, the return code will be
+        OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
+    @ingroup comp
+ */
+#define OMX_GetExtensionIndex(                              \
+        hComponent,                                         \
+        cParameterName,                                     \
+        pIndexType)                                         \
+    ((OMX_COMPONENTTYPE*)hComponent)->GetExtensionIndex(    \
+        hComponent,                                         \
+        cParameterName,                                     \
+        pIndexType)                     /* Macro End */
+
+
+/** The OMX_GetState macro will invoke the component to get the current 
+    state of the component and place the state value into the location
+    pointed to by pState.  
+    
+    The component should return from this call within 5 msec.
+    
+    @param [in] hComponent
+        Handle of the component to be accessed.  This is the component
+        handle returned by the call to the OMX_GetHandle function.
+    @param [out] pState
+        pointer to the location to receive the state.  The value returned
+        is one of the OMX_STATETYPE members 
+    @return OMX_ERRORTYPE
+        If the command successfully executes, the return code will be
+        OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
+    @ingroup comp
+ */
+#define OMX_GetState(                                       \
+        hComponent,                                         \
+        pState)                                             \
+    ((OMX_COMPONENTTYPE*)hComponent)->GetState(             \
+        hComponent,                                         \
+        pState)                         /* Macro End */
+
+
+/** The OMX_UseBuffer macro will request that the component use
+    a buffer (and allocate its own buffer header) already allocated 
+    by another component, or by the IL Client. This is a blocking 
+    call.
+    
+    The component should return from this call within 20 msec.
+    
+    @param [in] hComponent
+        Handle of the component to be accessed.  This is the component
+        handle returned by the call to the OMX_GetHandle function.
+    @param [out] ppBuffer
+        pointer to an OMX_BUFFERHEADERTYPE structure used to receive the 
+        pointer to the buffer header
+    @return OMX_ERRORTYPE
+        If the command successfully executes, the return code will be
+        OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
+    @ingroup comp buf
+ */
+
+#define OMX_UseBuffer(                                      \
+           hComponent,                                      \
+           ppBufferHdr,                                     \
+           nPortIndex,                                      \
+           pAppPrivate,                                     \
+           nSizeBytes,                                      \
+           pBuffer)                                         \
+    ((OMX_COMPONENTTYPE*)hComponent)->UseBuffer(            \
+           hComponent,                                      \
+           ppBufferHdr,                                     \
+           nPortIndex,                                      \
+           pAppPrivate,                                     \
+           nSizeBytes,                                      \
+           pBuffer)
+
+
+/** The OMX_AllocateBuffer macro will request that the component allocate 
+    a new buffer and buffer header.  The component will allocate the 
+    buffer and the buffer header and return a pointer to the buffer 
+    header.  This is a blocking call.
+    
+    The component should return from this call within 5 msec.
+    
+    @param [in] hComponent
+        Handle of the component to be accessed.  This is the component
+        handle returned by the call to the OMX_GetHandle function.
+    @param [out] ppBuffer
+        pointer to an OMX_BUFFERHEADERTYPE structure used to receive 
+        the pointer to the buffer header
+    @param [in] nPortIndex
+        nPortIndex is used to select the port on the component the buffer will
+        be used with.  The port can be found by using the nPortIndex
+        value as an index into the Port Definition array of the component.
+    @param [in] pAppPrivate
+        pAppPrivate is used to initialize the pAppPrivate member of the 
+        buffer header structure.
+    @param [in] nSizeBytes
+        size of the buffer to allocate.  Used when bAllocateNew is true.
+    @return OMX_ERRORTYPE
+        If the command successfully executes, the return code will be
+        OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
+    @ingroup comp buf
+ */    
+#define OMX_AllocateBuffer(                                 \
+        hComponent,                                         \
+        ppBuffer,                                           \
+        nPortIndex,                                         \
+        pAppPrivate,                                        \
+        nSizeBytes)                                         \
+    ((OMX_COMPONENTTYPE*)hComponent)->AllocateBuffer(       \
+        hComponent,                                         \
+        ppBuffer,                                           \
+        nPortIndex,                                         \
+        pAppPrivate,                                        \
+        nSizeBytes)                     /* Macro End */
+
+
+/** The OMX_FreeBuffer macro will release a buffer header from the component
+    which was allocated using either OMX_AllocateBuffer or OMX_UseBuffer. If  
+    the component allocated the buffer (see the OMX_UseBuffer macro) then 
+    the component shall free the buffer and buffer header. This is a 
+    blocking call. 
+    
+    The component should return from this call within 20 msec.
+    
+    @param [in] hComponent
+        Handle of the component to be accessed.  This is the component
+        handle returned by the call to the OMX_GetHandle function.
+    @param [in] nPortIndex
+        nPortIndex is used to select the port on the component the buffer will
+        be used with.
+    @param [in] pBuffer
+        pointer to an OMX_BUFFERHEADERTYPE structure allocated with UseBuffer
+        or AllocateBuffer.
+    @return OMX_ERRORTYPE
+        If the command successfully executes, the return code will be
+        OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
+    @ingroup comp buf
+ */
+#define OMX_FreeBuffer(                                     \
+        hComponent,                                         \
+        nPortIndex,                                         \
+        pBuffer)                                            \
+    ((OMX_COMPONENTTYPE*)hComponent)->FreeBuffer(           \
+        hComponent,                                         \
+        nPortIndex,                                         \
+        pBuffer)                        /* Macro End */
+
+
+/** The OMX_EmptyThisBuffer macro will send a buffer full of data to an 
+    input port of a component.  The buffer will be emptied by the component
+    and returned to the application via the EmptyBufferDone call back.
+    This is a non-blocking call in that the component will record the buffer
+    and return immediately and then empty the buffer, later, at the proper 
+    time.  As expected, this macro may be invoked only while the component 
+    is in the OMX_StateExecuting.  If nPortIndex does not specify an input
+    port, the component shall return an error.  
+    
+    The component should return from this call within 5 msec.
+    
+    @param [in] hComponent
+        Handle of the component to be accessed.  This is the component
+        handle returned by the call to the OMX_GetHandle function.
+    @param [in] pBuffer
+        pointer to an OMX_BUFFERHEADERTYPE structure allocated with UseBuffer
+        or AllocateBuffer.
+    @return OMX_ERRORTYPE
+        If the command successfully executes, the return code will be
+        OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
+    @ingroup comp buf
+ */
+#define OMX_EmptyThisBuffer(                                \
+        hComponent,                                         \
+        pBuffer)                                            \
+    ((OMX_COMPONENTTYPE*)hComponent)->EmptyThisBuffer(      \
+        hComponent,                                         \
+        pBuffer)                        /* Macro End */
+
+
+/** The OMX_FillThisBuffer macro will send an empty buffer to an 
+    output port of a component.  The buffer will be filled by the component
+    and returned to the application via the FillBufferDone call back.
+    This is a non-blocking call in that the component will record the buffer
+    and return immediately and then fill the buffer, later, at the proper 
+    time.  As expected, this macro may be invoked only while the component 
+    is in the OMX_ExecutingState.  If nPortIndex does not specify an output
+    port, the component shall return an error.  
+    
+    The component should return from this call within 5 msec.
+    
+    @param [in] hComponent
+        Handle of the component to be accessed.  This is the component
+        handle returned by the call to the OMX_GetHandle function.
+    @param [in] pBuffer
+        pointer to an OMX_BUFFERHEADERTYPE structure allocated with UseBuffer
+        or AllocateBuffer.
+    @return OMX_ERRORTYPE
+        If the command successfully executes, the return code will be
+        OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
+    @ingroup comp buf
+ */
+#define OMX_FillThisBuffer(                                 \
+        hComponent,                                         \
+        pBuffer)                                            \
+    ((OMX_COMPONENTTYPE*)hComponent)->FillThisBuffer(       \
+        hComponent,                                         \
+        pBuffer)                        /* Macro End */
+
+
+
+/** The OMX_UseEGLImage macro will request that the component use
+    a EGLImage provided by EGL (and allocate its own buffer header)
+    This is a blocking call.
+    
+    The component should return from this call within 20 msec.
+    
+    @param [in] hComponent
+        Handle of the component to be accessed.  This is the component
+        handle returned by the call to the OMX_GetHandle function.
+    @param [out] ppBuffer
+        pointer to an OMX_BUFFERHEADERTYPE structure used to receive the 
+        pointer to the buffer header.  Note that the memory location used
+        for this buffer is NOT visible to the IL Client.
+    @param [in] nPortIndex
+        nPortIndex is used to select the port on the component the buffer will
+        be used with.  The port can be found by using the nPortIndex
+        value as an index into the Port Definition array of the component.
+    @param [in] pAppPrivate
+        pAppPrivate is used to initialize the pAppPrivate member of the 
+        buffer header structure.
+    @param [in] eglImage
+        eglImage contains the handle of the EGLImage to use as a buffer on the
+        specified port.  The component is expected to validate properties of 
+        the EGLImage against the configuration of the port to ensure the component
+        can use the EGLImage as a buffer.          
+    @return OMX_ERRORTYPE
+        If the command successfully executes, the return code will be
+        OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
+    @ingroup comp buf
+ */
+#define OMX_UseEGLImage(                                    \
+           hComponent,                                      \
+           ppBufferHdr,                                     \
+           nPortIndex,                                      \
+           pAppPrivate,                                     \
+           eglImage)                                        \
+    ((OMX_COMPONENTTYPE*)hComponent)->UseEGLImage(          \
+           hComponent,                                      \
+           ppBufferHdr,                                     \
+           nPortIndex,                                      \
+           pAppPrivate,                                     \
+           eglImage)
+
+/** The OMX_Init method is used to initialize the OMX core.  It shall be the
+    first call made into OMX and it should only be executed one time without
+    an interviening OMX_Deinit call.  
+    
+    The core should return from this call within 20 msec.
+
+    @return OMX_ERRORTYPE
+        If the command successfully executes, the return code will be
+        OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
+    @ingroup core
+ */
+OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_Init(void);
+
+
+/** The OMX_Deinit method is used to deinitialize the OMX core.  It shall be 
+    the last call made into OMX. In the event that the core determines that 
+    thare are components loaded when this call is made, the core may return 
+    with an error rather than try to unload the components.
+        
+    The core should return from this call within 20 msec.
+    
+    @return OMX_ERRORTYPE
+        If the command successfully executes, the return code will be
+        OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
+    @ingroup core
+ */
+OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_Deinit(void);
+
+
+/** The OMX_ComponentNameEnum method will enumerate through all the names of
+    recognised valid components in the system. This function is provided
+    as a means to detect all the components in the system run-time. There is
+    no strict ordering to the enumeration order of component names, although
+    each name will only be enumerated once.  If the OMX core supports run-time
+    installation of new components, it is only requried to detect newly
+    installed components when the first call to enumerate component names
+    is made (i.e. when nIndex is 0x0).
+    
+    The core should return from this call in 20 msec.
+    
+    @param [out] cComponentName
+        pointer to a null terminated string with the component name.  The
+        names of the components are strings less than 127 bytes in length
+        plus the trailing null for a maximum size of 128 bytes.  An example 
+        of a valid component name is "OMX.TI.AUDIO.DSP.MIXER\0".  Names are 
+        assigned by the vendor, but shall start with "OMX." and then have 
+        the Vendor designation next.
+    @param [in] nNameLength
+        number of characters in the cComponentName string.  With all 
+        component name strings restricted to less than 128 characters 
+        (including the trailing null) it is recomended that the caller
+        provide a input string for the cComponentName of 128 characters.
+    @param [in] nIndex
+        number containing the enumeration index for the component. 
+        Multiple calls to OMX_ComponentNameEnum with increasing values
+        of nIndex will enumerate through the component names in the
+        system until OMX_ErrorNoMore is returned.  The value of nIndex
+        is 0 to (N-1), where N is the number of valid installed components
+        in the system.
+    @return OMX_ERRORTYPE
+        If the command successfully executes, the return code will be
+        OMX_ErrorNone.  When the value of nIndex exceeds the number of 
+        components in the system minus 1, OMX_ErrorNoMore will be
+        returned. Otherwise the appropriate OMX error will be returned.
+    @ingroup core
+ */
+OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_ComponentNameEnum(
+    OMX_OUT OMX_STRING cComponentName,
+    OMX_IN  OMX_U32 nNameLength,
+    OMX_IN  OMX_U32 nIndex);
+
+
+/** The OMX_GetHandle method will locate the component specified by the
+    component name given, load that component into memory and then invoke
+    the component's methods to create an instance of the component.  
+    
+    The core should return from this call within 20 msec.
+    
+    @param [out] pHandle
+        pointer to an OMX_HANDLETYPE pointer to be filled in by this method.
+    @param [in] cComponentName
+        pointer to a null terminated string with the component name.  The
+        names of the components are strings less than 127 bytes in length
+        plus the trailing null for a maximum size of 128 bytes.  An example 
+        of a valid component name is "OMX.TI.AUDIO.DSP.MIXER\0".  Names are 
+        assigned by the vendor, but shall start with "OMX." and then have 
+        the Vendor designation next.
+    @param [in] pAppData
+        pointer to an application defined value that will be returned
+        during callbacks so that the application can identify the source
+        of the callback.
+    @param [in] pCallBacks
+        pointer to a OMX_CALLBACKTYPE structure that will be passed to the
+        component to initialize it with.  
+    @return OMX_ERRORTYPE
+        If the command successfully executes, the return code will be
+        OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
+    @ingroup core
+ */
+OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_GetHandle(
+    OMX_OUT OMX_HANDLETYPE* pHandle, 
+    OMX_IN  OMX_STRING cComponentName,
+    OMX_IN  OMX_PTR pAppData,
+    OMX_IN  OMX_CALLBACKTYPE* pCallBacks);
+
+
+/** The OMX_FreeHandle method will free a handle allocated by the OMX_GetHandle 
+    method.  If the component reference count goes to zero, the component will
+    be unloaded from memory.  
+    
+    The core should return from this call within 20 msec when the component is 
+    in the OMX_StateLoaded state.
+
+    @param [in] hComponent
+        Handle of the component to be accessed.  This is the component
+        handle returned by the call to the GetHandle function.
+    @return OMX_ERRORTYPE
+        If the command successfully executes, the return code will be
+        OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
+    @ingroup core
+ */
+OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_FreeHandle(
+    OMX_IN  OMX_HANDLETYPE hComponent);
+
+
+
+/** The OMX_SetupTunnel method will handle the necessary calls to the components
+    to setup the specified tunnel the two components.  NOTE: This is
+    an actual method (not a #define macro).  This method will make calls into
+    the component ComponentTunnelRequest method to do the actual tunnel 
+    connection.  
+
+    The ComponentTunnelRequest method on both components will be called. 
+    This method shall not be called unless the component is in the 
+    OMX_StateLoaded state except when the ports used for the tunnel are
+    disabled. In this case, the component may be in the OMX_StateExecuting,
+    OMX_StatePause, or OMX_StateIdle states. 
+
+    The core should return from this call within 20 msec.
+    
+    @param [in] hOutput
+        Handle of the component to be accessed.  Also this is the handle
+        of the component whose port, specified in the nPortOutput parameter
+        will be used the source for the tunnel. This is the component handle
+        returned by the call to the OMX_GetHandle function.  There is a 
+        requirement that hOutput be the source for the data when
+        tunelling (i.e. nPortOutput is an output port).  If 0x0, the component
+        specified in hInput will have it's port specified in nPortInput
+        setup for communication with the application / IL client.
+    @param [in] nPortOutput
+        nPortOutput is used to select the source port on component to be
+        used in the tunnel. 
+    @param [in] hInput
+        This is the component to setup the tunnel with. This is the handle
+        of the component whose port, specified in the nPortInput parameter
+        will be used the destination for the tunnel. This is the component handle
+        returned by the call to the OMX_GetHandle function.  There is a 
+        requirement that hInput be the destination for the data when
+        tunelling (i.e. nPortInut is an input port).   If 0x0, the component
+        specified in hOutput will have it's port specified in nPortPOutput
+        setup for communication with the application / IL client.
+    @param [in] nPortInput
+        nPortInput is used to select the destination port on component to be
+        used in the tunnel.
+    @return OMX_ERRORTYPE
+        If the command successfully executes, the return code will be
+        OMX_ErrorNone.  Otherwise the appropriate OMX error will be returned.
+        When OMX_ErrorNotImplemented is returned, one or both components is 
+        a non-interop component and does not support tunneling.
+        
+        On failure, the ports of both components are setup for communication
+        with the application / IL Client.
+    @ingroup core tun
+ */
+OMX_API OMX_ERRORTYPE OMX_APIENTRY OMX_SetupTunnel(
+    OMX_IN  OMX_HANDLETYPE hOutput,
+    OMX_IN  OMX_U32 nPortOutput,
+    OMX_IN  OMX_HANDLETYPE hInput,
+    OMX_IN  OMX_U32 nPortInput);
+    
+/** @ingroup cp */
+OMX_API OMX_ERRORTYPE   OMX_GetContentPipe(
+    OMX_OUT OMX_HANDLETYPE *hPipe,
+    OMX_IN OMX_STRING szURI);
+
+/** The OMX_GetComponentsOfRole method will return the number of components that support the given
+    role and (if the compNames field is non-NULL) the names of those components. The call will fail if 
+    an insufficiently sized array of names is supplied. To ensure the array is sufficiently sized the
+    client should:
+        * first call this function with the compNames field NULL to determine the number of component names
+        * second call this function with the compNames field pointing to an array of names allocated 
+          according to the number returned by the first call.
+
+    The core should return from this call within 5 msec.
+    
+    @param [in] role
+        This is generic standard component name consisting only of component class 
+        name and the type within that class (e.g. 'audio_decoder.aac').
+    @param [inout] pNumComps
+        This is used both as input and output. 
+        If compNames is NULL, the input is ignored and the output specifies how many components support
+        the given role.
+     
+        If compNames is not NULL, on input it bounds the size of the input structure and 
+        on output, it specifies the number of components string names listed within the compNames parameter.
+    @param [inout] compNames
+        If NULL this field is ignored. If non-NULL this points to an array of 128-byte strings which accepts 
+        a list of the names of all physical components that implement the specified standard component name. 
+        Each name is NULL terminated. numComps indicates the number of names.
+    @ingroup core
+ */
+OMX_API OMX_ERRORTYPE OMX_GetComponentsOfRole ( 
+       OMX_IN      OMX_STRING role,
+    OMX_INOUT   OMX_U32 *pNumComps,
+    OMX_INOUT   OMX_U8  **compNames);
+
+/** The OMX_GetRolesOfComponent method will return the number of roles supported by the given
+    component and (if the roles field is non-NULL) the names of those roles. The call will fail if 
+    an insufficiently sized array of names is supplied. To ensure the array is sufficiently sized the
+    client should:
+        * first call this function with the roles field NULL to determine the number of role names
+        * second call this function with the roles field pointing to an array of names allocated 
+          according to the number returned by the first call.
+
+    The core should return from this call within 5 msec.
+
+    @param [in] compName
+        This is the name of the component being queried about.
+    @param [inout] pNumRoles
+        This is used both as input and output. 
+        If roles is NULL, the input is ignored and the output specifies how many roles the component supports.
+     
+        If compNames is not NULL, on input it bounds the size of the input structure and 
+        on output, it specifies the number of roles string names listed within the roles parameter.
+    @param [out] roles
+        If NULL this field is ignored. If non-NULL this points to an array of 128-byte strings 
+        which accepts a list of the names of all standard components roles implemented on the 
+        specified component name. numComps indicates the number of names.
+    @ingroup core
+ */
+OMX_API OMX_ERRORTYPE OMX_GetRolesOfComponent ( 
+       OMX_IN      OMX_STRING compName, 
+    OMX_INOUT   OMX_U32 *pNumRoles,
+    OMX_OUT     OMX_U8 **roles);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
+/* File EOF */
+
diff --git a/interface/vmcs_host/khronos/IL/OMX_ILCS.h b/interface/vmcs_host/khronos/IL/OMX_ILCS.h
new file mode 100755 (executable)
index 0000000..434b471
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// OpenMAX IL - ILCS specific types
+
+#ifndef OMX_ILCS_h
+#define OMX_ILCS_h
+
+typedef struct OMX_PARAM_PORTSUMMARYTYPE {
+   OMX_U32 nSize;            /**< Size of the structure in bytes */
+   OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
+   OMX_U32 nNumPorts;        /**< Total number of ports */
+   OMX_U32 reqSet;           /**< Which set of ports is details below, portIndex[0] is port reqSet*32 */
+   OMX_U32 portDir;          /**< Bitfield, 1 if output port, 0 if input port, max 256 ports */
+   OMX_U32 portIndex[32];    /**< Port Indexes */
+} OMX_PARAM_PORTSUMMARYTYPE;
+
+typedef struct OMX_PARAM_MARKCOMPARISONTYPE {
+   OMX_U32 nSize;            /**< Size of the structure in bytes */
+   OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
+   OMX_PTR mark;             /**< Pointer to be used for mark comparisons */
+} OMX_PARAM_MARKCOMPARISONTYPE;
+
+typedef struct OMX_PARAM_BRCMRECURSIONUNSAFETYPE {
+   OMX_U32 nSize;
+   OMX_VERSIONTYPE nVersion;
+   OMX_S32 (*pRecursionUnsafe)(OMX_PTR param);
+   OMX_PTR param;
+} OMX_PARAM_BRCMRECURSIONUNSAFETYPE;
+
+typedef struct OMX_PARAM_TUNNELSTATUSTYPE {
+   OMX_U32 nSize;            /**< Size of the structure in bytes */
+   OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
+   OMX_U32 nPortIndex;       /**< Port being queried */
+   OMX_U32 nIndex;           /**< Query the nIndex'th port and fill in nPortIndex */
+   OMX_BOOL bUseIndex;       /**< If OMX_TRUE read nIndex, otherwise read nPortIndex */
+   OMX_PTR hTunneledComponent; /**< Component currently tunnelling with */
+   OMX_U32 nTunneledPort;    /**< Port on tunnelled component */
+} OMX_PARAM_TUNNELSTATUSTYPE;
+
+#endif
diff --git a/interface/vmcs_host/khronos/IL/OMX_IVCommon.h b/interface/vmcs_host/khronos/IL/OMX_IVCommon.h
new file mode 100755 (executable)
index 0000000..71c9eaa
--- /dev/null
@@ -0,0 +1,1107 @@
+/**
+ * Copyright (c) 2008 The Khronos Group Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/**
+ * @file OMX_IVCommon.h - OpenMax IL version 1.1.2
+ *  The structures needed by Video and Image components to exchange
+ *  parameters and configuration data with the components.
+ */
+#ifndef OMX_IVCommon_h
+#define OMX_IVCommon_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * Each OMX header must include all required header files to allow the header
+ * to compile without errors.  The includes below are required for this header
+ * file to compile successfully
+ */
+
+#include "OMX_Core.h"
+
+/** @defgroup iv OpenMAX IL Imaging and Video Domain
+ * Common structures for OpenMAX IL Imaging and Video domains
+ * @{
+ */
+
+
+/**
+ * Enumeration defining possible uncompressed image/video formats.
+ *
+ * ENUMS:
+ *  Unused                 : Placeholder value when format is N/A
+ *  Monochrome             : black and white
+ *  8bitRGB332             : Red 7:5, Green 4:2, Blue 1:0
+ *  12bitRGB444            : Red 11:8, Green 7:4, Blue 3:0
+ *  16bitARGB4444          : Alpha 15:12, Red 11:8, Green 7:4, Blue 3:0
+ *  16bitARGB1555          : Alpha 15, Red 14:10, Green 9:5, Blue 4:0
+ *  16bitRGB565            : Red 15:11, Green 10:5, Blue 4:0
+ *  16bitBGR565            : Blue 15:11, Green 10:5, Red 4:0
+ *  18bitRGB666            : Red 17:12, Green 11:6, Blue 5:0
+ *  18bitARGB1665          : Alpha 17, Red 16:11, Green 10:5, Blue 4:0
+ *  19bitARGB1666          : Alpha 18, Red 17:12, Green 11:6, Blue 5:0
+ *  24bitRGB888            : Red 24:16, Green 15:8, Blue 7:0
+ *  24bitBGR888            : Blue 24:16, Green 15:8, Red 7:0
+ *  24bitARGB1887          : Alpha 23, Red 22:15, Green 14:7, Blue 6:0
+ *  25bitARGB1888          : Alpha 24, Red 23:16, Green 15:8, Blue 7:0
+ *  32bitBGRA8888          : Blue 31:24, Green 23:16, Red 15:8, Alpha 7:0
+ *  32bitARGB8888          : Alpha 31:24, Red 23:16, Green 15:8, Blue 7:0
+ *  YUV411Planar           : U,Y are subsampled by a factor of 4 horizontally
+ *  YUV411PackedPlanar     : packed per payload in planar slices
+ *  YUV420Planar           : Three arrays Y,U,V.
+ *  YUV420PackedPlanar     : packed per payload in planar slices
+ *  YUV420SemiPlanar       : Two arrays, one is all Y, the other is U and V
+ *  YUV422Planar           : Three arrays Y,U,V.
+ *  YUV422PackedPlanar     : packed per payload in planar slices
+ *  YUV422SemiPlanar       : Two arrays, one is all Y, the other is U and V
+ *  YCbYCr                 : Organized as 16bit YUYV (i.e. YCbYCr)
+ *  YCrYCb                 : Organized as 16bit YVYU (i.e. YCrYCb)
+ *  CbYCrY                 : Organized as 16bit UYVY (i.e. CbYCrY)
+ *  CrYCbY                 : Organized as 16bit VYUY (i.e. CrYCbY)
+ *  YUV444Interleaved      : Each pixel contains equal parts YUV
+ *  RawBayer8bit           : SMIA camera output format
+ *  RawBayer10bit          : SMIA camera output format
+ *  RawBayer8bitcompressed : SMIA camera output format
+ Vendor extensions
+ *  32bitABGR888           : Alpha 31:24, Blue 23:16, Green 15:8, Red 7:0
+ */
+typedef enum OMX_COLOR_FORMATTYPE {
+    OMX_COLOR_FormatUnused,
+    OMX_COLOR_FormatMonochrome,
+    OMX_COLOR_Format8bitRGB332,
+    OMX_COLOR_Format12bitRGB444,
+    OMX_COLOR_Format16bitARGB4444,
+    OMX_COLOR_Format16bitARGB1555,
+    OMX_COLOR_Format16bitRGB565,
+    OMX_COLOR_Format16bitBGR565,
+    OMX_COLOR_Format18bitRGB666,
+    OMX_COLOR_Format18bitARGB1665,
+    OMX_COLOR_Format19bitARGB1666,
+    OMX_COLOR_Format24bitRGB888,
+    OMX_COLOR_Format24bitBGR888,
+    OMX_COLOR_Format24bitARGB1887,
+    OMX_COLOR_Format25bitARGB1888,
+    OMX_COLOR_Format32bitBGRA8888,
+    OMX_COLOR_Format32bitARGB8888,
+    OMX_COLOR_FormatYUV411Planar,
+    OMX_COLOR_FormatYUV411PackedPlanar,
+    OMX_COLOR_FormatYUV420Planar,
+    OMX_COLOR_FormatYUV420PackedPlanar,
+    OMX_COLOR_FormatYUV420SemiPlanar,
+    OMX_COLOR_FormatYUV422Planar,
+    OMX_COLOR_FormatYUV422PackedPlanar,
+    OMX_COLOR_FormatYUV422SemiPlanar,
+    OMX_COLOR_FormatYCbYCr,
+    OMX_COLOR_FormatYCrYCb,
+    OMX_COLOR_FormatCbYCrY,
+    OMX_COLOR_FormatCrYCbY,
+    OMX_COLOR_FormatYUV444Interleaved,
+    OMX_COLOR_FormatRawBayer8bit,
+    OMX_COLOR_FormatRawBayer10bit,
+    OMX_COLOR_FormatRawBayer8bitcompressed,
+    OMX_COLOR_FormatL2,
+    OMX_COLOR_FormatL4,
+    OMX_COLOR_FormatL8,
+    OMX_COLOR_FormatL16,
+    OMX_COLOR_FormatL24,
+    OMX_COLOR_FormatL32,
+    OMX_COLOR_FormatYUV420PackedSemiPlanar,
+    OMX_COLOR_FormatYUV422PackedSemiPlanar,
+    OMX_COLOR_Format18BitBGR666,
+    OMX_COLOR_Format24BitARGB6666,
+    OMX_COLOR_Format24BitABGR6666,
+    OMX_COLOR_FormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+    OMX_COLOR_FormatVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_COLOR_Format32bitABGR8888,
+    OMX_COLOR_Format8bitPalette,
+    OMX_COLOR_FormatYUVUV128,
+    OMX_COLOR_FormatRawBayer12bit,
+    OMX_COLOR_FormatBRCMEGL,
+    OMX_COLOR_FormatBRCMOpaque,
+    OMX_COLOR_FormatYVU420PackedPlanar,
+    OMX_COLOR_FormatYVU420PackedSemiPlanar,
+    OMX_COLOR_FormatRawBayer16bit,
+    OMX_COLOR_FormatYUV420_16PackedPlanar,  /**< YUV420, 16bit/component */
+    OMX_COLOR_FormatYUVUV64_16,             /**< YUVUV, 16bit/component */
+    OMX_COLOR_FormatYUV420_10PackedPlanar,  /**< YUV420, 10bit/component as least sig 10bits of 16 bit words */
+    OMX_COLOR_FormatYUVUV64_10,             /**< YUVUV, 10bit/component as least sig 10bits of 16 bit words */
+#ifdef TIZEN_FEATURE_OMX
+       OMX_EXT_COLOR_FormatNV12TPhysicalAddress = 0x7F000001, /**< Reserved region for introducing Vendor Extensions */
+       OMX_EXT_COLOR_FormatNV12LPhysicalAddress = 0x7F000002,
+       OMX_EXT_COLOR_FormatNV12Tiled = 0x7FC00002,
+       OMX_EXT_COLOR_FormatNV12TFdValue = 0x7F000012,
+       OMX_EXT_COLOR_FormatNV12LFdValue = 0x7F000013,
+#endif
+    OMX_COLOR_FormatMax = 0x7FFFFFFF
+} OMX_COLOR_FORMATTYPE;
+
+
+/**
+ * Defines the matrix for conversion from RGB to YUV or vice versa.
+ * iColorMatrix should be initialized with the fixed point values
+ * used in converting between formats.
+ */
+typedef struct OMX_CONFIG_COLORCONVERSIONTYPE {
+    OMX_U32 nSize;              /**< Size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;   /**< OMX specification version info */
+    OMX_U32 nPortIndex;         /**< Port that this struct applies to */
+    OMX_S32 xColorMatrix[3][3]; /**< Stored in signed Q16 format */
+    OMX_S32 xColorOffset[4];    /**< Stored in signed Q16 format */
+}OMX_CONFIG_COLORCONVERSIONTYPE;
+
+
+/**
+ * Structure defining percent to scale each frame dimension.  For example:
+ * To make the width 50% larger, use fWidth = 1.5 and to make the width
+ * 1/2 the original size, use fWidth = 0.5
+ */
+typedef struct OMX_CONFIG_SCALEFACTORTYPE {
+    OMX_U32 nSize;            /**< Size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version info */
+    OMX_U32 nPortIndex;       /**< Port that this struct applies to */
+    OMX_S32 xWidth;           /**< Fixed point value stored as Q16 */
+    OMX_S32 xHeight;          /**< Fixed point value stored as Q16 */
+}OMX_CONFIG_SCALEFACTORTYPE;
+
+
+/**
+ * Enumeration of possible image filter types
+ */
+typedef enum OMX_IMAGEFILTERTYPE {
+    OMX_ImageFilterNone,
+    OMX_ImageFilterNoise,
+    OMX_ImageFilterEmboss,
+    OMX_ImageFilterNegative,
+    OMX_ImageFilterSketch,
+    OMX_ImageFilterOilPaint,
+    OMX_ImageFilterHatch,
+    OMX_ImageFilterGpen,
+    OMX_ImageFilterAntialias,
+    OMX_ImageFilterDeRing,
+    OMX_ImageFilterSolarize,
+    OMX_ImageFilterKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+    OMX_ImageFilterVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+
+    /* Broadcom specific image filters */
+    OMX_ImageFilterWatercolor,
+    OMX_ImageFilterPastel,
+    OMX_ImageFilterSharpen,
+    OMX_ImageFilterFilm,
+    OMX_ImageFilterBlur,
+    OMX_ImageFilterSaturation,
+
+    OMX_ImageFilterDeInterlaceLineDouble,
+    OMX_ImageFilterDeInterlaceAdvanced,
+
+    OMX_ImageFilterColourSwap,
+    OMX_ImageFilterWashedOut,
+    OMX_ImageFilterColourPoint,
+    OMX_ImageFilterPosterise,
+    OMX_ImageFilterColourBalance,
+    OMX_ImageFilterCartoon,
+
+    OMX_ImageFilterAnaglyph,
+    OMX_ImageFilterDeInterlaceFast,
+    OMX_ImageFilterMax = 0x7FFFFFFF
+} OMX_IMAGEFILTERTYPE;
+
+typedef enum OMX_IMAGEFILTERANAGLYPHTYPE {
+    OMX_ImageFilterAnaglyphNone,
+    OMX_ImageFilterAnaglyphSBStoRedCyan,
+    OMX_ImageFilterAnaglyphSBStoCyanRed,
+    OMX_ImageFilterAnaglyphSBStoGreenMagenta,
+    OMX_ImageFilterAnaglyphSBStoMagentaGreen,
+    OMX_ImageFilterAnaglyphTABtoRedCyan,
+    OMX_ImageFilterAnaglyphTABtoCyanRed,
+    OMX_ImageFilterAnaglyphTABtoGreenMagenta,
+    OMX_ImageFilterAnaglyphTABtoMagentaGreen,
+} OMX_IMAGEFILTERANAGLYPHTYPE;
+
+/**
+ * Image filter configuration
+ *
+ * STRUCT MEMBERS:
+ *  nSize        : Size of the structure in bytes
+ *  nVersion     : OMX specification version information
+ *  nPortIndex   : Port that this structure applies to
+ *  eImageFilter : Image filter type enumeration
+ */
+typedef struct OMX_CONFIG_IMAGEFILTERTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_IMAGEFILTERTYPE eImageFilter;
+} OMX_CONFIG_IMAGEFILTERTYPE;
+
+
+/**
+ * Customized U and V for color enhancement
+ *
+ * STRUCT MEMBERS:
+ *  nSize             : Size of the structure in bytes
+ *  nVersion          : OMX specification version information
+ *  nPortIndex        : Port that this structure applies to
+ *  bColorEnhancement : Enable/disable color enhancement
+ *  nCustomizedU      : Practical values: 16-240, range: 0-255, value set for
+ *                      U component
+ *  nCustomizedV      : Practical values: 16-240, range: 0-255, value set for
+ *                      V component
+ */
+typedef struct OMX_CONFIG_COLORENHANCEMENTTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_BOOL bColorEnhancement;
+    OMX_U8 nCustomizedU;
+    OMX_U8 nCustomizedV;
+} OMX_CONFIG_COLORENHANCEMENTTYPE;
+
+
+/**
+ * Define color key and color key mask
+ *
+ * STRUCT MEMBERS:
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version information
+ *  nPortIndex : Port that this structure applies to
+ *  nARGBColor : 32bit Alpha, Red, Green, Blue Color
+ *  nARGBMask  : 32bit Mask for Alpha, Red, Green, Blue channels
+ */
+typedef struct OMX_CONFIG_COLORKEYTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_U32 nARGBColor;
+    OMX_U32 nARGBMask;
+} OMX_CONFIG_COLORKEYTYPE;
+
+
+/**
+ * List of color blend types for pre/post processing
+ *
+ * ENUMS:
+ *  None          : No color blending present
+ *  AlphaConstant : Function is (alpha_constant * src) +
+ *                  (1 - alpha_constant) * dst)
+ *  AlphaPerPixel : Function is (alpha * src) + (1 - alpha) * dst)
+ *  Alternate     : Function is alternating pixels from src and dst
+ *  And           : Function is (src & dst)
+ *  Or            : Function is (src | dst)
+ *  Invert        : Function is ~src
+ */
+typedef enum OMX_COLORBLENDTYPE {
+    OMX_ColorBlendNone,
+    OMX_ColorBlendAlphaConstant,
+    OMX_ColorBlendAlphaPerPixel,
+    OMX_ColorBlendAlternate,
+    OMX_ColorBlendAnd,
+    OMX_ColorBlendOr,
+    OMX_ColorBlendInvert,
+    OMX_ColorBlendKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+    OMX_ColorBlendVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_ColorBlendMax = 0x7FFFFFFF
+} OMX_COLORBLENDTYPE;
+
+
+/**
+ * Color blend configuration
+ *
+ * STRUCT MEMBERS:
+ *  nSize             : Size of the structure in bytes
+ *  nVersion          : OMX specification version information
+ *  nPortIndex        : Port that this structure applies to
+ *  nRGBAlphaConstant : Constant global alpha values when global alpha is used
+ *  eColorBlend       : Color blend type enumeration
+ */
+typedef struct OMX_CONFIG_COLORBLENDTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_U32 nRGBAlphaConstant;
+    OMX_COLORBLENDTYPE  eColorBlend;
+} OMX_CONFIG_COLORBLENDTYPE;
+
+
+/**
+ * Hold frame dimension
+ *
+ * STRUCT MEMBERS:
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version information
+ *  nPortIndex : Port that this structure applies to
+ *  nWidth     : Frame width in pixels
+ *  nHeight    : Frame height in pixels
+ */
+typedef struct OMX_FRAMESIZETYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_U32 nWidth;
+    OMX_U32 nHeight;
+} OMX_FRAMESIZETYPE;
+
+
+/**
+ * Rotation configuration
+ *
+ * STRUCT MEMBERS:
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version information
+ *  nPortIndex : Port that this structure applies to
+ *  nRotation  : +/- integer rotation value
+ */
+typedef struct OMX_CONFIG_ROTATIONTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_S32 nRotation;
+} OMX_CONFIG_ROTATIONTYPE;
+
+
+/**
+ * Possible mirroring directions for pre/post processing
+ *
+ * ENUMS:
+ *  None       : No mirroring
+ *  Vertical   : Vertical mirroring, flip on X axis
+ *  Horizontal : Horizontal mirroring, flip on Y axis
+ *  Both       : Both vertical and horizontal mirroring
+ */
+typedef enum OMX_MIRRORTYPE {
+    OMX_MirrorNone = 0,
+    OMX_MirrorVertical,
+    OMX_MirrorHorizontal,
+    OMX_MirrorBoth,
+    OMX_MirrorKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+    OMX_MirrorVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_MirrorMax = 0x7FFFFFFF
+} OMX_MIRRORTYPE;
+
+
+/**
+ * Mirroring configuration
+ *
+ * STRUCT MEMBERS:
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version information
+ *  nPortIndex : Port that this structure applies to
+ *  eMirror    : Mirror type enumeration
+ */
+typedef struct OMX_CONFIG_MIRRORTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_MIRRORTYPE  eMirror;
+} OMX_CONFIG_MIRRORTYPE;
+
+
+/**
+ * Position information only
+ *
+ * STRUCT MEMBERS:
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version information
+ *  nPortIndex : Port that this structure applies to
+ *  nX         : X coordinate for the point
+ *  nY         : Y coordinate for the point
+ */
+typedef struct OMX_CONFIG_POINTTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_S32 nX;
+    OMX_S32 nY;
+} OMX_CONFIG_POINTTYPE;
+
+
+/**
+ * Frame size plus position
+ *
+ * STRUCT MEMBERS:
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version information
+ *  nPortIndex : Port that this structure applies to
+ *  nLeft      : X Coordinate of the top left corner of the rectangle
+ *  nTop       : Y Coordinate of the top left corner of the rectangle
+ *  nWidth     : Width of the rectangle
+ *  nHeight    : Height of the rectangle
+ */
+typedef struct OMX_CONFIG_RECTTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_S32 nLeft;
+    OMX_S32 nTop;
+    OMX_U32 nWidth;
+    OMX_U32 nHeight;
+} OMX_CONFIG_RECTTYPE;
+
+
+/**
+ * Deblocking state; it is required to be set up before starting the codec
+ *
+ * STRUCT MEMBERS:
+ *  nSize       : Size of the structure in bytes
+ *  nVersion    : OMX specification version information
+ *  nPortIndex  : Port that this structure applies to
+ *  bDeblocking : Enable/disable deblocking mode
+ */
+typedef struct OMX_PARAM_DEBLOCKINGTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_BOOL bDeblocking;
+} OMX_PARAM_DEBLOCKINGTYPE;
+
+
+/**
+ * Stabilization state
+ *
+ * STRUCT MEMBERS:
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version information
+ *  nPortIndex : Port that this structure applies to
+ *  bStab      : Enable/disable frame stabilization state
+ */
+typedef struct OMX_CONFIG_FRAMESTABTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_BOOL bStab;
+} OMX_CONFIG_FRAMESTABTYPE;
+
+
+/**
+ * White Balance control type
+ *
+ * STRUCT MEMBERS:
+ *  SunLight : Referenced in JSR-234
+ *  Flash    : Optimal for device's integrated flash
+ */
+typedef enum OMX_WHITEBALCONTROLTYPE {
+    OMX_WhiteBalControlOff = 0,
+    OMX_WhiteBalControlAuto,
+    OMX_WhiteBalControlSunLight,
+    OMX_WhiteBalControlCloudy,
+    OMX_WhiteBalControlShade,
+    OMX_WhiteBalControlTungsten,
+    OMX_WhiteBalControlFluorescent,
+    OMX_WhiteBalControlIncandescent,
+    OMX_WhiteBalControlFlash,
+    OMX_WhiteBalControlHorizon,
+    OMX_WhiteBalControlKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+    OMX_WhiteBalControlVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_WhiteBalControlMax = 0x7FFFFFFF
+} OMX_WHITEBALCONTROLTYPE;
+
+
+/**
+ * White Balance control configuration
+ *
+ * STRUCT MEMBERS:
+ *  nSize            : Size of the structure in bytes
+ *  nVersion         : OMX specification version information
+ *  nPortIndex       : Port that this structure applies to
+ *  eWhiteBalControl : White balance enumeration
+ */
+typedef struct OMX_CONFIG_WHITEBALCONTROLTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_WHITEBALCONTROLTYPE eWhiteBalControl;
+} OMX_CONFIG_WHITEBALCONTROLTYPE;
+
+
+/**
+ * Exposure control type
+ */
+typedef enum OMX_EXPOSURECONTROLTYPE {
+    OMX_ExposureControlOff = 0,
+    OMX_ExposureControlAuto,
+    OMX_ExposureControlNight,
+    OMX_ExposureControlBackLight,
+    OMX_ExposureControlSpotLight,
+    OMX_ExposureControlSports,
+    OMX_ExposureControlSnow,
+    OMX_ExposureControlBeach,
+    OMX_ExposureControlLargeAperture,
+    OMX_ExposureControlSmallAperture,
+    OMX_ExposureControlKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+    OMX_ExposureControlVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_ExposureControlVeryLong,
+    OMX_ExposureControlFixedFps,
+    OMX_ExposureControlNightWithPreview,
+    OMX_ExposureControlAntishake,
+    OMX_ExposureControlFireworks,
+    OMX_ExposureControlMax = 0x7FFFFFFF
+} OMX_EXPOSURECONTROLTYPE;
+
+
+/**
+ * White Balance control configuration
+ *
+ * STRUCT MEMBERS:
+ *  nSize            : Size of the structure in bytes
+ *  nVersion         : OMX specification version information
+ *  nPortIndex       : Port that this structure applies to
+ *  eExposureControl : Exposure control enumeration
+ */
+typedef struct OMX_CONFIG_EXPOSURECONTROLTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_EXPOSURECONTROLTYPE eExposureControl;
+} OMX_CONFIG_EXPOSURECONTROLTYPE;
+
+
+/**
+ * Defines sensor supported mode.
+ *
+ * STRUCT MEMBERS:
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version information
+ *  nPortIndex : Port that this structure applies to
+ *  nFrameRate : Single shot mode is indicated by a 0
+ *  bOneShot   : Enable for single shot, disable for streaming
+ *  sFrameSize : Framesize
+ */
+typedef struct OMX_PARAM_SENSORMODETYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_U32 nFrameRate;
+    OMX_BOOL bOneShot;
+    OMX_FRAMESIZETYPE sFrameSize;
+} OMX_PARAM_SENSORMODETYPE;
+
+
+/**
+ * Defines contrast level
+ *
+ * STRUCT MEMBERS:
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version information
+ *  nPortIndex : Port that this structure applies to
+ *  nContrast  : Values allowed for contrast -100 to 100, zero means no change
+ */
+typedef struct OMX_CONFIG_CONTRASTTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_S32 nContrast;
+} OMX_CONFIG_CONTRASTTYPE;
+
+
+/**
+ * Defines brightness level
+ *
+ * STRUCT MEMBERS:
+ *  nSize       : Size of the structure in bytes
+ *  nVersion    : OMX specification version information
+ *  nPortIndex  : Port that this structure applies to
+ *  nBrightness : 0-100%
+ */
+typedef struct OMX_CONFIG_BRIGHTNESSTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_U32 nBrightness;
+} OMX_CONFIG_BRIGHTNESSTYPE;
+
+
+/**
+ * Defines backlight level configuration for a video sink, e.g. LCD panel
+ *
+ * STRUCT MEMBERS:
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version information
+ *  nPortIndex : Port that this structure applies to
+ *  nBacklight : Values allowed for backlight 0-100%
+ *  nTimeout   : Number of milliseconds before backlight automatically turns
+ *               off.  A value of 0x0 disables backight timeout
+ */
+typedef struct OMX_CONFIG_BACKLIGHTTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_U32 nBacklight;
+    OMX_U32 nTimeout;
+} OMX_CONFIG_BACKLIGHTTYPE;
+
+
+/**
+ * Defines setting for Gamma
+ *
+ * STRUCT MEMBERS:
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version information
+ *  nPortIndex : Port that this structure applies to
+ *  nGamma     : Values allowed for gamma -100 to 100, zero means no change
+ */
+typedef struct OMX_CONFIG_GAMMATYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_S32 nGamma;
+} OMX_CONFIG_GAMMATYPE;
+
+
+/**
+ * Define for setting saturation
+ *
+ * STRUCT MEMBERS:
+ *  nSize       : Size of the structure in bytes
+ *  nVersion    : OMX specification version information
+ *  nPortIndex  : Port that this structure applies to
+ *  nSaturation : Values allowed for saturation -100 to 100, zero means
+ *                no change
+ */
+typedef struct OMX_CONFIG_SATURATIONTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_S32 nSaturation;
+} OMX_CONFIG_SATURATIONTYPE;
+
+
+/**
+ * Define for setting Lightness
+ *
+ * STRUCT MEMBERS:
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version information
+ *  nPortIndex : Port that this structure applies to
+ *  nLightness : Values allowed for lightness -100 to 100, zero means no
+ *               change
+ */
+typedef struct OMX_CONFIG_LIGHTNESSTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_S32 nLightness;
+} OMX_CONFIG_LIGHTNESSTYPE;
+
+
+/**
+ * Plane blend configuration
+ *
+ * STRUCT MEMBERS:
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version information
+ *  nPortIndex : Index of input port associated with the plane.
+ *  nDepth     : Depth of the plane in relation to the screen. Higher
+ *               numbered depths are "behind" lower number depths.
+ *               This number defaults to the Port Index number.
+ *  nAlpha     : Transparency blending component for the entire plane.
+ *               See blending modes for more detail.
+ */
+typedef struct OMX_CONFIG_PLANEBLENDTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_U32 nDepth;
+    OMX_U32 nAlpha;
+} OMX_CONFIG_PLANEBLENDTYPE;
+
+
+/**
+ * Define interlace type
+ *
+ * STRUCT MEMBERS:
+ *  nSize                 : Size of the structure in bytes
+ *  nVersion              : OMX specification version information
+ *  nPortIndex            : Port that this structure applies to
+ *  bEnable               : Enable control variable for this functionality
+ *                          (see below)
+ *  nInterleavePortIndex  : Index of input or output port associated with
+ *                          the interleaved plane.
+ *  pPlanarPortIndexes[4] : Index of input or output planar ports.
+ */
+typedef struct OMX_PARAM_INTERLEAVETYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_BOOL bEnable;
+    OMX_U32 nInterleavePortIndex;
+} OMX_PARAM_INTERLEAVETYPE;
+
+
+/**
+ * Defines the picture effect used for an input picture
+ */
+typedef enum OMX_TRANSITIONEFFECTTYPE {
+    OMX_EffectNone,
+    OMX_EffectFadeFromBlack,
+    OMX_EffectFadeToBlack,
+    OMX_EffectUnspecifiedThroughConstantColor,
+    OMX_EffectDissolve,
+    OMX_EffectWipe,
+    OMX_EffectUnspecifiedMixOfTwoScenes,
+    OMX_EffectKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+    OMX_EffectVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+
+    OMX_EffectReverseUnspecifiedMixOfTwoScenes,
+
+#ifndef __VIDEOCORE4__
+    OMX_EffectDiagonalWipe,
+    OMX_EffectDiagonalWipeRotate,
+    OMX_EffectEllipticalWipe,
+    OMX_EffectEllipticalWipeRotate,
+    OMX_EffectInverseEllipticalWipe,
+    OMX_EffectInverseEllipticalWipeRotate,
+    OMX_EffectGlassWipe,
+    OMX_EffectGlassWipeRotate,
+    OMX_EffectWavyWipe,
+    OMX_EffectWavyWipeRotate,
+    OMX_EffectMunchingSquares,
+    OMX_EffectStripeWipe,
+    OMX_EffectStripeWipeRotate,
+
+    OMX_EffectRotozoomUnmatched,
+    OMX_EffectRotozoomMatched,
+    OMX_EffectRotozoomGentle,
+#endif
+
+    OMX_EffectMunchRandom,
+    OMX_EffectMunchVRandom,
+    OMX_EffectMunchHRandom,
+    OMX_EffectMunchWipe,
+    OMX_EffectMunchMunch,
+    OMX_EffectMunchStripe,
+    OMX_EffectFadeRandom,
+    OMX_EffectFadeVRandom,
+    OMX_EffectFadeHRandom,
+    OMX_EffectFadeWipe,
+    OMX_EffectFadeMunch,
+    OMX_EffectFadeStripe,
+    OMX_EffectColourBlockRandom,
+    OMX_EffectColourBlockVRandom,
+    OMX_EffectColourBlockHRandom,
+    OMX_EffectColourBlockWipe,
+    OMX_EffectColourBlockMunch,
+    OMX_EffectColourBlockStripe,
+    OMX_EffectColourBlock2Random,
+    OMX_EffectColourBlock2VRandom,
+    OMX_EffectColourBlock2HRandom,
+    OMX_EffectColourBlock2Wipe,
+    OMX_EffectColourBlock2Munch,
+    OMX_EffectColourBlock2Stripe,
+    OMX_EffectShadeRandom,
+    OMX_EffectShadeVRandom,
+    OMX_EffectShadeHRandom,
+    OMX_EffectShadeWipe,
+    OMX_EffectShadeMunch,
+    OMX_EffectShadeStripe,
+    OMX_EffectBitmaskRandom,
+    OMX_EffectBitmaskVRandom,
+    OMX_EffectBitmaskHRandom,
+    OMX_EffectBitmaskWipe,
+    OMX_EffectBitmaskMunch,
+    OMX_EffectBitmaskStripe,
+    OMX_EffectBitmask2Random,
+    OMX_EffectBitmask2VRandom,
+    OMX_EffectBitmask2HRandom,
+    OMX_EffectBitmask2Wipe,
+    OMX_EffectBitmask2Munch,
+    OMX_EffectBitmask2Stripe,
+    OMX_EffectBitmask2ColourRandom,
+    OMX_EffectBitmask2ColourVRandom,
+    OMX_EffectBitmask2ColourHRandom,
+    OMX_EffectBitmask2ColourWipe,
+    OMX_EffectBitmask2ColourMunch,
+    OMX_EffectBitmask2ColourStripe,
+
+    OMX_EffectPushRight,
+    OMX_EffectPushLeft,
+    OMX_EffectPushDown,
+    OMX_EffectPushUp,
+    OMX_EffectCoverRight,
+    OMX_EffectCoverLeft,
+    OMX_EffectCoverDown,
+    OMX_EffectCoverUp,
+    OMX_EffectRevealRight,
+    OMX_EffectRevealLeft,
+    OMX_EffectRevealDown,
+    OMX_EffectRevealUp,
+    OMX_EffectWipeRight,
+    OMX_EffectWipeLeft,
+    OMX_EffectWipeDown,
+    OMX_EffectWipeUp,
+    OMX_EffectSpeckle,
+    OMX_EffectCircle,
+    OMX_EffectSpiral,
+    OMX_EffectDiamond,
+    OMX_EffectVert,
+    OMX_EffectPlus,
+    OMX_EffectClock,
+    OMX_EffectPlasma,
+    OMX_EffectDisplace,
+    OMX_EffectGenie,
+    OMX_EffectSide,
+    OMX_EffectMaze,
+    OMX_EffectRipple,
+    OMX_EffectStar,
+    OMX_EffectAlpha,
+    OMX_EffectIntense,
+    OMX_EffectIntenseU,
+    OMX_EffectIntenseV,
+    OMX_EffectInverseIntense,
+    OMX_EffectInverseIntenseU,
+    OMX_EffectInverseIntenseV,
+
+    OMX_EffectPageTurn,
+
+    OMX_EffectFlipPlaneDown,
+    OMX_EffectFlipPlaneDownMid,
+    OMX_EffectFlipPlaneDownHigh,
+    OMX_EffectFlipPlaneLeft,
+    OMX_EffectFlipPlaneLeftMid,
+    OMX_EffectFlipPlaneLeftHigh,
+    OMX_EffectFlipCubeDown,
+    OMX_EffectFlipCubeDownMid,
+    OMX_EffectFlipCubeDownHigh,
+    OMX_EffectFlipCubeLeft,
+    OMX_EffectFlipCubeLeftMid,
+    OMX_EffectFlipCubeLeftHigh,
+
+    OMX_EffectMax = 0x7FFFFFFF
+} OMX_TRANSITIONEFFECTTYPE;
+
+
+/**
+ * Structure used to configure current transition effect
+ *
+ * STRUCT MEMBERS:
+ * nSize      : Size of the structure in bytes
+ * nVersion   : OMX specification version information
+ * nPortIndex : Port that this structure applies to
+ * eEffect    : Effect to enable
+ */
+typedef struct OMX_CONFIG_TRANSITIONEFFECTTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_TRANSITIONEFFECTTYPE eEffect;
+} OMX_CONFIG_TRANSITIONEFFECTTYPE;
+
+
+/**
+ * Defines possible data unit types for encoded video data. The data unit
+ * types are used both for encoded video input for playback as well as
+ * encoded video output from recording.
+ */
+typedef enum OMX_DATAUNITTYPE {
+    OMX_DataUnitCodedPicture,
+    OMX_DataUnitVideoSegment,
+    OMX_DataUnitSeveralSegments,
+    OMX_DataUnitArbitraryStreamSection,
+    OMX_DataUnitKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+    OMX_DataUnitVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_DataUnitMax = 0x7FFFFFFF
+} OMX_DATAUNITTYPE;
+
+
+/**
+ * Defines possible encapsulation types for coded video data unit. The
+ * encapsulation information is used both for encoded video input for
+ * playback as well as encoded video output from recording.
+ */
+typedef enum OMX_DATAUNITENCAPSULATIONTYPE {
+    OMX_DataEncapsulationElementaryStream,
+    OMX_DataEncapsulationGenericPayload,
+    OMX_DataEncapsulationRtpPayload,
+    OMX_DataEncapsulationKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+    OMX_DataEncapsulationVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_DataEncapsulationMax = 0x7FFFFFFF
+} OMX_DATAUNITENCAPSULATIONTYPE;
+
+
+/**
+ * Structure used to configure the type of being decoded/encoded
+ */
+typedef struct OMX_PARAM_DATAUNITTYPE {
+    OMX_U32 nSize;            /**< Size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
+    OMX_U32 nPortIndex;       /**< Port that this structure applies to */
+    OMX_DATAUNITTYPE eUnitType;
+    OMX_DATAUNITENCAPSULATIONTYPE eEncapsulationType;
+} OMX_PARAM_DATAUNITTYPE;
+
+
+/**
+ * Defines dither types
+ */
+typedef enum OMX_DITHERTYPE {
+    OMX_DitherNone,
+    OMX_DitherOrdered,
+    OMX_DitherErrorDiffusion,
+    OMX_DitherOther,
+    OMX_DitherKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+    OMX_DitherVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_DitherMax = 0x7FFFFFFF
+} OMX_DITHERTYPE;
+
+
+/**
+ * Structure used to configure current type of dithering
+ */
+typedef struct OMX_CONFIG_DITHERTYPE {
+    OMX_U32 nSize;            /**< Size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
+    OMX_U32 nPortIndex;       /**< Port that this structure applies to */
+    OMX_DITHERTYPE eDither;   /**< Type of dithering to use */
+} OMX_CONFIG_DITHERTYPE;
+
+typedef struct OMX_CONFIG_CAPTUREMODETYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;     /**< Port that this structure applies to */
+    OMX_BOOL bContinuous;   /**< If true then ignore frame rate and emit capture
+                             *   data as fast as possible (otherwise obey port's frame rate). */
+    OMX_BOOL bFrameLimited; /**< If true then terminate capture after the port emits the
+                             *   specified number of frames (otherwise the port does not
+                             *   terminate the capture until instructed to do so by the client).
+                             *   Even if set, the client may manually terminate the capture prior
+                             *   to reaching the limit. */
+    OMX_U32 nFrameLimit;      /**< Limit on number of frames emitted during a capture (only
+                               *   valid if bFrameLimited is set). */
+} OMX_CONFIG_CAPTUREMODETYPE;
+
+typedef enum OMX_METERINGTYPE {
+
+    OMX_MeteringModeAverage,     /**< Center-weighted average metering. */
+    OMX_MeteringModeSpot,            /**< Spot (partial) metering. */
+    OMX_MeteringModeMatrix,      /**< Matrix or evaluative metering. */
+
+    OMX_MeteringKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+    OMX_MeteringVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_MeteringModeBacklit,
+    OMX_EVModeMax = 0x7fffffff
+} OMX_METERINGTYPE;
+
+typedef struct OMX_CONFIG_EXPOSUREVALUETYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_METERINGTYPE eMetering;
+    OMX_S32 xEVCompensation;      /**< Fixed point value stored as Q16 */
+    OMX_U32 nApertureFNumber;     /**< e.g. nApertureFNumber = 2 implies "f/2" - Q16 format */
+    OMX_BOOL bAutoAperture;            /**< Whether aperture number is defined automatically */
+    OMX_U32 nShutterSpeedMsec;    /**< Shutterspeed in milliseconds */
+    OMX_BOOL bAutoShutterSpeed;        /**< Whether shutter speed is defined automatically */
+    OMX_U32 nSensitivity;         /**< e.g. nSensitivity = 100 implies "ISO 100" */
+    OMX_BOOL bAutoSensitivity; /**< Whether sensitivity is defined automatically */
+} OMX_CONFIG_EXPOSUREVALUETYPE;
+
+/**
+ * Focus region configuration
+ *
+ * STRUCT MEMBERS:
+ *  nSize           : Size of the structure in bytes
+ *  nVersion        : OMX specification version information
+ *  nPortIndex      : Port that this structure applies to
+ *  bCenter         : Use center region as focus region of interest
+ *  bLeft           : Use left region as focus region of interest
+ *  bRight          : Use right region as focus region of interest
+ *  bTop            : Use top region as focus region of interest
+ *  bBottom         : Use bottom region as focus region of interest
+ *  bTopLeft        : Use top left region as focus region of interest
+ *  bTopRight       : Use top right region as focus region of interest
+ *  bBottomLeft     : Use bottom left region as focus region of interest
+ *  bBottomRight    : Use bottom right region as focus region of interest
+ */
+typedef struct OMX_CONFIG_FOCUSREGIONTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_BOOL bCenter;
+    OMX_BOOL bLeft;
+    OMX_BOOL bRight;
+    OMX_BOOL bTop;
+    OMX_BOOL bBottom;
+    OMX_BOOL bTopLeft;
+    OMX_BOOL bTopRight;
+    OMX_BOOL bBottomLeft;
+    OMX_BOOL bBottomRight;
+} OMX_CONFIG_FOCUSREGIONTYPE;
+
+/**
+ * Focus Status type
+ */
+typedef enum OMX_FOCUSSTATUSTYPE {
+    OMX_FocusStatusOff = 0,
+    OMX_FocusStatusRequest,
+    OMX_FocusStatusReached,
+    OMX_FocusStatusUnableToReach,
+    OMX_FocusStatusLost,
+    OMX_FocusStatusKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+    OMX_FocusStatusVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_FocusStatusCafWatching,
+    OMX_FocusStatusCafSceneChanged,
+    OMX_FocusStatusMax = 0x7FFFFFFF
+} OMX_FOCUSSTATUSTYPE;
+
+/**
+ * Focus status configuration
+ *
+ * STRUCT MEMBERS:
+ *  nSize               : Size of the structure in bytes
+ *  nVersion            : OMX specification version information
+ *  nPortIndex          : Port that this structure applies to
+ *  eFocusStatus        : Specifies the focus status
+ *  bCenterStatus       : Use center region as focus region of interest
+ *  bLeftStatus         : Use left region as focus region of interest
+ *  bRightStatus        : Use right region as focus region of interest
+ *  bTopStatus          : Use top region as focus region of interest
+ *  bBottomStatus       : Use bottom region as focus region of interest
+ *  bTopLeftStatus      : Use top left region as focus region of interest
+ *  bTopRightStatus     : Use top right region as focus region of interest
+ *  bBottomLeftStatus   : Use bottom left region as focus region of interest
+ *  bBottomRightStatus  : Use bottom right region as focus region of interest
+ */
+typedef struct OMX_PARAM_FOCUSSTATUSTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_FOCUSSTATUSTYPE eFocusStatus;
+    OMX_BOOL bCenterStatus;
+    OMX_BOOL bLeftStatus;
+    OMX_BOOL bRightStatus;
+    OMX_BOOL bTopStatus;
+    OMX_BOOL bBottomStatus;
+    OMX_BOOL bTopLeftStatus;
+    OMX_BOOL bTopRightStatus;
+    OMX_BOOL bBottomLeftStatus;
+    OMX_BOOL bBottomRightStatus;
+} OMX_PARAM_FOCUSSTATUSTYPE;
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
+/* File EOF */
diff --git a/interface/vmcs_host/khronos/IL/OMX_Image.h b/interface/vmcs_host/khronos/IL/OMX_Image.h
new file mode 100755 (executable)
index 0000000..4bf5b26
--- /dev/null
@@ -0,0 +1,347 @@
+/**
+ * Copyright (c) 2008 The Khronos Group Inc. 
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions: 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
+ */
+
+/** 
+ * @file OMX_Image.h - OpenMax IL version 1.1.2
+ * The structures needed by Image components to exchange parameters and 
+ * configuration data with the components.
+ */
+#ifndef OMX_Image_h
+#define OMX_Image_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/**
+ * Each OMX header must include all required header files to allow the 
+ * header to compile without errors.  The includes below are required  
+ * for this header file to compile successfully 
+ */
+
+#include "OMX_IVCommon.h"
+
+/** @defgroup imaging OpenMAX IL Imaging Domain
+ * @ingroup iv
+ * Structures for OpenMAX IL Imaging domain
+ * @{
+ */
+
+/** 
+ * Enumeration used to define the possible image compression coding. 
+ */
+typedef enum OMX_IMAGE_CODINGTYPE {
+    OMX_IMAGE_CodingUnused,      /**< Value when format is N/A */
+    OMX_IMAGE_CodingAutoDetect,  /**< Auto detection of image format */
+    OMX_IMAGE_CodingJPEG,        /**< JPEG/JFIF image format */
+    OMX_IMAGE_CodingJPEG2K,      /**< JPEG 2000 image format */
+    OMX_IMAGE_CodingEXIF,        /**< EXIF image format */
+    OMX_IMAGE_CodingTIFF,        /**< TIFF image format */
+    OMX_IMAGE_CodingGIF,         /**< Graphics image format */
+    OMX_IMAGE_CodingPNG,         /**< PNG image format */
+    OMX_IMAGE_CodingLZW,         /**< LZW image format */
+    OMX_IMAGE_CodingBMP,         /**< Windows Bitmap format */
+    OMX_IMAGE_CodingKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_IMAGE_CodingVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+
+    OMX_IMAGE_CodingTGA,
+    OMX_IMAGE_CodingPPM,
+
+    OMX_IMAGE_CodingMax = 0x7FFFFFFF
+} OMX_IMAGE_CODINGTYPE;
+
+
+/**
+ * Data structure used to define an image path. The number of image paths 
+ * for input and output will vary by type of the image component.  
+ * 
+ *  Input (aka Source) : Zero Inputs, one Output,
+ *  Splitter           : One Input, 2 or more Outputs,
+ *  Processing Element : One Input, one output,
+ *  Mixer              : 2 or more inputs, one output,
+ *  Output (aka Sink)  : One Input, zero outputs.
+ * 
+ * The PortDefinition structure is used to define all of the parameters 
+ * necessary for the compliant component to setup an input or an output  
+ * image path.  If additional vendor specific data is required, it should  
+ * be transmitted to the component using the CustomCommand function.   
+ * Compliant components will prepopulate this structure with optimal  
+ * values during the OMX_GetParameter() command.
+ *
+ * STRUCT MEMBERS:
+ *  cMIMEType             : MIME type of data for the port
+ *  pNativeRender         : Platform specific reference for a display if a 
+ *                          sync, otherwise this field is 0
+ *  nFrameWidth           : Width of frame to be used on port if 
+ *                          uncompressed format is used.  Use 0 for 
+ *                          unknown, don't care or variable
+ *  nFrameHeight          : Height of frame to be used on port if 
+ *                          uncompressed format is used. Use 0 for 
+ *                          unknown, don't care or variable
+ *  nStride               : Number of bytes per span of an image (i.e. 
+ *                          indicates the number of bytes to get from
+ *                          span N to span N+1, where negative stride 
+ *                          indicates the image is bottom up
+ *  nSliceHeight          : Height used when encoding in slices
+ *  bFlagErrorConcealment : Turns on error concealment if it is supported by 
+ *                          the OMX component
+ *  eCompressionFormat    : Compression format used in this instance of  
+ *                          the component. When OMX_IMAGE_CodingUnused is 
+ *                          specified, eColorFormat is valid
+ *  eColorFormat          : Decompressed format used by this component
+ *  pNativeWindow         : Platform specific reference for a window object if a 
+ *                          display sink , otherwise this field is 0x0. 
+ */
+typedef struct OMX_IMAGE_PORTDEFINITIONTYPE {
+    OMX_STRING cMIMEType;
+    OMX_NATIVE_DEVICETYPE pNativeRender;
+    OMX_U32 nFrameWidth; 
+    OMX_U32 nFrameHeight;
+    OMX_S32 nStride;     
+    OMX_U32 nSliceHeight;
+    OMX_BOOL bFlagErrorConcealment;
+    OMX_IMAGE_CODINGTYPE eCompressionFormat;
+    OMX_COLOR_FORMATTYPE eColorFormat;
+    OMX_NATIVE_WINDOWTYPE pNativeWindow;
+} OMX_IMAGE_PORTDEFINITIONTYPE;
+
+
+/**  
+ * Port format parameter.  This structure is used to enumerate the various 
+ * data input/output format supported by the port.
+ * 
+ * STRUCT MEMBERS:
+ *  nSize              : Size of the structure in bytes
+ *  nVersion           : OMX specification version information
+ *  nPortIndex         : Indicates which port to set
+ *  nIndex             : Indicates the enumeration index for the format from 
+ *                       0x0 to N-1
+ *  eCompressionFormat : Compression format used in this instance of the 
+ *                       component. When OMX_IMAGE_CodingUnused is specified, 
+ *                       eColorFormat is valid
+ *  eColorFormat       : Decompressed format used by this component
+ */
+typedef struct OMX_IMAGE_PARAM_PORTFORMATTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_U32 nIndex;
+    OMX_IMAGE_CODINGTYPE eCompressionFormat;
+    OMX_COLOR_FORMATTYPE eColorFormat;
+} OMX_IMAGE_PARAM_PORTFORMATTYPE;
+
+
+/** 
+ * Flash control type 
+ *
+ * ENUMS
+ *  Torch : Flash forced constantly on
+ */
+typedef enum OMX_IMAGE_FLASHCONTROLTYPE {
+    OMX_IMAGE_FlashControlOn = 0,
+    OMX_IMAGE_FlashControlOff,
+    OMX_IMAGE_FlashControlAuto,
+    OMX_IMAGE_FlashControlRedEyeReduction,
+    OMX_IMAGE_FlashControlFillin,
+    OMX_IMAGE_FlashControlTorch,
+    OMX_IMAGE_FlashControlKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_IMAGE_FlashControlVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_IMAGE_FlashControlMax = 0x7FFFFFFF
+} OMX_IMAGE_FLASHCONTROLTYPE;
+
+
+/** 
+ * Flash control configuration 
+ *
+ * STRUCT MEMBERS:
+ *  nSize         : Size of the structure in bytes
+ *  nVersion      : OMX specification version information
+ *  nPortIndex    : Port that this structure applies to
+ *  eFlashControl : Flash control type
+ */
+typedef struct OMX_IMAGE_PARAM_FLASHCONTROLTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_IMAGE_FLASHCONTROLTYPE eFlashControl;
+} OMX_IMAGE_PARAM_FLASHCONTROLTYPE;
+
+
+/** 
+ * Focus control type 
+ */
+typedef enum OMX_IMAGE_FOCUSCONTROLTYPE {
+    OMX_IMAGE_FocusControlOn = 0,
+    OMX_IMAGE_FocusControlOff,
+    OMX_IMAGE_FocusControlAuto,
+    OMX_IMAGE_FocusControlAutoLock,
+    OMX_IMAGE_FocusControlKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_IMAGE_FocusControlVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_IMAGE_FocusControlHyperfocal,         /* Focus at the hyperfocal point of the lens. */
+    OMX_IMAGE_FocusControlAutoMacro,          /* CF over a macro range (eg 0-50cm) */
+    OMX_IMAGE_FocusControlAutoInfinity,       /* CF over distant range (eg 50cm to infinity) */
+    OMX_IMAGE_FocusControlAutoLockMacro,      /* AF over a macro range (eg 0-50cm) */
+    OMX_IMAGE_FocusControlAutoLockInfinity,   /* AF over distant range (eg 50cm to infinity) */
+    OMX_IMAGE_FocusControlNearFixed,          /* Focus at a fixed near focus point - (50cm-1m) */
+    OMX_IMAGE_FocusControlAutoNear,           /* CF over a near range (eg 0-200cm) */
+    OMX_IMAGE_FocusControlAutoLockNear,       /* AF over a near range (eg 0-200cm) */
+    OMX_IMAGE_FocusControlInfinityFixed,      /* Focus at infinity */
+    OMX_IMAGE_FocusControlMacroFixed,         /* Focus at a macro distance */
+    OMX_IMAGE_FocusControlAutoFast,           /* CF over a full range with fast response */
+    OMX_IMAGE_FocusControlAutoMacroFast,      /* CF over a macro range (eg 0-50cm) with fast response */
+    OMX_IMAGE_FocusControlAutoNearFast,       /* CF over a near range (eg 0-200cm) */
+    OMX_IMAGE_FocusControlAutoInfinityFast,   /* CF over distant range (eg 50cm to infinity) with fast response */
+    OMX_IMAGE_FocusControlCurrentFixed,       /* Stop the lens at the current position */
+    OMX_IMAGE_FocusControlMax = 0x7FFFFFFF
+} OMX_IMAGE_FOCUSCONTROLTYPE;
+
+/** 
+ * Focus control configuration 
+ *
+ * STRUCT MEMBERS:
+ *  nSize           : Size of the structure in bytes
+ *  nVersion        : OMX specification version information
+ *  nPortIndex      : Port that this structure applies to
+ *  eFocusControl   : Focus control
+ *  nFocusSteps     : Focus can take on values from 0 mm to infinity. 
+ *                    Interest is only in number of steps over this range.
+ *  nFocusStepIndex : Current focus step index
+ */
+typedef struct OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_IMAGE_FOCUSCONTROLTYPE eFocusControl;
+    OMX_U32 nFocusSteps;
+    OMX_U32 nFocusStepIndex;
+} OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE;
+
+
+/** 
+ * Q Factor for JPEG compression, which controls the tradeoff between image
+ * quality and size.  Q Factor provides a more simple means of controlling
+ * JPEG compression quality, without directly programming Quantization
+ * tables for chroma and luma 
+ *
+ * STRUCT MEMBERS:
+ *  nSize      : Size of the structure in bytes         
+ *  nVersion   : OMX specification version information 
+ *  nPortIndex : Port that this structure applies to 
+ *  nQFactor   : JPEG Q factor value in the range of 1-100. A factor of 1 
+ *               produces the smallest, worst quality images, and a factor 
+ *               of 100 produces the largest, best quality images.  A 
+ *               typical default is 75 for small good quality images               
+ */
+typedef struct OMX_IMAGE_PARAM_QFACTORTYPE {
+    OMX_U32 nSize;            
+    OMX_VERSIONTYPE nVersion; 
+    OMX_U32 nPortIndex;       
+    OMX_U32 nQFactor;                                        
+} OMX_IMAGE_PARAM_QFACTORTYPE;
+
+/** 
+ * Quantization table type 
+ */
+
+typedef enum OMX_IMAGE_QUANTIZATIONTABLETYPE {
+    OMX_IMAGE_QuantizationTableLuma = 0,
+    OMX_IMAGE_QuantizationTableChroma,
+    OMX_IMAGE_QuantizationTableChromaCb,
+    OMX_IMAGE_QuantizationTableChromaCr,
+    OMX_IMAGE_QuantizationTableKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_IMAGE_QuantizationTableVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_IMAGE_QuantizationTableMax = 0x7FFFFFFF
+} OMX_IMAGE_QUANTIZATIONTABLETYPE;
+
+/** 
+ * JPEG quantization tables are used to determine DCT compression for
+ * YUV data, as an alternative to specifying Q factor, providing exact 
+ * control of compression 
+ *
+ * STRUCT MEMBERS:
+ *  nSize                   : Size of the structure in bytes
+ *  nVersion                : OMX specification version information 
+ *  nPortIndex              : Port that this structure applies to
+ *  eQuantizationTable      : Quantization table type
+ *  nQuantizationMatrix[64] : JPEG quantization table of coefficients stored 
+ *                            in increasing columns then by rows of data (i.e. 
+ *                            row 1, ... row 8). Quantization values are in 
+ *                            the range 0-255 and stored in linear order
+ *                            (i.e. the component will zig-zag the 
+ *                            quantization table data if required internally) 
+ */
+typedef struct OMX_IMAGE_PARAM_QUANTIZATIONTABLETYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_IMAGE_QUANTIZATIONTABLETYPE eQuantizationTable;
+    OMX_U8 nQuantizationMatrix[64];
+} OMX_IMAGE_PARAM_QUANTIZATIONTABLETYPE;
+
+
+/** 
+ * Huffman table type, the same Huffman table is applied for chroma and 
+ * luma component 
+ */
+typedef enum OMX_IMAGE_HUFFMANTABLETYPE {
+    OMX_IMAGE_HuffmanTableAC = 0,
+    OMX_IMAGE_HuffmanTableDC,
+    OMX_IMAGE_HuffmanTableACLuma,
+    OMX_IMAGE_HuffmanTableACChroma,
+    OMX_IMAGE_HuffmanTableDCLuma,
+    OMX_IMAGE_HuffmanTableDCChroma,
+    OMX_IMAGE_HuffmanTableKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_IMAGE_HuffmanTableVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_IMAGE_HuffmanTableMax = 0x7FFFFFFF
+} OMX_IMAGE_HUFFMANTABLETYPE;
+
+/** 
+ * JPEG Huffman table 
+ *
+ * STRUCT MEMBERS:
+ *  nSize                            : Size of the structure in bytes
+ *  nVersion                         : OMX specification version information
+ *  nPortIndex                       : Port that this structure applies to
+ *  eHuffmanTable                    : Huffman table type
+ *  nNumberOfHuffmanCodeOfLength[16] : 0-16, number of Huffman codes of each 
+ *                                     possible length
+ *  nHuffmanTable[256]               : 0-255, the size used for AC and DC 
+ *                                     HuffmanTable are 16 and 162 
+ */
+typedef struct OMX_IMAGE_PARAM_HUFFMANTTABLETYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_IMAGE_HUFFMANTABLETYPE eHuffmanTable;
+    OMX_U8 nNumberOfHuffmanCodeOfLength[16];
+    OMX_U8 nHuffmanTable[256];
+}OMX_IMAGE_PARAM_HUFFMANTTABLETYPE;
+
+/** @} */
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
+/* File EOF */
diff --git a/interface/vmcs_host/khronos/IL/OMX_Index.h b/interface/vmcs_host/khronos/IL/OMX_Index.h
new file mode 100755 (executable)
index 0000000..3ad2941
--- /dev/null
@@ -0,0 +1,549 @@
+/*
+ * Copyright (c) 2008 The Khronos Group Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions:
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+/** @file OMX_Index.h - OpenMax IL version 1.1.2
+ *  The OMX_Index header file contains the definitions for both applications
+ *  and components .
+ */
+
+
+#ifndef OMX_Index_h
+#define OMX_Index_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* Each OMX header must include all required header files to allow the
+ *  header to compile without errors.  The includes below are required
+ *  for this header file to compile successfully
+ */
+#include "OMX_Types.h"
+
+
+/** The OMX_INDEXTYPE enumeration is used to select a structure when either
+ *  getting or setting parameters and/or configuration data.  Each entry in
+ *  this enumeration maps to an OMX specified structure.  When the
+ *  OMX_GetParameter, OMX_SetParameter, OMX_GetConfig or OMX_SetConfig methods
+ *  are used, the second parameter will always be an entry from this enumeration
+ *  and the third entry will be the structure shown in the comments for the entry.
+ *  For example, if the application is initializing a cropping function, the
+ *  OMX_SetConfig command would have OMX_IndexConfigCommonInputCrop as the second parameter
+ *  and would send a pointer to an initialized OMX_RECTTYPE structure as the
+ *  third parameter.
+ *
+ *  The enumeration entries named with the OMX_Config prefix are sent using
+ *  the OMX_SetConfig command and the enumeration entries named with the
+ *  OMX_PARAM_ prefix are sent using the OMX_SetParameter command.
+ */
+typedef enum OMX_INDEXTYPE {
+
+    OMX_IndexComponentStartUnused = 0x01000000,
+    OMX_IndexParamPriorityMgmt,             /**< reference: OMX_PRIORITYMGMTTYPE */
+    OMX_IndexParamAudioInit,                /**< reference: OMX_PORT_PARAM_TYPE */
+    OMX_IndexParamImageInit,                /**< reference: OMX_PORT_PARAM_TYPE */
+    OMX_IndexParamVideoInit,                /**< reference: OMX_PORT_PARAM_TYPE */
+    OMX_IndexParamOtherInit,                /**< reference: OMX_PORT_PARAM_TYPE */
+    OMX_IndexParamNumAvailableStreams,      /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamActiveStream,             /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamSuspensionPolicy,         /**< reference: OMX_PARAM_SUSPENSIONPOLICYTYPE */
+    OMX_IndexParamComponentSuspended,       /**< reference: OMX_PARAM_SUSPENSIONTYPE */
+    OMX_IndexConfigCapturing,               /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigCaptureMode,             /**< reference: OMX_CONFIG_CAPTUREMODETYPE */
+    OMX_IndexAutoPauseAfterCapture,         /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamContentURI,               /**< reference: OMX_PARAM_CONTENTURITYPE */
+    OMX_IndexParamCustomContentPipe,        /**< reference: OMX_PARAM_CONTENTPIPETYPE */
+    OMX_IndexParamDisableResourceConcealment, /**< reference: OMX_RESOURCECONCEALMENTTYPE */
+    OMX_IndexConfigMetadataItemCount,       /**< reference: OMX_CONFIG_METADATAITEMCOUNTTYPE */
+    OMX_IndexConfigContainerNodeCount,      /**< reference: OMX_CONFIG_CONTAINERNODECOUNTTYPE */
+    OMX_IndexConfigMetadataItem,            /**< reference: OMX_CONFIG_METADATAITEMTYPE */
+    OMX_IndexConfigCounterNodeID,           /**< reference: OMX_CONFIG_CONTAINERNODEIDTYPE */
+    OMX_IndexParamMetadataFilterType,       /**< reference: OMX_PARAM_METADATAFILTERTYPE */
+    OMX_IndexParamMetadataKeyFilter,        /**< reference: OMX_PARAM_METADATAFILTERTYPE */
+    OMX_IndexConfigPriorityMgmt,            /**< reference: OMX_PRIORITYMGMTTYPE */
+    OMX_IndexParamStandardComponentRole,    /**< reference: OMX_PARAM_COMPONENTROLETYPE */
+
+    OMX_IndexPortStartUnused = 0x02000000,
+    OMX_IndexParamPortDefinition,           /**< reference: OMX_PARAM_PORTDEFINITIONTYPE */
+    OMX_IndexParamCompBufferSupplier,       /**< reference: OMX_PARAM_BUFFERSUPPLIERTYPE */
+    OMX_IndexReservedStartUnused = 0x03000000,
+
+    /* Audio parameters and configurations */
+    OMX_IndexAudioStartUnused = 0x04000000,
+    OMX_IndexParamAudioPortFormat,          /**< reference: OMX_AUDIO_PARAM_PORTFORMATTYPE */
+    OMX_IndexParamAudioPcm,                 /**< reference: OMX_AUDIO_PARAM_PCMMODETYPE */
+    OMX_IndexParamAudioAac,                 /**< reference: OMX_AUDIO_PARAM_AACPROFILETYPE */
+    OMX_IndexParamAudioRa,                  /**< reference: OMX_AUDIO_PARAM_RATYPE */
+    OMX_IndexParamAudioMp3,                 /**< reference: OMX_AUDIO_PARAM_MP3TYPE */
+    OMX_IndexParamAudioAdpcm,               /**< reference: OMX_AUDIO_PARAM_ADPCMTYPE */
+    OMX_IndexParamAudioG723,                /**< reference: OMX_AUDIO_PARAM_G723TYPE */
+    OMX_IndexParamAudioG729,                /**< reference: OMX_AUDIO_PARAM_G729TYPE */
+    OMX_IndexParamAudioAmr,                 /**< reference: OMX_AUDIO_PARAM_AMRTYPE */
+    OMX_IndexParamAudioWma,                 /**< reference: OMX_AUDIO_PARAM_WMATYPE */
+    OMX_IndexParamAudioSbc,                 /**< reference: OMX_AUDIO_PARAM_SBCTYPE */
+    OMX_IndexParamAudioMidi,                /**< reference: OMX_AUDIO_PARAM_MIDITYPE */
+    OMX_IndexParamAudioGsm_FR,              /**< reference: OMX_AUDIO_PARAM_GSMFRTYPE */
+    OMX_IndexParamAudioMidiLoadUserSound,   /**< reference: OMX_AUDIO_PARAM_MIDILOADUSERSOUNDTYPE */
+    OMX_IndexParamAudioG726,                /**< reference: OMX_AUDIO_PARAM_G726TYPE */
+    OMX_IndexParamAudioGsm_EFR,             /**< reference: OMX_AUDIO_PARAM_GSMEFRTYPE */
+    OMX_IndexParamAudioGsm_HR,              /**< reference: OMX_AUDIO_PARAM_GSMHRTYPE */
+    OMX_IndexParamAudioPdc_FR,              /**< reference: OMX_AUDIO_PARAM_PDCFRTYPE */
+    OMX_IndexParamAudioPdc_EFR,             /**< reference: OMX_AUDIO_PARAM_PDCEFRTYPE */
+    OMX_IndexParamAudioPdc_HR,              /**< reference: OMX_AUDIO_PARAM_PDCHRTYPE */
+    OMX_IndexParamAudioTdma_FR,             /**< reference: OMX_AUDIO_PARAM_TDMAFRTYPE */
+    OMX_IndexParamAudioTdma_EFR,            /**< reference: OMX_AUDIO_PARAM_TDMAEFRTYPE */
+    OMX_IndexParamAudioQcelp8,              /**< reference: OMX_AUDIO_PARAM_QCELP8TYPE */
+    OMX_IndexParamAudioQcelp13,             /**< reference: OMX_AUDIO_PARAM_QCELP13TYPE */
+    OMX_IndexParamAudioEvrc,                /**< reference: OMX_AUDIO_PARAM_EVRCTYPE */
+    OMX_IndexParamAudioSmv,                 /**< reference: OMX_AUDIO_PARAM_SMVTYPE */
+    OMX_IndexParamAudioVorbis,              /**< reference: OMX_AUDIO_PARAM_VORBISTYPE */
+
+    OMX_IndexConfigAudioMidiImmediateEvent, /**< reference: OMX_AUDIO_CONFIG_MIDIIMMEDIATEEVENTTYPE */
+    OMX_IndexConfigAudioMidiControl,        /**< reference: OMX_AUDIO_CONFIG_MIDICONTROLTYPE */
+    OMX_IndexConfigAudioMidiSoundBankProgram, /**< reference: OMX_AUDIO_CONFIG_MIDISOUNDBANKPROGRAMTYPE */
+    OMX_IndexConfigAudioMidiStatus,         /**< reference: OMX_AUDIO_CONFIG_MIDISTATUSTYPE */
+    OMX_IndexConfigAudioMidiMetaEvent,      /**< reference: OMX_AUDIO_CONFIG_MIDIMETAEVENTTYPE */
+    OMX_IndexConfigAudioMidiMetaEventData,  /**< reference: OMX_AUDIO_CONFIG_MIDIMETAEVENTDATATYPE */
+    OMX_IndexConfigAudioVolume,             /**< reference: OMX_AUDIO_CONFIG_VOLUMETYPE */
+    OMX_IndexConfigAudioBalance,            /**< reference: OMX_AUDIO_CONFIG_BALANCETYPE */
+    OMX_IndexConfigAudioChannelMute,        /**< reference: OMX_AUDIO_CONFIG_CHANNELMUTETYPE */
+    OMX_IndexConfigAudioMute,               /**< reference: OMX_AUDIO_CONFIG_MUTETYPE */
+    OMX_IndexConfigAudioLoudness,           /**< reference: OMX_AUDIO_CONFIG_LOUDNESSTYPE */
+    OMX_IndexConfigAudioEchoCancelation,    /**< reference: OMX_AUDIO_CONFIG_ECHOCANCELATIONTYPE */
+    OMX_IndexConfigAudioNoiseReduction,     /**< reference: OMX_AUDIO_CONFIG_NOISEREDUCTIONTYPE */
+    OMX_IndexConfigAudioBass,               /**< reference: OMX_AUDIO_CONFIG_BASSTYPE */
+    OMX_IndexConfigAudioTreble,             /**< reference: OMX_AUDIO_CONFIG_TREBLETYPE */
+    OMX_IndexConfigAudioStereoWidening,     /**< reference: OMX_AUDIO_CONFIG_STEREOWIDENINGTYPE */
+    OMX_IndexConfigAudioChorus,             /**< reference: OMX_AUDIO_CONFIG_CHORUSTYPE */
+    OMX_IndexConfigAudioEqualizer,          /**< reference: OMX_AUDIO_CONFIG_EQUALIZERTYPE */
+    OMX_IndexConfigAudioReverberation,      /**< reference: OMX_AUDIO_CONFIG_REVERBERATIONTYPE */
+    OMX_IndexConfigAudioChannelVolume,      /**< reference: OMX_AUDIO_CONFIG_CHANNELVOLUMETYPE */
+
+    /* Image specific parameters and configurations */
+    OMX_IndexImageStartUnused = 0x05000000,
+    OMX_IndexParamImagePortFormat,          /**< reference: OMX_IMAGE_PARAM_PORTFORMATTYPE */
+    OMX_IndexParamFlashControl,             /**< reference: OMX_IMAGE_PARAM_FLASHCONTROLTYPE */
+    OMX_IndexConfigFocusControl,            /**< reference: OMX_IMAGE_CONFIG_FOCUSCONTROLTYPE */
+    OMX_IndexParamQFactor,                  /**< reference: OMX_IMAGE_PARAM_QFACTORTYPE */
+    OMX_IndexParamQuantizationTable,        /**< reference: OMX_IMAGE_PARAM_QUANTIZATIONTABLETYPE */
+    OMX_IndexParamHuffmanTable,             /**< reference: OMX_IMAGE_PARAM_HUFFMANTTABLETYPE */
+    OMX_IndexConfigFlashControl,            /**< reference: OMX_IMAGE_PARAM_FLASHCONTROLTYPE */
+
+    /* Video specific parameters and configurations */
+    OMX_IndexVideoStartUnused = 0x06000000,
+    OMX_IndexParamVideoPortFormat,          /**< reference: OMX_VIDEO_PARAM_PORTFORMATTYPE */
+    OMX_IndexParamVideoQuantization,        /**< reference: OMX_VIDEO_PARAM_QUANTIZATIONTYPE */
+    OMX_IndexParamVideoFastUpdate,          /**< reference: OMX_VIDEO_PARAM_VIDEOFASTUPDATETYPE */
+    OMX_IndexParamVideoBitrate,             /**< reference: OMX_VIDEO_PARAM_BITRATETYPE */
+    OMX_IndexParamVideoMotionVector,        /**< reference: OMX_VIDEO_PARAM_MOTIONVECTORTYPE */
+    OMX_IndexParamVideoIntraRefresh,        /**< reference: OMX_VIDEO_PARAM_INTRAREFRESHTYPE */
+    OMX_IndexParamVideoErrorCorrection,     /**< reference: OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE */
+    OMX_IndexParamVideoVBSMC,               /**< reference: OMX_VIDEO_PARAM_VBSMCTYPE */
+    OMX_IndexParamVideoMpeg2,               /**< reference: OMX_VIDEO_PARAM_MPEG2TYPE */
+    OMX_IndexParamVideoMpeg4,               /**< reference: OMX_VIDEO_PARAM_MPEG4TYPE */
+    OMX_IndexParamVideoWmv,                 /**< reference: OMX_VIDEO_PARAM_WMVTYPE */
+    OMX_IndexParamVideoRv,                  /**< reference: OMX_VIDEO_PARAM_RVTYPE */
+    OMX_IndexParamVideoAvc,                 /**< reference: OMX_VIDEO_PARAM_AVCTYPE */
+    OMX_IndexParamVideoH263,                /**< reference: OMX_VIDEO_PARAM_H263TYPE */
+    OMX_IndexParamVideoProfileLevelQuerySupported, /**< reference: OMX_VIDEO_PARAM_PROFILELEVELTYPE */
+    OMX_IndexParamVideoProfileLevelCurrent, /**< reference: OMX_VIDEO_PARAM_PROFILELEVELTYPE */
+    OMX_IndexConfigVideoBitrate,            /**< reference: OMX_VIDEO_CONFIG_BITRATETYPE */
+    OMX_IndexConfigVideoFramerate,          /**< reference: OMX_CONFIG_FRAMERATETYPE */
+    OMX_IndexConfigVideoIntraVOPRefresh,    /**< reference: OMX_CONFIG_INTRAREFRESHVOPTYPE */
+    OMX_IndexConfigVideoIntraMBRefresh,     /**< reference: OMX_CONFIG_MACROBLOCKERRORMAPTYPE */
+    OMX_IndexConfigVideoMBErrorReporting,   /**< reference: OMX_CONFIG_MBERRORREPORTINGTYPE */
+    OMX_IndexParamVideoMacroblocksPerFrame, /**< reference: OMX_PARAM_MACROBLOCKSTYPE */
+    OMX_IndexConfigVideoMacroBlockErrorMap, /**< reference: OMX_CONFIG_MACROBLOCKERRORMAPTYPE */
+    OMX_IndexParamVideoSliceFMO,            /**< reference: OMX_VIDEO_PARAM_AVCSLICEFMO */
+    OMX_IndexConfigVideoAVCIntraPeriod,     /**< reference: OMX_VIDEO_CONFIG_AVCINTRAPERIOD */
+    OMX_IndexConfigVideoNalSize,            /**< reference: OMX_VIDEO_CONFIG_NALSIZE */
+
+    /* Image & Video common Configurations */
+    OMX_IndexCommonStartUnused = 0x07000000,
+    OMX_IndexParamCommonDeblocking,         /**< reference: OMX_PARAM_DEBLOCKINGTYPE */
+    OMX_IndexParamCommonSensorMode,         /**< reference: OMX_PARAM_SENSORMODETYPE */
+    OMX_IndexParamCommonInterleave,         /**< reference: OMX_PARAM_INTERLEAVETYPE */
+    OMX_IndexConfigCommonColorFormatConversion, /**< reference: OMX_CONFIG_COLORCONVERSIONTYPE */
+    OMX_IndexConfigCommonScale,             /**< reference: OMX_CONFIG_SCALEFACTORTYPE */
+    OMX_IndexConfigCommonImageFilter,       /**< reference: OMX_CONFIG_IMAGEFILTERTYPE */
+    OMX_IndexConfigCommonColorEnhancement,  /**< reference: OMX_CONFIG_COLORENHANCEMENTTYPE */
+    OMX_IndexConfigCommonColorKey,          /**< reference: OMX_CONFIG_COLORKEYTYPE */
+    OMX_IndexConfigCommonColorBlend,        /**< reference: OMX_CONFIG_COLORBLENDTYPE */
+    OMX_IndexConfigCommonFrameStabilisation,/**< reference: OMX_CONFIG_FRAMESTABTYPE */
+    OMX_IndexConfigCommonRotate,            /**< reference: OMX_CONFIG_ROTATIONTYPE */
+    OMX_IndexConfigCommonMirror,            /**< reference: OMX_CONFIG_MIRRORTYPE */
+    OMX_IndexConfigCommonOutputPosition,    /**< reference: OMX_CONFIG_POINTTYPE */
+    OMX_IndexConfigCommonInputCrop,         /**< reference: OMX_CONFIG_RECTTYPE */
+    OMX_IndexConfigCommonOutputCrop,        /**< reference: OMX_CONFIG_RECTTYPE */
+    OMX_IndexConfigCommonDigitalZoom,       /**< reference: OMX_CONFIG_SCALEFACTORTYPE */
+    OMX_IndexConfigCommonOpticalZoom,       /**< reference: OMX_CONFIG_SCALEFACTORTYPE*/
+    OMX_IndexConfigCommonWhiteBalance,      /**< reference: OMX_CONFIG_WHITEBALCONTROLTYPE */
+    OMX_IndexConfigCommonExposure,          /**< reference: OMX_CONFIG_EXPOSURECONTROLTYPE */
+    OMX_IndexConfigCommonContrast,          /**< reference: OMX_CONFIG_CONTRASTTYPE */
+    OMX_IndexConfigCommonBrightness,        /**< reference: OMX_CONFIG_BRIGHTNESSTYPE */
+    OMX_IndexConfigCommonBacklight,         /**< reference: OMX_CONFIG_BACKLIGHTTYPE */
+    OMX_IndexConfigCommonGamma,             /**< reference: OMX_CONFIG_GAMMATYPE */
+    OMX_IndexConfigCommonSaturation,        /**< reference: OMX_CONFIG_SATURATIONTYPE */
+    OMX_IndexConfigCommonLightness,         /**< reference: OMX_CONFIG_LIGHTNESSTYPE */
+    OMX_IndexConfigCommonExclusionRect,     /**< reference: OMX_CONFIG_RECTTYPE */
+    OMX_IndexConfigCommonDithering,         /**< reference: OMX_CONFIG_DITHERTYPE */
+    OMX_IndexConfigCommonPlaneBlend,        /**< reference: OMX_CONFIG_PLANEBLENDTYPE */
+    OMX_IndexConfigCommonExposureValue,     /**< reference: OMX_CONFIG_EXPOSUREVALUETYPE */
+    OMX_IndexConfigCommonOutputSize,        /**< reference: OMX_FRAMESIZETYPE */
+    OMX_IndexParamCommonExtraQuantData,     /**< reference: OMX_OTHER_EXTRADATATYPE */
+    OMX_IndexConfigCommonFocusRegion,       /**< reference: OMX_CONFIG_FOCUSREGIONTYPE */
+    OMX_IndexConfigCommonFocusStatus,       /**< reference: OMX_PARAM_FOCUSSTATUSTYPE */
+    OMX_IndexConfigCommonTransitionEffect,  /**< reference: OMX_CONFIG_TRANSITIONEFFECTTYPE */
+
+    /* Reserved Configuration range */
+    OMX_IndexOtherStartUnused = 0x08000000,
+    OMX_IndexParamOtherPortFormat,          /**< reference: OMX_OTHER_PARAM_PORTFORMATTYPE */
+    OMX_IndexConfigOtherPower,              /**< reference: OMX_OTHER_CONFIG_POWERTYPE */
+    OMX_IndexConfigOtherStats,              /**< reference: OMX_OTHER_CONFIG_STATSTYPE */
+
+
+    /* Reserved Time range */
+    OMX_IndexTimeStartUnused = 0x09000000,
+    OMX_IndexConfigTimeScale,               /**< reference: OMX_TIME_CONFIG_SCALETYPE */
+    OMX_IndexConfigTimeClockState,          /**< reference: OMX_TIME_CONFIG_CLOCKSTATETYPE */
+    OMX_IndexConfigTimeActiveRefClock,      /**< reference: OMX_TIME_CONFIG_ACTIVEREFCLOCKTYPE */
+    OMX_IndexConfigTimeCurrentMediaTime,    /**< reference: OMX_TIME_CONFIG_TIMESTAMPTYPE (read only) */
+    OMX_IndexConfigTimeCurrentWallTime,     /**< reference: OMX_TIME_CONFIG_TIMESTAMPTYPE (read only) */
+    OMX_IndexConfigTimeCurrentAudioReference, /**< reference: OMX_TIME_CONFIG_TIMESTAMPTYPE (write only) */
+    OMX_IndexConfigTimeCurrentVideoReference, /**< reference: OMX_TIME_CONFIG_TIMESTAMPTYPE (write only) */
+    OMX_IndexConfigTimeMediaTimeRequest,    /**< reference: OMX_TIME_CONFIG_MEDIATIMEREQUESTTYPE (write only) */
+    OMX_IndexConfigTimeClientStartTime,     /**<reference:  OMX_TIME_CONFIG_TIMESTAMPTYPE (write only) */
+    OMX_IndexConfigTimePosition,            /**< reference: OMX_TIME_CONFIG_TIMESTAMPTYPE */
+    OMX_IndexConfigTimeSeekMode,            /**< reference: OMX_TIME_CONFIG_SEEKMODETYPE */
+
+
+    OMX_IndexKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
+    /* Vendor specific area */
+    OMX_IndexVendorStartUnused = 0x7F000000,
+    /* Vendor specific structures should be in the range of 0x7F000000
+       to 0x7FFFFFFE.  This range is not broken out by vendor, so
+       private indexes are not guaranteed unique and therefore should
+       only be sent to the appropriate component. */
+
+    /* used for ilcs-top communication */
+    OMX_IndexParamMarkComparison,           /**< reference: OMX_PARAM_MARKCOMPARISONTYPE */
+    OMX_IndexParamPortSummary,              /**< reference: OMX_PARAM_PORTSUMMARYTYPE */
+    OMX_IndexParamTunnelStatus,             /**< reference : OMX_PARAM_TUNNELSTATUSTYPE */
+    OMX_IndexParamBrcmRecursionUnsafe,      /**< reference: OMX_PARAM_BRCMRECURSIONUNSAFETYPE */
+
+    /* used for top-ril communication */
+    OMX_IndexParamBufferAddress,            /**< reference : OMX_PARAM_BUFFERADDRESSTYPE */
+    OMX_IndexParamTunnelSetup,              /**< reference : OMX_PARAM_TUNNELSETUPTYPE */
+    OMX_IndexParamBrcmPortEGL,              /**< reference : OMX_PARAM_BRCMPORTEGLTYPE */
+    OMX_IndexParamIdleResourceCount,        /**< reference : OMX_PARAM_U32TYPE */
+
+    /* used for ril-ril communication */
+    OMX_IndexParamImagePoolDisplayFunction, /**<reference : OMX_PARAM_IMAGEDISPLAYFUNCTIONTYPE */
+    OMX_IndexParamBrcmDataUnit,             /**<reference: OMX_PARAM_DATAUNITTYPE */
+    OMX_IndexParamCodecConfig,              /**<reference: OMX_PARAM_CODECCONFIGTYPE */
+    OMX_IndexParamCameraPoolToEncoderFunction, /**<reference : OMX_PARAM_CAMERAPOOLTOENCODERFUNCTIONTYPE */
+    OMX_IndexParamCameraStripeFunction,     /**<reference : OMX_PARAM_CAMERASTRIPEFUNCTIONTYPE */
+    OMX_IndexParamCameraCaptureEventFunction, /**<reference : OMX_PARAM_CAMERACAPTUREEVENTFUNCTIONTYPE */
+
+    /* used for client-ril communication */
+    OMX_IndexParamTestInterface,            /**< reference : OMX_PARAM_TESTINTERFACETYPE */
+
+    // 0x7f000010
+    OMX_IndexConfigDisplayRegion,           /**< reference : OMX_CONFIG_DISPLAYREGIONTYPE */
+    OMX_IndexParamSource,                   /**< reference : OMX_PARAM_SOURCETYPE */
+    OMX_IndexParamSourceSeed,               /**< reference : OMX_PARAM_SOURCESEEDTYPE */
+    OMX_IndexParamResize,                   /**< reference : OMX_PARAM_RESIZETYPE */
+    OMX_IndexConfigVisualisation,           /**< reference : OMX_CONFIG_VISUALISATIONTYPE */
+    OMX_IndexConfigSingleStep,              /**<reference : OMX_PARAM_U32TYPE */
+    OMX_IndexConfigPlayMode,                /**<reference: OMX_CONFIG_PLAYMODETYPE */
+    OMX_IndexParamCameraCamplusId,          /**<reference : OMX_PARAM_U32TYPE */
+    OMX_IndexConfigCommonImageFilterParameters,  /**<reference : OMX_CONFIG_IMAGEFILTERPARAMSTYPE */
+    OMX_IndexConfigTransitionControl,       /**<reference : OMX_CONFIG_TRANSITIONCONTROLTYPE */
+    OMX_IndexConfigPresentationOffset,      /**<reference: OMX_TIME_CONFIG_TIMESTAMPTYPE */
+    OMX_IndexParamSourceFunctions,          /**<reference: OMX_PARAM_STILLSFUNCTIONTYPE */
+    OMX_IndexConfigAudioMonoTrackControl,   /**<reference : OMX_CONFIG_AUDIOMONOTRACKCONTROLTYPE */
+    OMX_IndexParamCameraImagePool,          /**<reference : OMX_PARAM_CAMERAIMAGEPOOLTYPE */
+    OMX_IndexConfigCameraISPOutputPoolHeight,/**<reference : OMX_PARAM_U32TYPE */
+    OMX_IndexParamImagePoolSize,            /**<reference: OMX_PARAM_IMAGEPOOLSIZETYPE */
+
+    // 0x7f000020
+    OMX_IndexParamImagePoolExternal,        /**<reference: OMX_PARAM_IMAGEPOOLEXTERNALTYPE */
+    OMX_IndexParamRUTILFifoInfo,            /**<reference: OMX_PARAM_RUTILFIFOINFOTYPE*/
+    OMX_IndexParamILFifoConfig,             /**<reference: OMX_PARAM_ILFIFOCONFIG */
+    OMX_IndexConfigCameraSensorModes,       /**<reference : OMX_CONFIG_CAMERASENSORMODETYPE */
+    OMX_IndexConfigBrcmPortStats,           /**<reference : OMX_CONFIG_BRCMPORTSTATSTYPE */
+    OMX_IndexConfigBrcmPortBufferStats,     /**<reference : OMX_CONFIG_BRCMPORTBUFFERSTATSTYPE */
+    OMX_IndexConfigBrcmCameraStats,         /**<reference : OMX_CONFIG_BRCMCAMERASTATSTYPE */
+    OMX_IndexConfigBrcmIOPerfStats,         /**<reference : OMX_CONFIG_BRCMIOPERFSTATSTYPE */
+    OMX_IndexConfigCommonSharpness,         /**<reference : OMX_CONFIG_SHARPNESSTYPE */
+    OMX_IndexConfigCommonFlickerCancellation,   /**reference : OMX_CONFIG_FLICKERCANCELTYPE */
+    OMX_IndexParamCameraSwapImagePools,     /**<reference : OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamCameraSingleBufferCaptureInput,  /**<reference : OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigCommonRedEyeRemoval,   /**<reference : OMX_CONFIG_REDEYEREMOVALTYPE  */
+    OMX_IndexConfigCommonFaceDetectionControl,  /**<reference : OMX_CONFIG_FACEDETECTIONCONTROLTYPE */
+    OMX_IndexConfigCommonFaceDetectionRegion,   /**<reference : OMX_CONFIG_FACEDETECTIONREGIONTYPE */
+    OMX_IndexConfigCommonInterlace,         /**<reference: OMX_CONFIG_INTERLACETYPE */
+
+    // 0x7f000030
+    OMX_IndexParamISPTunerName,             /**<reference: OMX_PARAM_CAMERAISPTUNERTYPE */
+    OMX_IndexParamCameraDeviceNumber,       /**<reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamCameraDevicesPresent,     /**<reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigCameraInputFrame,        /**<reference: OMX_CONFIG_IMAGEPTRTYPE */
+    OMX_IndexConfigStillColourDenoiseEnable,    /**<reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigVideoColourDenoiseEnable,    /**<reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigAFAssistLight,           /**<reference: OMX_CONFIG_AFASSISTTYPE */
+    OMX_IndexConfigSmartShakeReductionEnable, /**<reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigInputCropPercentages,    /**<reference: OMX_CONFIG_INPUTCROPTYPE */
+    OMX_IndexConfigStillsAntiShakeEnable,   /**<reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigWaitForFocusBeforeCapture,/**<reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigAudioRenderingLatency,   /**<reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigDrawBoxAroundFaces,      /**<reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamCodecRequirements,        /**<reference: OMX_PARAM_CODECREQUIREMENTSTYPE */
+    OMX_IndexConfigBrcmEGLImageMemHandle,   /**<reference: OMX_CONFIG_BRCMEGLIMAGEMEMHANDLETYPE */
+    OMX_IndexConfigPrivacyIndicator,        /**<reference: OMX_CONFIG_PRIVACYINDICATORTYPE */
+
+    // 0x7f000040
+    OMX_IndexParamCameraFlashType,          /**<reference: OMX_PARAM_CAMERAFLASHTYPE */
+    OMX_IndexConfigCameraEnableStatsPass,   /**<reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigCameraFlashConfig,       /**<reference: OMX_CONFIG_CAMERAFLASHCONFIGTYPE */
+    OMX_IndexConfigCaptureRawImageURI,      /**<reference: OMX_PARAM_CONTENTURITYPE */
+    OMX_IndexConfigCameraStripeFuncMinLines, /**<reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigCameraAlgorithmVersionDeprecated,   /**<reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigCameraIsoReferenceValue,  /**<reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigCameraCaptureAbortsAutoFocus, /**<reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigBrcmClockMissCount,      /**<reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigFlashChargeLevel,         /**<reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigBrcmVideoEncodedSliceSize, /**<reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigBrcmAudioTrackGaplessPlayback,  /**< reference: OMX_CONFIG_BRCMAUDIOTRACKGAPLESSPLAYBACKTYPE */
+    OMX_IndexConfigBrcmAudioTrackChangeControl,    /**< reference: OMX_CONFIG_BRCMAUDIOTRACKCHANGECONTROLTYPE */
+    OMX_IndexParamBrcmPixelAspectRatio,     /**< reference: OMX_CONFIG_POINTTYPE */
+    OMX_IndexParamBrcmPixelValueRange,      /**< reference: OMX_PARAM_BRCMPIXELVALUERANGETYPE */
+    OMX_IndexParamCameraDisableAlgorithm,   /**< reference: OMX_PARAM_CAMERADISABLEALGORITHMTYPE */
+
+    // 0x7f000050
+    OMX_IndexConfigBrcmVideoIntraPeriodTime, /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigBrcmVideoIntraPeriod,     /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigBrcmAudioEffectControl, /**< reference: OMX_CONFIG_BRCMAUDIOEFFECTCONTROLTYPE */
+    OMX_IndexConfigBrcmMinimumProcessingLatency, /**< reference: OMX_CONFIG_BRCMMINIMUMPROCESSINGLATENCY */
+    OMX_IndexParamBrcmVideoAVCSEIEnable,    /**< reference: OMX_PARAM_BRCMVIDEOAVCSEIENABLETYPE */
+    OMX_IndexParamBrcmAllowMemChange,   /**< reference: OMX_PARAM_BRCMALLOWMEMCHANGETYPE */
+    OMX_IndexConfigBrcmVideoEncoderMBRowsPerSlice, /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamCameraAFAssistDeviceNumber_Deprecated,   /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamCameraPrivacyIndicatorDeviceNumber_Deprecated,   /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigCameraUseCase,               /**< reference: OMX_CONFIG_CAMERAUSECASETYPE */
+    OMX_IndexParamBrcmDisableProprietaryTunnels,   /**< reference: OMX_PARAM_BRCMDISABLEPROPRIETARYTUNNELSTYPE */
+    OMX_IndexParamBrcmOutputBufferSize,         /**<  reference: OMX_PARAM_BRCMOUTPUTBUFFERSIZETYPE */
+    OMX_IndexParamBrcmRetainMemory,             /**< reference: OMX_PARAM_BRCMRETAINMEMORYTYPE */
+    OMX_IndexConfigCanFocus_Deprecated,                    /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamBrcmImmutableInput,           /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamDynamicParameterFile,        /**< reference: OMX_PARAM_CONTENTURITYPE */
+
+    // 0x7f000060
+    OMX_IndexParamUseDynamicParameterFile,     /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigCameraInfo,                 /**< reference: OMX_CONFIG_CAMERAINFOTYPE */
+    OMX_IndexConfigCameraFeatures,             /**< reference: OMX_CONFIG_CAMERAFEATURESTYPE */
+    OMX_IndexConfigRequestCallback,            /**< reference: OMX_CONFIG_REQUESTCALLBACKTYPE */ //Should be added to the spec as part of IL416c
+    OMX_IndexConfigBrcmOutputBufferFullCount,  /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigCommonFocusRegionXY,        /**< reference: OMX_CONFIG_FOCUSREGIONXYTYPE */
+    OMX_IndexParamBrcmDisableEXIF,             /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigUserSettingsId,             /**< reference: OMX_CONFIG_U8TYPE */
+    OMX_IndexConfigCameraSettings,             /**< reference: OMX_CONFIG_CAMERASETTINGSTYPE */
+    OMX_IndexConfigDrawBoxLineParams,          /**< reference: OMX_CONFIG_DRAWBOXLINEPARAMS */
+    OMX_IndexParamCameraRmiControl_Deprecated,            /**< reference: OMX_PARAM_CAMERARMITYPE */
+    OMX_IndexConfigBurstCapture,               /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamBrcmEnableIJGTableScaling,   /**< reference: OMX_PARAM_IJGSCALINGTYPE */
+    OMX_IndexConfigPowerDown,                  /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigBrcmSyncOutput,             /**< reference: OMX_CONFIG_BRCMSYNCOUTPUTTYPE */
+    OMX_IndexParamBrcmFlushCallback,           /**< reference: OMX_PARAM_BRCMFLUSHCALLBACK */
+
+    // 0x7f000070
+    OMX_IndexConfigBrcmVideoRequestIFrame,     /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamBrcmNALSSeparate,            /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigConfirmView,                /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigDrmView,                    /**< reference: OMX_CONFIG_DRMVIEWTYPE */
+    OMX_IndexConfigBrcmVideoIntraRefresh,      /**< reference: OMX_VIDEO_PARAM_INTRAREFRESHTYPE */
+    OMX_IndexParamBrcmMaxFileSize,             /**< reference: OMX_PARAM_BRCMU64TYPE */
+    OMX_IndexParamBrcmCRCEnable,               /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamBrcmCRC,                     /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigCameraRmiInUse_Deprecated,             /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigBrcmAudioSource,            /**<reference: OMX_CONFIG_BRCMAUDIOSOURCETYPE */
+    OMX_IndexConfigBrcmAudioDestination,       /**< reference: OMX_CONFIG_BRCMAUDIODESTINATIONTYPE */
+    OMX_IndexParamAudioDdp,                    /**< reference: OMX_AUDIO_PARAM_DDPTYPE */
+    OMX_IndexParamBrcmThumbnail,               /**< reference: OMX_PARAM_BRCMTHUMBNAILTYPE */
+    OMX_IndexParamBrcmDisableLegacyBlocks_Deprecated,     /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamBrcmCameraInputAspectRatio,  /**< reference: OMX_PARAM_BRCMASPECTRATIOTYPE */
+    OMX_IndexParamDynamicParameterFileFailFatal,/**< reference: OMX_CONFIG_BOOLEANTYPE */
+
+    // 0x7f000080
+    OMX_IndexParamBrcmVideoDecodeErrorConcealment, /**< reference: OMX_PARAM_BRCMVIDEODECODEERRORCONCEALMENTTYPE */
+    OMX_IndexParamBrcmInterpolateMissingTimestamps, /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamBrcmSetCodecPerformanceMonitoring, /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigFlashInfo,                  /**< reference: OMX_CONFIG_FLASHINFOTYPE */
+    OMX_IndexParamBrcmMaxFrameSkips,           /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigDynamicRangeExpansion,      /**< reference: OMX_CONFIG_DYNAMICRANGEEXPANSIONTYPE */
+    OMX_IndexParamBrcmFlushCallbackId,         /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamBrcmTransposeBufferCount,    /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigFaceRecognitionControl,     /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigFaceRecognitionSaveFace,    /**< reference: OMX_PARAM_BRCMU64TYPE */
+    OMX_IndexConfigFaceRecognitionDatabaseUri, /**< reference: OMX_PARAM_CONTENTURITYPE */
+    OMX_IndexConfigClockAdjustment,            /**< reference: OMX_TIME_CONFIG_TIMESTAMPTYPE */
+    OMX_IndexParamBrcmThreadAffinity,          /**< reference: OMX_PARAM_BRCMTHREADAFFINITYTYPE */
+    OMX_IndexParamAsynchronousOutput,          /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigAsynchronousFailureURI,     /**< reference: OMX_PARAM_CONTENTURITYPE */
+    OMX_IndexConfigCommonFaceBeautification,   /**< reference: OMX_CONFIG_BOOLEANTYPE */
+
+    // 0x7f000090
+    OMX_IndexConfigCommonSceneDetectionControl,/**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigCommonSceneDetected,        /**< reference: OMX_CONFIG_SCENEDETECTTYPE */
+    OMX_IndexParamDisableVllPool,              /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamVideoMvc,                    /**< reference: OMX_VIDEO_PARAM_MVCTYPE */
+    OMX_IndexConfigBrcmDrawStaticBox,          /**< reference: OMX_CONFIG_STATICBOXTYPE */
+    OMX_IndexConfigBrcmClockReferenceSource,   /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamPassBufferMarks,             /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigPortCapturing,              /**< reference: OMX_CONFIG_PORTBOOLEANTYPE */
+    OMX_IndexConfigBrcmDecoderPassThrough,     /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamBrcmDecoderPassThrough=OMX_IndexConfigBrcmDecoderPassThrough,  /* deprecated */
+    OMX_IndexParamBrcmMaxCorruptMBs,           /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigBrcmGlobalAudioMute,        /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamCameraCaptureMode,           /**< reference: OMX_PARAM_CAMERACAPTUREMODETYPE */
+    OMX_IndexParamBrcmDrmEncryption,           /**< reference: OMX_PARAM_BRCMDRMENCRYPTIONTYPE */
+    OMX_IndexConfigBrcmCameraRnDPreprocess,    /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigBrcmCameraRnDPostprocess,   /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigBrcmAudioTrackChangeCount,  /**< reference: OMX_PARAM_U32TYPE */
+
+    // 0x7f0000a0
+    OMX_IndexParamCommonUseStcTimestamps,      /**< reference: OMX_PARAM_TIMESTAMPMODETYPE */
+    OMX_IndexConfigBufferStall,                /**< reference: OMX_CONFIG_BUFFERSTALLTYPE */
+    OMX_IndexConfigRefreshCodec,               /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamCaptureStatus,               /**< reference: OMX_PARAM_CAPTURESTATETYPE */
+    OMX_IndexConfigTimeInvalidStartTime,       /**< reference: OMX_TIME_CONFIG_TIMESTAMPTYPE */
+    OMX_IndexConfigLatencyTarget,              /**< reference: OMX_CONFIG_LATENCYTARGETTYPE */
+    OMX_IndexConfigMinimiseFragmentation,      /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigBrcmUseProprietaryCallback, /**< reference: OMX_CONFIG_BRCMUSEPROPRIETARYTUNNELTYPE */
+    OMX_IndexParamPortMaxFrameSize,            /**< reference: OMX_FRAMESIZETYPE */
+    OMX_IndexParamComponentName,               /**< reference: OMX_PARAM_COMPONENTROLETYPE */
+    OMX_IndexConfigEncLevelExtension,          /**< reference: OMX_VIDEO_CONFIG_LEVEL_EXTEND */
+    OMX_IndexConfigTemporalDenoiseEnable,      /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamBrcmLazyImagePoolDestroy,    /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamBrcmEEDEEnable,              /**< reference: OMX_VIDEO_EEDE_ENABLE */
+    OMX_IndexParamBrcmEEDELossRate,            /**< reference: OMX_VIDEO_EEDE_LOSSRATE */
+    OMX_IndexParamAudioDts,                    /**< reference: OMX_AUDIO_PARAM_DTSTYPE */
+
+    // 0x7f0000b0
+    OMX_IndexParamNumOutputChannels,           /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigBrcmHighDynamicRange,       /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigBrcmPoolMemAllocSize,       /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigBrcmBufferFlagFilter,       /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamBrcmVideoEncodeMinQuant,     /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamBrcmVideoEncodeMaxQuant,     /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamRateControlModel,            /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamBrcmExtraBuffers,            /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigFieldOfView,                /**< reference: OMX_CONFIG_BRCMFOVTYPE */
+    OMX_IndexParamBrcmAlignHoriz,              /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamBrcmAlignVert,               /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamColorSpace,                  /**< reference: OMX_PARAM_COLORSPACETYPE */
+    OMX_IndexParamBrcmDroppablePFrames,        /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamBrcmVideoInitialQuant,       /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamBrcmVideoEncodeQpP,          /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamBrcmVideoRCSliceDQuant,      /**< reference: OMX_PARAM_U32TYPE */
+
+    // 0x7f0000c0
+    OMX_IndexParamBrcmVideoFrameLimitBits,     /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamBrcmVideoPeakRate,           /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigBrcmVideoH264DisableCABAC,  /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigBrcmVideoH264LowLatency,    /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigBrcmVideoH264AUDelimiters,  /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigBrcmVideoH264DeblockIDC,    /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigBrcmVideoH264IntraMBMode,   /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexConfigContrastEnhance,            /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamCameraCustomSensorConfig,    /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamBrcmHeaderOnOpen,            /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigBrcmUseRegisterFile,        /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigBrcmRegisterFileFailFatal,  /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamBrcmConfigFileRegisters,     /**< reference: OMX_PARAM_BRCMCONFIGFILETYPE */
+    OMX_IndexParamBrcmConfigFileChunkRegisters,/**< reference: OMX_PARAM_BRCMCONFIGFILECHUNKTYPE */
+    OMX_IndexParamBrcmAttachLog,               /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamCameraZeroShutterLag,        /**< reference: OMX_CONFIG_ZEROSHUTTERLAGTYPE */
+
+    // 0x7f0000d0
+    OMX_IndexParamBrcmFpsRange,                /**< reference: OMX_PARAM_BRCMFRAMERATERANGETYPE */
+    OMX_IndexParamCaptureExposureCompensation, /**< reference: OMX_PARAM_S32TYPE */
+    OMX_IndexParamBrcmVideoPrecodeForQP,       /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamBrcmVideoTimestampFifo,      /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamSWSharpenDisable,            /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexConfigBrcmFlashRequired,          /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamBrcmVideoDrmProtectBuffer,   /**< reference: OMX_PARAM_BRCMVIDEODRMPROTECTBUFFERTYPE */
+    OMX_IndexParamSWSaturationDisable,         /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamBrcmVideoDecodeConfigVD3,    /**< reference: OMX_PARAM_BRCMVIDEODECODECONFIGVD3TYPE */
+    OMX_IndexConfigBrcmPowerMonitor,           /**< reference: OMX_CONFIG_BOOLEANTYPE */
+    OMX_IndexParamBrcmZeroCopy,                /**< reference: OMX_CONFIG_PORTBOOLEANTYPE */
+    OMX_IndexParamBrcmVideoEGLRenderDiscardMode,   /**< reference: OMX_CONFIG_PORTBOOLEANTYPE */
+    OMX_IndexParamBrcmVideoAVC_VCLHRDEnable,    /**< reference: OMX_CONFIG_PORTBOOLEANTYPE*/
+    OMX_IndexParamBrcmVideoAVC_LowDelayHRDEnable, /**< reference: OMX_CONFIG_PORTBOOLEANTYPE*/
+    OMX_IndexParamBrcmVideoCroppingDisable,    /**< reference: OMX_CONFIG_PORTBOOLEANTYPE*/
+    OMX_IndexParamBrcmVideoAVCInlineHeaderEnable, /**< reference: OMX_CONFIG_PORTBOOLEANTYPE*/
+
+    // 0x7f0000f0
+    OMX_IndexConfigBrcmAudioDownmixCoefficients = 0x7f0000f0, /**< reference: OMX_CONFIG_BRCMAUDIODOWNMIXCOEFFICIENTS */
+    OMX_IndexConfigBrcmAudioDownmixCoefficients8x8,           /**< reference: OMX_CONFIG_BRCMAUDIODOWNMIXCOEFFICIENTS8x8 */
+    OMX_IndexConfigBrcmAudioMaxSample,                        /**< reference: OMX_CONFIG_BRCMAUDIOMAXSAMPLE */
+    OMX_IndexConfigCustomAwbGains,                            /**< reference: OMX_CONFIG_CUSTOMAWBGAINSTYPE */
+    OMX_IndexParamRemoveImagePadding,                         /**< reference: OMX_CONFIG_PORTBOOLEANTYPE*/
+    OMX_IndexParamBrcmVideoAVCInlineVectorsEnable,            /**< reference: OMX_CONFIG_PORTBOOLEANTYPE */
+    OMX_IndexConfigBrcmRenderStats,                           /**< reference: OMX_CONFIG_BRCMRENDERSTATSTYPE */
+    OMX_IndexConfigBrcmCameraAnnotate,                        /**< reference: OMX_CONFIG_BRCMANNOTATETYPE */
+    OMX_IndexParamBrcmStereoscopicMode,                       /**< reference :OMX_CONFIG_BRCMSTEREOSCOPICMODETYPE */
+    OMX_IndexParamBrcmLockStepEnable,                         /**< reference: OMX_CONFIG_PORTBOOLEANTYPE */
+    OMX_IndexParamBrcmTimeScale,                              /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamCameraInterface,                            /**< reference: OMX_PARAM_CAMERAINTERFACETYPE */
+    OMX_IndexParamCameraClockingMode,                         /**< reference: OMX_PARAM_CAMERACLOCKINGMODETYPE */
+    OMX_IndexParamCameraRxConfig,                             /**< reference: OMX_PARAM_CAMERARXCONFIG_TYPE */
+    OMX_IndexParamCameraRxTiming,                             /**< reference: OMX_PARAM_CAMERARXTIMING_TYPE */
+    OMX_IndexParamDynamicParameterConfig,                     /**< reference: OMX_PARAM_U32TYPE */
+
+    // 0x7f000100
+    OMX_IndexParamBrcmVideoAVCSPSTimingEnable,                /** reference: OMX_CONFIG_PORTBOOLEANTYPE */
+    OMX_IndexParamBrcmBayerOrder,                             /** reference: OMX_PARAM_BAYERORDERTYPE */
+    OMX_IndexParamBrcmMaxNumCallbacks,                        /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamBrcmJpegRestartInterval,                    /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamBrcmSupportsSlices,                         /**< reference: OMX_CONFIG_PORTBOOLEANTYPE */
+    OMX_IndexParamBrcmIspBlockOverride,                       /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamBrcmSupportsUnalignedSliceheight,           /**< reference: OMX_CONFIG_PORTBOOLEANTYPE */
+    OMX_IndexParamBrcmLensShadingOverride,                    /**< reference: OMX_PARAM_LENSSHADINGOVERRIDETYPE */
+    OMX_IndexParamBrcmBlackLevel,                             /**< reference: OMX_PARAM_U32TYPE */
+    OMX_IndexParamOutputShift,                                /**< reference: OMX_PARAM_S32TYPE */
+    OMX_IndexParamCcmShift,                                   /**< reference: OMX_PARAM_S32TYPE */
+    OMX_IndexParamCustomCcm,                                  /**< reference: OMX_PARAM_CUSTOMCCMTYPE */
+    OMX_IndexConfigCameraAnalogGain,                          /**< reference: OMX_CONFIG_CAMERAGAINTYPE */
+    OMX_IndexConfigCameraDigitalGain,                         /**< reference: OMX_CONFIG_CAMERAGAINTYPE */
+    OMX_IndexMax = 0x7FFFFFFF
+} OMX_INDEXTYPE;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
+/* File EOF */
+
diff --git a/interface/vmcs_host/khronos/IL/OMX_Other.h b/interface/vmcs_host/khronos/IL/OMX_Other.h
new file mode 100755 (executable)
index 0000000..e848dce
--- /dev/null
@@ -0,0 +1,347 @@
+/*
+ * Copyright (c) 2008 The Khronos Group Inc. 
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions: 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
+ *
+ */
+
+/** @file OMX_Other.h - OpenMax IL version 1.1.2
+ *  The structures needed by Other components to exchange
+ *  parameters and configuration data with the components.
+ */
+
+#ifndef OMX_Other_h
+#define OMX_Other_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/* Each OMX header must include all required header files to allow the
+ *  header to compile without errors.  The includes below are required
+ *  for this header file to compile successfully 
+ */
+
+#include "OMX_Core.h"
+
+
+/** 
+ * Enumeration of possible data types which match to multiple domains or no
+ * domain at all.  For types which are vendor specific, a value above
+ * OMX_OTHER_VENDORTSTART should be used.
+ */
+typedef enum OMX_OTHER_FORMATTYPE {
+    OMX_OTHER_FormatTime = 0, /**< Transmission of various timestamps, elapsed time, 
+                                   time deltas, etc */
+    OMX_OTHER_FormatPower,    /**< Perhaps used for enabling/disabling power 
+                                   management, setting clocks? */
+    OMX_OTHER_FormatStats,    /**< Could be things such as frame rate, frames 
+                                   dropped, etc */
+    OMX_OTHER_FormatBinary,   /**< Arbitrary binary data */
+    OMX_OTHER_FormatVendorReserved = 1000, /**< Starting value for vendor specific 
+                                                formats */
+
+    OMX_OTHER_FormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_OTHER_FormatVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+
+    OMX_OTHER_FormatText,
+    OMX_OTHER_FormatTextSKM2,
+    OMX_OTHER_FormatText3GP5,
+
+    OMX_OTHER_FormatMax = 0x7FFFFFFF
+} OMX_OTHER_FORMATTYPE;
+
+/** 
+ * Enumeration of seek modes.
+ */
+typedef enum OMX_TIME_SEEKMODETYPE {
+    OMX_TIME_SeekModeFast = 0, /**< Prefer seeking to an approximation
+                                * of the requested seek position over   
+                                * the actual seek position if it
+                                * results in a faster seek. */
+    OMX_TIME_SeekModeAccurate, /**< Prefer seeking to the actual seek 
+                                * position over an approximation
+                                * of the requested seek position even
+                                * if it results in a slower seek. */
+    OMX_TIME_SeekModeKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_TIME_SeekModeVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+
+    OMX_TIME_SeekModeDirectional, /**< Similar to Fast, but if seeking backwards will
+                                   * try and seek to a previous sync position from the
+                                   * current media time. */
+
+    OMX_TIME_SeekModeMax = 0x7FFFFFFF
+} OMX_TIME_SEEKMODETYPE;
+
+/* Structure representing the seekmode of the component */
+typedef struct OMX_TIME_CONFIG_SEEKMODETYPE {
+    OMX_U32 nSize;                  /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;       /**< OMX specification version information */
+    OMX_TIME_SEEKMODETYPE eType;    /**< The seek mode */
+} OMX_TIME_CONFIG_SEEKMODETYPE;
+
+/** Structure representing a time stamp used with the following configs 
+ * on the Clock Component (CC):
+ * 
+ * OMX_IndexConfigTimeCurrentWallTime: query of the CC\92s current wall  
+ *     time
+ * OMX_IndexConfigTimeCurrentMediaTime: query of the CC\92s current media
+ *     time
+ * OMX_IndexConfigTimeCurrentAudioReference and  
+ * OMX_IndexConfigTimeCurrentVideoReference: audio/video reference 
+ *     clock sending SC its reference time
+ * OMX_IndexConfigTimeClientStartTime: a Clock Component client sends 
+ *     this structure to the Clock Component via a SetConfig on its 
+ *     client port when it receives a buffer with
+ *     OMX_BUFFERFLAG_STARTTIME set. It must use the timestamp
+ *     specified by that buffer for nStartTimestamp. 
+ *
+ * It\92s also used with the following config on components in general:
+ *
+ * OMX_IndexConfigTimePosition: IL client querying component position 
+ * (GetConfig) or commanding a component to seek to the given location
+ * (SetConfig)
+ */    
+typedef struct OMX_TIME_CONFIG_TIMESTAMPTYPE {
+    OMX_U32 nSize;               /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;    /**< OMX specification version
+                                  *   information */
+    OMX_U32 nPortIndex;     /**< port that this structure applies to */
+    OMX_TICKS nTimestamp;           /**< timestamp .*/ 
+} OMX_TIME_CONFIG_TIMESTAMPTYPE;  
+
+/** Enumeration of possible reference clocks to the media time. */
+typedef enum OMX_TIME_UPDATETYPE {
+      OMX_TIME_UpdateRequestFulfillment,    /**< Update is the fulfillment of a media time request. */
+      OMX_TIME_UpdateScaleChanged,             /**< Update was generated because the scale chagned. */
+      OMX_TIME_UpdateClockStateChanged,     /**< Update was generated because the clock state changed. */
+      OMX_TIME_UpdateKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+      OMX_TIME_UpdateVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+      OMX_TIME_UpdateMax = 0x7FFFFFFF
+} OMX_TIME_UPDATETYPE;
+
+/** Enumeration of possible reference clocks to the media time. */
+typedef enum OMX_TIME_REFCLOCKTYPE {
+      OMX_TIME_RefClockNone,    /**< Use no references. */
+      OMX_TIME_RefClockAudio,  /**< Use references sent through OMX_IndexConfigTimeCurrentAudioReference */
+      OMX_TIME_RefClockVideo,   /**< Use references sent through OMX_IndexConfigTimeCurrentVideoReference */
+      OMX_TIME_RefClockKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+      OMX_TIME_RefClockVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+      OMX_TIME_RefClockMax = 0x7FFFFFFF
+} OMX_TIME_REFCLOCKTYPE;
+
+/** Enumeration of clock states. */
+typedef enum OMX_TIME_CLOCKSTATE {
+      OMX_TIME_ClockStateRunning,             /**< Clock running. */
+      OMX_TIME_ClockStateWaitingForStartTime, /**< Clock waiting until the 
+                                               *   prescribed clients emit their
+                                               *   start time. */
+      OMX_TIME_ClockStateStopped,             /**< Clock stopped. */
+      OMX_TIME_ClockStateKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+      OMX_TIME_ClockStateVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+      OMX_TIME_ClockStateMax = 0x7FFFFFFF
+} OMX_TIME_CLOCKSTATE;
+
+/** Structure representing a media time request to the clock component.
+ *
+ *  A client component sends this structure to the Clock Component via a SetConfig
+ *  on its client port to specify a media timestamp the Clock Component
+ *  should emit.  The Clock Component should fulfill the request by sending a
+ *  OMX_TIME_MEDIATIMETYPE when its media clock matches the requested 
+ *  timestamp.
+ *
+ *  The client may require a media time request be fulfilled slightly
+ *  earlier than the media time specified. In this case the client specifies 
+ *  an offset which is equal to the difference between wall time corresponding 
+ *  to the requested media time and the wall time when it will be 
+ *  fulfilled. 
+ *
+ *  A client component may uses these requests and the OMX_TIME_MEDIATIMETYPE to
+ *  time events according to timestamps. If a client must perform an operation O at
+ *  a time T (e.g. deliver a video frame at its corresponding timestamp), it makes a 
+ *  media time request at T (perhaps specifying an offset to ensure the request fulfillment
+ *  is a little early). When the clock component passes the resulting OMX_TIME_MEDIATIMETYPE
+ *  structure back to the client component, the client may perform operation O (perhaps having
+ *  to wait a slight amount more time itself as specified by the return values).
+ */
+
+typedef struct OMX_TIME_CONFIG_MEDIATIMEREQUESTTYPE {
+    OMX_U32 nSize;              /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;   /**< OMX specification version information */
+    OMX_U32 nPortIndex;         /**< port that this structure applies to */
+    OMX_PTR pClientPrivate;     /**< Client private data to disabiguate this media time 
+                                 *   from others (e.g. the number of the frame to deliver). 
+                                 *   Duplicated in the media time structure that fulfills 
+                                 *   this request. A value of zero is reserved for time scale 
+                                 *   updates. */
+    OMX_TICKS nMediaTimestamp;  /**< Media timestamp requested.*/ 
+    OMX_TICKS nOffset;          /**< Amount of wall clock time by which this
+                                 *   request should be fulfilled early */
+} OMX_TIME_CONFIG_MEDIATIMEREQUESTTYPE;
+
+/**< Structure sent from the clock component client either when fulfilling 
+ *   a media time request or when the time scale has changed. 
+ *
+ *   In the former case the Clock Component fills this structure and times its emission 
+ *   to a client component (via the client port) according to the corresponding media 
+ *   time request sent by the client. The Clock Component should time the emission to occur
+ *   when the requested timestamp matches the Clock Component's media time but also the 
+ *   prescribed offset early. 
+ *
+ *   Upon scale changes the clock component clears the nClientPrivate data, sends the current
+ *   media time and sets the nScale to the new scale via the client port. It emits a 
+ *   OMX_TIME_MEDIATIMETYPE to all clients independent of any requests. This allows clients to 
+ *   alter processing to accomodate scaling. For instance a video component might skip inter-frames 
+ *   in the case of extreme fastforward. Likewise an audio component might add or remove samples 
+ *   from an audio frame to scale audio data. 
+ *
+ *   It is expected that some clock components may not be able to fulfill requests
+ *   at exactly the prescribed time. This is acceptable so long as the request is 
+ *   fulfilled at least as early as described and not later. This structure provides 
+ *   fields the client may use to wait for the remaining time.
+ *
+ *   The client may use either the nOffset or nWallTimeAtMedia fields to determine the 
+ *   wall time until the nMediaTimestamp actually occurs. In the latter case the
+ *   client can get a more accurate value for offset by getting the current wall
+ *   from the cloc component and subtracting it from nWallTimeAtMedia. 
+ */
+
+typedef struct OMX_TIME_MEDIATIMETYPE {
+    OMX_U32 nSize;                  /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;       /**< OMX specification version information */
+    OMX_U32 nClientPrivate;         /**< Client private data to disabiguate this media time 
+                                     *   from others. Copied from the media time request. 
+                                     *   A value of zero is reserved for time scale updates. */
+    OMX_TIME_UPDATETYPE eUpdateType; /**< Reason for the update */
+    OMX_TICKS nMediaTimestamp;      /**< Media time requested. If no media time was 
+                                     *   requested then this is the current media time. */ 
+    OMX_TICKS nOffset;              /**< Amount of wall clock time by which this
+                                     *   request was actually fulfilled early */
+
+    OMX_TICKS nWallTimeAtMediaTime; /**< Wall time corresponding to nMediaTimeStamp.
+                                     *   A client may compare this value to current
+                                     *   media time obtained from the Clock Component to determine
+                                     *   the wall time until the media timestamp is really
+                                     *   current. */
+    OMX_S32 xScale;                 /**< Current media time scale in Q16 format. */
+    OMX_TIME_CLOCKSTATE eState;     /* Seeking Change. Added 7/12.*/
+                                    /**< State of the media time. */
+} OMX_TIME_MEDIATIMETYPE;  
+
+/** Structure representing the current media time scale factor. Applicable only to clock 
+ *  component, other components see scale changes via OMX_TIME_MEDIATIMETYPE buffers sent via
+ *  the clock component client ports. Upon recieving this config the clock component changes 
+ *  the rate by which the media time increases or decreases effectively implementing trick modes. 
+ */ 
+typedef struct OMX_TIME_CONFIG_SCALETYPE {
+    OMX_U32 nSize;                  /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;       /**< OMX specification version information */
+    OMX_S32 xScale;                 /**< This is a value in Q16 format which is used for
+                                     * scaling the media time */
+} OMX_TIME_CONFIG_SCALETYPE;
+/** Bits used to identify a clock port. Used in OMX_TIME_CONFIG_CLOCKSTATETYPE\92s nWaitMask field */
+#define OMX_CLOCKPORT0 0x00000001
+#define OMX_CLOCKPORT1 0x00000002
+#define OMX_CLOCKPORT2 0x00000004
+#define OMX_CLOCKPORT3 0x00000008
+#define OMX_CLOCKPORT4 0x00000010
+#define OMX_CLOCKPORT5 0x00000020
+#define OMX_CLOCKPORT6 0x00000040
+#define OMX_CLOCKPORT7 0x00000080
+
+/** Structure representing the current mode of the media clock. 
+ *  IL Client uses this config to change or query the mode of the 
+ *  media clock of the clock component. Applicable only to clock
+ *  component. 
+ *  
+ *  On a SetConfig if eState is OMX_TIME_ClockStateRunning media time
+ *  starts immediately at the prescribed start time. If
+ *  OMX_TIME_ClockStateWaitingForStartTime the Clock Component ignores
+ *  the given nStartTime and waits for all clients specified in the 
+ *  nWaitMask to send starttimes (via 
+ *  OMX_IndexConfigTimeClientStartTime). The Clock Component then starts 
+ *  the media clock using the earliest start time supplied. */    
+typedef struct OMX_TIME_CONFIG_CLOCKSTATETYPE {
+    OMX_U32 nSize;              /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;   /**< OMX specification version 
+                                 *   information */
+    OMX_TIME_CLOCKSTATE eState; /**< State of the media time. */
+    OMX_TICKS nStartTime;       /**< Start time of the media time. */
+    OMX_TICKS nOffset;          /**< Time to offset the media time by 
+                                 * (e.g. preroll). Media time will be
+                                 * reported to be nOffset ticks earlier.     
+                                 */
+    OMX_U32 nWaitMask;          /**< Mask of OMX_CLOCKPORT values. */
+} OMX_TIME_CONFIG_CLOCKSTATETYPE;
+
+/** Structure representing the reference clock currently being used to
+ *  compute media time. IL client uses this config to change or query the 
+ *  clock component's active reference clock */
+typedef struct OMX_TIME_CONFIG_ACTIVEREFCLOCKTYPE {
+    OMX_U32 nSize;                  /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion;       /**< OMX specification version information */
+    OMX_TIME_REFCLOCKTYPE eClock;   /**< Reference clock used to compute media time */                        
+} OMX_TIME_CONFIG_ACTIVEREFCLOCKTYPE;
+
+/** Descriptor for setting specifics of power type.
+ *  Note: this structure is listed for backwards compatibility. */
+typedef struct OMX_OTHER_CONFIG_POWERTYPE {
+    OMX_U32 nSize;            /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
+    OMX_BOOL bEnablePM;       /**< Flag to enable Power Management */
+} OMX_OTHER_CONFIG_POWERTYPE;
+
+
+/** Descriptor for setting specifics of stats type.
+ *  Note: this structure is listed for backwards compatibility. */
+typedef struct OMX_OTHER_CONFIG_STATSTYPE {
+    OMX_U32 nSize;            /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
+    /* what goes here */
+} OMX_OTHER_CONFIG_STATSTYPE;
+
+
+/**
+ * The PortDefinition structure is used to define all of the parameters 
+ * necessary for the compliant component to setup an input or an output other 
+ * path.
+ */
+typedef struct OMX_OTHER_PORTDEFINITIONTYPE {
+    OMX_OTHER_FORMATTYPE eFormat;  /**< Type of data expected for this channel */
+} OMX_OTHER_PORTDEFINITIONTYPE;
+
+/**  Port format parameter.  This structure is used to enumerate
+  *  the various data input/output format supported by the port.
+  */
+typedef struct OMX_OTHER_PARAM_PORTFORMATTYPE {
+    OMX_U32 nSize; /**< size of the structure in bytes */
+    OMX_VERSIONTYPE nVersion; /**< OMX specification version information */
+    OMX_U32 nPortIndex; /**< Indicates which port to set */
+    OMX_U32 nIndex; /**< Indicates the enumeration index for the format from 0x0 to N-1 */
+    OMX_OTHER_FORMATTYPE eFormat; /**< Type of data expected for this channel */
+} OMX_OTHER_PARAM_PORTFORMATTYPE; 
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
+/* File EOF */
diff --git a/interface/vmcs_host/khronos/IL/OMX_Types.h b/interface/vmcs_host/khronos/IL/OMX_Types.h
new file mode 100755 (executable)
index 0000000..f865eea
--- /dev/null
@@ -0,0 +1,372 @@
+/*
+ * Copyright (c) 2008 The Khronos Group Inc. 
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions: 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
+ *
+ */
+
+/** OMX_Types.h - OpenMax IL version 1.1.2
+ *  The OMX_Types header file contains the primitive type definitions used by 
+ *  the core, the application and the component.  This file may need to be
+ *  modified to be used on systems that do not have "char" set to 8 bits, 
+ *  "short" set to 16 bits and "long" set to 32 bits.
+ */
+
+#ifndef OMX_Types_h
+#define OMX_Types_h
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/** The OMX_API and OMX_APIENTRY are platform specific definitions used
+ *  to declare OMX function prototypes.  They are modified to meet the
+ *  requirements for a particular platform */
+#ifdef __SYMBIAN32__   
+#   ifdef __OMX_EXPORTS
+#       define OMX_API __declspec(dllexport)
+#   else
+#       ifdef _WIN32
+#           define OMX_API __declspec(dllexport) 
+#       else
+#           define OMX_API __declspec(dllimport)
+#       endif
+#   endif
+#else
+#   if defined(_WIN32) && !defined(__MINGW32__)
+#      ifdef __OMX_EXPORTS
+#          define OMX_API __declspec(dllexport)
+#      else
+#          define OMX_API __declspec(dllimport)
+#      endif
+#   else
+#      ifdef __OMX_EXPORTS
+#          define OMX_API
+#      else
+#          define OMX_API extern
+#      endif
+#   endif
+#endif
+
+#ifndef OMX_APIENTRY
+#define OMX_APIENTRY 
+#endif 
+
+/** OMX_IN is used to identify inputs to an OMX function.  This designation 
+    will also be used in the case of a pointer that points to a parameter 
+    that is used as an output. */
+#ifndef OMX_IN
+#define OMX_IN
+#endif
+
+/** OMX_OUT is used to identify outputs from an OMX function.  This 
+    designation will also be used in the case of a pointer that points 
+    to a parameter that is used as an input. */
+#ifndef OMX_OUT
+#define OMX_OUT
+#endif
+
+
+/** OMX_INOUT is used to identify parameters that may be either inputs or
+    outputs from an OMX function at the same time.  This designation will 
+    also be used in the case of a pointer that  points to a parameter that 
+    is used both as an input and an output. */
+#ifndef OMX_INOUT
+#define OMX_INOUT
+#endif
+
+/** OMX_ALL is used to as a wildcard to select all entities of the same type
+ *  when specifying the index, or referring to a object by an index.  (i.e.
+ *  use OMX_ALL to indicate all N channels). When used as a port index
+ *  for a config or parameter this OMX_ALL denotes that the config or
+ *  parameter applies to the entire component not just one port. */
+#define OMX_ALL 0xFFFFFFFF
+
+/** In the following we define groups that help building doxygen documentation */
+
+/** @defgroup core OpenMAX IL core
+ * Functions and structure related to the OMX IL core
+ */
+ /** @defgroup comp OpenMAX IL component
+ * Functions and structure related to the OMX IL component
+ */
+/** @defgroup rpm Resource and Policy Management 
+ * Structures for resource and policy management of components
+ */
+
+/** @defgroup buf Buffer Management
+ * Buffer handling functions and structures
+ */
+  
+/** @defgroup tun Tunneling
+ * @ingroup core comp
+ * Structures and functions to manage tunnels among component ports
+ */
+/** @defgroup cp Content Pipes
+ *  @ingroup core
+ */
+ /** @defgroup metadata Metadata handling
+  * 
+  */ 
+
+#if defined(__GNUC__)
+#include <stdint.h>
+#define STDINT_H_AVAILABLE
+#endif
+
+/** OMX_U8 is an 8 bit unsigned quantity that is byte aligned */
+typedef unsigned char OMX_U8;
+
+/** OMX_S8 is an 8 bit signed quantity that is byte aligned */
+typedef signed char OMX_S8;
+
+/** OMX_U16 is a 16 bit unsigned quantity that is 16 bit word aligned */
+typedef unsigned short OMX_U16;
+
+/** OMX_S16 is a 16 bit signed quantity that is 16 bit word aligned */
+typedef signed short OMX_S16;
+
+/** OMX_U32 is a 32 bit unsigned quantity that is 32 bit word aligned */
+#ifdef STDINT_H_AVAILABLE
+typedef uint32_t OMX_U32;
+#else
+typedef unsigned long OMX_U32;
+#endif
+
+/** OMX_S32 is a 32 bit signed quantity that is 32 bit word aligned */
+#ifdef STDINT_H_AVAILABLE
+typedef int32_t OMX_S32;
+#else
+typedef signed long OMX_S32;
+#endif
+
+
+/* Users with compilers that cannot accept the "long long" designation should
+   define the OMX_SKIP64BIT macro.  It should be noted that this may cause 
+   some components to fail to compile if the component was written to require
+   64 bit integral types.  However, these components would NOT compile anyway
+   since the compiler does not support the way the component was written.
+*/
+#ifndef OMX_SKIP64BIT
+#ifdef __SYMBIAN32__
+/** OMX_U64 is a 64 bit unsigned quantity that is 64 bit word aligned */
+typedef unsigned long long OMX_U64;
+
+/** OMX_S64 is a 64 bit signed quantity that is 64 bit word aligned */
+typedef signed long long OMX_S64;
+
+#elif defined(WIN32)
+
+/** OMX_U64 is a 64 bit unsigned quantity that is 64 bit word aligned */   
+typedef unsigned __int64  OMX_U64;
+
+/** OMX_S64 is a 64 bit signed quantity that is 64 bit word aligned */
+typedef signed   __int64  OMX_S64;
+
+#else /* WIN32 */
+
+/** OMX_U64 is a 64 bit unsigned quantity that is 64 bit word aligned */
+typedef unsigned long long OMX_U64;
+
+/** OMX_S64 is a 64 bit signed quantity that is 64 bit word aligned */
+typedef signed long long OMX_S64;
+
+#endif /* WIN32 */
+#endif
+
+
+/** The OMX_BOOL type is intended to be used to represent a true or a false 
+    value when passing parameters to and from the OMX core and components.  The
+    OMX_BOOL is a 32 bit quantity and is aligned on a 32 bit word boundary.
+ */
+typedef enum OMX_BOOL {
+    OMX_FALSE = 0,
+    OMX_TRUE = !OMX_FALSE,
+    OMX_BOOL_MAX = 0x7FFFFFFF
+} OMX_BOOL; 
+/** The OMX_PTR type is intended to be used to pass pointers between the OMX
+    applications and the OMX Core and components.  This is a 32 bit pointer and
+    is aligned on a 32 bit boundary.
+ */
+typedef void* OMX_PTR;
+
+/** The OMX_STRING type is intended to be used to pass "C" type strings between
+    the application and the core and component.  The OMX_STRING type is a 32 
+    bit pointer to a zero terminated string.  The  pointer is word aligned and 
+    the string is byte aligned.  
+ */
+typedef char* OMX_STRING;
+
+/** The OMX_BYTE type is intended to be used to pass arrays of bytes such as
+    buffers between the application and the component and core.  The OMX_BYTE 
+    type is a 32 bit pointer to a zero terminated string.  The  pointer is word
+    aligned and the string is byte aligned.
+ */
+typedef unsigned char* OMX_BYTE;
+
+/** OMX_UUIDTYPE is a very long unique identifier to uniquely identify
+    at runtime.  This identifier should be generated by a component in a way
+    that guarantees that every instance of the identifier running on the system
+    is unique. */
+typedef unsigned char OMX_UUIDTYPE[128];
+
+/** The OMX_DIRTYPE enumeration is used to indicate if a port is an input or
+    an output port.  This enumeration is common across all component types.    
+ */
+typedef enum OMX_DIRTYPE
+{
+    OMX_DirInput,              /**< Port is an input port */
+    OMX_DirOutput,             /**< Port is an output port */
+    OMX_DirMax = 0x7FFFFFFF
+} OMX_DIRTYPE;
+
+/** The OMX_ENDIANTYPE enumeration is used to indicate the bit ordering 
+    for numerical data (i.e. big endian, or little endian).    
+ */
+typedef enum OMX_ENDIANTYPE
+{
+    OMX_EndianBig, /**< big endian */
+    OMX_EndianLittle, /**< little endian */
+    OMX_EndianMax = 0x7FFFFFFF
+} OMX_ENDIANTYPE;
+
+
+/** The OMX_NUMERICALDATATYPE enumeration is used to indicate if data 
+    is signed or unsigned
+ */
+typedef enum OMX_NUMERICALDATATYPE
+{
+    OMX_NumericalDataSigned, /**< signed data */
+    OMX_NumericalDataUnsigned, /**< unsigned data */
+    OMX_NumercialDataMax = 0x7FFFFFFF
+} OMX_NUMERICALDATATYPE;
+
+
+/** Unsigned bounded value type */
+typedef struct OMX_BU32 {
+    OMX_U32 nValue; /**< actual value */
+    OMX_U32 nMin;   /**< minimum for value (i.e. nValue >= nMin) */
+    OMX_U32 nMax;   /**< maximum for value (i.e. nValue <= nMax) */
+} OMX_BU32;
+
+
+/** Signed bounded value type */
+typedef struct OMX_BS32 {
+    OMX_S32 nValue; /**< actual value */
+    OMX_S32 nMin;   /**< minimum for value (i.e. nValue >= nMin) */
+    OMX_S32 nMax;   /**< maximum for value (i.e. nValue <= nMax) */
+} OMX_BS32;
+
+
+/** Structure representing some time or duration in microseconds. This structure
+  *  must be interpreted as a signed 64 bit value. The quantity is signed to accommodate 
+  *  negative deltas and preroll scenarios. The quantity is represented in microseconds 
+  *  to accomodate high resolution timestamps (e.g. DVD presentation timestamps based
+  *  on a 90kHz clock) and to allow more accurate and synchronized delivery (e.g. 
+  *  individual audio samples delivered at 192 kHz). The quantity is 64 bit to 
+  *  accommodate a large dynamic range (signed 32 bit values would allow only for plus
+  *  or minus 35 minutes).
+  *
+  *  Implementations with limited precision may convert the signed 64 bit value to 
+  *  a signed 32 bit value internally but risk loss of precision.  
+  */
+#ifndef OMX_SKIP64BIT
+typedef OMX_S64 OMX_TICKS;
+#else
+typedef struct OMX_TICKS
+{
+    OMX_U32 nLowPart;    /** low bits of the signed 64 bit tick value */
+    OMX_U32 nHighPart;   /** high bits of the signed 64 bit tick value */
+} OMX_TICKS;
+#endif
+#define OMX_TICKS_PER_SECOND 1000000
+
+/** Define the public interface for the OMX Handle.  The core will not use
+    this value internally, but the application should only use this value.
+ */
+typedef void* OMX_HANDLETYPE;
+
+typedef struct OMX_MARKTYPE
+{
+    OMX_HANDLETYPE hMarkTargetComponent;   /**< The component that will 
+                                                generate a mark event upon 
+                                                processing the mark. */
+    OMX_PTR pMarkData;   /**< Application specific data associated with 
+                              the mark sent on a mark event to disambiguate 
+                              this mark from others. */
+} OMX_MARKTYPE;
+
+
+/** OMX_NATIVE_DEVICETYPE is used to map a OMX video port to the
+ *  platform & operating specific object used to reference the display 
+ *  or can be used by a audio port for native audio rendering */
+typedef void* OMX_NATIVE_DEVICETYPE;
+
+/** OMX_NATIVE_WINDOWTYPE is used to map a OMX video port to the
+ *  platform & operating specific object used to reference the window */
+typedef void* OMX_NATIVE_WINDOWTYPE;
+
+
+/** Define the OMX IL version that corresponds to this set of header files.
+ *  We also define a combined version that can be used to write or compare
+ *  values of the 32bit nVersion field, assuming a little endian architecture */
+#define OMX_VERSION_MAJOR 1
+#define OMX_VERSION_MINOR 1
+#define OMX_VERSION_REVISION 2
+#define OMX_VERSION_STEP 0
+
+#define OMX_VERSION ((OMX_VERSION_STEP<<24) | (OMX_VERSION_REVISION<<16) | (OMX_VERSION_MINOR<<8) | OMX_VERSION_MAJOR)
+
+
+/** The OMX_VERSIONTYPE union is used to specify the version for
+    a structure or component.  For a component, the version is entirely
+    specified by the component vendor.  Components doing the same function
+    from different vendors may or may not have the same version.  For 
+    structures, the version shall be set by the entity that allocates the
+    structure.  For structures specified in the OMX 1.1 specification, the
+    value of the version shall be set to 1.1.0.0 in all cases.  Access to the
+    OMX_VERSIONTYPE can be by a single 32 bit access (e.g. by nVersion) or
+    by accessing one of the structure elements to, for example, check only
+    the Major revision.
+ */
+typedef union OMX_VERSIONTYPE
+{
+    struct
+    {
+        OMX_U8 nVersionMajor;   /**< Major version accessor element */
+        OMX_U8 nVersionMinor;   /**< Minor version accessor element */
+        OMX_U8 nRevision;       /**< Revision version accessor element */
+        OMX_U8 nStep;           /**< Step version accessor element */
+    } s;
+    OMX_U32 nVersion;           /**< 32 bit value to make accessing the
+                                    version easily done in a single word
+                                    size copy/compare operation */
+} OMX_VERSIONTYPE;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
+/* File EOF */
diff --git a/interface/vmcs_host/khronos/IL/OMX_Video.h b/interface/vmcs_host/khronos/IL/OMX_Video.h
new file mode 100755 (executable)
index 0000000..cd941fc
--- /dev/null
@@ -0,0 +1,1082 @@
+/**
+ * Copyright (c) 2008 The Khronos Group Inc. 
+ * 
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject
+ * to the following conditions: 
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software. 
+ * 
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 
+ *
+ */
+
+/** 
+ *  @file OMX_Video.h - OpenMax IL version 1.1.2
+ *  The structures is needed by Video components to exchange parameters 
+ *  and configuration data with OMX components.
+ */
+#ifndef OMX_Video_h
+#define OMX_Video_h
+
+/** @defgroup video OpenMAX IL Video Domain
+ * @ingroup iv
+ * Structures for OpenMAX IL Video domain
+ * @{
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/**
+ * Each OMX header must include all required header files to allow the
+ * header to compile without errors.  The includes below are required
+ * for this header file to compile successfully 
+ */
+
+#include "OMX_IVCommon.h"
+
+
+/**
+ * Enumeration used to define the possible video compression codings.  
+ * NOTE:  This essentially refers to file extensions. If the coding is 
+ *        being used to specify the ENCODE type, then additional work 
+ *        must be done to configure the exact flavor of the compression 
+ *        to be used.  For decode cases where the user application can 
+ *        not differentiate between MPEG-4 and H.264 bit streams, it is 
+ *        up to the codec to handle this.
+ */
+typedef enum OMX_VIDEO_CODINGTYPE {
+    OMX_VIDEO_CodingUnused,     /**< Value when coding is N/A */
+    OMX_VIDEO_CodingAutoDetect, /**< Autodetection of coding type */
+    OMX_VIDEO_CodingMPEG2,      /**< AKA: H.262 */
+    OMX_VIDEO_CodingH263,       /**< H.263 */
+    OMX_VIDEO_CodingMPEG4,      /**< MPEG-4 */
+    OMX_VIDEO_CodingWMV,        /**< all versions of Windows Media Video */
+    OMX_VIDEO_CodingRV,         /**< all versions of Real Video */
+    OMX_VIDEO_CodingAVC,        /**< H.264/AVC */
+    OMX_VIDEO_CodingMJPEG,      /**< Motion JPEG */
+    OMX_VIDEO_CodingKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_VIDEO_CodingVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+
+#define OMX_AUDIO_CodingVP6_Supported 1
+    OMX_VIDEO_CodingVP6,        /**< On2 VP6 */
+#define OMX_AUDIO_CodingVP7_Supported 1
+    OMX_VIDEO_CodingVP7,        /**< On2 VP7 */
+#define OMX_AUDIO_CodingVP8_Supported 1
+    OMX_VIDEO_CodingVP8,        /**< On2 VP8 */
+#define OMX_AUDIO_CodingYUV_Supported 1
+    OMX_VIDEO_CodingYUV,        /* raw YUV video */
+#define OMX_AUDIO_CodingSorenson_Supported 1
+    OMX_VIDEO_CodingSorenson,   /**< Sorenson */
+#define OMX_AUDIO_CodingTheora_Supported 1
+    OMX_VIDEO_CodingTheora,     /**< Theora */
+#define OMX_AUDIO_CodingMVC_Supported 1
+    OMX_VIDEO_CodingMVC,        /**< H.264/MVC */      
+    
+    OMX_VIDEO_CodingMax = 0x7FFFFFFF
+} OMX_VIDEO_CODINGTYPE;
+
+
+/**
+ * Data structure used to define a video path.  The number of Video paths for 
+ * input and output will vary by type of the Video component.  
+ * 
+ *    Input (aka Source) : zero Inputs, one Output,
+ *    Splitter           : one Input, 2 or more Outputs,
+ *    Processing Element : one Input, one output,
+ *    Mixer              : 2 or more inputs, one output,
+ *    Output (aka Sink)  : one Input, zero outputs.
+ * 
+ * The PortDefinition structure is used to define all of the parameters 
+ * necessary for the compliant component to setup an input or an output video 
+ * path.  If additional vendor specific data is required, it should be 
+ * transmitted to the component using the CustomCommand function.  Compliant 
+ * components will prepopulate this structure with optimal values during the 
+ * GetDefaultInitParams command.
+ *
+ * STRUCT MEMBERS:
+ *  cMIMEType             : MIME type of data for the port
+ *  pNativeRender         : Platform specific reference for a display if a 
+ *                          sync, otherwise this field is 0
+ *  nFrameWidth           : Width of frame to be used on channel if 
+ *                          uncompressed format is used.  Use 0 for unknown,
+ *                          don't care or variable
+ *  nFrameHeight          : Height of frame to be used on channel if 
+ *                          uncompressed format is used. Use 0 for unknown,
+ *                          don't care or variable
+ *  nStride               : Number of bytes per span of an image 
+ *                          (i.e. indicates the number of bytes to get
+ *                          from span N to span N+1, where negative stride
+ *                          indicates the image is bottom up
+ *  nSliceHeight          : Height used when encoding in slices
+ *  nBitrate              : Bit rate of frame to be used on channel if 
+ *                          compressed format is used. Use 0 for unknown, 
+ *                          don't care or variable
+ *  xFramerate            : Frame rate to be used on channel if uncompressed 
+ *                          format is used. Use 0 for unknown, don't care or 
+ *                          variable.  Units are Q16 frames per second.
+ *  bFlagErrorConcealment : Turns on error concealment if it is supported by 
+ *                          the OMX component
+ *  eCompressionFormat    : Compression format used in this instance of the 
+ *                          component. When OMX_VIDEO_CodingUnused is 
+ *                          specified, eColorFormat is used
+ *  eColorFormat : Decompressed format used by this component
+ *  pNativeWindow : Platform specific reference for a window object if a 
+ *                          display sink , otherwise this field is 0x0. 
+ */
+typedef struct OMX_VIDEO_PORTDEFINITIONTYPE {
+    OMX_STRING cMIMEType;
+    OMX_NATIVE_DEVICETYPE pNativeRender;
+    OMX_U32 nFrameWidth;
+    OMX_U32 nFrameHeight;
+    OMX_S32 nStride;
+    OMX_U32 nSliceHeight;
+    OMX_U32 nBitrate;
+    OMX_U32 xFramerate;
+    OMX_BOOL bFlagErrorConcealment;
+    OMX_VIDEO_CODINGTYPE eCompressionFormat;
+    OMX_COLOR_FORMATTYPE eColorFormat;
+    OMX_NATIVE_WINDOWTYPE pNativeWindow;
+} OMX_VIDEO_PORTDEFINITIONTYPE;
+
+/**  
+ * Port format parameter.  This structure is used to enumerate the various 
+ * data input/output format supported by the port.
+ * 
+ * STRUCT MEMBERS:
+ *  nSize              : Size of the structure in bytes
+ *  nVersion           : OMX specification version information
+ *  nPortIndex         : Indicates which port to set
+ *  nIndex             : Indicates the enumeration index for the format from 
+ *                       0x0 to N-1
+ *  eCompressionFormat : Compression format used in this instance of the 
+ *                       component. When OMX_VIDEO_CodingUnused is specified, 
+ *                       eColorFormat is used 
+ *  eColorFormat       : Decompressed format used by this component
+ *  xFrameRate         : Indicates the video frame rate in Q16 format
+ */
+typedef struct OMX_VIDEO_PARAM_PORTFORMATTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_U32 nIndex;
+    OMX_VIDEO_CODINGTYPE eCompressionFormat; 
+    OMX_COLOR_FORMATTYPE eColorFormat;
+    OMX_U32 xFramerate;
+} OMX_VIDEO_PARAM_PORTFORMATTYPE;
+
+
+/**
+ * This is a structure for configuring video compression quantization 
+ * parameter values.  Codecs may support different QP values for different
+ * frame types.
+ *
+ * STRUCT MEMBERS:
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version info
+ *  nPortIndex : Port that this structure applies to
+ *  nQpI       : QP value to use for index frames
+ *  nQpP       : QP value to use for P frames
+ *  nQpB       : QP values to use for bidirectional frames 
+ */
+typedef struct OMX_VIDEO_PARAM_QUANTIZATIONTYPE {
+    OMX_U32 nSize;            
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_U32 nQpI;
+    OMX_U32 nQpP;
+    OMX_U32 nQpB;
+} OMX_VIDEO_PARAM_QUANTIZATIONTYPE;
+
+
+/** 
+ * Structure for configuration of video fast update parameters. 
+ *  
+ * STRUCT MEMBERS:
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version info 
+ *  nPortIndex : Port that this structure applies to
+ *  bEnableVFU : Enable/Disable video fast update
+ *  nFirstGOB  : Specifies the number of the first macroblock row
+ *  nFirstMB   : specifies the first MB relative to the specified first GOB
+ *  nNumMBs    : Specifies the number of MBs to be refreshed from nFirstGOB 
+ *               and nFirstMB
+ */
+typedef struct OMX_VIDEO_PARAM_VIDEOFASTUPDATETYPE {
+    OMX_U32 nSize;            
+    OMX_VERSIONTYPE nVersion; 
+    OMX_U32 nPortIndex;       
+    OMX_BOOL bEnableVFU;      
+    OMX_U32 nFirstGOB;                            
+    OMX_U32 nFirstMB;                            
+    OMX_U32 nNumMBs;                                  
+} OMX_VIDEO_PARAM_VIDEOFASTUPDATETYPE;
+
+
+/** 
+ * Enumeration of possible bitrate control types 
+ */
+typedef enum OMX_VIDEO_CONTROLRATETYPE {
+    OMX_Video_ControlRateDisable,
+    OMX_Video_ControlRateVariable,
+    OMX_Video_ControlRateConstant,
+    OMX_Video_ControlRateVariableSkipFrames,
+    OMX_Video_ControlRateConstantSkipFrames,
+    OMX_Video_ControlRateKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_Video_ControlRateVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_Video_ControlRateMax = 0x7FFFFFFF
+} OMX_VIDEO_CONTROLRATETYPE;
+
+
+/** 
+ * Structure for configuring bitrate mode of a codec. 
+ *
+ * STRUCT MEMBERS:
+ *  nSize          : Size of the struct in bytes
+ *  nVersion       : OMX spec version info
+ *  nPortIndex     : Port that this struct applies to
+ *  eControlRate   : Control rate type enum
+ *  nTargetBitrate : Target bitrate to encode with
+ */
+typedef struct OMX_VIDEO_PARAM_BITRATETYPE {
+    OMX_U32 nSize;                          
+    OMX_VERSIONTYPE nVersion;               
+    OMX_U32 nPortIndex;                     
+    OMX_VIDEO_CONTROLRATETYPE eControlRate; 
+    OMX_U32 nTargetBitrate;                 
+} OMX_VIDEO_PARAM_BITRATETYPE;
+
+
+/** 
+ * Enumeration of possible motion vector (MV) types 
+ */
+typedef enum OMX_VIDEO_MOTIONVECTORTYPE {
+    OMX_Video_MotionVectorPixel,
+    OMX_Video_MotionVectorHalfPel,
+    OMX_Video_MotionVectorQuarterPel,
+    OMX_Video_MotionVectorEighthPel,
+    OMX_Video_MotionVectorKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_Video_MotionVectorVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_Video_MotionVectorMax = 0x7FFFFFFF
+} OMX_VIDEO_MOTIONVECTORTYPE;
+
+
+/**
+ * Structure for configuring the number of motion vectors used as well
+ * as their accuracy.
+ * 
+ * STRUCT MEMBERS:
+ *  nSize            : Size of the struct in bytes
+ *  nVersion         : OMX spec version info
+ *  nPortIndex       : port that this structure applies to
+ *  eAccuracy        : Enumerated MV accuracy
+ *  bUnrestrictedMVs : Allow unrestricted MVs
+ *  bFourMV          : Allow use of 4 MVs
+ *  sXSearchRange    : Search range in horizontal direction for MVs
+ *  sYSearchRange    : Search range in vertical direction for MVs
+ */
+typedef struct OMX_VIDEO_PARAM_MOTIONVECTORTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_VIDEO_MOTIONVECTORTYPE eAccuracy;
+    OMX_BOOL bUnrestrictedMVs;
+    OMX_BOOL bFourMV;
+    OMX_S32 sXSearchRange;
+    OMX_S32 sYSearchRange;
+} OMX_VIDEO_PARAM_MOTIONVECTORTYPE;
+
+
+/** 
+ * Enumeration of possible methods to use for Intra Refresh 
+ */
+typedef enum OMX_VIDEO_INTRAREFRESHTYPE {
+    OMX_VIDEO_IntraRefreshCyclic,                         /**< Cyclic intra refresh, bit 0 is set*/
+    OMX_VIDEO_IntraRefreshAdaptive,                       /**< Adaptive intra refresh, bit 1 is set*/
+    OMX_VIDEO_IntraRefreshBoth,                           /**< Cyclic + Adaptive intra refresh (no mrows since bit 2 is off)*/
+    OMX_VIDEO_IntraRefreshKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_VIDEO_IntraRefreshVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_VIDEO_IntraRefreshCyclicMrows,                    /**< Cyclic intra refresh, multiple rows at a time bits 0 and 2 are set*/
+    OMX_VIDEO_IntraRefreshPseudoRand,                     /**< Pseudo random intra refresh, uses bit 3*/
+    OMX_VIDEO_IntraRefreshMax = 0x7FFFFFFF
+} OMX_VIDEO_INTRAREFRESHTYPE;
+
+
+/**
+ * Structure for configuring intra refresh mode 
+ * 
+ * STRUCT MEMBERS:
+ *  nSize        : Size of the structure in bytes
+ *  nVersion     : OMX specification version information
+ *  nPortIndex   : Port that this structure applies to
+ *  eRefreshMode : Cyclic, Adaptive, or Both
+ *  nAirMBs      : Number of intra macroblocks to refresh in a frame when 
+ *                 AIR is enabled
+ *  nAirRef      : Number of times a motion marked macroblock has to be  
+ *                 intra coded
+ *  nCirMBs      : Number of consecutive macroblocks to be coded as "intra"  
+ *                 when CIR is enabled
+ */
+typedef struct OMX_VIDEO_PARAM_INTRAREFRESHTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_VIDEO_INTRAREFRESHTYPE eRefreshMode;
+    OMX_U32 nAirMBs;
+    OMX_U32 nAirRef;
+    OMX_U32 nCirMBs;
+    OMX_U32 nPirMBs;
+} OMX_VIDEO_PARAM_INTRAREFRESHTYPE;
+
+
+/**
+ * Structure for enabling various error correction methods for video 
+ * compression.
+ *
+ * STRUCT MEMBERS:
+ *  nSize                   : Size of the structure in bytes
+ *  nVersion                : OMX specification version information 
+ *  nPortIndex              : Port that this structure applies to 
+ *  bEnableHEC              : Enable/disable header extension codes (HEC)
+ *  bEnableResync           : Enable/disable resynchronization markers
+ *  nResynchMarkerSpacing   : Resynch markers interval (in bits) to be 
+ *                            applied in the stream 
+ *  bEnableDataPartitioning : Enable/disable data partitioning 
+ *  bEnableRVLC             : Enable/disable reversible variable length 
+ *                            coding
+ */
+typedef struct OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_BOOL bEnableHEC;
+    OMX_BOOL bEnableResync;
+    OMX_U32  nResynchMarkerSpacing;
+    OMX_BOOL bEnableDataPartitioning;
+    OMX_BOOL bEnableRVLC;
+} OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE;
+
+
+/** 
+ * Configuration of variable block-size motion compensation (VBSMC) 
+ * 
+ * STRUCT MEMBERS:
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version information 
+ *  nPortIndex : Port that this structure applies to
+ *  b16x16     : Enable inter block search 16x16
+ *  b16x8      : Enable inter block search 16x8
+ *  b8x16      : Enable inter block search 8x16
+ *  b8x8       : Enable inter block search 8x8
+ *  b8x4       : Enable inter block search 8x4
+ *  b4x8       : Enable inter block search 4x8
+ *  b4x4       : Enable inter block search 4x4
+ */
+typedef struct OMX_VIDEO_PARAM_VBSMCTYPE {
+    OMX_U32 nSize; 
+    OMX_VERSIONTYPE nVersion; 
+    OMX_U32 nPortIndex;       
+    OMX_BOOL b16x16; 
+    OMX_BOOL b16x8; 
+    OMX_BOOL b8x16;
+    OMX_BOOL b8x8;
+    OMX_BOOL b8x4;
+    OMX_BOOL b4x8;
+    OMX_BOOL b4x4;
+} OMX_VIDEO_PARAM_VBSMCTYPE;
+
+
+/** 
+ * H.263 profile types, each profile indicates support for various 
+ * performance bounds and different annexes.
+ *
+ * ENUMS:
+ *  Baseline           : Baseline Profile: H.263 (V1), no optional modes                                                    
+ *  H320 Coding        : H.320 Coding Efficiency Backward Compatibility 
+ *                       Profile: H.263+ (V2), includes annexes I, J, L.4
+ *                       and T
+ *  BackwardCompatible : Backward Compatibility Profile: H.263 (V1), 
+ *                       includes annex F                                    
+ *  ISWV2              : Interactive Streaming Wireless Profile: H.263+ 
+ *                       (V2), includes annexes I, J, K and T                 
+ *  ISWV3              : Interactive Streaming Wireless Profile: H.263++  
+ *                       (V3), includes profile 3 and annexes V and W.6.3.8   
+ *  HighCompression    : Conversational High Compression Profile: H.263++  
+ *                       (V3), includes profiles 1 & 2 and annexes D and U   
+ *  Internet           : Conversational Internet Profile: H.263++ (V3),  
+ *                       includes profile 5 and annex K                       
+ *  Interlace          : Conversational Interlace Profile: H.263++ (V3),  
+ *                       includes profile 5 and annex W.6.3.11               
+ *  HighLatency        : High Latency Profile: H.263++ (V3), includes  
+ *                       profile 6 and annexes O.1 and P.5                       
+ */
+typedef enum OMX_VIDEO_H263PROFILETYPE {
+    OMX_VIDEO_H263ProfileBaseline            = 0x01,        
+    OMX_VIDEO_H263ProfileH320Coding          = 0x02,          
+    OMX_VIDEO_H263ProfileBackwardCompatible  = 0x04,  
+    OMX_VIDEO_H263ProfileISWV2               = 0x08,               
+    OMX_VIDEO_H263ProfileISWV3               = 0x10,               
+    OMX_VIDEO_H263ProfileHighCompression     = 0x20,     
+    OMX_VIDEO_H263ProfileInternet            = 0x40,            
+    OMX_VIDEO_H263ProfileInterlace           = 0x80,           
+    OMX_VIDEO_H263ProfileHighLatency         = 0x100,         
+    OMX_VIDEO_H263ProfileKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_VIDEO_H263ProfileVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_VIDEO_H263ProfileMax                 = 0x7FFFFFFF  
+} OMX_VIDEO_H263PROFILETYPE;
+
+
+/** 
+ * H.263 level types, each level indicates support for various frame sizes, 
+ * bit rates, decoder frame rates.
+ */
+typedef enum OMX_VIDEO_H263LEVELTYPE {
+    OMX_VIDEO_H263Level10  = 0x01,  
+    OMX_VIDEO_H263Level20  = 0x02,      
+    OMX_VIDEO_H263Level30  = 0x04,      
+    OMX_VIDEO_H263Level40  = 0x08,      
+    OMX_VIDEO_H263Level45  = 0x10,      
+    OMX_VIDEO_H263Level50  = 0x20,      
+    OMX_VIDEO_H263Level60  = 0x40,      
+    OMX_VIDEO_H263Level70  = 0x80, 
+    OMX_VIDEO_H263LevelKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_VIDEO_H263LevelVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_VIDEO_H263LevelMax = 0x7FFFFFFF  
+} OMX_VIDEO_H263LEVELTYPE;
+
+
+/** 
+ * Specifies the picture type. These values should be OR'd to signal all 
+ * pictures types which are allowed.
+ *
+ * ENUMS:
+ *  Generic Picture Types:          I, P and B
+ *  H.263 Specific Picture Types:   SI and SP
+ *  H.264 Specific Picture Types:   EI and EP
+ *  MPEG-4 Specific Picture Types:  S
+ */
+typedef enum OMX_VIDEO_PICTURETYPE {
+    OMX_VIDEO_PictureTypeI   = 0x01,
+    OMX_VIDEO_PictureTypeP   = 0x02,
+    OMX_VIDEO_PictureTypeB   = 0x04,
+    OMX_VIDEO_PictureTypeSI  = 0x08,
+    OMX_VIDEO_PictureTypeSP  = 0x10,
+    OMX_VIDEO_PictureTypeEI  = 0x11,
+    OMX_VIDEO_PictureTypeEP  = 0x12,
+    OMX_VIDEO_PictureTypeS   = 0x14,
+    OMX_VIDEO_PictureTypeKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_VIDEO_PictureTypeVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_VIDEO_PictureTypeMax = 0x7FFFFFFF
+} OMX_VIDEO_PICTURETYPE;
+
+
+/** 
+ * H.263 Params 
+ *
+ * STRUCT MEMBERS:
+ *  nSize                    : Size of the structure in bytes
+ *  nVersion                 : OMX specification version information 
+ *  nPortIndex               : Port that this structure applies to
+ *  nPFrames                 : Number of P frames between each I frame
+ *  nBFrames                 : Number of B frames between each I frame
+ *  eProfile                 : H.263 profile(s) to use
+ *  eLevel                   : H.263 level(s) to use
+ *  bPLUSPTYPEAllowed        : Indicating that it is allowed to use PLUSPTYPE 
+ *                             (specified in the 1998 version of H.263) to 
+ *                             indicate custom picture sizes or clock 
+ *                             frequencies 
+ *  nAllowedPictureTypes     : Specifies the picture types allowed in the 
+ *                             bitstream
+ *  bForceRoundingTypeToZero : value of the RTYPE bit (bit 6 of MPPTYPE) is 
+ *                             not constrained. It is recommended to change 
+ *                             the value of the RTYPE bit for each reference 
+ *                             picture in error-free communication
+ *  nPictureHeaderRepetition : Specifies the frequency of picture header 
+ *                             repetition
+ *  nGOBHeaderInterval       : Specifies the interval of non-empty GOB  
+ *                             headers in units of GOBs
+ */
+typedef struct OMX_VIDEO_PARAM_H263TYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_U32 nPFrames;
+    OMX_U32 nBFrames;
+    OMX_VIDEO_H263PROFILETYPE eProfile;
+       OMX_VIDEO_H263LEVELTYPE eLevel;
+    OMX_BOOL bPLUSPTYPEAllowed;
+    OMX_U32 nAllowedPictureTypes;
+    OMX_BOOL bForceRoundingTypeToZero;
+    OMX_U32 nPictureHeaderRepetition;
+    OMX_U32 nGOBHeaderInterval;
+} OMX_VIDEO_PARAM_H263TYPE;
+
+
+/** 
+ * MPEG-2 profile types, each profile indicates support for various 
+ * performance bounds and different annexes.
+ */
+typedef enum OMX_VIDEO_MPEG2PROFILETYPE {
+    OMX_VIDEO_MPEG2ProfileSimple = 0,  /**< Simple Profile */
+    OMX_VIDEO_MPEG2ProfileMain,        /**< Main Profile */
+    OMX_VIDEO_MPEG2Profile422,         /**< 4:2:2 Profile */
+    OMX_VIDEO_MPEG2ProfileSNR,         /**< SNR Profile */
+    OMX_VIDEO_MPEG2ProfileSpatial,     /**< Spatial Profile */
+    OMX_VIDEO_MPEG2ProfileHigh,        /**< High Profile */
+    OMX_VIDEO_MPEG2ProfileKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_VIDEO_MPEG2ProfileVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_VIDEO_MPEG2ProfileMax = 0x7FFFFFFF  
+} OMX_VIDEO_MPEG2PROFILETYPE;
+
+
+/** 
+ * MPEG-2 level types, each level indicates support for various frame 
+ * sizes, bit rates, decoder frame rates.  No need 
+ */
+typedef enum OMX_VIDEO_MPEG2LEVELTYPE {
+    OMX_VIDEO_MPEG2LevelLL = 0,  /**< Low Level */ 
+    OMX_VIDEO_MPEG2LevelML,      /**< Main Level */ 
+    OMX_VIDEO_MPEG2LevelH14,     /**< High 1440 */ 
+    OMX_VIDEO_MPEG2LevelHL,      /**< High Level */   
+    OMX_VIDEO_MPEG2LevelKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_VIDEO_MPEG2LevelVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_VIDEO_MPEG2LevelMax = 0x7FFFFFFF  
+} OMX_VIDEO_MPEG2LEVELTYPE;
+
+
+/** 
+ * MPEG-2 params 
+ *
+ * STRUCT MEMBERS:
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version information
+ *  nPortIndex : Port that this structure applies to
+ *  nPFrames   : Number of P frames between each I frame
+ *  nBFrames   : Number of B frames between each I frame
+ *  eProfile   : MPEG-2 profile(s) to use
+ *  eLevel     : MPEG-2 levels(s) to use
+ */
+typedef struct OMX_VIDEO_PARAM_MPEG2TYPE {
+    OMX_U32 nSize;           
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;      
+    OMX_U32 nPFrames;        
+    OMX_U32 nBFrames;        
+    OMX_VIDEO_MPEG2PROFILETYPE eProfile;
+       OMX_VIDEO_MPEG2LEVELTYPE eLevel;   
+} OMX_VIDEO_PARAM_MPEG2TYPE;
+
+
+/** 
+ * MPEG-4 profile types, each profile indicates support for various 
+ * performance bounds and different annexes.
+ * 
+ * ENUMS:
+ *  - Simple Profile, Levels 1-3
+ *  - Simple Scalable Profile, Levels 1-2
+ *  - Core Profile, Levels 1-2
+ *  - Main Profile, Levels 2-4
+ *  - N-bit Profile, Level 2
+ *  - Scalable Texture Profile, Level 1
+ *  - Simple Face Animation Profile, Levels 1-2
+ *  - Simple Face and Body Animation (FBA) Profile, Levels 1-2
+ *  - Basic Animated Texture Profile, Levels 1-2
+ *  - Hybrid Profile, Levels 1-2
+ *  - Advanced Real Time Simple Profiles, Levels 1-4
+ *  - Core Scalable Profile, Levels 1-3
+ *  - Advanced Coding Efficiency Profile, Levels 1-4
+ *  - Advanced Core Profile, Levels 1-2
+ *  - Advanced Scalable Texture, Levels 2-3
+ */
+typedef enum OMX_VIDEO_MPEG4PROFILETYPE {
+    OMX_VIDEO_MPEG4ProfileSimple           = 0x01,        
+    OMX_VIDEO_MPEG4ProfileSimpleScalable   = 0x02,    
+    OMX_VIDEO_MPEG4ProfileCore             = 0x04,              
+    OMX_VIDEO_MPEG4ProfileMain             = 0x08,             
+    OMX_VIDEO_MPEG4ProfileNbit             = 0x10,              
+    OMX_VIDEO_MPEG4ProfileScalableTexture  = 0x20,   
+    OMX_VIDEO_MPEG4ProfileSimpleFace       = 0x40,        
+    OMX_VIDEO_MPEG4ProfileSimpleFBA        = 0x80,         
+    OMX_VIDEO_MPEG4ProfileBasicAnimated    = 0x100,     
+    OMX_VIDEO_MPEG4ProfileHybrid           = 0x200,            
+    OMX_VIDEO_MPEG4ProfileAdvancedRealTime = 0x400,  
+    OMX_VIDEO_MPEG4ProfileCoreScalable     = 0x800,      
+    OMX_VIDEO_MPEG4ProfileAdvancedCoding   = 0x1000,    
+    OMX_VIDEO_MPEG4ProfileAdvancedCore     = 0x2000,      
+    OMX_VIDEO_MPEG4ProfileAdvancedScalable = 0x4000,
+    OMX_VIDEO_MPEG4ProfileAdvancedSimple   = 0x8000,
+    OMX_VIDEO_MPEG4ProfileKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_VIDEO_MPEG4ProfileVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_VIDEO_MPEG4ProfileMax              = 0x7FFFFFFF  
+} OMX_VIDEO_MPEG4PROFILETYPE;
+
+
+/** 
+ * MPEG-4 level types, each level indicates support for various frame 
+ * sizes, bit rates, decoder frame rates.  No need 
+ */
+typedef enum OMX_VIDEO_MPEG4LEVELTYPE {
+    OMX_VIDEO_MPEG4Level0  = 0x01,   /**< Level 0 */   
+    OMX_VIDEO_MPEG4Level0b = 0x02,   /**< Level 0b */   
+    OMX_VIDEO_MPEG4Level1  = 0x04,   /**< Level 1 */ 
+    OMX_VIDEO_MPEG4Level2  = 0x08,   /**< Level 2 */ 
+    OMX_VIDEO_MPEG4Level3  = 0x10,   /**< Level 3 */ 
+    OMX_VIDEO_MPEG4Level4  = 0x20,   /**< Level 4 */  
+    OMX_VIDEO_MPEG4Level4a = 0x40,   /**< Level 4a */  
+    OMX_VIDEO_MPEG4Level5  = 0x80,   /**< Level 5 */  
+    OMX_VIDEO_MPEG4Level6  = 0x100,  /**< Level 5 */  
+    OMX_VIDEO_MPEG4LevelKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_VIDEO_MPEG4LevelVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_VIDEO_MPEG4LevelMax = 0x7FFFFFFF  
+} OMX_VIDEO_MPEG4LEVELTYPE;
+
+
+/** 
+ * MPEG-4 configuration.  This structure handles configuration options
+ * which are specific to MPEG4 algorithms
+ *
+ * STRUCT MEMBERS:
+ *  nSize                : Size of the structure in bytes
+ *  nVersion             : OMX specification version information
+ *  nPortIndex           : Port that this structure applies to
+ *  nSliceHeaderSpacing  : Number of macroblocks between slice header (H263+ 
+ *                         Annex K). Put zero if not used
+ *  bSVH                 : Enable Short Video Header mode
+ *  bGov                 : Flag to enable GOV
+ *  nPFrames             : Number of P frames between each I frame (also called 
+ *                         GOV period)
+ *  nBFrames             : Number of B frames between each I frame
+ *  nIDCVLCThreshold     : Value of intra DC VLC threshold
+ *  bACPred              : Flag to use ac prediction
+ *  nMaxPacketSize       : Maximum size of packet in bytes.
+ *  nTimeIncRes          : Used to pass VOP time increment resolution for MPEG4. 
+ *                         Interpreted as described in MPEG4 standard.
+ *  eProfile             : MPEG-4 profile(s) to use.
+ *  eLevel               : MPEG-4 level(s) to use.
+ *  nAllowedPictureTypes : Specifies the picture types allowed in the bitstream
+ *  nHeaderExtension     : Specifies the number of consecutive video packet
+ *                         headers within a VOP
+ *  bReversibleVLC       : Specifies whether reversible variable length coding 
+ *                         is in use
+ */
+typedef struct OMX_VIDEO_PARAM_MPEG4TYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_U32 nSliceHeaderSpacing;
+    OMX_BOOL bSVH;
+    OMX_BOOL bGov;
+    OMX_U32 nPFrames;
+    OMX_U32 nBFrames;
+    OMX_U32 nIDCVLCThreshold;
+    OMX_BOOL bACPred;
+    OMX_U32 nMaxPacketSize;
+    OMX_U32 nTimeIncRes;
+    OMX_VIDEO_MPEG4PROFILETYPE eProfile;
+    OMX_VIDEO_MPEG4LEVELTYPE eLevel;
+    OMX_U32 nAllowedPictureTypes;
+    OMX_U32 nHeaderExtension;
+    OMX_BOOL bReversibleVLC;
+} OMX_VIDEO_PARAM_MPEG4TYPE;
+
+
+/** 
+ * WMV Versions 
+ */
+typedef enum OMX_VIDEO_WMVFORMATTYPE {
+    OMX_VIDEO_WMVFormatUnused = 0x01,   /**< Format unused or unknown */
+    OMX_VIDEO_WMVFormat7      = 0x02,   /**< Windows Media Video format 7 */
+    OMX_VIDEO_WMVFormat8      = 0x04,   /**< Windows Media Video format 8 */
+    OMX_VIDEO_WMVFormat9      = 0x08,   /**< Windows Media Video format 9 */
+    OMX_VIDEO_WMFFormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_VIDEO_WMFFormatVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_VIDEO_WMVFormatMax    = 0x7FFFFFFF
+} OMX_VIDEO_WMVFORMATTYPE;
+
+
+/** 
+ * WMV Params 
+ *
+ * STRUCT MEMBERS:
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version information
+ *  nPortIndex : Port that this structure applies to
+ *  eFormat    : Version of WMV stream / data
+ */
+typedef struct OMX_VIDEO_PARAM_WMVTYPE {
+    OMX_U32 nSize; 
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_VIDEO_WMVFORMATTYPE eFormat;
+} OMX_VIDEO_PARAM_WMVTYPE;
+
+
+/** 
+ * Real Video Version 
+ */
+typedef enum OMX_VIDEO_RVFORMATTYPE {
+    OMX_VIDEO_RVFormatUnused = 0, /**< Format unused or unknown */
+    OMX_VIDEO_RVFormat8,          /**< Real Video format 8 */
+    OMX_VIDEO_RVFormat9,          /**< Real Video format 9 */
+    OMX_VIDEO_RVFormatG2,         /**< Real Video Format G2 */
+    OMX_VIDEO_RVFormatKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_VIDEO_RVFormatVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_VIDEO_RVFormatMax = 0x7FFFFFFF
+} OMX_VIDEO_RVFORMATTYPE;
+
+
+/** 
+ * Real Video Params 
+ *
+ * STUCT MEMBERS:
+ *  nSize              : Size of the structure in bytes
+ *  nVersion           : OMX specification version information 
+ *  nPortIndex         : Port that this structure applies to
+ *  eFormat            : Version of RV stream / data
+ *  nBitsPerPixel      : Bits per pixel coded in the frame
+ *  nPaddedWidth       : Padded width in pixel of a video frame
+ *  nPaddedHeight      : Padded Height in pixels of a video frame
+ *  nFrameRate         : Rate of video in frames per second
+ *  nBitstreamFlags    : Flags which internal information about the bitstream
+ *  nBitstreamVersion  : Bitstream version
+ *  nMaxEncodeFrameSize: Max encoded frame size
+ *  bEnablePostFilter  : Turn on/off post filter
+ *  bEnableTemporalInterpolation : Turn on/off temporal interpolation
+ *  bEnableLatencyMode : When enabled, the decoder does not display a decoded 
+ *                       frame until it has detected that no enhancement layer 
+ *                                      frames or dependent B frames will be coming. This 
+ *                                      detection usually occurs when a subsequent non-B 
+ *                                      frame is encountered 
+ */
+typedef struct OMX_VIDEO_PARAM_RVTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_VIDEO_RVFORMATTYPE eFormat;
+    OMX_U16 nBitsPerPixel;
+    OMX_U16 nPaddedWidth;
+    OMX_U16 nPaddedHeight;
+    OMX_U32 nFrameRate;
+    OMX_U32 nBitstreamFlags;
+    OMX_U32 nBitstreamVersion;
+    OMX_U32 nMaxEncodeFrameSize;
+    OMX_BOOL bEnablePostFilter;
+    OMX_BOOL bEnableTemporalInterpolation;
+    OMX_BOOL bEnableLatencyMode;
+} OMX_VIDEO_PARAM_RVTYPE;
+
+
+/** 
+ * AVC profile types, each profile indicates support for various 
+ * performance bounds and different annexes.
+ */
+typedef enum OMX_VIDEO_AVCPROFILETYPE {
+    OMX_VIDEO_AVCProfileBaseline = 0x01,   /**< Baseline profile */
+    OMX_VIDEO_AVCProfileMain     = 0x02,   /**< Main profile */
+    OMX_VIDEO_AVCProfileExtended = 0x04,   /**< Extended profile */
+    OMX_VIDEO_AVCProfileHigh     = 0x08,   /**< High profile */
+    OMX_VIDEO_AVCProfileHigh10   = 0x10,   /**< High 10 profile */
+    OMX_VIDEO_AVCProfileHigh422  = 0x20,   /**< High 4:2:2 profile */
+    OMX_VIDEO_AVCProfileHigh444  = 0x40,   /**< High 4:4:4 profile */
+    OMX_VIDEO_AVCProfileConstrainedBaseline = 0x80, /**< Constrained Baseline Profile   */
+    OMX_VIDEO_AVCProfileKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_VIDEO_AVCProfileVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_VIDEO_AVCProfileMax      = 0x7FFFFFFF  
+} OMX_VIDEO_AVCPROFILETYPE;
+
+
+/** 
+ * AVC level types, each level indicates support for various frame sizes, 
+ * bit rates, decoder frame rates.  No need 
+ */
+typedef enum OMX_VIDEO_AVCLEVELTYPE {
+    OMX_VIDEO_AVCLevel1   = 0x01,     /**< Level 1 */
+    OMX_VIDEO_AVCLevel1b  = 0x02,     /**< Level 1b */
+    OMX_VIDEO_AVCLevel11  = 0x04,     /**< Level 1.1 */
+    OMX_VIDEO_AVCLevel12  = 0x08,     /**< Level 1.2 */
+    OMX_VIDEO_AVCLevel13  = 0x10,     /**< Level 1.3 */
+    OMX_VIDEO_AVCLevel2   = 0x20,     /**< Level 2 */
+    OMX_VIDEO_AVCLevel21  = 0x40,     /**< Level 2.1 */
+    OMX_VIDEO_AVCLevel22  = 0x80,     /**< Level 2.2 */
+    OMX_VIDEO_AVCLevel3   = 0x100,    /**< Level 3 */
+    OMX_VIDEO_AVCLevel31  = 0x200,    /**< Level 3.1 */
+    OMX_VIDEO_AVCLevel32  = 0x400,    /**< Level 3.2 */
+    OMX_VIDEO_AVCLevel4   = 0x800,    /**< Level 4 */
+    OMX_VIDEO_AVCLevel41  = 0x1000,   /**< Level 4.1 */
+    OMX_VIDEO_AVCLevel42  = 0x2000,   /**< Level 4.2 */
+    OMX_VIDEO_AVCLevel5   = 0x4000,   /**< Level 5 */
+    OMX_VIDEO_AVCLevel51  = 0x8000,   /**< Level 5.1 */
+    OMX_VIDEO_AVCLevelKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_VIDEO_AVCLevelVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_VIDEO_AVCLevelMax = 0x7FFFFFFF  
+} OMX_VIDEO_AVCLEVELTYPE;
+
+
+/** 
+ * AVC loop filter modes 
+ *
+ * OMX_VIDEO_AVCLoopFilterEnable               : Enable
+ * OMX_VIDEO_AVCLoopFilterDisable              : Disable
+ * OMX_VIDEO_AVCLoopFilterDisableSliceBoundary : Disabled on slice boundaries
+ */
+typedef enum OMX_VIDEO_AVCLOOPFILTERTYPE {
+    OMX_VIDEO_AVCLoopFilterEnable = 0,
+    OMX_VIDEO_AVCLoopFilterDisable,
+    OMX_VIDEO_AVCLoopFilterDisableSliceBoundary,
+    OMX_VIDEO_AVCLoopFilterKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_VIDEO_AVCLoopFilterVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_VIDEO_AVCLoopFilterMax = 0x7FFFFFFF
+} OMX_VIDEO_AVCLOOPFILTERTYPE;
+
+
+/** 
+ * AVC params 
+ *
+ * STRUCT MEMBERS:
+ *  nSize                     : Size of the structure in bytes
+ *  nVersion                  : OMX specification version information
+ *  nPortIndex                : Port that this structure applies to
+ *  nSliceHeaderSpacing       : Number of macroblocks between slice header, put  
+ *                              zero if not used
+ *  nPFrames                  : Number of P frames between each I frame
+ *  nBFrames                  : Number of B frames between each I frame
+ *  bUseHadamard              : Enable/disable Hadamard transform
+ *  nRefFrames                : Max number of reference frames to use for inter
+ *                              motion search (1-16)
+ *  nRefIdxTrailing           : Pic param set ref frame index (index into ref
+ *                              frame buffer of trailing frames list), B frame
+ *                              support
+ *  nRefIdxForward            : Pic param set ref frame index (index into ref
+ *                              frame buffer of forward frames list), B frame
+ *                              support
+ *  bEnableUEP                : Enable/disable unequal error protection. This 
+ *                              is only valid of data partitioning is enabled.
+ *  bEnableFMO                : Enable/disable flexible macroblock ordering
+ *  bEnableASO                : Enable/disable arbitrary slice ordering
+ *  bEnableRS                 : Enable/disable sending of redundant slices
+ *  eProfile                  : AVC profile(s) to use
+ *  eLevel                    : AVC level(s) to use
+ *  nAllowedPictureTypes      : Specifies the picture types allowed in the 
+ *                              bitstream
+ *  bFrameMBsOnly             : specifies that every coded picture of the 
+ *                              coded video sequence is a coded frame 
+ *                              containing only frame macroblocks
+ *  bMBAFF                    : Enable/disable switching between frame and 
+ *                              field macroblocks within a picture
+ *  bEntropyCodingCABAC       : Entropy decoding method to be applied for the 
+ *                              syntax elements for which two descriptors appear 
+ *                              in the syntax tables
+ *  bWeightedPPrediction      : Enable/disable weighted prediction shall not 
+ *                              be applied to P and SP slices
+ *  nWeightedBipredicitonMode : Default weighted prediction is applied to B 
+ *                              slices 
+ *  bconstIpred               : Enable/disable intra prediction
+ *  bDirect8x8Inference       : Specifies the method used in the derivation 
+ *                              process for luma motion vectors for B_Skip, 
+ *                              B_Direct_16x16 and B_Direct_8x8 as specified 
+ *                              in subclause 8.4.1.2 of the AVC spec 
+ *  bDirectSpatialTemporal    : Flag indicating spatial or temporal direct
+ *                              mode used in B slice coding (related to 
+ *                              bDirect8x8Inference) . Spatial direct mode is 
+ *                              more common and should be the default.
+ *  nCabacInitIdx             : Index used to init CABAC contexts
+ *  eLoopFilterMode           : Enable/disable loop filter
+ */
+typedef struct OMX_VIDEO_PARAM_AVCTYPE {
+    OMX_U32 nSize;                 
+    OMX_VERSIONTYPE nVersion;      
+    OMX_U32 nPortIndex;            
+    OMX_U32 nSliceHeaderSpacing;  
+    OMX_U32 nPFrames;     
+    OMX_U32 nBFrames;     
+    OMX_BOOL bUseHadamard;
+    OMX_U32 nRefFrames;  
+       OMX_U32 nRefIdx10ActiveMinus1;
+       OMX_U32 nRefIdx11ActiveMinus1;
+    OMX_BOOL bEnableUEP;  
+    OMX_BOOL bEnableFMO;  
+    OMX_BOOL bEnableASO;  
+    OMX_BOOL bEnableRS;   
+    OMX_VIDEO_AVCPROFILETYPE eProfile;
+       OMX_VIDEO_AVCLEVELTYPE eLevel; 
+    OMX_U32 nAllowedPictureTypes;  
+       OMX_BOOL bFrameMBsOnly;                                                                         
+    OMX_BOOL bMBAFF;               
+    OMX_BOOL bEntropyCodingCABAC;  
+    OMX_BOOL bWeightedPPrediction; 
+    OMX_U32 nWeightedBipredicitonMode; 
+    OMX_BOOL bconstIpred ;
+    OMX_BOOL bDirect8x8Inference;  
+       OMX_BOOL bDirectSpatialTemporal;
+       OMX_U32 nCabacInitIdc;
+       OMX_VIDEO_AVCLOOPFILTERTYPE eLoopFilterMode;
+} OMX_VIDEO_PARAM_AVCTYPE;
+
+typedef struct OMX_VIDEO_PARAM_PROFILELEVELTYPE {
+   OMX_U32 nSize;                 
+   OMX_VERSIONTYPE nVersion;      
+   OMX_U32 nPortIndex;            
+   OMX_U32 eProfile;      /**< type is OMX_VIDEO_AVCPROFILETYPE, OMX_VIDEO_H263PROFILETYPE, 
+                                 or OMX_VIDEO_MPEG4PROFILETYPE depending on context */
+   OMX_U32 eLevel;        /**< type is OMX_VIDEO_AVCLEVELTYPE, OMX_VIDEO_H263LEVELTYPE, 
+                                 or OMX_VIDEO_MPEG4PROFILETYPE depending on context */
+   OMX_U32 nProfileIndex; /**< Used to query for individual profile support information,
+                               This parameter is valid only for 
+                               OMX_IndexParamVideoProfileLevelQuerySupported index,
+                               For all other indices this parameter is to be ignored. */
+} OMX_VIDEO_PARAM_PROFILELEVELTYPE;
+
+/** 
+ * Structure for dynamically configuring bitrate mode of a codec. 
+ *
+ * STRUCT MEMBERS:
+ *  nSize          : Size of the struct in bytes
+ *  nVersion       : OMX spec version info
+ *  nPortIndex     : Port that this struct applies to
+ *  nEncodeBitrate : Target average bitrate to be generated in bps
+ */
+typedef struct OMX_VIDEO_CONFIG_BITRATETYPE {
+    OMX_U32 nSize;                          
+    OMX_VERSIONTYPE nVersion;               
+    OMX_U32 nPortIndex;                     
+    OMX_U32 nEncodeBitrate;                 
+} OMX_VIDEO_CONFIG_BITRATETYPE;
+
+/** 
+ * Defines Encoder Frame Rate setting
+ *
+ * STRUCT MEMBERS:
+ *  nSize            : Size of the structure in bytes
+ *  nVersion         : OMX specification version information 
+ *  nPortIndex       : Port that this structure applies to
+ *  xEncodeFramerate : Encoding framerate represented in Q16 format
+ */
+typedef struct OMX_CONFIG_FRAMERATETYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_U32 xEncodeFramerate; /* Q16 format */
+} OMX_CONFIG_FRAMERATETYPE;
+
+typedef struct OMX_CONFIG_INTRAREFRESHVOPTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_BOOL IntraRefreshVOP;
+} OMX_CONFIG_INTRAREFRESHVOPTYPE;
+
+typedef struct OMX_CONFIG_MACROBLOCKERRORMAPTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_U32 nErrMapSize;           /* Size of the Error Map in bytes */
+    OMX_U8  ErrMap[1];             /* Error map hint */
+} OMX_CONFIG_MACROBLOCKERRORMAPTYPE;
+
+typedef struct OMX_CONFIG_MBERRORREPORTINGTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_BOOL bEnabled;
+} OMX_CONFIG_MBERRORREPORTINGTYPE;
+
+typedef struct OMX_PARAM_MACROBLOCKSTYPE {
+    OMX_U32 nSize;
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_U32 nMacroblocks;
+} OMX_PARAM_MACROBLOCKSTYPE;
+
+/** 
+ * AVC Slice Mode modes 
+ *
+ * OMX_VIDEO_SLICEMODE_AVCDefault   : Normal frame encoding, one slice per frame
+ * OMX_VIDEO_SLICEMODE_AVCMBSlice   : NAL mode, number of MBs per frame
+ * OMX_VIDEO_SLICEMODE_AVCByteSlice : NAL mode, number of bytes per frame
+ */
+typedef enum OMX_VIDEO_AVCSLICEMODETYPE {
+    OMX_VIDEO_SLICEMODE_AVCDefault = 0,
+    OMX_VIDEO_SLICEMODE_AVCMBSlice,
+    OMX_VIDEO_SLICEMODE_AVCByteSlice,
+    OMX_VIDEO_SLICEMODE_AVCKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ 
+    OMX_VIDEO_SLICEMODE_AVCVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
+    OMX_VIDEO_SLICEMODE_AVCLevelMax = 0x7FFFFFFF
+} OMX_VIDEO_AVCSLICEMODETYPE;
+
+/** 
+ * AVC FMO Slice Mode Params 
+ *
+ * STRUCT MEMBERS:
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version information
+ *  nPortIndex : Port that this structure applies to
+ *  nNumSliceGroups : Specifies the number of slice groups
+ *  nSliceGroupMapType : Specifies the type of slice groups
+ *  eSliceMode : Specifies the type of slice
+ */
+typedef struct OMX_VIDEO_PARAM_AVCSLICEFMO {
+    OMX_U32 nSize; 
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_U8 nNumSliceGroups;
+    OMX_U8 nSliceGroupMapType;
+    OMX_VIDEO_AVCSLICEMODETYPE eSliceMode;
+} OMX_VIDEO_PARAM_AVCSLICEFMO;
+
+/** 
+ * AVC IDR Period Configs
+ *
+ * STRUCT MEMBERS:
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version information
+ *  nPortIndex : Port that this structure applies to
+ *  nIDRPeriod : Specifies periodicity of IDR frames
+ *  nPFrames : Specifies internal of coding Intra frames
+ */
+typedef struct OMX_VIDEO_CONFIG_AVCINTRAPERIOD {
+    OMX_U32 nSize; 
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_U32 nIDRPeriod;
+    OMX_U32 nPFrames;
+} OMX_VIDEO_CONFIG_AVCINTRAPERIOD;
+
+/** 
+ * AVC NAL Size Configs
+ *
+ * STRUCT MEMBERS:
+ *  nSize      : Size of the structure in bytes
+ *  nVersion   : OMX specification version information
+ *  nPortIndex : Port that this structure applies to
+ *  nNaluBytes : Specifies the NAL unit size
+ */
+typedef struct OMX_VIDEO_CONFIG_NALSIZE {
+    OMX_U32 nSize; 
+    OMX_VERSIONTYPE nVersion;
+    OMX_U32 nPortIndex;
+    OMX_U32 nNaluBytes;
+} OMX_VIDEO_CONFIG_NALSIZE;
+
+
+/** @} */
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
+/* File EOF */
+
diff --git a/interface/vmcs_host/linux/vcfiled/CMakeLists.txt b/interface/vmcs_host/linux/vcfiled/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..aed0e83
--- /dev/null
@@ -0,0 +1,33 @@
+
+add_definitions(-Werror)
+
+# vcfiled - serves files to videocore. used for media handlers from
+# OpenMAX/IL and loading VLLs.
+add_executable(vcfiled vcfiled.c)
+
+# library to check if vcfiled is running or not
+add_library(vcfiled_check vcfiled_check.c)
+
+target_link_libraries(vcfiled
+                     vcfiled_check
+                      vchostif
+                      vchiq_arm
+                      vcos)
+
+install(TARGETS vcfiled 
+        RUNTIME DESTINATION sbin)
+
+configure_file (etc/init.d/vcfiled ${PROJECT_BINARY_DIR}/etc/init.d/vcfiled)
+
+# script to start up vcfiled at start of day
+install(PROGRAMS ${PROJECT_BINARY_DIR}/etc/init.d/vcfiled
+        DESTINATION /etc/init.d)
+# install locally to the installation directory too
+install(PROGRAMS ${PROJECT_BINARY_DIR}/etc/init.d/vcfiled
+        DESTINATION ${VMCS_INSTALL_PREFIX}/share/install)
+
+# test program for vcfiled_check library
+add_executable(vcfiled_lock_test vcfiled_lock_test.c)
+target_link_libraries(vcfiled_lock_test vcfiled_check)
+
+install(TARGETS vcfiled_check DESTINATION lib)
diff --git a/interface/vmcs_host/linux/vcfiled/etc/init.d/vcfiled b/interface/vmcs_host/linux/vcfiled/etc/init.d/vcfiled
new file mode 100755 (executable)
index 0000000..afe7cbc
--- /dev/null
@@ -0,0 +1,132 @@
+#! /bin/sh
+### BEGIN INIT INFO
+# Provides:          vcfiled
+# Default-Start:     2 3 4 5
+# Default-Stop:      0 1 6
+# Required-Start:    udev
+# Required-Stop:     udev
+# Short-Description: VideoCore file server daemon
+### END INIT INFO
+
+# Author: Luke Diamand <luked@broadcom.com>
+#
+# Please remove the "Author" lines above and replace them
+# with your own name if you copy and modify this script.
+
+# Do NOT "set -e"
+
+# PATH should only include /usr/* if it runs after the mountnfs.sh script
+PATH=/sbin:/usr/sbin:/bin:/usr/bin
+DESC="VideoCore file server daemon"
+NAME=vcfiled
+VCROOT=${CMAKE_INSTALL_PREFIX}
+DAEMON=$VCROOT/sbin/$NAME
+DAEMON_ARGS=""
+PIDFILE=/var/run/$NAME/$NAME
+SCRIPTNAME=/etc/init.d/$NAME
+
+# Exit if the package is not installed
+[ -x "$DAEMON" ] || exit 0
+
+# Read configuration variable file if it is present
+[ -r /etc/default/$NAME ] && . /etc/default/$NAME
+
+# Load the VERBOSE setting and other rcS variables
+. /lib/init/vars.sh
+
+# Define LSB log_* functions.
+# Depend on lsb-base (>= 3.0-6) to ensure that this file is present.
+. /lib/lsb/init-functions
+
+#
+# Function that starts the daemon/service
+#
+do_start()
+{
+       # Return
+       #   0 if daemon has been started
+       #   1 if daemon was already running
+       #   2 if daemon could not be started
+       start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON --test > /dev/null \
+               || return 1
+       start-stop-daemon --start --quiet --pidfile $PIDFILE --exec $DAEMON -- \
+               $DAEMON_ARGS \
+               || return 2
+}
+
+#
+# Function that stops the daemon/service
+#
+do_stop()
+{
+       # Return
+       #   0 if daemon has been stopped
+       #   1 if daemon was already stopped
+       #   2 if daemon could not be stopped
+       #   other if a failure occurred
+       start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE --name $NAME
+       RETVAL="$?"
+       [ "$RETVAL" = 2 ] && return 2
+       start-stop-daemon --stop --quiet --oknodo --retry=0/30/KILL/5 --exec $DAEMON
+       [ "$?" = 2 ] && return 2
+       # Many daemons don't delete their pidfiles when they exit.
+       rm -f $PIDFILE
+       return "$RETVAL"
+}
+
+case "$1" in
+  start)
+       [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME"
+       do_start
+       case "$?" in
+               0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+               2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+       esac
+       ;;
+  stop)
+       [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME"
+       do_stop
+       case "$?" in
+               0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;;
+               2) [ "$VERBOSE" != no ] && log_end_msg 1 ;;
+       esac
+       ;;
+  #reload|force-reload)
+       #
+       # If do_reload() is not implemented then leave this commented out
+       # and leave 'force-reload' as an alias for 'restart'.
+       #
+       #log_daemon_msg "Reloading $DESC" "$NAME"
+       #do_reload
+       #log_end_msg $?
+       #;;
+  restart|force-reload)
+       #
+       # If the "reload" option is implemented then remove the
+       # 'force-reload' alias
+       #
+       log_daemon_msg "Restarting $DESC" "$NAME"
+       do_stop
+       case "$?" in
+         0|1)
+               do_start
+               case "$?" in
+                       0) log_end_msg 0 ;;
+                       1) log_end_msg 1 ;; # Old process is still running
+                       *) log_end_msg 1 ;; # Failed to start
+               esac
+               ;;
+         *)
+               # Failed to stop
+               log_end_msg 1
+               ;;
+       esac
+       ;;
+  *)
+       #echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
+       echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
+       exit 3
+       ;;
+esac
+
+:
diff --git a/interface/vmcs_host/linux/vcfiled/vcfiled.c b/interface/vmcs_host/linux/vcfiled/vcfiled.c
new file mode 100755 (executable)
index 0000000..c856285
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+  * @file
+  *
+  * Daemon serving files to VideoCore from the host filing system.
+  *
+  */
+
+#include <stdio.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <getopt.h>
+#include <syslog.h>
+#include <fcntl.h>
+#ifdef ANDROID
+#include <android/log.h>
+#endif
+
+#include "vchiq.h"
+#include "interface/vchi/vchi.h"
+#include "interface/vcos/vcos.h"
+#include "interface/vmcs_host/vc_vchi_filesys.h"
+#include "vchost.h"
+#include "vcfiled_check.h"
+
+static int log_stderr;                /** Debug output to stderr? */
+static int foreground;                /** Don't fork - run in foreground? */
+static const char *work_dir = "/";    /** Working directory */
+static const char *lock_prefix = "";  /** Lock file prefix */
+static int lock_prefix_set = 0;
+static const char *progname;
+
+VCHI_INSTANCE_T global_initialise_instance;
+VCHI_CONNECTION_T *global_connection;
+
+void vc_host_get_vchi_state(VCHI_INSTANCE_T *initialise_instance, VCHI_CONNECTION_T **connection)
+{
+   *initialise_instance = global_initialise_instance;
+   *connection = global_connection;
+}
+
+static void logmsg(int level, const char *fmt, ...)
+{
+   va_list ap;
+   va_start(ap, fmt);
+
+   if (log_stderr)
+   {
+      vfprintf(stderr, fmt, ap);
+   }
+   else
+   {
+#ifdef ANDROID
+      __android_log_vprint(level, "vcfiled", fmt, ap);
+#else
+      vsyslog(level | LOG_DAEMON, fmt, ap);
+#endif
+   }
+   va_end(ap);
+}
+
+static void usage(const char *progname)
+{
+
+   fprintf(stderr,"usage: %s [-debug] [-foreground] [-root dir] [-lock prefix]\n",
+           progname);
+   fprintf(stderr,"  --debug       - debug to stderr rather than syslog\n");
+   fprintf(stderr,"  --foreground  - do not fork, stay in foreground\n");
+   fprintf(stderr,"  --root dir    - chdir to this directory first\n");
+   fprintf(stderr,"  --lock prefix - prefix to append to VCFILED_LOCKFILE\n");
+}
+
+enum { OPT_DEBUG, OPT_FG, OPT_ROOT, OPT_LOCK };
+
+static void parse_args(int argc, char *const *argv)
+{
+   int finished = 0;
+   static struct option long_options[] =
+   {
+      {"debug", no_argument, &log_stderr, 1},
+      {"foreground", no_argument, &foreground, 1},
+      {"root", required_argument, NULL, OPT_ROOT},
+      {"lock", required_argument, NULL, OPT_LOCK},
+      {0, 0, 0, 0},
+   };
+   while (!finished)
+   {
+      int option_index = 0;
+      int c = getopt_long_only(argc, argv, "", long_options, &option_index);
+
+      switch (c)
+      {
+      case 0:
+         // debug or foreground options, just sets flags directly
+         break;
+      case OPT_ROOT:
+         work_dir = optarg;
+         // sanity check directory
+         if (chdir(work_dir) < 0)
+         {
+            fprintf(stderr,"cannot chdir to %s: %s\n", work_dir, strerror(errno));
+            exit(-1);
+         }
+         break;
+      case OPT_LOCK:
+         lock_prefix = optarg;
+         lock_prefix_set = 1;
+         break;
+
+      default:
+      case '?':
+         usage(argv[0]);
+         exit(-1);
+         break;
+
+      case -1:
+         finished = 1;
+         break;
+      }
+
+   }
+}
+
+int main(int argc, char *const *argv)
+{
+   VCHIQ_INSTANCE_T vchiq_instance;
+   int success;
+   char lockfile[128];
+
+   progname = argv[0];
+   const char *sep = strrchr(progname, '/');
+   if (sep)
+      progname = sep+1;
+
+   parse_args(argc, argv);
+
+   if (!foreground)
+   {
+      if ( daemon( 0, 1 ) != 0 )
+      {
+         fprintf( stderr, "Failed to daemonize: errno = %d", errno );
+         return -1;
+      }
+      log_stderr = 0;
+   }
+   if ( lock_prefix_set )
+   {
+      vcos_safe_sprintf( lockfile, sizeof(lockfile), 0, "%s/%s", lock_prefix, VCFILED_LOCKFILE );
+   }
+   else
+   {
+      vcos_safe_sprintf( lockfile, sizeof(lockfile), 0, "%s", VCFILED_LOCKFILE );
+   }
+   success = vcfiled_lock(lockfile, logmsg);
+   if (success != 0)
+   {
+      return -1;
+   }
+
+   logmsg( LOG_INFO, "vcfiled started" );
+
+   vcos_init();
+
+   if (vchiq_initialise(&vchiq_instance) != VCHIQ_SUCCESS)
+   {
+      logmsg(LOG_ERR, "%s: failed to open vchiq instance\n", argv[0]);
+      return -1;
+   }
+
+   success = vchi_initialise( &global_initialise_instance);
+   vcos_assert(success == 0);
+   vchiq_instance = (VCHIQ_INSTANCE_T)global_initialise_instance;
+
+   global_connection = vchi_create_connection(single_get_func_table(),
+                                              vchi_mphi_message_driver_func_table());
+
+   vchi_connect(&global_connection, 1, global_initialise_instance);
+  
+   vc_vchi_filesys_init (global_initialise_instance, &global_connection, 1);
+
+   for (;;)
+   {
+      sleep(INT_MAX);
+   }
+
+   vcos_deinit ();
+
+   return 0;
+}
+
diff --git a/interface/vmcs_host/linux/vcfiled/vcfiled_check.c b/interface/vmcs_host/linux/vcfiled/vcfiled_check.c
new file mode 100755 (executable)
index 0000000..35e0899
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "vcfiled_check.h"
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+int vcfiled_lock(const char *lockfile, VCFILED_LOGMSG_T logmsg)
+{
+   int rc, fd;
+   char pidbuf[32];
+   char *lockdir = strdup(lockfile);
+   char *sep = strrchr(lockdir, '/');
+   int ret = -1;
+   if (!sep)
+   {
+      free(lockdir);
+      return -1;
+   }
+   *sep = '\0';
+
+   if (mkdir(lockdir, S_IRWXU | S_IRGRP|S_IXGRP) < 0)
+   {
+      if (errno != EEXIST)
+      {
+         logmsg(LOG_CRIT, "could not create %s:%s\n", lockdir,strerror(errno));
+         goto finish;
+      }
+   }
+   fd = open(lockfile, O_RDWR | O_CREAT | O_EXCL, 0640);
+   if (fd<0)
+   {
+      if (errno != EEXIST)
+      {
+         logmsg(LOG_CRIT, "could not create lockfile %s:%s\n", lockfile, strerror(errno));
+         goto finish;
+      }
+      else
+      {
+         // it already exists - reopen it and try to lock it
+         fd = open(lockfile, O_RDWR);
+         if (fd<0)
+         {
+            logmsg(LOG_CRIT, "could not re-open lockfile %s:%s\n", lockfile, strerror(errno));
+            goto finish;
+         }
+      }
+   }
+   // at this point, we have opened the file, and can use discretionary locking, 
+   // which should work even over NFS
+
+   struct flock flock;
+   memset(&flock, 0, sizeof(flock));
+   flock.l_type   = F_WRLCK;
+   flock.l_whence = SEEK_SET;
+   flock.l_start  = 0;
+   flock.l_len    = 1;
+   if (fcntl(fd, F_SETLK, &flock) < 0)
+   {
+      // if we failed to lock, then it might mean we're already running, or
+      // something else bad.
+      if (errno == EACCES || errno == EAGAIN)
+      {
+         // already running
+         int pid = 0, rc = read(fd, pidbuf, sizeof(pidbuf));
+         if (rc)
+            pid = atoi(pidbuf);
+         logmsg(LOG_CRIT, "already running at pid %d\n", pid);
+         close(fd);
+         goto finish;
+      }
+      else
+      {
+         logmsg(LOG_CRIT, "could not lock %s:%s\n", lockfile, strerror(errno));
+         close(fd);
+         goto finish;
+      }
+   }
+   snprintf(pidbuf,sizeof(pidbuf),"%d", getpid());
+   rc = write(fd, pidbuf, strlen(pidbuf)+1);
+   if (rc<0)
+   {
+      logmsg(LOG_CRIT, "could not write pid:%s\n", strerror(errno));
+      goto finish;
+   }
+   /* do not close the file, as that will release the lock - it will
+    * will close automatically when the program exits.
+    */
+   ret = 0;
+finish:
+   free(lockdir);
+   /* coverity[leaked_handle] - fd left open on purpose */
+   return ret;
+}
+
+int vcfiled_is_running(const char *filename)
+{
+   int ret;
+   
+   int fd = open(filename, O_RDONLY);
+   if (fd < 0)
+   {
+      // file not there, so filed not running
+      ret = 0;
+   }
+
+   else
+   {
+      struct flock flock;
+      memset(&flock, 0, sizeof(flock));
+      flock.l_type   = F_WRLCK;
+      flock.l_whence = SEEK_SET;
+      flock.l_start  = 0;
+      flock.l_len    = 1;
+      int rc = fcntl(fd, F_GETLK, &flock);
+      if (rc != 0)
+      {
+         /* could not access lock info */
+         printf("%s: Could not access lockfile %s: %s\n",
+            "vmcs_main", filename, strerror(errno));
+         ret = 0;
+      }
+      else if (flock.l_pid == 0)
+      {
+         /* file is unlocked, so filed not running */
+         ret = 0;
+      }
+      else 
+      {
+         /* file is locked, so filed is running */
+         ret = 1;
+      }
+   }
+   /* coverity[leaked_handle] - fd left open on purpose */
+   return ret;
+}
+
+
+
diff --git a/interface/vmcs_host/linux/vcfiled/vcfiled_check.h b/interface/vmcs_host/linux/vcfiled/vcfiled_check.h
new file mode 100755 (executable)
index 0000000..360f50a
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VCFILED_CHECK_H
+#define VCFILED_CHECK_H
+
+#ifdef ANDROID
+#define VCFILED_LOCKDIR "/tmp/vcfiled/vcfiled.pid"
+#define VCFILED_LOCKFILE "/tmp/vcfiled"
+#endif
+
+#ifndef VCFILED_LOCKFILE
+#define VCFILED_LOCKDIR "/var/run/vcfiled"
+#define VCFILED_LOCKFILE VCFILED_LOCKDIR "/vcfiled"
+#endif
+
+typedef void (*VCFILED_LOGMSG_T)(int level, const char *fmt, ...);
+int vcfiled_lock(const char *filename, VCFILED_LOGMSG_T logmsg);
+extern int vcfiled_is_running(const char *lockfile);
+
+
+#endif
+
+
diff --git a/interface/vmcs_host/linux/vcfiled/vcfiled_lock_test.c b/interface/vmcs_host/linux/vcfiled/vcfiled_lock_test.c
new file mode 100755 (executable)
index 0000000..28e83ca
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/** Very simple test code for the vcfiled locking
+  */
+#include "vcfiled_check.h"
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+
+static void usage(const char *prog)
+{
+   fprintf(stderr, "usage: %s lock|check <lockfile>\n", prog);
+   exit(1);
+}
+
+static void logmsg(int level, const char *fmt, ...)
+{
+   (void)level;
+
+   va_list ap;
+   va_start(ap, fmt);
+   vprintf(fmt, ap);
+   va_end(ap);
+}
+
+int main(int argc, const char **argv)
+{
+   if (argc != 3)
+   {
+      usage(argv[0]);
+   }
+   const char *lockfile = argv[2];
+   if (strcmp(argv[1], "lock") == 0)
+   {
+      int rc = vcfiled_lock(lockfile, logmsg);
+      if (rc)
+      {
+         printf("failed to lock %s\n", lockfile);
+         exit(1);
+      }
+      sleep(300);
+   }
+   else if (strcmp(argv[1], "check") == 0)
+   {
+      printf("%s\n",
+             vcfiled_is_running(lockfile) ?
+             "running" : "not running");
+   }
+   else
+   {
+      usage(argv[0]);
+   }
+   return 0;
+}
+
diff --git a/interface/vmcs_host/linux/vcfilesys.c b/interface/vmcs_host/linux/vcfilesys.c
new file mode 100755 (executable)
index 0000000..9f3ebf1
--- /dev/null
@@ -0,0 +1,1131 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#define VCOS_LOG_CATEGORY (&hostfs_log_cat)
+
+#ifndef  _LARGEFILE_SOURCE
+#define  _LARGEFILE_SOURCE
+#endif
+#ifndef  _LARGEFILE64_SOURCE
+#define  _LARGEFILE64_SOURCE
+#endif
+#define  _FILE_OFFSET_BITS 64    /* So we get lseek and lseek64 */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/statfs.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <assert.h>
+#include <ctype.h>
+#include <limits.h>
+
+#if defined(__GLIBC__) && !defined( __USE_FILE_OFFSET64 )
+#error   "__USE_FILE_OFFSET64 isn't defined"
+#endif
+
+#include "interface/vcos/vcos.h"
+
+/* Some hackery to prevent a clash with the Linux type of the same name */
+#define dirent fs_dirent
+#include "vcfilesys_defs.h"
+#include "vchost.h"
+#undef dirent
+
+#include <dirent.h>
+
+#include "vc_fileservice_defs.h"
+
+VCOS_LOG_CAT_T hostfs_log_cat;
+
+/******************************************************************************
+Global data.
+******************************************************************************/
+
+/******************************************************************************
+Local types and defines.
+******************************************************************************/
+
+//#define DEBUG_LEVEL 1
+#define DEBUG_MINOR(...) vcos_log_info(__VA_ARGS__)
+#define DEBUG_MAJOR(...) vcos_log_warn(__VA_ARGS__)
+
+/* Define a wrapper for the native directory handle which includes the path
+ * to that directory (needed to retrieve size and attributes via stat()).
+ */
+
+struct fs_dir
+{
+   DIR *dhandle;
+   int pathlen;
+   char pathbuf[PATH_MAX];
+};
+
+/*
+ *  The media player on the Videocore may be asked to open a file on the Host that
+ *  is in fact a FIFO.  We need to note when a FIFO has been opened so that we
+ *  can fake out some FIFO seeks that the Videocore may perform, hence the following
+ *  types and variables.
+ */
+
+typedef struct
+{
+   int is_fifo;            // non-zero if file is a FIFO
+   uint64_t read_offset;   // read offset into file
+} file_info_t;
+
+#define FILE_INFO_TABLE_CHUNK_LEN   20
+
+/******************************************************************************
+Static data.
+******************************************************************************/
+
+static file_info_t *p_file_info_table = NULL;
+static int file_info_table_len = 0;
+
+/******************************************************************************
+Static functions.
+******************************************************************************/
+
+static void backslash_to_slash( char *s );
+
+/******************************************************************************
+Global functions.
+******************************************************************************/
+
+/******************************************************************************
+NAME
+   vc_hostfs_init
+
+SYNOPSIS
+   void vc_hostfs_init(void)
+
+FUNCTION
+   Initialises the host to accept requests from Videocore
+
+RETURNS
+   void
+******************************************************************************/
+
+void vc_hostfs_init(void)
+{
+   // This hostfs module is not thread safe - it allocaes a block
+   // of memory and uses it without any kind of locking. 
+   //
+   // It offers no advantage of stdio, and so most clients should
+   // not use it. Arguably FILESYS should use it in order to get
+   // the FIFO support.
+
+   const char *thread_name = vcos_thread_get_name(vcos_thread_current());
+   if (strcmp(thread_name, "FILESYS") != 0 && strcmp(thread_name, "HFilesys") != 0)
+   {
+      fprintf(stderr,"%s: vc_hostfs is deprecated. Please use stdio\n",
+              vcos_thread_get_name(vcos_thread_current()));
+   }
+
+   vcos_log_register("hostfs", &hostfs_log_cat);
+   DEBUG_MINOR("init");
+   // Allocate memory for the file info table
+   p_file_info_table = (file_info_t *)calloc( FILE_INFO_TABLE_CHUNK_LEN, sizeof( file_info_t ) );
+   assert( p_file_info_table != NULL );
+   if (p_file_info_table)
+   {
+      file_info_table_len = FILE_INFO_TABLE_CHUNK_LEN;
+   }
+}
+
+/** Terminate this library. Clean up resources.
+  */
+
+void vc_hostfs_exit(void)
+{
+   vcos_log_unregister(&hostfs_log_cat);
+   if (p_file_info_table)
+   {
+      free(p_file_info_table);
+      p_file_info_table = NULL;
+   }
+}
+
+/******************************************************************************
+NAME
+   vc_hostfs_close
+
+SYNOPSIS
+   int vc_hostfs_close(int fildes)
+
+FUNCTION
+   Deallocates the file descriptor to a file.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_hostfs_close(int fildes)
+{
+   DEBUG_MINOR("vc_hostfs_close(%d)", fildes);
+   return close(fildes);
+}
+
+/******************************************************************************
+NAME
+   vc_hostfs_lseek
+
+SYNOPSIS
+   long vc_hostfs_lseek(int fildes, long offset, int whence)
+
+FUNCTION
+   Sets the file pointer associated with the open file specified by fildes.  If
+   the file is a FIFO (Linux does not support seeking on a FIFO) then, for the
+   benefit of the Videocore streaming file handlers which do a number of null seeks,
+   that is, seeks to the current position, the return value is faked without an
+   actual seek being done.
+
+RETURNS
+   Successful completion: offset
+   Otherwise: -1
+******************************************************************************/
+
+long vc_hostfs_lseek(int fildes, long offset, int whence)
+{
+   return (long) vc_hostfs_lseek64( fildes, (int64_t) offset, whence);
+}
+
+
+/******************************************************************************
+NAME
+   vc_hostfs_lseek64
+
+SYNOPSIS
+   int64_t vc_hostfs_lseek64(int fildes, int64_t offset, int whence)
+
+FUNCTION
+   Sets the file pointer associated with the open file specified by fildes.  If
+   the file is a FIFO (Linux does not support seeking on a FIFO) then, for the
+   benefit of the Videocore streaming file handlers which do a number of null seeks,
+   that is, seeks to the current position, the return value is faked without an
+   actual seek being done.
+
+RETURNS
+   Successful completion: offset
+   Otherwise: -1
+******************************************************************************/
+
+int64_t vc_hostfs_lseek64(int fildes, int64_t offset, int whence)
+{
+   DEBUG_MINOR("vc_hostfs_lseek(%d,%" PRId64 ",%d)", fildes, offset, whence);
+   if (fildes >= file_info_table_len)
+   {
+      // File descriptor not in table, so this is an error
+      DEBUG_MAJOR("vc_hostfs_lseek: invalid fildes %d", fildes);
+      return -1;
+   }
+   else
+   {
+      // There is entry in the file info table for this file descriptor, so go
+      // ahead and handle the seek
+      int64_t read_offset = p_file_info_table[fildes].read_offset;
+
+      if (p_file_info_table[fildes].is_fifo)
+      {
+         // The Videocore is attempting to seek on a FIFO.  FIFOs don't support seeking
+         // but, for the benefit of certain Videocore "streaming" file handlers, we
+         // will fake limited FIFO seek functionality by computing where a seek
+         // would take us to
+         if (whence == SEEK_SET)
+         {
+            read_offset = offset;
+         }
+         else if (whence == SEEK_CUR)
+         {
+            read_offset += offset;
+         }
+         else
+         {
+            // seeking to the end of FIFO makes no sense, so this is an error
+            DEBUG_MAJOR("vc_hostfs_lseek(%d,%lld,%d): SEEK_END not supported on FIFO", fildes, (long long)offset, whence);
+            return -1;
+         }
+      }
+      else
+      {
+         // File is not a FIFO, so do the seek
+         read_offset = lseek64(fildes, offset, whence);
+      }
+      p_file_info_table[fildes].read_offset = read_offset;
+      DEBUG_MINOR("vc_hostfs_lseek returning %" PRId64 ")", read_offset);
+      return read_offset;
+   }
+}
+
+
+
+
+/******************************************************************************
+NAME
+   vc_hostfs_open
+
+SYNOPSIS
+   int vc_hostfs_open(const char *path, int vc_oflag)
+
+FUNCTION
+   Establishes a connection between a file and a file descriptor.  For the benefit
+   of faking out seeks on a FIFO, we will need to keep track of the read offset for
+   all reads, and to facilitate this each opened file is given an entry in a local
+   file info table.
+
+RETURNS
+   Successful completion: file descriptor
+   Otherwise: -1
+******************************************************************************/
+
+int vc_hostfs_open(const char *inPath, int vc_oflag)
+{
+   char *path = strdup( inPath );
+   //char *s;
+   int flags = 0, ret=errno;
+   struct stat fileStat;
+
+   // Replace all '\' with '/'
+   backslash_to_slash( path );
+
+#if 0
+   s = path + strlen( path );
+   if (( s - path ) >= 4 )
+   {
+      if ( strcasecmp( &s[ -4 ], ".vll" ) == 0 )
+      {
+         // The Videocore is asking for a .vll file. Since it isn't consistent with
+         // the case, we convert .vll files to all lowercase.
+          "vc_hostfs_open: '%s'", path ;
+
+         s--;   // backup to the last character (*s is on the '\0')
+         while (( s >= path ) && ( *s != '/' ))
+         {
+            *s = tolower( *s );
+            s--;
+         }
+      }
+   }
+#endif
+   DEBUG_MINOR("vc_hostfs_open: '%s'", path);
+
+   flags = O_RDONLY;
+   if (vc_oflag & VC_O_WRONLY)  flags =  O_WRONLY;
+   if (vc_oflag & VC_O_RDWR)    flags =  O_RDWR;
+   if (vc_oflag & VC_O_APPEND)  flags |= O_APPEND;
+   if (vc_oflag & VC_O_CREAT)   flags |= O_CREAT;
+   if (vc_oflag & VC_O_TRUNC)   flags |= O_TRUNC;
+   if (vc_oflag & VC_O_EXCL)    flags |= O_EXCL;
+
+   //while (*path == '\\') path++; // do not want initial '\'
+   if (flags & O_CREAT)
+      ret = open(path, flags, S_IRUSR | S_IWUSR );
+   else
+      ret = open(path, flags );
+
+   if (ret < 0 )
+   {
+      DEBUG_MINOR("vc_hostfs_open(%s,%d) = %d", path, vc_oflag, ret);
+   }
+   else
+   {
+      DEBUG_MINOR("vc_hostfs_open(%s,%d) = %d", path, vc_oflag, ret);
+   }
+
+   // If the file was successfully open then initialize its entry in
+   // the file info table.  If necessary, we expand the size of the table
+   if (ret >= 0)
+   {
+      // File was successfully opened
+      if (ret >= file_info_table_len)
+      {
+         file_info_t *p_new_file_info_table = p_file_info_table;
+         int new_file_info_table_len = file_info_table_len;
+
+         // try and allocate a bigger buffer for the file info table
+         new_file_info_table_len += FILE_INFO_TABLE_CHUNK_LEN;
+         p_new_file_info_table = calloc( (size_t)new_file_info_table_len, sizeof( file_info_t ) );
+         if (p_new_file_info_table == NULL)
+         {
+            // calloc failed
+            DEBUG_MAJOR("vc_hostfs_open: file_info_table calloc failed");
+            assert( 0 );
+         }
+         else
+         {
+            // calloc successful, so copy data from previous buffer to new buffer,
+            // free previous buffer and update ptr and len info
+            memcpy( p_new_file_info_table, p_file_info_table, sizeof( file_info_t ) * file_info_table_len );
+            free( p_file_info_table );
+            p_file_info_table = p_new_file_info_table;
+            file_info_table_len = new_file_info_table_len;
+         }
+      }
+      assert( ret < file_info_table_len );
+      {
+         // initialize this file's entry in the file info table
+         p_file_info_table[ret].is_fifo = 0;
+         p_file_info_table[ret].read_offset = 0;
+      }
+
+      // Check whether the file is a FIFO.  A FIFO does not support seeking
+      // but we will fake, to the extent supported by the buffered file system
+      // on the Videocore, limited FIFO seek functionality.  This is for the benefit
+      // of certain Videocore "streaming" file handlers.
+      if (fstat( ret, &fileStat ) != 0)
+      {
+         DEBUG_MINOR("vc_hostfs_open: fstat failed: %s", strerror(errno));
+      }
+      else if (S_ISFIFO( fileStat.st_mode ))
+      {
+         // file is a FIFO, so note its fildes for future reference
+         p_file_info_table[ret].is_fifo = 1;
+         DEBUG_MINOR("vc_hostfs_open: file with fildes %d is a FIFO", ret);
+      }
+   }
+
+   free( path );
+
+   return ret;
+}
+
+/******************************************************************************
+NAME
+   vc_hostfs_read
+
+SYNOPSIS
+   int vc_hostfs_read(int fildes, void *buf, unsigned int nbyte)
+
+FUNCTION
+   Attempts to read nbyte bytes from the file associated with the file
+   descriptor, fildes, into the buffer pointed to by buf.  For the benefit
+   of faking out seeks on a FIFO, we keep track of the read offset for all
+   reads.
+
+RETURNS
+   Successful completion: number of bytes read
+   Otherwise: -1
+******************************************************************************/
+
+int vc_hostfs_read(int fildes, void *buf, unsigned int nbyte)
+{
+   if (fildes >= file_info_table_len)
+   {
+      // File descriptor not in table, so this is an error
+      DEBUG_MAJOR("vc_hostfs_read(%d,%p,%u): invalid fildes", fildes, buf, nbyte);
+      return -1;
+   }
+   else
+   {
+      // There is entry in the file info table for this file descriptor, so go
+      // ahead and handle the read
+      int ret = (int) read(fildes, buf, nbyte);
+      DEBUG_MINOR("vc_hostfs_read(%d,%p,%u) = %d", fildes, buf, nbyte, ret);
+      if (ret > 0)
+      {
+         p_file_info_table[fildes].read_offset += (long) ret;
+      }
+      return ret;
+   }
+}
+
+/******************************************************************************
+NAME
+   vc_hostfs_write
+
+SYNOPSIS
+   int vc_hostfs_write(int fildes, const void *buf, unsigned int nbyte)
+
+FUNCTION
+   Attempts to write nbyte bytes from the buffer pointed to by buf to file
+   associated with the file descriptor, fildes.
+
+RETURNS
+   Successful completion: number of bytes written
+   Otherwise: -1
+******************************************************************************/
+
+int vc_hostfs_write(int fildes, const void *buf, unsigned int nbyte)
+{
+   int ret = (int) write(fildes, buf, nbyte);
+   DEBUG_MINOR("vc_hostfs_write(%d,%p,%u) = %d", fildes, buf, nbyte, ret);
+   return ret;
+}
+
+/******************************************************************************
+NAME
+   vc_hostfs_closedir
+
+SYNOPSIS
+   int vc_hostfs_closedir(void *dhandle)
+
+FUNCTION
+   Ends a directory list iteration.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_hostfs_closedir(void *dhandle)
+{
+   struct fs_dir *fsdir = (struct fs_dir *)dhandle;
+   int ret = -1;
+
+   DEBUG_MINOR( "vc_hostfs_closedir(%p)", dhandle );
+
+   if (dhandle && fsdir->dhandle)
+   {
+      (void)closedir(fsdir->dhandle);
+      fsdir->dhandle = NULL;
+      free(fsdir);
+      ret = 0;
+   }
+
+   return ret;
+}
+
+/******************************************************************************
+NAME
+   vc_hostfs_format
+
+SYNOPSIS
+   int vc_hostfs_format(const char *path)
+
+FUNCTION
+   Formats the physical file system that contains path.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_hostfs_format(const char *path)
+{
+   DEBUG_MINOR("vc_hostfs_format: '%s' not implemented", path);
+   return -1;
+}
+
+/******************************************************************************
+NAME
+   vc_hostfs_freespace
+
+SYNOPSIS
+   int vc_hostfs_freespace(const char *path)
+
+FUNCTION
+   Returns the amount of free space on the physical file system that contains
+   path.
+
+RETURNS
+   Successful completion: free space
+   Otherwise: -1
+******************************************************************************/
+
+int vc_hostfs_freespace(const char *inPath)
+{
+   int ret;
+
+   int64_t freeSpace =  vc_hostfs_freespace64( inPath );
+
+   // Saturate return value (need this in case we have a large file system)
+   if (freeSpace > (int64_t) INT_MAX)
+   {
+      ret = INT_MAX;
+   }
+   else
+   {
+      ret = (int) freeSpace;
+   }
+
+   return ret;
+}
+
+
+
+
+
+/******************************************************************************
+NAME
+   vc_hostfs_freespace
+
+SYNOPSIS
+   int vc_hostfs_freespace(const char *path)
+
+FUNCTION
+   Returns the amount of free space on the physical file system that contains
+   path.
+
+RETURNS
+   Successful completion: free space
+   Otherwise: -1
+******************************************************************************/
+int64_t vc_hostfs_freespace64(const char *inPath)
+{
+   char *path = strdup( inPath );
+   int64_t ret;
+   struct statfs fsStat;
+
+   // Replace all '\' with '/'
+   backslash_to_slash( path );
+
+   ret = (int64_t) statfs( path, &fsStat );
+
+   if (ret == 0)
+   {
+      ret = fsStat.f_bsize * fsStat.f_bavail;
+   }
+   else
+   {
+      ret = -1;
+   }
+
+   DEBUG_MINOR( "vc_hostfs_freespace64 for '%s' returning %" PRId64 "", path, ret );
+
+   free( path );
+   return ret;
+}
+
+
+/******************************************************************************
+NAME
+   vc_hostfs_get_attr
+
+SYNOPSIS
+   int vc_hostfs_get_attr(const char *path, fattributes_t *attr)
+
+FUNCTION
+   Gets the file/directory attributes.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_hostfs_get_attr(const char *path, fattributes_t *attr)
+{
+    struct stat sb;
+
+    DEBUG_MINOR("vc_hostfs_get_attr: '%s'", path );
+
+
+    *attr = 0;
+
+    if ( stat( path, &sb ) == 0 )
+    {
+        if ( S_ISDIR( sb.st_mode ))
+        {
+            *attr |= ATTR_DIRENT;
+        }
+
+        if (( sb.st_mode & S_IWUSR  ) == 0 )
+        {
+            *attr |= ATTR_RDONLY;
+        }
+
+        return 0;
+    }
+    return -1;
+}
+
+/******************************************************************************
+NAME
+   vc_hostfs_mkdir
+
+SYNOPSIS
+   int vc_hostfs_mkdir(const char *path)
+
+FUNCTION
+   Creates a new directory named by the pathname pointed to by path.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_hostfs_mkdir(const char *path)
+{
+    DEBUG_MINOR( "vc_hostfs_mkdir: '%s'",  path );
+    if ( mkdir( path, 0777 ) == 0 )
+    {
+        return 0;
+    }
+    return -1;
+}
+
+/******************************************************************************
+NAME
+   vc_hostfs_opendir
+
+SYNOPSIS
+   void *vc_hostfs_opendir(const char *dirname)
+
+FUNCTION
+   Starts a directory list iteration of sub-directories.
+
+RETURNS
+   Successful completion: dhandle (pointer)
+   Otherwise: NULL
+******************************************************************************/
+
+void *vc_hostfs_opendir(const char *dirname)
+{
+   struct fs_dir *fsdir = NULL;
+
+   DEBUG_MINOR( "vc_hostfs_opendir: '%s'", dirname );
+
+   if (dirname && dirname[0])
+   {
+      fsdir = (struct fs_dir *)malloc(sizeof(struct fs_dir));
+
+      if (fsdir)
+      {
+         DIR *dhandle;
+         int len = strlen(dirname);
+
+         memcpy(fsdir->pathbuf, dirname, len);
+
+         backslash_to_slash(fsdir->pathbuf);
+
+         /* Remove any trailing slashes */
+         while (fsdir->pathbuf[len - 1] == '/')
+            len--;
+
+         fsdir->pathbuf[len] = '\0';
+
+         dhandle = opendir(fsdir->pathbuf);
+         DEBUG_MINOR( "opendir: '%s' = %p", fsdir->pathbuf, dhandle );
+
+         if (dhandle)
+         {
+            fsdir->pathlen = len;
+            fsdir->dhandle = dhandle;
+         }
+         else
+         {
+            free(fsdir);
+            fsdir = NULL;
+         }
+      }
+   }
+
+   return fsdir;
+}
+
+/******************************************************************************
+NAME
+   vc_hostfs_readdir_r
+
+SYNOPSIS
+   struct dirent *vc_hostfs_readdir_r(void *dhandle, struct dirent *result)
+
+FUNCTION
+   Fills in the passed result structure with details of the directory entry
+   at the current psition in the directory stream specified by the argument
+   dhandle, and positions the directory stream at the next entry. If the last
+   sub-directory has been reached it ends the iteration and begins a new one
+   for files in the directory.
+
+RETURNS
+   Successful completion: result
+   End of directory stream: NULL
+******************************************************************************/
+
+struct fs_dirent *vc_hostfs_readdir_r(void *dhandle, struct fs_dirent *result)
+{
+   struct fs_dir *fsdir = (struct fs_dir *)dhandle;
+
+   DEBUG_MINOR( "vc_hostfs_readdir_r(%p)", fsdir );
+
+   if (fsdir && result)
+   {
+      struct dirent *dent;
+
+      while ((dent = readdir(fsdir->dhandle)) != NULL)
+      {
+         struct stat statbuf;
+         int ret;
+
+         /* Append the filename, and stat the resulting path */
+         fsdir->pathbuf[fsdir->pathlen] = '/';
+         vcos_safe_strcpy(fsdir->pathbuf, dent->d_name, sizeof(fsdir->pathbuf), fsdir->pathlen + 1);
+         ret = stat(fsdir->pathbuf, &statbuf);
+         fsdir->pathbuf[fsdir->pathlen] = '\0';
+
+         if (ret == 0)
+         {
+            vcos_safe_strcpy(result->d_name, dent->d_name, sizeof(result->d_name), 0);
+            result->d_size = (statbuf.st_size <= 0xffffffff) ? (unsigned int)statbuf.st_size : 0xffffffff;
+            result->d_attrib = ATTR_NORMAL;
+            if ((statbuf.st_mode & S_IWUSR) == 0)
+               result->d_attrib |= ATTR_RDONLY;
+            if (statbuf.st_mode & S_IFDIR)
+               result->d_attrib |= ATTR_DIRENT;
+            result->d_creatime = statbuf.st_ctime;
+            result->d_modtime = statbuf.st_mtime;
+            DEBUG_MINOR( "vc_hostfs_readdir_r() = '%s', %x, %x", result->d_name, result->d_size, result->d_attrib );
+            break;
+         }
+      }
+
+      if (!dent)
+      {
+         DEBUG_MINOR( "vc_hostfs_readdir_r() = NULL" );
+         rewinddir(fsdir->dhandle);
+         result = NULL;
+      }
+   }
+   else
+   {
+      result = NULL;
+   }
+
+   return result;
+}
+
+/******************************************************************************
+NAME
+   vc_hostfs_remove
+
+SYNOPSIS
+   int vc_hostfs_remove(const char *path)
+
+FUNCTION
+   Removes a file or a directory. A directory must be empty before it can be
+   deleted.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_hostfs_remove(const char *path)
+{
+    char *pathbuf = strdup(path);
+    int ret = -1;
+
+    DEBUG_MINOR( "vc_hostfs_remove: '%s'", path );
+
+    if (pathbuf)
+    {
+       backslash_to_slash(pathbuf);
+
+       if ( unlink( pathbuf ) == 0 )
+          ret = 0;
+    }
+
+    free(pathbuf);
+
+    return ret;
+}
+
+/******************************************************************************
+NAME
+   vc_hostfs_rename
+
+SYNOPSIS
+   int vc_hostfs_rename(const char *old, const char *new)
+
+FUNCTION
+   Changes the name of a file. The old and new pathnames must be on the same
+   physical file system.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_hostfs_rename(const char *old, const char *new)
+{
+    char *oldbuf = strdup(old);
+    char *newbuf = strdup(new);
+    int ret = -1;
+
+    DEBUG_MINOR( "vc_hostfs_rename: '%s' to '%s'", old, new );
+
+    if (oldbuf && newbuf)
+    {
+       backslash_to_slash(oldbuf);
+       backslash_to_slash(newbuf);
+
+       if ( rename( oldbuf, newbuf ) == 0 )
+          ret = 0;
+    }
+
+    if (oldbuf)
+       free(oldbuf);
+
+    if (newbuf)
+       free(newbuf);
+
+    return ret;
+}
+
+/******************************************************************************
+NAME
+   vc_hostfs_set_attr
+
+SYNOPSIS
+   int vc_hostfs_set_attr(const char *path, fattributes_t attr)
+
+FUNCTION
+   Sets file/directory attributes.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_hostfs_set_attr(const char *path, fattributes_t attr)
+{
+   char *pathbuf = strdup(path);
+   int ret = -1;
+
+   DEBUG_MINOR( "vc_hostfs_set_attr: '%s', %x", path, attr );
+
+   if (pathbuf)
+   {
+      mode_t mode = 0;
+      struct stat sb;
+
+      backslash_to_slash(pathbuf);
+
+      if ( stat( path, &sb ) == 0 )
+      {
+         mode = sb.st_mode;
+
+         if ( attr & ATTR_RDONLY )
+         {
+            mode &= ~S_IWUSR;
+         }
+         else
+         {
+            mode |= S_IWUSR;
+         }
+
+         /* coverity[toctou] Not doing anything security-relevant here,
+          * so the race condition is harmless */
+         if ( chmod( path, mode ) == 0 )
+            ret = 0;
+      }
+   }
+
+   if (pathbuf)
+      free(pathbuf);
+
+   return ret;
+}
+
+/******************************************************************************
+NAME
+   vc_hostfs_setend
+
+SYNOPSIS
+   int vc_hostfs_setend(int fildes)
+
+FUNCTION
+   Truncates file at current position.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_hostfs_setend(int filedes)
+{
+    off_t   currPosn;
+
+    if (( currPosn = lseek( filedes, 0, SEEK_CUR )) != (off_t)-1 )
+    {
+        if ( ftruncate( filedes, currPosn ) == 0 )
+        {
+            return 0;
+        }
+    }
+   return -1;
+}
+
+
+/******************************************************************************
+NAME
+   vc_hostfs_totalspace64
+
+SYNOPSIS
+   int64_t vc_hostfs_totalspace64(const char *path)
+
+FUNCTION
+   Returns the total amount of space on the physical file system that contains
+   path.
+
+RETURNS
+   Successful completion: total space
+   Otherwise: -1
+******************************************************************************/
+
+int64_t vc_hostfs_totalspace64(const char *inPath)
+{
+   char *path = strdup( inPath );
+   int64_t ret = -1;
+   struct statfs fsStat;
+
+   // Replace all '\' with '/'
+   if (path)
+   {
+      backslash_to_slash( path );
+
+      ret = statfs( path, &fsStat );
+
+      if (ret == 0)
+      {
+         ret = fsStat.f_bsize * fsStat.f_blocks;
+      }
+      else
+      {
+         ret = -1;
+      }
+   }
+
+   DEBUG_MINOR( "vc_hostfs_totalspace for '%s' returning %" PRId64 "", path, ret );
+
+   if (path)
+      free( path );
+   return ret;
+}
+
+
+/******************************************************************************
+NAME
+   vc_hostfs_totalspace
+
+SYNOPSIS
+   int vc_hostfs_totalspace(const char *path)
+
+FUNCTION
+   Returns the total amount of space on the physical file system that contains
+   path.
+
+RETURNS
+   Successful completion: total space
+   Otherwise: -1
+******************************************************************************/
+
+int vc_hostfs_totalspace(const char *inPath)
+{
+   int ret;
+   int64_t totalSpace = vc_hostfs_totalspace64(inPath);
+
+   // Saturate return value (need this in case we have a large file system)
+   if (totalSpace > (int64_t) INT_MAX)
+   {
+      ret = INT_MAX;
+   }
+   else
+   {
+      ret = (int) totalSpace;
+   }
+   return ret;
+}
+
+/******************************************************************************
+NAME
+   backslash_to_slash
+
+SYNOPSIS
+   void backslash_to_slash( char *s )
+
+FUNCTION
+   Convert all '\' in a string to '/'.
+
+RETURNS
+   None.
+******************************************************************************/
+
+static void backslash_to_slash( char *s )
+{
+   while ( *s != '\0' )
+   {
+       if ( *s == '\\' )
+       {
+           *s = '/';
+       }
+       s++;
+   }
+}
+
+/******************************************************************************
+NAME
+   vc_hostfs_scandisk
+
+SYNOPSIS
+   void vc_hostfs_scandisk(const char *path)
+
+FUNCTION
+   Invalidates any cluster chains in the FAT that are not referenced
+   in any directory structures
+
+RETURNS
+   Void
+******************************************************************************/
+
+void vc_hostfs_scandisk(const char *path)
+{
+   (void)path;
+
+   // not yet implemented
+}
+
+
+/******************************************************************************
+NAME
+   vc_hostfs_chkdsk
+
+SYNOPSIS
+   int vc_hostfs_chkdsk(const char *path, int fix_errors)
+
+FUNCTION
+   Checks whether or not a FAT filesystem is corrupt or not. If fix_errors
+   is TRUE behaves exactly as vc_filesys_scandisk.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: indicates failure
+******************************************************************************/
+
+int vc_hostfs_chkdsk(const char *path, int fix_errors)
+{
+   (void)path;
+   (void)fix_errors;
+   return 0;
+}
+
diff --git a/interface/vmcs_host/linux/vchost_config.h b/interface/vmcs_host/linux/vchost_config.h
new file mode 100755 (executable)
index 0000000..4207ec8
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VCHOST_CONFIG_H
+#define VCHOST_CONFIG_H
+
+#include "interface/vcos/vcos.h"
+
+#if 0
+/* Types that map onto VideoCore's types of the same name. */
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef short int16_t;
+typedef long int32_t;
+typedef unsigned long uint32_t;
+typedef long long int64_t;
+typedef unsigned long long uint64_t;
+
+#ifndef vc_assert
+#define vc_assert(cond) vcos_assert(cond)
+#endif
+#endif
+
+/* On this platform we need to be able to release the host-side software resources. */
+extern void vc_os_close(void);
+
+#ifndef VCHPRE_
+#define VCHPRE_     extern
+#endif
+#ifndef VCHPOST_
+#define VCHPOST_
+#endif
+#ifndef VCCPRE_
+#define VCCPRE_     
+#endif
+
+#endif
diff --git a/interface/vmcs_host/linux/vcmisc.c b/interface/vmcs_host/linux/vcmisc.c
new file mode 100755 (executable)
index 0000000..3253669
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <unistd.h>
+
+void vc_sleep(int ms)
+{
+   usleep(1000*ms);
+}
diff --git a/interface/vmcs_host/vc_cec.h b/interface/vmcs_host/vc_cec.h
new file mode 100755 (executable)
index 0000000..f7fe24e
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * CEC related constants - shared by both host and vc.
+ */
+
+#ifndef _VC_CEC_H_
+#define _VC_CEC_H_
+
+#ifndef STRINGIFY
+#define STRINGIFY(x) #x
+#define TOSTRING(x)  STRINGIFY(x)
+#endif
+
+//Broadcast address and TV logical address
+#define CEC_BROADCAST_ADDR       0x0F
+#define CEC_TV_ADDRESS           0x00
+
+//Maximum transmit length excluding the header byte */
+#define CEC_MAX_XMIT_LENGTH      15  /* +1 for CEC Header Length */
+//Invalid physical address
+#define CEC_CLEAR_ADDR           0xFFFF  /* packed 16 bits of F.F.F.F */
+
+/* ----------------------------------------------------------------------
+ * general CEC defines
+ * -------------------------------------------------------------------- */
+//Maximum transmission length and invalid physical address are now in vc_cec.h
+#define CEC_VERSION              0x04    /* HDMI 1.3a */
+//This OUI ID is registered at the current HQ address in Irvine
+#define CEC_VENDOR_ID_BROADCOM   (0x18C086L) // 24 bit OUI company id from IEEE. = Broadcom
+//These three OUI IDs are registered with the old address of Irvine office in case you need them
+//#define CEC_VENDOR_ID_BROADCOM   (0x000AF7L)
+//#define CEC_VENDOR_ID_BROADCOM   (0x001018L)
+//#define CEC_VENDOR_ID_BROADCOM   (0x001BE9L)
+#define CEC_VENDOR_ID_ONKYO            (0x0009B0L)
+#define CEC_VENDOR_ID_PANASONIC_EUROPE (0x000F12L)
+
+//If we want to "pretend" to be somebody else use a different company id
+#define CEC_VENDOR_ID  (0x000000L) //We should set the vendor id
+
+#define CEC_BLOCKING             1
+#define CEC_NONBLOCKING          0
+
+/**
+ * These are the logical addresses for all possible attached devices
+ */
+typedef enum CEC_AllDevices {
+   CEC_AllDevices_eTV = 0,            /**<TV only */
+   CEC_AllDevices_eRec1,              /**<Address for 1st Recording Device */
+   CEC_AllDevices_eRec2,              /**<Address for 2nd Recording Device */
+   CEC_AllDevices_eSTB1,              /**<Address for 1st SetTop Box Device */
+   CEC_AllDevices_eDVD1,              /**<Address for 1st DVD Device */
+   CEC_AllDevices_eAudioSystem,       /**<Address for Audio Device */
+   CEC_AllDevices_eSTB2,              /**<Address for 2nd SetTop Box Device */
+   CEC_AllDevices_eSTB3,              /**<Address for 3rd SetTop Box Device */
+   CEC_AllDevices_eDVD2,              /**<Address for 2nd DVD Device */
+   CEC_AllDevices_eRec3,              /**<Address for 3rd Recording Device */
+   CEC_AllDevices_eSTB4,              /**<10 Address for 4th Tuner Device */
+   CEC_AllDevices_eDVD3,              /**<11 Address for 3rd DVD Device */
+   CEC_AllDevices_eRsvd3,             /**<Reserved and cannot be used */
+   CEC_AllDevices_eRsvd4,             /**<Reserved and cannot be used */
+   CEC_AllDevices_eFreeUse,           /**<Free Address, use for any device */
+   CEC_AllDevices_eUnRegistered = 15  /**<UnRegistered Devices */
+} CEC_AllDevices_T;
+
+/**
+ * define device types for <Report Physical Address>
+ */
+typedef enum CEC_DeviceTypes{
+   CEC_DeviceType_TV           = 0, /**<TV only */
+   CEC_DeviceType_Rec          = 1, /**<Recoding device */
+   CEC_DeviceType_Reserved     = 2, /**<Reserved */
+   CEC_DeviceType_Tuner        = 3, /**<STB */
+   CEC_DeviceType_Playback     = 4, /**<DVD player */
+   CEC_DeviceType_Audio        = 5, /**<AV receiver */
+   CEC_DeviceType_Switch       = 6, /**<CEC switch */
+   CEC_DeviceType_VidProc      = 7, /**<Video processor */
+
+   CEC_DeviceType_Invalid      = 0xF, //RESERVED - DO NOT USE
+} CEC_DEVICE_TYPE_T;
+
+/**
+ * Generic CEC opcode
+ */
+typedef enum {
+   CEC_Opcode_FeatureAbort                 = 0x00,
+   CEC_Opcode_ImageViewOn                  = 0x04,
+   CEC_Opcode_TunerStepIncrement           = 0x05,
+   CEC_Opcode_TunerStepDecrement           = 0x06,
+   CEC_Opcode_TunerDeviceStatus            = 0x07,
+   CEC_Opcode_GiveTunerDeviceStatus        = 0x08,
+   CEC_Opcode_RecordOn                             = 0x09,
+   CEC_Opcode_RecordStatus                 = 0x0A,
+   CEC_Opcode_RecordOff                    = 0x0B,
+   CEC_Opcode_TextViewOn                   = 0x0D,
+   CEC_Opcode_RecordTVScreen                = 0x0F,
+   CEC_Opcode_GiveDeckStatus               = 0x1A,
+   CEC_Opcode_DeckStatus                   = 0x1B,
+   CEC_Opcode_SetMenuLanguage               = 0x32,
+   CEC_Opcode_ClearAnalogTimer              = 0x33,
+   CEC_Opcode_SetAnalogTimer                = 0x34,
+   CEC_Opcode_TimerStatus                   = 0x35,
+   CEC_Opcode_Standby                      = 0x36,
+   CEC_Opcode_Play                         = 0x41,
+   CEC_Opcode_DeckControl                  = 0x42,
+   CEC_Opcode_TimerClearedStatus            = 0x43,
+   CEC_Opcode_UserControlPressed           = 0x44,
+   CEC_Opcode_UserControlReleased          = 0x45,
+   CEC_Opcode_GiveOSDName                  = 0x46,
+   CEC_Opcode_SetOSDName                   = 0x47,
+   CEC_Opcode_SetOSDString                 = 0x64,
+   CEC_Opcode_SetTimerProgramTitle          = 0x67,
+   CEC_Opcode_SystemAudioModeRequest        = 0x70,
+   CEC_Opcode_GiveAudioStatus               = 0x71,
+   CEC_Opcode_SetSystemAudioMode            = 0x72,
+   CEC_Opcode_ReportAudioStatus             = 0x7A,
+   CEC_Opcode_GiveSystemAudioModeStatus     = 0x7D,
+   CEC_Opcode_SystemAudioModeStatus         = 0x7E,
+   CEC_Opcode_RoutingChange                = 0x80,
+   CEC_Opcode_RoutingInformation           = 0x81,
+   CEC_Opcode_ActiveSource                 = 0x82,
+   CEC_Opcode_GivePhysicalAddress           = 0x83,
+   CEC_Opcode_ReportPhysicalAddress         = 0x84,
+   CEC_Opcode_RequestActiveSource          = 0x85,
+   CEC_Opcode_SetStreamPath                = 0x86,
+   CEC_Opcode_DeviceVendorID               = 0x87,
+   CEC_Opcode_VendorCommand                = 0x89,
+   CEC_Opcode_VendorRemoteButtonDown       = 0x8A,
+   CEC_Opcode_VendorRemoteButtonUp         = 0x8B,
+   CEC_Opcode_GiveDeviceVendorID           = 0x8C,
+   CEC_Opcode_MenuRequest                  = 0x8D,
+   CEC_Opcode_MenuStatus                   = 0x8E,
+   CEC_Opcode_GiveDevicePowerStatus        = 0x8F,
+   CEC_Opcode_ReportPowerStatus            = 0x90,
+   CEC_Opcode_GetMenuLanguage               = 0x91,
+   CEC_Opcode_SelectAnalogService           = 0x92,
+   CEC_Opcode_SelectDigitalService         = 0x93,
+   CEC_Opcode_SetDigitalTimer               = 0x97,
+   CEC_Opcode_ClearDigitalTimer             = 0x99,
+   CEC_Opcode_SetAudioRate                  = 0x9A,
+   CEC_Opcode_InactiveSource               = 0x9D,
+   CEC_Opcode_CECVersion                    = 0x9E,
+   CEC_Opcode_GetCECVersion                 = 0x9F,
+   CEC_Opcode_VendorCommandWithID           = 0xA0,
+   CEC_Opcode_ClearExternalTimer            = 0xA1,
+   CEC_Opcode_SetExternalTimer              = 0xA2,
+   CEC_Opcode_ReportShortAudioDescriptor    = 0xA3,
+   CEC_Opcode_RequestShortAudioDescriptor   = 0xA4,
+   CEC_Opcode_InitARC                       = 0xC0,
+   CEC_Opcode_ReportARCInited               = 0xC1,
+   CEC_Opcode_ReportARCTerminated           = 0xC2,
+   CEC_Opcode_RequestARCInit                = 0xC3,
+   CEC_Opcode_RequestARCTermination         = 0xC4,
+   CEC_Opcode_TerminateARC                  = 0xC5,
+   CEC_Opcode_CDC                           = 0xF8,
+   CEC_Opcode_Abort                        = 0xFF
+} CEC_OPCODE_T;
+
+/**
+ * Reason parameter for <Feature Abort>
+ */
+typedef enum {
+   CEC_Abort_Reason_Unrecognised_Opcode   = 0,
+   CEC_Abort_Reason_Wrong_Mode            = 1,
+   CEC_Abort_Reason_Cannot_Provide_Source = 2,
+   CEC_Abort_Reason_Invalid_Operand       = 3,
+   CEC_Abort_Reason_Refused               = 4,
+   CEC_Abort_Reason_Undetermined          = 5
+} CEC_ABORT_REASON_T;
+
+/**
+ * Display control parameter for <Set OSD string>
+ */
+typedef enum {
+   CEC_DISPLAY_CONTROL_DEFAULT_TIME       = 0,
+   CEC_DISPLAY_CONTROL_UNTIL_CLEARED      = (1<<6),
+   CEC_DISPLAY_CONTROL_CLEAR_PREV_MSG     = (1<<7)
+} CEC_DISPLAY_CONTROL_T;
+
+/**
+ * Power status parameter for <Report Power Status>
+ */
+typedef enum {
+   CEC_POWER_STATUS_ON                    = 0,
+   CEC_POWER_STATUS_STANDBY               = 1,
+   CEC_POWER_STATUS_ON_PENDING            = 2,
+   CEC_POWER_STATUS_STANDBY_PENDING       = 3
+} CEC_POWER_STATUS_T;
+
+/**
+ * Menu state parameter for <Menu Status>
+ */
+typedef enum {
+   CEC_MENU_STATE_ACTIVATED               = 0,
+   CEC_MENU_STATE_DEACTIVATED             = 1,
+   CEC_MENU_STATE_QUERY                   = 2
+} CEC_MENU_STATE_T;
+
+/**
+ * Deck status parameter for <Deck Status>
+ */
+typedef enum {
+   CEC_DECK_INFO_PLAY                     = 0x11,
+   CEC_DECK_INFO_RECORD                   = 0x12,
+   CEC_DECK_INFO_PLAY_REVERSE             = 0x13,
+   CEC_DECK_INFO_STILL                    = 0x14,
+   CEC_DECK_INFO_SLOW                     = 0x15,
+   CEC_DECK_INFO_SLOW_REVERSE             = 0x16,
+   CEC_DECK_INFO_SEARCH_FORWARD           = 0x17,
+   CEC_DECK_INFO_SEARCH_REVERSE           = 0x18,
+   CEC_DECK_INFO_NO_MEDIA                 = 0x19,
+   CEC_DECK_INFO_STOP                     = 0x1A,
+   CEC_DECK_INFO_WIND                     = 0x1B,
+   CEC_DECK_INFO_REWIND                   = 0x1C,
+   CEC_DECK_IDX_SEARCH_FORWARD            = 0x1D,
+   CEC_DECK_IDX_SEARCH_REVERSE            = 0x1E,
+   CEC_DECK_OTHER_STATUS                  = 0x1F
+} CEC_DECK_INFO_T;
+
+/**
+ * Deck control mode for <Deck Control>
+ */
+typedef enum {
+   CEC_DECK_CTRL_FORWARD                  = 1,
+   CEC_DECK_CTRL_BACKWARD                 = 2,
+   CEC_DECK_CTRL_STOP                     = 3,
+   CEC_DECK_CTRL_EJECT                    = 4
+} CEC_DECK_CTRL_MODE_T;
+
+/**
+ * Play mode for <Play>
+ */
+typedef enum {
+   CEC_PLAY_FORWARD                       = 0x24,
+   CEC_PLAY_REVERSE                       = 0x20,
+   CEC_PLAY_STILL                         = 0x25,
+   CEC_PLAY_SCAN_FORWARD_MIN_SPEED        = 0x05,
+   CEC_PLAY_SCAN_FORWARD_MED_SPEED        = 0x06,
+   CEC_PLAY_SCAN_FORWARD_MAX_SPEED        = 0x07,
+   CEC_PLAY_SCAN_REVERSE_MIN_SPEED        = 0x09,
+   CEC_PLAY_SCAN_REVERSE_MED_SPEED        = 0x0A,
+   CEC_PLAY_SCAN_REVERSE_MAX_SPEED        = 0x0B,
+   CEC_PLAY_SLOW_FORWARD_MIN_SPEED        = 0x15,
+   CEC_PLAY_SLOW_FORWARD_MED_SPEED        = 0x16,
+   CEC_PLAY_SLOW_FORWARD_MAX_SPEED        = 0x17,
+   CEC_PLAY_SLOW_REVERSE_MIN_SPEED        = 0x19,
+   CEC_PLAY_SLOW_REVERSE_MED_SPEED        = 0x1A,
+   CEC_PLAY_SLOW_REVERSE_MAX_SPEED        = 0x1B
+} CEC_PLAY_MODE_T;
+
+/**
+ * Status request for <Give Deck Status>
+ */
+typedef enum {
+   CEC_DECK_STATUS_ON                     = 1,
+   CEC_DECK_STATUS_OFF                    = 2,
+   CEC_DECK_STATUS_ONCE                   = 3
+} CEC_DECK_STATUS_REQUEST_T;
+
+/**
+ * Button code for <User Control Pressed>
+ */
+typedef enum {
+   CEC_User_Control_Select                      = 0x00,
+   CEC_User_Control_Up                          = 0x01,
+   CEC_User_Control_Down                        = 0x02,
+   CEC_User_Control_Left                        = 0x03,
+   CEC_User_Control_Right                       = 0x04,
+   CEC_User_Control_RightUp                     = 0x05,
+   CEC_User_Control_RightDown                   = 0x06,
+   CEC_User_Control_LeftUp                      = 0x07,
+   CEC_User_Control_LeftDown                    = 0x08,
+   CEC_User_Control_RootMenu                    = 0x09,
+   CEC_User_Control_SetupMenu                   = 0x0A,
+   CEC_User_Control_ContentsMenu                = 0x0B,
+   CEC_User_Control_FavoriteMenu                = 0x0C,
+   CEC_User_Control_Exit                        = 0x0D,
+   CEC_User_Control_Number0                     = 0x20,
+   CEC_User_Control_Number1                     = 0x21,
+   CEC_User_Control_Number2                     = 0x22,
+   CEC_User_Control_Number3                     = 0x23,
+   CEC_User_Control_Number4                     = 0x24,
+   CEC_User_Control_Number5                     = 0x25,
+   CEC_User_Control_Number6                     = 0x26,
+   CEC_User_Control_Number7                     = 0x27,
+   CEC_User_Control_Number8                     = 0x28,
+   CEC_User_Control_Number9                     = 0x29,
+   CEC_User_Control_Dot                         = 0x2A,
+   CEC_User_Control_Enter                       = 0x2B,
+   CEC_User_Control_Clear                       = 0x2C,
+   CEC_User_Control_ChannelUp                   = 0x30,
+   CEC_User_Control_ChannelDown                 = 0x31,
+   CEC_User_Control_PreviousChannel             = 0x32,
+   CEC_User_Control_SoundSelect                 = 0x33,
+   CEC_User_Control_InputSelect                 = 0x34,
+   CEC_User_Control_DisplayInformation          = 0x35,
+   CEC_User_Control_Help                        = 0x36,
+   CEC_User_Control_PageUp                      = 0x37,
+   CEC_User_Control_PageDown                    = 0x38,
+   CEC_User_Control_Power                       = 0x40,
+   CEC_User_Control_VolumeUp                    = 0x41,
+   CEC_User_Control_VolumeDown                  = 0x42,
+   CEC_User_Control_Mute                        = 0x43,
+   CEC_User_Control_Play                        = 0x44,
+   CEC_User_Control_Stop                        = 0x45,
+   CEC_User_Control_Pause                       = 0x46,
+   CEC_User_Control_Record                      = 0x47,
+   CEC_User_Control_Rewind                      = 0x48,
+   CEC_User_Control_FastForward                 = 0x49,
+   CEC_User_Control_Eject                       = 0x4A,
+   CEC_User_Control_Forward                     = 0x4B,
+   CEC_User_Control_Backward                    = 0x4C,
+   CEC_User_Control_Angle                       = 0x50,
+   CEC_User_Control_Subpicture                  = 0x51,
+   CEC_User_Control_VideoOnDemand               = 0x52,
+   CEC_User_Control_EPG                         = 0x53,
+   CEC_User_Control_TimerProgramming            = 0x54,
+   CEC_User_Control_InitialConfig               = 0x55,
+   CEC_User_Control_PlayFunction                = 0x60,
+   CEC_User_Control_PausePlayFunction           = 0x61,
+   CEC_User_Control_RecordFunction              = 0x62,
+   CEC_User_Control_PauseRecordFunction         = 0x63,
+   CEC_User_Control_StopFunction                = 0x64,
+   CEC_User_Control_MuteFunction                = 0x65,
+   CEC_User_Control_RestoreVolumeFunction       = 0x66,
+   CEC_User_Control_TuneFunction                = 0x67,
+   CEC_User_Control_SelectDiskFunction          = 0x68,
+   CEC_User_Control_SelectAVInputFunction       = 0x69,
+   CEC_User_Control_SelectAudioInputFunction    = 0x6A,
+   CEC_User_Control_F1Blue                      = 0x71,
+   CEC_User_Control_F2Red                       = 0x72,
+   CEC_User_Control_F3Green                     = 0x73,
+   CEC_User_Control_F4Yellow                    = 0x74,
+   CEC_User_Control_F5                          = 0x75
+} CEC_USER_CONTROL_T;
+
+/**
+ *CEC topology struct
+ *
+ * Meaning of device_attr is as follows (one per active logical device)
+ * bit 3-0 logical address (see CEC_AllDevices_T above)
+ * bit 7-4 device type (see CEC_DEVICE_TYPE_T above)
+ * bit 11-8 index to upstream device
+ * bit 15-12 number of downstream device
+ * bit 31-16 index of first 4 downstream devices
+ * 
+ * To keep life simple we only show the first 4 connected downstream devices
+ *
+ */
+typedef struct {
+   uint16_t active_mask;       /**<bit n is set if logical device n is active */
+   uint16_t num_devices;       /**<no. of bits set above, save us from counting */
+   uint32_t device_attr[16];   /**<Device attribute, see above for explanation */
+} VC_CEC_TOPOLOGY_T;
+
+/**
+ * CEC message format (provided for host application's convenience
+ * for encapsulating a CEC message
+ */
+typedef struct {
+   uint32_t length; //Length of CEC message without the header, so zero indicates a poll message
+   CEC_AllDevices_T initiator;
+   CEC_AllDevices_T follower;
+   uint8_t payload[CEC_MAX_XMIT_LENGTH+1]; //We actually only need 15 bytes, this payload does not include header
+} VC_CEC_MESSAGE_T;
+
+/**
+ * CEC related notification
+ */
+typedef enum {
+   VC_CEC_NOTIFY_NONE     = 0,        //Reserved - NOT TO BE USED
+   VC_CEC_TX              = (1 << 0), /**<A message has been transmitted */
+   VC_CEC_RX              = (1 << 1), /**<A message has arrived (only for registered commands) */
+   VC_CEC_BUTTON_PRESSED  = (1 << 2), /**<<User Control Pressed> */
+   VC_CEC_BUTTON_RELEASE  = (1 << 3), /**<<User Control Release> */
+   VC_CEC_REMOTE_PRESSED  = (1 << 4), /**<<Vendor Remote Button Down> */
+   VC_CEC_REMOTE_RELEASE  = (1 << 5), /**<<Vendor Remote Button Up> */
+   VC_CEC_LOGICAL_ADDR    = (1 << 6), /**<New logical address allocated or released */
+   VC_CEC_TOPOLOGY        = (1 << 7), /**<Topology is available */
+   VC_CEC_LOGICAL_ADDR_LOST = (1 << 15) /**<Only for passive mode, if the logical address is lost for whatever reason, this will be triggered */
+} VC_CEC_NOTIFY_T;
+
+
+/**
+ * Callback reason and arguments (for sending back to host) All parameters are uint32_t
+ * For the reason parameter
+ * Bit 15-0 of reason is the reason code, 
+ * Bit 23-16 is length of valid bytes which follows in the 4 32-bit parameters (0 < length <= 16)
+ * Bit 31-24 is any return code (if required for this callback)
+ *
+ * Length of valid bytes for TX/RX/button press/release callbacks will be the length
+ * of the actual CEC message
+ *
+ * Length of valid bytes for logical address will always be 6 (first parameter + 16-bit physical address)
+ *
+ * Length of valid bytes for topology callback will always be 2 (16-bit mask)
+ * 
+ * Many CEC callback messages are of variable length so not all bytes 0-15 are available 
+ *
+ * Reason                  param1          param2       param3      param4           remark
+ * VC_CEC_TX               bytes 0-3       bytes 4-7    bytes 8-11  bytes 12-15      A message has been transmitted 
+ *                                                                                   Only a message sent from the host will 
+                                                                                     generate this callback
+                                                                                     (non-zero return code means failure)
+                                                     
+ * VC_CEC_RX               bytes 0-3       bytes 4-7    bytes 8-11  bytes 12-15      By definition only successful message will be forwarded
+ *
+ * VC_CEC_BUTTON_PRESSED   bytes 0-3       bytes 4-7     -           -               User Control pressed (byte 2 will be actual user control code)
+ * VC_CEC_BUTTON_RELEASE   bytes 0-3          -          -           -               User Control release (byte 2 will be actual user control code)
+
+ * VC_CEC_REMOTE_PRESSED   bytes 0-3       bytes 4-7    bytes 8-11  bytes 12-15      Vendor remote button down
+ * VC_CEC_REMOTE_RELEASE   bytes 0-3       bytes 4-7    bytes 8-11  bytes 12-15      Vendor remote button up
+
+ * VC_CEC_LOGICAL_ADDR     Log addr        Phy addr      -           -               Logical address allocated or failure
+ * VC_CEC_TOPOLOGY         topology bit 
+ *                         mask                                                      New topology is avaiable
+ *
+ *VC_CEC_LOGICAL_ADDR_LOST Last log addr   Phy addr                                  "Last log addr" is no longer available
+ *
+ * Notes: 
+ * VC_CEC_BUTTON_RELEASE and VC_CEC_REMOTE_RELEASE (<User Control Release> and <Vendor Remote Button Up> messages respectively)
+ * returns the code from the most recent <User Control pressed> <Vendor Remote button up> respectively.
+ * The host application will need to find out the vendor ID of the initiator
+ * separately in the case if <Vendor Remote Button Up>/<Vendor Remote Button Down> commands were received.
+ * <User Control Pressed> will not be longer than 6 bytes (including header)
+ *
+ * VC_CEC_LOGICAL_ADDR returns 0xF in param1 whenever no logical address is in used. If physical address is 0xFFFF, 
+ * this means CEC is being disabled. Otherwise physical address is the one read from EDID (and no suitable logical address 
+ * is avaiable to be allocated). Host application should only attempt to send message if both param1 is not 0xF AND param2
+ * is not 0xFFFF.
+ *
+ * VC_CEC_TOPOLOGY returns a 16-bit mask in param1 where bit n is set if logical address n is present. Host application
+ * must explicitly retrieve the entire topology if it wants to know how devices are connected. The bit mask includes our
+ * own logical address.
+ *
+ * If CEC is running in passive mode, the host will get a VC_CEC_LOGICAL_ADDR_LOST callback if the logical address is
+ * lost (e.g. HDMI mode change). In this case the host should try a new logical address. The physical address returned may 
+ * also change, so the host should check this.
+ */
+
+/**
+ * General callback function for notifications from CEC middleware (and CEC service)
+ *
+ * @param client_p is the callback context passed in by user
+ *
+ * @param reason is the notification nature (plus message lengths, return code, etc.)
+ *
+ * @param param1 is the first parameter of notification (see above)
+ *
+ * @param param2 is the second parameter of notification (see above)
+ *
+ * @param param3 is the third parameter of notification (see above)
+ *
+ * @param param4 is the fourth parameter of notification (see above)
+ *
+ * @return void
+ */
+typedef void (*CEC_CALLBACK_T)(void *client_p, uint32_t reason, uint32_t param1, uint32_t param2, uint32_t param3, uint32_t param4);
+
+/**
+ * Some macros to get some fields from the callback parameters in CEC callback 
+ */
+//Marcos operating on reason
+#define CEC_CB_REASON(x) ((x) & 0xFFFF) /** Get callback reason */
+#define CEC_CB_MSG_LENGTH(x) (((x) >> 16) & 0xFF) /** Get callback parameter length (this includes the header byte) */
+#define CEC_CB_RC(x) (((x) >> 24) & 0xFF) /** Get return value (only for TX callbacks for the moment) */
+
+//Macros operating on param1
+#define CEC_CB_INITIATOR(x) (((x) >> 4) & 0xF) /** Get the initiator from first parameter */
+#define CEC_CB_FOLLOWER(x) ((x) & 0xF) /** Get the follower from first parameter */
+#define CEC_CB_OPCODE(x) (((x) >> 8) & 0xFF) /** Get the opcode from first parameter */
+#define CEC_CB_OPERAND1(x) (((x) >> 16) & 0xFF) /** Get the button code from <User Control Pressed> or the first operand of the opcode */
+#define CEC_CB_OPERAND2(x) (((x) >> 24) & 0xFF) /** Get the second operand of opcode */
+
+//CEC service return code
+typedef enum {
+   VC_CEC_SUCCESS                = 0, /** OK */
+   VC_CEC_ERROR_NO_ACK           = 1, /** No acknowledgement */
+   VC_CEC_ERROR_SHUTDOWN         = 2, /** In the process of shutting down */
+   VC_CEC_ERROR_BUSY             = 3, /** block is busy */
+   VC_CEC_ERROR_NO_LA            = 4, /** No logical address */
+   VC_CEC_ERROR_NO_PA            = 5, /** No physical address */
+   VC_CEC_ERROR_NO_TOPO          = 6, /** No topology */
+   VC_CEC_ERROR_INVALID_FOLLOWER = 7, /** Invalid follower */
+   VC_CEC_ERROR_INVALID_ARGUMENT = 8  /** Invalid arguments */
+} VC_CEC_ERROR_T;
+
+#endif
diff --git a/interface/vmcs_host/vc_cecservice.h b/interface/vmcs_host/vc_cecservice.h
new file mode 100755 (executable)
index 0000000..1b24221
--- /dev/null
@@ -0,0 +1,515 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * CEC service host API, 
+ * See vc_cec.h and vc_cecservice_defs.h for related constants
+ */
+
+#ifndef _VC_CECSERVICE_H_
+#define _VC_CECSERVICE_H_
+
+#include "vcinclude/common.h"
+#include "interface/vcos/vcos.h"
+#include "interface/vchi/vchi.h"
+#include "interface/vmcs_host/vc_cecservice_defs.h"
+#include "interface/vmcs_host/vc_cec.h"
+
+/**
+ * \file
+ * This API defines the controls for CEC. HDMI must be powered on before
+ * CEC is available (subject to CEC support in TV). 
+ *
+ * In general, a zero return value indicates success; a negative return
+ * value indicates error in VCHI layer; a positive return value indicates
+ * alternative return value from the server
+ */
+
+/**
+ * Callback function for host side notification 
+ * This is the SAME as the callback function type defined in vc_cec.h
+ * Host applications register a single callback for all CEC related notifications.
+ * See vc_cec.h for meanings of all parameters
+ *
+ * @param callback_data is the context passed in by user in <DFN>vc_cec_register_callback</DFN>
+ *
+ * @param reason bits 15-0 is VC_CEC_NOTIFY_T in vc_cec.h;
+ *               bits 23-16 is the valid length of message in param1 to param4 (LSB of param1 is the byte0, MSB of param4 is byte15), little endian
+ *               bits 31-24 is the return code (if any)
+ *
+ * @param param1 is the first parameter
+ * 
+ * @param param2 is the second parameter
+ *
+ * @param param3 is the third parameter
+ *
+ * @param param4 is the fourth parameter
+ * 
+ * @return void
+ */
+typedef void (*CECSERVICE_CALLBACK_T)(void *callback_data, uint32_t reason, uint32_t param1, uint32_t param2, uint32_t param3, uint32_t param4);
+
+//API at application start time
+/**
+ * Call <DFN>vc_vchi_cec_init</DFN> to initialise the CEC service for use.
+ *
+ * @param initialise_instance is the VCHI instance
+ * @param connections are array of pointers to VCHI connections
+ * @param num_connections is the number of connections in array
+ * @return void
+ **********************************************************/
+VCHPRE_ void vc_vchi_cec_init(VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections );
+
+/**
+ * Call <DFN>vc_vchi_cec_stop</DFN> to stop host side CEC service.
+ *
+ * @param none
+ * @return void
+ **********************************************************/
+VCHPRE_ void vc_vchi_cec_stop( void );
+
+/**
+ * Host applications use <DFN>vc_cec_register_callaback</DFN> to register
+ * callback to handle all CEC notifications. If more than one applications 
+ * need to use CEC, there should be ONE central application which acts on
+ * behalf of all clients and handles all communications with CEC services.
+ *
+ * @param callback function 
+ * @param context to be passed when function is called
+ * @return void
+ ***********************************************************/
+VCHPRE_ void vc_cec_register_callback(CECSERVICE_CALLBACK_T callback, void *callback_data);
+
+//Service API
+/**
+ * Use <DFN>vc_cec_register_command</DFN> to register an opcode to
+ * to forwarded to the host application. By default <Feature Abort> 
+ * is always forwarded. Once an opcode is registered, it is left to
+ * the host application to reply to a CEC message (where appropriate).
+ * It is recommended NOT to register the following commands as they 
+ * are replied to automatically by CEC middleware:
+ * <Give Physical Address>, <Give Device Vendor ID>, <Give OSD Name>,
+ * <Get CEC Version>, <Give Device Power Status>, <Menu Request>,
+ * and <Get Menu Language>
+ * In addition, the following opcodes cannot be registered:
+ * <User Control Pressed>, <User Control Released>, 
+ * <Vendor Remote Button Down>, <Vendor Remote Button Up>,
+ * and <Abort>.
+ * <Feature Abort> is always forwarded if it is the reply
+ * of a command the host sent.
+ *
+ * @param opcode to be registered.
+ *
+ * @return zero if the command is successful, non-zero otherwise
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_register_command(CEC_OPCODE_T opcode);
+
+/**
+ * <DFN>vc_cec_register_all</DFN> registers all opcodes except <Abort>
+ *  to be forwarded as CEC_RX notification.
+ * Button presses <User Control Pressed>, etc. will still be forwarded 
+ * separately as VC_CEC_BUTTON_PRESSED etc. notification.
+ *
+ * @param None
+ *
+ * @return zero if the command is successful, non-zero otherwise
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_register_all( void );
+
+/**
+ * Use <DFN>vc_cec_deregister_command</DFN> to remove an opcode from
+ * the filter for forwarding. By default <Feature Abort> is always forwarded.
+ * The following opcode cannot be deregistered:
+ * <User Control Pressed>, <User Control Released>, 
+ * <Vendor Remote Button Down>, <Vendor Remote Button Up>,
+ * and <Abort>.
+ *
+ * @param opcode to be deregistered
+ *
+ * @return zero if the command is successful, non-zero otherwise
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_deregister_command(CEC_OPCODE_T opcode);
+
+/**
+ * <DFN>vc_cec_deregister_all</DFN> removes all registered opcodes,
+ * except the ones (e.g. button presses) which are always forwarded.
+ *
+ * @param None
+ *
+ * @return zero if the command is successful, non-zero otherwise
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_deregister_all( void );
+
+/**
+ * <DFN>vc_cec_send_message</DFN> allows a host application to 
+ * send a CEC message to another device. There are several 
+ * built-in functions for sending command messages. The host
+ * application MUST have a valid logical address (between 1 and
+ * 14 inclusive) before it can send a message.
+ * (For poll message set payload to NULL and length to zero).
+ *
+ * @param Follower's logical address
+ *
+ * @param Message payload WITHOUT the header byte (can be NULL)
+ *
+ * @param Payload length WITHOUT the header byte (can be zero)
+ *
+ * @param VC_TRUE if the message is a reply to an incoming message
+ *
+ * @return zero if the command is successful, non-zero otherwise
+ *         If the command is successful, there will be a Tx callback
+ *         in due course to indicate whether the message has been
+ *         acknowledged by the recipient or not
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_send_message(const uint32_t follower,
+                                         const uint8_t *payload,
+                                         uint32_t length,
+                                         vcos_bool_t is_reply);
+/**
+ * <DFN>vc_cec_get_logical_address</DFN> gets the logical address, 
+ * If one is being allocated 0xF (unregistered) will be set.
+ * A address value of 0xF also means CEC system is not yet ready
+ * to send or receive any messages.
+ *
+ * @param pointer to logical address (set to allocated address)
+ *
+ * @return zero if the command is successful, non-zero otherwise
+ *         logical_address is not modified if command failed
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_get_logical_address(CEC_AllDevices_T *logical_address);
+
+/**
+ * <DFN>vc_cec_alloc_logical_address</DFN> starts the allocation 
+ * of a logical address. Logical address is automatically allocated
+ * after HDMI power on is complete and AV mute is deassert.
+ * The host only needs to call this if the 
+ * initial allocation failed (logical address being 0xF and 
+ * physical address is NOT 0xFFFF from <DFN>VC_CEC_LOGICAL_ADDR</DFN>
+ * notification), or if the host explicitly released its logical 
+ * address.
+ *
+ * @param none
+ *
+ * @return zero if the command is successful, non-zero otherwise
+ *         If successful, there will be a callback notification
+ *         <DFN>VC_CEC_LOGICAL_ADDR</DFN>. 
+ *         The host should wait for this before calling this 
+ *         function again.
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_alloc_logical_address( void );
+
+/**
+ * Normally <DFN>vc_cec_release_logical_address</DFN> will not 
+ * be called by the host application. It is used to release 
+ * our logical address. This effectively disables CEC.
+ * The host will need to allocate a new logical address before
+ * doing any CEC calls (send/receive message, get topology, etc.). 
+ *
+ * @param none
+ *
+ * @return zero if the command is successful, non-zero otherwise
+ *         The host should get a callback <DFN>VC_CEC_LOGICAL_ADDR</DFN>
+ *         with 0xF being the logical address and 0xFFFF 
+ *         being the physical address.
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_release_logical_address( void );
+
+/**
+ * Use <DFN>vc_cec_get_topology</DFN> to get the topology.
+ *
+ * @param pointer to <DFN>VC_CEC_TOPOLOGY_T</DFN>
+ *
+ * @return zero if the command is successful, non-zero otherwise
+ *         If successful, the topology will be set, otherwise it is unchanged
+ *         A topology with only 1 device (us) means CEC is not supported.
+ *         If there is no topology available, this also returns a failure.
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_get_topology( VC_CEC_TOPOLOGY_T* topology);
+
+/**
+ * Use <DFN>vc_cec_set_vendor_id</DFN> to 
+ * set the response to <Give Device Vendor ID>
+ *
+ * @param 24-bit IEEE vendor id
+ *
+ * @return zero if the command is successful, non-zero otherwise
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_set_vendor_id( const uint32_t id );
+
+/**
+ * Use <DFN>vc_cec_set_osd_name</DFN> to
+ * set the response to <Give OSD Name>
+ * 
+ * @param OSD name (14 byte char array)
+ *
+ * @return zero if the command is successful, non-zero otherwise
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_set_osd_name( const char* name );
+
+/**
+ * <DFN>vc_cec_get_physical_address</DFN> gets our physical address
+ *
+ * @param pointer to physical address (returned as 16-bit packed value)
+ *
+ * @return zero if the command is successful, non-zero otherwise
+ *          If failed, physical address argument will not be changed
+ *          A physical address of 0xFFFF means CEC is not supported
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_get_physical_address(uint16_t *physical_address);
+
+/**
+ * <DFN>vc_cec_get_vendor_id(</DFN> gets the vendor id of a particular logical address
+ *
+ * @param logical_address is the logical address of the device [in]
+ *
+ * @param vendorid is the pointer to vendor ID (24-bit IEEE OUI value) [out]
+ *
+ * @return zero if the command is successful, non-zero otherwise
+ *         If failed, vendor id argument will not be changed
+ *         A vendor ID of 0xFFFFFF means the device does not exist
+ *         A vendor ID of 0x0 means vendor ID is not known and
+ *         the application can send <Give Device Vendor ID> to that device
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_get_vendor_id(const CEC_AllDevices_T logical_address, uint32_t *vendor_id);
+
+/**
+ * <DFN>vc_cec_device_type(</DFN> returns the default device type of a particular
+ * logical address, which can be used as the argument to vc_cec_send_ReportPhysicalAddress.
+ *
+ * @param logical address
+ *
+ * @return the default device type, if there is any error, the return device
+ *         type will be CEC_DeviceType_Invalid
+ *
+ ************************************************************/
+VCHPRE_ CEC_DEVICE_TYPE_T VCHPOST_ vc_cec_device_type(const CEC_AllDevices_T logical_address);
+
+/**
+ * These couple of functions are provided for host application's convenience:
+ * If the xmit message is encapsulate in a VC_CEC_MESSAGE_T
+ * then it can be sent as a normal message (not as a reply)
+ * and the initiator field is ignored with vc_cec_send_message2
+ * and return zero for success
+ * 
+ * Applications can call vc_cec_param2message to turn the callback parameters
+ * into a VC_CEC_MESSAGE_T (not for LOGICAL_ADDR and TOPOLOGY callbacks). 
+ * It also returns zero for success.
+ */
+VCHPRE_ int VCHPOST_ vc_cec_send_message2(const VC_CEC_MESSAGE_T *message);
+
+VCHPRE_ int VCHPOST_ vc_cec_param2message( const uint32_t reason, const uint32_t param1, 
+                                           const uint32_t param2, const uint32_t param3,
+                                           const uint32_t param4, VC_CEC_MESSAGE_T *message);
+
+//Extra API if CEC is running in passive mode
+//If CEC is not in passive mode the following 3 functions always
+//return failure
+/**
+ * <DFN> vc_cec_poll_address </DFN> sets and polls a particular address to find out
+ * its availability in the CEC network. Only available when CEC is running in passive
+ * mode. The host can only call this function during logical address allocation stage.
+ *
+ * @param logical address to try
+ *
+ * @return 0 if poll is successful (address is occupied)
+ *        >0 if poll is unsuccessful (Error code is in VC_CEC_ERROR_T in vc_cec.h)
+ *        <0 VCHI errors
+ */
+VCHPRE_ int VCHPOST_ vc_cec_poll_address(const CEC_AllDevices_T logical_address);
+
+/**
+ * <DFN> vc_cec_set_logical_address </DFN> sets the logical address, device type
+ * and vendor ID to be in use. Only available when CEC is running in passive
+ * mode. It is the responsibility of the host to make sure the logical address
+ * is actually free to be used. Physical address will be what is read from EDID.
+ *
+ * @param logical address
+ *
+ * @param device type
+ *
+ * @param vendor ID
+ *
+ * @return 0 if successful, non-zero otherwise
+ */
+VCHPRE_ int VCHPOST_ vc_cec_set_logical_address(const CEC_AllDevices_T logical_address,
+                                                const CEC_DEVICE_TYPE_T device_type,
+                                                const uint32_t vendor_id);
+
+/**
+ * <DFN> vc_cec_add_device </DFN> adds a new device to topology. 
+ * Only available when CEC is running in passive mode. Device will be
+ * automatically removed from topology if a failed xmit is detected.
+ * If last_device is true, it will trigger a topology computation
+ * (and may trigger a topology callback).
+ *
+ * @param logical address
+ * 
+ * @param physical address
+ *
+ * @param device type
+ *
+ * @param true if this is the last device, false otherwise
+ *
+ * @return 0 if successful, non-zero otherwise
+ */
+VCHPRE_ int VCHPOST_ vc_cec_add_device(const CEC_AllDevices_T logical_address,
+                                       const uint16_t physical_address,
+                                       const CEC_DEVICE_TYPE_T device_type,
+                                       vcos_bool_t last_device);
+
+/**
+ * <DFN> vc_cec_set_passive </DFN> enables and disables passive mode.
+ * Call this function first (with VC_TRUE as the argument) to enable
+ * passive mode before calling any of the above passive API functions
+ *
+ * @param TRUE to enable passive mode, FALSE to disable
+ * 
+ * @return 0 if successful, non-zero otherwise
+ */
+VCHPRE_ int VCHPOST_ vc_cec_set_passive(vcos_bool_t enabled);
+
+
+//API for some common CEC messages
+/** 
+ * Functions beginning with vc_cec_send_xxx make it easier for the 
+ * host application to send CEC message xxx to other devices
+ */
+/**
+ * <DFN>vc_cec_send_FeatureAbort</DFN> sends <Feature Abort> 
+ * for a received command.
+ *
+ * @param follower (cannot be 0xF)
+ *
+ * @param rejected opcode
+ *
+ * @param reject reason <DFN>CEC_ABORT_REASON_T</DFN>
+ *
+ * @return zero if the command is successful, non-zero otherwise
+ *         Tx callback if successful
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_send_FeatureAbort(uint32_t follower, 
+                                              CEC_OPCODE_T opcode, 
+                                              CEC_ABORT_REASON_T reason);
+
+/**
+ * <DFN>vc_cec_send_ActiveSource</DFN> broadcasts
+ * <Active Source> to all devices
+ *
+ * @param physical address (16-bit packed)
+ *
+ * @param reply or not (normally not)
+ *
+ * @return zero if the command is successful, non-zero otherwise
+ *         Tx callback if successful
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_send_ActiveSource(uint16_t physical_address, vcos_bool_t is_reply);
+
+/**
+ * <DFN>vc_cec_send_ImageViewOn</DFN> sends <Image View On>
+ * 
+ * @param follower
+ *
+ * @param reply or not (normally not)
+ *
+ * @return zero if the command is successful, non-zero otherwise
+ *         Tx callback if successful
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_send_ImageViewOn(uint32_t follower, vcos_bool_t is_reply);
+
+/**
+ * <DFN>vc_cec_send_SetOSDString</DFN> sends <Set OSD String>
+ *
+ * @param follower 
+ *
+ * @param string (char[13]) 
+ *
+ * @param display control <DFN>CEC_DISPLAY_CONTROL_T</DFN>
+ *
+ * @param reply or not (normally not)
+ *
+ * @return zero if the command is successful, non-zero otherwise
+ *         Tx callback if successful
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_send_SetOSDString(uint32_t follower, 
+                                              CEC_DISPLAY_CONTROL_T disp_ctrl, 
+                                              const char* string,
+                                              vcos_bool_t is_reply);
+
+/**
+ * <DFN>vc_cec_send_Standby</DFN> sends <Standby>.
+ * This will put any/all devices to standby if they support
+ * this CEC message.
+ *
+ * @param follower (can be 0xF)
+ *
+ * @param reply or not (normally not)
+ *
+ * @return zero if the command is successful, non-zero otherwise
+ *         Tx callback if successful
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_send_Standby(uint32_t follower, vcos_bool_t is_reply);
+
+/**
+ * <DFN>vc_cec_send_MenuStatus</DFN> sends <Menu Status> 
+ * (response to <Menu Request>)
+ *
+ * @param follower
+ * 
+ * @param menu state <DFN>CEC_MENU_STATE_T</DFN> but NOT CEC_MENU_STATE_QUERY
+ *
+ * @param reply or not (should always be yes)
+ *
+ * @return zero if the command is successful, non-zero otherwise
+ *         Tx callback if successful
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_send_MenuStatus(uint32_t follower, 
+                                            CEC_MENU_STATE_T menu_state, 
+                                            vcos_bool_t is_reply);
+
+/**
+ * <DFN>vc_cec_send_ReportPhysicalAddress</DFN> broadcasts
+ * <Report Physical Address> to all devices. Note although
+ * the passed in device type can be override the default one 
+ * associated the allocated logical address, it is not 
+ * recommended to do so. One can use <DFN>vc_cec_device_type</DFN>
+ * to get the default device type associated with the logical 
+ * address returned via VC_CEC_LOGICAL_ADDR callback.
+ *
+ * @param physical address (16-bit packed)
+ *
+ * @param device type to be broadcasted
+ *
+ * @param reply or not (normally not)
+ *
+ * @return zero if the command is successful, non-zero otherwise
+ *         Tx callback if successful
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_send_ReportPhysicalAddress(uint16_t physical_address, 
+                                                       CEC_DEVICE_TYPE_T device_type,
+                                                       vcos_bool_t is_reply);
+
+#endif //_VC_CECSERVICE_H_
diff --git a/interface/vmcs_host/vc_cecservice_defs.h b/interface/vmcs_host/vc_cecservice_defs.h
new file mode 100755 (executable)
index 0000000..01045e3
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * CEC service command enumeration and parameter types.
+ */
+
+/**
+ * \file
+ * This file contains definition shared by host side and
+ * Videocore side CEC service:
+ *
+ * In general, a zero return value indicates success of the function
+ * A non-zero value indicates VCHI error
+ * A positive value indicates alternative return value (for some functions).
+ *
+ */
+
+
+#ifndef _VC_CECSERVICE_DEFS_H_
+#define _VC_CECSERVICE_DEFS_H_
+#include "vcinclude/common.h"
+#include "interface/vcos/vcos.h"
+#include "interface/vcos/vcos_logging.h"
+#include "interface/vchi/message_drivers/message.h"
+
+//CEC VCOS logging stuff
+#define CECHOST_LOG_CATEGORY (&cechost_log_category)
+#define vc_cec_log_trace(...) _VCOS_LOG_X(CECHOST_LOG_CATEGORY, VCOS_LOG_TRACE, __VA_ARGS__)
+#define vc_cec_log_warn(...)  _VCOS_LOG_X(CECHOST_LOG_CATEGORY, VCOS_LOG_WARN, __VA_ARGS__)
+#define vc_cec_log_error(...) _VCOS_LOG_X(CECHOST_LOG_CATEGORY, VCOS_LOG_ERROR, __VA_ARGS__)
+#define vc_cec_log_info(...)  _VCOS_LOG_X(CECHOST_LOG_CATEGORY, VCOS_LOG_INFO, __VA_ARGS__)
+extern VCOS_LOG_CAT_T cechost_log_category; //The actual object lives in CEC host side service code
+
+#define VC_CECSERVICE_VER 1
+#define CECSERVICE_MSGFIFO_SIZE 1024
+#define CECSERVICE_CLIENT_NAME MAKE_FOURCC("CECS")
+#define CECSERVICE_NOTIFY_NAME MAKE_FOURCC("CECN")
+
+//CEC service commands
+typedef enum {
+   VC_CEC_REGISTER_CMD = 0,
+   VC_CEC_REGISTER_ALL,
+   VC_CEC_DEREGISTER_CMD,
+   VC_CEC_DEREGISTER_ALL,
+   VC_CEC_SEND_MSG,
+   VC_CEC_GET_LOGICAL_ADDR,
+   VC_CEC_ALLOC_LOGICAL_ADDR,
+   VC_CEC_RELEASE_LOGICAL_ADDR,
+   VC_CEC_GET_TOPOLOGY,
+   VC_CEC_SET_VENDOR_ID,
+   VC_CEC_SET_OSD_NAME,
+   VC_CEC_GET_PHYSICAL_ADDR,
+   VC_CEC_GET_VENDOR_ID,
+
+   //The following 3 commands are used when CEC middleware is 
+   //running in passive mode (i.e. it does not allocate 
+   //logical address automatically)
+   VC_CEC_POLL_ADDR,
+   VC_CEC_SET_LOGICAL_ADDR,
+   VC_CEC_ADD_DEVICE,
+   VC_CEC_SET_PASSIVE,
+   //Add more commands here
+   VC_CEC_END_OF_LIST
+} VC_CEC_CMD_CODE_T;
+
+//See vc_cec.h for details
+//REGISTER_CMD
+//Parameters: opcode to register (CEC_OPCODE_T sent as uint32)
+//Reply: none
+
+//REGISTER_ALL
+//Parameters: none
+//Reply: none
+
+//DEREGISTER_CMD
+//Parameters: opcode to deregister (CEC_OPCODE_T sent as uint32)
+//Reply: none
+
+//DEREGISTER_ALL
+//Parameters: none
+//Reply: none
+
+//SEND_MSG
+//Parameters: destination, length, 16 bytes buffer (message can only be at most 15 bytes however)
+//Reply: none (callback)
+typedef struct {
+   uint32_t follower;
+   uint32_t length;
+   uint8_t payload[16]; //max. 15 bytes padded to 16
+   uint32_t is_reply;   //non-zero if this is a reply, zero otherwise
+} CEC_SEND_MSG_PARAM_T;
+
+//GET_LOGICAL_ADDR
+//Parameters: none
+//Reply: logical address (uint8 returned as uint32)
+
+//ALLOC_LOGICAL_ADDR
+//Parameters: none
+//Reply: none (callback)
+
+//GET_TOPOLOGY
+//Parameters: none
+//Reply: topology (see VC_TOPOLOGY_T)
+
+//SET_VENDOR_ID
+//Parameters: vendor id (uint32)
+//Reply: none
+
+//Set OSD name
+//Parameters: 14 byte char
+//Reply: none
+#define OSD_NAME_LENGTH 14
+
+//GET_PHYSICAL_ADDR
+//Parameter: none
+//Reply: packed physical address returned as uint16
+
+//GET_VENDOR_ID
+//Parameter: logical address (CEC_AllDevices_T sent as uint32_t)
+//Reply: (uint32_t vendor id)
+
+//POLL_LOGICAL_ADDR (only for passive mode)
+//Used by host to test a logical address to see if it is available for use
+//Only available if CEC is compiled in passive mode and while the host
+//is testing the availability of a logical address
+//Parameter: logical address
+//Reply: 
+
+//SET_LOGICAL_ADDR [(only for passive mode) This will be changed when we support multiple logical addresses]
+//Set the logical address used 
+//Only available if CEC is compiled in passive mode
+//Parameter: logical address, device type, vendor ID
+//Reply: (int32_t - zero means success, non-zero otherwise)
+//This function will result in a VC_CEC_LOGICAL_ADDR callback
+typedef struct {
+   uint32_t logical_address;
+   uint32_t device_type;
+   uint32_t vendor_id;
+} CEC_SET_LOGICAL_ADDR_PARAM_T;
+   
+//ADD_DEVICE (only for passive mode)
+//Only available if CEC is compiled in passive mode
+//Parameter: logical address, physical address, device type, last device?
+//Reply: (int32_t - zero means success, non-zero otherwise)
+typedef struct {
+   uint32_t logical_address;  /**<logical address */
+   uint32_t physical_address; /**<16-bit packed physical address in big endian */
+   uint32_t device_type;      /**<CEC_DEVICE_TYPE_T */
+   uint32_t last_device;      /**<True (non-zero) or false (zero) */
+} CEC_ADD_DEVICE_PARAM_T;
+
+//SET PASSIVE (only for passive mode)
+//Enable/disable passive mode
+//Parameter: non-zero to enable passive mode, zero to disable
+//Reply: (int32_t - zero means success, non-zero otherwise, non zero will be VCHI errors)
+
+#endif //#ifndef _VC_CECSERVICE_DEFS_H_
diff --git a/interface/vmcs_host/vc_cma.h b/interface/vmcs_host/vc_cma.h
new file mode 100755 (executable)
index 0000000..1a275de
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef _VC_CMA_H_
+#define _VC_CMA_H_
+
+#include "interface/vcos/vcos.h"
+#include "interface/vchiq_arm/vchiq.h"
+
+#ifdef __linux__
+
+#include <linux/ioctl.h>
+
+#define VC_CMA_IOC_MAGIC 0xc5
+
+#define VC_CMA_IOC_RESERVE _IO(VC_CMA_IOC_MAGIC, 0)
+
+#endif
+
+#define VC_CMA_FOURCC VCHIQ_MAKE_FOURCC('C','M','A',' ')
+#define VC_CMA_VERSION 2
+
+#define VC_CMA_CHUNK_ORDER 6  /* 256K */
+#define VC_CMA_CHUNK_SIZE (4096 << VC_CMA_CHUNK_ORDER)
+#define VC_CMA_MAX_PARAMS_PER_MSG ((VCHIQ_MAX_MSG_SIZE - sizeof(unsigned short)) / sizeof(unsigned short))
+
+enum
+{
+   VC_CMA_MSG_QUIT,
+   VC_CMA_MSG_OPEN,
+   VC_CMA_MSG_TICK,
+   VC_CMA_MSG_ALLOC,     /* chunk count */
+   VC_CMA_MSG_FREE,      /* chunk, chunk, ... */
+   VC_CMA_MSG_ALLOCATED, /* chunk, chunk, ... */
+   VC_CMA_MSG_REQUEST_ALLOC, /* chunk count */
+   VC_CMA_MSG_REQUEST_FREE,  /* chunk count */
+   VC_CMA_MSG_RESERVE,   /* bytes lo, bytes hi */
+   VC_CMA_MSG_MAX
+};
+
+typedef struct vc_cma_msg_struct
+{
+    unsigned short type;
+    unsigned short params[VC_CMA_MAX_PARAMS_PER_MSG];
+} VC_CMA_MSG_T;
+
+#endif
diff --git a/interface/vmcs_host/vc_dispmanx.h b/interface/vmcs_host/vc_dispmanx.h
new file mode 100755 (executable)
index 0000000..37fdae1
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Display manager service API
+
+#ifndef _VC_DISPMANX_H_
+#define _VC_DISPMANX_H_
+
+#include "interface/vcos/vcos.h"
+#include "interface/vctypes/vc_image_types.h"
+#include "vc_dispservice_x_defs.h"
+#include "interface/vmcs_host/vc_dispmanx_types.h"
+#include "interface/vchi/vchi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+// Same function as above, to aid migration of code.
+VCHPRE_ int VCHPOST_ vc_dispman_init( void );
+// Stop the service from being used
+VCHPRE_ void VCHPOST_ vc_dispmanx_stop( void );
+// Set the entries in the rect structure
+VCHPRE_ int VCHPOST_ vc_dispmanx_rect_set( VC_RECT_T *rect, uint32_t x_offset, uint32_t y_offset, uint32_t width, uint32_t height );
+// Resources
+// Create a new resource
+VCHPRE_ DISPMANX_RESOURCE_HANDLE_T VCHPOST_ vc_dispmanx_resource_create( VC_IMAGE_TYPE_T type, uint32_t width, uint32_t height, uint32_t *native_image_handle );
+// Write the bitmap data to VideoCore memory
+VCHPRE_ int VCHPOST_ vc_dispmanx_resource_write_data( DISPMANX_RESOURCE_HANDLE_T res, VC_IMAGE_TYPE_T src_type, int src_pitch, void * src_address, const VC_RECT_T * rect );
+VCHPRE_ int VCHPOST_ vc_dispmanx_resource_write_data_handle( DISPMANX_RESOURCE_HANDLE_T res, VC_IMAGE_TYPE_T src_type, int src_pitch, VCHI_MEM_HANDLE_T handle, uint32_t offset, const VC_RECT_T * rect );
+VCHPRE_ int VCHPOST_ vc_dispmanx_resource_read_data(
+                              DISPMANX_RESOURCE_HANDLE_T handle,
+                              const VC_RECT_T* p_rect,
+                              void *   dst_address,
+                              uint32_t dst_pitch );
+// Delete a resource
+VCHPRE_ int VCHPOST_ vc_dispmanx_resource_delete( DISPMANX_RESOURCE_HANDLE_T res );
+
+// Displays
+// Opens a display on the given device
+VCHPRE_ DISPMANX_DISPLAY_HANDLE_T VCHPOST_ vc_dispmanx_display_open( uint32_t device );
+// Opens a display on the given device in the request mode
+VCHPRE_ DISPMANX_DISPLAY_HANDLE_T VCHPOST_ vc_dispmanx_display_open_mode( uint32_t device, uint32_t mode );
+// Open an offscreen display
+VCHPRE_ DISPMANX_DISPLAY_HANDLE_T VCHPOST_ vc_dispmanx_display_open_offscreen( DISPMANX_RESOURCE_HANDLE_T dest, DISPMANX_TRANSFORM_T orientation );
+// Change the mode of a display
+VCHPRE_ int VCHPOST_ vc_dispmanx_display_reconfigure( DISPMANX_DISPLAY_HANDLE_T display, uint32_t mode );
+// Sets the desstination of the display to be the given resource
+VCHPRE_ int VCHPOST_ vc_dispmanx_display_set_destination( DISPMANX_DISPLAY_HANDLE_T display, DISPMANX_RESOURCE_HANDLE_T dest );
+// Set the background colour of the display
+VCHPRE_ int VCHPOST_ vc_dispmanx_display_set_background( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_DISPLAY_HANDLE_T display,
+                                                                       uint8_t red, uint8_t green, uint8_t blue );
+// get the width, height, frame rate and aspect ratio of the display
+VCHPRE_ int VCHPOST_ vc_dispmanx_display_get_info( DISPMANX_DISPLAY_HANDLE_T display, DISPMANX_MODEINFO_T * pinfo );
+// Closes a display
+VCHPRE_ int VCHPOST_ vc_dispmanx_display_close( DISPMANX_DISPLAY_HANDLE_T display );
+
+// Updates
+// Start a new update, DISPMANX_NO_HANDLE on error
+VCHPRE_ DISPMANX_UPDATE_HANDLE_T VCHPOST_ vc_dispmanx_update_start( int32_t priority );
+// Add an elment to a display as part of an update
+VCHPRE_ DISPMANX_ELEMENT_HANDLE_T VCHPOST_ vc_dispmanx_element_add ( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_DISPLAY_HANDLE_T display,
+                                                                     int32_t layer, const VC_RECT_T *dest_rect, DISPMANX_RESOURCE_HANDLE_T src,
+                                                                     const VC_RECT_T *src_rect, DISPMANX_PROTECTION_T protection, 
+                                                                     VC_DISPMANX_ALPHA_T *alpha,
+                                                                     DISPMANX_CLAMP_T *clamp, DISPMANX_TRANSFORM_T transform );
+// Change the source image of a display element
+VCHPRE_ int VCHPOST_ vc_dispmanx_element_change_source( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_ELEMENT_HANDLE_T element,
+                                                        DISPMANX_RESOURCE_HANDLE_T src );
+// Change the layer number of a display element
+VCHPRE_ int VCHPOST_ vc_dispmanx_element_change_layer ( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_ELEMENT_HANDLE_T element,
+                                                        int32_t layer );
+// Signal that a region of the bitmap has been modified
+VCHPRE_ int VCHPOST_ vc_dispmanx_element_modified( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_ELEMENT_HANDLE_T element, const VC_RECT_T * rect );
+// Remove a display element from its display
+VCHPRE_ int VCHPOST_ vc_dispmanx_element_remove( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_ELEMENT_HANDLE_T element );
+// Ends an update
+VCHPRE_ int VCHPOST_ vc_dispmanx_update_submit( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_CALLBACK_FUNC_T cb_func, void *cb_arg );
+// End an update and wait for it to complete
+VCHPRE_ int VCHPOST_ vc_dispmanx_update_submit_sync( DISPMANX_UPDATE_HANDLE_T update );
+// Query the image formats supported in the VMCS build
+VCHPRE_ int VCHPOST_ vc_dispmanx_query_image_formats( uint32_t *supported_formats );
+
+//New function added to VCHI to change attributes, set_opacity does not work there.
+VCHPRE_ int VCHPOST_ vc_dispmanx_element_change_attributes( DISPMANX_UPDATE_HANDLE_T update, 
+                                                            DISPMANX_ELEMENT_HANDLE_T element,
+                                                            uint32_t change_flags,
+                                                            int32_t layer,
+                                                            uint8_t opacity,
+                                                            const VC_RECT_T *dest_rect,
+                                                            const VC_RECT_T *src_rect,
+                                                            DISPMANX_RESOURCE_HANDLE_T mask,
+                                                            DISPMANX_TRANSFORM_T transform );
+
+//xxx hack to get the image pointer from a resource handle, will be obsolete real soon
+VCHPRE_ uint32_t VCHPOST_ vc_dispmanx_resource_get_image_handle( DISPMANX_RESOURCE_HANDLE_T res);
+
+//Call this instead of vc_dispman_init
+VCHPRE_ void VCHPOST_ vc_vchi_dispmanx_init (VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections );
+
+// Take a snapshot of a display in its current state.
+// This call may block for a time; when it completes, the snapshot is ready.
+// only transform=0 is supported
+VCHPRE_ int VCHPOST_ vc_dispmanx_snapshot( DISPMANX_DISPLAY_HANDLE_T display, 
+                                           DISPMANX_RESOURCE_HANDLE_T snapshot_resource, 
+                                           DISPMANX_TRANSFORM_T transform );
+
+// Set the resource palette (for VC_IMAGE_4BPP and VC_IMAGE_8BPP)
+VCHPRE_ int VCHPOST_ vc_dispmanx_resource_set_palette( DISPMANX_RESOURCE_HANDLE_T handle, 
+                                                      void * src_address, int offset, int size);
+
+// Start triggering callbacks synced to vsync
+VCHPRE_ int VCHPOST_ vc_dispmanx_vsync_callback( DISPMANX_DISPLAY_HANDLE_T display, DISPMANX_CALLBACK_FUNC_T cb_func, void *cb_arg );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _VC_DISPMANX_H_
diff --git a/interface/vmcs_host/vc_dispmanx_types.h b/interface/vmcs_host/vc_dispmanx_types.h
new file mode 100755 (executable)
index 0000000..9ae9f26
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Typedefs and enums for the VideoCore III Display Manager
+
+#ifndef _DISPMANX_TYPES_H
+#define _DISPMANX_TYPES_H
+
+#include "interface/vctypes/vc_image_types.h"
+#include "interface/vctypes/vc_display_types.h"
+
+#define VC_DISPMANX_VERSION   1
+
+/* Opaque handles */
+typedef uint32_t DISPMANX_DISPLAY_HANDLE_T;
+typedef uint32_t DISPMANX_UPDATE_HANDLE_T;
+typedef uint32_t DISPMANX_ELEMENT_HANDLE_T;
+typedef uint32_t DISPMANX_RESOURCE_HANDLE_T;
+
+typedef uint32_t DISPMANX_PROTECTION_T;
+
+#define DISPMANX_NO_HANDLE 0
+
+#define DISPMANX_PROTECTION_MAX   0x0f
+#define DISPMANX_PROTECTION_NONE  0
+#define DISPMANX_PROTECTION_HDCP  11   // Derived from the WM DRM levels, 101-300
+
+
+
+/* Default display IDs.
+   Note: if you overwrite with your own dispmanx_platform_init function, you
+   should use IDs you provided during dispmanx_display_attach.
+*/
+#define DISPMANX_ID_MAIN_LCD  0
+#define DISPMANX_ID_AUX_LCD   1
+#define DISPMANX_ID_HDMI      2
+#define DISPMANX_ID_SDTV      3
+#define DISPMANX_ID_FORCE_LCD 4
+#define DISPMANX_ID_FORCE_TV  5
+#define DISPMANX_ID_FORCE_OTHER 6 /* non-default display */
+
+/* Return codes. Nonzero ones indicate failure. */
+typedef enum {
+  DISPMANX_SUCCESS      = 0,
+  DISPMANX_INVALID      = -1
+  /* XXX others TBA */
+} DISPMANX_STATUS_T;
+
+typedef enum {
+  /* Bottom 2 bits sets the orientation */
+  DISPMANX_NO_ROTATE = 0,
+  DISPMANX_ROTATE_90 = 1,
+  DISPMANX_ROTATE_180 = 2,
+  DISPMANX_ROTATE_270 = 3,
+
+  DISPMANX_FLIP_HRIZ = 1 << 16,
+  DISPMANX_FLIP_VERT = 1 << 17,
+
+  /* invert left/right images */
+  DISPMANX_STEREOSCOPIC_INVERT =  1 << 19,
+  /* extra flags for controlling 3d duplication behaviour */
+  DISPMANX_STEREOSCOPIC_NONE   =  0 << 20,
+  DISPMANX_STEREOSCOPIC_MONO   =  1 << 20,
+  DISPMANX_STEREOSCOPIC_SBS    =  2 << 20,
+  DISPMANX_STEREOSCOPIC_TB     =  3 << 20,
+  DISPMANX_STEREOSCOPIC_MASK   = 15 << 20,
+
+  /* extra flags for controlling snapshot behaviour */
+  DISPMANX_SNAPSHOT_NO_YUV = 1 << 24,
+  DISPMANX_SNAPSHOT_NO_RGB = 1 << 25,
+  DISPMANX_SNAPSHOT_FILL = 1 << 26,
+  DISPMANX_SNAPSHOT_SWAP_RED_BLUE = 1 << 27,
+  DISPMANX_SNAPSHOT_PACK = 1 << 28
+} DISPMANX_TRANSFORM_T;
+
+typedef enum {
+  /* Bottom 2 bits sets the alpha mode */
+  DISPMANX_FLAGS_ALPHA_FROM_SOURCE = 0,
+  DISPMANX_FLAGS_ALPHA_FIXED_ALL_PIXELS = 1,
+  DISPMANX_FLAGS_ALPHA_FIXED_NON_ZERO = 2,
+  DISPMANX_FLAGS_ALPHA_FIXED_EXCEED_0X07 = 3,
+
+  DISPMANX_FLAGS_ALPHA_PREMULT = 1 << 16,
+  DISPMANX_FLAGS_ALPHA_MIX = 1 << 17
+} DISPMANX_FLAGS_ALPHA_T;
+
+typedef struct {
+  DISPMANX_FLAGS_ALPHA_T flags;
+  uint32_t opacity;
+  VC_IMAGE_T *mask;
+} DISPMANX_ALPHA_T;
+
+typedef struct {
+  DISPMANX_FLAGS_ALPHA_T flags;
+  uint32_t opacity;
+  DISPMANX_RESOURCE_HANDLE_T mask;
+} VC_DISPMANX_ALPHA_T;  /* for use with vmcs_host */
+
+typedef enum {
+  DISPMANX_FLAGS_CLAMP_NONE = 0,
+  DISPMANX_FLAGS_CLAMP_LUMA_TRANSPARENT = 1,
+#if __VCCOREVER__ >= 0x04000000
+  DISPMANX_FLAGS_CLAMP_TRANSPARENT = 2,
+  DISPMANX_FLAGS_CLAMP_REPLACE = 3
+#else
+  DISPMANX_FLAGS_CLAMP_CHROMA_TRANSPARENT = 2,
+  DISPMANX_FLAGS_CLAMP_TRANSPARENT = 3
+#endif
+} DISPMANX_FLAGS_CLAMP_T;
+
+typedef enum {
+  DISPMANX_FLAGS_KEYMASK_OVERRIDE = 1,
+  DISPMANX_FLAGS_KEYMASK_SMOOTH = 1 << 1,
+  DISPMANX_FLAGS_KEYMASK_CR_INV = 1 << 2,
+  DISPMANX_FLAGS_KEYMASK_CB_INV = 1 << 3,
+  DISPMANX_FLAGS_KEYMASK_YY_INV = 1 << 4
+} DISPMANX_FLAGS_KEYMASK_T;
+
+typedef union {
+  struct {
+    uint8_t yy_upper;
+    uint8_t yy_lower;
+    uint8_t cr_upper;
+    uint8_t cr_lower;
+    uint8_t cb_upper;
+    uint8_t cb_lower;
+  } yuv;
+  struct {
+    uint8_t red_upper;
+    uint8_t red_lower;
+    uint8_t blue_upper;
+    uint8_t blue_lower;
+    uint8_t green_upper;
+    uint8_t green_lower;
+  } rgb;
+} DISPMANX_CLAMP_KEYS_T;
+
+typedef struct {
+  DISPMANX_FLAGS_CLAMP_T mode;
+  DISPMANX_FLAGS_KEYMASK_T key_mask;
+  DISPMANX_CLAMP_KEYS_T key_value;
+  uint32_t replace_value;
+} DISPMANX_CLAMP_T;
+
+typedef struct {
+  int32_t width;
+  int32_t height;
+  DISPMANX_TRANSFORM_T transform;
+  DISPLAY_INPUT_FORMAT_T input_format;
+  uint32_t display_num;
+} DISPMANX_MODEINFO_T;
+
+/* Update callback. */
+typedef void (*DISPMANX_CALLBACK_FUNC_T)(DISPMANX_UPDATE_HANDLE_T u, void * arg);
+
+/* Progress callback */
+typedef void (*DISPMANX_PROGRESS_CALLBACK_FUNC_T)(DISPMANX_UPDATE_HANDLE_T u,
+                                                  uint32_t line,
+                                                  void * arg);
+
+/* Pluggable display interface */
+
+typedef struct tag_DISPMANX_DISPLAY_FUNCS_T {
+   // Get essential HVS configuration to be passed to the HVS driver. Options
+   // is any combination of the following flags: HVS_ONESHOT, HVS_FIFOREG,
+   // HVS_FIFO32, HVS_AUTOHSTART, HVS_INTLACE; and if HVS_FIFOREG, one of;
+   // { HVS_FMT_RGB888, HVS_FMT_RGB565, HVS_FMT_RGB666, HVS_FMT_YUV }.
+   int32_t (*get_hvs_config)(void *instance, uint32_t *pchan,
+                             uint32_t *poptions, DISPLAY_INFO_T *info,
+                             uint32_t *bg_colour, uint32_t *test_mode);
+   
+   // Get optional HVS configuration for gamma tables, OLED matrix and dither controls.
+   // Set these function pointers to NULL if the relevant features are not required.
+   int32_t (*get_gamma_params)(void * instance,
+                               int32_t gain[3], int32_t offset[3], int32_t gamma[3]);
+   int32_t (*get_oled_params)(void * instance, uint32_t * poffsets,
+                              uint32_t coeffs[3]);
+   int32_t (*get_dither)(void * instance, uint32_t * dither_depth, uint32_t * dither_type);
+   
+   // Get mode information, which may be returned to the applications as a courtesy.
+   // Transform should be set to 0, and {width,height} should be final dimensions.
+   int32_t (*get_info)(void * instance, DISPMANX_MODEINFO_T * info);
+   
+   // Inform driver that the application refcount has become nonzero / zero
+   // These callbacks might perhaps be used for backlight and power management.
+   int32_t (*open)(void * instance);
+   int32_t (*close)(void * instance);
+   
+   // Display list updated callback. Primarily of use to a "one-shot" display.
+   // For convenience of the driver, we pass the register address of the HVS FIFO.
+   void (*dlist_updated)(void * instance, volatile uint32_t * fifo_reg);
+   
+   // End-of-field callback. This may occur in an interrupt context.
+   void (*eof_callback)(void * instance);
+
+   // Return screen resolution format
+   DISPLAY_INPUT_FORMAT_T (*get_input_format)(void * instance);
+
+   int32_t (*suspend_resume)(void *instance, int up);
+
+   DISPLAY_3D_FORMAT_T (*get_3d_format)(void * instance);
+} DISPMANX_DISPLAY_FUNCS_T;
+
+#endif /* ifndef _DISPMANX_TYPES_H */
diff --git a/interface/vmcs_host/vc_dispservice_defs.h b/interface/vmcs_host/vc_dispservice_defs.h
new file mode 100755 (executable)
index 0000000..1240f0e
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VC_DISPSERVICE_DEFS_H
+#define VC_DISPSERVICE_DEFS_H
+
+#define  HOST_PITCH_ALIGNMENT    4
+
+//Round up to the nearest multiple of 16
+#define  PAD16(x) (((x) + (VC_INTERFACE_BLOCK_SIZE-1)) & ~(VC_INTERFACE_BLOCK_SIZE-1))
+
+//The max length for an effect name
+#define DISPMAN_MAX_EFFECT_NAME  (28)
+
+typedef enum {
+   // Values initially chosen to match VC_IMAGE_TYPE_T to aid debugging
+   // This is now a mandatory constraint
+   VC_FORMAT_RGB565    = 1,
+   VC_FORMAT_YUV420    = 3,
+   VC_FORMAT_RGB888    = 5,
+   VC_FORMAT_RGBA32    = 15,
+   VC_FORMAT_RGBA565   = 17,
+   VC_FORMAT_RGBA16    = 18,
+   VC_FORMAT_TF_RGBA32 = 20,
+   VC_FORMAT_TF_RGBA16 = 23,
+   VC_FORMAT_TF_RGB565 = 25,
+   VC_FORMAT_BGR888    = 31,
+   VC_FORMAT_BGR888_NP = 32,
+   
+   VC_FORMAT_ARGB8888  = 43,
+   VC_FORMAT_XRGB8888  = 44,
+
+   /* To force 32-bit storage, enabling use in structures over-the-wire */
+   VC_FORMAT_RANGE_MAX = 0x7FFFFFFF
+} VC_IMAGE_FORMAT_T;
+
+// Transforms.
+/* Image transformations. These must match the DISPMAN and Media Player versions */
+#define TRANSFORM_HFLIP     (1<<0)
+#define TRANSFORM_VFLIP     (1<<1)
+#define TRANSFORM_TRANSPOSE (1<<2)
+
+typedef enum {
+   VC_DISPMAN_ROT0           = 0,
+   VC_DISPMAN_MIRROR_ROT0    = TRANSFORM_HFLIP,
+   VC_DISPMAN_MIRROR_ROT180  = TRANSFORM_VFLIP,
+   VC_DISPMAN_ROT180         = TRANSFORM_HFLIP|TRANSFORM_VFLIP,
+   VC_DISPMAN_MIRROR_ROT90   = TRANSFORM_TRANSPOSE,
+   VC_DISPMAN_ROT270         = TRANSFORM_TRANSPOSE|TRANSFORM_HFLIP,
+   VC_DISPMAN_ROT90          = TRANSFORM_TRANSPOSE|TRANSFORM_VFLIP,
+   VC_DISPMAN_MIRROR_ROT270  = TRANSFORM_TRANSPOSE|TRANSFORM_HFLIP|TRANSFORM_VFLIP,
+} VC_DISPMAN_TRANSFORM_T;
+
+typedef enum {
+   VC_RESOURCE_TYPE_HOST,
+   VC_RESOURCE_TYPE_VIDEOCORE,
+   VC_RESOURCE_TYPE_VIDEOCORE_UNCACHED,
+} VC_RESOURCE_TYPE_T;
+
+typedef struct {
+   uint8_t  type;            // VC_IMAGE_FORMAT_T
+   uint32_t width;           // width in pixels
+   uint32_t height;          // height in pixels
+   uint32_t pitch;           // pitch of image_data array in *bytes*
+   uint32_t size;            // number of *bytes* available in the image_data arry
+   uint32_t pointer;         // pointer for image_data - this allows the object to be cast to a VC_IMAGE_T on the VIDEOCORE side
+} VC_IMAGE_PARAM_T;
+
+typedef enum {
+   VC_DISPMAN_DISPLAY_SET_DESTINATION = 0,
+   VC_DISPMAN_DISPLAY_UPDATE_START,
+   VC_DISPMAN_DISPLAY_UPDATE_END,
+   VC_DISPMAN_DISPLAY_OBJECT_ADD,
+   VC_DISPMAN_DISPLAY_OBJECT_REMOVE,
+   VC_DISPMAN_DISPLAY_OBJECT_MODIFY,
+   VC_DISPMAN_DISPLAY_LOCK,
+   VC_DISPMAN_DISPLAY_UNLOCK,
+   VC_DISPMAN_DISPLAY_RESOURCE_CREATE,
+   VC_DISPMAN_DISPLAY_RESOURCE_DELETE,
+   VC_DISPMAN_DISPLAY_GET_COMPOSITE,
+   VC_DISPMAN_DISPLAY_APPLY_EFFECT_INSTANCE,
+   VC_DISPMAN_DISPLAY_RECONFIGURE,
+   VC_DISPMAN_DISPLAY_CREATE_EFFECTS_INSTANCE,
+   VC_DISPMAN_DISPLAY_DELETE_EFFECTS_INSTANCE,
+   VC_DISPMAN_DISPLAY_SET_EFFECT,
+   VC_DISPMAN_DISPLAY_RESOURCE_SET_ALPHA,
+   VC_DISPMAN_DISPLAY_SNAPSHOT,
+   VC_DISPMAN_DISPLAY_QUERY_IMAGE_FORMATS,
+   VC_DISPMAN_DISPLAY_GET_DISPLAY_DETAILS,
+   // new features - add to end of list
+   VC_DISPMAN_DISPLAY_RESOURCE_CREATE_FROM_IMAGE,
+   VC_CMD_END_OF_LIST
+} VC_CMD_CODE_T;
+
+/* The table of functions executed for each command. */
+
+typedef void (*INTERFACE_EXECUTE_FN_T)(int, int);
+
+extern INTERFACE_EXECUTE_FN_T interface_execute_fn[];
+
+//Parameter sets for dispservice commands
+typedef struct {
+   uint32_t state;
+   uint32_t dummy[3];   //Pad to multiple of 16 bytes
+} DISPMAN_LOCK_PARAM_T;
+
+typedef struct {
+   uint32_t display;
+   uint32_t dummy[3];   //Pad to multiple of 16 bytes
+} DISPMAN_GET_DISPLAY_DETAILS_PARAM_T;
+
+typedef struct {
+   uint32_t display;
+   uint32_t resource;
+   uint32_t dummy[2];   //Pad to multiple of 16 bytes
+} DISPMAN_SET_DEST_PARAM_T;
+
+typedef struct {
+   uint32_t display;
+   uint32_t dummy[3];   //Pad to multiple of 16 bytes
+} DISPMAN_GET_COMPOSITE_PARAM_T;
+
+typedef struct
+{
+   uint32_t display;
+   uint32_t effects_instance;
+
+   uint32_t dummy[2];   //Pad to multiple of 16 bytes
+} DISPMAN_APPLY_EFFECTS_INSTANCE_PARAM_T;
+
+typedef struct
+{
+   uint32_t read_response;
+   uint32_t effects_instance;
+} DISPMAN_CREATE_EFFECTS_INSTANCE_RESPONSE_T;
+
+typedef struct
+{
+   uint32_t effects_instance;
+   uint32_t dummy[3];   //Pad to multiple of 16 bytes
+} DISPMAN_DELETE_EFFECTS_INSTANCE_PARAM_T;
+
+typedef struct
+{
+   uint32_t effects_instance;
+   char effect_name[ DISPMAN_MAX_EFFECT_NAME ];
+   //no need to pad as long as DISPMAN_MAX_EFFECT_NAME +sizeof(uint32) = 32
+} DISPMAN_SET_EFFECT_PARAM_T;
+
+typedef struct {
+   uint32_t display;
+   uint16_t width;
+   uint16_t height;
+   uint32_t dummy[2];   //Pad to multiple of 16 bytes
+} DISPMAN_RECONFIGURE_PARAM_T;
+
+typedef struct {
+   uint32_t display;
+   uint32_t transparent_colour;
+   uint32_t dummy[2];   //Pad to multiple of 16 bytes
+} DISPMAN_SET_TRANSPARENT_COLOUR_PARAM_T;
+
+typedef struct {
+   //uint32_t object;
+   uint32_t display;
+   int32_t layer;
+   uint32_t transform;
+   uint32_t resource;
+   uint16_t dest_x;
+   uint16_t dest_y;
+   uint16_t dest_width;
+   uint16_t dest_height;
+   uint16_t src_x;
+   uint16_t src_y;
+   uint16_t src_width;
+   uint16_t src_height;
+} DISPMAN_OBJECT_ADD_PARAM_T;
+
+typedef struct {
+   uint32_t object;
+   uint32_t dummy[3];   //Pad to multiple of 16 bytes
+} DISPMAN_OBJECT_REMOVE_PARAM_T;
+
+typedef struct {
+   uint32_t object;
+   uint16_t src_x;
+   uint16_t src_y;
+   uint16_t width;
+   uint16_t height;
+   uint32_t dummy[1];   // Pad to multiple of 16 bytes
+} DISPMAN_OBJECT_MODIFY_PARAM_T;
+
+typedef struct
+{
+   uint32_t *resource;
+   VC_IMAGE_PARAM_T image;
+   uint8_t  type;   // VC_RESOURCE_TYPE_T
+   //Removed padding.  VC_IMAGE_T may change in size, so handle the size in the code that sends and receives the commands
+   //uint32_t dummy[3];   //Pad to multiple of 16 bytes
+} DISPMAN_RESOURCE_CREATE_PARAM_T;
+
+typedef struct
+{
+   uint32_t native_image_ptr;
+   uint32_t type;   // VC_RESOURCE_TYPE_T
+   uint32_t dummy[2];  // Pad to multiple of 16 bytes
+} DISPMAN_RESOURCE_CREATE_FROM_IMAGE_PARAM_T;
+
+typedef struct {
+   uint32_t resource;
+   uint32_t dummy[3];   //Pad to multiple of 16 bytes
+} DISPMAN_RESOURCE_DELETE_PARAM_T;
+
+typedef struct {
+   uint32_t resource;
+   uint32_t alpha;
+   uint32_t dummy[2];   //Pad to multiple of 16 bytes
+} DISPMAN_RESOURCE_SET_ALPHA_PARAM_T;
+
+typedef struct {
+   uint32_t display;
+   uint32_t resource;
+   uint32_t dummy[2];   //Pad to multiple of 16 bytes
+} DISPMAN_DISPLAY_SNAPSHOT_PARAM_T;
+
+#endif   //VC_DISPSERVICE_DEFS_H
diff --git a/interface/vmcs_host/vc_dispservice_x_defs.h b/interface/vmcs_host/vc_dispservice_x_defs.h
new file mode 100755 (executable)
index 0000000..9291eef
--- /dev/null
@@ -0,0 +1,276 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// Display service command enumeration.
+
+#ifndef VC_DISPSERVICEX_DEFS_H
+#define VC_DISPSERVICEX_DEFS_H
+
+#include "interface/vctypes/vc_image_types.h"
+
+#define  HOST_PITCH_ALIGNMENT    4
+
+//Round up to the nearest multiple of 16
+#define  PAD16(x) (((x) + (VC_INTERFACE_BLOCK_SIZE-1)) & ~(VC_INTERFACE_BLOCK_SIZE-1))
+
+//The max length for an effect name
+#define DISPMANX_MAX_EFFECT_NAME  (28)
+
+// Should really use the VC_IMAGE_TYPE_T, but this one has been extended
+// to force it up to 32-bits...
+typedef enum {
+   // Values initially chosen to match VC_IMAGE_TYPE_T to aid debugging
+   // This is now a mandatory constraint
+   VC_FORMAT_RGB565    = VC_IMAGE_RGB565,
+   VC_FORMAT_YUV420    = VC_IMAGE_YUV420,
+   VC_FORMAT_RGB888    = VC_IMAGE_RGB888,
+   VC_FORMAT_RGBA32    = VC_IMAGE_RGBA32,
+   VC_FORMAT_RGBA565   = VC_IMAGE_RGBA565,
+   VC_FORMAT_RGBA16    = VC_IMAGE_RGBA16,
+   VC_FORMAT_TF_RGBA32 = VC_IMAGE_TF_RGBA32,
+   VC_FORMAT_TF_RGBA16 = VC_IMAGE_TF_RGBA16,
+   VC_FORMAT_TF_RGB565 = VC_IMAGE_TF_RGB565,
+   VC_FORMAT_BGR888    = VC_IMAGE_BGR888,
+   VC_FORMAT_BGR888_NP = VC_IMAGE_BGR888_NP,
+
+   VC_FORMAT_ARGB8888  = VC_IMAGE_ARGB8888,
+   VC_FORMAT_XRGB8888  = VC_IMAGE_XRGB8888,
+
+   /* To force 32-bit storage, enabling use in structures over-the-wire */
+   VC_FORMAT_RANGE_MAX = 0x7FFFFFFF
+} VC_IMAGE_FORMAT_T;
+
+// Transforms.
+/* Image transformations. These must match the DISPMAN and Media Player versions */
+#define TRANSFORM_HFLIP     (1<<0)
+#define TRANSFORM_VFLIP     (1<<1)
+#define TRANSFORM_TRANSPOSE (1<<2)
+
+#define VC_DISPMAN_ROT0 VC_IMAGE_ROT0
+#define VC_DISPMAN_ROT90 VC_IMAGE_ROT90
+#define VC_DISPMAN_ROT180 VC_IMAGE_ROT180
+#define VC_DISPMAN_ROT270 VC_IMAGE_ROT270
+#define VC_DISPMAN_MIRROR_ROT0 VC_IMAGE_MIRROR_ROT0
+#define VC_DISPMAN_MIRROR_ROT90 VC_IMAGE_MIRROR_ROT90
+#define VC_DISPMAN_MIRROR_ROT180 VC_IMAGE_MIRROR_ROT180
+#define VC_DISPMAN_MIRROR_ROT270 VC_IMAGE_MIRROR_ROT270
+#define VC_DISPMAN_TRANSFORM_T VC_IMAGE_TRANSFORM_T
+
+typedef enum {
+   VC_RESOURCE_TYPE_HOST,
+   VC_RESOURCE_TYPE_VIDEOCORE,
+   VC_RESOURCE_TYPE_VIDEOCORE_UNCACHED,
+} VC_RESOURCE_TYPE_T;
+
+typedef struct {
+   uint8_t  type;            // VC_IMAGE_FORMAT_T
+   uint32_t width;           // width in pixels
+   uint32_t height;          // height in pixels
+   uint32_t pitch;           // pitch of image_data array in *bytes*
+   uint32_t size;            // number of *bytes* available in the image_data arry
+   uint32_t pointer;         // pointer for image_data - this allows the object to be cast to a VC_IMAGE_T on the VIDEOCORE side
+} VC_IMAGE_PARAM_T;
+
+typedef enum {
+   VC_DISPMANX_GET_DEVICES = 0,
+   VC_DISPMANX_GET_DEVICE_NAME,
+   VC_DISPMANX_GET_MODES,
+   VC_DISPMANX_GET_MODE_INFO,
+   VC_DISPMANX_DISPLAY_QUERY_IMAGE_FORMATS,
+   // Resources
+   VC_DISPMANX_RESOURCE_CREATE,
+   VC_DISPMANX_RESOURCE_WRITE_DATA,
+   VC_DISPMANX_RESOURCE_DELETE,
+   // Displays
+   VC_DISPMANX_DISPLAY_OPEN,
+   VC_DISPMANX_DISPLAY_OPEN_MODE,
+   VC_DISPMANX_DISPLAY_OPEN_OFFSCREEN,
+   VC_DISPMANX_DISPLAY_RECONFIGURE,
+   VC_DISPMANX_DISPLAY_SET_DESTINATION,
+   VC_DISPMANX_DISPLAY_SET_BACKGROUND,
+   VC_DISPMANX_DISPLAY_GET_INFO,
+   VC_DISPMANX_DISPLAY_CLOSE,
+   // Updates
+   VC_DISPMANX_UPDATE_START,
+   VC_DISPMANX_ELEMENT_ADD,
+   VC_DISPMANX_ELEMENT_CHANGE_SOURCE,
+   VC_DISPMANX_ELEMENT_MODIFIED,
+   VC_DISPMANX_ELEMENT_REMOVE,
+   VC_DISPMANX_UPDATE_SUBMIT,
+   VC_DISPMANX_UPDATE_SUBMIT_SYNC,
+   // Miscellaneous
+   VC_DISPMANX_SNAPSHOT,
+   // new features - add to end of list
+   VC_CMD_END_OF_LIST
+} VC_CMD_CODE_T;
+
+/* The table of functions executed for each command. */
+
+typedef void (*INTERFACE_EXECUTE_FN_T)(int, int);
+
+extern INTERFACE_EXECUTE_FN_T interface_execute_fn[];
+
+#define DISPMANX_MAX_HOST_DEVICES 8
+#define DISPMANX_MAX_DEVICE_NAME_LEN 16
+
+//Parameter sets for dispservice commands
+
+typedef struct {
+   int32_t response;
+   uint32_t ndevices;
+   uint32_t dummy[2];
+   uint8_t names[DISPMANX_MAX_HOST_DEVICES][DISPMANX_MAX_DEVICE_NAME_LEN];
+} DISPMANX_GET_DEVICES_RESP_T;
+typedef struct {
+   uint32_t device;
+   uint32_t dummy[3];   //Pad to multiple of 16 bytes
+} DISPMANX_GET_MODES_PARAM_T;
+typedef struct {
+   uint32_t display;
+   uint32_t mode;
+   uint32_t dummy[2];   //Pad to multiple of 16 bytes
+} DISPMANX_GET_MODE_INFO_PARAM_T;
+typedef struct {
+   uint32_t type;
+   uint32_t width;
+   uint32_t height;
+   uint32_t dummy[1];   // Pad to multiple of 16 bytes
+} DISPMANX_RESOURCE_CREATE_PARAM_T;
+typedef struct {
+   // This will be needed when we change to vchi.
+   int junk; // empty structure not allowed
+} DISPMANX_RESOURCE_WRITE_DATA_PARAM_T;
+typedef struct {
+   uint32_t handle;
+   uint32_t dummy[3];   //Pad to multiple of 16 bytes
+} DISPMANX_RESOURCE_DELETE_PARAM_T;
+typedef struct {
+   uint32_t device;
+   uint32_t dummy[3];
+} DISPMANX_DISPLAY_OPEN_PARAM_T;
+typedef struct {
+   uint32_t device;
+   uint32_t mode;
+   uint32_t dummy[2];
+} DISPMANX_DISPLAY_OPEN_MODE_PARAM_T;
+typedef struct {
+   uint32_t dest;
+   uint32_t orientation;
+   uint32_t dummy[2];
+} DISPMANX_DISPLAY_OPEN_OFFSCREEN_PARAM_T;
+typedef struct {
+   uint32_t display;
+   uint32_t dest;
+   uint32_t dummy[2];
+} DISPMANX_DISPLAY_SET_DESTINATION_PARAM_T;
+typedef struct {
+   uint32_t display;
+   uint32_t update;
+   uint32_t colour;
+   uint32_t dummy;
+} DISPMANX_DISPLAY_SET_BACKGROUND_PARAM_T;
+typedef struct {
+   uint32_t display;
+   uint32_t dummy[3];
+} DISPMANX_DISPLAY_GET_INFO_PARAM_T;
+typedef struct {
+   uint32_t read_response;
+   int32_t      width;
+   int32_t      height;
+   int32_t      aspect_pixwidth;
+   int32_t      aspect_pixheight;
+   int32_t      fieldrate_num;
+   int32_t      fieldrate_denom;
+   int32_t      fields_per_frame;
+   uint32_t transform;
+   uint32_t dummy[3];
+} DISPMANX_DISPLAY_GET_INFO_RESP_T;
+typedef struct {
+   int32_t priority;
+   uint32_t dummy[3];
+} DISPMANX_UPDATE_START_PARAM_T;
+typedef struct {
+   uint32_t update;
+   uint32_t display;
+   int32_t layer;
+   uint32_t transform;
+   uint32_t src_resource;
+   uint16_t dest_x;
+   uint16_t dest_y;
+   uint16_t dest_width;
+   uint16_t dest_height;
+   uint16_t src_x;
+   uint16_t src_y;
+   uint16_t src_width;
+   uint16_t src_height;
+   uint32_t flags;
+   uint32_t opacity;
+   uint32_t mask_resource;
+   // already 16 byte aligned
+} DISPMANX_ELEMENT_ADD_PARAM_T;
+typedef struct {
+   uint32_t update;
+   uint32_t element;
+   uint32_t src_resource;
+   uint32_t dummy; // pad to 16 bytes
+} DISPMANX_ELEMENT_CHANGE_SOURCE_PARAM_T;
+typedef struct {
+   uint32_t update;
+   uint32_t element;
+   uint16_t x;
+   uint16_t y;
+   uint16_t width;
+   uint16_t height;
+} DISPMANX_ELEMENT_MODIFIED_PARAM_T;
+typedef struct {
+   uint32_t update;
+   uint32_t element;
+   uint32_t dummy[2];
+} DISPMANX_ELEMENT_REMOVE_PARAM_T;
+typedef struct {
+   uint32_t update;
+   uint32_t dummy[3];
+} DISPMANX_UPDATE_SUBMIT_PARAM_T;
+typedef struct {
+   uint32_t update;
+   uint32_t dummy[3];
+} DISPMANX_UPDATE_SUBMIT_SYNC_PARAM_T;
+typedef struct {
+   uint32_t display;
+   uint32_t snapshot_resource;
+   uint32_t transform;
+   uint32_t dummy[1];
+} DISPMANX_DISPLAY_SNAPSHOT_PARAM_T;
+
+// for dispmanx
+
+#define TRANSFORM_HFLIP     (1<<0)
+#define TRANSFORM_VFLIP     (1<<1)
+#define TRANSFORM_TRANSPOSE (1<<2)
+
+
+#endif   //VC_DISPSERVICEX_DEFS_H
diff --git a/interface/vmcs_host/vc_fileservice_defs.h b/interface/vmcs_host/vc_fileservice_defs.h
new file mode 100755 (executable)
index 0000000..cfcb738
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// File service command enumeration.
+
+#ifndef VC_FILESERVICE_DEFS_H
+#define VC_FILESERVICE_DEFS_H
+
+#define VC_FILESERV_VER   1
+/* Definitions (not used by API) */
+#define FS_MAX_DATA 8192 //4096
+
+/* Protocol (not used by API) version 1.2 */
+
+enum {
+   /* Over-the-wire file open flags */
+   VC_O_RDONLY     = 0x01,
+   VC_O_WRONLY     = 0x02,
+   VC_O_RDWR            = 0x04,
+   VC_O_APPEND     = 0x08,
+   VC_O_CREAT           = 0x10,
+   VC_O_TRUNC           = 0x20,
+   VC_O_EXCL            = 0x40,
+
+   /* Request Commands (VC->Host->VC) */
+
+   /* These commands don't require a pathname */
+   VC_FILESYS_RESET      = 64,
+   VC_FILESYS_CLOSE      = 65,
+   VC_FILESYS_CLOSEDIR   = 66,
+   VC_FILESYS_LSEEK      = 67,
+   VC_FILESYS_READ       = 68,
+   VC_FILESYS_READDIR    = 69,
+   VC_FILESYS_SETEND     = 70,
+   VC_FILESYS_WRITE      = 71,
+
+   /* These commands require a pathname */
+   VC_FILESYS_FORMAT     = 72,
+   VC_FILESYS_FREESPACE  = 73,
+   VC_FILESYS_GET_ATTR   = 74,
+   VC_FILESYS_MKDIR      = 75,
+   VC_FILESYS_OPEN       = 76,
+   VC_FILESYS_OPENDIR    = 77,
+   VC_FILESYS_REMOVE     = 78,
+   VC_FILESYS_RENAME     = 79,
+   VC_FILESYS_SET_ATTR   = 80,
+   VC_FILESYS_SCANDISK   = 81,
+   VC_FILESYS_TOTALSPACE = 82,
+   VC_FILESYS_DISKWRITABLE=83,
+   VC_FILESYS_OPEN_DISK_RAW  = 84,
+   VC_FILESYS_CLOSE_DISK_RAW = 85,
+   VC_FILESYS_NUMSECTORS     = 86,
+   VC_FILESYS_READ_SECTORS   = 87,
+   VC_FILESYS_WRITE_SECTORS  = 88,
+
+   VC_FILESYS_MOUNT      = 89,
+   VC_FILESYS_UMOUNT     = 90,
+   VC_FILESYS_FSTYPE     = 91,
+
+   VC_FILESYS_READ_DIRECT = 92,
+
+   VC_FILESYS_LSEEK64     = 93,
+   VC_FILESYS_FREESPACE64 = 94,
+   VC_FILESYS_TOTALSPACE64= 95,
+   VC_FILESYS_OPEN_DISK   = 96,
+   VC_FILESYS_CLOSE_DISK  = 97,
+   
+   /* extra simple functions for mass storage testing */
+   VC_FILESYS_READ_SECTOR = 98, //1sect
+   VC_FILESYS_STREAM_SECTOR_BEGIN = 99,
+   VC_FILESYS_STREAM_SECTOR_END = 100,
+   VC_FILESYS_WRITE_SECTOR = 101,
+   VC_FILESYS_FSTAT      = 102,
+   VC_FILESYS_DIRSIZE     = 103,
+   VC_FILESYS_LIST_DIRS   = 104,
+   VC_FILESYS_LIST_FILES  = 105,
+   VC_FILESYS_NUM_DIRS    = 106,
+   VC_FILESYS_NUM_FILES   = 107,
+   VC_FILESYS_MAX_FILESIZE = 108,
+   VC_FILESYS_CHKDSK       = 109,
+};
+
+/* Parameters for lseek */
+
+#define  VC_FILESYS_SEEK_SET  0    /* Set file pointer to "offset" */
+#define  VC_FILESYS_SEEK_CUR  1    /* Set file pointer to current plus "offset" */
+#define  VC_FILESYS_SEEK_END  2    /* Set file pointer to EOF plus "offset" */
+
+/* Return values of vc_filesys_type */
+#define VC_FILESYS_FS_UNKNOWN 0
+#define VC_FILESYS_FS_FAT12 1
+#define VC_FILESYS_FS_FAT16 2
+#define VC_FILESYS_FS_FAT32 3
+
+#endif
diff --git a/interface/vmcs_host/vc_gencmd_defs.h b/interface/vmcs_host/vc_gencmd_defs.h
new file mode 100755 (executable)
index 0000000..ef9ea6f
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VC_GENCMD_DEFS_H
+#define VC_GENCMD_DEFS_H
+
+//Format of reply message is error code followed by a string
+#define GENCMDSERVICE_MSGFIFO_SIZE 1024
+
+#define VC_GENCMD_VER   1
+
+#endif
diff --git a/interface/vmcs_host/vc_hdmi.h b/interface/vmcs_host/vc_hdmi.h
new file mode 100755 (executable)
index 0000000..9fd844a
--- /dev/null
@@ -0,0 +1,545 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * HDMI common host header for TV service, defines resolution code which host applications should
+ * use for power up command for HDMI
+ */
+
+#ifndef _VC_HDMI_H_
+#define _VC_HDMI_H_
+
+#include "vc_hdmi_property.h" /**< All HDMI related properties have been moved to here */
+
+typedef int VC_HDMI_BOOL_T;
+
+/**
+ * HDMI resolution groups. There are two main groups: 
+ * CEA - the conventional HDMI ones like 720p
+ * DMT - computer monitor resolutions like XGA
+ */
+typedef enum {
+   HDMI_RES_GROUP_INVALID = 0, /**< Initialised value */
+   HDMI_RES_GROUP_CEA     = 1, /**< CEA - HDMI device */
+   HDMI_RES_GROUP_DMT     = 2, /**< DMT - computer monitors */
+   HDMI_RES_GROUP_CEA_3D  = 3, /* deprecated */
+
+} HDMI_RES_GROUP_T;
+
+#define HDMI_RES_GROUP_NAME(g) \
+   (((g) == HDMI_RES_GROUP_INVALID) ? "Invalid" : \
+   (((g) == HDMI_RES_GROUP_CEA) ? "CEA" : \
+   (((g) == HDMI_RES_GROUP_DMT) ? "DMT" : \
+    "Unknown")))
+
+/**
+ *  CEA 861 defined video code and aspect ratios for various HDMI modes
+ *  Not all values are valid for AVI infoframe
+ */
+typedef enum {
+   HDMI_ASPECT_UNKNOWN  = 0, /**< Unknown aspect ratio, or not one of the values below */
+   HDMI_ASPECT_4_3      = 1, /**< 4:3  */
+   HDMI_ASPECT_14_9     = 2, /**< 14:9 */
+   HDMI_ASPECT_16_9     = 3, /**< 16:9 */
+   HDMI_ASPECT_5_4      = 4, /**< 5:4  */
+   HDMI_ASPECT_16_10    = 5, /**< 16:10*/
+   HDMI_ASPECT_15_9     = 6, /**< 15:9 */
+   HDMI_ASPECT_64_27    = 7, /**< 64:27 */
+   HDMI_ASPECT_21_9     = HDMI_ASPECT_64_27 /**< 21:9 is jargon, 64:27 is the actual aspect ratio */
+   /* More aspect ratio values may be added here if defined by CEA in future */
+} HDMI_ASPECT_T;
+
+/**
+ * Display options set the bounding box (only used in CEA mode)
+ */
+typedef struct {
+   uint16_t aspect; /**<HDMI_ASPECT_T */
+   /** Active area information - meanings as in CEA-861. */
+   uint16_t vertical_bar_present; /**<VC_HDMI_BOOL_T */
+   uint16_t left_bar_width;
+   uint16_t right_bar_width;
+   uint16_t horizontal_bar_present; /**<VC_HDMI_BOOL_T */
+   uint16_t top_bar_height;
+   uint16_t bottom_bar_height;
+   /** S0/S1 flags as defined in CEA-861. */
+   uint8_t         overscan_flags;
+} HDMI_DISPLAY_OPTIONS_T;
+
+/**
+ * HDMI internal state (with some of the properties related to current display signal)
+ * Also see SDTV_DISPLAY_STATE_T in vc_sdtv.h, members up to scan_mode will be in the
+ * same position as the equivalent state in SDTV_DISPLAY_STATE_T;
+ */
+typedef struct {
+   uint32_t state;
+   uint32_t width;
+   uint32_t height;
+   uint16_t frame_rate;
+   uint16_t scan_mode;
+   uint32_t group; /**<HDMI_RES_GROUP_T */
+   uint32_t mode; /* This is the mode number of the format */
+   uint16_t pixel_rep;   /* Pixel repetition factor, only relevant for CEA formats */
+   uint16_t aspect_ratio; /* This is the format's native aspect ratio */
+   HDMI_DISPLAY_OPTIONS_T display_options; /* This has the aspect ratio sent in AVI infoframe */
+   uint16_t pixel_encoding;
+   uint16_t format_3d; /* 3D format, only relevant for CEA formats */
+} HDMI_DISPLAY_STATE_T;
+
+/**
+ * Copy protection for HDMI, only HDCP is available
+ * This enum is to make it consistent with the enums
+ * SDTV_CP_MODE_T in vc_sdtv.h
+ */
+typedef enum {
+   HDMI_CP_NONE         = 0, /**< No copyprotection */
+   HDMI_CP_HDCP         = 1  /**< HDCP 1.x */
+} HDMI_CP_MODE_T;
+
+/**
+ *  HDMI operation modes
+ */
+typedef enum {
+   HDMI_MODE_OFF,  /**< Off! */
+   HDMI_MODE_DVI,  /**< DVI */
+   HDMI_MODE_HDMI, /**< HDMI */
+   HDMI_MODE_3D    /**< HDMI 1.4a 3D */
+} HDMI_MODE_T;
+
+/**
+ * Possible values for the Source Product Description type code (in SPD infoframe).
+ * Taken from the CEA-861 spec.
+ */
+typedef enum {
+   HDMI_SPD_TYPE_UNKNOWN,
+   HDMI_SPD_TYPE_STB,           /**<Digital STB */
+   HDMI_SPD_TYPE_DVD,           /**<DVD player */
+   HDMI_SPD_TYPE_DVHS,          /**<D-VHS */
+   HDMI_SPD_TYPE_HDD_RECORDER,  /**<HDD video recoder */
+   HDMI_SPD_TYPE_DVC,           /**<DVC */
+   HDMI_SPD_TYPE_DSC,           /**<DSC */
+   HDMI_SPD_TYPE_VCD,           /**<Video CD */
+   HDMI_SPD_TYPE_GAME,          /**<Game */
+   HDMI_SPD_TYPE_PC,            /**<PC general */
+   HDMI_SPD_TYPE_BD,            /**<Blu-Ray Disc */
+   HDMI_SPD_TYPE_SACD,          /**<Super Audio CD */
+   HDMI_SPD_TYPE_HDDVD,         /**<HD DVD */
+   HDMI_SPD_TYPE_PMP            /**<Personal media player */
+} HDMI_SPD_TYPE_CODE_T;
+
+/**
+ * Structure for SPD infoframe
+ */
+typedef struct {
+   char  *manufacturer;        /**< Manufacture name (up to 8 characters) */
+   char  *description;         /**< Product name (up to 16 characters) */
+   HDMI_SPD_TYPE_CODE_T type;  /**< Product type */
+} HDMI_SPD_DATA_T;
+
+/**
+ * These are CEA mode numbers (sent in AVI infoframe) for different resolutions as define in CEA-861
+ * 1080i at 100/120Hz (40,46) are supported by HDMI H/W but note we cannot
+ * display the debug overlay under these modes.
+ * Some modes have two codes, the first one has aspect ratio 4:3 and
+ * the second one (with "H" suffix") 16:9.
+ * The modes with "4x", etc. are the same the corresponding "non-multiplied" modes
+ * but clocked at a higher pixel clock.
+ */
+typedef enum {
+   HDMI_CEA_VGA             =  1,
+   HDMI_CEA_480p60          =  2,
+   HDMI_CEA_480p60H         =  3,
+   HDMI_CEA_720p60          =  4,
+   HDMI_CEA_1080i60         =  5,
+   HDMI_CEA_480i60          =  6,
+   HDMI_CEA_480i60H         =  7,
+   HDMI_CEA_240p60          =  8,
+   HDMI_CEA_240p60H         =  9,
+   HDMI_CEA_480i60_4x       = 10,
+   HDMI_CEA_480i60_4xH      = 11,
+   HDMI_CEA_240p60_4x       = 12,
+   HDMI_CEA_240p60_4xH      = 13,
+   HDMI_CEA_480p60_2x       = 14,
+   HDMI_CEA_480p60_2xH      = 15,
+   HDMI_CEA_1080p60         = 16,
+   HDMI_CEA_576p50          = 17,
+   HDMI_CEA_576p50H         = 18,
+   HDMI_CEA_720p50          = 19,
+   HDMI_CEA_1080i50         = 20,
+   HDMI_CEA_576i50          = 21,
+   HDMI_CEA_576i50H         = 22,
+   HDMI_CEA_288p50          = 23,
+   HDMI_CEA_288p50H         = 24,
+   HDMI_CEA_576i50_4x       = 25,
+   HDMI_CEA_576i50_4xH      = 26,
+   HDMI_CEA_288p50_4x       = 27,
+   HDMI_CEA_288p50_4xH      = 28,
+   HDMI_CEA_576p50_2x       = 29,
+   HDMI_CEA_576p50_2xH      = 30,
+   HDMI_CEA_1080p50         = 31,
+   HDMI_CEA_1080p24         = 32,
+   HDMI_CEA_1080p25         = 33,
+   HDMI_CEA_1080p30         = 34,
+   HDMI_CEA_480p60_4x       = 35,
+   HDMI_CEA_480p60_4xH      = 36,
+   HDMI_CEA_576p50_4x       = 37,
+   HDMI_CEA_576p50_4xH      = 38,
+   HDMI_CEA_1080i50_rb      = 39,
+   HDMI_CEA_1080i100        = 40,
+   HDMI_CEA_720p100         = 41,
+   HDMI_CEA_576p100         = 42,
+   HDMI_CEA_576p100H        = 43,
+   HDMI_CEA_576i100         = 44,
+   HDMI_CEA_576i100H        = 45,
+   HDMI_CEA_1080i120        = 46,
+   HDMI_CEA_720p120         = 47,
+   HDMI_CEA_480p120         = 48,
+   HDMI_CEA_480p120H        = 49,
+   HDMI_CEA_480i120         = 50,
+   HDMI_CEA_480i120H        = 51,
+   HDMI_CEA_576p200         = 52,
+   HDMI_CEA_576p200H        = 53,
+   HDMI_CEA_576i200         = 54,
+   HDMI_CEA_576i200H        = 55,
+   HDMI_CEA_480p240         = 56,
+   HDMI_CEA_480p240H        = 57,
+   HDMI_CEA_480i240         = 58,
+   HDMI_CEA_480i240H        = 59,
+   HDMI_CEA_720p24          = 60,
+   HDMI_CEA_720p25          = 61,
+   HDMI_CEA_720p30          = 62,
+   HDMI_CEA_1080p120        = 63,
+   HDMI_CEA_1080p100        = 64,
+
+   /* Up-to-date as of CEA 861-E */
+
+   HDMI_CEA_OFF = 0xff /**<Special code to shutdown HDMI */
+
+} HDMI_CEA_RES_CODE_T;
+
+/**
+ * These are the DMT modes from VESA. They are used for powering up
+ * HDMI in DMT resolutions and are not sent in AVI infoframes.
+ * Enum is ordered as ascending order of DMT id.
+ * All reduced blanking formats are 60Hz unless stated otherwise.
+ */
+typedef enum {
+   HDMI_DMT_640x350_85      = 0x1,  /**<640x350 */
+   HDMI_DMT_640x400_85      = 0x2,  /**<640x400 */
+   HDMI_DMT_IBM_VGA_85      = 0x3,  /**<720x400 */
+   HDMI_DMT_VGA_60          = 0x4,  /**<640x480 (60Hz is same as VGA above) */
+   HDMI_DMT_VGA_72          = 0x5,
+   HDMI_DMT_VGA_75          = 0x6,
+   HDMI_DMT_VGA_85          = 0x7,
+   HDMI_DMT_SVGA_56         = 0x8,  /**<800x600 */
+   HDMI_DMT_SVGA_60         = 0x9,
+   HDMI_DMT_SVGA_72         = 0xA,
+   HDMI_DMT_SVGA_75         = 0xB,
+   HDMI_DMT_SVGA_85         = 0xC,
+   HDMI_DMT_SVGA_120        = 0xD,
+   HDMI_DMT_848x480_60      = 0xE,  /**<848x480 */
+   HDMI_DMT_XGA_43          = 0xF,  /**<1024x768 - interlaced, DO NOT USE */
+   HDMI_DMT_XGA_60          = 0x10, /**<1024x768 */
+   HDMI_DMT_XGA_70          = 0x11,
+   HDMI_DMT_XGA_75          = 0x12,
+   HDMI_DMT_XGA_85          = 0x13,
+   HDMI_DMT_XGA_120         = 0x14,
+   HDMI_DMT_XGAP_75         = 0x15, /**<1152x864 */
+   HDMI_DMT_WXGA_RB         = 0x16, /**<1280x768 reduced blanking */
+   HDMI_DMT_WXGA_60         = 0x17,
+   HDMI_DMT_WXGA_75         = 0x18,
+   HDMI_DMT_WXGA_85         = 0x19,
+   HDMI_DMT_WXGA_120        = 0x1A, /**<120Hz with reduced blanking */
+   HDMI_DMT_1280x800_RB     = 0x1B, /**<1280x800 reduced blanking */
+   HDMI_DMT_1280x800_60     = 0x1C,
+   HDMI_DMT_1280x800_75     = 0x1D,
+   HDMI_DMT_1280x800_85     = 0x1E,
+   HDMI_DMT_1280x800_120    = 0x1F, /** reduced blanking */
+   HDMI_DMT_1280x960_60     = 0x20, /**<1280x960 */
+   HDMI_DMT_1280x960_85     = 0x21,
+   HDMI_DMT_1280x960_120    = 0x22, /** reduced blanking */
+   HDMI_DMT_SXGA_60         = 0x23, /**<1280x1024 */
+   HDMI_DMT_SXGA_75         = 0x24,
+   HDMI_DMT_SXGA_85         = 0x25,
+   HDMI_DMT_SXGA_120        = 0x26, /** reduced blanking */
+   HDMI_DMT_1360x768_60     = 0x27, /**<1360x768 */
+   HDMI_DMT_1360x768_120    = 0x28, /**<120 Hz with reduced blanking */
+   HDMI_DMT_SXGAP_RB        = 0x29, /**<1400x1050 reduced blanking */
+   HDMI_DMT_SXGAP_60        = 0x2A,
+   HDMI_DMT_SXGAP_75        = 0x2B,
+   HDMI_DMT_SXGAP_85        = 0x2C,
+   HDMI_DMT_SXGAP_120       = 0x2D, /** reduced blanking */
+   HDMI_DMT_1440x900_RB     = 0x2E, /**<1440x900 reduced blanking */
+   HDMI_DMT_1440x900_60     = 0x2F,
+   HDMI_DMT_1440x900_75     = 0x30,
+   HDMI_DMT_1440x900_85     = 0x31,
+   HDMI_DMT_1440x900_120    = 0x32, /** reduced blanking */
+   HDMI_DMT_UXGA_60         = 0x33, /**<1600x1200 60Hz */
+   HDMI_DMT_UXGA_65         = 0x34, 
+   HDMI_DMT_UXGA_70         = 0x35, 
+   HDMI_DMT_UXGA_75         = 0x36, 
+   HDMI_DMT_UXGA_85         = 0x37, 
+   HDMI_DMT_UXGA_120        = 0x38, /** reduced blanking */
+   HDMI_DMT_SWXGAP_RB       = 0x39, /**<1680x1050 reduced blanking */
+   HDMI_DMT_SWXGAP_60       = 0x3A, /**<1680x1050 60Hz */
+   HDMI_DMT_SWXGAP_75       = 0x3B, 
+   HDMI_DMT_SWXGAP_85       = 0x3C, 
+   HDMI_DMT_SWXGAP_120      = 0x3D, /** reduced blanking */ 
+   HDMI_DMT_1792x1344_60    = 0x3E, /**<1792x1344 60Hz */
+   HDMI_DMT_1792x1344_75    = 0x3F, /**<1792x1344 75Hz */
+   HDMI_DMT_1792x1344_120   = 0x40, /** reduced blanking */
+   HDMI_DMT_1856x1392_60    = 0x41, /**<1856x1392 60Hz */
+   HDMI_DMT_1856x1392_75    = 0x42, /**<1856x1392 75Hz */
+   HDMI_DMT_1856x1392_120   = 0x43, /** reduced blanking */
+   HDMI_DMT_WUXGA_RB        = 0x44, /**<1920x1200 reduced blanking */
+   HDMI_DMT_WUXGA_60        = 0x45, /**<1920x1200 60Hz */
+   HDMI_DMT_WUXGA_75        = 0x46, /**<1920x1200 75Hz */
+   HDMI_DMT_WUXGA_85        = 0x47, /**<1920x1200 85Hz */
+   HDMI_DMT_WUXGA_120       = 0x48, /** reduced blanking */
+   HDMI_DMT_1920x1440_60    = 0x49, /**<1920x1440 60Hz */
+   HDMI_DMT_1920x1440_75    = 0x4A, /**<1920x1440 75Hz */
+   HDMI_DMT_1920x1440_120   = 0x4B, /** reduced blanking */
+   HDMI_DMT_2560x1600_RB    = 0x4C, /**<2560x1600 reduced blanking */
+   HDMI_DMT_2560x1600_60    = 0x4D, /**<2560x1600 60 Hz */
+   HDMI_DMT_2560x1600_75    = 0x4E, /**<2560x1600 75 Hz */
+   HDMI_DMT_2560x1600_85    = 0x4E, /**<2560x1600 85 Hz */
+   HDMI_DMT_2560x1600_120   = 0x50, /** reduced blanking */
+   HDMI_DMT_1366x768_60     = 0x51, /**<1366x768 60Hz */
+   HDMI_DMT_1080p_60        = 0x52, /**<Same as 1080p60 above */
+   HDMI_DMT_1600x900_RB     = 0x53, /**<1600x900 reduced blanking */
+   HDMI_DMT_2048x1152_RB    = 0x54, /**<2048x1152 reduced blanking */
+   HDMI_DMT_720p_60         = 0x55, /**<Same as 720p60 above */
+   HDMI_DMT_1366x768_RB     = 0x56, /**<1366x768 reduced blanking */
+   /* Up-to-date as of VESA DMT v1 r12 */
+
+   HDMI_DMT_OFF = 0xff
+} HDMI_DMT_RES_CODE_T;
+
+/**
+ * HDMI scanmode
+ */
+typedef enum {
+   HDMI_NONINTERLACED,
+   HDMI_INTERLACED
+} HDMI_INTERLACED_T;
+
+/**
+ * Preference for powering up HDMI using best mode
+ * Note we will only use CEA modes for matching
+ */
+typedef enum {
+   HDMI_MODE_MATCH_NONE          = 0x0, /**<No mode*/
+   HDMI_MODE_MATCH_FRAMERATE     = 0x1, /**<Match based on frame rate */
+   HDMI_MODE_MATCH_RESOLUTION    = 0x2, /**<Match based on resolution */
+   HDMI_MODE_MATCH_SCANMODE      = 0x4  /**<Match based on scan mode */
+} EDID_MODE_MATCH_FLAG_T;
+
+/**
+ * Audio support flags
+ */
+typedef enum {
+   EDID_AUDIO_NO_SUPPORT         = (1 << 0), /**<No support for that format */
+   EDID_AUDIO_CHAN_UNSUPPORTED   = (1 << 1), /**<max. no. of channels exceeded */
+   EDID_AUDIO_FS_UNSUPPORTED     = (1 << 2), /**<no support for that sampling frequency */
+   EDID_AUDIO_BR_UNSUPPORTED     = (1 << 3), /**<max. bitrate exceeded */
+   EDID_AUDIO_SAMP_UNSUPPORTED   = (1 << 4), /**sample size unsupported (pcm only) */
+} EDID_AUDIO_SUPPORT_FLAG_T;
+
+/**
+ * Enums for audio support in audio descriptor block (CEA only)
+ * audio formats as specified in CEA Short Audio Descriptors
+ */
+typedef enum {
+   EDID_AudioFormat_eReserved,      /**<Refer to header when set in audio info frame */
+   EDID_AudioFormat_ePCM,           /**<Plain old PCM, mandatory for any audio support */
+   EDID_AudioFormat_eAC3,           /**<AC3 */
+   EDID_AudioFormat_eMPEG1,         /**<Mpeg layer 1 and 2 */
+   EDID_AudioFormat_eMP3,           /**<Mpeg layer 3 */
+   EDID_AudioFormat_eMPEG2,         /**<Mpeg 2 audio */
+   EDID_AudioFormat_eAAC,           /**<AAC */
+   EDID_AudioFormat_eDTS,           /**<DTS */
+   EDID_AudioFormat_eATRAC,         /**<Sony proprietary */
+   EDID_AudioFormat_eDSD,           /**<Super Audio CD 1-bit audio */
+   EDID_AudioFormat_eEAC3,          /**<Dolby Digital + */
+   EDID_AudioFormat_eDTS_HD,        /**<DTS-HD */
+   EDID_AudioFormat_eMLP,           /**<Meridian Lossless Packing - for DVD audio */
+   EDID_AudioFormat_eDST,           /**<Direct stream transfer - compressed super audio CD */
+   EDID_AudioFormat_eWMAPRO,        /**<WMA Pro */
+   EDID_AudioFormat_eExtended,      /**<Refer to byte 3 of audio db for coding extension type */
+
+   EDID_AudioFormat_eMaxCount
+} EDID_AudioFormat;
+
+/**
+ * If audio format is set to EDID_AudioFormat_eExtended,
+ * this gives the extended audio type (see CEA-861E section 6.6.1)
+ */
+typedef enum {
+   EDID_AudioCodingExtension_NONE    = 0x0, /** no extension, for audio format != Extended */
+   EDID_AudioCodingExtension_HEAAC   = 0x1, /**<HE-AAC */
+   EDID_AudioCodingExtension_HEAAC2  = 0x2, /**<HE-AAC v2 */
+   EDID_AudioCodingExtension_MPEGSUR = 0x3, /**<MPEG Surround */
+
+   EDID_AudioCodingExtension_max
+} EDID_AudioCodingExtension;
+
+/**
+ * Audio sample rates as specified in CEA Short Audio Descriptors
+ */
+typedef enum {
+   EDID_AudioSampleRate_eReferToHeader = 0x0,      /**<Only used in audio infoframe */
+   EDID_AudioSampleRate_e32KHz         = (1 << 0), /**<32 kHz (mandatory) */
+   EDID_AudioSampleRate_e44KHz         = (1 << 1), /**<44.1 kHz (mandatory) */
+   EDID_AudioSampleRate_e48KHz         = (1 << 2), /**<48kHz (mandatory) */
+   EDID_AudioSampleRate_e88KHz         = (1 << 3), /**<88.2 kHz */
+   EDID_AudioSampleRate_e96KHz         = (1 << 4), /**<96kHz */
+   EDID_AudioSampleRate_e176KHz        = (1 << 5), /**<176.4 kHz */
+   EDID_AudioSampleRate_e192KHz        = (1 << 6)  /**<192 kHz */
+} EDID_AudioSampleRate;
+
+/**
+ * Audio sample sizes (L-PCM) as specified in CEA Short Audio Descriptors
+ */
+typedef enum {
+   EDID_AudioSampleSize_refertoheader = 0x0, /**<Only used in audio infoframe */
+   EDID_AudioSampleSize_16bit         = 0x1, /**<16-bit samples (mandatory) */
+   EDID_AudioSampleSize_20bit         = 0x2, /**<20-bit samples */
+   EDID_AudioSampleSize_24bit         = 0x4  /**<24-bit samples */
+} EDID_AudioSampleSize;
+
+/**
+ *  LFE feedback level as described in audio db
+ */
+typedef enum {
+   EDID_AudioLFEFB_UNKNOWN = 0x0, /**<Refer to other information */
+   EDID_AudioLFEFB_0dB     = 0x1, /**<0dB - same level as other channels */
+   EDID_AudioLFEFB_10dB    = 0x2  /**<+10dB relative to other channels */
+} EDID_AudioLFEFB;
+
+/**
+ * All possible 3D structures
+ * to be used in decoded 3D modes (e.g. HDMI_3D_SUPPORTED_MODE)
+ */
+typedef enum {
+   HDMI_3D_STRUCT_NONE                                   = 0,
+   HDMI_3D_STRUCT_FRAME_PACKING                          = (1<<0),
+   HDMI_3D_STRUCT_FIELD_ALTERNATIVE                      = (1<<1),
+   HDMI_3D_STRUCT_LINE_ALTERNATIVE                       = (1<<2),
+   HDMI_3D_STRUCT_SIDE_BY_SIDE_FULL                      = (1<<3),
+   HDMI_3D_STRUCT_L_DEPTH                                = (1<<4),
+   HDMI_3D_STRUCT_L_DEPTH_GRAPHICS_GRAPHICS_DEPTH        = (1<<5),
+   HDMI_3D_STRUCT_TOP_AND_BOTTOM                         = (1<<6),
+   HDMI_3D_STRUCT_SIDE_BY_SIDE_HALF_HORIZONTAL           = (1<<7),
+   HDMI_3D_STRUCT_SIDE_BY_SIDE_HALF_ODD_LEFT_ODD_RIGHT   = (1<<8),
+   HDMI_3D_STRUCT_SIDE_BY_SIDE_HALF_ODD_LEFT_EVEN_RIGHT  = (1<<9),
+   HDMI_3D_STRUCT_SIDE_BY_SIDE_HALF_EVEN_LEFT_ODD_RIGHT  = (1<<10),
+   HDMI_3D_STRUCT_SIDE_BY_SIDE_HALF_EVEN_LEFT_EVEN_RIGHT = (1<<11),
+   HDMI_3D_STRUCT_FRAME_SEQUENTIAL                       = (1<<12),
+} HDMI_3D_STRUCT_T;
+
+/**
+ * HDMI notifications (defined as a bit mask to be conveniently returned as a state),
+ * make sure this does not clash with the values in vc_sdtv.h
+ * SDTV notifications start at bit 16.
+ * These values are returned by the TV service in a callback.
+ */
+typedef enum {
+   VC_HDMI_UNPLUGGED          = (1 << 0),  /**<HDMI cable is detached */
+   VC_HDMI_ATTACHED           = (1 << 1),  /**<HDMI cable is attached but not powered on */
+   VC_HDMI_DVI                = (1 << 2),  /**<HDMI is on but in DVI mode (no audio) */
+   VC_HDMI_HDMI               = (1 << 3),  /**<HDMI is on and HDMI mode is active */
+   VC_HDMI_HDCP_UNAUTH        = (1 << 4),  /**<HDCP authentication is broken (e.g. Ri mismatched) or not active */
+   VC_HDMI_HDCP_AUTH          = (1 << 5),  /**<HDCP is active */
+   VC_HDMI_HDCP_KEY_DOWNLOAD  = (1 << 6),  /**<HDCP key download successful/fail */
+   VC_HDMI_HDCP_SRM_DOWNLOAD  = (1 << 7),  /**<HDCP revocation list download successful/fail */
+   VC_HDMI_CHANGING_MODE      = (1 << 8),  /**<HDMI is starting to change mode, clock has not yet been set */
+
+} VC_HDMI_NOTIFY_T;
+#define VC_HDMI_STANDBY (VC_HDMI_ATTACHED) /* For backward code compatibility */
+
+/**
+ * Callback reason and arguments from HDMI middleware
+ * Each callback comes with two optional uint32_t parameters.
+ * Reason                     param1       param2      remark
+ * VC_HDMI_UNPLUGGED            -            -         cable is unplugged
+ * VC_HDMI_STANDBY            CEA/DMT      mode code   cable is plugged in and peripheral powered off (preferred mode sent back if available)
+ * VC_HDMI_DVI                CEA/DMT      mode code   DVI mode is active at said resolution
+ * VC_HDMI_HDMI               CEA(3D)/DMT  mode code   HDMI mode is active at said resolution (in 3D mode if CEA3D)
+ * VC_HDMI_HDCP_UNAUTH        HDCP_ERROR_T  retry?     HDCP is inactive, the error can be none if we actively disable HDCP, if retry is non-zero, HDCP will attempt to reauthenticate
+ * VC_HDMI_HDCP_AUTH            -            -         HDCP is active
+ * VC_HDMI_HDCP_KEY_DOWNLOAD  success?       -         HDCP key download success (zero) or not (non zero)
+ * VC_HDMI_HDCP_SRM_DOWNLOAD  no. of keys    -         HDCP revocation list download set no. of keys (zero means failure)
+ * VC_HDMI_CHANGING_MODE        0            0         No information is supplied in this callback
+ */
+
+/* Some constants which are required on host side */
+#define HDCP_KEY_BLOCK_SIZE 328 /* KSV, padding, device keys and hash. */
+#define HDCP_KSV_LENGTH   5
+#define HDCP_MAX_DEVICE 127 /* Max. number of HDCP downstream device supported */
+#define HDCP_MAX_DEPTH 7 /* Max. number of levels HDCP 1.x can have */
+#define EDID_BLOCKSIZE 128
+#define HDMI_NUM_PACKET_BYTES 28 /* Size of HDMI infoframes minus the header */
+#define HDMI_MAX_EXPLICIT_3D_MODES 31 /* The number of explicit 3D modes is stored in 5 bits */
+#define EDID_MONITOR_DESC_SIZE  18 /* Size of detailed timing descriptor in EDID */
+#define EDID_DESC_HEADER_LEN     5 /* Size of detailed timing descriptor header in EDID */
+#define EDID_DESC_ASCII_STRING_LEN (EDID_MONITOR_DESC_SIZE - EDID_DESC_HEADER_LEN)
+#define EDID_DEVICE_VENDOR_ID_LENGTH 3 /* Expanded Device Vendor ID length in EDID */
+
+/* All CEC related constants now reside in vc_cec.h */
+
+/**
+ * General callback function for both HDMI and HDCP middleware
+ * reason is the notification nature
+ * param1 and param2 have different meanings depending on the notification (see above)
+ *
+ * @param client_p is the callback context
+ *
+ * @param reason is the callback reason
+ *
+ * @param param1 is the first callback argument (meaning as above)
+ *
+ * @param param2 is the second callback argument (meaning as above)
+ *
+ * @return void
+ */
+typedef void (*HDMI_CALLBACK_T)(void *client_p, VC_HDMI_NOTIFY_T reason, uint32_t param1, uint32_t param2);
+
+/* TV service error return code */
+typedef enum {
+   VC_HDMI_SUCCESS                  = 0, /** OK */
+   VC_HDMI_ERROR_FORMAT_UNSUPPORTED = 1, /** format not supported */
+   VC_HDMI_ERROR_INVALID_FORMAT     = 2, /** invalid format */
+   VC_HDMI_ERROR_INVALID_PROPERTY   = 3, /** invalid property */
+   VC_HDMI_ERROR_OUT_OF_RANGE       = 4, /** invalid values passed to set property */
+   VC_HDMI_ERROR_INVALID_INFOFRAME  = 5, /** invalid infoframe */
+} VC_HDMI_ERROR_T;
+
+/* Defines for backward code compatibility (these were originally in hdmi.h) */
+typedef VC_HDMI_ERROR_T HDMI_RESULT_T;
+#define HDMI_RESULT_SUCCESS (VC_HDMI_SUCCESS)
+#define HDMI_RESULT_FAILED  (VC_HDMI_ERROR_FORMAT_UNSUPPORTED)
+
+#endif
diff --git a/interface/vmcs_host/vc_hdmi_property.h b/interface/vmcs_host/vc_hdmi_property.h
new file mode 100755 (executable)
index 0000000..54c3fc4
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+Copyright (c) 2012 Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+      THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+      ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+      WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+      DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+      DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+      (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+      LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+      ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+      (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+      SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * This file contains all the properties one can set in HDMI
+ * Each property has up to two parameters corresponding to list of enums one can set via
+ * the set/get property function from TV service (HOST) or HDMI middleware API (Videocore)
+ * Each property also has a default value for these parameters. Please refer to 
+ * individual properties for details.
+ */
+
+#ifndef _VC_HDMI_PROPERTY_H_
+#define _VC_HDMI_PROPERTY_H_
+#include "vcinclude/common.h"
+
+/**
+ * Property type
+ */
+typedef enum {
+   HDMI_PROPERTY_PIXEL_ENCODING   = 0, /**< Set pixel encoding, value of property is HDMI_PIXEL_ENCODING_T, default is RGB full range (unless it is not supported) */
+   HDMI_PROPERTY_PIXEL_CLOCK_TYPE = 1, /**< See HDMI_PIXEL_CLOCK_TYPE_T, default is HDMI_PIXEL_CLOCK_TYPE_PAL */
+   HDMI_PROPERTY_CONTENT_TYPE     = 2, /**< Set content type flag EDID_ContentType_T */
+   HDMI_PROPERTY_FUZZY_MATCH      = 3, /**< disable (0 - default) or enable (1) fuzzy format match */
+   HDMI_PROPERTY_3D_STRUCTURE     = 4, /**< Set the 3D structure of the next HDMI power on (only for CEA mode) */
+
+   //More properties to be added here
+   HDMI_PROPERTY_MAX                   /**< place holder */
+} HDMI_PROPERTY_T;
+
+/**
+ * Setting/getting a property
+ */
+typedef struct {
+   HDMI_PROPERTY_T property;
+   uint32_t param1;
+   uint32_t param2;
+   //More fields may be added here if required in future
+} HDMI_PROPERTY_PARAM_T;
+
+/**
+ * PIXEL_ENCODING: param1: encoding type, param2: n/a
+ * Setting encoding type is subjected to support in EDID
+ */
+typedef enum {
+   HDMI_PIXEL_ENCODING_DEFAULT = 0,  /**<Default, note that CEA modes (except VGA) default to RGB limited but DMT modes default to RGB full */
+   HDMI_PIXEL_ENCODING_RGB_LIMITED,
+   HDMI_PIXEL_ENCODING_RGB_FULL,
+   HDMI_PIXEL_ENCODING_YCbCr444_LIMITED,
+   HDMI_PIXEL_ENCODING_YCbCr444_FULL,
+   /** YCbCr 422 are not used at the moment */
+   HDMI_PIXEL_ENCODING_YCbCr422_LIMITED,
+   HDMI_PIXEL_ENCODING_YCbCr422_FULL,
+   HDMI_PIXEL_ENCODING_MAX /**<place holder */
+} HDMI_PIXEL_ENCODING_T;
+
+/**
+ * PIXEL_CLOCK_TYPE: param1: pixel clock type, param2: n/a
+ * Pixel clock nudge factor (set pixel clock type)
+ */
+typedef enum {
+   HDMI_PIXEL_CLOCK_TYPE_PAL  = 0, /**< Use norminal pixel clock (default) */
+   HDMI_PIXEL_CLOCK_TYPE_NTSC = 1, /**< Multiply norminal pixel clock by 1000/1001 to get the alternative frame rate e.g. 59.94Hz rather than 60, not applicable to all formats */
+   HDMI_PIXEL_CLOCK_TYPE_MAX       /**< place holder */
+} HDMI_PIXEL_CLOCK_TYPE_T;
+
+/**
+ * Content type: param1: EDID content type, param2: n/a
+ */
+/**
+ * Content type: the enum is the actual value in AVI infoframe + 1
+ * because NODATA and Graphics both have value zero
+ */
+typedef enum {
+   EDID_ContentType_NODATA   = 0x0, /**<Content type none */
+   EDID_ContentType_Graphics = 0x1, /**<Graphics, ITC must be set to 1 */
+   EDID_ContentType_Photo    = 0x2, /**<Photo */
+   EDID_ContentType_Cinema   = 0x3, /**<Cinema */
+   EDID_ContentType_Game     = 0x4, /**<Game */
+   EDID_ContentType_MAX             /**<place holder */
+} EDID_ContentType_T;
+
+/**
+ * Fuzzy match: param1 zero (disabled) or non-zero (enabled), param2: n/a
+ * If enabled, match format in EDID based on resolutions and formats only
+ * Default is zero (disabled, so match on blanking periods and pixel clock)
+ * Set to non-zero to enable fuzzy match
+ */
+typedef enum {
+   EDID_FUZZY_MATCH_DISABLED = 0x0,
+   EDID_FUZZY_MATCH_ENABLED  = 0x1,
+   EDID_FUZZY_MATCH_MAX
+} EDID_FuzzyMatch_T;
+
+/**
+ * 3D structure: param1 - 3D structure (e.g. top/bottom side by side) (default value is none, i.e. 2D)
+ *               param2 - n/a at the moment, may be used in the future
+ *
+ * 3D structure is auto reset to "2D" every time HDMI is power on. Only affect CEA formats.
+ */
+/*
+ * Matched to the 3d struct bit fields stored internally to represent 3D support in EDID
+ */
+typedef enum {
+   HDMI_3D_FORMAT_NONE = 0,           /**<plain and simple 2D! */
+   HDMI_3D_FORMAT_SBS_HALF = (1<<7),  /**<side by side half horizontal */
+   HDMI_3D_FORMAT_TB_HALF  = (1<<6),  /**<top and bottom half vertical */
+   HDMI_3D_FORMAT_FRAME_PACKING = (1<<8),  /**<frame packed */
+   HDMI_3D_FORMAT_FRAME_SEQUENTIAL = (1<<9),  /**<Output left on even frames and right on odd frames (typically 120Hz)*/
+   /* More 3D structs, e.g. full frame packing, may be added here */
+   HDMI_3D_FORMAT_INVALID = 0xFFFF
+} HDMI_3D_FORMAT_T;
+
+#endif //_VC_HDMI_PROPERTY_H_
diff --git a/interface/vmcs_host/vc_ilcs_defs.h b/interface/vmcs_host/vc_ilcs_defs.h
new file mode 100755 (executable)
index 0000000..1bfe866
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// OpenMAX IL Component Service definitions
+
+#ifndef VC_ILCS_DEFS_H
+#define VC_ILCS_DEFS_H
+
+#define VC_ILCS_VERSION 1
+
+#ifdef USE_VCHIQ_ARM
+#include "interface/vchiq_arm/vchiq.h"
+#else
+#include "interface/vchiq/vchiq.h"
+#endif
+
+typedef enum {
+   IL_RESPONSE,
+   IL_CREATE_COMPONENT,
+
+   IL_GET_COMPONENT_VERSION,
+   IL_SEND_COMMAND,
+   IL_GET_PARAMETER,
+   IL_SET_PARAMETER,
+   IL_GET_CONFIG,
+   IL_SET_CONFIG,
+   IL_GET_EXTENSION_INDEX,
+   IL_GET_STATE,
+   IL_COMPONENT_TUNNEL_REQUEST,
+   IL_USE_BUFFER,
+   IL_USE_EGL_IMAGE,
+   IL_ALLOCATE_BUFFER,
+   IL_FREE_BUFFER,
+   IL_EMPTY_THIS_BUFFER,
+   IL_FILL_THIS_BUFFER,
+   IL_SET_CALLBACKS,
+   IL_COMPONENT_ROLE_ENUM,
+
+   IL_COMPONENT_DEINIT,
+
+   IL_EVENT_HANDLER,
+   IL_EMPTY_BUFFER_DONE,
+   IL_FILL_BUFFER_DONE,
+
+   IL_COMPONENT_NAME_ENUM,
+   IL_GET_DEBUG_INFORMATION,
+
+   IL_SERVICE_QUIT,
+   IL_FUNCTION_MAX_NUM,
+   IL_FUNCTION_MAX = 0x7fffffff
+} IL_FUNCTION_T;
+
+
+// size of the largest structure passed by get/set
+// parameter/config
+// this should be calculated at compile time from IL headers
+// must be a multiple of VC_INTERFACE_BLOCK_SIZE
+#define VC_ILCS_MAX_PARAM_SIZE 288
+
+// size of the largest structure below
+#define VC_ILCS_MAX_CMD_LENGTH (sizeof(IL_GET_EXECUTE_T))
+
+#define VC_ILCS_MAX_INLINE (VCHIQ_SLOT_SIZE-8-16)
+
+// all structures should be padded to be multiples of
+// VC_INTERFACE_BLOCK_SIZE in length (currently 16)
+typedef struct {
+   void *reference;
+} IL_EXECUTE_HEADER_T;
+
+typedef struct {
+   IL_FUNCTION_T func;
+   OMX_ERRORTYPE err;
+} IL_RESPONSE_HEADER_T;
+
+// create instance
+typedef struct {
+   OMX_PTR mark;
+   char name[256];
+} IL_CREATE_COMPONENT_EXECUTE_T;
+
+typedef struct {
+   IL_FUNCTION_T func;
+   OMX_ERRORTYPE err;
+   void *reference;
+   OMX_U32 numPorts;
+   OMX_U32 portDir;
+   OMX_U32 portIndex[32];
+} IL_CREATE_COMPONENT_RESPONSE_T;
+
+// set callbacks
+typedef struct {
+   void *reference;
+   void *pAppData;
+} IL_SET_CALLBACKS_EXECUTE_T;
+
+// get state
+typedef struct {
+   IL_FUNCTION_T func;
+   OMX_ERRORTYPE err;
+   OMX_STATETYPE state;
+} IL_GET_STATE_RESPONSE_T;
+
+// get parameter & get config
+#define IL_GET_EXECUTE_HEADER_SIZE 8
+typedef struct {
+   void *reference;
+   OMX_INDEXTYPE index;
+   unsigned char param[VC_ILCS_MAX_PARAM_SIZE];
+} IL_GET_EXECUTE_T;
+
+#define IL_GET_RESPONSE_HEADER_SIZE 8
+typedef struct {
+   IL_FUNCTION_T func;
+   OMX_ERRORTYPE err;
+   unsigned char param[VC_ILCS_MAX_PARAM_SIZE];
+} IL_GET_RESPONSE_T;
+
+// set parameter & set config
+#define IL_SET_EXECUTE_HEADER_SIZE 8
+typedef struct {
+   void *reference;
+   OMX_INDEXTYPE index;
+   unsigned char param[VC_ILCS_MAX_PARAM_SIZE];
+} IL_SET_EXECUTE_T;
+
+// send command
+typedef struct {
+   void *reference;
+   OMX_COMMANDTYPE cmd;
+   OMX_U32 param;
+   OMX_MARKTYPE mark;
+} IL_SEND_COMMAND_EXECUTE_T;
+
+// event handler callback
+typedef struct {
+   void *reference;
+   OMX_EVENTTYPE event;
+   OMX_U32 data1;
+   OMX_U32 data2;
+   OMX_PTR eventdata;
+} IL_EVENT_HANDLER_EXECUTE_T;
+
+// use/allocate buffer
+typedef struct {
+   void *reference;
+   OMX_PTR bufferReference;
+   OMX_U32 port;
+   OMX_U32 size;
+   void *eglImage;
+} IL_ADD_BUFFER_EXECUTE_T;
+
+typedef struct {
+   IL_FUNCTION_T func;
+   OMX_ERRORTYPE err;
+   OMX_PTR reference;
+   OMX_BUFFERHEADERTYPE bufferHeader;
+} IL_ADD_BUFFER_RESPONSE_T;
+
+// free buffer
+typedef struct {
+   void *reference;
+   OMX_U32 port;
+   OMX_PTR bufferReference;
+   IL_FUNCTION_T func;
+   OMX_PTR inputPrivate;
+   OMX_PTR outputPrivate;
+} IL_FREE_BUFFER_EXECUTE_T;
+
+// empty/fill this buffer
+typedef enum {
+   IL_BUFFER_NONE,
+   IL_BUFFER_BULK,
+   IL_BUFFER_INLINE,
+   IL_BUFFER_MAX = 0x7fffffff
+} IL_BUFFER_METHOD_T;
+
+#define IL_BUFFER_BULK_UNALIGNED_MAX (32) // This value needs to be the same on voth VC and HOST.
+                                          // Here, we just manually set it to the max of VCHI_BULK_ALIGN on VC and HOST. 
+#if ( VCHI_BULK_ALIGN > IL_BUFFER_BULK_UNALIGNED_MAX )
+   #error "VCHI_BULK_ALIGN > IL_BUFFER_BULK_UNALIGNED_MAX. Just set max higher on both VC and HOST so there's space to put the unaligned bytes."
+#endif
+typedef struct {
+   OMX_U8 header[IL_BUFFER_BULK_UNALIGNED_MAX-1];
+   OMX_U8 headerlen;
+   OMX_U8 trailer[IL_BUFFER_BULK_UNALIGNED_MAX-1];
+   OMX_U8 trailerlen;
+} IL_BUFFER_BULK_T;
+
+typedef struct {
+   OMX_U8 buffer[1];
+} IL_BUFFER_INLINE_T;
+
+typedef struct {
+   void *reference;
+   OMX_BUFFERHEADERTYPE bufferHeader;
+   IL_BUFFER_METHOD_T method;
+   OMX_U32 bufferLen;
+} IL_PASS_BUFFER_EXECUTE_T;
+
+// get component version
+typedef struct {
+   IL_FUNCTION_T func;
+   OMX_ERRORTYPE err;
+   char name[128];
+   OMX_VERSIONTYPE component_version;
+   OMX_VERSIONTYPE spec_version;
+   OMX_UUIDTYPE uuid;
+} IL_GET_VERSION_RESPONSE_T;
+
+// get extension index
+typedef struct {
+   void *reference;
+   char name[128];
+} IL_GET_EXTENSION_EXECUTE_T;
+
+typedef struct {
+   IL_FUNCTION_T func;
+   OMX_ERRORTYPE err;
+   OMX_INDEXTYPE index;
+} IL_GET_EXTENSION_RESPONSE_T;
+
+// component role enum
+typedef struct {
+   void *reference;
+   OMX_U32 index;
+} IL_COMPONENT_ROLE_ENUM_EXECUTE_T;
+
+typedef struct {
+   IL_FUNCTION_T func;
+   OMX_ERRORTYPE err;
+   OMX_U8 role[128];
+} IL_COMPONENT_ROLE_ENUM_RESPONSE_T;
+
+typedef struct {
+   void *reference;
+   OMX_U32 port;
+   OMX_PTR tunnel_ref;       // reference to use in requests - address of host/vc component
+   OMX_BOOL tunnel_host;     // whether tunnel_ref is a host component
+   OMX_U32 tunnel_port;
+   OMX_TUNNELSETUPTYPE setup;
+} IL_TUNNEL_REQUEST_EXECUTE_T;
+
+typedef struct {
+   IL_FUNCTION_T func;
+   OMX_ERRORTYPE err;
+   OMX_TUNNELSETUPTYPE setup;
+} IL_TUNNEL_REQUEST_RESPONSE_T;
+
+typedef struct {
+   int index;
+} IL_COMPONENT_NAME_ENUM_EXECUTE_T;
+
+typedef struct {
+   IL_FUNCTION_T func;
+   OMX_ERRORTYPE err;
+   OMX_U8 name[128];
+} IL_COMPONENT_NAME_ENUM_RESPONSE_T;
+
+typedef struct {
+   OMX_S32 len;
+} IL_GET_DEBUG_INFORMATION_EXECUTE_T;
+
+#endif // VC_ILCS_DEFS_H
diff --git a/interface/vmcs_host/vc_imageconv_defs.h b/interface/vmcs_host/vc_imageconv_defs.h
new file mode 100755 (executable)
index 0000000..418d758
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef IMAGECONV_DEFS_H
+#define IMAGECONV_DEFS_H
+
+/** Statistics for image conversion to foreign image types
+ */
+typedef struct
+{
+   uint32_t magic;
+   uint32_t size;                   /**< Size of this structure, in bytes */
+   uint32_t conversions;            /**< Total conversions so far */
+   uint32_t duplicate_conversions;  /**< Duplicate conversions (same image twice) */
+   uint32_t size_requests;          /**< Num calls to get_converted_size */
+   uint32_t consumed_count;         /**< How many converted images were consumed */
+   uint32_t failures;               /**< Failed conversions */
+   uint32_t time_spent;             /**< Time spent converting, us */
+   uint32_t max_vrf_delay;          /**< The max time waiting for the VRF */
+   uint32_t vrf_wait_time;          /**< Total time waiting for the VRF */
+   uint32_t last_mem_handle;        /**< Last mem handle converted */
+   uint32_t first_image_ts;         /**< Timestamp of first image */
+   uint32_t last_image_ts;          /**< Timestamp of first image */
+   uint32_t max_delay;              /**< Jitter */
+} IMAGECONV_STATS_T;
+
+#define IMAGECONV_STATS_MAGIC 0x494D454C
+#endif
diff --git a/interface/vmcs_host/vc_sdtv.h b/interface/vmcs_host/vc_sdtv.h
new file mode 100755 (executable)
index 0000000..5a57528
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * SDTV common host header for TV service
+ */
+#ifndef _VC_SDTV_H_
+#define _VC_SDTV_H_
+
+/** Different SDTV modes */
+/** colour */
+typedef enum SDTV_COLOUR_
+{
+   SDTV_COLOUR_UNKNOWN = 0x0,
+   SDTV_COLOUR_RGB     = 0x4,
+   SDTV_COLOUR_YPRPB   = 0x8,
+   SDTV_COLOUR_FORCE_32BIT    = 0x80000000
+} SDTV_COLOUR_T;
+/** operation mode */
+typedef enum SDTV_MODE_T_
+{
+   SDTV_MODE_NTSC       = 0, /**<Normal NTSC */
+   SDTV_MODE_NTSC_J     = 1, /**<Japanese version of NTSC - no pedestal.*/
+   SDTV_MODE_PAL        = 2, /**<Normal PAL */
+   SDTV_MODE_PAL_M      = 3, /**<Brazilian version of PAL - 525/60 rather than 625/50, different subcarrier */
+   SDTV_MODE_FORMAT_MASK = 0x3,
+   
+   SDTV_MODE_OUTPUT_MASK = 0xc,
+
+   SDTV_MODE_YPRPB_480i = (SDTV_MODE_NTSC | SDTV_COLOUR_YPRPB),
+   SDTV_MODE_RGB_480i   = (SDTV_MODE_NTSC | SDTV_COLOUR_RGB),
+   SDTV_MODE_YPRPB_576i = (SDTV_MODE_PAL  | SDTV_COLOUR_YPRPB),
+   SDTV_MODE_RGB_576i   = (SDTV_MODE_PAL  | SDTV_COLOUR_RGB),
+
+   SDTV_MODE_PROGRESSIVE = 0x10, /**<240p progressive output*/
+
+   SDTV_MODE_OFF        = 0x80,
+   SDTV_MODE_FORCE_32BIT = 0x80000000
+} SDTV_MODE_T;
+
+/** Different aspect ratios */
+typedef enum SDTV_ASPECT_T_
+{
+   // TODO: extend this to allow picture placement/size to be communicated.
+   SDTV_ASPECT_UNKNOWN  = 0, /**<Unknown */
+   SDTV_ASPECT_4_3      = 1, /**<4:3 */
+   SDTV_ASPECT_14_9     = 2, /**<14:9 */
+   SDTV_ASPECT_16_9     = 3, /**<16:9 */
+   SDTV_ASPECTFORCE_32BIT = 0x80000000
+} SDTV_ASPECT_T;
+
+/** SDTV power on option */
+typedef struct SDTV_OPTIONS_T_
+{
+   SDTV_ASPECT_T   aspect;
+} SDTV_OPTIONS_T;
+
+/**
+ * Different copy protection modes
+ * At the moment we have only implemented Macrovision
+ */
+typedef enum
+{
+   SDTV_CP_NONE              = 0, /**<No copy protection */
+   SDTV_CP_MACROVISION_TYPE1 = 1, /**<Macrovision Type 1 */
+   SDTV_CP_MACROVISION_TYPE2 = 2, /**<Macrovision Type 2 */
+   SDTV_CP_MACROVISION_TYPE3 = 3, /**<Macrovision Type 3 */
+   SDTV_CP_MACROVISION_TEST1 = 4, /**<Macrovision Test 1 */
+   SDTV_CP_MACROVISION_TEST2 = 5, /**<Macrovision Test 2 */
+   SDTV_CP_CGMS_COPYFREE     = 6, /**<CGMS copy freely */
+   SDTV_CP_CGMS_COPYNOMORE   = 7, /**<CGMS copy no more */
+   SDTV_CP_CGMS_COPYONCE     = 8, /**<CGMS copy once */
+   SDTV_CP_CGMS_COPYNEVER    = 9, /**<CGMS copy never */
+   SDTV_CP_WSS_COPYFREE      = 10, /**<WSS no restriction */
+   SDTV_CP_WSS_COPYRIGHT_COPYFREE = 11, /**<WSS copyright asserted */
+   SDTV_CP_WSS_NOCOPY        = 12, /**<WSS copying restricted */
+   SDTV_CP_WSS_COPYRIGHT_NOCOPY = 13, /**<WSS copying restriced, copyright asserted */
+   SDTV_CP_FORCE_32BIT = 0x80000000
+} SDTV_CP_MODE_T;
+
+/**
+ * SDTV internal state
+ */
+typedef struct {
+   uint32_t state;
+   uint32_t width;
+   uint32_t height;
+   uint16_t frame_rate;
+   uint16_t scan_mode;
+   SDTV_MODE_T mode;
+   SDTV_OPTIONS_T display_options;
+   SDTV_COLOUR_T colour;
+   SDTV_CP_MODE_T cp_mode;
+} SDTV_DISPLAY_STATE_T;
+
+/**
+ * SDTV notifications
+ */
+typedef enum 
+{
+   VC_SDTV_UNPLUGGED          = 1 << 16, /**<SDTV cable unplugged, subject to platform support */
+   VC_SDTV_ATTACHED           = 1 << 17, /**<SDTV cable is plugged in */
+   VC_SDTV_NTSC               = 1 << 18, /**<SDTV is in NTSC mode */
+   VC_SDTV_PAL                = 1 << 19, /**<SDTV is in PAL mode */
+   VC_SDTV_CP_INACTIVE        = 1 << 20, /**<Copy protection disabled */
+   VC_SDTV_CP_ACTIVE          = 1 << 21  /**<Copy protection enabled */
+} VC_SDTV_NOTIFY_T;
+#define VC_SDTV_STANDBY (VC_SDTV_ATTACHED) /* For backward code compatibility, to be consistent with HDMI */
+
+/**
+ * Callback reason and arguments from vec middleware
+ * Each callback comes with two optional uint32_t parameters.
+ * Reason                     param1       param2      remark
+ * VC_SDTV_UNPLUGGED            -            -         cable is unplugged
+ * VC_SDTV_STANDBY              -            -         cable is plugged in
+ * VC_SDTV_NTSC              SDTV_MODE_T SDTV_ASPECT_T NTSC mode active with said aspect ratio
+ * VC_SDTV_PAL               SDTV_MODE_T SDTV_ASPECT_T PAL  mode active with said aspect ratio
+ * VC_SDTV_CP_INACTIVE          -            -         copy protection is inactive
+ * VC_SDTV_CP_ACTIVE         SDTV_CP_MODE_T  -         copy protection is active
+ */
+
+#endif
diff --git a/interface/vmcs_host/vc_service_common.c b/interface/vmcs_host/vc_service_common.c
new file mode 100755 (executable)
index 0000000..a463d51
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include "interface/vchiq_arm/vchiq_if.h"
+#include "vc_service_common.h"
+VC_SERVICE_VCHI_STATUS_T vchi2service_status(int32_t x) {
+   VC_SERVICE_VCHI_STATUS_T ret;
+   switch(x) {
+   case VCHIQ_SUCCESS:
+      ret = VC_SERVICE_VCHI_SUCCESS; break;
+   case VCHIQ_ERROR:
+      ret = VC_SERVICE_VCHI_VCHIQ_ERROR; break;
+   case VCHIQ_RETRY:
+      ret = VC_SERVUCE_VCHI_RETRY; break;
+   default:
+      ret = VC_SERVICE_VCHI_UNKNOWN_ERROR;
+   }
+   return ret;
+}
+
+const char* vchi2service_status_string(VC_SERVICE_VCHI_STATUS_T status) {
+   const char* string = "";
+   switch(status) {
+   case VCHIQ_SUCCESS:
+      string = "success"; break;
+   case VCHIQ_ERROR:
+      string = "vchiq error"; break;
+   case VCHIQ_RETRY:
+      string = "retry"; break;
+   default:
+      string = "unknown";
+   }
+   return string;
+}
diff --git a/interface/vmcs_host/vc_service_common.h b/interface/vmcs_host/vc_service_common.h
new file mode 100755 (executable)
index 0000000..bb16a42
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+* Copyright (c) 2012 Broadcom Europe Ltd
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * Common definitions for services
+ */
+
+#ifndef _VC_SERVICE_COMMON_DEFS_H_
+#define _VC_SERVICE_COMMON_DEFS_H_
+#include "vcinclude/common.h"
+//Map VCHI return value to internal error code
+//VCHI return +1 for retry so we will map it to -2 to allow
+//servers to use positive values to indicate alternative return values
+typedef enum {
+   VC_SERVICE_VCHI_SUCCESS = 0,
+   VC_SERVICE_VCHI_VCHIQ_ERROR = -1,
+   VC_SERVUCE_VCHI_RETRY = -2,
+   VC_SERVICE_VCHI_UNKNOWN_ERROR = -3
+} VC_SERVICE_VCHI_STATUS_T;
+
+extern VC_SERVICE_VCHI_STATUS_T vchi2service_status(int32_t x);
+extern const char* vchi2service_status_string(VC_SERVICE_VCHI_STATUS_T status);
+
+#endif //#ifndef _VC_SERVICE_COMMON_DEFS_H_
diff --git a/interface/vmcs_host/vc_tvservice.h b/interface/vmcs_host/vc_tvservice.h
new file mode 100755 (executable)
index 0000000..ab290ac
--- /dev/null
@@ -0,0 +1,524 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * TV service host API,
+ * See vc_hdmi.h for HDMI related constants
+ * See vc_sdtv.h for SDTV related constants
+ */
+
+#ifndef _VC_TVSERVICE_H_
+#define _VC_TVSERVICE_H_
+
+#include "vcinclude/common.h"
+#include "interface/vcos/vcos.h"
+#include "interface/vchi/vchi.h"
+#include "interface/vmcs_host/vc_tvservice_defs.h"
+#include "interface/vmcs_host/vc_hdmi.h"
+#include "interface/vmcs_host/vc_sdtv.h"
+
+/**
+ * \file
+ *
+ * This API defines the controls for both HDMI and analogue TVs. It allows
+ * the user to dynamically switch between HDMI and SDTV without having
+ * to worry about switch one off before turning the other on. It also
+ * allows the user to query the supported HDMI resolutions and audio
+ * formats and turn on/off copy protection.
+ *
+ * There are three ways to turn on HDMI: preferred mode; best matched mode
+ * and explicit mode. See the three power on functions for details.
+ */
+
+/**
+ * TVSERVICE_CALLBACK_T is the callback function for host side notification.
+ * Host applications register a single callback for all TV related notifications.
+ * See <DFN>VC_HDMI_NOTIFY_T</DFN> and <DFN>VC_SDTV_NOTIFY_T</DFN> in vc_hdmi.h and vc_sdtv.h
+ * respectively for list of reasons and respective param1 and param2
+ *
+ * @param callback_data is the context passed in during the call to vc_tv_register_callback
+ *
+ * @param reason is the notification reason
+ *
+ * @param param1 is the first optional parameter
+ *
+ * @param param2 is the second optional parameter
+ *
+ * @return void
+ */
+typedef void (*TVSERVICE_CALLBACK_T)(void *callback_data, uint32_t reason, uint32_t param1, uint32_t param2);
+
+/* API at application start time */
+/**
+ * <DFN>vc_vchi_tv_init</DFN> is called at the beginning of the application
+ * to initialise the client to TV service
+ *
+ * @param initialise_instance is the VCHI instance
+ *
+ * @param array of pointers of connections
+ *
+ * @param number of connections (currently this is always <DFN>1</DFN>
+ *
+ * @return Zero is successful A negative return value indicates failure (which may mean it has not been started on VideoCore).
+ */
+VCHPRE_ int vc_vchi_tv_init(VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections );
+
+/**
+ * <DFN>vc_vchi_tv_stop</DFN> is called to stop the host side of TV service.
+ *
+ * @param none
+ *
+ * @return void
+ */
+VCHPRE_ void vc_vchi_tv_stop( void );
+
+/**
+ * Host applications should call <DFN>vc_tv_register_callback</DFN> at
+ * the beginning to register a callback function to handle all notifications.
+ * See <DFN>TVSERVICE_CALLBACK_T </DFN>
+ *
+ * @param callback function
+ *
+ * @param callback_data is the context to be passed when function is called
+ *
+ * @return void
+ */
+VCHPRE_ void vc_tv_register_callback(TVSERVICE_CALLBACK_T callback, void *callback_data);
+
+/**
+ * <DFN>vc_tv_unregister_callback</DFN> removes a function registered with
+ * <DFN>vc_tv_register_callback</DFN> from the list of callbacks.
+ *
+ * @param callback function
+ *
+ * @return void
+ */
+VCHPRE_ void vc_tv_unregister_callback(TVSERVICE_CALLBACK_T callback);
+
+/**
+ * <DFN>vc_tv_unregister_callback</DFN> removes a function registered with
+ * <DFN>vc_tv_register_callback</DFN> from the list of callbacks.
+ * In contrast to vc_tv_unregister_callback this one matches not only the
+ * function pointer but also the data pointer before removal.
+ *
+ * @param callback function
+ *
+ * @return void
+ */
+VCHPRE_ void vc_tv_unregister_callback_full(TVSERVICE_CALLBACK_T callback, void *callback_data);
+
+/**
+ * In the following API any functions applying to HDMI only will have hdmi_
+ * in the name, ditto for SDTV only will have sdtv_ in the name,
+ * Otherwise the function applies to both SDTV and HDMI (e.g. power off)
+ */
+
+/**
+ * <DFN>vc_tv_get_state</DFN> is used to obtain the current TV state.
+ * Host applications should call this function right after registering
+ * a callback in case any notifications are missed.
+ *
+ * Now deprecated - use vc_tv_get_display_state instead
+ *
+ * @param pointer to TV_GET_STATE_RESP_T
+ *
+ * @return zero if the command is sent successfully, non zero otherwise
+ * If the command fails to be sent, passed in state is unchanged
+ *
+ */
+VCHPRE_ int VCHPOST_ vc_tv_get_state(TV_GET_STATE_RESP_T *tvstate);
+
+/**
+ * <DFN>vc_tv_get_display_state</DFN> is used to obtain the current TV display
+ * state. This function supersedes vc_tv_get_state (which is only kept for
+ * backward compatibility.
+ * Host applications should call this function right after registering
+ * a callback in case any notifications are missed.
+ *
+ * @param pointer to TV_DISPLAY_STATE_T
+ *
+ * @return zero if the command is sent successfully, non zero otherwise
+ * If the command fails to be sent, passed in state is unchanged
+ *
+ */
+VCHPRE_ int VCHPOST_ vc_tv_get_display_state(TV_DISPLAY_STATE_T *tvstate);
+
+/**
+ * Use <DFN>vc_tv_hdmi_power_on_preferred</DFN> if you don't care what resolutions
+ * a TV supports and just want to turn on its native resolution. Analogue TV will
+ * be powered down if on (same for the following two HDMI power on functions.)
+ * If power on is successful, a host application must wait for the power on complete
+ * callback before attempting to open the display.
+ *
+ * @param none
+ *
+ * @return single value interpreted as HDMI_RESULT_T (zero means success)
+ *         if successful, there will be a callback when the power on is complete
+ *
+ **/
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_power_on_preferred( void );
+
+/**
+ * Same as above, but tell the TV to enter 3D mode. The TV will go to 2D mode
+ * if the preferred mode doesn't support 3D.
+ **/
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_power_on_preferred_3d( void );
+
+/**
+ * Use <DFN>vc_tv_hdmi_power_on_best</DFN> to power on HDMI at best matched resolution
+ * based on passed in parameters. Use HDMI_MODE_MATCH_FRAMERATE if you want to
+ * match the frame rate; use HDMI_MODE_MATCH_RESOLUTION if you want to match on
+ * screen size; add HDMI_MODE_MATCH_SCANMODE if you want to force
+ * interlaced/progressive mode. If no matching mode is found, the native resolution
+ * will be used instead.
+ *
+ * @param width is the desired minimum screen width
+ *
+ * @param height is the desired minimum screen height
+ *
+ * @param rate is the desired frame rate
+ *
+ * @param scan_mode (HDMI_NONINTERLACED / HDMI_INTERLACED) is the desired scan mode
+ *
+ * @param match flags is the matching flag <DFN>EDID_MODE_MATCH_FLAG_T</DFN>
+ *
+ * @return same as <DFN>vc_tv_hdmi_power_on_preferred</DFN>
+ */
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_power_on_best(uint32_t width, uint32_t height, uint32_t frame_rate,
+                                              HDMI_INTERLACED_T scan_mode, EDID_MODE_MATCH_FLAG_T match_flags);
+
+/**
+ * Same as above, but tell the TV to enter 3D mode. The TV will go to 2D mode
+ * if no suitable 3D mode can be found.
+ **/
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_power_on_best_3d(uint32_t width, uint32_t height, uint32_t frame_rate,
+                                              HDMI_INTERLACED_T scan_mode, EDID_MODE_MATCH_FLAG_T match_flags);
+
+/**
+ * Use <DFN>vc_tv_hdmi_power_on_explicit</DFN> if you want full control over what mode
+ * the TV is driven. This function is used, for example, when the host has the EDID
+ * and HDMI middleware does not know. If HDMI middleware has knowledge of EDID, the
+ * passed in mode is still subject to TV's supported modes
+ *
+ * @param mode (HDMI_MODE_HDMI/HDMI_MODE_DVI/HDMI_MODE_3D)
+ *
+ * @param group (HDMI_RES_GROUP_CEA/HDMI_RES_GROUP_DMT)
+ *
+ * @param code either <DFN>HDMI_CEA_RES_CODE_T</DFN> or <DFN>HDMI_DMT_RES_CODE_T</DFN>
+ *
+ * @return same as <DFN>vc_tv_hdmi_power_on_preferred</DFN>
+ */
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_power_on_explicit_new(HDMI_MODE_T mode, HDMI_RES_GROUP_T group, uint32_t code);
+
+/**
+ * <DFN>vc_tv_sdtv_power_on</DFN> is used to turn on analogue TV. HDMI will
+ * automatically be powered off if on.
+ *
+ * @param SDTV mode <DFN>SDTV_MODE_T</DFN>
+ *
+ * @param options <DFN>SDTV_OPTIONS_T</DFN>
+ *
+ * @return single value (zero means success) if successful, there will be a callback when the power on is complete
+ *
+ */
+VCHPRE_ int VCHPOST_ vc_tv_sdtv_power_on(SDTV_MODE_T mode, SDTV_OPTIONS_T *options);
+
+/**
+ * <DFN>vc_tv_power_off</DFN> is used to turn off either analogue or HDMI output.
+ * If HDMI is powered down, there will be a callback with reason UNPLUGGED (if no
+ * cable is attached) or STANDBY (if a cable is attached)
+ *
+ * @param none
+ *
+ * @return whether command is succcessfully sent
+ *
+ */
+VCHPRE_ int VCHPOST_ vc_tv_power_off( void );
+
+/**
+ * <DFN>vc_tv_hdmi_get_supported_modes</DFN> is used to get a list of supported
+ * modes for a particular standard (CEA/DMT/CEA3D). Prefer resolution (group and mode)
+ * is also returned, if needed. If there are more modes supported than the size of the array
+ * supply, only the array will be filled.
+ *
+ * @param group(HDMI_RES_GROUP_CEA/HDMI_RES_GROUP_DMT)
+ *
+ * @param array of <DFN>TV_SUPPORT_MODE_T</DFN> struct
+ *
+ * @param length of array above (in elements, not bytes)
+ *
+ * @pointer to preferred group (can be NULL)
+ *
+ * @pointer to prefer mode code (can be NULL)
+ *
+ * @return the number of modes actually written in the array,
+ *         zero means no modes (no EDID or cable unplugged)
+ *
+ */
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_get_supported_modes_new(HDMI_RES_GROUP_T group,
+                                                    TV_SUPPORTED_MODE_NEW_T *supported_modes,
+                                                    uint32_t max_supported_modes,
+                                                    HDMI_RES_GROUP_T *preferred_group,
+                                                    uint32_t *preferred_mode);
+/**
+ * <DFN>vc_tv_hdmi_mode_supported</DFN> is used to query whether a particular mode
+ * is supported or not.
+ *
+ * @param resolution standard (HDMI_RES_GROUP_CEA/HDMI_RES_GROUP_DMT)
+ *
+ * @param mode code
+ *
+ * @return > 0 means supported, 0 means unsupported, < 0 means error
+ *
+ */
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_mode_supported(HDMI_RES_GROUP_T group,
+                                               uint32_t mode);
+
+/**
+ * <DFN>vc_tv_hdmi_audio_supported</DFN> is used to query whether a
+ * particular audio format is supported. By default a device has to support
+ * 16-bit stereo PCM at 32/44.1/48 kHz if audio is supported at all.
+ * Support of other audio formats allow SPDIF to be used.
+ * A return value of zero means the audio format is completely supported.
+ * Any non-zero values are interpreted as bit mask (EDID_AUDIO_SUPPORT_FLAG_T).
+ * For example, if EDID_AUDIO_NO_SUPPORT is set, the audio format is not supported.
+ * If EDID_AUDIO_CHAN_UNSUPPORTED is set, the max no. of channels has exceeded.
+ *
+ * @param audio format supplied as (<DFN>EDID_AudioFormat</DFN> + <DFN>EDID_AudioCodingExtension</DFN>)
+ *
+ * @param no. of channels (1-8)
+ *
+ * @param sample rate <DFN>EDID_AudioSampleRate</DFN> but NOT "refer to header"
+ *
+ * @param bit rate (or sample size if pcm) use <DFN>EDID_AudioSampleSize</DFN> as sample size argument
+ *
+ * @return: single value return interpreted as flags in <DFN>EDID_AUDIO_SUPPORT_FLAG_T</DFN>
+ *
+ */
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_audio_supported(uint32_t audio_format, uint32_t num_channels,
+                                                EDID_AudioSampleRate fs, uint32_t bitrate);
+
+/**
+ * Use <DFN>vc_tv_enable_copyprotect</DFN> to turn on copy protection.
+ * For HDMI, only HDMI_CP_HDCP is recognised.
+ * For SDTV, use one of the values in SDTV_CP_MODE_T
+ *
+ * @param copy protect mode
+ *
+ * @param time out in milliseconds (only applicable to HDMI)
+ *
+ * @return 0 means success, additional result via callback
+ *
+ */
+VCHPRE_ int VCHPOST_ vc_tv_enable_copyprotect(uint32_t cp_mode, uint32_t timeout);
+
+/**
+ * Use <DFN>vc_tv_disable_copyprotect</DFN> to turn off copy protection
+ *
+ * @param none
+ *
+ * @rturn 0 means success, additional result via callback
+ *
+ */
+VCHPRE_ int VCHPOST_ vc_tv_disable_copyprotect( void );
+
+/**
+ * Use <DFN>vc_tv_show_info</DFN> to show or hide info screen.
+ * Only usable in HDMI at the moment.
+ *
+ * @param show (1) or hide (0) info screen
+ *
+ * @return zero if command is successfully sent
+ *
+ */
+VCHPRE_ int VCHPOST_ vc_tv_show_info(uint32_t show);
+
+/**
+ * <DFN>vc_tv_hdmi_get_av_latency</DFN> is used to get the AV latency
+ * (in ms) for HDMI (lipsync), only valid if HDMI is currently powered on,
+ * otherwise you get zero. The latency is defined as the relative delay
+ * of the video stream to the audio stream
+ *
+ * @param none
+ *
+ * @return latency (zero if error or latency is not defined),
+ *         < 0 if failed to send command)
+ *
+ */
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_get_av_latency( void );
+
+/**
+ * Use <DFN>vc_tv_hdmi_set_hdcp_key</DFN> to download HDCP key to HDCP middleware
+ *
+ * @param AES encrypted key block (328 bytes)
+ *
+ * @return single value return indicating queued status
+ *         Callback indicates the validity of key
+ */
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_set_hdcp_key(const uint8_t *key);
+
+/**
+ * Use <DFN>vc_tv_hdmi_set_hdcp_revoked_list</DFN> to download SRM
+ * revoked list
+ *
+ * @param list
+ *
+ * @param size of list (no. of keys)
+ *
+ * @return single value return indicating queued status
+ *         Callback indicates the number of keys set (zero if failed, unless you are clearing the list)
+ *
+ */
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_set_hdcp_revoked_list(const uint8_t *list, uint32_t num_keys);
+
+/**
+ * <DFN>vc_tv_hdmi_set_spd</DFN> is used to set the SPD infoframe.
+ *
+ * @param manufacturer (max. 8 characters)
+ *
+ * @param description (max. 16 characters)
+ *
+ * @param product type <DFN>HDMI_SPD_TYPE_CODE_T</DFN>
+ *
+ * @return whether command was sent successfully (zero means success)
+ *
+ */
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_set_spd(const char *manufacturer, const char *description, HDMI_SPD_TYPE_CODE_T type);
+
+/**
+ * <DFN>vc_tv_hdmi_set_display_options</DFN> is used to set the
+ * active area for HDMI (bar width/height should be set to zero if absent)
+ * This information is conveyed in AVI infoframe.
+ *
+ * @param aspect ratio <DFN>HDMI_ASPECT_T</DFN>
+ *
+ * @param left bar width
+ *
+ * @param right bar width
+ *
+ * @param top bar height
+ *
+ * @param bottom bar height
+ *
+ * @return whether command was sent successfully (zero means success)
+ *
+ */
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_set_display_options(HDMI_ASPECT_T aspect, uint32_t left_bar_width, uint32_t right_bar_width, uint32_t top_bar_height, uint32_t bottom_bar_height, uint32_t overscan_flags);
+
+/**
+ * Use <DFN>vc_tv_test_mode_start</DFN> to generate test signal.
+ * At the moment only DVI test signal is supported.
+ * HDMI must be powered off before this function is called.
+ *
+ * @param 24-bit background colour (if applicable)
+ *
+ * @param test mode <DFN>TV_TEST_MODE_T</DFN>
+ *
+ * @return whether command was sent successfully (zero means success)
+ *
+ */
+VCHPRE_ int VCHPOST_ vc_tv_test_mode_start(uint32_t colour, TV_TEST_MODE_T test_mode);
+
+/**
+ * Use <DFN>vc_tv_test_mode_stop</DFN> to stop the test signal and power down
+ * HDMI.
+ *
+ * @param none
+ *
+ * @return whether command was sent successfully (zero means success)
+ *
+ */
+VCHPRE_ int VCHPOST_ vc_tv_test_mode_stop( void );
+
+/**
+ * <DFN>vc_tv_hdmi_ddc_read</DFN> allows an host application to read EDID
+ * with DDC protocol.
+ *
+ * @param offset
+ *
+ * @param length to read (this is typically 128 bytes to coincide with EDID block size)
+ *
+ * @param pointer to buffer, must be 16 byte aligned
+ *
+ * @returns length of data read (so zero means error) and the buffer will be filled
+ *          only if there is no error
+ *
+ */
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_ddc_read(uint32_t offset, uint32_t length, uint8_t *buffer);
+
+/**
+ * Sets the TV state to attached.
+ * Required when hotplug interrupt is not handled by VideoCore.
+ *
+ * @param attached  non-zero if the TV is attached or zero for unplugged.
+ */
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_set_attached(uint32_t attached);
+
+/**
+ * Sets one of the HDMI properties. HDMI properties persist
+ * between HDMI power on/off
+ *
+ * @param property [in]
+ *
+ * @return zero if successful, non-zero otherwise
+ */
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_set_property(const HDMI_PROPERTY_PARAM_T *property);
+
+/**
+ * Gets the current value of an HDMI property.
+ *
+ * @param property [in/out]
+ *
+ * @return zero if success (param1/param2 will be set), non-zero otherwise (param1/param2 will not be set)
+ */
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_get_property(HDMI_PROPERTY_PARAM_T *property);
+
+/**
+ * Converts the notification reason to a string.
+ *
+ * @param reason is the notification reason
+ * @return  The notification reason as a string.
+ */
+VCHPRE_ const char* vc_tv_notification_name(VC_HDMI_NOTIFY_T reason);
+
+/**
+ * Get the unique device ID from the EDID
+ * @param pointer to device ID struct
+ * @return zero if successful, non-zero if failed.
+ */
+VCHPRE_ int VCHPOST_  vc_tv_get_device_id(TV_DEVICE_ID_T *id);
+
+// temporary: maintain backwards compatibility
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_get_supported_modes(HDMI_RES_GROUP_T group,
+                                                    TV_SUPPORTED_MODE_T *supported_modes,
+                                                    uint32_t max_supported_modes,
+                                                    HDMI_RES_GROUP_T *preferred_group,
+                                                    uint32_t *preferred_mode);
+// temporary: maintain backwards compatibility
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_power_on_explicit(HDMI_MODE_T mode, HDMI_RES_GROUP_T group, uint32_t code);
+
+#endif
diff --git a/interface/vmcs_host/vc_tvservice_defs.h b/interface/vmcs_host/vc_tvservice_defs.h
new file mode 100755 (executable)
index 0000000..a792929
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/*
+ * TV service command enumeration and parameter types.
+ */
+
+#ifndef _VC_TVSERVICE_DEFS_H_
+#define _VC_TVSERVICE_DEFS_H_
+#include "vcinclude/common.h"
+#include "interface/vchi/message_drivers/message.h"
+#include "vc_hdmi.h"
+#include "vc_sdtv.h"
+
+#define VC_TVSERVICE_VER   1
+
+#define TVSERVICE_MSGFIFO_SIZE 1024
+#define TVSERVICE_CLIENT_NAME MAKE_FOURCC("TVSV")
+#define TVSERVICE_NOTIFY_NAME MAKE_FOURCC("TVNT")
+
+#define TVSERVICE_MAX_CALLBACKS  5
+
+//TV service commands
+typedef enum {
+   VC_TV_GET_STATE = 0,
+   VC_TV_HDMI_ON_PREFERRED,
+   VC_TV_HDMI_ON_BEST,
+   VC_TV_HDMI_ON_EXPLICIT,
+   VC_TV_SDTV_ON,
+   VC_TV_OFF,
+   VC_TV_QUERY_SUPPORTED_MODES,
+   VC_TV_QUERY_MODE_SUPPORT,
+   VC_TV_QUERY_AUDIO_SUPPORT,
+   VC_TV_ENABLE_COPY_PROTECT,
+   VC_TV_DISABLE_COPY_PROTECT,
+   VC_TV_SHOW_INFO,
+   VC_TV_GET_AV_LATENCY,
+   VC_TV_HDCP_SET_KEY,
+   VC_TV_HDCP_SET_SRM,
+   VC_TV_SET_SPD,
+   VC_TV_SET_DISPLAY_OPTIONS,
+   VC_TV_TEST_MODE_START,
+   VC_TV_TEST_MODE_STOP,
+   VC_TV_DDC_READ,
+   VC_TV_SET_ATTACHED,
+   VC_TV_SET_PROP,
+   VC_TV_GET_PROP,
+   VC_TV_GET_DISPLAY_STATE,
+   VC_TV_QUERY_SUPPORTED_MODES_ACTUAL,
+   VC_TV_GET_DEVICE_ID,
+   //Add more commands here
+   VC_TV_END_OF_LIST
+} VC_TV_CMD_CODE_T;
+
+//Parameters for each command (padded to multiple of 16 bytes)
+//See vc_hdmi.h and vc_sdtv.h for details
+
+//GET_STATE
+//Parameters: none
+//Reply: state (flags of VC_HDMI_NOTIFY_T and VC_SDTV_NOTIFY_T)
+//       current width
+//       current height
+//       current refresh rate
+//       current scan mode
+
+typedef struct {
+   uint32_t state;     /**<TV state is a union of bitmask of VC_HDMI_NOTIFY_T and VC_SDTV_NOTIFY_T */
+   uint32_t width;     /**<Current display width if TV is on */
+   uint32_t height;    /**<Current display height if TV is on */
+   uint16_t frame_rate;/**<Current refresh rate is TV is on */
+   uint16_t scan_mode; /**<Current scanmode 0 for progressive, 1 for interlaced */
+} TV_GET_STATE_RESP_T;
+
+//Generic single returned interpreted based on the command
+typedef struct {
+   int32_t ret; //Single return value
+} TV_GENERAL_RESP_T;
+
+//HDMI_ON_PREFERRED
+//Parameters: 3d mode (on/off)
+//Reply: single return value interpreted as HDMI_RESULT_T or SDTV equivalent (all single reply value will be of this form)
+typedef struct {
+   uint32_t in_3d;
+} TV_HDMI_ON_PREFERRED_PARAM_T;
+
+//HDMI_ON_BEST
+//Parameters: width, height, frame rate, scan mode, matching flag (EDID_MODE_MATCH_FLAG_T), 3d mode (on/off)
+//Reply: single return value interpreted as HDMI_RESULT_T or SDTV equivalent
+typedef struct {
+   uint32_t width;
+   uint32_t height;
+   uint32_t frame_rate;
+   uint32_t scan_mode;
+   uint32_t match_flags;
+   uint32_t in_3d;
+} TV_HDMI_ON_BEST_PARAM_T;
+
+//HDMI_ON_EXPLICIT
+//Parameters: hdmi_mode, standard, mode
+//Reply: same as above
+typedef struct {
+   uint32_t hdmi_mode; //DVI or HDMI
+   uint32_t group;
+   uint32_t mode;
+} TV_HDMI_ON_EXPLICIT_PARAM_T;
+
+//SDTV_ON
+//Parameters: SDTV mode, aspect ratio
+//Reply: Same as above
+typedef struct {
+   uint32_t mode;
+   uint32_t aspect;
+} TV_SDTV_ON_PARAM_T;
+
+//TV_OFF
+//Parameters: none
+//Reply: none
+
+//TV_QUERY_SUPPORTED_MODES
+//Parameters: standard (CEA/DMT) sent as uint32_t
+//Reply: how many modes there are in this group,
+//       preferred resolution
+
+//TV_QUERY_SUPPORTED_MODES_ACTUAL (This  downloads the array of supported modes)
+//Parameters: standard (CEA/DMT) sent as uint32_t,
+//            table size supplied
+//Reply: how many modes which will be returned,
+//       prefer resolution,
+//       the actual array of modes (via bulk transfer)
+
+typedef struct {
+   uint32_t scan_mode    : 1; /**<1 is interlaced, 0 for progressive */
+   uint32_t native       : 1; /**<1 means native mode, 0 otherwise */
+   uint32_t group        : 3; /**<group */
+   uint32_t code         : 7; /**<mode code */
+   uint32_t pixel_rep    : 3; /**<pixel repetition (zero means no repetition)*/
+   uint32_t aspect_ratio : 5; /**<aspect ratio of the format */
+   uint16_t frame_rate;    /**<frame rate */
+   uint16_t width;         /**<frame width */
+   uint16_t height;        /**<frame height */
+   uint32_t pixel_freq;    /**<pixel clock in Hz */
+   uint32_t struct_3d_mask;/**<3D structure supported for this mode, only valid if group == CEA. This is a bitmask of HDMI_3D_STRUCT_T */
+} TV_SUPPORTED_MODE_NEW_T;
+
+typedef struct {
+   uint16_t scan_mode : 1; /**<1 is interlaced, 0 for progressive */
+   uint16_t native    : 1; /**<1 means native mode, 0 otherwise */
+   uint16_t code      : 7; /**<mode code */
+   uint16_t frame_rate;    /**<frame rate */
+   uint16_t width;         /**<frame width */
+   uint16_t height;        /**<frame height */
+} TV_SUPPORTED_MODE_T;
+
+typedef struct {
+   uint32_t num_supported_modes;
+   uint32_t preferred_group;
+   uint32_t preferred_mode;
+} TV_QUERY_SUPPORTED_MODES_RESP_T;
+
+//num_supported_modes is the no. of modes available in that group for TV_QUERY_SUPPORTED_MODES
+//and no. of modes which will be bulk sent across in TV_QUERY_SUPPORTED_MODES_ACTUAL
+
+//For TV_QUERY_SUPPORTED_MODES_ACTUAL, there will be a separate bulk receive
+//containing the supported modes array
+
+//TV_QUERY_MODE_SUPPORT
+//Parameters: stardard, mode
+//Reply: yes/no
+//but the return value meaning is reversed (zero is unsupported, non-zero is supported)
+typedef struct {
+   uint32_t group;
+   uint32_t mode;
+} TV_QUERY_MODE_SUPPORT_PARAM_T;
+
+//TV_QUERY_AUDIO_SUPPORT
+//Parameters: audio format, no. of channels, sampling frequency, bitrate/sample size
+//Reply: single value interpreted as flags EDID_AUDIO_SUPPORT_FLAG_T
+typedef struct {
+   uint32_t audio_format; //EDID_AudioFormat (if format is eExtended, add EDID_AudioCodingExtension to the audio format)
+   uint32_t num_channels; // 1-8
+   uint32_t fs;           // EDID_AudioSampleRate
+   uint32_t bitrate;      // EDID_AudioSampleSize if format == PCM, bitrate otherwise
+} TV_QUERY_AUDIO_SUPPORT_PARAM_T;
+
+//TV_ENABLE_COPY_PROTECT
+//Parameters: copy protect mode (for HDMI it will always be HDCP), timeout
+//Reply: single return value - cp result arrive via callback
+typedef struct {
+   uint32_t cp_mode;
+   uint32_t timeout;
+} TV_ENABLE_COPY_PROTECT_PARAM_T;
+
+//TV_DISABLE_COPY_PROTECT
+//Parameters: none
+//Reply: single value return - results arrive via callback
+
+//TV_SHOW_INFO
+//Parameters: visible
+//Reply: none
+typedef struct {
+   uint32_t visible; //0 to hide the screen
+} TV_SHOW_INFO_PARAM_T;
+
+//TV_GET_AV_LATENCY
+//Parameters: none
+//Reply: single value interpreted as latency in ms
+
+
+//TV_HDCP_SET_KEY
+//Parameters: key block buffer (fixed size HDCP_KEY_BLOCK_SIZE)
+//Reply: none, key validity result arrives via callback
+typedef struct {
+   uint8_t key[HDCP_KEY_BLOCK_SIZE];
+} TV_HDCP_SET_KEY_PARAM_T;
+
+//TV_HDCP_SET_SRM
+//Parameters: num of keys, pointer to revocation list (transferred as buffer)
+//Reply: none, callback indicates no. of keys set
+typedef struct {
+   uint32_t num_keys;
+} TV_HDCP_SET_SRM_PARAM_T;
+
+//TV_SET_SPD
+//Parameters: name [8], description [16], type
+//Reply: none
+#define TV_SPD_NAME_LEN 8
+#define TV_SPD_DESC_LEN 16
+typedef struct {
+   char manufacturer[TV_SPD_NAME_LEN];
+   char description[TV_SPD_DESC_LEN];
+   uint32_t type;
+} TV_SET_SPD_PARAM_T;
+
+//TV_SET_DISPLAY_OPTIONS
+//Parameters: aspect ratio (HDMI_ASPECT_T), vert bar present (bool),
+//            left bar width, right bar width, horiz bar present (bool)
+//            top bar height, bottom bar height
+//Reply: none
+typedef struct {
+   uint32_t aspect;
+   uint32_t vertical_bar_present;
+   uint32_t left_bar_width;
+   uint32_t right_bar_width;
+   uint32_t horizontal_bar_present;
+   uint32_t top_bar_height;
+   uint32_t bottom_bar_height;
+   uint32_t overscan_flags;
+} TV_SET_DISPLAY_OPTIONS_PARAM_T;
+
+//TV_TEST_MODE_START
+//Parameters: rgb colour, test mode
+//Reply: none
+
+//Actual enums used for test mode
+typedef enum {
+   TV_TEST_MODE_DISABLED        = 0, //Test mode disabled
+   TV_TEST_MODE_SOLID_BACKGND   = 1, //Solid background colur
+   TV_TEST_MODE_SOLID_VERTICAL  = 2, //Vertical bars
+   TV_TEST_MODE_SHADED_VERTICAL = 3, //Shaded vertical bars
+   TV_TEST_MODE_SHADED_WHITE_V  = 4, //White vertical bars
+   TV_TEST_MODE_SHADED_WHITE_H  = 5, //White horizontal bars
+   TV_TEST_MODE_SHADED_RGB      = 6, //Shaded RGB + white bars
+   TV_TEST_MODE_WALKING         = 7, //Walking one across 24-bit RGB
+   TV_TEST_MODE_DELAYED         = 8, //Delayed shaded RGB bars
+   TV_TEST_MODE_HVD             = 9, //Horizontal G, Vert. B, Diag. R bars
+   TV_TEST_MODE_ODD_CH          =10, //Odd field crosshairs
+   TV_TEST_MODE_EVEN_CH         =11, //Even field crosshairs
+   TV_TEST_MODE_32x32           =12, //32x32 white grid
+   TV_TEST_MODE_WYCGMRBK_SOLID  =13, //Solid blah blah
+   TV_TEST_MODE_WYCGMRBK_SHADED =14, //Shaded blah blah
+   TV_TEST_MODE_32x32_DIAGONAL  =15  //32x32 white diagonal grid
+} TV_TEST_MODE_T;
+
+typedef struct {
+   uint32_t colour; //RGB colour
+   uint32_t test_mode; //one of the TV_TEST_MODE_T enums above
+} TV_TEST_MODE_START_PARAM_T;
+
+//TV_TEST_MODE_STOP
+//Parameters: none
+//Reply: none
+
+//TV_DDC_READ
+//Parameters: offset, length
+//Reply: length of data actually read (so zero means error),
+//and fills in the passed in buffer if no error
+typedef struct {
+   uint32_t offset;
+   uint32_t length;
+} TV_DDC_READ_PARAM_T;
+
+//TV_SET_ATTACHED
+//Parameters: uint32_t attached or not (0 = hotplug low, 1 = hotplug high)
+
+//TV_SET_PROP
+//Parameters: HDMI_PROPERTY_PARAM_T
+//Reply: 0 = set successful, non-zero if error (int32_t) 
+#define HDMI_PROPERTY_SIZE_IN_WORDS (sizeof(HDMI_PROPERTY_T)/sizeof(uint32_t))
+
+//TV_GET_PROP
+//Parameters: parameter type (sent as uint32_t)
+//Reply param1/param2 of the passed in property and return code
+typedef struct {
+   int32_t  ret; /**<Return code */
+   HDMI_PROPERTY_PARAM_T property; /**<HDMI_PROPERTY_PARAM_T */
+} TV_GET_PROP_PARAM_T;
+
+//TV_GET_DISPLAY_STATE
+//Parameters: none
+//Return TV display state
+typedef struct {
+   uint32_t state;               /** This will be the state of HDMI | SDTV */
+   union {
+      SDTV_DISPLAY_STATE_T sdtv; /** If SDTV is active, this is the state of SDTV */
+      HDMI_DISPLAY_STATE_T hdmi; /** If HDMI is active, this is the state of HDMI */
+   } display;
+} TV_DISPLAY_STATE_T;
+
+//TV_GET_DEVICE_ID
+//Parameter: none
+//Return device ID information from EDID
+typedef struct {
+   char vendor[EDID_DEVICE_VENDOR_ID_LENGTH+1];
+   char monitor_name[EDID_DESC_ASCII_STRING_LEN+1];
+   uint32_t serial_num;
+} TV_DEVICE_ID_T;
+
+// state flag for LCD attached
+enum {
+   VC_LCD_ATTACHED_DEFAULT    = (1 <<22),  /**<LCD display is attached and default */
+};
+
+#endif
diff --git a/interface/vmcs_host/vc_vchi_audioserv_defs.h b/interface/vmcs_host/vc_vchi_audioserv_defs.h
new file mode 100755 (executable)
index 0000000..21b5d64
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _VC_AUDIO_DEFS_H_
+#define _VC_AUDIO_DEFS_H_
+
+#define VC_AUDIOSERV_MIN_VER 1
+#define VC_AUDIOSERV_VER 3
+
+// FourCC code used for VCHI connection
+#define VC_AUDIO_SERVER_NAME  MAKE_FOURCC("AUDS")
+
+// Maximum message length
+#define VC_AUDIO_MAX_MSG_LEN  (sizeof( VC_AUDIO_MSG_T ))
+
+// List of screens that are currently supported
+// All message types supported for HOST->VC direction
+typedef enum
+{
+   VC_AUDIO_MSG_TYPE_RESULT,              // Generic result
+   VC_AUDIO_MSG_TYPE_COMPLETE,              // playback of samples complete
+   VC_AUDIO_MSG_TYPE_CONFIG,                 // Configure
+   VC_AUDIO_MSG_TYPE_CONTROL,                 // control 
+   VC_AUDIO_MSG_TYPE_OPEN,                 //  open
+   VC_AUDIO_MSG_TYPE_CLOSE,                 // close/shutdown
+   VC_AUDIO_MSG_TYPE_START,                 // start output (i.e. resume)
+   VC_AUDIO_MSG_TYPE_STOP,                 // stop output (i.e. pause)
+   VC_AUDIO_MSG_TYPE_WRITE,                 // write samples
+   VC_AUDIO_MSG_TYPE_LATENCY,               // request latency in cycles
+   VC_AUDIO_MSG_TYPE_MAX
+
+} VC_AUDIO_MSG_TYPE;
+
+static const char *vc_audio_msg_type_names[] = {
+   "VC_AUDIO_MSG_TYPE_RESULT",
+   "VC_AUDIO_MSG_TYPE_COMPLETE",
+   "VC_AUDIO_MSG_TYPE_CONFIG",
+   "VC_AUDIO_MSG_TYPE_CONTROL",
+   "VC_AUDIO_MSG_TYPE_OPEN",
+   "VC_AUDIO_MSG_TYPE_CLOSE",
+   "VC_AUDIO_MSG_TYPE_START",
+   "VC_AUDIO_MSG_TYPE_STOP",
+   "VC_AUDIO_MSG_TYPE_WRITE",
+   "VC_AUDIO_MSG_TYPE_MAX"
+};
+
+// configure the audio
+typedef struct
+{
+   uint32_t channels;
+   uint32_t samplerate;
+   uint32_t bps;
+   uint32_t channelmap;
+
+} VC_AUDIO_CONFIG_T;
+
+typedef struct
+{
+   uint32_t volume;
+   uint32_t dest;
+
+} VC_AUDIO_CONTROL_T;
+
+// audio
+typedef struct
+{
+   uint32_t dummy;
+
+} VC_AUDIO_OPEN_T;
+
+// audio
+typedef struct
+{
+   uint32_t dummy;
+
+} VC_AUDIO_CLOSE_T;
+// audio
+typedef struct
+{
+   uint32_t dummy;
+
+} VC_AUDIO_START_T;
+// audio
+typedef struct
+{
+   uint32_t draining;
+
+} VC_AUDIO_STOP_T;
+// audio
+typedef struct
+{
+   uint32_t dummy;
+
+} VC_AUDIO_LATENCY_T;
+
+// configure the write audio samples
+typedef struct
+{
+   uint32_t count; // in bytes
+   void *callback;
+   void *cookie;
+   uint16_t silence;
+   uint16_t max_packet;
+} VC_AUDIO_WRITE_T;
+
+// Generic result for a request (VC->HOST)
+typedef struct
+{
+   int32_t success;  // Success value
+
+} VC_AUDIO_RESULT_T;
+
+// Generic result for a request (VC->HOST)
+typedef struct
+{
+   int32_t count;  // Success value
+   void *callback;
+   void *cookie;
+} VC_AUDIO_COMPLETE_T;
+
+// Message header for all messages in HOST->VC direction
+typedef struct
+{
+   int32_t type;     // Message type (VC_AUDIO_MSG_TYPE)
+   union
+   {
+       VC_AUDIO_CONFIG_T    config;
+   VC_AUDIO_CONTROL_T   control;
+       VC_AUDIO_OPEN_T  open;
+       VC_AUDIO_CLOSE_T  close;
+       VC_AUDIO_START_T  start;
+       VC_AUDIO_STOP_T  stop;
+       VC_AUDIO_WRITE_T  write;
+       VC_AUDIO_LATENCY_T  latency;
+       VC_AUDIO_RESULT_T result;
+       VC_AUDIO_COMPLETE_T complete;
+   } u;
+} VC_AUDIO_MSG_T;
+
+
+#endif // _VC_AUDIO_DEFS_H_
diff --git a/interface/vmcs_host/vc_vchi_bufman.h b/interface/vmcs_host/vc_vchi_bufman.h
new file mode 100755 (executable)
index 0000000..67b19f2
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VC_VCHI_BUFMAN_H
+#define VC_VCHI_BUFMAN_H
+
+#include "interface/vctypes/vc_image_types.h"
+#include "interface/vchi/vchi.h"
+#ifdef __SYMBIAN32__
+#include "interface/vmcs_host/vc_vchi_bufman_defs.h"
+typedef uint32_t DISPMANX_RESOURCE_HANDLE_T;
+namespace BufManX {
+#else
+#include "interface/vmcs_host/vc_dispmanx.h"
+#include "interface/vmcs_host/vc_vchi_bufman_defs.h"
+#endif
+
+typedef void (*vc_bufman_callback_t) (void *next_cookie, void *next_cookie2, int32_t success);
+
+VCHPRE_ void VCHPOST_ vc_vchi_bufman_init(VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections);
+
+typedef struct
+{
+   buf_frame_type_t type;
+   int width, height, pitch;
+   int bpp; // bits per pixel
+   int size;
+   void *pixels;
+} BUFMANX_IMAGE_T;
+
+#define BUFMAN_TRANSFORM_HFLIP     (1<<0)
+#define BUFMAN_TRANSFORM_VFLIP     (1<<1)
+#define BUFMAN_TRANSFORM_TRANSPOSE (1<<2)
+
+typedef enum {
+   BUFMAN_TRANSFORM_ROT0           = 0,
+   BUFMAN_TRANSFORM_MIRROR_ROT0    = BUFMAN_TRANSFORM_HFLIP,
+   BUFMAN_TRANSFORM_MIRROR_ROT180  = BUFMAN_TRANSFORM_VFLIP,
+   BUFMAN_TRANSFORM_ROT180         = BUFMAN_TRANSFORM_HFLIP|BUFMAN_TRANSFORM_VFLIP,
+   BUFMAN_TRANSFORM_MIRROR_ROT90   = BUFMAN_TRANSFORM_TRANSPOSE,
+   BUFMAN_TRANSFORM_ROT270         = BUFMAN_TRANSFORM_TRANSPOSE|BUFMAN_TRANSFORM_HFLIP,
+   BUFMAN_TRANSFORM_ROT90          = BUFMAN_TRANSFORM_TRANSPOSE|BUFMAN_TRANSFORM_VFLIP,
+   BUFMAN_TRANSFORM_MIRROR_ROT270  = BUFMAN_TRANSFORM_TRANSPOSE|BUFMAN_TRANSFORM_HFLIP|BUFMAN_TRANSFORM_VFLIP,
+} BUFMAN_TRANSFORM_T;
+
+
+// we use an opaque type here as the internals shouldn't be used externally, but allocation of the size of the block is required by the caller.
+#define BUFMANX_HANDLE_T_SIZE 1024
+typedef struct {
+   char opaque[BUFMANX_HANDLE_T_SIZE];
+} BUFMANX_HANDLE_T;
+
+VCHPRE_ int32_t VCHPOST_ vc_bufmanx_convert_init(void);
+VCHPRE_ int32_t VCHPOST_ vc_bufmanx_set_transform_buffer(void *pixels, int size);
+VCHPRE_ int32_t VCHPOST_ vc_bufmanx_allocate_image(BUFMANX_IMAGE_T *image);
+VCHPRE_ int32_t VCHPOST_ vc_bufmanx_release_image(BUFMANX_IMAGE_T *image);
+VCHPRE_ int32_t VCHPOST_ vc_bufmanx_get_default_pitch( BUFMANX_IMAGE_T *src );
+VCHPRE_ int32_t VCHPOST_ vc_bufmanx_get_default_size(BUFMANX_IMAGE_T *src);
+VCHPRE_ int32_t VCHPOST_ vc_bufmanx_push ( BUFMANX_HANDLE_T *h, const BUFMANX_IMAGE_T *src, DISPMANX_RESOURCE_HANDLE_T dst, const VC_RECT_T *src_rect, const VC_RECT_T *dest_rect, BUFMAN_TRANSFORM_T transform, vc_bufman_callback_t callback, void *cookie, void *cookie2 );
+VCHPRE_ int32_t VCHPOST_ vc_bufmanx_pull ( BUFMANX_HANDLE_T *h, BUFMANX_IMAGE_T *dst, const DISPMANX_RESOURCE_HANDLE_T src, const VC_RECT_T *src_rect, const VC_RECT_T *dest_rect, BUFMAN_TRANSFORM_T transform, vc_bufman_callback_t callback, void *cookie, void *cookie2 );
+VCHPRE_ int32_t VCHPOST_ vc_bufmanx_pull_blocking ( BUFMANX_HANDLE_T *h, BUFMANX_IMAGE_T *dst, const DISPMANX_RESOURCE_HANDLE_T src, const VC_RECT_T *src_rect, const VC_RECT_T *dest_rect, BUFMAN_TRANSFORM_T transform );
+VCHPRE_ int32_t VCHPOST_ vc_bufmanx_push_blocking ( BUFMANX_HANDLE_T *h, const BUFMANX_IMAGE_T *src, DISPMANX_RESOURCE_HANDLE_T dst, const VC_RECT_T *src_rect, const VC_RECT_T *dest_rect, BUFMAN_TRANSFORM_T transform );
+VCHPRE_ int32_t VCHPOST_ vc_bufmanx_pull_striped ( BUFMANX_HANDLE_T *xh, BUFMANX_IMAGE_T *dst, const DISPMANX_RESOURCE_HANDLE_T src, const VC_RECT_T *src_rect, const VC_RECT_T *dest_rect, BUFMAN_TRANSFORM_T transform, vc_bufman_callback_t callback, void *cookie, void *cookie2 );
+VCHPRE_ int32_t VCHPOST_ vc_bufmanx_pull_striped_blocking ( BUFMANX_HANDLE_T *xh, BUFMANX_IMAGE_T *dst, const DISPMANX_RESOURCE_HANDLE_T src, const VC_RECT_T *src_rect, const VC_RECT_T *dest_rect, BUFMAN_TRANSFORM_T transform );
+VCHPRE_ int32_t VCHPOST_ vc_bufmanx_push_striped ( BUFMANX_HANDLE_T *xh, const BUFMANX_IMAGE_T *src, DISPMANX_RESOURCE_HANDLE_T dst, const VC_RECT_T *src_rect, const VC_RECT_T *dest_rect, BUFMAN_TRANSFORM_T transform, vc_bufman_callback_t callback, void *cookie, void *cookie2 );
+VCHPRE_ int32_t VCHPOST_ vc_bufmanx_push_striped_blocking ( BUFMANX_HANDLE_T *xh, const BUFMANX_IMAGE_T *src, DISPMANX_RESOURCE_HANDLE_T dst, const VC_RECT_T *src_rect, const VC_RECT_T *dest_rect, BUFMAN_TRANSFORM_T transform );
+
+VCHPRE_ void VCHPOST_ vc_bufmanx_push_multi ( BUFMANX_HANDLE_T *h, const BUFMANX_IMAGE_T *src, DISPMANX_RESOURCE_HANDLE_T dst, BUFMAN_TRANSFORM_T transform, vc_bufman_callback_t callback, void *cookie, void *cookie2 );
+VCHPRE_ void VCHPOST_ vc_bufmanx_pull_multi ( BUFMANX_HANDLE_T *h, BUFMANX_IMAGE_T *dst, const DISPMANX_RESOURCE_HANDLE_T src, BUFMAN_TRANSFORM_T transform, vc_bufman_callback_t callback, void *cookie, void *cookie2 );
+VCHPRE_ int32_t VCHPOST_ vc_bufmanx_push_multi_blocking ( BUFMANX_HANDLE_T *h, const BUFMANX_IMAGE_T *src, DISPMANX_RESOURCE_HANDLE_T dst, BUFMAN_TRANSFORM_T transform );
+VCHPRE_ int32_t VCHPOST_ vc_bufmanx_pull_multi_blocking ( BUFMANX_HANDLE_T *h, BUFMANX_IMAGE_T *dst, const DISPMANX_RESOURCE_HANDLE_T src, BUFMAN_TRANSFORM_T transform );
+
+// Allocate the specified number and type of buffers on the server side, for use with streams
+VCHPRE_ int32_t VCHPOST_ vc_bufmanx_allocate_buffers
+   (uint32_t stream, uint32_t num_of_buffers,
+      buf_frame_type_t type, uint32_t width, uint32_t height);
+
+// Free buffers on the server which are associated with the specified stream
+#define VC_BUFMANX_FREE_BUFFERS_ALL    0
+VCHPRE_ int32_t VCHPOST_ vc_bufmanx_free_buffers(uint32_t stream, uint32_t num_of_buffers);
+
+// Like vc_bufmanx_push_multi(), but specifies a stream, rather than a dispmanx resource handle,
+// to push the data to.
+VCHPRE_ void VCHPOST_ vc_bufmanx_push_multi_stream ( BUFMANX_HANDLE_T *xh, const BUFMANX_IMAGE_T *src, uint32_t stream, BUFMAN_TRANSFORM_T transform, vc_bufman_callback_t callback, void *cookie, void *cookie2 );
+
+VCHPRE_ VC_IMAGE_TYPE_T VCHPOST_ vc_bufmanx_get_vc_image_type(buf_frame_type_t bm_type);
+
+#ifdef __SYMBIAN32__
+} // namespace BufManX
+#endif
+
+#endif /* VC_VCHI_BUFMAN_H */
diff --git a/interface/vmcs_host/vc_vchi_bufman_defs.h b/interface/vmcs_host/vc_vchi_bufman_defs.h
new file mode 100755 (executable)
index 0000000..57b79e0
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VC_VCHI_BUFMAN_DEFS_H
+#define VC_VCHI_BUFMAN_DEFS_H
+
+#ifdef __SYMBIAN32__
+typedef uint32_t DISPMANX_RESOURCE_HANDLE_T;
+namespace BufManX {
+#else
+#include "interface/vmcs_host/vc_dispmanx.h"
+#endif
+
+typedef enum {
+   // Insert extra frame types here
+   FRAME_HOST_IMAGE_BASE = 0x20000, // Base for host format images
+   FRAME_HOST_IMAGE_EFormatYuv420P,
+   FRAME_HOST_IMAGE_EFormatYuv422P,
+   FRAME_HOST_IMAGE_EFormatYuv422LE,
+   FRAME_HOST_IMAGE_EFormatRgb565,
+   FRAME_HOST_IMAGE_EFormatRgb888,
+   FRAME_HOST_IMAGE_EFormatRgbU32,
+   FRAME_HOST_IMAGE_EFormatRgbA32,
+   FRAME_HOST_IMAGE_EFormatRgbA32LE,
+   FRAME_HOST_IMAGE_EFormatRgbU32LE,
+
+   FRAME_FORCE_FIELD_WIDTH = 0xFFFFFFFF
+} buf_frame_type_t;
+
+typedef enum {
+    //host to videocore
+    VC_BUFMAN_CONVERT_UNUSED = 0,
+    VC_BUFMAN_PULL_FRAME,
+    VC_BUFMAN_PUSH_FRAME,
+    VC_BUFMAN_MESSAGE_RESPONSE,
+    VC_BUFMAN_SYNC,
+    VC_BUFMAN_ALLOC_BUF,
+    VC_BUFMAN_FREE_BUF,
+    VC_BUFMAN_PULL_MULTI,
+    VC_BUFMAN_PUSH_MULTI,
+    VC_BUFMAN_PUSH_MULTI_STREAM,
+    //vc to host
+    VC_BUFMAN_FRAME_SENT_CALLBACK,
+    VC_BUFMAN_FORCE_WIDTH = 0x7fffffff,
+} buf_command_t;
+
+/* A header used for all messages sent and received by bufman.
+ */
+typedef struct {
+   buf_command_t command;
+} BUF_MSG_HDR_T;
+
+/* General remotely call this bufman operation commands */
+typedef struct {
+   uint32_t resource_handle;
+   buf_frame_type_t type;
+   int32_t size, width, height, pitch;
+   VC_RECT_T src_rect;  // in 16.16 units
+   VC_RECT_T dest_rect; // in 32.0 units
+} BUF_MSG_REMOTE_FUNCTION_FRAME_T;
+
+typedef struct {
+   int32_t status;
+   int32_t total_stripes;
+   // normal stipe height and size
+   int32_t stripe_height, stripe_size;
+   // last stripe size (if height not a mulitple of stripe height, last stripe nay be smaller)
+   int32_t last_stripe_height, last_stripe_size;
+} BUF_MSG_RESPONSE_T;
+
+typedef struct
+{
+   uint32_t stream;
+   uint32_t num_of_buffers;
+   buf_frame_type_t type;
+   uint32_t width;
+   uint32_t height;
+} BUF_MSG_ALLOC_BUF_FRAME_T;
+
+typedef struct
+{
+   uint32_t stream;
+   uint32_t num_of_buffers;
+} BUF_MSG_FREE_BUF_FRAME_T;
+
+typedef struct {
+   BUF_MSG_HDR_T hdr;
+   union {
+      BUF_MSG_REMOTE_FUNCTION_FRAME_T frame;
+      BUF_MSG_RESPONSE_T message_response;
+      BUF_MSG_ALLOC_BUF_FRAME_T alloc_buf_frame;
+      BUF_MSG_FREE_BUF_FRAME_T free_buf_frame;
+   } u;
+} BUF_MSG_T;
+
+enum {
+   //host to videocore
+   VC_BUFMAN_ERROR_NONE = 0,
+   VC_BUFMAN_ERROR_BAD_GENERALLY = -1,
+   VC_BUFMAN_ERROR_BAD_RESOURCE = -2,
+   VC_BUFMAN_ERROR_BAD_TRANSFORM = -3,
+   VC_BUFMAN_ERROR_BAD_RESIZE = -4,
+   VC_BUFMAN_ERROR_BAD_HOST_FORMAT = -5,
+   VC_BUFMAN_ERROR_BAD_VC_FORMAT = -6,
+   VC_BUFMAN_ERROR_BAD_SIZE = -7,
+};
+
+#ifdef __SYMBIAN32__
+} // namespace BufManX
+#endif
+
+#endif /* VC_VCHI_BUFMAN_DEFS_H */
diff --git a/interface/vmcs_host/vc_vchi_cecservice.c b/interface/vmcs_host/vc_vchi_cecservice.c
new file mode 100755 (executable)
index 0000000..616b5b4
--- /dev/null
@@ -0,0 +1,1365 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <string.h>
+#include <stdio.h>
+#include "vchost_platform_config.h"
+#include "vchost.h"
+
+#include "interface/vcos/vcos.h"
+#include "interface/vchi/vchi.h"
+#include "interface/vchi/common/endian.h"
+#include "interface/vchi/message_drivers/message.h"
+#include "vc_cecservice.h"
+#include "vc_service_common.h"
+
+/******************************************************************************
+Local types and defines.
+******************************************************************************/
+#ifndef _min
+#define _min(x,y) (((x) <= (y))? (x) : (y))
+#endif
+#ifndef _max
+#define _max(x,y) (((x) >= (y))? (x) : (y))
+#endif
+
+//TV service host side state (mostly the same as Videocore side - TVSERVICE_STATE_T)
+typedef struct {
+   //Generic service stuff
+   VCHI_SERVICE_HANDLE_T client_handle[VCHI_MAX_NUM_CONNECTIONS]; //To connect to server on VC
+   VCHI_SERVICE_HANDLE_T notify_handle[VCHI_MAX_NUM_CONNECTIONS]; //For incoming notification
+   uint32_t              msg_flag[VCHI_MAX_NUM_CONNECTIONS];
+   char                  command_buffer[CECSERVICE_MSGFIFO_SIZE];
+   char                  response_buffer[CECSERVICE_MSGFIFO_SIZE];
+   uint32_t              response_length;
+   uint32_t              notify_buffer[CECSERVICE_MSGFIFO_SIZE/sizeof(uint32_t)];
+   uint32_t              notify_length;
+   uint32_t              num_connections;
+   VCOS_MUTEX_T          lock;
+   CECSERVICE_CALLBACK_T notify_fn;
+   void                 *notify_data;
+   int                   initialised;
+   int                   to_exit;
+
+   //CEC state, not much here
+   //Most things live on Videocore side
+   uint16_t               physical_address; //16-bit packed physical address
+   CEC_DEVICE_TYPE_T      logical_address;  //logical address
+   VC_CEC_TOPOLOGY_T     *topology; //16-byte aligned for the transfer
+
+} CECSERVICE_HOST_STATE_T;
+
+/******************************************************************************
+Static data.
+******************************************************************************/
+static CECSERVICE_HOST_STATE_T cecservice_client;
+static VCOS_EVENT_T cecservice_message_available_event;
+static VCOS_EVENT_T cecservice_notify_available_event;
+static VCOS_THREAD_T cecservice_notify_task;
+static uint32_t cecservice_log_initialised = 0;
+
+//Command strings - must match what's in vc_cecservice_defs.h
+static char* cecservice_command_strings[] = {
+   "register_cmd",
+   "register_all",
+   "deregister_cmd",
+   "deregister_all",
+   "send_msg",
+   "get_logical_addr",
+   "alloc_logical_addr",
+   "release_logical_addr",
+   "get_topology",
+   "set_vendor_id",
+   "set_osd_name",
+   "get_physical_addr",
+   "get_vendor_id",
+   "poll_addr",
+   "set_logical_addr",
+   "add_device",
+   "set_passive",
+   "end_of_list"
+};
+
+static const uint32_t max_command_strings = sizeof(cecservice_command_strings)/sizeof(char *);
+
+//Notification strings - must match vc_cec.h VC_CEC_NOTIFY_T
+static char* cecservice_notify_strings[] = {
+   "none",
+   "TX",
+   "RX",
+   "User Ctrl Pressed",
+   "User Ctrl Released",
+   "Vendor Remote Down",
+   "Vendor Remote Up",
+   "logical address",
+   "topology",
+   "logical address lost",
+   "???"
+};
+
+static const uint32_t max_notify_strings = sizeof(cecservice_notify_strings)/sizeof(char *);
+
+//Device type strings
+static char* cecservice_devicetype_strings[] = {
+   "TV", 
+   "Rec",
+   "Reserved",
+   "Tuner",
+   "Playback",
+   "Audio",
+   "Switch",
+   "VidProc",
+   "8", "9", "10", "11", "12", "13", "14", "invalid"
+};
+
+static const uint32_t max_devicetype_strings = sizeof(cecservice_devicetype_strings)/sizeof(char *);
+
+/******************************************************************************
+Static functions.
+******************************************************************************/
+//Lock the host state
+static __inline int lock_obtain (void) {
+   VCOS_STATUS_T status = VCOS_EAGAIN;
+   if(cecservice_client.initialised && (status = vcos_mutex_lock(&cecservice_client.lock)) == VCOS_SUCCESS) {
+      if(cecservice_client.initialised) { // check service hasn't been closed while we were waiting for the lock.
+         vchi_service_use(cecservice_client.client_handle[0]);
+         return status;
+      } else {
+         vcos_mutex_unlock(&cecservice_client.lock);
+         vc_cec_log_error("CEC Service closed while waiting for lock");
+         return VCOS_EAGAIN;
+      }
+   }
+   vc_cec_log_error("CEC service failed to obtain lock, initialised:%d, lock status:%d", 
+                    cecservice_client.initialised, status);
+   return status;
+}
+
+//Unlock the host state
+static __inline void lock_release (void) {
+   if(cecservice_client.initialised) {
+      vchi_service_release(cecservice_client.client_handle[0]);
+   }
+   vcos_mutex_unlock(&cecservice_client.lock);
+}
+
+//Forward declarations
+static void cecservice_client_callback( void *callback_param,
+                                       VCHI_CALLBACK_REASON_T reason,
+                                       void *msg_handle );
+
+static void cecservice_notify_callback( void *callback_param,
+                                      VCHI_CALLBACK_REASON_T reason,
+                                      void *msg_handle );
+
+static int32_t cecservice_wait_for_reply(void *response, uint32_t max_length);
+
+static int32_t cecservice_wait_for_bulk_receive(void *buffer, uint32_t max_length);
+
+static int32_t cecservice_send_command( uint32_t command, const void *buffer, uint32_t length, uint32_t has_reply);
+
+static int32_t cecservice_send_command_reply( uint32_t command, void *buffer, uint32_t length,
+                                              void *response, uint32_t max_length);
+
+static void *cecservice_notify_func(void *arg);
+
+static void cecservice_logging_init(void);
+
+/******************************************************************************
+ Global data
+*****************************************************************************/
+VCOS_LOG_CAT_T cechost_log_category;
+
+/******************************************************************************
+CEC service API
+******************************************************************************/
+/******************************************************************************
+NAME
+   vc_vchi_cec_init
+
+SYNOPSIS
+  void vc_vchi_cec_init(VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections )
+
+FUNCTION
+  Initialise the CEC service for use.  A negative return value
+   indicates failure (which may mean it has not been started on VideoCore).
+
+RETURNS
+   int
+******************************************************************************/
+VCHPRE_ void VCHPOST_ vc_vchi_cec_init(VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections ) {
+   int32_t success = -1;
+   VCOS_STATUS_T status;
+   VCOS_THREAD_ATTR_T attrs;
+   uint32_t i;
+
+   if (cecservice_client.initialised)
+     return;
+
+   vc_cec_log_info("Initialising CEC service");
+   // record the number of connections
+   vcos_memset( &cecservice_client, 0, sizeof(CECSERVICE_HOST_STATE_T) );
+   cecservice_client.num_connections = num_connections;
+   cecservice_client.physical_address = CEC_CLEAR_ADDR;
+   cecservice_client.logical_address = CEC_AllDevices_eUnRegistered;
+
+   status = vcos_mutex_create(&cecservice_client.lock, "HCEC");
+   vcos_assert(status == VCOS_SUCCESS);
+   status = vcos_event_create(&cecservice_message_available_event, "HCEC");
+   vcos_assert(status == VCOS_SUCCESS);
+   status = vcos_event_create(&cecservice_notify_available_event, "HCEC");
+   vcos_assert(status == VCOS_SUCCESS);
+
+   cecservice_client.topology = vcos_malloc_aligned(sizeof(VC_CEC_TOPOLOGY_T), 16, "HCEC topology");
+   vcos_assert(cecservice_client.topology);
+
+   for (i=0; i < cecservice_client.num_connections; i++) {
+   
+      // Create a 'Client' service on the each of the connections
+      SERVICE_CREATION_T cecservice_parameters = { VCHI_VERSION(VC_CECSERVICE_VER),
+                                                   CECSERVICE_CLIENT_NAME,     // 4cc service code
+                                                   connections[i],             // passed in fn ptrs
+                                                   0,                          // tx fifo size (unused)
+                                                   0,                          // tx fifo size (unused)
+                                                   &cecservice_client_callback,// service callback
+                                                   &cecservice_message_available_event,  // callback parameter
+                                                   VC_FALSE,                   // want_unaligned_bulk_rx
+                                                   VC_FALSE,                   // want_unaligned_bulk_tx
+                                                   VC_FALSE,                   // want_crc
+      };
+
+      SERVICE_CREATION_T cecservice_parameters2 = { VCHI_VERSION(VC_CECSERVICE_VER),
+                                                    CECSERVICE_NOTIFY_NAME,    // 4cc service code
+                                                    connections[i],            // passed in fn ptrs
+                                                    0,                         // tx fifo size (unused)
+                                                    0,                         // tx fifo size (unused)
+                                                    &cecservice_notify_callback,// service callback
+                                                    &cecservice_notify_available_event,  // callback parameter
+                                                    VC_FALSE,                  // want_unaligned_bulk_rx
+                                                    VC_FALSE,                  // want_unaligned_bulk_tx
+                                                    VC_FALSE,                  // want_crc
+      };
+
+      //Create the client to normal CEC service 
+      success = vchi_service_open( initialise_instance, &cecservice_parameters, &cecservice_client.client_handle[i] );
+      vcos_assert( success == 0 );
+      if(success)
+         vc_cec_log_error("Failed to connected to CEC service: %d", success);
+
+      //Create the client to the async CEC service (any CEC related notifications)
+      success = vchi_service_open( initialise_instance, &cecservice_parameters2, &cecservice_client.notify_handle[i] );
+      vcos_assert( success == 0 );
+
+      if(success)
+         vc_cec_log_error("Failed to connected to CEC async service: %d", success);
+
+      vchi_service_release(cecservice_client.client_handle[i]);
+      vchi_service_release(cecservice_client.notify_handle[i]);
+   }
+
+   //Create the notifier task
+   vcos_thread_attr_init(&attrs);
+   vcos_thread_attr_setstacksize(&attrs, 2048);
+   vcos_thread_attr_settimeslice(&attrs, 1);
+
+   //Initialise logging
+   cecservice_logging_init();
+
+   status = vcos_thread_create(&cecservice_notify_task, "HCEC Notify", &attrs, cecservice_notify_func, &cecservice_client);
+   vcos_assert(status == VCOS_SUCCESS);
+
+   cecservice_client.initialised = 1;
+   vc_cec_log_info("CEC service initialised");
+}
+
+/***********************************************************
+ * Name: vc_vchi_cec_stop
+ *
+ * Arguments:
+ *       -
+ *
+ * Description: Stops the Host side part of CEC service
+ *
+ * Returns: -
+ *
+ ***********************************************************/
+VCHPRE_ void VCHPOST_ vc_vchi_cec_stop( void ) {
+   // Wait for the current lock-holder to finish before zapping TV service
+   uint32_t i;
+
+   if (!cecservice_client.initialised)
+      return;
+
+   if(lock_obtain() == 0)
+   {
+      void *dummy;
+      vchi_service_release(cecservice_client.client_handle[0]);
+      vc_cec_log_info("Stopping CEC service");
+      for (i=0; i < cecservice_client.num_connections; i++) {
+         int32_t result;
+         vchi_service_use(cecservice_client.client_handle[i]);
+         vchi_service_use(cecservice_client.notify_handle[i]);
+         result = vchi_service_close(cecservice_client.client_handle[i]);
+         vcos_assert( result == 0 );
+         result = vchi_service_close(cecservice_client.notify_handle[i]);
+         vcos_assert( result == 0 );
+      }
+      cecservice_client.initialised = 0;
+
+      lock_release();
+      cecservice_client.to_exit = 1;
+      vcos_event_signal(&cecservice_notify_available_event);
+      vcos_thread_join(&cecservice_notify_task, &dummy);
+      vcos_mutex_delete(&cecservice_client.lock);
+      vcos_event_delete(&cecservice_message_available_event);
+      vcos_event_delete(&cecservice_notify_available_event);
+      vcos_free(cecservice_client.topology);
+      vc_cec_log_info("CEC service stopped");
+   }
+}
+
+/***********************************************************
+ * Name: vc_cec_register_callaback
+ *
+ * Arguments:
+ *       callback function, context to be passed when function is called
+ *
+ * Description: Register a callback function for all CEC notifications
+ *
+ * Returns: -
+ *
+ ***********************************************************/
+VCHPRE_ void VCHPOST_ vc_cec_register_callback(CECSERVICE_CALLBACK_T callback, void *callback_data) {
+   if(lock_obtain() == 0){
+      cecservice_client.notify_fn   = callback;
+      cecservice_client.notify_data = callback_data;
+      vc_cec_log_info("CEC service registered callback 0x%x", (uint32_t) callback);
+      lock_release();
+   } else {
+      vc_cec_log_error("CEC service registered callback 0x%x failed", (uint32_t) callback);
+   }
+}
+
+/*********************************************************************************
+ *
+ *  Static functions definitions
+ *
+ *********************************************************************************/
+//TODO: Might need to handle multiple connections later
+/***********************************************************
+ * Name: cecservice_client_callback
+ *
+ * Arguments: semaphore, callback reason and message handle
+ *
+ * Description: Callback when a message is available for CEC service
+ *
+ ***********************************************************/
+static void cecservice_client_callback( void *callback_param,
+                                        const VCHI_CALLBACK_REASON_T reason,
+                                        void *msg_handle ) {
+
+   VCOS_EVENT_T *event = (VCOS_EVENT_T *)callback_param;
+
+   if ( reason != VCHI_CALLBACK_MSG_AVAILABLE || event == NULL)
+      return;
+
+   vcos_event_signal(event);
+}
+
+/***********************************************************
+ * Name: cecservice_notify_callback
+ *
+ * Arguments: semaphore, callback reason and message handle
+ *
+ * Description: Callback when a message is available for CEC notify service
+ *
+ ***********************************************************/
+static void cecservice_notify_callback( void *callback_param,
+                                        const VCHI_CALLBACK_REASON_T reason,
+                                        void *msg_handle ) {
+   VCOS_EVENT_T *event = (VCOS_EVENT_T *)callback_param;
+
+   if ( reason != VCHI_CALLBACK_MSG_AVAILABLE || event == NULL)
+      return;
+
+   vcos_event_signal(event);
+}
+
+/***********************************************************
+ * Name: cecservice_wait_for_reply
+ *
+ * Arguments: response buffer, buffer length
+ *
+ * Description: blocked until something is in the buffer
+ *
+ * Returns zero if successful or error code of vchi otherwise (see vc_service_common_defs.h)
+ *         If success, response is updated
+ *
+ ***********************************************************/
+static int32_t cecservice_wait_for_reply(void *response, uint32_t max_length) {
+   int32_t success = 0;
+   uint32_t length_read = 0;
+   do {
+      //TODO : we need to deal with messages coming through on more than one connections properly
+      //At the moment it will always try to read the first connection if there is something there
+      //Check if there is something in the queue, if so return immediately
+      //otherwise wait for the semaphore and read again
+      success = (int32_t) vchi2service_status(vchi_msg_dequeue( cecservice_client.client_handle[0], response, max_length, &length_read, VCHI_FLAGS_NONE ));
+   } while( length_read == 0 && vcos_event_wait(&cecservice_message_available_event) == VCOS_SUCCESS);
+   if(length_read) {
+      vc_cec_log_info("CEC service got reply %d bytes", length_read);
+   } else {
+      vc_cec_log_warn("CEC service wait for reply failed, error: %s",
+                      vchi2service_status_string(success));
+   }
+   
+   return success;
+}
+
+/***********************************************************
+ * Name: cecservice_wait_for_bulk_receive
+ *
+ * Arguments: response buffer, buffer length
+ *
+ * Description: blocked until bulk receive
+ *
+ * Returns error code of vchi
+ *
+ ***********************************************************/
+static int32_t cecservice_wait_for_bulk_receive(void *buffer, uint32_t max_length) {
+   if(!vcos_verify(buffer)) { 
+      vc_cec_log_error("CEC: NULL buffer passed to wait_for_bulk_receive");
+      return -1;
+   }
+   return (int32_t) vchi2service_status(vchi_bulk_queue_receive( cecservice_client.client_handle[0],
+                                                                 buffer,
+                                                                 max_length,
+                                                                 VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE,
+                                                                 NULL ));
+}
+
+/***********************************************************
+ * Name: cecservice_send_command
+ *
+ * Arguments: command, parameter buffer, parameter legnth, has reply? (non-zero means yes)
+ *
+ * Description: send a command and optionally wait for its single value response (TV_GENERAL_RESP_T)
+ *
+ * Returns: < 0 if there is VCHI error, if tranmission is successful, value
+ *          returned is the response from CEC server (which will be VC_CEC_ERROR_T (>= 0))
+ *
+ ***********************************************************/
+
+static int32_t cecservice_send_command(  uint32_t command, const void *buffer, uint32_t length, uint32_t has_reply) {
+   VCHI_MSG_VECTOR_T vector[] = { {&command, sizeof(command)},
+                                  {buffer, length} };
+   int32_t success = 0;
+   int32_t response = -1;
+   vc_cec_log_info("CEC sending command %s length %d %s", 
+                   cecservice_command_strings[command], length, 
+                   (has_reply)? "has reply" : " no reply");
+   if(lock_obtain() == 0)
+   {
+      success =  (int32_t) vchi2service_status(vchi_msg_queuev(cecservice_client.client_handle[0],
+                                                               vector, sizeof(vector)/sizeof(vector[0]),
+                                                               VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL ));
+      if(success == VC_SERVICE_VCHI_SUCCESS && has_reply) {
+         //otherwise only wait for a reply if we ask for one
+         success = cecservice_wait_for_reply(&response, sizeof(response));
+         if(success == VC_SERVICE_VCHI_SUCCESS) {
+            response = VC_VTOH32(response);
+         } else {
+            response = success;
+         }
+      } else {
+         if(success != VC_SERVICE_VCHI_SUCCESS)
+            vc_cec_log_error("CEC failed to send command %s length %d, error: %s",
+                             cecservice_command_strings[command], length, 
+                             vchi2service_status_string(success));
+         //No reply expected or failed to send, send the success code back instead
+         response = success;
+      }
+      lock_release();
+   }
+   return response;
+}
+
+/***********************************************************
+ * Name: cecservice_send_command_reply
+ *
+ * Arguments: command, parameter buffer, parameter legnth, reply buffer, buffer length
+ *
+ * Description: send a command and wait for its non-single value response (in a buffer)
+ *
+ * Returns: error code, host app is responsible to do endian translation
+ *
+ ***********************************************************/
+static int32_t cecservice_send_command_reply(  uint32_t command, void *buffer, uint32_t length,
+                                               void *response, uint32_t max_length) {
+   VCHI_MSG_VECTOR_T vector[] = { {&command, sizeof(command)},
+                                  {buffer, length} };
+   int32_t success = VC_SERVICE_VCHI_VCHIQ_ERROR, ret = 0;
+
+   vc_cec_log_info("CEC sending command (with reply) %s length %d", 
+                   cecservice_command_strings[command], length); 
+   if(lock_obtain() == 0)
+   {
+      if((ret = vchi_msg_queuev( cecservice_client.client_handle[0],
+                                 vector, sizeof(vector)/sizeof(vector[0]),
+                                 VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL )) ==  VC_SERVICE_VCHI_SUCCESS) {
+         success = cecservice_wait_for_reply(response, max_length);
+      } else {
+         vc_cec_log_error("CEC failed to send command %s length %d, error code %d",
+                          cecservice_command_strings[command], length, ret);
+      }
+      lock_release();
+   }
+   return success;
+}
+
+/***********************************************************
+ * Name: cecservice_notify_func
+ *
+ * Arguments: CEC service state
+ *
+ * Description: This is the notification task which receives all CEC
+ *              service notifications
+ *
+ * Returns: does not return
+ *
+ ***********************************************************/
+static void *cecservice_notify_func(void *arg) {
+   int32_t success;
+   CECSERVICE_HOST_STATE_T *state = (CECSERVICE_HOST_STATE_T *) arg;
+
+   vc_cec_log_info("CEC service async thread started");
+   while(1) {
+      VCOS_STATUS_T status = vcos_event_wait(&cecservice_notify_available_event);
+      uint32_t cb_reason_str_idx = max_notify_strings - 1;
+      if(status != VCOS_SUCCESS || !state->initialised || state->to_exit)
+         break;
+
+      do {
+         uint32_t reason, param1, param2, param3, param4;
+         //Get all notifications in the queue
+         success = vchi_msg_dequeue( state->notify_handle[0], state->notify_buffer, sizeof(state->notify_buffer), &state->notify_length, VCHI_FLAGS_NONE );
+         if(success != 0 || state->notify_length < sizeof(uint32_t)*5 ) { //reason + 4x32-bit parameter
+            vcos_assert(state->notify_length == sizeof(uint32_t)*5);
+            break;
+         }
+
+         //if(lock_obtain() != 0)
+         //   break;
+         //All notifications are of format: reason, param1, param2, param3, param4 (all 32-bit unsigned int)
+         reason = VC_VTOH32(state->notify_buffer[0]);
+         param1 = VC_VTOH32(state->notify_buffer[1]);
+         param2 = VC_VTOH32(state->notify_buffer[2]);
+         param3 = VC_VTOH32(state->notify_buffer[3]);
+         param4 = VC_VTOH32(state->notify_buffer[4]);
+         //lock_release();
+
+         //Store away physical/logical addresses
+         if(CEC_CB_REASON(reason) == VC_CEC_LOGICAL_ADDR) {
+            state->logical_address = (CEC_DEVICE_TYPE_T) param1;
+            state->physical_address = (uint16_t) (param2 & 0xFFFF);
+         }
+         
+         switch(CEC_CB_REASON(reason)) {
+         case VC_CEC_NOTIFY_NONE:
+            cb_reason_str_idx = 0; break;
+         case VC_CEC_TX:
+            cb_reason_str_idx = 1; break;
+         case VC_CEC_RX:
+            cb_reason_str_idx = 2; break;
+         case VC_CEC_BUTTON_PRESSED:
+            cb_reason_str_idx = 3; break;
+         case VC_CEC_BUTTON_RELEASE:
+            cb_reason_str_idx = 4; break;
+         case VC_CEC_REMOTE_PRESSED:
+            cb_reason_str_idx = 5; break;
+         case VC_CEC_REMOTE_RELEASE:
+            cb_reason_str_idx = 6; break;
+         case VC_CEC_LOGICAL_ADDR:
+            cb_reason_str_idx = 7; break;
+         case VC_CEC_TOPOLOGY:
+            cb_reason_str_idx = 8; break;
+         case VC_CEC_LOGICAL_ADDR_LOST:
+            cb_reason_str_idx = 9; break;
+         }
+
+         vc_cec_log_info("CEC service callback [%s]: 0x%x, 0x%x, 0x%x, 0x%x",
+                         cecservice_notify_strings[cb_reason_str_idx], param1, param2, param3, param4);
+
+         if(state->notify_fn) {
+            (*state->notify_fn)(state->notify_data, reason, param1, param2, param3, param4);
+         } else {
+            vc_cec_log_info("CEC service: No callback handler specified, callback [%s] swallowed",
+                            cecservice_notify_strings[cb_reason_str_idx]);
+         }
+
+      } while(success == 0 && state->notify_length >= sizeof(uint32_t)*5); //read the next message if any
+   } //while (1)
+
+   if(state->to_exit)
+      vc_cec_log_info("CEC service async thread exiting");
+
+   return 0;
+}
+
+/***********************************************************
+ * Name: cecservice_logging_init
+ *
+ * Arguments: None
+ *
+ * Description: Initialise VCOS logging
+ *
+ * Returns: -
+ *
+ ***********************************************************/
+static void cecservice_logging_init() {
+   if(cecservice_log_initialised == 0) {
+      vcos_log_set_level(&cechost_log_category, VCOS_LOG_WARN);
+      vcos_log_register("cecservice-client", &cechost_log_category);
+      vc_cec_log_info("CEC HOST: log initialised");
+      cecservice_log_initialised = 1;
+   }
+}
+
+
+/***********************************************************
+ Actual CEC service API starts here
+***********************************************************/
+/***********************************************************
+ * Name: vc_cec_register_command (deprecated)
+ *
+ * Arguments:
+ *
+ * Description
+ *
+ * Returns: zero
+ ***********************************************************/
+VCHPRE_ int VCOS_DEPRECATED("has no effect") VCHPOST_ vc_cec_register_command(CEC_OPCODE_T opcode) {
+   return 0;
+}
+
+/***********************************************************
+ * Name: vc_cec_register_all (deprecated)
+ *
+ * Arguments:
+ *
+ * Description
+ *
+ * Returns: zero
+ ***********************************************************/
+VCHPRE_ int VCOS_DEPRECATED("has no effect") VCHPOST_ vc_cec_register_all( void ) {
+    return 0;
+}
+
+/***********************************************************
+ * Name: vc_cec_deregister_command (deprecated)
+ *
+ * Arguments:
+ *
+ * Description
+ *
+ * Returns: zero
+ ***********************************************************/
+VCHPRE_ int VCOS_DEPRECATED("has no effect") VCHPOST_ vc_cec_deregister_command(CEC_OPCODE_T opcode) {
+   return 0;
+}
+
+/***********************************************************
+ * Name: vc_cec_deregister_all (deprecated)
+ *
+ * Arguments:
+ *
+ * Description
+ *
+ * Returns: zero
+ ***********************************************************/
+VCHPRE_ int VCOS_DEPRECATED("has no effect") VCHPOST_ vc_cec_deregister_all( void ) {
+    return 0;
+}
+
+/***********************************************************
+ * Name: vc_cec_send_message
+ *
+ * Arguments:
+ *       Follower's logical address
+ *       Message payload WITHOUT the header byte (can be NULL)
+ *       Payload length WITHOUT the header byte (can be zero)
+ *       VC_TRUE if the message is a reply to an incoming message
+ *       (For poll message set payload to NULL and length to zero)
+ *
+ * Description
+ *       Remove all commands to be forwarded. This does not affect
+ *       the button presses which are always forwarded
+ *
+ * Returns: if the command is successful (zero) or not (non-zero)
+ *          If the command is successful, there will be a Tx callback
+ *          in due course to indicate whether the message has been
+ *          acknowledged by the recipient or not
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_send_message(const uint32_t follower,
+                                         const uint8_t *payload,
+                                         uint32_t length,
+                                         vcos_bool_t is_reply) {
+   int success = -1;  
+   CEC_SEND_MSG_PARAM_T param;
+   if(!vcos_verify(length <= CEC_MAX_XMIT_LENGTH))
+      return -1;
+
+   param.follower = VC_HTOV32(follower);
+   param.length = VC_HTOV32(length);
+   param.is_reply = VC_HTOV32(is_reply);
+   vcos_memset(param.payload, 0, sizeof(param.payload));
+   vc_cec_log_info("CEC service sending CEC message (%d->%d) (0x%02X) length %d%s",
+                   cecservice_client.logical_address, follower,
+                   (payload)? payload[0] : 0xFF, length, (is_reply)? " as reply" : "");
+
+   if(length > 0 && vcos_verify(payload)) {
+      char s[96] = {0}, *p = &s[0];
+      int i;
+      vcos_memcpy(param.payload, payload, _min(length, CEC_MAX_XMIT_LENGTH));
+      p += sprintf(p, "0x%02X",  (cecservice_client.logical_address << 4) | (follower & 0xF));
+      for(i = 0; i < _min(length, CEC_MAX_XMIT_LENGTH); i++) {
+         p += sprintf(p, " %02X", payload[i]);
+      }
+      vc_cec_log_info("CEC message: %s", s);
+   }
+
+   success = cecservice_send_command( VC_CEC_SEND_MSG, &param, sizeof(param), 1);
+   return success;
+}
+
+/***********************************************************
+ * Name: vc_cec_get_logical_address
+ *
+ * Arguments:
+ *       pointer to logical address
+ *
+ * Description
+ *       Get the logical address, if one is being allocated
+ *       0xF (unregistered) will be returned
+ *
+ * Returns: if the command is successful (zero) or not (non-zero)
+ *          logical_address is not modified if command failed
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_get_logical_address(CEC_AllDevices_T *logical_address) {
+   uint32_t response;
+   int32_t success = cecservice_send_command_reply( VC_CEC_GET_LOGICAL_ADDR, NULL, 0, 
+                                                    &response, sizeof(response));
+   if(success == 0) {
+      *logical_address = (CEC_AllDevices_T)(VC_VTOH32(response) & 0xF);
+      vc_cec_log_info("CEC got logical address %d", *logical_address);
+   }
+   return success;
+}
+
+/***********************************************************
+ * Name: vc_cec_alloc_logical_address
+ *
+ * Arguments:
+ *       None
+ *
+ * Description
+ *       Start the allocation of a logical address. The host only
+ *       needs to call this if the initial allocation failed
+ *       (logical address being 0xF and physical address is NOT 0xFFFF
+ *        from VC_CEC_LOGICAL_ADDR notification), or if the host explicitly
+ *       released its logical address.
+ * 
+ * Returns: if the command is successful (zero) or not (non-zero)
+ *         If successful, there will be a callback notification
+ *         VC_CEC_LOGICAL_ADDR. The host should wait for this before
+ *         calling this function again.
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_alloc_logical_address( void ) {
+   return cecservice_send_command( VC_CEC_ALLOC_LOGICAL_ADDR, NULL, 0, 0);
+}
+
+/***********************************************************
+ * Name: vc_cec_release_logical_address
+ *
+ * Arguments:
+ *       None
+ *
+ * Description
+ *       Release our logical address. This effectively disables CEC.
+ *       The host will need to allocate a new logical address before
+ *       doing any CEC calls (send/receive message, get topology, etc.). 
+ *
+ * Returns: if the command is successful (zero) or not (non-zero)
+ *         The host should get a callback VC_CEC_LOGICAL_ADDR with
+ *         0xF being the logical address and the current physical address.
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_release_logical_address( void ) {
+   return cecservice_send_command( VC_CEC_RELEASE_LOGICAL_ADDR, NULL, 0, 0);
+}
+
+/***********************************************************
+ * Name: vc_cec_get_topology (deprecated)
+ *
+ * Arguments:
+ *
+ * Description
+ *
+ * Returns: if the command is successful (zero) or not (non-zero)
+ *
+ ***********************************************************/
+VCHPRE_ int VCOS_DEPRECATED("returns invalid result") VCHPOST_ vc_cec_get_topology( VC_CEC_TOPOLOGY_T* topology) {
+   int32_t success = -1;
+   vchi_service_use(cecservice_client.client_handle[0]);
+   success = cecservice_send_command( VC_CEC_GET_TOPOLOGY, NULL, 0, 1);
+   if(success == 0) {
+      success = cecservice_wait_for_bulk_receive(cecservice_client.topology, sizeof(VC_CEC_TOPOLOGY_T));
+   }
+   vchi_service_release(cecservice_client.client_handle[0]);
+   if(success == 0) {
+      int i;
+      cecservice_client.topology->active_mask = VC_VTOH16(cecservice_client.topology->active_mask);
+      cecservice_client.topology->num_devices = VC_VTOH16(cecservice_client.topology->num_devices);
+      vc_cec_log_info("CEC topology: mask=0x%x; #device=%d",
+                      cecservice_client.topology->active_mask, 
+                      cecservice_client.topology->num_devices);
+      for(i = 0; i < 15; i++) {
+         cecservice_client.topology->device_attr[i] = VC_VTOH32(cecservice_client.topology->device_attr[i]);
+      }
+      vcos_memcpy(topology, cecservice_client.topology, sizeof(VC_CEC_TOPOLOGY_T));
+   }
+   return success;
+}
+
+/***********************************************************
+ * Name: vc_cec_set_vendor_id
+ *
+ * Arguments:
+ *       24-bit IEEE vendor id
+ *
+ * Description
+ *       Set the response to <Give Device Vendor ID>
+ *
+ * Returns: if the command is successful (zero) or not (non-zero)
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_set_vendor_id( uint32_t id ) {
+   uint32_t vendor_id = VC_HTOV32(id);
+   vc_cec_log_info("CEC setting vendor id to 0x%x", vendor_id);
+   return cecservice_send_command( VC_CEC_SET_VENDOR_ID, &vendor_id, sizeof(vendor_id), 0);
+}
+
+/***********************************************************
+ * Name: vc_cec_set_osd_name
+ *
+ * Arguments:
+ *       OSD name (14 byte array)
+ *
+ * Description
+ *       Set the response to <Give OSD Name>
+ *
+ * Returns: if the command is successful (zero) or not (non-zero)
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_set_osd_name( const char* name ) {
+   vc_cec_log_info("CEC setting OSD name to %s", name);
+   return cecservice_send_command( VC_CEC_SET_OSD_NAME, name, OSD_NAME_LENGTH, 0); 
+}
+
+/***********************************************************
+ * Name: vc_cec_get_physical_address
+ *
+ * Arguments:
+ *       pointer to physical address (returned as 16-bit packed value)
+ *
+ * Description
+ *       Get the physical address
+ *
+ * Returns: if the command is successful (zero) or not (non-zero)
+ *          If failed, physical address argument will not be changed
+ *          A physical address of 0xFFFF means CEC is not supported
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_get_physical_address(uint16_t *physical_address) {
+   uint32_t response;
+   int32_t success = cecservice_send_command_reply( VC_CEC_GET_PHYSICAL_ADDR, NULL, 0, 
+                                                    &response, sizeof(response));
+   if(success == 0) {
+      *physical_address = (uint16_t)(VC_VTOH32(response) & 0xFFFF);
+      vc_cec_log_info("CEC got physical address: %d.%d.%d.%d",
+                      (*physical_address >> 12), (*physical_address >> 8) & 0xF,
+                      (*physical_address >> 4) & 0xF, (*physical_address) & 0xF);
+   }
+   return success;
+}
+
+
+/***********************************************************
+ * Name: vc_cec_get_vendor_id
+ *
+ * Arguments:
+ *       logical address [in]
+ *       pointer to 24-bit IEEE vendor id [out]
+ *
+ * Description
+ *       Get the vendor ID of the device with the said logical address
+ *       Application should send <Give Device Vendor ID> if vendor ID
+ *       is not known (and register opcode <Device Vendor ID>)
+ *
+ * Returns: if the command is successful (zero) or not (non-zero)
+ *          vendor ID is set to zero if unknown or 0xFFFFFF if
+ *          device does not exist. 
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_get_vendor_id( const CEC_AllDevices_T logical_address, uint32_t *vendor_id) {
+   uint32_t log_addr = VC_HTOV32(logical_address);
+   uint32_t response;
+   int32_t success = cecservice_send_command_reply( VC_CEC_GET_VENDOR_ID, &log_addr, sizeof(log_addr), 
+                                                    &response, sizeof(response));
+   if(success == 0) {
+      vcos_assert(vendor_id);
+      *vendor_id = VC_VTOH32(response);
+      vc_cec_log_info("CEC got vendor id 0x%X", *vendor_id);
+   }
+   return success;
+}
+/***********************************************************
+ * Name: vc_cec_device_type
+ *
+ * Arguments:
+ *       logical address [in]
+ *
+ * Description
+ *       Get the default device type of a logical address
+ *       Logical address 12 to 14 cannot be used
+ *
+ * Returns: For logical addresses 0-11 the default
+ *          device type of that address will be returned
+ *          logical address 12-14 will return "reserved" type.
+ *          
+ ***********************************************************/
+VCHPRE_ CEC_DEVICE_TYPE_T VCHPOST_ vc_cec_device_type(const CEC_AllDevices_T logical_address) {
+   CEC_DEVICE_TYPE_T device_type = CEC_DeviceType_Invalid;
+   switch(logical_address) {
+   case CEC_AllDevices_eSTB1:
+   case CEC_AllDevices_eSTB2:
+   case CEC_AllDevices_eSTB3:
+   case CEC_AllDevices_eSTB4:
+      device_type = CEC_DeviceType_Tuner;
+      break;
+   case CEC_AllDevices_eDVD1:
+   case CEC_AllDevices_eDVD2:
+   case CEC_AllDevices_eDVD3:
+      device_type = CEC_DeviceType_Playback;
+      break;
+   case CEC_AllDevices_eRec1:
+   case CEC_AllDevices_eRec2:
+   case CEC_AllDevices_eRec3:
+      device_type = CEC_DeviceType_Rec;
+      break;
+   case CEC_AllDevices_eAudioSystem:
+      device_type = CEC_DeviceType_Audio;
+      break;
+   case CEC_AllDevices_eTV:
+      device_type = CEC_DeviceType_TV;
+      break;
+   case CEC_AllDevices_eRsvd3:
+   case CEC_AllDevices_eRsvd4:
+   case CEC_AllDevices_eFreeUse:
+      device_type = CEC_DeviceType_Reserved; //XXX: Are we allowed to use this?
+      break;
+   default:
+      vcos_assert(0); //Invalid
+      break;
+   }
+   return device_type;
+}
+
+/***********************************************************
+ * Name: vc_cec_send_message2 
+ *
+ * Arguments:
+ *       pointer to encapsulated message
+ *
+ * Description
+ *       Call vc_cec_send_message above
+ *       messages are always sent as non-reply
+ *
+ * Returns: if the command is successful (zero) or not (non-zero)
+ *          If the command is successful, there will be a Tx callback
+ *          in due course to indicate whether the message has been
+ *          acknowledged by the recipient or not
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_send_message2(const VC_CEC_MESSAGE_T *message) {
+   if(vcos_verify(message)) {
+      return vc_cec_send_message(message->follower,
+                                 (message->length)? 
+                                 message->payload : NULL,
+                                 message->length,
+                                 VC_FALSE);
+   } else {
+      return -1;
+   }
+}
+
+/***********************************************************
+ * Name: vc_cec_param2message
+ *
+ * Arguments:
+ *       arguments from CEC callback (reason, param1 to param4)
+ *       pointer to VC_CEC_MESSAGE_T
+ *
+ * Description
+ *       Turn the CEC_TX/CEC_RX/BUTTON_PRESS/BUTTON_RELEASE
+ *       callback parameters back into an encapsulated form
+ *
+ * Returns: zero normally
+ *          non-zero if something has gone wrong
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_param2message( const uint32_t reason, const uint32_t param1, 
+                                           const uint32_t param2, const uint32_t param3,
+                                           const uint32_t param4, VC_CEC_MESSAGE_T *message) {
+   if(vcos_verify(message && 
+                  CEC_CB_REASON(reason) != VC_CEC_LOGICAL_ADDR &&
+                  CEC_CB_REASON(reason) != VC_CEC_TOPOLOGY)) {
+      message->length = CEC_CB_MSG_LENGTH(reason) - 1; //Length is without the header byte
+      message->initiator = CEC_CB_INITIATOR(param1);
+      message->follower = CEC_CB_FOLLOWER(param1);
+      if(message->length) {
+         uint32_t tmp = param1 >> 8;
+         vcos_memcpy(message->payload, &tmp, sizeof(uint32_t)-1);
+         vcos_memcpy(message->payload+sizeof(uint32_t)-1, &param2, sizeof(uint32_t));
+         vcos_memcpy(message->payload+sizeof(uint32_t)*2-1, &param3, sizeof(uint32_t));
+         vcos_memcpy(message->payload+sizeof(uint32_t)*3-1, &param4, sizeof(uint32_t));
+      } else {
+         vcos_memset(message->payload, 0, sizeof(message->payload));
+      }
+      return 0;
+   } else {
+      return -1;
+   }
+}
+
+//Extra API if CEC is running in passive mode
+
+/***********************************************************
+ * Name: vc_cec_poll_address
+ *
+ * Arguments:
+ *       logical address to try
+ *
+ * Description
+ *       Sets and polls a particular address to find out
+ *       its availability in the CEC network. Only available 
+ *       when CEC is running in passive mode. The host can 
+ *       only call this function during logical address allocation stage.
+ *
+ * Returns: 0 if poll is successful (address is occupied)
+ *         >0 if poll is unsuccessful (address is free if error code is VC_CEC_ERROR_NO_ACK)
+ *         <0 other (VCHI) errors
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_poll_address(const CEC_AllDevices_T logical_address) {
+   uint32_t log_addr = VC_HTOV32(logical_address);
+   int32_t response =  VC_CEC_ERROR_INVALID_ARGUMENT;
+   int32_t success = -1;
+   vc_cec_log_info("CEC polling address %d", logical_address);
+   success = cecservice_send_command_reply( VC_CEC_POLL_ADDR, &log_addr, sizeof(log_addr), 
+                                                    &response, sizeof(response));
+   return (success == 0)? response : success;
+}
+
+/***********************************************************
+ * Name: vc_cec_set_logical_address
+ *
+ * Arguments:
+ *       logical address, device type, vendor id
+ *
+ * Description
+ *       sets the logical address, device type and vendor ID to be in use. 
+ *       Only available when CEC is running in passive mode. It is the 
+ *       responsibility of the host to make sure the logical address
+ *       is actually free (see vc_cec_poll_address). Physical address used
+ *       will be what is read from EDID and cannot be set.
+ *
+ * Returns: 0 if successful, non-zero otherwise
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_set_logical_address(const CEC_AllDevices_T logical_address,
+                                                const CEC_DEVICE_TYPE_T device_type,
+                                                const uint32_t vendor_id) {
+   CEC_SET_LOGICAL_ADDR_PARAM_T param = {VC_HTOV32(logical_address),
+                                         VC_HTOV32(device_type),
+                                         VC_HTOV32(vendor_id)};
+   int32_t response = VC_CEC_ERROR_INVALID_ARGUMENT;
+   int32_t success = VC_CEC_ERROR_INVALID_ARGUMENT;
+   if(vcos_verify(logical_address <= CEC_AllDevices_eUnRegistered &&
+                  (device_type <= CEC_DeviceType_VidProc ||
+                   device_type == CEC_DeviceType_Invalid))) {
+      vc_cec_log_info("CEC setting logical address to %d; device type %s; vendor 0x%X", 
+                      logical_address,
+                      cecservice_devicetype_strings[device_type], vendor_id );
+      success = cecservice_send_command_reply( VC_CEC_SET_LOGICAL_ADDR, &param, sizeof(param), 
+                                               &response, sizeof(response));
+   } else {
+      vc_cec_log_error("CEC invalid arguments for set_logical_address");
+   }
+   return (success == 0)? response : success;
+}
+
+/***********************************************************
+ * Name: vc_cec_add_device (deprecated)
+ *
+ * Arguments:
+ *
+ * Description
+ *
+ * Returns: 0 if successful, non-zero otherwise
+ ***********************************************************/
+VCHPRE_ int  VCOS_DEPRECATED("has no effect") VCHPOST_ vc_cec_add_device(const CEC_AllDevices_T logical_address,
+                                       const uint16_t physical_address,
+                                       const CEC_DEVICE_TYPE_T device_type,
+                                       vcos_bool_t last_device) {
+   CEC_ADD_DEVICE_PARAM_T param = {VC_HTOV32(logical_address),
+                                   VC_HTOV32(physical_address),
+                                   VC_HTOV32(device_type),
+                                   VC_HTOV32(last_device)};
+   int32_t response =  VC_CEC_ERROR_INVALID_ARGUMENT;
+   int32_t success = VC_CEC_ERROR_INVALID_ARGUMENT;
+   if(vcos_verify(logical_address <= CEC_AllDevices_eUnRegistered &&
+                  (device_type <= CEC_DeviceType_VidProc ||
+                   device_type == CEC_DeviceType_Invalid))) {
+      vc_cec_log_info("CEC adding device %d (0x%X); device type %s", 
+                      logical_address, physical_address,
+                      cecservice_devicetype_strings[device_type]);
+      success = cecservice_send_command_reply( VC_CEC_ADD_DEVICE, &param, sizeof(param), 
+                                               &response, sizeof(response));
+   } else {
+      vc_cec_log_error("CEC invalid arguments for add_device");
+   }
+   return (success == 0)? response : success;
+}
+
+/***********************************************************
+ * Name: vc_cec_set_passive
+ *
+ * Arguments:
+ *       Enable/disable (TRUE to enable/ FALSE to disable)
+ *
+ * Description
+ * Enable / disable CEC passive mode
+ *
+ * Returns: 0 if successful, non-zero otherwise
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_set_passive(vcos_bool_t enabled) {
+   uint32_t param = VC_HTOV32(enabled);
+   int32_t response;
+   int32_t success = cecservice_send_command_reply( VC_CEC_SET_PASSIVE, &param, sizeof(param), 
+                                                    &response, sizeof(response));
+   return (success == 0)? response : success;
+}
+
+/***********************************************************
+ API for some common CEC messages, uses the API above to 
+ actually send the message
+***********************************************************/
+
+/***********************************************************
+ * Name: vc_cec_send_FeatureAbort
+ *
+ * Arguments:
+ *       follower, rejected opcode, reject reason, reply or not
+ *
+ * Description
+ *       send <Feature Abort> for a received command
+ *
+ * Returns: if the command is successful (zero) or not (non-zero)
+ *          Tx callback if successful
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_send_FeatureAbort(uint32_t follower, 
+                                              CEC_OPCODE_T opcode, 
+                                              CEC_ABORT_REASON_T reason) { 
+   uint8_t tx_buf[3];
+   tx_buf[0] = CEC_Opcode_FeatureAbort;    // <Feature Abort>
+   tx_buf[1] = opcode;
+   tx_buf[2] = reason;
+   return vc_cec_send_message(follower,
+                              tx_buf,
+                              sizeof(tx_buf),
+                              VC_TRUE);
+}
+
+/***********************************************************
+ * Name: vc_cec_send_ActiveSource
+ *
+ * Arguments:
+ *       physical address, reply or not
+ *
+ * Description
+ *       send <Active Source> 
+ *
+ * Returns: if the command is successful (zero) or not (non-zero)
+ *          Tx callback if successful
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_send_ActiveSource(uint16_t physical_address, 
+                                              vcos_bool_t is_reply) {
+   uint8_t tx_buf[3];
+   tx_buf[0] = CEC_Opcode_ActiveSource;    // <Active Source>
+   tx_buf[1] = physical_address >> 8;      // physical address msb
+   tx_buf[2] = physical_address & 0x00FF;  // physical address lsb
+   return vc_cec_send_message(CEC_BROADCAST_ADDR, // This is a broadcast only message
+                              tx_buf,
+                              sizeof(tx_buf),
+                              is_reply);
+}
+
+/***********************************************************
+ * Name: vc_cec_send_ImageViewOn
+ *
+ * Arguments:
+ *       follower, reply or not
+ * Description
+ *       send <Image View On> 
+ *
+ * Returns: if the command is successful (zero) or not (non-zero)
+ *          Tx callback if successful
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_send_ImageViewOn(uint32_t follower, 
+                                             vcos_bool_t is_reply) {
+   uint8_t tx_buf[1];
+   tx_buf[0] = CEC_Opcode_ImageViewOn;      // <Image View On> no param required
+   return vc_cec_send_message(follower,
+                              tx_buf,
+                              sizeof(tx_buf),
+                              is_reply);
+}
+
+/***********************************************************
+ * Name: vc_cec_send_SetOSDString
+ *
+ * Arguments:
+ *       follower, display control, string (char[13]), reply or not
+ *
+ * Description
+ *       send <Image View On> 
+ *
+ * Returns: if the command is successful (zero) or not (non-zero)
+ *          Tx callback if successful
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_send_SetOSDString(uint32_t follower, 
+                                              CEC_DISPLAY_CONTROL_T disp_ctrl,                               
+                                              const char* string,
+                                              vcos_bool_t is_reply) {
+   uint8_t tx_buf[CEC_MAX_XMIT_LENGTH];
+   tx_buf[0] = CEC_Opcode_SetOSDString;     // <Set OSD String>
+   tx_buf[1] = disp_ctrl;
+   vcos_memset(&tx_buf[2], 0, sizeof(tx_buf)-2);
+   vcos_memcpy(&tx_buf[2], string, _min(strlen(string), CEC_MAX_XMIT_LENGTH-2));
+   return vc_cec_send_message(follower,
+                              tx_buf,
+                              sizeof(tx_buf),
+                              is_reply);
+}
+
+/***********************************************************
+ * Name: vc_cec_send_Standby
+ *
+ * Arguments:
+ *       follower, reply or not
+ *
+ * Description
+ *       send <Standby>. Turn other devices to standby 
+ *
+ * Returns: if the command is successful (zero) or not (non-zero)
+ *          Tx callback if successful
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_send_Standby(uint32_t follower, vcos_bool_t is_reply) {
+   uint8_t tx_buf[1];
+   tx_buf[0] = CEC_Opcode_Standby;           // <Standby>
+   return vc_cec_send_message(follower,
+                              tx_buf,
+                              sizeof(tx_buf),
+                              is_reply);
+}
+
+/***********************************************************
+ * Name: vc_cec_send_MenuStatus
+ *
+ * Arguments:
+ *       follower, menu state, reply or not
+ *
+ * Description
+ *       send <Menu Status> (response to <Menu Request>)
+ *       menu state is either CEC_MENU_STATE_ACTIVATED or CEC_MENU_STATE_DEACTIVATED
+ *
+ * Returns: if the command is successful (zero) or not (non-zero)
+ *          Tx callback if successful
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_send_MenuStatus(uint32_t follower, 
+                                            CEC_MENU_STATE_T menu_state, 
+                                            vcos_bool_t is_reply) {
+   uint8_t tx_buf[2];
+   if(!vcos_verify(menu_state < CEC_MENU_STATE_QUERY))
+      return -1;
+
+   tx_buf[0] = CEC_Opcode_MenuStatus;        // <Menu Status>
+   tx_buf[1] = menu_state;
+   return vc_cec_send_message(follower,
+                              tx_buf,
+                              sizeof(tx_buf),
+                              is_reply);
+}
+
+/***********************************************************
+ * Name: vc_cec_send_ReportPhysicalAddress
+ *
+ * Arguments:
+ *       physical address, device type, reply or not
+ *
+ * Description
+ *       send <Report Physical Address> (first command to be 
+ *       sent after a successful logical address allocation
+ *       device type should be the appropriate one for
+ *       the allocated logical address
+ *
+ * Returns: if the command is successful (zero) or not (non-zero)
+ *          Tx callback if successful. We also get a failure
+ *          if we do not currently have a valid physical address
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_cec_send_ReportPhysicalAddress(uint16_t physical_address, 
+                                                       CEC_DEVICE_TYPE_T device_type,
+                                                       vcos_bool_t is_reply) {
+   uint8_t tx_buf[4];
+   if(vcos_verify(physical_address == cecservice_client.physical_address &&
+                  cecservice_client.physical_address != CEC_CLEAR_ADDR)) {
+      tx_buf[0] = CEC_Opcode_ReportPhysicalAddress;
+      tx_buf[1] = physical_address >> 8;       // physical address msb
+      tx_buf[2] = physical_address & 0x00FF;   // physical address lsb
+      tx_buf[3] = device_type;                 // 'device type'
+      return vc_cec_send_message(CEC_BROADCAST_ADDR, // This is a broadcast only message
+                                 tx_buf,
+                                 sizeof(tx_buf),
+                                 is_reply);
+   } else {
+      //Current we do not allow sending a random physical address
+      vc_cec_log_error("CEC cannot send physical address 0x%X, does not match internal 0x%X", 
+                       physical_address, cecservice_client.physical_address);
+      return VC_CEC_ERROR_NO_PA; 
+   }
+}
diff --git a/interface/vmcs_host/vc_vchi_dispmanx.c b/interface/vmcs_host/vc_vchi_dispmanx.c
new file mode 100755 (executable)
index 0000000..7a6cdcd
--- /dev/null
@@ -0,0 +1,1321 @@
+/*
+Copyright (c) 2012-2014, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <string.h>
+#include <stdlib.h>
+
+#include "vchost_platform_config.h"
+#include "vchost.h"
+
+#include "interface/vcos/vcos.h"
+#include "vc_dispservice_x_defs.h"
+#include "vc_dispmanx.h"
+#include "interface/vchi/vchi.h"
+#include "vcinclude/common.h"
+#include "interface/vchi/common/endian.h"
+#include "interface/vchi/message_drivers/message.h"
+#include "vc_vchi_dispmanx.h"
+/******************************************************************************
+Local types and defines.
+******************************************************************************/
+//DispmanX service
+typedef struct {
+   VCHI_SERVICE_HANDLE_T client_handle[VCHI_MAX_NUM_CONNECTIONS]; //To connect to server on VC
+   VCHI_SERVICE_HANDLE_T notify_handle[VCHI_MAX_NUM_CONNECTIONS]; //For incoming notification
+   uint32_t              msg_flag[VCHI_MAX_NUM_CONNECTIONS];
+   char                  command_buffer[DISPMANX_MSGFIFO_SIZE];
+   char                  response_buffer[DISPMANX_MSGFIFO_SIZE];
+   uint32_t              response_length;
+   uint32_t              notify_buffer[DISPMANX_MSGFIFO_SIZE/sizeof(uint32_t)];
+   uint32_t              notify_length;
+   uint32_t              num_connections;
+   VCOS_MUTEX_T          lock;
+   char dispmanx_devices[DISPMANX_MAX_HOST_DEVICES][DISPMANX_MAX_DEVICE_NAME_LEN];
+   uint32_t num_devices;
+   uint32_t num_modes[DISPMANX_MAX_HOST_DEVICES];
+
+   //Callback for update
+   DISPMANX_CALLBACK_FUNC_T update_callback;
+   void *update_callback_param;
+   DISPMANX_UPDATE_HANDLE_T pending_update_handle;
+
+   //Callback for vsync
+   DISPMANX_CALLBACK_FUNC_T vsync_callback;
+   void *vsync_callback_param;
+   int vsync_enabled;
+
+   int initialised;
+} DISPMANX_SERVICE_T;
+
+/******************************************************************************
+Static data.
+******************************************************************************/
+static DISPMANX_SERVICE_T dispmanx_client;
+static VCOS_EVENT_T dispmanx_message_available_event;
+static VCOS_EVENT_T dispmanx_notify_available_event;
+static VCOS_THREAD_T dispmanx_notify_task;
+
+/******************************************************************************
+Static functions.
+******************************************************************************/
+//Lock the host state
+static __inline void lock_obtain (void) {
+   VCOS_STATUS_T status;
+   uint32_t i;
+   vcos_assert(dispmanx_client.initialised);
+   status = vcos_mutex_lock( &dispmanx_client.lock );
+   if(dispmanx_client.initialised)
+   {
+      for (i=0; i<dispmanx_client.num_connections; i++) {
+         vchi_service_use(dispmanx_client.client_handle[i]);
+      }
+   }
+   vcos_assert(status == VCOS_SUCCESS);
+}
+
+//Unlock the host state
+static __inline void lock_release (void) {
+   uint32_t i;
+   vcos_assert(dispmanx_client.initialised);
+   if(dispmanx_client.initialised)
+   {
+      for (i=0; i<dispmanx_client.num_connections; i++) {
+         vchi_service_release(dispmanx_client.client_handle[i]);
+      }
+   }
+   vcos_mutex_unlock( &dispmanx_client.lock );
+}
+
+//Forward declarations
+static void dispmanx_client_callback( void *callback_param,
+                                      VCHI_CALLBACK_REASON_T reason,
+                                      void *msg_handle );
+
+static void dispmanx_notify_callback( void *callback_param,
+                                      VCHI_CALLBACK_REASON_T reason,
+                                      void *msg_handle );
+
+static int32_t dispmanx_wait_for_reply(void *response, uint32_t max_length);
+
+static int32_t dispmanx_send_command(  uint32_t command, void *buffer, uint32_t length);
+
+static int32_t dispmanx_send_command_reply(  uint32_t command, void *buffer, uint32_t length,
+                                        void *response, uint32_t max_length);
+
+static uint32_t dispmanx_get_handle(  uint32_t command, void *buffer, uint32_t length);
+
+static void *dispmanx_notify_func( void *arg );
+
+
+/******************************************************************************
+NAME
+   vc_vchi_gencmd_init
+
+SYNOPSIS
+   void vc_vchi_gencmd_init(VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections )
+
+FUNCTION
+   Initialise the general command service for use. A negative return value
+   indicates failure (which may mean it has not been started on VideoCore).
+
+RETURNS
+   int
+******************************************************************************/
+
+void vc_vchi_dispmanx_init (VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections ) {
+   VCOS_STATUS_T status;
+   int32_t success;
+   uint32_t i;
+
+   if (dispmanx_client.initialised)
+     return;
+
+   // record the number of connections
+   memset( &dispmanx_client, 0, sizeof(DISPMANX_SERVICE_T) );
+   dispmanx_client.num_connections = num_connections;
+
+   status = vcos_mutex_create(&dispmanx_client.lock, "HDispmanx");
+   vcos_assert(status == VCOS_SUCCESS);
+
+   status = vcos_event_create(&dispmanx_message_available_event, "HDispmanx");
+   vcos_assert(status == VCOS_SUCCESS);
+
+   status = vcos_event_create(&dispmanx_notify_available_event, "HDispmanx");
+   vcos_assert(status == VCOS_SUCCESS);
+
+   dispmanx_client.initialised = 1;
+
+   for (i=0; i<dispmanx_client.num_connections; i++) {
+
+      VCOS_THREAD_ATTR_T attrs;
+
+      // Create a 'Client' service on the each of the connections
+      SERVICE_CREATION_T dispmanx_parameters = { VCHI_VERSION(VC_DISPMANX_VERSION),
+                                                 DISPMANX_CLIENT_NAME,     // 4cc service code
+                                                 connections[i],           // passed in fn ptrs
+                                                 0,                        // tx fifo size (unused)
+                                                 0,                        // tx fifo size (unused)
+                                                 &dispmanx_client_callback, // service callback
+                                                 &dispmanx_message_available_event,  // callback parameter
+                                                 VC_FALSE,                  // want_unaligned_bulk_rx
+                                                 VC_FALSE,                  // want_unaligned_bulk_tx
+                                                 VC_FALSE,                  // want_crc
+                                                 };
+
+      SERVICE_CREATION_T dispmanx_parameters2 = { VCHI_VERSION(VC_DISPMANX_VERSION),
+                                                  DISPMANX_NOTIFY_NAME,   // 4cc service code
+                                                  connections[i],           // passed in fn ptrs
+                                                  0,                        // tx fifo size (unused)
+                                                  0,                        // tx fifo size (unused)
+                                                  &dispmanx_notify_callback, // service callback
+                                                  &dispmanx_notify_available_event,  // callback parameter
+                                                  VC_FALSE,                  // want_unaligned_bulk_rx
+                                                  VC_FALSE,                  // want_unaligned_bulk_tx
+                                                  VC_FALSE,                  // want_crc
+                                                   };
+
+      success = vchi_service_open( initialise_instance, &dispmanx_parameters, &dispmanx_client.client_handle[i] );
+      vcos_assert( success == 0 );
+
+      // Create the async service of dispman to handle update callback
+
+      success = vchi_service_open( initialise_instance, &dispmanx_parameters2, &dispmanx_client.notify_handle[i] );
+      vcos_assert( success == 0 );
+
+      //Create the notifier task
+      vcos_thread_attr_init(&attrs);
+      vcos_thread_attr_setstacksize(&attrs, 2048);
+      vcos_thread_attr_settimeslice(&attrs, 1);
+
+      status = vcos_thread_create(&dispmanx_notify_task, "HDispmanx Notify", &attrs, dispmanx_notify_func, NULL);
+      vcos_assert(status == VCOS_SUCCESS);
+
+      // release services until they're actually used
+      vchi_service_release(dispmanx_client.client_handle[i]);
+      vchi_service_release(dispmanx_client.notify_handle[i]);
+   }
+}
+
+/***********************************************************
+ * Name: vc_dispmanx_stop
+ *
+ * Arguments:
+ *       -
+ *
+ * Description: Stops the Host side part of dispmanx
+ *
+ * Returns: -
+ *
+ ***********************************************************/
+VCHPRE_ void VCHPOST_ vc_dispmanx_stop( void ) {
+   // Wait for the current lock-holder to finish before zapping dispmanx.
+   //TODO: kill the notifier task
+   void *dummy;
+   uint32_t i;
+
+   if (!dispmanx_client.initialised)
+      return;
+
+   lock_obtain();
+   for (i=0; i<dispmanx_client.num_connections; i++) {
+      int32_t result;
+      result = vchi_service_close(dispmanx_client.client_handle[i]);
+      vcos_assert( result == 0 );
+      result = vchi_service_close(dispmanx_client.notify_handle[i]);
+      vcos_assert( result == 0 );
+   }
+   lock_release();
+   dispmanx_client.initialised = 0;
+
+   vcos_event_signal(&dispmanx_notify_available_event); 
+   vcos_thread_join(&dispmanx_notify_task, &dummy);
+   vcos_mutex_delete(&dispmanx_client.lock);
+   vcos_event_delete(&dispmanx_message_available_event);
+   vcos_event_delete(&dispmanx_notify_available_event);
+}
+
+/***********************************************************
+ * Name: vc_dispmanx_rect_set
+ *
+ * Arguments:
+ *       VC_RECT_T *rect
+ *       uint32_t x_offset
+ *       uint32_t y_offset
+ *       uint32_t width
+ *       uint32_t height
+ *
+ * Description: Fills in the fields of the supplied VC_RECT_T structure
+ *
+ * Returns: 0 or failure
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_dispmanx_rect_set( VC_RECT_T *rect, uint32_t x_offset, uint32_t y_offset, uint32_t width, uint32_t height ) {
+   rect->x = (int32_t) x_offset;
+   rect->y = (int32_t) y_offset;
+   rect->width = (int32_t) width;
+   rect->height = (int32_t) height;
+   return 0;
+}
+
+/******************************************************************************
+NAME
+   vc_dispmanx_query_image_formats
+
+PARAMS
+   uint32_t *support_formats - the returned supported image formats
+
+FUNCTION
+   Returns the support image formats from the VMCS host
+
+RETURNS
+   Success: 0
+   Otherwise non-zero
+******************************************************************************/
+VCHPRE_ int  VCHPOST_ vc_dispmanx_query_image_formats( uint32_t *supported_formats ) {
+   *supported_formats = dispmanx_get_handle(EDispmanQueryImageFormats, NULL, 0);
+   return (*supported_formats)? 0 : -1;
+}
+
+/***********************************************************
+ * Name: vc_dispmanx_resource_create
+ *
+ * Arguments:
+ *       VC_IMAGE_TYPE_T type
+ *       uint32_t width
+ *       uint32_t height
+ *
+ * Description: Create a new resource (in Videocore memory)
+ *
+ * Returns: resource handle
+ *
+ ***********************************************************/
+VCHPRE_ DISPMANX_RESOURCE_HANDLE_T VCHPOST_ vc_dispmanx_resource_create( VC_IMAGE_TYPE_T type, uint32_t width, uint32_t height, uint32_t *native_image_handle ) {
+   uint32_t resourceCreateParams[] = { (uint32_t)VC_HTOV32(type), VC_HTOV32(width), VC_HTOV32(height) };
+
+   uint32_t resource = 0;
+
+   resource = dispmanx_get_handle(EDispmanResourceCreate, resourceCreateParams, sizeof(resourceCreateParams));
+
+   //We don't get an image handle back, so explicitly set this to zero to let the caller know
+   *native_image_handle = 0;
+   //The caller should call vc_dispmanx_resource_get_image_handle below to get the VC_IMAGE_T *
+   //This will be deprecated soon, however
+
+   return (DISPMANX_RESOURCE_HANDLE_T) resource;
+}
+
+/***********************************************************
+ * Name: vc_dispmanx_resource_get_image_handle
+ *
+ * Arguments: resource handle
+ *
+ * Description: xxx only for hacking purpose, will be obsolete soon
+ *
+ * Returns: vc_image pointer
+ *
+ ***********************************************************/
+VCHPRE_ uint32_t VCHPOST_ vc_dispmanx_resource_get_image_handle( DISPMANX_RESOURCE_HANDLE_T res) {
+   return dispmanx_get_handle(EDispmanResourceGetImage, &res, sizeof(res));
+}
+
+/***********************************************************
+ * Name: vc_dispmanx_resource_delete
+ *
+ * Arguments:
+ *       DISPMANX_RESOURCE_HANDLE_T res
+ *
+ * Description:
+ *
+ * Returns: 0 or failure
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_dispmanx_resource_delete( DISPMANX_RESOURCE_HANDLE_T res ) {
+   int status;
+   res = VC_HTOV32(res);
+   //We block to make sure the memory is freed after the call
+   status = (int) dispmanx_send_command(EDispmanResourceDelete, &res, sizeof(res));
+
+   return status;
+}
+
+/***********************************************************
+ * Name: vc_dispmanx_resource_write_data
+ *
+ * Arguments:
+ *       DISPMANX_RESOURCE_HANDLE_T res
+ *       int src_pitch
+ *       void * src_address
+ *       const VC_RECT_T * rect
+ *
+ * Description: Copy the bitmap data to VideoCore memory
+ *
+ * Returns: 0 or failure
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_dispmanx_resource_write_data( DISPMANX_RESOURCE_HANDLE_T handle, VC_IMAGE_TYPE_T src_type /* not used */,
+                                                      int src_pitch, void * src_address, const VC_RECT_T * rect ) {
+       (void)src_type;
+
+   //Note that x coordinate of the rect is NOT used
+   //Address of data in host
+   uint8_t *host_start = (uint8_t *)src_address + src_pitch * rect->y;
+   int32_t bulk_len = src_pitch * rect->height, success = 0;
+
+   //Now send the bulk transfer across
+   //command parameters: resource handle, destination y, bulk length
+   uint32_t param[] = {VC_HTOV32(handle), VC_HTOV32(rect->y), VC_HTOV32(bulk_len), VC_HTOV32(src_type) };
+   success = dispmanx_send_command(  EDispmanBulkWrite | DISPMANX_NO_REPLY_MASK, param, sizeof(param));
+   if(success == 0)
+   {
+      lock_obtain();
+      success = vchi_bulk_queue_transmit( dispmanx_client.client_handle[0],
+                                          host_start,
+                                          bulk_len,
+                                          VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
+                                          NULL );
+      lock_release();
+   }
+   return (int) success;
+}
+/***********************************************************
+ * Name: vc_dispmanx_resource_read_data
+ *
+ * Arguments:
+ *       DISPMANX_RESOURCE_HANDLE_T res
+ *       int src_pitch
+ *       void * src_address
+ *       const VC_RECT_T * rect
+ *
+ * Description: Copy the bitmap data from VideoCore memory
+ *
+ * Returns: 0 or failure
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_
+vc_dispmanx_resource_read_data(
+   DISPMANX_RESOURCE_HANDLE_T handle,
+   const VC_RECT_T* p_rect,
+   void *   dst_address,
+   uint32_t dst_pitch )
+{
+   uint8_t* host_start;
+   int32_t  bulk_len;
+   int32_t  success = 0;
+
+   if ( p_rect == 0 || dst_address == 0 || dst_pitch == 0 )
+   {
+      return -1;
+   }
+
+   host_start = (uint8_t *)dst_address + (dst_pitch * p_rect->y);
+   bulk_len   = (int32_t)dst_pitch * p_rect->height;
+
+   // Now send the bulk transfer across
+   // command parameters: resource handle, destination y, bulk length
+   uint32_t param[] = { VC_HTOV32(handle), VC_HTOV32(p_rect->y), VC_HTOV32(bulk_len) };
+   success = dispmanx_send_command( EDispmanBulkRead | DISPMANX_NO_REPLY_MASK, param, sizeof(param));
+   if (success == 0)
+   {
+      lock_obtain();
+      success = vchi_bulk_queue_receive(  dispmanx_client.client_handle[0],
+                                          host_start,
+                                          bulk_len,
+                                          VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE,
+                                          0 );
+      lock_release();
+   }
+   return (int) success;
+}
+
+/***********************************************************
+ * Name: vc_dispmanx_resource_write_data_handle
+ *
+ * Arguments:
+ *       DISPMANX_RESOURCE_HANDLE_T res
+ *       int src_pitch
+ *       MEM_HANDLE_T handle
+ *       uint32_t offset
+ *       const VC_RECT_T * rect
+ *
+ * Description: Copy the bitmap data to VideoCore memory
+ *
+ * Returns: 0 or failure
+ *
+ ***********************************************************/
+#ifdef SELF_HOSTED
+VCHPRE_ int VCHPOST_ vc_dispmanx_resource_write_data_handle( DISPMANX_RESOURCE_HANDLE_T handle, VC_IMAGE_TYPE_T src_type /* not used */,
+                                                             int src_pitch, VCHI_MEM_HANDLE_T mem_handle, uint32_t offset,
+                                                             const VC_RECT_T * rect ) {
+   int32_t bulk_len;
+   uint32_t param[3];
+   uint32_t success = 0;
+
+   //Note that x coordinate of the rect is NOT used
+   //Address of data in host
+   offset += src_pitch * rect->y;
+   bulk_len = src_pitch * rect->height;
+
+   //Now send the bulk transfer across
+   //command parameters: resource handle, destination y, bulk length
+   param[0] = VC_HTOV32(handle);
+   param[1] = VC_HTOV32(rect->y);
+   param[2] = VC_HTOV32(bulk_len);
+   success = dispmanx_send_command(  EDispmanBulkWrite | DISPMANX_NO_REPLY_MASK, param, sizeof(param));
+   if(success == 0)
+   {
+      lock_obtain();
+      success = vchi_bulk_queue_transmit_reloc( dispmanx_client.client_handle[0],
+                                                mem_handle, offset,
+                                                bulk_len,
+                                                VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
+                                                NULL );
+      lock_release();
+   }
+   return (int) success;
+}
+#endif
+
+/***********************************************************
+ * Name: vc_dispmanx_display_open
+ *
+ * Arguments:
+ *       uint32_t device
+ *
+ * Description:
+ *
+ * Returns:
+ *
+ ***********************************************************/
+VCHPRE_ DISPMANX_DISPLAY_HANDLE_T VCHPOST_ vc_dispmanx_display_open( uint32_t device ) {
+   uint32_t display_handle;
+   char *env = getenv("VC_DISPLAY");
+
+   if (device == 0 && env)
+   {
+      device = atoi(env);
+   }
+
+   device = VC_HTOV32(device);
+   display_handle = dispmanx_get_handle(EDispmanDisplayOpen,
+                                                 &device, sizeof(device));
+
+   return (DISPMANX_DISPLAY_HANDLE_T) display_handle;
+}
+
+/***********************************************************
+ * Name: vc_dispmanx_display_open_mode
+ *
+ * Arguments:
+ *       uint32_t device
+ *       uint32_t mode
+ *
+ * Description:
+ *
+ * Returns:
+ *
+ ***********************************************************/
+VCHPRE_ DISPMANX_DISPLAY_HANDLE_T VCHPOST_ vc_dispmanx_display_open_mode( uint32_t device, uint32_t mode ) {
+   uint32_t display_open_param[] = {VC_HTOV32(device), VC_HTOV32(mode)};
+   uint32_t display_handle = dispmanx_get_handle(EDispmanDisplayOpenMode,
+                                                 &display_open_param, sizeof(display_open_param));
+
+   return (DISPMANX_DISPLAY_HANDLE_T) display_handle;
+}
+
+/***********************************************************
+ * Name: vc_dispmanx_display_open_offscreen
+ *
+ * Arguments:
+ *       DISPMANX_RESOURCE_HANDLE_T dest
+ *       DISPMANX_TRANSFORM_T orientation
+ *
+ * Description:
+ *
+ * Returns:
+ *
+ ***********************************************************/
+VCHPRE_ DISPMANX_DISPLAY_HANDLE_T VCHPOST_ vc_dispmanx_display_open_offscreen( DISPMANX_RESOURCE_HANDLE_T dest, DISPMANX_TRANSFORM_T orientation ) {
+   uint32_t display_open_param[] = {(uint32_t)VC_HTOV32(dest), (uint32_t)VC_HTOV32(orientation)};
+   uint32_t display_handle = dispmanx_get_handle(EDispmanDisplayOpenOffscreen,
+                                                 &display_open_param, sizeof(display_open_param));
+
+   return (DISPMANX_DISPLAY_HANDLE_T) display_handle;
+}
+
+/***********************************************************
+ * Name: vc_dispmanx_display_reconfigure
+ *
+ * Arguments:
+ *       DISPMANX_DISPLAY_HANDLE_T display
+ *       uint32_t mode
+ *
+ * Description:
+ *
+ * Returns:
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_dispmanx_display_reconfigure( DISPMANX_DISPLAY_HANDLE_T device, uint32_t mode ) {
+   uint32_t display_param[] = {(uint32_t)VC_HTOV32(device), VC_HTOV32(mode)};
+   int32_t success = dispmanx_send_command(  EDispmanDisplayReconfigure | DISPMANX_NO_REPLY_MASK,
+                                             display_param, sizeof(display_param));
+   return (int) success;
+}
+
+/***********************************************************
+ * Name: vc_dispmanx_display_set_destination
+ *
+ * Arguments:
+ *       DISPMANX_DISPLAY_HANDLE_T display
+ *       DISPMANX_RESOURCE_HANDLE_T dest
+ *
+ * Description:
+ *
+ * Returns:
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_dispmanx_display_set_destination( DISPMANX_DISPLAY_HANDLE_T display, DISPMANX_RESOURCE_HANDLE_T dest ) {
+   uint32_t display_param[] = {(uint32_t)VC_HTOV32(display), (uint32_t)VC_HTOV32(dest)};
+   int32_t success = dispmanx_send_command(  EDispmanDisplaySetDestination | DISPMANX_NO_REPLY_MASK,
+                                             display_param, sizeof(display_param));
+   return (int) success;
+}
+
+/***********************************************************
+ * Name: vc_dispmanx_display_set_background
+ *
+ * Arguments:
+ *       DISPMANX_UPDATE_HANDLE_T update
+ *       DISPMANX_DISPLAY_HANDLE_T display
+ *       uint8_t red
+ *       uint8_t green
+ *       uint8_t blue
+ *
+ * Description:
+ *
+ * Returns:
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_dispmanx_display_set_background( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_DISPLAY_HANDLE_T display,
+                                                                       uint8_t red, uint8_t green, uint8_t blue ) {
+   uint32_t display_param[] = {(uint32_t)VC_HTOV32(update), (uint32_t) VC_HTOV32(display), VC_HTOV32(red), VC_HTOV32(green), VC_HTOV32(blue)};
+   int success = (int) dispmanx_send_command( EDispmanDisplaySetBackground | DISPMANX_NO_REPLY_MASK,
+                                        display_param, sizeof(display_param));
+   return success;
+}
+
+/***********************************************************
+ * Name: vc_dispmanx_display_get_info
+ *
+ * Arguments:
+ *       DISPMANX_DISPLAY_HANDLE_T display
+ *       DISPMANX_MODEINFO_T * pinfo
+ *
+ * Description:
+ *
+ * Returns: VCHI error
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_
+vc_dispmanx_display_get_info (DISPMANX_DISPLAY_HANDLE_T display,
+                              DISPMANX_MODEINFO_T *pinfo)
+{
+   GET_INFO_DATA_T info;
+   int32_t success;
+   display = VC_HTOV32(display);
+   success = dispmanx_send_command_reply (EDispmanDisplayGetInfo,
+                                          &display, sizeof(display),
+                                          &info, sizeof(info));
+   if(success == 0) {
+      pinfo->width = VC_VTOH32(info.width);
+      pinfo->height = VC_VTOH32(info.height);
+      pinfo->transform = (DISPMANX_TRANSFORM_T)VC_VTOH32(info.transform);
+      pinfo->input_format = (DISPLAY_INPUT_FORMAT_T)VC_VTOH32(info.input_format);
+   }
+
+   return (int) success;
+}
+
+/***********************************************************
+ * Name: vc_dispmanx_display_close
+ *
+ * Arguments:
+ *       DISPMANX_DISPLAY_HANDLE_T display
+ *
+ * Description:
+ *
+ * Returns:
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_dispmanx_display_close( DISPMANX_DISPLAY_HANDLE_T display ) {
+   int success;
+   display = VC_HTOV32(display);
+   success = (int) dispmanx_send_command( EDispmanDisplayClose | DISPMANX_NO_REPLY_MASK,
+                                        &display, sizeof(display));
+   return success;
+}
+/***********************************************************
+ * Name: vc_dispmanx_update_start
+ *
+ * Arguments:
+ *       int32_t priority
+ *
+ * Description:
+ *
+ * Returns:
+ *
+ ***********************************************************/
+VCHPRE_ DISPMANX_UPDATE_HANDLE_T VCHPOST_ vc_dispmanx_update_start( int32_t priority ) {
+   uint32_t handle;
+   priority = VC_HTOV32(priority);
+   handle = dispmanx_get_handle(EDispmanUpdateStart,
+                                         &priority, sizeof(priority));
+
+   return (DISPMANX_UPDATE_HANDLE_T) handle;
+}
+
+
+/***********************************************************
+ * Name: vc_dispmanx_update_submit
+ *
+ * Arguments:
+ *       DISPMANX_UPDATE_HANDLE_T update
+ *       DISPMANX_CALLBACK_FUNC_T cb_func
+ *       void *cb_arg
+ *
+ * Description:
+ *
+ * Returns:
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_dispmanx_update_submit( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_CALLBACK_FUNC_T cb_func, void *cb_arg ) {
+   uint32_t update_param[] = {(uint32_t) VC_HTOV32(update), (uint32_t) ((cb_func)? VC_HTOV32(1) : 0)};
+   int success;
+
+   vcos_assert(update); // handles must be non-zero
+   if (update)
+   {
+      //Set the callback
+      dispmanx_client.update_callback = cb_func;
+      dispmanx_client.update_callback_param = cb_arg;
+      dispmanx_client.pending_update_handle = update;
+      vchi_service_use(dispmanx_client.notify_handle[0]); // corresponding release is in dispmanx_notify_func
+      success = (int) dispmanx_send_command( EDispmanUpdateSubmit | DISPMANX_NO_REPLY_MASK,
+                                             update_param, sizeof(update_param));
+   }
+   else
+   {
+      success = -1;
+   }
+   return success;
+}
+
+/***********************************************************
+ * Name: vc_dispmanx_update_submit_sync
+ *
+ * Arguments:
+ *       DISPMANX_UPDATE_HANDLE_T update
+ *
+ * Description:
+ *
+ * Returns: VCHI error code
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_dispmanx_update_submit_sync( DISPMANX_UPDATE_HANDLE_T update ) {
+   int success;
+   update = VC_HTOV32(update);
+   success = (int) dispmanx_send_command( EDispmanUpdateSubmitSync,
+                                          &update, sizeof(update));
+   return success;
+}
+
+
+/***********************************************************
+ * Name: vc_dispmanx_element_add
+ *
+ * Arguments:
+ *       DISPMANX_UPDATE_HANDLE_T update
+ *       DISPMANX_DISPLAY_HANDLE_T display
+ *       int32_t layer
+ *       const VC_RECT_T *dest_rect
+ *       DISPMANX_RESOURCE_HANDLE_T src
+ *       const VC_RECT_T *src_rect
+ *       DISPMANX_FLAGS_T flags
+ *       uint8_t opacity
+ *       DISPMANX_RESOURCE_HANDLE_T mask
+ *       DISPMANX_TRANSFORM_T transform
+ *
+ * Description:
+ *
+ * Returns: VCHI error code
+ *
+ ***********************************************************/
+VCHPRE_ DISPMANX_ELEMENT_HANDLE_T VCHPOST_ vc_dispmanx_element_add ( DISPMANX_UPDATE_HANDLE_T update,
+                                                                     DISPMANX_DISPLAY_HANDLE_T display,
+                                                                     int32_t layer,
+                                                                     const VC_RECT_T *dest_rect,
+                                                                     DISPMANX_RESOURCE_HANDLE_T src,
+                                                                     const VC_RECT_T *src_rect,
+                                                                     DISPMANX_PROTECTION_T protection,
+                                                                     VC_DISPMANX_ALPHA_T *alpha,
+                                                                     DISPMANX_CLAMP_T *clamp,
+                                                                     DISPMANX_TRANSFORM_T transform ) {
+
+   int32_t element_param[] = {
+      (int32_t) VC_HTOV32(update),
+      (int32_t) VC_HTOV32(display),
+      (int32_t) VC_HTOV32(layer),
+      (int32_t) VC_HTOV32(dest_rect->x),
+      (int32_t) VC_HTOV32(dest_rect->y),
+      (int32_t) VC_HTOV32(dest_rect->width),
+      (int32_t) VC_HTOV32(dest_rect->height),
+      (int32_t) VC_HTOV32(src),
+      (int32_t) VC_HTOV32(src_rect->x),
+      (int32_t) VC_HTOV32(src_rect->y),
+      (int32_t) VC_HTOV32(src_rect->width),
+      (int32_t) VC_HTOV32(src_rect->height),
+      (int32_t) VC_HTOV32(protection),
+      alpha ? (int32_t) VC_HTOV32(alpha->flags) : 0,
+      alpha ? (int32_t) VC_HTOV32(alpha->opacity) : 0,
+      alpha ? (int32_t) VC_HTOV32(alpha->mask) : 0,
+      clamp ? (int32_t) VC_HTOV32(clamp->mode) : 0,
+      clamp ? (int32_t) VC_HTOV32(clamp->key_mask) : 0,
+      clamp ? (int32_t) VC_HTOV32(clamp->key_value.yuv.yy_upper) : 0,
+      clamp ? (int32_t) VC_HTOV32(clamp->key_value.yuv.yy_lower) : 0,
+      clamp ? (int32_t) VC_HTOV32(clamp->key_value.yuv.cr_upper) : 0,
+      clamp ? (int32_t) VC_HTOV32(clamp->key_value.yuv.cr_lower) : 0,
+      clamp ? (int32_t) VC_HTOV32(clamp->key_value.yuv.cb_upper) : 0,
+      clamp ? (int32_t) VC_HTOV32(clamp->key_value.yuv.cb_lower) : 0,
+      clamp ? (int32_t) VC_HTOV32(clamp->replace_value) : 0,
+      (int32_t) VC_HTOV32(transform)
+   };
+
+   uint32_t handle =  dispmanx_get_handle(EDispmanElementAdd,
+                                          element_param, sizeof(element_param));
+   return (DISPMANX_ELEMENT_HANDLE_T) handle;
+}
+
+/***********************************************************
+ * Name: vc_dispmanx_element_change_source
+ *
+ * Arguments:
+ *       DISPMANX_UPDATE_HANDLE_T update
+ *       DISPMANX_ELEMENT_HANDLE_T element
+ *       DISPMANX_RESOURCE_HANDLE_T src
+ *
+ * Description:
+ *
+ * Returns: VCHI error code
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_dispmanx_element_change_source( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_ELEMENT_HANDLE_T element,
+                                                        DISPMANX_RESOURCE_HANDLE_T src ) {
+   uint32_t element_param[] = { (uint32_t) VC_HTOV32(update),
+                                (uint32_t) VC_HTOV32(element),
+                                (uint32_t) VC_HTOV32(src) };
+
+   int success = (int) dispmanx_send_command( EDispmanElementChangeSource | DISPMANX_NO_REPLY_MASK,
+                                              element_param, sizeof(element_param));
+   return success;
+
+}
+
+/***********************************************************
+ * Name: vc_dispmanx_element_change_layer
+ *
+ * Arguments:
+ *       DISPMANX_UPDATE_HANDLE_T update
+ *       DISPMANX_ELEMENT_HANDLE_T element
+ *       int32_t layer
+ *
+ * Description:
+ *
+ * Returns: VCHI error code
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_dispmanx_element_change_layer (DISPMANX_UPDATE_HANDLE_T update,
+                                                       DISPMANX_ELEMENT_HANDLE_T element,
+                                                       int32_t layer)
+{
+   uint32_t element_param[] = { (uint32_t) VC_HTOV32(update),
+                                (uint32_t) VC_HTOV32(element),
+                                (uint32_t) VC_HTOV32(layer) };
+
+   int success = (int) dispmanx_send_command( EDispmanElementChangeLayer | DISPMANX_NO_REPLY_MASK,
+                                              element_param, sizeof(element_param));
+   return success;
+
+}
+
+/***********************************************************
+ * Name: vc_dispmanx_element_modified
+ *
+ * Arguments:
+ *       DISPMANX_UPDATE_HANDLE_T update
+ *       DISPMANX_ELEMENT_HANDLE_T element
+ *       const VC_RECT_T * rect
+ *
+ * Description:
+ *
+ * Returns: VCHI error code
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_dispmanx_element_modified( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_ELEMENT_HANDLE_T element, const VC_RECT_T * rect ) {
+
+   uint32_t element_param[6] = { (uint32_t) VC_HTOV32(update),
+                                 (uint32_t) VC_HTOV32(element), 0, 0, 0, 0};
+   uint32_t param_length = 2*sizeof(uint32_t);
+   int success;
+
+   if(rect) {
+      element_param[2] = VC_HTOV32(rect->x);
+      element_param[3] = VC_HTOV32(rect->y);
+      element_param[4] = VC_HTOV32(rect->width);
+      element_param[5] = VC_HTOV32(rect->height);
+      param_length = 6*sizeof(uint32_t);
+   }
+   success = (int) dispmanx_send_command( EDispmanElementModified | DISPMANX_NO_REPLY_MASK,
+                                            element_param, param_length);
+   return success;
+}
+
+/***********************************************************
+ * Name: vc_dispmanx_element_remove
+ *
+ * Arguments:
+ *       DISPMANX_UPDATE_HANDLE_T update
+ *       DISPMANX_ELEMENT_HANDLE_T element
+ *
+ * Description:
+ *
+ * Returns:
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_dispmanx_element_remove( DISPMANX_UPDATE_HANDLE_T update, DISPMANX_ELEMENT_HANDLE_T element ) {
+   uint32_t element_param[] = {(uint32_t) VC_HTOV32(update), (uint32_t) VC_HTOV32(element)};
+   int success = (int) dispmanx_send_command( EDispmanElementRemove | DISPMANX_NO_REPLY_MASK,
+                                              element_param, sizeof(element_param));
+   return success;
+}
+
+/***********************************************************
+ * Name: vc_dispmanx_element_change_attributes
+ *
+ * Arguments:
+ *       DISPMANX_UPDATE_HANDLE_T update
+ *       DISPMANX_ELEMENT_HANDLE_T element
+ *       uint32_t change flags (bit 0 layer, bit 1 opacity, bit 2 dest rect, bit 3 src rect, bit 4 mask, bit 5 transform
+ *       uint32_t layer
+ *       uint8_t opacity
+ *       const VC_RECT_T *dest rect
+ *       const VC_RECT_T *src rect
+ *       DISPMANX_RESOURCE_HANDLE_T mask
+ *       VC_DISPMAN_TRANSFORM_T transform
+ *
+ * Description:
+ *
+ * Returns:
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_dispmanx_element_change_attributes( DISPMANX_UPDATE_HANDLE_T update,
+                                                            DISPMANX_ELEMENT_HANDLE_T element,
+                                                            uint32_t change_flags,
+                                                            int32_t layer,
+                                                            uint8_t opacity,
+                                                            const VC_RECT_T *dest_rect,
+                                                            const VC_RECT_T *src_rect,
+                                                            DISPMANX_RESOURCE_HANDLE_T mask,
+                                                            DISPMANX_TRANSFORM_T transform ) {
+
+   uint32_t element_param[15] = { (uint32_t) VC_HTOV32(update),
+                                  (uint32_t) VC_HTOV32(element),
+                                  VC_HTOV32(change_flags),
+                                  VC_HTOV32(layer),
+                                  VC_HTOV32(opacity),
+                                  (uint32_t) VC_HTOV32(mask),
+                                  (uint32_t) VC_HTOV32(transform), 0, 0, 0, 0, 0, 0, 0, 0};
+
+   uint32_t param_length = 7*sizeof(uint32_t);
+   int success;
+   if(dest_rect) {
+      element_param[7]  = VC_HTOV32(dest_rect->x);
+      element_param[8]  = VC_HTOV32(dest_rect->y);
+      element_param[9]  = VC_HTOV32(dest_rect->width);
+      element_param[10] = VC_HTOV32(dest_rect->height);
+      element_param[2] |= ELEMENT_CHANGE_DEST_RECT;
+      param_length += 4*sizeof(uint32_t);
+   }
+   if(src_rect) {
+      element_param[11] = VC_HTOV32(src_rect->x);
+      element_param[12] = VC_HTOV32(src_rect->y);
+      element_param[13] = VC_HTOV32(src_rect->width);
+      element_param[14] = VC_HTOV32(src_rect->height);
+      element_param[2] |= ELEMENT_CHANGE_SRC_RECT;
+      param_length += 4*sizeof(uint32_t);
+   }
+
+
+   success = (int) dispmanx_send_command( EDispmanElementChangeAttributes | DISPMANX_NO_REPLY_MASK,
+                                            element_param, param_length);
+   return success;
+}
+
+
+/***********************************************************
+ * Name: vc_dispmanx_snapshot
+ *
+ * Arguments:
+ *       DISPMANX_DISPLAY_HANDLE_T display
+ *       DISPMANX_RESOURCE_HANDLE_T snapshot_resource
+ *       DISPMANX_TRANSFORM_T transform
+ *
+ * Description: Take a snapshot of a display in its current state
+ *
+ * Returns:
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_dispmanx_snapshot( DISPMANX_DISPLAY_HANDLE_T display,
+                                           DISPMANX_RESOURCE_HANDLE_T snapshot_resource,
+                                           DISPMANX_TRANSFORM_T transform )
+{
+   uint32_t display_snapshot_param[] = {
+      VC_HTOV32(display),
+      VC_HTOV32(snapshot_resource),
+      VC_HTOV32(transform)};
+
+   int success = (int) dispmanx_send_command( EDispmanSnapshot,
+                                              display_snapshot_param,
+                                              sizeof(display_snapshot_param));
+   return success;
+}
+
+/***********************************************************
+ * Name: vc_dispmanx_resource_set_palette
+ *
+ * Arguments:
+ *       DISPMANX_RESOURCE_HANDLE_T res
+ *       void * src_address
+ *       int offset
+ *       int size
+ *
+ * Description: Set the resource palette (for VC_IMAGE_4BPP and VC_IMAGE_8BPP)
+ *              offset should be 0
+ *              size is 16*2 for 4BPP and 256*2 for 8BPP
+ * Returns: 0 or failure
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_dispmanx_resource_set_palette( DISPMANX_RESOURCE_HANDLE_T handle, 
+                                                      void * src_address, int offset, int size) {
+   //Note that x coordinate of the rect is NOT used
+   //Address of data in host
+   uint8_t *host_start = src_address;
+   int32_t bulk_len = size, success = 0;
+
+   //Now send the bulk transfer across
+   //command parameters: resource size
+   uint32_t param[] = {VC_HTOV32(handle), VC_HTOV32(offset), VC_HTOV32(bulk_len) };
+   success = dispmanx_send_command(  EDispmanSetPalette | DISPMANX_NO_REPLY_MASK, param, sizeof(param));
+   if(success == 0)
+   {
+      lock_obtain();
+      success = vchi_bulk_queue_transmit( dispmanx_client.client_handle[0],
+                                          host_start,
+                                          bulk_len,
+                                          VCHI_FLAGS_BLOCK_UNTIL_DATA_READ,
+                                          NULL );
+      lock_release();
+   }
+   return (int) success;
+}
+
+
+/***********************************************************
+ * Name: vc_dispmanx_vsync_callback
+ *
+ * Arguments:
+ *       DISPMANX_DISPLAY_HANDLE_T display
+ *       DISPMANX_CALLBACK_FUNC_T cb_func
+ *       void *cb_arg
+ *
+ * Description: start sending callbacks on vsync events
+ *              Use a NULL cb_func to stop the callbacks
+ * Returns: 0 or failure
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_dispmanx_vsync_callback( DISPMANX_DISPLAY_HANDLE_T display, DISPMANX_CALLBACK_FUNC_T cb_func, void *cb_arg )
+{
+   // Steal the invalid 0 handle to indicate this is a vsync request
+   DISPMANX_UPDATE_HANDLE_T update = 0;
+   int enable = (cb_func != NULL);
+   uint32_t update_param[] = {(uint32_t) VC_HTOV32(display), VC_HTOV32(update), (int32_t)enable};
+   int success;
+
+   // Set the callback
+   dispmanx_client.vsync_callback = cb_func;
+   dispmanx_client.vsync_callback_param = cb_arg;
+
+   if (!dispmanx_client.vsync_enabled && enable) {
+      // An extra "use" is required while a vsync callback is registered.
+      // The corresponding "release" is below.
+      vchi_service_use(dispmanx_client.notify_handle[0]);
+   }
+
+   success = (int) dispmanx_send_command( EDispmanVsyncCallback | DISPMANX_NO_REPLY_MASK,
+                                          update_param, sizeof(update_param));
+
+   if (dispmanx_client.vsync_enabled && !enable) {
+      // The extra "use" added above is no longer required.
+      vchi_service_release(dispmanx_client.notify_handle[0]);
+   }
+
+   dispmanx_client.vsync_enabled = enable;
+
+   return (int) success;
+}
+
+
+/*********************************************************************************
+ *
+ *  Static functions definitions
+ *
+ *********************************************************************************/
+//TODO: Might need to handle multiple connections later
+/***********************************************************
+ * Name: dispmanx_client_callback
+ *
+ * Arguments: semaphore, callback reason and message handle
+ *
+ * Description: VCHI callback for the DISP service
+ *
+ ***********************************************************/
+static void dispmanx_client_callback( void *callback_param,
+                                      const VCHI_CALLBACK_REASON_T reason,
+                                      void *msg_handle ) {
+
+       (void)msg_handle;
+
+   VCOS_EVENT_T *event = (VCOS_EVENT_T *)callback_param;
+
+   if ( reason != VCHI_CALLBACK_MSG_AVAILABLE )
+      return;
+
+   if ( event == NULL )
+      return;
+   
+   vcos_event_signal(event);
+}
+
+/***********************************************************
+ * Name: dispmanx_notify_callback
+ *
+ * Arguments: semaphore, callback reason and message handle
+ *
+ * Description: VCHI callback for the update callback
+ *
+ ***********************************************************/
+
+static void dispmanx_notify_callback( void *callback_param,
+                                      const VCHI_CALLBACK_REASON_T reason,
+                                      void *msg_handle ) {
+   VCOS_EVENT_T *event = (VCOS_EVENT_T *)callback_param;
+
+   (void)msg_handle;
+
+   if ( reason != VCHI_CALLBACK_MSG_AVAILABLE )
+      return;
+
+   if ( event == NULL )
+      return;
+
+   vcos_event_signal(event);
+}
+
+/***********************************************************
+ * Name: dispmanx_wait_for_reply
+ *
+ * Arguments: response buffer, buffer length
+ *
+ * Description: blocked until something is in the buffer
+ *
+ * Returns error code of vchi
+ *
+ ***********************************************************/
+static int32_t dispmanx_wait_for_reply(void *response, uint32_t max_length) {
+   int32_t success = 0;
+   uint32_t length_read = 0;
+   do {
+      //TODO : we need to deal with messages coming through on more than one connections properly
+      //At the moment it will always try to read the first connection if there is something there
+      //Check if there is something in the queue, if so return immediately
+      //otherwise wait for the semaphore and read again
+      success = vchi_msg_dequeue( dispmanx_client.client_handle[0], response, max_length, &length_read, VCHI_FLAGS_NONE );
+   } while( length_read == 0 && vcos_event_wait(&dispmanx_message_available_event) == VCOS_SUCCESS );
+
+   return success;
+
+}
+/***********************************************************
+ * Name: dispmanx_send_command
+ *
+ * Arguments: command, parameter buffer, parameter legnth
+ *
+ * Description: send a command and wait for its response (int)
+ *
+ * Returns: response
+ *
+ ***********************************************************/
+
+static int32_t dispmanx_send_command(  uint32_t command, void *buffer, uint32_t length) {
+   VCHI_MSG_VECTOR_T vector[] = { {&command, sizeof(command)},
+                                  {buffer, length} };
+   int32_t success = 0, response = -1;
+   lock_obtain();
+   success = vchi_msg_queuev( dispmanx_client.client_handle[0],
+                              vector, sizeof(vector)/sizeof(vector[0]),
+                              VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL );
+   if(success == 0 && !(command & DISPMANX_NO_REPLY_MASK)) {
+      //otherwise only wait for a reply if we ask for one
+      success = dispmanx_wait_for_reply(&response, sizeof(response));
+   } else {
+      //Not waiting for a reply, send the success code back instead
+      response = success;
+   }
+   lock_release();
+   return VC_VTOH32(response);
+}
+
+int32_t vc_dispmanx_send_command (uint32_t command, void *buffer,
+                                  uint32_t length)
+{
+  return dispmanx_send_command (command, buffer, length);
+}
+
+/***********************************************************
+ * Name: dispmanx_send_command_reply
+ *
+ * Arguments: command, parameter buffer, parameter legnth, reply buffer, buffer length
+ *
+ * Description: send a command and wait for its response (in a buffer)
+ *
+ * Returns: error code
+ *
+ ***********************************************************/
+
+static int32_t dispmanx_send_command_reply(  uint32_t command, void *buffer, uint32_t length,
+                                            void *response, uint32_t max_length) {
+   VCHI_MSG_VECTOR_T vector[] = { {&command, sizeof(command)},
+                                   {buffer, length} };
+
+   int32_t success = 0;
+   lock_obtain();
+   success = vchi_msg_queuev( dispmanx_client.client_handle[0],
+                               vector, sizeof(vector)/sizeof(vector[0]),
+                               VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL );
+   if(success == 0)
+      success = dispmanx_wait_for_reply(response, max_length);
+
+   lock_release();
+
+   return success;
+}
+
+int32_t vc_dispmanx_send_command_reply (uint32_t command, void *buffer, uint32_t length,
+                                        void *response, uint32_t max_length)
+{
+  return dispmanx_send_command_reply (command, buffer, length, response, max_length);
+}
+
+/***********************************************************
+ * Name: dispmanx_get_handle
+ *
+ * Arguments: command, parameter buffer, parameter legnth
+ *
+ * Description: same as dispmanx_send_command but returns uint instead
+ *
+ * Returns: handle
+ *
+ ***********************************************************/
+static uint32_t dispmanx_get_handle(  uint32_t command, void *buffer, uint32_t length) {
+   VCHI_MSG_VECTOR_T vector[] = { {&command, sizeof(command)},
+                                   {buffer, length} };
+   uint32_t success = 0;
+   uint32_t response = 0;
+   lock_obtain();
+   success += vchi_msg_queuev( dispmanx_client.client_handle[0],
+                               vector, sizeof(vector)/sizeof(vector[0]),
+                               VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL );
+   if(success == 0)
+      success = dispmanx_wait_for_reply(&response, sizeof(response));
+
+   lock_release();
+   return VC_VTOH32(response);
+}
+
+/***********************************************************
+ * Name: dispmanx_notify_handle
+ *
+ * Arguments: not used
+ *
+ * Description: this purely notifies the update callback
+ *
+ * Returns: does not return
+ *
+ ***********************************************************/
+static void *dispmanx_notify_func( void *arg ) {
+   int32_t success;
+   VCOS_STATUS_T status;
+
+   (void)arg;
+
+   while (1) {
+      DISPMANX_UPDATE_HANDLE_T handle;
+      status = vcos_event_wait(&dispmanx_notify_available_event);
+      if (status != VCOS_SUCCESS || !dispmanx_client.initialised)
+         break;
+
+      while (1) {
+         success = vchi_msg_dequeue( dispmanx_client.notify_handle[0], dispmanx_client.notify_buffer, sizeof(dispmanx_client.notify_buffer), &dispmanx_client.notify_length, VCHI_FLAGS_NONE );
+         if (success != 0)
+            break;
+
+         handle = (DISPMANX_UPDATE_HANDLE_T)dispmanx_client.notify_buffer[0];
+         if (handle) {
+            // This is the response to an update submit
+            // Decrement the use count - the corresponding "use" is in vc_dispmanx_update_submit.
+            vchi_service_release(dispmanx_client.notify_handle[0]);
+            if (dispmanx_client.update_callback ) {
+               vcos_assert( dispmanx_client.pending_update_handle == handle);
+               dispmanx_client.update_callback(handle, dispmanx_client.update_callback_param);
+            }
+         } else {
+            // This is a vsync notification
+            if (dispmanx_client.vsync_callback ) {
+               dispmanx_client.vsync_callback(handle, dispmanx_client.vsync_callback_param);
+            }
+         }
+      }
+   }
+   return 0;
+}
diff --git a/interface/vmcs_host/vc_vchi_dispmanx.h b/interface/vmcs_host/vc_vchi_dispmanx.h
new file mode 100755 (executable)
index 0000000..b723b76
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VC_VCHI_DISPMANX_H
+#define VC_VCHI_DISPMANX_H
+
+#include "interface/peer/vc_vchi_dispmanx_common.h"
+
+#define VC_NUM_HOST_RESOURCES 64
+#define DISPMANX_MSGFIFO_SIZE 1024
+#define DISPMANX_CLIENT_NAME MAKE_FOURCC("DISP")
+#define DISPMANX_NOTIFY_NAME MAKE_FOURCC("UPDH")
+
+//Or with command to indicate we don't need a response
+#define DISPMANX_NO_REPLY_MASK (1<<31)
+
+typedef struct {
+   char     description[32];
+   uint32_t width;
+   uint32_t height;
+   uint32_t aspect_pixwidth;
+   uint32_t aspect_pixheight;
+   uint32_t fieldrate_num;
+   uint32_t fieldrate_denom;
+   uint32_t fields_per_frame;
+   uint32_t transform;        
+} GET_MODES_DATA_T;
+
+typedef struct {
+   int32_t  response;
+   uint32_t width;
+   uint32_t height;
+   uint32_t transform;
+   uint32_t input_format;
+} GET_INFO_DATA_T;
+
+//Attributes changes flag mask
+#define ELEMENT_CHANGE_LAYER          (1<<0)
+#define ELEMENT_CHANGE_OPACITY        (1<<1)
+#define ELEMENT_CHANGE_DEST_RECT      (1<<2)
+#define ELEMENT_CHANGE_SRC_RECT       (1<<3)
+#define ELEMENT_CHANGE_MASK_RESOURCE  (1<<4)
+#define ELEMENT_CHANGE_TRANSFORM      (1<<5)
+
+#endif
diff --git a/interface/vmcs_host/vc_vchi_fileservice_defs.h b/interface/vmcs_host/vc_vchi_fileservice_defs.h
new file mode 100755 (executable)
index 0000000..0677076
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VC_VCHI_FILESERVICE_DEFS_H
+#define VC_VCHI_FILESERVICE_DEFS_H
+
+#include "interface/vchi/vchi.h"
+
+/* Definitions (not used by API) */
+
+/* structure used by both side to communicate */
+#define FILESERV_MAX_BULK_SECTOR  128   //must be power of two
+
+#define FILESERV_SECTOR_LENGTH  512
+
+#define FILESERV_MAX_BULK (FILESERV_MAX_BULK_SECTOR*FILESERV_SECTOR_LENGTH)
+
+#define FILESERV_4CC  MAKE_FOURCC("FSRV")
+
+typedef enum FILESERV_EVENT_T
+{
+   FILESERV_BULK_RX = 0,
+   FILESERV_BULK_TX,
+   FILESERV_BULK_RX_0,
+   FILESERV_BULK_RX_1
+}FILESERV_EVENT_T;
+//this following structure has to equal VCHI_MAX_MSG_SIZE
+#define FILESERV_MAX_DATA      (VCHI_MAX_MSG_SIZE - 40) //(VCHI_MAX_MSG_SIZE - 24)
+
+typedef struct{
+       uint32_t xid;               //4 // transaction's ID, used to match cmds with response
+   uint32_t cmd_code;    //4
+   uint32_t params[4];   //16
+   char  data[FILESERV_MAX_DATA];
+}FILESERV_MSG_T;
+
+typedef enum
+{
+   FILESERV_RESP_OK,
+   FILESERV_RESP_ERROR,
+   FILESERV_BULK_READ,
+   FILESERV_BULK_WRITE,
+
+} FILESERV_RESP_CODE_T;
+
+
+/* Protocol (not used by API) version 1.2 */
+
+
+
+#endif
diff --git a/interface/vmcs_host/vc_vchi_filesys.c b/interface/vmcs_host/vc_vchi_filesys.c
new file mode 100755 (executable)
index 0000000..26a34b9
--- /dev/null
@@ -0,0 +1,2509 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "vchost.h"
+
+#include "interface/vcos/vcos.h"
+#include "interface/vchi/vchi.h"
+#include "interface/vchi/common/endian.h"
+
+#include "vc_vchi_filesys.h"
+#include "interface/vmcs_host/vc_vchi_fileservice_defs.h"
+
+/******************************************************************************
+Global data.
+******************************************************************************/
+
+/******************************************************************************
+Local types and defines.
+******************************************************************************/
+typedef enum {
+   VC_SECTOR_IO_NONE,
+   VC_SECTOR_IO_READING,
+   VC_SECTOR_IO_WRITING
+} VC_SECTOR_IO_T;
+
+typedef struct {
+
+   VCHI_SERVICE_HANDLE_T open_handle;
+
+   int32_t               num_connections;
+
+   //Host->2727
+   FILESERV_MSG_T        fileserv_msg;
+
+   //2727->Host   XXX
+   FILESERV_MSG_T        vc_msg;
+
+   VCOS_THREAD_T         filesys_thread;
+
+   // used to signal response has arrived
+   VCOS_EVENT_T          response_event;
+
+   //we lock each vc_filesys function call
+   VCOS_MUTEX_T          filesys_lock;
+
+   //used to signal msg arrivals
+   VCOS_EVENT_T          filesys_msg_avail;
+
+   // Outstanding transaction's ID
+   volatile uint32_t     cur_xid;
+
+   // Copy of the header code from responses
+   int32_t      resp_code;
+   int32_t      err_no;
+
+   char        *bulk_buffer;
+   int32_t      initialised;
+
+} FILESYS_SERVICE_T;
+
+static FILESYS_SERVICE_T vc_filesys_client;
+
+
+/******************************************************************************
+Static functions.
+******************************************************************************/
+
+//Lock the host state
+static __inline int32_t lock_obtain (void) {
+   int ret = -1;
+   if(vc_filesys_client.initialised && vcos_mutex_lock(&vc_filesys_client.filesys_lock) == VCOS_SUCCESS) {
+      vchi_service_use(vc_filesys_client.open_handle);
+      ret = 0;
+   }
+   return ret;
+}
+
+//Unlock the host state
+static __inline void lock_release (void) {
+   vcos_assert(vc_filesys_client.initialised);
+   vchi_service_release(vc_filesys_client.open_handle);
+   vcos_mutex_unlock(&vc_filesys_client.filesys_lock);
+}
+
+// File Service VCHI functions
+
+static int vchi_msg_stub(FILESERV_MSG_T* msg, uint16_t cmd_id, int msg_len );
+
+static int vchi_msg_stub_noblock(FILESERV_MSG_T* msg, uint16_t cmd_id, int msg_len);
+
+static int vc_fs_message_handler( FILESERV_MSG_T* msg, uint32_t nbytes );
+
+static void *filesys_task_func(void *arg);
+
+static void filesys_callback( void *callback_param, VCHI_CALLBACK_REASON_T reason, void *msg_handle );
+
+
+
+#ifdef PRINTF
+#ifdef WIN32
+#define printf tprintf
+#endif
+static void showmsg(VC_MSGFIFO_CMD_HEADER_T const * head,
+                    struct file_service_msg_body const * body);
+#endif
+static int fs_host_direntbytestream_create(struct dirent *d, void *buffer);
+static void fs_host_direntbytestream_interp(struct dirent *d, void *buffer);
+
+/*---------------------------------------------------------------------------*/
+
+/******************************************************************************
+NAME
+   vc_filesys_init
+
+SYNOPSIS
+   vc_filesys_init (VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections ) {
+
+FUNCTION
+   Initialise the file system for use. A negative return value
+   indicates failure (which may mean it has not been started on VideoCore).
+
+RETURNS
+   int
+******************************************************************************/
+int vc_vchi_filesys_init (VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections )
+{
+   int32_t success = 0;
+   SERVICE_CREATION_T filesys_parameters;
+   VCOS_THREAD_ATTR_T attrs;
+   VCOS_STATUS_T status;
+
+   // record the number of connections
+   memset( &vc_filesys_client, 0, sizeof(FILESYS_SERVICE_T) );
+   vc_filesys_client.num_connections = num_connections;
+
+   if(!vcos_verify(vc_filesys_client.num_connections < 2))
+      return -1;
+
+   status = vcos_mutex_create(&vc_filesys_client.filesys_lock, "HFilesys");
+   vcos_assert(status == VCOS_SUCCESS);
+
+   status = vcos_event_create(&vc_filesys_client.filesys_msg_avail, "HFilesys");
+   vcos_assert(status == VCOS_SUCCESS);
+
+   //create sema used to signal cmd response has arrived
+   status = vcos_event_create(&vc_filesys_client.response_event, "HFilesys");
+   vcos_assert(status == VCOS_SUCCESS);
+
+   vc_filesys_client.bulk_buffer = vcos_malloc_aligned(FILESERV_MAX_BULK, 16, "HFilesys bulk_recv");
+   vc_filesys_client.cur_xid = 0;
+
+   memset(&filesys_parameters, 0, sizeof(filesys_parameters));
+   filesys_parameters.service_id = FILESERV_4CC;   // 4cc service code
+   filesys_parameters.connection = connections[0]; // passed in fn ptrs
+   filesys_parameters.rx_fifo_size = 0;            // rx fifo size (unused)
+   filesys_parameters.tx_fifo_size = 0;            // tx fifo size (unused)
+   filesys_parameters.callback = &filesys_callback;
+   filesys_parameters.callback_param = &vc_filesys_client.filesys_msg_avail;
+   filesys_parameters.want_unaligned_bulk_rx = 0;
+   filesys_parameters.want_unaligned_bulk_tx = 0;
+   filesys_parameters.want_crc = 0;
+   filesys_parameters.version.version = VC_FILESERV_VER;
+   filesys_parameters.version.version_min = VC_FILESERV_VER;
+
+   success = vchi_service_open( initialise_instance, &filesys_parameters, &vc_filesys_client.open_handle );
+   vcos_assert( success == 0 );
+
+   vcos_thread_attr_init(&attrs);
+   vcos_thread_attr_setstacksize(&attrs, 4000);
+   vcos_thread_attr_settimeslice(&attrs, 1);
+
+   vc_filesys_client.initialised = 1;
+
+   status = vcos_thread_create(&vc_filesys_client.filesys_thread, "HFilesys", &attrs, filesys_task_func, NULL);
+   vcos_assert(status == VCOS_SUCCESS);
+
+   /* Not using service immediately - release videocore */
+   vchi_service_release(vc_filesys_client.open_handle);
+
+   return (int)success;
+}
+
+static void *filesys_task_func(void *arg)
+{
+   int32_t success;
+   uint32_t msg_len;
+
+   (void)arg;
+
+   vc_hostfs_init();
+
+   while(1) {
+      // wait for the semaphore to say that there is a message
+      if (vcos_event_wait(&vc_filesys_client.filesys_msg_avail) != VCOS_SUCCESS || vc_filesys_client.initialised == 0)
+         break;
+
+      vchi_service_use(vc_filesys_client.open_handle);
+      // read the message - should we really "peek" this
+      while (1) {
+         success = vchi_msg_dequeue(vc_filesys_client.open_handle, &vc_filesys_client.vc_msg,
+                                    sizeof(vc_filesys_client.vc_msg), &msg_len, VCHI_FLAGS_NONE);
+         if (!success)
+            break;
+
+         /* coverity[tainted_string_argument] */
+         success = (int32_t) vc_fs_message_handler(&vc_filesys_client.vc_msg, msg_len);
+         (void)success;
+      }
+      vchi_service_release(vc_filesys_client.open_handle);
+   }
+
+   return 0;
+}
+
+
+/******************************************************************************
+NAME
+   filesys_callback
+
+SYNOPSIS
+   void filesys_callback( void *callback_param,
+                     const VCHI_CALLBACK_REASON_T reason,
+                     const void *msg_handle )
+
+FUNCTION
+   VCHI callback
+
+RETURNS
+   int
+******************************************************************************/
+static void filesys_callback( void *callback_param,
+                             const VCHI_CALLBACK_REASON_T reason,
+                             void *msg_handle )
+{
+   (void)msg_handle;
+
+   switch( reason ) {
+
+   case VCHI_CALLBACK_MSG_AVAILABLE:
+      {
+         VCOS_EVENT_T *event = (VCOS_EVENT_T *) callback_param;
+         if(event)
+            vcos_event_signal(event);
+      }
+      break;
+
+   case VCHI_CALLBACK_BULK_RECEIVED:
+      break;
+   case VCHI_CALLBACK_BULK_SENT:
+      break;
+
+   default:
+      return;
+   }
+}
+
+/******************************************************************************
+NAME
+   vc_filesys_stop
+
+SYNOPSIS
+   void vc_filesys_stop()
+
+FUNCTION
+   This tells us that the file system service has stopped, thereby preventing
+   any of the functions from doing anything.
+
+RETURNS
+   void
+******************************************************************************/
+
+void vc_filesys_stop ()
+{
+   int32_t result;
+   void *dummy;
+
+   if(lock_obtain() != 0)
+      return;
+
+   result = vchi_service_close(vc_filesys_client.open_handle);
+   vcos_assert(result == 0);
+
+   vc_filesys_client.initialised = 0;
+
+   vcos_event_signal(&vc_filesys_client.filesys_msg_avail);
+   vcos_thread_join(&vc_filesys_client.filesys_thread, &dummy);
+
+   vcos_event_delete(&vc_filesys_client.filesys_msg_avail);
+   vcos_event_delete(&vc_filesys_client.response_event);
+   vcos_mutex_delete(&vc_filesys_client.filesys_lock);
+
+   if(vc_filesys_client.bulk_buffer)
+      vcos_free(vc_filesys_client.bulk_buffer);
+}
+
+/******************************************************************************
+NAME
+   vc_filesys_single_param
+
+SYNOPSIS
+   int vc_filesys_single_param(uint32_t param, uint32_t fn)
+
+FUNCTION
+   Utility function for implementing filesys methods
+
+RETURNS
+   void
+******************************************************************************/
+static int vc_filesys_single_param(uint32_t param, uint32_t fn)
+{
+   int success = -1;
+
+   if(lock_obtain() == 0)
+   {
+      vc_filesys_client.fileserv_msg.params[0] = param;
+      if (vchi_msg_stub(&vc_filesys_client.fileserv_msg, fn, 4) == FILESERV_RESP_OK)
+         success = 0;
+      
+      lock_release();
+   }
+
+   return success;
+}
+
+/******************************************************************************
+NAME
+   vc_filesys_single_string
+
+SYNOPSIS
+   int vc_filesys_single_string(uint32_t param, const char *str, uint32_t fn, int return_param)
+
+FUNCTION
+   Utility function for implementing filesys methods
+
+RETURNS
+   void
+******************************************************************************/
+static int vc_filesys_single_string(uint32_t param, const char *str, uint32_t fn, int return_param)
+{
+   int ret = -1;
+   int len = strlen(str);
+
+   if(len < FILESERV_MAX_DATA && lock_obtain() == 0)
+   {
+      vc_filesys_client.fileserv_msg.params[0] = param;
+      /* coverity[buffer_size_warning] - the length of str has already been checked */
+      strncpy((char*)vc_filesys_client.fileserv_msg.data, str, FILESERV_MAX_DATA);
+    
+      if (vchi_msg_stub(&vc_filesys_client.fileserv_msg, fn, len+1+16) == FILESERV_RESP_OK)
+      {
+         if(return_param)
+            ret = (int) vc_filesys_client.fileserv_msg.params[0];
+         else
+            ret = 0;
+      }
+
+      lock_release();
+   }
+
+   return ret;
+}
+
+/* Standard UNIX low-level library functions (declared in unistd.h) */
+/******************************************************************************
+NAME
+   vc_filesys_close
+
+SYNOPSIS
+   int vc_filesys_close(int fildes)
+
+FUNCTION
+   Deallocates the file descriptor to a file.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_filesys_close(int fildes)
+{
+   return vc_filesys_single_param((uint32_t) fildes, VC_FILESYS_CLOSE);
+}
+
+
+/******************************************************************************
+NAME
+   vc_filesys_lseek
+
+SYNOPSIS
+   long vc_filesys_lseek(int fildes, long offset, int whence)
+
+FUNCTION
+   Sets the file pointer associated with the open file specified by fildes.
+
+RETURNS
+   Successful completion: offset
+   Otherwise: -1
+******************************************************************************/
+
+long vc_filesys_lseek(int fildes, long offset, int whence)
+{
+   long set = -1;
+
+   if(lock_obtain() == 0)
+   {
+      vc_filesys_client.fileserv_msg.params[0] = (uint32_t) fildes;
+      vc_filesys_client.fileserv_msg.params[1] = (uint32_t) offset;
+      vc_filesys_client.fileserv_msg.params[2] = (uint32_t) whence;
+      
+      if (vchi_msg_stub(&vc_filesys_client.fileserv_msg, VC_FILESYS_LSEEK, 12) == FILESERV_RESP_OK)
+         set = (long) vc_filesys_client.fileserv_msg.params[0];
+      
+      lock_release();
+   }
+
+   return set;
+}
+
+/******************************************************************************
+NAME
+   vc_filesys_lseek64
+
+SYNOPSIS
+   int64_t vc_filesys_lseek64(int fildes, int64_t offset, int whence)
+
+FUNCTION
+   Sets the file pointer associated with the open file specified by fildes.
+
+RETURNS
+   Successful completion: file pointer value
+   Otherwise: -1
+******************************************************************************/
+
+int64_t vc_filesys_lseek64(int fildes, int64_t offset, int whence)
+{
+   int64_t set = -1;
+
+   if(lock_obtain() == 0)
+   {
+      vc_filesys_client.fileserv_msg.params[0] = (uint32_t) fildes;
+      vc_filesys_client.fileserv_msg.params[1] = (uint32_t) offset;        // LSB
+      vc_filesys_client.fileserv_msg.params[2] = (uint32_t)(offset >> 32); // MSB
+      vc_filesys_client.fileserv_msg.params[3] = (uint32_t) whence;
+      
+      if (vchi_msg_stub(&vc_filesys_client.fileserv_msg, VC_FILESYS_LSEEK64, 16) == FILESERV_RESP_OK)
+      {
+         set = vc_filesys_client.fileserv_msg.params[0];
+         set += (int64_t)vc_filesys_client.fileserv_msg.params[1] << 32;
+      }
+      
+      lock_release();
+   }
+
+   return set;
+}
+
+/******************************************************************************
+NAME
+   vc_filesys_mount
+
+SYNOPSIS
+   int vc_filesys_mount(const char *device, const char *mountpoint, const char *options)
+
+FUNCTION
+   Mounts a filesystem at a given location
+
+RETURNS
+   Successful completion: 0
+******************************************************************************/
+
+int vc_filesys_mount(const char *device, const char *mountpoint, const char *options)
+{
+   int set = -1, len;
+   int a = strlen(device);
+   int b = strlen(mountpoint);
+   int c = strlen(options);
+
+   if(a + b + c + 3 < FILESERV_MAX_DATA && lock_obtain() == 0)
+   {
+      char *str = (char *) vc_filesys_client.fileserv_msg.data;
+
+      memcpy(str, device, a);
+      str[a] = 0;
+      memcpy(str+a+1, mountpoint, b);
+      str[a+1+b] = 0;
+      memcpy(str+a+b+2, options, c);
+      str[a+b+c+2] = 0;
+      len = a + b + c + 3 + (int)(((FILESERV_MSG_T *)0)->data);
+      len = ((len + (VCHI_BULK_GRANULARITY-1)) & ~(VCHI_BULK_GRANULARITY-1)) + VCHI_BULK_GRANULARITY;
+      
+      if (vchi_msg_stub(&vc_filesys_client.fileserv_msg, VC_FILESYS_MOUNT, len) == FILESERV_RESP_OK)
+         set = (int) vc_filesys_client.fileserv_msg.params[0];
+
+      lock_release();
+   }
+
+   return set;
+}
+
+/******************************************************************************
+NAME
+   vc_filesys_umount
+
+SYNOPSIS
+   int vc_filesys_mount(const char *mountpoint)
+
+FUNCTION
+   Un-mounts a removable device from the location that it has been mounted
+   to earlier in the session
+
+RETURNS
+   Successful completion: 0
+******************************************************************************/
+
+int vc_filesys_umount(const char *mountpoint)
+{
+   return vc_filesys_single_string(0, mountpoint, VC_FILESYS_UMOUNT, 1);
+}
+
+/******************************************************************************
+NAME
+   vc_filesys_open
+
+SYNOPSIS
+   int vc_filesys_open(const char *path, int vc_oflag)
+
+FUNCTION
+   Establishes a connection between a file and a file descriptor.
+
+RETURNS
+   Successful completion: file descriptor
+   Otherwise: -1
+******************************************************************************/
+
+int vc_filesys_open(const char *path, int vc_oflag)
+{
+   return vc_filesys_single_string((uint32_t) vc_oflag, path, VC_FILESYS_OPEN, 1);
+}
+
+
+/******************************************************************************
+NAME
+   vc_filesys_read
+
+SYNOPSIS
+   int vc_filesys_read(int fildes, void *buf, unsigned int nbyte)
+
+FUNCTION
+   Attempts to read nbyte bytes from the file associated with the file
+   descriptor, fildes, into the buffer pointed to by buf.
+
+RETURNS
+   Successful completion: number of bytes read
+   Otherwise: -1
+******************************************************************************/
+
+/******************************************************************************
+
+FUNCTION
+
+
+RETURNS
+   Successful completion: the number of bytes received
+   Otherwise  negative error code
+******************************************************************************/
+static int vc_vchi_msg_bulk_read(FILESERV_MSG_T* msg, uint16_t cmd_id, uint32_t transfer_len, uint8_t* recv_addr )
+{
+   uint32_t i;
+   int msg_len;
+   uint32_t host_align_bytes;
+   uint32_t num_bytes_read;
+   int32_t success;
+
+   //this is current file_io_buffer size so assuming never more than this
+   //otherwise we will split the read into chunks
+   if(!vcos_verify(transfer_len <= FILESERV_MAX_BULK))
+      return -1;
+
+   //number of bytes required to align recv_addr
+   host_align_bytes = VCHI_BULK_ALIGN_NBYTES(recv_addr);
+
+   i = vc_filesys_client.cur_xid + 1;
+   i &= 0x7fffffffUL;
+   vc_filesys_client.cur_xid = i;
+
+   msg->xid = vc_filesys_client.cur_xid;
+
+   //fill in cmd id: VC_FILESYS_READ etc
+   msg->cmd_code = cmd_id;
+
+   msg->params[2] = transfer_len;
+
+   msg->params[3] = host_align_bytes;
+
+   //24 comes from the static size of FILESERV_MSG_T
+   msg_len = 24;
+
+   if(vchi_msg_queue( vc_filesys_client.open_handle, msg, (uint32_t)msg_len, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL ) != 0)
+      return -1;
+
+   //wait to receive response
+   if(vcos_event_wait(&vc_filesys_client.response_event) != VCOS_SUCCESS || msg->cmd_code == FILESERV_RESP_ERROR)
+      return -1;
+
+   //total bytes read
+   num_bytes_read = msg->params[0];
+
+   if(!vcos_verify(num_bytes_read <= FILESERV_MAX_BULK))
+      return -1;
+
+   //everything is in msg->data
+   if(msg->cmd_code == FILESERV_RESP_OK) {
+      if(!vcos_verify(num_bytes_read <= FILESERV_MAX_DATA))
+         return -1;
+
+      memcpy(recv_addr, msg->data, num_bytes_read);
+      return (int) num_bytes_read;
+   }
+
+// Make this code conditional to stop Coverity complaining about dead code
+#if VCHI_BULK_ALIGN > 1
+   //copy host_align_bytes bytes to recv_addr, now ready for bulk
+   if(host_align_bytes) {
+      memcpy(recv_addr, msg->data, host_align_bytes);
+      recv_addr += host_align_bytes;
+      transfer_len -= host_align_bytes;
+   }
+#endif
+
+   //receive bulk from host
+   if(msg->cmd_code == FILESERV_BULK_WRITE){
+      //number of end bytes
+      uint32_t end_bytes = msg->params[1];
+      //calculate what portion of read transfer by bulk
+      uint32_t bulk_bytes = (num_bytes_read-host_align_bytes-end_bytes);
+
+      success = vchi_bulk_queue_receive(vc_filesys_client.open_handle,
+                              recv_addr,
+                              bulk_bytes,
+                              VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE,
+                              NULL );
+      if(!vcos_verify(success == 0))
+         return -1;
+
+      recv_addr+=bulk_bytes;
+
+      //copy any left over end bytes from original msg
+      if(end_bytes)
+         memcpy(recv_addr, &msg->data[host_align_bytes], end_bytes);
+   }
+   else {
+      return -1;
+   }
+
+   return (int) num_bytes_read;
+}
+
+
+int vc_filesys_read(int fildes, void *buf, unsigned int nbyte)
+{
+   int bulk_bytes = 0;
+   int actual_read = 0;
+   int total_byte = 0;
+   uint8_t* ptr = (uint8_t*)buf;
+
+   if (nbyte == 0) {
+      return 0;
+   }
+
+   if(lock_obtain() == 0)
+   {
+      do {
+         bulk_bytes = nbyte > FILESERV_MAX_BULK ? FILESERV_MAX_BULK : nbyte;
+         
+         //we overwrite the response here so fill in data again
+         vc_filesys_client.fileserv_msg.params[0] = (uint32_t)fildes;
+         vc_filesys_client.fileserv_msg.params[1] = 0xffffffffU;        // offset: use -1 to indicate no offset
+         
+         actual_read = vc_vchi_msg_bulk_read(&vc_filesys_client.fileserv_msg , VC_FILESYS_READ, (uint32_t)bulk_bytes, (uint8_t*)ptr);
+         
+         if(bulk_bytes != actual_read) {
+            if(actual_read < 0)
+               total_byte = -1;
+            else
+               total_byte += actual_read;
+            //exit loop
+            break;
+         }
+
+         ptr+=bulk_bytes;
+         nbyte -= actual_read;
+         total_byte += actual_read;
+      }while(nbyte > 0);
+
+      lock_release();
+   }
+
+   return total_byte;
+}
+
+/******************************************************************************
+NAME
+   vc_filesys_write
+
+SYNOPSIS
+   int vc_filesys_write(int fildes, const void *buf, unsigned int nbyte)
+
+FUNCTION
+   Attempts to write nbyte bytes from the buffer pointed to by buf to file
+   associated with the file descriptor, fildes.
+
+RETURNS
+   Successful completion: number of bytes written
+   Otherwise: -1
+******************************************************************************/
+
+/******************************************************************************
+
+FUNCTION
+
+
+RETURNS
+   Successful completion: the number of bytes received
+   Otherwise  negative error code
+******************************************************************************/
+static int vc_vchi_msg_bulk_write(FILESERV_MSG_T* msg, uint16_t cmd_id, uint32_t transfer_len, uint8_t* send_addr )
+{
+   uint32_t i;
+   int msg_len;
+   uint32_t align_bytes = 0;
+   uint32_t bulk_end_bytes = 0;
+   uint32_t bulk_bytes = 0;
+   int num_bytes_written = -1;
+
+   //this is current file_io_buffer size so assuming never more than this
+   //otherwise we will split the read into chunks
+   if(!vcos_verify(transfer_len <= FILESERV_MAX_BULK))
+      return -1;
+
+   i = vc_filesys_client.cur_xid + 1;
+   i &= 0x7fffffffUL;
+   vc_filesys_client.cur_xid = i;
+
+   msg->xid = vc_filesys_client.cur_xid;
+
+   //fill in cmd id VC_FILESYS_OPEN etc
+   msg->cmd_code = cmd_id;
+
+   msg->params[2] = transfer_len;
+
+   //24 comes from the static size of FILESERV_MSG_T
+   msg_len = 24;
+
+   //put it all in one msg
+   if(transfer_len <= FILESERV_MAX_DATA) {
+      memcpy(msg->data, send_addr, transfer_len);
+      msg->params[3] = 0;
+      msg_len += transfer_len;
+      //send request to write to host
+      if(vchi_msg_queue( vc_filesys_client.open_handle, msg, (uint32_t)msg_len, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL ) != 0)
+         return -1;
+
+      // wait to receive response
+      if(vcos_event_wait(&vc_filesys_client.response_event) == VCOS_SUCCESS &&
+         msg->cmd_code != FILESERV_RESP_ERROR && msg->params[0] == transfer_len)
+      {
+         //vc_fs_message_handler copies resp into outgoing msg struct
+         num_bytes_written = (int)msg->params[0];
+      }
+   }
+   else {
+      //required to make send_addr for bulk
+      align_bytes = VCHI_BULK_ALIGN_NBYTES(send_addr);
+
+// Make this code conditional to stop Coverity complaining about dead code
+#if VCHI_BULK_ALIGN > 1
+      //copy vc_align bytes to msg->data, send_addr ready for bulk
+      if(align_bytes) {
+         msg->params[3] = align_bytes;
+         memcpy(msg->data, send_addr, align_bytes);
+         transfer_len -= align_bytes;
+         send_addr += align_bytes;
+         msg_len += align_bytes;
+      }
+      else
+#endif
+         msg->params[3] = 0;
+
+      // need to ensure we have the appropriate alignment
+      bulk_bytes = (transfer_len)&(~(VCHI_BULK_GRANULARITY-1));
+
+      bulk_end_bytes = transfer_len-bulk_bytes;
+
+      if(bulk_end_bytes) {
+         memcpy(msg->data+align_bytes, send_addr+bulk_bytes, bulk_end_bytes);
+         msg_len += bulk_end_bytes;
+      }
+
+      //send request to write to host
+      if(vchi_msg_queue( vc_filesys_client.open_handle, msg, (uint32_t)msg_len, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL ) != 0)
+         return -1;
+
+      //send bulk VCHI_FLAGS_BLOCK_UNTIL_QUEUED is ok because we wait for response msg with actual length written
+      if(vchi_bulk_queue_transmit( vc_filesys_client.open_handle,
+                                   send_addr,
+                                   bulk_bytes,
+                                   VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
+                                   NULL ) != 0)
+         return -1;
+
+      // wait to receive response sent by filsys_task_func
+      if(vcos_event_wait(&vc_filesys_client.response_event) == VCOS_SUCCESS && msg->cmd_code == FILESERV_BULK_READ)
+         num_bytes_written = (int)msg->params[0];
+   }
+
+   return num_bytes_written;
+}
+
+
+int vc_filesys_write(int fildes, const void *buf, unsigned int nbyte)
+{
+   int num_wrt = 0;
+   int bulk_bytes = 0;
+   int actual_written = 0;
+   uint8_t *ptr = (uint8_t*) buf;
+
+   if (nbyte == 0) {
+      return 0;
+   }
+
+   if(lock_obtain() == 0)
+   {
+      //will split the read into 4K chunks based on vc fwrite buffer size array size
+      //we will make this more dynamic later
+      do {
+         bulk_bytes = nbyte > FILESERV_MAX_BULK ? FILESERV_MAX_BULK : nbyte;
+         
+         //we overwrite the response here so fill in data again
+         vc_filesys_client.fileserv_msg.params[0] = (uint32_t)fildes;
+         vc_filesys_client.fileserv_msg.params[1] = 0xffffffffU;        // offset: use -1 to indicate no offset
+         
+         actual_written = vc_vchi_msg_bulk_write(&vc_filesys_client.fileserv_msg , VC_FILESYS_WRITE, (uint32_t)bulk_bytes, (uint8_t*)ptr);
+         
+         if(bulk_bytes != actual_written) {
+            if(actual_written < 0)
+               num_wrt = -1;
+            else
+               num_wrt += actual_written;
+            break;
+         }
+         
+         ptr+=bulk_bytes;
+         nbyte -= actual_written;
+         num_wrt += actual_written;
+      }while(nbyte > 0);
+
+      lock_release();
+   }
+
+   return num_wrt;
+}
+
+
+/* Directory management functions */
+
+/******************************************************************************
+NAME
+   vc_filesys_closedir
+
+SYNOPSIS
+   int vc_filesys_closedir(void *dhandle)
+
+FUNCTION
+   Ends a directory list iteration.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_filesys_closedir(void *dhandle)
+{
+   return vc_filesys_single_param((uint32_t)dhandle, VC_FILESYS_CLOSEDIR);
+}
+
+
+/******************************************************************************
+NAME
+   vc_filesys_format
+
+SYNOPSIS
+   int vc_filesys_format(const char *path)
+
+FUNCTION
+   Formats the physical file system that contains path.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_filesys_format(const char *path)
+{
+   return vc_filesys_single_string(0, path, VC_FILESYS_FORMAT, 0);
+}
+
+
+/******************************************************************************
+NAME
+   vc_filesys_freespace
+
+SYNOPSIS
+   int vc_filesys_freespace(const char *path)
+
+FUNCTION
+   Returns the amount of free space on the physical file system that contains
+   path.
+
+RETURNS
+   Successful completion: free space
+   Otherwise: -1
+******************************************************************************/
+
+int vc_filesys_freespace(const char *path)
+{
+   return vc_filesys_single_string(0, path, VC_FILESYS_FREESPACE, 1);
+}
+
+
+/******************************************************************************
+NAME
+   vc_filesys_freespace64
+
+SYNOPSIS
+   int64_t vc_filesys_freespace64(const char *path)
+
+FUNCTION
+   Returns the amount of free space on the physical file system that contains
+   path.
+
+RETURNS
+   Successful completion: free space
+   Otherwise: -1
+******************************************************************************/
+
+int64_t vc_filesys_freespace64(const char *path)
+{
+   int64_t freespace = -1LL;
+
+   if(lock_obtain() == 0)
+   {
+      strncpy((char *)vc_filesys_client.fileserv_msg.data, path, FS_MAX_PATH);
+      
+      if (vchi_msg_stub(&vc_filesys_client.fileserv_msg, VC_FILESYS_FREESPACE64,
+                        (int)(16+strlen((char *)vc_filesys_client.fileserv_msg.data)+1)) == FILESERV_RESP_OK)
+      {
+         freespace = vc_filesys_client.fileserv_msg.params[0];
+         freespace += (int64_t)vc_filesys_client.fileserv_msg.params[1] << 32;
+      }
+
+      lock_release();
+   }
+
+   return freespace;
+}
+
+
+/******************************************************************************
+NAME
+   vc_filesys_get_attr
+
+SYNOPSIS
+   int vc_filesys_get_attr(const char *path, fattributes_t *attr)
+
+FUNCTION
+   Gets the file/directory attributes.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_filesys_get_attr(const char *path, fattributes_t *attr)
+{
+   int success = -1;
+
+   if(lock_obtain() == 0)
+   {
+      strncpy((char *)vc_filesys_client.fileserv_msg.data, path, FS_MAX_PATH);
+      
+      if (vchi_msg_stub(&vc_filesys_client.fileserv_msg, VC_FILESYS_GET_ATTR,
+                        (int)(16+strlen((char *)vc_filesys_client.fileserv_msg.data)+1)) == FILESERV_RESP_OK)
+      {
+         success = 0;
+         *attr = (fattributes_t) vc_filesys_client.fileserv_msg.params[0];
+      }
+
+      lock_release();
+   }
+
+   return success;
+}
+
+
+/******************************************************************************
+NAME
+   vc_filesys_fstat
+
+SYNOPSIS
+   int64_t vc_filesys_fstat(int fildes, FSTAT_T *buf)
+
+FUNCTION
+   Returns the file stat info structure for the specified file.
+   This structure includes date and size info.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_filesys_fstat(int fildes, FSTAT_T *buf)
+{
+   int success = -1;
+
+   if (buf != NULL && lock_obtain() == 0)
+   {
+      vc_filesys_client.fileserv_msg.params[0] = (uint32_t) fildes;
+      if ( vchi_msg_stub(&vc_filesys_client.fileserv_msg, VC_FILESYS_FSTAT, 4) == FILESERV_RESP_OK )
+      {
+         buf->st_size = (int64_t)vc_filesys_client.fileserv_msg.params[0];          // LSB
+         buf->st_size |= (int64_t)vc_filesys_client.fileserv_msg.params[1] << 32;    // MSB
+         buf->st_modtime = (uint32_t)vc_filesys_client.fileserv_msg.params[2];
+         // there's room for expansion here to pass across more elements of the structure if required...
+         success = 0;
+      }
+
+      lock_release();
+   }
+
+   return success;
+}
+
+
+/******************************************************************************
+NAME
+   vc_filesys_mkdir
+
+SYNOPSIS
+   int vc_filesys_mkdir(const char *path)
+
+FUNCTION
+   Creates a new directory named by the pathname pointed to by path.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_filesys_mkdir(const char *path)
+{
+   return vc_filesys_single_string(0, path, VC_FILESYS_MKDIR, 0);
+}
+
+
+/******************************************************************************
+NAME
+   vc_filesys_opendir
+
+SYNOPSIS
+   void *vc_filesys_opendir(const char *dirname)
+
+FUNCTION
+   Starts a directory list iteration.
+
+RETURNS
+   Successful completion: dhandle (pointer)
+   Otherwise: NULL
+******************************************************************************/
+
+void *vc_filesys_opendir(const char *dirname)
+{
+   return (void *) vc_filesys_single_string(0, dirname, VC_FILESYS_OPENDIR, 1);
+}
+
+
+/******************************************************************************
+NAME
+   vc_filesys_dirsize
+
+SYNOPSIS
+   int vc_filesys_dirsize(const char *path)
+
+FUNCTION
+   Look through the specified directory tree and sum the file sizes.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int64_t vc_filesys_dirsize(const char *path, uint32_t *num_files, uint32_t *num_dirs)
+{
+   int64_t ret = -1;
+
+   if(lock_obtain() == 0)
+   {
+      strncpy((char *)vc_filesys_client.fileserv_msg.data, path, FS_MAX_PATH);
+      
+      // FIXME: Should probably use a non-blocking call here since it may take a
+      // long time to do the operation...
+      if ( vchi_msg_stub(&vc_filesys_client.fileserv_msg,
+                         VC_FILESYS_DIRSIZE,
+                         (int)(16+strlen((char *)vc_filesys_client.fileserv_msg.data)+1)) == FILESERV_RESP_OK )
+      {
+         ret = vc_filesys_client.fileserv_msg.params[0]; 
+         ret += (int64_t)vc_filesys_client.fileserv_msg.params[1] << 32;
+         if (num_files)
+            *num_files = vc_filesys_client.fileserv_msg.params[2];
+         if (num_dirs)
+            *num_dirs = vc_filesys_client.fileserv_msg.params[3];
+      }
+
+      lock_release();
+   }
+
+   return ret;
+}
+
+
+/******************************************************************************
+NAME
+   vc_filesys_readdir_r
+
+SYNOPSIS
+   struct dirent *vc_filesys_readdir_r(void *dhandle, struct dirent *result)
+
+FUNCTION
+   Fills in the passed result structure with details of the directory entry
+   at the current psition in the directory stream specified by the argument
+   dhandle, and positions the directory stream at the next entry.
+
+RETURNS
+   Successful completion: result
+   End of directory stream: NULL
+******************************************************************************/
+
+struct dirent *vc_filesys_readdir_r(void *dhandle, struct dirent *result)
+{
+   struct dirent *ret = NULL;
+
+   if(lock_obtain() == 0)
+   {
+      vc_filesys_client.fileserv_msg.params[0] = (uint32_t)dhandle;
+      if (vchi_msg_stub(&vc_filesys_client.fileserv_msg, VC_FILESYS_READDIR, 4) == FILESERV_RESP_OK)
+      {
+         fs_host_direntbytestream_interp(result, (void *)vc_filesys_client.fileserv_msg.data);
+         ret = result;
+      }
+
+      lock_release();
+   }
+
+   return ret;
+}
+
+
+/******************************************************************************
+NAME
+   vc_filesys_remove
+
+SYNOPSIS
+   int vc_filesys_remove(const char *path)
+
+FUNCTION
+   Removes a file or a directory. A directory must be empty before it can be
+   deleted.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_filesys_remove(const char *path)
+{
+   return vc_filesys_single_string(0, path, VC_FILESYS_REMOVE, 0);
+}
+
+
+/******************************************************************************
+NAME
+   vc_filesys_rename
+
+SYNOPSIS
+   int vc_filesys_rename(const char *oldfile, const char *newfile)
+
+FUNCTION
+   Changes the name of a file. The old and new pathnames must be on the same
+   physical file system.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_filesys_rename(const char *oldfile, const char *newfile)
+{
+   int a, b, success = -1;
+
+   // Ensure the pathnames aren't too long
+   if ((a = strlen(oldfile)) < FS_MAX_PATH && (b = strlen(newfile)) < FS_MAX_PATH && lock_obtain() == 0)
+   {
+      strncpy((char *)vc_filesys_client.fileserv_msg.data, oldfile, FS_MAX_PATH);
+      strncpy((char *)&vc_filesys_client.fileserv_msg.data[a+1], newfile, FS_MAX_PATH);
+      
+      if (vchi_msg_stub(&vc_filesys_client.fileserv_msg, VC_FILESYS_RENAME, 16+a+1+b+1) == FILESERV_RESP_OK)
+         success = 0;
+
+      lock_release();
+   }
+
+   return success;
+}
+
+
+/******************************************************************************
+NAME
+   vc_filesys_reset
+
+SYNOPSIS
+   int vc_filesys_reset()
+
+FUNCTION
+   Send a vc_FILESYS_RESET command. This will return immediately.
+
+RETURNS
+   Successful completion: FILESERV_RESP_OK
+   Otherwise: -
+******************************************************************************/
+
+int vc_filesys_reset()
+{
+   return vc_filesys_single_param(0, VC_FILESYS_RESET);
+}
+
+
+/******************************************************************************
+NAME
+   vc_filesys_set_attr
+
+SYNOPSIS
+   int vc_filesys_set_attr(const char *path, fattributes_t attr)
+
+FUNCTION
+   Sets file/directory attributes.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_filesys_set_attr(const char *path, fattributes_t attr)
+{
+   return vc_filesys_single_string((uint32_t) attr, path, VC_FILESYS_SET_ATTR, 0);
+}
+
+
+/******************************************************************************
+NAME
+   vc_filesys_setend
+
+SYNOPSIS
+   int vc_filesys_setend(int fildes)
+
+FUNCTION
+   Truncates file at current position.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_filesys_setend(int fildes)
+{
+   return vc_filesys_single_param((uint32_t) fildes, VC_FILESYS_SETEND);
+}
+
+
+
+/******************************************************************************
+NAME
+   vc_filesys_scandisk
+
+SYNOPSIS
+   void vc_filesys_scandisk(const char *path)
+
+FUNCTION
+   Truncates file at current position.
+
+RETURNS
+   -
+******************************************************************************/
+
+void vc_filesys_scandisk(const char *path)
+{
+   vc_filesys_single_string(0, path, VC_FILESYS_SCANDISK, 0);
+   return;
+}
+
+/******************************************************************************
+NAME
+   vc_filesys_chkdsk
+
+SYNOPSIS
+   int vc_filesys_chkdsk(const char *path, int fix_errors)
+
+FUNCTION
+   Truncates file at current position.
+
+RETURNS
+   -
+******************************************************************************/
+
+int vc_filesys_chkdsk(const char *path, int fix_errors)
+{
+   return vc_filesys_single_string(fix_errors, path, VC_FILESYS_CHKDSK, 1);
+}
+
+/******************************************************************************
+NAME
+   vc_filesys_size
+
+SYNOPSIS
+   int vc_filesys_size(const char *path)
+
+FUNCTION
+   return size of file
+
+RETURNS
+   -
+******************************************************************************/
+
+int vc_filesys_size(const char *path)
+{
+   int fd;
+   int end_pos = 0;
+   int success = -1;
+   if((fd = vc_filesys_open(path, VC_O_RDONLY)) == 0)
+   {
+      end_pos = vc_filesys_lseek(fd, 0, SEEK_END);
+      success = vc_filesys_close(fd);
+      (void)success;
+   }
+
+   return end_pos;
+}
+/******************************************************************************
+NAME
+   vc_filesys_totalspace
+
+SYNOPSIS
+   int vc_filesys_totalspace(const char *path)
+
+FUNCTION
+   Returns the total amount of space on the physical file system that contains
+   path.
+
+RETURNS
+   Successful completion: total space
+   Otherwise: -1
+******************************************************************************/
+
+int vc_filesys_totalspace(const char *path)
+{
+   return vc_filesys_single_string(0, path, VC_FILESYS_TOTALSPACE, 1);
+}
+
+
+/******************************************************************************
+NAME
+   vc_filesys_totalspace64
+
+SYNOPSIS
+   int64_t vc_filesys_totalspace64(const char *path)
+
+FUNCTION
+   Returns the total amount of space on the physical file system that contains
+   path.
+
+RETURNS
+   Successful completion: total space
+   Otherwise: -1
+******************************************************************************/
+
+int64_t vc_filesys_totalspace64(const char *path)
+{
+   int64_t totalspace = -1LL;
+
+   if(lock_obtain() == 0)
+   {
+      strncpy((char *)vc_filesys_client.fileserv_msg.data, path, FS_MAX_PATH);
+      
+      if (vchi_msg_stub(&vc_filesys_client.fileserv_msg, VC_FILESYS_TOTALSPACE64,
+                        (int)(16+strlen((char *)vc_filesys_client.fileserv_msg.data)+1)) == FILESERV_RESP_OK)
+      {
+         totalspace = vc_filesys_client.fileserv_msg.params[0];
+         totalspace += (int64_t)vc_filesys_client.fileserv_msg.params[1] << 32;
+      }
+
+      lock_release();
+   }
+
+   return totalspace;
+}
+
+
+/******************************************************************************
+NAME
+   vc_filesys_diskwritable
+
+SYNOPSIS
+   int vc_filesys_diskwritable(const char *path)
+
+FUNCTION
+   Return whether the named disk is writable.
+
+RETURNS
+   Successful completion: 1 (disk writable) or 0 (disk not writable)
+   Otherwise: -1
+******************************************************************************/
+
+int vc_filesys_diskwritable(const char *path)
+{
+   return vc_filesys_single_string(0, path, VC_FILESYS_DISKWRITABLE, 1);
+}
+
+/******************************************************************************
+NAME
+   vc_filesys_fstype
+
+SYNOPSIS
+   int vc_filesys_fstype(const char *path)
+
+FUNCTION
+   Return the filesystem type of the named disk.
+
+RETURNS
+   Successful completion: disk type (see vc_fileservice_defs.h)
+   Otherwise: -1
+******************************************************************************/
+
+int vc_filesys_fstype(const char *path)
+{
+   return vc_filesys_single_string(0, path, VC_FILESYS_FSTYPE, 1);
+}
+
+/******************************************************************************
+NAME
+   vc_filesys_open_disk_raw
+
+SYNOPSIS
+   int vc_filesys_open_disk_raw(const char *path)
+
+FUNCTION
+   Open disk for access in raw mode.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_filesys_open_disk_raw(const char *path)
+{
+   return vc_filesys_single_string(0, path, VC_FILESYS_OPEN_DISK_RAW, 1);
+}
+
+/******************************************************************************
+NAME
+   vc_filesys_close_disk_raw
+
+SYNOPSIS
+   int vc_filesys_close_disk_raw(const char *path)
+
+FUNCTION
+   Close disk from access in raw mode.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_filesys_close_disk_raw(const char *path)
+{
+   return vc_filesys_single_string(0, path, VC_FILESYS_CLOSE_DISK_RAW, 1);
+}
+
+
+/******************************************************************************
+NAME
+   vc_filesys_open_disk
+
+SYNOPSIS
+   int vc_filesys_open_disk(const char *path)
+
+FUNCTION
+   Open disk for normal access.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_filesys_open_disk(const char *path)
+{
+   return vc_filesys_single_string(0, path, VC_FILESYS_OPEN_DISK, 1);
+}
+
+/******************************************************************************
+NAME
+   vc_filesys_close_disk
+
+SYNOPSIS
+   int vc_filesys_close_disk(const char *path)
+
+FUNCTION
+   Close disk from normal access.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_filesys_close_disk(const char *path)
+{
+   return vc_filesys_single_string(0, path, VC_FILESYS_CLOSE_DISK, 1);
+}
+
+/******************************************************************************
+NAME
+   vc_filesys_numsectors
+
+SYNOPSIS
+   int vc_filesys_numsectors(const char *path)
+
+FUNCTION
+   Return number of sectors on disk
+
+RETURNS
+   Successful completion: greater than 0
+   Otherwise: -1
+******************************************************************************/
+
+int vc_filesys_numsectors(const char *path)
+{
+   return vc_filesys_single_string(0, path, VC_FILESYS_NUMSECTORS, 1);
+}
+
+/******************************************************************************
+NAME
+   vc_filesys_read_sectors
+
+SYNOPSIS
+   int vc_filesys_read_sectors(const char *path, uint32_t sector_num, char *buffer, uint32_t num_sectors)
+
+FUNCTION
+   Start streaming sectors from 2727
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+int vc_filesys_read_sectors(const char *path, uint32_t sector_num, char *sectors, uint32_t num_sectors, uint32_t *sectors_read)
+{
+#if VCHI_BULK_ALIGN > 1
+   uint32_t align_bytes = 0;
+#endif
+   char* bulk_addr = sectors;
+   int len;
+   int ret = -1;
+
+   if((len = (int)strlen(path)) < FS_MAX_PATH && lock_obtain() == 0)
+   {
+      strncpy((char *)vc_filesys_client.fileserv_msg.data, path, FS_MAX_PATH);
+      vc_filesys_client.fileserv_msg.params[0] = sector_num;
+      vc_filesys_client.fileserv_msg.params[1] = num_sectors;
+
+#if VCHI_BULK_ALIGN > 1
+      //required to make buffer aligned for bulk
+      align_bytes = VCHI_BULK_ALIGN_NBYTES(sectors);
+#endif
+      //note for read we are currently doing memcpy on host to tell 2727 align is 0
+      vc_filesys_client.fileserv_msg.params[2] = 0;
+      
+      //we send read request
+      if (vchi_msg_stub_noblock(&vc_filesys_client.fileserv_msg, VC_FILESYS_READ_SECTORS, 16+len+1) == 0)
+      {
+         while(num_sectors)
+         {
+            uint32_t bulk_sectors = (num_sectors > FILESERV_MAX_BULK_SECTOR) ? (uint32_t)FILESERV_MAX_BULK_SECTOR : num_sectors;
+            if(vchi_bulk_queue_receive( vc_filesys_client.open_handle,
+#if VCHI_BULK_ALIGN > 1
+                                        align_bytes ? vc_filesys_client.bulk_buffer : bulk_addr,
+#else
+                                        bulk_addr,
+#endif
+                                        (bulk_sectors*FILESERV_SECTOR_LENGTH), VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE, NULL) != 0)
+               break;
+
+#if VCHI_BULK_ALIGN > 1
+            if(align_bytes) {
+               //this is bad but will do for now..
+               memcpy( bulk_addr, vc_filesys_client.bulk_buffer, (bulk_sectors*FILESERV_SECTOR_LENGTH));
+            }
+#endif
+            bulk_addr += (bulk_sectors*FILESERV_SECTOR_LENGTH);
+            num_sectors -= bulk_sectors;
+         }
+
+         // now wait to receive resp from original msg...
+         if(vcos_event_wait(&vc_filesys_client.response_event) == VCOS_SUCCESS && vc_filesys_client.fileserv_msg.cmd_code == FILESERV_RESP_OK)
+         {
+            *sectors_read = vc_filesys_client.fileserv_msg.params[0];
+            ret = 0;
+         }
+         else
+         {
+            //error code in [0]
+            *sectors_read = vc_filesys_client.fileserv_msg.params[1];
+            ret = vc_filesys_client.fileserv_msg.params[0];
+         }
+      }
+
+      lock_release();
+   }
+
+   return ret;
+}
+
+/******************************************************************************
+NAME
+   vc_filesys_write_sectors
+
+SYNOPSIS
+   int vc_filesys_write_sectors(const char *path, uint32_t sector_num, char *sectors, uint32_t num_sectors, uint32_t *sectors_written)
+
+FUNCTION
+   Start streaming sectors to 2727
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -error code
+******************************************************************************/
+int vc_filesys_write_sectors(const char *path, uint32_t sector_num, char *sectors, uint32_t num_sectors, uint32_t *sectors_written)
+{
+   uint32_t align_bytes = 0;
+   char* bulk_addr = sectors;
+   int len;
+   int ret = -1;
+
+   len = (int) strlen(path);
+   if((len = (int) strlen(path)) < FS_MAX_PATH && lock_obtain() == 0)
+   {
+      vc_filesys_client.fileserv_msg.params[0] = sector_num;
+      vc_filesys_client.fileserv_msg.params[1] = num_sectors;
+      
+      //required to make buffer aligned for bulk
+      align_bytes = ((unsigned long)sectors & (VCHI_BULK_ALIGN-1));
+      vc_filesys_client.fileserv_msg.params[2] = align_bytes;
+      
+      //copy path at end of any alignbytes
+      strncpy(((char *)vc_filesys_client.fileserv_msg.data), path, FS_MAX_PATH);
+      
+      //we send write request
+      if (vchi_msg_stub_noblock(&vc_filesys_client.fileserv_msg, VC_FILESYS_WRITE_SECTORS, 16+len+1) == 0)
+      {
+         if(align_bytes) {
+            //note we are cheating and going backward to make addr aligned and sending more data...
+            bulk_addr -= align_bytes;
+         }
+         
+         while(num_sectors) {
+            uint32_t bulk_sectors = (num_sectors > FILESERV_MAX_BULK_SECTOR) ? (uint32_t)FILESERV_MAX_BULK_SECTOR : num_sectors;
+            //we send some extra data at the start
+            if(vchi_bulk_queue_transmit( vc_filesys_client.open_handle, bulk_addr,
+                                         VCHI_BULK_ROUND_UP((bulk_sectors*FILESERV_SECTOR_LENGTH)+align_bytes),
+                                         VCHI_FLAGS_BLOCK_UNTIL_DATA_READ, NULL) != 0)
+               break;
+            
+            //go to next ALIGNED address
+            bulk_addr += FILESERV_MAX_BULK;
+            num_sectors -= bulk_sectors;
+         }
+         
+         // now wait to receive resp from original msg...
+         if(vcos_event_wait(&vc_filesys_client.response_event) == VCOS_SUCCESS && vc_filesys_client.fileserv_msg.cmd_code == FILESERV_RESP_OK)
+         {
+            *sectors_written = vc_filesys_client.fileserv_msg.params[0];
+            ret = 0;
+         }
+         else
+         {
+            //error code in [0]
+            *sectors_written = vc_filesys_client.fileserv_msg.params[1];
+            ret = vc_filesys_client.fileserv_msg.params[0];
+         }
+      }
+
+      lock_release();
+   }
+
+   return ret;
+}
+
+/******************************************************************************
+NAME
+   vc_filesys_errno
+
+SYNOPSIS
+   int vc_filesys_errno(void)
+
+FUNCTION
+   Returns the error code of the last file system error that occurred.
+
+RETURNS
+   Error code
+******************************************************************************/
+
+int vc_filesys_errno(void)
+{
+   return (int) vc_filesys_client.err_no;
+}
+
+
+/* File Service Message FIFO functions */
+
+/******************************************************************************
+NAME
+   vchi_msg_stub
+
+SYNOPSIS
+   static int vc_fs_stub(int verb, int ext_len)
+
+FUNCTION
+   Generates a request and sends it to the co-processor. It then suspends
+   until it receives a reply from the host. The calling task must hold
+   the filesys_lock.
+
+RETURNS
+   Successful completion: Response code of reply
+   Otherwise: -
+******************************************************************************/
+static int vchi_msg_stub(FILESERV_MSG_T* msg, uint16_t cmd_id, int msg_len )
+{
+   int ret = -1;
+   vchi_msg_stub_noblock(msg, cmd_id, msg_len);
+    
+   // wait to receive response
+   if(vcos_event_wait(&vc_filesys_client.response_event) == VCOS_SUCCESS)
+      ret = (int) msg->cmd_code;
+
+   return ret;
+}
+
+static int vchi_msg_stub_noblock(FILESERV_MSG_T* msg, uint16_t cmd_id, int msg_len)
+{
+   uint32_t i;
+
+   if(!vcos_verify(msg_len <= VCHI_MAX_MSG_SIZE))
+      return -1;
+
+   //will get changed by response from command
+   vc_filesys_client.resp_code = FILESERV_RESP_ERROR;
+
+   //the top bit is used for host/vc
+   i = vc_filesys_client.cur_xid + 1;
+   i &= 0x7fffffffUL;
+   vc_filesys_client.cur_xid = i;
+
+   //fill in transaction id, used for response identification
+   vchi_writebuf_uint32( &(msg->xid), vc_filesys_client.cur_xid  );
+
+   //fill in cmd id VC_FILESYS_OPEN etc
+   vchi_writebuf_uint32( &(msg->cmd_code), cmd_id );
+
+   //we always have cmd_id, xid
+   msg_len += 8;
+    
+   //return response code
+   return (int) vchi_msg_queue( vc_filesys_client.open_handle, msg, (uint32_t)msg_len, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL );
+}
+
+static int vc_send_response( FILESERV_MSG_T* msg, uint32_t retval, uint32_t nbytes )
+{
+   int success = -1;
+   //convert all to over the wire values
+   vchi_writebuf_uint32(&msg->cmd_code, retval);
+   vchi_writebuf_uint32(&msg->xid, msg->xid);
+   vchi_writebuf_uint32(&msg->params[0], msg->params[0]);
+   vchi_writebuf_uint32(&msg->params[1], msg->params[1]);
+   vchi_writebuf_uint32(&msg->params[2], msg->params[2]);
+   vchi_writebuf_uint32(&msg->params[3], msg->params[3]);
+
+   //start with 8 because always xid and retval
+   nbytes += 8;
+
+   if(vcos_verify(nbytes <= VCHI_MAX_MSG_SIZE))
+      success = (int) vchi_msg_queue( vc_filesys_client.open_handle, msg, nbytes, VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL );
+
+   return success;
+}
+
+/******************************************************************************
+NAME
+   vc_fs_message_handler
+
+SYNOPSIS
+   static int vc_fs_message_handler()
+
+FUNCTION
+   Handle messages from the co-processor.
+
+RETURNS
+   0 - No message found.
+   1 - Request received and actioned.
+   2 - Reply received.
+******************************************************************************/
+
+static int vc_fs_message_handler( FILESERV_MSG_T* msg, uint32_t nbytes )
+{
+   int rr = 0;
+   uint32_t xid = vchi_readbuf_uint32(&msg->xid);
+
+   if (xid == vc_filesys_client.cur_xid) {
+
+         //memcpy reply to msg should really peek before
+      vc_filesys_client.fileserv_msg.xid = xid;
+      vc_filesys_client.fileserv_msg.cmd_code  = vchi_readbuf_uint32(&msg->cmd_code);
+      vc_filesys_client.fileserv_msg.params[0] = vchi_readbuf_uint32(&msg->params[0]);
+      vc_filesys_client.fileserv_msg.params[1] = vchi_readbuf_uint32(&msg->params[1]);
+      vc_filesys_client.fileserv_msg.params[2] = vchi_readbuf_uint32(&msg->params[2]);
+      vc_filesys_client.fileserv_msg.params[3] = vchi_readbuf_uint32(&msg->params[3]);
+
+      //copy any data, 24 is size of header
+      if(nbytes >24)
+         memcpy(&vc_filesys_client.fileserv_msg.data, msg->data, (nbytes-24));
+
+      vc_filesys_client.resp_code = (int32_t)vc_filesys_client.fileserv_msg.cmd_code;
+
+      if (vc_filesys_client.resp_code == FILESERV_RESP_ERROR) {
+         vc_filesys_client.err_no = (int32_t)vc_filesys_client.fileserv_msg.params[0];
+      }
+
+      // signal vchi_msg_stub which will be waiting for response
+      vcos_event_signal(&vc_filesys_client.response_event);
+
+      rr = 2;
+   }
+   else if ((xid & 0x80000000UL) == 0x80000000UL) {
+      /* Process new requests from the co-processor */
+
+      uint32_t retval = FILESERV_RESP_OK;
+
+      //this is the number of uint32_t param[] + data that we send back to VC in bytes
+
+      uint32_t rlen = 0;
+      int i;
+
+      switch (msg->cmd_code) {
+
+      case VC_FILESYS_CLOSE:
+
+         i = vc_hostfs_close((int)msg->params[0]);
+         if (i != 0) {
+            retval = FILESERV_RESP_ERROR;
+         }
+         rlen = 0;
+         break;
+
+      case VC_FILESYS_CLOSEDIR:
+
+         i = vc_hostfs_closedir((void *)msg->params[0]);
+         if (i != 0) {
+            retval = FILESERV_RESP_ERROR;
+         }
+         rlen = 0;
+         break;
+
+      case VC_FILESYS_FORMAT:
+
+         i = vc_hostfs_format((const char *)msg->data);
+         if (i != 0) {
+            retval = FILESERV_RESP_ERROR;
+         }
+         rlen = 0;
+         break;
+
+      case VC_FILESYS_FREESPACE:
+
+         i = vc_hostfs_freespace((const char *)msg->data);
+         if (i < 0) {
+            retval = FILESERV_RESP_ERROR;
+            rlen = 0;
+         } else {
+            msg->params[0] = (uint32_t)i;
+            rlen = 4;
+         }
+         break;
+
+      case VC_FILESYS_FREESPACE64:
+         {
+            int64_t freespace;
+            freespace = vc_hostfs_freespace64((const char *)msg->data);
+            if (freespace < (int64_t)0) {
+               retval = FILESERV_RESP_ERROR;
+               rlen = 0;
+            } else {
+               msg->params[0] = (uint32_t)freespace;
+               msg->params[1] = (uint32_t)(freespace>>32);
+               rlen = 8;
+            }
+         }
+         break;
+
+      case VC_FILESYS_GET_ATTR:
+         {
+            fattributes_t attr;
+
+            i = vc_hostfs_get_attr((const char *)msg->data,
+                                   &attr);
+            if (i != 0) {
+               retval = FILESERV_RESP_ERROR;
+               rlen = 0;
+            } else {
+               msg->params[0] = (uint32_t) attr;
+               rlen = 4;
+            }
+         }
+         break;
+      case VC_FILESYS_LSEEK:
+
+         i = vc_hostfs_lseek( (int)msg->params[0],
+                              (int)msg->params[1],
+                              (int)msg->params[2]);
+         if (i < 0) {
+            retval = FILESERV_RESP_ERROR;
+            rlen = 0;
+         } else {
+            msg->params[0] = (uint32_t) i;
+            rlen = 4;
+         }
+         break;
+
+      case VC_FILESYS_LSEEK64:
+         {
+            int64_t offset;
+            offset = (((int64_t) msg->params[2]) << 32) + msg->params[1];
+
+            offset = vc_hostfs_lseek64( (int)msg->params[0], offset, (int)msg->params[3]);
+            if (offset < (int64_t)0) {
+               retval = FILESERV_RESP_ERROR;
+               rlen = 0;
+            } else {
+               msg->params[0] = (uint32_t)offset;
+               msg->params[1] = (uint32_t)(offset>>32);
+               rlen = 8;
+            }
+         }
+         break;
+
+      case VC_FILESYS_MKDIR:
+
+         i = vc_hostfs_mkdir((const char *)msg->data);
+         if (i != 0) {
+            retval = FILESERV_RESP_ERROR;
+         }
+         rlen = 0;
+         break;
+
+      case VC_FILESYS_OPEN:
+
+         i = vc_hostfs_open((const char *)msg->data,
+                            (int) msg->params[0]);
+         if (i < 0) {
+            retval = FILESERV_RESP_ERROR;
+         } else {
+            msg->params[0] = (uint32_t) i;
+         }
+         rlen = 4;
+         break;
+
+      case VC_FILESYS_OPENDIR:
+
+         msg->params[0] = (uint32_t)vc_hostfs_opendir(
+                                                      (const char *)msg->data);
+         if ((void *)msg->params[0] == NULL) {
+            retval = FILESERV_RESP_ERROR;
+         }
+         rlen = 4;
+         break;
+
+      case VC_FILESYS_READ:
+         {
+            uint32_t fd = msg->params[0];
+            uint32_t offset = msg->params[1];
+            int total_bytes = (int)msg->params[2];
+            uint32_t nalign_bytes = msg->params[3];
+
+            i = 0;
+
+            if(!vcos_verify(((int)vc_filesys_client.bulk_buffer & (VCHI_BULK_ALIGN-1)) == 0 &&
+                            total_bytes <= FILESERV_MAX_BULK))
+            {
+               retval = FILESERV_RESP_ERROR;
+               rlen = 4;
+               break;
+            }
+
+            rlen = 0;
+
+            //perform any seeking
+            if ( (uint32_t)0xffffffffUL != offset)
+            {
+               i = vc_hostfs_lseek( (int)fd,
+                                    (long int) offset,
+                                    VC_FILESYS_SEEK_SET);
+               if ( 0 > i)
+               {
+                  retval = FILESERV_RESP_ERROR;
+                  rlen = 4;
+                  break;
+               }
+            }
+
+
+            //put it all in one msg
+            if(total_bytes <= FILESERV_MAX_DATA) {
+               i = vc_hostfs_read( (int)fd,
+                                   msg->data,
+                                   (unsigned int) total_bytes);
+
+               if(i < 0) {
+                  retval = FILESERV_RESP_ERROR;
+                  msg->params[0] = 0;
+               }
+               else {
+                  retval = FILESERV_RESP_OK;
+                  //send back length of read
+                  msg->params[0] = (uint32_t) i;
+               }
+
+               msg->params[1] = 0;
+               rlen = 16 + (uint32_t) i;
+            }
+            //bulk transfer required
+            else {
+               uint32_t end_bytes = 0;
+               retval = FILESERV_BULK_WRITE;
+
+               //we send the bytes required for HOST buffer align
+               if(nalign_bytes) {
+                  i = vc_hostfs_read( (int)fd,
+                                      msg->data,
+                                      (unsigned int)nalign_bytes);
+                  if(i < 0) {
+                     retval = FILESERV_RESP_ERROR;
+                     rlen = 16;
+                     break;
+                  }
+                  else if(i != (int)nalign_bytes) {
+                     //all data will be in one msg
+                     retval = FILESERV_RESP_OK;
+                     msg->params[0] = (uint32_t) i;
+                     msg->params[1] = 0;
+                     rlen = 16 + (uint32_t) i;
+                     //send response
+                     break;
+                  }
+
+                  total_bytes -= i;
+                  rlen += (uint32_t) i;
+               }
+
+               //bulk bytes
+               i = vc_hostfs_read((int)fd, vc_filesys_client.bulk_buffer, (unsigned int)total_bytes);
+
+               if(i < 0) {
+                  retval = FILESERV_RESP_ERROR;
+                  rlen = 16;
+                  break;
+               }
+               else if((i+nalign_bytes) <= FILESERV_MAX_DATA) {
+                  retval = FILESERV_RESP_OK;
+                  memcpy(&msg->data[nalign_bytes], &vc_filesys_client.bulk_buffer[0], (size_t) i);
+                  //read size
+                  msg->params[0] = (i + nalign_bytes);
+                  msg->params[1] = 0;
+                  rlen = i + nalign_bytes + 16;
+                  break;
+               }
+
+               //copy end unaligned length bytes into msg->data
+               end_bytes  = (uint32_t) (i & (VCHI_BULK_GRANULARITY-1));
+               if(end_bytes) {
+                  int end_index = i - (int) end_bytes;
+                  memcpy(&msg->data[nalign_bytes], &vc_filesys_client.bulk_buffer[end_index], end_bytes);
+                  rlen += end_bytes;
+               }
+
+               //send back total bytes
+               msg->params[0] = (uint32_t)(i + nalign_bytes);
+               //number of end bytes
+               msg->params[1] = end_bytes;
+               //number of bulk bytes
+               msg->params[2] = (uint32_t)(i - end_bytes);
+               //16 for param len
+               rlen += 16;
+
+               //queue bulk to be sent
+               if(vchi_bulk_queue_transmit( vc_filesys_client.open_handle,
+                                            vc_filesys_client.bulk_buffer,
+                                            msg->params[2],
+                                            VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
+                                            NULL ) != 0)
+               {
+                  retval = FILESERV_RESP_ERROR;
+                  rlen = 4;
+                  break;
+               }
+            }
+         }
+         //send response
+         break;
+
+      case VC_FILESYS_READDIR:
+         {
+            struct dirent result;
+            if (vc_hostfs_readdir_r((void *)msg->params[0],
+                                    &result) == NULL) {
+               retval = FILESERV_RESP_ERROR;
+               rlen = 4;
+            } else {
+               rlen = (uint32_t) (16+fs_host_direntbytestream_create(&result,
+                                                                     (void *)msg->data));
+            }
+         }
+         break;
+
+      case VC_FILESYS_REMOVE:
+
+         i = vc_hostfs_remove((const char *)msg->data);
+         if (i != 0) {
+            retval = FILESERV_RESP_ERROR;
+         }
+         rlen = 0;
+         break;
+
+      case VC_FILESYS_RENAME:
+
+         i = (int) strlen((char *)msg->data);
+         if (vc_hostfs_rename((const char *)msg->data,
+                              (const char *)&msg->data[i+1])
+             != 0) {
+            retval = FILESERV_RESP_ERROR;
+         }
+         rlen = 0;
+         break;
+
+      case VC_FILESYS_SETEND:
+
+         i = vc_hostfs_setend( (int)msg->params[0] );
+         if (i != 0) {
+            retval = FILESERV_RESP_ERROR;
+         }
+         rlen = 0;
+         break;
+
+      case VC_FILESYS_SET_ATTR:
+
+         i = vc_hostfs_set_attr((const char *)msg->data,
+                                (fattributes_t)msg->params[0]);
+         if (i != 0) {
+            retval = FILESERV_RESP_ERROR;
+         }
+         rlen = 0;
+         break;
+
+      case VC_FILESYS_TOTALSPACE:
+
+         i = vc_hostfs_totalspace((const char *)msg->data);
+         if (i < 0) {
+            retval = FILESERV_RESP_ERROR;
+            rlen = 0;
+         } else {
+            msg->params[0] = (uint32_t) i;
+            rlen = 4;
+         }
+         break;
+
+      case VC_FILESYS_TOTALSPACE64:
+         {
+            int64_t totalspace;
+            totalspace = vc_hostfs_totalspace64((const char *)msg->data);
+            if (totalspace < (int64_t)0) {
+               retval = FILESERV_RESP_ERROR;
+               rlen = 0;
+            } else {
+               msg->params[0] = (uint32_t)totalspace;
+               msg->params[1] = (uint32_t)(totalspace>>32);
+               rlen = 8;
+            }
+         }
+         break;
+#if 0  // I don't think host systems are ready for these yet
+      case VC_FILESYS_SCANDISK:
+
+         vc_hostfs_scandisk((const char *)msg->data);
+         rlen = 0;
+         break;
+
+      case VC_FILESYS_CHKDSK:
+
+         i = vc_hostfs_chkdsk((const char *)msg->data, msg->params[0]);
+         if (i < 0) {
+            retval = FILESERV_RESP_ERROR;
+            rlen = 0;
+         } else {
+            msg->params[0] = (uint32_t)i;
+            rlen = 4;
+         }
+         break;
+#endif
+      case VC_FILESYS_WRITE:
+         {
+            uint32_t fd = msg->params[0];
+            //            uint32_t offset = msg->params[1];
+            int total_bytes = (int)msg->params[2];
+            uint32_t nalign_bytes = msg->params[3];
+            retval = FILESERV_RESP_OK;
+            i = 0;
+
+            //everything in one msg
+            if(total_bytes <= FILESERV_MAX_DATA)
+            {
+               i = vc_hostfs_write( (int)fd,
+                                    msg->data,
+                                    (unsigned int) total_bytes);
+               if (i < 0) {
+                  retval = FILESERV_RESP_ERROR;
+               } else {
+                  msg->params[0] = (uint32_t) i;
+               }
+               rlen = 4;
+               //send response
+               break;
+            }
+            else
+            {
+               uint32_t end_bytes;
+               uint32_t bulk_bytes;
+               uint32_t total_bytes_written = 0;
+               i = 0;
+               //one return param
+               rlen = 4;
+               retval = FILESERV_BULK_READ;
+
+               //write bytes required for VC buffer align
+               if(nalign_bytes) {
+                  i = vc_hostfs_write( (int)fd,
+                                       msg->data,
+                                       (unsigned int)nalign_bytes);
+                  if(i < 0) {
+                     retval = FILESERV_RESP_ERROR;
+                     msg->params[0] = 0;
+                     //break from switch and send reply
+                     break;
+                  }
+                  total_bytes_written += i;
+                  total_bytes -= nalign_bytes;
+               }
+
+               //calculate bytes that wil lbe sent by bulk
+               bulk_bytes = (uint32_t)((total_bytes)&(~(VCHI_BULK_ALIGN-1)));
+            
+               end_bytes = total_bytes-bulk_bytes;
+
+
+
+               if(vchi_bulk_queue_receive(vc_filesys_client.open_handle,
+                                          vc_filesys_client.bulk_buffer,
+                                          bulk_bytes,
+                                          VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE,
+                                          NULL) != 0 ||
+                  (i = vc_hostfs_write( (int)fd,
+                                        vc_filesys_client.bulk_buffer,
+                                        (unsigned int) bulk_bytes)) < 0)
+               {
+                  retval = FILESERV_RESP_ERROR;
+                  msg->params[0] = 0;
+                  break;
+               }
+            
+               total_bytes_written += i;
+            
+               if(end_bytes) {
+                  i = vc_hostfs_write( (int)fd,
+                                       msg->data+nalign_bytes,
+                                       (unsigned int)end_bytes);
+               
+                  total_bytes_written += i;
+               }
+            
+               if(i < 0) {
+                  retval = FILESERV_RESP_ERROR;
+                  msg->params[0] = 0;
+                  break;
+               }
+            
+               msg->params[0] = total_bytes_written;
+
+            }
+         }
+         break;
+
+      default:
+         rlen = 4;
+         retval = FILESERV_RESP_ERROR;
+         break;
+      }
+
+      //convert all to over the wire values and send
+      vc_send_response( msg, retval, rlen );
+
+      rr = 1;
+
+   } else {
+      /* A message has been left in the fifo and the host side has been reset.
+         The message needs to be flushed. It would be better to do this by resetting
+         the fifos. */
+   }
+
+   return rr;
+}
+
+
+/******************************************************************************
+NAME
+   showmsg
+
+SYNOPSIS
+   static void showmsg(VC_MSGFIFO_CMD_HEADER_T const * head,
+                       struct file_service_msg_body const * body)
+
+FUNCTION
+   De-bug tool: prints out fifo message.
+
+RETURNS
+   void
+******************************************************************************/
+
+#ifdef PRINTF
+static void showmsg(VC_MSGFIFO_CMD_HEADER_T const * head,
+                    struct file_service_msg_body const * body)
+{
+   unsigned int ael = (head->ext_length + 15) & ~15;
+   printf("Sync=%08x XID=%08x Code=%08x Extlen=%08x (%d bytes follow)\n",
+          head->sync, head->xid, head->cmd_code, head->ext_length, ael);
+   if (ael) {
+      unsigned int i;
+      printf("Content:");
+      for (i = 0; i < 4 && i*4 < head->ext_length; ++i) printf(" %08x", body->params[i]);
+      //for(i = 0; i+16 < head->ext_length; ++i) printf(" %02x", body->data[i]);
+      if (head->ext_length > 16) printf(" plus %d bytes\n", head->ext_length);
+   }
+   printf("\n");
+}
+#endif
+
+
+/******************************************************************************
+NAME
+   fs_host_direntbytestream_create
+
+SYNOPSIS
+   static int fs_host_direntbytestream_create(struct dirent *d, void *buffer)
+
+FUNCTION
+   Turns a variable of type struct dirent into a compiler independent byte
+   stream, which is stored in buffer.
+
+RETURNS
+   Successful completion: The length of the byte stream
+   Otherwise: -1
+******************************************************************************/
+static void write_bytestream(void *a, char *b, int n)
+{
+   int i;
+   for (i=0;i<n;i++) {
+      b[i] = ((char *)a)[i];
+   }
+   for (;i<4;i++) {
+      b[i] = 0;
+   }
+}
+
+static int fs_host_direntbytestream_create(struct dirent *d, void *buffer)
+{
+   char *buf = (char*)buffer;
+
+   // Write d_name (D_NAME_MAX_SIZE chars)
+   memcpy(buf, &d->d_name, D_NAME_MAX_SIZE);
+   buf += D_NAME_MAX_SIZE;
+
+   // Write d_size (unsigned int)
+   write_bytestream((void *)&d->d_size, buf, (int)sizeof(d->d_size));
+   buf += 4;
+
+   // Write d_attrib (int)
+   write_bytestream((void *)&d->d_attrib, buf, (int)sizeof(d->d_attrib));
+   buf += 4;
+
+   // Write d_modtime (time_t)
+   write_bytestream((void *)&d->d_modtime, buf, (int)sizeof(d->d_modtime));
+   buf += 4;
+
+   return (int)(buf-(char *)buffer);
+}
+
+
+/******************************************************************************
+NAME
+   fs_host_direntbytestream_interp
+
+SYNOPSIS
+   static void fs_host_direntbytestream_interp(struct dirent *d, void *buffer)
+
+FUNCTION
+   Turns a compiler independent byte stream back into a struct of type dirent.
+
+RETURNS
+   Successful completion: 0
+   Otherwise: -1
+******************************************************************************/
+static void read_bytestream(void *a, char *b, int n)
+{
+   int i;
+   for (i=0;i<n;i++) {
+      ((char *)a)[i] = b[i];
+   }
+}
+
+static void fs_host_direntbytestream_interp(struct dirent *d, void *buffer)
+{
+   char *buf = (char*)buffer;
+
+   // Read d_name (D_NAME_MAX_SIZE chars)
+   memcpy(&d->d_name, buf, D_NAME_MAX_SIZE);
+   buf += D_NAME_MAX_SIZE;
+
+   // Read d_size (unsigned int)
+   read_bytestream((void *)&d->d_size, buf, (int)sizeof(d->d_size));
+   d->d_size = VC_VTOH32(d->d_size);
+   buf += 4;
+
+   // Read d_attrib (int)
+   read_bytestream((void *)&d->d_attrib, buf, (int)sizeof(d->d_attrib));
+   d->d_attrib = VC_VTOH32(d->d_attrib);
+   buf += 4;
+
+   // Read d_modtime (time_t)
+   read_bytestream((void *)&d->d_modtime, buf, (int)sizeof(d->d_modtime));
+   d->d_modtime = VC_VTOH32(d->d_modtime);
+
+   return;
+}
+
+
+
+void vc_filesys_sendreset(void)
+{
+   //TODO
+}
diff --git a/interface/vmcs_host/vc_vchi_filesys.h b/interface/vmcs_host/vc_vchi_filesys.h
new file mode 100755 (executable)
index 0000000..393a3eb
--- /dev/null
@@ -0,0 +1,184 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VC_VCHI_VCFILESYS_H_
+#define VC_VCHI_VCFILESYS_H_
+
+#include "vchost_platform_config.h"
+#include "vcfilesys_defs.h"
+#include "vc_fileservice_defs.h"
+#include "interface/vchi/vchi.h"
+
+#ifndef _DIRENT_H  // This should really be in a dirent.h header to avoid conflicts
+typedef struct DIR_tag DIR;
+#endif // ifndef _DIRENT_H
+
+typedef struct {   
+   int64_t  st_size;    /* total size, in bytes  (off_t)*/      
+   uint32_t st_modtime;   /* time of last modification (time_t)*/   
+} FSTAT_T;
+
+
+VCHPRE_ int VCHPOST_  vc_vchi_filesys_init (VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections );
+
+// Stop it to prevent the functions from trying to use it.
+VCHPRE_ void VCHPOST_ vc_filesys_stop(void);
+
+// Return the service number (-1 if not running).
+VCHPRE_ int VCHPOST_ vc_filesys_inum(void);
+
+// Low level file system functions equivalent to close(), lseek(), open(), read() and write()
+VCHPRE_ int VCHPOST_ vc_filesys_close(int fildes);
+
+VCHPRE_ long VCHPOST_ vc_filesys_lseek(int fildes, long offset, int whence);
+
+VCHPRE_ int64_t VCHPOST_ vc_filesys_lseek64(int fildes, int64_t offset, int whence);
+
+VCHPRE_ int VCHPOST_ vc_filesys_open(const char *path, int vc_oflag);
+
+VCHPRE_ int VCHPOST_ vc_filesys_read(int fildes, void *buf, unsigned int nbyte);
+
+VCHPRE_ int VCHPOST_ vc_filesys_write(int fildes, const void *buf, unsigned int nbyte);
+
+VCHPRE_ int VCHPOST_ vc_filesys_mount(const char *device, const char *mountpoint, const char *options);
+VCHPRE_ int VCHPOST_ vc_filesys_umount(const char *mountpoint);
+
+
+// Ends a directory listing iteration
+VCHPRE_ int VCHPOST_ vc_filesys_closedir(void *dhandle);
+
+// Formats the drive that contains the given path
+VCHPRE_ int VCHPOST_ vc_filesys_format(const char *path);
+
+// Returns the amount of free space on the drive that contains the given path
+VCHPRE_ int VCHPOST_ vc_filesys_freespace(const char *path);
+VCHPRE_ int64_t VCHPOST_ vc_filesys_freespace64(const char *path);
+
+// Gets the attributes of the named file
+VCHPRE_ int VCHPOST_ vc_filesys_get_attr(const char *path, fattributes_t *attr);
+
+// Get the file stat info struct for the specified file.
+VCHPRE_ int VCHPOST_ vc_filesys_fstat(int filedes, FSTAT_T *buf);
+
+// Creates a new directory
+VCHPRE_ int VCHPOST_ vc_filesys_mkdir(const char *path);
+
+// Starts a directory listing iteration
+VCHPRE_ void * VCHPOST_ vc_filesys_opendir(const char *dirname);
+
+// Directory listing iterator
+VCHPRE_ struct dirent * VCHPOST_ vc_filesys_readdir_r(void *dhandle, struct dirent *result);
+
+// Get the sum of the filesizes, and the number of files under the specified directory path.
+VCHPRE_ int64_t VCHPOST_ vc_filesys_dirsize(const char *path, uint32_t *num_files, uint32_t *num_dirs);
+
+// Deletes a file or (empty) directory
+VCHPRE_ int VCHPOST_ vc_filesys_remove(const char *path);
+
+// Renames a file, provided the new name is on the same file system as the old
+VCHPRE_ int VCHPOST_ vc_filesys_rename(const char *oldfile, const char *newfile);
+
+// Resets the co-processor side file system
+VCHPRE_ int VCHPOST_ vc_filesys_reset(void);
+
+// Sets the attributes of the named file
+VCHPRE_ int VCHPOST_ vc_filesys_set_attr(const char *path, fattributes_t attr);
+
+// Truncates a file at its current position
+VCHPRE_ int VCHPOST_ vc_filesys_setend(int fildes);
+
+// Returns the size of a file in bytes.
+VCHPRE_ int VCHPOST_ vc_filesys_size(const char *path);
+
+// Checks whether there are any messages in the incoming message fifo and responds to any such messages
+VCHPRE_ int VCHPOST_ vc_filesys_poll_message_fifo(void);
+
+// Return the event used to wait for reads.
+VCHPRE_ void * VCHPOST_ vc_filesys_read_event(void);
+
+// Sends a command for VC01 to reset the file system
+VCHPRE_ void VCHPOST_ vc_filesys_sendreset(void);
+
+// Return the error code of the last file system error
+VCHPRE_ int VCHPOST_ vc_filesys_errno(void);
+
+// Invalidates any cluster chains in the FAT that are not referenced in any directory structures
+VCHPRE_ void VCHPOST_ vc_filesys_scandisk(const char *path);
+
+// Checks whether or not a FAT filesystem is corrupt or not. If fix_errors is TRUE behaves exactly as vc_filesys_scandisk.
+VCHPRE_ int VCHPOST_ vc_filesys_chkdsk(const char *path, int fix_errors);
+
+// Return whether a disk is writeable or not.
+VCHPRE_ int VCHPOST_ vc_filesys_diskwritable(const char *path);
+
+// Return file system type of a disk.
+VCHPRE_ int VCHPOST_ vc_filesys_fstype(const char *path);
+
+// Returns the toatl amount of space on the drive that contains the given path
+VCHPRE_ int VCHPOST_ vc_filesys_totalspace(const char *path);
+VCHPRE_ int64_t VCHPOST_ vc_filesys_totalspace64(const char *path);
+
+// Open disk for block level access
+VCHPRE_ int VCHPOST_ vc_filesys_open_disk_raw(const char *path);
+
+// Close disk from block level access mode
+VCHPRE_ int VCHPOST_ vc_filesys_close_disk_raw(const char *path);
+
+// Open disk for normal access
+VCHPRE_ int VCHPOST_ vc_filesys_open_disk(const char *path);
+
+// Close disk for normal access
+VCHPRE_ int VCHPOST_ vc_filesys_close_disk(const char *path);
+
+// Return number of sectors.
+VCHPRE_ int VCHPOST_ vc_filesys_numsectors(const char *path);
+VCHPRE_ int64_t VCHPOST_ vc_filesys_numsectors64(const char *path);
+
+// Read/Write sectors
+VCHPRE_ int VCHPOST_ vc_filesys_read_sectors(const char *path, uint32_t sector_num, char *sectors, uint32_t num_sectors, uint32_t *sectors_read);
+VCHPRE_ int VCHPOST_ vc_filesys_write_sectors(const char *path, uint32_t sector_num, char *sectors, uint32_t num_sectors, uint32_t *sectors_written);
+
+// Begin reading sectors from VideoCore.
+VCHPRE_ int VCHPOST_ vc_filesys_read_sectors_begin(const char *path, uint32_t sector, uint32_t count);
+
+// Read the next sector.
+VCHPRE_ int VCHPOST_ vc_filesys_read_sector(char *buf);
+
+// End streaming sectors.
+VCHPRE_ int VCHPOST_ vc_filesys_read_sectors_end(uint32_t *sectors_read);
+
+// Begin writing sectors from VideoCore.
+VCHPRE_ int VCHPOST_ vc_filesys_write_sectors_begin(const char *path, uint32_t sector, uint32_t count);
+
+// Write the next sector.
+VCHPRE_ int VCHPOST_ vc_filesys_write_sector(const char *buf);
+
+// End streaming sectors.
+VCHPRE_ int VCHPOST_ vc_filesys_write_sectors_end(uint32_t *sectors_written);
+
+#endif //VCFILESYS_H_
+
diff --git a/interface/vmcs_host/vc_vchi_gencmd.c b/interface/vmcs_host/vc_vchi_gencmd.c
new file mode 100755 (executable)
index 0000000..2da81a4
--- /dev/null
@@ -0,0 +1,532 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "vchost.h"
+
+#include "interface/vcos/vcos.h"
+#include "vcinclude/common.h"
+#include "vc_vchi_gencmd.h"
+#include "interface/vchi/vchi.h"
+#include "interface/vchi/common/endian.h"
+#include "interface/vmcs_host/vc_gencmd_defs.h"
+
+#ifdef HAVE_GENCMD_VERSION
+extern const char *gencmd_get_build_version(void);
+#error
+#endif
+
+/******************************************************************************
+Local types and defines.
+******************************************************************************/
+#define GENCMD_MAX_LENGTH 512
+typedef struct {
+   VCHI_SERVICE_HANDLE_T open_handle[VCHI_MAX_NUM_CONNECTIONS];
+   uint32_t              msg_flag[VCHI_MAX_NUM_CONNECTIONS];
+   char                  command_buffer[GENCMD_MAX_LENGTH+1];
+   char                  response_buffer[GENCMDSERVICE_MSGFIFO_SIZE];
+   uint32_t              response_length;  //Length of response minus the error code
+   int                   num_connections;
+   VCOS_MUTEX_T          lock;
+   int                   initialised;
+   VCOS_EVENT_T          message_available_event;
+} GENCMD_SERVICE_T;
+
+static GENCMD_SERVICE_T gencmd_client;
+
+
+/******************************************************************************
+Static function.
+******************************************************************************/
+static void gencmd_callback( void *callback_param,
+                             VCHI_CALLBACK_REASON_T reason,
+                             void *msg_handle );
+
+static __inline int lock_obtain (void) {
+   int ret = -1;
+   if(gencmd_client.initialised && vcos_mutex_lock(&gencmd_client.lock) == VCOS_SUCCESS)
+   {
+      ret = 0;
+   }
+
+   return ret;
+}
+static __inline void lock_release (void) {
+   vcos_mutex_unlock(&gencmd_client.lock);
+}
+
+int use_gencmd_service(void) {
+   int ret = 0;
+   int i=0;
+   for(i = 0; i < gencmd_client.num_connections; i++) {
+      ret = (ret == 0) ? vchi_service_use(gencmd_client.open_handle[i]) : ret;
+   }
+   return ret;
+}
+
+int release_gencmd_service(void) {
+   int ret = 0;
+   int i=0;
+   for(i = 0; i < gencmd_client.num_connections; i++) {
+      ret = (ret == 0) ? vchi_service_release(gencmd_client.open_handle[i]) : ret;
+   }
+   return ret;
+}
+
+
+//call vc_vchi_gencmd_init to initialise
+int vc_gencmd_init() {
+   assert(0);
+   return 0;
+}
+
+/******************************************************************************
+NAME
+   vc_vchi_gencmd_init
+
+SYNOPSIS
+   void vc_vchi_gencmd_init(VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections )
+
+FUNCTION
+   Initialise the general command service for use. A negative return value
+   indicates failure (which may mean it has not been started on VideoCore).
+
+RETURNS
+   int
+******************************************************************************/
+
+void vc_vchi_gencmd_init (VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections )
+{
+   VCOS_STATUS_T status;
+   int32_t success;
+   int i;
+
+   if (gencmd_client.initialised)
+     return;
+
+   // record the number of connections
+   memset( &gencmd_client, 0, sizeof(GENCMD_SERVICE_T) );
+   gencmd_client.num_connections = (int) num_connections;
+
+   status = vcos_mutex_create(&gencmd_client.lock, "HGencmd");
+   vcos_assert(status == VCOS_SUCCESS);
+   status = vcos_event_create(&gencmd_client.message_available_event, "HGencmd");
+   vcos_assert(status == VCOS_SUCCESS);
+
+   for (i=0; i<gencmd_client.num_connections; i++) {
+
+      // Create a 'LONG' service on the each of the connections
+      SERVICE_CREATION_T gencmd_parameters = { VCHI_VERSION(VC_GENCMD_VER),
+                                               MAKE_FOURCC("GCMD"),      // 4cc service code
+                                               connections[i],           // passed in fn ptrs
+                                               0,                        // tx fifo size (unused)
+                                               0,                        // tx fifo size (unused)
+                                               &gencmd_callback,         // service callback
+                                               &gencmd_client.message_available_event, // callback parameter
+                                               VC_FALSE,                 // want_unaligned_bulk_rx
+                                               VC_FALSE,                 // want_unaligned_bulk_tx
+                                               VC_FALSE                  // want_crc
+                                               };
+
+      success = vchi_service_open( initialise_instance, &gencmd_parameters, &gencmd_client.open_handle[i] );
+      assert( success == 0 );
+   }
+
+   gencmd_client.initialised = 1;
+   release_gencmd_service();
+}
+
+/******************************************************************************
+NAME
+   gencmd_callback
+
+SYNOPSIS
+   void gencmd_callback( void *callback_param,
+                     const VCHI_CALLBACK_REASON_T reason,
+                     const void *msg_handle )
+
+FUNCTION
+   VCHI callback
+
+RETURNS
+   int
+******************************************************************************/
+static void gencmd_callback( void *callback_param,
+                             const VCHI_CALLBACK_REASON_T reason,
+                             void *msg_handle ) {
+
+   VCOS_EVENT_T *event = (VCOS_EVENT_T *)callback_param;
+
+       (void)msg_handle;
+   if ( reason != VCHI_CALLBACK_MSG_AVAILABLE || !event)
+      return;
+
+   vcos_event_signal(event);
+}
+
+/******************************************************************************
+NAME
+   vc_gencmd_stop
+
+SYNOPSIS
+   int vc_gencmd_stop()
+
+FUNCTION
+   This tells us that the generak command service has stopped, thereby preventing
+   any of the functions from doing anything.
+
+RETURNS
+   int
+******************************************************************************/
+
+void vc_gencmd_stop () {
+   // Assume a "power down" gencmd has been sent and the lock is held. There will
+   // be no response so this should be called instead.
+   int32_t success,i;
+
+   if (!gencmd_client.initialised)
+      return;
+
+   if(lock_obtain() == 0)
+   {
+      use_gencmd_service();
+
+      for(i = 0; i< (int32_t)gencmd_client.num_connections; i++) {
+         success = vchi_service_close( gencmd_client.open_handle[i]);
+         assert(success == 0);
+      }
+
+      gencmd_client.initialised = 0;
+
+      lock_release();
+            
+      vcos_mutex_delete(&gencmd_client.lock);
+      vcos_event_delete(&gencmd_client.message_available_event);
+   }
+}
+
+/******************************************************************************
+NAME
+   vc_gencmd_send
+
+SYNOPSIS
+   int vc_gencmd_send( const char *format, ... )
+
+FUNCTION
+   Send a string to general command service.
+
+RETURNS
+   int
+******************************************************************************/
+int vc_gencmd_send_list ( const char *format, va_list a )
+{
+   int success = -1;
+
+   // Obtain the lock and keep it so no one else can butt in while we await the response.
+   if(lock_obtain() == 0)
+   {
+      int length = vsnprintf( gencmd_client.command_buffer, GENCMD_MAX_LENGTH, format, a );
+      
+      if (length >= 0 && length < GENCMD_MAX_LENGTH)
+      {
+         int i;
+         use_gencmd_service();
+         for( i=0; i<gencmd_client.num_connections; i++ ) {
+            success = vchi_msg_queue( gencmd_client.open_handle[i],
+                                           gencmd_client.command_buffer,
+                                           length+1,
+                                           VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL );
+
+            if(success == 0)
+            { // only want to send on one connection, so break on success
+               break;
+            }
+         }
+         release_gencmd_service();
+      }
+
+      lock_release();
+   }
+
+   return success;
+}
+
+int vc_gencmd_send ( const char *format, ... )
+{
+   va_list a;
+   int     rv;
+
+   va_start ( a, format );
+   rv = vc_gencmd_send_list( format, a );
+   va_end ( a );
+   return rv;
+}
+
+/******************************************************************************
+NAME
+   vc_gencmd_read_response
+
+SYNOPSIS
+   int vc_gencmd_read_response
+
+FUNCTION
+   Block until something comes back
+
+RETURNS
+   Error code from dequeue message
+******************************************************************************/
+int vc_gencmd_read_response (char *response, int maxlen) {
+   int i = 0;
+   int success = -1;
+   int ret_code = 0;
+   int32_t sem_ok = 0;
+
+   if(lock_obtain() == 0)
+   {
+      //Note this will ALWAYS reset response buffer and overwrite any partially read responses
+      use_gencmd_service();
+      do {
+         //TODO : we need to deal with messages coming through on more than one connections properly
+         //At the moment it will always try to read the first connection if there is something there
+         for(i = 0; i < gencmd_client.num_connections; i++) {
+            //Check if there is something in the queue, if so return immediately
+            //otherwise wait for the event and read again
+            success = (int) vchi_msg_dequeue( gencmd_client.open_handle[i], gencmd_client.response_buffer,
+                                              sizeof(gencmd_client.response_buffer), &gencmd_client.response_length, VCHI_FLAGS_NONE);
+            if(success == 0) {
+               ret_code = VC_VTOH32( *(int *)gencmd_client.response_buffer );
+               break;
+            } else {
+               gencmd_client.response_length = 0;
+            }
+         }
+      } while(!gencmd_client.response_length && vcos_event_wait(&gencmd_client.message_available_event) == VCOS_SUCCESS);
+      
+      if(gencmd_client.response_length && sem_ok == 0) {
+         gencmd_client.response_length -= sizeof(int); //first word is error code
+         memcpy(response, gencmd_client.response_buffer+sizeof(int), (size_t) vcos_min((int)gencmd_client.response_length, (int)maxlen));
+      }
+
+      release_gencmd_service();
+      lock_release();
+   }
+
+   // If we read anything, return the VideoCore code. Error codes < 0 mean we failed to
+   // read anything...
+   //How do we let the caller know the response code of gencmd?
+   //return ret_code;
+
+   return success;
+}
+
+/******************************************************************************
+NAME
+   vc_gencmd
+
+SYNOPSIS
+   int vc_gencmd(char *response, int maxlen, const char *format, ...)
+
+FUNCTION
+   Send a gencmd and receive the response as per vc_gencmd read_response.
+
+RETURNS
+   int
+******************************************************************************/
+int vc_gencmd(char *response, int maxlen, const char *format, ...) {
+   va_list args;
+   int ret = -1;
+
+   use_gencmd_service();
+
+   va_start(args, format);
+   ret = vc_gencmd_send_list(format, args);
+   va_end (args);
+
+   if (ret >= 0) {
+      ret = vc_gencmd_read_response(response, maxlen);
+   }
+
+   release_gencmd_service();
+
+   return ret;
+}
+
+/******************************************************************************
+NAME
+   vc_gencmd_string_property
+
+SYNOPSIS
+   int vc_gencmd_string_property(char *text, char *property, char **value, int *length)
+
+FUNCTION
+   Given a text string, containing items of the form property=value,
+   look for the named property and return the value. The start of the value
+   is returned, along with its length. The value may contain spaces, in which
+   case it is enclosed in double quotes. The double quotes are not included in
+   the return parameters. Return non-zero if the property is found.
+
+RETURNS
+   int
+******************************************************************************/
+
+int vc_gencmd_string_property(char *text, const char *property, char **value, int *length) {
+#define READING_PROPERTY 0
+#define READING_VALUE 1
+#define READING_VALUE_QUOTED 2
+   int state = READING_PROPERTY;
+   int delimiter = 1, match = 0, len = (int)strlen(property);
+   char *prop_start=text, *value_start=text;
+   for (; *text; text++) {
+      int ch = *text;
+      switch (state) {
+      case READING_PROPERTY:
+         if (delimiter) prop_start = text;
+         if (isspace(ch)) delimiter = 1;
+         else if (ch == '=') {
+            delimiter = 1;
+            match = (text-prop_start==len && strncmp(prop_start, property, (size_t)(text-prop_start))==0);
+            state = READING_VALUE;
+         }
+         else delimiter = 0;
+         break;
+      case READING_VALUE:
+         if (delimiter) value_start = text;
+         if (isspace(ch)) {
+            if (match) goto success;
+            delimiter = 1;
+            state = READING_PROPERTY;
+         }
+         else if (delimiter && ch == '"') {
+            delimiter = 1;
+            state = READING_VALUE_QUOTED;
+         }
+         else delimiter = 0;
+         break;
+      case READING_VALUE_QUOTED:
+         if (delimiter) value_start = text;
+         if (ch == '"') {
+            if (match) goto success;
+            delimiter = 1;
+            state = READING_PROPERTY;
+         }
+         else delimiter = 0;
+         break;
+      }
+   }
+   if (match) goto success;
+   return 0;
+success:
+   *value = value_start;
+   *length = text - value_start;
+   return 1;
+}
+
+/******************************************************************************
+NAME
+   vc_gencmd_number_property
+
+SYNOPSIS
+   int vc_gencmd_number_property(char *text, char *property, int *number)
+
+FUNCTION
+   Given a text string, containing items of the form property=value,
+   look for the named property and return the numeric value. If such a numeric
+   value is successfully found, return 1; otherwise return 0.
+
+RETURNS
+   int
+******************************************************************************/
+
+int vc_gencmd_number_property(char *text, const char *property, int *number) {
+   char *value, temp;
+   int length, retval;
+   if (vc_gencmd_string_property(text, property, &value, &length) == 0)
+      return 0;
+   temp = value[length];
+   value[length] = 0;
+   /* coverity[secure_coding] - this is not insecure */
+   retval = sscanf(value, "0x%x", (unsigned int*)number);
+   if (retval != 1)
+      /* coverity[secure_coding] - this is not insecure */
+      retval = sscanf(value, "%d", number);
+   value[length] = temp;
+   return retval;
+
+}
+
+/******************************************************************************
+NAME
+   vc_gencmd_until
+
+SYNOPSIS
+   int vc_gencmd_until(const char *cmd, const char *error_string, int timeout);
+
+FUNCTION
+   Sends the command repeatedly, until one of the following situations occurs:
+   The specified response string is found within the gencmd response.
+   The specified error string is found within the gencmd response.
+   The timeout is reached.
+
+   The timeout is a rough value, do not use it for precise timing.
+
+RETURNS
+   0 if the requested response was detected.
+   1 if the error string is detected or the timeout is reached.
+******************************************************************************/
+int vc_gencmd_until( char        *cmd,
+                     const char  *property,
+                     char        *value,
+                     const char  *error_string,
+                     int         timeout) {
+   char response[128];
+   int length;
+   char *ret_value;
+   int ret = 1;
+
+   use_gencmd_service();
+   for (;timeout > 0; timeout -= 10) {
+      vc_gencmd(response, (int)sizeof(response), cmd);
+      if (strstr(response,error_string)) {
+         ret = 1;
+         break;
+      }
+      else if (vc_gencmd_string_property(response, property, &ret_value, &length) &&
+               strncmp(value,ret_value,(size_t)length)==0) {
+         ret = 0;
+         break;
+      }
+      vcos_sleep(10);
+   }
+   release_gencmd_service();
+
+   return ret;
+}
+
diff --git a/interface/vmcs_host/vc_vchi_gencmd.h b/interface/vmcs_host/vc_vchi_gencmd.h
new file mode 100755 (executable)
index 0000000..da86b5d
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VC_VCHI_GENCMD_H
+#define VC_VCHI_GENCMD_H
+#include "vchost_platform_config.h"
+#include "interface/vchi/vchi.h"
+#include "interface/vcos/vcos.h" //for VCHPRE_ abd VCHPOST_ macro's for func declaration
+
+/* Initialise general command service. Returns it's interface number. This initialises
+   the host side of the interface, it does not send anything to VideoCore. */
+
+VCHPRE_ int VCHPOST_ vc_gencmd_init(void);
+
+VCHPRE_ void VCHPOST_ vc_vchi_gencmd_init(VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections );
+
+
+/* Stop the service from being used. */
+
+VCHPRE_ void VCHPOST_ vc_gencmd_stop(void);
+
+/* Functions to support videocore suspend/resume for cases where vc_gencmd_send expects a response to
+ * ensure videocore is not shut down (done internally in vc_gencmd / vc_gencmd_until) */
+
+VCHPRE_ int VCHPOST_ use_gencmd_service(void);
+VCHPRE_ int VCHPOST_ release_gencmd_service(void);
+
+/******************************************************************************
+Send commands to VideoCore.
+These all return 0 for success. They return VC_MSGFIFO_FIFO_FULL if there is
+insufficient space for the whole message in the fifo, and none of the message is
+sent.
+******************************************************************************/
+
+/*  send command to general command serivce */
+VCHPRE_ int VCHPOST_ vc_gencmd_send( const char *format, ... );
+
+/*  get resonse from general command serivce */
+VCHPRE_ int VCHPOST_ vc_gencmd_read_response(char *response, int maxlen);
+
+/* convenience function to send command and receive the response */
+VCHPRE_ int VCHPOST_ vc_gencmd(char *response, int maxlen, const char *format, ...);
+
+/******************************************************************************
+Utilities to help interpret the responses.
+******************************************************************************/
+
+/* Read the value of a property=value type pair from a string (typically VideoCore's
+   response to a general command). Return non-zero if found. */
+VCHPRE_ int VCHPOST_ vc_gencmd_string_property(char *text, const char *property, char **value, int *length);
+
+/* Read the numeric value of a property=number field from a response string. Return
+   non-zero if found. */
+VCHPRE_ int VCHPOST_ vc_gencmd_number_property(char *text, const char *property, int *number);
+
+/* Send a command until the desired response is received, the error message is detected, or the timeout */
+VCHPRE_ int VCHPOST_ vc_gencmd_until( char        *cmd,
+                                      const char  *property,
+                                      char        *value,
+                                      const char  *error_string,
+                                      int         timeout);
+
+
+#endif
diff --git a/interface/vmcs_host/vc_vchi_gpuserv.c b/interface/vmcs_host/vc_vchi_gpuserv.c
new file mode 100755 (executable)
index 0000000..695ed52
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+Copyright (c) 2016, Raspberry Pi (Trading) Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "vchost.h"
+
+#include "interface/vcos/vcos.h"
+#include "interface/vcos/vcos_logging.h"
+#include "vcinclude/common.h"
+#include "vc_vchi_gpuserv.h"
+#include "vchiq.h"
+#include "interface/vcos/vcos_stdbool.h"
+
+// VCOS logging category
+static VCOS_LOG_CAT_T vcos_log_category;
+#define VCOS_LOG_CATEGORY  (&vcos_log_category)
+
+static VCHIQ_INSTANCE_T gpuserv_client_vchiq_instance;
+static VCOS_ONCE_T gpuserv_client_once = VCOS_ONCE_INIT;
+
+/******************************************************************************
+Local types and defines.
+******************************************************************************/
+#define GPUSERV_MAX_LENGTH 512
+typedef struct {
+   VCHIQ_SERVICE_HANDLE_T service;
+   VCOS_MUTEX_T          lock;
+   int                   initialised;
+   VCOS_EVENT_T          message_available_event;
+   int refcount;
+} GPUSERV_SERVICE_T;
+
+static GPUSERV_SERVICE_T gpuserv_client;
+
+
+/******************************************************************************
+Static function.
+******************************************************************************/
+static VCHIQ_STATUS_T gpuserv_callback( VCHIQ_REASON_T reason,
+                                        VCHIQ_HEADER_T *header,
+                                        VCHIQ_SERVICE_HANDLE_T vchiq_handle,
+                                        void *bulk_userdata );
+
+static void init_once(void)
+{
+   vcos_mutex_create(&gpuserv_client.lock, VCOS_FUNCTION);
+}
+
+/******************************************************************************
+NAME
+
+   vc_gpuserv_init
+
+SYNOPSIS
+   int32_t vc_gpuserv_init( void )
+
+FUNCTION
+   Initialise the gpu service for use. A negative return value
+   indicates failure (which may mean it has not been started on VideoCore).
+
+RETURNS
+   zero on success
+******************************************************************************/
+
+int32_t vc_gpuserv_init( void )
+{
+   VCHIQ_SERVICE_PARAMS_T vchiq_params;
+   VCHIQ_STATUS_T vchiq_status;
+
+   vcos_once(&gpuserv_client_once, init_once);
+
+   vcos_mutex_lock(&gpuserv_client.lock);
+
+   if (gpuserv_client.refcount++ > 0)
+   {
+      /* Already initialised so nothing to do */
+      vcos_mutex_unlock(&gpuserv_client.lock);
+      return VCOS_SUCCESS;
+   }
+
+   vcos_log_set_level(VCOS_LOG_CATEGORY, VCOS_LOG_TRACE);
+   vcos_log_register("gpuserv", VCOS_LOG_CATEGORY);
+
+   vcos_log_trace("%s: starting initialisation", VCOS_FUNCTION);
+
+   /* Initialise a VCHIQ instance */
+   vchiq_status = vchiq_initialise(&gpuserv_client_vchiq_instance);
+   if (vchiq_status != VCHIQ_SUCCESS)
+   {
+      vcos_log_error("%s: failed to initialise vchiq: %d", VCOS_FUNCTION, vchiq_status);
+      goto error;
+   }
+
+   vchiq_status = vchiq_connect(gpuserv_client_vchiq_instance);
+   if (vchiq_status != VCHIQ_SUCCESS)
+   {
+      vcos_log_error("%s: failed to connect to vchiq: %d", VCOS_FUNCTION, vchiq_status);
+      goto error;
+   }
+
+   memset(&vchiq_params, 0, sizeof(vchiq_params));
+   vchiq_params.fourcc = VCHIQ_MAKE_FOURCC('G','P','U','S');
+   vchiq_params.callback = gpuserv_callback;
+   vchiq_params.userdata = NULL;
+   vchiq_params.version = 1;
+   vchiq_params.version_min = 1;
+
+   vchiq_status = vchiq_open_service(gpuserv_client_vchiq_instance, &vchiq_params, &gpuserv_client.service);
+   if (vchiq_status != VCHIQ_SUCCESS)
+   {
+      vcos_log_error("%s: could not open vchiq service: %d", VCOS_FUNCTION, vchiq_status);
+      goto error;
+   }
+   vcos_mutex_unlock(&gpuserv_client.lock);
+   return 0;
+error:
+   vcos_mutex_unlock(&gpuserv_client.lock);
+   return -1;
+}
+
+/******************************************************************************
+NAME
+
+   vc_gpuserv_deinit
+
+SYNOPSIS
+   void vc_gpuserv_init( void )
+
+FUNCTION
+   Deinitialise the gpu service. Should be called when gpu_service is no longer required
+
+RETURNS
+   zero on success
+******************************************************************************/
+
+void vc_gpuserv_deinit( void )
+{
+   vcos_mutex_lock(&gpuserv_client.lock);
+
+   if (gpuserv_client.refcount > 0 && --gpuserv_client.refcount == 0)
+   {
+      vchi_service_close(gpuserv_client.service);
+      gpuserv_client.service = 0;
+   }
+   vcos_mutex_unlock(&gpuserv_client.lock);
+}
+
+/******************************************************************************
+NAME
+   gpuserv_callback
+
+SYNOPSIS
+   void gpuserv_callback( VCHIQ_REASON_T reason,
+                          VCHIQ_HEADER_T *header,
+                          VCHIQ_SERVICE_HANDLE_T service,
+                          void *bulk_userdata )
+FUNCTION
+   VCHIQ callback
+
+RETURNS
+   zero on success
+******************************************************************************/
+static VCHIQ_STATUS_T gpuserv_callback( VCHIQ_REASON_T reason,
+                                        VCHIQ_HEADER_T *header,
+                                        VCHIQ_SERVICE_HANDLE_T service,
+                                        void *bulk_userdata )
+{
+   // reason is one of VCHIQ_MESSAGE_AVAILABLE, VCHIQ_BULK_TRANSMIT_DONE, VCHIQ_BULK_RECEIVE_DONE
+   switch (reason)
+   {
+      case VCHIQ_MESSAGE_AVAILABLE:
+      {
+         struct gpu_callback_s *c = (struct gpu_callback_s *)header->data;
+         if (c->func)
+            c->func(c->cookie);
+         vchiq_release_message(service, header);
+         break;
+      }
+      default:
+        ;
+   }
+   return 0; // Releases any command message (VCHIQ_MESSAGE_AVAILABLE), ignored otherwise
+}
+
+/******************************************************************************
+NAME
+   vc_gpuserv_execute_code
+
+SYNOPSIS
+   int32_t vc_gpuserv_execute_code(int num_jobs, struct gpu_job_s jobs[])
+
+FUNCTION
+   Submit a list of VPU/QPU jobs to be exeected by GPU
+
+RETURNS
+   zero on success
+******************************************************************************/
+#define MAX_JOBS 8
+int32_t vc_gpuserv_execute_code(int num_jobs, struct gpu_job_s jobs[])
+{
+   VCHIQ_ELEMENT_T elements[MAX_JOBS];
+   int i;
+
+   // hack: temporarily allow calling this function without calling vc_gpuserv_init
+   // will be removed later
+   if (!gpuserv_client.service)
+   {
+      vc_gpuserv_init();
+      vcos_log_error("%s: called without calling vc_gpuserv_init", VCOS_FUNCTION);
+   }
+
+   if (!gpuserv_client.service)
+   {
+      vcos_log_error("%s: vchiq service not initialised", VCOS_FUNCTION);
+      return -1;
+   }
+   if (num_jobs > MAX_JOBS)
+      return -1;
+
+   for (i=0; i<num_jobs; i++)
+   {
+      elements[i].data = jobs + i;
+      elements[i].size = sizeof *jobs;
+   }
+   if (vchiq_queue_message(gpuserv_client.service, elements, num_jobs) != VCHIQ_SUCCESS)
+   {
+      goto error_exit;
+   }
+   return 0;
+   error_exit:
+   return -1; 
+}
diff --git a/interface/vmcs_host/vc_vchi_gpuserv.h b/interface/vmcs_host/vc_vchi_gpuserv.h
new file mode 100755 (executable)
index 0000000..eca7e36
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+Copyright (c) 2016, Raspberry Pi (Trading) Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VC_VCHI_GPUSERV_H
+#define VC_VCHI_GPUSERV_H
+#include "interface/vchiq_arm/vchiq.h"
+
+// these go in command word of gpu_job_s
+// EXECUTE_VPU and EXECUTE_QPU are valid from host
+enum { EXECUTE_NONE, EXECUTE_VPU, EXECUTE_QPU, EXECUTE_SYNC };
+
+struct vpu_job_s {
+   // these are function address and parameters for vpu job
+   uint32_t q[7];
+   uint32_t dummy[21];
+};
+
+struct qpu_job_s {
+   // parameters for qpu job
+   uint32_t jobs;
+   uint32_t noflush;
+   uint32_t timeout;
+   uint32_t dummy;
+   uint32_t control[12][2];
+};
+
+struct sync_job_s {
+   // parameters for syncjob
+   // bit 0 set means wait for preceding vpu jobs to complete
+   // bit 1 set means wait for preceding qpu jobs to complete
+   uint32_t mask;
+   uint32_t dummy[27];
+};
+
+struct gpu_callback_s {
+  // callback to call when complete (can be NULL)
+  void (*func)();
+  void *cookie;
+};
+
+struct gpu_internal_s {
+   void *message;
+   int refcount;
+};
+
+struct gpu_job_s {
+  // from enum above
+  uint32_t command;
+  // qpu or vpu jobs
+  union {
+    struct vpu_job_s v;
+    struct qpu_job_s q;
+    struct sync_job_s s;
+  } u;
+  // callback function to call when complete
+  struct gpu_callback_s callback;
+  // for internal use - leave as zero
+  struct gpu_internal_s internal;
+};
+
+/* Initialise gpu service. Returns its interface number. This initialises
+   the host side of the interface, it does not send anything to VideoCore. */
+
+VCHPRE_ int32_t VCHPOST_ vc_gpuserv_init(void);
+
+VCHPRE_ void VCHPOST_ vc_gpuserv_deinit(void);
+
+VCHPRE_ int32_t VCHPOST_ vc_gpuserv_execute_code(int num_jobs, struct gpu_job_s jobs[]);
+
+#endif
diff --git a/interface/vmcs_host/vc_vchi_tvservice.c b/interface/vmcs_host/vc_vchi_tvservice.c
new file mode 100755 (executable)
index 0000000..69832ad
--- /dev/null
@@ -0,0 +1,1639 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if !defined(__KERNEL__)
+#include <string.h>
+#endif
+
+#include "interface/vcos/vcos.h"
+
+#include "vchost_platform_config.h"
+#include "vchost.h"
+
+#include "interface/vchi/vchi.h"
+#include "interface/vchi/common/endian.h"
+#include "interface/vchi/message_drivers/message.h"
+#include "vc_tvservice.h"
+
+/******************************************************************************
+Local types and defines.
+******************************************************************************/
+#ifndef _min
+#define _min(x,y) (((x) <= (y))? (x) : (y))
+#endif
+#ifndef _max
+#define _max(x,y) (((x) >= (y))? (x) : (y))
+#endif
+
+typedef struct
+{
+   TVSERVICE_CALLBACK_T  notify_fn;
+   void                 *notify_data;
+} TVSERVICE_HOST_CALLBACK_T;
+
+typedef struct {
+   uint32_t is_valid;
+   uint32_t max_modes; //How big the table have we allocated
+   uint32_t num_modes; //How many valid entries are there
+   TV_SUPPORTED_MODE_NEW_T *modes;
+} TVSERVICE_MODE_CACHE_T;
+
+//TV service host side state (mostly the same as Videocore side - TVSERVICE_STATE_T)
+typedef struct {
+   //Generic service stuff
+   VCHI_SERVICE_HANDLE_T client_handle[VCHI_MAX_NUM_CONNECTIONS]; //To connect to server on VC
+   VCHI_SERVICE_HANDLE_T notify_handle[VCHI_MAX_NUM_CONNECTIONS]; //For incoming notification
+   uint32_t              msg_flag[VCHI_MAX_NUM_CONNECTIONS];
+   char                  command_buffer[TVSERVICE_MSGFIFO_SIZE];
+   char                  response_buffer[TVSERVICE_MSGFIFO_SIZE];
+   uint32_t              response_length;
+   uint32_t              notify_buffer[TVSERVICE_MSGFIFO_SIZE/sizeof(uint32_t)];
+   uint32_t              notify_length;
+   uint32_t              num_connections;
+   VCOS_MUTEX_T          lock;
+   TVSERVICE_HOST_CALLBACK_T  callbacks[TVSERVICE_MAX_CALLBACKS];
+   int                   initialised;
+   int                   to_exit;
+
+   //TV stuff
+   uint32_t              copy_protect;
+
+   //HDMI specific stuff
+   HDMI_RES_GROUP_T      hdmi_current_group;
+   HDMI_MODE_T           hdmi_current_mode;
+   HDMI_DISPLAY_OPTIONS_T hdmi_options;
+
+   //If client ever asks for supported modes, we store them for quick return
+   HDMI_RES_GROUP_T      hdmi_preferred_group;
+   uint32_t              hdmi_preferred_mode;
+   TVSERVICE_MODE_CACHE_T dmt_cache;
+   TVSERVICE_MODE_CACHE_T cea_cache;
+
+   //SDTV specific stuff
+   SDTV_COLOUR_T         sdtv_current_colour;
+   SDTV_MODE_T           sdtv_current_mode;
+   SDTV_OPTIONS_T        sdtv_options;
+   SDTV_CP_MODE_T        sdtv_current_cp_mode;
+} TVSERVICE_HOST_STATE_T;
+
+/******************************************************************************
+Static data.
+******************************************************************************/
+static TVSERVICE_HOST_STATE_T tvservice_client;
+static VCOS_EVENT_T tvservice_message_available_event;
+static VCOS_EVENT_T tvservice_notify_available_event;
+static VCOS_THREAD_T tvservice_notify_task;
+
+#define  VCOS_LOG_CATEGORY (&tvservice_log_category)
+static VCOS_LOG_CAT_T  tvservice_log_category;
+
+//Command strings - must match what's in vc_tvservice_defs.h
+static char* tvservice_command_strings[] = {
+   "get_state",
+   "hdmi_on_preferred",
+   "hdmi_on_best",
+   "hdmi_on_explicit",
+   "sdtv_on",
+   "off",
+   "query_supported_modes",
+   "query_mode_support",
+   "query_audio_support",
+   "enable_copy_protect",
+   "disable_copy_protect",
+   "show_info",
+   "get_av_latency",
+   "hdcp_set_key",
+   "hdcp_set_srm",
+   "set_spd",
+   "set_display_options",
+   "test_mode_start",
+   "test_mode_stop",
+   "ddc_read",
+   "set_attached",
+   "set_property",
+   "get_property",
+   "get_display_state",
+   "end_of_list"
+};
+
+/******************************************************************************
+Static functions.
+******************************************************************************/
+//Lock the host state
+static __inline int tvservice_lock_obtain (void) {
+   if(tvservice_client.initialised && vcos_mutex_lock(&tvservice_client.lock) == VCOS_SUCCESS) {
+      //Check again in case the service has been stopped
+      if (tvservice_client.initialised) {
+         vchi_service_use(tvservice_client.client_handle[0]);
+         return 0;
+      }
+      else
+         vcos_mutex_unlock(&tvservice_client.lock);
+   }
+
+   return -1;
+}
+
+//Unlock the host state
+static __inline void tvservice_lock_release (void) {
+   if (tvservice_client.initialised) {
+      vchi_service_release(tvservice_client.client_handle[0]);
+   }
+   vcos_mutex_unlock(&tvservice_client.lock);
+}
+
+//Forward declarations
+static void tvservice_client_callback( void *callback_param,
+                                      VCHI_CALLBACK_REASON_T reason,
+                                      void *msg_handle );
+
+static void tvservice_notify_callback( void *callback_param,
+                                      VCHI_CALLBACK_REASON_T reason,
+                                      void *msg_handle );
+
+static int32_t tvservice_wait_for_reply(void *response, uint32_t max_length);
+
+static int32_t tvservice_wait_for_bulk_receive(void *buffer, uint32_t max_length);
+
+static int32_t tvservice_send_command( uint32_t command, void *buffer, uint32_t length, uint32_t has_reply);
+
+static int32_t tvservice_send_command_reply( uint32_t command, void *buffer, uint32_t length,
+                                             void *response, uint32_t max_length);
+
+static void *tvservice_notify_func(void *arg);
+
+
+/******************************************************************************
+TV service API
+******************************************************************************/
+/******************************************************************************
+NAME
+   vc_vchi_tv_init
+
+SYNOPSIS
+   int vc_vchi_tv_init(VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections )
+
+FUNCTION
+   Initialise the TV service for use. A negative return value
+   indicates failure (which may mean it has not been started on VideoCore).
+
+RETURNS
+   int
+******************************************************************************/
+VCHPRE_ int VCHPOST_ vc_vchi_tv_init(VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections ) {
+   int32_t success;
+   uint32_t i;
+   VCOS_STATUS_T status;
+   VCOS_THREAD_ATTR_T attrs;
+   static const HDMI_DISPLAY_OPTIONS_T hdmi_default_display_options =
+      {
+         HDMI_ASPECT_UNKNOWN,
+         VC_FALSE, 0, 0, // No vertical bar information.
+         VC_FALSE, 0, 0, // No horizontal bar information.
+         0               // No overscan flags.
+      };
+
+   if (tvservice_client.initialised)
+     return -2;
+
+   vcos_log_set_level(VCOS_LOG_CATEGORY, VCOS_LOG_ERROR);
+   vcos_log_register("tvservice-client", VCOS_LOG_CATEGORY);
+
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+
+   // record the number of connections
+   memset( &tvservice_client, 0, sizeof(TVSERVICE_HOST_STATE_T) );
+   tvservice_client.num_connections = num_connections;
+
+   status = vcos_mutex_create(&tvservice_client.lock, "HTV");
+   vcos_assert(status == VCOS_SUCCESS);
+   status = vcos_event_create(&tvservice_message_available_event, "HTV");
+   vcos_assert(status == VCOS_SUCCESS);
+   status = vcos_event_create(&tvservice_notify_available_event, "HTV");
+   vcos_assert(status == VCOS_SUCCESS);
+
+   //Initialise any other non-zero bits of the TV service state here
+   tvservice_client.sdtv_current_mode = SDTV_MODE_OFF;
+   tvservice_client.sdtv_options.aspect = SDTV_ASPECT_4_3;
+   memcpy(&tvservice_client.hdmi_options, &hdmi_default_display_options, sizeof(HDMI_DISPLAY_OPTIONS_T));
+
+   for (i=0; i < tvservice_client.num_connections; i++) {
+
+      // Create a 'Client' service on the each of the connections
+      SERVICE_CREATION_T tvservice_parameters = { VCHI_VERSION(VC_TVSERVICE_VER),
+                                                  TVSERVICE_CLIENT_NAME,      // 4cc service code
+                                                  connections[i],             // passed in fn ptrs
+                                                  0,                          // tx fifo size (unused)
+                                                  0,                          // tx fifo size (unused)
+                                                  &tvservice_client_callback, // service callback
+                                                  &tvservice_message_available_event,  // callback parameter
+                                                  VC_TRUE,                    // want_unaligned_bulk_rx
+                                                  VC_TRUE,                    // want_unaligned_bulk_tx
+                                                  VC_FALSE,                   // want_crc
+      };
+
+      SERVICE_CREATION_T tvservice_parameters2 = { VCHI_VERSION(VC_TVSERVICE_VER),
+                                                   TVSERVICE_NOTIFY_NAME,     // 4cc service code
+                                                   connections[i],            // passed in fn ptrs
+                                                   0,                         // tx fifo size (unused)
+                                                   0,                         // tx fifo size (unused)
+                                                   &tvservice_notify_callback,// service callback
+                                                   &tvservice_notify_available_event,  // callback parameter
+                                                   VC_FALSE,                  // want_unaligned_bulk_rx
+                                                   VC_FALSE,                  // want_unaligned_bulk_tx
+                                                   VC_FALSE,                  // want_crc
+      };
+
+      //Create the client to normal TV service
+      success = vchi_service_open( initialise_instance, &tvservice_parameters, &tvservice_client.client_handle[i] );
+
+      //Create the client to the async TV service (any TV related notifications)
+      if (success == 0)
+      {
+         success = vchi_service_open( initialise_instance, &tvservice_parameters2, &tvservice_client.notify_handle[i] );
+         if (success == 0)
+         {
+            vchi_service_release(tvservice_client.client_handle[i]);
+            vchi_service_release(tvservice_client.notify_handle[i]);
+         }
+         else
+         {
+            vchi_service_close(tvservice_client.client_handle[i]);
+            vcos_log_error("Failed to connect to async TV service: %d", success);
+         }
+      } else {
+         vcos_log_error("Failed to connect to TV service: %d", success);
+      }
+
+      if (success != 0)
+      {
+         while (i > 0)
+         {
+            --i;
+            vchi_service_close(tvservice_client.client_handle[i]);
+            vchi_service_close(tvservice_client.notify_handle[i]);
+         }
+         return -1;
+      }
+   }
+
+   //Create the notifier task
+   vcos_thread_attr_init(&attrs);
+   vcos_thread_attr_setstacksize(&attrs, 4096);
+   vcos_thread_attr_settimeslice(&attrs, 1);
+
+   status = vcos_thread_create(&tvservice_notify_task, "HTV Notify", &attrs, tvservice_notify_func, &tvservice_client);
+   vcos_assert(status == VCOS_SUCCESS);
+
+   tvservice_client.initialised = 1;
+   vcos_log_trace("TV service initialised");
+
+   return 0;
+}
+
+/***********************************************************
+ * Name: vc_vchi_tv_stop
+ *
+ * Arguments:
+ *       -
+ *
+ * Description: Stops the Host side part of TV service
+ *
+ * Returns: -
+ *
+ ***********************************************************/
+VCHPRE_ void VCHPOST_ vc_vchi_tv_stop( void ) {
+   // Wait for the current lock-holder to finish before zapping TV service
+   uint32_t i;
+
+   if (!tvservice_client.initialised)
+      return;
+
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   if(tvservice_lock_obtain() == 0)
+   {
+      void *dummy;
+      vchi_service_release(tvservice_client.client_handle[0]); // to match the use in tvservice_lock_obtain()
+
+      for (i=0; i < tvservice_client.num_connections; i++) {
+         int32_t result;
+         vchi_service_use(tvservice_client.client_handle[i]);
+         vchi_service_use(tvservice_client.notify_handle[i]);
+         result = vchi_service_close(tvservice_client.client_handle[i]);
+         vcos_assert( result == 0 );
+         result = vchi_service_close(tvservice_client.notify_handle[i]);
+         vcos_assert( result == 0 );
+      }
+
+      // Unset the initialise flag so no other threads can obtain the lock
+      tvservice_client.initialised = 0;
+
+      tvservice_lock_release();
+      tvservice_client.to_exit = 1; //Signal to quit
+      vcos_event_signal(&tvservice_notify_available_event);
+      vcos_thread_join(&tvservice_notify_task, &dummy);
+
+      if(tvservice_client.cea_cache.modes)
+         vcos_free(tvservice_client.cea_cache.modes);
+
+      if(tvservice_client.dmt_cache.modes)
+         vcos_free(tvservice_client.dmt_cache.modes);
+
+      vcos_mutex_delete(&tvservice_client.lock);
+      vcos_event_delete(&tvservice_message_available_event);
+      vcos_event_delete(&tvservice_notify_available_event);
+   }
+}
+
+
+/***********************************************************
+ * Name: vc_tv_register_callback
+ *
+ * Arguments:
+ *       callback function, context to be passed when function is called
+ *
+ * Description: Register a callback function for all TV notifications
+ *
+ * Returns: -
+ *
+ ***********************************************************/
+VCHPRE_ void VCHPOST_ vc_tv_register_callback(TVSERVICE_CALLBACK_T callback, void *callback_data) {
+
+   vcos_assert_msg(callback != NULL, "Use vc_tv_unregister_callback() to remove a callback");
+
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   if(tvservice_lock_obtain() == 0)
+   {
+      uint32_t done = 0;
+      uint32_t i;
+      for(i = 0; (i < TVSERVICE_MAX_CALLBACKS) && !done; i++)
+      {
+         if(tvservice_client.callbacks[i].notify_fn == NULL)
+         {
+            tvservice_client.callbacks[i].notify_fn = callback;
+            tvservice_client.callbacks[i].notify_data = callback_data;
+            done = 1;
+         } // if
+      } // for
+      vcos_assert(done);
+      tvservice_lock_release();
+   }
+}
+
+/***********************************************************
+ * Name: vc_tv_unregister_callback
+ *
+ * Arguments:
+ *       callback function
+ *
+ * Description: Unregister a previously-registered callback function for TV notifications
+ *
+ * Returns: -
+ *
+ ***********************************************************/
+VCHPRE_ void VCHPOST_ vc_tv_unregister_callback(TVSERVICE_CALLBACK_T callback)
+{
+   vcos_assert(callback != NULL);
+
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   if(tvservice_lock_obtain() == 0)
+   {
+      uint32_t done = 0;
+      uint32_t i;
+      for(i = 0; (i < TVSERVICE_MAX_CALLBACKS) && !done; i++)
+      {
+         if(tvservice_client.callbacks[i].notify_fn == callback)
+         {
+            tvservice_client.callbacks[i].notify_fn = NULL;
+            tvservice_client.callbacks[i].notify_data = NULL;
+            done = 1;
+         } // if
+      } // for
+      vcos_assert(done);
+      tvservice_lock_release();
+   }
+}
+
+/***********************************************************
+ * Name: vc_tv_unregister_callback_full
+ *
+ * Arguments:
+ *       callback function
+ *       callback function context
+ *
+ * Description: Unregister a previously-registered callback function for TV notifications
+ *
+ * Returns: -
+ *
+ ***********************************************************/
+VCHPRE_ void VCHPOST_ vc_tv_unregister_callback_full(TVSERVICE_CALLBACK_T callback, void *callback_data)
+{
+   vcos_assert(callback != NULL);
+
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   if(tvservice_lock_obtain() == 0)
+   {
+      uint32_t done = 0;
+      uint32_t i;
+      for(i = 0; (i < TVSERVICE_MAX_CALLBACKS) && !done; i++)
+      {
+         if(tvservice_client.callbacks[i].notify_fn == callback &&
+            tvservice_client.callbacks[i].notify_data == callback_data)
+         {
+            tvservice_client.callbacks[i].notify_fn = NULL;
+            tvservice_client.callbacks[i].notify_data = NULL;
+            done = 1;
+         } // if
+      } // for
+      vcos_assert(done);
+      tvservice_lock_release();
+   }
+}
+
+/*********************************************************************************
+ *
+ *  Static functions definitions
+ *
+ *********************************************************************************/
+//TODO: Might need to handle multiple connections later
+/***********************************************************
+ * Name: tvservice_client_callback
+ *
+ * Arguments: semaphore, callback reason and message handle
+ *
+ * Description: Callback when a message is available for TV service
+ *
+ ***********************************************************/
+static void tvservice_client_callback( void *callback_param,
+                                       const VCHI_CALLBACK_REASON_T reason,
+                                       void *msg_handle ) {
+   VCOS_EVENT_T *event = (VCOS_EVENT_T *)callback_param;
+
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   (void)msg_handle;
+
+   if ( reason != VCHI_CALLBACK_MSG_AVAILABLE || event == NULL)
+      return;
+
+   vcos_event_signal(event);
+}
+
+/***********************************************************
+ * Name: tvservice_notify_callback
+ *
+ * Arguments: semaphore, callback reason and message handle
+ *
+ * Description: Callback when a message is available for TV notify service
+ *
+ ***********************************************************/
+static void tvservice_notify_callback( void *callback_param,
+                                       const VCHI_CALLBACK_REASON_T reason,
+                                       void *msg_handle ) {
+   VCOS_EVENT_T *event = (VCOS_EVENT_T *)callback_param;
+
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   (void)msg_handle;
+
+   if ( reason != VCHI_CALLBACK_MSG_AVAILABLE || event == NULL)
+      return;
+
+   vcos_event_signal(event);
+}
+
+/***********************************************************
+ * Name: tvservice_wait_for_reply
+ *
+ * Arguments: response buffer, buffer length
+ *
+ * Description: blocked until something is in the buffer
+ *
+ * Returns error code of vchi
+ *
+ ***********************************************************/
+static int32_t tvservice_wait_for_reply(void *response, uint32_t max_length) {
+   int32_t success = 0;
+   uint32_t length_read = 0;
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   do {
+      //TODO : we need to deal with messages coming through on more than one connections properly
+      //At the moment it will always try to read the first connection if there is something there
+      //Check if there is something in the queue, if so return immediately
+      //otherwise wait for the semaphore and read again
+      success = vchi_msg_dequeue( tvservice_client.client_handle[0], response, max_length, &length_read, VCHI_FLAGS_NONE );
+   } while( length_read == 0 && vcos_event_wait(&tvservice_message_available_event) == VCOS_SUCCESS);
+   if(length_read) {
+      vcos_log_trace("TV service got reply %d bytes", length_read);
+   } else {
+      vcos_log_warn("TV service wait for reply failed");
+   }
+   return success;
+}
+
+/***********************************************************
+ * Name: tvservice_wait_for_bulk_receive
+ *
+ * Arguments: response buffer, buffer length
+ *
+ * Description: blocked until bulk receive
+ *
+ * Returns error code of vchi
+ *
+ ***********************************************************/
+static int32_t tvservice_wait_for_bulk_receive(void *buffer, uint32_t max_length) {
+   /*if(!vcos_verify(((uint32_t) buffer & 0xf) == 0)) //should be 16 byte aligned
+      return -1;*/
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   if(!vcos_verify(buffer)) { 
+      vcos_log_error("TV service: NULL buffer passed to wait_for_bulk_receive");
+      return -1;
+   }
+
+   return vchi_bulk_queue_receive( tvservice_client.client_handle[0],
+                                   buffer,
+                                   max_length,
+                                   VCHI_FLAGS_BLOCK_UNTIL_OP_COMPLETE,
+                                   NULL );
+}
+
+/***********************************************************
+ * Name: tvservice_send_command
+ *
+ * Arguments: command, parameter buffer, parameter length, has reply? (non-zero means yes)
+ *
+ * Description: send a command and optionally wait for its single value response (TV_GENERAL_RESP_T)
+ *
+ * Returns: response.ret (currently only 1 int in the wrapped response), endian translated if necessary
+ *
+ ***********************************************************/
+
+static int32_t tvservice_send_command(  uint32_t command, void *buffer, uint32_t length, uint32_t has_reply) {
+   VCHI_MSG_VECTOR_T vector[] = { {&command, sizeof(command)},
+                                  {buffer, length} };
+   int32_t success = 0;
+   TV_GENERAL_RESP_T response;
+   response.ret = -1;
+
+   if(vcos_verify(command < VC_TV_END_OF_LIST)) {
+      vcos_log_trace("[%s] command:%s param length %d %s", VCOS_FUNCTION,
+                     tvservice_command_strings[command], length, 
+                     (has_reply)? "has reply" : " no reply");
+   } else {
+      vcos_log_error("[%s] not sending invalid command %d", VCOS_FUNCTION, command);
+      return -1;
+   }
+
+   if(tvservice_lock_obtain() == 0)
+   {
+      success = vchi_msg_queuev( tvservice_client.client_handle[0],
+                                 vector, sizeof(vector)/sizeof(vector[0]),
+                                 VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL );
+      if(success == 0 && has_reply) {
+         //otherwise only wait for a reply if we ask for one
+         success = tvservice_wait_for_reply(&response, sizeof(response));
+         response.ret = VC_VTOH32(response.ret);
+      } else {
+         if(success != 0)
+            vcos_log_error("TV service failed to send command %s length %d, error code %d",
+                           tvservice_command_strings[command], length, success);
+         //No reply expected or failed to send, send the success code back instead
+         response.ret = success;
+      }
+      tvservice_lock_release();
+   }
+   return response.ret;
+}
+
+/***********************************************************
+ * Name: tvservice_send_command_reply
+ *
+ * Arguments: command, parameter buffer, parameter length, reply buffer, buffer length
+ *
+ * Description: send a command and wait for its non-single value response (in a buffer)
+ *
+ * Returns: error code, host app is responsible to do endian translation
+ *
+ ***********************************************************/
+static int32_t tvservice_send_command_reply(  uint32_t command, void *buffer, uint32_t length,
+                                              void *response, uint32_t max_length) {
+   VCHI_MSG_VECTOR_T vector[] = { {&command, sizeof(command)},
+                                   {buffer, length} };
+   int32_t success = 0;
+
+   vcos_log_trace("[%s] sending command (with reply) %s param length %d", VCOS_FUNCTION,
+                  tvservice_command_strings[command], length);
+
+   if(tvservice_lock_obtain() == 0)
+   {
+      success = vchi_msg_queuev( tvservice_client.client_handle[0],
+                                 vector, sizeof(vector)/sizeof(vector[0]),
+                                 VCHI_FLAGS_BLOCK_UNTIL_QUEUED, NULL );
+      if(success == 0)
+         success = tvservice_wait_for_reply(response, max_length);
+      else
+         vcos_log_error("TV service failed to send command %s param length %d, error code %d",
+                        tvservice_command_strings[command], length, success);
+      
+      tvservice_lock_release();
+   }
+
+   return success;
+}
+
+/***********************************************************
+ * Name: tvservice_notify_func
+ *
+ * Arguments: TV service state
+ *
+ * Description: This is the notification task which receives all TV
+ *              service notifications
+ *
+ * Returns: does not return
+ *
+ ***********************************************************/
+static void *tvservice_notify_func(void *arg) {
+   int32_t success;
+   TVSERVICE_HOST_STATE_T *state = (TVSERVICE_HOST_STATE_T *) arg;
+   TV_DISPLAY_STATE_T tvstate;
+
+   vcos_log_trace("TV service async thread started");
+   /* Check starting state, and put service in use if necessary */
+   success = tvservice_send_command_reply( VC_TV_GET_DISPLAY_STATE, NULL, 0, &tvstate, sizeof(TV_DISPLAY_STATE_T));
+   if (success != 0)
+      return 0;
+   if (tvstate.state & VC_HDMI_ATTACHED)
+   {
+      /* Connected */
+      if (tvstate.state & (VC_HDMI_HDMI | VC_HDMI_DVI))
+      {
+         /* Mode already selected */
+         vchi_service_use(state->notify_handle[0]);
+      }
+   }
+   // the state machine below only wants a single bit to be set
+   if (tvstate.state & (VC_HDMI_ATTACHED|VC_HDMI_UNPLUGGED))
+      tvstate.state &= ~(VC_HDMI_HDMI | VC_HDMI_DVI);
+
+   while(1) {
+      VCOS_STATUS_T status = vcos_event_wait(&tvservice_notify_available_event);
+      if(status != VCOS_SUCCESS || !state->initialised || state->to_exit)
+         break;
+
+      do {
+         uint32_t reason, param1, param2;
+         //Get all notifications in the queue
+         success = vchi_msg_dequeue( state->notify_handle[0], state->notify_buffer, sizeof(state->notify_buffer), &state->notify_length, VCHI_FLAGS_NONE );
+         if(success != 0 || state->notify_length < sizeof(uint32_t)*3 ) {
+            vcos_assert(state->notify_length == sizeof(uint32_t)*3);
+            break;
+         }
+
+         if(tvservice_lock_obtain() != 0)
+            break;
+
+         //Check what notification it is and update ourselves accordingly before notifying the host app
+         //All notifications are of format: reason, param1, param2 (all 32-bit unsigned int)
+         reason = VC_VTOH32(state->notify_buffer[0]), param1 = VC_VTOH32(state->notify_buffer[1]), param2 = VC_VTOH32(state->notify_buffer[2]);
+         vcos_log_trace("[%s] %s %d %d", VCOS_FUNCTION, vc_tv_notification_name(reason),
+                        param1, param2);
+         switch(reason) {
+         case VC_HDMI_UNPLUGGED:
+            if(tvstate.state & (VC_HDMI_HDMI|VC_HDMI_DVI)) {
+               state->copy_protect = 0;
+               if((tvstate.state & VC_HDMI_ATTACHED) == 0) {
+                  vchi_service_release(state->notify_handle[0]);
+               }
+            }
+            tvstate.state &= ~(VC_HDMI_HDMI|VC_HDMI_DVI|VC_HDMI_ATTACHED|VC_HDMI_HDCP_AUTH);
+            tvstate.state |= (VC_HDMI_UNPLUGGED | VC_HDMI_HDCP_UNAUTH);
+            vcos_log_trace("[%s] invalidating caches", VCOS_FUNCTION);
+            state->cea_cache.is_valid = state->cea_cache.num_modes = 0;
+            state->dmt_cache.is_valid = state->dmt_cache.num_modes = 0;
+            break;
+
+         case VC_HDMI_ATTACHED:
+            if(tvstate.state & (VC_HDMI_HDMI|VC_HDMI_DVI)) {
+               state->copy_protect = 0;
+               vchi_service_release(state->notify_handle[0]);
+            }
+            tvstate.state &=  ~(VC_HDMI_HDMI|VC_HDMI_DVI|VC_HDMI_UNPLUGGED|VC_HDMI_HDCP_AUTH);
+            tvstate.state |= VC_HDMI_ATTACHED;
+            state->hdmi_preferred_group = (HDMI_RES_GROUP_T) param1;
+            state->hdmi_preferred_mode = param2;
+            break;
+
+         case VC_HDMI_DVI:
+            if(tvstate.state & (VC_HDMI_ATTACHED|VC_HDMI_UNPLUGGED)) {
+               vchi_service_use(state->notify_handle[0]);
+            }
+            tvstate.state &= ~(VC_HDMI_HDMI|VC_HDMI_ATTACHED|VC_HDMI_UNPLUGGED);
+            tvstate.state |= VC_HDMI_DVI;
+            state->hdmi_current_group = (HDMI_RES_GROUP_T) param1;
+            state->hdmi_current_mode = param2;
+            break;
+
+         case VC_HDMI_HDMI:
+            if(tvstate.state & (VC_HDMI_ATTACHED|VC_HDMI_UNPLUGGED)) {
+               vchi_service_use(state->notify_handle[0]);
+            }
+            tvstate.state &= ~(VC_HDMI_DVI|VC_HDMI_ATTACHED|VC_HDMI_UNPLUGGED);
+            tvstate.state |= VC_HDMI_HDMI;
+            state->hdmi_current_group = (HDMI_RES_GROUP_T) param1;
+            state->hdmi_current_mode = param2;
+            break;
+
+         case VC_HDMI_HDCP_UNAUTH:
+            tvstate.state &= ~VC_HDMI_HDCP_AUTH;
+            tvstate.state |= VC_HDMI_HDCP_UNAUTH;
+            state->copy_protect = 0;
+            //Do we care about the reason for HDCP unauth in param1?
+            break;
+
+         case VC_HDMI_HDCP_AUTH:
+            tvstate.state &= ~VC_HDMI_HDCP_UNAUTH;
+            tvstate.state |= VC_HDMI_HDCP_AUTH;
+            state->copy_protect = 1;
+            break;
+
+         case VC_HDMI_HDCP_KEY_DOWNLOAD:
+         case VC_HDMI_HDCP_SRM_DOWNLOAD:
+            //Nothing to do here, just tell the host app whether it is successful or not (in param1)
+            break;
+
+         case VC_SDTV_UNPLUGGED: //Currently we don't get this
+            if(tvstate.state & (VC_SDTV_PAL | VC_SDTV_NTSC)) {
+               state->copy_protect = 0;
+            }
+            tvstate.state &= ~(VC_SDTV_ATTACHED | VC_SDTV_PAL | VC_SDTV_NTSC);
+            tvstate.state |= (VC_SDTV_UNPLUGGED | VC_SDTV_CP_INACTIVE);
+            state->sdtv_current_mode = SDTV_MODE_OFF;
+            break;
+
+         case VC_SDTV_ATTACHED: //Currently we don't get this either
+            tvstate.state &= ~(VC_SDTV_UNPLUGGED | VC_SDTV_PAL | VC_SDTV_NTSC);
+            tvstate.state |= VC_SDTV_ATTACHED;
+            state->sdtv_current_mode = SDTV_MODE_OFF;
+            break;
+
+         case VC_SDTV_NTSC:
+            tvstate.state &= ~(VC_SDTV_UNPLUGGED | VC_SDTV_ATTACHED | VC_SDTV_PAL);
+            tvstate.state |= VC_SDTV_NTSC;
+            state->sdtv_current_mode = (SDTV_MODE_T) param1;
+            state->sdtv_options.aspect = (SDTV_ASPECT_T) param2;
+            if(param1 & SDTV_COLOUR_RGB) {
+               state->sdtv_current_colour = SDTV_COLOUR_RGB;
+            } else if(param1 & SDTV_COLOUR_YPRPB) {
+               state->sdtv_current_colour = SDTV_COLOUR_YPRPB;
+            } else {
+               state->sdtv_current_colour = SDTV_COLOUR_UNKNOWN;
+            }
+            break;
+
+         case VC_SDTV_PAL:
+            tvstate.state &= ~(VC_SDTV_UNPLUGGED | VC_SDTV_ATTACHED | VC_SDTV_NTSC);
+            tvstate.state |= VC_SDTV_PAL;
+            state->sdtv_current_mode = (SDTV_MODE_T) param1;
+            state->sdtv_options.aspect = (SDTV_ASPECT_T) param2;
+            if(param1 & SDTV_COLOUR_RGB) {
+               state->sdtv_current_colour = SDTV_COLOUR_RGB;
+            } else if(param1 & SDTV_COLOUR_YPRPB) {
+               state->sdtv_current_colour = SDTV_COLOUR_YPRPB;
+            } else {
+               state->sdtv_current_colour = SDTV_COLOUR_UNKNOWN;
+            }
+            break;
+
+         case VC_SDTV_CP_INACTIVE:
+            tvstate.state &= ~VC_SDTV_CP_ACTIVE;
+            tvstate.state |= VC_SDTV_CP_INACTIVE;
+            state->copy_protect = 0;
+            state->sdtv_current_cp_mode = SDTV_CP_NONE;
+            break;
+
+         case VC_SDTV_CP_ACTIVE:
+            tvstate.state &= ~VC_SDTV_CP_INACTIVE;
+            tvstate.state |= VC_SDTV_CP_ACTIVE;
+            state->copy_protect = 1;
+            state->sdtv_current_cp_mode = (SDTV_CP_MODE_T) param1;
+            break;
+         }
+
+         tvservice_lock_release();
+
+         //Now callback the host app(s)
+         uint32_t i, called = 0;
+         for(i = 0; i < TVSERVICE_MAX_CALLBACKS; i++)
+         {
+            if(state->callbacks[i].notify_fn != NULL)
+            {
+               called++;
+               state->callbacks[i].notify_fn
+                  (state->callbacks[i].notify_data, reason, param1, param2);
+            } // if
+         } // for
+         if(called == 0) {
+            vcos_log_info("TV service: No callback handler specified, callback [%s] swallowed",
+                          vc_tv_notification_name(reason));
+         }
+      } while(success == 0 && state->notify_length >= sizeof(uint32_t)*3); //read the next message if any
+   } //while (1)
+   
+   if(state->to_exit)
+      vcos_log_trace("TV service async thread exiting");
+
+   return 0;
+}
+
+/***********************************************************
+ Actual TV service API starts here
+***********************************************************/
+
+/***********************************************************
+ * Name: vc_tv_get_state
+ *
+ * Arguments:
+ *       Pointer to tvstate structure
+ *
+ * Description: Get the current TV state
+ *
+ * Returns: if the command is successful (zero) or not (non-zero)
+ *          If the command fails to be sent, passed in state is unchanged
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_tv_get_state(TV_GET_STATE_RESP_T *tvstate) {
+   int success = -1;
+
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   if(vcos_verify(tvstate)) {
+      success = tvservice_send_command_reply( VC_TV_GET_STATE, NULL, 0,
+                                              tvstate, sizeof(TV_GET_STATE_RESP_T));
+      if(success == 0) {
+         tvstate->state = VC_VTOH32(tvstate->state);
+         tvstate->width = VC_VTOH32(tvstate->width);
+         tvstate->height = VC_VTOH32(tvstate->height);
+         tvstate->frame_rate = VC_VTOH16(tvstate->frame_rate);
+         tvstate->scan_mode = VC_VTOH16(tvstate->scan_mode);
+      }
+   }
+   return success;
+}
+
+/***********************************************************
+ * Name: vc_tv_get_display_state
+ *
+ * Arguments:
+ *       Pointer to tvstate structure
+ *
+ * Description: Get the current TV display state.
+ *
+ * Returns: if the command is successful (zero) or not (non-zero)
+ *          If the command fails to be sent, passed in state is unchanged
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_tv_get_display_state(TV_DISPLAY_STATE_T *tvstate) {
+   int success = -1;
+
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   if(vcos_verify(tvstate)) {
+      success = tvservice_send_command_reply( VC_TV_GET_DISPLAY_STATE, NULL, 0,
+                                              tvstate, sizeof(TV_DISPLAY_STATE_T));
+   }
+   return success;
+}
+
+/***********************************************************
+ * Name: vc_tv_hdmi_power_on_preferred/vc_tv_hdmi_power_on_preferred_3d
+ *
+ * Arguments:
+ *       none
+ *
+ * Description: Power on HDMI at preferred resolution
+ *              Enter 3d if the _3d function was called
+ *
+ *              Analogue TV will be powered down if on (same for the following
+ *              two HDMI power on functions below)
+ *
+ * Returns: single value interpreted as HDMI_RESULT_T (zero means success)
+ *          if successful, there will be a callback when the power on is complete
+ *
+ ***********************************************************/
+static int vc_tv_hdmi_power_on_preferred_actual(uint32_t in_3d) {
+   TV_HDMI_ON_PREFERRED_PARAM_T param;
+   int success;
+
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   param.in_3d = VC_HTOV32(in_3d);
+
+   success = tvservice_send_command( VC_TV_HDMI_ON_PREFERRED, &param, sizeof(param), 1);
+   return success;
+}
+
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_power_on_preferred( void ) {
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   return vc_tv_hdmi_power_on_preferred_actual(0);
+}
+
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_power_on_preferred_3d( void ) {
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   return vc_tv_hdmi_power_on_preferred_actual(1);
+}
+
+/***********************************************************
+ * Name: vc_tv_hdmi_power_on_best/vc_tv_hdmi_power_on_best_3d
+ *
+ * Arguments:
+ *       screen width, height, frame rate, scan_mode (HDMI_NONINTERLACED / HDMI_INTERLACED)
+ *       match flags
+ *
+ * Description: Power on HDMI at best matched resolution based on passed in parameters
+ *              Enter 3d mode if the _3d function was called
+ *
+ * Returns: single value interpreted as HDMI_RESULT_T (zero means success)
+ *          if successful, there will be a callback when the power on is complete
+ *
+ ***********************************************************/
+static int vc_tv_hdmi_power_on_best_actual(uint32_t width, uint32_t height, uint32_t frame_rate,
+                                           HDMI_INTERLACED_T scan_mode, EDID_MODE_MATCH_FLAG_T match_flags,
+                                           uint32_t in_3d) {
+   TV_HDMI_ON_BEST_PARAM_T param;
+   int success;
+
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   param.width = VC_HTOV32(width);
+   param.height = VC_HTOV32(height);
+   param.frame_rate = VC_HTOV32(frame_rate);
+   param.scan_mode = VC_HTOV32(scan_mode);
+   param.match_flags = VC_HTOV32(match_flags);
+   param.in_3d = VC_HTOV32(in_3d);
+
+   success = tvservice_send_command( VC_TV_HDMI_ON_BEST, &param, sizeof(TV_HDMI_ON_BEST_PARAM_T), 1);
+   return success;
+}
+
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_power_on_best(uint32_t width, uint32_t height, uint32_t frame_rate,
+                                              HDMI_INTERLACED_T scan_mode, EDID_MODE_MATCH_FLAG_T match_flags) {
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   return vc_tv_hdmi_power_on_best_actual(width, height, frame_rate, scan_mode, match_flags, 0);
+}
+
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_power_on_best_3d(uint32_t width, uint32_t height, uint32_t frame_rate,
+                                              HDMI_INTERLACED_T scan_mode, EDID_MODE_MATCH_FLAG_T match_flags) {
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   return vc_tv_hdmi_power_on_best_actual(width, height, frame_rate, scan_mode, match_flags, 1);
+}
+
+/***********************************************************
+ * Name: vc_tv_hdmi_power_on_explicit
+ *
+ * Arguments:
+ *       mode (HDMI_MODE_HDMI/HDMI_MODE_DVI),
+ *       group (HDMI_RES_GROUP_CEA/HDMI_RES_GROUP_DMT),
+ *       code
+ *
+ * Description: Power on HDMI at explicit mode
+ *              Enter 3d mode if supported by the TV and if mode was set to HDMI_MODE_3D
+ *              If Videocore has EDID, this will still be subject to EDID restriction,
+ *              otherwise HDMI will be powered on at the said mode
+ *
+ * Returns: single value interpreted as HDMI_RESULT_T (zero means success)
+ *          if successful, there will be a callback when the power on is complete
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_power_on_explicit_new(HDMI_MODE_T mode, HDMI_RES_GROUP_T group, uint32_t code) {
+   TV_HDMI_ON_EXPLICIT_PARAM_T param;
+   int success;
+
+   vcos_log_trace("[%s] mode %d group %d code %d", VCOS_FUNCTION,
+         mode, group, code);
+   param.hdmi_mode = mode;
+   param.group = group;
+   param.mode = code;
+
+   success = tvservice_send_command( VC_TV_HDMI_ON_EXPLICIT, &param, sizeof(TV_HDMI_ON_EXPLICIT_PARAM_T), 1);
+   return success;
+}
+
+/***********************************************************
+ * Name: vc_tv_sdtv_power_on
+ *
+ * Arguments:
+ *       SDTV mode, options (currently only aspect ratio)
+ *
+ * Description: Power on SDTV at required mode and aspect ratio (default 4:3)
+ *              HDMI will be powered down if currently on
+ *
+ * Returns: single value (zero means success)
+ *          if successful, there will be a callback when the power on is complete
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_tv_sdtv_power_on(SDTV_MODE_T mode, SDTV_OPTIONS_T *options) {
+   TV_SDTV_ON_PARAM_T param;
+   int success;
+
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   param.mode = VC_HTOV32(mode);
+   param.aspect = (options)? VC_HTOV32(options->aspect) : VC_HTOV32(SDTV_ASPECT_4_3);
+
+   success = tvservice_send_command( VC_TV_SDTV_ON, &param, sizeof(TV_SDTV_ON_PARAM_T), 1);
+   return success;
+}
+
+
+/***********************************************************
+ * Name: vc_tv_power_off
+ *
+ * Arguments:
+ *       none
+ *
+ * Description: Power off whatever is on at the moment, no effect if nothing is on
+ *
+ * Returns: whether command is successfully sent (and callback for HDMI)
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_tv_power_off( void ) {
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   return tvservice_send_command( VC_TV_OFF, NULL, 0, 0);
+}
+
+/***********************************************************
+ * Name: vc_tv_hdmi_get_supported_modes
+ *
+ * Arguments:
+ *       group (HDMI_RES_GROUP_CEA/HDMI_RES_GROUP_DMT),
+ *       array of TV_SUPPORT_MODE_T structs, length of array, pointer to preferred group,
+ *       pointer to prefer mode code (the last two pointers can be NULL, if the caller
+ *       is not interested to learn what the preferred mode is)
+ *       If passed in a null supported_modes array, or the length of array
+ *       is zero, the number of supported modes in that particular group
+ *       will be returned instead
+ *
+ * Description: Get supported modes for a particular group,
+ *              the length of array limits no. of modes returned
+ *
+ * Returns: Returns the number of modes actually written (or the number
+ *          of supported modes if passed in a null array or length of array==0).
+ *          Returns < 0 for error.
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_get_supported_modes_new(HDMI_RES_GROUP_T group,
+                                                    TV_SUPPORTED_MODE_NEW_T *supported_modes,
+                                                    uint32_t max_supported_modes,
+                                                    HDMI_RES_GROUP_T *preferred_group,
+                                                    uint32_t *preferred_mode) {
+   uint32_t param[2] = {(uint32_t) group, 0};
+   TV_QUERY_SUPPORTED_MODES_RESP_T response;
+   TVSERVICE_MODE_CACHE_T *cache = NULL;
+   int error = -1;
+   int modes_copied = 0;
+
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+
+   switch(group) {
+      case HDMI_RES_GROUP_DMT:
+         cache = &tvservice_client.dmt_cache;
+         break;
+      case HDMI_RES_GROUP_CEA:
+         cache = &tvservice_client.cea_cache;
+         break;
+      default:
+         vcos_log_error("Invalid group %d in [%s]", group, VCOS_FUNCTION);
+         return -1;
+   }
+   vcos_log_trace("[%s] group %d cache valid %d",
+                  VCOS_FUNCTION, group, cache->is_valid);
+
+   memset(&response, 0, sizeof(response));
+   if(!cache->is_valid) {
+      vchi_service_use(tvservice_client.client_handle[0]);
+      if((error = tvservice_send_command_reply(VC_TV_QUERY_SUPPORTED_MODES, &param[0], sizeof(uint32_t),
+                                               &response, sizeof(response))) == VC_HDMI_SUCCESS) {
+         //First ask how many modes there are, if the current table is big enough to hold
+         //all the modes, just copy over, otherwise allocate a new table
+         if(response.num_supported_modes) {
+            if(cache->max_modes < response.num_supported_modes) {
+               cache->max_modes = response.num_supported_modes;
+               if(cache->modes) {
+                  vcos_free(cache->modes);
+                  cache->modes = NULL;
+               }
+            } else {
+               vcos_assert(cache->modes);
+               memset(cache->modes, 0, cache->max_modes * sizeof(TV_SUPPORTED_MODE_NEW_T));
+            }
+            if(cache->modes == NULL) {
+               cache->modes = vcos_calloc(cache->max_modes, sizeof(TV_SUPPORTED_MODE_NEW_T), "cached modes");
+            }
+            if(vcos_verify(cache->modes)) {
+               //If we have successfully allocated the table, send
+               //another request to actually download the modes from Videocore
+               param[1] = response.num_supported_modes;
+               if((error = tvservice_send_command_reply(VC_TV_QUERY_SUPPORTED_MODES_ACTUAL, param, sizeof(param),
+                                                        &response, sizeof(response))) == VC_HDMI_SUCCESS) {
+                  //The response comes back may indicate a different number of modes to param[1].
+                  //This happens if a new EDID was read in between the two requests (should be rare),
+                  //in which case we just download as many as VC says will be sent
+                  cache->num_modes = response.num_supported_modes;
+                  vcos_assert(response.num_supported_modes <= param[1]); //VC will not return more than what we have allocated
+                  if(cache->num_modes) {
+                     error = tvservice_wait_for_bulk_receive(cache->modes, cache->num_modes * sizeof(TV_SUPPORTED_MODE_NEW_T));
+                     if(error)
+                        vcos_log_error("Failed to download %s cache in [%s]", HDMI_RES_GROUP_NAME(group), VCOS_FUNCTION);
+                  } else {
+                     vcos_log_error("First query of supported modes indicated there are %d, but now there are none, has the TV been unplugged? [%s]",
+                                    param[1], VCOS_FUNCTION);
+                  }
+               } else {
+                  vcos_log_error("Failed to request %s cache in [%s]", HDMI_RES_GROUP_NAME(group), VCOS_FUNCTION);
+               }
+            } else {
+               //If we failed to allocate memory, the request stops here
+               vcos_log_error("Failed to allocate memory for %s cache in [%s]", HDMI_RES_GROUP_NAME(group), VCOS_FUNCTION);
+            }
+         } else {
+            //The request also terminates if there are no supported modes reported
+            vcos_log_trace("No supported modes returned for group %s in [%s]", HDMI_RES_GROUP_NAME(group), VCOS_FUNCTION);
+         }
+      } else {
+         vcos_log_error("Failed to query supported modes for group %s in [%s]", HDMI_RES_GROUP_NAME(group), VCOS_FUNCTION);
+      }
+      vchi_service_release(tvservice_client.client_handle[0]);
+
+      if(!error) {
+         cache->is_valid = 1;
+         vcos_log_trace("[%s] cached %d %s resolutions", VCOS_FUNCTION, response.num_supported_modes, HDMI_RES_GROUP_NAME(group));
+         tvservice_client.hdmi_preferred_group = response.preferred_group;
+         tvservice_client.hdmi_preferred_mode  = response.preferred_mode;
+      }
+   }
+
+   if(cache->is_valid) {
+      if(supported_modes && max_supported_modes) {
+         modes_copied = _min(max_supported_modes, cache->num_modes);
+         memcpy(supported_modes, cache->modes, modes_copied*sizeof(TV_SUPPORTED_MODE_NEW_T));
+      } else {
+         //If we pass in a null pointer, return the size of table instead
+         modes_copied = cache->num_modes;
+      }
+   }
+
+   if(preferred_group && preferred_mode) {
+      *preferred_group = tvservice_client.hdmi_preferred_group;
+      *preferred_mode = tvservice_client.hdmi_preferred_mode;
+   }
+
+   return modes_copied; //If there was an error, this will be zero
+}
+
+/***********************************************************
+ * Name: vc_tv_hdmi_mode_supported
+ *
+ * Arguments:
+ *       resolution standard (CEA/DMT), mode code
+ *
+ * Description: Query if a particular mode is supported
+ *
+ * Returns: single value return > 0 means supported, 0 means unsupported, < 0 means error
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_mode_supported(HDMI_RES_GROUP_T group,
+                                               uint32_t mode) {
+   TV_QUERY_MODE_SUPPORT_PARAM_T param = {group, mode};
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+
+   return tvservice_send_command( VC_TV_QUERY_MODE_SUPPORT, &param, sizeof(TV_QUERY_MODE_SUPPORT_PARAM_T), 1);
+}
+
+/***********************************************************
+ * Name: vc_tv_hdmi_audio_supported
+ *
+ * Arguments:
+ *       audio format (EDID_AudioFormat + EDID_AudioCodingExtension),
+ *       no. of channels (1-8),
+ *       sample rate (EDID_AudioSampleRate except "refer to header"),
+ *       bit rate (or sample size if pcm)
+ *       use EDID_AudioSampleSize as sample size argument
+ *
+ * Description: Query if a particular audio format is supported
+ *
+ * Returns: single value return which will be flags in EDID_AUDIO_SUPPORT_FLAG_T
+ *          zero means everything is supported, < 0 means error
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_audio_supported(uint32_t audio_format, uint32_t num_channels,
+                                                EDID_AudioSampleRate fs, uint32_t bitrate) {
+   TV_QUERY_AUDIO_SUPPORT_PARAM_T param = { VC_HTOV32(audio_format),
+                                            VC_HTOV32(num_channels),
+                                            VC_HTOV32(fs),
+                                            VC_HTOV32(bitrate) };
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   if(!vcos_verify(num_channels > 0 && num_channels <= 8 && fs != EDID_AudioSampleRate_eReferToHeader))
+      return -1;
+
+   return tvservice_send_command( VC_TV_QUERY_AUDIO_SUPPORT, &param, sizeof(TV_QUERY_AUDIO_SUPPORT_PARAM_T), 1);
+}
+
+/***********************************************************
+ * Name: vc_tv_enable_copyprotect
+ *
+ * Arguments:
+ *       copy protect mode (only used for SDTV), time out in milliseconds
+ *
+ * Description: Enable copy protection (either HDMI or SDTV must be powered on)
+ *
+ * Returns: single value return 0 means success, additional result via callback
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_tv_enable_copyprotect(uint32_t cp_mode, uint32_t timeout) {
+   TV_ENABLE_COPY_PROTECT_PARAM_T param = {VC_HTOV32(cp_mode), VC_HTOV32(timeout)};
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   return tvservice_send_command( VC_TV_ENABLE_COPY_PROTECT, &param, sizeof(TV_ENABLE_COPY_PROTECT_PARAM_T), 1);
+}
+
+/***********************************************************
+ * Name: vc_tv_disable_copyprotect
+ *
+ * Arguments:
+ *       none
+ *
+ * Description: Disable copy protection (either HDMI or SDTV must be powered on)
+ *
+ * Returns: single value return 0 means success, additional result via callback
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_tv_disable_copyprotect( void ) {
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   return tvservice_send_command( VC_TV_DISABLE_COPY_PROTECT, NULL, 0, 1);
+}
+
+/***********************************************************
+ * Name: vc_tv_show_info
+ *
+ * Arguments:
+ *       show (1) or hide (0) info screen
+ *
+ * Description: Show or hide info screen, only works in HDMI at the moment
+ *
+ * Returns: zero if command is successfully sent
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_tv_show_info(uint32_t show) {
+   TV_SHOW_INFO_PARAM_T param = {VC_HTOV32(show)};
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   return tvservice_send_command( VC_TV_SHOW_INFO, &param, sizeof(TV_SHOW_INFO_PARAM_T), 0);
+}
+
+/***********************************************************
+ * Name: vc_tv_hdmi_get_av_latency
+ *
+ * Arguments:
+ *       none
+ *
+ * Description: Get the AV latency (in ms) for HDMI (lipsync), only valid if
+ *              HDMI is currently powered on, otherwise you get zero
+ *
+ * Returns: latency (zero if error or latency is not defined), < 0 if failed to send command)
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_get_av_latency( void ) {
+
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   return tvservice_send_command( VC_TV_GET_AV_LATENCY, NULL, 0, 1);
+}
+
+/***********************************************************
+ * Name: vc_tv_hdmi_set_hdcp_key
+ *
+ * Arguments:
+ *       key block, whether we wait (1) or not (0) for the key to download
+ *
+ * Description: Download HDCP key
+ *
+ * Returns: single value return indicating download status
+ *          (or queued status if we don't wait)
+ *          Callback indicates the validity of key
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_set_hdcp_key(const uint8_t *key) {
+   TV_HDCP_SET_KEY_PARAM_T param;
+
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   if(!vcos_verify(key))
+      return -1;
+   memcpy(param.key, key, HDCP_KEY_BLOCK_SIZE);
+   return tvservice_send_command( VC_TV_HDCP_SET_KEY, &param, sizeof(param), 0);
+}
+
+/***********************************************************
+ * Name: vc_tv_hdmi_set_hdcp_revoked_list
+ *
+ * Arguments:
+ *       list, size of list
+ *
+ * Description: Download HDCP revoked list
+ *
+ * Returns: single value return indicating download status
+ *          (or queued status if we don't wait)
+ *          Callback indicates the number of keys set (zero if failed, unless you are clearing the list)
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_set_hdcp_revoked_list(const uint8_t *list, uint32_t num_keys) {
+   TV_HDCP_SET_SRM_PARAM_T param = {VC_HTOV32(num_keys)};
+   int success = tvservice_send_command( VC_TV_HDCP_SET_SRM, &param, sizeof(TV_HDCP_SET_SRM_PARAM_T), 0);
+
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   if(success == 0 && num_keys && list) { //Set num_keys to zero if we are clearing the list
+      //Sent the command, now download the list
+      if(tvservice_lock_obtain() == 0)
+      {
+         success = vchi_bulk_queue_transmit( tvservice_client.client_handle[0],
+                                             list,
+                                             num_keys * HDCP_KSV_LENGTH,
+                                             VCHI_FLAGS_BLOCK_UNTIL_QUEUED,
+                                             0 );
+         tvservice_lock_release();
+      }
+      else
+         success = -1;
+   }
+   return success;
+}
+
+/***********************************************************
+ * Name: vc_tv_hdmi_set_spd
+ *
+ * Arguments:
+ *       manufacturer, description, product type (HDMI_SPD_TYPE_CODE_T)
+ *
+ * Description: Set SPD
+ *
+ * Returns: whether command was sent successfully (zero means success)
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_set_spd(const char *manufacturer, const char *description, HDMI_SPD_TYPE_CODE_T type) {
+   TV_SET_SPD_PARAM_T param;
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+
+   if(!vcos_verify(manufacturer && description))
+      return -1;
+
+   memcpy(param.manufacturer, manufacturer, TV_SPD_NAME_LEN);
+   memcpy(param.description, description, TV_SPD_DESC_LEN);
+   param.type = VC_HTOV32(type);
+   return tvservice_send_command( VC_TV_SET_SPD, &param, sizeof(TV_SET_SPD_PARAM_T), 0);
+}
+
+/***********************************************************
+ * Name: vc_tv_hdmi_set_display_options
+ *
+ * Arguments:
+ *       aspect ratio (HDMI_ASPECT_T enum), left/right bar width, top/bottom bar height
+ *
+ * Description: Set active area for HDMI (bar width/height should be set to zero if absent)
+ *
+ * Returns: whether command was sent successfully (zero means success)
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_set_display_options(HDMI_ASPECT_T aspect,
+                                                    uint32_t left_bar_width, uint32_t right_bar_width,
+                                                    uint32_t top_bar_height, uint32_t bottom_bar_height,
+                                                    uint32_t overscan_flags) {
+   TV_SET_DISPLAY_OPTIONS_PARAM_T param;
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+
+   param.aspect = VC_HTOV32(aspect);
+   param.vertical_bar_present = VC_HTOV32((left_bar_width || right_bar_width)? VC_TRUE : VC_FALSE);
+   param.left_bar_width = VC_HTOV32(left_bar_width);
+   param.right_bar_width = VC_HTOV32(right_bar_width);
+   param.horizontal_bar_present = VC_HTOV32((top_bar_height || bottom_bar_height)? VC_TRUE : VC_FALSE);
+   param.top_bar_height = VC_HTOV32(top_bar_height);
+   param.bottom_bar_height = VC_HTOV32(bottom_bar_height);
+   param.overscan_flags = VC_HTOV32(overscan_flags);
+   return tvservice_send_command( VC_TV_SET_DISPLAY_OPTIONS, &param, sizeof(TV_SET_DISPLAY_OPTIONS_PARAM_T), 0);
+}
+
+/***********************************************************
+ * Name: vc_tv_test_mode_start
+ *
+ * Arguments:
+ *       24-bit colour, test mode (TV_TEST_MODE_T enum)
+ *
+ * Description: Power on HDMI to test mode, HDMI must be off to start with
+ *
+ * Returns: whether command was sent successfully (zero means success)
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_tv_test_mode_start(uint32_t colour, TV_TEST_MODE_T test_mode) {
+   TV_TEST_MODE_START_PARAM_T param = {VC_HTOV32(colour), VC_HTOV32(test_mode)};
+
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   return tvservice_send_command( VC_TV_TEST_MODE_START, &param, sizeof(TV_TEST_MODE_START_PARAM_T), 0);
+}
+
+/***********************************************************
+ * Name: vc_tv_test_mode_stop
+ *
+ * Arguments:
+ *       none
+ *
+ * Description: Stop test mode and power down HDMI
+ *
+ * Returns: whether command was sent successfully (zero means success)
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_tv_test_mode_stop( void ) {
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+   return tvservice_send_command( VC_TV_TEST_MODE_STOP, NULL, 0, 0);
+}
+
+/***********************************************************
+ * Name: vc_tv_hdmi_ddc_read
+ *
+ * Arguments:
+ *       offset, length to read, pointer to buffer, must be 16 byte aligned
+ *
+ * Description: ddc read over i2c (HDMI only at the moment)
+ *
+ * Returns: length of data read (so zero means error) and the buffer will be filled
+ *          only if no error
+ *
+ ***********************************************************/
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_ddc_read(uint32_t offset, uint32_t length, uint8_t *buffer) {
+   int success;
+   TV_DDC_READ_PARAM_T param = {VC_HTOV32(offset), VC_HTOV32(length)};
+
+   vcos_log_trace("[%s]", VCOS_FUNCTION);
+
+   /*if(!vcos_verify(buffer && (((uint32_t) buffer) % 16) == 0))
+      return -1;*/
+
+   vchi_service_use(tvservice_client.client_handle[0]);
+   success = tvservice_send_command( VC_TV_DDC_READ, &param, sizeof(TV_DDC_READ_PARAM_T), 1);
+
+   if(success == 0) {
+      success = tvservice_wait_for_bulk_receive(buffer, length);
+   }
+   vchi_service_release(tvservice_client.client_handle[0]);
+   return (success == 0)? length : 0; //Either return the whole block or nothing
+}
+
+/**
+ * Sets whether the TV is attached or unplugged.
+ * Required when hotplug interrupt is not handled by VideoCore.
+ */
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_set_attached(uint32_t attached)
+{
+   vcos_log_trace("[%s] attached %d", VCOS_FUNCTION, attached);
+   return tvservice_send_command(VC_TV_SET_ATTACHED, &attached, sizeof(uint32_t), 0);
+}
+
+/**
+ * Sets a property in HDMI output
+ */
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_set_property(const HDMI_PROPERTY_PARAM_T *property) {
+   HDMI_PROPERTY_PARAM_T _property;
+   if(vcos_verify(property)) {
+      memcpy(&_property, property, sizeof(_property));
+      vcos_log_trace("[%s] property:%d values:%d,%d", VCOS_FUNCTION, property->property, property->param1, property->param2);
+      return tvservice_send_command(VC_TV_SET_PROP, &_property, sizeof(_property), 1);
+   }
+   return -1;
+}
+
+/**
+ * Gets a property from HDMI
+ */
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_get_property(HDMI_PROPERTY_PARAM_T *property) {
+   int ret = -1;
+   if(vcos_verify(property)) {
+      TV_GET_PROP_PARAM_T param = {0, {HDMI_PROPERTY_MAX, 0, 0}};
+      uint32_t prop = (uint32_t) property->property;
+      property->param1 = property->param2 = 0;
+      vcos_log_trace("[%s] property:%d", VCOS_FUNCTION, property->property);
+      if((ret = tvservice_send_command_reply( VC_TV_GET_PROP, &prop, sizeof(prop),
+                                              &param, sizeof(param))) == VC_HDMI_SUCCESS) {
+         property->param1 = param.property.param1;
+         property->param2 = param.property.param2;
+      }
+   }
+   return ret;
+}
+
+/**
+ * Converts the notification reason to a string.
+ *
+ * @param reason is the notification reason
+ * @return  The notification reason as a string.
+ */
+VCHPRE_ const char* vc_tv_notification_name(VC_HDMI_NOTIFY_T reason)
+{
+   switch (reason)
+   {
+      case VC_HDMI_UNPLUGGED:
+         return "VC_HDMI_UNPLUGGED";
+      case VC_HDMI_ATTACHED:
+         return "VC_HDMI_ATTACHED";
+      case VC_HDMI_DVI:
+         return "VC_HDMI_DVI";
+      case VC_HDMI_HDMI:
+         return "VC_HDMI_HDMI";
+      case VC_HDMI_HDCP_UNAUTH:
+         return "VC_HDMI_HDCP_UNAUTH";
+      case VC_HDMI_HDCP_AUTH:
+         return "VC_HDMI_HDCP_AUTH";
+      case VC_HDMI_HDCP_KEY_DOWNLOAD:
+         return "VC_HDMI_HDCP_KEY_DOWNLOAD";
+      case VC_HDMI_HDCP_SRM_DOWNLOAD:
+         return "VC_HDMI_HDCP_SRM_DOWNLOAD";
+      case VC_HDMI_CHANGING_MODE:
+         return "VC_HDMI_CHANGING_MODE";
+      default:
+         return "VC_HDMI_UNKNOWN";
+   }
+}
+
+// temporary: maintain backwards compatibility
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_get_supported_modes(HDMI_RES_GROUP_T group,
+                                                    TV_SUPPORTED_MODE_T *supported_modes_deprecated,
+                                                    uint32_t max_supported_modes,
+                                                    HDMI_RES_GROUP_T *preferred_group,
+                                                    uint32_t *preferred_mode) {
+   TV_SUPPORTED_MODE_NEW_T *supported_modes_new = malloc(max_supported_modes * sizeof *supported_modes_new);
+   int modes_copied = vc_tv_hdmi_get_supported_modes_new(group==3 ? HDMI_RES_GROUP_CEA:group, supported_modes_new, max_supported_modes, preferred_group, preferred_mode);
+   int i, j=0;
+
+   for (i=0; i<modes_copied; i++) {
+      TV_SUPPORTED_MODE_T *q = supported_modes_deprecated + j;
+      TV_SUPPORTED_MODE_NEW_T *p = supported_modes_new + i;
+      if (group != 3 || (p->struct_3d_mask & HDMI_3D_STRUCT_SIDE_BY_SIDE_HALF_HORIZONTAL)) {
+         q->scan_mode = p->scan_mode;
+         q->native = p->native;
+         q->code = p->code;
+         q->frame_rate = p->frame_rate;
+         q->width = p->width;
+         q->height = p->height;
+         j++;
+      }
+   }
+   free(supported_modes_new);
+
+   return 0;
+}
+
+/**
+ * Get the unique device ID from the EDID
+ * @param pointer to device ID struct
+ * @return zero if successful, non-zero if failed.
+ */
+VCHPRE_ int VCHPOST_  vc_tv_get_device_id(TV_DEVICE_ID_T *id) {
+   int ret = -1;
+   TV_DEVICE_ID_T param;
+   memset(&param, 0, sizeof(TV_DEVICE_ID_T));
+   if(vcos_verify(id)) {
+      if((ret = tvservice_send_command_reply( VC_TV_GET_DEVICE_ID, NULL, 0,
+                                              &param, sizeof(param))) == VC_HDMI_SUCCESS) {
+         memcpy(id, &param, sizeof(TV_DEVICE_ID_T));
+      } else {
+         id->vendor[0] = '\0';
+         id->monitor_name[0] = '\0';
+         id->serial_num = 0;
+      }
+   }
+   return ret;
+}
+
+// temporary: maintain backwards compatibility
+VCHPRE_ int VCHPOST_ vc_tv_hdmi_power_on_explicit(HDMI_MODE_T mode, HDMI_RES_GROUP_T group, uint32_t code) {
+   if (group == HDMI_RES_GROUP_CEA_3D) {
+      HDMI_PROPERTY_PARAM_T property;
+      property.property = HDMI_PROPERTY_3D_STRUCTURE;
+      property.param1 = HDMI_RES_GROUP_CEA;
+      property.param2 = 0;
+      vc_tv_hdmi_set_property(&property);
+      group = HDMI_RES_GROUP_CEA;
+   }
+   return vc_tv_hdmi_power_on_explicit_new(mode, group, code);
+}
+
diff --git a/interface/vmcs_host/vcfilesys.h b/interface/vmcs_host/vcfilesys.h
new file mode 100755 (executable)
index 0000000..c8617cf
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "vchost_platform_config.h"
+#include "vcfilesys_defs.h"
+#include "vc_fileservice_defs.h"
+
+#ifndef VCFILESYS_H_
+#define VCFILESYS_H_
+
+#ifndef FILESYS_DIR_DEFINED
+#define  FILESYS_DIR_DEFINED
+typedef struct DIR_tag DIR;
+#endif
+
+// Initialises the file system for use
+VCHPRE_ int VCHPOST_ vc_filesys_init (void);
+
+// Stop it to prevent the functions from trying to use it.
+VCHPRE_ void VCHPOST_ vc_filesys_stop(void);
+
+// Return the service number (-1 if not running).
+VCHPRE_ int VCHPOST_ vc_filesys_inum(void);
+
+// Low level file system functions equivalent to close(), lseek(), open(), read() and write()
+VCHPRE_ int VCHPOST_ vc_filesys_close(int fildes);
+
+VCHPRE_ long VCHPOST_ vc_filesys_lseek(int fildes, long offset, int whence);
+
+VCHPRE_ int64_t VCHPOST_ vc_filesys_lseek64(int fildes, int64_t offset, int whence);
+
+VCHPRE_ int VCHPOST_ vc_filesys_open(const char *path, int vc_oflag);
+
+VCHPRE_ int VCHPOST_ vc_filesys_read(int fildes, void *buf, unsigned int nbyte);
+
+VCHPRE_ int VCHPOST_ vc_filesys_write(int fildes, const void *buf, unsigned int nbyte);
+
+VCHPRE_ int VCHPOST_ vc_filesys_mount(const char *device, const char *mountpoint, const char *options);
+VCHPRE_ int VCHPOST_ vc_filesys_umount(const char *mountpoint);
+
+
+// Ends a directory listing iteration
+VCHPRE_ int VCHPOST_ vc_filesys_closedir(void *dhandle);
+
+// Formats the drive that contains the given path
+VCHPRE_ int VCHPOST_ vc_filesys_format(const char *path);
+
+// Returns the amount of free space on the drive that contains the given path
+VCHPRE_ int VCHPOST_ vc_filesys_freespace(const char *path);
+VCHPRE_ int64_t VCHPOST_ vc_filesys_freespace64(const char *path);
+
+// Gets the attributes of the named file
+VCHPRE_ int VCHPOST_ vc_filesys_get_attr(const char *path, fattributes_t *attr);
+
+// Creates a new directory
+VCHPRE_ int VCHPOST_ vc_filesys_mkdir(const char *path);
+
+// Starts a directory listing iteration
+VCHPRE_ void * VCHPOST_ vc_filesys_opendir(const char *dirname);
+
+// Directory listing iterator
+VCHPRE_ struct dirent * VCHPOST_ vc_filesys_readdir_r(void *dhandle, struct dirent *result);
+
+// Deletes a file or (empty) directory
+VCHPRE_ int VCHPOST_ vc_filesys_remove(const char *path);
+
+// Renames a file, provided the new name is on the same file system as the old
+VCHPRE_ int VCHPOST_ vc_filesys_rename(const char *oldfile, const char *newfile);
+
+// Resets the co-processor side file system
+VCHPRE_ int VCHPOST_ vc_filesys_reset(void);
+
+// Sets the attributes of the named file
+VCHPRE_ int VCHPOST_ vc_filesys_set_attr(const char *path, fattributes_t attr);
+
+// Truncates a file at its current position
+VCHPRE_ int VCHPOST_ vc_filesys_setend(int fildes);
+
+// Checks whether there are any messages in the incoming message fifo and responds to any such messages
+VCHPRE_ int VCHPOST_ vc_filesys_poll_message_fifo(void);
+
+// Return the event used to wait for reads.
+VCHPRE_ void * VCHPOST_ vc_filesys_read_event(void);
+
+// Sends a command for VC01 to reset the file system
+VCHPRE_ void VCHPOST_ vc_filesys_sendreset(void);
+
+// Return the error code of the last file system error
+VCHPRE_ int VCHPOST_ vc_filesys_errno(void);
+
+// Invalidates any cluster chains in the FAT that are not referenced in any directory structures
+VCHPRE_ void VCHPOST_ vc_filesys_scandisk(const char *path);
+
+// Checks whether or not a FAT filesystem is corrupt or not. If fix_errors is TRUE behaves exactly as vc_filesys_scandisk.
+VCHPRE_ int VCHPOST_ vc_filesys_chkdsk(const char *path, int fix_errors);
+
+// Return whether a disk is writeable or not.
+VCHPRE_ int VCHPOST_ vc_filesys_diskwritable(const char *path);
+
+// Return file system type of a disk.
+VCHPRE_ int VCHPOST_ vc_filesys_fstype(const char *path);
+
+// Returns the toatl amount of space on the drive that contains the given path
+VCHPRE_ int VCHPOST_ vc_filesys_totalspace(const char *path);
+VCHPRE_ int64_t VCHPOST_ vc_filesys_totalspace64(const char *path);
+
+// Open disk for block level access
+VCHPRE_ int VCHPOST_ vc_filesys_open_disk_raw(const char *path);
+
+// Close disk from block level access mode
+VCHPRE_ int VCHPOST_ vc_filesys_close_disk_raw(const char *path);
+
+// Open disk for normal access
+VCHPRE_ int VCHPOST_ vc_filesys_open_disk(const char *path);
+
+// Close disk for normal access
+VCHPRE_ int VCHPOST_ vc_filesys_close_disk(const char *path);
+
+// Return number of sectors.
+VCHPRE_ int VCHPOST_ vc_filesys_numsectors(const char *path);
+VCHPRE_ int64_t VCHPOST_ vc_filesys_numsectors64(const char *path);
+
+// Begin reading sectors from VideoCore.
+VCHPRE_ int VCHPOST_ vc_filesys_read_sectors_begin(const char *path, uint32_t sector, uint32_t count);
+
+// Read the next sector.
+VCHPRE_ int VCHPOST_ vc_filesys_read_sector(char *buf);
+
+// End streaming sectors.
+VCHPRE_ int VCHPOST_ vc_filesys_read_sectors_end(uint32_t *sectors_read);
+
+// Begin writing sectors from VideoCore.
+VCHPRE_ int VCHPOST_ vc_filesys_write_sectors_begin(const char *path, uint32_t sector, uint32_t count);
+
+// Write the next sector.
+VCHPRE_ int VCHPOST_ vc_filesys_write_sector(const char *buf);
+
+// End streaming sectors.
+VCHPRE_ int VCHPOST_ vc_filesys_write_sectors_end(uint32_t *sectors_written);
+
+#endif //VCFILESYS_H_
+
diff --git a/interface/vmcs_host/vcfilesys_defs.h b/interface/vmcs_host/vcfilesys_defs.h
new file mode 100755 (executable)
index 0000000..cf7d70e
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// File service required types
+
+#ifndef VCFILESYS_DEFS_H
+#define VCFILESYS_DEFS_H
+
+#include <time.h>  // for time_t
+
+/* Define type fattributes_t and struct dirent for use in file system functions */
+
+typedef int fattributes_t;
+//enum {ATTR_RDONLY=1, ATTR_DIRENT=2};
+#define ATTR_RDONLY     0x01        /* Read only file attributes */
+#define ATTR_HIDDEN     0x02        /* Hidden file attributes */
+#define ATTR_SYSTEM     0x04        /* System file attributes */
+#define ATTR_VOLUME     0x08        /* Volume Label file attributes */
+#define ATTR_DIRENT     0x10        /* Dirrectory file attributes */
+#define ATTR_ARCHIVE     0x20        /* Archives file attributes */
+#define ATTR_NORMAL     0x00        /* Normal file attributes */
+
+#define D_NAME_MAX_SIZE 256
+
+#ifndef _DIRENT_H  // This should really be in a dirent.h header to avoid conflicts
+struct dirent
+{
+   char d_name[D_NAME_MAX_SIZE];
+   unsigned int d_size;
+   fattributes_t d_attrib;
+   time_t d_creatime;
+   time_t d_modtime;
+};
+#endif // ifndef _DIRENT_H
+
+#define FS_MAX_PATH 256   // The maximum length of a pathname
+/* Although not used in the API, this value is required on the host and
+VC01 sides of the file system, even if there is no host side. Putting it in
+vc_fileservice_defs.h is not appropriate as it would only be included if there
+was a host side. */
+
+/* File system error codes */
+#define FS_BAD_USER  -7000     // The task isn't registered as a file system user
+
+#define FS_BAD_FILE  -7001     // The path or filename or file descriptor is invalid
+#define FS_BAD_PARM  -7002     // Invalid parameter given
+#define FS_ACCESS    -7003     // File access conflict
+#define FS_MAX_FILES -7004     // Maximum number of files already open
+#define FS_NOEMPTY   -7005     // Directory isn't empty
+#define FS_MAX_SIZE  -7006     // File is over the maximum file size
+
+#define FS_NO_DISK   -7007     // No disk is present, or the disk has not been opened
+#define FS_DISK_ERR  -7008     // There is a problem with the disk
+
+#define FS_IO_ERROR  -7009     // Driver level error
+
+#define FS_FMT_ERR   -7010     // Format error
+
+#define FS_NO_BUFFER -7011     // Internal Nucleus File buffer not available
+#define FS_NUF_INT   -7012     // Internal Nucleus File error
+
+#define FS_UNSPEC_ERR -7013    // Unspecified error
+
+#endif
diff --git a/interface/vmcs_host/vcgencmd.h b/interface/vmcs_host/vcgencmd.h
new file mode 100755 (executable)
index 0000000..31f00af
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// General command service API
+
+#ifndef GENCMD_H
+#define GENCMD_H
+
+#include "vchost_platform_config.h"
+#include "interface/vchi/vchi.h"
+
+VCHPRE_ void VCHPOST_ vc_vchi_gencmd_init(VCHI_INSTANCE_T initialise_instance, VCHI_CONNECTION_T **connections, uint32_t num_connections );
+
+
+/* Initialise general command service. Returns it's interface number. This initialises
+   the host side of the interface, it does not send anything to VideoCore. */
+
+VCHPRE_ int VCHPOST_ vc_gencmd_init(void);
+
+/* Stop the service from being used. */
+
+VCHPRE_ void VCHPOST_ vc_gencmd_stop(void);
+
+/* Return the service number (-1 if not running). */
+VCHPRE_ int VCHPOST_ vc_gencmd_inum(void);
+
+/******************************************************************************
+Send commands to VideoCore.
+These all return 0 for success. They return VC_MSGFIFO_FIFO_FULL if there is
+insufficient space for the whole message in the fifo, and none of the message is
+sent.
+******************************************************************************/
+
+/*  send command to general command serivce */
+VCHPRE_ int VCHPOST_ vc_gencmd_send( const char *format, ... );
+
+/*  get resonse from general command serivce */
+VCHPRE_ int VCHPOST_ vc_gencmd_read_response(char *response, int maxlen);
+
+/* convenience function to send command and receive the response */
+VCHPRE_ int VCHPOST_ vc_gencmd(char *response, int maxlen, const char *format, ...);
+
+/* read part of a response from the general command service */
+VCHPRE_ int VCHPOST_ vc_gencmd_read_response_partial(char *response, int nbytes);
+
+/* if reading with vc_gencmd_read_response_partial end response reads with this */
+VCHPRE_ int VCHPOST_ vc_gencmd_close_response_partial(void);
+
+/* get state of reading of response */
+VCHPRE_ int VCHPOST_ vc_gencmd_read_partial_state(void);
+
+/******************************************************************************
+Utilities to help interpret the responses.
+******************************************************************************/
+
+/* Read the value of a property=value type pair from a string (typically VideoCore's
+   response to a general command). Return non-zero if found. */
+VCHPRE_ int VCHPOST_ vc_gencmd_string_property(char *text, const char *property, char **value, int *length);
+
+/* Read the numeric value of a property=number field from a response string. Return
+   non-zero if found. */
+VCHPRE_ int VCHPOST_ vc_gencmd_number_property(char *text, const char *property, int *number);
+
+/* Send a command until the desired response is received, the error message is detected, or the timeout */
+VCHPRE_ int VCHPOST_ vc_gencmd_until( char        *cmd,
+                                      const char  *property,
+                                      char        *value,
+                                      const char  *error_string,
+                                      int         timeout);
+
+#endif
diff --git a/interface/vmcs_host/vchost.h b/interface/vmcs_host/vchost.h
new file mode 100755 (executable)
index 0000000..23ffa63
--- /dev/null
@@ -0,0 +1,273 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VCHOST_H
+#define VCHOST_H
+
+#include "vchost_platform_config.h"
+#include "vcfilesys_defs.h"
+#include "interface/vcos/vcos.h" //for VCHPRE_ abd VCHPOST_ macro's for func declaration
+#include "interface/vmcs_host/vc_fileservice_defs.h" // for VC_O_XXX file definitions
+#include "interface/vchi/vchi.h"
+
+#define UNUSED_PARAMETER(x) ((void)(x))/* macro to suppress not use warning */
+
+/*---------------------------------------------------------------------------*/
+/* Byte-swapping, dependent on host's orientation */
+/*---------------------------------------------------------------------------*/
+
+#ifndef VC_HOST_IS_BIG_ENDIAN
+#define VC_HTOV32(val) (val)
+#define VC_HTOV16(val) (val)
+#define VC_VTOH32(val) (val)
+#define VC_VTOH16(val) (val)
+#else
+static unsigned long  VC_HTOV32(unsigned long val)  {
+   return ((val<<24) | ((val&0xff00)<<8) | ((val>>8)&0xff00) | ((val>>24)&0xff)); }
+static unsigned short VC_HTOV16(unsigned short val) {
+   return ((val<<8)|(val>>8)); }
+static unsigned long  VC_VTOH32(unsigned long val)  {
+   return ((val<<24) | ((val&0xff00)<<8) | ((val>>8)&0xff00) | ((val>>24)&0xff)); }
+static unsigned short VC_VTOH16(unsigned short val) {
+   return ((val<<8)|(val>>8)); }
+#endif
+
+/*---------------------------------------------------------------------------*/
+/* Host port related functions */
+/*---------------------------------------------------------------------------*/
+
+/* Boot a bin file from flash into RAM. Returns the id of the application running */
+
+VCHPRE_ int VCHPOST_ vc_host_boot(char *cmd_line, void *binimg, int nbytes, int bootloader);
+
+/* Perform any platform specific initialisations. */
+
+VCHPRE_ int VCHPOST_ vc_host_init(void);
+
+/* Read a multiple of 16 bytes from VideoCore. host_addr has no particular alignment,
+   but it is important that it transfers the data in 16-bit chunks if this is possible. */
+
+VCHPRE_ int VCHPOST_ vc_host_read_consecutive(void *host_addr, uint32_t vc_addr, int nbytes, int channel);
+
+#ifdef VC_HOST_IS_BIG_ENDIAN
+// Reads from VideoCore with an implicit swap of each pair of bytes.
+VCHPRE_ int VCHPOST_ vc_host_read_byteswapped(void *host_addr, uint32_t vc_addr, int nbytes, int channel);
+#endif
+
+/* Write a multiple of 16 bytes to VideoCore. host_addr has no particular alignment,
+   but it is important that it transfers the data in 16-bit chunks if this is possible. */
+
+VCHPRE_ int VCHPOST_ vc_host_write_consecutive(uint32_t vc_addr, void *host_addr, int nbytes, int channel);
+
+#ifdef VC_HOST_IS_BIG_ENDIAN
+// Write to VideoCore with an implicit swap of each pair of bytes.
+VCHPRE_ int VCHPOST_ vc_host_write_byteswapped(uint32_t vc_addr, void *host_addr, int nbytes, int channel);
+#endif
+
+/* Send an interrupt to VideoCore. */
+
+VCHPRE_ int VCHPOST_ vc_host_send_interrupt(int channel);
+
+/* Wait for an interrupt from VideoCore. This can return immediately if applications
+   are happy to busy-wait. */
+
+VCHPRE_ int VCHPOST_ vc_host_wait_interrupt(void);
+
+/* Tell the host to act on or ignore interrupts. */
+
+VCHPRE_ void VCHPOST_ vc_host_interrupts(int on);
+
+/* Function called when there is some kind of internal error. Breakpoints can be set on
+   this for debugging. */
+
+VCHPRE_ void VCHPOST_ vc_error(void);
+
+
+/*---------------------------------------------------------------------------*/
+/* Event (interrupt) related functions */
+/*---------------------------------------------------------------------------*/
+
+// Minimum number of event objects an implementation should support.
+// Sufficient for 2 per 8 interfaces/services + 4 others
+#define VC_EVENT_MAX_NUM  20
+
+/* Create (and clear) an event.  Returns a pointer to the event object. */
+VCHPRE_ void * VCHPOST_ vc_event_create(void);
+
+/* Wait for an event to be set, blocking until it is set.
+   Only one thread may be waiting at any one time.
+   The event is automatically cleared on leaving this function. */
+VCHPRE_ void VCHPOST_ vc_event_wait(void *sig);
+
+/* Reads the state of an event (for polling systems) */
+VCHPRE_ int VCHPOST_ vc_event_status(void *sig);
+
+/* Forcibly clears any pending event */
+VCHPRE_ void VCHPOST_ vc_event_clear(void *sig);
+
+/* Sets an event - can be called from any thread */
+VCHPRE_ void VCHPOST_ vc_event_set(void *sig);
+
+/* Register the calling task to be notified of an event. */
+VCHPRE_ void VCHPOST_ vc_event_register(void *ievent);
+
+/* Set events to block, stopping polling mode. */
+VCHPRE_ void VCHPOST_ vc_event_blocking(void);
+
+/*---------------------------------------------------------------------------*/
+/* Semaphore related functions */
+/*---------------------------------------------------------------------------*/
+
+// Minimum number of locks an implementation should support.
+
+#define VC_LOCK_MAX_NUM 32
+
+// Create a lock. Returns a pointer to the lock object. A lock is initially available
+// just once.
+
+VCHPRE_ void * VCHPOST_ vc_lock_create(void);
+
+// Obtain a lock. Block until we have it. Locks are not re-entrant for the same thread.
+
+VCHPRE_ void VCHPOST_ vc_lock_obtain(void *lock);
+
+// Release a lock. Anyone can call this, even if they didn't obtain the lock first.
+
+VCHPRE_ void VCHPOST_ vc_lock_release(void *lock);
+
+/*---------------------------------------------------------------------------*/
+/* File system related functions */
+/*---------------------------------------------------------------------------*/
+
+// Initialises the host dependent file system functions for use
+VCHPRE_ void VCHPOST_ vc_hostfs_init(void);
+VCHPRE_ void VCHPOST_ vc_hostfs_exit(void);
+
+// Low level file system functions equivalent to close(), lseek(), open(), read() and write()
+VCHPRE_ int VCHPOST_ vc_hostfs_close(int fildes);
+
+VCHPRE_ long VCHPOST_ vc_hostfs_lseek(int fildes, long offset, int whence);
+
+VCHPRE_ int64_t VCHPOST_ vc_hostfs_lseek64(int fildes, int64_t offset, int whence);
+
+VCHPRE_ int VCHPOST_ vc_hostfs_open(const char *path, int vc_oflag);
+
+VCHPRE_ int VCHPOST_ vc_hostfs_read(int fildes, void *buf, unsigned int nbyte);
+
+VCHPRE_ int VCHPOST_ vc_hostfs_write(int fildes, const void *buf, unsigned int nbyte);
+
+// Ends a directory listing iteration
+VCHPRE_ int VCHPOST_ vc_hostfs_closedir(void *dhandle);
+
+// Formats the drive that contains the given path
+VCHPRE_ int VCHPOST_ vc_hostfs_format(const char *path);
+
+// Returns the amount of free space on the drive that contains the given path
+VCHPRE_ int VCHPOST_ vc_hostfs_freespace(const char *path);
+VCHPRE_ int64_t VCHPOST_ vc_hostfs_freespace64(const char *path);
+
+// Gets the attributes of the named file
+VCHPRE_ int VCHPOST_ vc_hostfs_get_attr(const char *path, fattributes_t *attr);
+
+// Creates a new directory
+VCHPRE_ int VCHPOST_ vc_hostfs_mkdir(const char *path);
+
+// Starts a directory listing iteration
+VCHPRE_ void * VCHPOST_ vc_hostfs_opendir(const char *dirname);
+
+// Directory listing iterator
+VCHPRE_ struct dirent * VCHPOST_ vc_hostfs_readdir_r(void *dhandle, struct dirent *result);
+
+// Deletes a file or (empty) directory
+VCHPRE_ int VCHPOST_ vc_hostfs_remove(const char *path);
+
+// Renames a file, provided the new name is on the same file system as the old
+VCHPRE_ int VCHPOST_ vc_hostfs_rename(const char *oldfile, const char *newfile);
+
+// Sets the attributes of the named file
+VCHPRE_ int VCHPOST_ vc_hostfs_set_attr(const char *path, fattributes_t attr);
+
+// Truncates a file at its current position
+VCHPRE_ int VCHPOST_ vc_hostfs_setend(int fildes);
+
+// Returns the total amount of space on the drive that contains the given path
+VCHPRE_ int VCHPOST_ vc_hostfs_totalspace(const char *path);
+VCHPRE_ int64_t VCHPOST_ vc_hostfs_totalspace64(const char *path);
+
+// Return millisecond resolution system time, only used for differences
+VCHPRE_ int VCHPOST_ vc_millitime(void);
+
+// Invalidates any cluster chains in the FAT that are not referenced in any directory structures
+VCHPRE_ void VCHPOST_ vc_hostfs_scandisk(const char *path);
+
+// Checks whether or not a FAT filesystem is corrupt or not. If fix_errors is TRUE behaves exactly as vc_filesys_scandisk.
+VCHPRE_ int VCHPOST_ vc_hostfs_chkdsk(const char *path, int fix_errors);
+
+/*---------------------------------------------------------------------------*/
+/* These functions only need to be implemented for the test system. */
+/*---------------------------------------------------------------------------*/
+
+// Open a log file.
+VCHPRE_ void VCHPOST_ vc_log_open(const char *fname);
+
+// Flush any pending data to the log file.
+VCHPRE_ void VCHPOST_ vc_log_flush(void);
+
+// Close the log file.
+VCHPRE_ void VCHPOST_ vc_log_close(void);
+
+// Log an error.
+VCHPRE_ void VCHPOST_ vc_log_error(const char *format, ...);
+
+// Log a warning.
+VCHPRE_ void VCHPOST_ vc_log_warning(const char *format, ...);
+
+// Write a message to the log.
+VCHPRE_ void VCHPOST_ vc_log_msg(const char *format, ...);
+
+// Flush the log.
+VCHPRE_ void VCHPOST_ vc_log_flush(void);
+
+// Return the total number of warnings and errors logged.
+VCHPRE_ void VCHPOST_ vc_log_counts(int *warnings, int *errors);
+
+// Wait for the specified number of microseconds. Used in test system only.
+VCHPRE_ void VCHPOST_ vc_sleep(int ms);
+
+// Get a time value in milliseconds. Used for measuring time differences
+VCHPRE_ uint32_t VCHPOST_ vc_time(void);
+
+// Check timing functions are available. Use in calibrating tests.
+VCHPRE_ int VCHPOST_ calibrate_sleep (const char *data_dir);
+
+/*---------------------------------------------------------------------------*/
+/* Functions to allow dynamic service creation */
+/*---------------------------------------------------------------------------*/
+
+VCHPRE_ void VCHPOST_ vc_host_get_vchi_state(VCHI_INSTANCE_T *initialise_instance, VCHI_CONNECTION_T **connection);
+
+#endif
diff --git a/interface/vmcs_host/vchost_platform_config.h b/interface/vmcs_host/vchost_platform_config.h
new file mode 100755 (executable)
index 0000000..fc9bcd2
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+Copyright (c) 2016, Raspberry Pi (Trading) Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#if defined(__unix__) && !defined(__ANDROID__)
+#include "linux/vchost_config.h"
+#else
+#include "vchost_config.h"
+#endif
diff --git a/interface/vmcs_host/vcilcs.c b/interface/vmcs_host/vcilcs.c
new file mode 100755 (executable)
index 0000000..980a21d
--- /dev/null
@@ -0,0 +1,1071 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+
+/* Project includes */
+#include "vcinclude/common.h"
+
+#include "interface/vchiq_arm/vchiq.h"
+#include "interface/vmcs_host/khronos/IL/OMX_Component.h"
+#include "interface/vmcs_host/vc_ilcs_defs.h"
+#include "interface/vmcs_host/vcilcs.h"
+
+#ifdef USE_VCHI
+#include "interface/vchi/vchiq_wrapper.h"
+#endif
+
+#ifdef _VIDEOCORE
+#include "applications/vmcs/ilcs/ilcs_common.h"
+#endif
+
+/******************************************************************************
+Private types and defines.
+******************************************************************************/
+
+// number of threads that can use ilcs
+#define ILCS_MAX_WAITING 8
+
+// maximum number of retries to grab a wait slot,
+// before the message is discarded and failure returned.
+#define ILCS_WAIT_TIMEOUT 250
+
+// maximum number of concurrent function calls that can
+// be going at once.  Each function call requires to copy
+// the message data so we can dequeue the message from vchi
+// before executing the function, otherwise ILCS may cause
+// a deadlock.  Must be larger than ILCS_MAX_WAITING
+#define ILCS_MAX_NUM_MSGS (ILCS_MAX_WAITING+1)
+#define ILCS_MSG_INUSE_MASK ((1<<ILCS_MAX_NUM_MSGS)-1)
+
+typedef struct {
+   int xid;
+   void *resp;
+   int *rlen;
+   VCOS_EVENT_T event;
+} ILCS_WAIT_T;
+
+typedef enum {
+   NORMAL_SERVICE  = 0,  // process all messages
+   ABORTED_BULK    = 1,  // reject incoming calls
+   CLOSED_CALLBACK = 2,  // quit thread and cleanup, use reaper, VC only
+   DEINIT_CALLED   = 3,  // quit thread and cleanup, no reaper
+} ILCS_QUIT_T;
+
+struct ILCS_SERVICE_T {
+   char name[12];
+#ifdef USE_VCHIQ_ARM
+   VCHIQ_INSTANCE_T vchiq;
+   VCHIQ_SERVICE_HANDLE_T service;
+#else
+   VCHIQ_STATE_T *vchiq;
+#endif
+   int fourcc;
+   VCOS_TIMER_T timer;
+   volatile int timer_expired;
+   VCOS_THREAD_T thread;
+   int timer_needed;
+   ILCS_QUIT_T kill_service;
+   int use_memmgr;
+
+   ILCS_COMMON_T *ilcs_common;
+   ILCS_CONFIG_T config;
+
+   VCHIU_QUEUE_T queue;
+   VCOS_EVENT_T bulk_rx;
+
+   VCOS_SEMAPHORE_T send_sem; // for making control+bulk serialised
+   VCOS_MUTEX_T wait_mtx; // for protecting ->wait and ->next_xid
+   ILCS_WAIT_T wait[ILCS_MAX_WAITING];
+   int next_xid;
+   VCOS_EVENT_T wait_event;  // for signalling when a wait becomes free
+
+   // don't need locking around msg_inuse as only touched by
+   // the server thread in ilcs_process_message
+   unsigned int msg_inuse;
+   unsigned char msg[ILCS_MAX_NUM_MSGS][VCHIQ_SLOT_SIZE];
+   uint32_t header_array[(sizeof(VCHIQ_HEADER_T)+8)/4];
+};
+
+/******************************************************************************
+Private functions in this file.
+Define as static.
+******************************************************************************/
+#ifdef USE_VCHIQ_ARM
+static VCHIQ_STATUS_T ilcs_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header, VCHIQ_SERVICE_HANDLE_T service_user, void *bulk_user);
+#else
+static int ilcs_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header, void *service_user, void *bulk_user);
+#endif
+static void *ilcs_task(void *param);
+static void ilcs_response(ILCS_SERVICE_T *st, uint32_t xid, const unsigned char *msg, int len );
+static void ilcs_transmit(ILCS_SERVICE_T *st, uint32_t cmd, uint32_t xid,
+                          const unsigned char *msg, int len,
+                          const unsigned char *msg2, int len2);
+static void ilcs_command(ILCS_SERVICE_T *st, uint32_t cmd, uint32_t xid, unsigned char *msg, int len);
+static void ilcs_timer(void *param);
+static int ilcs_process_message(ILCS_SERVICE_T *st, int block);
+
+/* ----------------------------------------------------------------------
+ * initialise OpenMAX IL component service
+ * -------------------------------------------------------------------- */
+#ifdef USE_VCHIQ_ARM
+ILCS_SERVICE_T *ilcs_init(VCHIQ_INSTANCE_T state, void **connection, ILCS_CONFIG_T *config, int use_memmgr)
+#else
+ILCS_SERVICE_T *ilcs_init(VCHIQ_STATE_T *state, void **connection, ILCS_CONFIG_T *config, int use_memmgr)
+#endif
+{
+   int32_t i;
+   VCOS_THREAD_ATTR_T thread_attrs;
+   ILCS_SERVICE_T *st;
+   VCHIQ_SERVICE_PARAMS_T params;
+
+   st = vcos_malloc(sizeof(ILCS_SERVICE_T), "ILCS State");
+   if(!st)
+      goto fail_alloc;
+
+   memset(st, 0, sizeof(ILCS_SERVICE_T));
+   st->vchiq = state;
+   st->fourcc = VCHIQ_MAKE_FOURCC('I', 'L', 'C', 'S');
+   st->config = *config;
+
+   // setting this to true implies we have relocatable handles as
+   // buffer pointers, otherwise we interpret them to be real pointers
+   st->use_memmgr = use_memmgr;
+
+   // create semaphore for protecting wait/xid structures
+   if(vcos_mutex_create(&st->wait_mtx, "ILCS") != VCOS_SUCCESS)
+      goto fail_all;
+
+   // create smaphore for control+bulk protection   
+   if(vcos_semaphore_create(&st->send_sem, "ILCS", 1) != VCOS_SUCCESS)
+      goto fail_send_sem;
+
+   // create event group for signalling when a waiting slot becomes free   
+   if(vcos_event_create(&st->wait_event, "ILCS") != VCOS_SUCCESS)
+      goto fail_wait_event;
+
+   for(i=0; i<ILCS_MAX_WAITING; i++)
+      if(vcos_event_create(&st->wait[i].event, "ILCS") != VCOS_SUCCESS)
+      {
+         while(--i >= 0)
+            vcos_event_delete(&st->wait[i].event);
+         goto fail_wait_events;
+      }
+
+   if(vcos_timer_create(&st->timer, "ILCS", ilcs_timer, st) != VCOS_SUCCESS)
+      goto fail_timer;
+
+   // create the queue of incoming messages
+   if(!vchiu_queue_init(&st->queue, 256))
+      goto fail_queue;
+
+   // create the bulk receive event
+   if(vcos_event_create(&st->bulk_rx, "ILCS") != VCOS_SUCCESS)
+      goto fail_bulk_event;
+
+   // create an 'ILCS' service
+#ifdef USE_VCHIQ_ARM
+   /* VCHIQ_ARM distinguishes between servers and clients. Use use_memmgr
+      parameter to detect usage by the client.
+    */
+
+   memset(&params,0,sizeof(params));
+   params.fourcc = st->fourcc;
+   params.callback = ilcs_callback;
+   params.userdata = st;
+   params.version = VC_ILCS_VERSION;
+   params.version_min = VC_ILCS_VERSION;
+
+   if (use_memmgr == 0)
+   {
+      // Host side, which will connect to a listening VideoCore side
+      if (vchiq_open_service(st->vchiq, &params, &st->service) != VCHIQ_SUCCESS)
+         goto fail_service;
+   }
+   else
+   {
+      // VideoCore side, a listening service not connected
+      if (vchiq_add_service(st->vchiq, &params, &st->service) != VCHIQ_SUCCESS)
+         goto fail_service;
+
+      // On VC shutdown we defer calling vchiq_remove_service until after the callback has
+      // returned, so we require not to have the autoclose behaviour
+      vchiq_set_service_option(st->service, VCHIQ_SERVICE_OPTION_AUTOCLOSE, 0);
+   }
+#else
+#ifdef USE_VCHI
+   if(!vchiq_wrapper_add_service(st->vchiq, connection, st->fourcc, ilcs_callback, st))
+      goto fail_service;
+#else
+   if(!vchiq_add_service(st->vchiq, st->fourcc, ilcs_callback, st))
+      goto fail_service;
+#endif
+#endif
+
+   if((st->ilcs_common = st->config.ilcs_common_init(st)) == NULL)
+      goto fail_ilcs_common;
+
+   vcos_thread_attr_init(&thread_attrs);
+   vcos_thread_attr_setstacksize(&thread_attrs, 4096);
+
+   snprintf(st->name, sizeof(st->name), "ILCS_%s", use_memmgr ? "VC" : "HOST");
+
+   if(vcos_thread_create(&st->thread, st->name, &thread_attrs, ilcs_task, st) != VCOS_SUCCESS)
+      goto fail_thread;
+
+   return st;
+
+ fail_thread:
+   st->config.ilcs_common_deinit(st->ilcs_common);
+ fail_ilcs_common:
+#ifdef USE_VCHIQ_ARM
+   vchiq_remove_service(st->service);
+#endif
+ fail_service:
+   vcos_event_delete(&st->bulk_rx);
+ fail_bulk_event:
+   vchiu_queue_delete(&st->queue);
+ fail_queue:
+   vcos_timer_delete(&st->timer);
+ fail_timer:
+   for(i=0; i<ILCS_MAX_WAITING; i++)
+      vcos_event_delete(&st->wait[i].event);
+ fail_wait_events:
+   vcos_event_delete(&st->wait_event);
+ fail_wait_event:
+   vcos_semaphore_delete(&st->send_sem);
+ fail_send_sem:
+   vcos_mutex_delete(&st->wait_mtx);
+ fail_all:
+   vcos_free(st);
+ fail_alloc:
+   return NULL;
+}
+
+/* ----------------------------------------------------------------------
+ * sends a message to the thread to quit
+ * -------------------------------------------------------------------- */
+static void ilcs_send_quit(ILCS_SERVICE_T *st)
+{
+   // We're closing, so tell the task to cleanup
+   VCHIQ_HEADER_T *header = (VCHIQ_HEADER_T *)st->header_array;
+   char *msg;
+   int i;
+   header->size = 8;
+   msg = header->data;
+   msg[0] = IL_SERVICE_QUIT & 0xff;
+   msg[1] = (IL_SERVICE_QUIT >> 8) & 0xff; 
+   msg[2] = (IL_SERVICE_QUIT >> 16) & 0xff;
+   msg[3] = IL_SERVICE_QUIT >> 24;
+         
+   vchiu_queue_push(&st->queue, header);
+
+   // force all currently waiting clients to wake up
+   for(i=0; i<ILCS_MAX_WAITING; i++)
+      if(st->wait[i].resp)
+         vcos_event_signal(&st->wait[i].event);
+
+   vcos_event_signal(&st->wait_event);
+}
+
+/* ----------------------------------------------------------------------
+ * deinitialises the OpenMAX IL Component Service.
+ * This is the usual way that the host side service shuts down, called
+ * from OMX_Deinit().
+ * -------------------------------------------------------------------- */
+void ilcs_deinit(ILCS_SERVICE_T *st)
+{
+   void *data;
+   st->kill_service = DEINIT_CALLED;
+   ilcs_send_quit(st);
+   vcos_thread_join(&st->thread, &data);
+   vcos_free(st);
+}
+
+/* ----------------------------------------------------------------------
+ * sets the wait event, to timeout blocked threads
+ * -------------------------------------------------------------------- */
+static void ilcs_timer(void *param)
+{
+   ILCS_SERVICE_T *st = (ILCS_SERVICE_T *) param;
+
+   vcos_assert(st->timer_expired == 0);
+   st->timer_expired = 1;
+   vcos_event_signal(&st->wait_event);
+}
+
+/* ----------------------------------------------------------------------
+ * returns pointer to common object
+ * -------------------------------------------------------------------- */
+ILCS_COMMON_T *ilcs_get_common(ILCS_SERVICE_T *st)
+{
+   return st->ilcs_common;
+}
+
+/* ----------------------------------------------------------------------
+ * whether the ilcsg thread is currently running
+ * returns 1 if the ilcsg is the current thread, 0 otherwise
+ * -------------------------------------------------------------------- */
+int ilcs_thread_current(void *param)
+{
+   ILCS_SERVICE_T *st = (ILCS_SERVICE_T *) param;
+   return vcos_thread_current() == &st->thread;
+}
+
+/* ----------------------------------------------------------------------
+ * called from the vchiq layer whenever an event happens.
+ * here, we are only interested in the 'message available' callback
+ * -------------------------------------------------------------------- */
+#ifdef USE_VCHIQ_ARM
+static VCHIQ_STATUS_T ilcs_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header, VCHIQ_SERVICE_HANDLE_T service_user, void *bulk_user)
+{
+   ILCS_SERVICE_T *st = (ILCS_SERVICE_T *)VCHIQ_GET_SERVICE_USERDATA(service_user);
+#else
+static int ilcs_callback(VCHIQ_REASON_T reason, VCHIQ_HEADER_T *header, void *service_user, void *bulk_user)
+{
+   ILCS_SERVICE_T *st = (ILCS_SERVICE_T *) service_user;
+#endif
+
+   switch(reason) {
+
+#ifdef USE_VCHIQ_ARM
+   case VCHIQ_SERVICE_OPENED:
+      {
+#ifdef _VIDEOCORE
+         // We're on the VideoCore side and we've been connected to, so we need to spawn another
+         // listening service.  Create another ILCS instance.
+         ILCS_CONFIG_T config;
+         ilcs_config(&config);
+         ilcs_init(st->vchiq, NULL, &config, st->use_memmgr);
+#else
+         vcos_abort();
+#endif
+      }
+      break;
+
+   case VCHIQ_SERVICE_CLOSED:
+      if(st && st->kill_service < CLOSED_CALLBACK)
+      {
+         st->kill_service = CLOSED_CALLBACK;
+         ilcs_send_quit(st);
+      }
+      break;
+
+   case VCHIQ_BULK_RECEIVE_ABORTED:
+      // bulk rx only aborted if we're about to close the service,
+      // so signal this now so that the person waiting for this
+      // bulk rx can return a failure to the user
+      st->kill_service = ABORTED_BULK;
+      vcos_event_signal(&st->bulk_rx);
+      break;
+#endif
+
+   case VCHIQ_MESSAGE_AVAILABLE:
+#ifndef _VIDEOCORE
+      {
+        static int queue_warn = 0;
+        int queue_len = st->queue.write - st->queue.read;
+        if (!queue_warn)
+           queue_warn = getenv("ILCS_WARN") ? (st->queue.size/2) : st->queue.size;
+        if (queue_len >= queue_warn)
+        {
+           if (queue_len == st->queue.size)
+              VCOS_ALERT("ILCS queue full");
+           else
+              VCOS_ALERT("ILCS queue len = %d", queue_len);
+           queue_warn = queue_warn + (st->queue.size - queue_warn)/2;
+        }
+      }
+#endif
+      vchiu_queue_push(&st->queue, header);
+      break;
+
+   case VCHIQ_BULK_RECEIVE_DONE:
+      vcos_event_signal(&st->bulk_rx);
+      break;
+
+   default:
+      break;
+   }
+
+#ifdef USE_VCHIQ_ARM
+   return VCHIQ_SUCCESS;
+#else
+   return 1;
+#endif
+}
+
+/* ----------------------------------------------------------------------
+ * send a message and wait for reply.
+ * repeats continuously, on each connection
+ * -------------------------------------------------------------------- */
+static void *ilcs_task(void *param)
+{
+   ILCS_SERVICE_T *st = (ILCS_SERVICE_T *) param;
+   int i;
+
+   st->config.ilcs_thread_init(st->ilcs_common);
+
+   while(st->kill_service < CLOSED_CALLBACK)
+      ilcs_process_message(st, 1);
+
+   // tidy up after ourselves
+   st->config.ilcs_common_deinit(st->ilcs_common);
+#ifdef USE_VCHIQ_ARM
+   vchiq_remove_service(st->service);
+#endif
+   vcos_event_delete(&st->bulk_rx);
+   vchiu_queue_delete(&st->queue);
+   vcos_timer_delete(&st->timer);
+   for(i=0; i<ILCS_MAX_WAITING; i++)
+      vcos_event_delete(&st->wait[i].event);
+   vcos_event_delete(&st->wait_event);
+   vcos_semaphore_delete(&st->send_sem);
+   vcos_mutex_delete(&st->wait_mtx);
+
+   if(st->kill_service == CLOSED_CALLBACK)
+   {
+#ifdef _VIDEOCORE
+      // need vcos reaper thread to do join/free for us
+      vcos_thread_reap(&st->thread, vcos_free, st);
+#else
+      // we've got a CLOSED callback from vchiq without ilcs_deinit being called.
+      // this shouldn't really happen, so we just want to abort at this point.
+      vcos_abort();
+#endif
+   }
+
+   return 0;
+}
+
+/* ----------------------------------------------------------------------
+ * check to see if there are any pending messages
+ *
+ * if there are no messages, return 0
+ *
+ * otherwise, fetch and process the first queued message (which will
+ * be either a command or response from host)
+ * -------------------------------------------------------------------- */
+#define UINT32(p) ((p)[0] | ((p)[1] << 8) | ((p)[2] << 16) | ((p)[3] << 24))
+
+static int ilcs_process_message(ILCS_SERVICE_T *st, int block)
+{
+   unsigned char *msg;
+   VCHIQ_HEADER_T *header;
+   uint32_t i, msg_len, cmd, xid;
+   if(!block && vchiu_queue_is_empty(&st->queue))
+      return 0; // no more messages
+
+   header = vchiu_queue_pop(&st->queue);
+
+   msg = (unsigned char *) header->data;
+
+   cmd = UINT32(msg);
+   xid = UINT32(msg+4);
+
+   msg += 8;
+   msg_len = header->size - 8;
+
+   if(cmd == IL_RESPONSE)
+   {
+      ilcs_response(st, xid, msg, msg_len);
+#ifdef USE_VCHIQ_ARM
+      vchiq_release_message(st->service, header);
+#else
+      vchiq_release_message(st->vchiq, header);
+#endif
+   }
+   else if(cmd == IL_SERVICE_QUIT)
+   {
+      return 1;
+   }
+   else
+   {
+      // we can only handle commands if we have space to copy the message first
+      if(st->msg_inuse == ILCS_MSG_INUSE_MASK)
+      {
+         // this shouldn't happen, since we have more msg slots than the
+         // remote side is allowed concurrent clients.  this is classed
+         // as a failure case, so we discard the message knowing that things
+         // will surely lock up fairly soon after.
+         vcos_assert(0);
+         return 1;
+      }
+
+      i = 0;
+      while(st->msg_inuse & (1<<i))
+         i++;
+      
+      st->msg_inuse |= (1<<i);
+      
+      memcpy(st->msg[i], msg, msg_len);
+#ifdef USE_VCHIQ_ARM
+      vchiq_release_message(st->service, header);
+#else
+      vchiq_release_message(st->vchiq, header);
+#endif
+      ilcs_command(st, cmd, xid, st->msg[i], msg_len);
+      
+      // mark the message copy as free
+      st->msg_inuse &= ~(1<<i);
+   }
+
+   return 1;
+}
+
+/* ----------------------------------------------------------------------
+ * received response to an ILCS command
+ * -------------------------------------------------------------------- */
+static void ilcs_response(ILCS_SERVICE_T *st, uint32_t xid, const unsigned char *msg, int len)
+{
+   ILCS_WAIT_T *wait = NULL;
+   int i, copy = len;
+
+   // atomically retrieve given ->wait entry
+   vcos_mutex_lock(&st->wait_mtx);
+   for (i=0; i<ILCS_MAX_WAITING; i++) {
+      wait = &st->wait[i];
+      if(wait->resp && wait->xid == xid)
+         break;
+   }
+   vcos_mutex_unlock(&st->wait_mtx);
+
+   if(i == ILCS_MAX_WAITING) {
+      // something bad happened, someone has sent a response back
+      // when the caller said they weren't expecting a response
+      vcos_assert(0);
+      return;
+   }
+
+   // check that we have enough space to copy into.
+   // if we haven't the user can tell by the updated rlen value.
+   if(len > *wait->rlen)
+      copy = *wait->rlen;
+
+   *wait->rlen = len;
+
+   // extract command from fifo and place in response buffer.
+   memcpy(wait->resp, msg, copy);
+
+   vcos_event_signal(&wait->event);
+}
+
+/* ----------------------------------------------------------------------
+ * helper function to transmit an ilcs command/response + payload
+ * -------------------------------------------------------------------- */
+static void ilcs_transmit(ILCS_SERVICE_T *st, uint32_t cmd, uint32_t xid,
+                          const unsigned char *msg, int len,
+                          const unsigned char *msg2, int len2)
+{
+   VCHIQ_ELEMENT_T vec[4];
+   int32_t count = 3;
+
+   vec[0].data = &cmd;
+   vec[0].size = sizeof(cmd);
+   vec[1].data = &xid;
+   vec[1].size = sizeof(xid);
+   vec[2].data = msg;
+   vec[2].size = len;
+
+   if(msg2)
+   {
+      vec[3].data = msg2;
+      vec[3].size = len2;
+      count++;
+   }
+
+#ifdef USE_VCHIQ_ARM
+   vchiq_queue_message(st->service, vec, count);
+#else
+   vchiq_queue_message(st->vchiq, st->fourcc, vec, count);
+#endif
+}
+
+/* ----------------------------------------------------------------------
+ * received response to an ILCS command
+ * -------------------------------------------------------------------- */
+static void
+ilcs_command(ILCS_SERVICE_T *st, uint32_t cmd, uint32_t xid, unsigned char *msg, int len)
+{
+   // execute this function call
+   unsigned char resp[VC_ILCS_MAX_CMD_LENGTH];
+   unsigned char *rbuf = resp;
+   int rlen = -1;
+   IL_FN_T fn;
+
+   if(cmd >= IL_FUNCTION_MAX_NUM) {
+      vcos_assert(0);
+      return;
+   }
+
+   fn = st->config.fns[cmd];
+   if(!fn) {
+      vcos_assert(0);
+      return;
+   }
+
+   // for one method we allow the response to go in the same slot as the 
+   // msg, since it wants to return quite a big amount of debug information
+   // and we know this is safe.
+   if(cmd == IL_GET_DEBUG_INFORMATION)
+   {
+      int max = VCHIQ_SLOT_SIZE - 8;
+      IL_GET_DEBUG_INFORMATION_EXECUTE_T *exe = (IL_GET_DEBUG_INFORMATION_EXECUTE_T *) msg;
+      if(exe->len > max)
+         exe->len = max;
+
+      rbuf = msg;
+   }
+
+   // at this point we are executing in ILCS task context
+   // NOTE: this can cause ilcs_execute_function() calls from within guts of openmaxil!
+   fn(st->ilcs_common, msg, len, rbuf, &rlen);
+   
+   // make sure rlen has been initialised by the function
+   vcos_assert(rlen != -1);
+
+   if(rlen > 0)
+      ilcs_transmit(st, IL_RESPONSE, xid, rbuf, rlen, NULL, 0);
+}
+
+/**
+ * send a string to the host side IL component service.  if resp is NULL
+ * then there is no response to this call, so we should not wait for one.
+ *
+ * returns 0 on successful call made, -1 on failure to send call.
+ * on success, the response is written to 'resp' pointer
+ *
+ * @param data            function parameter data
+ * @param len             length of function parameter data
+ * @param data            optional second function parameter data
+ * @param len2            length of second function parameter data
+ * @param msg_mem_handle  option mem handle to be sent as part of msg data
+ * @param msg_offset      Offset with msg mem handle
+ * @param msg_len         Length of msg mem handle
+ * @param bulk_mem_handle Mem handle sent using VCHI bulk transfer
+ * @param bulk_offset     Offset within memory handle
+ * @param bulk_len        Length of bulk transfer
+ * 
+ * -------------------------------------------------------------------- */
+
+static int ilcs_execute_function_ex(ILCS_SERVICE_T *st, IL_FUNCTION_T func,
+                                    void *data, int len, 
+                                    void *data2, int len2,
+                                    VCHI_MEM_HANDLE_T bulk_mem_handle, void *bulk_offset, int bulk_len,
+                                    void *resp, int *rlen)
+{
+   ILCS_WAIT_T *wait = NULL;
+   int num = 0;
+   uint32_t xid;
+
+   if(st->kill_service)
+      return -1;
+
+   // need to atomically find free ->wait entry
+   vcos_mutex_lock(&st->wait_mtx);
+
+   // if resp is NULL, we do not expect any response
+   if(resp == NULL) {
+      xid = st->next_xid++;
+   }
+   else
+   {
+      int i;
+
+      if(st->timer_needed++ == 0)
+      {
+         vcos_timer_set(&st->timer, 10);
+      }
+
+      // we try a number of times then give up with an error message
+      // rather than just deadlocking
+
+      // Note: the real reason for the timeout is nothing to do with hardware
+      // errors, but is to ensure that if the ILCS thread is calling this function
+      // (because the client makes an OMX call from one of the callbacks) then
+      // the queue of messages from VideoCore still gets serviced.
+
+      for (i=0; i<ILCS_WAIT_TIMEOUT; i++) {
+         num = 0;
+         
+         while(num < ILCS_MAX_WAITING && st->wait[num].resp != NULL)
+            num++;
+         
+         if(num < ILCS_MAX_WAITING || i == ILCS_WAIT_TIMEOUT-1)
+            break;
+         
+         // the previous time round this loop, we woke up because the timer
+         // expired, so restart it
+         if (st->timer_expired)
+         {
+            st->timer_expired = 0;
+            vcos_timer_set(&st->timer, 10);
+         }
+
+         // might be a fatal error if another thread is relying
+         // on this call completing before it can complete
+         // we'll pause until we can carry on and hope that's sufficient.
+         vcos_mutex_unlock(&st->wait_mtx);
+
+         // if we're the ilcs thread, then the waiters might need
+         // us to handle their response, so try and clear those now
+         if(vcos_thread_current() == &st->thread)
+         {
+            while (vcos_event_try(&st->wait_event) != VCOS_SUCCESS)
+            {
+               while(ilcs_process_message(st, 0))
+                  if(st->kill_service >= CLOSED_CALLBACK)
+                     return -1;
+               if (vcos_event_try(&st->wait_event) == VCOS_SUCCESS)
+                  break;
+               vcos_sleep(1);
+            }
+         }
+         else
+         {
+            vcos_event_wait(&st->wait_event);
+         }
+
+         vcos_mutex_lock(&st->wait_mtx);
+      }
+
+      if(--st->timer_needed == 0)
+      {
+         vcos_timer_cancel(&st->timer);
+         st->timer_expired = 0;
+      }
+
+      if(num == ILCS_MAX_WAITING)
+      {
+         // failed to send message.
+         vcos_mutex_unlock(&st->wait_mtx);
+         return -1;
+      }
+
+      wait = &st->wait[num];
+      
+      wait->resp = resp;
+      wait->rlen = rlen;
+      xid = wait->xid = st->next_xid++;
+   }
+
+   vcos_mutex_unlock(&st->wait_mtx);
+   
+   if(bulk_len != 0)
+      vcos_semaphore_wait(&st->send_sem);
+
+   ilcs_transmit(st, func, xid, data, len, data2, len2);
+      
+   if(bulk_len != 0)
+   {
+#ifdef USE_VCHIQ_ARM
+      vchiq_queue_bulk_transmit_handle(st->service, bulk_mem_handle, bulk_offset, bulk_len, NULL);
+#else
+      vchiq_queue_bulk_transmit(st->vchiq, st->fourcc, bulk_mem_handle, bulk_offset, bulk_len, NULL);
+#endif
+      vcos_semaphore_post(&st->send_sem);
+   }
+
+   if(!wait)
+   {
+      // nothing more to do
+      return 0;
+   }
+
+   if(vcos_thread_current() != &st->thread)
+   {
+      // block waiting for response
+      vcos_event_wait(&wait->event);
+   }
+   else
+   {
+      // since we're the server task, to receive our own response code
+      // we need to keep reading messages from the other side.  In
+      // addition, our function executing on the host may also call
+      // functions on VideoCore before replying, so we need to handle
+      // all incoming messages until our response arrives.
+      for (;;)
+      {
+         // wait->sem will not be released until we process the response message
+         // so handle one incoming message
+         ilcs_process_message(st, 1);
+
+         // did the last message release wait->sem ?
+         if(st->kill_service >= CLOSED_CALLBACK || vcos_event_try(&wait->event) == VCOS_SUCCESS)
+            break;
+      }
+   }
+
+   // safe to do the following - the assignment of NULL is effectively atomic
+   wait->resp = NULL;
+   vcos_event_signal(&st->wait_event);
+
+   return st->kill_service >= CLOSED_CALLBACK ? -1 : 0;
+}
+
+int ilcs_execute_function(ILCS_SERVICE_T *st, IL_FUNCTION_T func, void *data, int len, void *resp, int *rlen)
+{
+   return ilcs_execute_function_ex(st, func, data, len, NULL, 0, VCHI_MEM_HANDLE_INVALID, 0, 0, resp, rlen);
+}
+
+/* ----------------------------------------------------------------------
+ * send a buffer via the IL component service.
+ * -------------------------------------------------------------------- */
+
+OMX_ERRORTYPE ilcs_pass_buffer(ILCS_SERVICE_T *st, IL_FUNCTION_T func, void *reference,
+                               OMX_BUFFERHEADERTYPE *pBuffer)                       
+{
+   IL_PASS_BUFFER_EXECUTE_T exe;
+   IL_BUFFER_BULK_T fixup;
+   IL_RESPONSE_HEADER_T resp;
+   VCHI_MEM_HANDLE_T mem_handle = VCHI_MEM_HANDLE_INVALID;
+   void *ret = NULL, *data2 = NULL, *bulk_offset = NULL;
+   int len2 = 0, bulk_len = 0;
+   OMX_U8 *ptr = NULL;
+   int rlen = sizeof(resp);
+
+   if(st->kill_service)
+      return OMX_ErrorHardware;
+
+   if((func == IL_EMPTY_THIS_BUFFER && pBuffer->pInputPortPrivate == NULL) ||
+      (func == IL_FILL_THIS_BUFFER && pBuffer->pOutputPortPrivate == NULL))
+   {
+      // return this to pass conformance
+      // the actual error is using a buffer that hasn't be registered with usebuffer/allocatebuffer
+      return OMX_ErrorIncorrectStateOperation;
+   }
+
+   if((pBuffer->nFlags & OMX_BUFFERFLAG_EXTRADATA) || pBuffer->nFilledLen)
+      ptr = st->config.ilcs_mem_lock(pBuffer) + pBuffer->nOffset;
+
+   exe.reference = reference;
+   memcpy(&exe.bufferHeader, pBuffer, sizeof(OMX_BUFFERHEADERTYPE));
+
+   exe.bufferLen = pBuffer->nFilledLen;
+   if(pBuffer->nFlags & OMX_BUFFERFLAG_EXTRADATA)
+   {
+      // walk down extra-data's appended to the buffer data to work out their length
+      OMX_U8 *end = ptr + pBuffer->nAllocLen - pBuffer->nOffset;
+      OMX_OTHER_EXTRADATATYPE *extra =
+         (OMX_OTHER_EXTRADATATYPE *) (((uint32_t) (ptr + pBuffer->nFilledLen + 3)) & ~3);
+      OMX_BOOL b_corrupt = OMX_FALSE;
+      OMX_EXTRADATATYPE extra_type;
+
+      do
+      {
+         // sanity check the extra data before doing anything with it
+         if(((uint8_t *)extra) + sizeof(OMX_OTHER_EXTRADATATYPE) > end ||
+            ((uint8_t *)extra) + extra->nSize > end ||
+            extra->nSize < sizeof(OMX_OTHER_EXTRADATATYPE) ||
+            (extra->nSize & 3))
+         {
+            // shouldn't happen. probably a problem with the component
+            b_corrupt = OMX_TRUE;
+            break;
+         }
+
+         extra_type = extra->eType;
+         extra = (OMX_OTHER_EXTRADATATYPE *) (((uint8_t *) extra) + extra->nSize);
+      }
+      while(extra_type != OMX_ExtraDataNone);
+
+      // if corrupt then drop the extra data since we can't do anything with it
+      if(b_corrupt)
+         pBuffer->nFlags &= ~OMX_BUFFERFLAG_EXTRADATA;
+      else
+         exe.bufferLen = ((uint8_t *) extra) - ptr;
+   }
+
+   // check that the buffer fits in the allocated region
+   if(exe.bufferLen + pBuffer->nOffset > pBuffer->nAllocLen)
+   {
+      if(ptr != NULL)
+         st->config.ilcs_mem_unlock(pBuffer);
+
+      return OMX_ErrorBadParameter;
+   }
+
+   if(exe.bufferLen)
+   {
+      if(exe.bufferLen + sizeof(IL_PASS_BUFFER_EXECUTE_T) <= VC_ILCS_MAX_INLINE)
+      {
+         // Pass the data in the message itself, and avoid doing a bulk transfer at all...
+         exe.method = IL_BUFFER_INLINE;
+
+         data2 = ptr;
+         len2 = exe.bufferLen;
+      }
+      else
+      {
+         // Pass the misaligned area at the start at end inline within the 
+         // message, and the bulk of the message using a separate bulk
+         // transfer
+         const uint8_t *start = ptr;
+         const uint8_t *end   = start + exe.bufferLen;
+         const uint8_t *round_start = (const OMX_U8*)ILCS_ROUND_UP(start);
+         const uint8_t *round_end   = (const OMX_U8*)ILCS_ROUND_DOWN(end);
+
+         exe.method = IL_BUFFER_BULK;
+
+         if(st->use_memmgr)
+         {
+            bulk_offset = (void *) (round_start-(ptr-pBuffer->nOffset));
+            mem_handle = (VCHI_MEM_HANDLE_T) pBuffer->pBuffer;
+         }
+         else
+            bulk_offset = (void *) round_start;
+
+         bulk_len = round_end-round_start;
+
+         if((fixup.headerlen = round_start - start) > 0)
+            memcpy(fixup.header, start, fixup.headerlen);
+
+         if((fixup.trailerlen = end - round_end) > 0)
+            memcpy(fixup.trailer, round_end, fixup.trailerlen);
+
+         data2 = &fixup;
+         len2 = sizeof(fixup);
+      }
+   }
+   else 
+   {
+      exe.method = IL_BUFFER_NONE;
+   }
+
+   // when used for callbacks to client, no need for response
+   // so only set ret when use component to component
+   if(func == IL_EMPTY_THIS_BUFFER || func == IL_FILL_THIS_BUFFER)
+      ret = &resp;
+
+   if(ilcs_execute_function_ex(st, func, &exe, sizeof(IL_PASS_BUFFER_EXECUTE_T),
+                               data2, len2, mem_handle, bulk_offset, bulk_len, ret, &rlen) < 0 || rlen != sizeof(resp))
+   {
+      ret = &resp;
+      resp.err = OMX_ErrorHardware;
+   }
+
+   if(ptr != NULL)
+      st->config.ilcs_mem_unlock(pBuffer);
+
+   return ret ? resp.err : OMX_ErrorNone;
+}
+
+
+/* ----------------------------------------------------------------------
+ * receive a buffer via the IL component service.
+ * -------------------------------------------------------------------- */
+
+OMX_BUFFERHEADERTYPE *ilcs_receive_buffer(ILCS_SERVICE_T *st, void *call, int clen, OMX_COMPONENTTYPE **pComp)
+{
+   IL_PASS_BUFFER_EXECUTE_T *exe = call;
+   OMX_BUFFERHEADERTYPE *pHeader = exe->bufferHeader.pInputPortPrivate;
+   OMX_U8 *dest, *pBuffer = pHeader->pBuffer;
+   OMX_PTR *pAppPrivate = pHeader->pAppPrivate;
+   OMX_PTR *pPlatformPrivate = pHeader->pPlatformPrivate;
+   OMX_PTR *pInputPortPrivate = pHeader->pInputPortPrivate;
+   OMX_PTR *pOutputPortPrivate = pHeader->pOutputPortPrivate;
+
+   if(st->kill_service)
+      return NULL;
+
+   vcos_assert(pHeader);
+   memcpy(pHeader, &exe->bufferHeader, sizeof(OMX_BUFFERHEADERTYPE));
+
+   *pComp = exe->reference;
+
+   pHeader->pBuffer = pBuffer;
+   pHeader->pAppPrivate = pAppPrivate;
+   pHeader->pPlatformPrivate = pPlatformPrivate;
+   pHeader->pInputPortPrivate = pInputPortPrivate;
+   pHeader->pOutputPortPrivate = pOutputPortPrivate;
+
+   dest = st->config.ilcs_mem_lock(pHeader) + pHeader->nOffset;
+
+   if(exe->method == IL_BUFFER_BULK)
+   {
+      IL_BUFFER_BULK_T *fixup = (IL_BUFFER_BULK_T *) (exe+1);
+      VCHI_MEM_HANDLE_T mem_handle = VCHI_MEM_HANDLE_INVALID;
+      void *bulk_offset;
+      int32_t bulk_len = exe->bufferLen - fixup->headerlen - fixup->trailerlen;
+      
+      vcos_assert(clen == sizeof(IL_PASS_BUFFER_EXECUTE_T) + sizeof(IL_BUFFER_BULK_T));
+
+      if(st->use_memmgr)
+      {
+         mem_handle = (VCHI_MEM_HANDLE_T) pBuffer;
+         bulk_offset = (void*)(pHeader->nOffset + fixup->headerlen);
+      }
+      else
+         bulk_offset = dest + fixup->headerlen;
+
+#ifdef USE_VCHIQ_ARM
+      vchiq_queue_bulk_receive_handle(st->service, mem_handle, bulk_offset, bulk_len, NULL);
+#else
+      vchiq_queue_bulk_receive(st->vchiq, st->fourcc, mem_handle, bulk_offset, bulk_len, NULL);
+#endif
+
+      vcos_event_wait(&st->bulk_rx);
+
+      if(st->kill_service)
+      {
+         // the bulk receive was aborted, and we're about the quit, however this function
+         // being called means the buffer header control message made it across, so we
+         // need to think that this buffer is on VideoCore.  So pretend this is all okay,
+         // but zero the buffer contents so we don't process bad data
+         pHeader->nFilledLen = 0;
+         pHeader->nFlags = 0;
+      }
+      else if(fixup->headerlen || fixup->trailerlen)
+      {
+         uint8_t *end = dest + exe->bufferLen;
+         
+         if(fixup->headerlen)
+            memcpy(dest, fixup->header, fixup->headerlen);
+         if(fixup->trailerlen)
+            memcpy(end-fixup->trailerlen, fixup->trailer, fixup->trailerlen);
+      }
+   }
+   else if(exe->method == IL_BUFFER_INLINE)
+   {
+      IL_BUFFER_INLINE_T *buffer = (IL_BUFFER_INLINE_T *) (exe+1);
+
+      vcos_assert(clen == sizeof(IL_PASS_BUFFER_EXECUTE_T) + exe->bufferLen);
+      memcpy(dest, buffer->buffer, exe->bufferLen);
+   }
+   else if(exe->method == IL_BUFFER_NONE)
+   {
+      vcos_assert(clen == sizeof(IL_PASS_BUFFER_EXECUTE_T));
+   }
+   else
+   {
+      vcos_assert(0);
+   }
+
+   st->config.ilcs_mem_unlock(pHeader);
+   return pHeader;
+}
diff --git a/interface/vmcs_host/vcilcs.h b/interface/vmcs_host/vcilcs.h
new file mode 100755 (executable)
index 0000000..3a11b84
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// OpenMAX IL Component Service definitions
+
+#ifndef ILCS_H
+#define ILCS_H
+
+#include "interface/vmcs_host/khronos/IL/OMX_Component.h"
+#include "interface/vmcs_host/vc_ilcs_defs.h"
+
+struct ILCS_SERVICE_T;
+typedef struct ILCS_SERVICE_T ILCS_SERVICE_T;
+
+struct ILCS_COMMON_T;
+typedef struct ILCS_COMMON_T ILCS_COMMON_T;
+
+typedef void (*IL_FN_T)(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen);
+
+typedef struct {
+   IL_FN_T *fns;
+   ILCS_COMMON_T *(*ilcs_common_init)(ILCS_SERVICE_T *);
+   void (*ilcs_common_deinit)(ILCS_COMMON_T *st);
+   void (*ilcs_thread_init)(ILCS_COMMON_T *st);
+   unsigned char *(*ilcs_mem_lock)(OMX_BUFFERHEADERTYPE *buffer);
+   void (*ilcs_mem_unlock)(OMX_BUFFERHEADERTYPE *buffer);
+} ILCS_CONFIG_T;
+
+// initialise the VideoCore IL Component service
+// returns pointer to state on success, NULL on failure
+#ifdef USE_VCHIQ_ARM
+VCHPRE_ ILCS_SERVICE_T VCHPOST_ *ilcs_init(VCHIQ_INSTANCE_T state, void **connection, ILCS_CONFIG_T *config, int use_memmgr);
+#else
+VCHPRE_ ILCS_SERVICE_T VCHPOST_ *ilcs_init(VCHIQ_STATE_T *state, void **connection, ILCS_CONFIG_T *config, int use_memmgr);
+#endif
+
+// deinitialises the IL Component service
+VCHPRE_ void VCHPOST_ ilcs_deinit(ILCS_SERVICE_T *ilcs);
+
+// returns 1 if the current thread is the ilcs thread, 0 otherwise
+VCHPRE_ int VCHPOST_ ilcs_thread_current(void *param);
+
+// returns pointer to shared state
+VCHPRE_ ILCS_COMMON_T *ilcs_get_common(ILCS_SERVICE_T *ilcs);
+
+VCHPRE_ int VCHPOST_ ilcs_execute_function(ILCS_SERVICE_T *ilcs, IL_FUNCTION_T func, void *data, int len, void *resp, int *rlen);
+VCHPRE_ OMX_ERRORTYPE VCHPOST_ ilcs_pass_buffer(ILCS_SERVICE_T *ilcs, IL_FUNCTION_T func, void *reference, OMX_BUFFERHEADERTYPE *pBuffer);
+VCHPRE_ OMX_BUFFERHEADERTYPE * VCHPOST_ ilcs_receive_buffer(ILCS_SERVICE_T *ilcs, void *call, int clen, OMX_COMPONENTTYPE **pComp);
+
+// bulks are 16 bytes aligned, implicit in use of vchiq
+#define ILCS_ALIGN   16
+
+#define ILCS_ROUND_UP(x) ((((unsigned long)(x))+ILCS_ALIGN-1) & ~(ILCS_ALIGN-1))
+#define ILCS_ROUND_DOWN(x) (((unsigned long)(x)) & ~(ILCS_ALIGN-1))
+#define ILCS_ALIGNED(x) (((unsigned long)(x) & (ILCS_ALIGN-1)) == 0)
+
+
+#ifdef _VIDEOCORE
+#include "vcfw/logging/logging.h"
+
+#ifdef ILCS_LOGGING
+
+#define LOG_MSG ILCS_LOGGING
+extern void ilcs_log_event_handler(OMX_HANDLETYPE hComponent, OMX_PTR pAppData, OMX_EVENTTYPE eEvent,
+                                   OMX_U32 nData1,OMX_U32 nData2,OMX_PTR pEventData);
+
+#else
+
+#define LOG_MSG LOGGING_GENERAL
+#define ilcs_log_event_handler(...)
+extern void dummy_logging_message(int level, const char *format, ...);
+#undef logging_message
+#define logging_message if (1) {} else dummy_logging_message
+
+#endif // ILCS_LOGGING
+#endif // _VIDEOCORE
+
+#endif // ILCS_H
+
diff --git a/interface/vmcs_host/vcilcs_common.c b/interface/vmcs_host/vcilcs_common.c
new file mode 100755 (executable)
index 0000000..ada38da
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/vmcs_host/khronos/IL/OMX_Component.h"
+
+#include "interface/vmcs_host/vcilcs.h"
+#include "interface/vmcs_host/vcilcs_common.h"
+
+static IL_FN_T vcilcs_fns[] = {NULL, // response
+                               NULL, // create component
+
+                               vcil_in_get_component_version,
+                               NULL, // send command
+                               vcil_in_get_parameter,
+                               vcil_in_set_parameter,
+                               vcil_in_get_config,
+                               vcil_in_set_config,
+                               vcil_in_get_extension_index,
+                               vcil_in_get_state,
+                               NULL, // tunnel request
+                               vcil_in_use_buffer,
+                               NULL, // use egl image
+                               NULL, // allocate buffer
+                               vcil_in_free_buffer,
+                               vcil_in_empty_this_buffer,
+                               vcil_in_fill_this_buffer,
+                               NULL, // set callbacks
+                               NULL, // component role enum
+
+                               NULL, // deinit
+
+                               vcil_out_event_handler,
+                               vcil_out_empty_buffer_done,
+                               vcil_out_fill_buffer_done,
+
+                               NULL, // component name enum
+                               NULL, // get debug information
+
+                               NULL
+};
+
+static ILCS_COMMON_T *vcilcs_common_init(ILCS_SERVICE_T *ilcs)
+{
+   ILCS_COMMON_T *st;
+
+   st = vcos_malloc(sizeof(ILCS_COMMON_T), "ILCS_HOST_COMMON");
+   if(!st)
+      return NULL;
+
+   if(vcos_semaphore_create(&st->component_lock, "ILCS", 1) != VCOS_SUCCESS)
+   {
+      vcos_free(st);
+      return NULL;
+   }
+
+   st->ilcs = ilcs;
+   st->component_list = NULL;
+   return st;
+}
+
+static void vcilcs_common_deinit(ILCS_COMMON_T *st)
+{
+   vcos_semaphore_delete(&st->component_lock);
+
+   while(st->component_list)
+   {
+      VC_PRIVATE_COMPONENT_T *comp = st->component_list;
+      st->component_list = comp->next;
+      vcos_free(comp);
+   }
+
+   vcos_free(st);
+}
+
+static void vcilcs_thread_init(ILCS_COMMON_T *st)
+{
+}
+
+static unsigned char *vcilcs_mem_lock(OMX_BUFFERHEADERTYPE *buffer)
+{
+   return buffer->pBuffer;
+}
+
+static void vcilcs_mem_unlock(OMX_BUFFERHEADERTYPE *buffer)
+{
+}
+
+
+void vcilcs_config(ILCS_CONFIG_T *config)
+{
+   config->fns = vcilcs_fns;
+   config->ilcs_common_init = vcilcs_common_init;
+   config->ilcs_common_deinit = vcilcs_common_deinit;
+   config->ilcs_thread_init = vcilcs_thread_init;
+   config->ilcs_mem_lock = vcilcs_mem_lock;
+   config->ilcs_mem_unlock = vcilcs_mem_unlock;
+}
+
diff --git a/interface/vmcs_host/vcilcs_common.h b/interface/vmcs_host/vcilcs_common.h
new file mode 100755 (executable)
index 0000000..0659466
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+// OpenMAX IL Component Service common - Host side header
+
+typedef struct {
+   OMX_U32 port;
+   IL_FUNCTION_T func;
+   OMX_BOOL bEGL;
+   OMX_U32 numBuffers;
+   OMX_DIRTYPE dir;
+} VC_PRIVATE_PORT_T;
+
+struct _VC_PRIVATE_COMPONENT_T {
+   OMX_COMPONENTTYPE *comp;
+   void *reference;
+   OMX_U32 numPorts;
+   OMX_CALLBACKTYPE callbacks;
+   OMX_PTR callback_state;
+   VC_PRIVATE_PORT_T *port;
+   struct _VC_PRIVATE_COMPONENT_T *next;
+};
+typedef struct _VC_PRIVATE_COMPONENT_T  VC_PRIVATE_COMPONENT_T;
+
+struct ILCS_COMMON_T {
+   VCOS_SEMAPHORE_T component_lock;
+   VC_PRIVATE_COMPONENT_T *component_list;
+   ILCS_SERVICE_T *ilcs;
+};
+   
+VCHPRE_ void VCHPOST_ vcilcs_config(ILCS_CONFIG_T *config);
+
+// functions that implement incoming functions calls
+// from VideoCore components to host based components
+VCHPRE_ void VCHPOST_ vcil_in_get_state(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen);
+VCHPRE_ void VCHPOST_ vcil_in_get_parameter(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen);
+VCHPRE_ void VCHPOST_ vcil_in_set_parameter(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen);
+VCHPRE_ void VCHPOST_ vcil_in_get_config(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen);
+VCHPRE_ void VCHPOST_ vcil_in_set_config(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen);
+VCHPRE_ void VCHPOST_ vcil_in_use_buffer(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen);
+VCHPRE_ void VCHPOST_ vcil_in_free_buffer(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen);
+VCHPRE_ void VCHPOST_ vcil_in_empty_this_buffer(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen);
+VCHPRE_ void VCHPOST_ vcil_in_fill_this_buffer(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen);
+VCHPRE_ void VCHPOST_ vcil_in_get_component_version(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen);
+VCHPRE_ void VCHPOST_ vcil_in_get_extension_index(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen);
+VCHPRE_ void VCHPOST_ vcil_in_component_role_enum(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen);
+
+// functions that implement callbacks from VideoCore
+// components to the host core.
+// The prefix is vcil_out since they implement part
+// of the API that the host uses out to VideoCore
+VCHPRE_ void VCHPOST_ vcil_out_event_handler(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen);
+VCHPRE_ void VCHPOST_ vcil_out_empty_buffer_done(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen);
+VCHPRE_ void VCHPOST_ vcil_out_fill_buffer_done(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen);
+
+// functions used by the host IL core
+VCHPRE_ OMX_ERRORTYPE VCHPOST_ vcil_out_get_debug_information(ILCS_COMMON_T *st, OMX_STRING debugInfo, OMX_S32 *pLen);
+VCHPRE_ OMX_ERRORTYPE VCHPOST_ vcil_out_create_component(ILCS_COMMON_T *st, OMX_HANDLETYPE hComponent, OMX_STRING component_name);
+VCHPRE_ OMX_ERRORTYPE VCHPOST_ vcil_out_component_name_enum(ILCS_COMMON_T *st, OMX_STRING cComponentName, OMX_U32 nNameLength, OMX_U32 nIndex);
diff --git a/interface/vmcs_host/vcilcs_in.c b/interface/vmcs_host/vcilcs_in.c
new file mode 100755 (executable)
index 0000000..15efebc
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#include "interface/vmcs_host/khronos/IL/OMX_Component.h"
+
+#include "interface/vmcs_host/vc_ilcs_defs.h"
+#include "interface/vmcs_host/vcilcs.h"
+#include "interface/vmcs_host/vcilcs_common.h"
+
+#ifndef NDEBUG
+static int is_valid_hostside_buffer(OMX_BUFFERHEADERTYPE *pBuf)
+{
+   if (!pBuf->pBuffer)
+      return 0;
+   if ((unsigned long)pBuf->pBuffer < 0x100)
+      return 0; // not believable
+   return 1;
+}
+#endif
+
+void vcil_in_get_state(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen)
+{
+   IL_EXECUTE_HEADER_T *exe = call;
+   IL_GET_STATE_RESPONSE_T *ret = resp;
+   OMX_COMPONENTTYPE *pComp = exe->reference;
+
+   *rlen = sizeof(IL_GET_STATE_RESPONSE_T);
+   ret->func = IL_GET_STATE;
+   ret->err = pComp->GetState(pComp, &ret->state);
+}
+
+void vcil_in_get_parameter(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen)
+{
+   IL_GET_EXECUTE_T *exe = call;
+   IL_GET_RESPONSE_T *ret = resp;
+   OMX_COMPONENTTYPE *pComp  = exe->reference;
+   OMX_U32 size = *((OMX_U32 *) (&exe->param));
+
+   ret->func = IL_GET_PARAMETER;
+
+   if(size > VC_ILCS_MAX_PARAM_SIZE)
+   {
+      *rlen = IL_GET_RESPONSE_HEADER_SIZE;
+      ret->err = OMX_ErrorHardware;
+   }
+   else
+   {
+      *rlen = size + IL_GET_RESPONSE_HEADER_SIZE;
+      ret->err = pComp->GetParameter(pComp, exe->index, exe->param);
+      memcpy(ret->param, exe->param, size);
+   }
+}
+
+void vcil_in_set_parameter(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen)
+{
+   IL_SET_EXECUTE_T *exe = call;
+   IL_RESPONSE_HEADER_T *ret = resp;
+   OMX_COMPONENTTYPE *pComp  = exe->reference;
+
+   *rlen = sizeof(IL_RESPONSE_HEADER_T);
+   ret->func = IL_SET_PARAMETER;
+   ret->err = pComp->SetParameter(pComp, exe->index, exe->param);
+}
+
+void vcil_in_get_config(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen)
+{
+   IL_GET_EXECUTE_T *exe = call;
+   IL_GET_RESPONSE_T *ret = resp;
+   OMX_COMPONENTTYPE *pComp  = exe->reference;
+   OMX_U32 size = *((OMX_U32 *) (&exe->param));
+
+   ret->func = IL_GET_CONFIG;
+
+   if(size > VC_ILCS_MAX_PARAM_SIZE)
+   {
+      *rlen = IL_GET_RESPONSE_HEADER_SIZE;
+      ret->err = OMX_ErrorHardware;
+   }
+   else
+   {
+      *rlen = size + IL_GET_RESPONSE_HEADER_SIZE;
+      ret->func = IL_GET_CONFIG;
+      ret->err = pComp->GetConfig(pComp, exe->index, exe->param);
+      memcpy(ret->param, exe->param, size);
+   }
+}
+
+void vcil_in_set_config(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen)
+{
+   IL_SET_EXECUTE_T *exe = call;
+   IL_RESPONSE_HEADER_T *ret = resp;
+   OMX_COMPONENTTYPE *pComp  = exe->reference;
+
+   *rlen = sizeof(IL_RESPONSE_HEADER_T);
+   ret->func = IL_SET_CONFIG;
+   ret->err = pComp->SetConfig(pComp, exe->index, exe->param);
+}
+
+void vcil_in_use_buffer(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen)
+{
+   IL_ADD_BUFFER_EXECUTE_T *exe = call;
+   IL_ADD_BUFFER_RESPONSE_T *ret = resp;
+   OMX_COMPONENTTYPE *pComp = exe->reference;
+   OMX_U8 *buffer;
+   OMX_BUFFERHEADERTYPE *bufferHeader;
+
+   *rlen = sizeof(IL_ADD_BUFFER_RESPONSE_T);
+
+   buffer = vcos_malloc_aligned(exe->size, 32, "vcin mapping buffer"); // 32-byte aligned
+   if (!buffer)
+   {
+      ret->err = OMX_ErrorInsufficientResources;
+      return;
+   }
+
+   //OMX_OSAL_Trace(OMX_OSAL_TRACE_COMPONENT, "hostcomp: use buffer(%p)\n", buffer);
+   ret->func = IL_USE_BUFFER;
+   ret->err = pComp->UseBuffer(pComp, &bufferHeader, exe->port, exe->bufferReference, exe->size, buffer);
+
+   if (ret->err == OMX_ErrorNone)
+   {
+      // we're going to pass this buffer to VC
+      // initialise our private field in their copy with the host buffer reference
+      OMX_PARAM_PORTDEFINITIONTYPE def;
+      OMX_ERRORTYPE error;
+      def.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
+      def.nVersion.nVersion = OMX_VERSION;
+      def.nPortIndex = exe->port;
+      error = pComp->GetParameter(pComp, OMX_IndexParamPortDefinition, &def);
+      vc_assert(error == OMX_ErrorNone);
+
+      ret->reference = bufferHeader;
+      memcpy(&ret->bufferHeader, bufferHeader, sizeof(OMX_BUFFERHEADERTYPE));
+
+      if (def.eDir == OMX_DirInput)
+         ret->bufferHeader.pInputPortPrivate = bufferHeader;
+      else
+         ret->bufferHeader.pOutputPortPrivate = bufferHeader;
+   }
+   else
+      vcos_free(buffer);
+}
+
+void vcil_in_free_buffer(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen)
+{
+   IL_FREE_BUFFER_EXECUTE_T *exe = call;
+   IL_RESPONSE_HEADER_T *ret = resp;
+   OMX_COMPONENTTYPE *pComp = exe->reference;
+   OMX_BUFFERHEADERTYPE *pHeader;
+   OMX_U8 *buffer;
+   OMX_PARAM_PORTDEFINITIONTYPE def;
+   OMX_ERRORTYPE error;
+
+   def.nSize = sizeof(OMX_PARAM_PORTDEFINITIONTYPE);
+   def.nVersion.nVersion = OMX_VERSION;
+   def.nPortIndex = exe->port;
+   error = pComp->GetParameter(pComp, OMX_IndexParamPortDefinition, &def);
+   vc_assert(error == OMX_ErrorNone);
+   if (def.eDir == OMX_DirInput)
+      pHeader = exe->inputPrivate;
+   else
+      pHeader = exe->outputPrivate;
+
+   buffer = pHeader->pBuffer;
+
+   *rlen = sizeof(IL_RESPONSE_HEADER_T);
+   ret->func = IL_FREE_BUFFER;
+   ret->err = pComp->FreeBuffer(pComp, exe->port, pHeader);
+   if (ret->err == OMX_ErrorNone)
+      vcos_free(buffer);
+}
+
+void vcil_in_empty_this_buffer(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen)
+{
+   IL_RESPONSE_HEADER_T *ret = resp;
+   OMX_COMPONENTTYPE *pComp;
+   OMX_BUFFERHEADERTYPE *pHeader;
+
+   pHeader = ilcs_receive_buffer(st->ilcs, call, clen, &pComp);
+
+   *rlen = sizeof(IL_RESPONSE_HEADER_T);
+   ret->func = IL_EMPTY_THIS_BUFFER;
+
+   if(pHeader)
+   {
+      vc_assert(is_valid_hostside_buffer(pHeader));
+      ret->err = pComp->EmptyThisBuffer(pComp, pHeader);
+   }
+   else
+      ret->err = OMX_ErrorHardware;
+}
+
+void vcil_in_fill_this_buffer(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen)
+{
+   IL_PASS_BUFFER_EXECUTE_T *exe = call;
+   IL_RESPONSE_HEADER_T *ret = resp;
+   OMX_COMPONENTTYPE *pComp = exe->reference;
+   OMX_BUFFERHEADERTYPE *pHeader = exe->bufferHeader.pOutputPortPrivate;
+   OMX_U8 *pBuffer = pHeader->pBuffer;
+   OMX_PTR *pAppPrivate = pHeader->pAppPrivate;
+   OMX_PTR *pPlatformPrivate = pHeader->pPlatformPrivate;
+   OMX_PTR *pInputPortPrivate = pHeader->pInputPortPrivate;
+   OMX_PTR *pOutputPortPrivate = pHeader->pOutputPortPrivate;
+
+   vc_assert(pHeader);
+   memcpy(pHeader, &exe->bufferHeader, sizeof(OMX_BUFFERHEADERTYPE));
+
+   pHeader->pBuffer = pBuffer;
+   pHeader->pAppPrivate = pAppPrivate;
+   pHeader->pPlatformPrivate = pPlatformPrivate;
+   pHeader->pInputPortPrivate = pInputPortPrivate;
+   pHeader->pOutputPortPrivate = pOutputPortPrivate;
+
+   vc_assert(is_valid_hostside_buffer(pHeader));
+
+   *rlen = sizeof(IL_RESPONSE_HEADER_T);
+   ret->func = IL_FILL_THIS_BUFFER;
+   ret->err = pComp->FillThisBuffer(pComp, pHeader);
+}
+
+void vcil_in_get_component_version(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen)
+{
+   IL_EXECUTE_HEADER_T *exe = call;
+   IL_GET_VERSION_RESPONSE_T *ret = resp;
+   OMX_COMPONENTTYPE *pComp = exe->reference;
+
+   *rlen = sizeof(IL_GET_VERSION_RESPONSE_T);
+   ret->func = IL_GET_COMPONENT_VERSION;
+   ret->err = pComp->GetComponentVersion(pComp, ret->name, &ret->component_version, &ret->spec_version, &ret->uuid);
+}
+
+void vcil_in_get_extension_index(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen)
+{
+   IL_GET_EXTENSION_EXECUTE_T *exe = call;
+   IL_GET_EXTENSION_RESPONSE_T *ret = resp;
+   OMX_COMPONENTTYPE *pComp = exe->reference;
+
+   *rlen = sizeof(IL_GET_EXTENSION_RESPONSE_T);
+   ret->func = IL_GET_EXTENSION_INDEX;
+   ret->err = pComp->GetExtensionIndex(pComp, exe->name, &ret->index);
+}
diff --git a/interface/vmcs_host/vcilcs_out.c b/interface/vmcs_host/vcilcs_out.c
new file mode 100755 (executable)
index 0000000..545ddc7
--- /dev/null
@@ -0,0 +1,917 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#include "interface/vchi/vchi.h"
+#include "interface/vcos/vcos_dlfcn.h"
+#include "interface/vmcs_host/khronos/IL/OMX_Component.h"
+#include "interface/vmcs_host/khronos/IL/OMX_ILCS.h"
+#include "interface/vmcs_host/vc_ilcs_defs.h"
+#include "interface/vmcs_host/vcilcs.h"
+#include "interface/vmcs_host/vcilcs_common.h"
+#include "interface/vcos/vcos_dlfcn.h"
+
+static VC_PRIVATE_PORT_T *find_port(VC_PRIVATE_COMPONENT_T *comp, OMX_U32 nPortIndex)
+{
+   OMX_U32 i=0;
+   while (i<comp->numPorts && comp->port[i].port != nPortIndex)
+      i++;
+
+   if (i < comp->numPorts)
+      return &comp->port[i];
+
+   return NULL;
+}
+
+#ifndef NDEBUG
+static int is_valid_hostside_buffer(OMX_BUFFERHEADERTYPE *pBuf)
+{
+   if (!pBuf)
+      return 0;
+   if (!pBuf->pBuffer)
+      return 0;
+   if ((unsigned long)pBuf->pBuffer < 0x100)
+      return 0; // not believable
+   return 1;
+}
+#endif
+
+static OMX_ERRORTYPE vcil_out_ComponentDeInit(OMX_IN OMX_HANDLETYPE hComponent)
+{
+   OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent;
+   VC_PRIVATE_COMPONENT_T *comp;
+   IL_EXECUTE_HEADER_T exe;
+   IL_RESPONSE_HEADER_T resp;
+   ILCS_COMMON_T *st;
+   int rlen = sizeof(resp);
+
+   if(!pComp)
+      return OMX_ErrorBadParameter;
+
+   st = pComp->pApplicationPrivate;
+   comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate;
+
+   exe.reference = comp->reference;
+
+   if(ilcs_execute_function(st->ilcs, IL_COMPONENT_DEINIT, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp) ||
+      resp.err == OMX_ErrorNone)
+   {
+      // remove from list, assuming that we successfully managed to deinit
+      // this component, or that ilcs has returned an error.  The assumption
+      // here is that if the component has managed to correctly signal an
+      // error, it still exists, but if the transport has failed then we might
+      // as well try and cleanup
+      VC_PRIVATE_COMPONENT_T *list, *prev;
+
+      vcos_semaphore_wait(&st->component_lock);
+
+      list = st->component_list;
+      prev = NULL;
+
+      while (list != NULL && list != comp)
+      {
+         prev = list;
+         list = list->next;
+      }
+
+      // failing to find this component is not a good sign.
+      if(vcos_verify(list))
+      {
+         if (prev == NULL)
+            st->component_list = list->next;
+         else
+            prev->next = list->next;
+      }
+
+      vcos_semaphore_post(&st->component_lock);
+      vcos_free(comp);
+   }
+
+   return resp.err;
+}
+
+static OMX_ERRORTYPE vcil_out_GetComponentVersion(OMX_IN  OMX_HANDLETYPE hComponent,
+      OMX_OUT OMX_STRING pComponentName,
+      OMX_OUT OMX_VERSIONTYPE* pComponentVersion,
+      OMX_OUT OMX_VERSIONTYPE* pSpecVersion,
+      OMX_OUT OMX_UUIDTYPE* pComponentUUID)
+{
+   OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent;
+   VC_PRIVATE_COMPONENT_T *comp;
+   IL_EXECUTE_HEADER_T exe;
+   IL_GET_VERSION_RESPONSE_T resp;
+   ILCS_COMMON_T *st;
+   int rlen = sizeof(resp);
+
+   if (!(pComp && pComponentName && pComponentVersion && pSpecVersion && pComponentUUID))
+      return OMX_ErrorBadParameter;
+
+   st = pComp->pApplicationPrivate;
+   comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate;
+
+   exe.reference = comp->reference;
+
+   if(ilcs_execute_function(st->ilcs, IL_GET_COMPONENT_VERSION, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp))
+      return OMX_ErrorHardware;
+
+   strncpy(pComponentName, resp.name, 128);
+   pComponentName[127] = 0;
+   *pComponentVersion = resp.component_version;
+   *pSpecVersion = resp.spec_version;
+   memcpy(pComponentUUID, resp.uuid, sizeof(OMX_UUIDTYPE));
+
+   return resp.err;
+}
+
+static OMX_ERRORTYPE vcil_out_SetCallbacks(OMX_IN  OMX_HANDLETYPE hComponent,
+      OMX_IN  OMX_CALLBACKTYPE* pCallbacks,
+      OMX_IN  OMX_PTR pAppData)
+{
+   OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent;
+   VC_PRIVATE_COMPONENT_T *comp;
+   IL_SET_CALLBACKS_EXECUTE_T exe;
+   IL_RESPONSE_HEADER_T resp;
+   ILCS_COMMON_T *st;
+   int rlen = sizeof(resp);
+
+   if(!(pComp && pCallbacks))
+      return OMX_ErrorBadParameter;
+
+   st = pComp->pApplicationPrivate;
+   comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate;
+
+   comp->callbacks = *pCallbacks;
+   comp->callback_state = pAppData;
+
+   exe.reference = comp->reference;
+   exe.pAppData = pComp;
+
+   if(ilcs_execute_function(st->ilcs, IL_SET_CALLBACKS, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp))
+      return OMX_ErrorHardware;
+
+   return resp.err;
+}
+
+static OMX_ERRORTYPE vcil_out_GetState(OMX_IN  OMX_HANDLETYPE hComponent,
+                                       OMX_OUT OMX_STATETYPE* pState)
+{
+   OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent;
+   VC_PRIVATE_COMPONENT_T *comp;
+   IL_EXECUTE_HEADER_T exe;
+   IL_GET_STATE_RESPONSE_T resp;
+   ILCS_COMMON_T *st;
+   int rlen = sizeof(resp);
+
+   if (!(pComp && pState))
+      return OMX_ErrorBadParameter;
+
+   st = pComp->pApplicationPrivate;
+   comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate;
+
+   exe.reference = comp->reference;
+
+   if(ilcs_execute_function(st->ilcs, IL_GET_STATE, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp))
+      return OMX_ErrorHardware;
+
+   *pState = resp.state;
+
+   return resp.err;
+}
+
+static OMX_ERRORTYPE vcil_out_get(OMX_IN  OMX_HANDLETYPE hComponent,
+                                  OMX_IN  OMX_INDEXTYPE nParamIndex,
+                                  OMX_INOUT OMX_PTR pComponentParameterStructure,
+                                  IL_FUNCTION_T func)
+{
+   OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent;
+   VC_PRIVATE_COMPONENT_T *comp;
+   IL_GET_EXECUTE_T exe;
+   IL_GET_RESPONSE_T resp;
+   OMX_U32 size;
+   ILCS_COMMON_T *st;
+   int rlen = sizeof(resp);
+
+   if (!(pComp && pComponentParameterStructure))
+      return OMX_ErrorBadParameter;
+
+   st = pComp->pApplicationPrivate;
+   comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate;
+
+   exe.reference = comp->reference;
+   exe.index = nParamIndex;
+
+   size = *((OMX_U32 *) pComponentParameterStructure);
+
+   if(size > VC_ILCS_MAX_PARAM_SIZE)
+      return OMX_ErrorHardware;
+
+   memcpy(exe.param, pComponentParameterStructure, size);
+
+   if(ilcs_execute_function(st->ilcs, func, &exe, size + IL_GET_EXECUTE_HEADER_SIZE, &resp, &rlen) < 0 || rlen > sizeof(resp))
+      return OMX_ErrorHardware;
+
+   memcpy(pComponentParameterStructure, resp.param, size);
+
+   return resp.err;
+}
+
+static OMX_ERRORTYPE vcil_out_set(OMX_IN  OMX_HANDLETYPE hComponent,
+                                  OMX_IN  OMX_INDEXTYPE nParamIndex,
+                                  OMX_IN OMX_PTR pComponentParameterStructure,
+                                  IL_FUNCTION_T func)
+{
+   OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent;
+   VC_PRIVATE_COMPONENT_T *comp;
+   IL_SET_EXECUTE_T exe;
+   IL_RESPONSE_HEADER_T resp;
+   OMX_U32 size;
+   ILCS_COMMON_T *st;
+   int rlen = sizeof(resp);
+
+   if (!(pComp && pComponentParameterStructure))
+      return OMX_ErrorBadParameter;
+
+   st = pComp->pApplicationPrivate;
+   comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate;
+
+   exe.reference = comp->reference;
+   exe.index = nParamIndex;
+
+   size = *((OMX_U32 *) pComponentParameterStructure);
+
+   if(size > VC_ILCS_MAX_PARAM_SIZE)
+      return OMX_ErrorHardware;
+
+   memcpy(exe.param, pComponentParameterStructure, size);
+
+   if(ilcs_execute_function(st->ilcs, func, &exe, size + IL_SET_EXECUTE_HEADER_SIZE, &resp, &rlen) < 0 || rlen != sizeof(resp))
+      return OMX_ErrorHardware;
+
+   return resp.err;
+}
+
+static OMX_ERRORTYPE vcil_out_GetParameter(OMX_IN  OMX_HANDLETYPE hComponent,
+      OMX_IN  OMX_INDEXTYPE nParamIndex,
+      OMX_INOUT OMX_PTR pComponentParameterStructure)
+{
+   return vcil_out_get(hComponent, nParamIndex, pComponentParameterStructure, IL_GET_PARAMETER);
+}
+
+static OMX_ERRORTYPE vcil_out_SetParameter(OMX_IN  OMX_HANDLETYPE hComponent,
+      OMX_IN  OMX_INDEXTYPE nParamIndex,
+      OMX_IN OMX_PTR pComponentParameterStructure)
+{
+   return vcil_out_set(hComponent, nParamIndex, pComponentParameterStructure, IL_SET_PARAMETER);
+}
+
+static OMX_ERRORTYPE vcil_out_GetConfig(OMX_IN  OMX_HANDLETYPE hComponent,
+                                        OMX_IN  OMX_INDEXTYPE nParamIndex,
+                                        OMX_INOUT OMX_PTR pComponentParameterStructure)
+{
+   return vcil_out_get(hComponent, nParamIndex, pComponentParameterStructure, IL_GET_CONFIG);
+}
+
+static OMX_ERRORTYPE vcil_out_SetConfig(OMX_IN  OMX_HANDLETYPE hComponent,
+                                        OMX_IN  OMX_INDEXTYPE nParamIndex,
+                                        OMX_IN OMX_PTR pComponentParameterStructure)
+{
+   return vcil_out_set(hComponent, nParamIndex, pComponentParameterStructure, IL_SET_CONFIG);
+}
+
+static OMX_ERRORTYPE vcil_out_SendCommand(OMX_IN  OMX_HANDLETYPE hComponent,
+      OMX_IN  OMX_COMMANDTYPE Cmd,
+      OMX_IN  OMX_U32 nParam1,
+      OMX_IN  OMX_PTR pCmdData)
+{
+   OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent;
+   VC_PRIVATE_COMPONENT_T *comp;
+   IL_SEND_COMMAND_EXECUTE_T exe;
+   IL_RESPONSE_HEADER_T resp;
+   ILCS_COMMON_T *st;
+   int rlen = sizeof(resp);
+
+   if (!pComp)
+      return OMX_ErrorBadParameter;
+
+   st = pComp->pApplicationPrivate;
+   comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate;
+
+   exe.reference = comp->reference;
+   exe.cmd = Cmd;
+   exe.param = nParam1;
+
+   if (Cmd == OMX_CommandMarkBuffer)
+   {
+      exe.mark = *((OMX_MARKTYPE *) pCmdData);
+   }
+   else
+   {
+      exe.mark.hMarkTargetComponent = 0;
+      exe.mark.pMarkData = 0;
+   }
+
+   if(ilcs_execute_function(st->ilcs, IL_SEND_COMMAND, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp))
+      return OMX_ErrorHardware;
+
+   return resp.err;
+}
+
+// Called to pass a buffer from the host-side across the interface to videcore.
+
+static OMX_ERRORTYPE vcil_out_addBuffer(OMX_IN OMX_HANDLETYPE hComponent,
+                                        OMX_INOUT OMX_BUFFERHEADERTYPE** ppBufferHdr,
+                                        OMX_IN OMX_U32 nPortIndex,
+                                        OMX_IN OMX_PTR pAppPrivate,
+                                        OMX_IN OMX_U32 nSizeBytes,
+                                        OMX_IN OMX_U8* pBuffer,
+                                        OMX_IN void *eglImage,
+                                        IL_FUNCTION_T func)
+{
+   OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent;
+   VC_PRIVATE_COMPONENT_T *comp;
+   IL_ADD_BUFFER_EXECUTE_T exe;
+   IL_ADD_BUFFER_RESPONSE_T resp;
+   OMX_BUFFERHEADERTYPE *pHeader;
+   VC_PRIVATE_PORT_T *port;
+   ILCS_COMMON_T *st;
+   int rlen = sizeof(resp);
+
+   if (!(pComp && ppBufferHdr))
+      return OMX_ErrorBadParameter;
+
+   st = pComp->pApplicationPrivate;
+   comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate;
+
+   port = find_port(comp, nPortIndex);
+   if (!port) // bad port index
+      return OMX_ErrorBadPortIndex;
+
+   if (port->numBuffers > 0 && port->func != func)
+   {
+      // inconsistent use of usebuffer/allocatebuffer/eglimage
+      // all ports must receive all buffers by exactly one of these methods
+      vc_assert(port->func != func);
+      return OMX_ErrorInsufficientResources;
+   }
+   port->func = func;
+
+   if (!VCHI_BULK_ALIGNED(pBuffer))
+   {
+      // cannot transfer this buffer across the host interface
+      return OMX_ErrorBadParameter;
+   }
+
+   pHeader = vcos_malloc(sizeof(*pHeader), "vcout buffer header");
+
+   if (!pHeader)
+      return OMX_ErrorInsufficientResources;
+
+   if (func == IL_ALLOCATE_BUFFER)
+   {
+      pBuffer = vcos_malloc_aligned(nSizeBytes, ILCS_ALIGN, "vcout mapping buffer");
+      if (!pBuffer)
+      {
+         vcos_free(pHeader);
+         return OMX_ErrorInsufficientResources;
+      }
+   }
+
+   exe.reference = comp->reference;
+   exe.bufferReference = pHeader;
+   exe.port = nPortIndex;
+   exe.size = nSizeBytes;
+   exe.eglImage = eglImage;
+
+   if(ilcs_execute_function(st->ilcs, func, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp))
+      resp.err = OMX_ErrorHardware;
+
+   if (resp.err == OMX_ErrorNone)
+   {
+      memcpy(pHeader, &resp.bufferHeader, sizeof(OMX_BUFFERHEADERTYPE));
+      if (port->dir == OMX_DirOutput)
+         pHeader->pOutputPortPrivate = resp.reference;
+      else
+         pHeader->pInputPortPrivate = resp.reference;
+
+      if (func == IL_USE_EGL_IMAGE)
+      {
+         pHeader->pBuffer = (OMX_U8*)eglImage;
+         port->bEGL = OMX_TRUE;
+      }         
+      else
+      {
+         pHeader->pBuffer = pBuffer;
+         port->bEGL = OMX_FALSE;
+      }
+
+      pHeader->pAppPrivate = pAppPrivate;
+      *ppBufferHdr = pHeader;
+      port->numBuffers++;
+   }
+   else
+   {
+      if (func == IL_ALLOCATE_BUFFER)
+         vcos_free(pBuffer);
+      vcos_free(pHeader);
+   }
+
+   return resp.err;
+}
+
+static VCOS_ONCE_T loaded_eglIntOpenMAXILDoneMarker = VCOS_ONCE_INIT;
+static int (*local_eglIntOpenMAXILDoneMarker) (void* component_handle, void *egl_image) = NULL;
+
+static void load_eglIntOpenMAXILDoneMarker(void)
+{
+   void *handle;
+
+   /* First try to load from the current process, this will succeed
+    * if something that is linked to libEGL is already loaded or
+    * something explicitly loaded libEGL with RTLD_GLOBAL
+    */
+   handle = vcos_dlopen(NULL, VCOS_DL_GLOBAL);
+   local_eglIntOpenMAXILDoneMarker = (void * )vcos_dlsym(handle, "eglIntOpenMAXILDoneMarker");
+   if (local_eglIntOpenMAXILDoneMarker == NULL)
+   {
+      vcos_dlclose(handle);
+      /* If that failed try to load libEGL.so explicitely */
+      handle = vcos_dlopen("libEGL.so", VCOS_DL_LAZY | VCOS_DL_LOCAL);
+      vc_assert(handle != NULL);
+      local_eglIntOpenMAXILDoneMarker = (void * )vcos_dlsym(handle, "eglIntOpenMAXILDoneMarker");
+      vc_assert(local_eglIntOpenMAXILDoneMarker != NULL);
+   }
+}
+
+static OMX_ERRORTYPE vcil_out_UseEGLImage(OMX_IN OMX_HANDLETYPE hComponent,
+      OMX_INOUT OMX_BUFFERHEADERTYPE** ppBufferHdr,
+      OMX_IN OMX_U32 nPortIndex,
+      OMX_IN OMX_PTR pAppPrivate,
+      OMX_IN void* eglImage)
+{
+   /* Load eglIntOpenMAXILDoneMarker() and libEGL here, it will be needed later */
+   vcos_once(&loaded_eglIntOpenMAXILDoneMarker, load_eglIntOpenMAXILDoneMarker);
+
+   return vcil_out_addBuffer(hComponent, ppBufferHdr, nPortIndex, pAppPrivate, 0, NULL, eglImage, IL_USE_EGL_IMAGE);
+}
+
+static OMX_ERRORTYPE vcil_out_UseBuffer(OMX_IN OMX_HANDLETYPE hComponent,
+                                        OMX_INOUT OMX_BUFFERHEADERTYPE** ppBufferHdr,
+                                        OMX_IN OMX_U32 nPortIndex,
+                                        OMX_IN OMX_PTR pAppPrivate,
+                                        OMX_IN OMX_U32 nSizeBytes,
+                                        OMX_IN OMX_U8* pBuffer)
+{
+   return vcil_out_addBuffer(hComponent, ppBufferHdr, nPortIndex, pAppPrivate, nSizeBytes, pBuffer, NULL, IL_USE_BUFFER);
+}
+
+static OMX_ERRORTYPE vcil_out_AllocateBuffer(OMX_IN OMX_HANDLETYPE hComponent,
+      OMX_INOUT OMX_BUFFERHEADERTYPE** ppBufferHdr,
+      OMX_IN OMX_U32 nPortIndex,
+      OMX_IN OMX_PTR pAppPrivate,
+      OMX_IN OMX_U32 nSizeBytes)
+{
+   return vcil_out_addBuffer(hComponent, ppBufferHdr, nPortIndex, pAppPrivate, nSizeBytes, NULL, NULL, IL_ALLOCATE_BUFFER);
+}
+
+static OMX_ERRORTYPE vcil_out_FreeBuffer(OMX_IN  OMX_HANDLETYPE hComponent,
+      OMX_IN  OMX_U32 nPortIndex,
+      OMX_IN  OMX_BUFFERHEADERTYPE* pBufferHdr)
+{
+   OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent;
+   VC_PRIVATE_COMPONENT_T *comp;
+   IL_FREE_BUFFER_EXECUTE_T exe;
+   IL_RESPONSE_HEADER_T resp;
+   VC_PRIVATE_PORT_T *port;
+   ILCS_COMMON_T *st;
+   int rlen = sizeof(resp);
+
+   if (!(pComp && pBufferHdr))
+      return OMX_ErrorBadParameter;
+
+   st = pComp->pApplicationPrivate;
+   comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate;
+
+   port = find_port(comp, nPortIndex);
+   if (!port)
+      return OMX_ErrorBadPortIndex;
+
+   if (port->numBuffers == 0)
+      return OMX_ErrorIncorrectStateTransition;
+
+   exe.reference = comp->reference;
+   exe.port = nPortIndex;
+   if (port->dir == OMX_DirOutput)
+      exe.bufferReference = pBufferHdr->pOutputPortPrivate;
+   else
+      exe.bufferReference = pBufferHdr->pInputPortPrivate;
+   exe.func = port->func;
+   exe.inputPrivate = NULL;
+   exe.outputPrivate = NULL;
+
+   if(ilcs_execute_function(st->ilcs, IL_FREE_BUFFER, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp))
+      return OMX_ErrorHardware;
+
+   if (resp.err == OMX_ErrorNone)
+   {
+      if (port->func == IL_ALLOCATE_BUFFER)
+         vcos_free(pBufferHdr->pBuffer);
+      vcos_free(pBufferHdr);
+      port->numBuffers--;
+   }
+
+   return resp.err;
+}
+
+// Called on host-side to pass a buffer to VideoCore to be emptied
+static OMX_ERRORTYPE vcil_out_EmptyThisBuffer(OMX_IN  OMX_HANDLETYPE hComponent,
+      OMX_IN  OMX_BUFFERHEADERTYPE* pBuffer)
+{
+   OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent;
+   VC_PRIVATE_COMPONENT_T *comp;
+   ILCS_COMMON_T *st;
+   if (!(pComp && pBuffer))
+      return (OMX_ErrorBadParameter);
+
+   st = pComp->pApplicationPrivate;
+   comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate;
+   
+   return ilcs_pass_buffer(st->ilcs, IL_EMPTY_THIS_BUFFER, comp->reference, pBuffer);
+}
+
+// Called from ril_top as OMX_FillThisBuffer().
+// ->pBuffer field is expected to be a memory handle.
+
+static OMX_ERRORTYPE vcil_out_FillThisBuffer(OMX_IN  OMX_HANDLETYPE hComponent,
+      OMX_IN  OMX_BUFFERHEADERTYPE* pBuffer)
+{
+   OMX_ERRORTYPE err;
+   OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent;
+   VC_PRIVATE_COMPONENT_T *comp;
+   VC_PRIVATE_PORT_T *port;
+   ILCS_COMMON_T *st;
+
+   if (!(pComp && pBuffer))
+      return (OMX_ErrorBadParameter);
+
+   st = pComp->pApplicationPrivate;
+   comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate;
+
+   port = find_port(comp, pBuffer->nOutputPortIndex);
+   if(!port)
+      return OMX_ErrorBadPortIndex;
+
+   if(pBuffer->pBuffer == 0)
+      return OMX_ErrorIncorrectStateOperation;
+
+   vcos_assert(pComp != NULL && comp != NULL && port != NULL && st != NULL);
+   
+   // The lower layers will attempt to transfer the bytes specified if we don't
+   // clear these - callers should ideally do this themselves, but it is not
+   // mandated in the specification.
+   pBuffer->nFilledLen = 0;
+   pBuffer->nFlags = 0;
+
+   vc_assert(port->bEGL == OMX_TRUE || is_valid_hostside_buffer(pBuffer));  
+
+   err = ilcs_pass_buffer(st->ilcs, IL_FILL_THIS_BUFFER, comp->reference, pBuffer);
+   
+   if (err == OMX_ErrorNone && port->bEGL == OMX_TRUE)
+   {
+      // If an output port is marked as an EGL port, we request EGL to notify the IL component 
+      // when it's allowed to render into the buffer/EGLImage.
+      vc_assert(local_eglIntOpenMAXILDoneMarker != NULL);
+      local_eglIntOpenMAXILDoneMarker(comp->reference, pBuffer->pBuffer);
+   }      
+
+   return err;
+}
+
+static OMX_ERRORTYPE vcil_out_ComponentTunnelRequest(OMX_IN  OMX_HANDLETYPE hComponent,
+      OMX_IN  OMX_U32 nPort,
+      OMX_IN  OMX_HANDLETYPE hTunneledComp,
+      OMX_IN  OMX_U32 nTunneledPort,
+      OMX_INOUT  OMX_TUNNELSETUPTYPE* pTunnelSetup)
+{
+   OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent;
+   VC_PRIVATE_COMPONENT_T *comp;
+   IL_TUNNEL_REQUEST_EXECUTE_T exe;
+   IL_TUNNEL_REQUEST_RESPONSE_T resp;
+   VC_PRIVATE_COMPONENT_T *list;
+   ILCS_COMMON_T *st;
+   int rlen = sizeof(resp);
+
+   if(!pComp)
+      return OMX_ErrorBadParameter;
+
+   st = pComp->pApplicationPrivate;
+   comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate;
+
+   exe.reference = comp->reference;
+   exe.port = nPort;
+   exe.tunnel_port = nTunneledPort;
+   if (pTunnelSetup)
+      exe.setup = *pTunnelSetup;
+
+   // the other component may be on the host or on VC.  Look through our list
+   // so we can tell, and tell ILCS on VC the details.
+   vcos_semaphore_wait(&st->component_lock);
+
+   list = st->component_list;
+   while (list != NULL && list->comp != (void *) hTunneledComp)
+      list = list->next;
+
+   vcos_semaphore_post(&st->component_lock);
+
+   if (list == NULL)
+   {
+      exe.tunnel_ref = hTunneledComp;
+      exe.tunnel_host = OMX_TRUE;
+   }
+   else
+   {
+      exe.tunnel_ref = list->reference;
+      exe.tunnel_host = OMX_FALSE;
+   }
+
+   if(ilcs_execute_function(st->ilcs, IL_COMPONENT_TUNNEL_REQUEST, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp))
+      return OMX_ErrorHardware;
+
+   if (pTunnelSetup)
+      *pTunnelSetup = resp.setup;
+   return resp.err;
+}
+
+static OMX_ERRORTYPE vcil_out_GetExtensionIndex(OMX_IN  OMX_HANDLETYPE hComponent,
+      OMX_IN  OMX_STRING cParameterName,
+      OMX_OUT OMX_INDEXTYPE* pIndexType)
+{
+   OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent;
+   VC_PRIVATE_COMPONENT_T *comp;
+   IL_GET_EXTENSION_EXECUTE_T exe;
+   IL_GET_EXTENSION_RESPONSE_T resp;
+   ILCS_COMMON_T *st;
+   int rlen = sizeof(resp);
+
+   if (!(pComp && cParameterName && pIndexType))
+      return OMX_ErrorBadParameter;
+
+   st = pComp->pApplicationPrivate;
+   comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate;
+
+   exe.reference = comp->reference;
+   strncpy(exe.name, cParameterName, 128);
+   exe.name[127] = 0;
+
+   if(ilcs_execute_function(st->ilcs, IL_GET_EXTENSION_INDEX, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp))
+      return OMX_ErrorHardware;
+
+   *pIndexType = resp.index;
+   return resp.err;
+}
+
+static OMX_ERRORTYPE vcil_out_ComponentRoleEnum(OMX_IN OMX_HANDLETYPE hComponent,
+      OMX_OUT OMX_U8 *cRole,
+      OMX_IN OMX_U32 nIndex)
+{
+   OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent;
+   VC_PRIVATE_COMPONENT_T *comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate;
+   IL_COMPONENT_ROLE_ENUM_EXECUTE_T exe;
+   IL_COMPONENT_ROLE_ENUM_RESPONSE_T resp;
+   ILCS_COMMON_T *st = pComp->pApplicationPrivate;
+   int rlen = sizeof(resp);
+
+   exe.reference = comp->reference;
+   exe.index = nIndex;
+
+   if(ilcs_execute_function(st->ilcs, IL_COMPONENT_ROLE_ENUM, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp))
+      return OMX_ErrorHardware;
+
+   strncpy((char *) cRole, (char *) resp.role, 128);
+   cRole[127] = 0;
+   return resp.err;
+}
+
+OMX_ERRORTYPE vcil_out_component_name_enum(ILCS_COMMON_T *st, OMX_STRING cComponentName, OMX_U32 nNameLength, OMX_U32 nIndex)
+{
+   IL_COMPONENT_NAME_ENUM_EXECUTE_T exe;
+   IL_COMPONENT_NAME_ENUM_RESPONSE_T resp;
+   int rlen = sizeof(resp);
+
+   exe.index = nIndex;
+
+   if(ilcs_execute_function(st->ilcs, IL_COMPONENT_NAME_ENUM, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp))
+      return OMX_ErrorHardware;
+
+   if (sizeof(resp.name) < nNameLength)
+      nNameLength = sizeof(resp.name);
+
+   strncpy((char *)cComponentName, (char *) resp.name, nNameLength);
+   cComponentName[127] = 0;
+   return resp.err;
+}
+
+OMX_ERRORTYPE vcil_out_get_debug_information(ILCS_COMMON_T *st, OMX_STRING debugInfo, OMX_S32 *pLen)
+{
+   IL_GET_DEBUG_INFORMATION_EXECUTE_T exe;
+
+   exe.len = *pLen;
+
+   if(ilcs_execute_function(st->ilcs, IL_GET_DEBUG_INFORMATION, &exe, sizeof(exe), debugInfo, (int *) pLen) < 0)
+      return OMX_ErrorHardware;
+
+   return OMX_ErrorNone;
+}
+
+// Called on the host side to create an OMX component.
+OMX_ERRORTYPE vcil_out_create_component(ILCS_COMMON_T *st, OMX_HANDLETYPE hComponent, OMX_STRING component_name)
+{
+   OMX_COMPONENTTYPE *pComp = (OMX_COMPONENTTYPE *) hComponent;
+   IL_CREATE_COMPONENT_EXECUTE_T exe;
+   IL_CREATE_COMPONENT_RESPONSE_T resp;
+   VC_PRIVATE_COMPONENT_T *comp;
+   OMX_U32 i;
+   int rlen = sizeof(resp);
+
+   if (strlen(component_name) >= sizeof(exe.name))
+      return OMX_ErrorInvalidComponent;
+
+   strcpy(exe.name, component_name);
+   exe.mark = pComp;
+
+   if(ilcs_execute_function(st->ilcs, IL_CREATE_COMPONENT, &exe, sizeof(exe), &resp, &rlen) < 0 || rlen != sizeof(resp))
+      return OMX_ErrorHardware;
+
+   if (resp.err != OMX_ErrorNone)
+      return resp.err;
+
+   comp = vcos_malloc(sizeof(VC_PRIVATE_COMPONENT_T) + (sizeof(VC_PRIVATE_PORT_T) * resp.numPorts), "ILCS Host Comp");
+   if (!comp)
+   {
+      IL_EXECUTE_HEADER_T dexe;
+      IL_RESPONSE_HEADER_T dresp;
+      int dlen = sizeof(dresp);
+
+      dexe.reference = resp.reference;
+
+      ilcs_execute_function(st->ilcs, IL_COMPONENT_DEINIT, &dexe, sizeof(dexe), &dresp, &dlen);
+      return OMX_ErrorInsufficientResources;
+   }
+
+   memset(comp, 0, sizeof(VC_PRIVATE_COMPONENT_T) + (sizeof(VC_PRIVATE_PORT_T) * resp.numPorts));
+
+   comp->reference = resp.reference;
+   comp->comp = pComp;
+   comp->numPorts = resp.numPorts;
+   comp->port = (VC_PRIVATE_PORT_T *) ((unsigned char *) comp + sizeof(VC_PRIVATE_COMPONENT_T));
+
+   for (i=0; i<comp->numPorts; i++)
+   {
+      if (i && !(i&0x1f))
+      {
+         IL_GET_EXECUTE_T gexe;
+         IL_GET_RESPONSE_T gresp;
+         OMX_PARAM_PORTSUMMARYTYPE *summary;
+         int glen = sizeof(gresp);
+
+         gexe.reference = comp->reference;
+         gexe.index = OMX_IndexParamPortSummary;
+
+         summary = (OMX_PARAM_PORTSUMMARYTYPE *) &gexe.param;
+         summary->nSize = sizeof(OMX_PARAM_PORTSUMMARYTYPE);
+         summary->nVersion.nVersion = OMX_VERSION;
+         summary->reqSet = i>>5;
+
+         ilcs_execute_function(st->ilcs, IL_GET_PARAMETER, &gexe,
+                               sizeof(OMX_PARAM_PORTSUMMARYTYPE)+IL_GET_EXECUTE_HEADER_SIZE,
+                               &gresp, &glen);
+
+         summary = (OMX_PARAM_PORTSUMMARYTYPE *) &gresp.param;
+         resp.portDir = summary->portDir;
+         memcpy(resp.portIndex, summary->portIndex, sizeof(OMX_U32) * 32);
+      }
+
+      comp->port[i].port = resp.portIndex[i&0x1f];
+      comp->port[i].dir = ((resp.portDir >> (i&0x1f)) & 1) ? OMX_DirOutput : OMX_DirInput;
+   }
+
+   vcos_semaphore_wait(&st->component_lock);
+   // insert into head of list
+   comp->next = st->component_list;
+   st->component_list = comp;
+   vcos_semaphore_post(&st->component_lock);
+
+   pComp->pComponentPrivate = comp;
+   pComp->pApplicationPrivate = st;
+
+   pComp->GetComponentVersion = vcil_out_GetComponentVersion;
+   pComp->ComponentDeInit = vcil_out_ComponentDeInit;
+   pComp->SetCallbacks = vcil_out_SetCallbacks;
+   pComp->GetState = vcil_out_GetState;
+   pComp->GetParameter = vcil_out_GetParameter;
+   pComp->SetParameter = vcil_out_SetParameter;
+   pComp->GetConfig = vcil_out_GetConfig;
+   pComp->SetConfig = vcil_out_SetConfig;
+   pComp->SendCommand = vcil_out_SendCommand;
+   pComp->UseBuffer = vcil_out_UseBuffer;
+   pComp->AllocateBuffer = vcil_out_AllocateBuffer;
+   pComp->FreeBuffer = vcil_out_FreeBuffer;
+   pComp->EmptyThisBuffer = vcil_out_EmptyThisBuffer;
+   pComp->FillThisBuffer = vcil_out_FillThisBuffer;
+   pComp->ComponentTunnelRequest = vcil_out_ComponentTunnelRequest;
+   pComp->GetExtensionIndex = vcil_out_GetExtensionIndex;
+   pComp->UseEGLImage = vcil_out_UseEGLImage;
+   pComp->ComponentRoleEnum = vcil_out_ComponentRoleEnum;
+
+   return resp.err;
+}
+
+/* callbacks */
+
+void vcil_out_event_handler(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen)
+{
+   IL_EVENT_HANDLER_EXECUTE_T *exe = call;
+   OMX_COMPONENTTYPE *pComp = exe->reference;
+   VC_PRIVATE_COMPONENT_T *comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate;
+
+   *rlen = 0;
+
+   vcos_assert(comp->callbacks.EventHandler);
+   comp->callbacks.EventHandler(pComp, comp->callback_state, exe->event, exe->data1, exe->data2, exe->eventdata);
+}
+
+// Called on host side via RPC in response to empty buffer completing
+void vcil_out_empty_buffer_done(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen)
+{
+   IL_PASS_BUFFER_EXECUTE_T *exe = call;
+   OMX_COMPONENTTYPE *pComp = exe->reference;
+   VC_PRIVATE_COMPONENT_T *comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate;
+   OMX_BUFFERHEADERTYPE *pHeader = exe->bufferHeader.pOutputPortPrivate;
+   OMX_U8 *pBuffer = pHeader->pBuffer;
+   OMX_PTR *pAppPrivate = pHeader->pAppPrivate;
+   OMX_PTR *pPlatformPrivate = pHeader->pPlatformPrivate;
+   OMX_PTR *pInputPortPrivate = pHeader->pInputPortPrivate;
+   OMX_PTR *pOutputPortPrivate = pHeader->pOutputPortPrivate;
+
+   memcpy(pHeader, &exe->bufferHeader, sizeof(OMX_BUFFERHEADERTYPE));
+
+   pHeader->pBuffer = pBuffer;
+   pHeader->pAppPrivate = pAppPrivate;
+   pHeader->pPlatformPrivate = pPlatformPrivate;
+   pHeader->pInputPortPrivate = pInputPortPrivate;
+   pHeader->pOutputPortPrivate = pOutputPortPrivate;
+
+   *rlen = 0;
+
+   vcos_assert(comp->callbacks.EmptyBufferDone);
+   comp->callbacks.EmptyBufferDone(pComp, comp->callback_state, pHeader);
+}
+
+// Called on host side via RPC in response to a fill-buffer completing
+// on the VideoCore side. ->pBuffer is a real pointer.
+void vcil_out_fill_buffer_done(ILCS_COMMON_T *st, void *call, int clen, void *resp, int *rlen)
+{
+   OMX_COMPONENTTYPE *pComp;
+   VC_PRIVATE_COMPONENT_T *comp;
+   OMX_BUFFERHEADERTYPE *pHeader;
+
+   pHeader = ilcs_receive_buffer(st->ilcs, call, clen, &pComp);
+   *rlen = 0;
+
+   if(pHeader)
+   {
+      comp = (VC_PRIVATE_COMPONENT_T *) pComp->pComponentPrivate;
+
+      vc_assert(comp->callbacks.FillBufferDone);
+      comp->callbacks.FillBufferDone(pComp, comp->callback_state, pHeader);
+   }
+}
diff --git a/makefiles/cmake/arm-linux.cmake b/makefiles/cmake/arm-linux.cmake
new file mode 100755 (executable)
index 0000000..957846a
--- /dev/null
@@ -0,0 +1,130 @@
+# setup environment for cross compile to arm-linux
+
+if (DEFINED CMAKE_TOOLCHAIN_FILE)
+else()
+   message(WARNING
+       "  *********************************************************\n"
+       "  *   CMAKE_TOOLCHAIN_FILE not defined                    *\n"
+       "  *   This is correct for compiling on the Raspberry Pi   *\n"
+       "  *                                                       *\n"
+       "  *   If you are cross-compiling on some other machine    *\n"
+       "  *   then DELETE the build directory and re-run with:    *\n"
+       "  *   -DCMAKE_TOOLCHAIN_FILE=toolchain_file.cmake         *\n"
+       "  *                                                       *\n"
+       "  *   Toolchain files are in makefiles/cmake/toolchains.  *\n"
+       "  *********************************************************"
+       )
+endif()
+
+# pull in headers for android
+if(ANDROID)
+    #
+    # work out where android headers and library are
+    #
+
+    set(ANDROID_NDK_ROOT $ENV{ANDROID_NDK_ROOT} CACHE INTERNAL "" FORCE)
+    set(ANDROID_LIBS $ENV{ANDROID_LIBS} CACHE INTERNAL "" FORCE)
+    set(ANDROID_BIONIC $ENV{ANDROID_BIONIC} CACHE INTERNAL "" FORCE)
+    set(ANDROID_LDSCRIPTS $ENV{ANDROID_LDSCRIPTS} CACHE INTERNAL "" FORCE)
+      
+    if("${ANDROID_NDK_ROOT}" STREQUAL "")
+        find_program(ANDROID_COMPILER arm-eabi-gcc)
+        get_filename_component(ANDROID_BIN ${ANDROID_COMPILER} PATH CACHE)
+        find_path(_ANDROID_ROOT Makefile PATHS ${ANDROID_BIN}
+                  PATH_SUFFIXES ../../../../..
+                  NO_DEFAULT_PATH)
+                if("${_ANDROID_ROOT}" STREQUAL "_ANDROID_ROOT-NOTFOUND")
+                    set(_ANDROID_ROOT "" CACHE INTERNAL "" FORCE)
+                endif()
+                if("${_ANDROID_ROOT}" STREQUAL "")
+            message(FATAL_ERROR "Cannot find android root directory")
+        endif()
+        get_filename_component(ANDROID_ROOT ${_ANDROID_ROOT} ABSOLUTE CACHE)
+        #
+        # top level of cross-compiler target include and lib directory structure
+        #
+        set(ANDROID_NDK_ROOT
+            "${ANDROID_ROOT}/prebuilt/ndk" CACHE INTERNAL "" FORCE)
+        set(ANDROID_BIONIC
+            "${ANDROID_ROOT}/bionic" CACHE INTERNAL "" FORCE)
+        set(ANDROID_LDSCRIPTS
+            "${ANDROID_ROOT}/build/core" CACHE INTERNAL "" FORCE)
+        set(ANDROID_LIBS
+            "${ANDROID_ROOT}/out/target/product/${ANDROID_PRODUCT}/obj/lib"
+            CACHE INTERNAL "" FORCE)
+    endif()
+
+    if("${ANDROID_NDK_ROOT}" STREQUAL "")
+        message(FATAL_ERROR "Cannot find Android NDK root directory")
+    endif()
+    if("${ANDROID_BIONIC}" STREQUAL "")
+        message(FATAL_ERROR "Cannot find Android BIONIC directory")
+    endif()
+    if("${ANDROID_LDSCRIPTS}" STREQUAL "")
+        message(FATAL_ERROR "Cannot find Android LD scripts directory")
+    endif()
+    
+    set(CMAKE_SYSTEM_PREFIX_PATH "${ANDROID_NDK_ROOT}/android-ndk-r${ANDROID_NDK_RELEASE}/platforms/android-${ANDROID_NDK_PLATFORM}/arch-${CMAKE_SYSTEM_PROCESSOR}/usr")
+    
+    if("${ANDROID_LIBS}" STREQUAL "")
+        set(ANDROID_LIBS "${CMAKE_SYSTEM_PREFIX_PATH}/lib"
+            CACHE INTERNAL "" FORCE)
+        # message(FATAL_ERROR "Cannot find android libraries")
+    endif()
+
+    #
+    # add include directories for pthreads
+    #
+    include_directories("${CMAKE_SYSTEM_PREFIX_PATH}/include" BEFORE SYSTEM)
+    include_directories("${ANDROID_BIONIC}/libc/include" BEFORE SYSTEM)
+    include_directories("${ANDROID_BIONIC}/libc/include/arch-arm/include" BEFORE SYSTEM)
+    include_directories("${ANDROID_BIONIC}/libc/kernel/arch-arm" BEFORE SYSTEM)
+    include_directories("${ANDROID_BIONIC}/libc/kernel/common" BEFORE SYSTEM)
+    include_directories("${ANDROID_BIONIC}/libm/include" BEFORE SYSTEM)
+    include_directories("${ANDROID_BIONIC}/libm/include/arch/arm" BEFORE SYSTEM)
+    include_directories("${ANDROID_BIONIC}/libstdc++/include" BEFORE SYSTEM)
+    
+
+    #
+    # Pull in Android link options manually
+    #
+    set(ANDROID_CRTBEGIN "${ANDROID_LIBS}/crtbegin_dynamic.o")
+    set(ANDROID_CRTEND "${ANDROID_LIBS}/crtend_android.o")
+    set(CMAKE_SHARED_LINKER_FLAGS "-nostdlib ${ANDROID_CRTBEGIN} -Wl,-Bdynamic -Wl,-T${ANDROID_LDSCRIPTS}/armelf.x")
+
+    link_directories(${ANDROID_LIBS})
+    set(CMAKE_EXE_LINKER_FLAGS "-nostdlib ${ANDROID_CRTBEGIN} -nostdlib -Wl,-z,noexecstack") 
+    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-dynamic-linker,/system/bin/linker -Wl,-rpath,${CMAKE_INSTALL_PREFIX}/lib")
+    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-T${ANDROID_LDSCRIPTS}/armelf.x -Wl,--gc-sections")
+    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-z,nocopyreloc -Wl,-z,noexecstack -Wl,--fix-cortex-a8 -Wl,--no-undefined")
+
+    set(CMAKE_C_STANDARD_LIBRARIES "-llog -lc -lgcc ${ANDROID_CRTEND}" CACHE INTERNAL "" FORCE)
+    
+    set(SHARED "")
+else()
+    set(SHARED "SHARED")
+endif()
+
+
+# All linux systems have sbrk()
+add_definitions(-D_HAVE_SBRK)
+
+# pull in declarations of lseek64 and friends
+add_definitions(-D_LARGEFILE64_SOURCE)
+       
+# test for glibc malloc debugging extensions
+try_compile(HAVE_MTRACE
+            ${CMAKE_BINARY_DIR}
+            ${PROJECT_SOURCE_DIR}/makefiles/cmake/srcs/test-mtrace.c
+            OUTPUT_VARIABLE foo)
+
+# test for existence of execinfo.h header
+include(CheckIncludeFile)
+check_include_file(execinfo.h HAVE_EXECINFO_H)
+
+add_definitions(-DHAVE_CMAKE_CONFIG)
+configure_file (
+    "makefiles/cmake/cmake_config.h.in"
+    "${PROJECT_BINARY_DIR}/cmake_config.h"
+    )
diff --git a/makefiles/cmake/cmake_config.h.in b/makefiles/cmake/cmake_config.h.in
new file mode 100755 (executable)
index 0000000..080b8e8
--- /dev/null
@@ -0,0 +1,15 @@
+#ifndef CMAKE_CONFIG_H
+#define CMAKE_CONFIG_H
+
+/*
+ * Autogenerated by cmake from makefiles/cmake/cmake_config.h.in
+ */
+
+/** Do we have support for GLIBC mtrace() ? */
+#cmakedefine                    HAVE_MTRACE
+
+/** Do we have the execinfo.h include file ? */
+#cmakedefine                    HAVE_EXECINFO_H
+
+#endif
+
diff --git a/makefiles/cmake/global_settings.cmake b/makefiles/cmake/global_settings.cmake
new file mode 100755 (executable)
index 0000000..8de2e7e
--- /dev/null
@@ -0,0 +1,83 @@
+# Run this file only once per cmake run. This is so that
+# users projects can override those global settings before
+# parsing subdirectories (which can also include this file
+# directly so that they can be built as standalone projects).
+if (DEFINED GLOBAL_SETTINGS_SET)
+   return ()
+endif ()
+set (GLOBAL_SETTINGS_SET "TRUE")
+
+if (NOT DEFINED VIDEOCORE_ROOT)
+   message (FATAL_ERROR
+      " **************************************************\n"
+      " * Variable VIDEOCORE_ROOT is not defined. please *\n"
+      " * define it before including this cmake file.    *\n"
+      " * this variable has to be set to the *absolute*  *\n"
+      " * path to the top of the videocore source tree   *\n"
+      " **************************************************\n"
+   )
+endif ()
+
+if (NOT IS_ABSOLUTE "${VIDEOCORE_ROOT}")
+   message (FATAL_ERROR
+      " **************************************************\n"
+      " * Variable VIDEOCORE_ROOT doesn't contain        *\n"
+      " * absolute path                                  *\n"
+      " **************************************************\n"
+   )
+endif ()
+
+set (VIDEOCORE_RTOSES threadx none win32 pthreads nucleus)
+foreach (possible_rtos ${VIDEOCORE_RTOSES})
+   set (VIDEOCORE_RTOSES_STR "${possible_rtos}, ${VIDEOCORE_RTOSES_STR}")
+   set (VIDEOCORE_RTOSES_RE "${VIDEOCORE_RTOSES_RE}|(${possible_rtos})")
+endforeach ()
+
+if (NOT DEFINED RTOS)
+   # Guess which OS we are on to maintain backwards compatibility
+   if (WIN32)
+      set (RTOS win32)
+   else ()
+      set (RTOS pthreads)
+   endif ()
+endif ()
+
+if (NOT ${RTOS} MATCHES ${VIDEOCORE_RTOSES_RE})
+   message (FATAL_ERROR
+      " **************************************************\n"
+      " * RTOS incorrectly defined. Please define it     *\n"
+      " * correctly and rerun cmake (possibly after      *\n"
+      " * removing files from this run).                 *\n"
+      " * Possible options are: ${VIDEOCORE_RTOSES_STR}\n"
+      " **************************************************\n"
+   )
+endif ()
+
+if (NOT DEFINED VIDEOCORE_BUILD_DIR)
+   set (VIDEOCORE_BUILD_DIR "${VIDEOCORE_ROOT}/build")
+endif ()
+set (VIDEOCORE_ARCHIVE_BUILD_DIR "${VIDEOCORE_BUILD_DIR}/lib")
+set (VIDEOCORE_HEADERS_BUILD_DIR "${VIDEOCORE_BUILD_DIR}/inc")
+set (VIDEOCORE_RUNTIME_BUILD_DIR "${VIDEOCORE_BUILD_DIR}/bin")
+if (VIDEOCORE_ALL_RUNTIMES_AND_LIBRARIES_IN_SAME_DIRECTORY)
+   # this is useful on windows to avoid problems with dlls not being found at
+   # runtime...
+   set (VIDEOCORE_LIBRARY_BUILD_DIR "${VIDEOCORE_BUILD_DIR}/bin")
+   set (VIDEOCORE_TESTAPP_BUILD_DIR "${VIDEOCORE_BUILD_DIR}/bin")
+else ()
+   set (VIDEOCORE_LIBRARY_BUILD_DIR "${VIDEOCORE_BUILD_DIR}/lib")
+   set (VIDEOCORE_TESTAPP_BUILD_DIR "${VIDEOCORE_BUILD_DIR}/test")
+endif ()
+
+set (VCOS_HEADERS_BUILD_DIR "${VIDEOCORE_HEADERS_BUILD_DIR}/interface/vcos")
+
+set (CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${VIDEOCORE_ARCHIVE_BUILD_DIR}")
+set (CMAKE_LIBRARY_OUTPUT_DIRECTORY "${VIDEOCORE_LIBRARY_BUILD_DIR}")
+set (CMAKE_RUNTIME_OUTPUT_DIRECTORY "${VIDEOCORE_RUNTIME_BUILD_DIR}")
+
+include_directories ("${VIDEOCORE_HEADERS_BUILD_DIR}")
+
+function (add_testapp_subdirectory name)
+   set (CMAKE_RUNTIME_OUTPUT_DIRECTORY "${VIDEOCORE_TESTAPP_BUILD_DIR}")
+   add_subdirectory (${name})
+endfunction ()
diff --git a/makefiles/cmake/srcs/test-mtrace.c b/makefiles/cmake/srcs/test-mtrace.c
new file mode 100755 (executable)
index 0000000..d4cd615
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <mcheck.h>
+
+int main(int argc, const char **argv)
+{
+   mtrace();
+   muntrace();
+}
+
diff --git a/makefiles/cmake/toolchains/arm-linux-gnueabihf.cmake b/makefiles/cmake/toolchains/arm-linux-gnueabihf.cmake
new file mode 100755 (executable)
index 0000000..aa1457c
--- /dev/null
@@ -0,0 +1,22 @@
+
+#
+# CMake defines to cross-compile to ARM/Linux on BCM2708 using glibc.
+#
+
+SET(CMAKE_SYSTEM_NAME Linux)
+SET(CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
+SET(CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
+SET(CMAKE_ASM_COMPILER arm-linux-gnueabihf-gcc)
+SET(CMAKE_SYSTEM_PROCESSOR arm)
+
+#ADD_DEFINITIONS("-march=armv6")
+add_definitions("-mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard -marm")
+
+# rdynamic means the backtrace should work
+IF (CMAKE_BUILD_TYPE MATCHES "Debug")
+   add_definitions(-rdynamic)
+ENDIF()
+
+# avoids annoying and pointless warnings from gcc
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -U_FORTIFY_SOURCE")
+SET(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -c")
diff --git a/makefiles/cmake/toolchains/bcm2708-glibc-linux.cmake b/makefiles/cmake/toolchains/bcm2708-glibc-linux.cmake
new file mode 100755 (executable)
index 0000000..8c3314d
--- /dev/null
@@ -0,0 +1,21 @@
+
+#
+# CMake defines to cross-compile to ARM/Linux on BCM2708 using glibc.
+#
+
+SET(CMAKE_SYSTEM_NAME Linux)
+SET(CMAKE_C_COMPILER bcm2708-gcc)
+SET(CMAKE_CXX_COMPILER bcm2708-g++)
+SET(CMAKE_ASM_COMPILER bcm2708-gcc)
+SET(CMAKE_SYSTEM_PROCESSOR arm)
+
+ADD_DEFINITIONS("-march=armv6")
+
+# rdynamic means the backtrace should work
+IF (CMAKE_BUILD_TYPE MATCHES "Debug")
+   add_definitions(-rdynamic)
+ENDIF()
+
+# avoids annoying and pointless warnings from gcc
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -U_FORTIFY_SOURCE")
+SET(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -c")
diff --git a/makefiles/cmake/vmcs.cmake b/makefiles/cmake/vmcs.cmake
new file mode 100755 (executable)
index 0000000..718cd3b
--- /dev/null
@@ -0,0 +1,80 @@
+
+
+SET(CPACK_PACKAGE_VERSION_MAJOR "1")
+SET(CPACK_PACKAGE_VERSION_MINOR "0")
+SET(CPACK_PACKAGE_VERSION_PATCH "pre-1")
+
+INCLUDE(CPack)
+
+# Where shall we install?
+if (ANDROID)
+  SET(VMCS_INSTALL_PREFIX "/vendor/brcm/islands" CACHE PATH "Prefix prepended to install directories" FORCE)
+elseif(NOT DEFINED VMCS_INSTALL_PREFIX)
+  SET(VMCS_INSTALL_PREFIX "/opt/vc" CACHE PATH "Prefix prepended to install directories" FORCE)
+endif()
+
+SET(CMAKE_INSTALL_PREFIX "${VMCS_INSTALL_PREFIX}" CACHE INTERNAL "Prefix
+    prepended to install directories" FORCE)
+if(NOT DEFINED VMCS_PLUGIN_DIR)
+  SET(VMCS_PLUGIN_DIR ${CMAKE_INSTALL_PREFIX}/${CMAKE_SHARED_LIBRARY_PREFIX}/plugins)
+endif()
+
+# What kind of system are we?
+if (${UNIX})
+   set (VMCS_TARGET linux)
+elseif (${SYMBIAN})
+   set (VMCS_TARGET symbian)
+elseif (${WIN32})
+   set (VMCS_TARGET win32)
+else()
+   message(FATAL_ERROR,"Unknown system type")
+endif()
+set (ARM64 OFF CACHE BOOL "Whether target is ARM64")
+
+# construct the vmcs config header file
+add_definitions(-DHAVE_VMCS_CONFIG)
+configure_file (
+    "${vmcs_root}/host_applications/vmcs/vmcs_config.h.in"
+    "${PROJECT_BINARY_DIR}/vmcs_config.h"
+    )
+
+# install an ld.so.conf file to pick up our shared libraries
+#configure_file (${vmcs_root}/makefiles/cmake/srcs/vmcs.conf.in
+#                ${PROJECT_BINARY_DIR}/vmcs.conf)
+#if(NOT DEFINED ANDROID)
+#   install(FILES ${PROJECT_BINARY_DIR}/vmcs.conf DESTINATION /etc/ld.so.conf.d)
+#endif()
+
+# also put it in /opt/vc for access by install script
+#install(FILES  ${PROJECT_BINARY_DIR}/vmcs.conf
+#        DESTINATION ${VMCS_INSTALL_PREFIX}/share/install)
+# provide headers the libraries need in /opt/vc too
+#install(DIRECTORY interface/khronos/include
+#        DESTINATION ${VMCS_INSTALL_PREFIX})
+#install(DIRECTORY interface/vmcs_host/khronos/IL
+#        DESTINATION ${VMCS_INSTALL_PREFIX}/include)
+# provide an install script
+#install(PROGRAMS ${vmcs_root}/makefiles/cmake/scripts/install_vmcs
+#        DESTINATION ${VMCS_INSTALL_PREFIX}/sbin
+#        PERMISSIONS OWNER_WRITE WORLD_READ)
+
+# provide hello_pi demos
+install(DIRECTORY host_applications/linux/apps/hello_pi
+        DESTINATION ${VMCS_INSTALL_PREFIX}/src)
+
+# provide header files
+#install(DIRECTORY host_applications/linux/libs/bcm_host/include
+#        DESTINATION ${VMCS_INSTALL_PREFIX}/)
+
+install(DIRECTORY ${vmcs_root}/interface/vcos      DESTINATION ${VMCS_INSTALL_PREFIX}/include/interface FILES_MATCHING PATTERN "*.h")
+install(DIRECTORY ${vmcs_root}/interface/vchiq_arm DESTINATION ${VMCS_INSTALL_PREFIX}/include/interface FILES_MATCHING PATTERN "*.h")
+install(DIRECTORY ${vmcs_root}/interface/vchi      DESTINATION ${VMCS_INSTALL_PREFIX}/include/interface FILES_MATCHING PATTERN "*.h")
+install(DIRECTORY ${vmcs_root}/interface/vctypes   DESTINATION ${VMCS_INSTALL_PREFIX}/include/interface FILES_MATCHING PATTERN "*.h")
+install(DIRECTORY ${vmcs_root}/vcinclude           DESTINATION ${VMCS_INSTALL_PREFIX}/include           FILES_MATCHING PATTERN "*.h")
+install(DIRECTORY ${vmcs_root}/interface/vmcs_host DESTINATION ${VMCS_INSTALL_PREFIX}/include/interface FILES_MATCHING PATTERN "*.h" PATTERN "${vmcs_root}/interface/vmcs_host/khronos" EXCLUDE)
+
+install(DIRECTORY ${vmcs_root}/interface/khronos/include       DESTINATION ${VMCS_INSTALL_PREFIX}     FILES_MATCHING PATTERN "*.h")
+install(DIRECTORY ${vmcs_root}/interface/vmcs_host/khronos/IL  DESTINATION ${VMCS_INSTALL_PREFIX}/include     FILES_MATCHING PATTERN "*.h")
+
+install(DIRECTORY ${vmcs_root}/host_applications/linux/libs/bcm_host/include     DESTINATION ${VMCS_INSTALL_PREFIX}       FILES_MATCHING PATTERN "*.h")
+
diff --git a/middleware/dlloader/dlfcn.h b/middleware/dlloader/dlfcn.h
new file mode 100755 (executable)
index 0000000..6ad2d6d
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef _DLLOADER_H
+#define _DLLOADER_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+   /*
+    * Declarations used for dynamic linking support routines.
+    */
+   extern void dlloader_init(void);
+   extern void *dlopen (const char *dllName, int mode);
+   extern void *dlopen_at(const char *dllName, void *kept, int keptspace, void *unkept, int unkeptspace);
+   extern void *dlopen_pmm(const char *dllName, void *(*pmm_alloc)(void *, unsigned int, unsigned int, const char *, unsigned int), void (*pmm_free)(void *, void *), void *pmm_priv);
+   extern void (*dlsym(void *, const char *))();
+   extern int dlclose(void *);
+   extern const char *dlerror(void);
+   extern void dldone(void *handle);
+   extern int  dlcheck(const char *pathName);
+   extern void *dlshared_vll_load(const char *vll_name, 
+                        const char **symbols, 
+                        void *(*pmm_alloc)(void *, unsigned int, unsigned int, const char *, unsigned int), 
+                        void (*pmm_free)(void *, void *), 
+                        void *pmm_priv,
+                        int *vll_init_required);
+   extern void dlshared_vll_init_done(void *vll);
+   extern void (*dlshared_get_vll_symbol(void *vll, const char *symbol))();
+   extern int dlshared_vll_closing(void *vll);
+   extern int dlshared_vll_unload(void *vll);
+
+
+   /*
+    * Valid values for mode argument to dlopen.
+    */
+#define  RTLD_LAZY      0x00001     /* deferred function binding */
+#define  RTLD_NOW       0x00002     /* immediate function binding */
+
+#define  RTLD_GLOBAL    0x00100     /* export symbols to others */
+#define  RTLD_LOCAL     0x00000     /* symbols are only available */
+   /* to group members */
+
+#ifdef   __cplusplus
+}
+#endif
+
+#ifdef FOR_VMCS
+// Set the path where vlls are to be retrieved from. Return non-zero for success.
+int dl_set_vll_dir(char const *dir_name);
+#endif
+
+enum dl_pmm_flags {
+   DL_PMM_NORMAL = 0,
+   DL_PMM_TEMPORARY = 1,
+   DL_PMM_DEBUGINFO = 2,
+};
+
+enum dlpoolflags {
+   DL_POOLFLAGS_EXECUTABLE = 1,
+   DL_POOLFLAGS_WRITABLE = 2,
+   DL_POOLFLAGS_TEMPORARY = 4,
+   DL_POOLFLAGS_DEBUGINFO = 8,
+};
+
+struct dlsegmentsizedata {
+   int size;
+   int align;
+   enum dlpoolflags flags;
+};
+
+extern int dlgetsegmentsizes(const char *vll, int *nrows, struct dlsegmentsizedata *segdata);
+
+#endif   /* _DLFCN_H */
diff --git a/middleware/imageconv/imageconv.h b/middleware/imageconv/imageconv.h
new file mode 100755 (executable)
index 0000000..f7a9a0e
--- /dev/null
@@ -0,0 +1,448 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef IMAGECONV_H
+#define IMAGECONV_H
+
+#include "interface/vcos/vcos.h"
+#include "interface/vctypes/vc_image_types.h"
+#include "vcfw/rtos/common/rtos_common_mem.h"
+#include "interface/vmcs_host/vc_imageconv_defs.h"
+
+typedef struct
+{
+   void *data;
+   /** Width of the converted image in pixels */
+   uint32_t width;
+   /** Height of the converted image in pixels */
+   uint32_t height;
+   /** Cropped width of the converted image in pixels */
+   uint32_t crop_width;
+   /** Cropped height of the converted image in pixels */
+   uint32_t crop_height;
+   /** The pitch of the converted image */
+   uint32_t pitch;
+   /** The size required for the converted image */
+   uint32_t size;
+   /** The type of the converted image */
+   VC_IMAGE_TYPE_T type;
+   /** Whether the destination has been sub-sampled */
+   uint32_t subsampled;
+   /** Non-zero = image is V/U interleaved */
+   uint32_t is_vu;
+   /** Vertical pitch of the buffer */
+   uint32_t vpitch;
+} IMAGECONV_IMAGE_DATA_T;
+
+
+typedef struct IMAGECONV_DRIVER_IMAGE_T IMAGECONV_DRIVER_IMAGE_T;
+
+/** Converter class */
+typedef struct IMAGE_CONVERT_CLASS_T IMAGE_CONVERT_CLASS_T;
+
+/**
+ * Create an image.
+ * The initial reference count is 1.
+ * @param data     Image data. Not all fields are used by all convert classes. 'data' must be
+ *                 filled in for all classes.
+ * @param handle   On success, this points to the newly created image handle.
+ * @return 0 on success; -1 on failure.
+ */
+typedef int (*IMAGECONV_CREATE)(const IMAGE_CONVERT_CLASS_T *converter,
+                                const IMAGECONV_IMAGE_DATA_T *data, MEM_HANDLE_T *handle);
+
+typedef int (*IMAGECONV_GET_SIZE)(const IMAGE_CONVERT_CLASS_T *converter,
+                                  const IMAGECONV_DRIVER_IMAGE_T *image, uint32_t *width,
+                                  uint32_t *height, uint32_t *pitch, VC_IMAGE_TYPE_T *type);
+
+/** Get an image which can be used in one of the other conversion function,
+ * given a mem handle.
+ */
+typedef int (*IMAGECONV_GET_IMAGE)(const IMAGE_CONVERT_CLASS_T *converter, MEM_HANDLE_T src,
+                                   IMAGECONV_DRIVER_IMAGE_T **image);
+
+/** Gets the dimensions and allocation size of the destination image
+ * required by IMAGECONV_CONVERT.
+ *
+ * Must NOT be NULL.
+ *
+ * @return 0 if successful
+ */
+typedef int (*IMAGECONV_GET_CONVERTED_SIZE)(
+      const IMAGE_CONVERT_CLASS_T *converter, MEM_HANDLE_T src,
+      VC_IMAGE_TYPE_T type, IMAGECONV_IMAGE_DATA_T *dest_info);
+
+/*
+ * Tell the converter that we've finished with the image for now (so it can
+ * unlock it etc.).
+ *
+ * May be NULL if the converter does not support or require this.
+ */
+typedef void (*IMAGECONV_UNGET_IMAGE)(const IMAGE_CONVERT_CLASS_T *converter,
+                                      MEM_HANDLE_T src,
+                                      IMAGECONV_DRIVER_IMAGE_T *image);
+
+/*
+ * Add a reference count to an image, preventing it from being returned to its
+ * image pool.
+ *
+ * May be NULL if the converter does not support or require this.
+ */
+typedef int (*IMAGECONV_ACQUIRE_IMAGE)(const IMAGE_CONVERT_CLASS_T *converter,
+                                       IMAGECONV_DRIVER_IMAGE_T *image);
+
+/*
+ * Remove a reference count to an image, releasing it back to its
+ * image pool.
+ *
+ * May be NULL if the converter does not support or require this.
+ */
+typedef void (*IMAGECONV_RELEASE_IMAGE)(const IMAGE_CONVERT_CLASS_T *converter,
+                                        IMAGECONV_DRIVER_IMAGE_T *image);
+
+/* mem-lock an image and return the data pointer(s).
+ */
+typedef int (*IMAGECONV_LOCK)(const IMAGE_CONVERT_CLASS_T *converter,
+                              IMAGECONV_DRIVER_IMAGE_T *image, IMAGECONV_IMAGE_DATA_T *data);
+
+/* mem-unlock an image.
+ */
+typedef void (*IMAGECONV_UNLOCK)(const IMAGE_CONVERT_CLASS_T *converter,
+                                 IMAGECONV_DRIVER_IMAGE_T *image);
+
+/* Convert src to dest */
+typedef int (*IMAGECONV_CONVERT)(const IMAGE_CONVERT_CLASS_T *converter,
+      MEM_HANDLE_T dest, uint32_t dest_offset,
+      MEM_HANDLE_T src, uint32_t src_offset, VC_IMAGE_TYPE_T dest_type);
+
+/** Set the description of the source image data. Optional function to aid memory debugging.
+ * This envisages the source image data is in the relocatable heap, so will call mem_set_desc_vprintf() to
+ * set the description.
+ *
+ * May be NULL if the converter does not support or require this.
+ */
+typedef void (*IMAGECONV_SET_SRC_DESC)(const IMAGE_CONVERT_CLASS_T *converter, MEM_HANDLE_T src,
+                                       const char *fmt, va_list ap);
+
+/** Get the description of the source image data. Optional function to aid memory debugging.
+ * This envisages the source image data is in the relocatable heap, so will call mem_get_desc() to
+ * get the description.
+ *
+ * May be NULL if the converter does not support or require this.
+ */
+typedef const char *(*IMAGECONV_GET_SRC_DESC)(const IMAGE_CONVERT_CLASS_T *converter, MEM_HANDLE_T src);
+
+/* Callback made in response to IMAGECONV_NOTIFY
+ *
+ * A status of 0 indicates that a reference to the image can now be acquired
+ * via imageconv_acquire(_image).
+ *
+ * Any other value indicates that the request timed out.
+ */
+typedef void (*IMAGECONV_NOTIFY_CALLBACK)(const IMAGE_CONVERT_CLASS_T *converter,
+                                          IMAGECONV_DRIVER_IMAGE_T *image,
+                                          void *context,
+                                          int status);
+
+/* Request notification when a reference to the image can be acquired.
+ *
+ * May be NULL if the converter does not support or require this.
+ */
+typedef int (*IMAGECONV_NOTIFY)(const IMAGE_CONVERT_CLASS_T *converter,
+                                IMAGECONV_DRIVER_IMAGE_T *image,
+                                uint32_t timeout,
+                                IMAGECONV_NOTIFY_CALLBACK callback,
+                                void *context);
+
+/* Cancel an outstanding IMAGECONV_NOTIFY request.
+*/
+typedef void (*IMAGECONV_CANCEL_NOTIFY)(const IMAGE_CONVERT_CLASS_T *converter,
+                                        IMAGECONV_DRIVER_IMAGE_T *image);
+
+typedef enum IMAGECONV_ID_T {
+    IMAGECONV_ID_MMAL,        /**< MMAL opaque buffer to Khronos */
+    IMAGECONV_ID_KHRONOS,     /**< YV12 to Khronos */
+    IMAGECONV_ID_EGL_VC,      /**< EGL image to VC_IMAGE_T */
+    IMAGECONV_ID_GENERIC,
+    IMAGECONV_ID_KHRONOS_VC,  /**< Khronos to VC_IMAGE_T */
+    IMAGECONV_ID_MAX
+} IMAGECONV_ID_T;
+
+/* Do not call these directly! */
+struct IMAGE_CONVERT_CLASS_T {
+    IMAGECONV_CREATE                create;
+    IMAGECONV_GET_SIZE              get_size;
+    IMAGECONV_GET_IMAGE             get;
+    IMAGECONV_GET_CONVERTED_SIZE    get_converted_size;
+    IMAGECONV_UNGET_IMAGE           unget;
+    IMAGECONV_ACQUIRE_IMAGE         acquire;
+    IMAGECONV_RELEASE_IMAGE         release;
+    IMAGECONV_LOCK                  lock;
+    IMAGECONV_UNLOCK                unlock;
+    IMAGECONV_CONVERT               convert;
+    IMAGECONV_SET_SRC_DESC          set_src_desc;
+    IMAGECONV_GET_SRC_DESC          get_src_desc;
+    IMAGECONV_NOTIFY                notify;
+    IMAGECONV_CANCEL_NOTIFY         cancel_notify;
+    IMAGECONV_ID_T                  id;
+};
+
+typedef enum IMAGECONV_ERR_T {
+    IMAGECONV_ERR_NONE = 0,
+    IMAGECONV_ERR_GENERAL = -1,
+    IMAGECONV_ERR_NOT_SUPPORTED = -2,
+    IMAGECONV_ERR_NOT_READY = -3,
+    IMAGECONV_ERR_ALREADY = -4,
+} IMAGECONV_ERR_T;
+
+/** Initialise the library
+ */
+void imageconv_init(void);
+
+/** Retrieve the conversion function routines for a given type of
+ * image.
+ *
+ * @param converter_id           type of image to support
+ * @param converter              function pointers for this image type
+ *
+ * @return IMAGECONV_ERR_NONE on success
+ * @return IMAGECONV_ERR_NOT_SUPPORTED if image type unknown.
+ */
+int imageconv_get_convert_class(
+        IMAGECONV_ID_T converter_id,
+        const IMAGE_CONVERT_CLASS_T **converter);
+
+/** Set the image conversion functions to use for a given type of
+ * image.
+ *
+ * @param converter_class        type of image to support
+ * @param converter              function pointers for this image type
+ */
+void imageconv_set_convert_class(IMAGECONV_ID_T converter_id,
+      const IMAGE_CONVERT_CLASS_T *converter);
+
+/**
+ * Create an image.
+ *
+ * The initial reference count is 1.
+ *
+ * @param converter  Convert class.
+ * @param data       Image data. Not all fields are used by all convert classes. 'data' must be
+ *                   filled in for all classes.
+ * @param handle     On success, this points to the newly created image handle. The actual type
+ *                   depends on the convert class, but is probably a MEM_HANDLE_T in most cases.
+ *
+ * @return IMAGECONV_ERR_NOT_SUPPORTED if not implemented by the converter class
+ * @return IMAGECONV_ERR_NONE on success
+ * @return IMAGECONV_ERR_GENERAL on failure
+ */
+int imageconv_create(const IMAGE_CONVERT_CLASS_T *converter, const IMAGECONV_IMAGE_DATA_T *data,
+                     MEM_HANDLE_T *handle);
+
+/** Get the size of an image.
+ *
+ * @param converter    converter functions for this image
+ * @param self   MEM_HANDLE to image structure.
+ * @param width  width of image
+ * @param height height of image
+ * @param pitch  pitch of image in bytes
+ * @param type   type of image
+ *
+ * @return IMAGECONV_ERR_NOT_SUPPORTED if not implemented by the converter class
+ * @return IMAGECONV_ERR_NONE on success
+ * @return IMAGECONV_ERR_GENERAL if image handle is invalid.
+ */
+int imageconv_get_size(const IMAGE_CONVERT_CLASS_T *converter, MEM_HANDLE_T self,
+     uint32_t *width, uint32_t *height, uint32_t *pitch, VC_IMAGE_TYPE_T *type);
+
+/** Converts the image writing the result to the memory specified at 
+ * dst, dst_offset.
+ *
+ * @return IMAGECONV_ERR_NOT_SUPPORTED if not implemented by the converter class
+ * @return IMAGECONV_ERR_NONE on success
+ * @return IMAGECONV_ERR_GENERAL on failure
+ */
+int imageconv_convert(const IMAGE_CONVERT_CLASS_T *converter,
+                      MEM_HANDLE_T dest, uint32_t dest_offset,
+                      MEM_HANDLE_T src, uint32_t src_offset,
+                      VC_IMAGE_TYPE_T dest_type);
+
+/** Convert a MEM_HANDLE_T handle to an actual image pointer (typically by
+ * calling mem_lock() but possibly involving other operations). The image
+ * must be unlocked later with imageconv_unget().
+ *
+ * @param converter    converter functions for this image
+ * @param src          MEM_HANDLE_T to image structure
+ * @param image        Return image pointer.
+ *
+ * @return IMAGECONV_ERR_NONE on success
+ * @return IMAGECONV_ERR_GENERAL if image handle is invalid.
+ */
+int imageconv_get(const IMAGE_CONVERT_CLASS_T *converter,
+                  MEM_HANDLE_T src,
+                  IMAGECONV_DRIVER_IMAGE_T **image);
+
+/* Gets the dimensions of the image that will be created if the image
+ * is converted.
+ *
+ * @param converter    converter functions for this image
+ * @param src          MEM_HANDLE_T to image structure
+ * @param type         The desired type of the destination image.
+ * @param dest_info    A pointer to the image data structure which will be
+ *                     updated with the image metadata. The data pointer to
+ *                     the image storage is not modified; all other fields
+ *                     will be filled in.
+ *
+ * @return IMAGECONV_ERR_NOT_SUPPORTED if not implemented by the converter class
+ * @return IMAGECONV_ERR_NONE on success
+ * @return IMAGECONV_ERR_GENERAL if image handle is invalid.
+ */
+int imageconv_get_converted_size(const IMAGE_CONVERT_CLASS_T *converter,
+      MEM_HANDLE_T src, VC_IMAGE_TYPE_T type, IMAGECONV_IMAGE_DATA_T *dest_info); 
+
+/** Release an image that was previously taken with imageconv_get().
+ *
+ * @param converter    converter functions for this image
+ * @param src          MEM_HANDLE_T to image structure
+ * @param image        image obtained from imageconv_get
+ */
+void imageconv_unget(const IMAGE_CONVERT_CLASS_T *converter,
+                     MEM_HANDLE_T src,
+                     IMAGECONV_DRIVER_IMAGE_T *image);
+
+/** Acquire a lock on an image to prevent it being recycled into its
+ * image pool.
+ *
+ * @param converter    converter functions for this image
+ * @param src          MEM_HANDLE_T to image structure
+ *
+ * @return IMAGECONV_ERR_NOT_SUPPORTED if not implemented by the converter class
+ * @return IMAGECONV_ERR_NONE on success
+ * @return IMAGECONV_ERR_GENERAL if image handle is invalid
+ * @return IMAGECONV_ERR_NOT_READY if reference cannot be currently acquired
+ */
+int imageconv_acquire(const IMAGE_CONVERT_CLASS_T *converter,
+                      MEM_HANDLE_T src);
+
+
+/** Acquire a lock on an image to prevent it being recycled into its
+ * image pool.
+ *
+ * @param converter    converter functions for this image
+ * @param image        image pointer from imageconv_get
+ *
+ * @return IMAGECONV_ERR_NOT_SUPPORTED if not implemented by the converter class
+ * @return IMAGECONV_ERR_NONE on success
+ * @return IMAGECONV_ERR_GENERAL if image handle is invalid
+ * @return IMAGECONV_ERR_NOT_READY if reference cannot be currently acquired
+ */
+int imageconv_acquire_image(const IMAGE_CONVERT_CLASS_T *converter,
+                      IMAGECONV_DRIVER_IMAGE_T *image);
+
+/** Release a lock on an image to allow it to be recycled back
+ * to its image pool.
+ *
+ * @param converter    converter functions for this image
+ * @param image        image pointer from imageconv_get
+ *
+ * @return IMAGECONV_ERR_NOT_SUPPORTED if not implemented by the converter class
+ * @return IMAGECONV_ERR_NONE on success
+ * @return IMAGECONV_ERR_GENERAL if image handle is invalid
+ */
+int imageconv_release_image(const IMAGE_CONVERT_CLASS_T *converter,
+                      IMAGECONV_DRIVER_IMAGE_T *image);
+
+/** Set the description of the source image data. Function to aid memory debugging; may not be
+ * supported by every converter class (in which case it becomes a no-op).
+ *
+ * @param converter    converter functions for this image
+ * @param src          MEM_HANDLE_T to source image
+ * @param desc         Memory block description
+ */
+void imageconv_set_src_desc(const IMAGE_CONVERT_CLASS_T *converter, MEM_HANDLE_T src,
+                            const char *desc);
+
+/** Set the description of the source image data. Function to aid memory debugging; may not be
+ * supported by every converter class (in which case it becomes a no-op).
+ *
+ * @param converter    converter functions for this image
+ * @param src          MEM_HANDLE_T to source image
+ * @param fmt,...      Memory block description
+ */
+void imageconv_set_src_desc_printf(const IMAGE_CONVERT_CLASS_T *converter, MEM_HANDLE_T src,
+                                   const char *fmt, ...);
+
+/** Get the description of the source image data. Function to aid memory debugging; may not be
+ * supported by every converter class (in which case it returns NULL).
+ * The returned string will be valid for the lifetime of the src handle, or
+ * until a new description is set.
+ *
+ * @param converter    converter functions for this image
+ * @param src          MEM_HANDLE_T to source image
+ *
+ * @return Memory block description, or NULL if unavailable
+ */
+const char *imageconv_get_src_desc(const IMAGE_CONVERT_CLASS_T *converter, MEM_HANDLE_T src);
+
+/* Request notification when a reference to the image can be acquired.
+ *
+ * If the reference can already be acquired at the time when the request is made,
+ * this is indicated via the return code, and no callback will be made.
+ *
+ * Otherwise the callback is made when the reference can be acquired, or when
+ * the specified time period has elapsed.
+ *
+ * The thread context in which callbacks are executed depends upon the converter
+ * class implementation.  The callback function should therefore do as little
+ * work as possible, deferring to a known thread context for any further
+ * processing.
+ *
+ * @param converter    converter functions for this image
+ * @param image        image pointer
+ * @param timeout      time to wait in milliseconds; 0 means wait indefinitely
+ * @param callback     callback to be invoked when image is valid, or timeout expires
+ *
+ * @return IMAGECONV_ERR_NOT_SUPPORTED if not implemented by the converter class
+ * @return IMAGECONV_ERR_ALREADY if reference can be acquired immediately
+ * @return IMAGECONV_ERR_NONE if reference cannot be acquire immediately; callback will be made
+ */
+int imageconv_notify(const IMAGE_CONVERT_CLASS_T *converter,
+                     IMAGECONV_DRIVER_IMAGE_T *image,
+                     uint32_t timeout,
+                     IMAGECONV_NOTIFY_CALLBACK callback,
+                     void *context);
+
+/* Cancel an outstanding IMAGECONV_NOTIFY request.
+ *
+ * @param converter    converter functions for this image
+ * @param image        return image pointer
+ */
+void imageconv_cancel_notify(const IMAGE_CONVERT_CLASS_T *converter,
+                             IMAGECONV_DRIVER_IMAGE_T *image);
+
+#endif
+
diff --git a/middleware/khronos/common/2708/khrn_interlock_filler_4.h b/middleware/khronos/common/2708/khrn_interlock_filler_4.h
new file mode 100755 (executable)
index 0000000..cd6f18b
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_INTERLOCK_FILLER_4_H
+#define KHRN_INTERLOCK_FILLER_4_H
+
+#include "interface/khronos/common/khrn_int_util.h"
+
+/* users are render states. user = 1 << render state index */
+typedef enum {
+   KHRN_INTERLOCK_USER_NONE    = 0,
+   KHRN_INTERLOCK_USER_INVALID = 1 << 29, /* <= 29 render states, so can use top 3 bits for temp/writing/inv */
+   KHRN_INTERLOCK_USER_TEMP    = 1 << 30, 
+   KHRN_INTERLOCK_USER_WRITING = 1 << 31
+} KHRN_INTERLOCK_USER_T;
+static INLINE KHRN_INTERLOCK_USER_T khrn_interlock_user(uint32_t i) { return (KHRN_INTERLOCK_USER_T)(1 << i); }
+static INLINE uint32_t khrn_interlock_render_state_i(KHRN_INTERLOCK_USER_T user) { return _msb(user); }
+
+typedef struct {
+   /* top bits: who? */
+   uint64_t hw_read_pos;
+   uint64_t worker_read_pos;
+   uint64_t write_pos;
+} KHRN_INTERLOCK_EXTRA_T;
+
+#endif
diff --git a/middleware/khronos/common/2708/khrn_prod_4.h b/middleware/khronos/common/2708/khrn_prod_4.h
new file mode 100755 (executable)
index 0000000..4fa9477
--- /dev/null
@@ -0,0 +1,545 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_PROD_4_H
+#define KHRN_PROD_4_H
+
+#include "middleware/khronos/egl/egl_disp.h"
+#include "middleware/khronos/common/khrn_hw.h"
+#include "interface/khronos/common/khrn_int_util.h"
+#if defined(SIMPENROSE)
+   #include "tools/v3d/simpenrose/simpenrose.h"
+   #ifdef SIMPENROSE_RECORD_OUTPUT
+      #include "tools/v3d/simpenrose/record.h"
+   #endif
+#elif defined(ABSTRACT_PLATFORM)
+   /* nothing included */
+#else
+   #include "vcfw/vclib/vclib.h"
+   #include "hardware_alias.h"
+#include "hardware_v3d.h"
+#endif
+
+#if defined(KHRN_CARBON)
+#include "tools/v3d/carbon/carbon_lib/carbon_functions.h"
+#endif
+
+/******************************************************************************
+constants that come from the hw
+******************************************************************************/
+
+#if defined(SIMPENROSE) || defined(KHRN_CARBON)
+   #define KHRN_HW_SYSTEM_CACHE_LINE_SIZE 4
+#else
+   #define KHRN_HW_SYSTEM_CACHE_LINE_SIZE 32
+#endif
+#define KHRN_HW_TLB_ALIGN 16 /* todo: is this right? */
+#define KHRN_HW_LOG2_BRCM1_WIDTH 6 /* non-ms */
+#define KHRN_HW_LOG2_BRCM1_HEIGHT 6 /* non-ms */
+#define KHRN_HW_BRCM1_WIDTH (1 << KHRN_HW_LOG2_BRCM1_WIDTH)
+#define KHRN_HW_BRCM1_HEIGHT (1 << KHRN_HW_LOG2_BRCM1_HEIGHT)
+#define KHRN_HW_BRCM1_STATE_SIZE 48
+#define KHRN_HW_BIN_MEM_ALIGN 256
+#define KHRN_HW_BIN_MEM_GRANULARITY 4096
+#define KHRN_HW_CL_BLOCK_SIZE_MIN 32
+#define KHRN_HW_CL_BLOCK_SIZE_MAX 256
+#define KHRN_HW_TEX_SIZE_MAX 2048 /* max width/height */
+#define KHRN_HW_TEX_ALIGN 4096
+#define KHRN_HW_VPM_BLOCKS_N (192 / 4)
+#define KHRN_HW_USER_QUEUE_LENGTH 16
+#define KHRN_HW_QPUS_N 12
+
+/******************************************************************************
+misc stuff
+******************************************************************************/
+
+#if defined(SIMPENROSE) || defined(KHRN_CARBON)
+   #define khrn_hw_alias_direct(addr) (addr)
+   #define khrn_hw_alias_normal(addr) (addr)
+   #define khrn_hw_alias_l1_nonallocating(addr) (addr)
+#if defined(SIMPENROSE)
+   #define khrn_hw_addr simpenrose_hw_addr
+   #define khrn_hw_unaddr simpenrose_pc_addr
+#else
+   #define khrn_hw_addr(addr) carbon_hw_addr(addr)
+   #define khrn_hw_unaddr(addr) carbon_hw_unaddr(addr)
+#endif
+   static INLINE void khrn_hw_flush_dcache(void) {}
+   static INLINE void khrn_hw_flush_dcache_range(void *p, uint32_t size) {}
+   static INLINE void khrn_hw_flush_l1cache_range(void *p, uint32_t size) {}
+   static INLINE void khrn_hw_invalidate_dcache_range(void *p, uint32_t size) {}
+   static INLINE void khrn_hw_invalidate_l1cache_range(void *p, uint32_t size) {}
+#elif defined(ABSTRACT_PLATFORM)
+   /* NEXUS has to convert to physical addresses from the cached version and back */
+   #define khrn_hw_alias_direct(addr) (addr)
+   #define khrn_hw_alias_normal(addr) (addr)
+   #define khrn_hw_alias_l1_nonallocating(addr) (addr)
+   #define khrn_hw_alias_l1l2_nonallocating(addr) (addr)
+
+   static INLINE uint32_t khrn_hw_addr(const void *addr)
+   {
+      uint32_t addr_device;
+      addr_device = mem_map_cached_to_physical((void*)addr);
+      return addr_device;
+   }
+
+   static INLINE void *khrn_hw_unaddr(uint32_t addr)
+   {
+      void * addr_cached = mem_map_physical_to_cached(addr);
+      return addr_cached;
+   }
+
+   static INLINE void *khrn_hw_cached_to_uncached(const void *addr)
+   {
+      void * addr_uncached = mem_map_cached_to_uncached((void*)addr);
+      return addr_uncached;
+   }
+
+   static INLINE void *khrn_hw_uncached_to_cached(const void *addr)
+   {
+      void * addr_cached = mem_map_uncached_to_cached((void*)addr);
+      return addr_cached;
+   }
+
+   static INLINE void khrn_hw_full_memory_barrier(void) {}
+
+   static INLINE void khrn_hw_flush_dcache(void) { mem_flush_cache(); }
+   static INLINE void khrn_hw_flush_dcache_range(void *p, uint32_t size) { mem_flush_cache_range(p, size); }
+   static INLINE void khrn_hw_flush_l1cache_range(void *p, uint32_t size) { UNUSED(p); UNUSED(size); }
+   static INLINE void khrn_hw_invalidate_dcache_range(void *p, uint32_t size) { mem_flush_cache_range(p, size); }
+   static INLINE void khrn_hw_invalidate_l1cache_range(void *p, uint32_t size) { UNUSED(p); UNUSED(size); }
+#else
+   #define khrn_hw_alias_direct ALIAS_DIRECT
+   #define khrn_hw_alias_normal ALIAS_NORMAL
+   #define khrn_hw_alias_l1_nonallocating ALIAS_L1_NONALLOCATING
+
+   static INLINE uint32_t khrn_hw_addr(const void *addr)
+   {
+      return (uint32_t)(uintptr_t)addr;
+   }
+
+   static INLINE void *khrn_hw_unaddr(uint32_t addr)
+   {
+      return (void *)(uintptr_t)addr;
+   }
+
+   static INLINE void khrn_hw_flush_dcache(void) { vclib_dcache_flush(); }
+   static INLINE void khrn_hw_flush_dcache_range(void *p, uint32_t size) { vclib_dcache_flush_range(p, size); }
+   static INLINE void khrn_hw_flush_l1cache_range(void *p, uint32_t size) { vclib_l1cache_flush_range(p, size); }
+   static INLINE void khrn_hw_invalidate_dcache_range(void *p, uint32_t size) { vclib_dcache_invalidate_range(p, size); }
+   static INLINE void khrn_hw_invalidate_l1cache_range(void *p, uint32_t size) { vclib_l1cache_invalidate_range(p, size); }
+#endif
+
+/******************************************************************************
+stuff for writing control lists
+******************************************************************************/
+
+typedef uint64_t KHRN_SHADER_T;
+static INLINE uint8_t get_byte(const uint8_t *p)
+{
+   #ifdef BIG_ENDIAN_CPU
+      return ((uint8_t)*(uint8_t*)((uint32_t)&p[0]^0x3));
+   #else
+      return p[0];
+   #endif
+}
+
+static INLINE uint16_t get_short(const uint8_t *p)
+{
+   #ifdef BIG_ENDIAN_CPU
+      return ((uint16_t)*(uint8_t*)((uint32_t)&p[0]^0x3)) |
+             ((uint16_t)*(uint8_t*)(((uint32_t)&p[1]^0x3)) << 8);
+   #else
+      return  (uint16_t)p[0] |
+             ((uint16_t)p[1] << 8);
+   #endif
+}
+
+static INLINE uint32_t get_word(const uint8_t *p)
+{
+   #ifdef BIG_ENDIAN_CPU
+      return ((uint32_t)*(uint8_t*)((uint32_t)&p[0]^0x3)) |
+             ((uint32_t)*(uint8_t*)(((uint32_t)&p[1]^0x3)) << 8) |
+             ((uint32_t)*(uint8_t*)(((uint32_t)&p[2]^0x3)) << 16) |
+             ((uint32_t)*(uint8_t*)(((uint32_t)&p[3]^0x3)) << 24);
+   #else
+      return  (uint32_t)p[0] |
+             ((uint32_t)p[1] << 8) |
+             ((uint32_t)p[2] << 16) |
+             ((uint32_t)p[3] << 24);
+   #endif
+}
+
+static INLINE void put_byte(uint8_t *p, uint8_t n)
+{
+   #ifdef BIG_ENDIAN_CPU
+      *(uint8_t*)((uint32_t)&p[0]^0x3) = n;
+   #else
+      p[0] = n;
+   #endif
+}
+static INLINE void put_short(uint8_t *p, uint16_t n)
+{
+   #ifdef BIG_ENDIAN_CPU
+      *(uint8_t*)((uint32_t)&p[0]^0x3) = (uint8_t)n;
+      *(uint8_t*)((uint32_t)&p[1]^0x3) = (uint8_t)(n >> 8);
+   #else
+      p[0] = (uint8_t)n;
+      p[1] = (uint8_t)(n >> 8);
+   #endif
+}
+
+static INLINE void put_word(uint8_t *p, uint32_t n)
+{
+   #ifdef BIG_ENDIAN_CPU
+      *(uint8_t*)((uint32_t)&p[0]^0x3) = (uint8_t)n;
+      *(uint8_t*)((uint32_t)&p[1]^0x3) = (uint8_t)(n >> 8);
+      *(uint8_t*)((uint32_t)&p[2]^0x3) = (uint8_t)(n >> 16);
+      *(uint8_t*)((uint32_t)&p[3]^0x3) = (uint8_t)(n >> 24);
+   #else
+      p[0] = (uint8_t)n;
+      p[1] = (uint8_t)(n >> 8);
+      p[2] = (uint8_t)(n >> 16);
+      p[3] = (uint8_t)(n >> 24);
+   #endif
+}
+
+static INLINE void put_float(uint8_t *p, float f)
+{
+   put_word(p, float_to_bits(f));
+}
+
+static INLINE void add_byte(uint8_t **p, uint8_t n)
+{
+   put_byte(*p, n);
+   (*p) += 1;
+}
+
+static INLINE void add_short(uint8_t **p, uint16_t n)
+{
+   put_short(*p, n);
+   (*p) += 2;
+}
+
+static INLINE void add_word(uint8_t **p, uint32_t n)
+{
+   put_word(*p, n);
+   (*p) += 4;
+}
+
+static INLINE void add_float(uint8_t **p, float f)
+{
+   add_word(p, float_to_bits(f));
+}
+
+#if V3D_VER_AT_LEAST(3, 0)
+static INLINE void add_float16(uint8_t **p, float16_t f16)
+{
+   add_short(p, (uint16_t) f16);
+}
+#endif
+
+static INLINE void add_pointer(uint8_t **p, void *ptr)
+{
+   add_word(p, khrn_hw_addr(khrn_hw_alias_direct(ptr)));   //PTR
+}
+
+#define ADD_BYTE(p, n) add_byte(&(p), (n))
+#define ADD_SHORT(p, n) add_short(&(p), (n))
+#define ADD_WORD(p, n) add_word(&(p), (n))
+#define ADD_FLOAT(p, n) add_float(&(p), (n))
+#define ADD_POINTER(p, n) add_pointer(&(p), (n))
+
+#define KHRN_HW_INSTR_HALT                   0
+#define KHRN_HW_INSTR_NOP                    1
+#define KHRN_HW_INSTR_MARKER                 2
+#define KHRN_HW_INSTR_RESET_MARKER_COUNT     3
+#define KHRN_HW_INSTR_FLUSH                  4
+#define KHRN_HW_INSTR_FLUSH_ALL_STATE        5
+#define KHRN_HW_INSTR_START_BRCM1_BINNING     6
+#define KHRN_HW_INSTR_INCR_SEMAPHORE         7
+#define KHRN_HW_INSTR_WAIT_SEMAPHORE         8
+#define KHRN_HW_INSTR_BRANCH                16
+#define KHRN_HW_INSTR_BRANCH_SUB            17
+#define KHRN_HW_INSTR_RETURN                18
+#define KHRN_HW_INSTR_REPEAT_START_MARKER   19
+#define KHRN_HW_INSTR_REPEAT_FROM_START_MARKER 20
+#define KHRN_HW_INSTR_STORE_SUBSAMPLE       24
+#define KHRN_HW_INSTR_STORE_SUBSAMPLE_EOF   25
+#define KHRN_HW_INSTR_STORE_FULL            26
+#define KHRN_HW_INSTR_LOAD_FULL             27
+#ifndef __BCM2708A0__
+#define KHRN_HW_INSTR_STORE_GENERAL         28
+#define KHRN_HW_INSTR_LOAD_GENERAL          29
+#endif
+#define KHRN_HW_INSTR_GLDRAWELEMENTS        32
+#define KHRN_HW_INSTR_GLDRAWARRAYS          33
+#define KHRN_HW_INSTR_VG_COORD_LIST         41
+#ifndef __BCM2708A0__
+#define KHRN_HW_INSTR_VG_INLINE_PRIMS       42
+#endif
+#define KHRN_HW_INSTR_COMPRESSED_LIST       48
+#define KHRN_HW_INSTR_CLIPPED_PRIM          49
+#define KHRN_HW_INSTR_PRIMITIVE_LIST_FORMAT 56
+#define KHRN_HW_INSTR_GL_SHADER             64
+#define KHRN_HW_INSTR_NV_SHADER             65
+#define KHRN_HW_INSTR_VG_SHADER             66
+#ifndef __BCM2708A0__
+#define KHRN_HW_INSTR_INLINE_VG_SHADER      67
+#endif
+/* ... */
+#if V3D_VER_AT_LEAST(3, 0)
+#define KHRN_HW_INSTR_STATE_BLEND_MODE          84
+#define KHRN_HW_INSTR_STATE_BLEND_CCOLOR_RGBA32 85
+#define KHRN_HW_INSTR_STATE_BLEND_CCOLOR_HDR16  86
+#endif
+/* ... */
+#define KHRN_HW_INSTR_STATE_CFG             96
+#define KHRN_HW_INSTR_STATE_FLATSHADE       97
+#define KHRN_HW_INSTR_STATE_POINT_SIZE      98
+#define KHRN_HW_INSTR_STATE_LINE_WIDTH      99
+#define KHRN_HW_INSTR_STATE_RHTX           100
+#define KHRN_HW_INSTR_STATE_DEPTH_OFFSET   101
+#define KHRN_HW_INSTR_STATE_CLIP           102
+#define KHRN_HW_INSTR_STATE_VIEWPORT_OFFSET 103
+#define KHRN_HW_INSTR_STATE_CLIPZ          104
+#define KHRN_HW_INSTR_STATE_CLIPPER_XY     105
+#define KHRN_HW_INSTR_STATE_CLIPPER_Z      106
+#define KHRN_HW_INSTR_STATE_BRCM1_BINNING_MODE 112
+#define KHRN_HW_INSTR_STATE_BRCM1_RENDERING_MODE 113
+#define KHRN_HW_INSTR_STATE_CLEARCOL       114
+#define KHRN_HW_INSTR_STATE_BRCM1_COORDS    115
+
+/******************************************************************************
+simpenrose recording
+******************************************************************************/
+
+#ifdef SIMPENROSE_RECORD_OUTPUT
+
+static INLINE void record_map_pointer(const void *p, unsigned int len, LABEL_T type, unsigned int flags, unsigned int align)
+{
+   record_map_buffer(khrn_hw_addr(p), len, type, flags, align);
+}
+
+static INLINE void record_map_extent(const void *begin, const void *end, LABEL_T type, unsigned int flags, unsigned int align)
+{
+   record_map_pointer(begin, (uint8_t *)end - (uint8_t *)begin, type, flags, align);
+}
+
+void record_map_mem_buffer_section(MEM_HANDLE_T handle, unsigned int begin, unsigned int len, LABEL_T type, unsigned int flags, unsigned int align);
+
+static INLINE void record_map_mem_buffer(MEM_HANDLE_T handle, LABEL_T type, unsigned int flags, unsigned int align)
+{
+   record_map_mem_buffer_section(handle, 0, mem_get_size(handle), type, flags, align);
+}
+
+void record_set_frame_config(uint32_t width, uint32_t height, uint32_t bpp, bool tformat);
+
+#endif
+
+/******************************************************************************
+hw fifo
+******************************************************************************/
+
+extern bool khrn_hw_init(void);
+extern void khrn_hw_term(void);
+
+#define KHRN_HW_SPECIAL_0            ((MEM_HANDLE_T)0) /* used for extra thrsw removing hack. todo: no need for this hack on b0 */
+#define KHRN_HW_SPECIAL_BIN_MEM      ((MEM_HANDLE_T)1)
+#define KHRN_HW_SPECIAL_BIN_MEM_END  ((MEM_HANDLE_T)2)
+#define KHRN_HW_SPECIAL_BIN_MEM_SIZE ((MEM_HANDLE_T)3)
+
+/*
+   if we don't run out of memory at any point, callback will be called:
+   - after locking everything in place, with reason
+     KHRN_HW_CALLBACK_REASON_FIXUP, from the llat task. khrn_hw_fixup_done
+     should be called at some point after this to signal that fixup is complete
+     and binning can begin
+   - after binning has completed, first with reason
+     KHRN_HW_CALLBACK_REASON_BIN_FINISHED_LLAT from the llat task, then with
+     KHRN_HW_CALLBACK_REASON_BIN_FINISHED from the master task
+   - after rendering has completed, with reason
+     KHRN_HW_CALLBACK_REASON_RENDER_FINISHED, from the master task
+
+   we can run out of memory before or during binning (but not after). if we do
+   run out of memory, callback will be called first with reason
+   KHRN_HW_CALLBACK_REASON_OUT_OF_MEM_LLAT from the llat task, then with reason
+   KHRN_HW_CALLBACK_REASON_OUT_OF_MEM from the master task, after which it will
+   not be called again
+*/
+
+typedef enum {
+   KHRN_HW_CALLBACK_REASON_FIXUP,
+   KHRN_HW_CALLBACK_REASON_OUT_OF_MEM_LLAT,
+   KHRN_HW_CALLBACK_REASON_OUT_OF_MEM,
+   KHRN_HW_CALLBACK_REASON_BIN_FINISHED_LLAT,
+   KHRN_HW_CALLBACK_REASON_BIN_FINISHED,
+   KHRN_HW_CALLBACK_REASON_RENDER_FINISHED,
+   KHRN_HW_CALLBACK_REASON_UNFIXUP,
+} KHRN_HW_CALLBACK_REASON_T;
+
+typedef void (*KHRN_HW_CALLBACK_T)(KHRN_HW_CALLBACK_REASON_T reason, void *data, const uint32_t *specials);
+
+/*
+   calling code should look something like this:
+
+   void my_callback(KHRN_HW_CALLBACK_REASON_T reason, void *data)
+   {
+      MY_STRUCT_T *my_struct = (MY_STRUCT_T *)data;
+      ...
+   }
+
+   MY_STRUCT_T *my_struct = (MY_STRUCT_T *)khrn_hw_queue(..., sizeof(MY_STRUCT_T));
+   my_struct->x = x;
+   ...
+
+   khrn_hw_ready(true, my_struct); // may be called at some later point from any thread
+*/
+
+typedef enum {
+   KHRN_HW_CC_FLAG_NONE = 0,
+
+   KHRN_HW_CC_FLAG_L2 = 1 << 0,
+   KHRN_HW_CC_FLAG_IC = 1 << 1,
+   KHRN_HW_CC_FLAG_UC = 1 << 2,
+   KHRN_HW_CC_FLAG_TU = 1 << 3
+} KHRN_HW_CC_FLAG_T;
+
+typedef enum {
+   KHRN_HW_TYPE_GL,
+   KHRN_HW_TYPE_VG
+} KHRN_HW_TYPE_T;
+
+extern void *khrn_hw_queue(
+   uint8_t *bin_begin, uint8_t *bin_end, KHRN_HW_CC_FLAG_T bin_cc,
+   uint8_t *render_begin, uint8_t *render_end, KHRN_HW_CC_FLAG_T render_cc, uint32_t render_n,
+   uint32_t special_0, /* used for extra thrsw removing hack. todo: no need for this hack on b0 */
+   uint32_t bin_mem_size_min, /* KHRN_HW_SPECIAL_BIN_MEM_SIZE will be >= this */
+   uint32_t actual_user_vpm, uint32_t max_user_vpm,
+   KHRN_HW_TYPE_T type,
+   KHRN_HW_CALLBACK_T callback,
+   uint32_t callback_data_size);
+extern void khrn_hw_ready(bool ok, void *callback_data); /* if ok is false, callback will later be called with KHRN_HW_CALLBACK_REASON_OUT_OF_MEM_LLAT/KHRN_HW_CALLBACK_REASON_OUT_OF_MEM */
+extern void khrn_hw_fixup_done(bool in_callback, void *callback_data); /* todo: i'm not sure i like this fixup done thing... */
+
+extern void khrn_hw_queue_wait_for_worker(uint64_t pos);
+
+extern void khrn_hw_queue_wait_for_display(EGL_DISP_HANDLE_T disp_handle, uint32_t pos);
+extern void khrn_hw_queue_display(EGL_DISP_SLOT_HANDLE_T slot_handle);
+
+extern void khrn_hw_wait(void);
+#ifdef KHRN_BCG_LINUX_GNUC
+extern void khrn_monitored_event_wait(void * sem);
+extern bool khrn_event_wait_timeout(void * sem, unsigned int t);
+#endif
+
+extern void khrn_hw_update_perf_counters(KHRN_DRIVER_COUNTERS_T *counters);
+extern void khrn_hw_reset_perf_counters(uint32_t hw_bank, uint32_t l3c_bank);
+
+extern void khrn_hw_notify(void);
+extern void khrn_hw_cleanup(void); /* called from khrn_sync_master_wait */
+
+/*
+   fifo pos stuff for interlocking with other fifos (eg worker)
+
+   khrn_hw_get_enter_pos should only be called from the master task and should
+   always return the right value
+
+   khrn_hw_get_bin_exit_pos/khrn_hw_get_render_exit_pos can be called from any
+   task, but might return the wrong value. the value returned will always be <=
+   the right value however
+*/
+
+#if defined(SIMPENROSE)
+/* no fifo... */
+static INLINE void khrn_hw_advance_enter_pos(void) {}
+static INLINE uint64_t khrn_hw_get_enter_pos(void) { return 0; }
+static INLINE void khrn_hw_advance_bin_exit_pos(void) {}
+static INLINE uint64_t khrn_hw_get_bin_exit_pos(void) { return 0; }
+static INLINE void khrn_hw_advance_render_exit_pos(void) {}
+static INLINE uint64_t khrn_hw_get_render_exit_pos(void) { return 0; }
+#else
+extern uint64_t khrn_hw_enter_pos;
+
+static INLINE void khrn_hw_advance_enter_pos(void)
+{
+   ++khrn_hw_enter_pos;
+}
+
+static INLINE uint64_t khrn_hw_get_enter_pos(void)
+{
+   return khrn_hw_enter_pos;
+}
+
+extern uint32_t khrn_hw_bin_exit_pos_0, khrn_hw_bin_exit_pos_1;
+
+static INLINE void khrn_hw_advance_bin_exit_pos(void)
+{
+   uint64_t next_exit_pos = (((uint64_t)khrn_hw_bin_exit_pos_1 << 32) | khrn_hw_bin_exit_pos_0) + 1;
+   khrn_barrier();
+   khrn_hw_bin_exit_pos_0 = (uint32_t)next_exit_pos;
+   khrn_barrier();
+   khrn_hw_bin_exit_pos_1 = (uint32_t)(next_exit_pos >> 32);
+}
+
+static INLINE uint64_t khrn_hw_get_bin_exit_pos(void)
+{
+   uint32_t exit_pos_1;
+   uint32_t exit_pos_0;
+
+   exit_pos_1 = khrn_hw_bin_exit_pos_1;
+   khrn_barrier();
+   exit_pos_0 = khrn_hw_bin_exit_pos_0;
+   khrn_barrier();
+   return ((uint64_t)exit_pos_1 << 32) | exit_pos_0;
+}
+
+extern uint32_t khrn_hw_render_exit_pos_0, khrn_hw_render_exit_pos_1;
+
+static INLINE void khrn_hw_advance_render_exit_pos(void)
+{
+   uint64_t next_exit_pos = (((uint64_t)khrn_hw_render_exit_pos_1 << 32) | khrn_hw_render_exit_pos_0) + 1;
+   khrn_barrier();
+   khrn_hw_render_exit_pos_0 = (uint32_t)next_exit_pos;
+   khrn_barrier();
+   khrn_hw_render_exit_pos_1 = (uint32_t)(next_exit_pos >> 32);
+}
+
+static INLINE uint64_t khrn_hw_get_render_exit_pos(void)
+{
+   uint32_t exit_pos_1;
+   uint32_t exit_pos_0;
+
+   exit_pos_1 = khrn_hw_render_exit_pos_1;
+   khrn_barrier();
+   exit_pos_0 = khrn_hw_render_exit_pos_0;
+   khrn_barrier();
+   return ((uint64_t)exit_pos_1 << 32) | exit_pos_0;
+}
+#endif
+
+#endif
diff --git a/middleware/khronos/common/khrn_hw.h b/middleware/khronos/common/khrn_hw.h
new file mode 100755 (executable)
index 0000000..486b748
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_HW_H
+#define KHRN_HW_H
+
+#include "interface/khronos/common/khrn_int_common.h"
+#include "middleware/khronos/common/khrn_image.h"
+#include "middleware/khronos/egl/egl_disp.h"
+#include "interface/khronos/include/EGL/egl.h"
+#include "interface/khronos/include/EGL/eglext.h"
+#include "interface/vcos/vcos.h"
+
+bool khrn_hw_common_init(void);
+void khrn_hw_common_term(void);
+
+void khrn_delayed_display(KHRN_IMAGE_T *image, EGL_DISP_SLOT_HANDLE_T slot_handle);
+void khrn_delayed_wait_for_display(uint32_t fifo, EGL_DISP_HANDLE_T disp_handle, uint32_t pos);
+void khrn_delayed_copy_buffer(MEM_HANDLE_T dst_handle, MEM_HANDLE_T src_handle);
+
+bool khrn_hw_supports_early_z(void);
+
+/* flush all queued stuff */
+extern void khrn_hw_common_flush(void);
+
+/* wait for all flushed stuff to finish */
+extern void khrn_hw_common_wait(void);
+
+/*
+   void khrn_hw_common_finish()
+
+   Flush all queued stuff. Wait for all flushed stuff to finish.
+
+   Preconditions:
+
+   -
+
+   Postcondtions:
+
+   For all KHRN_IMAGE_T image:
+      image.conceptual_readable_by_master is true
+      image.conceptual_writeable_by_master is true
+   conceptual_buffers_owned_by_master is true
+   conceptual_programs_owned_by_master is true
+*/
+
+static INLINE void khrn_hw_common_finish(void)
+{
+   khrn_hw_common_flush();
+   khrn_hw_common_wait();
+}
+
+extern void khrn_sync_init(void);
+extern void khrn_sync_notify_master(void);
+extern void khrn_sync_master_wait(void);
+#ifdef KHRN_BCG_WAIT_TIMEOUT
+extern bool khrn_sync_master_wait_timeout(unsigned int t);
+#endif
+extern void khrn_sync_display_returned_notify(void); /* called when something comes off the display */
+extern void khrn_specify_event(VCOS_EVENT_T *ev);
+extern int32_t khrn_do_suspend_resume(uint32_t up);
+
+typedef void KHRN_SYNC_MASTER_WAIT_FUNC(void);
+typedef void KHRN_SPECIFY_EVENT_FUNC(VCOS_EVENT_T *ev);
+typedef int32_t KHRN_DO_SUSPEND_RESUME_FUNC(uint32_t up);
+
+typedef struct {
+   uint32_t acquire;
+   uint32_t release;
+} KHRN_CACHE_COUNTERS_T;
+
+extern void khrn_memcpy(void *dest, const void *src, uint32_t size);
+extern void khrn_memset(void *dest, uint32_t val, uint32_t size);
+
+typedef struct {
+   /*
+      primitive counters
+   */
+
+   uint32_t fovcull;
+   uint32_t fovclip;
+   uint32_t revcull;
+   uint32_t nofepix;
+
+   /*
+      texture units
+   */
+
+   uint32_t tu0access;
+   uint32_t tu0miss;
+   uint32_t tu1access;
+   uint32_t tu1miss;
+
+   /*
+      backend
+   */
+
+   uint32_t dpthfail;
+   uint32_t stclfail;
+   uint32_t dpthstclpass;
+} KHRN_PERF_COUNTERS_T;
+
+typedef struct {
+   uint64_t qpu_cycles_idle;
+   uint64_t qpu_cycles_vert_shade;
+   uint64_t qpu_cycles_frag_shade;
+   uint64_t qpu_cycles_exe_valid;
+   uint64_t qpu_cycles_wait_tmu;
+   uint64_t qpu_cycles_wait_scb;
+   uint64_t qpu_cycles_wait_vary;
+   uint64_t qpu_icache_hits;
+   uint64_t qpu_icache_miss;
+   uint64_t qpu_ucache_hits;
+   uint64_t qpu_ucache_miss;
+
+   uint64_t tmu_total_quads;
+   uint64_t tmu_cache_miss;
+
+   uint64_t l2c_hits;
+   uint64_t l2c_miss;
+} KHRN_DRIVER_HW_COUNTERS0_T;
+
+typedef struct {
+   uint64_t fep_valid_prims;
+   uint64_t fep_valid_prims_no_pixels;
+   uint64_t fep_earlyz_clipped_quads;
+   uint64_t fep_valid_quads;
+
+   uint64_t tlb_quads_no_stencil_pass_pixels;
+   uint64_t tlb_quads_no_z_stencil_pass_pixels;
+   uint64_t tlb_quads_z_stencil_pass_pixels;
+   uint64_t tlb_quads_all_pixels_zero_cvg;
+   uint64_t tlb_quads_all_pixels_nonzero_cvg;
+   uint64_t tlb_quads_valid_pixels_written;
+
+   uint64_t ptb_prims_viewport_discarded;
+   uint64_t ptb_prims_needing_clip;
+
+   uint64_t pse_prims_reverse_discarded;
+
+   uint64_t vpm_cycles_vdw_stalled;
+   uint64_t vpm_cycles_vcd_stalled;
+} KHRN_DRIVER_HW_COUNTERS1_T;
+
+typedef struct {
+   uint32_t hard_clears;
+   uint32_t soft_clears;
+   uint32_t tb_grp_color_loads;
+   uint32_t tb_grp_ms_color_loads;
+   uint32_t tb_grp_ds_loads;
+   uint32_t tb_grp_color_stores;
+   uint32_t tb_grp_ms_color_stores;
+   uint32_t tb_grp_ds_stores;
+   uint32_t tb_color_loads;
+   uint32_t tb_ms_color_loads;
+   uint32_t tb_ds_loads;
+   uint32_t tb_color_stores;
+   uint32_t tb_ms_color_stores;
+   uint32_t tb_ds_stores;
+   uint32_t tex_submissions;
+   uint32_t tex_fast_paths;
+   uint32_t mipmap_gens;
+   uint32_t mipmap_gens_fast;
+   uint32_t draw_calls;
+   uint32_t num_swaps;
+
+   uint32_t hw_group_active;
+
+#ifdef __linux__
+   uint32_t reset_time;       /* time in ms when the statistics were last reset */
+   uint32_t in_time;          /* time at which acquire happened */
+   uint32_t total_time;       /* total of all (release time - acquire time) */
+
+   uint32_t last_cpu_time;
+   uint32_t last_cpu_ticks;
+#endif
+
+   union
+   {
+      KHRN_DRIVER_HW_COUNTERS0_T hw_0;
+      KHRN_DRIVER_HW_COUNTERS1_T hw_1;
+   } hw;
+
+   uint32_t l3c_group_active;
+   union
+   {
+      uint64_t l3c_read_bw_0;
+      uint64_t l3c_write_bw_1;
+   } l3c;
+   union
+   {
+      uint64_t l3c_mem_read_bw_0;
+      uint64_t l3c_mem_write_bw_1;
+   } l3c_mem;
+
+} KHRN_DRIVER_COUNTERS_T;
+
+extern void khrn_hw_register_perf_counters(KHRN_DRIVER_COUNTERS_T *counters);
+extern void khrn_hw_unregister_perf_counters(void);
+extern void khrn_reset_driver_counters(int32_t hw_bank, int32_t l3c_bank);
+
+extern KHRN_DRIVER_COUNTERS_T *khrn_driver_counters(void);
+
+#if EGL_BRCM_driver_monitor
+#define INCR_DRIVER_COUNTER(counter) khrn_driver_counters()->counter++;
+#else
+#define INCR_DRIVER_COUNTER(counter) ;
+#endif
+
+extern void khrn_hw_kick(void);
+
+#endif
diff --git a/middleware/khronos/common/khrn_image.h b/middleware/khronos/common/khrn_image.h
new file mode 100755 (executable)
index 0000000..d3a01db
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_IMAGE_H
+#define KHRN_IMAGE_H
+
+#include "interface/khronos/common/khrn_int_image.h"
+#include "middleware/khronos/common/khrn_interlock.h"
+#include "middleware/khronos/common/khrn_mem.h"
+
+#ifdef _VIDEOCORE
+#include "helpers/vc_image/vc_image.h"
+#endif
+
+#include <string.h>
+
+/******************************************************************************
+image handling
+******************************************************************************/
+
+/*
+   Binding flags
+   These specify which, if any, of the 3 EGL binding mechanisms this image is
+   taking part in. This information is stored in the image itself rather than
+   the API objects which use it, to enable communication between objects.
+   (For example if a pbuffer is bound to a texture, releasing the texture means
+   the pbuffer can now be bound to a different texture).
+   The IMAGE_FLAG_BOUND_CLIENTBUFFER and IMAGE_FLAG_BOUND_TEXIMAGE flags may be
+   used together, but not with IMAGE_FLAG_BOUND_EGLIMAGE (giving a total of 5
+   possible states).
+
+   texture is responsible for setting and clearing IMAGE_FLAG_BOUND_TEXIMAGE.
+   EGL is responsible for setting and clearing IMAGE_FLAG_BOUND_CLIENTBUFFER.
+   EGL is responsible for setting IMAGE_FLAG_BOUND_EGLIMAGE (this flag never
+      gets cleared once set).
+*/
+#define IMAGE_FLAG_BOUND_CLIENTBUFFER (1<<0)
+#define IMAGE_FLAG_BOUND_TEXIMAGE (1<<1)
+#define IMAGE_FLAG_BOUND_EGLIMAGE (1<<2)
+
+/* if these flags are set, the image should be usable in that way (eg if the
+ * texture flag is set it should be ok to use this image as a texture). the
+ * opposite may not be true. khrn_image_create_dup preserves these flags (so if
+ * you duplicate an image that can be used as a texture, the new image will also
+ * be usable as a texture) */
+#define IMAGE_FLAG_RENDER_TARGET (1<<3)
+#define IMAGE_FLAG_TEXTURE       (1<<4)
+#define IMAGE_FLAG_RSO_TEXTURE   (1<<5)
+#define IMAGE_FLAG_DISPLAY       (1<<6)
+
+typedef struct {
+   KHRN_IMAGE_FORMAT_T format;
+
+   uint16_t width;
+   uint16_t height;
+
+   int32_t stride; /* in bytes */
+
+   MEM_HANDLE_T mh_aux; /* palette or early z */
+
+   /* For external images mh_storage is not initialised until
+    * the it needs to be drawn */
+   MEM_HANDLE_T mh_storage;
+   uint32_t offset;
+
+   uint16_t flags;
+
+   KHRN_INTERLOCK_T interlock;
+
+#ifdef ABSTRACT_PLATFORM
+   void * opaque_buffer_handle;
+#endif
+
+} KHRN_IMAGE_T;
+
+typedef struct {
+   KHRN_IMAGE_WRAP_T w;
+   KHRN_INTERLOCK_T *interlock;
+} KHRN_IMAGE_INTERLOCK_WRAP_T;
+
+typedef enum {
+   /*
+      select whether the image data should be uninitialized, or initialized to 0xff or 0x00
+   */
+
+   IMAGE_CREATE_FLAG_NONE = 0 << 0,
+   IMAGE_CREATE_FLAG_ONE  = 1 << 0,
+   IMAGE_CREATE_FLAG_ZERO = 2 << 0,
+
+   /*
+      select whether the image data should be padded
+   */
+
+   IMAGE_CREATE_FLAG_PAD_ROTATE = 1 << 2,
+
+   /*
+      usage bits. image parameters will be fudged to ensure the created image
+      can be used in the specified manner (assuming the format is acceptable).
+      this might involve eg changing the memory layout to brcm1 or forcing a
+      large alignment. once created, the corresponding image flags will be set
+      on the image (eg if you pass IMAGE_CREATE_FLAG_TEXTURE to
+      khrn_image_create, the created image will have the IMAGE_FLAG_TEXTURE flag
+      set)
+   */
+
+   IMAGE_CREATE_FLAG_TEXTURE       = 1 << 3,
+   IMAGE_CREATE_FLAG_RSO_TEXTURE   = 1 << 4,
+   IMAGE_CREATE_FLAG_RENDER_TARGET = 1 << 5,
+   IMAGE_CREATE_FLAG_DISPLAY       = 1 << 6,
+
+   /*
+      don't allocate storage for the image yet?
+   */
+
+   IMAGE_CREATE_FLAG_NO_STORAGE = 1 << 7,
+
+   /*
+      mark the image as invalid (khrn_interlock_invalidate)?
+   */
+
+   IMAGE_CREATE_FLAG_INVALID = 1 << 8
+} KHRN_IMAGE_CREATE_FLAG_T;
+
+#define IMAGE_CREATE_FLAG_INIT_MASK (3 << 0)
+
+extern bool khrn_image_prefer_lt(KHRN_IMAGE_FORMAT_T format, uint32_t width, uint32_t height);
+extern uint32_t khrn_image_get_width_ut(const KHRN_IMAGE_T *image);
+extern uint32_t khrn_image_get_width_brcm1s(const KHRN_IMAGE_T *image);
+extern uint32_t khrn_image_get_aux_width_ut(const KHRN_IMAGE_T *image);
+extern uint32_t khrn_image_wrap_get_width_ut(const KHRN_IMAGE_WRAP_T *wrap);
+extern uint32_t khrn_image_wrap_get_width_brcm1s(const KHRN_IMAGE_WRAP_T *wrap);
+extern uint32_t khrn_image_get_align(const KHRN_IMAGE_T *image);
+extern uint32_t khrn_image_get_space(const KHRN_IMAGE_T *image);
+
+/* these should only be called on color formats */
+extern bool khrn_image_is_ok_for_render_target(KHRN_IMAGE_FORMAT_T format, bool ignore_mem_layout);
+extern bool khrn_image_can_use_as_render_target(KHRN_IMAGE_T *image); /* should only be called if khrn_image_is_ok_for_render_target() */
+
+extern void khrn_image_platform_fudge(
+   KHRN_IMAGE_FORMAT_T *format,
+   uint32_t *padded_width, uint32_t *padded_height,
+   uint32_t *align, uint32_t *stagger,
+   KHRN_IMAGE_CREATE_FLAG_T flags);
+
+extern void khrn_image_term(void *v, uint32_t);
+
+extern MEM_HANDLE_T khrn_image_create_from_storage(KHRN_IMAGE_FORMAT_T format,
+   uint32_t width, uint32_t height, int32_t stride,
+   MEM_HANDLE_T aux_handle, MEM_HANDLE_T storage_handle, uint32_t offset,
+   KHRN_IMAGE_CREATE_FLAG_T flags); /* just used for setting up usage flags */
+extern MEM_HANDLE_T khrn_image_create(KHRN_IMAGE_FORMAT_T format,
+   uint32_t width, uint32_t height,
+   KHRN_IMAGE_CREATE_FLAG_T flags);
+extern MEM_HANDLE_T khrn_image_create_dup(const KHRN_IMAGE_T *src,
+   KHRN_IMAGE_CREATE_FLAG_T flags); /* flags are in addition to implicit flags from src */
+
+extern bool khrn_image_resize(KHRN_IMAGE_T *image, uint32_t width, uint32_t height);
+
+static INLINE void *khrn_image_lock(const KHRN_IMAGE_T *image)
+{
+   return (uint8_t *)mem_lock(image->mh_storage) + image->offset;
+}
+
+static INLINE void khrn_image_unlock(const KHRN_IMAGE_T *image)
+{
+   mem_unlock(image->mh_storage);
+}
+
+extern void khrn_image_lock_wrap(const KHRN_IMAGE_T *image, KHRN_IMAGE_WRAP_T *wrap);
+extern void khrn_image_unlock_wrap(const KHRN_IMAGE_T *image);
+extern void khrn_image_lock_interlock_wrap(const KHRN_IMAGE_T *image, KHRN_IMAGE_INTERLOCK_WRAP_T *wrap);
+extern void khrn_image_interlock_wrap(KHRN_IMAGE_INTERLOCK_WRAP_T *wrap, KHRN_IMAGE_FORMAT_T format, uint32_t width, uint32_t height, int32_t stride, void *storage, KHRN_INTERLOCK_T *interlock);
+
+#ifdef _VIDEOCORE
+/* vc_image->image_data will be set to NULL */
+static INLINE void khrn_image_fill_vcimage(const KHRN_IMAGE_T *image, VC_IMAGE_T *vc_image)
+{
+   memset(vc_image, 0, sizeof(*vc_image));
+
+   if (khrn_image_is_color(image->format)) {
+      switch (image->format & ~(IMAGE_FORMAT_PRE | IMAGE_FORMAT_LIN)) {
+      case ABGR_8888_TF:  vc_image->type = VC_IMAGE_TF_RGBA32;   break;
+      case XBGR_8888_TF:  vc_image->type = VC_IMAGE_TF_RGBX32;   break;
+      case RGBA_4444_TF:  vc_image->type = VC_IMAGE_TF_RGBA16;   break;
+      case RGBA_5551_TF:  vc_image->type = VC_IMAGE_TF_RGBA5551; break;
+      case RGB_565_TF:    vc_image->type = VC_IMAGE_TF_RGB565;   break;
+      case RGBA_8888_RSO:
+      case ABGR_8888_RSO:
+      case ARGB_8888_RSO: vc_image->type = VC_IMAGE_RGBA32;      break;   //TODO: color channels in the right order? Right upside-downness? (one of these is wrong!)
+      case RGBX_8888_RSO: vc_image->type = VC_IMAGE_RGBX32;      break;
+      case XBGR_8888_RSO: vc_image->type = VC_IMAGE_RGBX32;      break;   //TODO: color channels in the right order? Right upside-downness? (one of these is wrong!)
+      case RGB_565_RSO:   vc_image->type = VC_IMAGE_RGB565;      break;   //if you change these, make sure it doesn't break EGL_KHR_lock_surface
+      case ARGB_4444_RSO: vc_image->type = VC_IMAGE_RGBA16;      break;
+      default:
+         UNREACHABLE();
+         vc_image->type = 0;
+      }
+   } else {
+      UNREACHABLE();
+      vc_image->type = 0;
+   }
+   vc_image->width = image->width;
+   vc_image->height = image->height;
+   vc_image->pitch = image->stride;
+   vc_image->size = mem_get_size(image->mh_storage);
+   vc_image->mem_handle = image->mh_storage;
+}
+
+static INLINE void khrn_image_lock_vcimage(const KHRN_IMAGE_T *image, VC_IMAGE_T *vc_image)
+{
+   khrn_image_fill_vcimage(image, vc_image);
+   vc_image->image_data = khrn_image_lock(image);
+}
+
+static INLINE void khrn_image_unlock_vcimage(const KHRN_IMAGE_T *image)
+{
+   khrn_image_unlock(image);
+}
+#endif
+
+/******************************************************************************
+blitting etc
+******************************************************************************/
+
+typedef enum {
+   /*
+      alpha-only images are implicitly black
+      to convert rgb to luminance, just take the red channel
+      ignore premultiplied and linear flags
+   */
+
+   IMAGE_CONV_GL,
+
+   /*
+      alpha-only images are implicitly white
+      to convert rgb to luminance, take a weighted average
+      observe premultiplied and linear flags
+   */
+
+   IMAGE_CONV_VG
+} KHRN_IMAGE_CONV_T;
+
+extern uint32_t khrn_image_wrap_get_pixel(const KHRN_IMAGE_WRAP_T *wrap, uint32_t x, uint32_t y);
+extern void khrn_image_wrap_put_pixel(KHRN_IMAGE_WRAP_T *wrap, uint32_t x, uint32_t y, uint32_t pixel);
+extern void khrn_image_wrap_put_etc1_block(KHRN_IMAGE_WRAP_T *wrap, uint32_t x, uint32_t y, uint32_t word0, uint32_t word1);
+
+extern uint32_t khrn_image_pixel_to_rgba(KHRN_IMAGE_FORMAT_T format, uint32_t pixel, KHRN_IMAGE_CONV_T conv);
+extern uint32_t khrn_image_rgba_to_pixel(KHRN_IMAGE_FORMAT_T format, uint32_t rgba, KHRN_IMAGE_CONV_T conv);
+
+extern uint32_t khrn_image_rgba_convert_pre_lin(KHRN_IMAGE_FORMAT_T dst_format, KHRN_IMAGE_FORMAT_T src_format, uint32_t rgba);
+extern uint32_t khrn_image_rgba_convert_l_pre_lin(KHRN_IMAGE_FORMAT_T dst_format, KHRN_IMAGE_FORMAT_T src_format, uint32_t rgba);
+
+extern void khrn_image_wrap_clear_region(
+   KHRN_IMAGE_WRAP_T *wrap, uint32_t x, uint32_t y,
+   uint32_t width, uint32_t height,
+   uint32_t rgba, /* rgba non-lin, unpre */
+   KHRN_IMAGE_CONV_T conv);
+extern void khrn_image_wrap_copy_region(
+   KHRN_IMAGE_WRAP_T *dst, uint32_t dst_x, uint32_t dst_y,
+   uint32_t width, uint32_t height,
+   const KHRN_IMAGE_WRAP_T *src, uint32_t src_x, uint32_t src_y,
+   KHRN_IMAGE_CONV_T conv);
+extern void khrn_image_wrap_copy_scissor_regions(
+   KHRN_IMAGE_WRAP_T *dst, uint32_t dst_x, uint32_t dst_y,
+   uint32_t width, uint32_t height,
+   const KHRN_IMAGE_WRAP_T *src, uint32_t src_x, uint32_t src_y,
+   KHRN_IMAGE_CONV_T conv,
+   const int32_t *scissor_rects, uint32_t scissor_rects_count);
+extern void khrn_image_wrap_convert(KHRN_IMAGE_WRAP_T *dst, const KHRN_IMAGE_WRAP_T *src, KHRN_IMAGE_CONV_T conv);
+extern void khrn_image_wrap_copy_stencil_channel(KHRN_IMAGE_WRAP_T *dst, const KHRN_IMAGE_WRAP_T *src);
+extern void khrn_image_wrap_subsample(KHRN_IMAGE_WRAP_T *dst, const KHRN_IMAGE_WRAP_T *src);
+bool khrn_image_wrap_copy_region_tlb(
+   MEM_HANDLE_T dst_handle, KHRN_IMAGE_INTERLOCK_WRAP_T *dst,
+   uint32_t dst_x, uint32_t dst_y,
+   uint32_t width, uint32_t height,
+   MEM_HANDLE_T src_handle, KHRN_IMAGE_INTERLOCK_WRAP_T *src,
+   uint32_t src_x, uint32_t src_y,
+   KHRN_IMAGE_CONV_T conv);
+void khrn_image_wrap_copy_region_client(
+   KHRN_IMAGE_INTERLOCK_WRAP_T *dst, uint32_t dst_x, uint32_t dst_y,
+   uint32_t width, uint32_t height,
+   KHRN_IMAGE_INTERLOCK_WRAP_T *src, uint32_t src_x, uint32_t src_y,
+   KHRN_IMAGE_CONV_T conv);
+void khrn_image_wrap_copy_region_server(
+   KHRN_IMAGE_INTERLOCK_WRAP_T *dst, uint32_t dst_x, uint32_t dst_y,
+   uint32_t width, uint32_t height,
+   KHRN_IMAGE_INTERLOCK_WRAP_T *src, uint32_t src_x, uint32_t src_y,
+   KHRN_IMAGE_CONV_T conv);
+
+/*
+   KHRN_IMAGE_T functions (forward to the KHRN_IMAGE_WRAP_T functions above)
+*/
+
+extern void khrn_image_clear_region(
+   KHRN_IMAGE_T *image, uint32_t x, uint32_t y,
+   uint32_t width, uint32_t height,
+   uint32_t rgba, /* non-lin, unpre */
+   KHRN_IMAGE_CONV_T conv);
+extern void khrn_image_copy_region(
+   KHRN_IMAGE_T *dst, uint32_t dst_x, uint32_t dst_y,
+   uint32_t width, uint32_t height,
+   const KHRN_IMAGE_T *src, uint32_t src_x, uint32_t src_y,
+   KHRN_IMAGE_CONV_T conv);
+extern void khrn_image_copy_region_flip(
+   KHRN_IMAGE_T *dst, uint32_t dst_x, uint32_t dst_y,
+   uint32_t width, uint32_t height,
+   const KHRN_IMAGE_T *src, uint32_t src_x, uint32_t src_y,
+   KHRN_IMAGE_CONV_T conv);
+extern void khrn_image_convert_master(KHRN_IMAGE_T *dst, const KHRN_IMAGE_T *src, KHRN_IMAGE_CONV_T conv);
+extern void khrn_image_copy_stencil_channel(KHRN_IMAGE_T *dst, const KHRN_IMAGE_T *src);
+extern void khrn_image_subsample(KHRN_IMAGE_T *dst, const KHRN_IMAGE_T *src);
+
+extern bool khrn_image_alloc_storage(KHRN_IMAGE_T *image, const char *description);
+
+#endif
diff --git a/middleware/khronos/common/khrn_interlock.h b/middleware/khronos/common/khrn_interlock.h
new file mode 100755 (executable)
index 0000000..c02a17a
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_INTERLOCK_H
+#define KHRN_INTERLOCK_H
+
+#include "middleware/khronos/common/khrn_mem.h"
+#include "middleware/khronos/egl/egl_disp.h"
+
+/* should define KHRN_INTERLOCK_USER_T, KHRN_INTERLOCK_USER_NONE,
+ * KHRN_INTERLOCK_USER_TEMP, KHRN_INTERLOCK_USER_WRITING, and
+ * KHRN_INTERLOCK_EXTRA_T */
+#include "middleware/khronos/common/2708/khrn_interlock_filler_4.h"
+
+typedef struct {
+   EGL_DISP_IMAGE_HANDLE_T disp_image_handle;
+   KHRN_INTERLOCK_USER_T users;
+   KHRN_INTERLOCK_EXTRA_T extra;
+} KHRN_INTERLOCK_T;
+
+/*
+   platform-independent implementations
+*/
+
+extern void khrn_interlock_init(KHRN_INTERLOCK_T *interlock);
+extern void khrn_interlock_term(KHRN_INTERLOCK_T *interlock);
+
+extern bool khrn_interlock_read(KHRN_INTERLOCK_T *interlock, KHRN_INTERLOCK_USER_T user); /* user allowed to be KHRN_INTERLOCK_USER_NONE */
+extern bool khrn_interlock_write(KHRN_INTERLOCK_T *interlock, KHRN_INTERLOCK_USER_T user); /* user allowed to be KHRN_INTERLOCK_USER_NONE */
+extern KHRN_INTERLOCK_USER_T khrn_interlock_get_writer(KHRN_INTERLOCK_T *interlock);
+extern bool khrn_interlock_release(KHRN_INTERLOCK_T *interlock, KHRN_INTERLOCK_USER_T user);
+
+extern bool khrn_interlock_write_would_block(KHRN_INTERLOCK_T *interlock);
+
+extern void khrn_interlock_invalidate(KHRN_INTERLOCK_T *interlock);
+extern bool khrn_interlock_is_invalid(KHRN_INTERLOCK_T *interlock);
+
+/*
+   platform-dependent implementations
+*/
+
+extern void khrn_interlock_extra_init(KHRN_INTERLOCK_T *interlock);
+extern void khrn_interlock_extra_term(KHRN_INTERLOCK_T *interlock);
+
+extern void khrn_interlock_read_immediate(KHRN_INTERLOCK_T *interlock);
+extern void khrn_interlock_write_immediate(KHRN_INTERLOCK_T *interlock);
+
+extern void khrn_interlock_flush(KHRN_INTERLOCK_USER_T user);
+
+#endif
diff --git a/middleware/khronos/common/khrn_map.h b/middleware/khronos/common/khrn_map.h
new file mode 100755 (executable)
index 0000000..84967cf
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_MAP_H
+#define KHRN_MAP_H
+
+#define khrn_generic_map(X) khrn_map_##X
+#define KHRN_GENERIC_MAP(X) KHRN_MAP_##X
+#define KHRN_GENERIC_MAP_KEY_T uint32_t
+#define KHRN_GENERIC_MAP_VALUE_T MEM_HANDLE_T
+#define KHRN_GENERIC_MAP_RELOCATABLE
+
+#ifdef KHRN_MAP_C
+   #include "interface/khronos/common/khrn_int_generic_map.c"
+#else
+   #include "interface/khronos/common/khrn_int_generic_map.h"
+#endif
+
+#undef KHRN_GENERIC_MAP_RELOCATABLE
+#undef KHRN_GENERIC_MAP_VALUE_T
+#undef KHRN_GENERIC_MAP_KEY_T
+#undef KHRN_GENERIC_MAP
+#undef khrn_generic_map
+
+#endif
diff --git a/middleware/khronos/common/khrn_mem.h b/middleware/khronos/common/khrn_mem.h
new file mode 100755 (executable)
index 0000000..6c4bd60
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/khronos/common/khrn_int_util.h"
+
+#include "vcfw/rtos/common/rtos_common_mem.h"
diff --git a/middleware/khronos/common/khrn_misc.h b/middleware/khronos/common/khrn_misc.h
new file mode 100755 (executable)
index 0000000..589e903
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_MISC_H
+#define KHRN_MISC_H
+
+//if you want KHRN_USE_VCHIQ define it in the platform makefile
+//e.g in vcfw/platform/broadcom/2763dbrev2/2763dbrev2_linux.mk
+//#ifndef KHRN_USE_VCHIQ
+//#define KHRN_USE_VCHIQ
+//#endif
+
+#include "middleware/khronos/common/khrn_hw.h"
+
+#ifndef V3D_LEAN
+#include "middleware/khronos/dispatch/khrn_dispatch.h"
+#endif
+
+#include "interface/khronos/common/khrn_int_misc_impl.h"
+
+#include "interface/khronos/include/GLES/gl.h"
+#include "interface/khronos/include/GLES/glext.h"
+#include "interface/khronos/glxx/glxx_int_attrib.h"
+#include "interface/khronos/include/VG/openvg.h"
+#include "interface/khronos/include/VG/vgext.h"
+#include "interface/khronos/include/VG/vgu.h"
+#include "interface/khronos/vg/vg_int.h"
+#include "interface/khronos/vg/vg_int_mat3x3.h"
+#include "interface/khronos/include/EGL/egl.h"
+#include "interface/khronos/include/EGL/eglext.h"
+#include "interface/khronos/common/khrn_int_image.h"
+#include "interface/khronos/egl/egl_int.h"
+#ifndef KHRN_NO_WFC
+#include "interface/khronos/wf/wfc_int.h"
+#include "middleware/khronos/wf/wfc_server_stream.h"
+#endif
+
+typedef struct {
+   KHRONOS_DISPATCH_FUNC *dispatch;
+   KHRN_SYNC_MASTER_WAIT_FUNC *sync_master_wait;
+   KHRN_SPECIFY_EVENT_FUNC *specify_event;
+   KHRN_DO_SUSPEND_RESUME_FUNC *do_suspend_resume;
+
+#define KHRN_IMPL_STRUCT
+#include "interface/khronos/glxx/gl11_int_impl.h"
+#include "interface/khronos/glxx/gl20_int_impl.h"
+#include "interface/khronos/glxx/glxx_int_impl.h"
+#include "interface/khronos/vg/vg_int_impl.h"
+#include "interface/khronos/egl/egl_int_impl.h"
+#include "interface/khronos/common/khrn_int_misc_impl.h"
+#undef KHRN_IMPL_STRUCT
+} KHRONOS_FUNC_TABLE_T;
+
+typedef const KHRONOS_FUNC_TABLE_T *KHRONOS_GET_FUNC_TABLE_FUNC(void);
+
+#ifdef USE_VCHIQ_ARM
+extern void khrn_misc_set_connection_pid(uint32_t pid_0, uint32_t pid_1);
+#endif
+#ifdef RPC_DIRECT
+/* No way of checking this in RPC_DIRECT mode, that I can think of */
+#define KHRN_ASSERT_IN_MASTER_THREAD
+#else
+extern bool khrn_in_master_thread();
+#define KHRN_ASSERT_IN_MASTER_THREAD vcos_assert(khrn_in_master_thread())
+#endif
+#endif
diff --git a/middleware/khronos/common/khrn_pid_map.h b/middleware/khronos/common/khrn_pid_map.h
new file mode 100755 (executable)
index 0000000..7b117d0
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_PID_MAP_H
+#define KHRN_PID_MAP_H
+
+#include "middleware/khronos/common/khrn_pid_map_value.h"
+
+#define khrn_generic_map(X) khrn_pid_map_##X
+#define KHRN_GENERIC_MAP(X) KHRN_PID_MAP_##X
+#define KHRN_GENERIC_MAP_KEY_T uint32_t
+#define KHRN_GENERIC_MAP_VALUE_T KHRN_PID_MAP_VALUE_T
+#define KHRN_GENERIC_MAP_RELOCATABLE
+
+#ifdef KHRN_PID_MAP_C
+   #include "interface/khronos/common/khrn_int_generic_map.c"
+#else
+   #include "interface/khronos/common/khrn_int_generic_map.h"
+#endif
+
+#undef KHRN_GENERIC_MAP_RELOCATABLE
+#undef KHRN_GENERIC_MAP_VALUE_T
+#undef KHRN_GENERIC_MAP_KEY_T
+#undef KHRN_GENERIC_MAP
+#undef khrn_generic_map
+
+#endif
diff --git a/middleware/khronos/common/khrn_pid_map_value.h b/middleware/khronos/common/khrn_pid_map_value.h
new file mode 100755 (executable)
index 0000000..ed0f956
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef KHRN_PID_MAP_VALUE_H
+#define KHRN_PID_MAP_VALUE_H
+
+typedef struct KHRN_PID_MAP_VALUE_S {
+   MEM_HANDLE_T handle;
+   uint64_t pid;
+} KHRN_PID_MAP_VALUE_T;
+
+static INLINE KHRN_PID_MAP_VALUE_T khrn_pid_map_value_get_none(void)
+{
+   KHRN_PID_MAP_VALUE_T x = {MEM_INVALID_HANDLE, 0L};
+   return x;
+}
+
+static INLINE KHRN_PID_MAP_VALUE_T khrn_pid_map_value_get_deleted(void)
+{
+   KHRN_PID_MAP_VALUE_T x = {(MEM_HANDLE_T)(MEM_INVALID_HANDLE - 1), 0L};
+   return x;
+}
+
+static INLINE void khrn_pid_map_value_acquire(KHRN_PID_MAP_VALUE_T value)
+{
+   mem_acquire(value.handle);
+}
+
+static INLINE void khrn_pid_map_value_release(KHRN_PID_MAP_VALUE_T value)
+{
+   mem_release(value.handle);
+}
+
+static INLINE bool khrn_pid_map_value_cmp(
+   KHRN_PID_MAP_VALUE_T x,
+   KHRN_PID_MAP_VALUE_T y)
+{
+   return (x.handle == y.handle) && (x.pid == y.pid);
+}
+
+#endif
diff --git a/middleware/khronos/common/khrn_server_pointermap.h b/middleware/khronos/common/khrn_server_pointermap.h
new file mode 100755 (executable)
index 0000000..b9a6a4a
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef KHRN_SERVER_POINTERMAP_H
+#define KHRN_SERVER_POINTERMAP_H
+
+#define khrn_generic_map(X) khrn_server_pointer_map_##X
+#define KHRN_GENERIC_MAP(X) KHRN_SERVER_POINTER_MAP_##X
+#define KHRN_GENERIC_MAP_KEY_T uint32_t
+#define KHRN_GENERIC_MAP_VALUE_T void *
+#define KHRN_GENERIC_MAP_RELOCATABLE
+
+#ifdef SERVER_POINTER_MAP_C
+   #include "interface/khronos/common/khrn_int_generic_map.c"
+#else
+   #include "interface/khronos/common/khrn_int_generic_map.h"
+#endif
+
+#undef KHRN_GENERIC_MAP_VALUE_T
+#undef KHRN_GENERIC_MAP_KEY_T
+#undef KHRN_GENERIC_MAP
+#undef khrn_generic_map
+
+#endif
diff --git a/middleware/khronos/dispatch/khrn_dispatch.h b/middleware/khronos/dispatch/khrn_dispatch.h
new file mode 100755 (executable)
index 0000000..5abf709
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+#ifndef KHRN_DISPATCH_H
+#define KHRN_DISPATCH_H
+
+#include <stdlib.h>
+
+#ifdef KHRN_USE_VCHIQ
+#include "interface/vchiq_arm/vchiq.h"
+
+extern int khronos_dispatch( void *_message, int _length, VCHIQ_SERVICE_HANDLE_T khrn_handle, VCHIU_QUEUE_T *queue, VCOS_SEMAPHORE_T *sem );
+typedef int KHRONOS_DISPATCH_FUNC( void *_message, int _length, VCHIQ_SERVICE_HANDLE_T khrn_handle, VCHIU_QUEUE_T *queue, VCOS_SEMAPHORE_T *sem );
+extern void khdispatch_push_local( uint64_t pid_in, const void *out, uint32_t len);
+
+#else
+#include "interface/vchi/vchi.h"
+
+extern int khronos_dispatch( void *_message, int _length, VCHI_SERVICE_HANDLE_T _khrn_handle, VCHI_SERVICE_HANDLE_T _khan_handle );
+
+typedef int KHRONOS_DISPATCH_FUNC( void *_message, int _length, VCHI_SERVICE_HANDLE_T _khrn_handle, VCHI_SERVICE_HANDLE_T _khan_handle );
+#endif
+
+extern bool khdispatch_within_workspace( const void *ptr, size_t length );
+
+extern void khdispatch_send_async_len(uint32_t command, uint64_t pid_in, uint32_t len, void * msg);
+
+#endif /* SERVER_DISPATCH_H */
diff --git a/middleware/khronos/egl/egl_disp.h b/middleware/khronos/egl/egl_disp.h
new file mode 100755 (executable)
index 0000000..0ee8200
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef EGL_DISP_H
+#define EGL_DISP_H
+
+#include "interface/khronos/common/khrn_int_common.h"
+#include "middleware/khronos/common/khrn_mem.h"
+
+extern bool egl_disp_init(void);
+extern void egl_disp_term(void);
+
+typedef enum {
+   EGL_DISP_HANDLE_INVALID = -1,
+   EGL_DISP_HANDLE_FORCE_32BIT = (int)0x80000000
+} EGL_DISP_HANDLE_T;
+
+/* there are only a fixed number of handles available; EGL_DISP_HANDLE_INVALID
+ * may be returned even when there is plenty of free memory. todo: fix this?
+ *
+ * khdispatch_send_async(ASYNC_COMMAND_POST, pid, sem) is called every time an
+ * image comes off the display
+ *
+ * call from master task */
+extern EGL_DISP_HANDLE_T egl_disp_alloc(
+   uint64_t pid, uint32_t sem,
+   uint32_t n, const MEM_HANDLE_T *images);
+
+/* this will not return until all images are off the display
+ *
+ * call from master task */
+extern void egl_disp_free(EGL_DISP_HANDLE_T disp_handle);
+
+/* wait until we're ready to display the next image, ie we're idle. this implies
+ * we won't call egl_server_platform_display until the next image comes along */
+extern void egl_disp_finish(EGL_DISP_HANDLE_T disp_handle);
+
+/* equivalent to calling egl_disp_finish on all valid handles */
+extern void egl_disp_finish_all(void);
+
+/* display the next image in the chain. image_handle is optional -- if provided,
+ * it is merely checked against the handle of the image to be displayed
+ *
+ * we will wait (asynchronously) until the image is actually ready to be
+ * displayed (ie there are no outstanding writes) before calling
+ * egl_server_platform_display
+ *
+ * images are displayed in sequence (even if they become ready out of sequence)
+ *
+ * swap_interval is the minimum display time of the image in v-sync periods. a
+ * swap_interval of 0 is special: in addition to not requiring any display time
+ * at all, we won't hold back rendering to wait for the (previous) image to
+ * come off the display. this can result in tearing
+ *
+ * the image parameters (size/stride) are read before returning from this
+ * function to make resizing (in the case where the storage handle and size
+ * aren't changed) safe. this won't prevent visual glitches with swap interval
+ * 0
+ *
+ * call from master task */
+extern void egl_disp_next(EGL_DISP_HANDLE_T disp_handle,
+   MEM_HANDLE_T image_handle, uint32_t win, uint32_t swap_interval);
+
+typedef enum {
+   EGL_DISP_SLOT_HANDLE_INVALID = -1,
+   EGL_DISP_SLOT_HANDLE_FORCE_32BIT = (int)0x80000000
+} EGL_DISP_SLOT_HANDLE_T;
+
+/* mark the slot as ready. if skip, the swap interval of the image is forced to
+ * 0 and we won't actually display the image
+ *
+ * call from any task */
+extern void egl_disp_ready(EGL_DISP_SLOT_HANDLE_T slot_handle, bool skip);
+
+typedef enum {
+   EGL_DISP_IMAGE_HANDLE_INVALID = -1,
+   EGL_DISP_IMAGE_HANDLE_FORCE_32BIT = (int)0x80000000
+} EGL_DISP_IMAGE_HANDLE_T;
+
+/* wait until the image is not on the display. an image is considered to be on
+ * the display between an egl_disp_next call that queues the image for display
+ * and the image coming off the display
+ *
+ * call from master task */
+extern void egl_disp_wait(EGL_DISP_IMAGE_HANDLE_T image_handle);
+
+/* post a wait-for-display message to fifo. this function will filter out
+ * unnecessary waits, but otherwise just forwards (with transformed arguments)
+ * to khrn_delayed_wait_for_display(). the wait-for-display message itself
+ * should wait until egl_disp_on() returns false
+ *
+ * call egl_disp_post_wait() from master task. call egl_disp_on() from any
+ * task */
+extern void egl_disp_post_wait(uint32_t fifo, EGL_DISP_IMAGE_HANDLE_T image_handle);
+extern bool egl_disp_on(EGL_DISP_HANDLE_T disp_handle, uint32_t pos);
+
+extern void egl_disp_callback(uint32_t cb_arg);
+
+#endif
diff --git a/middleware/khronos/egl/egl_server.h b/middleware/khronos/egl/egl_server.h
new file mode 100755 (executable)
index 0000000..011ec8f
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef EGL_SERVER_H
+#define EGL_SERVER_H
+
+#include "interface/khronos/egl/egl_int.h"
+#include "middleware/khronos/common/khrn_map.h"
+#include "middleware/khronos/common/khrn_pid_map.h"
+#include "middleware/khronos/common/khrn_server_pointermap.h"
+#include "middleware/khronos/common/khrn_image.h"
+#include "middleware/khronos/common/khrn_hw.h"
+#include "middleware/khronos/egl/egl_disp.h"
+#include "interface/khronos/include/EGL/egl.h"
+#include "interface/khronos/include/EGL/eglext.h"
+#include "middleware/khronos/vg/vg_image.h"
+
+#include "interface/khronos/include/WF/wfc.h"
+
+// Must be enough for triple-buffering (windows) and mipmaps (pbuffers)
+#define EGL_MAX_BUFFERS       12
+
+// There is a single global instance of this
+typedef struct
+{
+   KHRN_MAP_T surfaces;
+   KHRN_MAP_T glcontexts;
+   KHRN_MAP_T vgcontexts;
+   KHRN_PID_MAP_T eglimages;
+   VCOS_MUTEX_T eglimages_lock;
+   KHRN_MAP_T wintoeglimage;//TODO window ids should be per process?
+   VCOS_MUTEX_T wintoeglimage_mutex;
+   
+#if EGL_KHR_sync
+   KHRN_MAP_T syncs;
+#endif
+
+   uint32_t next_surface;
+   uint32_t next_context;
+   uint32_t next_eglimage;
+#if EGL_KHR_sync
+   uint32_t next_sync;
+#endif
+
+   uint64_t pid;                   //currently selected process id
+
+   uint32_t glversion;             //EGL_SERVER_GL11 or EGL_SERVER_GL20. (0 if invalid)
+   MEM_HANDLE_T glcontext;
+   MEM_HANDLE_T gldrawsurface;     //EGL_SERVER_SURFACE_T
+   MEM_HANDLE_T glreadsurface;     //EGL_SERVER_SURFACE_T
+   MEM_HANDLE_T vgcontext;
+   MEM_HANDLE_T vgsurface;         //EGL_SERVER_SURFACE_T
+
+   /*
+      locked_glcontext
+
+      Invariants:
+
+      (EGL_SERVER_STATE_LOCKED_GLCONTEXT)
+      locked_glcontext == NULL or locked_glcontext is the locked version of glcontext (and we own the lock)
+   */
+   void *locked_glcontext;
+   /*
+      locked_vgcontext
+
+      Invariants:
+
+      (EGL_SERVER_STATE_LOCKED_VGCONTEXT)
+      locked_vgcontext == NULL or locked_vgcontext is the locked version of vgcontext (and we own the lock)
+   */
+   void *locked_vgcontext;
+   /*
+      locked_vgcontext_shared
+
+      Invariants:
+
+      (EGL_SERVER_STATE_LOCKED_VGCONTEXT_SHARED)
+      locked_vgcontext_shared == NULL or locked_vgcontext_shared is the locked version of vgcontext->shared_state (and we own the lock)
+   */
+   void *locked_vgcontext_shared;
+   /*
+      locked_vgcontext_shared_objects_storage
+
+      Invariants:
+
+      (EGL_SERVER_STATE_LOCKED_VGCONTEXT_SHARED_OBJECTS_STORAGE)
+      locked_vgcontext_shared_objects_storage == NULL or locked_vgcontext_shared_objects_storage is the locked version of vgcontext->shared_state->objects->storage (and we own the lock)
+   */
+   void *locked_vgcontext_shared_objects_storage;
+
+#if EGL_BRCM_perf_monitor
+   uint32_t perf_monitor_refcount;
+   uint32_t perf_monitor_lasttime;
+
+   KHRN_PERF_COUNTERS_T perf_monitor_counters;
+
+   MEM_HANDLE_T perf_monitor_images[2];      //KHRN_IMAGE_T
+#endif
+
+#if EGL_BRCM_driver_monitor
+   uint32_t driver_monitor_refcount;
+   KHRN_DRIVER_COUNTERS_T driver_monitor_counters;
+#endif
+
+} EGL_SERVER_STATE_T;
+
+typedef struct
+{
+   uint32_t name;
+
+   bool mipmap;
+   uint32_t buffers;
+   uint32_t back_buffer_index;
+   /*
+      mh_color
+
+      Invariant:
+
+      For 0 <= i < buffers
+         mh_color[i] is a handle to a valid KHRN_IMAGE_T
+   */
+   MEM_HANDLE_T mh_color[EGL_MAX_BUFFERS];
+   MEM_HANDLE_T mh_depth;  //floating KHRN_IMAGE_T
+   MEM_HANDLE_T mh_multi;  //floating KHRN_IMAGE_T
+   MEM_HANDLE_T mh_mask;   //floating KHRN_IMAGE_T
+
+   uint8_t config_depth_bits;   // How many depth bits were requested in config. May not match actual buffer.
+   uint8_t config_stencil_bits; // How many stencil bits were requested in config. May not match actual buffer.
+
+   uint32_t win;                    // Opaque handle passed to egl_server_platform_display
+   uint64_t pid;                    // Opaque handle to creating process
+   uint32_t sem;                    // Opaque handle (probably semaphore name) passed on KHAN channel
+
+   MEM_HANDLE_T mh_bound_texture;
+   uint32_t swap_interval;
+   uint32_t semaphoreId;  //Symbian needs a handle passed back in Khan, not just surface number
+
+
+   //for android, the mh_storage this points at needs updating to point to where rendering happened
+   uint32_t egl_render_image; 
+
+   EGL_DISP_HANDLE_T disp_handle;
+} EGL_SERVER_SURFACE_T;
+
+typedef struct
+{
+   uint32_t type;
+   uint32_t condition;
+   int32_t threshold;
+
+   uint64_t pid;
+   uint32_t sem;
+
+   bool state;
+} EGL_SERVER_SYNC_T;
+
+#define EGL_SERVER_FIFO_LEN 4
+
+typedef struct
+{
+   uint64_t pid;
+
+   EGLImageKHR egl_image_id;
+
+   struct {
+      EGLImageKHR    egl_images[EGL_SERVER_FIFO_LEN];
+      unsigned       count;
+      unsigned       read;
+      unsigned       write;
+   } fifo;
+
+} EGL_SERVER_WIN_TO_EGL_IMAGE_T;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+EGLAPI void EGLAPIENTRY egl_server_startup_hack(void);
+#ifdef __cplusplus
+}
+#endif
+
+extern bool egl_server_is_empty(void);
+extern void egl_server_shutdown(void);
+
+/*
+   egl_server_state_initted
+
+   Invariants:
+
+   True iff valid EGL server state exists
+*/
+extern bool egl_server_state_initted;
+extern EGL_SERVER_STATE_T egl_server_state;
+
+/*
+   EGL_SERVER_STATE_T *EGL_GET_SERVER_STATE()
+
+   Returns pointer to EGL server state.
+
+   Implementation notes:
+
+   There is only one of these globally, and it does not need locking and unlocking.
+
+   Preconditions:
+
+   Valid EGL server state exists
+
+   Postconditions:
+
+   Return value is a valid pointer
+*/
+
+static INLINE EGL_SERVER_STATE_T *EGL_GET_SERVER_STATE(void)
+{
+   vcos_assert(egl_server_state_initted);
+   return &egl_server_state;
+}
+
+extern void egl_server_unlock(void);
+
+#include "interface/khronos/egl/egl_int_impl.h"
+
+extern void egl_khr_fence_update(void);
+
+extern void egl_update_current_rendering_image(uint64_t pid, uint32_t window, MEM_HANDLE_T himage);
+
+#if EGL_BRCM_perf_monitor
+extern void egl_brcm_perf_monitor_update();
+#endif
+
+#endif
diff --git a/middleware/khronos/ext/egl_khr_image.h b/middleware/khronos/ext/egl_khr_image.h
new file mode 100755 (executable)
index 0000000..5a073fe
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include "interface/khronos/common/khrn_int_common.h"
+#include "interface/khronos/include/EGL/egl.h"
+#include "interface/khronos/include/EGL/eglext.h"
+#include "middleware/khronos/egl/egl_server.h"
+#include "middleware/imageconv/imageconv.h"
+#include "vcinclude/vc_image_types.h"
+
+
+typedef struct EGL_IMAGE_T {
+   uint64_t pid;
+
+   /*
+    * Handle to a KHRN_IMAGE_T, whose format is required to be something
+    * suitable for texturing directly from. If NULL, then use external.convert
+    * below to make one (in glBindTexture_impl probably).
+    */
+   MEM_HANDLE_T mh_image;
+
+   bool flip_y;
+
+   /*
+    * Any kind of "external" image-- i.e. that can't be used directly for
+    * texturing.
+    */
+   struct
+   {
+      /*
+       * Handle to an object that convert knows how to convert into a
+       * KHRN_IMAGE_T suitable for texturing from, e.g. a multimedia image.
+       */
+      MEM_HANDLE_T src;
+      const IMAGE_CONVERT_CLASS_T *convert;
+      KHRN_IMAGE_FORMAT_T conv_khrn_format;
+      VC_IMAGE_TYPE_T conv_vc_format;
+      uint32_t src_updated;
+      uint32_t src_converted;
+   } external;
+
+} EGL_IMAGE_T;
+
+extern void egl_image_term(void *v, uint32_t size);
diff --git a/middleware/khronos/vg/2708/vg_config_filler_4.h b/middleware/khronos/vg/2708/vg_config_filler_4.h
new file mode 100755 (executable)
index 0000000..045360b
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VG_CONFIG_FILLER_4_H
+#define VG_CONFIG_FILLER_4_H
+
+#define VG_CONFIG_RENDERER "VideoCore IV HW"
+
+#endif
diff --git a/middleware/khronos/vg/vg_image.h b/middleware/khronos/vg/vg_image.h
new file mode 100755 (executable)
index 0000000..e8fb0d7
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VG_IMAGE_H
+#define VG_IMAGE_H
+
+#include "middleware/khronos/common/khrn_image.h"
+#include "middleware/khronos/common/khrn_mem.h"
+#include "interface/khronos/include/VG/openvg.h"
+
+/******************************************************************************
+image
+******************************************************************************/
+
+typedef struct {
+   VGImageFormat format;
+   uint32_t allowed_quality;
+   int32_t width;
+   int32_t height;
+} VG_IMAGE_BPRINT_T;
+
+extern void vg_image_bprint_from_stem(
+   MEM_HANDLE_T handle,
+   VGImageFormat format,
+   uint32_t allowed_quality,
+   int32_t width, int32_t height);
+
+extern void vg_image_bprint_term(void *, uint32_t);
+
+static INLINE bool vg_is_image_bprint(MEM_HANDLE_T handle)
+{
+   return mem_get_term(handle) == vg_image_bprint_term;
+}
+
+typedef struct {
+   uint32_t allowed_quality;
+
+   MEM_HANDLE_T image; /* KHRN_IMAGE_T */
+   uint32_t image_width;
+   uint32_t image_height;
+   KHRN_IMAGE_FORMAT_T image_format;
+} VG_IMAGE_T;
+
+extern bool vg_image_from_bprint(MEM_HANDLE_T handle);
+extern VGImageFormat vg_image_get_external_format(KHRN_IMAGE_FORMAT_T format); /* (VGImageFormat)-1 if internal format isn't permitted */
+extern MEM_HANDLE_T vg_image_alloc_from_image(MEM_HANDLE_T src_handle);
+extern void vg_image_from_stem_and_image(MEM_HANDLE_T handle, MEM_HANDLE_T src_handle);
+
+extern void vg_image_term(void *, uint32_t);
+
+static INLINE bool vg_is_image(MEM_HANDLE_T handle)
+{
+   return mem_get_term(handle) == vg_image_term;
+}
+
+extern VG_IMAGE_T *vg_image_lock_adam(
+   uint32_t *x, uint32_t *y, uint32_t *width, uint32_t *height,
+   MEM_HANDLE_T *handle);
+
+static INLINE bool vg_image_share_storage(VG_IMAGE_T *image, VG_IMAGE_T *other)
+{
+   return image->image == other->image;
+}
+
+extern bool vg_image_leak(VG_IMAGE_T *image);
+
+/******************************************************************************
+child image
+******************************************************************************/
+
+/*
+   the same structure is used for both blueprints and instantiated child images
+
+   in the blueprint case, parent is either a VG_IMAGE_T, a VG_IMAGE_BPRINT_T, or
+   a VG_CHILD_IMAGE_T (of either type)
+
+   in the instantiated case, parent is either a VG_IMAGE_T or an
+   instantiated-type VG_CHILD_IMAGE_T
+*/
+
+typedef struct {
+   MEM_HANDLE_T parent;
+   uint16_t x, y, width, height;
+} VG_CHILD_IMAGE_T;
+
+extern void vg_child_image_bprint_from_stem(
+   MEM_HANDLE_T handle,
+   MEM_HANDLE_T parent_handle,
+   int32_t x, int32_t y,
+   int32_t width, int32_t height);
+
+extern void vg_child_image_bprint_term(void *, uint32_t);
+
+static INLINE bool vg_is_child_image_bprint(MEM_HANDLE_T handle)
+{
+   return mem_get_term(handle) == vg_child_image_bprint_term;
+}
+
+extern bool vg_child_image_from_bprint(MEM_HANDLE_T handle);
+
+extern void vg_child_image_term(void *, uint32_t);
+
+static INLINE bool vg_is_child_image(MEM_HANDLE_T handle)
+{
+   return mem_get_term(handle) == vg_child_image_term;
+}
+
+#endif
diff --git a/middleware/khronos/wf/wfc_server_stream.h b/middleware/khronos/wf/wfc_server_stream.h
new file mode 100755 (executable)
index 0000000..727b575
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef WFC_SERVER_STREAM_H
+#define WFC_SERVER_STREAM_H
+
+#include "interface/khronos/include/WF/wfc.h"
+#include "interface/khronos/wf/wfc_int.h"
+#include "helpers/vc_image/vc_image.h"
+#include "interface/khronos/common/khrn_int_common.h"
+#include "interface/khronos/include/EGL/eglext.h"
+
+#ifdef ANDROID
+// Special SurfaceFlinger stream ID (cf SF_DISPMANX_ID in khrn_client_platform_android.c)
+#define SF_STREAM_ID 0x2000000F
+#endif
+
+#define WFC_QUEUE_OK                   0
+#define WFC_QUEUE_NO_IMAGE             (1 << 0)
+#define WFC_QUEUE_WRONG_DIMENSIONS     (1 << 1)
+#define WFC_QUEUE_WRONG_PIXEL_FORMAT   (1 << 2)
+#define WFC_QUEUE_NO_ASSOC_ELEMENT     (1 << 3)
+#define WFC_QUEUE_STREAM_PLACEHOLDER   (1 << 4)
+#define WFC_QUEUE_BUSY                 (1 << 5)
+#define WFC_QUEUE_NOT_REGISTERED       (1 << 6)
+#define WFC_QUEUE_NO_MEMORY            (1 << 7)
+
+/** Set the given buffer to be the new front buffer for the stream.
+ *
+ * If the vc_image is NULL, it means that there is no front buffer for the stream,
+ * and NULL will be returned when the front buffer is requested. The callback function
+ * shall not be called in this situation.
+ *
+ * If the callback function is not NULL, it shall either be called when the buffer
+ * is no longer in use (either as the current front buffer, or because it is part of a
+ * current composition), or when it has been used in composition, according to whether
+ * the WFC_IMAGE_CB_ON_COMPOSE flag is set.
+ *
+ * @param stream The client handle for the stream.
+ * @param vc_image Details of the new buffer, or NULL.
+ * @param flags Flags associated with the new buffer, combination of WFC_IMAGE_FLAGS_T
+ * values.
+ * @param cb_func Function to call when either the buffer is no longer in use or
+ * has been used in composition, or NULL.
+ * @param cb_data Data to be passed to the callback function, or NULL.
+ * @return TBD
+ */
+uint32_t wfc_server_stream_set_front_image(
+      WFCNativeStreamType stream, const VC_IMAGE_T *vc_image, int flags,
+      WFC_SERVER_STREAM_CALLBACK_T cb_func, void *cb_data);
+
+/** Signal to client that images are available for writing to. For use when
+ * renderer is allocating its images.
+ *
+ * @param stream The client handle for the stream.
+ * @param num_of_images The number of images allocated by the renderer.
+ */
+void wfc_server_stream_signal_images_avail(WFCNativeStreamType stream, uint32_t num_of_images);
+
+// Request update to destination and/or source rectangles. Sends request to host
+// for executing via WF-C.
+void wfc_server_stream_update_rects(WFCNativeStreamType stream,
+   const VC_RECT_T *vc_dest_rect, const VC_RECT_T *vc_src_rect);
+
+//------------------------------------------------------------------------------
+// Functions called only by Khronos dispatcher
+
+bool wfc_server_stream_is_empty(void);
+
+#endif /* WFC_SERVER_STREAM_H_ */
+
diff --git a/middleware/openmaxil/CMakeLists.txt b/middleware/openmaxil/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..3e9c5f9
--- /dev/null
@@ -0,0 +1,52 @@
+# =============================================================================
+# Copyright (c) 2012 Broadcom Europe Limited.
+# All rights reserved.
+#
+# FILE DESCRIPTION
+# CMake build file for OpenMAX IL.
+# =============================================================================
+
+cmake_minimum_required (VERSION 2.8)
+
+if (VIDEOCORE_SIMULATION)
+
+   # VC-simulation build.
+
+   add_library (openmaxil SHARED
+ #               core/ilcore.c
+                core/ril_top.c
+                core/ilmalloc.c
+                core/ilvlls.c
+                core/ilfifo.c
+                core/ilutil.c)
+
+   add_subdirectory (components)
+
+else ()
+
+   # Host build.
+   #
+   # Provides a host OpenMAX IL core as well as access to OpenMAX IL core and
+   # components running on Videocore with the help of the ILCS library.
+   #
+   # Ideally, we would want the native 64-bit OMX_TICKS datatype but on
+   # Videocore, structures are word-aligned, even if they have 64-bit members.
+   #
+   #    remove_definitions(-DOMX_SKIP64BIT)
+
+   add_definitions (-DVLL_PATH_PREFIX="${VMCS_PLUGIN_DIR}/")
+
+   add_library (openmaxil SHARED 
+                ../../host_applications/framework/common/ilcore.c
+#                core/ilcore.c
+#                core/ril_top.c
+#                core/ilmalloc.c
+#                core/ilvlls.c
+#                core/ilfifo.c
+                )
+
+   target_link_libraries (openmaxil vcilcs vcos dl)
+
+endif ()
+
+install (TARGETS openmaxil DESTINATION lib)
diff --git a/opensrc/helpers/libfdt/CMakeLists.txt b/opensrc/helpers/libfdt/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..f57c61c
--- /dev/null
@@ -0,0 +1,13 @@
+include_directories(.)
+
+add_library(fdt
+            fdt.c 
+            fdt_empty_tree.c
+            fdt_ro.c
+            fdt_rw.c
+            fdt_sw.c
+            fdt_strerror.c
+            fdt_wip.c)
+
+INSTALL(FILES)
+
diff --git a/opensrc/helpers/libfdt/fdt.c b/opensrc/helpers/libfdt/fdt.c
new file mode 100755 (executable)
index 0000000..22286a1
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_check_header(const void *fdt)
+{
+       if (fdt_magic(fdt) == FDT_MAGIC) {
+               /* Complete tree */
+               if (fdt_version(fdt) < FDT_FIRST_SUPPORTED_VERSION)
+                       return -FDT_ERR_BADVERSION;
+               if (fdt_last_comp_version(fdt) > FDT_LAST_SUPPORTED_VERSION)
+                       return -FDT_ERR_BADVERSION;
+       } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
+               /* Unfinished sequential-write blob */
+               if (fdt_size_dt_struct(fdt) == 0)
+                       return -FDT_ERR_BADSTATE;
+       } else {
+               return -FDT_ERR_BADMAGIC;
+       }
+
+       return 0;
+}
+
+const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int len)
+{
+       unsigned absoffset = offset + fdt_off_dt_struct(fdt);
+
+       if ((absoffset < offset)
+           || ((absoffset + len) < absoffset)
+           || (absoffset + len) > fdt_totalsize(fdt))
+               return NULL;
+
+       if (fdt_version(fdt) >= 0x11)
+               if (((offset + len) < offset)
+                   || ((offset + len) > fdt_size_dt_struct(fdt)))
+                       return NULL;
+
+       return _fdt_offset_ptr(fdt, offset);
+}
+
+uint32_t fdt_next_tag(const void *fdt, int startoffset, int *nextoffset)
+{
+       const fdt32_t *tagp, *lenp;
+       uint32_t tag;
+       int offset = startoffset;
+       const char *p;
+
+       *nextoffset = -FDT_ERR_TRUNCATED;
+       tagp = fdt_offset_ptr(fdt, offset, FDT_TAGSIZE);
+       if (!tagp)
+               return FDT_END; /* premature end */
+       tag = fdt32_to_cpu(*tagp);
+       offset += FDT_TAGSIZE;
+
+       *nextoffset = -FDT_ERR_BADSTRUCTURE;
+       switch (tag) {
+       case FDT_BEGIN_NODE:
+               /* skip name */
+               do {
+                       p = fdt_offset_ptr(fdt, offset++, 1);
+               } while (p && (*p != '\0'));
+               if (!p)
+                       return FDT_END; /* premature end */
+               break;
+
+       case FDT_PROP:
+               lenp = fdt_offset_ptr(fdt, offset, sizeof(*lenp));
+               if (!lenp)
+                       return FDT_END; /* premature end */
+               /* skip-name offset, length and value */
+               offset += sizeof(struct fdt_property) - FDT_TAGSIZE
+                       + fdt32_to_cpu(*lenp);
+               break;
+
+       case FDT_END:
+       case FDT_END_NODE:
+       case FDT_NOP:
+               break;
+
+       default:
+               return FDT_END;
+       }
+
+       if (!fdt_offset_ptr(fdt, startoffset, offset - startoffset))
+               return FDT_END; /* premature end */
+
+       *nextoffset = FDT_TAGALIGN(offset);
+       return tag;
+}
+
+int _fdt_check_node_offset(const void *fdt, int offset)
+{
+       if ((offset < 0) || (offset % FDT_TAGSIZE)
+           || (fdt_next_tag(fdt, offset, &offset) != FDT_BEGIN_NODE))
+               return -FDT_ERR_BADOFFSET;
+
+       return offset;
+}
+
+int _fdt_check_prop_offset(const void *fdt, int offset)
+{
+       if ((offset < 0) || (offset % FDT_TAGSIZE)
+           || (fdt_next_tag(fdt, offset, &offset) != FDT_PROP))
+               return -FDT_ERR_BADOFFSET;
+
+       return offset;
+}
+
+int fdt_next_node(const void *fdt, int offset, int *depth)
+{
+       int nextoffset = 0;
+       uint32_t tag;
+
+       if (offset >= 0)
+               if ((nextoffset = _fdt_check_node_offset(fdt, offset)) < 0)
+                       return nextoffset;
+
+       do {
+               offset = nextoffset;
+               tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+               switch (tag) {
+               case FDT_PROP:
+               case FDT_NOP:
+                       break;
+
+               case FDT_BEGIN_NODE:
+                       if (depth)
+                               (*depth)++;
+                       break;
+
+               case FDT_END_NODE:
+                       if (depth && ((--(*depth)) < 0))
+                               return nextoffset;
+                       break;
+
+               case FDT_END:
+                       if ((nextoffset >= 0)
+                           || ((nextoffset == -FDT_ERR_TRUNCATED) && !depth))
+                               return -FDT_ERR_NOTFOUND;
+                       else
+                               return nextoffset;
+               }
+       } while (tag != FDT_BEGIN_NODE);
+
+       return offset;
+}
+
+int fdt_first_subnode(const void *fdt, int offset)
+{
+       int depth = 0;
+
+       offset = fdt_next_node(fdt, offset, &depth);
+       if (offset < 0 || depth != 1)
+               return -FDT_ERR_NOTFOUND;
+
+       return offset;
+}
+
+int fdt_next_subnode(const void *fdt, int offset)
+{
+       int depth = 1;
+
+       /*
+        * With respect to the parent, the depth of the next subnode will be
+        * the same as the last.
+        */
+       do {
+               offset = fdt_next_node(fdt, offset, &depth);
+               if (offset < 0 || depth < 1)
+                       return -FDT_ERR_NOTFOUND;
+       } while (depth > 1);
+
+       return offset;
+}
+
+const char *_fdt_find_string(const char *strtab, int tabsize, const char *s)
+{
+       int len = strlen(s) + 1;
+       const char *last = strtab + tabsize - len;
+       const char *p;
+
+       for (p = strtab; p <= last; p++)
+               if (memcmp(p, s, len) == 0)
+                       return p;
+       return NULL;
+}
+
+int fdt_move(const void *fdt, void *buf, int bufsize)
+{
+       FDT_CHECK_HEADER(fdt);
+
+       if (fdt_totalsize(fdt) > bufsize)
+               return -FDT_ERR_NOSPACE;
+
+       memmove(buf, fdt, fdt_totalsize(fdt));
+       return 0;
+}
diff --git a/opensrc/helpers/libfdt/fdt.h b/opensrc/helpers/libfdt/fdt.h
new file mode 100755 (executable)
index 0000000..526aedb
--- /dev/null
@@ -0,0 +1,111 @@
+#ifndef _FDT_H
+#define _FDT_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ * Copyright 2012 Kim Phillips, Freescale Semiconductor.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __ASSEMBLY__
+
+struct fdt_header {
+       fdt32_t magic;                   /* magic word FDT_MAGIC */
+       fdt32_t totalsize;               /* total size of DT block */
+       fdt32_t off_dt_struct;           /* offset to structure */
+       fdt32_t off_dt_strings;          /* offset to strings */
+       fdt32_t off_mem_rsvmap;          /* offset to memory reserve map */
+       fdt32_t version;                 /* format version */
+       fdt32_t last_comp_version;       /* last compatible version */
+
+       /* version 2 fields below */
+       fdt32_t boot_cpuid_phys;         /* Which physical CPU id we're
+                                           booting on */
+       /* version 3 fields below */
+       fdt32_t size_dt_strings;         /* size of the strings block */
+
+       /* version 17 fields below */
+       fdt32_t size_dt_struct;          /* size of the structure block */
+};
+
+struct fdt_reserve_entry {
+       fdt64_t address;
+       fdt64_t size;
+};
+
+struct fdt_node_header {
+       fdt32_t tag;
+       char name[0];
+};
+
+struct fdt_property {
+       fdt32_t tag;
+       fdt32_t len;
+       fdt32_t nameoff;
+       char data[0];
+};
+
+#endif /* !__ASSEMBLY */
+
+#define FDT_MAGIC      0xd00dfeed      /* 4: version, 4: total size */
+#define FDT_TAGSIZE    sizeof(fdt32_t)
+
+#define FDT_BEGIN_NODE 0x1             /* Start node: full name */
+#define FDT_END_NODE   0x2             /* End node */
+#define FDT_PROP       0x3             /* Property: name off,
+                                          size, content */
+#define FDT_NOP                0x4             /* nop */
+#define FDT_END                0x9
+
+#define FDT_V1_SIZE    (7*sizeof(fdt32_t))
+#define FDT_V2_SIZE    (FDT_V1_SIZE + sizeof(fdt32_t))
+#define FDT_V3_SIZE    (FDT_V2_SIZE + sizeof(fdt32_t))
+#define FDT_V16_SIZE   FDT_V3_SIZE
+#define FDT_V17_SIZE   (FDT_V16_SIZE + sizeof(fdt32_t))
+
+#endif /* _FDT_H */
diff --git a/opensrc/helpers/libfdt/fdt_empty_tree.c b/opensrc/helpers/libfdt/fdt_empty_tree.c
new file mode 100755 (executable)
index 0000000..f72d13b
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2012 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_create_empty_tree(void *buf, int bufsize)
+{
+       int err;
+
+       err = fdt_create(buf, bufsize);
+       if (err)
+               return err;
+
+       err = fdt_finish_reservemap(buf);
+       if (err)
+               return err;
+
+       err = fdt_begin_node(buf, "");
+       if (err)
+               return err;
+
+       err =  fdt_end_node(buf);
+       if (err)
+               return err;
+
+       err = fdt_finish(buf);
+       if (err)
+               return err;
+
+       return fdt_open_into(buf, buf, bufsize);
+}
+
diff --git a/opensrc/helpers/libfdt/fdt_ro.c b/opensrc/helpers/libfdt/fdt_ro.c
new file mode 100755 (executable)
index 0000000..5f59f72
--- /dev/null
@@ -0,0 +1,679 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int _fdt_nodename_eq(const void *fdt, int offset,
+                           const char *s, int len)
+{
+       const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
+
+       if (! p)
+               /* short match */
+               return 0;
+
+       if (memcmp(p, s, len) != 0)
+               return 0;
+
+       if (p[len] == '\0')
+               return 1;
+       else if (!memchr(s, '@', len) && (p[len] == '@'))
+               return 1;
+       else
+               return 0;
+}
+
+const char *fdt_string(const void *fdt, int stroffset)
+{
+       return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
+}
+
+static int _fdt_string_eq(const void *fdt, int stroffset,
+                         const char *s, int len)
+{
+       const char *p = fdt_string(fdt, stroffset);
+
+       return (strlen(p) == len) && (memcmp(p, s, len) == 0);
+}
+
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
+{
+       FDT_CHECK_HEADER(fdt);
+       *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
+       *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
+       return 0;
+}
+
+int fdt_num_mem_rsv(const void *fdt)
+{
+       int i = 0;
+
+       while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
+               i++;
+       return i;
+}
+
+static int _nextprop(const void *fdt, int offset)
+{
+       uint32_t tag;
+       int nextoffset;
+
+       do {
+               tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+               switch (tag) {
+               case FDT_END:
+                       if (nextoffset >= 0)
+                               return -FDT_ERR_BADSTRUCTURE;
+                       else
+                               return nextoffset;
+
+               case FDT_PROP:
+                       return offset;
+               }
+               offset = nextoffset;
+       } while (tag == FDT_NOP);
+
+       return -FDT_ERR_NOTFOUND;
+}
+
+int fdt_subnode_offset_namelen(const void *fdt, int offset,
+                              const char *name, int namelen)
+{
+       int depth;
+
+       FDT_CHECK_HEADER(fdt);
+
+       for (depth = 0;
+            (offset >= 0) && (depth >= 0);
+            offset = fdt_next_node(fdt, offset, &depth))
+               if ((depth == 1)
+                   && _fdt_nodename_eq(fdt, offset, name, namelen))
+                       return offset;
+
+       if (depth < 0)
+               return -FDT_ERR_NOTFOUND;
+       return offset; /* error */
+}
+
+int fdt_subnode_offset(const void *fdt, int parentoffset,
+                      const char *name)
+{
+       return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
+{
+       const char *end = path + namelen;
+       const char *p = path;
+       int offset = 0;
+
+       FDT_CHECK_HEADER(fdt);
+
+       /* see if we have an alias */
+       if (*path != '/') {
+               const char *q = memchr(path, '/', end - p);
+
+               if (!q)
+                       q = end;
+
+               p = fdt_get_alias_namelen(fdt, p, q - p);
+               if (!p)
+                       return -FDT_ERR_BADPATH;
+               offset = fdt_path_offset(fdt, p);
+
+               p = q;
+       }
+
+       while (p < end) {
+               const char *q;
+
+               while (*p == '/') {
+                       p++;
+                       if (p == end)
+                               return offset;
+               }
+               q = memchr(p, '/', end - p);
+               if (! q)
+                       q = end;
+
+               offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
+               if (offset < 0)
+                       return offset;
+
+               p = q;
+       }
+
+       return offset;
+}
+
+int fdt_path_offset(const void *fdt, const char *path)
+{
+       return fdt_path_offset_namelen(fdt, path, strlen(path));
+}
+
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
+{
+       const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
+       int err;
+
+       if (((err = fdt_check_header(fdt)) != 0)
+           || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
+                       goto fail;
+
+       if (len)
+               *len = strlen(nh->name);
+
+       return nh->name;
+
+ fail:
+       if (len)
+               *len = err;
+       return NULL;
+}
+
+int fdt_first_property_offset(const void *fdt, int nodeoffset)
+{
+       int offset;
+
+       if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
+               return offset;
+
+       return _nextprop(fdt, offset);
+}
+
+int fdt_next_property_offset(const void *fdt, int offset)
+{
+       if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0)
+               return offset;
+
+       return _nextprop(fdt, offset);
+}
+
+const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
+                                                     int offset,
+                                                     int *lenp)
+{
+       int err;
+       const struct fdt_property *prop;
+
+       if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) {
+               if (lenp)
+                       *lenp = err;
+               return NULL;
+       }
+
+       prop = _fdt_offset_ptr(fdt, offset);
+
+       if (lenp)
+               *lenp = fdt32_to_cpu(prop->len);
+
+       return prop;
+}
+
+const struct fdt_property *fdt_get_property_namelen(const void *fdt,
+                                                   int offset,
+                                                   const char *name,
+                                                   int namelen, int *lenp)
+{
+       for (offset = fdt_first_property_offset(fdt, offset);
+            (offset >= 0);
+            (offset = fdt_next_property_offset(fdt, offset))) {
+               const struct fdt_property *prop;
+
+               if ((prop = fdt_get_property_by_offset(fdt, offset, lenp)) == 0) {
+                       offset = -FDT_ERR_INTERNAL;
+                       break;
+               }
+               if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
+                                  name, namelen))
+                       return prop;
+       }
+
+       if (lenp)
+               *lenp = offset;
+       return NULL;
+}
+
+const struct fdt_property *fdt_get_property(const void *fdt,
+                                           int nodeoffset,
+                                           const char *name, int *lenp)
+{
+       return fdt_get_property_namelen(fdt, nodeoffset, name,
+                                       strlen(name), lenp);
+}
+
+const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
+                               const char *name, int namelen, int *lenp)
+{
+       const struct fdt_property *prop;
+
+       prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
+       if (! prop)
+               return NULL;
+
+       return prop->data;
+}
+
+const void *fdt_getprop_by_offset(const void *fdt, int offset,
+                                 const char **namep, int *lenp)
+{
+       const struct fdt_property *prop;
+
+       prop = fdt_get_property_by_offset(fdt, offset, lenp);
+       if (!prop)
+               return NULL;
+       if (namep)
+               *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
+       return prop->data;
+}
+
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+                       const char *name, int *lenp)
+{
+       return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
+}
+
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
+{
+       const fdt32_t *php;
+       int len;
+
+       /* FIXME: This is a bit sub-optimal, since we potentially scan
+        * over all the properties twice. */
+       php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
+       if (!php || (len != sizeof(*php))) {
+               php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
+               if (!php || (len != sizeof(*php)))
+                       return 0;
+       }
+
+       return fdt32_to_cpu(*php);
+}
+
+const char *fdt_get_alias_namelen(const void *fdt,
+                                 const char *name, int namelen)
+{
+       int aliasoffset;
+
+       aliasoffset = fdt_path_offset(fdt, "/aliases");
+       if (aliasoffset < 0)
+               return NULL;
+
+       return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
+}
+
+const char *fdt_get_alias(const void *fdt, const char *name)
+{
+       return fdt_get_alias_namelen(fdt, name, strlen(name));
+}
+
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
+{
+       int pdepth = 0, p = 0;
+       int offset, depth, namelen;
+       const char *name;
+
+       FDT_CHECK_HEADER(fdt);
+
+       if (buflen < 2)
+               return -FDT_ERR_NOSPACE;
+
+       for (offset = 0, depth = 0;
+            (offset >= 0) && (offset <= nodeoffset);
+            offset = fdt_next_node(fdt, offset, &depth)) {
+               while (pdepth > depth) {
+                       do {
+                               p--;
+                       } while (buf[p-1] != '/');
+                       pdepth--;
+               }
+
+               if (pdepth >= depth) {
+                       name = fdt_get_name(fdt, offset, &namelen);
+                       if (!name)
+                               return namelen;
+                       if ((p + namelen + 1) <= buflen) {
+                               memcpy(buf + p, name, namelen);
+                               p += namelen;
+                               buf[p++] = '/';
+                               pdepth++;
+                       }
+               }
+
+               if (offset == nodeoffset) {
+                       if (pdepth < (depth + 1))
+                               return -FDT_ERR_NOSPACE;
+
+                       if (p > 1) /* special case so that root path is "/", not "" */
+                               p--;
+                       buf[p] = '\0';
+                       return 0;
+               }
+       }
+
+       if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+               return -FDT_ERR_BADOFFSET;
+       else if (offset == -FDT_ERR_BADOFFSET)
+               return -FDT_ERR_BADSTRUCTURE;
+
+       return offset; /* error from fdt_next_node() */
+}
+
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+                                int supernodedepth, int *nodedepth)
+{
+       int offset, depth;
+       int supernodeoffset = -FDT_ERR_INTERNAL;
+
+       FDT_CHECK_HEADER(fdt);
+
+       if (supernodedepth < 0)
+               return -FDT_ERR_NOTFOUND;
+
+       for (offset = 0, depth = 0;
+            (offset >= 0) && (offset <= nodeoffset);
+            offset = fdt_next_node(fdt, offset, &depth)) {
+               if (depth == supernodedepth)
+                       supernodeoffset = offset;
+
+               if (offset == nodeoffset) {
+                       if (nodedepth)
+                               *nodedepth = depth;
+
+                       if (supernodedepth > depth)
+                               return -FDT_ERR_NOTFOUND;
+                       else
+                               return supernodeoffset;
+               }
+       }
+
+       if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+               return -FDT_ERR_BADOFFSET;
+       else if (offset == -FDT_ERR_BADOFFSET)
+               return -FDT_ERR_BADSTRUCTURE;
+
+       return offset; /* error from fdt_next_node() */
+}
+
+int fdt_node_depth(const void *fdt, int nodeoffset)
+{
+       int nodedepth;
+       int err;
+
+       err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
+       if (err)
+               return (err < 0) ? err : -FDT_ERR_INTERNAL;
+       return nodedepth;
+}
+
+int fdt_parent_offset(const void *fdt, int nodeoffset)
+{
+       int nodedepth = fdt_node_depth(fdt, nodeoffset);
+
+       if (nodedepth < 0)
+               return nodedepth;
+       return fdt_supernode_atdepth_offset(fdt, nodeoffset,
+                                           nodedepth - 1, NULL);
+}
+
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+                                 const char *propname,
+                                 const void *propval, int proplen)
+{
+       int offset;
+       const void *val;
+       int len;
+
+       FDT_CHECK_HEADER(fdt);
+
+       /* FIXME: The algorithm here is pretty horrible: we scan each
+        * property of a node in fdt_getprop(), then if that didn't
+        * find what we want, we scan over them again making our way
+        * to the next node.  Still it's the easiest to implement
+        * approach; performance can come later. */
+       for (offset = fdt_next_node(fdt, startoffset, NULL);
+            offset >= 0;
+            offset = fdt_next_node(fdt, offset, NULL)) {
+               val = fdt_getprop(fdt, offset, propname, &len);
+               if (val && (len == proplen)
+                   && (memcmp(val, propval, len) == 0))
+                       return offset;
+       }
+
+       return offset; /* error from fdt_next_node() */
+}
+
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
+{
+       int offset;
+
+       if ((phandle == 0) || (phandle == -1))
+               return -FDT_ERR_BADPHANDLE;
+
+       FDT_CHECK_HEADER(fdt);
+
+       /* FIXME: The algorithm here is pretty horrible: we
+        * potentially scan each property of a node in
+        * fdt_get_phandle(), then if that didn't find what
+        * we want, we scan over them again making our way to the next
+        * node.  Still it's the easiest to implement approach;
+        * performance can come later. */
+       for (offset = fdt_next_node(fdt, -1, NULL);
+            offset >= 0;
+            offset = fdt_next_node(fdt, offset, NULL)) {
+               if (fdt_get_phandle(fdt, offset) == phandle)
+                       return offset;
+       }
+
+       return offset; /* error from fdt_next_node() */
+}
+
+int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
+{
+       int len = strlen(str);
+       const char *p;
+
+       while (listlen >= len) {
+               if (memcmp(str, strlist, len+1) == 0)
+                       return 1;
+               p = memchr(strlist, '\0', listlen);
+               if (!p)
+                       return 0; /* malformed strlist.. */
+               listlen -= (p-strlist) + 1;
+               strlist = p + 1;
+       }
+       return 0;
+}
+
+int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
+{
+       const char *list, *end;
+       int length, count = 0;
+
+       list = fdt_getprop(fdt, nodeoffset, property, &length);
+       if (!list)
+               return -length;
+
+       end = list + length;
+
+       while (list < end) {
+               length = strnlen(list, end - list) + 1;
+
+               /* Abort if the last string isn't properly NUL-terminated. */
+               if (list + length > end)
+                       return -FDT_ERR_BADVALUE;
+
+               list += length;
+               count++;
+       }
+
+       return count;
+}
+
+int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
+                         const char *string)
+{
+       int length, len, idx = 0;
+       const char *list, *end;
+
+       list = fdt_getprop(fdt, nodeoffset, property, &length);
+       if (!list)
+               return -length;
+
+       len = strlen(string) + 1;
+       end = list + length;
+
+       while (list < end) {
+               length = strnlen(list, end - list) + 1;
+
+               /* Abort if the last string isn't properly NUL-terminated. */
+               if (list + length > end)
+                       return -FDT_ERR_BADVALUE;
+
+               if (length == len && memcmp(list, string, length) == 0)
+                       return idx;
+
+               list += length;
+               idx++;
+       }
+
+       return -FDT_ERR_NOTFOUND;
+}
+
+const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
+                              const char *property, int idx,
+                              int *lenp)
+{
+       const char *list, *end;
+       int length;
+
+       list = fdt_getprop(fdt, nodeoffset, property, &length);
+       if (!list) {
+               if (lenp)
+                       *lenp = length;
+
+               return NULL;
+       }
+
+       end = list + length;
+
+       while (list < end) {
+               length = strnlen(list, end - list) + 1;
+
+               /* Abort if the last string isn't properly NUL-terminated. */
+               if (list + length > end) {
+                       if (lenp)
+                               *lenp = -FDT_ERR_BADVALUE;
+
+                       return NULL;
+               }
+
+               if (idx == 0) {
+                       if (lenp)
+                               *lenp = length - 1;
+
+                       return list;
+               }
+
+               list += length;
+               idx--;
+       }
+
+       if (lenp)
+               *lenp = -FDT_ERR_NOTFOUND;
+
+       return NULL;
+}
+
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+                             const char *compatible)
+{
+       const void *prop;
+       int len;
+
+       prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
+       if (!prop)
+               return len;
+       if (fdt_stringlist_contains(prop, len, compatible))
+               return 0;
+       else
+               return 1;
+}
+
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+                                 const char *compatible)
+{
+       int offset, err;
+
+       FDT_CHECK_HEADER(fdt);
+
+       /* FIXME: The algorithm here is pretty horrible: we scan each
+        * property of a node in fdt_node_check_compatible(), then if
+        * that didn't find what we want, we scan over them again
+        * making our way to the next node.  Still it's the easiest to
+        * implement approach; performance can come later. */
+       for (offset = fdt_next_node(fdt, startoffset, NULL);
+            offset >= 0;
+            offset = fdt_next_node(fdt, offset, NULL)) {
+               err = fdt_node_check_compatible(fdt, offset, compatible);
+               if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
+                       return err;
+               else if (err == 0)
+                       return offset;
+       }
+
+       return offset; /* error from fdt_next_node() */
+}
diff --git a/opensrc/helpers/libfdt/fdt_rw.c b/opensrc/helpers/libfdt/fdt_rw.c
new file mode 100755 (executable)
index 0000000..a41d356
--- /dev/null
@@ -0,0 +1,494 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int _fdt_blocks_misordered(const void *fdt,
+                             int mem_rsv_size, int struct_size)
+{
+       return (fdt_off_mem_rsvmap(fdt) < FDT_ALIGN(sizeof(struct fdt_header), 8))
+               || (fdt_off_dt_struct(fdt) <
+                   (fdt_off_mem_rsvmap(fdt) + mem_rsv_size))
+               || (fdt_off_dt_strings(fdt) <
+                   (fdt_off_dt_struct(fdt) + struct_size))
+               || (fdt_totalsize(fdt) <
+                   (fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt)));
+}
+
+static int _fdt_rw_check_header(void *fdt)
+{
+       FDT_CHECK_HEADER(fdt);
+
+       if (fdt_version(fdt) < 17)
+               return -FDT_ERR_BADVERSION;
+       if (_fdt_blocks_misordered(fdt, sizeof(struct fdt_reserve_entry),
+                                  fdt_size_dt_struct(fdt)))
+               return -FDT_ERR_BADLAYOUT;
+       if (fdt_version(fdt) > 17)
+               fdt_set_version(fdt, 17);
+
+       return 0;
+}
+
+#define FDT_RW_CHECK_HEADER(fdt) \
+       { \
+               int __err; \
+               if ((__err = _fdt_rw_check_header(fdt)) != 0) \
+                       return __err; \
+       }
+
+static inline int _fdt_data_size(void *fdt)
+{
+       return fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+}
+
+static int _fdt_splice(void *fdt, void *splicepoint, int oldlen, int newlen)
+{
+       char *p = splicepoint;
+       char *end = (char *)fdt + _fdt_data_size(fdt);
+
+       if (((p + oldlen) < p) || ((p + oldlen) > end))
+               return -FDT_ERR_BADOFFSET;
+       if ((p < (char *)fdt) || ((end - oldlen + newlen) < (char *)fdt))
+               return -FDT_ERR_BADOFFSET;
+       if ((end - oldlen + newlen) > ((char *)fdt + fdt_totalsize(fdt)))
+               return -FDT_ERR_NOSPACE;
+       memmove(p + newlen, p + oldlen, end - p - oldlen);
+       return 0;
+}
+
+static int _fdt_splice_mem_rsv(void *fdt, struct fdt_reserve_entry *p,
+                              int oldn, int newn)
+{
+       int delta = (newn - oldn) * sizeof(*p);
+       int err;
+       err = _fdt_splice(fdt, p, oldn * sizeof(*p), newn * sizeof(*p));
+       if (err)
+               return err;
+       fdt_set_off_dt_struct(fdt, fdt_off_dt_struct(fdt) + delta);
+       fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+       return 0;
+}
+
+static int _fdt_splice_struct(void *fdt, void *p,
+                             int oldlen, int newlen)
+{
+       int delta = newlen - oldlen;
+       int err;
+
+       if ((err = _fdt_splice(fdt, p, oldlen, newlen)) != 0)
+               return err;
+
+       fdt_set_size_dt_struct(fdt, fdt_size_dt_struct(fdt) + delta);
+       fdt_set_off_dt_strings(fdt, fdt_off_dt_strings(fdt) + delta);
+       return 0;
+}
+
+static int _fdt_splice_string(void *fdt, int newlen)
+{
+       void *p = (char *)fdt
+               + fdt_off_dt_strings(fdt) + fdt_size_dt_strings(fdt);
+       int err;
+
+       if ((err = _fdt_splice(fdt, p, 0, newlen)) != 0)
+               return err;
+
+       fdt_set_size_dt_strings(fdt, fdt_size_dt_strings(fdt) + newlen);
+       return 0;
+}
+
+static int _fdt_find_add_string(void *fdt, const char *s)
+{
+       char *strtab = (char *)fdt + fdt_off_dt_strings(fdt);
+       const char *p;
+       char *new;
+       int len = strlen(s) + 1;
+       int err;
+
+       p = _fdt_find_string(strtab, fdt_size_dt_strings(fdt), s);
+       if (p)
+               /* found it */
+               return (p - strtab);
+
+       new = strtab + fdt_size_dt_strings(fdt);
+       err = _fdt_splice_string(fdt, len);
+       if (err)
+               return err;
+
+       memcpy(new, s, len);
+       return (new - strtab);
+}
+
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size)
+{
+       struct fdt_reserve_entry *re;
+       int err;
+
+       FDT_RW_CHECK_HEADER(fdt);
+
+       re = _fdt_mem_rsv_w(fdt, fdt_num_mem_rsv(fdt));
+       err = _fdt_splice_mem_rsv(fdt, re, 0, 1);
+       if (err)
+               return err;
+
+       re->address = cpu_to_fdt64(address);
+       re->size = cpu_to_fdt64(size);
+       return 0;
+}
+
+int fdt_del_mem_rsv(void *fdt, int n)
+{
+       struct fdt_reserve_entry *re = _fdt_mem_rsv_w(fdt, n);
+       int err;
+
+       FDT_RW_CHECK_HEADER(fdt);
+
+       if (n >= fdt_num_mem_rsv(fdt))
+               return -FDT_ERR_NOTFOUND;
+
+       err = _fdt_splice_mem_rsv(fdt, re, 1, 0);
+       if (err)
+               return err;
+       return 0;
+}
+
+static int _fdt_resize_property(void *fdt, int nodeoffset, const char *name,
+                               int len, struct fdt_property **prop)
+{
+       int oldlen;
+       int err;
+
+       *prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
+       if (! (*prop))
+               return oldlen;
+
+       if ((err = _fdt_splice_struct(fdt, (*prop)->data, FDT_TAGALIGN(oldlen),
+                                     FDT_TAGALIGN(len))) != 0)
+               return err;
+
+       (*prop)->len = cpu_to_fdt32(len);
+       return 0;
+}
+
+static int _fdt_add_property(void *fdt, int nodeoffset, const char *name,
+                            int len, struct fdt_property **prop)
+{
+       int proplen;
+       int nextoffset;
+       int namestroff;
+       int err;
+
+       if ((nextoffset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
+               return nextoffset;
+
+       namestroff = _fdt_find_add_string(fdt, name);
+       if (namestroff < 0)
+               return namestroff;
+
+       *prop = _fdt_offset_ptr_w(fdt, nextoffset);
+       proplen = sizeof(**prop) + FDT_TAGALIGN(len);
+
+       err = _fdt_splice_struct(fdt, *prop, 0, proplen);
+       if (err)
+               return err;
+
+       (*prop)->tag = cpu_to_fdt32(FDT_PROP);
+       (*prop)->nameoff = cpu_to_fdt32(namestroff);
+       (*prop)->len = cpu_to_fdt32(len);
+       return 0;
+}
+
+int fdt_set_name(void *fdt, int nodeoffset, const char *name)
+{
+       char *namep;
+       int oldlen, newlen;
+       int err;
+
+       FDT_RW_CHECK_HEADER(fdt);
+
+       namep = (char *)(uintptr_t)fdt_get_name(fdt, nodeoffset, &oldlen);
+       if (!namep)
+               return oldlen;
+
+       newlen = strlen(name);
+
+       err = _fdt_splice_struct(fdt, namep, FDT_TAGALIGN(oldlen+1),
+                                FDT_TAGALIGN(newlen+1));
+       if (err)
+               return err;
+
+       memcpy(namep, name, newlen+1);
+       return 0;
+}
+
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+               const void *val, int len)
+{
+       struct fdt_property *prop;
+       int err;
+
+       FDT_RW_CHECK_HEADER(fdt);
+
+       err = _fdt_resize_property(fdt, nodeoffset, name, len, &prop);
+       if (err == -FDT_ERR_NOTFOUND)
+               err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
+       if (err)
+               return err;
+
+       memcpy(prop->data, val, len);
+       return 0;
+}
+
+int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
+                  const void *val, int len)
+{
+       struct fdt_property *prop;
+       int err, oldlen, newlen;
+
+       FDT_RW_CHECK_HEADER(fdt);
+
+       prop = fdt_get_property_w(fdt, nodeoffset, name, &oldlen);
+       if (prop) {
+               newlen = len + oldlen;
+               err = _fdt_splice_struct(fdt, prop->data,
+                                        FDT_TAGALIGN(oldlen),
+                                        FDT_TAGALIGN(newlen));
+               if (err)
+                       return err;
+               prop->len = cpu_to_fdt32(newlen);
+               memcpy(prop->data + oldlen, val, len);
+       } else {
+               err = _fdt_add_property(fdt, nodeoffset, name, len, &prop);
+               if (err)
+                       return err;
+               memcpy(prop->data, val, len);
+       }
+       return 0;
+}
+
+int fdt_delprop(void *fdt, int nodeoffset, const char *name)
+{
+       struct fdt_property *prop;
+       int len, proplen;
+
+       FDT_RW_CHECK_HEADER(fdt);
+
+       prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+       if (! prop)
+               return len;
+
+       proplen = sizeof(*prop) + FDT_TAGALIGN(len);
+       return _fdt_splice_struct(fdt, prop, proplen, 0);
+}
+
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+                           const char *name, int namelen)
+{
+       struct fdt_node_header *nh;
+       int offset, nextoffset;
+       int nodelen;
+       int err;
+       uint32_t tag;
+       fdt32_t *endtag;
+
+       FDT_RW_CHECK_HEADER(fdt);
+
+       offset = fdt_subnode_offset_namelen(fdt, parentoffset, name, namelen);
+       if (offset >= 0)
+               return -FDT_ERR_EXISTS;
+       else if (offset != -FDT_ERR_NOTFOUND)
+               return offset;
+
+       /* Try to place the new node after the parent's properties */
+       fdt_next_tag(fdt, parentoffset, &nextoffset); /* skip the BEGIN_NODE */
+       do {
+               offset = nextoffset;
+               tag = fdt_next_tag(fdt, offset, &nextoffset);
+       } while ((tag == FDT_PROP) || (tag == FDT_NOP));
+
+       nh = _fdt_offset_ptr_w(fdt, offset);
+       nodelen = sizeof(*nh) + FDT_TAGALIGN(namelen+1) + FDT_TAGSIZE;
+
+       err = _fdt_splice_struct(fdt, nh, 0, nodelen);
+       if (err)
+               return err;
+
+       nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+       memset(nh->name, 0, FDT_TAGALIGN(namelen+1));
+       memcpy(nh->name, name, namelen);
+       endtag = (fdt32_t *)((char *)nh + nodelen - FDT_TAGSIZE);
+       *endtag = cpu_to_fdt32(FDT_END_NODE);
+
+       return offset;
+}
+
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
+{
+       return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
+}
+
+int fdt_del_node(void *fdt, int nodeoffset)
+{
+       int endoffset;
+
+       FDT_RW_CHECK_HEADER(fdt);
+
+       endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+       if (endoffset < 0)
+               return endoffset;
+
+       return _fdt_splice_struct(fdt, _fdt_offset_ptr_w(fdt, nodeoffset),
+                                 endoffset - nodeoffset, 0);
+}
+
+static void _fdt_packblocks(const char *old, char *new,
+                           int mem_rsv_size, int struct_size)
+{
+       int mem_rsv_off, struct_off, strings_off;
+
+       mem_rsv_off = FDT_ALIGN(sizeof(struct fdt_header), 8);
+       struct_off = mem_rsv_off + mem_rsv_size;
+       strings_off = struct_off + struct_size;
+
+       memmove(new + mem_rsv_off, old + fdt_off_mem_rsvmap(old), mem_rsv_size);
+       fdt_set_off_mem_rsvmap(new, mem_rsv_off);
+
+       memmove(new + struct_off, old + fdt_off_dt_struct(old), struct_size);
+       fdt_set_off_dt_struct(new, struct_off);
+       fdt_set_size_dt_struct(new, struct_size);
+
+       memmove(new + strings_off, old + fdt_off_dt_strings(old),
+               fdt_size_dt_strings(old));
+       fdt_set_off_dt_strings(new, strings_off);
+       fdt_set_size_dt_strings(new, fdt_size_dt_strings(old));
+}
+
+int fdt_open_into(const void *fdt, void *buf, int bufsize)
+{
+       int err;
+       int mem_rsv_size, struct_size;
+       int newsize;
+       const char *fdtstart = fdt;
+       const char *fdtend = fdtstart + fdt_totalsize(fdt);
+       char *tmp;
+
+       FDT_CHECK_HEADER(fdt);
+
+       mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+               * sizeof(struct fdt_reserve_entry);
+
+       if (fdt_version(fdt) >= 17) {
+               struct_size = fdt_size_dt_struct(fdt);
+       } else {
+               struct_size = 0;
+               while (fdt_next_tag(fdt, struct_size, &struct_size) != FDT_END)
+                       ;
+               if (struct_size < 0)
+                       return struct_size;
+       }
+
+       if (!_fdt_blocks_misordered(fdt, mem_rsv_size, struct_size)) {
+               /* no further work necessary */
+               err = fdt_move(fdt, buf, bufsize);
+               if (err)
+                       return err;
+               fdt_set_version(buf, 17);
+               fdt_set_size_dt_struct(buf, struct_size);
+               fdt_set_totalsize(buf, bufsize);
+               return 0;
+       }
+
+       /* Need to reorder */
+       newsize = FDT_ALIGN(sizeof(struct fdt_header), 8) + mem_rsv_size
+               + struct_size + fdt_size_dt_strings(fdt);
+
+       if (bufsize < newsize)
+               return -FDT_ERR_NOSPACE;
+
+       /* First attempt to build converted tree at beginning of buffer */
+       tmp = buf;
+       /* But if that overlaps with the old tree... */
+       if (((tmp + newsize) > fdtstart) && (tmp < fdtend)) {
+               /* Try right after the old tree instead */
+               tmp = (char *)(uintptr_t)fdtend;
+               if ((tmp + newsize) > ((char *)buf + bufsize))
+                       return -FDT_ERR_NOSPACE;
+       }
+
+       _fdt_packblocks(fdt, tmp, mem_rsv_size, struct_size);
+       memmove(buf, tmp, newsize);
+
+       fdt_set_magic(buf, FDT_MAGIC);
+       fdt_set_totalsize(buf, bufsize);
+       fdt_set_version(buf, 17);
+       fdt_set_last_comp_version(buf, 16);
+       fdt_set_boot_cpuid_phys(buf, fdt_boot_cpuid_phys(fdt));
+
+       return 0;
+}
+
+int fdt_pack(void *fdt)
+{
+       int mem_rsv_size;
+
+       FDT_RW_CHECK_HEADER(fdt);
+
+       mem_rsv_size = (fdt_num_mem_rsv(fdt)+1)
+               * sizeof(struct fdt_reserve_entry);
+       _fdt_packblocks(fdt, fdt, mem_rsv_size, fdt_size_dt_struct(fdt));
+       fdt_set_totalsize(fdt, _fdt_data_size(fdt));
+
+       return 0;
+}
diff --git a/opensrc/helpers/libfdt/fdt_strerror.c b/opensrc/helpers/libfdt/fdt_strerror.c
new file mode 100755 (executable)
index 0000000..e6c3cee
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+struct fdt_errtabent {
+       const char *str;
+};
+
+#define FDT_ERRTABENT(val) \
+       [(val)] = { .str = #val, }
+
+static struct fdt_errtabent fdt_errtable[] = {
+       FDT_ERRTABENT(FDT_ERR_NOTFOUND),
+       FDT_ERRTABENT(FDT_ERR_EXISTS),
+       FDT_ERRTABENT(FDT_ERR_NOSPACE),
+
+       FDT_ERRTABENT(FDT_ERR_BADOFFSET),
+       FDT_ERRTABENT(FDT_ERR_BADPATH),
+       FDT_ERRTABENT(FDT_ERR_BADSTATE),
+
+       FDT_ERRTABENT(FDT_ERR_TRUNCATED),
+       FDT_ERRTABENT(FDT_ERR_BADMAGIC),
+       FDT_ERRTABENT(FDT_ERR_BADVERSION),
+       FDT_ERRTABENT(FDT_ERR_BADSTRUCTURE),
+       FDT_ERRTABENT(FDT_ERR_BADLAYOUT),
+};
+#define FDT_ERRTABSIZE (sizeof(fdt_errtable) / sizeof(fdt_errtable[0]))
+
+const char *fdt_strerror(int errval)
+{
+       if (errval > 0)
+               return "<valid offset/length>";
+       else if (errval == 0)
+               return "<no error>";
+       else if (errval > -FDT_ERRTABSIZE) {
+               const char *s = fdt_errtable[-errval].str;
+
+               if (s)
+                       return s;
+       }
+
+       return "<unknown error>";
+}
diff --git a/opensrc/helpers/libfdt/fdt_sw.c b/opensrc/helpers/libfdt/fdt_sw.c
new file mode 100755 (executable)
index 0000000..ab504ee
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+static int _fdt_sw_check_header(void *fdt)
+{
+       if (fdt_magic(fdt) != FDT_SW_MAGIC)
+               return -FDT_ERR_BADMAGIC;
+       /* FIXME: should check more details about the header state */
+       return 0;
+}
+
+#define FDT_SW_CHECK_HEADER(fdt) \
+       { \
+               int err; \
+               if ((err = _fdt_sw_check_header(fdt)) != 0) \
+                       return err; \
+       }
+
+static void *_fdt_grab_space(void *fdt, size_t len)
+{
+       int offset = fdt_size_dt_struct(fdt);
+       int spaceleft;
+
+       spaceleft = fdt_totalsize(fdt) - fdt_off_dt_struct(fdt)
+               - fdt_size_dt_strings(fdt);
+
+       if ((offset + len < offset) || (offset + len > spaceleft))
+               return NULL;
+
+       fdt_set_size_dt_struct(fdt, offset + len);
+       return _fdt_offset_ptr_w(fdt, offset);
+}
+
+int fdt_create(void *buf, int bufsize)
+{
+       void *fdt = buf;
+
+       if (bufsize < sizeof(struct fdt_header))
+               return -FDT_ERR_NOSPACE;
+
+       memset(buf, 0, bufsize);
+
+       fdt_set_magic(fdt, FDT_SW_MAGIC);
+       fdt_set_version(fdt, FDT_LAST_SUPPORTED_VERSION);
+       fdt_set_last_comp_version(fdt, FDT_FIRST_SUPPORTED_VERSION);
+       fdt_set_totalsize(fdt,  bufsize);
+
+       fdt_set_off_mem_rsvmap(fdt, FDT_ALIGN(sizeof(struct fdt_header),
+                                             sizeof(struct fdt_reserve_entry)));
+       fdt_set_off_dt_struct(fdt, fdt_off_mem_rsvmap(fdt));
+       fdt_set_off_dt_strings(fdt, bufsize);
+
+       return 0;
+}
+
+int fdt_resize(void *fdt, void *buf, int bufsize)
+{
+       size_t headsize, tailsize;
+       char *oldtail, *newtail;
+
+       FDT_SW_CHECK_HEADER(fdt);
+
+       headsize = fdt_off_dt_struct(fdt);
+       tailsize = fdt_size_dt_strings(fdt);
+
+       if ((headsize + tailsize) > bufsize)
+               return -FDT_ERR_NOSPACE;
+
+       oldtail = (char *)fdt + fdt_totalsize(fdt) - tailsize;
+       newtail = (char *)buf + bufsize - tailsize;
+
+       /* Two cases to avoid clobbering data if the old and new
+        * buffers partially overlap */
+       if (buf <= fdt) {
+               memmove(buf, fdt, headsize);
+               memmove(newtail, oldtail, tailsize);
+       } else {
+               memmove(newtail, oldtail, tailsize);
+               memmove(buf, fdt, headsize);
+       }
+
+       fdt_set_off_dt_strings(buf, bufsize);
+       fdt_set_totalsize(buf, bufsize);
+
+       return 0;
+}
+
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size)
+{
+       struct fdt_reserve_entry *re;
+       int offset;
+
+       FDT_SW_CHECK_HEADER(fdt);
+
+       if (fdt_size_dt_struct(fdt))
+               return -FDT_ERR_BADSTATE;
+
+       offset = fdt_off_dt_struct(fdt);
+       if ((offset + sizeof(*re)) > fdt_totalsize(fdt))
+               return -FDT_ERR_NOSPACE;
+
+       re = (struct fdt_reserve_entry *)((char *)fdt + offset);
+       re->address = cpu_to_fdt64(addr);
+       re->size = cpu_to_fdt64(size);
+
+       fdt_set_off_dt_struct(fdt, offset + sizeof(*re));
+
+       return 0;
+}
+
+int fdt_finish_reservemap(void *fdt)
+{
+       return fdt_add_reservemap_entry(fdt, 0LL, 0LL);
+}
+
+int fdt_begin_node(void *fdt, const char *name)
+{
+       struct fdt_node_header *nh;
+       int namelen = strlen(name) + 1;
+
+       FDT_SW_CHECK_HEADER(fdt);
+
+       nh = _fdt_grab_space(fdt, sizeof(*nh) + FDT_TAGALIGN(namelen));
+       if (! nh)
+               return -FDT_ERR_NOSPACE;
+
+       nh->tag = cpu_to_fdt32(FDT_BEGIN_NODE);
+       memcpy(nh->name, name, namelen);
+       return 0;
+}
+
+int fdt_end_node(void *fdt)
+{
+       fdt32_t *en;
+
+       FDT_SW_CHECK_HEADER(fdt);
+
+       en = _fdt_grab_space(fdt, FDT_TAGSIZE);
+       if (! en)
+               return -FDT_ERR_NOSPACE;
+
+       *en = cpu_to_fdt32(FDT_END_NODE);
+       return 0;
+}
+
+static int _fdt_find_add_string(void *fdt, const char *s)
+{
+       char *strtab = (char *)fdt + fdt_totalsize(fdt);
+       const char *p;
+       int strtabsize = fdt_size_dt_strings(fdt);
+       int len = strlen(s) + 1;
+       int struct_top, offset;
+
+       p = _fdt_find_string(strtab - strtabsize, strtabsize, s);
+       if (p)
+               return p - strtab;
+
+       /* Add it */
+       offset = -strtabsize - len;
+       struct_top = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+       if (fdt_totalsize(fdt) + offset < struct_top)
+               return 0; /* no more room :( */
+
+       memcpy(strtab + offset, s, len);
+       fdt_set_size_dt_strings(fdt, strtabsize + len);
+       return offset;
+}
+
+int fdt_property(void *fdt, const char *name, const void *val, int len)
+{
+       struct fdt_property *prop;
+       int nameoff;
+
+       FDT_SW_CHECK_HEADER(fdt);
+
+       nameoff = _fdt_find_add_string(fdt, name);
+       if (nameoff == 0)
+               return -FDT_ERR_NOSPACE;
+
+       prop = _fdt_grab_space(fdt, sizeof(*prop) + FDT_TAGALIGN(len));
+       if (! prop)
+               return -FDT_ERR_NOSPACE;
+
+       prop->tag = cpu_to_fdt32(FDT_PROP);
+       prop->nameoff = cpu_to_fdt32(nameoff);
+       prop->len = cpu_to_fdt32(len);
+       memcpy(prop->data, val, len);
+       return 0;
+}
+
+int fdt_finish(void *fdt)
+{
+       char *p = (char *)fdt;
+       fdt32_t *end;
+       int oldstroffset, newstroffset;
+       uint32_t tag;
+       int offset, nextoffset;
+
+       FDT_SW_CHECK_HEADER(fdt);
+
+       /* Add terminator */
+       end = _fdt_grab_space(fdt, sizeof(*end));
+       if (! end)
+               return -FDT_ERR_NOSPACE;
+       *end = cpu_to_fdt32(FDT_END);
+
+       /* Relocate the string table */
+       oldstroffset = fdt_totalsize(fdt) - fdt_size_dt_strings(fdt);
+       newstroffset = fdt_off_dt_struct(fdt) + fdt_size_dt_struct(fdt);
+       memmove(p + newstroffset, p + oldstroffset, fdt_size_dt_strings(fdt));
+       fdt_set_off_dt_strings(fdt, newstroffset);
+
+       /* Walk the structure, correcting string offsets */
+       offset = 0;
+       while ((tag = fdt_next_tag(fdt, offset, &nextoffset)) != FDT_END) {
+               if (tag == FDT_PROP) {
+                       struct fdt_property *prop =
+                               _fdt_offset_ptr_w(fdt, offset);
+                       int nameoff;
+
+                       nameoff = fdt32_to_cpu(prop->nameoff);
+                       nameoff += fdt_size_dt_strings(fdt);
+                       prop->nameoff = cpu_to_fdt32(nameoff);
+               }
+               offset = nextoffset;
+       }
+       if (nextoffset < 0)
+               return nextoffset;
+
+       /* Finally, adjust the header */
+       fdt_set_totalsize(fdt, newstroffset + fdt_size_dt_strings(fdt));
+       fdt_set_magic(fdt, FDT_MAGIC);
+       return 0;
+}
diff --git a/opensrc/helpers/libfdt/fdt_wip.c b/opensrc/helpers/libfdt/fdt_wip.c
new file mode 100755 (executable)
index 0000000..c5bbb68
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "libfdt_env.h"
+
+#include <fdt.h>
+#include <libfdt.h>
+
+#include "libfdt_internal.h"
+
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+                       const void *val, int len)
+{
+       void *propval;
+       int proplen;
+
+       propval = fdt_getprop_w(fdt, nodeoffset, name, &proplen);
+       if (! propval)
+               return proplen;
+
+       if (proplen != len)
+               return -FDT_ERR_NOSPACE;
+
+       memcpy(propval, val, len);
+       return 0;
+}
+
+static void _fdt_nop_region(void *start, int len)
+{
+       fdt32_t *p;
+
+       for (p = start; (char *)p < ((char *)start + len); p++)
+               *p = cpu_to_fdt32(FDT_NOP);
+}
+
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name)
+{
+       struct fdt_property *prop;
+       int len;
+
+       prop = fdt_get_property_w(fdt, nodeoffset, name, &len);
+       if (! prop)
+               return len;
+
+       _fdt_nop_region(prop, len + sizeof(*prop));
+
+       return 0;
+}
+
+int _fdt_node_end_offset(void *fdt, int offset)
+{
+       int depth = 0;
+
+       while ((offset >= 0) && (depth >= 0))
+               offset = fdt_next_node(fdt, offset, &depth);
+
+       return offset;
+}
+
+int fdt_nop_node(void *fdt, int nodeoffset)
+{
+       int endoffset;
+
+       endoffset = _fdt_node_end_offset(fdt, nodeoffset);
+       if (endoffset < 0)
+               return endoffset;
+
+       _fdt_nop_region(fdt_offset_ptr_w(fdt, nodeoffset, 0),
+                       endoffset - nodeoffset);
+       return 0;
+}
diff --git a/opensrc/helpers/libfdt/libfdt.h b/opensrc/helpers/libfdt/libfdt.h
new file mode 100755 (executable)
index 0000000..78adb12
--- /dev/null
@@ -0,0 +1,1653 @@
+#ifndef _LIBFDT_H
+#define _LIBFDT_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <libfdt_env.h>
+#include <fdt.h>
+
+#define FDT_FIRST_SUPPORTED_VERSION    0x10
+#define FDT_LAST_SUPPORTED_VERSION     0x11
+
+/* Error codes: informative error codes */
+#define FDT_ERR_NOTFOUND       1
+       /* FDT_ERR_NOTFOUND: The requested node or property does not exist */
+#define FDT_ERR_EXISTS         2
+       /* FDT_ERR_EXISTS: Attemped to create a node or property which
+        * already exists */
+#define FDT_ERR_NOSPACE                3
+       /* FDT_ERR_NOSPACE: Operation needed to expand the device
+        * tree, but its buffer did not have sufficient space to
+        * contain the expanded tree. Use fdt_open_into() to move the
+        * device tree to a buffer with more space. */
+
+/* Error codes: codes for bad parameters */
+#define FDT_ERR_BADOFFSET      4
+       /* FDT_ERR_BADOFFSET: Function was passed a structure block
+        * offset which is out-of-bounds, or which points to an
+        * unsuitable part of the structure for the operation. */
+#define FDT_ERR_BADPATH                5
+       /* FDT_ERR_BADPATH: Function was passed a badly formatted path
+        * (e.g. missing a leading / for a function which requires an
+        * absolute path) */
+#define FDT_ERR_BADPHANDLE     6
+       /* FDT_ERR_BADPHANDLE: Function was passed an invalid phandle
+        * value.  phandle values of 0 and -1 are not permitted. */
+#define FDT_ERR_BADSTATE       7
+       /* FDT_ERR_BADSTATE: Function was passed an incomplete device
+        * tree created by the sequential-write functions, which is
+        * not sufficiently complete for the requested operation. */
+
+/* Error codes: codes for bad device tree blobs */
+#define FDT_ERR_TRUNCATED      8
+       /* FDT_ERR_TRUNCATED: Structure block of the given device tree
+        * ends without an FDT_END tag. */
+#define FDT_ERR_BADMAGIC       9
+       /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
+        * device tree at all - it is missing the flattened device
+        * tree magic number. */
+#define FDT_ERR_BADVERSION     10
+       /* FDT_ERR_BADVERSION: Given device tree has a version which
+        * can't be handled by the requested operation.  For
+        * read-write functions, this may mean that fdt_open_into() is
+        * required to convert the tree to the expected version. */
+#define FDT_ERR_BADSTRUCTURE   11
+       /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt
+        * structure block or other serious error (e.g. misnested
+        * nodes, or subnodes preceding properties). */
+#define FDT_ERR_BADLAYOUT      12
+       /* FDT_ERR_BADLAYOUT: For read-write functions, the given
+        * device tree has it's sub-blocks in an order that the
+        * function can't handle (memory reserve map, then structure,
+        * then strings).  Use fdt_open_into() to reorganize the tree
+        * into a form suitable for the read-write operations. */
+
+/* "Can't happen" error indicating a bug in libfdt */
+#define FDT_ERR_INTERNAL       13
+       /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion.
+        * Should never be returned, if it is, it indicates a bug in
+        * libfdt itself. */
+
+/* Errors in device tree content */
+#define FDT_ERR_BADNCELLS      14
+       /* FDT_ERR_BADNCELLS: Device tree has a #address-cells, #size-cells
+        * or similar property with a bad format or value */
+
+#define FDT_ERR_BADVALUE       15
+       /* FDT_ERR_BADVALUE: Device tree has a property with an unexpected
+        * value. For example: a property expected to contain a string list
+        * is not NUL-terminated within the length of its value. */
+
+#define FDT_ERR_MAX            15
+
+/**********************************************************************/
+/* Low-level functions (you probably don't need these)                */
+/**********************************************************************/
+
+const void *fdt_offset_ptr(const void *fdt, int offset, unsigned int checklen);
+static inline void *fdt_offset_ptr_w(void *fdt, int offset, int checklen)
+{
+       return (void *)(uintptr_t)fdt_offset_ptr(fdt, offset, checklen);
+}
+
+uint32_t fdt_next_tag(const void *fdt, int offset, int *nextoffset);
+
+/**********************************************************************/
+/* Traversal functions                                                */
+/**********************************************************************/
+
+int fdt_next_node(const void *fdt, int offset, int *depth);
+
+/**
+ * fdt_first_subnode() - get offset of first direct subnode
+ *
+ * @fdt:       FDT blob
+ * @offset:    Offset of node to check
+ * @return offset of first subnode, or -FDT_ERR_NOTFOUND if there is none
+ */
+int fdt_first_subnode(const void *fdt, int offset);
+
+/**
+ * fdt_next_subnode() - get offset of next direct subnode
+ *
+ * After first calling fdt_first_subnode(), call this function repeatedly to
+ * get direct subnodes of a parent node.
+ *
+ * @fdt:       FDT blob
+ * @offset:    Offset of previous subnode
+ * @return offset of next subnode, or -FDT_ERR_NOTFOUND if there are no more
+ * subnodes
+ */
+int fdt_next_subnode(const void *fdt, int offset);
+
+/**********************************************************************/
+/* General functions                                                  */
+/**********************************************************************/
+
+#define fdt_get_header(fdt, field) \
+       (fdt32_to_cpu(((const struct fdt_header *)(fdt))->field))
+#define fdt_magic(fdt)                         (fdt_get_header(fdt, magic))
+#define fdt_totalsize(fdt)             (fdt_get_header(fdt, totalsize))
+#define fdt_off_dt_struct(fdt)         (fdt_get_header(fdt, off_dt_struct))
+#define fdt_off_dt_strings(fdt)                (fdt_get_header(fdt, off_dt_strings))
+#define fdt_off_mem_rsvmap(fdt)                (fdt_get_header(fdt, off_mem_rsvmap))
+#define fdt_version(fdt)               (fdt_get_header(fdt, version))
+#define fdt_last_comp_version(fdt)     (fdt_get_header(fdt, last_comp_version))
+#define fdt_boot_cpuid_phys(fdt)       (fdt_get_header(fdt, boot_cpuid_phys))
+#define fdt_size_dt_strings(fdt)       (fdt_get_header(fdt, size_dt_strings))
+#define fdt_size_dt_struct(fdt)                (fdt_get_header(fdt, size_dt_struct))
+
+#define __fdt_set_hdr(name) \
+       static inline void fdt_set_##name(void *fdt, uint32_t val) \
+       { \
+               struct fdt_header *fdth = (struct fdt_header*)fdt; \
+               fdth->name = cpu_to_fdt32(val); \
+       }
+__fdt_set_hdr(magic);
+__fdt_set_hdr(totalsize);
+__fdt_set_hdr(off_dt_struct);
+__fdt_set_hdr(off_dt_strings);
+__fdt_set_hdr(off_mem_rsvmap);
+__fdt_set_hdr(version);
+__fdt_set_hdr(last_comp_version);
+__fdt_set_hdr(boot_cpuid_phys);
+__fdt_set_hdr(size_dt_strings);
+__fdt_set_hdr(size_dt_struct);
+#undef __fdt_set_hdr
+
+/**
+ * fdt_check_header - sanity check a device tree or possible device tree
+ * @fdt: pointer to data which might be a flattened device tree
+ *
+ * fdt_check_header() checks that the given buffer contains what
+ * appears to be a flattened device tree with sane information in its
+ * header.
+ *
+ * returns:
+ *     0, if the buffer appears to contain a valid device tree
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings, as above
+ */
+int fdt_check_header(const void *fdt);
+
+/**
+ * fdt_move - move a device tree around in memory
+ * @fdt: pointer to the device tree to move
+ * @buf: pointer to memory where the device is to be moved
+ * @bufsize: size of the memory space at buf
+ *
+ * fdt_move() relocates, if possible, the device tree blob located at
+ * fdt to the buffer at buf of size bufsize.  The buffer may overlap
+ * with the existing device tree blob at fdt.  Therefore,
+ *     fdt_move(fdt, fdt, fdt_totalsize(fdt))
+ * should always succeed.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, bufsize is insufficient to contain the device tree
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_move(const void *fdt, void *buf, int bufsize);
+
+/**********************************************************************/
+/* Read-only functions                                                */
+/**********************************************************************/
+
+/**
+ * fdt_string - retrieve a string from the strings block of a device tree
+ * @fdt: pointer to the device tree blob
+ * @stroffset: offset of the string within the strings block (native endian)
+ *
+ * fdt_string() retrieves a pointer to a single string from the
+ * strings block of the device tree blob at fdt.
+ *
+ * returns:
+ *     a pointer to the string, on success
+ *     NULL, if stroffset is out of bounds
+ */
+const char *fdt_string(const void *fdt, int stroffset);
+
+/**
+ * fdt_num_mem_rsv - retrieve the number of memory reserve map entries
+ * @fdt: pointer to the device tree blob
+ *
+ * Returns the number of entries in the device tree blob's memory
+ * reservation map.  This does not include the terminating 0,0 entry
+ * or any other (0,0) entries reserved for expansion.
+ *
+ * returns:
+ *     the number of entries
+ */
+int fdt_num_mem_rsv(const void *fdt);
+
+/**
+ * fdt_get_mem_rsv - retrieve one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: pointers to 64-bit variables
+ *
+ * On success, *address and *size will contain the address and size of
+ * the n-th reserve map entry from the device tree blob, in
+ * native-endian format.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size);
+
+/**
+ * fdt_subnode_offset_namelen - find a subnode based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_subnode_offset(), but only examine the first
+ * namelen characters of name for matching the subnode name.  This is
+ * useful for finding subnodes based on a portion of a larger string,
+ * such as a full path.
+ */
+int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
+                              const char *name, int namelen);
+/**
+ * fdt_subnode_offset - find a subnode of a given node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_subnode_offset() finds a subnode of the node at structure block
+ * offset parentoffset with the given name.  name may include a unit
+ * address, in which case fdt_subnode_offset() will find the subnode
+ * with that unit address, or the unit address may be omitted, in
+ * which case fdt_subnode_offset() will find an arbitrary subnode
+ * whose name excluding unit address matches the given name.
+ *
+ * returns:
+ *     structure block offset of the requested subnode (>=0), on success
+ *     -FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ *     -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ *      -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_subnode_offset(const void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_path_offset_namelen - find a tree node by its full path
+ * @fdt: pointer to the device tree blob
+ * @path: full path of the node to locate
+ * @namelen: number of characters of path to consider
+ *
+ * Identical to fdt_path_offset(), but only consider the first namelen
+ * characters of path as the path name.
+ */
+int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen);
+
+/**
+ * fdt_path_offset - find a tree node by its full path
+ * @fdt: pointer to the device tree blob
+ * @path: full path of the node to locate
+ *
+ * fdt_path_offset() finds a node of a given path in the device tree.
+ * Each path component may omit the unit address portion, but the
+ * results of this are undefined if any such path component is
+ * ambiguous (that is if there are multiple nodes at the relevant
+ * level matching the given component, differentiated only by unit
+ * address).
+ *
+ * returns:
+ *     structure block offset of the node with the requested path (>=0), on success
+ *     -FDT_ERR_BADPATH, given path does not begin with '/' or is invalid
+ *     -FDT_ERR_NOTFOUND, if the requested node does not exist
+ *      -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_path_offset(const void *fdt, const char *path);
+
+/**
+ * fdt_get_name - retrieve the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the starting node
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_name() retrieves the name (including unit address) of the
+ * device tree node at structure block offset nodeoffset.  If lenp is
+ * non-NULL, the length of this name is also returned, in the integer
+ * pointed to by lenp.
+ *
+ * returns:
+ *     pointer to the node's name, on success
+ *             If lenp is non-NULL, *lenp contains the length of that name (>=0)
+ *     NULL, on error
+ *             if lenp is non-NULL *lenp contains an error code (<0):
+ *             -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *             -FDT_ERR_BADMAGIC,
+ *             -FDT_ERR_BADVERSION,
+ *             -FDT_ERR_BADSTATE, standard meanings
+ */
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *lenp);
+
+/**
+ * fdt_first_property_offset - find the offset of a node's first property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ *
+ * fdt_first_property_offset() finds the first property of the node at
+ * the given structure block offset.
+ *
+ * returns:
+ *     structure block offset of the property (>=0), on success
+ *     -FDT_ERR_NOTFOUND, if the requested node has no properties
+ *     -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_BEGIN_NODE tag
+ *      -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_first_property_offset(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_next_property_offset - step through a node's properties
+ * @fdt: pointer to the device tree blob
+ * @offset: structure block offset of a property
+ *
+ * fdt_next_property_offset() finds the property immediately after the
+ * one at the given structure block offset.  This will be a property
+ * of the same node as the given property.
+ *
+ * returns:
+ *     structure block offset of the next property (>=0), on success
+ *     -FDT_ERR_NOTFOUND, if the given property is the last in its node
+ *     -FDT_ERR_BADOFFSET, if nodeoffset did not point to an FDT_PROP tag
+ *      -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_next_property_offset(const void *fdt, int offset);
+
+/**
+ * fdt_get_property_by_offset - retrieve the property at a given offset
+ * @fdt: pointer to the device tree blob
+ * @offset: offset of the property to retrieve
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_property_by_offset() retrieves a pointer to the
+ * fdt_property structure within the device tree blob at the given
+ * offset.  If lenp is non-NULL, the length of the property value is
+ * also returned, in the integer pointed to by lenp.
+ *
+ * returns:
+ *     pointer to the structure representing the property
+ *             if lenp is non-NULL, *lenp contains the length of the property
+ *             value (>=0)
+ *     NULL, on error
+ *             if lenp is non-NULL, *lenp contains an error code (<0):
+ *             -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag
+ *             -FDT_ERR_BADMAGIC,
+ *             -FDT_ERR_BADVERSION,
+ *             -FDT_ERR_BADSTATE,
+ *             -FDT_ERR_BADSTRUCTURE,
+ *             -FDT_ERR_TRUNCATED, standard meanings
+ */
+const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
+                                                     int offset,
+                                                     int *lenp);
+
+/**
+ * fdt_get_property_namelen - find a property based on substring
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @namelen: number of characters of name to consider
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * Identical to fdt_get_property(), but only examine the first namelen
+ * characters of name for matching the property name.
+ */
+const struct fdt_property *fdt_get_property_namelen(const void *fdt,
+                                                   int nodeoffset,
+                                                   const char *name,
+                                                   int namelen, int *lenp);
+
+/**
+ * fdt_get_property - find a given property in a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_get_property() retrieves a pointer to the fdt_property
+ * structure within the device tree blob corresponding to the property
+ * named 'name' of the node at offset nodeoffset.  If lenp is
+ * non-NULL, the length of the property value is also returned, in the
+ * integer pointed to by lenp.
+ *
+ * returns:
+ *     pointer to the structure representing the property
+ *             if lenp is non-NULL, *lenp contains the length of the property
+ *             value (>=0)
+ *     NULL, on error
+ *             if lenp is non-NULL, *lenp contains an error code (<0):
+ *             -FDT_ERR_NOTFOUND, node does not have named property
+ *             -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *             -FDT_ERR_BADMAGIC,
+ *             -FDT_ERR_BADVERSION,
+ *             -FDT_ERR_BADSTATE,
+ *             -FDT_ERR_BADSTRUCTURE,
+ *             -FDT_ERR_TRUNCATED, standard meanings
+ */
+const struct fdt_property *fdt_get_property(const void *fdt, int nodeoffset,
+                                           const char *name, int *lenp);
+static inline struct fdt_property *fdt_get_property_w(void *fdt, int nodeoffset,
+                                                     const char *name,
+                                                     int *lenp)
+{
+       return (struct fdt_property *)(uintptr_t)
+               fdt_get_property(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_getprop_by_offset - retrieve the value of a property at a given offset
+ * @fdt: pointer to the device tree blob
+ * @ffset: offset of the property to read
+ * @namep: pointer to a string variable (will be overwritten) or NULL
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop_by_offset() retrieves a pointer to the value of the
+ * property at structure block offset 'offset' (this will be a pointer
+ * to within the device blob itself, not a copy of the value).  If
+ * lenp is non-NULL, the length of the property value is also
+ * returned, in the integer pointed to by lenp.  If namep is non-NULL,
+ * the property's namne will also be returned in the char * pointed to
+ * by namep (this will be a pointer to within the device tree's string
+ * block, not a new copy of the name).
+ *
+ * returns:
+ *     pointer to the property's value
+ *             if lenp is non-NULL, *lenp contains the length of the property
+ *             value (>=0)
+ *             if namep is non-NULL *namep contiains a pointer to the property
+ *             name.
+ *     NULL, on error
+ *             if lenp is non-NULL, *lenp contains an error code (<0):
+ *             -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_PROP tag
+ *             -FDT_ERR_BADMAGIC,
+ *             -FDT_ERR_BADVERSION,
+ *             -FDT_ERR_BADSTATE,
+ *             -FDT_ERR_BADSTRUCTURE,
+ *             -FDT_ERR_TRUNCATED, standard meanings
+ */
+const void *fdt_getprop_by_offset(const void *fdt, int offset,
+                                 const char **namep, int *lenp);
+
+/**
+ * fdt_getprop_namelen - get property value based on substring
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @namelen: number of characters of name to consider
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * Identical to fdt_getprop(), but only examine the first namelen
+ * characters of name for matching the property name.
+ */
+const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
+                               const char *name, int namelen, int *lenp);
+
+/**
+ * fdt_getprop - retrieve the value of a given property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to find
+ * @name: name of the property to find
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop() retrieves a pointer to the value of the property
+ * named 'name' of the node at offset nodeoffset (this will be a
+ * pointer to within the device blob itself, not a copy of the value).
+ * If lenp is non-NULL, the length of the property value is also
+ * returned, in the integer pointed to by lenp.
+ *
+ * returns:
+ *     pointer to the property's value
+ *             if lenp is non-NULL, *lenp contains the length of the property
+ *             value (>=0)
+ *     NULL, on error
+ *             if lenp is non-NULL, *lenp contains an error code (<0):
+ *             -FDT_ERR_NOTFOUND, node does not have named property
+ *             -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *             -FDT_ERR_BADMAGIC,
+ *             -FDT_ERR_BADVERSION,
+ *             -FDT_ERR_BADSTATE,
+ *             -FDT_ERR_BADSTRUCTURE,
+ *             -FDT_ERR_TRUNCATED, standard meanings
+ */
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+                       const char *name, int *lenp);
+static inline void *fdt_getprop_w(void *fdt, int nodeoffset,
+                                 const char *name, int *lenp)
+{
+       return (void *)(uintptr_t)fdt_getprop(fdt, nodeoffset, name, lenp);
+}
+
+/**
+ * fdt_get_phandle - retrieve the phandle of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of the node
+ *
+ * fdt_get_phandle() retrieves the phandle of the device tree node at
+ * structure block offset nodeoffset.
+ *
+ * returns:
+ *     the phandle of the node at nodeoffset, on success (!= 0, != -1)
+ *     0, if the node has no phandle, or another error occurs
+ */
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_get_alias_namelen - get alias based on substring
+ * @fdt: pointer to the device tree blob
+ * @name: name of the alias th look up
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_get_alias(), but only examine the first namelen
+ * characters of name for matching the alias name.
+ */
+const char *fdt_get_alias_namelen(const void *fdt,
+                                 const char *name, int namelen);
+
+/**
+ * fdt_get_alias - retreive the path referenced by a given alias
+ * @fdt: pointer to the device tree blob
+ * @name: name of the alias th look up
+ *
+ * fdt_get_alias() retrieves the value of a given alias.  That is, the
+ * value of the property named 'name' in the node /aliases.
+ *
+ * returns:
+ *     a pointer to the expansion of the alias named 'name', if it exists
+ *     NULL, if the given alias or the /aliases node does not exist
+ */
+const char *fdt_get_alias(const void *fdt, const char *name);
+
+/**
+ * fdt_get_path - determine the full path of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose path to find
+ * @buf: character buffer to contain the returned path (will be overwritten)
+ * @buflen: size of the character buffer at buf
+ *
+ * fdt_get_path() computes the full path of the node at offset
+ * nodeoffset, and records that path in the buffer at buf.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ *     0, on success
+ *             buf contains the absolute path of the node at
+ *             nodeoffset, as a NUL-terminated string.
+ *     -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *     -FDT_ERR_NOSPACE, the path of the given node is longer than (bufsize-1)
+ *             characters and will not fit in the given buffer.
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen);
+
+/**
+ * fdt_supernode_atdepth_offset - find a specific ancestor of a node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ * @supernodedepth: depth of the ancestor to find
+ * @nodedepth: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_supernode_atdepth_offset() finds an ancestor of the given node
+ * at a specific depth from the root (where the root itself has depth
+ * 0, its immediate subnodes depth 1 and so forth).  So
+ *     fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, NULL);
+ * will always return 0, the offset of the root node.  If the node at
+ * nodeoffset has depth D, then:
+ *     fdt_supernode_atdepth_offset(fdt, nodeoffset, D, NULL);
+ * will return nodeoffset itself.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+
+ *     structure block offset of the node at node offset's ancestor
+ *             of depth supernodedepth (>=0), on success
+ *     -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+*      -FDT_ERR_NOTFOUND, supernodedepth was greater than the depth of nodeoffset
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
+                                int supernodedepth, int *nodedepth);
+
+/**
+ * fdt_node_depth - find the depth of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_node_depth() finds the depth of a given node.  The root node
+ * has depth 0, its immediate subnodes depth 1 and so forth.
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset.
+ *
+ * returns:
+ *     depth of the node at nodeoffset (>=0), on success
+ *     -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_depth(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_parent_offset - find the parent of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose parent to find
+ *
+ * fdt_parent_offset() locates the parent node of a given node (that
+ * is, it finds the offset of the node which contains the node at
+ * nodeoffset as a subnode).
+ *
+ * NOTE: This function is expensive, as it must scan the device tree
+ * structure from the start to nodeoffset, *twice*.
+ *
+ * returns:
+ *     structure block offset of the parent of the node at nodeoffset
+ *             (>=0), on success
+ *     -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_parent_offset(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_node_offset_by_prop_value - find nodes with a given property value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @propname: property name to check
+ * @propval: property value to search for
+ * @proplen: length of the value in propval
+ *
+ * fdt_node_offset_by_prop_value() returns the offset of the first
+ * node after startoffset, which has a property named propname whose
+ * value is of length proplen and has value equal to propval; or if
+ * startoffset is -1, the very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ *     offset = fdt_node_offset_by_prop_value(fdt, -1, propname,
+ *                                            propval, proplen);
+ *     while (offset != -FDT_ERR_NOTFOUND) {
+ *             // other code here
+ *             offset = fdt_node_offset_by_prop_value(fdt, offset, propname,
+ *                                                    propval, proplen);
+ *     }
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ *     structure block offset of the located node (>= 0, >startoffset),
+ *              on success
+ *     -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ *             tree after startoffset
+ *     -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
+                                 const char *propname,
+                                 const void *propval, int proplen);
+
+/**
+ * fdt_node_offset_by_phandle - find the node with a given phandle
+ * @fdt: pointer to the device tree blob
+ * @phandle: phandle value
+ *
+ * fdt_node_offset_by_phandle() returns the offset of the node
+ * which has the given phandle value.  If there is more than one node
+ * in the tree with the given phandle (an invalid tree), results are
+ * undefined.
+ *
+ * returns:
+ *     structure block offset of the located node (>= 0), on success
+ *     -FDT_ERR_NOTFOUND, no node with that phandle exists
+ *     -FDT_ERR_BADPHANDLE, given phandle value was invalid (0 or -1)
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle);
+
+/**
+ * fdt_node_check_compatible: check a node's compatible property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @compatible: string to match against
+ *
+ *
+ * fdt_node_check_compatible() returns 0 if the given node contains a
+ * 'compatible' property with the given string as one of its elements,
+ * it returns non-zero otherwise, or on error.
+ *
+ * returns:
+ *     0, if the node has a 'compatible' property listing the given string
+ *     1, if the node has a 'compatible' property, but it does not list
+ *             the given string
+ *     -FDT_ERR_NOTFOUND, if the given node has no 'compatible' property
+ *     -FDT_ERR_BADOFFSET, if nodeoffset does not refer to a BEGIN_NODE tag
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,
+                             const char *compatible);
+
+/**
+ * fdt_node_offset_by_compatible - find nodes with a given 'compatible' value
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @compatible: 'compatible' string to match against
+ *
+ * fdt_node_offset_by_compatible() returns the offset of the first
+ * node after startoffset, which has a 'compatible' property which
+ * lists the given compatible string; or if startoffset is -1, the
+ * very first such node in the tree.
+ *
+ * To iterate through all nodes matching the criterion, the following
+ * idiom can be used:
+ *     offset = fdt_node_offset_by_compatible(fdt, -1, compatible);
+ *     while (offset != -FDT_ERR_NOTFOUND) {
+ *             // other code here
+ *             offset = fdt_node_offset_by_compatible(fdt, offset, compatible);
+ *     }
+ *
+ * Note the -1 in the first call to the function, if 0 is used here
+ * instead, the function will never locate the root node, even if it
+ * matches the criterion.
+ *
+ * returns:
+ *     structure block offset of the located node (>= 0, >startoffset),
+ *              on success
+ *     -FDT_ERR_NOTFOUND, no node matching the criterion exists in the
+ *             tree after startoffset
+ *     -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
+                                 const char *compatible);
+
+/**
+ * fdt_stringlist_contains - check a string list property for a string
+ * @strlist: Property containing a list of strings to check
+ * @listlen: Length of property
+ * @str: String to search for
+ *
+ * This is a utility function provided for convenience. The list contains
+ * one or more strings, each terminated by \0, as is found in a device tree
+ * "compatible" property.
+ *
+ * @return: 1 if the string is found in the list, 0 not found, or invalid list
+ */
+int fdt_stringlist_contains(const char *strlist, int listlen, const char *str);
+
+/**
+ * fdt_stringlist_count - count the number of strings in a string list
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @property: name of the property containing the string list
+ * @return:
+ *   the number of strings in the given property
+ *   -FDT_ERR_BADVALUE if the property value is not NUL-terminated
+ *   -FDT_ERR_NOTFOUND if the property does not exist
+ */
+int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property);
+
+/**
+ * fdt_stringlist_search - find a string in a string list and return its index
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @property: name of the property containing the string list
+ * @string: string to look up in the string list
+ *
+ * Note that it is possible for this function to succeed on property values
+ * that are not NUL-terminated. That's because the function will stop after
+ * finding the first occurrence of @string. This can for example happen with
+ * small-valued cell properties, such as #address-cells, when searching for
+ * the empty string.
+ *
+ * @return:
+ *   the index of the string in the list of strings
+ *   -FDT_ERR_BADVALUE if the property value is not NUL-terminated
+ *   -FDT_ERR_NOTFOUND if the property does not exist or does not contain
+ *                     the given string
+ */
+int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
+                         const char *string);
+
+/**
+ * fdt_stringlist_get() - obtain the string at a given index in a string list
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of a tree node
+ * @property: name of the property containing the string list
+ * @index: index of the string to return
+ * @lenp: return location for the string length or an error code on failure
+ *
+ * Note that this will successfully extract strings from properties with
+ * non-NUL-terminated values. For example on small-valued cell properties
+ * this function will return the empty string.
+ *
+ * If non-NULL, the length of the string (on success) or a negative error-code
+ * (on failure) will be stored in the integer pointer to by lenp.
+ *
+ * @return:
+ *   A pointer to the string at the given index in the string list or NULL on
+ *   failure. On success the length of the string will be stored in the memory
+ *   location pointed to by the lenp parameter, if non-NULL. On failure one of
+ *   the following negative error codes will be returned in the lenp parameter
+ *   (if non-NULL):
+ *     -FDT_ERR_BADVALUE if the property value is not NUL-terminated
+ *     -FDT_ERR_NOTFOUND if the property does not exist
+ */
+const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
+                              const char *property, int index,
+                              int *lenp);
+
+/**********************************************************************/
+/* Read-only functions (addressing related)                           */
+/**********************************************************************/
+
+/**
+ * FDT_MAX_NCELLS - maximum value for #address-cells and #size-cells
+ *
+ * This is the maximum value for #address-cells, #size-cells and
+ * similar properties that will be processed by libfdt.  IEE1275
+ * requires that OF implementations handle values up to 4.
+ * Implementations may support larger values, but in practice higher
+ * values aren't used.
+ */
+#define FDT_MAX_NCELLS         4
+
+/**
+ * fdt_address_cells - retrieve address size for a bus represented in the tree
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to find the address size for
+ *
+ * When the node has a valid #address-cells property, returns its value.
+ *
+ * returns:
+ *     0 <= n < FDT_MAX_NCELLS, on success
+ *      2, if the node has no #address-cells property
+ *      -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #address-cells property
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_address_cells(const void *fdt, int nodeoffset);
+
+/**
+ * fdt_size_cells - retrieve address range size for a bus represented in the
+ *                  tree
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to find the address range size for
+ *
+ * When the node has a valid #size-cells property, returns its value.
+ *
+ * returns:
+ *     0 <= n < FDT_MAX_NCELLS, on success
+ *      2, if the node has no #address-cells property
+ *      -FDT_ERR_BADNCELLS, if the node has a badly formatted or invalid #size-cells property
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_size_cells(const void *fdt, int nodeoffset);
+
+
+/**********************************************************************/
+/* Write-in-place functions                                           */
+/**********************************************************************/
+
+/**
+ * fdt_setprop_inplace - change a property's value, but not its size
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to replace the property value with
+ * @len: length of the property value
+ *
+ * fdt_setprop_inplace() replaces the value of a given property with
+ * the data in val, of length len.  This function cannot change the
+ * size of a property, and so will only work if len is equal to the
+ * current length of the property.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, if len is not equal to the property's current length
+ *     -FDT_ERR_NOTFOUND, node does not have the named property
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop_inplace(void *fdt, int nodeoffset, const char *name,
+                       const void *val, int len);
+
+/**
+ * fdt_setprop_inplace_u32 - change the value of a 32-bit integer property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value to replace the property with
+ *
+ * fdt_setprop_inplace_u32() replaces the value of a given property
+ * with the 32-bit integer value in val, converting val to big-endian
+ * if necessary.  This function cannot change the size of a property,
+ * and so will only work if the property already exists and has length
+ * 4.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, if the property's length is not equal to 4
+ *     -FDT_ERR_NOTFOUND, node does not have the named property
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_inplace_u32(void *fdt, int nodeoffset,
+                                         const char *name, uint32_t val)
+{
+       fdt32_t tmp = cpu_to_fdt32(val);
+       return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_inplace_u64 - change the value of a 64-bit integer property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 64-bit integer value to replace the property with
+ *
+ * fdt_setprop_inplace_u64() replaces the value of a given property
+ * with the 64-bit integer value in val, converting val to big-endian
+ * if necessary.  This function cannot change the size of a property,
+ * and so will only work if the property already exists and has length
+ * 8.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the given property value, and will not alter or move any other part
+ * of the tree.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, if the property's length is not equal to 8
+ *     -FDT_ERR_NOTFOUND, node does not have the named property
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_inplace_u64(void *fdt, int nodeoffset,
+                                         const char *name, uint64_t val)
+{
+       fdt64_t tmp = cpu_to_fdt64(val);
+       return fdt_setprop_inplace(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_inplace_cell - change the value of a single-cell property
+ *
+ * This is an alternative name for fdt_setprop_inplace_u32()
+ */
+static inline int fdt_setprop_inplace_cell(void *fdt, int nodeoffset,
+                                          const char *name, uint32_t val)
+{
+       return fdt_setprop_inplace_u32(fdt, nodeoffset, name, val);
+}
+
+/**
+ * fdt_nop_property - replace a property with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_nop_property() will replace a given property's representation
+ * in the blob with FDT_NOP tags, effectively removing it from the
+ * tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the property, and will not alter or move any other part of the
+ * tree.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOTFOUND, node does not have the named property
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_property(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_nop_node - replace a node (subtree) with nop tags
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_nop_node() will replace a given node's representation in the
+ * blob, including all its subnodes, if any, with FDT_NOP tags,
+ * effectively removing it from the tree.
+ *
+ * This function will alter only the bytes in the blob which contain
+ * the node and its properties and subnodes, and will not alter or
+ * move any other part of the tree.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_nop_node(void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Sequential write functions                                         */
+/**********************************************************************/
+
+int fdt_create(void *buf, int bufsize);
+int fdt_resize(void *fdt, void *buf, int bufsize);
+int fdt_add_reservemap_entry(void *fdt, uint64_t addr, uint64_t size);
+int fdt_finish_reservemap(void *fdt);
+int fdt_begin_node(void *fdt, const char *name);
+int fdt_property(void *fdt, const char *name, const void *val, int len);
+static inline int fdt_property_u32(void *fdt, const char *name, uint32_t val)
+{
+       fdt32_t tmp = cpu_to_fdt32(val);
+       return fdt_property(fdt, name, &tmp, sizeof(tmp));
+}
+static inline int fdt_property_u64(void *fdt, const char *name, uint64_t val)
+{
+       fdt64_t tmp = cpu_to_fdt64(val);
+       return fdt_property(fdt, name, &tmp, sizeof(tmp));
+}
+static inline int fdt_property_cell(void *fdt, const char *name, uint32_t val)
+{
+       return fdt_property_u32(fdt, name, val);
+}
+#define fdt_property_string(fdt, name, str) \
+       fdt_property(fdt, name, str, strlen(str)+1)
+int fdt_end_node(void *fdt);
+int fdt_finish(void *fdt);
+
+/**********************************************************************/
+/* Read-write functions                                               */
+/**********************************************************************/
+
+int fdt_create_empty_tree(void *buf, int bufsize);
+int fdt_open_into(const void *fdt, void *buf, int bufsize);
+int fdt_pack(void *fdt);
+
+/**
+ * fdt_add_mem_rsv - add one memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @address, @size: 64-bit values (native endian)
+ *
+ * Adds a reserve map entry to the given blob reserving a region at
+ * address address of length size.
+ *
+ * This function will insert data into the reserve map and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *             contain the new reservation entry
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_add_mem_rsv(void *fdt, uint64_t address, uint64_t size);
+
+/**
+ * fdt_del_mem_rsv - remove a memory reserve map entry
+ * @fdt: pointer to the device tree blob
+ * @n: entry to remove
+ *
+ * fdt_del_mem_rsv() removes the n-th memory reserve map entry from
+ * the blob.
+ *
+ * This function will delete data from the reservation table and will
+ * therefore change the indexes of some entries in the table.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOTFOUND, there is no entry of the given index (i.e. there
+ *             are less than n+1 reserve map entries)
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_mem_rsv(void *fdt, int n);
+
+/**
+ * fdt_set_name - change the name of a given node
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: structure block offset of a node
+ * @name: name to give the node
+ *
+ * fdt_set_name() replaces the name (including unit address, if any)
+ * of the given node with the given string.  NOTE: this function can't
+ * efficiently check if the new name is unique amongst the given
+ * node's siblings; results are undefined if this function is invoked
+ * with a name equal to one of the given node's siblings.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, there is insufficient free space in the blob
+ *             to contain the new name
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE, standard meanings
+ */
+int fdt_set_name(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_setprop - create or change a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: pointer to data to set the property value to
+ * @len: length of the property value
+ *
+ * fdt_setprop() sets the value of the named property in the given
+ * node to the given value and length, creating the property if it
+ * does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *             contain the new property value
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_setprop(void *fdt, int nodeoffset, const char *name,
+               const void *val, int len);
+
+/**
+ * fdt_setprop_u32 - set a property to a 32-bit integer
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value for the property (native endian)
+ *
+ * fdt_setprop_u32() sets the value of the named property in the given
+ * node to the given 32-bit integer value (converting to big-endian if
+ * necessary), or creates a new property with that value if it does
+ * not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *             contain the new property value
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_u32(void *fdt, int nodeoffset, const char *name,
+                                 uint32_t val)
+{
+       fdt32_t tmp = cpu_to_fdt32(val);
+       return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_u64 - set a property to a 64-bit integer
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 64-bit integer value for the property (native endian)
+ *
+ * fdt_setprop_u64() sets the value of the named property in the given
+ * node to the given 64-bit integer value (converting to big-endian if
+ * necessary), or creates a new property with that value if it does
+ * not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *             contain the new property value
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_setprop_u64(void *fdt, int nodeoffset, const char *name,
+                                 uint64_t val)
+{
+       fdt64_t tmp = cpu_to_fdt64(val);
+       return fdt_setprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_setprop_cell - set a property to a single cell value
+ *
+ * This is an alternative name for fdt_setprop_u32()
+ */
+static inline int fdt_setprop_cell(void *fdt, int nodeoffset, const char *name,
+                                  uint32_t val)
+{
+       return fdt_setprop_u32(fdt, nodeoffset, name, val);
+}
+
+/**
+ * fdt_setprop_string - set a property to a string value
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @str: string value for the property
+ *
+ * fdt_setprop_string() sets the value of the named property in the
+ * given node to the given string value (using the length of the
+ * string to determine the new length of the property), or creates a
+ * new property with that value if it does not already exist.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *             contain the new property value
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_setprop_string(fdt, nodeoffset, name, str) \
+       fdt_setprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
+/**
+ * fdt_appendprop - append to or create a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to append to
+ * @val: pointer to data to append to the property value
+ * @len: length of the data to append to the property value
+ *
+ * fdt_appendprop() appends the value to the named property in the
+ * given node, creating the property if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *             contain the new property value
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_appendprop(void *fdt, int nodeoffset, const char *name,
+                  const void *val, int len);
+
+/**
+ * fdt_appendprop_u32 - append a 32-bit integer value to a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 32-bit integer value to append to the property (native endian)
+ *
+ * fdt_appendprop_u32() appends the given 32-bit integer value
+ * (converting to big-endian if necessary) to the value of the named
+ * property in the given node, or creates a new property with that
+ * value if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *             contain the new property value
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_appendprop_u32(void *fdt, int nodeoffset,
+                                    const char *name, uint32_t val)
+{
+       fdt32_t tmp = cpu_to_fdt32(val);
+       return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_appendprop_u64 - append a 64-bit integer value to a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @val: 64-bit integer value to append to the property (native endian)
+ *
+ * fdt_appendprop_u64() appends the given 64-bit integer value
+ * (converting to big-endian if necessary) to the value of the named
+ * property in the given node, or creates a new property with that
+ * value if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *             contain the new property value
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+static inline int fdt_appendprop_u64(void *fdt, int nodeoffset,
+                                    const char *name, uint64_t val)
+{
+       fdt64_t tmp = cpu_to_fdt64(val);
+       return fdt_appendprop(fdt, nodeoffset, name, &tmp, sizeof(tmp));
+}
+
+/**
+ * fdt_appendprop_cell - append a single cell value to a property
+ *
+ * This is an alternative name for fdt_appendprop_u32()
+ */
+static inline int fdt_appendprop_cell(void *fdt, int nodeoffset,
+                                     const char *name, uint32_t val)
+{
+       return fdt_appendprop_u32(fdt, nodeoffset, name, val);
+}
+
+/**
+ * fdt_appendprop_string - append a string to a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to change
+ * @name: name of the property to change
+ * @str: string value to append to the property
+ *
+ * fdt_appendprop_string() appends the given string to the value of
+ * the named property in the given node, or creates a new property
+ * with that value if it does not already exist.
+ *
+ * This function may insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *             contain the new property value
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+#define fdt_appendprop_string(fdt, nodeoffset, name, str) \
+       fdt_appendprop((fdt), (nodeoffset), (name), (str), strlen(str)+1)
+
+/**
+ * fdt_delprop - delete a property
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node whose property to nop
+ * @name: name of the property to nop
+ *
+ * fdt_del_property() will delete the given property.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_NOTFOUND, node does not have the named property
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_delprop(void *fdt, int nodeoffset, const char *name);
+
+/**
+ * fdt_add_subnode_namelen - creates a new node based on substring
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ * @namelen: number of characters of name to consider
+ *
+ * Identical to fdt_add_subnode(), but use only the first namelen
+ * characters of name as the name of the new node.  This is useful for
+ * creating subnodes based on a portion of a larger string, such as a
+ * full path.
+ */
+int fdt_add_subnode_namelen(void *fdt, int parentoffset,
+                           const char *name, int namelen);
+
+/**
+ * fdt_add_subnode - creates a new node
+ * @fdt: pointer to the device tree blob
+ * @parentoffset: structure block offset of a node
+ * @name: name of the subnode to locate
+ *
+ * fdt_add_subnode() creates a new node as a subnode of the node at
+ * structure block offset parentoffset, with the given name (which
+ * should include the unit address, if any).
+ *
+ * This function will insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+
+ * returns:
+ *     structure block offset of the created nodeequested subnode (>=0), on success
+ *     -FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ *     -FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ *     -FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
+ *             the given name
+ *     -FDT_ERR_NOSPACE, if there is insufficient free space in the
+ *             blob to contain the new node
+ *     -FDT_ERR_NOSPACE
+ *     -FDT_ERR_BADLAYOUT
+ *      -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_add_subnode(void *fdt, int parentoffset, const char *name);
+
+/**
+ * fdt_del_node - delete a node (subtree)
+ * @fdt: pointer to the device tree blob
+ * @nodeoffset: offset of the node to nop
+ *
+ * fdt_del_node() will remove the given node, including all its
+ * subnodes if any, from the blob.
+ *
+ * This function will delete data from the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *     0, on success
+ *     -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *     -FDT_ERR_BADLAYOUT,
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_del_node(void *fdt, int nodeoffset);
+
+/**********************************************************************/
+/* Debugging / informational functions                                */
+/**********************************************************************/
+
+const char *fdt_strerror(int errval);
+
+#endif /* _LIBFDT_H */
diff --git a/opensrc/helpers/libfdt/libfdt_env.h b/opensrc/helpers/libfdt/libfdt_env.h
new file mode 100755 (executable)
index 0000000..1c966b8
--- /dev/null
@@ -0,0 +1,118 @@
+#ifndef _LIBFDT_ENV_H
+#define _LIBFDT_ENV_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ * Copyright 2012 Kim Phillips, Freescale Semiconductor.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stddef.h>
+#include <stdint.h>
+#include <string.h>
+
+#ifdef __CHECKER__
+#define __force __attribute__((force))
+#define __bitwise __attribute__((bitwise))
+#else
+#define __force
+#define __bitwise
+#endif
+
+typedef uint16_t __bitwise fdt16_t;
+typedef uint32_t __bitwise fdt32_t;
+typedef uint64_t __bitwise fdt64_t;
+
+//#define EXTRACT_BYTE(x, n)   ((unsigned long long)((uint8_t *)&x)[n])
+// xxx work around a compiler bug...
+#define EXTRACT_BYTE(x, n)     EXTRACT_BYTE_f(&x, n)
+static inline unsigned long long EXTRACT_BYTE_f(void *x, int n)
+{
+       return ((uint8_t *)x)[n];
+}
+
+#define CPU_TO_FDT16(x) ((EXTRACT_BYTE(x, 0) << 8) | EXTRACT_BYTE(x, 1))
+#define CPU_TO_FDT32(x) ((EXTRACT_BYTE(x, 0) << 24) | (EXTRACT_BYTE(x, 1) << 16) | \
+                        (EXTRACT_BYTE(x, 2) << 8) | EXTRACT_BYTE(x, 3))
+#define CPU_TO_FDT64(x) ((EXTRACT_BYTE(x, 0) << 56) | (EXTRACT_BYTE(x, 1) << 48) | \
+                        (EXTRACT_BYTE(x, 2) << 40) | (EXTRACT_BYTE(x, 3) << 32) | \
+                        (EXTRACT_BYTE(x, 4) << 24) | (EXTRACT_BYTE(x, 5) << 16) | \
+                        (EXTRACT_BYTE(x, 6) << 8) | EXTRACT_BYTE(x, 7))
+
+static inline uint16_t fdt16_to_cpu(fdt16_t x)
+{
+       return (__force uint16_t)CPU_TO_FDT16(x);
+}
+static inline fdt16_t cpu_to_fdt16(uint16_t x)
+{
+       return (__force fdt16_t)CPU_TO_FDT16(x);
+}
+
+static inline uint32_t fdt32_to_cpu(fdt32_t x)
+{
+       return (__force uint32_t)CPU_TO_FDT32(x);
+}
+static inline fdt32_t cpu_to_fdt32(uint32_t x)
+{
+       return (__force fdt32_t)CPU_TO_FDT32(x);
+}
+
+static inline uint64_t fdt64_to_cpu(fdt64_t x)
+{
+       return (__force uint64_t)CPU_TO_FDT64(x);
+}
+static inline fdt64_t cpu_to_fdt64(uint64_t x)
+{
+       return (__force fdt64_t)CPU_TO_FDT64(x);
+}
+#undef CPU_TO_FDT64
+#undef CPU_TO_FDT32
+#undef CPU_TO_FDT16
+#undef EXTRACT_BYTE
+
+#endif /* _LIBFDT_ENV_H */
diff --git a/opensrc/helpers/libfdt/libfdt_internal.h b/opensrc/helpers/libfdt/libfdt_internal.h
new file mode 100755 (executable)
index 0000000..02cfa6f
--- /dev/null
@@ -0,0 +1,95 @@
+#ifndef _LIBFDT_INTERNAL_H
+#define _LIBFDT_INTERNAL_H
+/*
+ * libfdt - Flat Device Tree manipulation
+ * Copyright (C) 2006 David Gibson, IBM Corporation.
+ *
+ * libfdt is dual licensed: you can use it either under the terms of
+ * the GPL, or the BSD license, at your option.
+ *
+ *  a) This library is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of the
+ *     License, or (at your option) any later version.
+ *
+ *     This library is distributed in the hope that it will be useful,
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *     GNU General Public License for more details.
+ *
+ *     You should have received a copy of the GNU General Public
+ *     License along with this library; if not, write to the Free
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ *     MA 02110-1301 USA
+ *
+ * Alternatively,
+ *
+ *  b) Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *     1. Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *     2. Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <fdt.h>
+
+#define FDT_ALIGN(x, a)                (((x) + (a) - 1) & ~((a) - 1))
+#define FDT_TAGALIGN(x)                (FDT_ALIGN((x), FDT_TAGSIZE))
+
+#define FDT_CHECK_HEADER(fdt) \
+       { \
+               int __err; \
+               if ((__err = fdt_check_header(fdt)) != 0) \
+                       return __err; \
+       }
+
+int _fdt_check_node_offset(const void *fdt, int offset);
+int _fdt_check_prop_offset(const void *fdt, int offset);
+const char *_fdt_find_string(const char *strtab, int tabsize, const char *s);
+int _fdt_node_end_offset(void *fdt, int nodeoffset);
+
+static inline const void *_fdt_offset_ptr(const void *fdt, int offset)
+{
+       return (const char *)fdt + fdt_off_dt_struct(fdt) + offset;
+}
+
+static inline void *_fdt_offset_ptr_w(void *fdt, int offset)
+{
+       return (void *)(uintptr_t)_fdt_offset_ptr(fdt, offset);
+}
+
+static inline const struct fdt_reserve_entry *_fdt_mem_rsv(const void *fdt, int n)
+{
+       const struct fdt_reserve_entry *rsv_table =
+               (const struct fdt_reserve_entry *)
+               ((const char *)fdt + fdt_off_mem_rsvmap(fdt));
+
+       return rsv_table + n;
+}
+static inline struct fdt_reserve_entry *_fdt_mem_rsv_w(void *fdt, int n)
+{
+       return (void *)(uintptr_t)_fdt_mem_rsv(fdt, n);
+}
+
+#define FDT_SW_MAGIC           (~FDT_MAGIC)
+
+#endif /* _LIBFDT_INTERNAL_H */
diff --git a/packaging/libomxil-vc4.manifest b/packaging/libomxil-vc4.manifest
new file mode 100755 (executable)
index 0000000..017d22d
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+ <request>
+    <domain name="_"/>
+ </request>
+</manifest>
diff --git a/packaging/libomxil-vc4.spec b/packaging/libomxil-vc4.spec
new file mode 100755 (executable)
index 0000000..c75b975
--- /dev/null
@@ -0,0 +1,109 @@
+Name:          libomxil-vc4
+Version:       0.0.1
+Release:       0.1
+Summary:       Libraries for interfacing to Raspberry Pi GPU
+Group:         System/Libraries
+URL:           https://github.com/raspberrypi/userland
+Source:         %{name}-%{version}.tar.gz
+License:       BSD
+BuildRequires: glibc-devel
+BuildRequires: cmake
+BuildRequires: gcc-c++
+BuildRequires: pkgconfig(libtbm)
+
+%description
+Libraries for interfacing to Raspberry Pi GPU.
+
+%package -n    libomxil-vc4-utils
+Group:         System/Tools
+Summary:       System tools for the Raspberry Pi
+
+%description -n libomxil-vc4-utils
+This package contains some system tools for the Raspberry Pi.
+Source: https://github.com/libomxil-vc4/userland.git
+
+%package -n libomxil-vc4-devel
+Group:         Development/Libraries
+Summary:       Development files for the Raspberry Pi GPU
+
+%description -n libomxil-vc4-devel
+This package contains libraries and header files for developing applications that use Raspberry Pi GPU.
+
+%prep
+%setup -q
+
+%build
+BUILDTYPE=Release
+BUILDSUBDIR=`echo $BUILDTYPE | tr '[A-Z]' '[a-z]'`;
+mkdir -p build/armv7l-linux/$BUILDSUBDIR
+pushd build/armv7l-linux/$BUILDSUBDIR
+cmake -DCMAKE_BUILD_TYPE=Release ../../../
+make
+popd
+
+%install
+mkdir -p %{buildroot}/opt/vc/lib/plugins
+mkdir %{buildroot}/opt/vc/lib/pkgconfig
+mkdir %{buildroot}/opt/vc/bin
+mkdir -p %{buildroot}/opt/vc/include/interface
+pushd %{buildroot}/opt/vc/lib
+cp %{_builddir}/%{name}-%{version}/build/lib/lib*.so ./
+cp %{_builddir}/%{name}-%{version}/build/armv7l-linux/release/bcm_host.pc ./pkgconfig
+cp %{_builddir}/%{name}-%{version}/build/armv7l-linux/release/brcmegl.pc ./pkgconfig
+cp %{_builddir}/%{name}-%{version}/build/armv7l-linux/release/brcmglesv2.pc ./pkgconfig
+cp %{_builddir}/%{name}-%{version}/build/armv7l-linux/release/brcmvg.pc ./pkgconfig
+cp %{_builddir}/%{name}-%{version}/build/armv7l-linux/release/mmal.pc ./pkgconfig
+cp %{_builddir}/%{name}-%{version}/build/armv7l-linux/release/vcsm.pc ./pkgconfig
+cd ./plugins
+cp %{_builddir}/%{name}-%{version}/build/lib/reader_*.so ./
+cp %{_builddir}/%{name}-%{version}/build/lib/writer_*.so ./
+cd ../../bin
+cp %{_builddir}/%{name}-%{version}/build/bin/* ./
+
+cd ../lib
+cp %{_builddir}/%{name}-%{version}/build/lib/lib*.a ./
+cd ../include
+cp -a %{_builddir}/%{name}-%{version}/interface/khronos/include/EGL ./
+cp -a %{_builddir}/%{name}-%{version}/interface/khronos/include/GLES ./
+cp -a %{_builddir}/%{name}-%{version}/interface/khronos/include/GLES2 ./
+cp -a %{_builddir}/%{name}-%{version}/interface/khronos/include/KHR ./
+cp -a %{_builddir}/%{name}-%{version}/interface/khronos/include/VG ./
+cp -a %{_builddir}/%{name}-%{version}/interface/khronos/include/WF ./
+cp -a %{_builddir}/%{name}-%{version}/interface/vmcs_host/khronos/IL ./
+cp -a %{_builddir}/%{name}-%{version}/interface/mmal ./interface/
+cp -a %{_builddir}/%{name}-%{version}/interface/vchi ./interface/
+cp -a %{_builddir}/%{name}-%{version}/interface/vchiq_arm ./interface/
+cp -a %{_builddir}/%{name}-%{version}/interface/vcos ./interface/
+cp -a %{_builddir}/%{name}-%{version}/interface/vctypes ./interface/
+cp -a %{_builddir}/%{name}-%{version}/interface/vmcs_host ./interface/
+cp -a %{_builddir}/%{name}-%{version}/vcinclude ./
+cp %{_builddir}/%{name}-%{version}/host_applications/linux/libs/bcm_host/include/bcm_host.h ./
+popd
+
+%clean
+[ "%{buildroot}" != / ] && rm -rf "%{buildroot}"
+
+%files -n libomxil-vc4-utils
+/opt/vc/bin/*
+%doc LICENCE COPYING
+
+%files -n libomxil-vc4
+%manifest packaging/%{name}.manifest
+%defattr(-,root,root)
+%license LICENCE COPYING
+/opt/vc/lib/lib*.so
+/opt/vc/lib/plugins/*.so
+
+%files -n libomxil-vc4-devel
+/opt/vc/lib/lib*.a
+/opt/vc/include/EGL
+/opt/vc/include/GLES
+/opt/vc/include/GLES2
+/opt/vc/include/IL
+/opt/vc/include/KHR
+/opt/vc/include/VG
+/opt/vc/include/WF
+/opt/vc/include/interface
+/opt/vc/include/vcinclude
+/opt/vc/include/*.h
+/opt/vc/lib/pkgconfig/*.pc
diff --git a/pkgconfig/bcm_host.pc.in b/pkgconfig/bcm_host.pc.in
new file mode 100755 (executable)
index 0000000..c7237c5
--- /dev/null
@@ -0,0 +1,10 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: bcm_host
+Description: Broadcom VideoCore host API library
+Version: 1
+Libs: -L${libdir} -lbcm_host -lvcos -lvchiq_arm -pthread
+Cflags: -I${includedir} -I${includedir}/interface/vmcs_host/linux -I${includedir}/interface/vcos/pthreads -DUSE_VCHIQ_ARM
diff --git a/pkgconfig/brcmegl.pc.in b/pkgconfig/brcmegl.pc.in
new file mode 100755 (executable)
index 0000000..5dd3d5b
--- /dev/null
@@ -0,0 +1,13 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: brcmEGL
+Description: Fake brcmEGL package for RPi
+Version: 10
+Requires: bcm_host
+Libs: -L${libdir} -lbrcmEGL -lbrcmGLESv2 -lbcm_host -lvchostif
+Cflags: -I${includedir} -I${includedir}/interface/vmcs_host/linux \
+        -I${includedir}/interface/vcos/pthreads
+
diff --git a/pkgconfig/brcmglesv2.pc.in b/pkgconfig/brcmglesv2.pc.in
new file mode 100755 (executable)
index 0000000..e0e36f5
--- /dev/null
@@ -0,0 +1,12 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: brcmGLESv2
+Description: Fake brcmGLES2 package for RPi
+Version: 10
+Requires: bcm_host
+Libs: -L${libdir} -lbrcmGLESv2
+Cflags: -I${includedir}
+
diff --git a/pkgconfig/brcmvg.pc.in b/pkgconfig/brcmvg.pc.in
new file mode 100755 (executable)
index 0000000..763a44b
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: brcmOpenVG
+Description: Fake brcmOpenVG package for RPi
+Version: 10
+Requires: bcm_host
+Libs: -L${libdir} -lbrcmOpenVG
+Cflags: -I${includedir}
diff --git a/pkgconfig/egl.pc.in b/pkgconfig/egl.pc.in
new file mode 100755 (executable)
index 0000000..27a6236
--- /dev/null
@@ -0,0 +1,13 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: EGL
+Description: Fake EGL package for RPi
+Version: 10
+Requires: bcm_host
+Libs: -L${libdir} -lEGL -lGLESv2 -lbcm_host -lvchostif
+Cflags: -I${includedir} -I${includedir}/interface/vmcs_host/linux \
+        -I${includedir}/interface/vcos/pthreads
+
diff --git a/pkgconfig/glesv2.pc.in b/pkgconfig/glesv2.pc.in
new file mode 100755 (executable)
index 0000000..5900225
--- /dev/null
@@ -0,0 +1,12 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: GLESv2
+Description: Fake GL ES 2 package for RPi
+Version: 10
+Requires: bcm_host
+Libs: -L${libdir} -lGLESv2
+Cflags: -I${includedir}
+
diff --git a/pkgconfig/mmal.pc.in b/pkgconfig/mmal.pc.in
new file mode 100755 (executable)
index 0000000..37d344c
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: MMAL
+Description: Multi-Media Abstraction Layer library for RPi
+Version: 1
+Requires: vcsm
+Libs: -L${libdir} -lmmal -lmmal_core -lmmal_util -lmmal_vc_client -lbcm_host
+Cflags: -I${includedir}
diff --git a/pkgconfig/vcsm.pc.in b/pkgconfig/vcsm.pc.in
new file mode 100755 (executable)
index 0000000..6780eff
--- /dev/null
@@ -0,0 +1,10 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: VCSM
+Description: VideoCore Shared Memory library for RPi
+Version: 1
+Libs: -L${libdir} -lvcsm
+Cflags: -I${includedir}
diff --git a/pkgconfig/vg.pc.in b/pkgconfig/vg.pc.in
new file mode 100755 (executable)
index 0000000..8c39c98
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@CMAKE_INSTALL_PREFIX@
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: OpenVG
+Description: Fake OpenVG package for RPi
+Version: 10
+Requires: bcm_host
+Libs: -L${libdir} -lOpenVG
+Cflags: -I${includedir}
diff --git a/vcfw/drivers/driver.h b/vcfw/drivers/driver.h
new file mode 100755 (executable)
index 0000000..3e85e7c
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef DRIVER_H_
+#define DRIVER_H_
+
+#include "vcinclude/common.h"
+
+/******************************************************************************
+ Global Macros
+ *****************************************************************************/
+
+// build the driver function table names through macro magic
+#define DRIVER_CONCATENATE(a,b) a##b
+
+//concat the driver name and the _get_func_table extension
+#define DRIVER_NAME(x) DRIVER_CONCATENATE( x, _get_func_table )
+
+/******************************************************************************
+ Global Defines
+ *****************************************************************************/
+
+typedef enum
+{
+   DRIVER_FLAGS_DUMMY
+
+   //   DRIVER_FLAGS_SUPPORTS_CORE_FREQ_CHANGE = 0x1,
+   //   DRIVER_FLAGS_SUPPORTS_RUN_DOMAIN_CHANGE = 0x2,
+   //   DRIVER_FLAGS_SUPPORTS_SUSPEND_RESUME = 0x4
+
+} DRIVER_FLAGS_T;
+
+
+/******************************************************************************
+ Function defines
+ *****************************************************************************/
+
+//Generic handle passed used by all drivers
+typedef struct opaque_driver_handle_t *DRIVER_HANDLE_T;
+
+//Routine to initialise a driver
+typedef int32_t (*DRIVER_INIT_T)( void );
+
+//Routine to shutdown a driver
+typedef int32_t (*DRIVER_EXIT_T)( void );
+
+
+//Routine to return a drivers info (name, version etc..)
+typedef int32_t (*DRIVER_INFO_T)(const char **driver_name,
+                                 uint32_t *version_major,
+                                 uint32_t *version_minor,
+                                 DRIVER_FLAGS_T *flags );
+
+//Routine to open a driver.
+typedef int32_t (*DRIVER_OPEN_T)(const void *params,
+                                 DRIVER_HANDLE_T *handle );
+
+//Routine to close a driver
+typedef int32_t (*DRIVER_CLOSE_T)( const DRIVER_HANDLE_T handle );
+
+
+//Test routine to open a test driver
+typedef int32_t (*DRIVER_TEST_INIT_T)( DRIVER_HANDLE_T *handle );
+
+//Test routine to close a test driver
+typedef int32_t (*DRIVER_TEST_EXIT_T)( const DRIVER_HANDLE_T handle );
+
+/******************************************************************************
+ Driver struct definition
+ *****************************************************************************/
+
+/* Basic driver structure, as implemented by all device drivers */
+#define COMMON_DRIVER_API(param1) \
+   /*Used to be param1... but no drivers were using multiple params and MSVC doesn't like vararg macros*/ \
+   /*Function to initialize the driver. This is used at the start of day to //initialize the driver*/ \
+   DRIVER_INIT_T   init; \
+   \
+   /*Routine to shutdown a driver*/ \
+   DRIVER_EXIT_T   exit; \
+   \
+   /*Function to get the driver name + version*/ \
+   DRIVER_INFO_T   info; \
+   \
+   /*Function to open an instance of the driver. Takes in option parameters, //defined per driver.*/ \
+   /*Returns a handle to the open driver and a success code*/ \
+   int32_t (*open)(param1, \
+                   DRIVER_HANDLE_T *handle ); \
+   \
+   /*Function to close a driver instance*/ \
+   /*Returns success code*/ \
+   DRIVER_CLOSE_T   close;
+
+
+typedef struct
+{
+   //just include the basic driver api
+   COMMON_DRIVER_API(void const *unused)
+
+} DRIVER_T;
+
+
+/******************************************************************************
+ Test Driver struct definition
+ *****************************************************************************/
+
+/* Test driver structure, implemented by all (optional) test drivers */
+
+#define COMMON_DRIVER_TEST_API \
+   /*Function used to tell a driver that the core freq is about to change*/ \
+   /*Returns success code (0 if its ok to change the clock)*/ \
+   DRIVER_TEST_INIT_T   test_init;\
+   \
+   /*Function used to tell a driver if a power domain is about to change*/ \
+   /*Returns success code (0 if its ok to change the power domains)*/ \
+   DRIVER_TEST_EXIT_T   test_exit;
+
+
+typedef struct
+{
+   //just include the test driver api
+   COMMON_DRIVER_TEST_API
+
+} DRIVER_TEST_T;
+
+#define VCFW_AUTO_REGISTER_DRIVER(type, name)      \
+   pragma Data(LIT, ".drivers");                   \
+   static const type * const name##_ptr = &name;   \
+   pragma Data;
+
+#define VCFW_AUTO_REGISTER_BASE_DRIVER(type, name) \
+   pragma Data(LIT, ".drivers_base");              \
+   static const type * const name##_ptr = &name;   \
+   pragma Data;
+
+#endif // DRIVER_H_
diff --git a/vcfw/logging/logging.h b/vcfw/logging/logging.h
new file mode 100755 (executable)
index 0000000..ea09201
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef LOGGING_LOGGING_H
+#define LOGGING_LOGGING_H
+
+#include <stdarg.h>
+
+#include "vcinclude/vcore.h"
+
+/* Bitfield for indicating the category and level of a logging message. */
+#define LOGGING_GENERAL                   (1<<0)  /* for logging general messages */
+#define LOGGING_GENERAL_VERBOSE           (2<<0)
+#define LOGGING_CODECS                    (1<<2)  /* for codec messages */
+#define LOGGING_CODECS_VERBOSE            (2<<2)
+#define LOGGING_FILESYSTEM                (1<<4)  /* filesystem messages */
+#define LOGGING_FILESYSTEM_VERBOSE        (2<<4)
+#define LOGGING_VMCS                      (1<<6)  /* VMCS related messages */
+#define LOGGING_VMCS_VERBOSE              (2<<6)
+#define LOGGING_DISPMAN2                  (1<<8)  /* Dispman2/scalar logs */
+#define LOGGING_DISPMAN2_VERBOSE          (2<<8)
+#define LOGGING_GCE                       (1<<8)  /* Re-use Dispman2 for GCE logging */
+#define LOGGING_GCE_VERBOSE               (2<<8)
+#define LOGGING_CAMPLUS                   (1<<10) /* Camplus logs */
+#define LOGGING_CAMPLUS_VERBOSE           (2<<10)
+#define LOGGING_APPS                      (1<<12) /* Application logs */
+#define LOGGING_APPS_VERBOSE              (2<<12)
+#define LOGGING_CLOCKMAN_POWERMAN         (1<<14) /* Clockman + powerman logs */
+#define LOGGING_CLOCKMAN_POWERMAN_VERBOSE (2<<14)
+#define LOGGING_VCOS                      (1<<16)
+#define LOGGING_VCOS_VERBOSE              (2<<16)
+#define LOGGING_IMAGE_POOL                (1<<18) /* Image pool messages */
+#define LOGGING_IMAGE_POOL_VERBOSE        (2<<18)
+#define LOGGING_HDMI                      (1<<20) /* HDMI and HDCP messages */
+#define LOGGING_HDMI_VERBOSE              (2<<20)
+#define LOGGING_MINIMAL                   (1<<22) /* minimal logging for bandwidth measurement, ie all others off. */
+#define LOGGING_MINIMAL_VERBOSE           (2<<22)
+#define LOGGING_TUNER                     (1<<24) /* ISP Tuner logs - AGC, AWB etc */
+#define LOGGING_TUNER_VERBOSE             (2<<24)
+#define LOGGING_VCHI                      (1<<26) /* For all VCHI based services */
+#define LOGGING_VCHI_VERBOSE              (2<<26)
+#define LOGGING_FOCUS                     (1<<28) /* Focus messages */
+#define LOGGING_HANDLERS                  (1<<29) /* For handler messages */
+#define LOGGING_VOWIFI                    (1<<28) /* Re-use FOCUS for VOWIFI */
+#define LOGGING_VOWIFI_VERBOSE            (2<<28) /* Re-use HANDLERS for VOWIFI */
+// add more here
+#define LOGGING_USER                      (1<<30) /* only for code under development - do not check in! */
+#define LOGGING_USER_VERBOSE              (2<<30)
+
+/* Define some rarely used messages as general messages */
+#define LOGGING_DMB            (LOGGING_GENERAL)         /* DMB logs */
+#define LOGGING_DMB_VERBOSE    (LOGGING_GENERAL_VERBOSE)
+#define LOGGING_MEMORY         (LOGGING_GENERAL)         /* memory task pool logs */
+#define LOGGING_MEMORY_VERBOSE (LOGGING_GENERAL_VERBOSE)
+
+#define LOGGING_ALL 0x55555555                /* log all messages */
+#define LOGGING_ALL_VERBOSE 0xaaaaaaaa
+#define LOGGING_NONE 0                        /* log nothing */
+
+typedef enum {
+   LOGGING_FIFO_LOG = 1,
+   LOGGING_ASSERTION_LOG,
+   LOGGING_TASK_LOG,
+} LOG_FORMAT_T;
+
+typedef struct {
+   LOG_FORMAT_T type;
+   void *log;
+} LOG_DESCRIPTOR_T;
+
+// This header prefixes the logged data on every fifo log entry.
+typedef struct {
+   unsigned long time;
+   unsigned short seq_num;    // if two entries have the same timestamp then this seq num differentiates them.
+   unsigned short size;       // = size of entire log entry = header + data
+} logging_fifo_log_msg_header_t;
+
+// This describes the state of a fifo type log.
+typedef struct {
+   char name[4];
+   unsigned char *start;      // Start and End are defined when the log is created.
+   unsigned char *end;
+   unsigned char *ptr;        // Always points to where the next contents will be written.
+   unsigned char *next_msg;   // Points to the first entry in the fifo. Is updated when the fifo gets full and overwrites the oldest entry.
+   logging_fifo_log_msg_header_t msg_header;    // used to keep track of forming a log entry between calls to _start and _end.
+} logging_fifo_log_t;
+
+// This describes the state of an array type log.
+typedef struct {
+   char name[4];
+   unsigned short nitems, item_size;
+   unsigned long available;
+   unsigned char *data;
+} logging_array_log_t;
+
+
+// The header at the start of the log may be one of a number of different types,
+// but they all start with a common portion:
+
+#define LOGGING_SYNC 'VLOG'
+
+typedef unsigned long LOGGING_LOG_TYPE_T;
+#define LOGGING_LOG_TYPE_VCLIB ((LOGGING_LOG_TYPE_T) 0)
+#define LOGGING_LOG_TYPE_VMCS  ((LOGGING_LOG_TYPE_T) 1)
+
+typedef struct {
+   unsigned long sync;
+   LOGGING_LOG_TYPE_T type;
+   unsigned long version;
+   void *self;
+} logging_common_header_t;
+
+#define N_VCLIB_LOGS  3  //Does not include the task switch log
+
+// This is the top level data structure for the Videocore Logs. It houses several
+// logs from different sources as well as extra state info.
+typedef struct {
+   logging_common_header_t common;
+   unsigned long stc;
+   int task_switch_log_size;
+   unsigned char *task_switch_log;
+   unsigned long n_logs;
+   LOG_DESCRIPTOR_T assertion_log;
+   LOG_DESCRIPTOR_T message_log;
+   LOG_DESCRIPTOR_T task_log;
+
+   //LOG_DESCRIPTOR_T logs[N_VCLIB_LOGS - 3];
+
+   //logging_fifo_log_t *assertion_log;
+   //logging_fifo_log_t *message_log;
+   //logging_array_log_t *task_log;
+} logging_header_t;
+
+typedef void (*logging_notify_callback_fn)( void );
+
+#ifdef LOGGING
+
+#ifndef BLOGGING
+
+/* Initialise a log for use, supplying the memory where it starts and the
+   number of bytes available. */
+void logging_fifo_log_init(logging_fifo_log_t *log, const char *name, void *start, int size);
+
+/* Begin writing a log message. */
+void logging_fifo_log_start(logging_fifo_log_t *log);
+/* Write nbytes of message data. */
+void logging_fifo_log_write(logging_fifo_log_t *log, const void *ptr, int nbytes);
+/* Finish a log message. */
+void logging_fifo_log_end(logging_fifo_log_t *log);
+
+/* Read a log message */
+int logging_read( LOG_FORMAT_T logFormat, void *buf, int bufLen );
+
+/* Initialise an array log. */
+void logging_array_log_init(logging_array_log_t *log, char *name, int nitems, int item_size, void *data, int total_size);
+/* Add an item to the array log. */
+void logging_array_log_add(logging_array_log_t *log, unsigned long key, void *data, int nbytes);
+/* Remove an item. */
+void logging_array_log_delete(logging_array_log_t *log, unsigned long key);
+
+/* Initialise vclib's logging fifos. */
+void logging_init();
+
+/* Reset assert log */
+void logging_assert_reset();
+
+/* Reset mesage log */
+void logging_message_reset();
+
+/* Setup a fifo in the given block of memory. */
+unsigned char *logging_setup_fifo (logging_fifo_log_t **ptr, const char *name, unsigned char *addr, int fifo_size);
+/* Set the current logging level. */
+void logging_level(int level);
+/* Get the current logging level. */
+int logging_get_level(void);
+/* Test if a logging level will actually produce logging messages. */
+int logging_will_log(int level);
+/* Log an assertion. */
+void logging_assert(const char *file, const char *func, int line, const char *format, ...);
+/* dumps registers and stack which get printed by logging_assert */
+void logging_assert_dump(void);
+/* Log a general message. */
+void logging_message(int level, const char *format, ...);
+void vlogging_message (int level, const char *format, va_list args);
+
+
+/* Log a simple string */
+void logging_string(int level, const char *string);
+/* The log for recording the current tasks. */
+logging_array_log_t *logging_task_log(void);
+
+void logging_set_notify_callback( logging_notify_callback_fn fn );
+
+/* Dump log to sdcard, discarding any logging that happens during the file write */
+int logging_dump_log(char* filename);
+
+/* Dump log to sdcard. If a sufficiently large temporary buffer is not provided, 
+logging messages will be discarded during the file write. */
+int logging_dump_log_buffered(char* filename, void *buffer, int buffer_size);
+
+/* Parse a fifo log entry and put it into a human readable string. */
+int logging_fifo_extract_entry(logging_fifo_log_t *log, const unsigned char *entry_ptr, char *target_buffer, int target_size);
+
+/* Log a hexadecimal representation of the first num_bytes of byte_array,
+   formatted to format using logging_message() at logging-level level. */
+int logging_message_hex(int level, const char *format, const void *byte_array, int num_bytes);
+
+/* Log a hexadecimal representation of the Vector Register File contents.*/
+int logging_message_vrf(int level);
+
+/* Append logging to a file. If flag set, only output to the file */
+int logging_set_logfile(const char *file, int only_to_file);
+
+/* Close the file opened above */
+void logging_close_logfile(void);
+
+#ifdef WANT_LOGGING_UART
+/* Enables/disables outputing log messages to the UART. */
+void logging_uart_enable_output(int enable_output);
+/* Set the current UART logging level. */
+void logging_level_uart(int level);
+/* Get the current UART logging level. */
+int logging_get_level_uart(void);
+#endif
+
+unsigned char* get_message_log_ptr_and_size (int* size);
+
+#else   // BLOGGING
+
+#include "vcfw/blogging/blogging.h"
+
+#define logging_fifo_log_init(log, start, size)
+#define logging_fifo_log_start(log)
+#define logging_fifo_log_write(log, ptr, nbytes)
+#define logging_fifo_log_end(log)
+
+#endif  // BLOGGING
+
+/* Cause the assert macro to log a message if it's defined. Only changed without NDEBUG, though other assert macros still work.*/
+#ifdef __VIDEOCORE__
+#if !defined(NDEBUG) && defined(assert)
+#undef assert
+#ifndef ARTS
+#define assert(cond) \
+   ( (cond) ? (void)0 : (_bkpt(),logging_assert_dump(),logging_assert(__FILE__, __func__, __LINE__, #cond)))
+#else //ARTS
+#define assert(cond) \
+   ( (cond) ? (void)0 : (logging_assert_dump(),logging_assert(__FILE__, __func__, __LINE__, #cond)))
+#endif //ARTS
+#endif // !defined(NDEBUG) && defined(assert)
+
+/* This will only trigger assert first time it fires */
+#define assert_once(cond,comment) \
+   do { \
+      static char i_asrt=0; \
+      if (!(cond)) { \
+         if (i_asrt==0) { \
+            _bkpt(); \
+            i_asrt++; \
+            logging_assert_dump(),logging_assert(__FILE__, __func__, __LINE__, (comment)); \
+         } \
+      } \
+   } while (0)
+
+#define assert_comment(cond, comment) if (cond) {} else logging_assert_dump(),logging_assert(__FILE__, __func__, __LINE__,(comment))
+
+#else
+   #ifndef ARTS
+      #include <assert.h>
+   #else
+      #undef assert
+      #define assert(cond) ( (cond) ? (void)0 : (logging_assert_dump(),logging_assert(__FILE__, __FUNCTION__, __LINE__, #cond)))
+   #endif
+
+#define assert_once(cond,comment) \
+   do { \
+      static char i_asrt=0; \
+      if (!(cond)) { \
+         if (i_asrt==0) { \
+            i_asrt++; \
+            logging_assert_dump(),logging_assert(__FILE__, __func__, __LINE__, (comment)); \
+         } \
+      } \
+   } while (0)
+
+#endif // not __VIDEOCORE__
+
+#else   //LOGGING
+
+#define logging_fifo_log_init(log, start, size)
+
+#define logging_fifo_log_start(log)
+#define logging_fifo_log_write(log, ptr, nbytes)
+#define logging_fifo_log_end(log)
+
+#define logging_array_log_init(log, nitems, item_size, data, total_size)
+#define logging_array_log_add(log, key, data, nbytes)
+#define logging_array_log_delete(log, key)
+
+#define logging_init()
+#define logging_level(level)
+#define logging_get_level() 0
+#define logging_assert(file, func, line, ...)
+#define logging_message_hex(level, format, byte_array, num_bytes)
+#define logging_dump_log(filename) -1
+#define logging_will_log(level) 0
+
+#ifndef EDID_TOOL //logging_message is mapped to printf for our edid_parser tool
+/* Hacky way of getting rid of a var args function with a macro... */
+static __inline void logging_message (int level, const char *format, ...) { }
+#endif
+#define vlogging_message(level, format, args)
+#define logging_string(level, string)
+
+#define logging_task_log()
+
+#define assert_periodic(cond,nreps,dt,comment)
+#define assert_once(cond,comment)
+#define assert_comment(cond, comment)
+
+#define logging_set_notify_callback(fn)
+
+#endif  // LOGGING
+
+#endif // LOGGING_LOGGING_H
+
diff --git a/vcfw/rtos/common/rtos_common_mem.h b/vcfw/rtos/common/rtos_common_mem.h
new file mode 100755 (executable)
index 0000000..33ea2a7
--- /dev/null
@@ -0,0 +1,1360 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef COMMON_MEM_H
+#define COMMON_MEM_H
+
+#ifndef MEM_DONT_USE_SMALL_ALLOC_POOL
+#define MEM_USE_SMALL_ALLOC_POOL
+#endif
+
+#ifndef MEM_CHUNK_SIZE
+#define MEM_CHUNK_SIZE           0x40000
+#endif
+
+#include <stdarg.h>
+
+#include "vcinclude/common.h"
+
+#ifdef _MSC_VER
+   #define RCM_ALIGNOF(T) __alignof(T)
+#else
+   #define RCM_ALIGNOF(T) (sizeof(struct { T t; char ch; }) - sizeof(T))
+#endif
+
+#ifdef _MSC_VER
+   #define RCM_INLINE __inline
+#else
+   #ifdef __LCC__
+      #define RCM_INLINE
+   #else
+      #define RCM_INLINE inline
+   #endif
+#endif
+
+/******************************************************************************
+Global initialisation helpers
+******************************************************************************/
+
+/*
+   Locate the relocatable heap partition, or malloc sufficient space, then
+   call mem_init.
+ */
+int32_t rtos_common_mem_init( void );
+
+/******************************************************************************
+Pool management API
+******************************************************************************/
+
+/*
+   Options for mem_compact.
+*/
+
+typedef enum
+{
+   /* these values are duplicated in rtos_common_mem.inc */
+
+   MEM_COMPACT_NONE       = 0,   /* No compaction allowed */
+   MEM_COMPACT_NORMAL     = 1,   /* Move unlocked blocks */
+   MEM_COMPACT_DISCARD    = 2,   /* _NORMAL + discard blocks where possible */
+   MEM_COMPACT_AGGRESSIVE = 4,   /* _NORMAL + move locked blocks where possible */
+   MEM_COMPACT_ALL        = MEM_COMPACT_NORMAL | MEM_COMPACT_DISCARD | MEM_COMPACT_AGGRESSIVE,
+   MEM_COMPACT_NOT_BLOCKING = 8,    /* don't retry if initial allocation fails */
+
+   MEM_COMPACT_SHUFFLE    = 0x80 /* Move the lowest unlocked block up to the top
+                                    (space permitting) - for testing */
+} mem_compact_mode_t;
+
+/*
+   Get default values for memory pool defined in the platform makefile
+*/
+
+extern void mem_get_default_partition(void **mempool_base, uint32_t *mempool_size, void **mempool_handles_base, uint32_t *mempool_handles_size);
+
+/*
+   Initialize the memory subsystem, allocating a pool of a given size and
+   with space for the given number of handles.
+*/
+
+extern int mem_init(void *mempool_base, uint32_t mempool_size, void *mempool_handles_base, uint32_t mempool_handles_size);
+
+/*
+   Terminate the memory subsystem, releasing the pool.
+*/
+
+extern void mem_term(void);
+
+/*
+   The heap is compacted to the maximum possible extent. If (mode & MEM_COMPACT_DISCARD)
+   is non-zero, all discardable, unlocked, and unretained MEM_HANDLE_Ts are resized to size 0.
+   If (mode & MEM_COMPACT_AGGRESSIVE) is non-zero, all long-term block owners (which are
+   obliged to have registered a callback) are asked to unlock their blocks for the duration
+   of the compaction.
+*/
+
+extern void mem_compact(mem_compact_mode_t mode);
+
+/******************************************************************************
+Movable memory core API
+******************************************************************************/
+
+/*
+   A MEM_HANDLE_T refers to a movable block of memory.
+
+   The only way to get a MEM_HANDLE_T is to call mem_alloc.
+
+   The MEM_HANDLE_T you get is immutable and remains valid until its reference
+   count reaches 0.
+
+   A MEM_HANDLE_T has an initial reference count of 1. This can be incremented
+   by calling mem_acquire and decremented by calling mem_release.
+*/
+
+/*
+   MEM_ZERO_SIZE_HANDLE is a preallocated handle to a zero-size block of memory
+   MEM_EMPTY_STRING_HANDLE is a preallocated handle to a block of memory containing the empty string
+
+   MEM_HANDLE_INVALID is the equivalent of NULL for MEM_HANDLE_Ts -- no valid
+   MEM_HANDLE_T will ever equal MEM_HANDLE_INVALID.
+*/
+
+typedef enum { /* enum to get stricter type checking on msvc */
+#ifdef MEM_USE_SMALL_ALLOC_POOL
+   MEM_ZERO_SIZE_HANDLE = 0x80000000,
+   MEM_EMPTY_STRING_HANDLE = 0x80000001,
+#else
+   MEM_ZERO_SIZE_HANDLE = 1,
+   MEM_EMPTY_STRING_HANDLE = 2,
+#endif
+
+   MEM_HANDLE_INVALID = 0,
+
+   MEM_HANDLE_FORCE_32BIT = 0x80000000,
+
+   // deprecated - for backward compatibility
+   MEM_INVALID_HANDLE = MEM_HANDLE_INVALID
+} MEM_HANDLE_T;
+
+
+/*
+   Flags are set once in mem_alloc -- they do not change over the lifetime of
+   the MEM_HANDLE_T.
+*/
+
+typedef enum {
+   MEM_FLAG_NONE = 0,
+
+   /*
+      If a MEM_HANDLE_T is discardable, the memory manager may resize it to size
+      0 at any time when it is not locked or retained.
+   */
+
+   MEM_FLAG_DISCARDABLE = 1 << 0,
+
+   /*
+      MEM_FLAG_RETAINED should only ever be used when passing flags to
+      mem_alloc. If it is set, the initial retain count is 1, otherwise it is 0.
+   */
+
+   MEM_FLAG_RETAINED = 1 << 9, /* shared with MEM_FLAG_ABANDONED. only used when passing flags to mem_alloc */
+
+   /*
+      Block must be kept within bottom 256M region of the relocatable heap.
+      Specifying this flag means that an allocation will fail if the block
+      cannot be allocated within that region, and the block will not be moved
+      out of that range.
+      (This is to support memory blocks used by the codec cache, which must
+      have same top 4 bits; see HW-3058)
+      This flag is ignored on non-VideoCore platforms.
+   */
+
+   MEM_FLAG_LOW_256M = 1 << 1,
+
+   /*
+      Define a mask to extract the memory alias used by the block of memory.
+   */
+
+   MEM_FLAG_ALIAS_MASK = 3 << 2,
+
+   /*
+      If a MEM_HANDLE_T is allocating (or normal), its block of memory will be
+      accessed in an allocating fashion through the cache.
+   */
+
+   MEM_FLAG_NORMAL = 0 << 2,
+   MEM_FLAG_ALLOCATING = MEM_FLAG_NORMAL,
+
+   /*
+      If a MEM_HANDLE_T is direct, its block of memory will be accessed
+      directly, bypassing the cache.
+   */
+
+   MEM_FLAG_DIRECT = 1 << 2,
+
+   /*
+      If a MEM_HANDLE_T is coherent, its block of memory will be accessed in a
+      non-allocating fashion through the cache.
+   */
+
+   MEM_FLAG_COHERENT = 2 << 2,
+
+   /*
+      If a MEM_HANDLE_T is L1-nonallocating, its block of memory will be accessed by
+      the VPU in a fashion which is allocating in L2, but only coherent in L1.
+   */
+
+   MEM_FLAG_L1_NONALLOCATING = (MEM_FLAG_DIRECT | MEM_FLAG_COHERENT),
+
+   /*
+      If a MEM_HANDLE_T is zero'd, its contents are set to 0 rather than
+      MEM_HANDLE_INVALID on allocation and resize up.
+   */
+
+   MEM_FLAG_ZERO = 1 << 4,
+
+   /*
+      If a MEM_HANDLE_T is uninitialised, it will not be reset to a defined value
+      (either zero, or all 1's) on allocation.
+    */
+
+   MEM_FLAG_NO_INIT = 1 << 5,
+
+   /*
+      The INIT flag is a placeholder, designed to make it explicit that
+      initialisation is required, and to make it possible to change the sense
+      of this bit at a later date.
+    */
+
+   MEM_FLAG_INIT    = 0 << 5,
+
+   /*
+      Hints.
+   */
+
+   MEM_FLAG_HINT_PERMALOCK = 1 << 6, /* Likely to be locked for long periods of time. */
+
+   MEM_FLAG_HINT_ALL = 0xc0,
+
+   MEM_FLAG_USER = 1 << 7,
+   MEM_FLAG_HINT_GROW      = 1 << 7, /* Likely to grow in size over time. If this flag is specified, MEM_FLAG_RESIZEABLE must also be. */
+
+   MEM_FLAG_UNUSED = 1 << 7,
+
+   /*
+      If a MEM_HANDLE_T is to be resized with mem_resize, this flag must be
+      present. This flag prevents things from being allocated out of the small
+      allocation pool.
+   */
+   MEM_FLAG_RESIZEABLE = 1 << 8,
+
+   /*
+      If the ABANDONED flag is set, because mem_abandon was called when the lock
+      count was zero, the contents are undefined. This flag is cleared by
+      mem_lock. Automatically set for blocks allocated with MEM_FLAG_NO_INIT.
+   */
+
+   MEM_FLAG_ABANDONED = 1 << 9, /* shared with MEM_FLAG_RETAINED. never used when passing flags to mem_alloc */
+
+   /* There is currently room in MEM_HEADER_X_T for 10 flags */
+   MEM_FLAG_ALL = 0x3ff
+} MEM_FLAG_T;
+
+/*
+   A MEM_HANDLE_T may optionally have a terminator. This is a function that will
+   be called just before the MEM_HANDLE_T becomes invalid: see mem_release.
+*/
+
+typedef void (*MEM_TERM_T)(void *, uint32_t);
+
+
+/*
+   A common way of storing a MEM_HANDLE_T together with an offset into it.
+*/
+
+typedef struct
+{
+   MEM_HANDLE_T mh_handle;
+   uint32_t offset;
+} MEM_HANDLE_OFFSET_T;
+
+/*
+   Attempts to allocate a movable block of memory of the specified size and
+   alignment. size may be 0. A MEM_HANDLE_T with size 0 is special: see
+   mem_lock/mem_unlock. mode specifies the types of compaction permitted,
+   including MEM_COMPACT_NONE.
+
+   Preconditions:
+
+   - align is a power of 2.
+   - flags only has set bits within the range specified by MEM_FLAG_ALL.
+   - desc is NULL or a pointer to a null-terminated string.
+   - the caller of this function is contracted to later call mem_release (or pass such responsibility on) if we don't return MEM_HANDLE_INVALID
+
+   Postconditions:
+
+   If the attempt succeeds:
+   - A fresh MEM_HANDLE_T referring to the allocated block of memory is
+     returned.
+   - The MEM_HANDLE_T is unlocked, without a terminator, and has a reference
+     count of 1.
+   - If MEM_FLAG_RETAINED was specified, the MEM_HANDLE_T has a retain count of
+     1, otherwise it is unretained.
+   - If the MEM_FLAG_ZERO flag was specified, the block of memory is set to 0.
+     Otherwise, each aligned word is set to MEM_HANDLE_INVALID.
+
+   If the attempt fails:
+   - MEM_HANDLE_INVALID is returned.
+*/
+
+extern MEM_HANDLE_T mem_alloc_ex(
+   uint32_t size,
+   uint32_t align,
+   MEM_FLAG_T flags,
+   const char *desc,
+   mem_compact_mode_t mode);
+
+#define mem_alloc(s,a,f,d) mem_alloc_ex(s,a,f,d,MEM_COMPACT_ALL)
+
+#define MEM_WRAP_HACK
+
+#ifdef MEM_WRAP_HACK
+extern MEM_HANDLE_T mem_wrap(void *p, uint32_t size, uint32_t align, MEM_FLAG_T flags, const char *desc);
+
+typedef void (*MEM_WRAP_TERM_T)(void */*priv*/, MEM_HANDLE_T /*term_handle*/, void */*p*/, int /*size*/);
+
+/*
+   int mem_wrap_set_on_term(MEM_HANDLE_T handle, MEM_WRAP_TERM_T term_cb, void *cb_priv);
+
+   Adds an additional release callback for wrapped MEM_HANDLE_T.
+   This allows the underlying allocator to release the wrapped memory.
+   The MEM_HANDLE_T must NOT be accessed with mem_lock/mem_acquire etc
+   from the callback context as the handle is already partially released.
+*/
+extern int mem_wrap_set_on_term(MEM_HANDLE_T handle, MEM_WRAP_TERM_T term_cb, void *cb_priv);
+
+#endif
+
+/*
+   Preconditions:
+
+   - handle is a valid MEM_HANDLE_T.
+
+   Postconditions:
+
+   - The reference count of the MEM_HANDLE_T is incremented.
+*/
+
+extern void mem_acquire(
+   MEM_HANDLE_T handle);
+
+/*
+   Calls mem_acquire and also calls mem_retain if the handle is discardable.
+*/
+
+extern void mem_acquire_retain(MEM_HANDLE_T handle);
+
+/*
+   If the reference count of the MEM_HANDLE_T is 1 and it has a terminator, the
+   terminator is called with a pointer to and the size of the MEM_HANDLE_T's
+   block of memory (or NULL/0 if the size of the MEM_HANDLE_T is 0). The
+   MEM_HANDLE_T may not be used during the call.
+
+   Preconditions:
+
+   - handle is a valid MEM_HANDLE_T.
+   - If its reference count is 1, it must not be locked or retained.
+
+   Postconditions:
+
+   If the reference count of the MEM_HANDLE_T was 1:
+   - The MEM_HANDLE_T is now invalid. The associated block of memory has been
+     freed.
+
+   Otherwise:
+   - The reference count of the MEM_HANDLE_T is decremented.
+*/
+
+extern void mem_release(
+   MEM_HANDLE_T handle);
+
+/*
+   Preconditions:
+
+   - handle is a valid MEM_HANDLE_T.
+
+   Postconditions:
+
+   If the reference count of the MEM_HANDLE_T was 1:
+   - false is returned.
+   - The reference count of the MEM_HANDLE_T is still 1.
+
+   Otherwise:
+   - true is returned.
+   - The reference count of the MEM_HANDLE_T is decremented.
+*/
+
+extern int mem_try_release(
+   MEM_HANDLE_T handle);
+
+/*
+   Preconditions:
+
+   - handle is a valid MEM_HANDLE_T.
+
+   Postconditions:
+
+   - The total space used by the MEM_HANDLE_T is returned (this includes the
+     header, the actual block, and padding).
+   - sum_over_handles(mem_get_space(handle)) + mem_get_free_space() is constant
+     over the lifetime of the pool.
+*/
+
+extern uint32_t mem_get_space(
+   MEM_HANDLE_T handle);
+
+/*
+   uint32_t mem_get_size(MEM_HANDLE_T handle);
+
+   The size of the MEM_HANDLE_T's block of memory is returned.
+   This is consistent with the size requested in a mem_alloc call.
+
+   Implementation notes:
+
+   -
+
+   Preconditions:
+
+   handle is not MEM_HANDLE_INVALID
+
+   Postconditions:
+
+   result <= INT_MAX
+
+   Invariants preserved:
+
+   -
+*/
+
+extern uint32_t mem_get_size(
+   MEM_HANDLE_T handle);
+
+/*
+   Preconditions:
+
+   - handle is a valid MEM_HANDLE_T.
+
+   Postconditions:
+
+   - The minimum required alignment of the MEM_HANDLE_T's block of memory (as
+     passed to mem_alloc) is returned.
+   -
+*/
+
+extern uint32_t mem_get_align(
+   MEM_HANDLE_T handle);
+
+/*
+   Preconditions:
+
+   - handle is a valid MEM_HANDLE_T.
+
+   Postconditions:
+
+   - The MEM_HANDLE_T's flags (as passed to mem_alloc) are returned.
+*/
+
+extern MEM_FLAG_T mem_get_flags(
+   MEM_HANDLE_T handle);
+
+/*
+   Preconditions:
+
+   - handle is a valid MEM_HANDLE_T.
+
+   Postconditions:
+
+   - The MEM_HANDLE_T's reference count is returned.
+*/
+
+extern uint32_t mem_get_ref_count(
+   MEM_HANDLE_T handle);
+
+/*
+   Preconditions:
+
+   - handle is a valid MEM_HANDLE_T.
+
+   Postconditions:
+
+   - The MEM_HANDLE_T's lock count is returned.
+*/
+
+extern uint32_t mem_get_lock_count(
+   MEM_HANDLE_T handle);
+
+/*
+   Preconditions:
+
+   - handle is a valid MEM_HANDLE_T.
+
+   Postconditions:
+
+   - The MEM_HANDLE_T's retain count is returned.
+*/
+
+extern uint32_t mem_get_retain_count(
+   MEM_HANDLE_T handle);
+
+/*
+   Preconditions:
+
+   - handle is a valid MEM_HANDLE_T.
+
+   Postconditions:
+
+   - The MEM_HANDLE_T's description string is returned.
+*/
+
+extern const char *mem_get_desc(
+   MEM_HANDLE_T handle);
+
+/*
+   Preconditions:
+
+   - handle is a valid MEM_HANDLE_T.
+   - desc is NULL or a pointer to a null-terminated string.
+
+   Postconditions:
+
+   - The MEM_HANDLE_T's description is set to desc.
+*/
+
+extern void mem_set_desc(
+   MEM_HANDLE_T handle,
+   const char *desc);
+
+extern void mem_set_desc_vprintf(
+   MEM_HANDLE_T handle,
+   const char *fmt,
+   va_list ap);
+
+extern void mem_set_desc_printf(
+   MEM_HANDLE_T handle,
+   const char *fmt,
+   ...);
+
+/*
+   void mem_set_term(MEM_HANDLE_T handle, MEM_TERM_T term)
+
+   The MEM_HANDLE_T's terminator is set to term (if term was NULL, the
+   MEM_HANDLE_T no longer has a terminator).
+   The MEM_HANDLE_T's terminator is called just before the MEM_HANDLE_T becomes
+   invalid: see mem_release.
+
+   Preconditions:
+
+   handle is a valid handle to a (possibly uninitialised or partially initialised*)
+   object of type X
+
+   This implies mem_get_size(handle) == sizeof(type X)
+
+   memory management invariants for handle are satisfied
+
+   term must be NULL or a pointer to a function compatible with the MEM_TERM_T
+   type:
+
+      void *term(void *v, uint32_t size)
+
+   if term is not NULL, its precondition must be no stronger than the following:
+       is only called from memory manager internals during destruction of an object of type X
+       v is a valid pointer to a (possibly uninitialised or partially initialised*) object of type X
+       memory management invariants for v are satisfied
+       size == sizeof(type X)
+
+   if term is not NULL, its postcondition must be at least as strong as the following:
+       Frees any references to resources that are referred to by the object of type X
+
+
+   Postconditions:
+
+   -
+*/
+
+extern void mem_set_term(
+   MEM_HANDLE_T handle,
+   MEM_TERM_T term);
+
+/*
+   Preconditions:
+
+   - handle is a valid MEM_HANDLE_T.
+
+   Postconditions:
+
+   - The MEM_HANDLE_T's terminator is returned, or NULL if there is none.
+*/
+
+extern MEM_TERM_T mem_get_term(
+   MEM_HANDLE_T handle);
+
+/*
+   void mem_set_user_flag(MEM_HANDLE_T handle, int flag)
+
+   Preconditions:
+
+   - handle is a valid MEM_HANDLE_T.
+
+   Postconditions:
+
+   - The MEM_HANDLE_T's user flag is set to 0 if flag is 0, or to 1 otherwise.
+*/
+
+extern void mem_set_user_flag(
+   MEM_HANDLE_T handle, int flag);
+
+/*
+   Attempts to resize the MEM_HANDLE_T's block of memory. The attempt is
+   guaranteed to succeed if the new size is less than or equal to the old size.
+   size may be 0. A MEM_HANDLE_T with size 0 is special: see
+   mem_lock/mem_unlock. mode specifies the types of compaction permitted,
+   including MEM_COMPACT_NONE.
+
+   Preconditions:
+
+   - handle is a valid MEM_HANDLE_T.
+   - It must not be locked.
+
+   Postconditions:
+
+   If the attempt succeeds:
+   - true is returned.
+   - The MEM_HANDLE_T's block of memory has been resized.
+   - The contents in the region [0, min(old size, new size)) are unchanged. If
+     the MEM_HANDLE_T is zero'd, the region [min(old size, new size), new size)
+     is set to 0. Otherwise, each aligned word in the region
+     [min(old size, new size), new size) is set to MEM_HANDLE_INVALID.
+
+   If the attempt fails:
+   - false is returned.
+   - The MEM_HANDLE_T is still valid.
+   - Its block of memory is unchanged.
+*/
+
+extern int mem_resize_ex(
+   MEM_HANDLE_T handle,
+   uint32_t size,
+   mem_compact_mode_t mode);
+
+#define mem_resize(h,s) mem_resize_ex(h,s,MEM_COMPACT_ALL)
+
+/*
+   A MEM_HANDLE_T with a lock count greater than 0 is considered to be locked
+   and may not be moved by the memory manager.
+
+   Preconditions:
+
+   - handle is a valid MEM_HANDLE_T.
+
+   Postconditions:
+
+   If the MEM_HANDLE_T's size is 0:
+   - NULL is returned.
+   - The MEM_HANDLE_T is completely unchanged.
+
+   Otherwise:
+   - A pointer to the MEM_HANDLE_T's block of memory is returned. The pointer is
+     valid until the MEM_HANDLE_T's lock count reaches 0.
+   - The MEM_HANDLE_T's lock count is incremented.
+   - Clears MEM_FLAG_ABANDONED.
+*/
+
+/*@null@*/ extern void *mem_lock(
+   MEM_HANDLE_T handle);
+
+/*
+   Lock a number of memory handles and store the results in an array of pointers.
+   May be faster than calling mem_lock repeatedly as we only need to acquire the
+   memory mutex once.
+   For convenience you can also pass invalid handles in, and get out either null pointers or
+   valid pointers (depending on the associated offset field)
+
+   Preconditions:
+
+   pointers is a valid pointer to n elements
+   handles is a valid pointer to n elements
+   For all 0 <= i < n
+   - handles[i].mh_handle is MEM_HANDLE_INVALID or a valid MEM_HANDLE_T.
+   - If handles[i] != MEM_HANDLE_INVALID then handles[i].offset <= handles[i].size
+
+   Postconditions:
+
+   For all 0 <= i < n
+      If handles[i] == MEM_HANDLE_INVALID:
+      - pointers[i] is set to offsets[i]
+
+      Else if handles[i].mh_handle.size == 0:
+      - pointers[i] is set to 0.
+      - handles[i].mh_handle is completely unchanged.
+
+      Otherwise:
+      - pointers[i] is set to a pointer which is valid until handles[i].lockcount reaches 0
+      - pointers[i] points to a block of size (handles[i].size - handles[i].offset)
+      - handles[i].mh_handle.lockcount is incremented.
+      - MEM_FLAG_ABANDONED is cleared in handles[i].mh_handle.x.flags
+*/
+
+extern void mem_lock_multiple(
+   void **pointers,
+   MEM_HANDLE_OFFSET_T *handles,
+   uint32_t n);
+
+/*
+   Preconditions:
+
+   - handle is a valid MEM_HANDLE_T.
+   - If its size is not 0, it must be locked.
+
+   Postconditions:
+
+   If the MEM_HANDLE_T's size is 0:
+   - The MEM_HANDLE_T is completely unchanged.
+
+   Otherwise:
+   - The MEM_HANDLE_T's lock count is decremented.
+*/
+
+extern void mem_unlock(
+   MEM_HANDLE_T handle);
+
+/*
+   Unlock a number of memory handles.
+   May be faster than calling mem_unlock repeatedly as we only need to acquire the
+   memory mutex once.
+
+   Preconditions:
+
+   pointers is a valid pointer to n elements
+   handles is a valid pointer to n elements
+   For all 0 <= i < n
+   - handles[i].mh_handle is a valid MEM_HANDLE_T.
+   - If handles[i].mh_handle.size is not 0, it must be locked.
+
+   Postconditions:
+
+   For all 0 <= i < n
+      If handles[i] == MEM_HANDLE_INVALID or handles[i].mh_handle.size == 0:
+      - handles[i].mh_handle is completely unchanged.
+
+      Otherwise:
+      - handles[i].mh_handle.lockcount is decremented.
+*/
+
+extern void mem_unlock_multiple(
+   MEM_HANDLE_OFFSET_T *handles,
+   uint32_t n);
+
+/*
+   Like mem_unlock_multiple, but will unretain handles if they are discardable.
+   Also releases handles.
+*/
+
+extern void mem_unlock_unretain_release_multiple(
+   MEM_HANDLE_OFFSET_T *handles,
+   uint32_t n);
+
+/*
+   Like mem_unlock_unretain_release_multiple, but without the unlocking.
+   Also releases handles.
+*/
+
+extern void mem_unretain_release_multiple(
+   MEM_HANDLE_OFFSET_T *handles,
+   uint32_t n);
+
+/*
+   Preconditions:
+
+   - handle is a valid MEM_HANDLE_T.
+
+   Postconditions:
+
+   If the MEM_HANDLE_T is not a small handle:
+   - Sets MEM_FLAG_ABANDONED, which causes the data content to become undefined
+    when the lock count reaches zero.
+   - Sets MEM_FLAG_NO_INIT.
+
+   Otherwise:
+   - Does nothing.
+*/
+
+extern void mem_abandon(
+   MEM_HANDLE_T handle);
+
+/*
+   A discardable MEM_HANDLE_T with a retain count greater than 0 is
+   considered retained and may not be discarded by the memory manager.
+
+   Preconditions:
+
+   - handle is a valid MEM_HANDLE_T.
+   - It must be discardable.
+
+   Postconditions:
+
+   - 0 is returned if the size of the MEM_HANDLE_T's block of memory is 0,
+     otherwise 1 is returned.
+   - The retain count of the MEM_HANDLE_T is incremented.
+*/
+
+extern int mem_retain(
+   MEM_HANDLE_T handle);
+
+/*
+   Preconditions:
+
+   - handle is a valid MEM_HANDLE_T.
+   - It must be retained.
+
+   Postconditions:
+
+   - The retain count of the MEM_HANDLE_T is decremented.
+*/
+
+extern void mem_unretain(
+   MEM_HANDLE_T handle);
+
+/*
+   A version of mem_lock which adds an indication that an aggressive compaction
+   should not wait for the block to be unlocked.
+*/
+
+extern void *mem_lock_perma(
+   MEM_HANDLE_T handle);
+
+/*
+   A version of mem_unlock which removes an indication that an aggressive
+   compaction should not wait for the block to be unlocked.
+*/
+
+extern void mem_unlock_perma(
+   MEM_HANDLE_T handle);
+
+/******************************************************************************
+Legacy memory blocks API
+******************************************************************************/
+
+/*
+   Allocate a fixed-size block. The size of legacy blocks is a constant for the
+   life of the memory subsystem (and may be a build-time constant). Legacy
+   blocks are stored in offline chunks, so this is a veneer over mem_offline.
+
+   Preconditions:
+
+   - flags must specify a memory alias
+     o MEM_FLAG_NORMAL
+     o MEM_FLAG_COHERENT
+     o MEM_FLAG_DIRECT
+     o MEM_FLAG_L1_NONALLOCATING (VC4 only)
+   - other permitted flags
+     o MEM_FLAG_LOW_256M
+
+   Postconditions:
+
+   If the attempt succeeds:
+   - A pointer to the legacy block is returned.
+
+   If the attempt fails:
+   - NULL (0) is returned.
+*/
+
+extern void *mem_alloc_legacy_ex(MEM_FLAG_T flags);
+
+#define mem_alloc_legacy() mem_alloc_legacy_ex(MEM_FLAG_NORMAL)
+
+
+/*
+   Free a previously-allocated fixed-size block.
+
+   Preconditions:
+
+   - ptr must point to a block previously returned by mem_alloc_legacy.
+
+   Postconditions:
+
+   - None.
+*/
+
+extern void mem_free_legacy(void *ptr);
+
+
+/*
+   If count_max is positive then it sets a maximum number of legacy blocks which
+   can be allocated, otherwise the maximum possible (capped at 32) are allowed.
+
+   Preconditions:
+
+   - align must be a power of two.
+   - There must be no allocated legacy blocks.
+
+   Postconditions:
+
+   If the attempt succeeds:
+   - Returns the maximum number of legacy blocks, assuming no other allocations.
+
+   If the attempt fails:
+   - Returns -1.
+*/
+
+extern int mem_init_legacy(uint32_t size, uint32_t align, int count_max);
+
+
+/*
+   Preconditions:
+
+   - None.
+
+   Postconditions:
+
+   - Returns the size of the legacy blocks.
+*/
+
+extern uint32_t mem_get_legacy_size(void);
+
+
+/*
+   Preconditions:
+
+   - None.
+
+   Postconditions:
+
+   - Returns the alignment of the legacy blocks.
+*/
+
+extern uint32_t mem_get_legacy_align(void);
+
+
+/******************************************************************************
+Offline chunks API
+******************************************************************************/
+
+/*
+   Mark a contiguous chunk as being "offline". This is similar to a regular
+   block which is allocated and locked, except that chunks are always a
+   multiple of MEM_CHUNK_SIZE, and have no headers. Also, the allocator prefers
+   chunks at higher addresses.
+   mode specifies the types of compaction permitted, including MEM_COMPACT_NONE.
+   If no contiguous range of chunks can be found, the heap will be compacted
+   before retrying.
+
+   Preconditions:
+
+   - size must be an integer multiple of MEM_CHUNK_SIZE
+   - flags must specify a memory alias
+     o MEM_FLAG_NORMAL
+     o MEM_FLAG_COHERENT
+     o MEM_FLAG_DIRECT
+     o MEM_FLAG_L1_NONALLOCATING (VC4 only)
+   - other permitted flags
+     o MEM_FLAG_LOW_256M
+
+   Postconditions:
+
+   If the attempt succeeds:
+   - A pointer to the offline block is returned.
+
+   If the attempt fails:
+   - NULL (0) is returned.
+*/
+
+extern void *mem_offline(uint32_t size, MEM_FLAG_T flags,
+   mem_compact_mode_t mode);
+
+extern int mem_offline_chunks(uint32_t num_chunks, MEM_FLAG_T flags,
+   mem_compact_mode_t mode);
+
+
+/*
+   Free a previously-allocated fixed-size block. Note that it is legal
+   to take a large chunk offline and then bring a portion of it back
+   online.
+
+   Preconditions:
+
+   - ptr must point to a block previously returned by mem_alloc_legacy,
+     or a chunk-aligned section thereof.
+   - size must be an integer multiple of MEM_CHUNK_SIZE.
+
+   Postconditions:
+
+   - None.
+*/
+
+extern void mem_online(void *ptr, uint32_t size);
+
+extern void mem_online_chunks(int chunk, int num_chunks);
+
+/*
+   Retrieves various statistics about the heap chunks.
+   Note that _used + _available may not equal _total in the case of
+   overlapping areas.
+ */
+
+extern void mem_get_chunk_stats(uint32_t *total,
+   uint32_t *legacy_used, uint32_t *legacy_available, uint32_t *legacy_total,
+   uint32_t *offline_used, uint32_t *offline_available, uint32_t *offline_total);
+
+
+/******************************************************************************
+Long-term lock owners' API
+******************************************************************************/
+
+typedef enum
+{
+   /* An aggressive compaction is beginning. Any long-term locks should be released. */
+   MEM_CALLBACK_REASON_UNLOCK,
+
+   /* An aggressive compaction has completed. Any long-term locks can be reclaimed. */
+   MEM_CALLBACK_REASON_RELOCK,
+
+   /* The total amount of free memory has fallen below the threshold
+    * defined by mem_set_low_memory_threshold.
+    * To avoid repeated callbacks this callback is only invoked for the
+    * allocation that caused the free memory threshold to be crossed.
+    *
+    * Caveats
+    * The internal overheads of the heap are ignored.
+    * Small allocs are ignored.
+    * The available memory may be fragmented.
+    */
+   MEM_CALLBACK_REASON_LOW_MEMORY,
+
+   MEM_CALLBACK_REASON_MAX
+} mem_callback_reason_t;
+
+typedef void (*mem_callback_func_t)(mem_callback_reason_t reason, uintptr_t context);
+
+/* Returns 1 on success, 0 on failure. */
+extern int mem_register_callback(mem_callback_func_t func, uintptr_t context);
+
+/* Defines the threshold in bytes at which the
+ * MEM_CALLBACK_REASON_LOW_MEMORY will be invoked.
+ */
+extern void mem_set_low_mem_threshold(uint32_t threshold);
+
+extern void mem_unregister_callback(mem_callback_func_t func, uintptr_t context);
+
+
+/******************************************************************************
+Compaction notification API
+******************************************************************************/
+
+/** Type of compaction operation. */
+typedef enum
+{
+   /* A compaction is about to begin. */
+   MEM_COMPACT_OP_BEGIN,
+
+   /* A compaction has just ended. */
+   MEM_COMPACT_OP_END,
+
+   MEM_COMPACT_OP_MAX
+} mem_compact_op_t;
+
+/**
+ * Compaction notification function. Called when a relocatable heap compaction is
+ * about to begin or has just ended.
+ * This gives the callback the ability to delay the start of compaction.
+ * Will be invoked independently from those registered via mem_register_callback().
+ * @param op      Compaction operation.
+ * @param context Context passed in compaction registration.
+ * @param retries Number of retries remaining (assuming at least one callback returns non-zero).
+ *                0 means the last call for this compaction.
+ * @return non-zero to delay compaction; 0 if ok for compaction to start.
+ */
+typedef int (*mem_compact_cb_t)(mem_compact_op_t op, uintptr_t context, int retries);
+
+/**
+ * Register a callback function to be invoked at the start and end of every relocatable
+ * heap compaction.
+ * @return 1 on success; 0 on failure.
+ * @note Do not call from a compaction notification function.
+ */
+int mem_register_compact_cb(mem_compact_cb_t func, uintptr_t context);
+
+/**
+ * Unregister a callback registered via mem_register_compact_cb().
+ * @note Do not call from a compaction notification function.
+ */
+void mem_unregister_compact_cb(mem_compact_cb_t func, uintptr_t context);
+
+/******************************************************************************
+Movable memory helpers
+******************************************************************************/
+
+/*
+   Enable/disable the memory shuffler.  Only has effect if the memory shuffler
+   has been included in the build (by setting the MEM_SHUFFLE define).  The shuffler
+   will be started and enabled by default.  A zero value of enable will disable
+   compactions.  A non-zero value for enable will enable compactions.
+*/
+void rtos_common_mem_shuffle_enable(int enable);
+
+extern MEM_HANDLE_T mem_strdup_ex(
+   const char *str,
+   mem_compact_mode_t mode);
+
+#define mem_strdup(str) mem_strdup_ex((str),MEM_COMPACT_ALL)
+
+/*
+   Allocate a new buffer (with a single reference) with the same size and
+   contents as the supplied buffer. This is intended to be used for data buffers
+   rather than structures (structures would require adding a reference to each
+   of their member handles). Hence the returned buffer does not have a
+   terminator and we require that the supplied buffer doesn't have one either.
+
+   At present, *all* flags are carried across to the new buffer. I'm not sure
+   if this is wise. TODO: decide which we should allow, and whether any extra
+   ones should be passed as arguments.
+
+   Alignment is carried across too.
+
+   A valid MEM_HANDLE_T must be passed. It must have no terminator.
+*/
+
+extern MEM_HANDLE_T mem_dup_ex(
+   MEM_HANDLE_T handle,
+   const char *desc,
+   mem_compact_mode_t mode);
+
+#define mem_dup(handle,desc) mem_dup_ex((handle),(desc),MEM_COMPACT_ALL)
+
+extern void mem_print_state(void);
+extern void mem_print_small_alloc_pool_state(void);
+extern uint32_t mem_debug_get_alloc_count(void);
+
+/*
+   Retrieves various statistics about the allocated blocks.
+ */
+
+extern void mem_get_stats(uint32_t *blocks, uint32_t *bytes, uint32_t *locked);
+
+/*
+   Returns the size of the pool.
+*/
+
+extern uint32_t mem_get_total_space(void);
+
+/*
+   Returns the size of the largest possible allocation, assuming no fragmentation.
+ */
+
+extern uint32_t mem_get_free_space(void);
+
+/*
+   Returns the actual amount of free space. You won't actually be able to
+   allocate anything this big due to overhead. If the heap is empty, the return
+   value should equal mem_get_total_space()
+*/
+
+extern uint32_t mem_get_actual_free_space(void);
+
+/*
+   Returns the free space statistics. NULL pointers will not be written to.
+ */
+
+extern void mem_get_free_space_stats(uint32_t *total, uint32_t *max, uint32_t *count);
+
+/*
+   Returns the current estimate of available free space. Quicker than mem_get_free_space.
+ */
+
+extern uint32_t mem_get_low_mem_available_space(void);
+
+/*
+   Check the internal consistency of the heap. A corruption will result in
+   a failed assert, which will cause a breakpoint in a debug build.
+
+   If MEM_FILL_FREE_SPACE is defined for the build, then free space is also
+   checked for corruption; this has a large performance penalty, but can help
+   to track down random memory corruptions.
+
+   Note that defining MEM_AUTO_VALIDATE will enable the automatic validation
+   of the heap at key points - allocation, deallocation and compaction.
+
+   Preconditions:
+
+   - None.
+
+   Postconditions:
+
+   - None.
+*/
+
+extern void mem_validate(void);
+
+/*
+   Attempts to allocate a movable block of memory of the same size and alignment
+   as the specified structure type.
+
+   Implementation Notes:
+
+   The returned object obeys the invariants of the memory subsystem only.  Invariants
+   of the desired structure type may not yet be obeyed.
+   The memory will be filled such that any handles in the structure would be
+   interpreted as MEM_HANDLE_INVALID
+
+   Preconditions:
+
+   STRUCT is a structure type
+
+   the caller of this macro is contracted to later call mem_release (or pass such responsibility on) if we don't return MEM_HANDLE_INVALID
+
+   Postconditions:
+
+   If the attempt succeeds:
+   - A fresh MEM_HANDLE_T referring to the allocated block of memory is
+     returned.
+   - The MEM_HANDLE_T is unlocked, unretained, without a terminator, and has a
+     reference count of 1.
+
+   If the attempt fails:
+   - MEM_HANDLE_INVALID is returned.
+*/
+
+#define MEM_ALLOC_STRUCT_EX(STRUCT, mode) mem_alloc_ex(sizeof(STRUCT), RCM_ALIGNOF(STRUCT), MEM_FLAG_NONE, #STRUCT, mode)
+#define MEM_ALLOC_STRUCT(STRUCT) mem_alloc(sizeof(STRUCT), RCM_ALIGNOF(STRUCT), MEM_FLAG_NONE, #STRUCT)
+
+/*
+  Find out if a memory pointer is within the relocatable pool (excluding legacy blocks).
+  Returns non-zero if it is.
+ */
+
+extern int mem_is_relocatable(const void *ptr);
+
+#ifndef VCMODS_LCC
+// LCC doesn't support inline so cannot define these functions in a header file
+
+static RCM_INLINE void mem_assign(MEM_HANDLE_T *x, MEM_HANDLE_T y)
+{
+   if (y != MEM_HANDLE_INVALID)
+      mem_acquire(y);
+   if (*x != MEM_HANDLE_INVALID)
+      mem_release(*x);
+
+   *x = y;
+}
+
+/*
+   MEM_ASSIGN(x, y)
+
+   Overwrite a handle with another handle, managing reference counts appropriately
+
+   Implementation notes:
+
+   Always use the macro version rather than the inline function above
+
+   Preconditions:
+
+   each of x and y is MEM_HANDLE_INVALID or a handle to a block with non-zero ref_count
+   if x is not MEM_HANDLE_INVALID and x != y and x.ref_count is 1, x.lock_count is zero
+   is y is not MEM_HANDLE_INVALID there must at some point be a MEM_ASSIGN(x, MEM_HANDLE_INVALID)
+
+   Postconditions:
+
+   Invariants preserved:
+*/
+
+#define MEM_ASSIGN(x, y)            mem_assign(&(x), (y))
+
+/*@null@*/ static RCM_INLINE void * mem_maybe_lock(MEM_HANDLE_T handle)
+{
+   if (handle == MEM_HANDLE_INVALID)
+      return 0;
+   else
+      return mem_lock(handle);
+}
+
+static RCM_INLINE void mem_maybe_unlock(MEM_HANDLE_T handle)
+{
+   if (handle != MEM_HANDLE_INVALID)
+      mem_unlock(handle);
+}
+
+#endif
+
+extern void mem_assign_null_multiple(
+   MEM_HANDLE_OFFSET_T *handles,
+   uint32_t n);
+
+
+struct MEM_MANAGER_STATS_T;
+extern void mem_get_internal_stats(struct MEM_MANAGER_STATS_T *stats);
+
+extern int mem_handle_acquire_if_valid(MEM_HANDLE_T handle);
+
+void mem_compact_task_enable(int enable);
+
+/******************************************************************************
+API of memory access control using sandbox regions
+    Users take the responsibility of assuring thread-safety
+******************************************************************************/
+#undef MEM_ACCESS_CTRL
+
+#ifdef MEM_ACCESS_CTRL
+
+#      if defined( NDEBUG ) || !defined( __BCM2708__ ) || defined(  __BCM2708A0__ )
+#              error "BCM2708b0 or better needed"
+#      endif
+
+#define MEM_SSSR_PRIV_SECURE  (0x18)
+#define MEM_SSSR_PRIV_SUPER   (0x08)
+#define MEM_SSSR_PRIV_USER    (0x00)
+#define MEM_SSSR_READ         (0x04)
+#define MEM_SSSR_WRITE        (0x02)
+#define MEM_SSSR_EXECUTE      (0x01)
+
+#define MEM_ACCESSCTRL_BLOCKS_MAX              (7)  // Sandbox 0 is reserved for .text
+
+typedef struct {
+   uint32_t start;
+   uint32_t size;
+   uint32_t flags;
+} MEM_ACCESSCTRL_BLOCK;
+
+void mem_clr_accessctrl();
+void mem_set_accessctrl(MEM_ACCESSCTRL_BLOCK *blocks, uint32_t n);
+#define MEM_CLR_ACCESSCTRL             mem_clr_accessctrl
+#define MEM_SET_ACCESSCTRL             mem_set_accessctrl
+
+#else
+#define MEM_CLR_ACCESSCTRL()                           ((void)0)
+#define MEM_SET_ACCESSCTRL(BLOCKS, NUM)                ((void)0)
+#endif //#ifdef MEM_ACCESS_CTRL
+
+
+#endif
diff --git a/vcfw/rtos/rtos.h b/vcfw/rtos/rtos.h
new file mode 100755 (executable)
index 0000000..adee818
--- /dev/null
@@ -0,0 +1,540 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef RTOS_H_
+#define RTOS_H_
+
+#if !defined(__VIDEOCORE__) && !defined(__vce__) && !defined(VIDEOCORE_CODE_IN_SIMULATION)
+#error This code is only for use on VideoCore. If it is being included
+#error on the host side, then you have done something wrong. Defining
+#error __VIDEOCORE__ is *not* the right answer!
+#endif
+
+#include "vcinclude/common.h"
+#include "vcfw/drivers/driver.h"
+
+#ifdef _VIDEOCORE
+#include "host_support/include/vc_debug_sym.h"
+#endif
+
+#include <stdlib.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************
+ Global funcs - implementation is specific to which RTOS you are including
+ *****************************************************************************/
+
+//Routine to initialise the RTOS
+extern int32_t rtos_init( void );
+
+//Routine to start the RTOS
+extern int32_t rtos_start( int argc, char *argv[] );
+
+/******************************************************************************
+ Global data
+ *****************************************************************************/
+
+extern int rtos_argc;
+extern char **rtos_argv;
+
+/******************************************************************************
+ RTOS Time functions
+ *****************************************************************************/
+
+//Routine to delay the execution cycle
+extern int32_t rtos_delay( const uint32_t usecs, const uint32_t suspend );
+
+//Routine used to put the current task (if there is one) to sleep
+extern int32_t rtos_sleep( void );
+
+/***********************************************************
+ * Returns the current hardware microsecond counter value.
+ *
+ * @return       Microsecond counter value.
+ *
+ ***********************************************************/
+
+extern unsigned rtos_getmicrosecs(void);
+extern uint64_t rtos_getmicrosecs64(void);
+
+/******************************************************************************
+ Driver + module loading / unloading code
+ *****************************************************************************/
+
+//Routine to load a driver
+extern int32_t rtos_driver_load( const char *driver_name, DRIVER_T **driver );
+
+//Routine to unload a driver
+extern int32_t rtos_driver_unload( const DRIVER_T *driver );
+
+/******************************************************************************
+ ISR functionality
+ *****************************************************************************/
+
+//Definition of a LISR
+typedef void (*RTOS_LISR_T)( const uint32_t vector_num );
+
+//Definition of an ASM lisr
+typedef void (*RTOS_LISR_ASM_T)( void );
+
+//Routine to register a isr
+extern int32_t rtos_register_lisr ( const uint32_t vector, RTOS_LISR_T new_lisr, RTOS_LISR_T *old_lisr );
+
+//Routine to register an assembler based isr
+extern int32_t rtos_register_asm_lisr ( const uint32_t vector, RTOS_LISR_ASM_T new_lisr, RTOS_LISR_ASM_T *old_lisr );
+
+//Routine to disable interrupts
+extern uint32_t rtos_disable_interrupts( void );
+
+//Routine to re-enable interrupts
+extern void rtos_restore_interrupts( const uint32_t previous_state );
+
+
+//Routine to query if interrupts are enable or not
+#ifdef __VIDEOCORE__
+static inline uint32_t rtos_interrupts_enabled( void )
+{
+   return !!(_vasm("mov %D,%sr") & (1<<30));
+}
+#endif // ifdef __HIGHC__
+
+/******************************************************************************
+ Secure functionality
+ *****************************************************************************/
+
+//Definition for a secure function handle
+typedef uint32_t RTOS_SECURE_FUNC_HANDLE_T;
+
+//Definition for a secure function
+//NOTE! Whilst no params are shown for this function, the calling function can pass up to 5 registers to it
+#if defined( __linux__ )
+// I get compiler warnings when building for linux (MxC) since () isn't a valid prototype.
+// Using (...) isn't valid under ANSI C, (you need to have at least one fixed argument).
+// So since I don't think that this stuff is actually used from linux, I decided to make it 
+// use (void) until a better solution can be done.
+typedef void (*RTOS_SECURE_FUNC_T)(void);
+#else
+typedef void (*RTOS_SECURE_FUNC_T)();
+#endif
+
+
+//Function to register secure functions
+//NOTE - these functions should be encrypted
+extern int32_t rtos_secure_function_register( RTOS_SECURE_FUNC_T secure_func,
+                                              RTOS_SECURE_FUNC_HANDLE_T *secure_func_handle );
+
+//Routine to call a secure function
+extern int32_t rtos_secure_function_call( const RTOS_SECURE_FUNC_HANDLE_T secure_func_handle,
+                                          const uint32_t r0,
+                                          const uint32_t r1,
+                                          const uint32_t r2,
+                                          const uint32_t r3,
+                                          const uint32_t r4 );
+
+/******************************************************************************
+ Multithreading functionality
+ *****************************************************************************/
+// This constant is a thread id which should never be returned by
+// rtos_get_thread_id
+#define RTOS_INVALID_THREAD_ID      (~0)
+
+// Routine to get the id of the current thread
+extern uint32_t rtos_get_thread_id( void );
+
+// Routine to migrate the current thread to the other cpu. Does nothing if
+// already on the requested cpu.
+// In rtos_none, fails if something is already running on the other cpu.
+extern void rtos_cpu_migrate( const uint32_t cpu );
+
+// Launch the given function asynchronously on the other cpu. Do not wait
+// for it to return.
+// In rtos_none, fails if the specified cpu is either the one you're calling
+// from, or has something else running on it.
+typedef void (*RTOS_LAUNCH_FUNC_T)( uint32_t argc, void *argv );
+extern uint32_t rtos_cpu_launch( const uint32_t cpu, RTOS_LAUNCH_FUNC_T launch_func, const uint32_t argc, void *argv, const uint32_t stack_size );
+
+// Wait for the specified thread to terminate. This should be called exactly
+// once for each thread created. After it is called, thread_id may identify
+// a new thread.
+extern void rtos_thread_join( const uint32_t thread_id );
+
+// Return the amount of free space on the stack (in bytes). Useful for making
+// recursive algorithms safe.
+extern uint32_t rtos_check_stack( void );
+
+// Returns non-zero if the caller is within interrupt context, otherwise
+// returns zero.
+extern int rtos_in_interrupt( void );
+
+/******************************************************************************
+ Latch functionality
+ *****************************************************************************/
+
+//typedef of a latch
+typedef struct opaque_rtos_latch_t* RTOS_LATCH_T;
+
+// Latch values:
+//    0 = unlocked
+//    1 = locked without contention
+//    Other = locked with contention (one or more threads waiting in rtos_latch_get)
+
+#define rtos_latch_locked() ((RTOS_LATCH_T)1) // For use in initialisation only
+
+#define rtos_latch_unlocked() ((RTOS_LATCH_T)0)
+
+// N.B. a latch can also be a pointer to a queue of waiting threads, so
+// comparison to rtos_latch_locked() is rarely wise; inequality to
+// rtos_latch_unlocked() is a better test of lockedness.
+
+// Don't call these functions, use the rtos_latch_get etc macros.
+//Routine to get the latch. Will suspend / busy wait dependent on the rtos implementation
+extern void rtos_latch_get_real( RTOS_LATCH_T *latch );
+//Routine to put the latch.
+extern void rtos_latch_put_real( RTOS_LATCH_T *latch );
+
+// Routine to try and get a latch. Can be called from an interrupt
+extern int32_t rtos_latch_try_real( RTOS_LATCH_T *latch );
+
+
+// See vcfw/rtos/common/rtos_latch_logging.c for more about latch logging.
+//#define LATCH_LOGGING_ENABLED
+
+#ifdef NDEBUG
+#undef LATCH_LOGGING_ENABLED
+#endif
+
+#ifdef LATCH_LOGGING_ENABLED
+
+extern void rtos_latch_logging_latch_get( RTOS_LATCH_T *latch, const char * name );
+extern void rtos_latch_logging_latch_put( RTOS_LATCH_T *latch, const char * name );
+extern int32_t rtos_latch_logging_latch_try( RTOS_LATCH_T *latch, const char * name );
+
+
+#ifndef STRINGISED
+#define _STRINGISED(x) #x
+#define  STRINGISED(x) _STRINGISED(x)
+#endif
+
+#define rtos_latch_get( latch ) rtos_latch_logging_latch_get( (latch) , "Loc:" __FILE__ " " STRINGISED(__LINE__) )
+#define rtos_latch_put( latch ) rtos_latch_logging_latch_put( (latch) , "Loc:" __FILE__ " " STRINGISED(__LINE__) )
+#define rtos_latch_try( latch ) rtos_latch_logging_latch_try( (latch) , "Loc:" __FILE__ " " STRINGISED(__LINE__) )
+
+extern void rtos_latch_logging_init();
+
+#else
+
+#define rtos_latch_get( latch ) rtos_latch_get_real( (latch) )
+#define rtos_latch_put( latch ) rtos_latch_put_real( (latch) )
+#define rtos_latch_try( latch ) rtos_latch_try_real( (latch) )
+
+
+#endif
+
+
+/******************************************************************************
+ CPU-related functions
+ *****************************************************************************/
+
+// Returns the number of CPUs controlled by the RTOS
+extern uint32_t rtos_get_cpu_count( void );
+
+// Returns the number of the current CPU (numbered from 0)
+extern uint32_t rtos_get_cpu_number( void );
+
+// This constant indicates that the current CPU should be used
+#define RTOS_CPU_CURRENT               (~0)
+
+// Returns a count of the usecs spent sleeping on the specified CPU
+extern uint32_t rtos_get_sleep_time( const uint32_t cpu );
+
+// Zero the sleep time on specified cpu.  Used to find out if
+// CPU1 has a running thread system after being started:
+// zeroing the recorded sleep time is otherwise undesirable.
+extern void rtos_reset_sleep_time( const uint32_t cpu );
+
+
+// Returns a count of the total usecs spent executing LISRs on the
+// specified CPU
+extern uint32_t rtos_get_lisr_time( const uint32_t cpu );
+
+// This constant is used to specify an unlimited execution time
+#define RTOS_MAX_TIME_UNLIMITED        (~0)
+
+// Sets the upper limit on the number of usecs an LISR can take.
+// Exceeding this limit will trigger a breakpoint on completion.
+// Returns the previous limit.
+extern uint32_t rtos_set_lisr_max_time( const uint32_t cpu, const uint32_t limit );
+
+/******************************************************************************
+ Common RTOS functions, stored in vcfw/rtos/common.
+ Note! There is only 1 copy of these functions and they do not contain platform,
+ rtos or chip specific functions
+ *****************************************************************************/
+
+/******************************************************************************
+ Timer funcs
+ *****************************************************************************/
+
+// forward-declare struct RTOS_TIMER
+struct RTOS_TIMER;
+
+//Callback definition for when the timer has expired
+typedef void (*RTOS_TIMER_DONE_OPERATION_T)( struct RTOS_TIMER *timer, void *priv );
+
+//The time to delay before calling the callback
+typedef uint32_t RTOS_TIMER_TIME_T; /* microseconds */
+
+typedef uint32_t RTOS_TIMER_TICKS_T;
+
+typedef struct RTOS_TIMER
+{
+   RTOS_TIMER_DONE_OPERATION_T done;
+   void *priv;
+
+   /* implementation */
+   RTOS_TIMER_TICKS_T ticks;
+   RTOS_TIMER_TICKS_T offset;
+   struct RTOS_TIMER *next;
+
+} RTOS_TIMER_T;
+
+// Initialises TIMER with the given parameters. Returns zero on success
+extern int32_t rtos_timer_init( RTOS_TIMER_T *timer, RTOS_TIMER_DONE_OPERATION_T done, void *priv);
+
+// Returns non-zero if TIMER is in the queue
+extern int32_t rtos_timer_is_running( const RTOS_TIMER_T *timer );
+
+// Adds TIMER to the queue to run TIMER->done(TIMER->priv) after DELAY microseconds
+extern int32_t rtos_timer_set( RTOS_TIMER_T *timer, const RTOS_TIMER_TIME_T delay);
+
+// TIMER is cancelled and then set. Returns zero if successful
+extern int32_t rtos_timer_reset( RTOS_TIMER_T *timer, const RTOS_TIMER_TIME_T delay);
+
+// TIMER is cancelled if running and the callback is not called. Returns 0 if the timer was running
+extern int32_t rtos_timer_cancel( RTOS_TIMER_T *timer );
+
+
+/******************************************************************************
+ Memory- and address space-related functions
+ *****************************************************************************/
+
+#define RTOS_ALIGN_DEFAULT             4
+#define RTOS_ALIGN_128BIT              16
+#define RTOS_ALIGN_256BIT              32
+#define RTOS_ALIGN_AXI                 RTOS_ALIGN_128BIT
+#define RTOS_ALIGN_512BIT              64
+#define RTOS_ALIGN_4KBYTE              4096
+#define RTOS_PRIORITY_INTERNAL         9999  // must be in internal memory
+#define RTOS_PRIORITY_EXTERNAL         0 // must be in external memory
+#define RTOS_PRIORITY_UNIMPORTANT      1
+
+#if defined(__VIDEOCORE5__)
+
+#define RTOS_PRIORITY_SHIFT            30
+#define RTOS_ALIAS_NORMAL(x)               (x) // normal cached data (uses main 128K L2 cache)
+#define RTOS_ALIAS_L1_NONALLOCATING(x)     (x) // coherent with L1, allocating in L2
+#define RTOS_ALIAS_COHERENT(x)             (x) // cache coherent but non-allocating
+#define RTOS_ALIAS_DIRECT(x)               (x) // uncached
+#define RTOS_IS_ALIAS_NOT_L1(x)            (0)
+#define RTOS_IS_ALIAS_DIRECT(x)            (0)
+
+#define RTOS_PRIORITY_L1_NONALLOCATING         (0 << RTOS_PRIORITY_SHIFT)
+#define RTOS_PRIORITY_L1L2_NONALLOCATING       (0 << RTOS_PRIORITY_SHIFT)
+#define RTOS_PRIORITY_COHERENT         RTOS_PRIORITY_L1L2_NONALLOCATING
+#define RTOS_PRIORITY_DIRECT           (0 << RTOS_PRIORITY_SHIFT)
+
+#elif defined(__VIDEOCORE4__)
+
+#define RTOS_PRIORITY_SHIFT            30
+#define RTOS_ALIAS_NORMAL(x)               ((void*)(((unsigned)(x)&~0xc0000000)|0x00000000)) // normal cached data (uses main 128K L2 cache)
+#define RTOS_ALIAS_L1_NONALLOCATING(x)     ((void*)(((unsigned)(x)&~0xc0000000)|0x40000000)) // coherent with L1, allocating in L2
+#if defined(__BCM2708A0__) || defined(__BCM2708B0__)
+// HW-2827 workaround
+#define RTOS_ALIAS_COHERENT(x)             RTOS_ALIAS_L1_NONALLOCATING(x)
+#else
+#define RTOS_ALIAS_COHERENT(x)             ((void*)(((unsigned)(x)&~0xc0000000)|0x80000000)) // cache coherent but non-allocating
+#endif
+#define RTOS_ALIAS_DIRECT(x)               ((void*)(((unsigned)(x)&~0xc0000000)|0xc0000000)) // uncached
+#define RTOS_IS_ALIAS_NOT_L1(x)            (((((unsigned)(x)>>30)&0x3)==1) || (((unsigned)(x)>>29)>=3))
+#define RTOS_IS_ALIAS_DIRECT(x)            ((((unsigned)(x)>>30)&0x3)==3)
+
+// RTOS_PRIORITY_L1_NONALLOCATING will skip the L1 cache, but still allocate in L2
+// this is needed if VPU is communicating with hardware via memory
+#define RTOS_PRIORITY_L1_NONALLOCATING         (1 << RTOS_PRIORITY_SHIFT)
+#define RTOS_PRIORITY_L1L2_NONALLOCATING       (2 << RTOS_PRIORITY_SHIFT)
+#define RTOS_PRIORITY_COHERENT         RTOS_PRIORITY_L1L2_NONALLOCATING
+#define RTOS_PRIORITY_DIRECT           (3 << RTOS_PRIORITY_SHIFT)
+
+#else // defined (__VIDEOCORE4__)
+
+#define RTOS_PRIORITY_SHIFT            28
+#define RTOS_ALIAS_NORMAL(x)               ((void*)(((unsigned)(x)&~0xf0000000)|0x00000000)) // normal cached data (uses main 128K L2 cache)
+#define RTOS_ALIAS_L1_NONALLOCATING(x)     (x)                                               // coherent with L1, allocating in L2
+#define RTOS_ALIAS_COHERENT(x)             ((void*)(((unsigned)(x)&~0xf0000000)|0x20000000)) // cache coherent but non-allocating
+#define RTOS_ALIAS_DIRECT(x)               ((void*)(((unsigned)(x)&~0xf0000000)|0x30000000)) // uncached
+#define RTOS_IS_ALIAS_NOT_L1(x)            (1)              // compatibility with vc4
+#define RTOS_IS_ALIAS_DIRECT(x)            ((((unsigned)(x)>>28)&0xf)==3)
+
+#define RTOS_PRIORITY_L1_NONALLOCATING         (0 << RTOS_PRIORITY_SHIFT)
+#define RTOS_PRIORITY_L1L2_NONALLOCATING       (2 << RTOS_PRIORITY_SHIFT)
+#define RTOS_PRIORITY_COHERENT         RTOS_PRIORITY_L1L2_NONALLOCATING
+#define RTOS_PRIORITY_DIRECT           (3 << RTOS_PRIORITY_SHIFT)
+
+#endif
+
+#ifdef __VIDEOCORE__
+#define RTOS_WRITE_BARRIER(x) _vasm("ld %D, (%r)\nadd %D, 0", x)
+#else
+#define RTOS_WRITE_BARRIER(x) (void)0
+#endif
+
+// Returns a pointer to the the start of the memory allocated to VideoCore
+extern void *   rtos_get_vc_mem_start(void);
+
+// Returns the size of the memory allocated to VideoCore
+extern uint32_t rtos_get_vc_mem_size(void);
+
+// Returns a pointer to the the start of the memory addressable by VideoCore
+extern void *   rtos_get_sys_mem_start(void);
+
+// Returns the size of the memory addressable by VideoCore
+extern uint32_t rtos_get_sys_mem_size(void);
+
+
+/******************************************************************************
+ Malloc / free funcs
+ *****************************************************************************/
+
+extern void * const __RTOS_HEAP_END, * const __RTOS_HEAP_START;
+
+#ifdef _VIDEOCORE
+
+typedef struct OPAQUE_RTOS_MEMPOOL_T *rtos_mempool_t;
+
+// Allocates memory using a priority based scheme
+extern void *rtos_malloc_priority( const uint32_t size, const uint32_t align, const uint32_t priority, const char *description);
+
+// Allocates and clears memory using a priority based scheme
+extern void *rtos_calloc_priority(const uint32_t size, const uint32_t align, const uint32_t priority, const char *description);
+
+// Re-allocates some memory (and changes it size)
+extern void *rtos_realloc_256bit(void *ret, const uint32_t size);
+
+//Routine to query how much free memory is available in the pool
+extern uint32_t rtos_get_free_mem(const rtos_mempool_t pool);
+
+//Routine to query the initial malloc heap memory size
+extern uint32_t rtos_get_total_mem(const rtos_mempool_t pool);
+
+/* return a pointer to whatever called us, which can be used as a malloc name
+ * (works best before first function call in a function).
+ * This should normally be used only in malloc() wrappers to avoid the
+ * situation where everything gets named "abstract_malloc" or the like.
+ */
+#define rtos_default_malloc_name() (char const *)_vasm("bitset %D, %lr, 31")
+#define RTOS_MALLOC_NAME_IS_CODE_FLAG                            (1u << 31)
+
+VC_DEBUG_EXTERN_UNCACHED_VAR(uint32_t,boot_state);
+VC_DEBUG_EXTERN_UNCACHED_VAR(uint32_t,boot_state_info);
+
+#define BOOT_STATE(c0,c1,c2,c3) VC_DEBUG_ACCESS_UNCACHED_VAR(boot_state) = (c0+(c1<<8)+(c2<<16)+(c3<<24))
+#define BOOT_STATE_INFO(v) VC_DEBUG_ACCESS_UNCACHED_VAR(boot_state_info) = (v)
+#define BOOT_STATE_EQUALS(c0,c1,c2,c3) (VC_DEBUG_ACCESS_UNCACHED_VAR(boot_state) == (c0+(c1<<8)+(c2<<16)+(c3<<24)))
+
+#else //ifdef _VIDEOCORE
+
+#define rtos_malloc_priority(size, align, priority, description)   malloc(size)
+#define rtos_calloc_priority(size, align, priority, description)   calloc(1,size)
+#define rtos_realloc_256bit(ret, size)   realloc(ret,size)
+
+#define rtos_default_malloc_name() (char const *)0
+#define RTOS_MALLOC_NAME_IS_CODE_FLAG 0
+
+#endif // ifdef _VIDEOCORE
+
+// Malloc aliases
+#ifdef NDEBUG
+   #define rtos_prioritymalloc( size, align, priority, description ) rtos_malloc_priority(size, align, priority, (char const *)0)
+   #define rtos_prioritycalloc( size, align, priority, description ) rtos_calloc_priority(size, align, priority, (char const *)0)
+#else
+   #define rtos_prioritymalloc( size, align, priority, description ) rtos_malloc_priority(size, align, priority, description)
+   #define rtos_prioritycalloc( size, align, priority, description ) rtos_calloc_priority(size, align, priority, description)
+#endif
+
+#define rtos_priorityfree( buffer ) free(buffer)
+#define rtos_malloc_256bit( size )  rtos_prioritymalloc(size, RTOS_ALIGN_256BIT, 100, (char const *)0)
+#define rtos_free_256bit( ret ) free(ret)
+#define rtos_malloc_external( size )  rtos_prioritymalloc(size, RTOS_ALIGN_DEFAULT, 1, (char const *)0)
+#define rtos_malloc_external_256bit( size ) rtos_prioritymalloc(size, RTOS_ALIGN_256BIT, 1, (char const *)0);
+
+// manipulate priority level for mallocs
+extern int rtos_setpriority(const uint32_t priority);
+extern int rtos_getpriority(void);
+
+// Perform basic safety checks on a memory range
+extern int rtos_memory_is_valid(void const *base, int length);
+
+// Scan the heap for evidence of memory corruption -- returns pointer to first corrupt block or NULL if OK
+extern void const *rtos_find_heap_corruption(int flags);
+
+#define rtos_calloc(a, b) calloc( a, b )
+#define rtos_malloc(size) malloc( size )
+
+/******************************************************************************
+   Power / reset functions
+******************************************************************************/
+
+// Reset the processor
+void rtos_reset( void );
+
+//Routine to initialise the relocatable heap.
+void rtos_relocatable_heap_init( void );
+
+/******************************************************************************
+   Testing functions
+******************************************************************************/
+
+extern int vctest_should_open_fail(char const *description);
+extern int vctest_should_alloc_fail(char const *description);
+extern int vctest_should_readwrite_fail(char const *description);
+extern void vctest_start_failure_testing(void);
+
+#ifdef _VIDEOCORE
+#define VCTEST_DEBUGGER_BKPT_TRAP(name) _vasm(#name ": \n .globl " #name "\n\t  nop")
+#else
+#define VCTEST_DEBUGGER_BKPT_TRAP(name) 0
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif // RTOS_H_
diff --git a/vcfw/vclib/vclib.h b/vcfw/vclib/vclib.h
new file mode 100755 (executable)
index 0000000..024137a
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VCFW_VCLIB_H
+#define VCFW_VCLIB_H
+
+ #ifdef __VIDEOCORE__
+
+#include "vcfw/rtos/rtos.h"
+#include "vcfw/logging/logging.h"
+
+int32_t vclib_vcfw_init( void );
+int32_t vclib_vcfw_driver_init( void );
+
+typedef enum {
+   FATAL_RED = 1,
+   FATAL_GREEN,
+   FATAL_BLUE,
+   FATAL_CYAN,
+   FATAL_MAGENTA,
+   FATAL_YELLOW,
+   FATAL_WHITE,
+   FATAL_BLACK,
+
+   FATAL_SUB_RED     = FATAL_RED     << 4,
+   FATAL_SUB_GREEN   = FATAL_GREEN   << 4,
+   FATAL_SUB_BLUE    = FATAL_BLUE    << 4,
+   FATAL_SUB_CYAN    = FATAL_CYAN    << 4,
+   FATAL_SUB_MAGENTA = FATAL_MAGENTA << 4,
+   FATAL_SUB_YELLOW  = FATAL_YELLOW  << 4,
+   FATAL_SUB_WHITE   = FATAL_WHITE   << 4,
+   FATAL_SUB_BLACK   = FATAL_BLACK   << 4,
+} FATAL_COLOUR;
+
+void vclib_fatal_fn(FATAL_COLOUR colour);
+  #ifdef FATAL_ASSERTS
+#define vclib_fatal_assert(x, c) if (x) {} else vclib_fatal_fn(c)
+  #else
+#define vclib_fatal_assert(x, c) assert(x)
+  #endif
+
+extern void vclib_init();
+extern int  vclib_obtain_VRF(int block);
+extern void vclib_release_VRF(void);
+extern int  vclib_check_VRF(void);
+
+#define get_free_mem(pool) (rtos_get_free_mem(pool))
+
+#define malloc_setpool( external)         rtos_malloc_setpool( external)
+#define malloc_256bit( size)              rtos_malloc_256bit( size)
+#define free_256bit(ret)                  rtos_free_256bit(ret)
+#define realloc_256bit(ret,  size)        rtos_realloc_256bit(ret,  size)
+#define malloc_external( size)            rtos_malloc_external( size)
+#define malloc_external_256bit( size)     rtos_malloc_external_256bit( size )
+
+#define malloc_priority( size,  align,  priority,  description) rtos_prioritymalloc( size,  align,  priority,  description)
+#define calloc_priority( size,  align,  priority,  description) rtos_prioritycalloc( size,  align,  priority,  description)
+
+#define vclib_setpriority rtos_setpriority
+#define vclib_getpriority rtos_getpriority
+
+#define vclib_prioritymalloc(size, align, priority, description) rtos_prioritymalloc(size, align, priority, description)
+#define vclib_prioritycalloc(size, align, priority, description) rtos_prioritycalloc(size, align, priority, description)
+
+#define vclib_priorityfree(buffer) rtos_priorityfree(buffer)
+#define VCLIB_ALIGN_DEFAULT                  RTOS_ALIGN_DEFAULT
+#define VCLIB_ALIGN_128BIT                   RTOS_ALIGN_128BIT
+#define VCLIB_ALIGN_256BIT                   RTOS_ALIGN_256BIT
+#define VCLIB_ALIGN_AXI                      RTOS_ALIGN_AXI
+#define VCLIB_ALIGN_512BIT                   RTOS_ALIGN_512BIT
+#define VCLIB_ALIGN_4KBYTE                   RTOS_ALIGN_4KBYTE
+#define VCLIB_PRIORITY_INTERNAL              RTOS_PRIORITY_INTERNAL
+#define VCLIB_PRIORITY_EXTERNAL              RTOS_PRIORITY_EXTERNAL
+#define VCLIB_PRIORITY_UNIMPORTANT           RTOS_PRIORITY_UNIMPORTANT
+#define VCLIB_PRIORITY_COHERENT              RTOS_PRIORITY_COHERENT
+#define VCLIB_PRIORITY_DIRECT                RTOS_PRIORITY_DIRECT
+
+extern void vclib_save_vrf( unsigned char *vrf_strorage );
+extern void vclib_restore_vrf( unsigned char *vrf_strorage );
+extern void vclib_save_quarter_vrf( unsigned char *vrf_strorage );
+extern void vclib_restore_quarter_vrf( unsigned char *vrf_strorage );
+
+extern void vclib_cache_flush(void);
+extern void vclib_dcache_flush(void);
+extern void vclib_icache_flush(void);
+extern void vclib_dcache_flush_range(void *start_addr, int length);
+extern void vclib_l1cache_flush_range(void *start_addr, int length);
+
+/* Use these function to identify the condition where you don't care if the data is
+ * written back -- if it becomes possible then we save ourselves the bother of
+ * hunting for places where it should be done that way.
+ */
+extern void vclib_dcache_invalidate_range(void *start_addr, int length);
+extern void vclib_l1cache_invalidate_range(void *start_addr, int length);
+
+#define vclib_timer_t RTOS_TIMER_T
+#define vclib_timer_done_op RTOS_TIMER_DONE_OPERATION_T
+#define vclib_timer_time_t RTOS_TIMER_TIME_T
+#define vclib_timer_ticks_t RTOS_TIMER_TICKS_T
+
+#define vclib_timer_init rtos_timer_init
+#define vclib_timer_is_running rtos_timer_is_running
+#define vclib_timer_set rtos_timer_set
+#define vclib_timer_reset rtos_timer_reset
+#define vclib_timer_cancel rtos_timer_cancel
+
+extern int vclib_disableint(void);
+extern void vclib_restoreint(int sr);
+
+
+/* Some support for automatic logging. */
+
+/* Have a macro that is guaranteed to be a simple "assert" even when logging is on. */
+  #ifdef NDEBUG
+#define simple_assert(cond)
+  #else
+#define simple_assert(cond) if (cond) {} else _bkpt()
+  #endif
+
+
+/*********
+** HACK!!!!!! Temp function definition (code in cache_flush.s) used to enable the run domain in VCIII
+**********/
+extern void vc_enable_run_domain( void );
+
+#define vclib_memory_is_valid rtos_memory_is_valid
+
+
+/* Latch events are fast and small event notifications */
+typedef RTOS_LATCH_T latch_event_t;
+
+#define latch_event_present() ((latch_event_t)rtos_latch_unlocked())
+
+#define latch_event_absent() ((latch_event_t)rtos_latch_locked())
+
+
+#define latch_event_is_present( latch ) (latch_event_present() == *(latch))
+
+  #if defined(__HIGHC__) /* MetaWare tools */
+
+   static inline unsigned vclib_status_register(void)
+   {
+      /* Would have liked use == syntax for assigning a variable to be a register
+      but the compiler issues a warning about that */
+      return _vasm("mov %D,%sr");
+   }
+   static inline int vclib_interrupts_enabled(void)
+   {
+      unsigned sr = vclib_status_register();
+      return !!(sr&(1<<30));
+   }
+
+  #else
+
+   static inline unsigned vclib_status_register(void)
+   {
+      unsigned i;
+      asm("mov %0, sr" : "=r"(i));
+      return i;
+   }
+   static inline int vclib_interrupts_enabled(void)
+   {
+      unsigned sr = vclib_status_register();
+      return !!(sr&(1<<30));
+   }
+
+  #endif
+
+ #endif // defined __VIDEOCORE__
+
+
+// A few helpful things for windows / standalone Linux
+# ifndef __VIDEOCORE__
+
+#  ifdef __GNUC__
+    static inline int vclib_obtain_VRF(int block) { return 1; }
+    static inline void vclib_release_VRF(void) {}
+    static inline int vclib_check_VRF(void) { return 1; }
+#  else
+#   define vclib_obtain_VRF(b) (1)
+#   define vclib_release_VRF()
+#   define vclib_check_VRF() (1)
+#  endif
+
+#  ifdef VIDEOCORE_CODE_IN_SIMULATION
+
+#   undef abs // prior to including stdlib.h
+#   include <stdlib.h> // For malloc() et al.
+
+#   define vclib_dcache_flush_range(start_addr, length)
+
+#   define VCLIB_ALIGN_DEFAULT   4
+#   define VCLIB_ALIGN_256BIT    32
+#   define VCLIB_ALIGN_4KBYTE    4096
+
+#   define VCLIB_PRIORITY_COHERENT      0
+#   define VCLIB_PRIORITY_DIRECT        0
+#   define VCLIB_PRIORITY_UNIMPORTANT   0
+
+#   define vclib_fatal_assert(x, c) assert(x)
+#   define vclib_prioritymalloc(size, align, priority, description) \
+           rtos_prioritymalloc((size), (align), (priority), (description))
+#   define vclib_prioritycalloc(size, align, priority, description) \
+           rtos_prioritycalloc((size), (align), (priority), (description))
+
+#   define vclib_priorityfree(buffer) rtos_priorityfree((buffer))
+#   define malloc_256bit(size) rtos_malloc_256bit((size))
+#   define free_256bit(ret) rtos_free_256bit((ret))
+
+#  endif
+
+# endif // !defined(__VIDEOCORE__)
+
+#endif // defined VCFW_VCLIB_H
diff --git a/vcinclude/common.h b/vcinclude/common.h
new file mode 100755 (executable)
index 0000000..05d1bdd
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __VC_INCLUDE_COMMON_H__
+#define __VC_INCLUDE_COMMON_H__
+
+#include "interface/vcos/vcos_stdint.h"
+#include "interface/vctypes/vc_image_types.h"
+
+#if defined(__HIGHC__) && defined(_VIDEOCORE) && !defined(_I386)
+// __HIGHC__ is only available with MW
+// The scvc plugins are compiled (bizarrely) on an x86 with _VIDEOCORE set!
+#include <vc/intrinsics.h>
+#endif
+
+#ifdef __COVERITY__
+#ifndef _Rarely
+#define _Rarely(x) (x)
+#endif
+#ifndef _Usually
+#define _Usually(x) (x)
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __SYMBIAN32__
+# ifndef INLINE
+#  define INLINE __inline
+# endif
+
+/* Align a pointer/integer by rounding up/down */
+#define ALIGN_DOWN(p, n)   ((uint32_t)(p) - ( (uint32_t)(p) % (uint32_t)(n) ))
+#define ALIGN_UP(p, n)     ALIGN_DOWN((uint32_t)(p) + (uint32_t)(n) - 1, (n))
+
+#elif defined (VCMODS_LCC)
+#include <limits.h>
+
+
+#elif !defined(__KERNEL__)
+#include <limits.h>
+
+#endif
+
+
+/*}}}*/
+
+/* Fixed-point types */
+typedef unsigned short uint8p8_t;
+typedef signed short sint8p8_t;
+typedef unsigned short uint4p12_t;
+typedef signed short sint4p12_t;
+typedef signed short sint0p16_t;
+typedef signed char sint8p0_t;
+typedef unsigned char uint0p8_t;
+typedef signed long int24p8_t;
+
+/*{{{ Common typedefs */
+
+typedef enum bool_e
+{
+   VC_FALSE = 0,
+   VC_TRUE = 1,
+} VC_BOOL_T;
+
+#ifndef bool_t
+#define bool_t VC_BOOL_T
+#endif
+
+/*}}}*/
+
+/*{{{ Common macros */
+
+
+/* Align a pointer/integer by rounding up/down */
+#define ALIGN_DOWN(p, n)   ((uintptr_t)(p) - ( (uintptr_t)(p) % (uintptr_t)(n) ))
+#define ALIGN_UP(p, n)     ALIGN_DOWN((uintptr_t)(p) + (uintptr_t)(n) - 1, (n))
+
+#define CLIP(lower, n, upper) _min((upper), _max((lower), (n)))
+
+/*}}}*/
+
+/*{{{ Debugging and profiling macros */
+
+#if 0
+/* There's already an assert_once in <logging/logging.h> */
+#ifdef DEBUG
+#define assert_once(x) \
+   { \
+      static uint8_t ignore = 0; \
+      if(!ignore) \
+      { \
+         assert(x); \
+         ignore++; \
+      } \
+   }
+#else
+#define assert_once(x) (void)0
+#endif
+#endif /* 0 */
+
+#if defined(__HIGHC__) && !defined(NDEBUG)
+/* HighC lacks a __FUNCTION__ preproc symbol... :( */
+#define profile_rename(name) _ASM(".global " name "\n" name ":\n")
+#else
+#define profile_rename(name) (void)0
+#endif
+
+/*}}}*/
+#ifdef __cplusplus
+ }
+#endif
+#endif /* __VCINCLUDE_COMMON_H__ */
+
diff --git a/vcinclude/vc_image_types.h b/vcinclude/vc_image_types.h
new file mode 100755 (executable)
index 0000000..58ac333
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __VC_INCLUDE_IMAGE_TYPES_H__
+#define __VC_INCLUDE_IMAGE_TYPES_H__
+
+#include "interface/vctypes/vc_image_types.h"
+#include "interface/vctypes/vc_image_structs.h"
+
+#endif /* __VC_INCLUDE_IMAGE_TYPES_H__ */
diff --git a/vcinclude/vcore.h b/vcinclude/vcore.h
new file mode 100755 (executable)
index 0000000..7fd7113
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef VCORE_H
+#define VCORE_H
+
+#ifdef __VIDEOCORE__
+#include "vc/intrinsics.h"
+#undef asm
+#define asm(x) _ASM(x)
+
+#undef min
+#define min(x,y) _min(x,y)
+
+#undef max
+#define max(x,y) _max(x,y)
+
+#ifndef abs
+#define abs(x) _abs(x)
+#endif
+#else
+#define _vasm asm
+#define _bkpt() do {asm(" bkpt");}while(0)
+#define _di() do{asm(" di");}while(0)
+#define _ei() do{asm(" ei");}while(0)
+#define _nop() do{asm(" nop");}while(0)
+#define _sleep() do{asm(" sleep");}while(0)
+
+#undef min
+#define min(x,y) ((x)<(y) ? (x):(y))
+
+#undef max
+#define max(x,y) ((x)>(y) ? (x):(y))
+
+#ifndef abs
+#define abs(x) ((x)>=0 ? (x):-(x))
+#endif
+#endif
+
+#endif